⟨/⟩ 55_Backend/Recognition/FieldExtractionPrompt.cs

1437 строк · в начало

using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd.Domain.Cards;

namespace Ban.Sdaid.Icd.Backend.Recognition
{
    /// <summary>
    /// Запрос к модели распознавания: что передаётся вместе с кадром страницы и в каком виде
    /// ожидается ответ. Каталог полей приведён для обеих страниц формы «Издания из фондов БАН».
    /// </summary>
    public class FieldExtractionPrompt : IApplicationServiceDocument, IFolder<BackendFolder>
    {
        public static string _refName = "запрос к модели распознавания";

        public string Name => "Запрос на извлечение полей";

        public string Description =>
            @"Инструкция модели распознавания, каталог полей страницы и схема ответа. Собирается из конфигурации документа и формы, а не пишется руками.";

        public string Version => "0.2";
        public string Status => "draft";

        public string[] Comments => new[]
        {
            "2026-08-18. Первая редакция: страница 1 формы «Издания из фондов БАН» по образцам заказчика.",
            "2026-08-18. Добавлена страница 2 (оборот) по образцу инв. 74870: 81 отметка, 5 текстовых полей, 3 таблицы; в схему ответа введены таблицы.",
        };

        public static string S1_Structure = $"""
            ## Из чего состоит запрос

            Запрос к модели складывается из четырёх частей, и только первая написана прозой.

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

            **Каталог не пишется руками.** Он выводится из состава вида ИК и размещений на форме:
            код и тип берутся у атрибута, подпись — у размещения на конкретном бланке. Иначе
            добавление поля в спеку и в запрос к модели разъедутся при первой же правке.

            **Схему ответа передаём параметром, а не текстом.** Современные модели принимают
            JSON Schema отдельным полем запроса и физически не могут вернуть что-то другое;
            схема, вписанная в текст промта, — только пожелание.

            Образцы, по которым составлен каталог, — {nameof(CardSamples)}.
            """;

        public static string S2_Instruction = """
            ## Инструкция модели

            ```
            Ты извлекаешь данные из скана бумажной информационной карты Библиотеки Российской
            академии наук (форма «Издания из фондов БАН», страница 1).

            НА ИЗОБРАЖЕНИИ
            Бланк с типографскими подписями полей; значения вписаны от руки чернилами. Два блока:
            1. «Описание документального памятника» — таблица с текстовыми полями.
            2. «Консервация» — матрица отметок: строка «мероприятие», две колонки «Задано»
               и «Выполнено». Значение отметки — факт заполненности клетки любым знаком:
               крестик, галочка, косая черта, точка.

            ЗАДАЧА
            Для каждого поля из каталога верни распознанное значение, уверенность и область
            на изображении.

            ПРАВИЛА
            1. Не додумывай. Не читается — верни value: null, confidence: 0. Пустая клетка бланка —
               тоже null: незаполненные поля на этих картах обычны.
            2. Транскрибируй как написано, без исправлений орфографии и раскрытия сокращений.
               «105 д» остаётся «105 д».
            3. Если в клетке помимо значения есть уточнение, верни содержимое целиком:
               «5,83 перед форзац», а не «5,83».
            4. Отметку возвращай как true либо false. Любой знак в клетке — true, пустая — false.
            5. confidence — от 0 до 1, оценка того, что прочитано верно: печатный текст около 0.95,
               разборчивый рукописный около 0.7, неуверенное чтение ниже 0.5.
            6. bbox — [x, y, ширина, высота] в процентах от размера изображения, с одним знаком
               после запятой. Область охватывает значение, а не подпись поля.
            7. Часть текста на бланке впечатана типографски — например, описание экслибриса.
               Возвращай её как значение и ставь printed: true.
            8. Рукописный текст, не помещающийся ни в одно поле каталога, возвращай в notes:
               текст, область и подпись ближайшего поля.
            9. Если страница не похожа на описанную форму, верни form_match: false и не заполняй поля.
            ```
            """;

        public static string S3_TextFields = """
            ## Каталог: текстовые поля страницы 1

            Блок «Описание документального памятника», 29 полей.

            | Код | Подпись на бланке | Тип | Ограничения и замечания |
            |---|---|---|---|
            | `shelf` | Шифр | строка | обязательное; примеры: «105 д», «III 099» |
            | `inventory_no` | Инв. номер | строка | обязательное; цифры, иногда с буквой |
            | `card_date` | Дата | дата | обязательное; часто в виде «17.10.22» |
            | `author` | Автор | строка | |
            | `translator_compiler` | Перев., сост. и др. | строка | |
            | `title` | Заглавие | строка | до 500 знаков; поле в несколько строк |
            | `place` | Место издания | строка | |
            | `language` | Язык издания | строка | часто сокращённо: «рус.» |
            | `publisher` | Издатель (-ство) | строка | |
            | `printing_house` | Типография | строка | |
            | `binding_type` | Переплёт | строка | описание переплёта словами |
            | `year` | Год издания | число | от 1500 до текущего года |
            | `convolute` | Конволют | строка | есть не во всех редакциях бланка |
            | `alligate_count` | Количество аллигат | число | |
            | `alligate_no` | Номер алл. / тома, вып. | строка | |
            | `pages_count` | Кол-во стр. | число | подпись бывает «Количество страниц» |
            | `separate_ill_sheets` | Отд. листы ил. | строка | подпись бывает «Отдельные листы иллюстраций» |
            | `ill_in_text` | Ил. в тексте | строка | подпись бывает «Иллюстрации в тексте» |
            | `format` | Формат | строка | пишут дробью или парой чисел |
            | `manuscript_sheets` | Рук. листы | строка | подпись бывает «Рукописные листы» |
            | `bookplate` | Экслибрис | строка | |
            | `bookplate_description` | Описание экслибриса | строка | в части бланков впечатано типографски |
            | `private_library_evidence` | Др. свидетельства принадлежности к частной б-ке | строка | |
            | `academy_stamp` | Первонач. Акад. штамп | строка | |
            | `chamber_catalog` | Камерный каталог | строка | |
            | `marginalia` | Маргиналии | строка | |
            | `records` | Записи | строка | |
            | `acquisition_source` | Источ. поступ. | строка | есть не во всех редакциях бланка |
            | `comments` | Комментарии | строка | поле в несколько строк внизу блока |
            """;

