Spaces:
Runtime error
Runtime error
| import os | |
| import uuid | |
| from fastapi import FastAPI, HTTPException, Request | |
| from fastapi.responses import StreamingResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.staticfiles import StaticFiles | |
| from pydantic import BaseModel | |
| from typing import Optional, List | |
| from rag_engine import rag_engine | |
| from grok_client import grok_client | |
| from memory_manager import memory_manager | |
| from search_tool import search_tool | |
| app = FastAPI(title="DStv AI Support API") | |
| # Enable CORS for frontend development | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Serve static files from frontend/dist | |
| # This will be used in production (Docker) | |
| if os.path.exists("frontend/dist"): | |
| app.mount("/", StaticFiles(directory="frontend/dist", html=True), name="static") | |
| class ChatRequest(BaseModel): | |
| message: str | |
| session_id: Optional[str] = None | |
| SYSTEM_PROMPT = """You are DStv AI Support, a helpful and professional customer support representative for DStv. | |
| Your tone is friendly, clear, practical, and human. | |
| Rules: | |
| 1. Never say "as an AI". | |
| 2. Never mention internal systems. | |
| 3. Speak like real DStv support (e.g., "I can help you with that", "Let me check our guides for you"). | |
| 4. Use the provided context to answer accurately. | |
| 5. If you cannot find the answer in the context or search results, politely inform the user and suggest they contact DStv support via official channels like the DStv app or WhatsApp. | |
| When answering, focus on providing direct, actionable advice to the user. | |
| """ | |
| async def chat_endpoint(request: ChatRequest): | |
| session_id = request.session_id or str(uuid.uuid4()) | |
| user_message = request.message | |
| # 1. Search RAG | |
| rag_results = rag_engine.query(user_message) | |
| context = "" | |
| if rag_results: | |
| context = "\n".join([doc.page_content for doc in rag_results]) | |
| # 2. If RAG results are weak or not found, try web search fallback | |
| if not context or len(context) < 100: | |
| web_results = search_tool.search_web(user_message) | |
| if web_results: | |
| context += "\n\nWeb Search Results:\n" | |
| for res in web_results: | |
| context += f"- {res['title']}: {res['snippet']}\n" | |
| # 3. Retrieve Memory | |
| history = memory_manager.get_history(session_id) | |
| # 4. Prepare messages for Grok | |
| current_context_prompt = f"Context Information:\n{context}\n\nUser Question: {user_message}" | |
| messages = [{"role": "system", "content": SYSTEM_PROMPT}] | |
| # Add relevant history (last 5 exchanges for context) | |
| for msg in history[-10:]: | |
| messages.append(msg) | |
| messages.append({"role": "user", "content": current_context_prompt}) | |
| # Save user message to memory | |
| memory_manager.save_message(session_id, "user", user_message) | |
| async def response_generator(): | |
| full_response = "" | |
| async for chunk in grok_client.stream_chat(messages): | |
| full_response += chunk | |
| yield chunk | |
| # Save assistant response to memory after stream finishes | |
| memory_manager.save_message(session_id, "assistant", full_response) | |
| return StreamingResponse(response_generator(), media_type="text/event-stream") | |
| async def create_session(): | |
| return {"session_id": str(uuid.uuid4())} | |
| async def health_check(): | |
| return {"status": "healthy"} | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=8000) | |