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

Ниже на примере OpenAI-совместимого интерфейса и типичных OCR-сервисов разобрана цепочка от загрузки до структурированного вывода, приведены примеры, предобработка, разбор ошибок и проверка при миграции.

Примечание: OpenAI, Google, Microsoft, Alibaba Cloud, Tencent Cloud, Baidu и другие упомянутые бренды — товарные знаки их правообладателей. Статья носит технический характер и не означает аффилированности с производителями; интерфейсы, модели, ограничения изображений и правила тарификации смотрите в официальной документации платформ и на страницах сайта.

1. Интерфейс и аутентификация

Есть две распространённые формы OCR, сначала определите свою:

  • Специализированный OCR-интерфейс: отдельная точка распознавания, на входе изображение или PDF, на выходе текстовые блоки, координаты и уверенность; часть поддерживает шаблоны счетов, документов и таблиц.
  • Мультимодальный диалоговый интерфейс: через /v1/chat/completions, изображение помещается в сообщение, визуальная модель выдаёт текст или JSON; подходит для сложной вёрстки, рукописного текста и задач с пониманием.

Аутентификация OpenAI-совместимого интерфейса обычно такая:

POST https://ai.zhongshangqihang.com/v1/chat/completions
Authorization: Bearer sk-ваш-ключ
Content-Type: application/json

Base URL указывайте только до /v1 и не собирайте путь вручную перед передачей в SDK, иначе легко получить 404. Некоторые облачные провайдеры используют подпись Access Key + Secret Key или сначала обменивают данные на access_token; схему Bearer туда напрямую применить нельзя, ориентируйтесь на официальную документацию.

2. Как передавать изображение: URL, Base64 и загрузка файла

Есть три распространённых способа; выбор зависит от того, где находится изображение и что поддерживает интерфейс:

Способ Когда подходит На что обратить внимание
Публичный URL Изображение уже в объектном хранилище или CDN Сервер должен иметь доступ; срок действия ссылки должен быть достаточным; не публикуйте чувствительные изображения
Base64 data URL Локальные файлы, изображения внутренней сети, временные тесты Объём растёт примерно на треть; ошибка префикса или кодирования даёт 400
multipart-загрузка файла Специализированные OCR-интерфейсы провайдера Имя поля, кодирование и размер — по документации

Формат Base64 обычно data:image/jpeg;base64,<закодированные данные>. Частые ошибки: пропущен префикс, в строку попали переводы строк или использовано URL-safe кодирование без обратного преобразования.

Из форматов чаще всего встречаются JPEG, PNG и WebP; GIF, TIFF, BMP и PDF зависят от интерфейса. Размер одного файла обычно от нескольких МБ до 20 МБ; превышение даёт 413 или 400. Разрешение не всегда «чем выше, тем лучше»: слишком большое сервер может уменьшить. Для сканов обычно 200–300 DPI, для фотографий с телефона начинайте с длинной стороны 1600–2400 пикселей и проверяйте на реальных образцах.

3. Синхронно или асинхронно

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

Асинхронный интерфейс подходит для пакетов и многостраничных документов. Процесс обычно такой:

  1. Отправить изображение или файл и получить ID задачи.
  2. Опрашивать статус или ждать уведомления по callback.
  3. После завершения скачать или запросить результат.
  4. Результат обычно хранится ограниченное время; сохраняйте его в свою базу вовремя.

Не смотрите только на простоту интерфейса. Если запрос может выполняться десятки секунд, синхронный вызов занимает соединение и поток, а повторы усиливают нагрузку. В асинхронном режиме нужно продумать идемпотентность, повторную отправку, паузы при опросе и истечение результата. В production рекомендуется завести таблицу задач с ID, статусом и местом хранения результата.

4. Пример вызова curl

Ниже распознавание изображения через OpenAI-совместимый интерфейс. Имя модели смотрите на странице тарифов; выбирайте модель с поддержкой изображений:

export ZSQH_API_KEY="sk-ваш-ключ"

curl "https://ai.zhongshangqihang.com/v1/chat/completions" \
  -H "Authorization: Bearer $ZSQH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5",
    "messages": [
      {
        "role": "user",
        "content": [
          {"type": "text", "text": "Распознай текст на изображении, выведи построчно, без пояснений."},
          {"type": "image_url", "image_url": {"url": "https://example.com/invoice.jpg"}}
        ]
      }
    ]
  }'

При 401 сначала проверьте ключ и заголовок; при 400 — доступность URL изображения и поддержку формата; при 404 — Base URL и повторное склеивание пути.

5. Вызов на Python и структурированный вывод

Реальному проекту редко нужен только текст, чаще — поля. Можно попросить модель вывести JSON по схеме и проверить его локально:

import base64
import json
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["ZSQH_API_KEY"],
    base_url="https://ai.zhongshangqihang.com/v1",
)

with open("invoice.jpg", "rb") as f:
    image_b64 = base64.b64encode(f.read()).decode()

schema_hint = '{"invoice_no": "", "date": "", "amount": "", "seller": ""}'
resp = client.chat.completions.create(
    model=os.environ["OCR_MODEL"],  # имя модели с поддержкой изображений со страницы тарифов
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": f"Распознай документ и выведи по этой JSON-схеме, отсутствующие поля заполни null: {schema_hint}"},
            {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}},
        ],
    }],
)
data = json.loads(resp.choices[0].message.content)
print(data)

Код запускается, но это не значит, что его можно выводить в production. Модель может добавить блок кода, пояснения или лишние поля, и json.loads сразу упадёт. На практике: используйте поддерживаемый платформой JSON-режим или структурированный вывод; перед разбором убирайте маркеры блоков кода; проверяйте типы через Pydantic или jsonschema; при ошибке возвращайте сообщение модели на один повтор, затем переводите на ручную проверку. Суммы, даты и налоговые номера дополнительно сверяйте.

