Dify学习-16-儿童故事绘本- 儿童故事绘本文生视频语音合成版-实操版本

https://github.com/claire360/Dify-Learing

儿童故事绘本文生视频语音合成版

本工作流主要是实现儿童故事绘本文本分镜提示词,通过分镜提示词生成图片,然后把后端图片和语音合成一个动画视频功能

代码解析

models/const.py

在这里插入图片描述
该文件定义了一些常量和枚举类型,用于统一管理故事类型、图片风格、支持的语言等信息。

from enum import Enum

class StoryType(str, Enum):
    custom = "custom"  # 自定义故事
    bedtime = "bedtime"  # 睡前故事
    fairy_tale = "fairy_tale"  # 童话故事
    adventure = "adventure"  # 冒险故事
    science = "science"  # 科普故事
    moral = "moral"  # 寓言故事

class ImageStyle(str, Enum):
    realistic = "realistic"  # 写实风格
    cartoon = "cartoon"  # 卡通风格
    watercolor = "watercolor"  # 水彩风格
    oil_painting = "oil_painting"  # 油画风格

class Language(str, Enum):
    CHINESE_CN = "zh-CN"      # 中文(简体)
    CHINESE_TW = "zh-TW"      # 中文(繁体)
    ENGLISH_US = "en-US"      # 英语(美国)
    JAPANESE = "ja-JP"        # 日语
    KOREAN = "ko-KR"          # 韩语

# 语言名称映射
LANGUAGE_NAMES = {
    Language.CHINESE_CN: "中文(简体)",
    Language.CHINESE_TW: "中文(繁体)",
    Language.ENGLISH_US: "English",
    Language.JAPANESE: "日本語",
    Language.KOREAN: "한국어"
}

schemas

在这里插入图片描述

llm.py

from pydantic import BaseModel, Field
from typing import List, Dict, Any
from models.const import Language
from typing import Optional

# 故事生成的设置
class StoryGenerationRequest(BaseModel):
    resolution: Optional[str] = Field(default="1024*1024", description="分辨率")
    text_llm_provider: Optional[str] = Field(default=None, description="Text LLM provider")
    text_llm_model: Optional[str] = Field(default=None, description="Text LLM model")
    image_llm_provider: Optional[str] = Field(default=None, description="Image LLM provider")
    image_llm_model: Optional[str] = Field(default=None, description="Image LLM model")
    segments: int = Field(..., ge=1, le=10, description="Number of story segments to generate")
    story_prompt: str = Field(..., min_length=1, max_length=4000, description="Theme or topic of the story")
    language: Language = Field(default=Language.CHINESE_CN, description="Story language")

# 故事分镜
class StorySegment(BaseModel):
    text: str = Field(..., description="Story text")
    image_prompt: str = Field(..., description="Image generation prompt")
    url: str = Field(None, description="Generated image URL")

# 故事生成请求
class StoryGenerationResponse(BaseModel):
    segments: List[StorySegment] = Field(..., description="Generated story segments")

# 图像生成请求模型类
class ImageGenerationRequest(BaseModel):
    prompt: str = Field(..., min_length=1, max_length=4000, description="Description of the image to generate")
    image_llm_provider: Optional[str] = Field(default=None, description="Image LLM provider")
    image_llm_model: Optional[str] = Field(default=None, description="Image LLM model")
    resolution: Optional[str] = Field(default="1024*1024", description="Image resolution")

# 图像生成响应模型类
class ImageGenerationResponse(BaseModel):
    image_url: str = Field(..., description="Generated image URL")

video.py

video.py: 定义了与视频生成相关的数据结构

enum
from enum import Enum:从 enum 模块导入 Enum 类,用于定义枚举类型。枚举类型可以将一组相关的常量组织在一起,提高代码的可读性和可维护性。

在这里插入图片描述

typing
from typing import Any, List, Optional, Union, Dict:从 typing 模块导入类型注解相关的类。Any 表示任意类型,List 用于表示列表类型,Optional 表示该类型可以是指定类型或者 None,Union 用于表示联合类型,Dict 用于表示字典类型。

在这里插入图片描述

pydantic

https://zhuanlan.zhihu.com/p/387492501

在这里插入图片描述

忽略特定警告
# 忽略 Pydantic 的特定警告
warnings.filterwarnings(
    "ignore",
    category=UserWarning,
    message="Field name.*shadows an attribute in parent.*",
)
定义枚举类型
class VideoConcatMode(str, Enum):
    random = "random"
    sequential = "sequential"


class VideoAspect(str, Enum):
    landscape = "16:9"
    portrait = "9:16"
    square = "1:1"

    def to_resolution(self):
        if self == VideoAspect.landscape.value:
            return 1920, 1080
        elif self == VideoAspect.portrait.value:
            return 1080, 1920
        elif self == VideoAspect.square.value:
            return 1080, 1080
        return 1080, 1920

