Архитектура

Как устроены четыре конвейера перевода в InterMIND

В InterMIND нет «одного перевода». Есть четыре конвейера — голос, чат, заметки, документы — у каждого свой движок, бюджет задержки и предел качества. Это то, что на самом деле происходит между моментом, когда вы говорите, и моментом, когда участник на другом языке вас понимает.

The Mind.com Team

Как устроены четыре конвейера перевода в InterMIND

Как устроены четыре конвейера перевода в InterMIND

Старая страница /product/overview/how-it-works на mind.com отстала на несколько крупных релизов. Она описывает единый «движок перевода» так, как это делает большинство страниц вендоров — одна большая стрелка от «вы говорите» к «они слышат». Эта картинка была упрощением ещё два года назад. Сегодня она просто неверна.

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

Это обновлённый ответ на вопрос «как это работает».

Сопутствующий материал: «Сколько языков вы поддерживаете?» рассказывает, что каждый конвейер охватывает (24 / 22 / 30 / 12). Этот пост — о том, что каждый конвейер делает, и почему это отдельная вещь.


Почему «один движок на всё» — это ложь

В платформе для живых встреч одновременно нужно решать как минимум четыре задачи, и они тянут в несовместимые стороны:

  1. Голос в реальном времени — аудио на входе, переведённое аудио на выходе, меньше секунды, каждый зритель — на своём языке. Жёсткое ограничение — задержка.
  2. Текст чата в реальном времени — короткие сообщения, быстро, с правками, цитатами и сохранением HTML-структуры.
  3. Совместные заметки в реальном времени — посимвольный совместный ввод, со структурной иерархией (списки, заголовки, чекбоксы), которая должна пережить перевод.
  4. Асинхронные файлы документов — PDF на 40 страниц, скинутый в чат. Никакого бюджета задержки. Жёсткое ограничение — точность воспроизведения: форматирование, таблицы, номера страниц, шрифт.

Можно построить один гигантский вызов LLM, который пытается делать всё четыре. Мы пробовали. Получается плохо во всех четырёх случаях. Бюджет задержки для голоса означает, что модель не может думать; бюджет точности для документов означает, что должна. Для правки в чате нужен дифф на языке зрителя; для 40-страничного PDF нужно сохранение формата, которого ни одна потоковая по токенам модель не даёт.

Поэтому у нас их четыре. Вот каждый из них.


Конвейер 1: перевод голоса в реальном времени

Задача: один участник говорит по-французски. Другой подключился на немецком, третий — на бразильском португальском, четвёртый — на японском. Каждый должен слышать говорящего на своём языке, в своём ухе, с задержкой достаточно короткой, чтобы зрительный контакт оставался возможным.

Бюджет: меньше секунды от начала до конца. Всё, что больше ~1,2 секунды, и разговор ломается — люди начинают говорить поверх перевода, и встреча скатывается в «давайте просто перейдём на английский».

Как на самом деле движется звук

Конвейер перевода голоса: браузер говорящего выполняет ASR локально через Mind SDK, ws-сервер распределяет транскрипт по движку перевода через один WebSocket на каждый целевой язык, присутствующий в комнате, и каждый зритель получает свою собственную дорожку переведённого аудио.

Несколько вещей, которые стоит проговорить явно:

  • ASR работает в браузере говорящего, а не на центральном сервере. Мы используем Mind SDK локально; это экономит обращение к серверу и даёт нам транскрипт на исходном языке с минимально возможной задержкой ещё до того, как может начаться перевод.
  • Перевод — это не один fan-out. Мы держим пул WebSocket-соединений к нашему движку перевода, по одному на каждый целевой язык, присутствующий в комнате. Если трое участников выбрали немецкий — немецкий использует одно соединение. Если никто не выбрал арабский — соединение для арабского не открывается. Пул сбрасывает простаивающие соединения через пять минут. Именно поэтому встреча с четырьмя языками стоит столько же, сколько встреча с сорока, до момента, когда становится ясно, кто на самом деле пришёл — мы никогда не переводим на языки, которые никто не слушает.
  • Синтезированная речь — индивидуальная для каждого зрителя. Каждый участник получает свою дорожку переведённого аудио, наложенную на оригинальное видео говорящего. Они не смотрят общую «переведённую встречу» — они смотрят одну и ту же встречу, со своим персональным аудиоканалом, переведённым на выбранный ими язык. Именно поэтому два человека в одной физической комнате могут надеть наушники и слышать разные языки.

Почему это важно, когда встреча идёт не по плану

В часовом звонке с восемью языками вещи ломаются интересными способами: рвутся WebSocket-соединения, ASR временно неверно распознаёт имя собственное, у одного участника сеть начинает дёргаться. Архитектура выше — это то, что позволяет нам изолировать сбои: глюк аудио у одного зрителя не затрагивает остальных семерых, потому что движок перевода никогда не выдавал «один перевод» — он выдал восемь, параллельно, и восстанавливаться приходится только тому, у кого сбой.

