CLAUDE.md 5.9 KB

CLAUDE.md

本文件为 Claude Code (claude.ai/code) 在本仓库中工作时提供指引。

项目概述

文本转视频生成流水线。接收描述视频结构(封面、场景、结束语)的 JSON 输入,输出带 TTS 旁白、字幕和模板视觉样式的 MP4 视频。

常用命令

pnpm build          # 构建所有包 (turbo)
pnpm typecheck      # 类型检查所有包
pnpm lint           # Lint 所有包

# 运行视频渲染
node apps/cli/dist/index.js render test/fixtures/sample-knowledge.json -t knowledge -p bilibili

# Web UI 开发服务器
cd apps/web && pnpm dev

架构

pnpm workspaces + Turborepo 的 monorepo 结构。

apps/cli/          CLI 入口 (Commander)
apps/web/          Next.js 15 WebUI + API 路由
packages/shared/   Zod schema、类型定义、常量、LLM 客户端
packages/core/     流水线编排与 6 个阶段
packages/tts/      TTS provider 注册表 + 4 个 provider
packages/templates/ 5 个模板的 Remotion React 组件

流水线数据流

输入始终是结构化 JSON (VideoInputSchema)。流水线在 packages/core/src/stages/ 中依次执行 6 个阶段:

  1. parse — 通过 VideoInputSchema 验证 JSON,转换为内部 ParsedContent(cover → scene-0,outro → 最后一个 scene)。github-trending 模板在这里确定性注入额外的 summary 场景(不交给 LLM):拆分 cover 开场白为 masthead + "今日精选 N 个项目",并将 videoInput.scenes[].github.repo 收集为 summary 场景的 trendingRepos 字段
  2. tts — 按场景调用 TTS provider,生成逐场景音频文件 + word timestamps
  3. assets — 解析图片资源(本地 path > 远程 url > 关键词 query),复制背景图/字体
  4. compose — 转换为带帧时间轴的 ComposedProject,word timestamps 转为场景内相对时间。逐字段拷贝场景数据——新增场景字段时必须在此阶段显式透传buildInputProps...scene 自动透传,但 compose 是手写字段映射)
  5. render — 打包 Remotion bundle,将资源复制到 publicDir,通过 renderMedia 渲染
  6. export — 输出最终 MP4 到指定目录

核心类型链:VideoInputParsedContentComposedProject → Remotion props。

Remotion 约束

Remotion 通过其 webpack dev server 提供所有静态资源。组件中绝不能使用文件系统绝对路径 — 必须使用 staticFile(filename)。render 阶段会将所有资源(音频、图片、背景图)复制到统一的 publicDir,通过 props 传递文件名。

音频按场景独立播放:每个 <Sequence> 包含自己的 <Audio> 组件,不使用全局音频轨道。

TTS Provider 体系

Provider 通过 registerProvider()packages/tts/src/providers/ 中注册。每个 provider 实现 TTSProvider 接口(synthesizelistVoicesalign)。新增 provider 的方式:在 providers/ 下创建文件并在 index.ts 中 import。

模板系统

5 个模板(news、knowledge、opinion、marketing、github-trending),每个在 packages/templates/src/<name>/index.tsx 中有对应的场景组件。共享基础组件位于 packages/templates/src/base/Root.tsx 按以下规则路由:

  • sceneType === "cover" → 内置 CoverScene
  • sceneType === "outro" → 内置 OutroScene
  • sceneType === "summary"template === "github-trending"GithubTrendingSummaryScene(仅此模板有 summary 场景)
  • 其他 content 类型 → SCENE_MAP[template] 对应模板组件

github-trending 是当前唯一带 isPortrait 分支的模板,竖屏布局采用 flex column(头部取自然高度,内容 flex 填充),横屏保持绝对定位。Section 子组件通过 size: "default" | "large" 区分横竖屏字号档位,并用 -webkit-line-clamp 做安全截断(body 用 flex: "0 0 auto" 防止 shrink 导致的单行底部裁剪)。

SubtitleBarpackages/templates/src/base/components/subtitle-bar.tsx)接受可选 fontSizestyle prop——竖屏场景可传 { bottom: 380 } 提高字幕位置、fontSize: 56 放大字号;横屏不传则保持默认(bottom: 60fontSize: 40)。

配置

  • .env(monorepo 根目录)— 所有 provider 的 API Key(CLI 启动时加载,Next.js 通过 next.config.ts 加载)
  • config/default.yaml — TTS provider、模型、模板配色、输出设置
  • CLI 按以下顺序读取配置:--config 参数 → pipeline.config.yamlconfig/default.yaml

核心 Schema

全部在 packages/shared/src/types/ 中用 Zod 定义:

  • VideoInputSchema — 用户输入格式(title、subtitle、cover、scenes[]、outro、globalStyle)
  • SceneSchema — 内部场景,含 sceneType: "cover" | "content" | "summary" | "outro"、可选 github(GithubSceneData)、可选 trendingRepos(RepoMeta[],仅 summary 场景使用)
  • ComposedSceneSchema — compose 后的场景,含帧时间轴、audioPath、已解析的图片。字段与 SceneSchema 一一对应
  • PipelineInputSchema — 顶层流水线输入(text、template、platform、ttsProvider)

新增场景字段时三个 schema 都要同步: SceneSchema(scene.ts)、ComposedSceneSchema(pipeline.ts)、RemotionScene(Root.tsx 的 interface)。还要在 compose.ts 手动透传(不是 ...scene 展开),否则字段会在 compose 阶段丢失。

LLM 与 TTS 提示

  • LLMClientpackages/shared/src/llm/client.ts)显式设置 max_tokens: 8192——github-trending 多仓库结构化 JSON 输出约 6000 tokens,provider 默认值(1024-4096)会截断响应导致 JSON 解析失败
  • github-trending 的 cover/summary narration 是 parse.ts 硬编码模板字符串(含日期和仓库计数),不交给 LLM;LLM 只产出 per-repo scenes[]
  • TTS 按场景独立合成,受 provider 配额限制;调试布局可用 --no-tts 跳过(生成静音视频)