213 lines
9.9 KiB
Python
213 lines
9.9 KiB
Python
#!/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()
|