Метод POST /api/v1/gateway/upload-product-photo

Документация API: Добавление продуктов через готовый снимок с автоматической gRPC ИИ-модерацией

Author

Application & Simulation Services Framework Documentation

Published

June 11, 2026

WarningОграничение публичной документации

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

  • Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).

Функциональное назначение

This method is designed for the asynchronous processing and object detection of product images (or receipts) using computer vision (YOLO).

Within the updated architecture, this method acts as a Vision Context Provider:

  1. Binary Traffic Isolation: The FastAPI gateway does not hold the image in RAM during model inference. Instead, it instantly streams the file to the distributed object storage MinIO (S3), freeing up Uvicorn network worker threads.
  2. Asynchronous Detection (YOLO): Heavy convolutional neural network (CNN) inference is offloaded from the API tier to an isolated product-vision-processor worker, which translates graphical pixels into a canonical text class representing the item.
  3. Censorship Perimeter Reuse: Once detection is complete, the extracted text string is automatically routed to the existing censorship-control-worker. This guarantees that unified edge security policies are enforced (Fail-Close via Redis).

Interaction Protocol (HTTP Contract)

  • Method: POST
  • Route: /api/v1/purchase/upload-product-photo
  • Data Format: multipart/form-data

Headers Specification (HTTP Headers)

Header Required Description Example Value
Content-Type Yes Indicates the transmission of composite form data (multipart). multipart/form-data; boundary=----WebKitFormBoundary...
Authorization Yes Access token used to extract the user_id and the multi-tenancy home_group_id stamp. Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
X-Request-ID Yes End-to-end request ID to trace the session lifecycle (FastAPI \(\rightarrow\) MinIO \(\rightarrow\) Kafka \(\rightarrow\) Workers). req-5f9c-2b1a-88ef
Accept No Expected response format from the backend gateway. application/json

Query Parameters Specification

Parameter Type Required Description Example Value
app_lang String Yes Target application language used to adapt the system prompt at the downstream censorship phase. ru

Request Body Specification (Request Body — Multipart FormData)

Field Type Required Description Example Value
file Binary (File) Yes Raw binary data of the product photo (image/jpeg, image/png). Constraint: up to 10 MB. snapshot.jpg
crop_type String No Matrix cropping and preprocessing mode for the AI worker (default, square, raw). "square"

Raw HTTP Request Example (Payload):

POST /api/v1/purchase/upload-product-photo?app_lang=ru HTTP/1.1
Host: foodlifecycle.com
Authorization: Bearer eyJhbGciOiJIUzI1Ni...
X-Request-ID: req-5f9c-2b1a-88ef
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="snapshot.jpg"
Content-Type: image/jpeg

[BINARY_IMAGE_DATA]
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="crop_type"

square
------WebKitFormBoundary7MA4YWxkTrZu0gW--

Метод предназначен для асинхронной обработки и распознавания изображений продуктов (или чеков) с использованием компьютерного зрения (YOLO).

В рамках новой архитектуры этот метод выполняет роль поставщика медиа-контекста (Vision Context Provider):

  1. Изоляция бинарного трафика: Шлюз FastAPI не держит изображение в оперативной памяти во время инференса, а мгновенно сбрасывает его в распределенное объектное хранилище MinIO (S3), освобождая сетевые потоки Uvicorn.
  2. Асинхронная детекция (YOLO): Тяжелый инференс сверточных нейросетей вынесен из API-слоя в изолированный воркер product-vision-processor, который транслирует графические пиксели в текстовый канонический класс предмета.
  3. Переиспользование контура защиты: После детекции текстовая строка автоматически направляется в уже существующий воркер цензуры (censorship-control-worker), что гарантирует соблюдение единых политик безопасности периметра (Fail-Close через Redis).

Протокол взаимодействия (HTTP Контракт)

  • Метод: POST
  • Маршрут: /api/v1/purchase/upload-product-photo
  • Формат данных: multipart/form-data

Спецификация заголовков (HTTP Headers)

