diff --git a/eval/dovodka/d7_self.py b/eval/dovodka/d7_self.py new file mode 100644 index 00000000..63a72516 --- /dev/null +++ b/eval/dovodka/d7_self.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +"""Д7 — МИКРО-ПРОБА САМООЦЕНКИ ЖИЛЬЦОВ (идея владельца). Платный, ≤$0.05. + +⚠ РЕШЕНИЙ НЕ НЕСЁТ, и это записано ДО покупки. Заказ формулирует прямо: «печатается как +любопытство с оговоркой „самооценка моделей ненадёжна“; никакие решения на ней не стоят». +Ценность в СВЕРКЕ: модель говорит, что ей будет трудно, а фаза уже знает, что вышло на самом +деле — и расхождение между предсказанием модели о себе и фактом само по себе любопытно. + +Спрашиваются ОБА жильца обеих ролей по ТРЁМ книгам фазы. Вопрос один и тот же, чтобы ответы +сравнивались между парами: «сможешь ли перевести эту книгу на издательском уровне; что будет +трудным?» Отрывок даётся настоящий — из тех же приколотых единиц, что покупала фаза. + +Запуск: d7_self.py --dry | --run | --show | --selftest +""" +from __future__ import annotations + +import importlib.util +import json +import sys +from pathlib import Path + +REPO = Path("/home/ubuntu/projects/textmachine") +ZONE = Path(__file__).resolve().parent +for d in ("dovodka", "editor_tier", "tenant_panel", "role_topology", "bank_arbitration"): + sys.path.insert(0, str(REPO / "eval" / d)) + + +def _load(name: str, path: Path): + 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 + + +C = _load("contour_d7", ZONE / "contour.py") +PE = _load("pair_en_d7", REPO / "eval" / "role_topology" / "pair_en.py") +MJ = _load("mat_ja_d7", ZONE / "material_ja.py") +MONEY, ROSTER, ED22 = C.MONEY, C.ROSTER, C.ED22 + +RESIDENTS = ("deepseek-v4-flash", "deepseek-v4-pro") +PHASE, PFX = "ФД-D", "dv-d" +MAX_OUT = 8000 + +SYS = ("Ты — переводчик художественной литературы. Тебе дают отрывок книги. Ответь ЧЕСТНО и " + "коротко, двумя абзацами:\n" + "1) Сможешь ли ты перевести ЭТУ книгу на русский на ИЗДАТЕЛЬСКОМ уровне (так, чтобы " + "текст читался как написанный по-русски, а не переведённый)? Ответь прямо: да, нет или " + "с оговорками — и какими.\n" + "2) Что в ЭТОЙ книге будет для тебя самым трудным? Назови конкретные места и явления, " + "а не общие слова про «культурные различия».") + + +def books() -> dict[str, tuple[str, str]]: + """{ключ: (язык, отрывок)} — из ПРИКОЛОТЫХ единиц фазы, а не из случайного места книги.""" + zh = C.units_ok()[0]["source"] + en = PE.units(8)[0]["source"] + ja = MJ.units()[0]["source"] + return {"zh": ("китайская вебновелла", zh), "en": ("английское тёмное фэнтези", en), + "ja": ("японская веб-новелла", ja)} + + +def tag(res: str, book: str) -> str: + return f"{PFX}-self-{res.replace('.', '')}-{book}" + + +def text_of(res: str, book: str) -> str: + f = MONEY.OUT / f"{tag(res, book)}.json" + if not f.exists(): + return "" + return json.loads(f.read_text(encoding="utf-8")).get("content") or "" + + +def cmd_run() -> None: + led = MONEY.Guarded(PHASE, default_expect=0.004) + for res in RESIDENTS: + for book, (what, src) in books().items(): + tg = tag(res, book) + if text_of(res, book).strip(): + continue + msgs = [{"role": "system", "content": SYS}, + {"role": "user", "content": f"Книга: {what}.\n\nОтрывок:\n{src[:2500]}"}] + rec = MONEY.purchase(led, tg, res, ED22.client(res), + ROSTER.call_kwargs(res, msgs, max_out=MAX_OUT), + role="selfassess", book=book, arm="SELF") + if rec.get("skipped"): + raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП") + MONEY.report() + + +def cmd_show() -> None: + print("Д7 — САМООЦЕНКА ЖИЛЬЦОВ\n") + print("⚠ САМООЦЕНКА МОДЕЛЕЙ НЕНАДЁЖНА. Печатается как любопытство; никакие решения фазы на " + "этих ответах НЕ стоят — так объявлено ДО покупки.\n") + fact = {"zh": "факт фазы: связка 4.00 ошибок/ед., черновик хуже", + "en": "факт фазы: черновик 2.78 → связка 1.22 ошибок/ед.", + "ja": "факт фазы: черновик 5.44 → связка 2.22 ошибок/ед. (ХУДШИЙ черновик фазы)"} + for res in RESIDENTS: + for book in books(): + t = text_of(res, book) + if not t.strip(): + continue + print(f"### {res} · {book} — {fact[book]}") + print(" " + t.strip().replace("\n", "\n ")[:900] + "\n") + + +def cmd_dry() -> None: + have = sum(1 for r in RESIDENTS for b in books() if text_of(r, b).strip()) + n = len(RESIDENTS) * len(books()) + sp = MONEY.Guarded(PHASE).spent() + print(f"Д7 · клеток {have}/{n} · жильцы {' · '.join(RESIDENTS)} · книги zh/en/ja") + print(f" {PHASE}: потрачено ${sp:.4f} · потолок ${MONEY.CEILINGS[PHASE]:.2f} · " + f"смета ${(n - have) * 0.004:.4f}") + + +def cmd_selftest() -> int: + bad = 0 + + def ck(n: str, ok: bool, d: str = "") -> None: + nonlocal bad + bad += not ok + print(f"[{'OK ' if ok else 'ПРОВАЛ'}] {n}" + (f" {d}" if d else "")) + + bk = books() + ck("три книги фазы", len(bk) == 3, " ".join(bk)) + ck("отрывки — из приколотых единиц, непустые", + all(len(v[1]) > 500 for v in bk.values())) + ck("тег покрыт глобом кассы ФД-D", tag("m", "zh").startswith("dv-d-")) + ck("вопрос НЕ подсказывает ответ (нет слов «трудно»/«не сможешь» в постановке)", + "не сможешь" not in SYS) + # Оговорка обязана быть в САМОЙ печати, а не в моей памяти: иначе при чтении отчёта + # «любопытство» незаметно превратится в довод. + src = Path(__file__).read_text(encoding="utf-8") + ck("оговорка о ненадёжности зашита в печать", "САМООЦЕНКА МОДЕЛЕЙ НЕНАДЁЖНА" in src) + print(f"\n{'Д7 ГОТОВ' if not bad else f'ПРОВАЛОВ: {bad}'}") + return bad + + +if __name__ == "__main__": + a = sys.argv[1] if len(sys.argv) > 1 else "--dry" + fn = {"--dry": cmd_dry, "--run": cmd_run, "--show": cmd_show, + "--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a) + fn() if fn else print(__doc__)