Сам движок — наш, размещён на нашей собственной инфраструктуре. Мы не маршрутизируем голос в реальном времени через сторонние LLM общего назначения. Бюджет задержки их исключает; история с резидентностью данных исключает их для регулируемых клиентов, которым это действительно важно.

Что мы публикуем про качество голоса: /benchmark ежемесячно прогоняет продакшен-конвейер голоса на предложениях FLORES-200 для каждой опубликованной языковой пары. Судья назван (Gemini 2.5 Flash основной, Claude Sonnet 4 резервный). Полное распределение — медиана, p10, p90, минимум, максимум, размер выборки — на странице. См. методологию — что эти числа измеряют и не измеряют.


Конвейер 2: перевод чата в реальном времени

Задача: каждое сообщение в чате встречи переводится для каждого участника на его язык по мере отправки. Плюс правки — и правки должны выглядеть как правки, а не как новые переводы.

Бюджет: быстро, но не меньше секунды. Сообщение в чате может появиться на другом языке за полсекунды — и никого это не расстроит. Что людям важно — правильный ли перевод и осмысленно ли выглядят правки.

Что на самом деле делает конвейер чата

Каждое сообщение проходит через тот же движок перевода, который использует голосовой конвейер, — но с другой пред- и постобработкой:

  • HTML-структура сохраняется. Чат поддерживает форматированный текст (абзацы, списки, цитаты, жирный, курсив). Мы конвертируем в обычный текст для модели, переводим и затем оборачиваем результат обратно в исходные теги. Модель никогда не видит HTML — она видит чистую прозу.
  • Цитаты переводятся независимо. Если вы отвечаете на сообщение и цитируете его, блок [QUOTE]…[/QUOTE] и новый контент переводятся как отдельные единицы — чтобы модель не могла их перепутать.
  • Длинные сообщения разбиваются на куски. Мы делим по границам абзацев, по 1000 символов на кусок. Каждый кусок — отдельный вызов перевода. Мы не подаём модели романы по 4000 символов одним заходом — режимы отказа (обрезание, потеря абзацев, обрывы посреди предложения) слишком уродливы.
  • Перевод ленивый. Мы используем IntersectionObserver: сообщение переводится только когда оно прокручивается в зону видимости зрителя. Раньше переключение языка в долгоживущем канале запускало повторно все вызовы API перевода из истории. Теперь — нет.

Интересная часть: правки как диффы

В v1.2 мы изменили поведение правок чата для зрителей на других языках. Старое поведение: кто-то правит сообщение, мы перепереводим всё целиком, вы видите новый абзац и должны сами заметить, что изменилось.

Новое поведение:

  1. Исходное сообщение уже было переведено на ваш язык.
  2. Когда отправитель его правит, мы переводим новую версию.
  3. Мы считаем дифф между вашим предыдущим переводом и вашим новым переводом, на вашем языке.
  4. Мы показываем этот дифф прямо в строке — так же, как Git показывает, что изменилось.

Так что когда «review by Tuesday» становится «review by Thursday» по-английски, ваш коллега, читающий по-испански, видит подсвеченное martes → jueves, а не перепереведённый абзац, который надо перечитывать.

Для этого пришлось трактовать конвейер чата как stateful кеш на каждого зрителя, а не как stateless эндпоинт «переведи по запросу». Документам и голосу это не нужно. Чату — нужно.


Конвейер 3: перевод совместных заметок в реальном времени

Задача: ведущий открывает панель совместных заметок и начинает печатать. Каждый участник видит заметки на своём языке, посимвольно, со структурой документа — заголовки, вложенные списки, чек-листы, блоки кода — в неизменном виде.

Бюджет: как у чата (~полсекунды), но с двумя дополнительными ограничениями:

  • То, что переводится, меняется в процессе перевода. Ведущий всё ещё печатает. Наивная система, которая переводит «весь документ» на каждое нажатие клавиши, даёт мерцание и сжигает бюджет API. Мы переводим на гранулярности изменившейся единицы, а не всего документа.
  • Структура должна выжить. Если попросить модель перевода перевести markdown-блоб с тремя вложенными списками, вы получите что-то, что выглядит как оригинал, но с незаметно сплющенной иерархией, перенумерованными пунктами или съехавшими отступами. Мы не даём модели видеть весь блоб.

Чем конвейер заметок отличается от чата

Главное — сохранение структуры. Мы переводим каждый пункт списка независимо, а не как один документ. Модель видит:

«Проверка соответствия — поставки за второй квартал»

— а не:

"# Project plan\n## Quarter\n- Compliance review — Q2 deliverables\n- Vendor scoring\n - Tier 1 vendors..."

Обёртывающий документ — <ul>, заголовки, отступы — пересобирается на стороне клиента по той же структуре, что и оригинальный документ, с каждым листовым узлом, заменённым на свой перевод. Модель не получает шанса «улучшить» иерархию.

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


Конвейер 4: асинхронный перевод документов

Задача: кто-то скидывает в чат PDF на 40 страниц, документ Word, презентацию PowerPoint или таблицу Excel. Каждый участник может запросить копию на своём языке. Переведённый файл должен выглядеть как оригинал — те же шрифты, те же таблицы, те же номера страниц, те же колонтитулы, те же графики на своих местах.

