【大模型】AI视频课程制作工具开发

news2024/11/29 4:05:16

1. 需求信息

1.1 需求背景

讲师们在制作视频的过程中,发现录制课程比较麻烦,要保证环境安静,保证录制过程不出错,很容易反复重复录制,为了解决重复录制的工作量,想通过 ai 课程制作工具,来解决这些问题。

2. 业务分析

2.1 视频生成过程

  1. 视频素材来源: 首先由产品研发团队的产品、架构师协助提供基础资料,根据产品材料来输出ppt文档;
  2. 素材上传:使用的授课课件材料,如:PPT 或 PDF(也有doc课件大纲、课程详细内容,现在我们基本上用不上),上传到AI视频制作工具平台;
  3. 素材文本提取:a. 提取素材文本内容(ppt内容+备注);b. 将素材截图成图片;
  4. 演讲稿制作:将第3步提取的文字,交由混元来生成讲课稿,这里可以人工校验句子合理性;
  5. 演讲稿合成语音:将第4步生成的讲课稿合成音频文件;
  6. 合成视频:将音频、图片合成视频。

其中,2~6可以合成一步,就是在有讲课稿的情况下,直接提取备注合成视频。

2.2 视频课程权限

  1. 数据隔离和安全:课程以空间的概念相互隔离, 用户使用OA登录系统后,默认不可见其他同事创建的空间,只能看到自己创建的空间。
  2. 数据共享协作:空间创建者默认拥有空间管理权限,可以邀请其他同事协作;
  3. 超级管理员:超级管理员课件所以课件,超级管理员不可配置,只能研发修改数据库角色。

2.4 发音修正

部分专业英文缩写发音不准的问题,可以通过SMAL标记语言修正发音,因此提供一个发音修正管理菜单,用户可以自定义发音部分单词。

2.5 用户登录限制

  1. 系统接入OA登录,只能在内网访问;
  2. 给用户添加权限,必须在用户登录过系统之后,才能添加(必须用户登录之后,系统才会记录用户信息)。

3. 技术设计

3.1 视频制作流程

目前我们的技术方案是腾讯云语音合成(TTS)+视频合成(云点播)+混元大模型来搭建的。支持2种方式来生成视频:

  1. 无讲课稿的情况下,通过解析读取ppt文档的内容和备注, 调用混元大模型来生成演讲稿, 演讲稿生成语音, 再截取PPT的图片,来合成视频;
  2. 有讲课稿的情况下, 支持一件生成讲课视频。

整体流程入下图所示:

在这里插入图片描述

3.2 发音纠正

由于课程内容主要是腾讯云的产品培训,因此有很多腾讯云相关的专有英文名词和缩写,腾讯云TTS对这些词的合成不够理想,不过提供了SSML 标记语言,用来自定义纠正发音,如上图发音纠正部分。

3.3 相关技术工具

  1. 腾讯云对象存储cos,制作课程过程中的各种素材,包括:文件、图片、音频、视频等都是存储在cos里面
  2. 数据万象: PPT转PDF使用的是cos 自带的数据万象能力,可以把ppt转换为pdf格式文件
  3. 开源工具pptx:可以读取ppt的演讲稿的文本和备注;
  4. 开源工具PyPDF2:可以把pdf文件截取成图;
  5. 混元大模型:提供AIGC能力,写入prompt讲提取的课件文本生成讲课稿;
  6. 语音合成(TTS):使用腾讯云TTS将文本生成生动的语音;
  7. 视频合成:腾讯云点播将音频和图片按时间线生成视频;
  8. 后端web框架:fastapi,一个python的http服务框架;
  9. 前端框架:内部开源的TDesign。

4 问题

4.1 语音合成(TTS)

目前业务方使用反馈最多的是腾讯云TTS的语言合成效果问题,例如:

  1. 专有名词发音不正确;
  2. 同一个语音类型发音过程中切换;
  3. 中、英切换过程中出现不同发音。

针对上述问题已经在尝试2个不同的解决方案:

  1. 推动腾讯云TTS优化:已经拉通TTS产品团队在支持,并逐步在收集发音的base case;
  2. 调研开源TTS语音合成大模型,目前已知的ChatTTS 和阿里开源的CosyVoice 都有非常流畅的效果;
  3. 第三方云平台的TTS 实现,目前国内讯飞的合成效果也不错。

4.2 讲课稿生成

讲课稿的生成过程比较耗时,一个课程小节经常长达100+页ppt,每一页都需要AIGC生成后,还需要人工精调。

