# 部署文档 文本转视频生成流水线的部署与运行说明。项目以**容器化、服务化**为重心: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 及签名密钥 | | `FEISHU_AT_OPEN_IDS` | 否 | 推送消息时 @ 的成员 open_id(逗号分隔多个)。自定义机器人只能按 open_id @人,且需在机器人租户/群内可解析 | | `LOG_LEVEL` | 否 | 日志级别 `debug\|info\|warn\|error`,默认 `info` | | `PORT` | 否 | 宿主机映射端口,默认 13000 | | `SCHEDULES` | 否 | 定时任务(JSON 数组),整体覆盖 `config/default.yaml` 的 `schedules`,便于部署期改而无需重建镜像 | | `SCHEDULER_ENABLED` | 否 | 调度器总开关,`false` 关闭(默认开启) | > 也可在 WebUI **Settings** 页面填写并保存到 `.env`(敏感值自动脱敏显示)。 ### 4.2 `config/default.yaml` TTS provider 选择、模型、对齐(whisper)、模板配色、采集源(`collect`)、OSS/飞书的**非敏感**默认值(region/bucket/path 等)在此配置。详见文件内注释。 ### 4.3 定时生成(容器内调度) `schedules` 段定义定时任务,Next.js 服务启动时由**进程内调度器**(`instrumentation` 钩子 + `node-cron`)注册,到点 spawn CLI 渲染——复用 WebUI/HTTP 同一链路,任务进 jobs 列表、走 OSS/飞书发布。cron 按容器时区(`TZ`,默认 `Asia/Shanghai`=北京时间)解释。 ```yaml schedules: - cron: "50 7 * * *" # 北京时间每天 07:50 template: "github-trending" platform: "bilibili" source: "github-trending" # 先采集当日 trending,再解析→渲染→发布 publish: true enabled: true ``` - 改配置后需重启容器(`docker compose up -d`)生效;或用 `SCHEDULES` 环境变量(JSON 数组,同结构)整体覆盖,部署期改无需重建镜像。 - `SCHEDULER_ENABLED=false` 关闭整个调度器。 - 单副本下进程内调度天然不会重复执行;渲染较重,已内置单飞(上一次未结束则跳过本次)。 --- ## 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=""))`。 - 设置 `FEISHU_AT_OPEN_IDS`(逗号分隔的 open_id)后,每条推送都会 @ 这些成员:消息正文追加 `` 标签,并在 payload 顶层声明 `at.open_ids`(二者齐备才会真正触发 @ 通知)。注意自定义机器人只能按 **open_id** @人(无通讯录权限,不支持 user_id / 邮箱),且 open_id 须在该机器人租户内可解析(通常为目标群成员)。 - 上传后的 OSS URL 会回填到导出文件(CLI 打印 `oss: `;WebUI 任务详情页展示「OSS Links」)。 --- ## 7. 日志与可观测性 排查问题看三处: 1. **容器日志(实时)**:`docker compose logs -f pipeline`。CLI 子进程的每阶段进度、TTS 重试、publish(OSS 上传 / 飞书发送)日志都会**镜像**到这里,每行带 `[job ]` 前缀与时间戳,便于区分并发任务。 2. **WebUI 任务详情页「日志」面板**:任务结束后展示完整捕获的 CLI 输出(上限 ~200KB,超出截断头部)。失败任务同样可看。 3. **失败任务的 `error` / `publishError`**:任务卡片与详情页直接显示。 日志格式:` [LEVEL] [scope] message`,scope 含 `pipeline` / `tts` / `publish`。用 `LOG_LEVEL`(`debug|info|warn|error`,默认 `info`)调节详细程度。 > 说明:渲染由 Web 服务 spawn CLI 子进程执行;CLI 的 stdout/stderr 默认被管道捕获。现在这些输出既会镜像到容器 stdout/stderr(供 `docker compose logs`),也会存入任务(供 UI)。TTS 的瞬时 502/网络重试会以 `[WARN] [tts] HTTP 502, retrying …` 形式出现;OSS/飞书失败会以 `[ERROR] [publish] …` 出现,不再被静默吞掉。 ## 8. 本地开发(非 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 # 全量构建 ``` --- ## 9. CLI 用法 ```bash node apps/cli/dist/index.js render -t