ai-girlfriend / main.py
jeevzz's picture
Update main.py
3a0aba1 verified
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")