aigenrec/luminabackend
0
1from fastapi import APIRouter, HTTPException, Depends2from fastapi.responses import StreamingResponse3from services.rag_service import rag_service4from models.schemas import ChatRequest, ChatResponse, ChatMessage5from typing import Any, List6from api.deps import get_current_user7from db.client import supabase_client8 9router = APIRouter()10 11@router.get("/history/{project_id}", response_model=List[ChatMessage])12async def get_chat_history(13 project_id: str,14 current_user: dict = Depends(get_current_user)15):16 """17 Get chat history for a project18 """19 try:20 # Verify access (simple check or RLS)21 response = supabase_client.table("chat_messages")\22 .select("*")\23 .eq("project_id", project_id)\24 .order("created_at", desc=False)\25 .execute()26 27 return [28 ChatMessage(role=msg["role"], content=msg["content"]) 29 for msg in response.data30 ]31 except Exception as e:32 raise HTTPException(500, str(e))33 34@router.post("/message", response_model=ChatResponse)35async def chat_message(36 request: ChatRequest,37 current_user: dict = Depends(get_current_user)38):39 """40 Send a message to the RAG chat (Blocking/Non-streaming)41 """42 try:43 # Save User Message44 supabase_client.table("chat_messages").insert({45 "project_id": request.project_id,46 "role": "user",47 "content": request.message48 }).execute()49 50 # Fetch full history for context51 history_res = supabase_client.table("chat_messages")\52 .select("*")\53 .eq("project_id", request.project_id)\54 .order("created_at", desc=False)\55 .execute()56 57 chat_history_dicts = [58 {"role": msg["role"], "content": msg["content"]} 59 for msg in history_res.data60 ]61 62 result = await rag_service.get_answer(63 project_id=request.project_id,64 question=request.message,65 selected_documents=request.selected_documents,66 chat_history=chat_history_dicts[:-1] # Exclude current msg to avoid duplication if RAG appends it67 )68 69 # Save Assistant Message70 supabase_client.table("chat_messages").insert({71 "project_id": request.project_id,72 "role": "assistant",73 "content": result["answer"],74 "sources": result["sources"]75 }).execute()76 77 return result78 79 except Exception as e:80 raise HTTPException(500, str(e))81 82@router.post("/stream")83async def chat_stream(84 request: ChatRequest,85 current_user: dict = Depends(get_current_user)86):87 """88 Send a message to the RAG chat (Streaming)89 """90 try:91 # Save User Message92 supabase_client.table("chat_messages").insert({93 "project_id": request.project_id,94 "role": "user",95 "content": request.message96 }).execute()97 98 # Fetch full history99 history_res = supabase_client.table("chat_messages")\100 .select("*")\101 .eq("project_id", request.project_id)\102 .order("created_at", desc=False)\103 .execute()104 105 chat_history_dicts = [106 {"role": msg["role"], "content": msg["content"]} 107 for msg in history_res.data108 ]109 110 # Wrapper generator to intercept and save the final answer111 async def stream_and_save():112 full_answer = ""113 sources = []114 115 async for chunk in rag_service.get_answer_stream(116 project_id=request.project_id,117 question=request.message,118 selected_documents=request.selected_documents,119 chat_history=chat_history_dicts[:-1]120 ):121 # Check for sources marker122 if "__SOURCES__:" in chunk:123 parts = chunk.split("__SOURCES__:")124 full_answer += parts[0]125 yield parts[0] # Send final text part126 127 # Process sources128 try:129 import json130 sources = json.loads(parts[1])131 except: pass132 133 yield chunk # Forward the marker to frontend134 else:135 full_answer += chunk136 yield chunk137 138 # Save Assistant Message after stream ends139 try:140 supabase_client.table("chat_messages").insert({141 "project_id": request.project_id,142 "role": "assistant",143 "content": full_answer,144 "sources": sources145 }).execute()146 except Exception as save_err:147 print(f"Failed to save assistant message: {save_err}")148 149 return StreamingResponse(150 stream_and_save(),151 media_type="text/event-stream"152 )153 except Exception as e:154 raise HTTPException(500, str(e))155 156@router.get("/summary/{project_id}", response_model=ChatResponse)157async def get_project_summary(158 project_id: str,159 current_user: dict = Depends(get_current_user)160):161 """162 Generate a summary for the project documents163 """164 try:165 result = await rag_service.generate_summary(project_id)166 return result167 except Exception as e:168 raise HTTPException(500, str(e))