Бюджет: никакого требования реального времени. Минута — нормально. Две минуты — нормально. Ограничение — точность воспроизведения: если переведённый PDF не похож на оригинал, получатель ему не поверит.

Почему этот конвейер не делит движок с голосом

LLM общего назначения, даже очень хорошая, вернёт вам переведённый текст документа. Она не вернёт вам переведённый PDF с той же раскладкой. У модели нет понятия «разрыв страницы, который должен совпадать с исходником» или «ячейка таблицы, которая должна сохранить ширину столбца».

Для этой задачи мы используем DeepL Document API напрямую. Он специально создан для перевода файлов как файлов, а не прозы, извлечённой из файлов. DeepL обрабатывает:

  • PDF (с сохранением раскладки)
  • DOCX, DOC
  • PPTX
  • XLSX

Документ загружается в конвейер DeepL, переводится на стороне сервера с сохранением форматирования и возвращается в том же формате. Затем мы заливаем результат в наше объектное хранилище и показываем его обратно в чате как скачиваемое вложение.

Сколько это стоит и почему мы это не прячем

DeepL тарифицирует минимум 50 000 символов на документ — примерно один доллар США за файл на тарифе Pro, независимо от того, одна в документе страница или тридцать. Мы поглощаем эту стоимость, а не берём плату за файл; в использовании переводов на встрече это отображается как тарифицированные символы, переведённые в слова, чтобы соответствовать тому, как остальная часть продукта отчитывается об активности перевода.

Мы выбрали DeepL для этой задачи, потому что это лучший в своём классе движок именно для перевода документов. Мы не делаем вид, что построили лучше. Обратное неверно — DeepL не запускает конвейер живого голоса того типа, который мы построили для встреч. Разные задачи; разные инструменты. Честная версия того, «что питает перевод InterMIND», — это «правильный движок на каждый конвейер», а не «наш движок везде».

Языки, которые этот конвейер охватывает, а голос — нет

Конвейер документов охватывает 30 языков, против 22 у голоса. Дополнительные включают: болгарский, греческий, эстонский, индонезийский, литовский, латышский, норвежский (букмол), словацкий, словенский — плюс арабский, который мы прячем из выбора в реальном времени, потому что качество голоса не дотягивает до нашей планки, но DeepL хорошо справляется с ним в документах.

Эта асимметрия реальна. Это значит, что французский участник встречи может запросить PDF договора на эстонском, даже если не может слушать встречу на эстонском. Мы помечаем это в селекторе, а не сглаживаем единым числом. Обоснование — в посте про количество языков.


Где конвейеры встречаются

Четыре конвейера работают не в изоляции. Комната встречи — это место, где они соприкасаются, и швы здесь важны:

  • Сообщение чата с вложением-документом запускает конвейер чата для текста и конвейер документов для файла. Участник на другом языке видит сообщение, переведённое сразу, и перевод вложения, приходящий асинхронно как скачиваемый файл.
  • Совместная заметка, цитирующая строку транскрипта, пересекает заметки ↔ голос. Транскрипт — это то, что голосовой конвейер выдал для языка отправителя; перевод заметки порождает копию этой цитаты для каждого зрителя на его языке, с сохранением атрибуции источника.
  • Транскрипт, экспортированный после встречи, прогоняется через текстовый конвейер в стиле чата по всему разговору, давая файл на каждый язык, который участники могут скачать. Это тот же код, что и перевод чата, просто в пакетном режиме.

Селектор языка — это один элемент интерфейса. Инфраструктура под ним — это четыре конвейера, разговаривающие друг с другом.


Чего мы намеренно не пытаемся делать

  • Никакой «единой модели перевода». Мы не строим одну модель, которая делает голос, чат, заметки и документы. У компромисса между задержкой и точностью нет победителя. Мы используем правильный движок на каждой поверхности.
  • Никакого тихого перенаправления. Если голос сегодня не может переводить на хинди, мы не откатываемся незаметно на движок документов и не делаем вид, что всё сработало. Хинди скрыт из селектора на обеих поверхностях, потому что результат на любой из них сегодня нельзя выпускать.
  • Никаких «мы переводим на 200 языков». Наш движок выдаёт 24. Наш продукт поставляет 22 на живых поверхностях и 30 на документах. Маркетингово удобное большее число — это просто потолок движка. Число продукта — это то, что реально проходит планку перед аудитором.

Попробуйте сами

  • /demo — прогоняет живой голосовой конвейер на вашем аудио, на любом из 22 продуктовых языков. Тот же конвейер, который оценивается на /benchmark.
  • /benchmark — качество по парам и по месяцам на реальном трафике. Включает пары, которые мы намеренно прячем из селектора, со ссылками напрямую.
  • /benchmark/methodology — что эти числа значат, чем не являются, кто судья.

Четыре конвейера, четыре движка, одна комната встречи. Это честная замена старой страницы how-it-works.

— The Mind.com Team

Получать новые публикации по email

Мы пришлём письмо, когда выйдет новая публикация. Отписаться можно в любой момент.