Учебник

Vision API: данные с накладных и скриншотов без ручного ввода

Ваши сотрудники тратят часы на перенос цифр со сканов договоров и скриншотов в учётную систему. Vision API GPT-4o и Claude умеют читать текст с картинок и извлекать данные автоматически. Разбираем, как настроить это за 2 часа без найма программиста - на примере стройфирмы и турагентства. Никаких курсов, только готовые шаблоны кода.

Макс Космов··9 мин чтения

У ваших менеджеров уходит по 2-3 часа в день на то, чтобы вручную перепечатать данные из отсканированных накладных, договоров или скриншотов интерфейса. Ошибки, потерянные строки, задержки. Хорошая новость: GPT-4o и Claude умеют анализировать изображения - читать текст на скане, описывать диаграммы, классифицировать фото. Всё это делается простым вызовом к API, без найма программиста и без специального софта для компьютерного зрения.

Разберём на примере стройфирмы: приходит скан накладной от поставщика - менеджер открывает, сверяет, переносит в 1С. Автоматизируем: отправляем скан в Vision API, получаем структурированные данные за 10 секунд. Или для турагентства: скриншот брони отеля с сайта - раньше перепечатывали вручную, теперь извлекаем автоматически.

Это примеры, а не реальные кейсы автора.

Поддерживаемые форматы и ограничения

Оба провайдера принимают: JPEG, PNG, GIF (первый кадр), WebP.

OpenAI: максимум 20 MB на файл, максимум 20 изображений в одном запросе. Для больших файлов рекомендуется передавать URL.

Anthropic: base64 до 5 MB на изображение, URL без жёсткого лимита (сервер загружает сам). До 20 изображений в запросе.

Практический совет: для изображений больше 1 MB передавайте через URL или Files API. Это экономит размер запроса и время отправки. Base64 увеличивает объём данных примерно в 1.37 раза.

Поддержки видео нет - только статичные изображения. Анализ видео делается через нарезку на кадры (но это дорого, лучше использовать специализированные решения).

OpenAI: передача изображения

Есть два способа передать изображение в GPT-4o: по ссылке (URL) и через base64-кодирование. Base64 - это когда файл превращается в текстовую строку и вставляется прямо в запрос. URL - сервер OpenAI сам скачивает файл по ссылке.

Первый способ - передаём ссылку на файл и просим описать график. Параметр detail управляет качеством анализа - и одновременно стоимостью:

from openai import OpenAI

client = OpenAI()

# Способ 1: по URL
response = client.chat.completions.create(
 model="gpt-4o",
 messages=[
 {
 "role": "user",
 "content": [
 {
 "type": "image_url",
 "image_url": {
 "url": "https://example.com/chart.png",
 "detail": "high" # 'low', 'high', 'auto'
 }
 },
 {
 "type": "text",
 "text": "Опиши что показано на этом графике"
 }
 ]
 }
 ]
)
print(response.choices[0].message.content)

Тот же запрос, но изображение читается с диска и кодируется в base64:

import base64

# Способ 2: base64
with open("screenshot.png", "rb") as f:
 image_data = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
 model="gpt-4o",
 messages=[{
 "role": "user",
 "content": [
 {
 "type": "image_url",
 "image_url": {
 "url": f"data:image/png;base64,{image_data}",
 "detail": "auto"
 }
 },
 {"type": "text", "text": "Извлеки весь текст с этого скриншота"}
 ]
 }]
)

Расчёт токенов OpenAI: detail=low vs high

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

detail='low': изображение масштабируется до 512x512 пикселей. Фиксированная стоимость - 85 токенов. Подходит для общего описания, но не для чтения текста.

detail='high': изображение нарезается на тайлы 512x512. Каждый тайл стоит 170 токенов, плюс базовые 85. Полное изображение 1920x1080 даёт около 1105 токенов. При цене GPT-4o $2.50 за миллион токенов - это примерно $0.003 за одно изображение. Тысяча таких изображений в день - $3. Если обрабатываете 50 000 документов в день, уже $150 в день только на картинки. Для таких объёмов считайте сначала.

