textmachine/eval/tenant_panel/itog22.py

213 lines
9.9 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
"""ПЕРЕ-СЧЁТ ВСЕХ НЕСУЩИХ ЧИСЕЛ ЭКСП-22 ИЗ СЫРЬЯ. $0.
Зачем. Эксп-21 сдал отчёт, несущие числа которого НЕ ИМЕЛИ пути воспроизведения в дереве: часть
бралась из stdout прогонов, утраченных инцидентом. Число, которое нельзя пере-снять командой из
репозитория, ничем не отличается от числа по памяти. Здесь каждый блок ИТОГа печатается заново из
персистированных артефактов, с провенансом — из какого прохода и по какой формуле.
Ничего не покупается и не судится: только счёт по тому, что уже лежит на диске.
Запуск: eval/.venv/bin/python eval/tenant_panel/itog22.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(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 economics() -> None:
h("Ф2 (д) ЦЕНА/ЕДИНИЦА И ПРОЕКЦИЯ НА КНИГУ (1500 единиц)")
zh = M.units_zh()
print(f" {'жилец':26s}{'черновик':>11s}{'редактор':>11s}{'связка':>11s}{'книга $':>10s}")
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
d50, e50 = st.median(dc), (st.median(ec) if ec else 0.0)
print(f" {m:26s}{d50:11.5f}{e50:11.5f}{d50 + e50:11.5f}{(d50 + e50) * 1500:10.2f}")
print(" ⚠ DeepSeek объявил на прайс-странице 08.08 повышение цен — проекция едет с оговоркой")
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}")
for n, c in sorted(empty_paid, key=lambda x: -x[1])[:5]:
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()
economics()
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}")
money_two_ways()
agent_runs()
print("\nВСЁ ВЫШЕ ПЕРЕ-СНЯТО ИЗ СЫРЬЯ. Чисел без пути воспроизведения в отчёте быть не должно.")
if __name__ == "__main__":
main()