        public static string S4_MarkFields = """
            ## Каталог: отметки блока «Консервация»

            Каждое мероприятие даёт **два поля** — «задано» и «выполнено», по числу клеток в строке.
            Итого 42 отметки.

            **Книга** — 10 мероприятий, коды с приставкой `book_`:

            | Мероприятие | Код «задано» | Код «выполнено» |
            |---|---|---|
            | Реконструкция | `book_reconstruction_assigned` | `book_reconstruction_done` |
            | Дезинфекция | `book_disinfection_assigned` | `book_disinfection_done` |
            | Дезинсекция | `book_disinsection_assigned` | `book_disinsection_done` |
            | Реставрация | `book_restoration_assigned` | `book_restoration_done` |
            | Ремонт | `book_repair_assigned` | `book_repair_done` |
            | Суперобложка | `book_jacket_assigned` | `book_jacket_done` |
            | Инкапсулирование | `book_encapsulation_assigned` | `book_encapsulation_done` |
            | Конвертирование | `book_enveloping_assigned` | `book_enveloping_done` |
            | Гигиеническая обработка | `book_hygienic_assigned` | `book_hygienic_done` |
            | Помещение в контейнер | `book_container_assigned` | `book_container_done` |

            **Переплёт** — 5 мероприятий, приставка `binding_`: реконструкция
            (`binding_reconstruction_*`), реставрация (`binding_restoration_*`), ремонт
            (`binding_repair_*`), чистка (`binding_cleaning_*`), умягчение (`binding_softening_*`).

            **Блок** — 3 мероприятия, приставка `block_`: реставрация (`block_restoration_*`),
            нейтрализация (`block_neutralization_*`), ремонт (`block_repair_*`).

            **Условия хранения** — 3 позиции, приставка `storage_`: вертикальное
            (`storage_vertical_*`), горизонтальное (`storage_horizontal_*`), другое
            (`storage_other_*`).

            Все поля этого блока имеют тип «отметка»: значение true либо false, ограничений нет.
            """;

        public static string S41_Page2Structure = """
            ## Страница 2: устройство бланка

            Оборот целиком посвящён состоянию памятника и его обследованиям. Текстовых полей
            почти нет: страница — это матрицы отметок и три журнальные таблицы.

            | Блок | Что содержит | Чем описывается |
            |---|---|---|
            | Сохранность | размеры экземпляра в мм | 3 числа |
            | Переплёт | состояние, состав, материалы, декор | 21 отметка |
            | Повреждения переплёта | физико-механические, биологические; степень | 17 отметок + 9 отметок степени |
            | Блок | состояние, состав тетрадей и листов | 9 отметок |
            | Повреждения блока | физико-механические, биологические; степень; величина pH | 16 отметок + 9 отметок степени + 1 текст |
            | Мониторинг | биотест и текущая биологическая экспертиза | 2 таблицы |
            | Эксперт | кто и когда проводил экспертизу | 1 таблица |
            | Комментарий | свободный рукописный текст | 1 текст |

            Итого 81 отметка, 5 текстовых полей и 3 таблицы.

            **Степень повреждения — тоже отметки.** На бланке это три клетки «Низкая», «Средняя»,
            «Высокая», и заполнена бывает любая из них либо ни одной. Модель отмечает заполненность
            клеток; то, что значения взаимоисключающие, — правило состава, а не задача распознавания.
            Своя тройка степени есть у каждой группы повреждений: физико-механических,
            микробиологических, энтомологических — и отдельно для переплёта и для блока.

            **Три таблицы — повторяющиеся группы.** Число строк заранее неизвестно, строки
            заполняются по мере обследований. Поэтому в ответе они идут не полями, а массивом строк
            (см. схему ответа): каждая строка — набор тех же полей.

            **Поля за пределами клеток.** На образце справа от строк степени повреждения рукой
            приписано «нет» — вне какого-либо поля бланка. Такое возвращается в `notes` с указанием
            ближайшего поля, а не приписывается наугад к соседней клетке.
            """;

