using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;
namespace Ban.Sdaid.Icd.Arch.Tech.CSharp
{
/// <summary>
/// ADR-SRV-005: Нормализация изображений через внешний сервис orthocover. Перекошенное фото страницы/формы →
/// выровненное «как со сканера» изображение для этапа «Проверка файлов». Интеграция за абстракцией
/// `IImageNormalizer`; запуск — ручной; обработанные хранятся рядом с оригиналом.
/// </summary>
public class ADR_SRV_005_ImageNormalizationOrthocover : IAdrDocument, IFolder<ArchCSharpFolder>
{
public string Name => "ADR-SRV-005. Нормализация изображений (orthocover)";
public string Description =>
@"Кадры пакета — это фото форм ИК (под углом, с фоном, с изгибом). Для проверки и распознавания нужен
вид «как со сканера». Фиксируем: нормализацию выполняет внешний ML-сервис **orthocover** за абстракцией
`IImageNormalizer`; запуск — ручной (кнопка на предобработке); обработанное изображение хранится рядом с
оригиналом, а кадр получает ссылку на него. Тип страницы для сервиса выводится из роли кадра.";
public string Version => "1.0";
public string Status => "accepted";
public string[] Comments => new[]
{
"2026-08-14. Принято при подключении orthocover (живой стенд) для этапа «Проверка файлов».",
};
public Type? Supersedes => null;
public static string S1_Context = """
## Контекст и постановка задачи
Оператор снимает форму ИК камерой рабочего места: кадр перекошен, с фоном и изгибом. Этап
«Проверка файлов» показывает переключение «оригинал ↔ обработанное», а распознавание полей идёт по
выровненному изображению. Значит нужен шаг **нормализации**: получить из фото чистое выровненное
изображение «как со сканера».
Писать свой пайплайн (сегментация/выравнивание/dewarp) — отдельный ML-проект. Есть готовый внешний
сервис **orthocover**, который это делает и попутно детектит штрихкоды. Нужно зафиксировать, как мы
его подключаем, когда запускаем и где храним результат, не завязывая прикладной код на конкретный
сервис.
""";
public static string S2_DecisionDrivers = """
## Драйверы решения
1. **Не строить свой ML** — переиспользовать готовый сервис нормализации.
2. **Изоляция** — прикладной код не должен зависеть от конкретного сервиса (сменяемость).
3. **Без фоновой инфраструктуры** — очереди/воркеров пока нет; запуск должен работать «здесь и сейчас».
4. **Предсказуемое хранение** — обработанное лежит рядом с оригиналом, доступно по варианту.
""";
public static string S3_ConsideredOptions = """
## Рассмотренные варианты
- **A (выбран).** Внешний **orthocover** по HTTP за абстракцией `IImageNormalizer`; ручной запуск;
обработанное — в файловом хранилище, ссылка — на кадре.
- **B.** Свой пайплайн нормализации (onnx/opencv) в процессе бэка. Тяжело, отдельный проект,
дублирует готовый сервис.
- **C.** Без нормализации, распознавать по оригиналу. Хуже качество, не соответствует этапу
«Проверка файлов».
""";
public static string S4_DecisionOutcome = """
## Решение
Выбран **Вариант A**.
### Абстракция и клиент
- `IImageNormalizer` (в `Ban.Icd.Infrastructure`, домен-нейтральна) — вход: байты изображения + тип
страницы; выход: обработанные изображения + метаданные (флаг качества/режим, штрихкоды).
- `OrthocoverImageNormalizer` — реализация поверх типизированного `HttpClient`.
### Контракт сервиса (orthocover)
- `POST {Orthocover:Url}/normalize` — **multipart/form-data**: `image` + `type` + `enhance`;
заголовок `X-API-Key` (если сервис требует).
- Ответ **multipart/mixed**: часть `meta` (JSON: `results[]` с `mode`/`flag`/`side`/`barcodes[]`) +
по PNG-части на каждый результат.
### Тип страницы из роли кадра
Роль штрихкода → `barcode` (только коды, без картинки); остальные роли → `text` (кроп листа + dewarp).
### Хранение результата
Обработанный PNG — в файловом хранилище под ключом `<номер пакета>/<NN>_<роль>_norm.png`
(схема ключей — ADR-002). Кадр получает ссылку на обработанное, флаг качества и время обработки.
Содержимое отдаётся тем же endpoint выдачи кадра с параметром `variant=normalized`.
### Запуск — ручной
Кнопка «повторить обработку» на предобработке: пер-кадровый вызов
`POST /api/InputPacket/{id}/frames/{order}/normalize` (есть и пакетный `.../normalize`). Обработка
синхронная (≈2–5 с/кадр). Сбой по кадру не валит остальные — фиксируется в сводке.
### Конфигурация
`Orthocover:Url` — в `appsettings` (не секрет). `Orthocover:ApiKey` — секрет: локально в
`appsettings.Local.json` (вне git) или переменной окружения; на стендах — через devops-генератор
конфигов (ADR-SRV-004). Пустой `Url` = интеграция не сконфигурирована (клиент вернёт понятную ошибку).
### Что не делаем сейчас
- Не запускаем нормализацию автоматически при сдаче пакета (нужна очередь — отложено).
- Не сохраняем штрихкоды/атрибуты (извлечение идентификаторов — отдельный этап).
- Не обрабатываем «разворот» (`spread`) — не встречается в ИК.
""";
public static string S5_PositiveConsequences = """
## Положительные следствия
- Готовое качество нормализации без своего ML.
- Прикладной код зависит от `IImageNormalizer`, а не от orthocover — сервис сменяем.
- Обработанное предсказуемо лежит рядом с оригиналом и доступно по варианту.
""";
public static string S6_NegativeConsequences = """
## Отрицательные следствия и компромиссы
- Синхронный ручной запуск блокирует запрос на ≈2–5 с/кадр — до введения очереди это осознанный
компромисс.
- Внешняя зависимость: недоступность сервиса → кадр не обработается (ошибка фиксируется, не падение).
""";
public static string S7_Validation = """
## Проверка
- Живой прогон против стенда: сдача пакета → запуск обработки → обработанный PNG отдаётся по
`variant=normalized`; у кадра выставлен признак «обработан».
- При недоступном сервисе запрос не падает — в сводке по кадру фиксируется ошибка.
""";
public static string S8_OpenQuestions = """
## Открытые вопросы / отложено
- **Автозапуск при сдаче** — вместе с фоновой очередью обработки.
- **Штрихкоды/идентификаторы** — сохранение и авто-подстановка на этапе полей/экземпляров.
- **Флаги качества** (`low_quality` → пересъёмка) — явный показ и действия оператору.
- **Пер-пакетный прогресс** — при многокадровых пакетах.
""";
public static string S99_Related = $"""
## Связанные артефакты
- {nameof(Ban.Sdaid.Icd.Api.Endpoints.InputPackets.NormalizePacket.DOC_NormalizePacket)} — контракт запуска обработки.
- {nameof(Ban.Sdaid.Icd.Backend.Handlers.InputPackets.NormalizePacketHandler)} — сценарий обработки.
- {nameof(Ban.Sdaid.Icd.Domain.Capture.ImageFrameSpec)} — поля обработанного изображения на кадре.
- {nameof(Ban.Sdaid.Icd.Arch.Adr.ADR_002_PacketIdentityAndFileKeys)} — ключи файлов (в т.ч. обработанного).
- {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_004_AppConfigAndCors)} — конфигурация/секреты по средам.
""";
}
}