# 主 project 对 Doco PRD v2 的回复

> 来源:TPS 主 project 顾问(Claude Opus 4.7)
> 日期:2026-06-12
> 针对:`PRD_doco_文稿整理子项目_v2.md` 第四章 5 个问题
> 性质:正式批复,Doco 子项目据此出 v3 后启动 P1

---

## 总体意见

**5 个问题的子项目推荐**,**整体方向 4 个批准、1 个调整**:
- Q1 OCR 选型:**批准 DeepSeek API,但有附加条件**(见下)
- Q2 ffmpeg 入口:**批准,有补充约束**
- Q3 单期 vs 批量接口:**批准,加交付契约**
- Q4 密钥管理:**调整方案** — 走"自管 + 中台登记 inventory"
- Q5 目录规约:**批准草案,但 episode_id 命名规则需主项目定**

5.3 §"23 期是否常态化":**这是一个产品问题,我代制片人答不了。子项目可以按"先按 23 期一次性做完、保留兜底回退路径"开干,常态化的事跟栏目组确认后再回头审。**

---

## Q1. OCR 方案选型 — 批准 DeepSeek API

### 主 project 现状
- **主 project 没有 OCR 子模块/能力**(已确认)。旧设计里 B 稿来自"上游既有 OCR 流程",指的是栏目组那边人工跑的 OCR,不是 TPS 内部的服务。
- 主 project `backend/.env` 里有 `DEEPSEEK_API_KEY`,但**只用作 Cline 工具的 Plan/Act 模型**——没有任何业务代码在调 DeepSeek。所以 doco 调 DeepSeek 视觉模型相当于**新增一条业务调用**,不是"复用现有基础设施"。

### 批复

**Doco 子模块新增 DeepSeek Vision 调用,自管 API key。**

- API key 独立申请,**不复用 Cline 用的那把 key**。理由:Cline 的 key 是开发工具用的,doco 是生产服务,生命周期、配额、监控都该独立。
- 6900 张图 × 几厘 / 张 ≈ 50-150 元,在制片人手上的 API 余额范围内,**不存在配额冲突问题**(主 project 业务代码侧没人在花)。
- 黑底白字字幕场景对 LLM 视觉模型确实是舒适区,**实施前先在 demo 那期视频上跑 10 帧抽样,验证识别准确率达到目标后再扩到 23 期**。
- **降级路径**:如果 DeepSeek Vision 在某些边角 case 上不达标(比如有同期声同步显示双行字幕、字号变化等),回退到 PaddleOCR 本地。**不要回退到讯飞 OCR**(余额独立 + 单期 ~13 元成本太高)。

---

## Q2. 视频处理依赖(ffmpeg)入口 — 批准方案 A

### 主 project 现状
- **没有视频处理子模块/服务**(已确认),dev_plan 也没规划。

### 批复

**Doco 自带 ffmpeg 系统依赖 + Python subprocess 调用。**

附加约束:
- **不引入 `ffmpeg-python` wrapper**——subprocess 足够,不增加新依赖。
- ffmpeg 命令封装在 `doco/video_split.py` 内,**对外只暴露 Python 函数接口**,不让上层调用方直接 shell 调 ffmpeg。
- 在 doco 的 `README.md` 明确写"系统依赖:ffmpeg ≥ 4.x"——这是部署的前置条件。
- 未来如果主 project 真做了统一的视频处理服务,**doco 的封装方式应该使迁移成本最低**(把 subprocess 调用换成 HTTP 调用即可,业务逻辑不动)。

---

## Q3. 23 期批量 vs 单期接口 — 批准方案 A,加契约

### 主 project 现状
- **没有节目素材批量处理编排层**(已确认)。dev_plan 提到的"批量导入工具 v1/v2"是收视数据和报题单的批量,跟视频处理是两回事。

### 批复

**Doco 只对单期负责。同时提供 CLI 和 Python API 两套接口。**

**接口契约(子项目正式实现时按这个出)**:

```python
# Python API
def process_episode(
    episode_id: str,             # 调用方给定,doco 不管命名规则
    video_path: Path,            # 输入视频
    a_draft_path: Path,          # A 稿 docx
    output_dir: Path,            # 产物存放目录
    cleanup_level: str = "medium",  # keep_all / medium / clean
) -> ProcessResult

# ProcessResult 必含字段
@dataclass
class ProcessResult:
    episode_id: str
    status: Literal["success", "partial", "failed"]
    final_docx_path: Optional[Path]
    diff_report_path: Optional[Path]
    needs_review_json_path: Optional[Path]
    errors: List[str]
    stage_timings: Dict[str, float]  # 哪个 phase 用了多久
```

```bash
# CLI 等价形式
doco process \
  --episode-id ep023 \
  --input-video /path/to/video.mp4 \
  --input-a-draft /path/to/a_draft.docx \
  --output-dir /path/to/output \
  --cleanup-level medium
```

**关于 23 期推进**:**先单期跑通再批量**——拿 demo 那期《现代防空反导大对决》视频做 golden test(P4),与 demo 已有产物比对零回归,再扩到 23 期。一次性 batch 23 期风险太大。

未来主 project 若开节目素材批量处理编排层,**会反过来调 doco 的单期接口**,不会改 doco。

---

## Q4. 讯飞密钥管理 — 调整方案:自管 + Inventory 登记

### 主 project 现状
- **没有中台密钥管理子模块**(已确认),也不在 dev_plan 排期内。
- 主 project 凭证都在 `backend/.env`,各模块走环境变量。

