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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

字节跳动青训营——入营考核解答(持续更新中~~~)

考核内容: 在指定的题库中自主选择不少于 15 道算法题并完成解题,其中题目难度分配如下: 简单题不少于 10 道中等题不少于 4 道困难题不少于 1 道 解答代码 5.简单四则运算 (中) 代码实现: import ja…

TON(六)——fift算法,注释的改写

系列文章目录 TON(五) TON(四) TON(三) TON(二) TON(一) 前言 fift是一门十分强大的栈编程语言,,在TON中它是由c编译而成的语言…

WordPress官方发布“新”插件“SCF”(安全自定义字段)

安全自定义字段 (SCF) 为您提供了处理数据所需的所有工具,从而将 WordPress 网站转变为成熟的内容管理系统。 使用 SCF 插件可以完全控制您的 WordPress 编辑屏幕、自定义字段数据等。 按需添加字段—SCF字段生成器允许您快速轻松地将字段添加到 WP 编辑屏幕&…

第一个servlet程序

文章目录 在原有工程上建立模块前端配置前后端映射关系添加外部依赖库后端代码启动配置 在原有工程上建立模块 添加web框架 前端 应用结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>第一…

什么是SYN flood,如何处理

在数字化时代&#xff0c;随着互联网的普及和技术的飞速发展&#xff0c;网络安全问题变得日益严峻。Flood攻击&#xff0c;作为一种典型的网络攻击手段&#xff0c;对个人和企业的信息安全构成了重大威胁。通过深入了解Flood攻击的概念、特点、影响及解决方案&#xff0c;我们…

SpringSecurity源码分析以及如何解决前后端分离出现的跨域问题

解决Security前后端分离出现的跨域问题 一. Security源码分析 首先在看源码之前我们先来看这张图 , 这张图展示了Security执行的全部流程 从上图可知Security执行的入口是UsernamePasswordAuthenticationFilter这个抽象类 , 那我们就先从该类进行分析 1. UsernamePasswordAu…

【智慧大屏】BI智慧大屏,大屏可视化解决方案(word原件)

1.系统概述 1.1.需求分析 1.2.重难点分析 1.3.重难点解决措施 2.系统架构设计 2.1.系统架构图 2.2.关键技术 2.3.接口及要求 3.系统功能设计 3.1.功能清单列表 3.2.数据源管理 3.3.数据集管理 3.4.视图管理 3.5.仪表盘管理 3.6.移动端设计 3.1.系统权限设计 3.…

Scala入门基础(12)抽象类

抽象类&#xff0c;制定标准&#xff0c;不要求去具体实现 包含了抽象方法的类就是抽象类。抽象方法只是有方法名&#xff0c;没有具体方法体的方法 定义抽象类要用abstract&#xff08;抽象&#xff09;关键字 用智能驾驶技术举例&#xff1a;演示&#xff09…

深入理解WPF中的命令机制

Windows Presentation Foundation&#xff08;WPF&#xff09;是微软推出的一种用于构建桌面客户端应用程序的技术。它被认为是现代Windows应用程序的基础&#xff0c;具有强大的图形和媒体处理能力。在WPF中&#xff0c;“命令”是一个重要的概念&#xff0c;它为应用程序开发…

2024.10月11日--- SpringMVC拦截器

拦截器 1 回顾过滤器&#xff1a; Servlet规范中的三大接口&#xff1a;Servlet接口&#xff0c;Filter接口、Listener接口。 过滤器接口&#xff0c;是Servlet2.3版本以来&#xff0c;定义的一种小型的&#xff0c;可插拔的Web组件&#xff0c;可以用来拦截和处理Servlet容…

力扣 142.环形链表Ⅱ【详细解释】

一、题目 二、思路 三、代码 /*** Definition for singly-linked list.* class ListNode {* int val;* ListNode next;* ListNode(int x) {* val x;* next null;* }* }*/ public class Solution {public ListNode detectCycle(ListNode hea…

LSL常见应用场景及示例<一>

目录 往期推荐 场景1&#xff1a;如何在指定内存定义中定位一个函数&#xff1f; 场景2&#xff1a;如何在绝对内存偏移地址处定位一个函数&#xff1f; 场景3&#xff1a;如何在绝对地址处定位一个函数&#xff1f; 场景4&#xff1a;有多个函数必须位于特定的内存定义中。…

vue3+ts+vite--路由跳转,params传参好像丢失了?

前言 相信大家一定写过后台管理系统&#xff0c;有一个很普遍的功能&#xff0c;就是点击编辑&#xff0c;根据id&#xff0c;跳转到相对应的编辑页面&#xff0c;id是通过路由params传递过去了&#xff0c;但是还有一个需求是要将父组件的名称也传递过去 &#xff0c;过程特别…

从0到1封装一个image/pdf预览组件

iShot_2024-10-14_16.47.10 目录结构 content.vue <template><div class"no-content-block"><i class"iconfont icondocument large-file" /><div class"text-wrapper">{{ t(__ui__.siPreview.previewSupported) }}<…

Spring Cloud Sentinel配置

Spring Cloud Sentinel 文章目录 Spring Cloud Sentinel1. Sentinel Dashboard 启动2. Spring Cloud 客户端配置3. Sentinel Dashboard 限流配置流控模式直连关联链路 流控规则快速失败Warm Up排队等待 4. Sentinel Dashboard 熔断配置5. Sentinel Dashboard 热点配置 1. Senti…

MEMC功能详解

文章目录 MEMC的工作原理&#xff1a;优点&#xff1a;缺点&#xff1a;适用场景&#xff1a;1. Deblur&#xff08;去模糊&#xff09;2. Dejudder&#xff08;去抖动&#xff09;总结两者区别&#xff1a; MEMC&#xff08;Motion Estimation and Motion Compensation&#x…

打破“几何第五公设不可证明”的神话——黄氏平行定义使证明第五公设易如反掌

黄小宁 绿色图片中的直线平行的定义&#xff08;此定义可推广为相应的平面平行的定义&#xff09;使人能根据几何常识一下子证明第五公设从而表明“2000年都无人能解决的世界著名数学难题”其实是一个天大的笑话。

Linux 手撕线程池

前言 线程池 是 池化技术 中很典型的一个&#xff0c;它旨在高效的管理和复用线程资源&#xff01;在现在的计算机体系中&#xff0c;线程是执行任务&#xff08;调度&#xff09;的基本单位。然而&#xff0c;频繁的创建和销毁线程也会带来较大的开销&#xff0c;包括系统资源…

RISC-V笔记——Pipeline依赖

1. 前言 RISC-V的RVWMO模型主要包含了preserved program order、load value axiom、atomicity axiom、progress axiom和I/O Ordering。今天主要记录下preserved program order(保留程序顺序)中的Pipeline Dependencies(Pipeline依赖)。 2. Pipeline依赖 Pipeline依赖指的是&a…

ECCV‘24 | WTConv:小参数大感受野,基于小波变换的新型卷积

前言 近年来&#xff0c;人们尝试增加卷积神经网络&#xff08;CNN&#xff09;的卷积核大小&#xff0c;以模拟视觉Transformer&#xff08;ViTs&#xff09;自注意力模块的全局感受野。然而&#xff0c;这种方法很快就遇到了上限&#xff0c;并在实现全局感受野之前就达到了饱…