from datetime import datetime, timezone import uuid from fastapi import APIRouter, Request, Depends, Form from fastapi.responses import HTMLResponse, StreamingResponse from fastapi.templating import Jinja2Templates from sqlalchemy import select, desc from app.models.base import async_session from app.models.user import User from app.models.chat import ChatMessage from app.auth import get_current_user from app.services.opencode_proxy import query_opencode router = APIRouter() templates = Jinja2Templates(directory="app/templates") @router.get("/chat", response_class=HTMLResponse) async def chat_page(request: Request, user: User = Depends(get_current_user)): session_id = request.cookies.get("chat_session_id") if not session_id: session_id = str(uuid.uuid4()) async with async_session() as session: result = await session.execute( select(ChatMessage) .where( ChatMessage.user_id == user.id, ChatMessage.session_id == session_id, ) .order_by(ChatMessage.created_at) ) messages = result.scalars().all() resp = templates.TemplateResponse(request, "chat.html", { "user": user, "messages": messages, "session_id": session_id, }) resp.set_cookie(key="chat_session_id", value=session_id, httponly=True, max_age=86400 * 30) return resp @router.post("/chat") async def chat_send( request: Request, user: User = Depends(get_current_user), message: str = Form(), ): session_id = request.cookies.get("chat_session_id") or str(uuid.uuid4()) user_context = ( f"Username: {user.username}. " f"Weight: {user.weight_lb} lb. " f"Goals: {user.goals or 'Not specified'}. " f"Medical: {user.medical_notes or 'None'}" ) async def stream(): async with async_session() as session: user_msg = ChatMessage( user_id=user.id, session_id=session_id, role="user", content=message, created_at=datetime.now(timezone.utc).isoformat(), ) session.add(user_msg) await session.commit() assistant_content = "" async for chunk in query_opencode(message, session_id, user_context): assistant_content += chunk yield f"data: {chunk}\n\n" async with async_session() as session: assistant_msg = ChatMessage( user_id=user.id, session_id=session_id, role="assistant", content=assistant_content, created_at=datetime.now(timezone.utc).isoformat(), ) session.add(assistant_msg) await session.commit() resp = StreamingResponse(stream(), media_type="text/event-stream") resp.set_cookie(key="chat_session_id", value=session_id, httponly=True, max_age=86400 * 30) return resp