"""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)