using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;
using Ban.Sdaid.Icd.Api.Based;
namespace Ban.Sdaid.Icd.Api.Endpoints.Recognition.ClassifyFrame
{
/// <summary>Документ-обёртка над endpoint опознания формы и страницы кадра (геометрический детектор).</summary>
public class DOC_ClassifyFrame : IApiContractDocument, IFolder<ApiFolder>, IHasStructuralLinks
{
public SdaidLink[] Links => new[]
{
Rel.Uses<Ban.Sdaid.Icd.Backend.Handlers.Recognition.ClassifyFrameHandler>(),
};
public static string _refName = "Endpoint ClassifyFrame";
public string Name => "Endpoint: ClassifyFrame";
public string Description =>
@"Опознание формы и страницы кадра: по эталонным профилям детектор относит кадр к форме/странице и возвращает уверенность и ближайшие альтернативы. Основной запуск — автоматический в фоновой очереди (ADR-014); endpoint — ручной повтор/инспекция. Поведение — ClassifyFrameHandler.";
public string Version => "0.1";
public string Status => "draft";
public string[] Comments => new string[0];
public static string Transport = """
## Транспорт
- `POST /api/InputPacket/{id}/frames/{order}/classify` — опознать **один** кадр.
- `POST /api/InputPacket/{id}/classify` — опознать **все** кадры пакета.
Параметры — в пути, тела запроса нет. Ответ — единая обёртка со сводкой по кадрам
(форма, страница, уверенность, альтернативы).
Штатно опознание выполняет фоновая очередь автоматически (ADR-014): результат уже готов
к моменту, когда пакет берёт оператор. Этот endpoint — ручной повтор (после пересъёмки/правки
состава кадров) и инспекция результата; окончательное слово за оператором (выбор формы вручную
авторитетнее детектора, ADR-015).
""";
public static string Body = $"""
## Command
{SdaidCode.OfClass<ClassifyFrameCommand>()}
## Result
{SdaidCode.OfClass<ClassifyFrameResult>()}
## Payload
{SdaidCode.OfClass<ClassifiedPacketPayload>()}
## FrameInfo
{SdaidCode.OfClass<ClassifiedFrameInfo>()}
## Candidate
{SdaidCode.OfClass<FormCandidate>()}
""";
}
/// <summary>Команда опознания: `FrameOrder` задан — один кадр; null — все кадры пакета.</summary>
public class ClassifyFrameCommand : BasedCommand
{
public Guid PacketId { get; init; }
/// <summary>Порядковый номер кадра; null — опознать все кадры.</summary>
public int? FrameOrder { get; init; }
}
/// <summary>Результат опознания (обёртка + сводка по кадрам).</summary>
public class ClassifyFrameResult : BasedResult
{
public ClassifiedPacketPayload? Payload { get; init; }
}
/// <summary>Итог: сколько кадров опознано/не опознано и результат по каждому.</summary>
public class ClassifiedPacketPayload
{
public Guid PacketId { get; init; }
public int Recognized { get; init; }
public int Unrecognized { get; init; }
public ClassifiedFrameInfo[] Frames { get; init; } = new ClassifiedFrameInfo[0];
}
/// <summary>Результат опознания одного кадра.</summary>
public class ClassifiedFrameInfo
{
public int Order { get; init; }
/// <summary>Опознанная форма; null — вид не опознан.</summary>
public Guid? FormId { get; init; }
/// <summary>Наименование опознанной формы; null — вид не опознан.</summary>
public string? FormName { get; init; }
/// <summary>Номер страницы опознанной формы; null — вид не опознан.</summary>
public int? PageNumber { get; init; }
/// <summary>Уверенность — отрыв лучшего кандидата от второго места (больше = увереннее).</summary>
public double Confidence { get; init; }
/// <summary>Ближайшие альтернативы (для ручного выбора оператором при низкой уверенности).</summary>
public FormCandidate[] Alternatives { get; init; } = new FormCandidate[0];
/// <summary>Причина, если вид не опознан (нет подходящей формы / уверенность ниже порога); null — успех.</summary>
public string? Error { get; init; }
}
/// <summary>Кандидат опознания: форма, страница и её оценка соответствия (меньше — ближе).</summary>
public class FormCandidate
{
public Guid FormId { get; init; }
public string FormName { get; init; } = "";
public int PageNumber { get; init; }
public double Score { get; init; }
}
}