smhs16's picture
Upload 9 files
c13bbb4 verified
"""
PriceOye AI Phone Advisor β€” FastAPI Backend
============================================
Endpoints:
POST /chat β€” send a message, get response + phone cards
GET /phones β€” full phone database
GET /phone/{id} β€” single phone detail
GET /health β€” health check
Deploy: uvicorn api.main:app --host 0.0.0.0 --port 7860
"""
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional
import uuid
from src.conversation import (
ConversationState, handle_message, get_greeting, format_phone_summary
)
from src.phone_database import build_database
from src.scoring_engine import get_category_scores, get_sub_scores
app = FastAPI(
title="PriceOye AI Phone Advisor",
description="ML-powered phone recommendation engine for Pakistan's market",
version="2.0.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# In-memory session store (replace with Redis for production)
SESSIONS: dict[str, ConversationState] = {}
PHONE_DB = build_database()
# ─────────────────────────────────────────────
# SCHEMAS
# ─────────────────────────────────────────────
class ChatRequest(BaseModel):
session_id: Optional[str] = None
message: str
class ChatResponse(BaseModel):
session_id: str
text: str
followup: Optional[str] = None
quick_replies: list[str]
phones: Optional[list[dict]] = None
# ─────────────────────────────────────────────
# ENDPOINTS
# ─────────────────────────────────────────────
@app.get("/health")
def health():
return {"status": "ok", "phones_in_db": len(PHONE_DB), "version": "2.0.0"}
@app.post("/chat", response_model=ChatResponse)
def chat(req: ChatRequest):
# Create or retrieve session
session_id = req.session_id or str(uuid.uuid4())
if session_id not in SESSIONS or req.session_id is None:
# New session β€” return greeting
greeting = get_greeting()
SESSIONS[session_id] = greeting["state"]
return ChatResponse(
session_id=session_id,
text=greeting["text"],
quick_replies=greeting["quick_replies"],
phones=None,
)
state = SESSIONS[session_id]
response = handle_message(req.message, state)
SESSIONS[session_id] = response["state"]
return ChatResponse(
session_id=session_id,
text=response["text"],
followup=response.get("followup"),
quick_replies=response.get("quick_replies", []),
phones=response.get("phones"),
)
@app.get("/phones")
def list_phones():
return [
{
"id": p.id,
"name": p.name,
"brand": p.brand,
"os": p.os,
"price_pkr": p.price_pkr,
"price_label": p.price_label,
"emoji": p.emoji,
"tags": p.tags,
"priceoye_url": p.priceoye_url,
"whatmobile_url": p.whatmobile_url,
"category_scores": {k: round(v, 1) for k, v in get_category_scores(p).items()},
}
for p in PHONE_DB
]
@app.get("/phone/{phone_id}")
def get_phone(phone_id: str, category: str = "camera"):
phone = next((p for p in PHONE_DB if p.id == phone_id), None)
if not phone:
raise HTTPException(status_code=404, detail="Phone not found")
cats = get_category_scores(phone)
return {
"id": phone.id,
"name": phone.name,
"brand": phone.brand,
"os": phone.os,
"price_pkr": phone.price_pkr,
"price_label": phone.price_label,
"emoji": phone.emoji,
"tags": phone.tags,
"highlights": phone.highlights,
"priceoye_url": phone.priceoye_url,
"whatmobile_url": phone.whatmobile_url,
"category_scores": {k: round(v, 1) for k, v in cats.items()},
"deep_dive": {
"category": category,
"scores": get_sub_scores(phone, category),
},
}