import re from app.data_loader import loader class IntentParser: def __init__(self): pass def parse(self, text): text = text.lower() response = { "intent": "general_chat", # Default to LLM "item_code": None, "location": None, "horizon_days": None, "extra": {} } # 1. Detect Intent (order matters - more specific checks first) if any(x in text for x in ["list items", "show catalog", "what items", "available items", "list available", "show items"]): response["intent"] = "list_items" elif any(x in text for x in ["forecast", "demand", "predict", "future", "sales"]): response["intent"] = "demand_forecast" elif any(x in text for x in ["details", "info", "about", "price", "description"]): response["intent"] = "item_details" elif any(x in text for x in ["inventory", "stock", "how many", "available", "on hand"]): response["intent"] = "check_inventory" elif any(x in text for x in ["supplier", "vendor", "who supplies", "lead time"]): response["intent"] = "supplier_info" elif any(x in text for x in ["buy", "order", "purchase", "requisition"]): response["intent"] = "create_requisition" elif any(x in text for x in ["status", "alerts", "dashboard", "overview"]): response["intent"] = "system_status" elif any(x in text for x in ["pdf", "download", "report", "file"]): response["intent"] = "generate_report" # 2. Extract Item Code # Look for patterns like FS1234, BMS0001, etc. (2-3 letters + 4 digits) item_match = re.search(r'\b([a-z]{2,3}\d{4})\b', text) if item_match: response["item_code"] = item_match.group(1).upper() else: # Fallback: check against known items in DB if loader.items_df is not None: known_items = loader.items_df['item_code'].tolist() for item in known_items: if item.lower() in text: response["item_code"] = item break # 2.5 Extract Quantity (for orders) qty_match = re.search(r'\b(\d+)\s*(?:units|pcs|pieces)?\b', text) if qty_match: # Avoid confusing horizon days with quantity if possible # If "days" is not next to it, assume qty if "day" not in text[qty_match.end():qty_match.end()+5]: response["extra"]["qty"] = int(qty_match.group(1)) # 3. Extract Location if re.search(r'\b(na|north america|usa|us)\b', text): response["location"] = "NA" elif re.search(r'\b(eu|europe|uk|germany)\b', text): response["location"] = "EU" elif re.search(r'\b(apac|asia|china|india)\b', text): response["location"] = "APAC" # 4. Extract Horizon response["horizon_days"] = self._parse_horizon(text) return response def _parse_horizon(self, text): days = None # Explicit days days_match = re.search(r'(\d+)\s*days?', text) if days_match: return int(days_match.group(1)) # Weeks weeks_match = re.search(r'(\d+)\s*weeks?', text) if weeks_match: return int(weeks_match.group(1)) * 7 # Months months_match = re.search(r'(\d+)\s*months?', text) if months_match: return int(months_match.group(1)) * 30 # Keywords if "next week" in text: return 7 if "next month" in text: return 30 if "next year" in text: return 365 if "tomorrow" in text: return 1 return days parser = IntentParser()