Заголовок Обязательный Описание Пример значения
Content-Type Да Указывает на передачу составных данных формы (мультипарт) multipart/form-data; boundary=----WebKitFormBoundary...
Authorization Да Токен авторизации для извлечения user_id и Multi-Tenancy клейма home_group_id Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
X-Request-ID Да Сквозной ID запроса для трассировки сессии (FastAPI \(\rightarrow\) MinIO \(\rightarrow\) Kafka \(\rightarrow\) Workers) req-5f9c-2b1a-88ef
Accept Нет Ожидаемый формат ответа от бэкенд-шлюза application/json

Спецификация параметров запроса (Query Parameters)

Параметр Тип Обязательный Описание Пример значения
app_lang String Да Целевой язык приложения для адаптации системного промпта на этапе цензуры ru

Спецификация тела запроса (Request Body — Multipart FormData)

Поле Тип Обязательный Описание Пример значения
file Binary (File) Да Бинарный файл фотографии продукта (image/jpeg, image/png). Ограничение: до 10 МБ. snapshot.jpg
crop_type String Нет Режим кадрирования и предобработки матрицы для ИИ-воркера (default, square, raw) "square"

Пример сырого HTTP-запроса (Payload):

POST /api/v1/purchase/upload-product-photo?app_lang=ru HTTP/1.1
Host: foodlifecycle.com
Authorization: Bearer eyJhbGciOiJIUzI1Ni...
X-Request-ID: req-5f9c-2b1a-88ef
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="snapshot.jpg"
Content-Type: image/jpeg

[БИНАРНЫЕ ДАННЫЕ ИЗОБРАЖЕНИЯ]
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="crop_type"

square
------WebKitFormBoundary7MA4YWxkTrZu0gW--

Диаграмма последовательности (Mermaid)

sequenceDiagram
    autonumber
    
    actor App as APP (📱 Client)
    participant GW as GATEWAY (FastAPI)
    participant S3 as MinIO (S3 Storage)
    participant K as Broker: Kafka
    participant Vision as product-vision (YOLO)
    participant Censor as censorship-worker

    %% PART A: UPLOAD AND QUEUE PUSH
    App->>GW: POST /upload-product-photo (Multipart, lang)
    activate GW
    GW->>S3: PutObject: Save image file
    activate S3
    S3-->>GW: Return image_file_url
    deactivate S3
    note over GW: trace_id Generation & Payload Assembly
    GW->>K: Push to topic: bpds.inventory.in.product.image
    GW-->>App: HTTP 202 Accepted (Gateway released)
    deactivate GW

    %% PART B: YOLO DETECTION
    K->>Vision: Handler: ProcessProductImage()
    activate Vision
    Vision->>S3: GetObject: Download via URL
    activate S3
    S3-->>Vision: Binary graphic stream
    deactivate S3
    note over Vision: YOLO Inference:<br/>Contour localization and class detection
    Vision->>K: Push to topic: bpds.inventory.in.receipt.upload
    deactivate Vision

Image Upload, YOLO Detection, and Asynchronous Product Censorship Pipeline

sequenceDiagram
    autonumber
    
    actor App as APP (📱 Клиент)
    participant GW as GATEWAY (FastAPI)
    participant S3 as MinIO (S3 Storage)
    participant K as Брокер: Kafka
    participant Vision as product-vision (YOLO)
    participant Censor as censorship-worker

    %% ЧАСТЬ А: ЗАГРУЗКА И ПУШ В ОЧЕРЕДЬ
    App->>GW: POST /upload-product-photo (Multipart, lang)
    activate GW
    GW->>S3: PutObject: Сохранение файла изображения
    activate S3
    S3-->>GW: Возврат image_file_url
    deactivate S3
    note over GW: trace_id Generation & Payload Assembly
    GW->>K: Пуш в топик: bpds.inventory.in.product.image
    GW-->>App: HTTP 202 Accepted (Шлюз свободен)
    deactivate GW

    %% ЧАСТЬ Б: YOLO ДЕТЕКЦИЯ
    K->>Vision: Handler: ProcessProductImage()
    activate Vision
    Vision->>S3: GetObject: Скачивание по URL
    activate S3
    S3-->>Vision: Бинарный графический поток
    deactivate S3
    note over Vision: YOLO Inference:<br/>Локализация контуров и детекция класса
    Vision->>K: Пуш в топик: bpds.inventory.in.receipt.upload
    deactivate Vision

