Задача: извлечь данные из документа и передать в LLM
Пользователь открывает мобильное приложение, прикрепляет PDF контракта и спрашивает: «На каком сроке расторгается договор?» На первый взгляд — типовой сценарий. Но между file_picker и осмысленным ответом модели — десяток нетривиальных решений: от рендеринга каждой страницы скана до чанкинга 100-страничного файла, не влезающего в контекст. Мы реализовали такой функционал для нескольких проектов — финансовых, юридических, медицинских — и знаем каждый подводный камень. Ошибка в одном звене — и ответ модели бессмысленный, или вы рискуете получить блокировку за несоответствие App Store Review Guidelines по пользовательскому контенту. Чтобы этого избежать, разберём ключевые этапы: выбор способа передачи, обработка сканов, организация RAG для больших объёмов.
Как передать документ в LLM?
Большинство LLM принимают текст, а не PDF. Нужна конвертация. Рассмотрим два основных подхода.
Прямой upload через Files API
OpenAI Assistants API и Gemini Files API принимают PDF, DOCX, TXT напрямую. Для мобильного приложения это самый чистый путь: загружаем файл, получаем file_id, вставляем в messages[]. Но есть ограничения — у OpenAI лимит 512 МБ на файл и 100 файлов на assistant, и Files API привязан к Assistants/Batch, не к Chat Completions.
Извлечение текста на клиенте
Для PDF на Android — PdfRenderer (встроен с API 21) для рендеринга страниц в Bitmap + OCR через ML Kit TextRecognizer, или Apache PDFBox порт. На iOS — PDFKit + PDFPage.string для машинописного PDF; для сканов — Vision framework с VNRecognizeTextRequest. Текст уходит в content[] как строка. PDFKit documentation
Проблема сканированных документов
PDFKit.string вернёт пустую строку для PDF из отсканированных страниц — там нет текстового слоя. ML Kit TextRecognizer справляется, но нужно рендерить каждую страницу в Bitmap/CGImage и прогонять через OCR. Для 50-страничного документа это 2–5 секунд на устройстве.
Что делать со сканами и большими файлами?
Извлечение текста: подводные камни
На Android PdfRenderer требует ParcelFileDescriptor с флагом MODE_READ_ONLY. Если файл пришёл через content:// URI от FileProvider, нужен contentResolver.openFileDescriptor(). Прямой File() от content:// бросает FileNotFoundException — распространённая ошибка у тех, кто не работал с SAF (Storage Access Framework).
Многостраничные документы нужно обрабатывать постранично, не грузя всё в память сразу. PdfRenderer.Page нужно закрывать после каждой страницы — page.close() обязателен, иначе IllegalStateException на следующей итерации.
На iOS PDFDocument(url:) может вернуть nil для зашифрованных PDF. Обрабатывайте isEncrypted и запрашивайте пароль через UI, а не крашитесь молча.
Архитектурное решение для больших документов
Полный текст 100-страничного договора не влезет в контекстное окно большинства моделей — или влезет, но дорого. Правильный путь для объёмных документов — RAG: разбиваем на чанки по 500–1000 токенов с перекрытием 50–100 токенов, индексируем в векторную БД, при запросе ищем топ-5 релевантных чанков и только их передаём в context. Экономия на токенах — до 40% по сравнению с прямой передачей полного текста. Для документов до 10 страниц клиентская экстракция работает в 3 раза быстрее, чем загрузка через Files API с ожиданием ответа.
Для мобильного приложения это обычно означает серверную обработку: клиент загружает файл на бэкенд, бэкенд занимается чанкингом и эмбеддингами. На клиенте остаётся только UI запроса и рендеринг ответа. Реализовывать векторный поиск прямо на телефоне имеет смысл только для оффлайн-сценариев.
Сравнение подходов
| Подход | Скорость | Стоимость токенов | Поддержка сканов |
|---|---|---|---|
| Прямой Files API | Быстро (сервер) | Высокая (весь текст) | Да (если есть текст) |
| Клиентская экстракция + текст | Средне (зависит от объёма) | Средняя (только текст) | Да (OCR на клиенте) |
| RAG с серверным чанкингом | Медленно (индексация), быстро (запрос) | Низкая (только релевантные чанки) | Да (если есть OCR) |
Форматы и лимиты
| Формат | Android | iOS | Лимит API (OpenAI) |
|---|---|---|---|
| PDF (текст) | PdfRenderer + PDFBox | PDFKit | 512 МБ |
| PDF (скан) | ML Kit OCR | Vision VNRecognizeTextRequest | — (нужна предобработка) |
| DOCX | Apache POI (Java) | — | 512 МБ (через Files API) |
| TXT / MD | Нативно | Нативно | Без ограничений |
| XLSX | Apache POI | — | 512 МБ |
DOCX на iOS без сторонних библиотек — боль. Либо серверная конвертация (LibreOffice headless), либо ограничиваете поддержку форматов PDF + TXT для мобильного клиента.
Что входит в работу под ключ
- Аудит форматов документов в вашем продукте
- Выбор оптимальной стратегии (Files API vs клиентская экстракция vs RAG)
- Реализация загрузки файлов (
file_picker, SAF,UIDocumentPickerViewController) - Конвертация и очистка текста (OCR для сканов)
- Интеграция с LLM (OpenAI / Gemini / Anthropic)
- Индикаторы прогресса для долгих операций
- Тестирование на реальных документах разного качества
- Документация и обучение команды
Почему выбирают нас
Мы — команда мобильных разработчиков с 5+ годами опыта в создании AI-решений под iOS и Android. Реализовали более 20 интеграций мультимодального ввода для финансовых, юридических и медицинских проектов. Гарантируем качество кода и соблюдение сроков. Свяжитесь с нами для оценки вашего проекта — подберём оптимальное решение под ваш бюджет.
Сроки: базовая поддержка PDF + TXT с прямой передачей — 1–2 недели. Полноценный pipeline с OCR, несколькими форматами и RAG для больших документов — 4–6 недель. Оценим ваш проект бесплатно — пишите.







