#!/usr/bin/env python3 """ПЕРЕ-СЧЁТ ВСЕХ НЕСУЩИХ ЧИСЕЛ ПАКА ИЗ СЫРЬЯ. $0. Число, которое нельзя пере-снять командой из репозитория, ничем не отличается от числа по памяти. Здесь каждый блок ИТОГа печатается заново из персистированных артефактов, деньги — двумя независимыми путями (касса и пере-счёт из сырых `usage` × прайс). Запуск: eval/.venv/bin/python eval/editor_tier/itog23.py """ from __future__ import annotations import json import statistics as st 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")) sys.path.insert(0, str(REPO / "eval" / "role_topology")) def _load(name: str, path: Path): import importlib.util # noqa: PLC0415 spec = importlib.util.spec_from_file_location(name, path) mod = importlib.util.module_from_spec(spec) sys.modules[name] = mod spec.loader.exec_module(mod) return mod JU = _load("judge_et", ZONE / "judge.py") PAN, SCR, MONEY, MAT = JU.PAN, JU.PAN.SCR, JU.MONEY, JU.MAT ROSTER = SCR.ROSTER OUT = MONEY.OUT def h(t: str) -> None: print(f"\n═══ {t} ═══") def material() -> None: h("МАТЕРИАЛ") old, new = JU.P22.M.units_zh(), MAT.units_new() print(f" единиц эксп-22 (приколоты манифестом) {len(old)} · глав " f"{sorted(u['chapter'] for u in old)}") ln = sorted(len(u["source"]) for u in new) print(f" НОВЫХ единиц {len(new)} · глав {sorted(u['chapter'] for u in new)}") print(f" знаков {ln[0]}…{ln[-1]} медиана {ln[len(ln) // 2]} · " f"макс. близость {JU.P22.M._pairwise_max_sim(new):.3f}") # noqa: SLF001 print(f" снято гейтом прав из своего пула: {MAT.rights_dropped(set()) or '—'}" if False else f" пересечений с эксп-22: " f"{len({u['uid'] for u in new} & {u['uid'] for u in old})}") def screen() -> None: h("ФАЗА A — СКРИН СИЛЬНОГО ТИРА (пороги эксп-22, не свои)") rs = SCR.result() print(f" {'модель':16s}{'вердикт':>10s}{'ед.':>4s}{'$/ед edit':>11s}{'размышл':>9s} причины") for m, r in rs.items(): print(f" {m:16s}{r['verdict']:>10s}{r['n']:4d}{(r['price_editor'] or 0):11.5f}" f"{r['reasoning_share']:9.1%} {'; '.join(r['why'])}") print(f" прошли: {[m for m, r in rs.items() if r['verdict'] == 'прошёл']}") print(" СПРАВКА (полный критерий эксп-22, с переводческим порогом, которого нет в пре-реге):") for m, r in rs.items(): print(f" {m:16s}{r['verdict_full22']:>10s} $/ед transl " f"{(r['price_translator'] or 0):.5f}") def judged(pass_: str) -> None: h(f"СУДЕЙСТВО, проход {pass_}") JU.setup(pass_) import absjudge as AJ # noqa: PLC0415 if not AJ._by_unit(): # noqa: SLF001 print(" голосов нет") return AJ.controls() print() AJ.score() def positional() -> None: h("ПОЗИЦИОННЫЙ НАКЛОН — ЗАМЕРЕН И ВЫЧТЕН (требование ЗАКОНа)") for pass_ in JU.PASSES: JU.setup(pass_) import absjudge as AJ # noqa: PLC0415 if not AJ._by_unit(): # noqa: SLF001 continue print(f" --- {pass_} ---") AJ.position() print() def money_two_ways() -> None: h("ДЕНЬГИ — ДВА НЕЗАВИСИМЫХ ПУТИ") led = {ph: MONEY.Guarded(ph).spent() for ph in MONEY.TAGS} def indep(rec: dict) -> float: m = rec.get("model") if m not in ROSTER.CANDIDATES: return rec.get("cost_usd", 0.0) _, _, pin, pc, pout, _t, _s = ROSTER.CANDIDATES[m] pt, cd = rec.get("prompt_tokens", 0), rec.get("cached_tokens", 0) out = ROSTER.billed_output(m, rec.get("completion_tokens", 0), rec.get("reasoning_tokens", 0), rec.get("total_tokens", 0), pt) return (pt - cd) / 1e6 * pin + cd / 1e6 * pc + out / 1e6 * pout tot2 = {ph: 0.0 for ph in led} empty = [] for ph, globs in MONEY.TAGS.items(): for g in globs: for f in OUT.glob(g): r = json.loads(f.read_text(encoding="utf-8")) tot2[ph] += indep(r) if r.get("cost_usd", 0) > 0 and not (r.get("content") or "").strip(): empty.append((f.name, r["cost_usd"])) print(f" {'фаза':6s}{'касса':>12s}{'пере-счёт':>12s}{'расхождение':>13s}{'потолок':>10s}") for ph in MONEY.TAGS: mark = " ⛔ ПРОБОЙ" if led[ph] > MONEY.CEILINGS[ph] + 1e-9 else "" print(f" {ph:6s}{led[ph]:12.6f}{tot2[ph]:12.6f}{led[ph] - tot2[ph]:13.6f}" f"{MONEY.CEILINGS[ph]:10.2f}{mark}") print(f" {'ПАК':6s}{sum(led.values()):12.6f}{sum(tot2.values()):12.6f}" f"{sum(led.values()) - sum(tot2.values()):13.6f}{MONEY.PACK_CEILING:10.2f}") if empty: t = sum(c for _n, c in empty) print(f" оплачено за ПУСТОЙ выход: {len(empty)} вызовов ${t:.5f} " f"({t / max(1e-9, sum(led.values())) * 100:.1f}% пака)") for n, c in sorted(empty, key=lambda x: -x[1]): print(f" {n} ${c:.5f}") def _cost(f: Path) -> float: return json.loads(f.read_text(encoding="utf-8")).get("cost_usd", 0.0) if f.exists() else 0.0 def economics() -> None: """⚠ Строка R0 считается ИЗ СЫРЬЯ эксп-22, а не через `hasattr(P22,"edit_cost")`. Прежняя редакция спрашивала у эксп-22 метод, которого у него нет (есть только `draft_cost`), — строка молча выходила нулевой и отфильтровывалась, а в отчёт попадали числа, снятые где-то ещё и друг с другом не сходившиеся (0.00545 × 1500 = $8.18, напечатано $13.45). Поймано приёмкой. Колонки печатаются ДВУМЯ семействами: редактура отдельно и СВЯЗКА черновик+редактор — сравнивать связку одного арма с редактурой другого нельзя, а именно это отчёт и делал. """ h("ЦЕНА РЕДАКТОРСКОЙ КЛЕТКИ, p50 И p95 ПО ЕДИНИЦАМ") us = JU.P22.M.units_zh() T22 = JU.P22.OUT base = [_cost(T22 / f"{JU.P22.tag_draft(PAN.ANCHOR, u['uid'])}.json") for u in us] rows = [("R0 " + PAN.BATTLE, [_cost(T22 / f"{JU.P22.tag_edit(PAN.ANCHOR, u['uid'])}.json") for u in us])] for i, m in enumerate(PAN.survivors(), start=1): rows.append((f"T{i} {m}", [_cost(OUT / f"{PAN.tag_c(m, u['uid'])}.json") for u in us])) def q(cs: list[float], p: int) -> float: s = sorted(c for c in cs if c > 0) return s[min(len(s) - 1, -(-p * len(s) // 100) - 1)] if s else 0.0 print(f" {'арм':26s}{'ед.':>5s}{'p50 edit':>10s}{'p95 edit':>10s}" f"{'p50 связка':>12s}{'книга p50':>12s}{'книга p95':>12s}") for name, cs in rows: nz = [c for c in cs if c > 0] if not nz: continue link = [c + b for c, b in zip(cs, base, strict=True) if c > 0 and b > 0] print(f" {name:26s}{len(nz):5d}{st.median(nz):10.5f}{q(nz, 95):10.5f}" f"{(st.median(link) if link else 0):12.5f}" f"{(st.median(link) if link else 0) * 1500:12.2f}{q(link, 95) * 1500:12.2f}") print(f" якорный черновик (общая база связки): p50 {st.median([b for b in base if b > 0]):.5f}" if any(base) else " якорного черновика в сырье нет") def agent_runs() -> None: h("АГЕНТ-ЗАПУСКИ") for p in JU.PASSES: v = OUT / f"aj-{p}-votes" t = OUT / f"aj-{p}-tasks" print(f" {p:8s} заданий {len(list(t.glob('*.txt'))) if t.exists() else 0} · " f"голосов принято {len(list(v.glob('*.json'))) if v.exists() else 0}") def main() -> None: print("ИТОГ ПАКА «СИЛЬНЫЙ ТИР» — ВСЕ НЕСУЩИЕ ЧИСЛА ИЗ СЫРЬЯ ($0)") material() screen() economics() for p in JU.PASSES: try: judged(p) except Exception as e: # noqa: BLE001 print(f"\n═══ СУДЕЙСТВО {p} ═══\n не считается: {type(e).__name__}: {e}") positional() money_two_ways() agent_runs() print("\nВСЁ ВЫШЕ ПЕРЕ-СНЯТО ИЗ СЫРЬЯ.") if __name__ == "__main__": main()