Video_generate.md 17 KB

AI视频生成模块开发文档

模块概述

实现完整的AI视频生成模块,集成阿里云百炼平台(DashScope),支持数字人合成和通用视频合成两大功能。

技术栈

  • 后端框架:FastAPI
  • ORM:SQLAlchemy 2.0
  • 数据库:PostgreSQL(schema: aigcspace)
  • AI平台:阿里云百炼平台(dashscope SDK + HTTP API)
  • 存储:阿里云OSS(已有oss_service)
  • 认证:JWT Token(已有auth中间件)

一、子模块划分

1.1 数字人合成模块

基于数字人模型,通过单张图片和音频生成动作自然的说话/唱歌/表演视频。

模型列表: | 模型ID(model_id) | 功能 | 计费说明 | |---------|------|------| | wan2.2-s2v | 数字人视频合成 | 按视频时长计费,从model_price表获取单价 | | wan2.2-s2v-detect | 图像检测(检测图片是否符合规范) | 按张计费,从model_price表获取单价 |

支持参数(完全参照文档):

  • image_url:人物图片URL(必填)
  • audio_url:音频文件URL(必填,wav/mp3,<15M,<20s)
  • resolution:分辨率(可选,480P/720P,默认480P)

1.2 视频合成模块

统一API端点,支持三种输入模式的视频生成。

模型列表: | 模型ID(model_id) | 功能 | 计费说明 | |---------|------|------| | wan2.6-t2v | 文生视频(多镜头叙事、自动配音、720P/1080P、5/10/15秒) | 按视频时长计费,从model_price表获取单价 | | wan2.6-i2v | 图生视频(首帧/尾帧控制、音频同步、720P/1080P、5/10/15秒) | 按视频时长计费,从model_price表获取单价 |

三种输入模式:

  1. 仅提示词:调用wan2.6-t2v文生视频
  2. 提示词+首帧图片:调用wan2.6-i2v图生视频
  3. 提示词+首帧+尾帧图片:调用wan2.6-i2v图生视频(尾帧控制结束画面)

二、API端点设计

2.1 数字人合成API

# 图像检测(前端预检测)
POST /api/video/avatar/detect
请求体:{ "image_url": "string" }
响应:{ "check_pass": bool, "humanoid": bool, "message": "string" }

# 创建数字人合成任务
POST /api/video/avatar/generate
请求体:{
    "image_url": "string",      // 必填,人物图片URL
    "audio_url": "string",      // 必填,音频URL
    "resolution": "480P|720P"   // 可选,默认480P
}
响应:{ "task_id": "string", "task_status": "PENDING" }

# 查询任务状态
GET /api/video/avatar/task/{task_id}
响应:{
    "task_id": "string",
    "task_status": "PENDING|RUNNING|SUCCEEDED|FAILED",
    "video_url": "string",      // 成功时返回
    "video_duration": float,    // 视频时长(秒)
    "error_message": "string"   // 失败时返回
}

2.2 视频合成API(统一端点)

# 创建视频生成任务
POST /api/video/generate
请求体:{
    "prompt": "string",              // 必填,视频描述提示词
    "first_frame_url": "string",     // 可选,首帧图片URL
    "last_frame_url": "string",      // 可选,尾帧图片URL(需先有首帧)
    "negative_prompt": "string",     // 可选,反向提示词
    "resolution": "720P|1080P",      // 可选,默认720P
    "duration": 5|10|15,             // 可选,默认5秒
    "audio_url": "string",           // 可选,自定义音频URL
    "audio": bool,                   // 可选,是否自动生成音频,默认true
    "prompt_extend": bool,           // 可选,是否智能改写,默认true
    "shot_type": "single|multi",     // 可选,镜头类型(仅文生视频)
    "watermark": bool,               // 可选,是否添加水印,默认false
    "seed": int                      // 可选,随机种子
}
响应:{ "task_id": "string", "task_status": "PENDING" }

# 查询任务状态
GET /api/video/task/{task_id}
响应:{
    "task_id": "string",
    "task_status": "PENDING|RUNNING|SUCCEEDED|FAILED",
    "video_url": "string",
    "video_duration": float,
    "actual_prompt": "string",       // 智能改写后的提示词
    "error_message": "string"
}