6. Координаты, таблицы и структурированные поля

Классический OCR возвращает содержимое текстовых блоков, координаты и уверенность; мультимодальная модель выводит по промпту, и координаты не всегда надёжны. Сначала уточните формат координат: четырёхточечный полигон, [x1, y1, x2, y2] или [x, y, w, h]; единицы — пиксели или нормализация до 0–1000; где начало координат — в левом верхнем углу; после поворота и обрезки координаты нужно пересчитывать.

Если перед распознаванием изображение масштабировали, координаты нужно пропорционально вернуть к исходному размеру, иначе рамка подсветки сместится. Для таблиц заранее определите правила строк, столбцов, объединённых ячеек и пустых значений; сложные таблицы лучше распознавать специализированным интерфейсом, а затем передавать модели для упорядочивания.

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

7. Предобработка: сделать распознавание стабильнее

Большая часть ошибок распознавания предопределена до запроса. Обрабатывайте в таком порядке:

  1. Прочитайте ориентацию EXIF и поверните изображение, чтобы документ не лежал на боку.
  2. Обрежьте до области документа, уберите большой фон и посторонние объекты.
  3. Выполните коррекцию небольшого наклона; при заметном перекосе сначала определите края.
  4. Управляйте разрешением: сканы 200–300 DPI, фото с телефона — от 1600–2400 пикселей по длинной стороне.
  5. Выцветшие и низкоконтрастные документы можно перевести в оттенки серого и умеренно повысить контраст.
  6. Многостраничные PDF и длинные скриншоты делите по страницам с небольшим перекрытием на стыках.

Размытое изображение не спасти повышением резкости, а текст низкого разрешения не приобретёт детали при увеличении. Цель предобработки — уменьшить помехи, а не сделать картинку красивой. При каждом изменении параметров сравнивайте точность полей на одной и той же партии реальных образцов.

8. Частые ошибки и диагностика

Ошибка Частая причина Что делать
401 Unauthorized Неверный или просроченный ключ, неверный заголовок Проверить формат Bearer, пробелы и переменные окружения
403 Forbidden Нет прав на модель, ограничение региона, недостаточно прав субаккаунта Проверить авторизацию модели и политику аккаунта
400 ошибка изображения Неверный префикс Base64, повреждённый файл, неподдерживаемый формат Проверить заголовок файла после декодирования, перейти на JPEG или PNG
413 Payload Too Large Превышен размер изображения или тела запроса Сжать, уменьшить, обрезать или перейти на загрузку файла/асинхронный режим
429 Too Many Requests Превышена частота или параллелизм Снизить параллелизм, повторять с экспоненциальной паузой
Тайм-аут или 502 Большое изображение, длинный документ, очередь на сервере Перейти на асинхронную задачу или уменьшить запрос
Пустой или перепутанный результат Неверная ориентация, низкое разрешение, сложная вёрстка Повернуть, повысить чёткость, разбить на колонки

При диагностике сначала фиксируйте request ID, имя модели, размер изображения и длительность. Часто «плохое качество модели» оказывается неверно переданным изображением, непересчитанными координатами или несовпадением схемы.

9. Миграция и проверка перед запуском

Переход от одного OCR-сервиса к другому обычно не ограничивается заменой base_url и api_key. Перед запуском проверьте:

  • Новый интерфейс специализированный OCR или диалоговый визуальный; совместима ли структура запроса.
  • Какие форматы изображений поддерживаются, какие ограничения на размер, число страниц и разрешение.
  • Синхронный или асинхронный режим, сколько хранится результат, нужен ли публичный адрес для callback.
  • Совпадают ли формат координат, единицы и начало отсчёта со старым сервисом.
  • Покрывают ли схема полей, языки и типы документов текущий бизнес.
  • Есть ли схема постепенного переключения, чтобы сначала пустить часть трафика и сравнить точность.
  • Есть ли путь отката; старый ключ и интерфейс сохраняются на время.

Рекомендуется обернуть OCR в отдельный клиент, например recognize(image, schema) -> Result, и спрятать различия провайдеров в адаптере; тогда при смене сервиса бизнес-код не придётся переписывать. Модели, ограничения и цены — на странице тарифов.

Частые вопросы

Поддерживает ли OCR API PDF?

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

Какой максимальный размер изображения можно передать?

У разных провайдеров по-разному; обычно от нескольких МБ до 20 МБ на файл, плюс ограничения по пикселям и страницам. Рекомендуется сжимать и уменьшать до загрузки, чтобы снизить тайм-ауты и затраты на передачу.

Почему порядок распознанного текста нарушен?

Частые причины — несколько колонок, таблицы и смешанная вёрстка. Классический OCR сортирует по координатам, мультимодальная модель генерирует в порядке чтения; оба могут ошибаться. Можно делить на колонки, просить вывод по областям или использовать интерфейс с анализом вёрстки.

Какой способ структурированных полей самый надёжный?

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

Что менять при переходе с одного OCR-сервиса на другой?

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

Что дальше

Чтобы выполнить первый запрос, создайте ключ с небольшим лимитом на странице регистрации и проверьте на реальном счёте загрузку, распознавание и JSON-вывод. Для выбора тарифа смотрите цены и сравните точность полей на небольшой размеченной партии изображений. Цены меняются; ориентируйтесь на информацию сайта.

Читайте также:

Примечание: OpenAI, Google, Microsoft, Alibaba Cloud, Tencent Cloud, Baidu и другие упомянутые бренды — товарные знаки их правообладателей. Статья носит технический характер; ограничения и правила тарификации определяются официальной документацией платформ.