        public static string S42_Page2Marks = """
            ## Каталог: отметки страницы 2

            **Переплёт**, приставка `bnd_` — 21 отметка:

            | Группа | Позиции и коды |
            |---|---|
            | Состояние | не повреждён `bnd_state_intact`, повреждён `bnd_state_damaged`, утрачен `bnd_state_lost`, ранее подвергался реставрации `bnd_state_restored_before` |
            | Состав | комбинированный `bnd_comp_combined`, цельный `bnd_comp_solid` |
            | Материалы покрытия | кожа `bnd_cover_leather`, пергамент `bnd_cover_parchment`, ткань `bnd_cover_fabric`, бумага `bnd_cover_paper` |
            | Материалы основы | дерево `bnd_base_wood`, картон `bnd_base_cardboard`, др. материалы `bnd_base_other` |
            | Декор · тиснение | слепое `bnd_dec_blind`, золотое `bnd_dec_gold` |
            | Декор · украшения | накладки `bnd_dec_overlays`, застёжки `bnd_dec_clasps`, металл `bnd_dec_metal` |
            | Декор · обрез | золото `bnd_edge_gold`, др. виды `bnd_edge_other`, тиснение `bnd_edge_tooled` |

            **Повреждения переплёта**, приставка `bnd_` — 17 отметок:

            | Группа | Позиции и коды |
            |---|---|
            | Физико-механические | оторван `bnd_dmg_torn_off`, утраты `bnd_dmg_losses`, разрывы `bnd_dmg_tears`, деформация `bnd_dmg_deformation`, пятна `bnd_dmg_stains`, затёки `bnd_dmg_tidelines`, изменения окраски `bnd_dmg_discoloration`, разрушения `bnd_dmg_destruction`, ломкость `bnd_dmg_brittleness` |
            | Микробиологические | биологическая пигментация `bnd_bio_pigmentation`, колонии микромицетов `bnd_bio_colonies`, биологическое разрушение `bnd_bio_destruction`, жизнеспособная микрофлора `bnd_bio_viable_microflora` |
            | Энтомологические | личиночные ходы `bnd_ent_larval_tunnels`, экзувии `bnd_ent_exuviae`, личинки `bnd_ent_larvae`, имаго `bnd_ent_imago` |

            **Блок**, приставка `blk_` — 9 отметок состава и состояния:

            | Группа | Позиции и коды |
            |---|---|
            | Состояние | не повреждён `blk_state_intact`, повреждён `blk_state_damaged`, ранее подвергался реставрации `blk_state_restored_before` |
            | Тетради | выпадают `blk_quires_falling`, отсутствуют `blk_quires_missing`, нарушено шитьё `blk_sewing_broken` |
            | Листы | выпадают `blk_sheets_falling`, отсутствуют `blk_sheets_missing`, повреждения `blk_sheets_damaged` |

            **Повреждения блока**, приставка `blk_` — 16 отметок:

            | Группа | Позиции и коды |
            |---|---|
            | Физико-механические | утраты `blk_dmg_losses`, разрывы `blk_dmg_tears`, деформация `blk_dmg_deformation`, затёки `blk_dmg_tidelines`, изменения окраски `blk_dmg_discoloration`, разрушения `blk_dmg_destruction`, ломкость `blk_dmg_brittleness`, пятна `blk_dmg_stains` |
            | Микробиологические | `blk_bio_pigmentation`, `blk_bio_colonies`, `blk_bio_destruction`, `blk_bio_viable_microflora` |
            | Энтомологические | `blk_ent_larval_tunnels`, `blk_ent_exuviae`, `blk_ent_larvae`, `blk_ent_imago` |

            **Степень повреждения** — 18 отметок: по три клетки (`_low`, `_medium`, `_high`)
            на каждую из шести троек:

            `bnd_deg_physmech_*`, `bnd_deg_bio_*`, `bnd_deg_ento_*`,
            `blk_deg_physmech_*`, `blk_deg_bio_*`, `blk_deg_ento_*`.
            """;

        public static string S43_Page2Tables = """
            ## Каталог: текстовые поля и таблицы страницы 2

            **Текстовые поля** — 5:

            | Код | Подпись на бланке | Тип | Замечания |
            |---|---|---|---|
            | `dim_length` | Размеры (мм): Длина | число | |
            | `dim_width` | Размеры (мм): Ширина | число | |
            | `dim_height` | Размеры (мм): Высота | число | |
            | `blk_ph` | Величина pH | строка | не число: пишут с уточнением места замера — «5,83 перед форзацем» |
            | `page2_comment` | Комментарий | строка | рукописный текст в несколько строк внизу страницы |

            **Таблица «Биотест»**, код `biotest`:

            | Код колонки | Подпись | Тип |
            |---|---|---|
            | `seq_no` | № П/П | число |
            | `placed_at` | Дата закладки | дата |
            | `performer` | Исполнитель | строка |

            **Таблица «Текущая биологическая экспертиза»**, код `bio_expertise`:

            | Код колонки | Подпись | Тип |
            |---|---|---|
            | `examined_at` | Дата экспертизы | дата |
            | `performer` | Исполнитель | строка |
            | `result` | Результат | строка |

            **Таблица «Эксперт»**, код `experts`:

            | Код колонки | Подпись | Тип |
            |---|---|---|
            | `role` | должность в левой колонке | строка |
            | `examined_at` | Дата экспертизы | дата |
            | `person` | Ф И О | строка |
            | `signature` | Подпись | строка |
            | `result` | Результат | строка |

            Про подпись и должность: в левой колонке таблицы «Эксперт» на образце вписано
            «Микробиолог» и «Консерватор» — это не подпись бланка, а значение. Колонка `signature`
            содержит росчерк, а не текст: разбирать его не нужно, достаточно отметить, что он есть.
            """;

