#!/usr/bin/env python3 """exp12 — «кандидат-фикс» (пост-фидбек владельца, ВНЕ слепого бейк-оффа). Демонстрация направления фикса на 3 тех же главах: glm-5 БИЛИНГВ (судейский #1, не течёт преамбулой как gemini) + разрешение переверстать абзацы + жанр-конвенции (культивация, секты/школы, земной поклон). Спорные термины (人祖, 花酒行者) НЕ хардкожу — оставляю модели с исходником + пометкой «на утверждение глоссария». НЕ арм пре-регистрации. Выход: diag/arms/CAND/_.txt """ from __future__ import annotations import json, os, sys, urllib.request from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) # script now under eval/expNN/ — reach up to parent eval/ for the refusal_bench oracle from refusal_bench import load_env_file load_env_file() DIAG = Path("/home/ubuntu/books/gu-zhenren/diag") OUT = DIAG / "arms" / "CAND" chunks = json.loads((DIAG / "chunks.json").read_text(encoding="utf-8")) blocks = json.loads((DIAG / "blocks.json").read_text(encoding="utf-8")) SYS = ( "Ты — литературный редактор художественного перевода китайской вебновеллы-культиваторки " "(сянься/уся) на русский. Тебе дан ИСХОДНИК (китайский) и его ЧЕРНОВОЙ перевод. Сделай из " "черновика ЖИВУЮ, читаемую русскую прозу издательского уровня:\n" "1. АБЗАЦЫ: собирай предложения в логические ЕВРОПЕЙСКИЕ абзацы. Китайская манера " "«предложение = отдельная строка» для русской прозы деструктивна — группируй повествование " "по смыслу. Реплики прямой речи — отдельными строками с тире.\n" "2. СМЫСЛ И СЮЖЕТ: сверяйся с ИСХОДНИКОМ, следи за тем, ЧТО происходит по сюжету, и правь так, " "чтобы читатель понимал сцену. Исправляй искажения и машинные кальки черновика; сохраняй полноту.\n" "3. ЖАНР-КОНВЕНЦИИ русского фан-перевода культиваторок: 修炼 = «культивация» (не «совершенствование»); " "门派/派 = «секты»/«школы» (не «фракции»); 磕头 = «земной поклон»/«коснулся лбом пола» (не «ударил головой»); " "меры времени (时辰≈2 часа) переводи или глоссируй. Прочую терминологию имён/титулов держи " "последовательно (в приложенном глоссарии, если есть).\n" "4. Убери канцелярит и кальки, оживи синтаксис и ритм (школа Норы Галь). Не пересочиняй сцены, " "не добавляй отсебятины.\n" "Выведи ТОЛЬКО отредактированный русский текст, без преамбул, комментариев и пояснений." ) SPEC = dict(model="glm-5", base="https://api.z.ai/api/paas/v4", keyenv="ZAI_API_KEY", extra={"thinking": {"type": "disabled"}}, max_tokens=8000) def call(msgs): key = os.environ.get(SPEC["keyenv"], "") body = {"model": SPEC["model"], "temperature": 0.5, "max_tokens": SPEC["max_tokens"], "messages": msgs, **SPEC["extra"]} req = urllib.request.Request(SPEC["base"].rstrip("/") + "/chat/completions", data=json.dumps(body).encode(), headers={"Content-Type": "application/json", "Authorization": f"Bearer {key}"}) with urllib.request.urlopen(req, timeout=300) as r: return json.loads(r.read())["choices"][0]["message"]["content"].strip() def main(): OUT.mkdir(parents=True, exist_ok=True) for ch, ci in [(5, 0), (5, 1), (7, 0), (7, 1), (14, 0), (14, 1)]: key = f"{ch}/{ci}" src, draft, gl = chunks[key]["source"], chunks[key]["draft"], blocks[key]["bilingual_glossary"] msgs = [{"role": "system", "content": SYS}] if gl.strip(): msgs.append({"role": "system", "content": gl}) msgs.append({"role": "user", "content": f"ИСХОДНИК (zh):\n\n{src}\n\n---\n\nЧерновик для редактуры:\n\n{draft}"}) out = call(msgs) (OUT / f"{ch}_{ci}.txt").write_text(out, encoding="utf-8") print(f" CAND {key}: {len(out)} ch") if __name__ == "__main__": main()