class VideoAspect(str, Enum):定义一个名为 VideoAspect 的枚举类,继承自 str 和 Enum,表示视频的纵横比。
landscape = "16:9"、portrait = "9:16" 和 square = "1:1":定义枚举的三个值,分别表示横向(16:9)、纵向(9:16)和方形(1:1)的纵横比。
def to_resolution(self):定义一个实例方法 to_resolution,用于根据枚举值返回对应的视频分辨率。根据不同的纵横比返回不同的分辨率,默认返回纵向的分辨率(1080, 1920)。

api

在这里插入图片描述
video.py: 定义了与视频生成相关的 API 路由,通过 FastAPI 框架提供对外服务。

读取配置文件

这部分代码是导入所需的模块和函数:
fastapi 相关导入:
APIRouter:用于创建 API 路由的类。
HTTPException:用于在 API 中抛出 HTTP 异常。
Query:用于处理查询参数。
Header:用于获取 HTTP 请求头。
Depends:用于依赖注入。
loguru.logger:用于日志记录的工具。
services.video 模块中的函数:generate_video、create_video_with_scenes 和 generate_voice,这些函数可能用于视频生成、场景创建和语音生成。
schemas.video 模块中的类:VideoGenerateRequest、VideoGenerateResponse 和 StoryScene,用于定义请求和响应的数据结构。
os 模块:提供了与操作系统进行交互的功能。
json 模块:用于处理 JSON 数据。
utils.utils 模块中的 extract_id 函数,可能用于提取 ID。
configparser 模块:用于读取配置文件。

router = APIRouter()

创建一个 APIRouter 实例,用于定义和组织 API 路由。

有什么用呢?

router = APIRouter() 是 FastAPI 中用于组织和管理路由(API 端点)的核心工具,它的作用类似于 Flask 中的 Blueprint 或 Django 中的 urls.py。通过 APIRouter(),你可以将大型项目的 API 拆分为多个模块化组件,提升代码的可维护性和可扩展性。
@router.post("/story/generatestory")
async def generate_video_endpoint(
    request: VideoGenerateRequest,
    auth_token: str = Depends(verify_auth_token)
):
    """生成视频"""
    try:
        video_file = await generate_video(request)
        video_url = video_file
        print("video_url::::"+video_url)
        return VideoGenerateResponse(
            success=True,
            data={"video_url": video_url}
        )
    except Exception as e:
        logger.error(f"Failed to generate video: {str(e)}")
        return VideoGenerateResponse(
            success=False,
            message=str(e)
        )
使用 @router.post 装饰器定义一个 POST 请求的 API 路由,路径为 /story/generatestory。
定义一个异步函数 generate_video_endpoint,用于处理视频生成请求。
函数接受两个参数:
request:类型为 VideoGenerateRequest,表示视频生成请求的数据。
auth_token:通过依赖注入调用 verify_auth_token 函数进行令牌验证。
尝试调用 generate_video 函数生成视频文件,并将其赋值给 video_file。
将 video_file 赋值给 video_url。
打印视频 URL。
如果视频生成成功,返回一个 VideoGenerateResponse 对象,包含 success 为 True 和视频 URL。
如果发生异常,记录错误日志并返回一个 VideoGenerateResponse 对象,包含 success 为 False 和错误消息。

这个auth valid_tokens 是在哪得到的,填的是什么呢?

这个auth valid_tokens 是在哪得到的,填的是什么呢?
[auth] 部分的 valid_tokens 是自定义的有效令牌列表,用于 API 鉴权。你可以手动生成令牌或从第三方服务获取令牌,并将其添加到列表中。客户端在调用 API 时需要在请求头中提供有效的令牌,服务端会对其进行验证。

teststoryvideo.py

该文件提供了一个测试客户端 StoryVideoClient,用于测试视频生成功能。
在这里插入图片描述

storymain.py

该文件是项目的入口文件,使用 FastAPI 框架启动一个 Web 服务,并挂载视频生成相关的路由。

整体流程

整体流程
用户通过 StoryVideoClient 发起视频生成请求,传入故事提示、分段数、语言等参数。
StoryVideoClient 向服务端发送 HTTP 请求,请求地址为 /story/generatestory。
服务端接收到请求后,根据测试模式的不同进行处理:

测试模式:从 story.json 文件中读取数据。

非测试模式:调用 LLMService 生成故事场景和配图,下载图片并保存故事数据到 story.json 文件。
最后,调用 create_video_with_scenes 函数生成视频。

.ttc

在这里插入图片描述

zh-CN-XiaoxiaoNeural

在这里插入图片描述
文字转语音的包

在这里插入图片描述

提示

文字和图片的返回形式都已经定义好了

