feat: add API endpoints
This commit is contained in:
180
app/main.py
Normal file
180
app/main.py
Normal file
@@ -0,0 +1,180 @@
|
||||
import uuid
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import FastAPI, Depends, HTTPException, BackgroundTasks
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
from app.core.config import settings
|
||||
from app.data.database import init_db
|
||||
from app.data.models import (
|
||||
StartSessionRequest,
|
||||
SendMessageRequest,
|
||||
SessionResponse,
|
||||
SessionStatusResponse
|
||||
)
|
||||
from app.services.session_service import SessionService
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Initialize database on startup."""
|
||||
logger.info("Initializing database...")
|
||||
await init_db()
|
||||
logger.info("Database initialized successfully")
|
||||
yield
|
||||
logger.info("Shutting down...")
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title="SkyTalk API",
|
||||
description="AI-powered backend service for conversational idea exploration and knowledge synthesis",
|
||||
version="1.0.0",
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
# Add CORS middleware for development
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"], # Configure appropriately for production
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
def get_session_service() -> SessionService:
|
||||
"""Dependency to get SessionService instance."""
|
||||
return SessionService()
|
||||
|
||||
|
||||
@app.post("/sessions/start", response_model=SessionResponse)
|
||||
async def start_session(
|
||||
request: StartSessionRequest,
|
||||
session_service: Annotated[SessionService, Depends(get_session_service)]
|
||||
) -> SessionResponse:
|
||||
"""Start a new interview session.
|
||||
|
||||
Args:
|
||||
request: StartSessionRequest containing the topic
|
||||
session_service: Injected SessionService instance
|
||||
|
||||
Returns:
|
||||
SessionResponse with session_id, status, and initial message
|
||||
"""
|
||||
try:
|
||||
result = await session_service.start_session(request.topic)
|
||||
return SessionResponse(
|
||||
session_id=result["session_id"],
|
||||
status=result["status"],
|
||||
message=result["message"]
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error starting session: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to start session")
|
||||
|
||||
|
||||
@app.post("/sessions/sendMessage", response_model=SessionResponse)
|
||||
async def send_message(
|
||||
request: SendMessageRequest,
|
||||
background_tasks: BackgroundTasks,
|
||||
session_service: Annotated[SessionService, Depends(get_session_service)]
|
||||
) -> SessionResponse:
|
||||
"""Send a message to an active session.
|
||||
|
||||
Args:
|
||||
request: SendMessageRequest containing session_id and message
|
||||
background_tasks: FastAPI background tasks for async processing
|
||||
session_service: Injected SessionService instance
|
||||
|
||||
Returns:
|
||||
SessionResponse with the AI's response
|
||||
"""
|
||||
try:
|
||||
result = await session_service.handle_message(
|
||||
session_id=request.session_id,
|
||||
message=request.message
|
||||
)
|
||||
|
||||
# If session is ending, trigger background synthesis
|
||||
if result.get("session_ending", False):
|
||||
background_tasks.add_task(
|
||||
session_service.process_session_background_task,
|
||||
request.session_id
|
||||
)
|
||||
logger.info(f"Triggered background synthesis for session {request.session_id}")
|
||||
|
||||
return SessionResponse(
|
||||
session_id=result["session_id"],
|
||||
status=result["status"],
|
||||
message=result["message"]
|
||||
)
|
||||
|
||||
except ValueError as e:
|
||||
logger.error(f"Session error: {e}")
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Error handling message: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to process message")
|
||||
|
||||
|
||||
@app.get("/sessions/getStatus", response_model=SessionStatusResponse)
|
||||
async def get_session_status(
|
||||
session_id: uuid.UUID,
|
||||
session_service: Annotated[SessionService, Depends(get_session_service)]
|
||||
) -> SessionStatusResponse:
|
||||
"""Get the current status of a session.
|
||||
|
||||
Args:
|
||||
session_id: UUID of the session
|
||||
session_service: Injected SessionService instance
|
||||
|
||||
Returns:
|
||||
SessionStatusResponse with session status and metadata
|
||||
"""
|
||||
try:
|
||||
result = await session_service.get_session_status(session_id)
|
||||
return SessionStatusResponse(
|
||||
session_id=result["session_id"],
|
||||
status=result["status"],
|
||||
notes_count=result["notes_count"],
|
||||
created_at=result["created_at"]
|
||||
)
|
||||
except ValueError as e:
|
||||
logger.error(f"Session not found: {e}")
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting session status: {e}")
|
||||
raise HTTPException(status_code=500, detail="Failed to get session status")
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
"""Health check endpoint."""
|
||||
return {"status": "healthy", "service": "SkyTalk API"}
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def root():
|
||||
"""Root endpoint with API information."""
|
||||
return {
|
||||
"message": "Welcome to SkyTalk API",
|
||||
"description": "AI-powered conversational idea exploration and knowledge synthesis",
|
||||
"version": "1.0.0",
|
||||
"docs": "/docs"
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
uvicorn.run(
|
||||
"app.main:app",
|
||||
host=settings.API_HOST,
|
||||
port=settings.API_PORT,
|
||||
reload=True
|
||||
)
|
||||
Reference in New Issue
Block a user