### 批复

不走子项目推荐的"申请新凭证 + 写入中台密钥资产文档"(因为中台密钥服务不存在,不能凭空捏一个)。改为:

**1. Doco 自管凭证。** 讯飞、DeepSeek 各自的 API key 放 doco 自己的 `.env`,**不放进主 project 的 `backend/.env`**——保持子模块自治。

**2. 主 project 仓库根目录新增一份登记文档:`docs/api_credentials_inventory.md`**

这份文档:
- **不存储真实凭证**(那些在各自子模块的 .env 里)
- 只存储**元信息**:每个外部 API 用了什么、所属子模块是谁、开通时间、激活状态、到期日、续费责任人
- 子模块申请新 key、key 到期更换,都更新这份文档
- 这是主 project 帮所有子模块做"凭证清单"的最小落地——比起"中台密钥服务",轻得多,但解决"忘了谁管哪把 key"的问题

**3. Inventory 文档的字段**(供子项目和未来其他子模块参考):

```markdown
| 子模块 | API 服务 | Key 类型 | 开通日 | 激活状态 | 到期日 | 责任人 | 备注 |
|---|---|---|---|---|---|---|---|
| doco | 讯飞开放平台 - 录音文件转写 | APP_ID + SECRET_KEY | 2026-06-12 | 已激活 5h 试用包 | 2027-06-12 | 制片人 | demo 凭证已过期,新申请 |
| doco | DeepSeek Vision | API_KEY | 2026-06-12 | 已激活 | — | 制片人 | doco OCR 用 |
| (主) | Anthropic Claude API | API_KEY | ... | ... | ... | ... | AI 融合层用 |
```

**4. 制片人现在要做的事**(代答 Q4 里"新申请的讯飞开发端密钥应该登记在哪里"):
- 去讯飞开放平台 console 申请新的开发端凭证
- 走 0 元购买流程激活 5 小时免费试用包
- 把 APP_ID / SECRET_KEY 写到 doco 的 .env 里
- 在 `docs/api_credentials_inventory.md` 登记一行

---

## Q5. 目录结构与命名规约 — 批准草案,episode_id 命名由主项目定

### 主 project 现状
- **没有节目素材目录的统一规约**(已确认)。主 project 处理的是数据维度的 `episodes` 表,episode_id 是 INT 自增主键。
- 但是,**素材文件名跟数据库 ID 是两层东西**,不能直接套。

### 批复

**子项目提的 `programs/{episode_id}/source|work|output/...` 结构批准。**

**关于 episode_id 命名规则**——这是主项目要定的规约,定如下:

**episode_id 格式:`ep{NNN}_{YYYYMMDD}_{slug}`**

- `ep{NNN}` = episodes 表自增 INT 主键,零填充到 3 位(如 ep023)
- `{YYYYMMDD}` = 首播日期
- `{slug}` = 节目名称的拼音缩写或简称中文(无空格、无特殊字符)

举例:
- `ep023_20260612_haishang_xianfeng`
- `ep007_20260201_马年军事图鉴`

**理由**:
- INT 主键稳定可关联到 episodes 表
- 日期方便文件系统按时间排序
- slug 让人眼可读

**约定**:
- episode_id **由调用方给定**(主项目编排层 / 责编 / CLI 调用者),doco 不生成
- doco 只把它当一个字符串使用
- 主项目责编/编排层在调 doco 前**先在 episodes 表落库该期、拿到 INT ID**,再拼出 episode_id

**work/ 中间产物保留时长**:
- 节目入档案库后保留 **30 天**,然后可清理(由编排层负责,doco 不管)
- 出问题需要复查时,30 天窗口够定位

---

## §5 第 3 条:23 期是常态化吗?

**这是产品问题,不是技术问题。我代制片人答不了。**

**建议子项目的处理**:
- 按"23 期一次性"开干,先把这批做完
- 算法层零侵入是硬保证,即使将来变常态化,流水线也能继续跑
- **保留旧的 mp3+独立 OCR 流程作为回退路径**(代码不删,加 feature flag 或环境变量切换)。万一某期视频不符合"黑底白字+干净人声"特殊条件,降级到旧流程
- 23 期完成 + 制片人跟栏目组确认后,再决定是否清理回退路径

---

## 子项目可以启动的部分

按 PRD v2 §七 的回复期望:
- ✅ **Q1 已答**(DeepSeek API + 附加条件) → P1 可开始
- ✅ **Q2 已答**(subprocess + 不引入 wrapper)→ P1 可开始
- ✅ **Q3 已答**(单期 + 契约) → P5 推进时按契约
- ✅ **Q4 已答**(自管 + inventory 登记) → 制片人先申请讯飞新凭证 + 建 inventory,P2 可开始
- ✅ **Q5 已答**(目录草案批准 + episode_id 规则) → P1 输出有处可放

**Doco 子项目现在可以出 PRD v3,启动 P1。**

---

## 顺便给子项目的两条提醒

1. **demo 的 5 份 fixture 必须进 git**(transcripts / A 稿 / B 稿 / ASR / 终版 / 差异报告),作为单元测试 + golden test 黄金对照。这件事属于 Doco 内部自治,主项目不管,但提醒一下。
2. **AI 融合层模型选 Sonnet 4.6**(PRD v2 §二 已锁),不要在子项目里临时换成别的模型。主项目这边也不会推翻这个选择。

---

*主 project 顾问(Claude Opus 4.7)签发,2026-06-12*
