import asyncio import os from contextlib import asynccontextmanager from fastapi import FastAPI from services import offline_audio_cache from services.device_config import DeviceConfigManager from services.schedule_session_cleanup import background_cleanup_task from services.role_manager import role_manager from services.task_manager import task_manager from initialization import register_services, init_directories from config import settings from utils.logger import session_logger from api import api_router from api.assets import configure_static_assets from api.wechat_verify import router as wechat_verify_router from banban.routers import banban_router from banban.middleware.auth import install_auth_middleware from banban.middleware.request_log import install_request_logging_middleware from database.init_db import init_db from database.connection import get_db_manager from services.firmware_scanner import firmware_scanner from handlers.mqtt_handler import TalkingQMQTTService from services.scheduler import TaskScheduler device_config_manager = DeviceConfigManager() @asynccontextmanager async def lifespan(app: FastAPI): worker_id = os.environ.get("UVICORN_WID", "0") is_main_process = worker_id == "0" if is_main_process: session_logger.system_info( "startup", f"服务器启动,HTTP服务地址: http://{settings.server_host}:{settings.server_port}", ) init_directories() try: session_logger.system_info("startup", "初始化数据库...") await init_db() session_logger.system_info("startup", "数据库初始化和迁移完成") except Exception as e: session_logger.system_info("startup", f"数据库初始化失败: {str(e)}") scheduler = TaskScheduler.get_instance() scheduler.start() scheduler.add_interval_task( interval_seconds=settings.talkingq_mqtt_nfc_notice_interval ) if settings.talkingq_mqtt_broker: mqtt_config = { "broker": settings.talkingq_mqtt_broker, "port": settings.talkingq_mqtt_port, "username": settings.talkingq_mqtt_username, "password": settings.talkingq_mqtt_password, "device_prefix": settings.talkingq_mqtt_device_prefix, "qos": settings.talkingq_mqtt_qos, "keepalive": settings.talkingq_mqtt_keepalive, "nfc_notice_interval": settings.talkingq_mqtt_nfc_notice_interval, } service = await TalkingQMQTTService.get_instance(mqtt_config) await service.connect() session_logger.system_info("startup", "TalkingQ MQTT 设备命令服务链接已启动") else: session_logger.system_info("startup", "未配置 TalkingQ_MQTT,MQTT 服务链接未启动") exit(1) await role_manager.initialize() await register_services() try: await firmware_scanner.scan_firmware_files() session_logger.system_info("startup", "固件文件扫描完成") except Exception as e: session_logger.system_info("startup", f"固件文件扫描失败: {str(e)}") session_logger.system_info("startup", "中断处理服务已初始化") cleanup_task = asyncio.create_task(background_cleanup_task()) try: yield finally: cleanup_task.cancel() try: await asyncio.wait_for(cleanup_task, timeout=5.0) except (asyncio.CancelledError, asyncio.TimeoutError): if is_main_process: session_logger.system_info("shutdown", "后台清理任务已取消") from services.audio_session import audio_session_manager sessions_to_close = await audio_session_manager.get_all_sessions() for session_key, session in sessions_to_close: try: if session.send_task: session.send_task.cancel() if hasattr(session, "asr_service") and session.asr_service: await session.asr_service.close() if hasattr(session, "llm_service") and session.llm_service: await session.llm_service.close() except Exception as e: if is_main_process: session_logger.system_info("shutdown", f"清理会话时出错: {str(e)}") # 清理所有任务管理器的任务 try: await task_manager.cleanup_all_tasks() if is_main_process: session_logger.system_info("shutdown", "任务管理器清理完成") except Exception as e: if is_main_process: session_logger.system_info("shutdown", f"任务管理器清理时出错: {str(e)}") try: db_manager = await get_db_manager() await db_manager.close() if is_main_process: session_logger.system_info("shutdown", "数据库连接已关闭") except Exception as e: if is_main_process: session_logger.system_info("shutdown", f"关闭数据库连接时出错: {str(e)}") TaskScheduler.reset_instance() await TalkingQMQTTService.reset_instance() session_logger.system_info("shutdown", "TalkingQ MQTT 服务链接已关闭") if is_main_process: session_logger.system_info("shutdown", "应用关闭") app = FastAPI(lifespan=lifespan) configure_static_assets(app) # 安装中间件 install_request_logging_middleware(app) install_auth_middleware(app) app.include_router(wechat_verify_router) app.include_router(api_router) app.include_router(banban_router)