Процесс загрузки изображения, YOLO-детекции и асинхронного цензурирования продукта

Расшифровка шагов

ImportantDocumentation Under Development

This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.

  • Stable documentation version: Will be published upon final completion and validation of the method code.
Step Action Parameters / Requests / DTO Errors (Exceptions / Statuses)
1 (Gateway -> MinIO) The API Gateway captures the raw binary product photo (.jpg or .png) from the user’s mobile client, validates its size and media signature, and streams it to the S3 bucket. S3 API PUT Object Request:
Bucket: "product-images", Key: "uploads/2026/07/product_photo_202.jpg"
Headers: Content-Type: image/jpeg, Content-Length: 3145728
IAD-VISION-422: Unsupported mime-type or invalid file signature format.
IAD-VISION-413: File size exceeds the allowed 10 MB limit.
2 (MinIO -> Gateway) MinIO flushes the incoming image stream to disk arrays and returns an internal URL reference of the stored graphic object to the API Gateway. S3 API PUT Object Response:
HTTP Status: 200 OK
ETag: "4a28c319ba27d3322d8d8a7c5cb9c402", URL: https://minio.internal
No business errors
3 (Gateway -> T_Photo) The gateway constructs the initial computer vision task DTO, embeds application language metadata with the end-to-end trace ID, and publishes the message to the Kafka broker. Kafka Message (Topic: bpds.inventory.in.product.image):
Payload: { "image_file_url": "https://minio.internal", "app_lang": "ru-RU", "x_request_id": "trace-cv-censor-uuid" }
IAD-VAL-400: Mandatory payload metadata properties or structural parameters are missing.
4 (T_Photo -> ProductAI) The product-vision-processor microservice, subscribed to the product image topic, polls the next task event from the queue to run object analysis. Kafka Consumer Poll Request:
Group_ID: "product-cv-processors", Payload from Step 3 received.
Partition: 2, Offset: 99412
No business errors
5 (ProductAI -> MinIO) The computer vision service calls the S3 object store endpoint to fetch the image matrix binary stream into the temporary GPU/CPU memory allocation buffer. HTTP GET /product-images/uploads/2026/07/product_photo_202.jpg:
Headers: Internal Auth Tokens. Output: raw binary graphics byte stream.
IAD-VISION-404: Target source image asset was not found or deleted from storage before processing.
6 (ProductAI -> T_Results) The local YOLO model delineates object boundaries and maps them to a string representation of the item class. The outcome is pushed to the unified input topic along with the trace ID. Kafka Message (Topic: bpds.inventory.in.receipt.upload):
Payload: { "raw_text_input": "Груша Конференция", "app_lang": "ru-RU", "x_request_id": "trace-cv-censor-uuid" }
IAD-YOLO-422: Detection confidence score dropped below safety threshold or model classification failed.
Шаг Действие Параметры / Запросы / DTO Ошибки (Исключения / Статусы)
Шаг 1 (Gateway -> MinIO) API-шлюз принимает бинарный файл фотографии продукта (.jpg или .png) со смартфона пользователя, выполняет валидацию размера и сигнатуры медиафайла, после чего загружает его в S3-бакет. S3 API PUT Object Request:
Bucket: "product-images", Key: "uploads/2026/07/product_photo_202.jpg"
Headers: Content-Type: image/jpeg, Content-Length: 3145728
MinIOException: BucketNotFound
MinIOException: AccessDenied (неверные или просроченные учетные данные API Gateway)
StorageFullException
Шаг 2 (MinIO -> Gateway) MinIO сохраняет изображение на диски и возвращает API-шлюзу внутреннюю URL-ссылку на загруженный графический объект. S3 API PUT Object Response:
HTTP Статус: 200 OK
ETag: "4a28c319ba27d3322d8d8a7c5cb9c402", URL: https://minio.internal
MinIOException: ConnectionTimeout
DiskWriteError (критическая ошибка ввода-вывода или размонтирование RAID-массива)
Шаг 3 (Gateway -> T_Photo) Шлюз формирует стартовое DTO задачи компьютерного зрения, внедряет метаданные языка локали приложения, сквозной trace-id и отправляет сообщение в брокер Kafka. Kafka Message (Topic: bpds.inventory.in.product.image):
Payload: { "image_file_url": "https://minio.internal", "app_lang": "ru-RU", "x_request_id": "trace-cv-censor-uuid" }
FastAPI.ValidationError (передан некорректный URL или отсутствуют обязательные поля)
KafkaException: QueueFullException
MessageTimedOut
Шаг 4 (T_Photo -> ProductAI) Микросервис product-vision-processor, подписанный на топик изображений продуктов, вычитывает очередную задачу для проведения объектного анализа. Kafka Consumer Poll Request:
Group_ID: "product-cv-processors", Получен payload шага 3.
Partition: 2, Offset: 99412
KafkaException: CommitFailedException (зависание потока детекции, консьюмер выпал из группы по таймауту)
SerializationException
Шаг 5 (ProductAI -> MinIO) Сервис компьютерного зрения обращается к объектному хранилищу S3 для скачивания бинарной матрицы картинки во временный буфер памяти GPU/CPU. HTTP GET /product-images/uploads/2026/07/product_photo_202.jpg:
Headers: Internal Auth Tokens. На выходе: бинарный поток байт графического файла.
HTTP 404 Not Found (файл удален из бакета до начала обработки воркером)
HTTP 403 Forbidden
ConnectTimeout
Шаг 6 (ProductAI -> T_Results) Локальная нейросеть YOLO определяет границы объекта и транслирует его в строковое имя класса (например, ‘Груша’). Результат вместе с trace-id пушится в общий топик. Kafka Message (Topic: bpds.inventory.in.receipt.upload):
Payload: { "raw_text_input": "Груша Конференция", "app_lang": "ru-RU", "x_request_id": "trace-cv-censor-uuid" }
YOLOInferenceError (низкая уверенность модели или сбой CUDA ядра)
KafkaException: DeliveryTimeout
KafkaException: RecordTooLargeException