Функция ниже рассчитывает, сколько токенов займёт изображение при detail=high в GPT-4o. Это удобно для планирования бюджета до запуска в работу:

import math

def calc_image_tokens(width: int, height: int) -> int:
 # Масштабируем до максимума 2048x2048
 scale = min(2048 / width, 2048 / height, 1.0)
 w, h = int(width * scale), int(height * scale)

 # Масштабируем меньшую сторону до 768
 scale2 = 768 / min(w, h)
 if scale2 < 1.0:
 w, h = int(w * scale2), int(h * scale2)

 # Считаем тайлы 512x512
 tiles_x = math.ceil(w / 512)
 tiles_y = math.ceil(h / 512)
 total_tiles = tiles_x * tiles_y

 return total_tiles * 170 + 85

print(calc_image_tokens(1024, 1024)) # 765 токенов
print(calc_image_tokens(1920, 1080)) # ~1105 токенов

detail='auto': OpenAI сам выбирает low или high по размеру. До 512x512 пикселей - low, иначе high.

Для экономии при больших объёмах: detail='low' снижает стоимость примерно в 13 раз при разрешении 1920x1080, но делает мелкий текст нечитаемым. Для классификации фото товаров или описания диаграмм - подходит. Для OCR документов - нет.

Claude: передача изображения

У Anthropic синтаксис немного отличается от OpenAI, но логика та же. Изображение - это отдельный блок в массиве content, рядом с текстовым блоком вопроса.

Следующий код показывает запрос к Claude с изображением по URL:

import anthropic
import base64

client = anthropic.Anthropic()

# Способ 1: URL
response = client.messages.create(
 model="claude-sonnet-4-6",
 max_tokens=1024,
 messages=[{
 "role": "user",
 "content": [
 {
 "type": "image",
 "source": {
 "type": "url",
 "url": "https://example.com/diagram.png"
 }
 },
 {"type": "text", "text": "Что показано на этой диаграмме?"}
 ]
 }]
)

Тот же запрос через base64 - когда файл на диске и нет публичного URL:

# Способ 2: base64
with open("photo.jpg", "rb") as f:
 image_data = base64.standard_b64encode(f.read()).decode()

response = client.messages.create(
 model="claude-sonnet-4-6",
 max_tokens=1024,
 messages=[{
 "role": "user",
 "content": [
 {
 "type": "image",
 "source": {
 "type": "base64",
 "media_type": "image/jpeg",
 "data": image_data
 }
 },
 {"type": "text", "text": "Опиши содержимое фото"}
 ]
 }]
)

Claude Files API: загрузи один раз, используй много

Если одно и то же изображение нужно проанализировать с разных сторон - например, накладная сканируется и из неё нужно извлечь поставщика, номер, даты и суммы через разные запросы - выгоднее загрузить файл один раз через Files API.

Без Files API: 5 запросов к изображению в 2 MB через base64 = 5 раз отправляете 2.74 MB (с учётом раздутия base64). С Files API: загружаете один раз, остальные запросы используют только идентификатор файла.

Следующий код загружает изображение один раз и использует его в нескольких запросах без повторной отправки данных:

# Загружаем один раз
with open("company_logo.png", "rb") as f:
 file = client.beta.files.upload(
 file=("logo.png", f, "image/png")
 )

file_id = file.id
print(f"Загружено: {file_id}")

# Используем в нескольких запросах без повторной загрузки
for question in questions:
 response = client.messages.create(
 model="claude-haiku-4-5",
 max_tokens=256,
 messages=[{
 "role": "user",
 "content": [
 {
 "type": "image",
 "source": {
 "type": "file",
 "file_id": file_id
 }
 },
 {"type": "text", "text": question}
 ]
 }]
 )
 print(response.content[0].text)

# Удаляем когда не нужен
client.beta.files.delete(file_id)

Практические задачи

Ниже - три готовых шаблона для самых распространённых бизнес-сценариев.

OCR: извлечение текста

