BOOK-LIBRARY: LLM-переводы книг

LLM-переводы в BOOK-LIBRARY нужны не ради красивой кнопки «перевести книгу», а ради более практичной цели: сделать текст доступным читателю, не превращая перевод в непрозрачный чёрный ящик. Если книга есть только на одном языке, хочется быстро получить рабочую версию на другом. Но книга — это не короткая заметка: в ней есть главы, сноски, повторы терминов, авторский ритм и места, где автоматике нельзя доверять вслепую.

Поэтому переводы в BOOK-LIBRARY сделаны как pipeline, а не как один большой prompt. Книгу нельзя нормально отправить модели целиком, получить файл обратно и считать задачу закрытой. Нужны подготовка текста, деление на сегменты, устойчивое выполнение, проверка качества, сборка artifacts и ручное решение о публикации.

Переводы вынесены в отдельный рабочий контур рядом с импортом, но не смешаны с ним. Импорт добавляет книгу в каталог. Translation pipeline готовит перевод, который может остаться черновиком или стать опубликованным EPUB/PDF для читателя. Так сохраняется важная граница: LLM помогает получить полезный перевод, но исходный текст, проверка и решение о публикации остаются отдельными частями процесса.

Почему не один prompt

На коротком тексте один prompt может выглядеть убедительно. С книгой всё иначе: ошибка не всегда заметна сразу, а потерянный термин или переставленная сноска портят не один абзац, а впечатление от всего чтения. У книги есть несколько проблем, которые плохо решаются одной LLM-командой:

  • текст может быть слишком большим для context window;
  • главы и сноски нужно сохранить в правильном порядке;
  • ошибки одного фрагмента не должны ломать весь перевод;
  • разные модели могут вести себя по-разному на длинных текстах;
  • результат нужно проверить до публикации;
  • стоимость и повторы должны быть управляемыми.

Pipeline делает процесс менее эффектным, зато более надёжным. Вместо «переведи всё» появляется набор этапов, каждый из которых можно показать в админке, повторить или остановить. Для читателя это означает не магическое обещание идеального текста, а более честный путь к версии, которую хотя бы можно проверить перед публикацией.

Durable translation jobs

Перевод запускается как durable job. Backend сохраняет задачу в SQLite, обновляет её состояние и даёт React-админке читать прогресс через polling. Это тот же принцип, что и у долгого импорта: вкладка может обновиться, но задача не должна исчезнуть.

У translation job есть понятное состояние: queued, running, failed, cancelled или completed. Отдельные этапы могут фиксировать свои ошибки. Если provider упал или сегмент не перевёлся, администратор должен увидеть проблему, а не получить общий ответ «что-то пошло не так».

Общая цепочка

Типовая цепочка перевода выглядит так:

  1. Ingestion — система берёт исходную книгу и готовит её к обработке.
  2. Canonical document — текст приводится к внутреннему представлению, с которым дальше работает pipeline.
  3. Segmentation — документ делится на управляемые сегменты.
  4. LLM batch translation — сегменты переводятся пакетами через выбранного провайдера.
  5. QA — система собирает findings: пропуски, подозрительные места, ошибки или несоответствия.
  6. Assembly — переведённые сегменты собираются обратно в документ.
  7. Review — администратор проверяет результат и спорные места.
  8. Publish — готовые EPUB/PDF artifacts становятся видимыми публичной витрине.

Эта схема не обещает идеальный перевод без человека. Наоборот, она признаёт, что ручная проверка нужна, и создаёт для неё место. Перевод здесь не подменяет исходник и не объявляется финальным только потому, что его вернула модель: сначала он становится кандидатом, потом проходит проверку, и только после этого может попасть в публичную витрину.

Провайдеры и fallback

LLM providers хранятся в SQLite как runtime-сущности. Их можно настраивать из админки: включать, выключать, менять priority и использовать fallback. Это не абстрактная гибкость «на будущее», а нормальная страховка для длинной работы: LLM-интеграции зависят от лимитов, стоимости, доступности и качества конкретной модели.

