#!/usr/bin/env python3 """exp12 — сборка СЛЕПЫХ пакетов чтения владельца (слой 1, главный сигнал). Per глава: 7 вариантов (A0,A1,A2,A3,A4,A5,A6), каждый = склейка чанков арма в полную главу. Метки V1..V7 ПЕРЕ-РАНДОМИЗИРОВАНЫ ПО ФРАГМЕНТАМ (своя перестановка на главу — D13.5), ключ соответствий — в ОТДЕЛЬНОМ файле ВНЕ пакета (diag/reading_KEY.json). A1′ (QC) в пакет НЕ идёт. Выход: diag/reading_pack/глава_.md — 7 слепых вариантов + бланк ответа diag/reading_pack/КАК_ЧИТАТЬ.md diag/reading_KEY.json — метка→арм (ВНЕ пакета; не открывать до вынесения оценки) """ from __future__ import annotations import json, random from pathlib import Path DIAG = Path("/home/ubuntu/books/gu-zhenren/diag") ARMS = DIAG / "arms" PACK = DIAG / "reading" # D27-аддендум: пакеты чтения владельца сюда (вне git) SALT = "exp12-blind-v1" CHAPTERS = [5, 7, 14] CHUNKS = {5: [0, 1], 7: [0, 1], 14: [0, 1]} POOL = ["A0", "A1", "A2", "A3", "A4", "A5", "A6"] REGISTER = {5: "смешанная (нарратив+диалог)", 7: "диалого-плотная", 14: "экспозиция/описание"} def arm_chapter_text(arm: str, ch: int, chunks_json: dict) -> str | None: parts = [] for ci in CHUNKS[ch]: key = f"{ch}/{ci}" if arm == "A0": t = chunks_json[key]["draft"] elif arm == "A1": t = chunks_json[key]["final"] else: p = ARMS / arm / f"{ch}_{ci}.txt" if not p.exists() or not p.read_text(encoding="utf-8").strip(): return None t = p.read_text(encoding="utf-8").strip() parts.append(t.strip()) return "\n\n".join(parts) def main() -> None: chunks_json = json.loads((DIAG / "chunks.json").read_text(encoding="utf-8")) PACK.mkdir(parents=True, exist_ok=True) key_map = {} for ch in CHAPTERS: texts = {arm: arm_chapter_text(arm, ch, chunks_json) for arm in POOL} missing = [a for a, t in texts.items() if t is None] if missing: print(f"!! глава {ch}: НЕ ГОТОВЫ армы {missing} — пропуск (перезапусти после arms)") continue order = POOL[:] random.Random(f"{SALT}-{ch}").shuffle(order) # per-chapter permutation labels = [f"V{i+1}" for i in range(len(order))] key_map[str(ch)] = {lab: arm for lab, arm in zip(labels, order)} out = [f"# Глава {ch} — слепое чтение ({REGISTER[ch]})", "", "Ниже 7 вариантов ОДНОЙ главы (разные редактуры одного черновика). " "Прочитай каждый, оцени как ЧИТАТЕЛЬ (естественность русского, живость прозы, " "отсутствие канцелярита/калек). Форма ответа — в конце файла.", "", "---", ""] for lab, arm in zip(labels, order): out += [f"## Вариант {lab}", "", texts[arm], "", "---", ""] out += ["## БЛАНК ОТВЕТА (глава %d)" % ch, "", "1. **Ранжирование** (лучший→худший): V… > V… > V… > V… > V… > V… > V…", "2. **Читаемо ли** (да/нет по каждому): V1=? V2=? V3=? V4=? V5=? V6=? V7=?", "3. **Свободные пометки** (что бесит / что хорошо; можно указывать V-метки и абзацы):", ""] (PACK / f"глава_{ch}.md").write_text("\n".join(out), encoding="utf-8") print(f"глава {ch}: пакет собран (7 вариантов, перестановка {[key_map[str(ch)][l] for l in labels]})") if key_map: (PACK / "_КЛЮЧ_НЕ_ОТКРЫВАТЬ.json").write_text( json.dumps({"salt": SALT, "map": key_map, "arms": {"A0": "черновик deepseek (без редактуры)", "A1": "glm-5 моно (= финал этапа A)", "A2": "glm-5 билингв", "A3": "grok-4.3 моно", "A4": "grok-4.3 билингв", "A5": "gemini-3.1-pro билингв", "A6": "grok-4.3 моно БЕЗ глоссарных констрейнтов"}}, ensure_ascii=False, indent=1), encoding="utf-8") howto = [ "# Как читать (exp12, слепое)", "", "- В `diag/reading/` — 3 файла `глава_5.md`, `глава_7.md`, `глава_14.md`. В каждом 7 вариантов V1..V7 ОДНОЙ главы.", "- Метки V1..V7 **перемешаны СВОЕЙ перестановкой в каждой главе** — «V3» в гл.5 и «V3» в гл.7 это РАЗНЫЕ конфиги. Не пытайся угадать модель — оценивай текст.", "- Заполни БЛАНК в конце каждого файла: ранжирование + читаемо(да/нет) + пометки. ~1–2 часа на все три.", "- Файл `_КЛЮЧ_НЕ_ОТКРЫВАТЬ.json` лежит рядом — **не открывай до сдачи ответов** (слепота свята, урок exp04).", "- Root-cause (10–20 худших мест из 25 глав) уже прислан — обрабатывается отдельным треком.", ] (PACK / "КАК_ЧИТАТЬ.md").write_text("\n".join(howto), encoding="utf-8") print(f"\nКлюч → {PACK/'_КЛЮЧ_НЕ_ОТКРЫВАТЬ.json'} (в пакете, держать закрытым до ответов)") if __name__ == "__main__": main()