#!/usr/bin/env python3 """D39.8 blind-read package builder for the pere-run (rerun2). 3 editor arms (glm-5 / mistral / deepseek-pro) of 蛊真人 ch1-5, zh->ru. Per CHAPTER, the 3 versions are shuffled to neutral labels A/B/C with a PER-CHAPTER salt (so the reader cannot accumulate "C = one model" across chapters). Source at the top of each chapter for fidelity comparison. Auto-QA (CJK-in-ru residual) runs before the human. Correspondence key -> a SEPARATE file, withheld from the owner until verdict (D39.8). """ import json, random, re from pathlib import Path RUN = Path("/home/ubuntu/books/gu-zhenren/rerun2") OUT = RUN / "blind" OUT.mkdir(exist_ok=True) ARMS = ["glm", "mistral", "dspro"] def load(): arms = {} for a in ARMS: d = json.load(open(RUN / f"export-{a}.json")) arms[a] = d["chunks"] return arms def by_chapter(chunks): ch = {} for c in sorted(chunks, key=lambda c: (int(c["chapter"]), int(c["chunk_idx"]))): ch.setdefault(c["chapter"], {"final": [], "source": [], "disp": []}) ch[c["chapter"]]["final"].append(c["final_text"]) ch[c["chapter"]]["source"].append(c["source"]) ch[c["chapter"]]["disp"].append(c["disposition"]) return {k: {"final": "\n\n".join(v["final"]), "source": "\n\n".join(v["source"]), "disp": v["disp"]} for k, v in ch.items()} CJK = re.compile(r"[㐀-鿿豈-﫿]") def auto_qa(text): flags = [] cjk = CJK.findall(text) if cjk: flags.append(f"CJK-in-ru residual: {len(cjk)} char(s) e.g. {''.join(cjk[:6])}") # crude latin-word leak (>=3 latin letters run, excluding common ok tokens) lat = re.findall(r"[A-Za-z]{3,}", text) if lat: flags.append(f"latin run(s): {lat[:5]}") return flags def main(): arms = load() chap = {a: by_chapter(arms[a]) for a in ARMS} chapters = sorted(chap["glm"].keys(), key=int) key = {} packet = [] packet.append("# Слепой пакет чтения — пере-прогон rerun2 (蛊真人, главы 1–5, zh→ru)\n") packet.append( "Три версии перевода каждой главы (**A / B / C**) — это три редакторских «руки» одного и того же " "чернового перевода. Метки **перетасованы заново в каждой главе** (в гл.1 «A» и в гл.2 «A» — это, " "скорее всего, РАЗНЫЕ руки). Соответствие меток и моделей — в отдельном файле " "`blind_read_KEY.json`, **его не смотреть до вердикта**.\n") packet.append( "**Как читать (планка: ≤2 претензии на версию):** по каждой главе отметьте для A/B/C претензии " "по ярусам — **критические** (искажение смысла / пропуск / неверный род / непереведённый " "китайский / сломанное слово), **смысловые** (неточность, единицы времени, числа), " "**редакторские** (стиль, ритм, канцелярит) — и назовите предпочтительную версию.\n") packet.append("---\n") for ch in chapters: rng = random.Random(f"rerun2-blind-ch{ch}") order = ARMS[:] rng.shuffle(order) labels = ["A", "B", "C"] key[ch] = {labels[i]: order[i] for i in range(3)} src = chap[order[0]][ch]["source"] # same source across arms packet.append(f"## Глава {ch}\n") packet.append(f"
Китайский исходник (для сверки верности)\n\n```\n{src}\n```\n
\n") for i, lab in enumerate(labels): arm = order[i] txt = chap[arm][ch]["final"] qa = auto_qa(txt) qa_note = f"\n> _(авто-QA: {'; '.join(qa)})_\n" if qa else "" packet.append(f"### Глава {ch} — версия {lab}\n{qa_note}\n{txt}\n") packet.append(f"\n**Ваши претензии по главе {ch}:**\n" "- Версия A — критич.: … · смысл.: … · редакт.: …\n" "- Версия B — критич.: … · смысл.: … · редакт.: …\n" "- Версия C — критич.: … · смысл.: … · редакт.: …\n" "- Предпочтение: …\n\n---\n") (OUT / "blind_read_packet.md").write_text("\n".join(packet)) (OUT / "blind_read_KEY.json").write_text(json.dumps( {"note": "WITHHELD from owner until verdict (D39.8). Per-chapter label->arm mapping.", "arm_label": {"glm": "glm-5 (base)", "mistral": "mistral-large-2512", "dspro": "deepseek-v4-pro"}, "mapping": key}, ensure_ascii=False, indent=2)) # QA summary (mine, not owner-facing) qa_summary = {} for ch in chapters: for arm in ARMS: f = auto_qa(chap[arm][ch]["final"]) if f: qa_summary.setdefault(arm, {})[ch] = f (OUT / "auto_qa.json").write_text(json.dumps(qa_summary, ensure_ascii=False, indent=2)) print("packet:", OUT / "blind_read_packet.md") print("key (withheld):", OUT / "blind_read_KEY.json") print("chapters:", chapters) print("auto-QA hits by arm:", {a: list(v.keys()) for a, v in qa_summary.items()}) if __name__ == "__main__": main()