针对这个问题可以考虑:

  1. 增强知识库,随着课程制作素材的累积,我们将形成一个优质的知识库,可以提供大模型非常好的知识增强;
  2. 个性化微调大模型:随着数据的积累,可以使用混元一站式训练平台,对针对性微调个性化模型专门用来优化演讲稿生成。

附件

主要python工具包

  • fastapi==0.111.0 // fastapi web框架
  • python-pptx==0.6.23 // pptx 内容读取
  • pdf2image==1.17.0 // pdf转图片
  • tencentcloud-sdk-python==3.0.1132 // 调用腾讯云api

文本提取

from pptx import Presentation
import PyPDF2
import tempfile,io,requests
from dependencies import FILE_NAME_MAX_LENGTH, new_file_name
from logger_config import logger
from repo import schemas
from typing import List
from fastapi import HTTPException
from starlette.status import HTTP_400_BAD_REQUEST, HTTP_200_OK

# 提取ppt中的正文和备注
def extract_info_from_ppt(ppt_url: str) -> List[schemas.PPtTextNode]:
        # 下载PDF文件
    logger.info('开始下载ppt文件: ' + ppt_url)
    response = requests.get(ppt_url)
    if response.status_code != HTTP_200_OK:
        logger.error("file download failed : " + ppt_url)
        raise HTTPException(
            status_code=HTTP_400_BAD_REQUEST,
            detail="文件下载失败",
        )
    pdf_bytes = response.content
     # 将字节流转换为文件对象
    file_obj = io.BytesIO(pdf_bytes)
    # 加载 PowerPoint 文档
    presentation = Presentation(file_obj)

    # 备注内容
    slide_infos : List[schemas.PPtTextNode] = []
    # 遍历幻灯片
    for slide in presentation.slides:
        # 获取幻灯片上的文本
        slide_text = ""
        for shape in slide.shapes:
            if hasattr(shape, "text"):
                slide_text += shape.text
        # 获取幻灯片的备注
        notes_slide = slide.notes_slide
        # 获取备注文本
        notes_text = notes_slide.notes_text_frame.text

        # 添加到备注列表
        slide_infos.append(schemas.PPtTextNode(text=slide_text, note=notes_text))
    return slide_infos
# 提取pdf中的内容
def extract_info_from_pdf(pdf_url: str):
    # 下载PDF文件
    logger.info('开始下载PDF文件: ' + pdf_url)
    response = requests.get(pdf_url)
    if response.status_code != HTTP_200_OK:
        raise HTTPException(
            status_code=HTTP_400_BAD_REQUEST,
            detail="文件下载失败",
        )
    pdf_bytes = response.content
    # 将字节流转换为文件对象
    file_obj = io.BytesIO(pdf_bytes)

    # 加载 PDF 文件
    pdf_reader = PyPDF2.PdfReader(file_obj)
    # 获取 PDF 文件的页数
    num_pages = len(pdf_reader.pages)
    # 遍历 PDF 文件的每一页
    slide_infos : List[schemas.PPtTextNode] = []
    for page_num in range(num_pages):
        # 获取当前页
        page = pdf_reader.pages[page_num]
        # 提取页面内容
        content = page.extract_text()
        # 添加到备注列表
        silde_info = schemas.PPtTextNode(text=content, notes="")
        slide_infos.append(silde_info)
    return slide_infos

pdf转图片

import os
from logic.qcloud import cosclient
import tempfile
from logger_config import logger
import requests,re
from pdf2image import convert_from_bytes
from typing import List
from repo import schemas
import tracemalloc
import config

from dependencies import FILE_NAME_MAX_LENGTH, new_file_name

# 定义一个函数来验证文件名是否安全
def is_safe_filename(filename):
    # 使用正则表达式来匹配合法的文件名
    return bool(re.match(r'^[\w\-.]+$', filename))

