#!/usr/bin/env python3 """ПЕРЕ-СЧЁТ ВСЕХ НЕСУЩИХ ЧИСЕЛ ЭКСП-22 ИЗ СЫРЬЯ. $0. Зачем. Эксп-21 сдал отчёт, несущие числа которого НЕ ИМЕЛИ пути воспроизведения в дереве: часть бралась из stdout прогонов, утраченных инцидентом. Число, которое нельзя пере-снять командой из репозитория, ничем не отличается от числа по памяти. Здесь каждый блок ИТОГа печатается заново из персистированных артефактов, с провенансом — из какого прохода и по какой формуле. Ничего не покупается и не судится: только счёт по тому, что уже лежит на диске. Запуск: eval/.venv/bin/python eval/tenant_panel/itog22.py """ from __future__ import annotations import json import math 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(ZONE)) sys.path.insert(0, str(REPO / "eval" / "role_topology")) import bank as BANK # noqa: E402 import battery as B # noqa: E402 import judge as JU # noqa: E402 import material as M # noqa: E402 import money as MONEY # noqa: E402 import panel as P2 # noqa: E402 import roster as R # noqa: E402 OUT = MONEY.OUT def h(t: str) -> None: print(f"\n═══ {t} ═══") def contamination() -> None: h("Ф0.2 КОНТАМИНАЦИЯ СРЕЗА (порог: узнавание ≥3/5 = непригоден)") f = OUT / "contamination.json" if not f.exists(): print(" пробы нет") return for r in json.loads(f.read_text(encoding="utf-8")): v = "НЕПРИГОДЕН" if r["recognized"] * 5 >= 3 * max(1, r["n"]) else "следов нет" print(f" {r['book']:14s} {r['model']:22s} узнано {r['recognized']}/{r['n']} · " f"клоуз {r['cloze']}/{r['n']} {v} [{r['kind']}]") def material() -> None: h("Ф0.2 МАТЕРИАЛ") zs = M.units_zh() allch = M.chapters(all_=True) print(f" книга {M.BOOK['title']} · 首发 {M.BOOK['first_pub']} · глав скачано {len(allch)} · " f"снято гейтом прав {sorted(M.se_dropped(allch))}") print(f" zh-единиц {len(zs)} · знаков {min(len(u['source']) for u in zs)}…" f"{max(len(u['source']) for u in zs)} · медиана " f"{sorted(len(u['source']) for u in zs)[len(zs) // 2]} · глав-источников " f"{len({u['chapter'] for u in zs})} · макс. близость {M._pairwise_max_sim(zs):.3f}") # noqa: SLF001 b = BANK.PR.bank() tot = sum(sum(u["source"].count(t) for u in zs) for t in b) print(f" банк {len(b)} терминов · знаменатель покрытия {tot} упоминаний · signed=false") def screen() -> None: h("Ф1 СКРИН — по КАЖДОМУ кандидату") res = P2.screen_result() if not res: print(" скрина нет") return print(f" {'модель':26s}{'вердикт':>11s}{'$/ед transl':>13s}{'$/ед edit':>11s} причины") for m in R.by_out_price(): r = res.get(m, {}) print(f" {m:26s}{r.get('verdict', '—'):>11s}" f"{(r.get('price_translator') or 0):13.5f}{(r.get('price_editor') or 0):11.5f}" f" {'; '.join(r.get('why', []))}") def echo_rate() -> None: h("Ф2 (в) ЭХО-МИНА — доля единиц, потребовавших ре-гена") for m in P2.tenants(): nz, tz = P2.regen_rate(m, en=False) ne, te = P2.regen_rate(m, en=True) print(f" {m:26s} zh {nz}/{tz} = {nz / max(1, tz):.0%} · en {ne}/{te} = {ne / max(1, te):.0%}") def battery_canon() -> None: h("Ф2 (г) БАТАРЕЯ И ПОКРЫТИЕ КАНОНА (zh, детерминированно, шума нет)") zh, cards = M.units_zh(), B.load_cards() print(f" {'арм':32s}{'ед.':>5s}{'ханьцзы':>9s}{'типогр':>8s}{'потеря':>8s}" f"{'канон':>14s}{'покрытие':>10s}") for m in P2.tenants(): for kind in ("D", "E"): rows, k, s = [], 0, 0 for u in zh: t = P2.draft_text(m, u["uid"]) if kind == "D" else P2.edit_text(m, u["uid"]) if not t.strip(): continue rows.append(B.run_unit(B.Unit(source=u["source"], draft=t, final=t, cards=cards))) kk, ss = BANK.coverage(u["source"], t) k += kk s += ss if rows: print(f" {kind + '[' + m + ']':32s}{len(rows):5d}" f"{sum(r['cjk_leak']['han_chars'] for r in rows):9d}" f"{sum(r['typography']['violations'] for r in rows):8d}" f"{sum(r['numbers']['lost_n'] for r in rows):8d}" f"{f'{k}/{s}':>14s}{(k / s if s else 0):>10.3f}") def battery_canon_f3() -> None: """Та же батарея по армам Ф3. Прежде §6.2 отчёта считалась ВНЕ дерева: шапка обещала, что пере-считывается каждое число, а таблица Ф3 под пере-счёт не попадала — клейм был шире гейта.""" h("Ф3 БАТАРЕЯ И ПОКРЫТИЕ КАНОНА ПО АРМАМ РЕДАКТОРОВ (детерминированно, шума нет)") import editors as ED # noqa: PLC0415 zh, cards = M.units_zh(), B.load_cards() print(f" {'арм':30s}{'ед.':>5s}{'ханьцзы':>9s}{'типогр':>8s}{'потеря':>8s}" f"{'канон':>14s}{'покрытие':>10s}{'$/ед':>10s}") pan = ED.panel() for i, model in enumerate(pan): arm = f"R{i}" rows, k, s, costs = [], 0, 0, [] for u in zh: t = ED.text_of(arm, u["uid"]) if not t.strip(): continue rows.append(B.run_unit(B.Unit(source=u["source"], draft=t, final=t, cards=cards))) kk, ss = BANK.coverage(u["source"], t) k += kk s += ss f = OUT / f"{ED.tag(model, u['uid'])}.json" if f.exists(): costs.append(json.loads(f.read_text(encoding="utf-8")).get("cost_usd", 0.0)) if rows: print(f" {arm + ' ' + model:30s}{len(rows):5d}" f"{sum(r['cjk_leak']['han_chars'] for r in rows):9d}" f"{sum(r['typography']['violations'] for r in rows):8d}" f"{sum(r['numbers']['lost_n'] for r in rows):8d}" f"{f'{k}/{s}':>14s}{(k / s if s else 0):>10.3f}" f"{(st.median(costs) if costs else 0):10.5f}") print(" ⚠ Клетки с ПУСТЫМ содержимым в счёт не идут — именно поэтому у части армов ед. < 16;") print(" оплаченные пустые клетки перечислены в блоке ДЕНЬГИ.") def _p95(xs: list[float]) -> float: """p95 по ЕДИНИЦАМ, ближайший ранг. При n=16 это 16-я по возрастанию, то есть максимум: честнее так и сказать, чем интерполяцией изображать точность, которой при таком n нет.""" if not xs: return 0.0 s = sorted(xs) return s[min(len(s) - 1, math.ceil(0.95 * len(s)) - 1)] def economics() -> None: h("Ф2 (д) ЦЕНА/ЕДИНИЦА И ПРОЕКЦИЯ НА КНИГУ (1500 единиц) — p50 И p95, как заказано промтом") zh = M.units_zh() print(f" {'жилец':26s}{'связка p50':>11s}{'связка p95':>11s}" f"{'книга p50':>11s}{'книга p95':>11s}") for m in P2.tenants(): dc = [P2.draft_cost(m, u["uid"]) for u in zh] ec = [] for u in zh: f = OUT / f"{P2.tag_edit(m, u['uid'])}.json" if f.exists(): ec.append(json.loads(f.read_text(encoding="utf-8")).get("cost_usd", 0.0)) if not dc: continue # p50/p95 берутся от СВЯЗКИ по единице, а не складываются из отдельных квантилей ролей: # сумма p95 двух ролей — не p95 суммы, и завышала бы хвост. pair = [d + e for d, e in zip(dc, ec, strict=False)] if ec else dc print(f" {m:26s}{st.median(pair):11.5f}{_p95(pair):11.5f}" f"{st.median(pair) * 1500:11.2f}{_p95(pair) * 1500:11.2f}") print(" ⚠ DeepSeek объявил на прайс-странице 08.08 повышение цен — проекция едет с оговоркой") def drafts_as_text() -> None: h("Ф2 (а) ЧЕРНОВИК КАК ТЕКСТ — ОПИСАТЕЛЬНАЯ ОСЬ ЗАКАЗА (поправки не несёт, вердиктов не даёт)") import statistics as sst # noqa: PLC0415 for pass_ in ("p2zh", "p2en"): JU.setup(pass_) import absjudge as AJ # noqa: PLC0415 if not AJ._by_unit(): # noqa: SLF001 continue fl = {"p2zh": 2.03, "p2en": None}[pass_] print(f" --- {pass_} --- порог различимости " f"{('%.2f' % fl) if fl else 'своего пола нет (пол Ф2 снят на zh)'}") for a, bb, _w in JU.family_desc(pass_): m = AJ._margins(a, bb) # noqa: SLF001 if not m: continue mean = sst.mean(m) mark = ("ниже порога различимости" if fl and abs(mean) < fl else "выше порога" if fl else "") print(f" {a} vs {bb} n={len(m):2d} {mean:+6.2f} {mark}") print(" ⚠ Знак ПОЛОЖИТЕЛЬНЫЙ = черновик жильца лучше якорного. Ось описательная: пре-рег Ф2") print(" сузил решающее семейство до финалов, поэтому Холм по ней НЕ считается.") def positional() -> None: h("ПОЗИЦИОННЫЙ НАКЛОН — ЗАМЕРЕН И ВЫЧТЕН (требование ЗАКОНа промта)") for pass_ in ("p2zh", "p2en", "p3", "dva"): JU.setup(pass_) import absjudge as AJ # noqa: PLC0415 if not AJ._by_unit(): # noqa: SLF001 continue print(f" --- {pass_} ---") AJ.position() print() def judged(pass_: str) -> None: h(f"СУДЕЙСТВО, проход {pass_}") JU.setup(pass_) import absjudge as AJ # noqa: PLC0415 data = AJ._by_unit() # noqa: SLF001 if not data: print(" голосов нет") return AJ.controls() print() AJ.score() def money_two_ways() -> None: h("ДЕНЬГИ — ДВА НЕЗАВИСИМЫХ ПУТИ") led = {ph: MONEY.Guarded(ph).spent() for ph in ("Ф0", "Ф1", "Ф2", "Ф3")} # второй путь: пере-счёт из сырых usage × прайс, правило биллинга выписано заново def indep(rec: dict) -> float: m = rec.get("model") if m not in R.CANDIDATES: return rec.get("cost_usd", 0.0) _, _, pin, pc, pout, _t, _s = R.CANDIDATES[m] pt, cd = rec.get("prompt_tokens", 0), rec.get("cached_tokens", 0) ct, rt = rec.get("completion_tokens", 0), rec.get("reasoning_tokens", 0) tt = rec.get("total_tokens", 0) mode = R.REASONING_BILLING.get(m) out = ct + rt if mode == "additive" else ( max(tt - pt, ct + rt) if mode == "additive_total" else ct) return (pt - cd) / 1e6 * pin + cd / 1e6 * pc + out / 1e6 * pout tot2 = {ph: 0.0 for ph in led} empty_paid = [] 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_paid.append((f.name, r["cost_usd"])) print(f" {'фаза':6s}{'касса':>12s}{'пере-счёт':>12s}{'расхождение':>13s}{'потолок':>10s}") for ph in ("Ф0", "Ф1", "Ф2", "Ф3"): 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_paid: print(f" оплачено за ПУСТОЙ выход: {len(empty_paid)} вызовов " f"${sum(c for _n, c in empty_paid):.5f}") tot_empty = sum(c for _n, c in empty_paid) print(f" доля пака: {tot_empty / sum(led.values()) * 100:.1f}% " f"(${tot_empty:.5f} из ${sum(led.values()):.6f})") for n, c in sorted(empty_paid, key=lambda x: -x[1]): print(f" {n} ${c:.5f}") def agent_runs() -> None: h("АГЕНТ-ЗАПУСКИ") rs = JU.runs_used() print(f" израсходовано {len(rs)} из {JU.CAP}") by: dict[str, int] = {} for r in rs: by[r["pass_"]] = by.get(r["pass_"], 0) + 1 for p, n in sorted(by.items()): print(f" {p:6s} {n}") def main() -> None: print("ИТОГ ЭКСП-22 — ВСЕ НЕСУЩИЕ ЧИСЛА, ПЕРЕ-СНЯТЫЕ ИЗ СЫРЬЯ ($0)") material() contamination() screen() echo_rate() battery_canon() battery_canon_f3() economics() drafts_as_text() for p in ("p2zh", "p2en", "p3", "dva"): 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()