# app/__init__.py from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager import logging from fastapi.staticfiles import StaticFiles import os # Настройка логгера logger = logging.getLogger('VADApp') @asynccontextmanager async def lifespan(app: FastAPI): """Управление жизненным циклом приложения""" from app.core.config import get_settings from app.core.vad import init_vad_and_stt, cleanup_vad_and_stt from app.api.session import set_session_manager logger.info("Инициализация приложения...") try: # Загружаем настройки settings = get_settings() # Инициализируем аудиоподсистему для TTS import sys sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import piper_TTS logger.info("Инициализация аудиоподсистемы...") piper_TTS.initialize_audio() # Инициализируем VAD и STT vad_instance, stt_instance, commands, session_manager = init_vad_and_stt() app.state.vad_instance = vad_instance app.state.stt_instance = stt_instance app.state.commands = commands app.state.session_manager = session_manager # Передаем session_manager в API модуль set_session_manager(session_manager) from app.core.status import status_tracker, SystemStatus # Добавлено app.state.status_tracker = status_tracker # Добавлено status_tracker.set_status(SystemStatus.LISTENING) # Добавлено logger.info("Сервер запущен") yield except Exception as e: logger.error(f"Ошибка в lifespan: {e}", exc_info=True) raise finally: logger.info("Завершение работы сервера...") cleanup_vad_and_stt(app.state.vad_instance, app.state.stt_instance) logger.info("Сервер завершил работу") def create_app() -> FastAPI: """Создание и настройка приложения FastAPI""" app = FastAPI(title="My Speaker API", lifespan=lifespan) # Настройка CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], # В продакшене указать конкретные домены allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Подключение маршрутов API from app.api.router import api_router app.include_router(api_router) # Монтирование статических файлов на корень app.mount("/", StaticFiles(directory="webapp", html=True), name="static") # Удаляем лишние маршруты, так как StaticFiles обрабатывает всё # @app.get("/") # async def read_root(): # return FileResponse(os.path.join("webapp", "index.html")) # # @app.get("/index.html") # async def read_index(): # return FileResponse(os.path.join("webapp", "index.html")) # # @app.get("/{full_path:path}") # async def catch_all(full_path: str): # if full_path.startswith("api/") or full_path.startswith("static/"): # raise HTTPException(status_code=404, detail="Not Found") # return FileResponse(os.path.join("webapp", "index.html")) # # @app.exception_handler(StarletteHTTPException) # async def custom_http_exception_handler(request, exc): # if exc.status_code == 404: # return FileResponse(os.path.join("webapp", "index.html")) # raise exc return app