MailQuery / mcp /server /routes.py
Da-123's picture
Upload 7 files
7c68554 verified
raw
history blame
4.79 kB
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 ----------------------------------------------
@router.post("/parse_query")
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))
@router.post("/get_orders")
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))