diff --git a/.memory/worklog.json b/.memory/worklog.json index 41d972a..a2a0354 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1,11 +1,5 @@ { "entries": [ - { - "files_changed": 3, - "message": "Codex 会话活跃 · 最近命令:codex · 3 项未提交变更 · 最近提交:auto-save 2026-05-15 17:50 (~1)", - "ts": "2026-05-15T09:54:48Z", - "type": "session-heartbeat" - }, { "files_changed": 4, "hash": "a662130", @@ -3257,6 +3251,13 @@ "message": "auto-save 2026-05-18 15:13 (~8)", "hash": "2a1aa4c", "files_changed": 8 + }, + { + "ts": "2026-05-18T15:29:47+08:00", + "type": "commit", + "message": "auto-save 2026-05-18 15:29 (+1, ~5)", + "hash": "1c451c6", + "files_changed": 6 } ] } diff --git a/api/README.md b/api/README.md index 6c21794..d59f802 100644 --- a/api/README.md +++ b/api/README.md @@ -18,6 +18,7 @@ uvicorn main:app --host 127.0.0.1 --port 4291 ## 路由 - `GET /health` — 健康检查 + 配置状态 +- `GET /documents` — 后端数据库里的文档归类列表;一条 TK 链接或一次上传视频默认一个 document - `POST /jobs` `{url}` — 创建 job,后台下载源视频,视频就绪后可手动解析或提取音频 - `GET /jobs/{id}` — 当前状态 + 产物;若原始音轨已拆出,会返回 `source_audio_url` - `POST /jobs/{id}/transcribe` — 触发音频提取 + ASR + 翻译 + SKG 英文产品介绍文案;文案长度按原音频时长估算,配置 Azure OpenAI TTS 后从 Azure 音色池生成配音。前端 Audio 节点提供“提取音频 / 重新提取音频”按钮,可与抽帧并行,不自动触发 @@ -34,5 +35,6 @@ uvicorn main:app --host 127.0.0.1 --port 4291 - `ffmpeg` 系统二进制(拆轨 / 抽帧) - `yt-dlp` 系统二进制(也可走 Python 包) +- SQLite 元数据数据库(默认 `APP_DB_URL=sqlite:///./jobs/app.db`);只存 document / job / media asset 元数据,原视频、音频、抽帧和生成文件继续放 `jobs//` - OpenAI 兼容 LLM 网关(ASR / 翻译 / 文案改写);如果 `/audio/transcriptions` 不可用,会用 `ASR_FALLBACK_MODEL` 走 Gemini 多模态音频识别 - Azure OpenAI TTS(英文产品介绍文案配音,使用 `AZURE_OPENAI_API_KEY` 或回退复用 `LLM_API_KEY`;默认音色池 `alloy,verse,shimmer`) diff --git a/docs/source-analysis.html b/docs/source-analysis.html index 9723e09..4d8f707 100644 --- a/docs/source-analysis.html +++ b/docs/source-analysis.html @@ -603,7 +603,7 @@ web/components/product-library-picker.tsxSKG 内置白底产品图库选择器:搜索、品类筛选、预览尺寸,并把库内图片复制为当前 job 的 assetweb/components/storyboard-bar.tsx顶部分镜编排条:展示选入编排的关键帧,并作为唯一分镜导航。 web/components/storyboard-workbench.tsx顶部分镜编排条下方的明细区:4 图槽、改造目标、时长、自动保存。 - web/lib/api.ts前端类型和 API client,是前后端数据契约镜像;RuntimeHealth / RuntimeModels 读取 GET /health,把 ASR、翻译、视觉、图像、视频等模型名作为前端模型标注的真源。 + web/lib/api.ts前端类型和 API client,是前后端数据契约镜像;RuntimeHealth / RuntimeModels 读取 GET /health,把 ASR、翻译、视觉、图像、视频等模型名作为前端模型标注的真源;DocumentSummary / listDocuments 预留给后续文档侧栏和多视频素材库。 @@ -611,10 +611,12 @@

后端核心

- + + - + + @@ -679,13 +681,38 @@ api/main.py

Job

一个视频任务。前端维护多个 jobs[],当前激活的是 activeJobId。URL 查询参数会持久化多个 job。

Job {
-  id, url, status, progress, message,
+  id, document_id, source_kind, workflow_mode, storage_prefix,
+  url, status, progress, message,
   video_url, source_audio_url, duration, width, height,
   frames: KeyFrame[],
   transcript: TranscriptSegment[],
   audio_script: AudioScript,
   storyboard_images?: StoryboardImage[],
   product_refs?: ProductRefStateItem[]
+}
+ +
+

