Мультимодальность в UI: Загрузка картинок, PDF и аудио в один инпут

22.06.2026 21:00

Пользователь открывает чат, берет мышку и перетаскивает в окно браузера три файла: скриншот с ошибкой, PDF-документ на сорок страниц и голосовое сообщение в формате .ogg. Он ожидает, что нейросеть поймет этот хаос так же легко, как человек. Интерфейс приветливо мигает рамкой dropzone. Иллюзия простоты сохраняется ровно до того момента, пока этот массив байтов не достигает слоя бизнес-логики.

Мультимодальность в UI выглядит как единый , но под капотом она требует архитектуры, способной на лету разбирать, нормализовать и упаковывать данные совершенно разной природы.

Идентификация формата — первая ловушка. Полагаться на свойство file.type, которое отдает браузер, — прямой путь к ошибкам. Пользователи переименовывают расширения, пересылают HEIC-фотографии с айфонов под видом стандартных JPEG, а системные буферы обмена при вставке картинки через Ctrl+V часто генерируют бинарные блобы без внятных метаданных. Frontend вынужден читать магические числа (magic bytes) в начале файлов, чтобы гарантированно понять, с чем именно он имеет дело.

Настоящая архитектурная проблема возникает на этапе передачи этих данных в API. LLM-провайдеры ожидают структурированный JSON. Задача — интегрировать тяжелый бинарный файл в текстовый формат обмена данными. Здесь система сталкивается с неизбежной развилкой: Base64 или URL.

Кодирование в Base64 выглядит наиболее прямолинейным решением. Мы читаем файл, превращаем его в строку и отправляем внутри массива messages. Плата за эту простоту — раздувание payload. Base64 увеличивает изначальный объем данных примерно на 33%. Фотография размером 5 МБ превращается в 6.6 МБ текста. Большинство API-шлюзов и балансировщиков нагрузки (включая Nginx с дефолтными настройками client_max_body_size) безжалостно сбросят такое соединение еще до того, как оно дойдет до бэкенда. Кроме того, сериализация и парсинг гигантских JSON-строк блокирует event loop в однопоточных средах вроде Node.js и вызывает резкие скачки потребления оперативной памяти. Пропуск тяжелого JSON через каждый этап сетевого маршрута уничтожает производительность.

Передача через URL решает проблему размера тела запроса, но создает новые точки отказа. Frontend или Backend сначала загружает файл в объектное хранилище (например, AWS S3), генерирует pre-signed URL со сроком жизни в пару часов и передает эту ссылку в LLM. Провайдер сам скачивает файл. Появляется зависимость от внешней сети: сеть провайдера может быть изолирована или иметь жесткие таймауты на скачивание. Если файл приватный, токен авторизации в URL может истечь раньше, чем модель начнет генерацию (особенно актуально для долгих очередей на инференс). Разработчик вынужден реализовывать асинхронную логику управления жизненным циклом временных файлов, чтобы не разориться на хранении мусорных данных в бакетах.

Дальше начинается специфика самих форматов. PDF ломает стандартные паттерны обработки. Пользователь кидает PDF и пишет: "Объясни график на третьей странице". Если использовать стандартный парсер текста вроде pdf2json, из документа извлекутся только символы. График исчезнет из контекста. Для сохранения визуального контекста PDF необходимо растеризовать — превратить каждую страницу в отдельную картинку. Документ на 50 страниц превращается в 50 изображений. Отправка 50 изображений высокого разрешения в Vision-модель за один запрос сожжет значительную часть дневного лимита токенов пользователя. Каждое изображение тарифицируется по сложной сетке провайдера (базовые токены плюс токены за тайлы). Инженерам приходится внедрять эвристику: если в промпте есть слова "график", "схема" или "фото" — растеризуем, если запрос касается чистого текста — извлекаем только текст.

Аудио добавляет свой слой хаоса кодеков. Frontend использует MediaRecorder API для записи голоса в браузере. Chrome по умолчанию пишет поток в контейнер WebM с аудиокодеком Opus. Safari отдает MP4/AAC. Провайдеры транскрибации (например, Whisper API) обладают жесткими требованиями к частоте дискретизации и поддерживаемым форматам. Бэкенд вынужден держать запущенные инстансы ffmpeg, чтобы на лету перепаковывать и ресемплировать аудиопотоки перед отправкой в нейросеть. Это сжигает процессорное время и увеличивает задержку до первого байта ответа (TTFB).

Прагматичное решение этих проблем требует смещения фокуса вычислений с бэкенда на клиент. Тяжелая нормализация должна происходить в браузере пользователя. Отправлять 12-мегабайтное фото с современной камеры на сервер бессмысленно. Vision-модели (включая GPT-4o и Claude 3.5 Sonnet) все равно ужимают входные изображения (обычно до 768x768 или 1024x1024 пикселей) для обработки алгоритмом тайлов. Canvas API позволяет изменить размер картинки и сжать ее в современный формат WebP прямо на устройстве пользователя, сократив объем передаваемых данных с 12 МБ до 300 КБ за миллисекунды. Тот же принцип работает для извлечения текста из PDF через pdf.js, скомпилированный в WebAssembly.

Когда данные локально нормализованы и сжаты, возникает задача маршрутизации. Мультимодальные запросы радикально фрагментированы на уровне API-провайдеров. Одни модели принимают только текст. Другие переваривают картинки, но падают при виде PDF. Интеграция RouterAPI берет этот хаос под системный контроль. Вместо того чтобы писать жесткие ветвления на клиенте if (hasImage) { useVisionModel }, система позволяет отправлять унифицированный массив сообщений в стандарте OpenAI.

[
 {
 "role": "user",
 "content": [
 { "type": "text", "text": "Что здесь изображено и есть ли об этом упоминание в документе?" },
 { "type": "image_url", "image_url": { "url": "data:image/webp;base64,UklGR.." } },
 { "type": "text", "text": "Содержимое PDF: [экстрагированный текст..]" }
 ]
 }
]

RouterAPI перехватывает этот payload. Если в запросе присутствует image_url, шлюз автоматически маршрутизирует его на узлы, поддерживающие Vision, опираясь на внутреннюю конфигурацию (маршрутизацию, доступность апстримов и fallback-цепочки). Если клиент запрашивает легковесную текстовую модель, но прикрепляет картинку, шлюз отсекает несовместимый контент или возвращает структурированную ошибку валидации, предотвращая падение апстрима.

Главная архитектурная победа RouterAPI кроется в абстрагировании биллинга. Обработка мультимодальных данных стоит дорого и считается нелинейно. Затраты зависят от итогового разрешения картинки и алгоритма расчета тайлов конкретного провайдера. Разные провайдеры считают мультимодальные токены по‑разному. RouterAPI нормализует эти расходы (через механизмы вроде система тарификации RouterAPI), переводя расчеты из абстрактных пикселей в понятные финансовые единицы, списывая их с баланса пользователя в одной транзакции вместе с текстовыми токенами.

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

Теги

Ещё по теме