Spaces:
Sleeping
Sleeping
from fastapi import APIRouter, HTTPException | |
from pydantic import BaseModel | |
from swiggy_scraper import fetch_swiggy_orders | |
from datetime import datetime | |
from openai import OpenAI | |
import os, json | |
router = APIRouter() | |
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) | |
class QueryInput(BaseModel): | |
query: str | |
class DateRange(BaseModel): | |
start_date: str | |
end_date: str | |
# @router.post("/parse_query") | |
# def parse_query_llm(input: QueryInput): | |
# print("\ninput query:") | |
# print(input) | |
# today_str = datetime.today().strftime("%d-%b-%Y") | |
# system = ( | |
# f"You are a date range extractor.\n" | |
# f"Today is {today_str}.\n" | |
# "Extract start_date and end_date in 'DD-MMM-YYYY' format.\n" | |
# "Respond with:\n" | |
# "Output ONLY a valid JSON object like:\n" | |
# '{ "start_date": "17-May-2025", "end_date": "18-May-2025" }\n' | |
# 'no extra commentry needed.' | |
# ) | |
# try: | |
# rsp = client.chat.completions.create( | |
# model="gpt-4o-mini", | |
# temperature=0, | |
# messages=[ | |
# {"role": "system", "content": system}, | |
# {"role": "user", "content": input.query}, | |
# ] | |
# ) | |
# result = json.loads(rsp.choices[0].message.content.strip()) | |
# if "start_date" not in result or "end_date" not in result: | |
# raise ValueError("Invalid response format") | |
# print("results:", result) | |
# return result | |
# except Exception as e: | |
# raise HTTPException(status_code=400, detail=str(e)) | |
def _llm(messages, model="gpt-4o-mini", temperature=0): | |
rsp = client.chat.completions.create( | |
model=model, | |
temperature=temperature, | |
messages=messages, | |
) | |
return rsp.choices[0].message.content.strip() | |
# ---------- Stage 1: classify + extract dates -------------------------- | |
def _extract_scope(user_query: str): | |
today_str = datetime.today().strftime("%d-%b-%Y") | |
sys_prompt = f""" | |
Today is {today_str}. | |
You are a SCOPING assistant: decide if the user's text is about Swiggy food orders, | |
extract ONE date range, and keep the leftover words. | |
Return ONLY valid JSON like: | |
{{ | |
"is_swiggy_query": true, | |
"start_date": "15-May-2025", | |
"end_date": "20-May-2025", | |
"remainder": "non veg expense" | |
}} | |
Rules: | |
• Accept natural phrases (“last week”, “since 1 May”). | |
• If no dates → start_date & end_date = null. | |
• If not Swiggy related → is_swiggy_query=false and remainder is full original text. | |
• Do NOT invent a remainder; it is literally whatever words follow the date phrase(s). | |
""" | |
raw = _llm( | |
[ | |
{"role": "system", "content": sys_prompt}, | |
{"role": "user", "content": user_query} | |
] | |
) | |
return json.loads(raw) | |
# ---------- Stage 2: shrink “remainder” into an intent ----------------- | |
def _extract_intent(remainder: str): | |
sys_prompt = """ | |
You are an INTENT classifier for Swiggy-order analytics. | |
Map the sentence into one concise snake_case intent. | |
Allowed intents (extendable): | |
• calculate_expense | |
• list_orders | |
• list_items | |
• list_nonveg_items | |
• list_veg_items | |
• count_orders | |
• unknown | |
Return JSON: { "intent": "calculate_expense" } | |
If unsure choose "unknown". | |
""" | |
raw = _llm( | |
[ | |
{"role": "system", "content": sys_prompt}, | |
{"role": "user", "content": remainder.strip()} | |
] | |
) | |
return json.loads(raw)["intent"] | |
# ---------- FastAPI route ---------------------------------------------- | |
def parse_query_llm(input: QueryInput): | |
try: | |
scope = _extract_scope(input.query) | |
print("scope") | |
print(scope) | |
# If it is a Swiggy query, classify intent; else, intent = "unrelated" | |
if scope.get("is_swiggy_query", False): | |
intent = _extract_intent(scope.get("remainder", "")) | |
else: | |
intent = "unrelated" | |
result = { | |
"is_swiggy_query": scope["is_swiggy_query"], | |
"start_date": scope["start_date"], | |
"end_date": scope["end_date"], | |
"intent": intent | |
} | |
print("result") | |
print(result) | |
return result | |
except Exception as e: | |
raise HTTPException(status_code=400, detail=str(e)) | |
def get_orders(range: DateRange): | |
try: | |
orders = fetch_swiggy_orders(range.start_date, range.end_date) | |
return orders | |
except Exception as e: | |
raise HTTPException(status_code=500, detail=str(e)) | |