textmachine/eval/editor_tier/material.py

127 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""МАТЕРИАЛ ПАКА: 16 НОВЫХ единиц той же книги. $0 — глава уже скачана эксп-22.
Зачем новые единицы. Контраст `R2 glm-5` против боевого редактора дал 2.12 при шуме одного вызова
sd≈3.5: это вопрос МОЩНОСТИ, а не судьи. Пред-объявленный порог эксп-22 (2.03) он проходит,
собственный порог своего прохода (2.47) — нет, и вердикт зависит от того, какой взять. Удвоение
n с 16 до 32 либо разводит интервал от порога, либо честно говорит «эффект меньше, чем стоит
различать». Оба ответа годны; зависимость вердикта от выбора порога — нет.
Методика отбора та же, что в эксп-21 §0 и эксп-22: абзацные чанки, дедуп по подписи без заголовка
главы, ключ = хеш источника, отбор из СЕРЕДИНЫ распределения длин. Отличие ровно одно: главы,
из которых эксп-22 уже брал единицы, исключаются целиком — иначе «новые» единицы были бы соседними
абзацами тех же глав, и прирост n оказался бы мнимым (соседние куски одной главы делят персонажей,
сцену и лексику, то есть коррелируют сильнее случайных).
Гейт прав эксп-22 (снятые главы верхнего дециля эротических маркеров) продолжает действовать: он
применяется в `chapters()`, который здесь переиспользуется как есть.
"""
from __future__ import annotations
import sys
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")
ZONE = Path(__file__).resolve().parent
sys.path.insert(0, str(REPO / "eval" / "tenant_panel"))
import material as M22 # noqa: E402
N_NEW = 16
def used_chapters() -> set[int]:
"""Главы, из которых эксп-22 уже взял единицы."""
return {u["chapter"] for u in M22.units_zh()}
def used_uids() -> set[str]:
return {u["uid"] for u in M22.units_zh()}
def rights_dropped(pool: set[int]) -> set[int]:
"""Гейт прав по СВОЕМУ пулу: верхний дециль по плотности эротических маркеров.
⚠ Число снятых глав НЕ переносится из эксп-22. Там гейт снял две главы — это был верхний
дециль пула из 18. Пул этого пака другой, и перенос константы «2» пропустил бы в замер главы,
которые объявленное правило снимает. Правило одно и то же, число считается заново.
"""
allch = {c["idx"]: c for c in M22.chapters(all_=True)}
ranked = sorted(pool, key=lambda i: (-M22.se_density(allch[i]["text"]), i))
k = max(1, round(len(pool) * 0.10))
return set(ranked[:k])
def units_new(n: int = N_NEW) -> list[dict]:
"""N новых единиц из глав, которых эксп-22 не касался и которые прошли гейт прав."""
allidx = {c["idx"] for c in M22.chapters(all_=True)}
free = allidx - used_chapters() - M22.se_dropped(M22.chapters(all_=True))
dropped = rights_dropped(free)
busy = used_chapters() | dropped | M22.se_dropped(M22.chapters(all_=True))
globals()["RIGHTS_DROPPED"] = sorted(dropped)
uniq: dict[str, dict] = {}
seen: set[str] = set()
for c in M22.chunks():
if c["chapter"] in busy:
continue
sig = M22._dedup_sig(c["text"]) # noqa: SLF001
if sig in seen:
continue
seen.add(sig)
uid = M22.uid_of(c["text"])
uniq.setdefault(uid, dict(source=c["text"], uid=uid, chapter=c["chapter"]))
keys = sorted(uniq, key=lambda k: (len(uniq[k]["source"]), k))
if len(keys) < n:
raise SystemExit(f"свободных единиц {len(keys)}, нужно {n} — материал не набирается")
lo = (len(keys) - n) // 2
picked = [uniq[k] for k in keys[lo:lo + n]]
# одна глава — не более одной единицы: иначе внутри «новых» появится та же корреляция,
# ради снятия которой исключались главы эксп-22
out, taken = [], set()
for u in picked:
if u["chapter"] in taken:
continue
taken.add(u["chapter"])
out.append(u)
if len(out) < n: # добираем по тому же порядку, соблюдая правило главы
for k in keys[lo + n:] + keys[:lo][::-1]:
u = uniq[k]
if u["chapter"] in taken:
continue
taken.add(u["chapter"])
out.append(u)
if len(out) == n:
break
return out[:n]
def selfcheck() -> int:
bad = 0
us = units_new()
if len(us) != N_NEW:
print(f"[ПРОВАЛ] единиц {len(us)}, нужно {N_NEW}")
bad += 1
if set(u["uid"] for u in us) & used_uids():
print("[ПРОВАЛ] единица повторяет эксп-22")
bad += 1
if set(u["chapter"] for u in us) & used_chapters():
print("[ПРОВАЛ] глава повторяет эксп-22")
bad += 1
if len({u["chapter"] for u in us}) != len(us):
print("[ПРОВАЛ] две единицы из одной главы")
bad += 1
sim = M22._pairwise_max_sim(us) # noqa: SLF001
if sim > 0.5:
print(f"[ПРОВАЛ] единицы слишком похожи: макс. близость {sim:.3f}")
bad += 1
ln = sorted(len(u["source"]) for u in us)
print(f"новых единиц {len(us)} из {len({u['chapter'] for u in us})} глав · "
f"знаков {ln[0]}{ln[-1]} медиана {ln[len(ln) // 2]} · макс. близость {sim:.3f}")
print(f"главы: {sorted(u['chapter'] for u in us)}")
print(f"снято гейтом прав из своего пула: {globals().get('RIGHTS_DROPPED')}")
print(f"провалов {bad}")
return bad
if __name__ == "__main__":
sys.exit(1 if selfcheck() else 0)