Humanoids / main.py
MuhammedSuhaib's picture
Upload folder using huggingface_hub
f5b0cd7 verified
Raw
History Blame Contribute Delete
7.15 kB
import logging
from typing import Optional
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from agents import Runner
from simple_agents.aagents import Triage_Agent
from models.user_context import UserContext
from pydantic import BaseModel
from services.rag import RAGService
from data.vector_store import VectorStore
# Initialize services globally but handle initialization errors gracefully
try:
vector_store = VectorStore()
rag_service = RAGService()
rag_service.set_vector_store(vector_store)
except Exception as e:
logging.error(f"Failed to initialize services: {e}")
vector_store = None
rag_service = None
app = FastAPI()
# CORS middleware for Vercel deployment
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://muhammedsuhaib.github.io",
"http://localhost:3000",
"http://localhost:8080",
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ---------------------------
# Pydantic Models for Frontend Requests
# ---------------------------
# Matches the payload for the general chat endpoint (/api/query)
class QueryRequest(BaseModel):
query: str
user_context: Optional[dict] = None
# Matches the payload for the selection endpoint (/api/selection)
class SelectionRequest(BaseModel):
selected_text: str
question: str
user_context: Optional[dict] = None
# Matches the payload for the translation endpoint (/api/translate-text)
class TranslationRequest(BaseModel):
text: str
target_language: str
# ---------------------------
# FastAPI Endpoints (Matching React expectations)
# ---------------------------
@app.get("/")
def read_root():
return {"message": "Python Assistant Backend is running."}
@app.post("/api/query")
async def handle_query(req: QueryRequest):
"""Handles general chat queries from the React component."""
logging.info(f"Received general query: {req.query}")
# Check if services are properly initialized
if not rag_service or not vector_store:
logging.error("RAG service not initialized")
return {
"answer": "Service temporarily unavailable",
"sources": []
}
# Create user context from request data
user_context_data = req.user_context or {}
user_context = UserContext(
name=user_context_data.get('name', 'User'),
uid=user_context_data.get('uid'),
email=user_context_data.get('email'),
personalization_data=user_context_data.get('personalization_data'),
session_id=user_context_data.get('session_id')
)
# Use global RAG service to get context from Qdrant
# Get relevant context from Qdrant
try:
rag_result = await rag_service.query(req.query)
print(rag_result)
print(rag_result.sources)
context = rag_result.answer if rag_result.answer != "I don't know" else ""
except Exception as e:
logging.error(f"RAG query failed: {e}")
# Fallback to no context if RAG fails
rag_result = None
context = ""
# Include context in the agent's query if available
if context and context != "I don't know":
enhanced_query = f"Based on the following context: {context}\n\nQuestion: {req.query}"
else:
enhanced_query = req.query
# Run the main agent with the enhanced query and user context
result = await Runner.run(
Triage_Agent,
enhanced_query,
context=user_context
)
# CRITICAL: Response structure must match React component: {"answer": "...", "sources": []}
return {
"answer": result.final_output,
"sources": rag_result.sources if rag_result and hasattr(rag_result, 'sources') else [] # Must be included, even if empty
}
@app.post("/api/selection")
async def handle_selection(req: SelectionRequest):
"""Handles queries based on selected text (RAG context)."""
logging.info(f"Received selection query. Question: {req.question}")
# Create user context from request data
user_context_data = req.user_context or {}
user_context = UserContext(
name=user_context_data.get('name', 'User'),
uid=user_context_data.get('uid'),
email=user_context_data.get('email'),
personalization_data=user_context_data.get('personalization_data'),
session_id=user_context_data.get('session_id')
)
# Check if services are properly initialized
if not rag_service or not vector_store:
logging.error("RAG service not initialized")
return {
"answer": "Service temporarily unavailable",
"sources": []
}
# Use global RAG service to get additional context from Qdrant
# Get relevant context from Qdrant based on the question
try:
rag_result = await rag_service.query(req.question)
additional_context = rag_result.answer if rag_result.answer != "I don't know" else ""
except Exception as e:
logging.error(f"RAG query failed: {e}")
# Fallback to no context if RAG fails
rag_result = None
additional_context = ""
# Construct a RAG-style prompt for the agent
if additional_context and additional_context != "I don't know":
prompt = (
f"Based *only* on the following context, answer the user's question. "
f"If the context does not contain the answer, state that. "
f"Context: \"{req.selected_text}\"\n\nAdditional context from knowledge base: {additional_context} "
f"Question: {req.question}"
)
else:
prompt = (
f"Based *only* on the following context, answer the user's question. "
f"If the context does not contain the answer, state that. "
f"Context: \"{req.selected_text}\" "
f"Question: {req.question}"
)
# Run the agent with the context-aware prompt and user context
result = await Runner.run(
Triage_Agent,
prompt,
context=user_context
)
# CRITICAL: Response structure must match React component: {"answer": "...", "sources": []}
return {
"answer": result.final_output,
"sources": rag_result.sources if rag_result and hasattr(rag_result, 'sources') else [] # Must be included, even if empty
}
@app.get("/health")
def health_check():
"""Health check endpoint for Vercel deployment."""
return {"status": "healthy", "message": "Backend is running"}
@app.post("/api/translate-text")
async def translate_text(req: TranslationRequest):
"""Translates text to the specified target language."""
from deep_translator import GoogleTranslator
try:
# Validate target language
if req.target_language != 'ur':
return {"error": "Currently only Urdu (ur) translation is supported"}
# Perform translation
translated = GoogleTranslator(source='en', target=req.target_language).translate(req.text)
return {"translated_text": translated}
except Exception as e:
logging.error(f"Translation error: {e}")
return {"error": str(e)}