Skip to content

feat(F9-2h): render 旁白套該課 glossary 讀音表(job↔課 → TTS)#75

Merged
dofliu merged 1 commit into
mainfrom
claude/f9-2h-glossary-tts
Jun 14, 2026
Merged

feat(F9-2h): render 旁白套該課 glossary 讀音表(job↔課 → TTS)#75
dofliu merged 1 commit into
mainfrom
claude/f9-2h-glossary-tts

Conversation

@dofliu

@dofliu dofliu commented Jun 14, 2026

Copy link
Copy Markdown
Owner

做什麼

F9-2「課程術語/讀音表 glossary」的下一塊 offline slice(接 F9-2g #74)。把已落地的 JobRecord.project_id 接到 TTS:render 旁白前現讀該課 glossary 讀音表,render 期間掛上 → 旁白照課程術語讀音念。對應 docs/JOB_COURSE_ASSOCIATION_RFC.md §4.2。

為什麼這樣做(架構選擇)

render 旁白 → TTS 深埋在 pipeline.main → gen_tts → synthesize → normalize_text 一條鏈。把 extra_pronunciation 逐層穿過去要動 synthesize 抽象介面 + 三個 backend(Edge/F5/Google)+ FallbackTTS + gen_tts + render_video 簽章(>5 檔、碰抽象介面)。

改採 codebase 既有的 render-scoped override 慣例core.config.video_dimensions_override / talking_head_override):

  • tts_backend.py:新增 course_pronunciation_override context manager(module-level 覆寫;sequential job 設計下非 thread-safe 可接受,與既有 override 同取捨)。normalize_text 在呼叫端未顯式給 extra_pronunciation 時自動沿用該覆寫;顯式 arg(含 {})永遠優先
  • server/runner.py:新增 _resolve_course_pronunciation(rec)rec.project_idProjectStore.get_glossary(...).to_pronunciation_map(),並把 _run_render 的 inner render 包進第三層 override。

不可妥協紀律

  • 不繞 review gate:完全不碰 R-2 render 入口 assert / 狀態機 / reviewed(只影響「旁白怎麼念」,硬規則 Add pronunciation mapping for mathematical and Greek symbols in TTS #1)。
  • fail-soft(RFC §5):無 project_id(無主 job)/ 課不存在 / 無 glossary / 讀音表空 → 一律 None =沿用全域 pronunciation.json 行為,glossary 解析絕不讓 render 失敗
  • 既有 caller 零影響(顯式 arg 與全域行為皆不變)。

怎麼測

新增 tests/test_glossary_tts_render.py 15 測,全 offline(不打 API、不真跑 TTS/ffmpeg、tmp 隔離 ProjectStore):

  • normalize_text × override:套用 / 顯式優先 / {} 停用 / 還原·例外還原·巢狀還原 / None·空 no-op
  • _resolve_course_pronunciation:無 pid / 有 glossary 回 map / 課不存在 fail-soft / 無 glossary / 空 map 收斂 None
  • _run_render wiring:override 在 inner render 期間掛上、出去還原、無 glossary 沿用全域

本機相關子集 105 passed、全套 2665 passed(3 個 QR/journal 字型像素失敗為容器缺 Noto CJK 假象,CI 裝了字型為權威)。

Reviewer 決策點

無新架構抉擇——Option A 已於 #73 RFC 拍板,本 PR 是 RFC §4.2 列好的 offline 接線。唯一風格選擇是「render-scoped override vs 逐層穿參」,已按既有慣例擇前者(理由見上)。

https://claude.ai/code/session_01Ae7ZGWzWw4kfVLcsyAXQv9


Generated by Claude Code

把 F9-2g 落地的 JobRecord.project_id 接到 TTS:render 前以
ProjectStore.get_glossary(project_id).to_pronunciation_map() 現讀該課讀音表,
render 期間掛上 → 旁白照課程術語讀音念。

- tts_backend.py:新增 course_pronunciation_override context manager(比照
  既有 render-scoped override 慣例 video_dimensions_override/talking_head_override,
  module-level 覆寫、sequential job 設計下非 thread-safe 可接受),normalize_text
  在呼叫端未顯式給 extra_pronunciation 時自動沿用該覆寫(顯式 arg 含 {} 永遠優先)。
  深埋的 pipeline.main→gen_tts→synthesize→normalize_text 一條鏈因此不必逐層穿參。
- server/runner.py:新增 _resolve_course_pronunciation(rec)(fail-soft:無 project_id
  / 課不存在 / 無 glossary / 讀音表空 → None=沿用全域,glossary 解析絕不讓 render
  失敗)並把 _run_render 的 inner render 包進第三層 override。
- 守紀律:完全不碰 R-2 render 入口 assert / 狀態機 / reviewed(只影響旁白怎麼念)。

補 tests/test_glossary_tts_render.py 15 測(normalize_text 套用/顯式優先/{} 停用/
還原·例外·巢狀·None no-op;_resolve_course_pronunciation fail-soft 各路;_run_render
wiring inner 期間掛上·出去還原,全 offline 不打 API、不真跑 TTS)。
全套 2665 passed(3 個 QR/journal 字型像素為容器缺 Noto CJK 假象,CI 權威)。

https://claude.ai/code/session_01Ae7ZGWzWw4kfVLcsyAXQv9
@dofliu dofliu marked this pull request as ready for review June 14, 2026 03:14
@dofliu dofliu merged commit 5c85fe2 into main Jun 14, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants