books/gu-zhenren/research15-probes/probe_voice.py

101 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Проба P1/P2: voice-exemplars A/B/C/D + реестр ты/вы пар. Индикатив (малый N).
Дизайн по итогам веб-ресёрча research/15:
- C-арм: экземпляры как скрипт-строки «Имя: реплика» (приближение к RoleLLM
dialogue-turns в рамках одного system-блока), 3-4 реплики на спикера, отбор
по разнообразию, НЕ по similarity (Enron-находка).
- D-арм: гибрид «voice sheet» (1 строка регистра) + 2-3 экземпляра (STYLL-паттерн).
- R-арм (P2): только реестр обращений пар (ты/вы) без экземпляров.
Инъекция аппроксимируется добавочным блоком в КОНЦЕ system (боевой слот — отдельное
system-сообщение после кэш-границы; call_provider двухсообщенчатый — честная оговорка).
"""
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import probe_runner as pr
SCRATCH = Path(__file__).resolve().parent
BASE_SYSTEM = """Ты — профессиональный литературный переводчик с китайского языка на русский.
Жанр книги: сянься (уся-фэнтези о культивации). Аудитория: взрослые читатели вебновелл. Книга: «Гу Чжэньжэнь» (蛊真人).
Правила перевода (translation brief):
- Транскрипция имён и реалий: система Палладия.
- Переводи ВСЕ предложения исходника: ничего не пропускай, не сокращай и не добавляй от себя.
- Сохраняй разбивку на абзацы и прямую речь как в оригинале.
- Пиши живым литературным русским языком; избегай канцелярита и калек с китайского.
Выведи ТОЛЬКО перевод, без комментариев, пояснений и заголовков."""
GLOSS = """
ГЛОССАРИЙ (используй эти утверждённые переводы имён последовательно):
方源 → Фан Юань
方正 → Фан Чжэн
沈翠 → Шэнь Цуй
古月 → Гу Юэ
舅母 → тётушка (жена дяди)
舅父 → дядюшка (брат матери)
元石 → камень стихий
蛊 → гу
月光蛊 → гу лунного света"""
DESCRIPTORS = """
ГОЛОСА ПЕРСОНАЖЕЙ (передавай речь каждого в его манере, различимо):
- Фан Юань — ледяной, властный; короткие рубленые фразы; к слугам и младшему брату на «ты», повелительно; ирония холодная, без эмоций.
- Шэнь Цуй — заискивающая молодая служанка; слащавая, кокетливая, самоуничижительная речь («ваша служанка»); к хозяину — «молодой господин», строго на «вы».
- Фан Чжэн — наивный, вспыльчивый подросток; многословный, эмоциональный, обидчивый; к брату на «ты».
- Тётушка — приторно-ласковая, лицемерно-заботливая; к племянникам сверху вниз, ласково, на «ты».
- Дядюшка — снисходительно-важный, ворчливый; к племянникам на «ты»."""
EXEMPLARS = """
ОБРАЗЦЫ РЕЧИ ПЕРСОНАЖЕЙ (канонические реплики из утверждённого перевода ранних глав; держи голос каждого персонажа в этой манере):
{exemplars}"""
REGISTER_PAIRS = """
РЕЕСТР ОБРАЩЕНИЙ (строго соблюдай форму обращения в каждой паре говорящий → адресат):
- Шэнь Цуй → Фан Юань: на «вы», «молодой господин» (служанка к хозяину)
- Фан Юань → Шэнь Цуй: на «ты», повелительно (хозяин к служанке)
- Фан Юань → Фан Чжэн: на «ты» (старший брат к младшему)
- Фан Чжэн → Фан Юань: на «ты», «брат» (младший к старшему; семья, не «вы»)
- Тётушка/дядюшка → племянники: на «ты»
- Фан Чжэн → тётушка/дядюшка: на «вы», почтительно"""
TEST_CHUNKS = {
"T1": (SCRATCH / "chunk-T1-shencui-test.txt").read_text(),
"T2": (SCRATCH / "chunk-T2-brothers-test.txt").read_text(),
}
def translate(tag: str, injection: str, chunk: str):
system = BASE_SYSTEM + GLOSS + injection
user = "Переведи следующий фрагмент:\n\n" + chunk
text, err, usage = pr.call("deepseek", system, user, tag)
return text
def main():
exemplars = (SCRATCH / "exemplar-pool.txt").read_text()
arms = {
"A": "", # база: только глоссарий
"B": DESCRIPTORS, # дескрипторы
"C": EXEMPLARS.format(exemplars=exemplars), # экземпляры
"D": (SCRATCH / "voice-sheet-hybrid.txt").read_text(),# гибрид
"R": REGISTER_PAIRS, # P2: только реестр пар
}
only = sys.argv[1:] or list(arms)
for chunk_id, chunk in TEST_CHUNKS.items():
for arm, inj in arms.items():
if arm not in only:
continue
tag = f"p1-{chunk_id}-{arm}"
if (pr.RAW / f"{tag}.json").exists():
print(f"[skip] {tag} exists", file=sys.stderr)
continue
translate(tag, inj, chunk)
if __name__ == "__main__":
main()