async def _get_story_prompt(self, story_prompt: str = None, language: Language = Language.CHINESE_CN, segments: int = 3) -> str:
        """生成故事提示词

        Args:
            story_prompt (str, optional): 故事提示. Defaults to None.
            segments (int, optional): 故事分段数. Defaults to 3.

        Returns:
            str: 完整的提示词
        """

        languageValue = LANGUAGE_NAMES[language]
        if story_prompt:
            base_prompt = f"讲一个故事,主题是:{story_prompt}"
        
        return f"""
        {base_prompt}. The story needs to be divided into {segments} scenes, and each scene must include descriptive text and an image prompt.

        Please return the result in the following JSON format, where the key `list` contains an array of objects:

        **Expected JSON format**:
        {{
            "list": [
                {{
                    "text": "Descriptive text for the scene",
                    "image_prompt": "Detailed image generation prompt, described in English"
                }},
                {{
                    "text": "Another scene description text",
                    "image_prompt": "Another detailed image generation prompt in English"
                }}
            ]
        }}

        **Requirements**:
        1. The root object must contain a key named `list`, and its value must be an array of scene objects.
        2. Each object in the `list` array must include:
            - `text`: A descriptive text for the scene, written in {languageValue}.
            - `image_prompt`: A detailed prompt for generating an image, written in English.
        3. Ensure the JSON format matches the above example exactly. Avoid extra fields or incorrect key names like `cimage_prompt` or `inage_prompt`.

        **Important**:
        - If there is only one scene, the array under `list` should contain a single object.
        - The output must be a valid JSON object. Do not include explanations, comments, or additional content outside the JSON.

        Example output:
        {{
            "list": [
                {{
                    "text": "Scene description text",
                    "image_prompt": "Detailed image generation prompt in English"
                }}
            ]
        }}
        """

在这里插入图片描述

生成故事情节和每个情节对应的图片描述(英文)

在这里插入图片描述

开始生成每个视频的场景
在这里插入图片描述

.srt是什么文件

.srt 是一种常见的 字幕文件格式(SubRip Subtitle),主要用于存储视频的文本字幕信息。它的特点是纯文本、结构简单,被广泛用于视频播放器、剪辑软件和流媒体平台。

在这里插入图片描述

合成了所有的片段

在这里插入图片描述
返回了生成视频的地址-我没有上传到腾讯COS,因为又要注册,感觉可能还要花钱,我觉得没这个必要。

生成视频

保存图片

在这里插入图片描述

开始配置进行debug吧

问题1:ini是什么东西+如何传入代码里面的

config.ini

.ini 文件是一种常见的 配置文件格式(扩展名为 .ini),用于存储程序的配置参数(如数据库连接、路径设置等)。它的结构简单、易读,通常由 节(Section)、键(Key) 和 值(Value) 组成。Python 中可以通过标准库 configparser 或第三方库(如 pydantic)来解析和传入配置。
在这里插入图片描述

在这里插入图片描述

import configparser

# 读取配置文件中的API密钥
config = configparser.ConfigParser()

这是什么意思

在这里插入图片描述
我还好奇为什么要用腾讯的COS,这里没有出现调用[common]的地方
在这里插入图片描述
在这里插入图片描述

2. 使用腾讯云 COS 的原因
使用腾讯云对象存储(COS)可能有以下几个原因:
2.1 高可靠性和可用性
腾讯云 COS 提供了高可靠性的数据存储服务,采用了分布式存储架构和多副本机制,确保数据的安全性和可靠性。即使在硬件故障或自然灾害等情况下,也能保证数据的可用性。
2.2 弹性扩展
COS 支持弹性扩展,用户可以根据实际需求动态调整存储空间的大小,无需担心存储空间不足的问题。这对于处理大量数据或数据量波动较大的应用场景非常有用。
2.3 高性能
腾讯云 COS 具有高性能的数据读写能力,能够快速响应应用程序的请求。通过优化存储架构和网络性能,COS 可以提供低延迟、高吞吐量的数据访问服务,满足应用程序对数据读写速度的要求。
2.4 安全性
COS 提供了多种安全机制,包括访问控制、数据加密、防盗链等,确保数据的安全性和隐私性。用户可以根据自己的需求设置不同的安全策略,保护数据不被非法访问和篡改。
2.5 成本效益
相比自建存储系统,使用腾讯云 COS 可以降低企业的 IT 成本。用户无需购买和维护硬件设备,只需根据实际使用量支付费用,降低了前期投资和运营成本。
2.6 集成方便
腾讯云 COS 提供了丰富的 SDK 和 API,方便开发者将其集成到自己的应用程序中。同时,COS 还与腾讯云的其他服务(如云服务器、云函数等)紧密集成,为开发者提供了一站式的解决方案。
综上所述,使用腾讯云 COS 可以为应用程序提供高可靠性、高性能、安全性和成本效益的存储服务,同时方便开发者进行集成和管理。

我不太想用,我也不知道为什么要用,就是为了传入到云上面去吗?

说明 common 配置下面4个值是腾讯COS 相关配置,主要目的生成的视频上传腾讯COS 上方便后面浏览和显示视频。

在【api/video.py】也有是调用config.ini
在这里插入图片描述

得到了视频的本地的地址,就可以直接返回给前端,进行下载不就可以了吗

搞不了,一直返回不出来,有问题!!!

结果

在这里插入图片描述
在这里插入图片描述

网络端口号是怎么看啊

dify中写的是ip地址,而不是这个本地的地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向上Claire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值