#!/usr/bin/env python3 """从 tools/gen_voice_dual.py 台词表提取 id -> 台词全文 映射,输出 JSON。 供试玩转写 harness(web/harness/)把语音播放事件转写成人类可读文本。 台词表是唯一事实源:新台词先改进 gen_voice_dual.py,再跑本脚本刷新 JSON。 用法:.venv-tts/bin/python tools/extract_voice_text.py 输出:web/harness/voice_text.json {"game": {"id": "全文", ...}} """ import ast import json import sys from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "tools")) import gen_voice_dual as gvd # noqa: E402 out = {} for game, lines in gvd.GAMES.items(): table = {} for fid, _ins, text in lines: if fid in table: raise SystemExit(f"重复 id:{game}/{fid}") table[fid] = text # NPC 单音色平铺(gen_voice_dual.NPCS:id, speaker, instruct, 台词) for fid, _sp, _ins, text in gvd.NPCS.get(game, []): if fid in table: raise SystemExit(f"重复 id:{game}/{fid}") table[fid] = text out[game] = table # 键盘变体(P1 路线 a):独立顶层表 "__key__",不与主表混放——现有消费者 # (mock.mjs / transcribe.mjs / live/control.mjs 的 VOICE_TEXT[game][id] 查找) # 行为零改动;键盘措辞会话(input=key)按 VOICE_TEXT.__key__[game][id] 取期望文本。 out["__key__"] = { game: {fid: text for fid, text in gvd.KEY_LINES[game]} for game in gvd.GAMES } def parse_legacy(py_path: Path) -> dict: """AST 解析旧版 gen_voice.py:提取 ('id', ("Speaker", "instruct"), "text") 元组。 不能 import——这些脚本顶层直接执行生成。""" tree = ast.parse(py_path.read_text(encoding="utf-8")) found = {} for node in ast.walk(tree): if not isinstance(node, ast.Tuple) or len(node.elts) != 3: continue a, _b, c = node.elts if (isinstance(a, ast.Constant) and isinstance(a.value, str) and isinstance(c, ast.Constant) and isinstance(c.value, str) and len(c.value) >= 2): found[a.value] = c.value return found # 旧 flavor 脚本补齐角色台词(storyline 林晚等、escape 角色音);主表优先,不覆盖 for game, legacy in [("storyline", ROOT / "app/src/storyline/gen/gen_voice.py"), ("escape", ROOT / "app/src/escape/gen/gen_voice.py")]: for fid, text in parse_legacy(legacy).items(): out[game].setdefault(fid, text) dest = ROOT / "web" / "harness" / "voice_text.json" dest.parent.mkdir(parents=True, exist_ok=True) dest.write_text(json.dumps(out, ensure_ascii=False, indent=1), encoding="utf-8") total = sum(len(v) for k, v in out.items() if k != "__key__") key_total = sum(len(v) for v in out["__key__"].values()) print(f"OK {dest.relative_to(ROOT)} games={len(out) - 1} lines={total} key_variants={key_total}")