MusAI / main.py
Eng-Musa's picture
return model used
8b4ea9c
Raw
History Blame Contribute Delete
3.4 kB
import json
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from functools import lru_cache
from clients.groq_client import GroqClient
from fastapi.responses import StreamingResponse
app = FastAPI()
# Allowed origins
origins = [
"http://localhost:4200",
"https://mosesmangabo.vercel.app",
"https://chatbot-bridge-service.onrender.com",
"https://eng-musa-chatbotbridge.hf.space",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"], # allow all HTTP methods (GET, POST, ...)
allow_headers=["*"], # allow all headers
)
class QueryRequest(BaseModel):
query: str
ip: str
# Lazy singleton for GroqClient
@lru_cache(maxsize=1)
def get_groq_client():
return GroqClient()
# Non - Streaming
# ============================================
@app.post("/chat")
async def chat_endpoint(request: QueryRequest):
try:
groq_client = get_groq_client()
response, model = groq_client.ask(request.query)
if response.startswith("Error while"):
return {"status_code": 500, "response": response, "model": model, "next_questions": []}
return {
"status_code": 200,
"response": response,
"model": model,
"next_questions": groq_client.get_next_questions(request.ip),
}
except Exception as e:
return {
"status_code": 500,
"response": f"Internal error: {e}",
"model": None,
"next_questions": [],
}
# Streaming
# ============================================
@app.post("/chat-stream")
async def chat_stream_endpoint(request: QueryRequest):
"""Streaming endpoint that returns chunks in real-time with a consistent structure"""
try:
groq_client = get_groq_client()
def generate():
try:
response = ""
for chunk in groq_client.ask_stream(request.query):
response += chunk
yield f"data: {json.dumps({'status_code': 200, 'response': chunk, 'next_questions': []})}\n\n"
if response.startswith("Error while"):
yield f"data: {json.dumps({'status_code': 500, 'response': response, 'next_questions': []})}\n\n"
else:
yield f"data: {json.dumps({'status_code': 200, 'response': response, 'next_questions': []})}\n\n"
yield f"data: {json.dumps({'status_code': 200, 'response': '[DONE]', 'next_questions': groq_client.get_next_questions(request.ip)})}\n\n"
except Exception as e:
yield f"data: {json.dumps({'status_code': 500, 'response': f'Error: {str(e)}', 'next_questions': []})}\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no", # Disable nginx buffering
},
)
except Exception as e:
return {
"status_code": 500,
"response": f"Internal error: {e}",
"next_questions": [],
}
@app.get("/")
def healthcheck():
return {"status": "ok"}
# python -m uvicorn main:app --reload