feat(Ф1): контракты стадий + parse_multipart + store_document
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
"""Контракты стадий пайплайна — frozen dataclass на выходах, dict на входах."""
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional
|
||||
from datetime import date
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ParseResult:
|
||||
"""Выход parse.py — результат парсинга документа."""
|
||||
status: str # 'parsed' | 'error'
|
||||
element_count: int # количество извлечённых элементов
|
||||
elements: list # [{type, text/rows}, ...]
|
||||
error: Optional[str] = None # сообщение об ошибке (если status='error')
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: dict):
|
||||
"""Из строки БД (documents)."""
|
||||
return cls(
|
||||
status=row.get("status", "error"),
|
||||
element_count=0, # вычисляется отдельно
|
||||
elements=row.get("elements_json", []),
|
||||
error=row.get("error_message"),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ClassifyResult:
|
||||
"""Выход classify.py — результат классификации документа."""
|
||||
doc_type: str # 'contract' | 'supplement' | 'specification' | 'garbage' | 'other'
|
||||
own_number: Optional[str] = None
|
||||
parent_number: Optional[str] = None
|
||||
doc_date: Optional[str] = None
|
||||
counterparty: Optional[str] = None
|
||||
|
||||
@classmethod
|
||||
def from_llm(cls, raw: dict):
|
||||
"""Из сырого ответа LLM."""
|
||||
return cls(
|
||||
doc_type=raw.get("doc_type", "other"),
|
||||
own_number=raw.get("own_number") or None,
|
||||
parent_number=raw.get("parent_number") or None,
|
||||
doc_date=raw.get("doc_date") or None,
|
||||
counterparty=raw.get("counterparty") or None,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GroupingResult:
|
||||
"""Выход grouping.py — результат группировки по контрактам."""
|
||||
contract_number: str # нормализованный номер договора
|
||||
counterparty: Optional[str] = None
|
||||
documents: list = field(default_factory=list) # [{doc_id, filename, doc_type, ...}]
|
||||
unresolved: list = field(default_factory=list) # документы без группы
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: dict):
|
||||
"""Из строки БД или вычисленной группы."""
|
||||
return cls(
|
||||
contract_number=row.get("contract_number", ""),
|
||||
counterparty=row.get("counterparty"),
|
||||
documents=row.get("documents", []),
|
||||
unresolved=row.get("unresolved", []),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CompareOp:
|
||||
"""Одна операция сравнения (ADD/UPDATE/DELETE/UNRESOLVED)."""
|
||||
action: str # 'ADD' | 'UPDATE' | 'DELETE' | 'UNRESOLVED'
|
||||
new_row: Optional[dict] = None
|
||||
new_values: Optional[dict] = None
|
||||
target_hash: Optional[str] = None
|
||||
comment: str = ""
|
||||
|
||||
@classmethod
|
||||
def from_llm(cls, raw: dict):
|
||||
"""Из сырого ответа LLM."""
|
||||
return cls(
|
||||
action=raw.get("action", "UNRESOLVED"),
|
||||
new_row=raw.get("new_row") or None,
|
||||
new_values=raw.get("new_values") or None,
|
||||
target_hash=raw.get("target_hash") or raw.get("target_id"),
|
||||
comment=raw.get("comment", ""),
|
||||
)
|
||||
Reference in New Issue
Block a user