        public static string S45_Payload = """
            ## Готовый текст запроса

            Ниже — то, что отправляется модели одним сообщением вместе с кадром страницы.
            Инструкция и каталог полей идут подряд; схема ответа передаётся отдельным параметром
            запроса, а не текстом.

            Каталог здесь приведён для страницы 1 формы «Издания из фондов БАН» и должен
            собираться Сервисом из состава вида ИК: этот текст — образец того, что получается
            на выходе, а не то, что правится руками.

            ```text
            Ты извлекаешь данные из скана бумажной информационной карты Библиотеки Российской
            академии наук (форма «Издания из фондов БАН», страница 1).

            НА ИЗОБРАЖЕНИИ
            Бланк с типографскими подписями полей; значения вписаны от руки чернилами. Два блока:
            1. «Описание документального памятника» — таблица с текстовыми полями.
            2. «Консервация» — матрица отметок: строка «мероприятие», две колонки «Задано»
               и «Выполнено». Значение отметки — факт заполненности клетки любым знаком:
               крестик, галочка, косая черта, точка.

            ЗАДАЧА
            Для каждого поля из каталога верни распознанное значение, уверенность и область
            на изображении. Ответ — JSON по заданной схеме, без пояснений вокруг него.

            ПРАВИЛА
            1. Не додумывай. Не читается — value: null, confidence: 0. Пустая клетка бланка —
               тоже null: незаполненные поля на этих картах обычны.
            2. Транскрибируй как написано, без исправлений орфографии и раскрытия сокращений.
            3. Если в клетке помимо значения есть уточнение, верни содержимое целиком:
               «5,83 перед форзац», а не «5,83».
            4. Отметку возвращай как true либо false. Любой знак в клетке — true, пустая — false.
            5. confidence — от 0 до 1: печатный текст около 0.95, разборчивый рукописный около 0.7,
               неуверенное чтение ниже 0.5.
            6. bbox — [x, y, ширина, высота] в процентах от размера изображения, с одним знаком
               после запятой. Область охватывает значение, а не подпись поля.
            7. Текст, впечатанный в бланк типографски, возвращай как значение с printed: true.
            8. Рукописный текст, не помещающийся ни в одно поле каталога, возвращай в notes:
               текст, область и подпись ближайшего поля.
            9. Если страница не похожа на описанную форму, верни form_match: false и не заполняй поля.

            КАТАЛОГ ПОЛЕЙ
            {
              "form": "Издания из фондов БАН, страница 1",
              "fields": [
                {
                  "code": "shelf",
                  "label": "Шифр",
                  "type": "string",
                  "required": true,
                  "hint": "примеры: «105 д», «III 099»"
                },
                {
                  "code": "inventory_no",
                  "label": "Инв. номер",
                  "type": "string",
                  "required": true
                },
                {
                  "code": "card_date",
                  "label": "Дата",
                  "type": "date",
                  "required": true,
                  "hint": "часто в виде «17.10.22»"
                },
                {
                  "code": "author",
                  "label": "Автор",
                  "type": "string"
                },
                {
                  "code": "translator_compiler",
                  "label": "Перев., сост. и др.",
                  "type": "string"
                },
                {
                  "code": "title",
                  "label": "Заглавие",
                  "type": "string",
                  "max": 500
                },
                {
                  "code": "place",
                  "label": "Место издания",
                  "type": "string"
                },
                {
                  "code": "language",
                  "label": "Язык издания",
                  "type": "string",
                  "hint": "часто сокращённо: «рус.»"
                },
                {
                  "code": "publisher",
                  "label": "Издатель (-ство)",
                  "type": "string"
                },
                {
                  "code": "printing_house",
                  "label": "Типография",
                  "type": "string"
                },
                {
                  "code": "binding_type",
                  "label": "Переплёт",
                  "type": "string"
                },
                {
                  "code": "year",
                  "label": "Год издания",
                  "type": "number",
                  "min": 1500,
                  "max": 2026
                },
                {
                  "code": "convolute",
                  "label": "Конволют",
                  "type": "string",
                  "hint": "есть не во всех редакциях бланка"
                },
                {
                  "code": "alligate_count",
                  "label": "Количество аллигат",
                  "type": "number"
                },
                {
                  "code": "alligate_no",
                  "label": "Номер алл. / тома, вып.",
                  "type": "string"
                },
                {
                  "code": "pages_count",
                  "label": "Кол-во стр.",
                  "type": "number",
                  "hint": "подпись бывает «Количество страниц»"
                },
                {
                  "code": "separate_ill_sheets",
                  "label": "Отд. листы ил.",
                  "type": "string",
                  "hint": "подпись бывает «Отдельные листы иллюстраций»"
                },
                {
                  "code": "ill_in_text",
                  "label": "Ил. в тексте",
                  "type": "string",
                  "hint": "подпись бывает «Иллюстрации в тексте»"
                },
                {
                  "code": "format",
                  "label": "Формат",
                  "type": "string"
                },
                {
                  "code": "manuscript_sheets",
                  "label": "Рук. листы",
                  "type": "string"
                },
                {
                  "code": "bookplate",
                  "label": "Экслибрис",
                  "type": "string"
                },
                {
                  "code": "bookplate_description",
                  "label": "Описание экслибриса",
                  "type": "string",
                  "hint": "в части бланков впечатано типографски"
                },
                {
                  "code": "private_library_evidence",
                  "label": "Др. свидетельства принадлежности к частной б-ке",
                  "type": "string"
                },
                {
                  "code": "academy_stamp",
                  "label": "Первонач. Акад. штамп",
                  "type": "string"
                },
                {
                  "code": "chamber_catalog",
                  "label": "Камерный каталог",
                  "type": "string"
                },
                {
                  "code": "marginalia",
                  "label": "Маргиналии",
                  "type": "string"
                },
                {
                  "code": "records",
                  "label": "Записи",
                  "type": "string"
                },
                {
                  "code": "acquisition_source",
                  "label": "Источ. поступ.",
                  "type": "string",
                  "hint": "есть не во всех редакциях бланка"
                },
                {
                  "code": "comments",
                  "label": "Комментарии",
                  "type": "string"
                },
                {
                  "code": "book_reconstruction_assigned",
                  "label": "Книга · Реконструкция · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_reconstruction_done",
                  "label": "Книга · Реконструкция · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_disinfection_assigned",
                  "label": "Книга · Дезинфекция · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_disinfection_done",
                  "label": "Книга · Дезинфекция · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_disinsection_assigned",
                  "label": "Книга · Дезинсекция · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_disinsection_done",
                  "label": "Книга · Дезинсекция · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_restoration_assigned",
                  "label": "Книга · Реставрация · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_restoration_done",
                  "label": "Книга · Реставрация · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_repair_assigned",
                  "label": "Книга · Ремонт · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_repair_done",
                  "label": "Книга · Ремонт · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_jacket_assigned",
                  "label": "Книга · Суперобложка · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_jacket_done",
                  "label": "Книга · Суперобложка · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_encapsulation_assigned",
                  "label": "Книга · Инкапсулирование · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_encapsulation_done",
                  "label": "Книга · Инкапсулирование · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_enveloping_assigned",
                  "label": "Книга · Конвертирование · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_enveloping_done",
                  "label": "Книга · Конвертирование · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_hygienic_assigned",
                  "label": "Книга · Гигиеническая обработка · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_hygienic_done",
                  "label": "Книга · Гигиеническая обработка · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "book_container_assigned",
                  "label": "Книга · Помещение в контейнер · Задано",
                  "type": "bool"
                },
                {
                  "code": "book_container_done",
                  "label": "Книга · Помещение в контейнер · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "binding_reconstruction_assigned",
                  "label": "Переплёт · Реконструкция · Задано",
                  "type": "bool"
                },
                {
                  "code": "binding_reconstruction_done",
                  "label": "Переплёт · Реконструкция · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "binding_restoration_assigned",
                  "label": "Переплёт · Реставрация · Задано",
                  "type": "bool"
                },
                {
                  "code": "binding_restoration_done",
                  "label": "Переплёт · Реставрация · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "binding_repair_assigned",
                  "label": "Переплёт · Ремонт · Задано",
                  "type": "bool"
                },
                {
                  "code": "binding_repair_done",
                  "label": "Переплёт · Ремонт · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "binding_cleaning_assigned",
                  "label": "Переплёт · Чистка · Задано",
                  "type": "bool"
                },
                {
                  "code": "binding_cleaning_done",
                  "label": "Переплёт · Чистка · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "binding_softening_assigned",
                  "label": "Переплёт · Умягчение · Задано",
                  "type": "bool"
                },
                {
                  "code": "binding_softening_done",
                  "label": "Переплёт · Умягчение · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "block_restoration_assigned",
                  "label": "Блок · Реставрация · Задано",
                  "type": "bool"
                },
                {
                  "code": "block_restoration_done",
                  "label": "Блок · Реставрация · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "block_neutralization_assigned",
                  "label": "Блок · Нейтрализация · Задано",
                  "type": "bool"
                },
                {
                  "code": "block_neutralization_done",
                  "label": "Блок · Нейтрализация · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "block_repair_assigned",
                  "label": "Блок · Ремонт · Задано",
                  "type": "bool"
                },
                {
                  "code": "block_repair_done",
                  "label": "Блок · Ремонт · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "storage_vertical_assigned",
                  "label": "Условия хранения · Вертикальное · Задано",
                  "type": "bool"
                },
                {
                  "code": "storage_vertical_done",
                  "label": "Условия хранения · Вертикальное · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "storage_horizontal_assigned",
                  "label": "Условия хранения · Горизонтальное · Задано",
                  "type": "bool"
                },
                {
                  "code": "storage_horizontal_done",
                  "label": "Условия хранения · Горизонтальное · Выполнено",
                  "type": "bool"
                },
                {
                  "code": "storage_other_assigned",
                  "label": "Условия хранения · Другое · Задано",
                  "type": "bool"
                },
                {
                  "code": "storage_other_done",
                  "label": "Условия хранения · Другое · Выполнено",
                  "type": "bool"
                }
              ]
            }
            ```
            """;

