#!/usr/bin/env python3 """exp14 — рендер промптов армов (ЗАМОРОЖЕНЫ; sha256 в §2 дока). - baseline editor = backend/prompts/editor.md (v2-bilingual-reflow), brief-filled. - discourse editor = baseline + дискурс-reflow ядро (§1.2: 5 техник Ван Цуй + Розенталь) + few-shot. - translator (для re-draft глав/нарезки) = backend/prompts/translator.md (v1-reflow). Few-shot — минимальные ортогональные (narrative N:1, dialogue 1:N, focal-shift). НЕ ручной CoT. """ from __future__ import annotations import hashlib from pathlib import Path PROMPTS = Path("/home/ubuntu/projects/textmachine/backend/prompts") BRIEF = dict(source_lang="zh", target_lang="ru", genre="вебновелла", audience="взрослые читатели вебновелл", title="蛊真人", honorifics="keep", transcription="palladius", venuti="0.6", footnotes="minimal") def _fill(t: str) -> str: for k, v in BRIEF.items(): t = t.replace("{{" + k + "}}", v) return t def _split(md_text: str) -> tuple[str, str]: sysmd, usermd = md_text.split("---USER---", 1) return _fill(sysmd).strip(), _fill(usermd).strip() # ── Дискурс-reflow ядро (§1.2; арм для ЗАМЕРА, не «оптимальный промпт») ────────────── DISCOURSE_CORE = """ ДИСКУРС-ПЕРЕВЁРСТКА (обязательная операция передачи китайского паратаксиса в русскую гипотактическую прозу — это КОНВЕНЦИЯ русского языка, а не вольность): 1. Молча определи смысловые ходы фрагмента: единый фокал/наблюдатель; действие и его непосредственная реакция; одна тема рассуждения; границы — смена говорящего, времени, места или фокала. 2. Один повествовательный ход оформляй ОДНИМ русским абзацем, ДАЖЕ если китайский исходник разбит на однофразовые строки. Инструмент слияния — причастные и деепричастные обороты, подчинительные союзы и связки (построй иерархию, сегментируй по смыслу, промаркируй вид/время предикатов, варьируй лексику, добавляй связки). Не сливай ТОЛЬКО ради длины и не теряй смысловые атомы. 3. Каждую новую реплику начинай с нового абзаца через тире «—»; слова автора при той же реплике оставляй в её абзаце. 4. Разрешено объединять и делить русские предложения; число предложений и абзацев совпадать с исходником НЕ обязано. Запрещено терять смысловые атомы (участников, действия, числа, полярность, заголовки). """ FEWSHOT = """ Примеры требуемой ПЕРЕВЁРСТКИ (показана структура вывода, не стиль): [narrative N:1] Исходник построчно — «Он вышел за дверь.» / «Небо было серым.» / «Он вздохнул.» / «Дорога уходила вдаль.» — становится ОДНИМ абзацем: Он вышел за дверь. Небо было серым; вздохнув, он смотрел, как дорога уходит вдаль. [dialogue 1:N] Исходник — «Дядя нахмурился и сказал: „Время летит. Садись.“ Племянник ответил: „Спасибо.“» — становится: Дядя нахмурился. — Время летит. Садись, — сказал он. — Спасибо, — ответил племянник. [focal-shift] При смене наблюдателя/места/времени — новый абзац, даже если в исходнике это продолжение той же строки. """ REFERENCE_NOTE = ("\n\nСПРАВОЧНЫЙ КОНТЕКСТ (соседние фрагменты — ТОЛЬКО для разрешения связей, " "местоимений и опущенных подлежащих; НЕ переводи и НЕ пересказывай его в выходе):") def editor_system(variant: str, few_shot: bool = True) -> str: sysmd, _ = _split((PROMPTS / "editor.md").read_text(encoding="utf-8")) if variant == "baseline": return sysmd if variant == "discourse": out = sysmd + "\n" + DISCOURSE_CORE if few_shot: out += FEWSHOT return out raise ValueError(variant) def editor_user(source: str, draft: str, reference: str = "") -> str: _, usermd = _split((PROMPTS / "editor.md").read_text(encoding="utf-8")) u = usermd.replace("{{text}}", source).replace("{{draft}}", draft) if reference.strip(): u += REFERENCE_NOTE + "\n" + reference.strip() return u def translator_system() -> str: sysmd, _ = _split((PROMPTS / "translator.md").read_text(encoding="utf-8")) return sysmd def translator_user(source: str) -> str: _, usermd = _split((PROMPTS / "translator.md").read_text(encoding="utf-8")) return usermd.replace("{{text}}", source) def sha_frozen() -> dict: return { "editor_baseline_sys": hashlib.sha256(editor_system("baseline").encode()).hexdigest()[:16], "editor_discourse_sys": hashlib.sha256(editor_system("discourse").encode()).hexdigest()[:16], "discourse_core": hashlib.sha256(DISCOURSE_CORE.encode()).hexdigest()[:16], "fewshot": hashlib.sha256(FEWSHOT.encode()).hexdigest()[:16], "translator_sys": hashlib.sha256(translator_system().encode()).hexdigest()[:16], } if __name__ == "__main__": import json print("=== frozen prompt sha256[:16] ===") print(json.dumps(sha_frozen(), indent=1, ensure_ascii=False)) print("\n=== editor discourse system (first 600) ===") print(editor_system("discourse")[:600])