OCR (Optical Character Recognition) - автоматическое распознавание и извлечение текста с изображений и сканов. Раньше для этого нужны были специализированные библиотеки или отдельные сервисы вроде Tesseract. Теперь это делает обычный запрос к GPT-4o.

Реалистичный сценарий: компания получает накладные по электронной почте в виде отсканированных PDF. Раньше оператор вручную переносил данные в 1С - 5-10 минут на документ. После автоматизации через Vision API: загружается страница, извлекается текст, парсятся нужные поля - менее 10 секунд.

Функция ниже читает файл, кодирует в base64 и отправляет в GPT-4o с инструкцией сохранить структуру документа:

def extract_text_from_scan(image_path: str) -> str:
 with open(image_path, "rb") as f:
 data = base64.b64encode(f.read()).decode()

 response = client.chat.completions.create(
 model="gpt-4o",
 messages=[{
 "role": "user",
 "content": [
 {
 "type": "image_url",
 "image_url": {"url": f"data:image/jpeg;base64,{data}", "detail": "high"}
 },
 {"type": "text", "text": "Извлеки весь текст с изображения. Сохраняй форматирование, таблицы и структуру. Выводи только текст без комментариев."}
 ]
 }]
 )
 return response.choices[0].message.content

Анализ скриншотов интерфейса

Полезно для команд QA и продукта: вместо того чтобы описывать проблему словами, делают скриншот и получают структурированный разбор. Команда из 5 тестировщиков тратит на описание багов примерно 2 часа в день. Автоматизация через Vision API сокращает это вдвое.

Функция анализирует скриншот и возвращает JSON с проблемами и сильными сторонами интерфейса:

def analyze_ui_screenshot(screenshot_path: str) -> dict:
 response = client.messages.create(
 model="claude-sonnet-4-6",
 max_tokens=1024,
 messages=[{
 "role": "user",
 "content": [
 {"type": "image", "source": {"type": "base64", "media_type": "image/png",
 "data": encode_image(screenshot_path)}},
 {"type": "text", "text": """Проанализируй этот скриншот интерфейса.
Выведи JSON:
{"issues": ["список проблем UX"], "good_parts": ["что сделано хорошо"], "priority_fix": "главная проблема"}"""}
 ]
 }]
 )
 import json as json_lib
 return json_lib.loads(response.content[0].text)

PDF-страница как изображение

Прямой загрузки PDF нет ни в OpenAI, ни в Anthropic. Стандартное решение - конвертировать страницы в изображения через pdf2image. При DPI=150 страница A4 даёт примерно 1240x1754 пикселей и около 765 токенов. DPI=72 снижает и разрешение, и стоимость - но мелкий текст становится нечитаемым.

Следующий код конвертирует страницу PDF в изображение и отправляет в GPT-4o для извлечения текста:

from pdf2image import convert_from_path

def analyze_pdf_page(pdf_path: str, page_num: int = 0) -> str:
 images = convert_from_path(pdf_path, first_page=page_num+1, last_page=page_num+1, dpi=150)
 page_image = images[0]

 from io import BytesIO
 buffer = BytesIO()
 page_image.save(buffer, format="PNG")
 image_data = base64.b64encode(buffer.getvalue()).decode()

 response = client.chat.completions.create(
 model="gpt-4o",
 messages=[{
 "role": "user",
 "content": [
 {
 "type": "image_url",
 "image_url": {"url": f"data:image/png;base64,{image_data}", "detail": "high"}
 },
 {"type": "text", "text": "Извлеки содержимое страницы в markdown-формате"}
 ]
 }]
 )
 return response.choices[0].message.content

GPT-4o или Claude: что выбрать для визуальных задач

Оба провайдера справляются с анализом изображений на высоком уровне. Разница - в деталях.

GPT-4o быстрее отвечает при коротких запросах (первый токен за 0.5-1 секунду против 1-2 секунд у Claude). Автоматический кеш без настройки. Хорошо интегрируется в Batch API для пакетной обработки со скидкой 50%.