# 获取历史记录
GET /api/video/history?page=1&page_size=20
响应:{
    "items": [...],
    "total": int,
    "page": int,
    "page_size": int
}

三、数据表设计

3.1 视频模型参数表(video_model_config)

存储各视频模型的支持参数配置,供前端动态渲染表单。

CREATE TABLE IF NOT EXISTS aigcspace.video_model_config (
    id SERIAL PRIMARY KEY,
    model_name VARCHAR(100) NOT NULL UNIQUE,        -- 模型名称(如wan2.6-t2v)
    model_id VARCHAR(100) NOT NULL,                 -- 模型ID
    model_type VARCHAR(50) NOT NULL,                -- 模型类型:t2v/i2v/s2v
    supported_params JSONB NOT NULL,                -- 支持的参数配置JSON
    is_active BOOLEAN DEFAULT TRUE,                 -- 是否启用
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 索引
CREATE INDEX idx_video_model_config_type ON aigcspace.video_model_config(model_type);
CREATE INDEX idx_video_model_config_active ON aigcspace.video_model_config(is_active);

supported_params JSON结构示例:

{
    "resolutions": ["720P", "1080P"],
    "durations": [5, 10, 15],
    "max_prompt_length": 1500,
    "supports_audio": true,
    "supports_audio_url": true,
    "supports_multi_shot": true,
    "supports_first_frame": false,
    "supports_last_frame": false,
    "aspect_ratios": {
        "720P": ["1280*720", "720*1280", "960*960"],
        "1080P": ["1920*1080", "1080*1920", "1440*1440"]
    }
}

3.2 视频生成记录表(ai_video)

CREATE TABLE IF NOT EXISTS aigcspace.ai_video (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,                       -- 用户ID
    task_id VARCHAR(100) NOT NULL UNIQUE,           -- 百炼平台任务ID
    model_name VARCHAR(100) NOT NULL,               -- 使用的模型名称
    video_type VARCHAR(50) NOT NULL,                -- 视频类型:t2v/i2v/s2v
    
    -- 输入参数
    input_params JSONB NOT NULL,                    -- 输入参数JSON(包含所有请求参数)
    prompt TEXT,                                    -- 原始提示词
    actual_prompt TEXT,                             -- 智能改写后的提示词
    first_frame_url VARCHAR(500),                   -- 首帧图片URL
    last_frame_url VARCHAR(500),                    -- 尾帧图片URL
    audio_url VARCHAR(500),                         -- 音频URL
    
    -- 输出结果
    video_url VARCHAR(500),                         -- 输出视频OSS URL
    video_duration NUMERIC(10, 2),                  -- 视频时长(秒)
    resolution VARCHAR(20),                         -- 视频分辨率
    
    -- 任务状态
    status VARCHAR(20) NOT NULL DEFAULT 'PENDING',  -- PENDING/RUNNING/SUCCEEDED/FAILED
    error_message TEXT,                             -- 错误信息
    
    -- 费用
    bill NUMERIC(10, 4) DEFAULT 0,                  -- 任务消耗费用
    
    -- 时间戳
    submit_time TIMESTAMP,                          -- 任务提交时间
    scheduled_time TIMESTAMP,                       -- 任务开始执行时间
    end_time TIMESTAMP,                             -- 任务完成时间
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 索引
CREATE INDEX idx_ai_video_user_id ON aigcspace.ai_video(user_id);
CREATE INDEX idx_ai_video_task_id ON aigcspace.ai_video(task_id);
CREATE INDEX idx_ai_video_status ON aigcspace.ai_video(status);
CREATE INDEX idx_ai_video_created_at ON aigcspace.ai_video(created_at DESC);
CREATE INDEX idx_ai_video_video_type ON aigcspace.ai_video(video_type);

-- 表注释
COMMENT ON TABLE aigcspace.ai_video IS 'AI视频生成记录表';
COMMENT ON COLUMN aigcspace.ai_video.video_type IS '视频类型:t2v=文生视频,i2v=图生视频,s2v=数字人合成';
COMMENT ON COLUMN aigcspace.ai_video.input_params IS '完整输入参数JSON,便于追溯';
COMMENT ON COLUMN aigcspace.ai_video.actual_prompt IS '开启prompt_extend时返回的改写后提示词';

四、后端服务实现

4.1 文件结构

backend/app/
├── models/
│   └── ai_video.py              # 视频相关ORM模型
├── schemas/
│   └── video_schema.py          # 视频相关Pydantic模型
├── services/
│   ├── video_service.py         # 视频合成服务(统一入口)
│   ├── avatar_service.py        # 数字人合成服务
│   └── video_billing.py         # 视频费用计算
├── routers/
│   └── video_router.py          # 视频API路由
└── migrations/
    ├── 022_create_video_model_config.sql
    └── 023_create_ai_video_table.sql

4.2 核心服务实现要点

video_billing.py(视频费用计算)

"""
视频生成计费计算器

从数据库model_price表获取模型价格,计算视频生成费用
视频模型使用output_price字段存储每秒视频的价格
计费公式: cost = output_price × video_duration
"""
from decimal import Decimal, ROUND_HALF_UP
from sqlalchemy.orm import Session, joinedload

from app.models.model import Model, ModelPrice


class VideoBillingCalculator:
    """视频生成计费计算器"""

    def __init__(self, db: Session):
        self.db = db

    def calculate_cost(self, model_id: str, video_duration: float) -> Decimal:
        """
        计算视频生成费用
        
        Args:
            model_id: 模型标识(如 wan2.6-t2v, wan2.2-s2v)
            video_duration: 视频时长(秒)
            
        Returns:
            费用金额(CNY),精度4位小数
        """
        if video_duration <= 0:
            return Decimal("0.0000")

        model = self.db.query(Model).options(
            joinedload(Model.price_info)
        ).filter(Model.title == model_id).first()

        if not model or not model.price_info:
            return Decimal("0.0000")

        price_per_second = Decimal(str(model.price_info.output_price))
        total_cost = price_per_second * Decimal(str(video_duration))

        return total_cost.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP)

    def calculate_detect_cost(self, model_id: str = "wan2.2-s2v-detect") -> Decimal:
        """计算图像检测费用(按张计费)"""
        model = self.db.query(Model).options(
            joinedload(Model.price_info)
        ).filter(Model.title == model_id).first()

        if not model or not model.price_info:
            return Decimal("0.0000")

        return Decimal(str(model.price_info.output_price)).quantize(
            Decimal("0.0001"), rounding=ROUND_HALF_UP
        )

video_service.py(视频合成服务)

class VideoService:
    """视频合成服务 - 统一处理文生视频和图生视频"""
    
    async def generate(self, request: VideoGenerateRequest) -> VideoTaskResponse:
        """
        统一视频生成入口
        根据输入参数自动选择模型:
        - 有first_frame_url → 使用wan2.6-i2v(图生视频)
        - 无first_frame_url → 使用wan2.6-t2v(文生视频)
        """
        if request.first_frame_url:
            return await self._image_to_video(request)
        else:
            return await self._text_to_video(request)
    
    async def _text_to_video(self, request):
        """文生视频 - 调用wan2.6-t2v"""
        # 构建请求参数(完全参照文档)
        # 异步提交任务
        # 保存记录到数据库
        # 返回task_id
        pass
    
    async def _image_to_video(self, request):
        """图生视频 - 调用wan2.6-i2v"""
        # 支持首帧+可选尾帧
        # 异步提交任务
        # 保存记录到数据库
        # 返回task_id
        pass
    
    async def get_task_status(self, task_id: str) -> VideoTaskResult:
        """查询任务状态并更新数据库"""
        # 调用百炼API查询
        # 更新本地数据库状态
        # 如果成功,下载视频到OSS
        pass

avatar_service.py(数字人合成服务)

class AvatarService:
    """数字人合成服务"""
    
    async def detect_image(self, image_url: str) -> AvatarDetectResponse:
        """图像检测 - 调用wan2.2-s2v-detect"""
        # 同步调用检测API
        # 返回检测结果
        pass
    
    async def generate(self, request: AvatarGenerateRequest) -> VideoTaskResponse:
        """数字人视频合成 - 调用wan2.2-s2v"""
        # 异步提交任务
        # 保存记录到数据库
        # 返回task_id
        pass

4.3 API调用规范

文生视频(wan2.6-t2v)HTTP调用:

POST https://dashscope.aliyuncs.com/api/v1/services/aigc/video-generation/video-synthesis
Headers:
  - Authorization: Bearer {API_KEY}
  - Content-Type: application/json
  - X-DashScope-Async: enable

Body:
{
    "model": "wan2.6-t2v",
    "input": {
        "prompt": "...",
        "negative_prompt": "...",
        "audio_url": "..."
    },
    "parameters": {
        "size": "1280*720",
        "duration": 10,
        "prompt_extend": true,
        "shot_type": "single",
        "watermark": false,
        "seed": 12345
    }
}

图生视频(wan2.6-i2v)SDK调用:

from dashscope import VideoSynthesis

rsp = VideoSynthesis.async_call(
    api_key=api_key,
    model='wan2.6-i2v',
    prompt='...',
    img_url=first_frame_url,
    audio_url=audio_url,
    resolution="1080P",
    duration=10,
    prompt_extend=True,
    watermark=False,
    seed=12345
)

数字人合成(wan2.2-s2v)HTTP调用:

POST https://dashscope.aliyuncs.com/api/v1/services/aigc/image2video/video-synthesis
Headers:
  - Authorization: Bearer {API_KEY}
  - Content-Type: application/json
  - X-DashScope-Async: enable

Body:
{
    "model": "wan2.2-s2v",
    "input": {
        "image_url": "...",
        "audio_url": "..."
    },
    "parameters": {
        "resolution": "720P"
    }
}

五、前端完善要点

5.1 现有页面分析

前端VideoSynthesis.tsx已有基础框架,包含:

  • 数字人合成Tab(basic):形象选择、音频上传、配置面板
  • 视频合成Tab(video):首帧/尾帧上传、提示词输入、参数配置

5.2 需要完善的功能

数字人合成Tab:

  1. 自定义形象上传时调用图像检测API
  2. 检测不通过时显示错误提示
  3. 音频上传限制(wav/mp3,<15M,<20s)
  4. 分辨率选择(480P/720P)
  5. 调用数字人合成API

视频合成Tab:

  1. 根据是否有首帧自动切换模型
  2. 音频设置:上传自定义音频 / 自动生成音频
  3. 镜头类型选择(仅文生视频时显示)
  4. 完善参数传递与API调用

5.3 videoApi.ts 需要新增的接口

// 数字人图像检测
async detectAvatarImage(imageUrl: string): Promise<ApiResponse<AvatarDetectResult>>

// 数字人合成
async createAvatarTask(request: AvatarGenerateRequest): Promise<ApiResponse<VideoTaskResponse>>

// 查询数字人任务状态
async getAvatarTaskStatus(taskId: string): Promise<ApiResponse<VideoTaskResult>>

六、开发任务清单

阶段一:数据库迁移

  • 创建video_model_config表迁移文件
  • 创建ai_video表迁移文件
  • 执行迁移并初始化模型配置数据

阶段二:后端服务

  • 创建ai_video.py ORM模型
  • 创建video_schema.py Schema定义
  • 实现video_service.py(文生视频、图生视频)
  • 实现avatar_service.py(数字人检测、合成)
  • 实现video_billing.py(费用计算)
  • 创建video_router.py API路由
  • 注册路由到main.py

阶段三:前端完善

  • 完善videoApi.ts接口定义
  • 数字人合成Tab:图像检测、参数完善、API调用
  • 视频合成Tab:参数完善、API调用
  • 任务状态轮询与结果展示

阶段四:测试与优化

  • 接口联调测试
  • 错误处理完善
  • 费用计算验证

七、注意事项

  1. API地域:使用北京地域API(https://dashscope.aliyuncs.com/api/v1)
  2. 视频URL有效期:百炼返回的video_url仅24小时有效,需下载到OSS永久存储
  3. 任务查询有效期:task_id查询有效期24小时
  4. 费用计算
    • model_price表根据model_id获取单价(output_price字段)
    • 视频模型按时长计费:bill = output_price × video_duration
    • 图像检测按张计费:bill = output_price × 1
    • 参考ImageBillingCalculator实现方式
  5. 音频限制
    • 数字人合成:wav/mp3,<15M,<20s
    • 视频合成:wav/mp3,3~30s,<15MB
  6. 图片限制:jpg/jpeg/png/bmp/webp,宽高[400, 7000]像素