Files

120 lines
5.1 KiB
Python

"""
extractor.py — Извлечение строк спецификации из текста документа.
Берёт распарсенный текст (parsed_text из documents), отправляет LLM,
получает структурированный список строк спецификации.
Не зависит от parser.py, textify.py, upload.py.
Зависит только от llm_client.py.
"""
import json
import llm_client
def extract(parsed_text: str, custom_prompt: str = None) -> dict:
"""
Извлечь строки спецификации из текста документа через LLM.
Args:
parsed_text: текст документа (выдача textify.py)
custom_prompt: свой промпт (если None — используется DEFAULT_PROMPT)
Returns:
{"rows": [...], "unresolved": [...]} или {"error": "..."}
"""
prompt = custom_prompt or DEFAULT_PROMPT
prompt = prompt.replace("{parsed_text}", parsed_text)
"""
extractor.py — Извлечение строк спецификации из текста документа.
Берёт распарсенный текст (parsed_text из documents), отправляет LLM,
получает структурированный список строк спецификации.
Не зависит от parser.py, textify.py, upload.py.
Зависит только от llm_client.py.
"""
import json
import llm_client
# ── Промпт по умолчанию ─────────────────────────────────────────
# {parsed_text} будет заменён на текст документа
DEFAULT_PROMPT = """Ты — анализатор договоров. Ниже текст спецификации услуг из договора облачного провайдера.
Найди ВСЕ таблицы со списком услуг. Извлеки каждую строку в JSON-массив.
Для каждой строки верни:
- row_num: номер по порядку (целое число)
- name: полное наименование услуги (весь текст из ячейки)
- price: цена за единицу в рублях (число, из колонки "Цена")
- qty: количество/объём (число, из колонки "Объем")
- sum: итоговая сумма (число, из колонки "Сумма")
- date_start: дата начала оказания (строка YYYY-MM-DD)
ПРАВИЛА:
1. Пропускай итоговые строки ("Итого...") и строки с подписями.
2. Если ячейка пустая — ставь null.
3. Если не можешь определить значение — ставь null и добавь в unresolved.
4. Верни ТОЛЬКО JSON, без пояснений.
Пример ответа:
{{"rows":[{{"row_num":1,"name":"Аренда стойко-места","price":213905.44,"qty":3,"sum":641716.32,"date_start":"2026-04-01"}}],"unresolved":[]}}
Текст документа:
---
{parsed_text}
---
"""
def extract(parsed_text: str, custom_prompt: str = None) -> dict:
"""
Извлечь строки спецификации из текста документа через LLM.
Args:
parsed_text: текст документа (выдача textify.py)
custom_prompt: свой промпт (если None — DEFAULT_PROMPT).
Должен содержать {parsed_text} для подстановки текста.
Returns:
{"rows": [...], "unresolved": [...]} или {"error": "..."}
"""
prompt = (custom_prompt or DEFAULT_PROMPT).replace("{parsed_text}", parsed_text)
# ── Вызов LLM ────────────────────────────────────────────────
result = llm_client.ask(prompt, max_tokens=8000)
if "error" in result:
return {"error": result["error"]}
# ── Парсинг ответа ───────────────────────────────────────────
raw_text = result.get("text", "")
try:
# Найти JSON в ответе (может быть обёрнут в ```json ... ```)
json_text = raw_text
if "```json" in json_text:
json_text = json_text.split("```json")[1].split("```")[0]
elif "```" in json_text:
json_text = json_text.split("```")[1].split("```")[0]
data = json.loads(json_text.strip())
rows = data.get("rows", [])
unresolved = data.get("unresolved", [])
return {
"rows": rows,
"unresolved": unresolved,
"model": result.get("model", ""),
"usage": result.get("usage", {}),
}
except (json.JSONDecodeError, IndexError, KeyError) as e:
return {
"error": f"parse_failed: {e}",
"raw_response": raw_text[:1000],
}