""" PrecisionVoice - Speech-to-Text & Speaker Diarization Application Main FastAPI entry point """ import logging import gc import jinja2 from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse from app.core.config import get_settings from app.api.routes import router from app.services.transcription import TranscriptionService from app.services.diarization import DiarizationService from app.services.emo import EmotionService logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger(__name__) settings = get_settings() @asynccontextmanager async def lifespan(app: FastAPI): logger.info("Starting PrecisionVoice...") logger.info(f"Device: {settings.resolved_device}") logger.info(f"Whisper: {settings.default_whisper_model}") logger.info(f"Diarization: {settings.diarization_backend}") logger.info(f"Emotion: {settings.default_dual_emotion_model}") try: logger.info("Preloading Whisper...") TranscriptionService.preload_model() except Exception as e: logger.error(f"Whisper preload failed: {e}") try: logger.info("Preloading diarization...") DiarizationService.preload_pipeline() except Exception as e: logger.warning(f"Diarization failed: {e}") try: logger.info("Preloading emotion model...") EmotionService.preload_model() except Exception as e: logger.warning(f"Emotion preload failed: {e}") logger.info("Startup complete") yield logger.info("Shutting down...") gc.collect() app = FastAPI( title="PrecisionVoice", description="Speech-to-Text + Diarization + Emotion", version="2.0.0", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.mount("/static", StaticFiles(directory="app/static"), name="static") templates = Jinja2Templates(directory="app/templates") app.include_router(router) @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse( request=request, name="index.html", context={ "max_upload_mb": settings.max_upload_size_mb, "allowed_formats": ", ".join(settings.allowed_extensions), }, ) if __name__ == "__main__": import uvicorn uvicorn.run( "app.main:app", host=settings.host, port=settings.port, reload=True )