diff --git a/site/llm_prompt.py b/site/llm_prompt.py index 3fb3f7c..da106c9 100644 --- a/site/llm_prompt.py +++ b/site/llm_prompt.py @@ -279,3 +279,84 @@ def build_classify_prompt(header_text): {header_text} ---""".replace("{header_text}", header_text) return body, "" + + +def build_stateless_extractor_prompt(structured_text): + """Собрать изолированный prompt для извлечения фактов из одного документа. + + В отличие от `build_prompt`, эта функция не читает активный prompt из БД, + не получает текущую спецификацию и не может подмешать результаты обработки + других файлов. Единственный изменяемый вход — текст текущего документа. + """ + instructions = """Ты — извлекатель проверяемых фактов из документов договорного архива ООО «НУБЕС». + Проанализируй только один документ ниже. Не используй сведения из других документов, + предыдущие версии спецификаций или внешние знания. Верни ровно один JSON-объект без + markdown, пояснений, комментариев и текста до или после объекта. + + Схема ответа: + { + "doc_class": "contract_frame | specification | supplement | ignored_accounting", + "intent_mode": "no_spec | full_snapshot | delta_amendment | termination", + "own_number": null, + "own_date": null, + "counterparty": {"name": null, "inn": null}, + "referenced_contracts": [ + {"number": "номер как в документе", "date": null, "source": "header | preamble | appendix | other"} + ], + "sections": [ + { + "table_ref": "table_1", + "section_title": null, + "charge_type": "one_time | recurring | payg | unknown", + "period_start": null, + "period_end": null, + "header_stated_total": null, + "table_footer_total": null, + "vat_mode": "with_vat | without_vat | vat_unknown", + "rows": [ + { + "row_ref": "table_1_row_1", + "raw_name": "наименование дословно", + "charge_type": "one_time | recurring | payg | unknown", + "unit": null, + "qty": null, + "price": null, + "sum": null, + "date_start": null, + "date_end": null, + "date_status": "explicit | inherited | unknown", + "delta_action": "snapshot | add | update | delete | unresolved | unknown", + "target_hint": null + } + ] + } + ] + } + + Правила извлечения: + 1. Выбирай только значения из этого документа. Для отсутствующих или неразборчивых + значений используй JSON null; не угадывай и не восстанавливай данные по контексту. + 2. Исполнитель всегда ООО «НУБЕС», ИНН 9706005293. Никогда не записывай его в + counterparty; counterparty — только другая сторона, если она явно установлена. + 3. Перечисли все номера и даты договоров из шапки, преамбулы и заголовков приложений + в referenced_contracts. Не объединяй разные номера, даже если один выглядит опечаткой. + 4. Для рамочного договора без спецификации укажи intent_mode="no_spec". Для документа, + полностью задающего состав услуг, укажи "full_snapshot"; для точечных изменений — + "delta_amendment"; для прекращения обязательств — "termination". + 5. Каждую таблицу услуг верни отдельной секцией. Контекст над таблицей применяй к ней: + даты периода наследуй в строки только когда в строке нет собственной даты; тогда + date_status="inherited". Иначе ставь "explicit" или "unknown". + 6. Не включай итоговые строки в rows. Их суммы указывай в table_footer_total; + сумму из заголовка секции указывай в header_stated_total. + 7. Числа верни JSON-числами с точкой как десятичным разделителем, без валюты и + разделителей тысяч. Не вычисляй и не исправляй price, qty, sum или итоги. + 8. Если документ является счетом, счетом-фактурой, УПД, актом сверки, актом услуг, + платежным поручением или иным бухгалтерским документом, укажи + doc_class="ignored_accounting", intent_mode="no_spec", пустые sections. + 9. Не выдумывай target_hint: указывай его только если сам документ однозначно называет + изменяемую строку или услугу. Сохраняй исходное написание raw_name. + + СТРУКТУРИРОВАННЫЙ ТЕКСТ ЕДИНСТВЕННОГО ДОКУМЕНТА: + --- + """ + return instructions + str(structured_text or "") + "\n---"