feat(ai): 自由创作视频生成全量移植(/free-create)——Seedance 文/图生视频+按时长计费+人物素材库

后端:
- free_video.py: 提交/轮询/收藏/软删全链路,复用 AITask(新增 is_deleted/is_favorited, migration 0022)
- video_pricing.py: 按时长 token 计费(×1.10 buffer+clamp); video_errors.py 错误归一; media_probe.py 时长探测
- catalog/volcano: Seedance free-video 模型接入+seed(migration 0023)
- 素材库: FreeAssetGroup/FreeAsset(火山 Assets API 引用登记, migration 0009)+ 上传/轮询/删除接口
- settings: FREE_VIDEO_MAX_CONCURRENT 团队并发闸(默认3); CELERY_TASK_ALWAYS_EAGER 本地联调开关(生产恒关)
- 测试: test_free_video.py 新增; billing/products/projects tests 配套调整

前端:
- /free-create 页面+components/free-create/ 全套(输入栏/@mention 素材引用/生成卡/视频详情弹窗/素材库弹窗)
- api.ts/types.ts 扩展 free-video 与 free-assets 接口; 路由/侧边栏入口接入

bug/: 测试清单 (11)(12) 与截图归档

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-07-06 10:58:36 +08:00
co-authored by Claude Fable 5
parent 94202e7bce
commit c5f7eb2acc
45 changed files with 5186 additions and 21 deletions
+5
View File
@@ -27,6 +27,7 @@ export type Page =
| "team"
| "messages"
| "assetFactory"
| "freeCreate"
| "imageOptimize"
| "modelPhoto"
| "modelPhotoDemoA"
@@ -92,6 +93,7 @@ export const routeLabels: Record<Page, string> = {
team: "团队",
messages: "消息",
assetFactory: "图片工具",
freeCreate: "自由创作",
imageOptimize: "图片创作",
modelPhoto: "模特上身图",
modelPhotoDemoA: "模特图方案 A",
@@ -151,6 +153,7 @@ export function resolveRoute(): ResolvedRoute {
if (path === "/team") return { page: "team", authMode: "login", hash };
if (path === "/messages") return { page: "messages", authMode: "login", hash };
if (path === "/asset-factory") return { page: "assetFactory", authMode: "login", hash };
if (path === "/free-create") return { page: "freeCreate", authMode: "login", hash };
if (path === "/image-optimize") return { page: "imageOptimize", authMode: "login", hash };
if (path === "/model-photo") return { page: "modelPhoto", authMode: "login", hash };
if (path === "/model-photo/demo-a") return { page: "modelPhotoDemoA", authMode: "login", hash };
@@ -190,6 +193,8 @@ export function pathForPage(page: Page, options: NavigateOptions = {}) {
return "/messages";
case "assetFactory":
return "/asset-factory";
case "freeCreate":
return "/free-create";
case "imageOptimize":
return "/image-optimize";
case "modelPhoto":