        public static string S46_PayloadPage2 = """
            ## Готовый текст запроса: страница 2

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

            ```text
            Ты извлекаешь данные из скана бумажной информационной карты Библиотеки Российской
            академии наук (форма «Издания из фондов БАН», страница 2, оборот).

            НА ИЗОБРАЖЕНИИ
            Бланк описания сохранности; значения проставлены от руки чернилами. Четыре части:
            1. «Сохранность» — размеры экземпляра в миллиметрах.
            2. «Переплёт» и «Блок» — матрицы отметок: строка «свойство», клетки по столбцам
               («Кожа», «Картон», «Низкая», «Средняя», «Высокая» и прочие). Значение отметки —
               факт заполненности клетки любым знаком: крестик, галочка, косая черта, точка.
            3. «Мониторинг» и «Эксперт» — журнальные таблицы, заполняются построчно
               по мере обследований; число заполненных строк заранее неизвестно.
            4. «Комментарий» — свободный рукописный текст внизу страницы.

            ЗАДАЧА
            Для каждого поля из каталога верни распознанное значение, уверенность и область
            на изображении. Ответ — JSON по заданной схеме, без пояснений вокруг него.

            ПРАВИЛА
            1. Не додумывай. Не читается — value: null, confidence: 0. Пустая клетка бланка —
               тоже null: незаполненные поля на этих картах обычны.
            2. Транскрибируй как написано, без исправлений орфографии и раскрытия сокращений.
            3. Если в клетке помимо значения есть уточнение, верни содержимое целиком:
               «5,83 перед форзацем», а не «5,83».
            4. Отметку возвращай как true либо false. Любой знак в клетке — true, пустая — false.
            5. Степень повреждения — три отдельные клетки. Отмечай заполненные; не выбирай одну
               из трёх и не выводи её из других полей.
            6. confidence — от 0 до 1: печатный текст около 0.95, разборчивый рукописный около 0.7,
               неуверенное чтение ниже 0.5.
            7. bbox — [x, y, ширина, высота] в процентах от размера изображения, с одним знаком
               после запятой. Область охватывает значение, а не подпись поля.
            8. Таблицы каталога возвращай в tables: по одной строке ответа на каждую заполненную
               строку бланка, в порядке сверху вниз. Пустые строки таблицы пропускай.
            9. Подпись эксперта не разбирай: если росчерк есть — «есть», если нет — null.
            10. Рукописный текст, не помещающийся ни в одно поле каталога, возвращай в notes:
                текст, область и код ближайшего поля. На этом бланке приписки на полях обычны.
            11. Если страница не похожа на описанную форму, верни form_match: false
                и не заполняй поля.

            КАТАЛОГ ПОЛЕЙ
            {
              "form": "Издания из фондов БАН, страница 2 (оборот)",
              "fields": [
                {
                  "code": "dim_length",
                  "label": "Размеры (мм) · Длина",
                  "type": "number"
                },
                {
                  "code": "dim_width",
                  "label": "Размеры (мм) · Ширина",
                  "type": "number"
                },
                {
                  "code": "dim_height",
                  "label": "Размеры (мм) · Высота",
                  "type": "number"
                },
                {
                  "code": "bnd_state_intact",
                  "label": "Переплёт · Состояние · Не повреждён",
                  "type": "bool"
                },
                {
                  "code": "bnd_state_damaged",
                  "label": "Переплёт · Состояние · Повреждён",
                  "type": "bool"
                },
                {
                  "code": "bnd_state_lost",
                  "label": "Переплёт · Состояние · Утрачен",
                  "type": "bool"
                },
                {
                  "code": "bnd_state_restored_before",
                  "label": "Переплёт · Состояние · Ранее подвергался реставрации",
                  "type": "bool"
                },
                {
                  "code": "bnd_comp_combined",
                  "label": "Переплёт · Состав · Комбинированный",
                  "type": "bool"
                },
                {
                  "code": "bnd_comp_solid",
                  "label": "Переплёт · Состав · Цельный",
                  "type": "bool"
                },
                {
                  "code": "bnd_cover_leather",
                  "label": "Переплёт · Материалы покрытия · Кожа",
                  "type": "bool"
                },
                {
                  "code": "bnd_cover_parchment",
                  "label": "Переплёт · Материалы покрытия · Пергамент",
                  "type": "bool"
                },
                {
                  "code": "bnd_cover_fabric",
                  "label": "Переплёт · Материалы покрытия · Ткань",
                  "type": "bool"
                },
                {
                  "code": "bnd_cover_paper",
                  "label": "Переплёт · Материалы покрытия · Бумага",
                  "type": "bool"
                },
                {
                  "code": "bnd_base_wood",
                  "label": "Переплёт · Материалы основы · Дерево",
                  "type": "bool"
                },
                {
                  "code": "bnd_base_cardboard",
                  "label": "Переплёт · Материалы основы · Картон",
                  "type": "bool"
                },
                {
                  "code": "bnd_base_other",
                  "label": "Переплёт · Материалы основы · Др. материалы",
                  "type": "bool"
                },
                {
                  "code": "bnd_dec_blind",
                  "label": "Переплёт · Декор · Тиснение · Слепое",
                  "type": "bool"
                },
                {
                  "code": "bnd_dec_gold",
                  "label": "Переплёт · Декор · Тиснение · Золотое",
                  "type": "bool"
                },
                {
                  "code": "bnd_dec_overlays",
                  "label": "Переплёт · Декор · Украшения · Накладки",
                  "type": "bool"
                },
                {
                  "code": "bnd_dec_clasps",
                  "label": "Переплёт · Декор · Украшения · Застёжки",
                  "type": "bool"
                },
                {
                  "code": "bnd_dec_metal",
                  "label": "Переплёт · Декор · Украшения · Металл",
                  "type": "bool"
                },
                {
                  "code": "bnd_edge_gold",
                  "label": "Переплёт · Декор · Обрез · Золото",
                  "type": "bool"
                },
                {
                  "code": "bnd_edge_other",
                  "label": "Переплёт · Декор · Обрез · Др. виды",
                  "type": "bool"
                },
                {
                  "code": "bnd_edge_tooled",
                  "label": "Переплёт · Декор · Обрез · Тиснение",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_torn_off",
                  "label": "Повреждения переплёта · Физико-механические · Оторван",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_losses",
                  "label": "Повреждения переплёта · Физико-механические · Утраты",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_tears",
                  "label": "Повреждения переплёта · Физико-механические · Разрывы",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_deformation",
                  "label": "Повреждения переплёта · Физико-механические · Деформация",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_stains",
                  "label": "Повреждения переплёта · Физико-механические · Пятна",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_tidelines",
                  "label": "Повреждения переплёта · Физико-механические · Затёки",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_discoloration",
                  "label": "Повреждения переплёта · Физико-механические · Изменения окраски",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_destruction",
                  "label": "Повреждения переплёта · Физико-механические · Разрушения",
                  "type": "bool"
                },
                {
                  "code": "bnd_dmg_brittleness",
                  "label": "Повреждения переплёта · Физико-механические · Ломкость",
                  "type": "bool"
                },
                {
                  "code": "bnd_bio_pigmentation",
                  "label": "Повреждения переплёта · Микробиологические · Биологическая пигментация",
                  "type": "bool"
                },
                {
                  "code": "bnd_bio_colonies",
                  "label": "Повреждения переплёта · Микробиологические · Колонии микромицетов",
                  "type": "bool"
                },
                {
                  "code": "bnd_bio_destruction",
                  "label": "Повреждения переплёта · Микробиологические · Биологическое разрушение",
                  "type": "bool"
                },
                {
                  "code": "bnd_bio_viable_microflora",
                  "label": "Повреждения переплёта · Микробиологические · Жизнеспособная микрофлора",
                  "type": "bool"
                },
                {
                  "code": "bnd_ent_larval_tunnels",
                  "label": "Повреждения переплёта · Энтомологические · Личиночные ходы",
                  "type": "bool"
                },
                {
                  "code": "bnd_ent_exuviae",
                  "label": "Повреждения переплёта · Энтомологические · Экзувии",
                  "type": "bool"
                },
                {
                  "code": "bnd_ent_larvae",
                  "label": "Повреждения переплёта · Энтомологические · Личинки",
                  "type": "bool"
                },
                {
                  "code": "bnd_ent_imago",
                  "label": "Повреждения переплёта · Энтомологические · Имаго",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_physmech_low",
                  "label": "Переплёт · Степень повреждения · Физико-механические · Низкая",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_physmech_medium",
                  "label": "Переплёт · Степень повреждения · Физико-механические · Средняя",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_physmech_high",
                  "label": "Переплёт · Степень повреждения · Физико-механические · Высокая",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_bio_low",
                  "label": "Переплёт · Степень повреждения · Микробиологические · Низкая",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_bio_medium",
                  "label": "Переплёт · Степень повреждения · Микробиологические · Средняя",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_bio_high",
                  "label": "Переплёт · Степень повреждения · Микробиологические · Высокая",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_ento_low",
                  "label": "Переплёт · Степень повреждения · Энтомологические · Низкая",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_ento_medium",
                  "label": "Переплёт · Степень повреждения · Энтомологические · Средняя",
                  "type": "bool"
                },
                {
                  "code": "bnd_deg_ento_high",
                  "label": "Переплёт · Степень повреждения · Энтомологические · Высокая",
                  "type": "bool"
                },
                {
                  "code": "blk_state_intact",
                  "label": "Блок · Состояние · Не повреждён",
                  "type": "bool"
                },
                {
                  "code": "blk_state_damaged",
                  "label": "Блок · Состояние · Повреждён",
                  "type": "bool"
                },
                {
                  "code": "blk_state_restored_before",
                  "label": "Блок · Состояние · Ранее подвергался реставрации",
                  "type": "bool"
                },
                {
                  "code": "blk_quires_falling",
                  "label": "Блок · Тетради · Выпадают",
                  "type": "bool"
                },
                {
                  "code": "blk_quires_missing",
                  "label": "Блок · Тетради · Отсутствуют",
                  "type": "bool"
                },
                {
                  "code": "blk_sewing_broken",
                  "label": "Блок · Тетради · Нарушено шитьё",
                  "type": "bool"
                },
                {
                  "code": "blk_sheets_falling",
                  "label": "Блок · Листы · Выпадают",
                  "type": "bool"
                },
                {
                  "code": "blk_sheets_missing",
                  "label": "Блок · Листы · Отсутствуют",
                  "type": "bool"
                },
                {
                  "code": "blk_sheets_damaged",
                  "label": "Блок · Листы · Повреждения",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_losses",
                  "label": "Повреждения блока · Физико-механические · Утраты",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_tears",
                  "label": "Повреждения блока · Физико-механические · Разрывы",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_deformation",
                  "label": "Повреждения блока · Физико-механические · Деформация",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_tidelines",
                  "label": "Повреждения блока · Физико-механические · Затёки",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_discoloration",
                  "label": "Повреждения блока · Физико-механические · Изменения окраски",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_destruction",
                  "label": "Повреждения блока · Физико-механические · Разрушения",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_brittleness",
                  "label": "Повреждения блока · Физико-механические · Ломкость",
                  "type": "bool"
                },
                {
                  "code": "blk_dmg_stains",
                  "label": "Повреждения блока · Физико-механические · Пятна",
                  "type": "bool"
                },
                {
                  "code": "blk_bio_pigmentation",
                  "label": "Повреждения блока · Микробиологические · Биологическая пигментация",
                  "type": "bool"
                },
                {
                  "code": "blk_bio_colonies",
                  "label": "Повреждения блока · Микробиологические · Колонии микромицетов",
                  "type": "bool"
                },
                {
                  "code": "blk_bio_destruction",
                  "label": "Повреждения блока · Микробиологические · Биологическое разрушение",
                  "type": "bool"
                },
                {
                  "code": "blk_bio_viable_microflora",
                  "label": "Повреждения блока · Микробиологические · Жизнеспособная микрофлора",
                  "type": "bool"
                },
                {
                  "code": "blk_ent_larval_tunnels",
                  "label": "Повреждения блока · Энтомологические · Личиночные ходы",
                  "type": "bool"
                },
                {
                  "code": "blk_ent_exuviae",
                  "label": "Повреждения блока · Энтомологические · Экзувии",
                  "type": "bool"
                },
                {
                  "code": "blk_ent_larvae",
                  "label": "Повреждения блока · Энтомологические · Личинки",
                  "type": "bool"
                },
                {
                  "code": "blk_ent_imago",
                  "label": "Повреждения блока · Энтомологические · Имаго",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_physmech_low",
                  "label": "Блок · Степень повреждения · Физико-механические · Низкая",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_physmech_medium",
                  "label": "Блок · Степень повреждения · Физико-механические · Средняя",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_physmech_high",
                  "label": "Блок · Степень повреждения · Физико-механические · Высокая",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_bio_low",
                  "label": "Блок · Степень повреждения · Микробиологические · Низкая",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_bio_medium",
                  "label": "Блок · Степень повреждения · Микробиологические · Средняя",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_bio_high",
                  "label": "Блок · Степень повреждения · Микробиологические · Высокая",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_ento_low",
                  "label": "Блок · Степень повреждения · Энтомологические · Низкая",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_ento_medium",
                  "label": "Блок · Степень повреждения · Энтомологические · Средняя",
                  "type": "bool"
                },
                {
                  "code": "blk_deg_ento_high",
                  "label": "Блок · Степень повреждения · Энтомологические · Высокая",
                  "type": "bool"
                },
                {
                  "code": "blk_ph",
                  "label": "Величина pH",
                  "type": "string",
                  "hint": "пишут с уточнением места замера: «5,83 перед форзацем»"
                },
                {
                  "code": "page2_comment",
                  "label": "Комментарий",
                  "type": "string"
                }
              ],
              "tables": [
                {
                  "code": "biotest",
                  "label": "Биотест",
                  "columns": [
                    {
                      "code": "seq_no",
                      "label": "№ П/П",
                      "type": "number"
                    },
                    {
                      "code": "placed_at",
                      "label": "Дата закладки",
                      "type": "date"
                    },
                    {
                      "code": "performer",
                      "label": "Исполнитель",
                      "type": "string"
                    }
                  ]
                },
                {
                  "code": "bio_expertise",
                  "label": "Текущая биологическая экспертиза",
                  "columns": [
                    {
                      "code": "examined_at",
                      "label": "Дата экспертизы",
                      "type": "date"
                    },
                    {
                      "code": "performer",
                      "label": "Исполнитель",
                      "type": "string"
                    },
                    {
                      "code": "result",
                      "label": "Результат",
                      "type": "string"
                    }
                  ]
                },
                {
                  "code": "experts",
                  "label": "Эксперт",
                  "columns": [
                    {
                      "code": "role",
                      "label": "Должность",
                      "type": "string"
                    },
                    {
                      "code": "examined_at",
                      "label": "Дата экспертизы",
                      "type": "date"
                    },
                    {
                      "code": "person",
                      "label": "Ф И О",
                      "type": "string"
                    },
                    {
                      "code": "signature",
                      "label": "Подпись",
                      "type": "string",
                      "hint": "росчерк не разбирать: «есть» либо null"
                    },
                    {
                      "code": "result",
                      "label": "Результат",
                      "type": "string"
                    }
                  ]
                }
              ]
            }
            ```
            """;

