实现完整的AI视频生成模块,集成阿里云百炼平台(DashScope),支持数字人合成和通用视频合成两大功能。
基于数字人模型,通过单张图片和音频生成动作自然的说话/唱歌/表演视频。
模型列表: | 模型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)统一API端点,支持三种输入模式的视频生成。
模型列表: | 模型ID(model_id) | 功能 | 计费说明 | |---------|------|------| | wan2.6-t2v | 文生视频(多镜头叙事、自动配音、720P/1080P、5/10/15秒) | 按视频时长计费,从model_price表获取单价 | | wan2.6-i2v | 图生视频(首帧/尾帧控制、音频同步、720P/1080P、5/10/15秒) | 按视频时长计费,从model_price表获取单价 |
三种输入模式:
wan2.6-t2v文生视频wan2.6-i2v图生视频wan2.6-i2v图生视频(尾帧控制结束画面)# 图像检测(前端预检测)
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" // 失败时返回
}
# 创建视频生成任务
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
}
存储各视频模型的支持参数配置,供前端动态渲染表单。
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"]
}
}
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时返回的改写后提示词';
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
"""
视频生成计费计算器
从数据库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
)
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
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
文生视频(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"
}
}
前端VideoSynthesis.tsx已有基础框架,包含:
数字人合成Tab:
视频合成Tab:
// 数字人图像检测
async detectAvatarImage(imageUrl: string): Promise<ApiResponse<AvatarDetectResult>>
// 数字人合成
async createAvatarTask(request: AvatarGenerateRequest): Promise<ApiResponse<VideoTaskResponse>>
// 查询数字人任务状态
async getAvatarTaskStatus(taskId: string): Promise<ApiResponse<VideoTaskResult>>
model_price表根据model_id获取单价(output_price字段)bill = output_price × video_durationbill = output_price × 1ImageBillingCalculator实现方式