93 lines
2.9 KiB
Python
93 lines
2.9 KiB
Python
import logging
|
|
import json
|
|
from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import JSONResponse
|
|
from contextlib import asynccontextmanager
|
|
from app.routers import auth, meetings, analyses
|
|
from app.config import settings
|
|
from app.services.websocket_service import manager
|
|
|
|
|
|
class JSONFormatter(logging.Formatter):
|
|
def format(self, record):
|
|
log_record = {
|
|
"level": record.levelname,
|
|
"message": record.getMessage(),
|
|
"logger": record.name,
|
|
"time": self.formatTime(record),
|
|
}
|
|
if record.exc_info:
|
|
log_record["exception"] = self.formatException(record.exc_info)
|
|
return json.dumps(log_record, ensure_ascii=False)
|
|
|
|
|
|
handler = logging.StreamHandler()
|
|
handler.setFormatter(JSONFormatter())
|
|
logging.basicConfig(handlers=[handler], level=logging.INFO, force=True)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
logger.info(json.dumps({"event": "startup", "message": "Meeting Assistant API starting"}))
|
|
yield
|
|
logger.info(json.dumps({"event": "shutdown", "message": "Meeting Assistant API stopping"}))
|
|
|
|
|
|
app = FastAPI(
|
|
title="Meeting Assistant API",
|
|
description="Orchestration server for Meeting Assistant - middleware between Mobile App and AI services",
|
|
version="1.0.0",
|
|
lifespan=lifespan,
|
|
docs_url="/docs",
|
|
redoc_url="/redoc",
|
|
)
|
|
|
|
origins = settings.ALLOWED_ORIGINS.split(",") if settings.ALLOWED_ORIGINS != "*" else ["*"]
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=origins,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
app.include_router(auth.router, prefix="/api/auth", tags=["auth"])
|
|
app.include_router(meetings.router, prefix="/api/meetings", tags=["meetings"])
|
|
app.include_router(analyses.router, prefix="/api", tags=["analyses"])
|
|
|
|
|
|
@app.get("/health", tags=["health"])
|
|
async def health_check():
|
|
return {
|
|
"status": "healthy",
|
|
"service": "meeting-assistant-api",
|
|
"version": "1.0.0",
|
|
}
|
|
|
|
|
|
@app.websocket("/ws/meetings/{meeting_id}")
|
|
async def websocket_endpoint(websocket: WebSocket, meeting_id: str):
|
|
await manager.connect(websocket, meeting_id)
|
|
try:
|
|
while True:
|
|
data = await websocket.receive_text()
|
|
await manager.send_message(meeting_id, {"type": "ping", "data": data})
|
|
except WebSocketDisconnect:
|
|
manager.disconnect(websocket, meeting_id)
|
|
|
|
|
|
@app.exception_handler(Exception)
|
|
async def global_exception_handler(request: Request, exc: Exception):
|
|
logger.error(json.dumps({
|
|
"event": "unhandled_exception",
|
|
"error": str(exc),
|
|
"path": str(request.url),
|
|
"method": request.method,
|
|
}))
|
|
return JSONResponse(
|
|
status_code=500,
|
|
content={"detail": "Internal server error"},
|
|
)
|