def pdf_url_to_images(pdf_url: str, space_id: int)->List[schemas.PPtToImage]:
    # 下载PDF文件
    logger.info('开始下载PDF文件: ' + pdf_url)
    response = requests.get(pdf_url)
    pdf_bytes = response.content
    
     # 将PPT文件的每一页保存为图像
    output_folder = tempfile.mkdtemp()
    
    # 将PDF文件转换为图像
    tracemalloc.start()
    # 获取内存分配情况的快照
    if config.get_settings().is_tracemalloc == True:
        snapshot1 = tracemalloc.take_snapshot()
            
    images = convert_from_bytes(pdf_bytes)

    if config.get_settings().is_tracemalloc == True:
        snapshot2 = tracemalloc.take_snapshot()
        # 比较两个快照,找出内存分配差异
        top_stats = snapshot2.compare_to(snapshot1, "lineno")
        # 打印内存分配差异的统计信息
        for stat in top_stats[:10]:
            logger.info("读取文件后,内存分配差异: %s" % stat)

        total_size = sum(stat.size for stat in snapshot2.statistics("lineno"))

        # 将字节转换为合适的单位(如 MiB)
        total_size_mib = total_size / (1024 * 1024)

        logger.info(f"读取文件后,总内存分配: {total_size_mib:.2f} MiB")

    #image_urls = []
    file_infos : List[schemas.PPtToImage] = []
    for index, image in enumerate(images):
        image_path = os.path.join(output_folder, f"page_{index + 1}.png")
        image.save(image_path, "PNG")

        # 上传图像到COS
        url = ""
        file_name = os.path.basename(image_path)
        image_key = new_file_name(file_name, space_id)
        if len(image_key) > FILE_NAME_MAX_LENGTH:
            image_key = image_key[:FILE_NAME_MAX_LENGTH]
        
        cosclient.put_object_file(image_path, image_key)
        url = cosclient.get_presigned_url(image_key)
        file_infos.append(schemas.PPtToImage(image_name=image_key, image_url=url))
        logger.info(f"Uploaded {image_path} to {image_key}")

    # 删除临时文件夹
    for image_filename in os.listdir(output_folder):
            # 验证文件名是否安全
        if is_safe_filename(image_filename):
            # 如果文件名安全,则删除文件
            os.unlink(os.path.join(output_folder, image_filename))
        else:
            # 如果文件名不安全,记录日志并跳过删除操作
            logger.warning(f"Unsafe filename detected: {image_filename}. Skipping deletion.")

    os.rmdir(output_folder)

    return file_infos

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2218750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Rust引用与C++取地址、引用的区别(C++引用、Rust解引用、C++指针)

文章目录 Rust引用与C取地址和引用的比较一、内存安全与管理Rust的内存安全机制C的内存管理 二、引用和取地址Rust的引用C的引用和取地址 三、代码示例比较修改数据的安全性Rust示例C示例 四、结论 Rust引用与C取地址和引用的比较 在程序设计语言的世界里,Rust和C都…

【C++】string类(接口使用详解 下)