Спецификация ответов сервера (Response Body)

ImportantDocumentation Under Development

This documentation section is currently under development and may contain incomplete data. Some technical descriptions, parameters, and system operation scenarios for the digital business process simulator are subject to change.

  • Stable documentation version: Will be published upon final completion and validation of the method code.

1. Успешные ответы (Success Responses)

HTTP 202 Accepted (Успешный асинхронный ответ — Шаг 6)

Возвращается мобильному приложению шлюзом FastAPI Gateway мгновенно после успешного сохранения бинарного multipart-потока в MinIO S3 и публикации задачи в топик брокера сообщений Kafka.

  • Заголовки ответа (Response Headers):
    • Content-Type: application/json
  • Тело ответа (Response Body):
{
  "status": "PHOTO_UPLOAD_ACCEPTED",
  "data": {
    "trace_id": "req-5f9c-2b1a-88ef",
    "message": "Фотография успешно загружена в S3-хранилище и принята в пайплайн ИИ-детекции YOLO.",
    "processed_at": "2026-07-20T23:21:00Z"
  }
}

HTTP 201 Created (Асинхронный Исход 10а / Финальное авто-подтверждение)

Генерируется на финальном этапе обработки чека или фото после успешного прохождения цензуры, NER-распознавания и параллельной фиксации (Fan-Out) транзакций в инвентарных базах данных.

  • Заголовки ответа (Response Headers):
    • Content-Type: application/json
  • Тело ответа (Response Body):
{
  "status": "CONFIRMED",
  "product_name": "ГРУША",
  "applied_quantity": 1.0,
  "unit": "шт",
  "timestamp": "2026-07-20T23:21:00Z"
}

2. Спецификация ошибок и исключений (Error Responses)

