个人自托管的 AI 短视频生产工作站。架构依据见 docs/design/hot-factory-overview-design.md v1.0(现行架构单一真源);运行与出片见 docs/runbook/weekend-slice.md;进度与验证见 docs/progress/PROCESS.md。
当前状态:第一阶段工程骨架已可运行,真实 MoneyPrinterTurbo 出片已验证。 已实现「创建任务 → Worker 原子认领 → 脚本生成 → 视频引擎合成 → ffprobe 基础质检 → 待人工审核 → 前端轮询进度与预览」的完整垂直链路。发布、多平台、热点官方 API 均未实现(按三阶段路线)。
不要重复造轮子(硬约束):配音、字幕、素材、异步任务与进度、视频合成全部由 MoneyPrinterTurbo 提供,本项目只透传配置、翻译状态、做质检。没有
providers/tts/、没有自研字幕、没有第二套进度体系。新增模块前先查上游是否已提供,详见架构文档第 3 章。
| 能力 | 由谁提供 |
|---|---|
| 结构化脚本(落盘、可手改、可复用) | 本项目 providers/llm(DeepSeek / fake) |
配音 voice_name、字幕 subtitle_enabled、素材 video_source |
MoneyPrinterTurbo,本项目只透传配置项 |
异步任务 task_id 与 0~100 进度 |
MoneyPrinterTurbo,本项目只做 engine_job_id 映射与状态翻译 |
| 视频合成 / 转码 | MoneyPrinterTurbo + FFmpeg |
| 任务持久化、ffprobe 质检、预览、审核 | 本项目(引擎不产出质检报告) |
frontend/ Vue 3 + TS + Vite + Element Plus
backend/app/
api/ FastAPI 路由
core/ 配置
models/ SQLAlchemy 模型与 SQLite 连接(WAL + busy_timeout)
schemas/ 接口契约
services/ 任务生命周期
providers/ llm / video / qc —— 外部能力适配(不设 tts)
workers/ Worker 入口、流水线、批量出片 CLI
backend/tests/ pytest
config/ 配置样例、topics 清单样例、本机 .env
data/ 数据库、脚本、素材、成片(不进 Git)
docs/
design/ 架构单一真源(现行 v1.0)
runbook/ 运行与出片手册(命令、配置、降级矩阵)
progress/ 进度台账与废弃决策留痕
scripts/ Windows 一键启动脚本
docker-compose.yml 目标部署形态
根目录只放门面、协作规范与部署入口三类文件,文档一律进 docs/ 子目录分类存放:
| 分类 | 位置 |
|---|---|
| 门面 / 法律 | README.md、LICENSE、THIRD-PARTY-NOTICES.md |
| AI 协作规范 | AGENTS.md、CLAUDE.md(规范本体在全局,不随仓库分发) |
| 部署与启动 | docker-compose.yml、.gitignore、config/、start.bat |
| 文档 | docs/design/、docs/runbook/、docs/progress/ |
双击根目录的 start.bat(或在终端执行),从零到能点出片:
start.bat脚本按顺序做五件事:检查 Python / Node / FFmpeg 与端口 → 缺 config/.env 就由 env.example 生成(默认 fake + mock,不需要任何 Key)→ 前端产物过期就重新构建 → 起后台 Worker → 起 FastAPI 并自动开浏览器。
- 访问地址
http://127.0.0.1:8000:前端由 FastAPI 托管,单端口,不用另开终端;接口文档在/docs。 - 停止:在启动窗口按
Ctrl+C,Worker 会被一起收掉,不留孤儿进程。 - 参数:
start.bat -WithEngine(video=mpt时顺带把 MoneyPrinterTurbo 起在 8080)、-Dev(前端 vite 热更新,访问 5173)、-Rebuild(强制重建前端)、-Port 8010(换端口)、-SkipWorker(只起 Web)、-NoBrowser、-Help。 - 日志:
data/logs/worker.log;-WithEngine时另有data/logs/mpt.log;-Dev时另有data/logs/vite.log。 - 首次运行会自动装
backend/.venv与frontend/node_modules(需要几分钟,之后秒起)。 - 改了
config/.env或后端代码之后:直接重跑start.bat。Worker 的配置与代码都是启动那一刻读进内存的,所以脚本默认接管:没有任务在跑时,杀掉遗留 Worker 重启一个;有任务正在跑时保留它并提示你等跑完再重跑。不存在「复用一个别人起的旧 Worker」这种情况。 - 要出真片:把
config/.env的HF_VIDEO_PROVIDER改成mpt,再start.bat -WithEngine——脚本会先等引擎在 8080 就绪再起 Web,退出时把引擎一起收掉;引擎侧配置(本地素材、Edge 字幕)见docs/runbook/weekend-slice.md第 2 章。 - 不配 LLM 也能出片:
HF_LLM_PROVIDER=fake会把主题套进 6 段通用口播稿;想文案对题,就在页面「可选:粘贴自己的口播稿」里填稿,填了就完全跳过 LLM。 - 素材在页面直接传:点「上传图片 / 视频」选文件即可(jpg/png/bmp/mp4/mov/avi/mkv/webm,图片 ≤20MB、视频 ≤200MB)。传上去的会作为本条任务的素材,只使用你选中的这些,引擎素材库里别的文件(比如测试彩条)不会混进成片;一个都不传才会用引擎库全集。
- 成片按主题命名:落到
data/videos/{任务ID}/{主题}.mp4,页面任务列表也有「主题」和「成片」两列,不用再靠 task_id 猜哪条是自己的。 - 成片时长与配音语速:主题框下面两个下拉框,每条任务单独设。时长 15 / 30 / 45 / 60 秒或「不限(按稿件)」,语速 0.8x ~ 2.0x。引擎没有总时长参数——成片多长完全由配音多长决定,所以选 30 秒 = 把稿件裁到约「30 × 4.5 × 语速」字(中文口播实测 4.5 字/秒),裁在完整句子上,不会半句话断掉。稿子框下面会实时显示「当前多少字 ≈ 多少秒」,超了会提示将被截断。
已实测(2026-11-13,Windows 11 + PowerShell 7):零凭据模式下点一次生成 → Worker 原子认领 → mock 引擎出片 5s / 1080×1920 / H.264 + AAC → ffprobe 质检 6 项全过 → 状态 WAITING_REVIEW,全程约 2 秒;-Dev 模式下 vite 页面与 /api 代理均验证可用。
不另写第二套流水线:批量 CLI 只是「批量入队 + 汇总报告」的薄封装,复用同一张 task 表、同一条 workers/pipeline.py、同一套 providers 和 ffprobe 质检,避免两套流水线各自漂移。
cd backend
# 单主题
.venv/Scripts/python.exe -m app.workers.cli --subject "一杯手冲咖啡的冲泡过程"
# 批量:先改 config/topics.example.json
.venv/Scripts/python.exe -m app.workers.cli --topics ../config/topics.example.json \
--report ../data/videos/batch-report.json
# 改词不重新调 LLM:复用已落盘脚本,或直接用手写口播稿
.venv/Scripts/python.exe -m app.workers.cli --topics ../config/topics.example.json \
--from-script ../data/scripts/<task_id>/script.json- 主题清单支持
["主题A", "主题B"]或{"topics": [{"topic": "...", "script": "...", "voice_name": "..."}]};条目里填script即跳过 DeepSeek。 - 每条任务一个
data/videos/{task_id}/目录,不覆盖历史成片。 - 报告含
status/file_path/qc_passed/ 错误信息;--limit N只跑前 N 条;有任务失败时退出码为 1。 - 该命令会把队列中所有 PENDING 任务跑完。若 Worker 正在运行,先停 Worker,避免进度归属分散(认领是原子的,不会重复执行)。
- 引擎侧分段排错用 MoneyPrinterTurbo 自带的 CLI
--stop-at script|audio|video,本项目不重复实现。
已实测(2026-11-13,真实 ffmpeg / ffprobe,无 API Key):3 条主题一次跑完,3/3 WAITING_REVIEW,产出 3 条 1080×1920 / H.264 + AAC MP4,质检全项通过,报告见 data/cli-smoke/batch-report.json。注意这是 mock 引擎的测试图,只证明一键链路可复现;真成片要切到 MoneyPrinterTurbo。
不需要 Docker、不需要任何 API Key、不需要 MoneyPrinterTurbo,就能验证整条链路。
# 1. 后端依赖(Python 3.12+,本机已验证 3.13)
cd backend
uv venv .venv --python 3.13
uv pip install -r requirements.txt
# 2. 配置(复制样例,默认就是 fake + mock)
cp ../config/env.example ../config/.env
# 3. 跑测试
.venv/Scripts/python.exe -m pytest
# 4. 启动 Web 与 Worker(两个终端,或用 run-dev.sh 一次起)
.venv/Scripts/python.exe -m uvicorn app.main:app --port 8000
.venv/Scripts/python.exe -m app.workers # 另一个终端
# 5. 创建任务并轮询
curl -X POST http://127.0.0.1:8000/api/tasks -H "Content-Type: application/json" \
-d '{"topic":"一杯手冲咖啡的冲泡过程"}'
curl http://127.0.0.1:8000/api/tasks/<上一步返回的 id>前端:
cd frontend
npm install
npm run dev # http://127.0.0.1:5173,/api 代理到 8000
# 或者:npm run build 后直接访问 http://127.0.0.1:8000(由 FastAPI 托管 dist)- 安装并启动 8080 API(已在本机实测):
python -m pip install mpt # 官方包 mpt 1.3.10,harry0703 维护,Python ≥ 3.11
# 注意:mpt CLI 只有 cli / webui 两个子命令,不会启动 API。
# 8080 是包内的 FastAPI 应用 app.asgi:app:
python -m uvicorn app.asgi:app --host 127.0.0.1 --port 8080
# API 文档: http://127.0.0.1:8080/docs OpenAPI: /openapi.json
mpt webui # 可选,WebUI 8501 人工试片PyPI 上另有旧名称发行包
MoneyPrinterTurbo,不作为安装依据。api_key默认空(免认证),8080 只监听本机、不得暴露公网;CORS 默认同源,服务端调用不带Origin不受限。
- 准备素材与引擎配置(没有 Pexels Key 时必做):
- 把 3~10 张图片或视频片段放到 MPT 自己的
storage/local_videos/目录,Windows 下通常是%LOCALAPPDATA%\MoneyPrinterTurbo\storage\local_videos\;或调引擎POST /api/v1/video_materials上传。 - 适配器会自动调
GET /api/v1/video_materials取文件名并填进video_materials,HotFactory 不扫描也不配置这个目录。 - MPT 的
config.toml里按需设subtitle_provider = "edge"(别开 whisper,首跑要下 1.6~3 GB)、LLM Key(填了video_script就不需要)、ffmpeg_path。包内自带中文字体STHeitiMedium.ttc,字幕字体不是阻塞。 - 配音与字幕是引擎能力,本项目的
HF_MPT_*只透传参数,不生成音频或字幕文件。
-
实测契约要点(完整表见架构文档第 4 章):统一响应信封
{"status","data","message"};任务state是FAILED=-1 / COMPLETE=1 / PROCESSING=4(不是网上流传的 0/1/2/3);videos返回/tasks/<id>/final-1.mp4相对 URI,由适配器从引擎 HTTP 下载;video_source=local时必须带video_materials。这三处已用契约测试锁定。 -
改
config/.env:
HF_LLM_PROVIDER=deepseek
HF_DEEPSEEK_API_KEY=你的Key
HF_DEEPSEEK_MODEL=官方当前可用的模型标识
HF_VIDEO_PROVIDER=mpt
HF_MPT_API_BASE=http://127.0.0.1:8080
HF_MPT_VIDEO_SOURCE=local
HF_MPT_STORAGE_DIR= # 引擎返回相对路径时填其 storage/tasks 根目录- 重启 Web 与 Worker。Worker 会把 MPT 的
task_id存进video_task.engine_job_id,把state/progress翻译成本系统任务状态,不重复实现一套进度体系。
用同一条批量命令接真实 MPT,没有 DeepSeek Key、没有 Pexels Key(fake 脚本 + 3 张本地图):
cd backend
HF_LLM_PROVIDER=fake HF_VIDEO_PROVIDER=mpt HF_MPT_API_BASE=http://127.0.0.1:8080 \
HF_MPT_VIDEO_SOURCE=local HF_MPT_POLL_INTERVAL=3 \
.venv/Scripts/python.exe -m app.workers.cli \
--subject "一杯手冲咖啡的冲泡过程" --report ../data/mpt-smoke/report.json结果:WAITING_REVIEW / 100 / qc=PASS,耗时 5 分 26 秒,成片 39.6 秒 / 1080×1920 / H.264 + AAC / 30fps / 7.2 MB。引擎侧日志确认 Edge TTS 生成 39 秒中文配音、Edge 时间戳字幕、3 张本地图预处理成 zoom 片段、合并 40 秒、最终烧字幕渲染;抽帧确认中文字幕已烧录且无乱码。
画面用的是 ffmpeg 生成的测试彩条,只证明链路可用。把 MPT 的
storage/local_videos/换成自己的图片、在config/.env填 DeepSeek Key,即可出真正的内容片。当前长句字幕换行处略挤,可调font_size/subtitle_position。
| 缺什么 | 怎么办 |
|---|---|
| 抖音热点 Scope | 一等公民降级:POST /api/tasks {"topic": ...} 或 CLI --topics 主题清单就是手工热点源;不为将来才可能拿到的官方 API 提前写 HotSource 抽象 |
| DeepSeek Key | HF_LLM_PROVIDER=fake,或条目里填 script 用手写口播稿,或 --from-script 复用落盘脚本 |
| Pexels / Pixabay Key | HF_MPT_VIDEO_SOURCE=local,素材放 MPT 自己的 storage/local_videos/,文件名由引擎 GET /api/v1/video_materials 提供 |
| MPT 未启动 | HF_VIDEO_PROVIDER=mock,用测试图 MP4 验证链路与质检 |
| ffmpeg | 已装则无需处理;未装则 ffprobe 质检会报明确错误,不会静默通过 |
| 中文字幕异常 | 关闭 subtitle_enabled 保底出片 |
| 引擎半途失败 | 用 MPT 自带 --stop-at 分段跑,复用已生成的脚本和音频 |
| Method | Path | 说明 |
|---|---|---|
| POST | /api/tasks |
创建视频任务,立即返回 id |
| GET | /api/tasks/{id} |
轮询状态、进度、阶段、错误和结果 |
| GET | /api/tasks |
最近任务列表 |
| POST | /api/tasks/{id}/retry / cancel / approve |
重试 / 取消 / 审核通过 |
| GET | /api/videos |
成片列表(可按 task_id 过滤) |
| GET | /api/videos/{id}/stream |
视频预览(限制在 data/videos/ 内) |
| POST | /api/materials |
上传图片 / 视频素材(multipart file),转发引擎素材接口 |
| GET | /api/materials |
当前可用素材清单 |
| GET | /api/health |
健康检查 |
| GET | /docs |
FastAPI 自动生成的接口文档 |
任务状态机:PENDING → SCRIPTING → GENERATING → QC → WAITING_REVIEW → APPROVED,异常 FAILED / CANCELLED。
cd backend && .venv/Scripts/python.exe -m pytest # 50 个用例
cd frontend && npm run typecheck && npm run build- 基础质检只覆盖元数据(流、时长、分辨率、大小);黑屏 / 静音语义检测未实现。
- 主题靠手工输入(CLI 主题清单 / API
topic字段),没有官方热点 API,也没有自动选题评分;等抖音 Scope 到位再引入HotSource抽象。 - 没有用户认证,管理接口只应监听本机或受保护网络;MPT 的 8080 不要暴露公网。
- 前端全量引入 Element Plus,构建产物约 1 MB,后续按需引入或分包。
docker-compose.yml目前只编排 Web + Worker 两个自有服务;本机未安装 Docker,第三个程序 MPT 按上游文档单独启动并通过HF_MPT_API_BASE接入。待 Docker 就绪且固定上游镜像 digest 后再编入。- 本机已验证环境:Python 3.13.14 / uv 0.12.5 / Node 22.22.2 / FFmpeg 9.0.1 / Windows + Git Bash;Docker 未安装。
本项目代码以 MIT License 发布。第三方组件版本、许可证与来源记录在 THIRD-PARTY-NOTICES.md;接入前需按架构文档第 11.3 节复核上游 LICENSE 与服务条款。