"""Core route optimizer — sorts classified items into warehouse traversal order.""" from costco_route.config import ZONES, ZONE_ORDER def generate_route(classified: dict[str, list[str]], learned_overrides: dict[str, dict] | None = None) -> list[dict]: """Generate a route-optimized shopping list. Args: classified: LLM-classified items {zone_id: [items]} learned_overrides: Override from ChromaDB {item_name: {zone, notes, ...}} Returns: List of zone dicts in traversal order, each with zone info and items. """ if learned_overrides: classified = _apply_overrides(classified, learned_overrides) route = [] for zone_id in ZONE_ORDER: items = classified.get(zone_id, []) if not items: continue zone_info = ZONES.get(zone_id, {"name": f"Zone {zone_id}"}) route.append({ "zone_id": zone_id, "zone_name": zone_info["name"], "items": items, }) return route def _apply_overrides(classified: dict[str, list[str]], overrides: dict[str, dict]) -> dict[str, list[str]]: """Move items to their learned zones, overriding LLM classification. If an item was classified to zone X by the LLM but the user previously calibrated it to zone Y, move it to zone Y. """ # Build a lookup: item_lower → override zone override_map = {} for item_name, override_info in overrides.items(): override_map[item_name.lower().strip()] = override_info["zone"] # Rebuild classified dict with overrides applied result = {} for zone_id, items in classified.items(): remaining = [] for item in items: key = item.lower().strip() if key in override_map: # Move to the learned zone instead target_zone = override_map[key] result.setdefault(target_zone, []) result[target_zone].append(item) else: remaining.append(item) if remaining: result[zone_id] = remaining return result def format_route(route: list[dict], store_name: str = "Green Bay Bellevue") -> str: """Format a route into a Telegram-friendly shopping list. Args: route: Output from generate_route() store_name: Display name for the warehouse Returns: Formatted string ready for Telegram. """ lines = [f"šŸ›’ Costco Route — {store_name}"] total_items = 0 zone_count = len(route) for zone in route: lines.append(f"\nšŸ“¦ Zone {zone['zone_id']} — {zone['zone_name']}") for item in zone["items"]: lines.append(f" ☐ {item}") total_items += 1 # Estimate time: ~2 min per zone + 1 min per item, minimum 15 min est_minutes = max(15, zone_count * 2 + total_items) lines.append(f"\nāœ… {total_items} items across {zone_count} zones — ~{est_minutes} min") return "\n".join(lines) def format_route_markdown(route: list[dict], store_name: str = "Green Bay Bellevue") -> str: """Format a route with markdown (for CLI / non-Telegram output). Same as format_route but with markdown checkboxes for copy-paste. """ lines = [f"## šŸ›’ Costco Route — {store_name}"] total_items = 0 zone_count = len(route) for zone in route: lines.append(f"\n### Zone {zone['zone_id']} — {zone['zone_name']}") for item in zone["items"]: lines.append(f"- [ ] {item}") total_items += 1 est_minutes = max(15, zone_count * 2 + total_items) lines.append(f"\n**{total_items} items across {zone_count} zones — ~{est_minutes} min**") return "\n".join(lines)