kirana-detective / models.py
naazimsnh02's picture
Finetuning completed for yolo26n-indian-fmcg-detection and minicpm5-1b-indian-fmcg-normalizer
7b5611f
Raw
History Blame
5.27 kB
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Dict, List, Literal, Optional
# ── Line item ────────────────────────────────────────────────────────────────
@dataclass
class InvoiceLineItem:
product_raw: str
product_normalized: Optional[str] = None
product_id: Optional[str] = None
quantity: float = 0.0
unit_price: float = 0.0
gst_rate: float = 0.0
line_total: float = 0.0
# ── Invoice JSON ──────────────────────────────────────────────────────────────
@dataclass
class InvoiceJSON:
invoice_number: Optional[str] = None
supplier: Optional[str] = None
date: Optional[str] = None
items: List[InvoiceLineItem] = field(default_factory=list)
grand_total: float = 0.0
extraction_warnings: List[str] = field(default_factory=list)
unmatched_products: List[str] = field(default_factory=list)
NormalisedInvoice = InvoiceJSON
# ── Anomaly flags ─────────────────────────────────────────────────────────────
FlagType = Literal[
"price_anomaly",
"delivery_shortage",
"duplicate_charge",
"gst_mismatch",
"duplicate_invoice",
]
@dataclass
class AnomalyFlag:
flag_type: FlagType
product_id: Optional[str] = None
product_name: Optional[str] = None
amount_inr: float = 0.0
description: str = ""
action_item: str = ""
metadata: dict = field(default_factory=dict)
# ── Leakage report ────────────────────────────────────────────────────────────
@dataclass
class LeakageReport:
audit_run_id: str
invoice_number: Optional[str] = None
supplier: Optional[str] = None
date: Optional[str] = None
anomaly_flags: List[AnomalyFlag] = field(default_factory=list)
total_leakage_inr: float = 0.0
action_items: List[str] = field(default_factory=list)
has_delivery_data: bool = False
unexpected_deliveries: List[str] = field(default_factory=list)
low_confidence_photos: List[str] = field(default_factory=list)
skipped_price_checks: int = 0
skipped_gst_checks: int = 0
passed_all_checks: bool = False
# ── Agent trace ───────────────────────────────────────────────────────────────
@dataclass
class AgentTraceEntry:
agent_name: str
agent_version: str
audit_run_id: str
timestamp_start: str # ISO 8601 UTC
timestamp_end: str
duration_ms: int
input_summary: str
output_summary: str
CANONICAL_AGENT_ORDER: List[str] = [
"Invoice_Extractor",
"Product_Matcher",
"Pricing_Agent",
"Visual_Counter",
"Reconciliation_Agent",
"Savings_Agent",
]
# ── Catalog entry ─────────────────────────────────────────────────────────────
@dataclass
class CatalogEntry:
product_id: str
canonical_name: str
hsn_code: str
gst_rate: float
category: str
brand: str
common_aliases: List[str] = field(default_factory=list)
# ── Type aliases ──────────────────────────────────────────────────────────────
DeliveryCountMap = Dict[str, int]
# ── Progress streaming ────────────────────────────────────────────────────────
AuditStage = Literal[
"extracting",
"normalising",
"checking_prices",
"counting_products",
"reconciling",
"generating_report",
"complete",
"error",
]
@dataclass
class AuditProgressUpdate:
stage: AuditStage
message: str = ""
agent_name: str = ""
duration_ms: int = 0
# ── Pricing agent metadata ────────────────────────────────────────────────────
@dataclass
class PricingAgentMeta:
skipped_price_checks: int = 0
skipped_gst_checks: int = 0