72 lines
4.9 KiB
Python
72 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
||
"""exp12 — «кандидат-фикс» (пост-фидбек владельца, ВНЕ слепого бейк-оффа).
|
||
|
||
Демонстрация направления фикса на 3 тех же главах: glm-5 БИЛИНГВ (судейский #1, не течёт
|
||
преамбулой как gemini) + разрешение переверстать абзацы + жанр-конвенции (культивация,
|
||
секты/школы, земной поклон). Спорные термины (人祖, 花酒行者) НЕ хардкожу — оставляю модели
|
||
с исходником + пометкой «на утверждение глоссария». НЕ арм пре-регистрации.
|
||
|
||
Выход: diag/arms/CAND/<ch>_<ci>.txt
|
||
"""
|
||
from __future__ import annotations
|
||
import json, os, sys, urllib.request
|
||
from pathlib import Path
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
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()
|