        public static string S5_ResponseSchema = """
            ## Схема ответа

            ```json
            {
              "type": "object",
              "required": ["form_match", "values"],
              "properties": {
                "form_match": { "type": "boolean" },
                "values": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": ["code", "value", "confidence"],
                    "properties": {
                      "code":       { "type": "string" },
                      "value":      { "type": ["string", "number", "boolean", "null"] },
                      "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
                      "printed":    { "type": "boolean" },
                      "bbox":       { "type": "array", "minItems": 4, "maxItems": 4,
                                      "items": { "type": "number" } }
                    }
                  }
                },
                "tables": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": ["code", "rows"],
                    "properties": {
                      "code": { "type": "string" },
                      "rows": {
                        "type": "array",
                        "items": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": ["code", "value", "confidence"],
                            "properties": {
                              "code":       { "type": "string" },
                              "value":      { "type": ["string", "number", "null"] },
                              "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
                              "bbox":       { "type": "array", "minItems": 4, "maxItems": 4,
                                              "items": { "type": "number" } }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "notes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": ["text", "bbox"],
                    "properties": {
                      "text":       { "type": "string" },
                      "bbox":       { "type": "array", "minItems": 4, "maxItems": 4,
                                      "items": { "type": "number" } },
                      "near_field": { "type": "string" }
                    }
                  }
                }
              }
            }
            ```

            Пример ответа по образцу инв. 74870, где заполнены только шифр и инвентарный номер:

            ```json
            {
              "form_match": true,
              "values": [
                { "code": "shelf",        "value": "105 д", "confidence": 0.58, "bbox": [25, 14.4, 12, 2.1] },
                { "code": "inventory_no", "value": "74870", "confidence": 0.77, "bbox": [57, 14.3, 15, 2.1] },
                { "code": "card_date",    "value": null,    "confidence": 0 },
                { "code": "title",        "value": null,    "confidence": 0 },
                { "code": "bookplate_description",
                  "value": "Овальный штамп сажевый гербовый: орёл с саблей под графской короной",
                  "confidence": 0.96, "printed": true, "bbox": [34, 38.4, 32, 3.7] },
                { "code": "book_restoration_assigned", "value": true,  "confidence": 0.88, "bbox": [27, 68.2, 8, 2.7] },
                { "code": "book_restoration_done",     "value": false, "confidence": 0.9 }
              ],
              "notes": []
            }
            ```

            Фрагмент ответа по обороту того же образца — с таблицей и с припиской вне полей:

            ```json
            {
              "form_match": true,
              "values": [
                { "code": "bnd_state_damaged",   "value": true,  "confidence": 0.85 },
                { "code": "bnd_comp_combined",   "value": true,  "confidence": 0.83 },
                { "code": "bnd_cover_paper",     "value": true,  "confidence": 0.8 },
                { "code": "bnd_base_cardboard",  "value": true,  "confidence": 0.82 },
                { "code": "bnd_edge_other",      "value": true,  "confidence": 0.72 },
                { "code": "bnd_deg_physmech_high", "value": true, "confidence": 0.79 },
                { "code": "blk_ph", "value": "5,83 перед форзацем", "confidence": 0.54,
                  "bbox": [11.8, 59.1, 17.5, 2.4] }
              ],
              "tables": [
                {
                  "code": "bio_expertise",
                  "rows": [
                    [
                      { "code": "examined_at", "value": "11.01.23",   "confidence": 0.74 },
                      { "code": "performer",   "value": "Тишева З.А.", "confidence": 0.41 },
                      { "code": "result",      "value": "отр.",        "confidence": 0.38 }
                    ]
                  ]
                },
                {
                  "code": "experts",
                  "rows": [
                    [
                      { "code": "role",        "value": "микробиолог", "confidence": 0.46 },
                      { "code": "examined_at", "value": "20.01.23",    "confidence": 0.68 },
                      { "code": "person",      "value": "Тишева",      "confidence": 0.39 },
                      { "code": "signature",   "value": "есть",        "confidence": 0.9 }
                    ],
                    [
                      { "code": "role",        "value": "консерватор",   "confidence": 0.52 },
                      { "code": "examined_at", "value": "23.01.23",      "confidence": 0.66 },
                      { "code": "person",      "value": "Колотилкина Е.В.", "confidence": 0.44 },
                      { "code": "signature",   "value": "есть",          "confidence": 0.9 }
                    ]
                  ]
                }
              ],
              "notes": [
                { "text": "нет", "bbox": [88.2, 47.1, 5.4, 2.0],
                  "near_field": "bnd_deg_ento_low" }
              ]
            }
            ```

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

        public static string S6_Risks = """
            ## Чего ожидать от модели

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

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

            **Уверенность модели — не вероятность.** Это её собственная оценка, склонная к завышению
            на рукописном тексте. Пороги отсечения имеет смысл подбирать по размеченным образцам,
            а не назначать умозрительно.
            """;

        public static string S99_Related = $"""
            ## Связанные артефакты

            - {nameof(Ban.Sdaid.Icd.Requirements.FR_003_AttributeExtraction)} — требование к извлечению атрибутов
            - {nameof(Ban.Sdaid.Icd.Arch.Adr.ADR_006_CardDataStructure)} — структура данных карты, откуда берётся каталог полей
            - {nameof(CardSamples)} — образцы, по которым составлен каталог
            """;
    }
}