Если один provider временно недоступен, pipeline может переключиться на другой. Если для части задач нужен более дешёвый или более стабильный endpoint, это тоже лучше решать настройкой, а не правкой кода.

При этом provider не становится источником истины. Он выполняет этап перевода, а качество результата проверяется отдельно.

Сегменты и ручная проверка

Сегментация нужна не только из-за технических лимитов. Она делает перевод проверяемым и менее пугающим. Если один фрагмент выглядит плохо, можно посмотреть именно его, сравнить с исходником и повторить работу над конкретным местом, а не искать ошибку в огромном файле.

В админке важны такие действия:

  • открыть список сегментов;
  • увидеть статус каждого сегмента;
  • посмотреть исходный и переведённый текст;
  • повторить перевод отдельного сегмента;
  • отметить проблемное место;
  • вернуться к QA findings после правки.

Это особенно важно для книг с терминами, именами, диалогами и длинными главами. LLM может дать гладкий текст, но потерять смысл в деталях: сгладить интонацию, перепутать устойчивый термин или пропустить важную связку между фрагментами. Поэтому review — обязательная часть pipeline, а не необязательный бонус.

QA findings

QA findings помогают не читать весь результат вслепую. Система может подсветить подозрительные места: пропущенный сегмент, слишком короткий перевод, странное расхождение, ошибку provider или технический сбой сборки.

Такие findings не заменяют редактора. Их задача скромнее и полезнее: показать, куда смотреть в первую очередь. Для частной библиотеки этого достаточно, чтобы не публиковать совсем сырой результат и не заставлять читателя первым находить технические ошибки.

Retry и cancel

У длинной задачи обязательно должны быть retry и cancel. Без этого любой сбой превращается в ручную чистку базы или полный перезапуск книги.

Retry полезен, когда:

  • упал один provider;
  • сегмент не прошёл проверку;
  • запрос оборвался по лимиту;
  • нужно повторить только неудачную часть.

Cancel нужен, если администратор понял, что выбрал не ту книгу, не тот язык, неподходящего provider или слишком дорогой сценарий. Отмена должна быть нормальным состоянием задачи, а не аварией.

Artifacts: EPUB и PDF

Результат pipeline — не просто текст в базе. Читателю нужен привычный файл, который можно открыть и читать, поэтому система собирает output artifacts, прежде всего EPUB и PDF. Именно artifacts потом могут быть опубликованы для читателя.

Важно разделять «artifact собран» и «artifact опубликован». Сборка файла означает, что технический результат появился. Публикация означает, что администратор проверил его достаточно, чтобы показать в публичной витрине. Эта пауза между сборкой и публикацией защищает проект от соблазна выдавать любой сгенерированный файл за готовую книгу.

Публично видны только published translations. Черновики, неудачные сборки, спорные версии и внутренние проверки остаются в админке.

Deferred scope

У переводческого направления есть честно отложенные части:

  • OCR для сканов и сложных PDF;
  • production PDF renderer;
  • извлечение медиа из DOCX/PDF;
  • translation memory;
  • budget dashboards;
  • более глубокое сравнение версий перевода;
  • удобная редактура больших книг внутри админки.

Это не мелкие украшения. Каждая такая задача может стать отдельным слоем продукта. Поэтому лучше держать их как deferred scope, а не притворяться, что текущий pipeline уже закрывает все случаи.

Почему это отдельная статья

LLM-переводы легко описать слишком громко: будто модель сама превращает любую книгу в готовое издание. В BOOK-LIBRARY подход спокойнее и честнее. Модель — часть процесса, но вокруг неё нужны очередь, сегменты, QA, retry, artifacts и публикация.

Именно поэтому этому направлению нужна отдельная заметка. Здесь важна не сама возможность вызвать LLM, а способ встроить её в библиотеку так, чтобы перевод был полезен читателю и при этом оставался проверяемым. Такой pipeline сложнее, чем одна кнопка, зато он ближе к реальной эксплуатации: администратор видит, что происходит, может вмешаться и решает, когда перевод действительно можно показать читателю.

Связанные заметки