Claude точнее при анализе сложных диаграмм и схем с большим количеством подписей. Лучше справляется с длинными документами, когда нужно извлечь структурированные данные из нескольких изображений сразу. Files API позволяет загрузить изображение один раз и не передавать его повторно.

Для OCR на больших объёмах: если главное - скорость и цена, GPT-4o-mini при detail=high. Если важна точность структуры - Claude Haiku или Sonnet. В задачах классификации товарных фото оба провайдера дают похожий результат, но gpt-4o-mini дешевле в 5-10 раз.

Мультиизображение в одном запросе

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

Порядок блоков важен - модель обрабатывает контент последовательно. Текстовая метка рядом с изображением помогает понять контекст каждого.

Следующий код отправляет два изображения с подписями «ДО» и «ПОСЛЕ» и просит описать изменения:

response = client.messages.create(
 model="claude-sonnet-4-6",
 max_tokens=2048,
 messages=[{
 "role": "user",
 "content": [
 {"type": "text", "text": "Сравни эти два скриншота:"},
 {"type": "image", "source": {"type": "url", "url": before_url}},
 {"type": "text", "text": "ДО"},
 {"type": "image", "source": {"type": "url", "url": after_url}},
 {"type": "text", "text": "ПОСЛЕ. Какие изменения внесены в интерфейс?"}
 ]
 }]
)

Claude обрабатывает до 20 изображений в запросе. GPT-4o тоже до 20. Для пакетного анализа галерей - смотрите Batch API.

Ограничения и честные ожидания

Что Vision API делает плохо:

  • Подсчёт объектов на изображении если их больше 15 (систематические ошибки)
  • Чтение мелкого текста на скриншотах с разрешением ниже 72 DPI
  • Распознавание конкретных людей (политика обоих провайдеров)
  • Точный OCR рукописного текста (работает, но с ошибками)
  • Анализ медицинских снимков (ограничения по политике)

Что работает хорошо:

  • Извлечение печатного текста со сканов при достаточном разрешении
  • Описание изображений для alt-текстов и архивного поиска
  • Классификация товарных фото по категориям
  • Чтение диаграмм, графиков, блок-схем
  • Анализ интерфейсов и скриншотов сайтов
  • Сравнение двух изображений

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

Что дешевле - URL или base64?

Стоимость токенов одинакова - платите за визуальные токены, не за способ передачи. Но URL быстрее при больших изображениях (не надо гонять данные в запросе) и снижает лимит по размеру тела запроса.

Можно ли анализировать видео покадрово?

Технически да - нарезать видео через ffmpeg на кадры и отправить несколько изображений. Но это дорого: видео 10 сек при 1 кадре в секунду = 10 изображений = около 7000 токенов только за картинки. Для видеоанализа есть специализированные решения.

Как загрузить PDF-страницу?

Прямой загрузки PDF нет. Конвертируйте в изображения через pdf2image (обёртка над poppler) или PyMuPDF. Рекомендуемый DPI: 150-200 для OCR, 72-100 для общего анализа. Пример кода выше в разделе про практические задачи.

Почему detail=low не видит мелкий текст?

Detail=low масштабирует изображение до 512x512 пикселей. Текст размером 10pt при масштабировании с A4 становится несколько пикселей - нечитаемо. Для OCR всегда используйте detail=high.

Работает ли Vision API в Batch API?

Да. В OpenAI Batch API можно передавать запросы с изображениями в JSONL так же как обычные. Изображения по URL - работают. Base64 в JSONL - работают, но файл становится большим. Для пакетного анализа изображений это хороший способ сэкономить 50%.

Что дальше

Возьмите один из готовых шаблонов кода выше (OCR, анализ скриншота или PDF) и запустите его на своём компьютере с одним файлом. Если ваш менеджер не программист - передайте этот код своему фрилансеру или IT-отделу (если есть). Время внедрения: 2-4 часа. Бесплатный план OpenAI или Anthropic даёт достаточно токенов для теста.

AI Компас (t.me/kosmoslab_ai) - канал для предпринимателей в РФ и СНГ, которые применяют AI в своём бизнесе без программиста. Разбираем инструменты и схемы - без курсов и теории.