diff --git a/.memory/worklog.json b/.memory/worklog.json
index 7c6179d..4e1c284 100644
--- a/.memory/worklog.json
+++ b/.memory/worklog.json
@@ -1,19 +1,5 @@
{
"entries": [
- {
- "files_changed": 1,
- "hash": "686baa1",
- "message": "auto-save 2026-05-13 08:51 (~1)",
- "ts": "2026-05-13T08:52:11+08:00",
- "type": "commit"
- },
- {
- "files_changed": 1,
- "hash": "afab4bc",
- "message": "auto-save 2026-05-13 08:57 (~1)",
- "ts": "2026-05-13T08:57:46+08:00",
- "type": "commit"
- },
{
"files_changed": 1,
"hash": "d6a5223",
@@ -3278,6 +3264,19 @@
"type": "session-heartbeat",
"message": "Codex 会话活跃 · 最近命令:codex · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 13:21 (~3)",
"files_changed": 1
+ },
+ {
+ "ts": "2026-05-14T13:27:18+08:00",
+ "type": "commit",
+ "message": "auto-save 2026-05-14 13:27 (~1)",
+ "hash": "00435b2",
+ "files_changed": 1
+ },
+ {
+ "ts": "2026-05-14T05:28:40Z",
+ "type": "session-heartbeat",
+ "message": "Codex 会话活跃 · 最近命令:codex · 2 项未提交变更 · 最近提交:auto-save 2026-05-14 13:27 (~1)",
+ "files_changed": 2
}
]
}
diff --git a/api/.env.example b/api/.env.example
index a49662b..7dba4ed 100644
--- a/api/.env.example
+++ b/api/.env.example
@@ -36,6 +36,10 @@ POE_API_KEY=
# SKG 豆包/Seedance 视频网关也使用同一套 content JSON 提交格式:
# VIDEO_API_BASE_URL=https://ai.skg.com/doubao
# VIDEO_API_KEY=
+# VIDEO_MODEL_SEEDANCE=doubao-seedance-2-0-fast-260128
+# VIDEO_CREATE_PATHS=/api/v3/contents/generations/tasks
+# VIDEO_STATUS_PATH=/api/v3/contents/generations/tasks/{id}
+# VIDEO_CONTENT_PATH=/api/v3/contents/generations/tasks/{id}/content
#
# 自定义视频网关覆盖;留空时如配置 POE_API_KEY,则走 Poe。
VIDEO_API_BASE_URL=
diff --git a/api/main.py b/api/main.py
index 14e179b..3f8a770 100644
--- a/api/main.py
+++ b/api/main.py
@@ -91,14 +91,37 @@ VIDEO_MODEL_ALIASES = {
}
VIDEO_API_BASE_URL = os.getenv("VIDEO_API_BASE_URL", "").strip()
VIDEO_API_KEY = os.getenv("VIDEO_API_KEY", "").strip()
-VIDEO_CREATE_PATH = os.getenv("VIDEO_CREATE_PATH", "/videos").strip() or "/videos"
+
+
+def default_video_gateway_paths(base_url: str) -> tuple[str, str, str]:
+ base = base_url.strip().rstrip("/").lower()
+ if "ai.skg.com/doubao" in base:
+ return (
+ "/api/v3/contents/generations/tasks",
+ "/api/v3/contents/generations/tasks/{id}",
+ "/api/v3/contents/generations/tasks/{id}/content",
+ )
+ if "ark.cn-beijing.volces.com" in base:
+ return (
+ "/contents/generations/tasks",
+ "/contents/generations/tasks/{id}",
+ "/contents/generations/tasks/{id}/content",
+ )
+ return ("/videos", "/videos/{id}", "/videos/{id}/content")
+
+
+DEFAULT_VIDEO_CREATE_PATH, DEFAULT_VIDEO_STATUS_PATH, DEFAULT_VIDEO_CONTENT_PATH = default_video_gateway_paths(VIDEO_API_BASE_URL)
+VIDEO_CREATE_PATH = os.getenv("VIDEO_CREATE_PATH", DEFAULT_VIDEO_CREATE_PATH).strip() or DEFAULT_VIDEO_CREATE_PATH
VIDEO_CREATE_PATHS = [
p.strip()
- for p in os.getenv("VIDEO_CREATE_PATHS", f"{VIDEO_CREATE_PATH},/videos/generations,/video/generations").split(",")
+ for p in os.getenv(
+ "VIDEO_CREATE_PATHS",
+ VIDEO_CREATE_PATH if VIDEO_CREATE_PATH != "/videos" else f"{VIDEO_CREATE_PATH},/videos/generations,/video/generations",
+ ).split(",")
if p.strip()
]
-VIDEO_STATUS_PATH = os.getenv("VIDEO_STATUS_PATH", "/videos/{id}").strip() or "/videos/{id}"
-VIDEO_CONTENT_PATH = os.getenv("VIDEO_CONTENT_PATH", "/videos/{id}/content").strip() or "/videos/{id}/content"
+VIDEO_STATUS_PATH = os.getenv("VIDEO_STATUS_PATH", DEFAULT_VIDEO_STATUS_PATH).strip() or DEFAULT_VIDEO_STATUS_PATH
+VIDEO_CONTENT_PATH = os.getenv("VIDEO_CONTENT_PATH", DEFAULT_VIDEO_CONTENT_PATH).strip() or DEFAULT_VIDEO_CONTENT_PATH
VIDEO_DURATION_FIELD = os.getenv("VIDEO_DURATION_FIELD", "seconds").strip() or "seconds"
VIDEO_POLL_TIMEOUT_SECONDS = max(60, int(os.getenv("VIDEO_POLL_TIMEOUT_SECONDS", "900")))
diff --git a/docs/source-analysis.html b/docs/source-analysis.html
index 109eec0..2f2b461 100644
--- a/docs/source-analysis.html
+++ b/docs/source-analysis.html
@@ -919,6 +919,19 @@ SubjectAsset {
变更记录
这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。
+
+
+ 2026-05-14 · 修正 SKG 豆包视频网关路径
+ Video Gen
+ Seedance
+
+
+
问题:产品融合视频能进入队列,但后台任务 5% 后失败,错误为 /contents/generations/tasks 返回 404。
+
根因:https://ai.skg.com/doubao 这个 SKG 豆包网关的真实视频入口是 /api/v3/contents/generations/tasks,不是火山方舟直连 base 下使用的 /contents/generations/tasks。
+
改动:后端默认路径识别 ai.skg.com/doubao 并自动使用 /api/v3/contents/generations/tasks、/api/v3/contents/generations/tasks/{id}、/api/v3/contents/generations/tasks/{id}/content;本机 api/.env 和 api/.env.example 同步更新。
+
影响:api/main.py、api/.env、api/.env.example、docs/source-analysis.html。
+
+
2026-05-14 · 产品融合改为内置角色 + 产品 + 描述生成
@@ -1076,7 +1089,7 @@ SubjectAsset {
问题:用户提供 https://ai.skg.com/doubao 作为视频模型网关;该网关应按 Seedance / 方舟内容生成任务格式提交,而不能误走普通 multipart 上传。
-
改动:video_uses_ark() 现在同时识别火山方舟域名和 ai.skg.com/doubao,统一使用 content JSON:文本 prompt、首帧、尾帧和产品参考图作为不同 role 传入,再按 /contents/generations/tasks/{id} 轮询。api/.env.example 增加 SKG 豆包视频网关配置示例;生视频轮询上限改为 VIDEO_POLL_TIMEOUT_SECONDS,默认 900 秒,避免慢任务过早失败。
+
改动:video_uses_ark() 现在同时识别火山方舟域名和 ai.skg.com/doubao,统一使用 content JSON:文本 prompt、首帧、尾帧和产品参考图作为不同 role 传入。火山方舟直连按 /contents/generations/tasks/{id} 轮询;SKG 豆包网关按 /api/v3/contents/generations/tasks/{id} 轮询。api/.env.example 增加 SKG 豆包视频网关配置示例;生视频轮询上限改为 VIDEO_POLL_TIMEOUT_SECONDS,默认 900 秒,避免慢任务过早失败。
影响:api/main.py、api/.env.example、docs/source-analysis.html。本机 api/.env 已配置 VIDEO_API_BASE_URL=https://ai.skg.com/doubao 和视频专用 key。
@@ -1696,7 +1709,7 @@ SubjectAsset {
问题:用户提供火山方舟 https://ark.cn-beijing.volces.com/api/v3 作为生视频通道;这个通道不是 Poe 的 /videos 形态,而是内容生成异步任务。
-
改动:后端识别 Ark base 后,提交改为 POST /contents/generations/tasks,请求体使用 content 数组:文本 prompt + 首帧 image_url data URL;轮询改为 GET /contents/generations/tasks/{id},成功后读取 content.video_url 下载 MP4。本机默认 Seedance 模型改为 Ark 可见的 doubao-seedance-2-0-fast-260128。
+
改动:后端识别 Ark base 后,提交改为内容生成任务接口,火山方舟直连使用 POST /contents/generations/tasks,SKG 豆包网关使用 POST /api/v3/contents/generations/tasks。请求体使用 content 数组:文本 prompt + 首帧 image_url data URL;轮询对应的 {id} 任务地址,成功后读取 content.video_url 下载 MP4。本机默认 Seedance 模型改为 Ark 可见的 doubao-seedance-2-0-fast-260128。
影响:api/main.py、api/.env.example、docs/source-analysis.html。本机 api/.env 需要把 VIDEO_API_BASE_URL/VIDEO_API_KEY/VIDEO_CREATE_PATHS/VIDEO_STATUS_PATH 指向 Ark。