96 lines
6.1 KiB
Python
96 lines
6.1 KiB
Python
#!/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/глава_<ch>.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()
|