research: 交互研究项目立项(章程/5路调研4份/游戏交互清点/玩家感知转写harness)

- research/00-charter.md 研究章程:RQ1-8、多人设×场景矩阵、成功标准
- research/01-literature/ 01/03/04/05 四份调研报告(02 sonification 进行中)
- research/03-schemes/game-inventory.md 6游戏状态机与交互接线清单(带行号)
- web/harness/ 玩家感知转写器:虚拟时钟mock+台词全文转写+静默/缺资产如实标注
- tools/extract_voice_text.py 台词表→JSON 提取(主表+旧flavor AST解析)
This commit is contained in:
SoundGame Dev
2026-08-30 21:10:06 +08:00
parent 0a8b5df717
commit 18f299f446
11 changed files with 2450 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
#!/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
out[game] = table
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 v in out.values())
print(f"OK {dest.relative_to(ROOT)} games={len(out)} lines={total}")