Finetuning completed for yolo26n-indian-fmcg-detection and minicpm5-1b-indian-fmcg-normalizer
7b5611f | from __future__ import annotations | |
| import logging | |
| import time | |
| from typing import List, Tuple | |
| from models import AnomalyFlag, NormalisedInvoice, DeliveryCountMap, AgentTraceEntry | |
| from tracer import make_trace_entry | |
| logger = logging.getLogger(__name__) | |
| AGENT_NAME = "Reconciliation_Agent" | |
| AGENT_VERSION = "1.0.0" | |
| class ReconciliationAgent: | |
| def run( | |
| self, | |
| invoice: NormalisedInvoice, | |
| delivery_count_map: DeliveryCountMap, | |
| audit_run_id: str, | |
| ) -> Tuple[List[AnomalyFlag], List[str], AgentTraceEntry]: | |
| t_start = time.monotonic() | |
| flags: List[AnomalyFlag] = [] | |
| invoiced_product_ids: set[str] = set() | |
| for item in invoice.items: | |
| if item.product_id is None: | |
| continue | |
| invoiced_product_ids.add(item.product_id) | |
| delivered = delivery_count_map.get(item.product_id, 0) | |
| if item.quantity > delivered: | |
| shortage = item.quantity - delivered | |
| flags.append(AnomalyFlag( | |
| flag_type="delivery_shortage", | |
| product_id=item.product_id, | |
| product_name=item.product_normalized or item.product_raw, | |
| amount_inr=shortage * item.unit_price, | |
| description=( | |
| f"{item.product_normalized or item.product_raw}: " | |
| f"invoiced {item.quantity}, delivered {delivered}, short {shortage}" | |
| ), | |
| action_item=( | |
| f"Request delivery of {shortage:.0f} missing " | |
| f"{item.product_normalized or item.product_raw} " | |
| f"or credit note for ₹{shortage * item.unit_price:.2f}" | |
| ), | |
| metadata={ | |
| "invoice_quantity": item.quantity, | |
| "delivered_quantity": delivered, | |
| "shortage_quantity": shortage, | |
| "unit_price": item.unit_price, | |
| }, | |
| )) | |
| # Products in delivery photos but NOT on invoice | |
| unexpected = [ | |
| pid for pid in delivery_count_map | |
| if pid not in invoiced_product_ids | |
| ] | |
| t_end = time.monotonic() | |
| n_flags = len(flags) | |
| n_unexpected = len(unexpected) | |
| trace = make_trace_entry( | |
| agent_name=AGENT_NAME, | |
| agent_version=AGENT_VERSION, | |
| audit_run_id=audit_run_id, | |
| t_start=t_start, | |
| t_end=t_end, | |
| input_summary=( | |
| f"{len(invoice.items)} invoice items; " | |
| f"{len(delivery_count_map)} delivery entries" | |
| ), | |
| output_summary=f"{n_flags} shortage flags; {n_unexpected} unexpected deliveries", | |
| ) | |
| return flags, unexpected, trace | |