|
|
@@ -0,0 +1,266 @@
|
|
|
+# 部署文档
|
|
|
+
|
|
|
+文本转视频生成流水线的部署与运行说明。项目以**容器化、服务化**为重心:Docker Compose 一键起服务,CLI / HTTP / WebUI 共享同一套配置与统一输出目录。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 1. 架构概览
|
|
|
+
|
|
|
+```
|
|
|
+ ┌──────────────────────────────┐
|
|
|
+ 浏览器 (WebUI) ──────► │ Next.js Web 服务 (端口 3000) │
|
|
|
+ HTTP /api/render ────► │ apps/web │
|
|
|
+ └───────────────┬──────────────┘
|
|
|
+ │ spawn 子进程
|
|
|
+ ▼
|
|
|
+ ┌──────────────────────────────┐
|
|
|
+ │ CLI apps/cli/dist/index.js │
|
|
|
+ │ runPipeline (7 阶段) │
|
|
|
+ │ parse → tts → assets → │
|
|
|
+ │ compose → render → export │
|
|
|
+ │ → publish(可选) │
|
|
|
+ └───────────────┬──────────────┘
|
|
|
+ │
|
|
|
+ ┌────────────────────────┼────────────────────────┐
|
|
|
+ ▼ ▼ ▼
|
|
|
+ 统一输出目录 阿里云 OSS 飞书 Webhook
|
|
|
+ {output}/{模板}/{日期}/{文件} (上传视频) (推送结果/失败)
|
|
|
+```
|
|
|
+
|
|
|
+- **Web 服务**(Next.js 15)提供 UI 与 HTTP API;渲染时 `spawn` 调用 CLI 子进程执行 `runPipeline`。
|
|
|
+- **CLI**(`apps/cli`)是流水线唯一入口;WebUI 与 HTTP 都复用它,因此 OSS 上传 / 飞书推送只在 CLI 进程内发生一次。
|
|
|
+- **统一输出目录**:CLI / HTTP / WebUI 写入同一目录,按 `{模板}/{ISO日期}/{文件名}.mp4` 自动建子目录。
|
|
|
+- **monorepo**:pnpm workspaces + Turborepo(`packages/shared|core|tts|templates|collect`,`apps/cli|web`)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 2. 前置要求
|
|
|
+
|
|
|
+**Docker 方式(推荐)**
|
|
|
+- Docker 20+ 与 Docker Compose v2。
|
|
|
+
|
|
|
+**本地开发方式**
|
|
|
+- Node.js 22、pnpm 10、ffmpeg。
|
|
|
+- 渲染依赖 headless Chrome:首次运行 Remotion 会自动下载(`@remotion/renderer`),或设置 `PUPPETEER_EXECUTABLE_PATH` 指向系统 Chrome。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 3. 快速开始:Docker Compose(推荐)
|
|
|
+
|
|
|
+```bash
|
|
|
+# 1. 准备配置(密钥 / 端点)
|
|
|
+cp .env.example .env
|
|
|
+# 编辑 .env,至少填入 LLM、TTS 的 key;按需开启 OSS / 飞书
|
|
|
+
|
|
|
+# 2. 构建并启动
|
|
|
+docker compose up --build -d
|
|
|
+
|
|
|
+# 3. 访问
|
|
|
+# WebUI: http://localhost:13000
|
|
|
+# (PORT 可在 .env 中覆盖,默认 13000 → 容器 3000)
|
|
|
+```
|
|
|
+
|
|
|
+`docker compose up` 会自动读取仓库根目录的 `.env`,把其中的变量替换进容器的 `environment:`(见 `docker-compose.yml`)。因此**密钥放在宿主机 `.env`,不需要把 `.env` 打进镜像**。
|
|
|
+
|
|
|
+停止 / 查看日志 / 重建:
|
|
|
+
|
|
|
+```bash
|
|
|
+docker compose logs -f pipeline # 跟随日志
|
|
|
+docker compose down # 停止
|
|
|
+docker compose up --build -d # 改完代码后重新构建
|
|
|
+```
|
|
|
+
|
|
|
+容器内:
|
|
|
+- Web 服务运行于 `/app/apps/web`,监听 `3000`。
|
|
|
+- 输出目录 `/app/output` 挂载到宿主机 `./output`(视频落盘可见、可清理)。
|
|
|
+- 任务元数据(`jobs.json`)保存在 docker volume `pipeline-jobs`(`/tmp/pipeline-jobs`)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 4. 配置说明
|
|
|
+
|
|
|
+配置分两层:**`.env`(密钥 / 端点)** + **`config/default.yaml`(业务参数)**。CLI 读取顺序:`--config` 参数 → `pipeline.config.yaml` → `config/default.yaml`;密钥统一走环境变量。
|
|
|
+
|
|
|
+### 4.1 环境变量(`.env`)
|
|
|
+
|
|
|
+| 变量 | 必填 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `OPENAI_API_KEY` / `OPENAI_BASE_URL` | 是* | LLM(OpenAI 兼容端点:DeepSeek / Qwen / GLM 等)。`*`用结构化 JSON + `--skip-llm` 时可省 |
|
|
|
+| `OPENAI_TTS_API_KEY` / `OPENAI_TTS_BASE_URL` | 是* | 默认 TTS provider。`*`用 `--no-tts` 时可省 |
|
|
|
+| `OPENAI_TTS_MODEL` | 否 | TTS 模型,默认 `seed-tts-1.1` |
|
|
|
+| `TTS_MAX_RETRIES` | 否 | TTS 请求失败重试次数(网络错误 / 429 / 5xx,指数退避),默认 3;`0` 关闭 |
|
|
|
+| `FISH_AUDIO_API_KEY` | 否 | Fish Audio provider |
|
|
|
+| `MINIMAX_API_KEY` / `MINIMAX_GROUP_ID` | 否 | MiniMax provider |
|
|
|
+| `ELEVENLABS_API_KEY` | 否 | ElevenLabs provider |
|
|
|
+| `OUTPUT_DIR` | 否 | 统一输出目录;空则用 `config.output.dir`(默认 `./output`)。Docker 内固定 `/app/output` |
|
|
|
+| `OUTPUT_RETENTION_DAYS` | 否 | 缓存保留天数,默认 30;`0` 关闭自动清理 |
|
|
|
+| `OSS_REGION` `OSS_BUCKET` `OSS_ACCESS_KEY_ID` `OSS_ACCESS_KEY_SECRET` | 否 | 阿里云 OSS;四项齐全才启用上传 |
|
|
|
+| `OSS_ENDPOINT` `OSS_PATH` `OSS_PUBLIC_DOMAIN` `OSS_SECURE` | 否 | OSS 自定义端点 / key 前缀 / 资源链接域名(如 CDN) / 是否 HTTPS |
|
|
|
+| `FEISHU_WEBHOOK_URL` `FEISHU_WEBHOOK_SECRET` | 否 | 飞书自定义机器人 webhook 及签名密钥 |
|
|
|
+| `PORT` | 否 | 宿主机映射端口,默认 13000 |
|
|
|
+
|
|
|
+> 也可在 WebUI **Settings** 页面填写并保存到 `.env`(敏感值自动脱敏显示)。
|
|
|
+
|
|
|
+### 4.2 `config/default.yaml`
|
|
|
+
|
|
|
+TTS provider 选择、模型、对齐(whisper)、模板配色、采集源(`collect`)、OSS/飞书的**非敏感**默认值(region/bucket/path 等)在此配置。详见文件内注释。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 5. 输出目录与缓存清理
|
|
|
+
|
|
|
+- **布局**:`{OUTPUT_DIR}/{模板名}/{YYYY-MM-DD(UTC)}/{模板}-{平台}-{jobId前8位}.mp4`
|
|
|
+ - 例:`output/github-trending/2026-07-16/github-trending-bilibili-701832d4.mp4`
|
|
|
+- **统一性**:相对路径相对 monorepo 根解析,CLI 与 `apps/web` 落到同一物理目录;容器内为 `/app/output`。
|
|
|
+- **自动清理**:每次渲染启动时按 `OUTPUT_RETENTION_DAYS`(默认 30)扫描,删除 mtime 超过阈值的文件及随之变空的日期目录(best-effort,不影响渲染)。设 `0` 关闭。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 6. 发布:OSS 与飞书
|
|
|
+
|
|
|
+渲染完成后自动执行(可被 `--no-publish` / `config.skipPublish` 跳过):
|
|
|
+
|
|
|
+| 场景 | 行为 |
|
|
|
+| --- | --- |
|
|
|
+| 上传 OSS 成功 | 推送飞书:✅ 视频生成成功 + OSS 资源链接 |
|
|
|
+| 渲染成功但上传失败 | 推送飞书:⚠️ 已生成但上传失败 + 本地路径 + 错误(本地视频仍保留) |
|
|
|
+| 渲染本身失败 | 推送飞书:❌ 生成失败 + 错误信息 |
|
|
|
+
|
|
|
+- OSS 用 `ali-oss` 分片上传;资源链接优先用 `OSS_PUBLIC_DOMAIN`(CDN),否则用 bucket 默认域名。**假定对象为公开读**;若为私读需另行接签名 URL。
|
|
|
+- 飞书支持自定义机器人的**签名校验**(`FEISHU_WEBHOOK_SECRET`),算法为 `base64(HMAC-SHA256(key=timestamp+"\n"+secret, message=""))`。
|
|
|
+- 上传后的 OSS URL 会回填到导出文件(CLI 打印 `oss: <url>`;WebUI 任务详情页展示「OSS Links」)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 7. 本地开发(非 Docker)
|
|
|
+
|
|
|
+```bash
|
|
|
+pnpm install
|
|
|
+pnpm build # 构建所有包(含 apps/cli/dist、apps/web/.next)
|
|
|
+
|
|
|
+# CLI 直接渲染
|
|
|
+node apps/cli/dist/index.js render test/fixtures/sample-knowledge.json \
|
|
|
+ -t knowledge -p bilibili --skip-llm --no-tts --no-publish
|
|
|
+
|
|
|
+# WebUI 开发服务器(热更新)
|
|
|
+cd apps/web && pnpm dev # http://localhost:3000
|
|
|
+```
|
|
|
+
|
|
|
+常用命令:
|
|
|
+
|
|
|
+```bash
|
|
|
+pnpm typecheck # 全包类型检查
|
|
|
+pnpm lint # 全包 lint
|
|
|
+pnpm build # 全量构建
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 8. CLI 用法
|
|
|
+
|
|
|
+```bash
|
|
|
+node apps/cli/dist/index.js render <input> -t <template> [options]
|
|
|
+```
|
|
|
+
|
|
|
+- `<input>`:JSON / Markdown / 纯文本文件路径;或用 `--source <name>` 从采集源取数(如 `github-trending`、`github-daily`)。
|
|
|
+- `-t/--template`:`news|knowledge|opinion|marketing|github-trending`(必填)。
|
|
|
+- `-p/--platform`:`bilibili|douyin-long|douyin-short|universal-16x9|universal-9x16`,逗号分隔多平台。
|
|
|
+- `-o/--output`:输出目录(默认走 `config.output.dir` / `./output`)。
|
|
|
+- `--no-tts`:跳过 TTS,生成静音视频(调试布局)。
|
|
|
+- `--skip-llm`:跳过 LLM,要求输入是合法 `VideoInputSchema` JSON。
|
|
|
+- `--no-publish`:跳过 OSS 上传与飞书推送。
|
|
|
+- `--config`:指定配置文件路径。
|
|
|
+
|
|
|
+其它子命令:`collect`、`preview`、`templates`、`voices`、`init`(`--help` 查看)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 9. HTTP API(服务化调用)
|
|
|
+
|
|
|
+### 发起渲染
|
|
|
+
|
|
|
+```http
|
|
|
+POST /api/render
|
|
|
+Content-Type: application/json
|
|
|
+
|
|
|
+{
|
|
|
+ "input": {
|
|
|
+ "template": "knowledge",
|
|
|
+ "platforms": ["bilibili"],
|
|
|
+ "ttsProvider": "openai-tts",
|
|
|
+ "text": "<VideoInput JSON / Markdown / 纯文本>"
|
|
|
+ },
|
|
|
+ "options": { "noTts": false }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+- `input.template`(必填)、`input.ttsProvider`(必填)。
|
|
|
+- `input.text` 与 `input.source` 二选一;`platforms` 缺省为 `["bilibili"]`。
|
|
|
+- 采集源:`input.source` + `input.sourceArgs`(如 `{ "owner": "x", "repo": "y" }`)。
|
|
|
+
|
|
|
+响应:`{ "jobId": "<uuid>", "status": "started" }`。
|
|
|
+
|
|
|
+### 轮询任务 / 下载
|
|
|
+
|
|
|
+```http
|
|
|
+GET /api/jobs/<jobId> # 返回任务状态、outputFiles、ossUrls、publishError
|
|
|
+GET /api/jobs # 任务列表
|
|
|
+GET /api/download?file=<绝对路径>&download=1 # 下载视频(仅允许统一输出目录或任务目录内文件)
|
|
|
+```
|
|
|
+
|
|
|
+任务状态:`pending | running | completed | failed`。`completed` 后 `outputFiles` 给出本地路径,`ossUrls` 给出 OSS 链接(若已上传)。
|
|
|
+
|
|
|
+### cURL 示例
|
|
|
+
|
|
|
+```bash
|
|
|
+curl -X POST http://localhost:13000/api/render \
|
|
|
+ -H 'Content-Type: application/json' \
|
|
|
+ -d '{"input":{"template":"knowledge","platforms":["bilibili"],"ttsProvider":"openai-tts","text":"<JSON 字符串>"}}'
|
|
|
+
|
|
|
+# 轮询
|
|
|
+curl http://localhost:13000/api/jobs/<jobId>
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 10. 数据持久化(卷)
|
|
|
+
|
|
|
+| 挂载 | 容器路径 | 用途 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `./output` | `/app/output` | 视频产物 + 渲染临时目录(按模板/日期归档,自动清理) |
|
|
|
+| docker volume `pipeline-jobs` | `/tmp/pipeline-jobs` | 任务元数据 `jobs.json`(重启保留) |
|
|
|
+
|
|
|
+> 注意:任务元数据存在内存卷中,**删除 volume 会丢失任务历史**(但不影响已生成的视频文件)。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 11. 排错
|
|
|
+
|
|
|
+| 现象 | 排查 |
|
|
|
+| --- | --- |
|
|
|
+| 渲染卡在 `[5/7] Rendering` | headless Chrome 未就绪。本地确认 Chrome / Chromium 可用,或设 `PUPPETEER_EXECUTABLE_PATH`;Docker 镜像已内置所需系统库 |
|
|
|
+| TTS 报 API_KEY 错误 | 检查 `.env` 的 TTS key;或临时用 `--no-tts` 调布局 |
|
|
|
+| TTS 报 502 / 503 / 网络错误 | TTS 网关上游瞬时故障(如 DNS、滚动重启);已内置重试(`TTS_MAX_RETRIES` 默认 3)。若持续失败,检查 `OPENAI_TTS_BASE_URL` 网关健康度或临时换 provider |
|
|
|
+| 日志里出现 `Note: … @remotion/media-parser … license` | 这是 Remotion 的**许可证提醒**(`parseMedia()` 探测音频时长时打印),不是错误、不影响渲染。若要消除,需在 `packages/tts/src/duration.ts` 的 `parseMedia()` 传入 `acknowledgeRemotionLicense: true`——注意这是对许可证的**法律确认**,公司用途请先确认是否需要 [Remotion 许可](https://remotion.dev/license) |
|
|
|
+| OSS 上传失败 | 检查 `OSS_REGION/BUCKET/ACCESS_KEY_*`;任务详情会展示 `Publish warning`,本地视频仍生成 |
|
|
|
+| 飞书收不到消息 | 确认 `FEISHU_WEBHOOK_URL`;若启用了签名校验需同时填 `FEISHU_WEBHOOK_SECRET` |
|
|
|
+| 容器内找不到输出 | 确认挂载到 `/app/output`(`OUTPUT_DIR`),`docker compose` 已默认如此 |
|
|
|
+| 改了 `.env` 不生效 | 重启服务:`docker compose up -d`(环境变量在容器启动时注入) |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 12. 目录速查
|
|
|
+
|
|
|
+```
|
|
|
+apps/cli/ CLI 入口(Commander)
|
|
|
+apps/web/ Next.js WebUI + API 路由
|
|
|
+packages/shared/ Zod schema、类型、常量、LLM 客户端、路径/发布配置解析
|
|
|
+packages/core/ 流水线编排、7 阶段、cleanup、publish(OSS+飞书)
|
|
|
+packages/tts/ TTS provider 注册表
|
|
|
+packages/templates/ Remotion 场景组件
|
|
|
+packages/collect/ 数据采集器(github-trending 等)
|
|
|
+config/default.yaml 业务配置(provider / 模板配色 / 采集源 / OSS·飞书默认值)
|
|
|
+.env(.example) 密钥与端点
|
|
|
+docker-compose.yml 容器编排
|
|
|
+Dockerfile 多阶段构建
|
|
|
+```
|