ai-girlfriend / main.py
jeevzz's picture
Update main.py
3a0aba1 verified
raw
history blame
4.94 kB
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pydantic import BaseModel
from typing import List, Optional
import os
try:
from . import chat, voice, database
except ImportError:
import chat, voice, database
import traceback
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Initialize database on startup
@app.on_event("startup")
async def startup_event():
database.init_db()
class ChatRequest(BaseModel):
message: str
# history is now optional/deprecated as we use session_id, but keeping for backward compatibility if needed
history: List[dict] = []
class SessionCreateRequest(BaseModel):
name: str = "New Chat"
user_id: str
class VoiceRequest(BaseModel):
text: str
voice: str
@app.get("/")
async def root():
return {"message": "AI Girlfriend API"}
@app.get("/sessions/{user_id}")
async def get_sessions(user_id: str):
return database.get_sessions(user_id)
@app.post("/sessions")
async def create_session(request: SessionCreateRequest):
return database.create_session(request.user_id, request.name)
@app.delete("/sessions/{session_id}")
async def delete_session(session_id: str):
database.delete_session(session_id)
return {"message": "Session deleted"}
@app.get("/sessions/{session_id}/messages")
async def get_session_messages(session_id: str):
return database.get_messages(session_id)
@app.post("/sessions/{session_id}/chat")
async def chat_session_endpoint(session_id: str, request: ChatRequest):
try:
# Get existing history from DB
db_history = database.get_messages(session_id)
# Convert to format expected by chat.py (list of dicts with role/content)
history_for_model = [{"role": msg["role"], "content": msg["content"]} for msg in db_history]
# Get response from AI
response_text = chat.get_chat_response(request.message, history_for_model)
# Save user message and AI response to DB
database.add_message(session_id, "user", request.message)
database.add_message(session_id, "assistant", response_text)
# If this was the first message (history was empty before this turn), generate a summary
if not db_history:
try:
summary = chat.generate_summary(request.message, response_text)
database.update_session_name(session_id, summary)
except Exception as e:
print(f"Failed to generate summary: {e}")
return {"response": response_text}
except Exception as e:
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
# Legacy endpoint - keeping for now or can be removed if frontend is fully updated
@app.post("/chat")
async def chat_endpoint(request: ChatRequest):
try:
response = chat.get_chat_response(request.message, request.history)
return {"response": response}
except Exception as e:
traceback.print_exc() # Print error to console
raise HTTPException(status_code=500, detail=str(e))
@app.get("/voices")
async def voices_endpoint():
return voice.get_voices()
@app.post("/speak")
async def speak_endpoint(request: VoiceRequest):
try:
audio_path = await voice.generate_audio(request.text, request.voice)
return FileResponse(audio_path, media_type="audio/mpeg", filename="response.mp3")
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
# Mount static files if they exist (for production/served build)
frontend_dist = os.path.join(os.path.dirname(__file__), "../frontend/dist")
assets_path = os.path.join(frontend_dist, "assets")
if os.path.exists(assets_path):
app.mount("/assets", StaticFiles(directory=assets_path), name="assets")
@app.get("/{full_path:path}")
async def serve_frontend(full_path: str):
# Only serve if dist exists
if os.path.exists(frontend_dist):
# Serve index.html for any other path (SPA routing)
# Check if file exists in dist, else serve index.html
target_file = os.path.join(frontend_dist, full_path)
if full_path and os.path.exists(target_file):
return FileResponse(target_file)
return FileResponse(os.path.join(frontend_dist, "index.html"))
# If dist doesn't exist, just return a message or 404 for frontend routes
# This allows backend to run even if frontend isn't built
if full_path == "":
return {"message": "Backend is running. Frontend build not found. Use 'npm run dev' for frontend development."}
raise HTTPException(status_code=404, detail="Frontend build not found")