Все ошибки бэкенда возвращаются в едином стандартизированном формате RFC 7807 (Problem Details) или стандартном JSON-формате FastAPI HTTPException. Это позволяет Flutter-клиенту (Dio) однозначно парсить код ошибки и выводить корректный локализованный текст на основе динамического справочника.

Исключение: Низкое качество изображения / Сбой распознавания (Асинхронный Исход 10б)

Формируется ИИ-воркером, если модель YOLO вернула score уверенности ниже порогового значения 0.85. Пайплайн инвентаризации приостанавливается, система генерирует черновик и отправляет пуш-контекст на UI через WebSocket.

{
  "error_code": "ERR-LOW-VISION-CONFIDENCE",
  "message": "Не удалось однозначно распознать продукт на фотографии. Требуется ручное подтверждение.",
  "details": {
    "yolo_score": 0.54,
    "image_snapshot_url": "s3://raw-images/uuid-99.jpg",
    "action": "Render interactive draft card on UI with user text-input field fallback."
  }
}

Ошибка загрузки и персистентности файла в бакет (HTTP 500 Internal Server Error — Шаг 2)

Выбрасывается шлюзом FastAPI, если внутренний кластер MinIO S3 недоступен, пул соединений переполнен или хранилище выдало отказ на прием бинарного потока put_object().

{
  "error_code": "ERR-BUCKET",
  "message": "Не удалось сохранить или верифицировать медиафайл во внутреннем объектном хранилище.",
  "details": {
    "reason": "MinIO S3 storage cluster rejected input stream or partition disk is full."
  }
}

Ошибка ИИ-цензурирования и детекции (Асинхронный Исход 10в — Шаг 14в)

Формируется воркером цензуры, если в процессе распознавания или анализа текстового класса модели YOLO локальная нейросеть Ollama через gRPC зафиксировала попытку инъекции кода в метаданные, мат, спам или деструктивный контент (is_profane == true).

{
  "error_code": "ERR-CENSOR",
  "message": "Изображение или распознанный текст класса не прошли автоматическую проверку политик безопасности.",
  "details": {
    "reason": "Spam, explicit content, or prompt injection pattern detected by Ollama Guardrails."
  }
}

Ошибка валидации структуры контракта (HTTP 422 Unprocessable Entity — Шаг 1.1)

Выбрасывается шлюзом FastAPI, если размер переданного файла превышает лимит в 10 МБ, либо нарушена multipart-структура тела запроса формы.

{
  "error_code": "IAD-VAL-422",
  "message": "Переданные данные формы или файл не соответствуют ожидаемой схеме валидации Pydantic.",
  "details": [
    {
      "loc": ["body", "file"],
      "msg": "Размер загружаемой фотографии продукта не должен превышать 10 МБ.",
      "type": "value_error.file.size_limit"
    }
  ]
}

Ошибка авторизации периметра (HTTP 401 Unauthorized — Триггер Interceptor)

Выбрасывается API-шлюзом на самом верхнем уровне, если Access Token просрочен, подпись заголовка изменена, либо токен заблокирован в черном списке.

{
  "error_code": "IAD_JWT_ACCESS_EXPIRED",
  "message": "Срок действия сессии авторизации истек. Доступ к ИИ-пайплайну отклонен.",
  "details": {
    "action": "Trigger queued token refresh mechanism using refresh_token underneath Dio Interceptor."
  }
}

Ошибка недоступности шины данных и периметра защиты (HTTP 503 Service Unavailable)

Выбрасывается шлюзом FastAPI (Шаг 5) при попытке пуша в топик bpds.inventory.in.product.image, если брокер Kafka лежит по таймауту, а также в рамках жесткой стратегии Fail-Close, если упала In-Memory Redis база проверки черных списков.

{
  "error_code": "ERR-INFRASTRUCTURE-OFFLINE",
  "message": "Сервис временно недоступен. Пожалуйста, повторите попытку позже.",
  "details": {
    "reason": "Kafka broker cluster connection timeout or Redis security check failure (Fail-Close enforced)."
  }
}