我们接着【C】string类(接口使用详解 上)-CSDN博客 继续介绍string的使用。 1.string类对象的修改操作 我们就说一下用的比较多的接口。 1.1 operator 这个接口可以尾插一个字符,或者一个字符串,或者一个对象。 string s1(&qu…

Java—类和对象习题讲解

如果您觉得这篇文章对您有帮助的话 欢迎您一键三连,小编尽全力做到更好 欢迎您分享给更多人哦 目录 习题一: 习题二: 习题三:.import static 能够导入一些静态方法 习题四: 习题五: 习题六&#xff1…

[LeetCode] 415.字符串相加

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。 你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。 示例 1: 输入&#xff…

SHELL脚本之数组介绍

shell数组 一.数组介绍 一段连续的内存空间,根据需要可以存多个数据。 变量定义:从内存中申请一段空间,用来存储数据。 如果同一种类型的数据,每一个数据都定义一个变量,当机器对这些变量进行寻址的时候&#xff0…

【Neo4j】- 轻松入门图数据库

文章目录 前言-场景一、Neo4j概述二、软件安装部署1.软件下载2.软件部署3.软件使用4.语法学习 总结 前言-场景 这里用大家都了解的关系数据与图数据据库对比着说,更加方便大家理解图数据库的作用 图形数据库和关系数据库均存储信息并表示数据之间的关系。但是,关系…

Aspose.PDF功能演示:使用 JavaScript 从 PDF 中提取文本

在数据提取、业务文档自动化和文本挖掘方面,使用 JavaScript 从PDF中提取文本非常有用。它允许开发人员自动执行从 PDF 收集信息的过程,从而显著提高处理大量文档的生产力和效率。在这篇博文中,我们将学习如何使用 JavaScript 从 PDF 中提取文…

功能安全实战系列-软件FEMA分析与组件鉴定

本文框架 前言1. 功能安全分析1.1 Why1.2 What?1.3 How?1.3.1 分析范围确定1.3.2 失效模式分析1.3.3 安全措施制定1.3.4 确认是否满足功能安全目标2. 软件组件鉴定2.1 Why2.2 How?前言 在本系列笔者将结合工作中对功能安全实战部分的开发经验进一步介绍常用,包括Memory(Fl…

stable diffusion 大模型及lora等下载安装使用教程及项目目录说明

首先说明,stable diffusion大模型并非controlNet中使用的模型,这两者有根本的区别,请仔细区分。 国内可下载模型的站点: 哩布哩布 https://liblib.ai 模型分为几类,下载的时候看清楚类型,都会标记在模型…

Python编程探索:从基础语法到循环结构实践(下)

文章目录 前言🍷四、 字符串拼接:连接多个字符串🍸4.1 使用 操作符进行字符串拼接🍸4.2 使用 join() 方法进行字符串拼接🍸4.3 使用 format() 方法进行格式化拼接🍸4.4 使用 f-string(格式化字…

【Linux】进程池

目录 进程池 进程池的概念: 手搓进程池: 1、创建信道和子进程 2、通过channel控制子进程 3、回收管道和子进程 进程池 进程池的概念: 定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中…

Linux fork函数

目录 0.前言 1.fork函数初识 2.写时拷贝 3.fork常规用法 4.fork调用失败的原因 5.小结 (图像《分叉之光:科幻视角下的Linux进程复制》由AI生成) 0.前言 在Linux操作系统中,进程是系统资源管理的核心单元。每一个程序的执行都对…

机器学习(MachineLearning)(8)——模型评估与优化

机器学习(MachineLearning)(1)——机器学习概述 机器学习(MachineLearning)(2)——线性回归 机器学习(MachineLearning)(3)——决策树…

Java网络编程-简单的API调用

Get请求 - 无参数 安装依赖库 首先需要安装一个库&#xff1a; Okhttp3&#xff0c;这是一个非常流行的 HTTP 库&#xff0c;可以简单、快速的实现 HTTP 调用。 安装 Okhttp3 的方式是在 pom.xml 文件中增加依赖&#xff1a; <!-- https://mvnrepository.com/artifact/co…

【Vue.js设计与实现】第三篇第9章:渲染器-简单Diff算法-阅读笔记

文章目录 9.1 减少 DOM 操作的性能开销9.2 DOM 复用与 key 的作用9.3 找到需要移动的元素9.4 如何移动元素9.5 添加新元素9.6 移除不存在的元素 系列目录&#xff1a;【Vue.js设计与实现】阅读笔记目录 当新旧vnode 的子节点都是一组节点时&#xff0c;为了以最小的性能…

PSPICE FOR TI笔记记录1

快捷放置器件 R旋转 连线 w,单击器件引脚方块部分 电压探测笔 创建仿真文件 Analysis Type 分析模式&#xff1a;比如时域分析&#xff0c;频域分析 Run To Time 仿真时长 Skip intial transient bias point calculation (跳过初始瞬态偏置点计算(SKIPBP))一定要勾选 编辑…

高级语言源程序转换为可执行目标文件

将高级语言源程序转换为可执行目标文件的过程通常包括以下几个主要步骤&#xff1a; ​ 1. 预处理&#xff08;Preprocessing&#xff09;&#xff1a; 由谁完成预处理器&#xff08;cpp&#xff09;操作处理源代码中的预处理指令&#xff08;如宏定义、文件包含、条件编译等&…

k8s 1.28.2 集群部署 harbor v2.11.1 接入 MinIO 对象存储

文章目录 [toc]提前准备什么是 HarborHarbor 架构描述Harbor 安装的先决条件硬件资源软件依赖端口依赖 Harbor 在 k8s 的高可用Harbor 部署Helm 编排YAML 编排创建 namespace导入镜像部署 Redis部署 PostgreSQL部署 Harbor core部署 Harbor trivy部署 Harbor jobservice部署 Ha…

《Sui区块链:重塑去中心化应用的新星与未来潜力》

目录 引言 一、Sui 1、 技术架构 2、 编程语言 3、Move起源 4、Move的几个关键点&#xff1a; 5、Move 智能合约编程语言 6、智能合约编程语言可以做什么 7、和其他编程语言有什么不同 8、 安全性 9、开发者体验 10、生态系统 11、 未来发展 总结 引言 在区块链技…

AIGC助力小学生编程梦:C++入门不再难!

文章目录 一、AIGC时代下的编程教育新趋势二、小学生C入门趣味编程的意义三、小学生C入门趣味编程的实践策略四、面临的挑战与应对策略五、AIGC技术在小学生C编程中的应用与前景《小学生C趣味编程从入门到精通》编辑推荐内容简介作者简介目录 随着人工智能生成内容&#xff08;…