|
|
import uuid, time, sys |
|
|
from contextlib import asynccontextmanager |
|
|
from loguru import logger |
|
|
from fastapi import FastAPI, HTTPException, Response |
|
|
from fastapi.middleware.cors import CORSMiddleware |
|
|
from fastapi.staticfiles import StaticFiles |
|
|
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST |
|
|
import os |
|
|
from schemas import ChatRequest, ChatResponse |
|
|
from agent import SupportAgent |
|
|
import httpx |
|
|
from fastapi import Request |
|
|
from starlette.responses import StreamingResponse |
|
|
from prometheus_client import make_asgi_app |
|
|
os.environ["ANONYMIZED_TELEMETRY"] = "False" |
|
|
|
|
|
|
|
|
logger.remove() |
|
|
logger.add(sys.stdout, format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level}</level> | {message}", level="INFO") |
|
|
|
|
|
@asynccontextmanager |
|
|
async def lifespan(app: FastAPI): |
|
|
logger.info("Initializing SmartCoffee Agent for Hugging Face...") |
|
|
try: |
|
|
|
|
|
app.state.agent = SupportAgent() |
|
|
logger.success("SupportAgent successfully initialized.") |
|
|
except Exception as e: |
|
|
logger.error(f"Critical Startup Error: {e}") |
|
|
yield |
|
|
logger.info("Shutting down...") |
|
|
|
|
|
app = FastAPI(title="SmartCoffee AI 2026", lifespan=lifespan) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
""" |
|
|
Adding the dashaboard for monitoring |
|
|
""" |
|
|
@app.api_route("/grafana/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]) |
|
|
async def grafana_proxy(path: str, request: Request): |
|
|
async with httpx.AsyncClient(follow_redirects=True, timeout=30.0) as client: |
|
|
resp = await client.request( |
|
|
request.method, |
|
|
f"http://127.0.0.1:3000/{path}", |
|
|
params=request.query_params, |
|
|
headers={ |
|
|
k: v |
|
|
for k, v in request.headers.items() |
|
|
if k.lower() not in ("host", "content-length") |
|
|
}, |
|
|
content=await request.body(), |
|
|
) |
|
|
|
|
|
return StreamingResponse( |
|
|
resp.aiter_raw(), |
|
|
status_code=resp.status_code, |
|
|
headers={ |
|
|
k: v |
|
|
for k, v in resp.headers.items() |
|
|
if k.lower() not in ("content-encoding", "transfer-encoding") |
|
|
}, |
|
|
) |
|
|
|
|
|
|
|
|
app.add_middleware( |
|
|
CORSMiddleware, |
|
|
allow_origins=["*"], |
|
|
allow_methods=["*"], |
|
|
allow_headers=["*"], |
|
|
) |
|
|
|
|
|
|
|
|
@app.get("/health") |
|
|
async def health(): |
|
|
return {"status": "healthy", "time": time.time(), "agent_loaded": hasattr(app.state, 'agent')} |
|
|
|
|
|
|
|
|
@app.get("/metrics") |
|
|
def metrics(): |
|
|
return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST) |
|
|
|
|
|
|
|
|
@app.post("/api/v1/chat", response_model=ChatResponse) |
|
|
async def chat(request: ChatRequest): |
|
|
if request.session_id == "default": |
|
|
request.session_id = f"hf_{uuid.uuid4().hex[:12]}" |
|
|
|
|
|
if not hasattr(app.state, 'agent'): |
|
|
raise HTTPException(status_code=503, detail="Agent logic is still initializing or failed to load.") |
|
|
|
|
|
try: |
|
|
|
|
|
result = app.state.agent.run(request.question, session_id=request.session_id) |
|
|
|
|
|
return ChatResponse( |
|
|
question=request.question, |
|
|
answer=result["answer"], |
|
|
session_id=request.session_id, |
|
|
timestamp=result.get("timestamp", time.time()) |
|
|
) |
|
|
except Exception as e: |
|
|
logger.error(f"Chat Execution Error: {e}") |
|
|
raise HTTPException(status_code=500, detail=str(e)) |
|
|
|
|
|
|
|
|
@app.post("/api/v1/chat/sync", response_model=ChatResponse) |
|
|
async def chat_sync(request: ChatRequest): |
|
|
return await chat(request) |
|
|
|
|
|
|
|
|
app.mount("/", StaticFiles(directory="frontend", html=True), name="static") |
|
|
app.mount("/metrics", make_asgi_app()) |