Document / DB

+

文档是业务归类顶层,不等于物理文件。当前一条 TK 链接或一次上传视频默认生成一个 document;不同来源或模式通过 source_kindworkflow_mode 区分。数据库只保存元数据、状态和文件索引,不保存视频/图片二进制。

+
documents {
+  id, title, source_kind, workflow_mode,
+  source_url, primary_job_id, status,
+  storage_prefix, metadata_json,
+  created_at, updated_at
+}
+
+jobs {
+  id, document_id, source_kind, workflow_mode,
+  source_url, status, progress,
+  storage_path, state_path,
+  frame_count, video_count
+}
+
+media_assets {
+  id, document_id, job_id,
+  kind: video | audio | image,
+  role: source_video | keyframe | product_ref | subject_asset | first_frame | last_frame | generated_video,
+  path, url, frame_index, metadata_json
 }
@@ -882,10 +909,11 @@ ProductRefStateItem {
- - - - + + + + + @@ -926,8 +954,8 @@ ProductRefStateItem { - - + + @@ -963,7 +991,7 @@ ProductRefStateItem {
  • 手动按时间戳加关键帧。
  • 关键帧清洗水印,全图或区域清洗。
  • GPT 画面理解识别关键帧,输出 scene、objects、style、suggested_prompt,并作为主体候选来源。
  • -
  • “开始”会在下载完成后自动触发音频处理,不再默认自动抽帧、Vision 扫描或保存分镜初稿。
  • +
  • “开始”会在下载完成后自动触发音频处理和 6 张人物随机参考帧抽取,不再默认 Vision 扫描或保存分镜初稿。
  • 主体候选确认、改名、删除和主体资产包生成能力保留在底层旧面板和接口中,当前第一步主界面不主动展示。
  • 分镜工作台 4 图槽和改造说明自动保存。
  • 音频文案轨:点击开始或提取音频后提取原文案、中文翻译、讲话人、语速节奏、背景音乐/环境声/音效;结果集中在右侧工作表展示。
  • @@ -1016,6 +1044,18 @@ ProductRefStateItem {

    变更记录

    这个记录不是 git log 的替代品。它记录“产品理解发生了什么变化、影响了哪些源码、你以后描述需求时该怎么说”。后续每次改功能都要补一条。

    +
    +
    +

    2026-05-18 · 新增后端文档数据库

    + API + Data +
    +
    +

    问题:多个 TK 视频和上传视频都只靠 state.json 和目录扫描管理,后续做文档归类、素材调度、批量查询和不同工作模式会越来越难。

    +

    改动:新增 api/database.py,默认使用 APP_DB_URL / DATABASE_URLJOBS_DIR/app.db 的 SQLite 数据库,创建 documentsjobsmedia_assets 三张元数据表。Job 新增 document_idsource_kindworkflow_modestorage_prefix;保存状态时同步 DB,删除 job 时同步清理 DB;新增 GET /documents/health.database

    +

    影响:后续文件归类以 document 为顶层:TK 链接默认 source_kind=tiktok_linkworkflow_mode=feed_recreation;上传视频默认 source_kind=uploadworkflow_mode=uploaded_reference。数据库只存元数据和文件索引,原视频、音频、抽帧、生图、视频候选继续放文件系统。

    +
    +

    2026-05-18 · 自动抽帧改为 6 张人物随机

    diff --git a/web/lib/api.ts b/web/lib/api.ts index 4ea549e..108cc6c 100644 --- a/web/lib/api.ts +++ b/web/lib/api.ts @@ -187,6 +187,15 @@ export interface RuntimeHealth { llm_configured?: boolean auth_configured?: boolean base_url?: string + database?: { + enabled: boolean + url?: string + schema_version?: number + documents?: number + jobs?: number + assets?: number + error?: string + } models?: RuntimeModels } @@ -572,6 +581,10 @@ export interface ProductRefStateItem { export interface Job { id: string url: string + document_id?: string + source_kind?: "tiktok_link" | "upload" | "unknown" + workflow_mode?: "feed_recreation" | "uploaded_reference" + storage_prefix?: string status: JobStatus progress: number message?: string @@ -594,6 +607,7 @@ export interface BackendHealth { llm_configured: boolean auth_configured?: boolean base_url: string + database?: RuntimeHealth["database"] models?: { asr?: string translate?: string @@ -661,6 +675,9 @@ export async function deleteJob(id: string): Promise<{ ok: boolean; id: string } export interface JobSummary { id: string + document_id?: string + source_kind?: string + workflow_mode?: string url: string status: JobStatus progress: number @@ -676,6 +693,28 @@ export interface JobSummary { mtime: number } +export interface DocumentSummary { + id: string + title: string + source_kind: string + workflow_mode: string + source_url: string + primary_job_id: string + status: string + storage_prefix: string + job_count: number + asset_count: number + created_at: number + updated_at: number +} + +export async function listDocuments(limit?: number): Promise { + const qs = limit && limit > 0 ? `?limit=${limit}` : "" + const res = await fetch(`${API_BASE}/documents${qs}`) + if (!res.ok) throw new Error(`listDocuments ${res.status}`) + return res.json() +} + export async function listJobs(limit?: number): Promise { const qs = limit && limit > 0 ? `?limit=${limit}` : "" const res = await fetch(`${API_BASE}/jobs${qs}`)
    api/main.pyFastAPI 单文件后端:登录会话、状态模型、任务恢复、下载、抽帧、Vision、清洗、元素、分镜、原音频转写/翻译、声音与背景音分析、后续口播改写/TTS、文件返回。
    api/main.pyFastAPI 单文件后端:登录会话、状态模型、任务恢复、下载、抽帧、Vision、清洗、元素、分镜、原音频转写/翻译、声音与背景音分析、后续口播改写/TTS、文件返回,并在保存 state.json 时同步数据库元数据。
    api/database.py后端数据库层:当前内置 SQLite,维护 documentsjobsmedia_assets 三类元数据;文档是顶层归类,一条 TK 链接或一次上传默认一个 document,媒体文件仍保留在 jobs/<jobId>/
    api/product_library/skg-products内置 SKG 白底产品图库:manifest.json 记录从桌面产品图筛出的 gallery 白底图和桌面 4 张产品角度图,images/ 存 45 张参考图。
    api/character_library/skg-characters内置相似主体形象库:从桌面 5 套策划形象导入,manifest.json 记录运动阳光男、都市型男、优雅白领女、运动辣妹、绅士大叔,每套含 7 张透明骨架参考图,用于相似主体高清视图包的创意方向选择。
    jobs/<jobId>/state.json运行时状态文件,不在源码列表里,但刷新恢复依赖它。
    jobs/app.db默认本地后端数据库,路径由 APP_DB_URL / DATABASE_URL 控制;生产模板默认 sqlite:////data/jobs/app.db
    jobs/<jobId>/state.json运行时状态文件,当前仍是兼容恢复真源;保存时同步写入数据库,后续迁移再逐步改成 DB 主读。
    jobs/<jobId>/audio.wav拆轨得到的原始音频,当前只作为后端分析和后续必要预览的只读文件来源;主界面不再默认渲染底部音频条。
    jobs/<jobId>/frames关键帧 jpg。注意 frame.index 是稳定 ID,不等于数组下标。
    jobs/<jobId>/cleaned清洗后待应用图片。
    网页登录POST /auth/loginGET /auth/checkPOST /auth/logoutweb/app/login/page.tsx、Nginx auth_request登录页提交账号密码到 /api/auth/login,后端设置 HttpOnly 会话 Cookie;生产 Nginx 对工作台和 /api//auth/check 做统一校验,未登录页面跳 /login/,API 返回 JSON 401。
    运行配置 / 模型标注GET /healthgetRuntimeHealthModelTrace返回 models:ASR、本机 ASR、ASR fallback、翻译、GPT 改写、GPT 画面理解、产品视角识别 product_view、GPT 图像模型、主体 6 视图 GPT 图像模型、Azure OpenAI TTS、视频别名和 Seedance 服务商。当前 REWRITE_MODELAUDIO_REWRITE_MODELVISION_MODEL 默认使用 gpt-4o;如果旧环境变量仍写 gemini-*,后端会归一化回 GPT_TEXT_MODEL / REWRITE_MODEL。语音只走 Azure OpenAI TTS,models.voice_tts_paths 会回传当前尝试的语音路径,方便区分路径错误和语音服务不可用。前端所有当前主路径里会调用模型的按钮旁显示模型名,点击弹出小窗口查看模型链路和输入输出逻辑;不返回 API Key 或敏感凭证。
    历史列表GET /jobslistJobs所有 job 精简列表(id/url/status/thumbnail/mtime…),按 state.json mtime 倒序。前端 URL 无 ?job= 时拉它回填全部历史;带 limit 可截断。
    创建任务POST /jobscreateJob提交 TK 链接,后台开始下载;前端“开始”队列会在 downloaded 后自动触发音频解析。
    上传视频POST /jobs/uploaduploadJob保存 source.mp4,然后同样进入下载完成状态;当前上传后也加入第一步队列,下载完成后自动解析音频。
    运行配置 / 模型标注GET /healthgetRuntimeHealthModelTrace返回 models:ASR、本机 ASR、ASR fallback、翻译、GPT 改写、GPT 画面理解、产品视角识别 product_view、GPT 图像模型、主体 6 视图 GPT 图像模型、Azure OpenAI TTS、视频别名和 Seedance 服务商。当前 REWRITE_MODELAUDIO_REWRITE_MODELVISION_MODEL 默认使用 gpt-4o;如果旧环境变量仍写 gemini-*,后端会归一化回 GPT_TEXT_MODEL / REWRITE_MODEL。语音只走 Azure OpenAI TTS,models.voice_tts_paths 会回传当前尝试的语音路径,方便区分路径错误和语音服务不可用。database 回传 DB 是否启用、URL、schema 版本和 document/job/asset 计数。前端所有当前主路径里会调用模型的按钮旁显示模型名,点击弹出小窗口查看模型链路和输入输出逻辑;不返回 API Key 或敏感凭证。
    文档列表GET /documents后续文档侧栏 / 素材库入口从数据库读取 document 归类列表,包含 source_kind、workflow_mode、primary_job_id、storage_prefix、job_count、asset_count 和更新时间。当前前端还未接主入口,后端已可作为多视频/多上传文档管理的索引。
    历史列表GET /jobslistJobs所有 job 精简列表(id/document_id/source_kind/workflow_mode/url/status/thumbnail/mtime…),按 state.json mtime 倒序。前端 URL 无 ?job= 时拉它回填全部历史;带 limit 可截断。
    创建任务POST /jobscreateJob提交 TK 链接,后台开始下载;后端自动建立 document_id=job_idsource_kind=tiktok_linkworkflow_mode=feed_recreation 的 document,并在状态保存时同步 DB。
    上传视频POST /jobs/uploaduploadJob保存 source.mp4,然后同样进入下载完成状态;后端自动建立 source_kind=uploadworkflow_mode=uploaded_reference 的 document。当前上传后也加入第一步队列,下载完成后自动解析音频。
    删除输入视频DELETE /jobs/{id}deleteJob从任务队列、URL 和磁盘 jobs/<id> 目录移除整个 job,包括源视频、关键帧、元素提取图和生成视频。
    解析视频POST /jobs/{id}/analyze?frames=&target=&mode=&quality=analyzeJob后续阶段保留的抽帧能力。默认 frames=6target 支持人物随机、透明骨架人、综合、清晰主体、转场变化、表情瞬间、动作峰值。当前“开始分析”和源视频旁的“自动抽帧 6 张”都会显式用 target=random_subjectquality=accuratemode=replace 生成清晰人物候选里的随机参考帧池。
    音频文案轨POST /jobs/{id}/transcribetriggerTranscribe若尚未拆轨,先从 source.mp4 提取 audio.wav 并回填 source_audio_url;随后用 ASR 提取原始文案,翻译成中文,写入 audio_script.source_textsource_zh 和逐句 transcript。远端 ASR_MODEL 失败后先走本机 LOCAL_ASR_BIN/LOCAL_ASR_MODEL(默认 mlx_whisper),再尝试 ASR_FALLBACK_MODEL。后端会拒绝重复文本、逐秒假字幕或覆盖率过低的结果,不再把不可听的多模态输出写进时间轴。再用 ASR_FALLBACK_MODEL 多模态音频分析讲话人、语速节奏、停顿、背景音乐/环境声/音效,写入 speaker_profilerhythm_profilebackground_audio_profile。当前第一步不默认生成 SKG 新口播和 Azure OpenAI 配音。
    复刻工作表承载当前第一步主路径:素材输入列按文件任务管理素材;点击“开始”后自动下载源视频,下载完成后只触发音频提取、原文案转写、中文翻译、讲话人/节奏/背景音分析,并以工作表方式展示。不要在当前开始流程里自动抽帧、自动写分镜、自动生成元素或自动合成视频;不要恢复右侧空白画布占位。承载当前第一步主路径:素材输入列按文件任务管理素材;点击“开始”后自动下载源视频,下载完成后并行触发音频提取/原文案转写/翻译/讲话人节奏背景音分析,以及 6 张人物随机参考帧抽取,并以工作表方式展示。不要在当前开始流程里自动写分镜、自动生成元素或自动合成视频;不要恢复右侧空白画布占位。 web/components/ad-recreation-board.tsxweb/app/page.tsx