liumaolin commited on
Commit
a16e0e5
·
1 Parent(s): 5c0e715

Introduce core module for API lifecycle management: add configuration, service factories, service manager, and lifespan handlers to streamline application startup, shutdown, and service orchestration.

Browse files
src/VoiceDialogue/api/app.py CHANGED
@@ -1,17 +1,11 @@
1
  import logging
2
- from contextlib import asynccontextmanager
3
  from typing import Dict, Any
4
 
5
  from fastapi import FastAPI, HTTPException, APIRouter
6
  from fastapi.middleware.cors import CORSMiddleware
7
 
8
- from services.audio.audio_player import AudioStreamPlayer
9
- from services.core.constants import (
10
- transcribed_text_queue, text_input_queue, audio_output_queue, audio_frames_queue, user_voice_queue
11
- )
12
- from services.speech import SpeechStateMonitor, ASRWorker
13
- from services.text.text_generator import LLMResponseGenerator
14
- from utils import get_system_language
15
  from .middleware.logging import LoggingMiddleware
16
  from .middleware.rate_limit import RateLimitMiddleware
17
  from .routes import tts_routes, asr_routes
@@ -23,138 +17,99 @@ logging.basicConfig(
23
  )
24
  logger = logging.getLogger(__name__)
25
 
26
- # 全局状态存储
27
- app_state: Dict[str, Any] = {}
28
 
 
 
29
 
30
- @asynccontextmanager
31
- async def lifespan(app: FastAPI):
32
- """应用启动和关闭的生命周期管理"""
33
- # 启动时的初始化
34
- logger.info("正在启动VoiceDialogue API服务...")
35
 
36
- system_default_language = get_system_language()
 
 
 
 
 
 
 
 
37
 
38
- # 初始化TTS配置注册表
39
- try:
40
- from services.audio.audio_generator import tts_config_registry
41
- logger.info(f"已加载 {len(tts_config_registry.get_all_configs())} 个TTS配置")
42
- app_state["tts_configs_loaded"] = True
43
- except Exception as e:
44
- logger.error(f"TTS配置加载失败: {e}")
45
- app_state["tts_configs_loaded"] = False
46
 
47
- speech_monitor = SpeechStateMonitor(
48
- audio_frame_queue=audio_frames_queue,
49
- user_voice_queue=user_voice_queue,
50
- )
51
- speech_monitor.start()
52
- app_state['speech_monitor'] = speech_monitor
53
 
54
- asr_worker = ASRWorker(
55
- user_voice_queue=user_voice_queue, transcribed_text_queue=transcribed_text_queue,
56
- language=system_default_language
57
- )
58
- asr_worker.start()
59
- app_state['asr_worker'] = asr_worker
60
 
61
- llm_generator = LLMResponseGenerator(
62
- user_question_queue=transcribed_text_queue, generated_answer_queue=text_input_queue
63
- )
64
- llm_generator.start()
65
- app_state['llm_generator'] = llm_generator
66
-
67
- audio_player = AudioStreamPlayer(audio_playing_queue=audio_output_queue)
68
- audio_player.start()
69
- app_state['audio_player'] = audio_player
70
-
71
- app_state["system_running"] = True
72
- logger.info("VoiceDialogue API服务启动完成")
73
- yield
74
-
75
- # 关闭时的清理
76
- logger.info("正在关闭VoiceDialogue API服务...")
77
- app_state["system_running"] = False
78
- logger.info("VoiceDialogue API服务已关闭")
79
-
80
-
81
- # 创建FastAPI应用
82
- app = FastAPI(
83
- title="VoiceDialogue API",
84
- description="""
85
- 语音对话系统的HTTP API接口
86
-
87
- ## 功能特性
88
-
89
- * **TTS模型管理**: 查看、加载、删除TTS模型
90
- * **模型状态监控**: 实时监控模型下载和加载状态
91
- * **RESTful API**: 标准的REST接口设计
92
- * **自动文档**: 自动生成的API文档和测试界面
93
-
94
- ## 使用方法
95
-
96
- 1. 查看所有可用的TTS模型: `GET /api/v1/tts/models`
97
- 2. 加载指定模型: `POST /api/v1/tts/models/load`
98
- 3. 查看模型状态: `GET /api/v1/tts/models/{model_id}/status`
99
- 4. 删除模型: `DELETE /api/v1/tts/models/{model_id}`
100
- """,
101
- version="1.0.0",
102
- docs_url="/docs",
103
- redoc_url="/redoc",
104
- lifespan=lifespan,
105
- )
106
 
107
- # 添加CORS中间件
108
- app.add_middleware(
109
- CORSMiddleware,
110
- allow_origins=["*"], # 生产环境中应该设置具体的域名
111
- allow_credentials=True,
112
- allow_methods=["*"],
113
- allow_headers=["*"],
114
- )
115
 
116
- # 添加自定义中间件
117
- app.add_middleware(LoggingMiddleware)
118
- app.add_middleware(RateLimitMiddleware)
119
-
120
- # 注册路由
121
- v1_router = APIRouter(prefix="/api/v1")
122
- # v1_router.include_router(voice_routes.router, prefix="/voice", tags=["语音处理"])
123
- # v1_router.include_router(system_routes.router, prefix="/system", tags=["系统控制"])
124
- v1_router.include_router(tts_routes.router, prefix="/tts", tags=["TTS模型管理"])
125
- v1_router.include_router(asr_routes.router, prefix="/asr", tags=["ASR模型管理"])
126
-
127
- app.include_router(v1_router)
128
-
129
-
130
- @app.get("/")
131
- async def root():
132
- """根路径健康检查"""
133
- return {
134
- "message": "欢迎使用VoiceDialogue API",
135
- "status": "running",
136
- "version": "1.0.0",
137
- "docs_url": "/docs",
138
- "redoc_url": "/redoc"
139
- }
140
-
141
-
142
- @app.get("/health")
143
- async def health_check():
144
- """健康检查端点"""
145
- return {
146
- "status": "healthy",
147
- "tts_configs_loaded": app_state.get("tts_configs_loaded", False),
148
- "system_running": app_state.get("system_running", False),
149
- "available_models": len(app_state.get("available_models", []))
150
- }
151
-
152
-
153
- # 全局异常处理器
154
- @app.exception_handler(Exception)
155
- async def global_exception_handler(request, exc):
156
- logger.error(f"未处理的异常: {exc}", exc_info=True)
157
- return HTTPException(
158
- status_code=500,
159
- detail="内部服务器错误"
160
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import logging
 
2
  from typing import Dict, Any
3
 
4
  from fastapi import FastAPI, HTTPException, APIRouter
5
  from fastapi.middleware.cors import CORSMiddleware
6
 
7
+ from .core.config import AppConfig
8
+ from .core.lifespan import lifespan
 
 
 
 
 
9
  from .middleware.logging import LoggingMiddleware
10
  from .middleware.rate_limit import RateLimitMiddleware
11
  from .routes import tts_routes, asr_routes
 
17
  )
18
  logger = logging.getLogger(__name__)
19
 
 
 
20
 
21
+ def create_app() -> FastAPI:
22
+ """创建并配置FastAPI应用"""
23
 
24
+ # 应用配置
25
+ config = AppConfig()
 
 
 
26
 
27
+ # 创建FastAPI应用
28
+ app = FastAPI(
29
+ title=config.title,
30
+ description=config.description,
31
+ version=config.version,
32
+ docs_url=config.docs_url,
33
+ redoc_url=config.redoc_url,
34
+ lifespan=lifespan,
35
+ )
36
 
37
+ # 添加CORS中间件
38
+ app.add_middleware(CORSMiddleware, **config.get_cors_config())
 
 
 
 
 
 
39
 
40
+ # 添加自定义中间件
41
+ app.add_middleware(LoggingMiddleware)
42
+ app.add_middleware(RateLimitMiddleware)
 
 
 
43
 
44
+ # 注册路由
45
+ _register_routes(app)
 
 
 
 
46
 
47
+ # 注册异常处理器
48
+ _register_exception_handlers(app)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ return app
 
 
 
 
 
 
 
51
 
52
+
53
+ def _register_routes(app: FastAPI):
54
+ """注册所有路由"""
55
+ # API路由
56
+ v1_router = APIRouter(prefix="/api/v1")
57
+ v1_router.include_router(tts_routes.router, prefix="/tts", tags=["TTS模型管理"])
58
+ v1_router.include_router(asr_routes.router, prefix="/asr", tags=["ASR模型管理"])
59
+
60
+ app.include_router(v1_router)
61
+
62
+ # 根路径和健康检查
63
+ _register_health_routes(app)
64
+
65
+
66
+ def _register_health_routes(app: FastAPI):
67
+ """注册健康检查路由"""
68
+
69
+ @app.get("/")
70
+ async def root():
71
+ """根路径健康检查"""
72
+ return {
73
+ "message": "欢迎使用VoiceDialogue API",
74
+ "status": "running",
75
+ "version": "1.0.0",
76
+ "docs_url": "/docs",
77
+ "redoc_url": "/redoc"
78
+ }
79
+
80
+ @app.get("/health")
81
+ async def health_check():
82
+ """健康检查端点"""
83
+ app_state = getattr(app, 'state', {})
84
+
85
+ return {
86
+ "status": "healthy",
87
+ "tts_configs_loaded": app_state.get("tts_configs_loaded", False),
88
+ "system_running": app_state.get("system_running", False),
89
+ "tts_config_count": app_state.get("tts_config_count", 0),
90
+ "services": _get_service_status(app_state)
91
+ }
92
+
93
+
94
+ def _get_service_status(app_state: Dict[str, Any]) -> dict:
95
+ """获取服务状态信息"""
96
+ service_manager = app_state.get("service_manager")
97
+ if service_manager:
98
+ return service_manager.get_service_status()
99
+ return {"total_services": 0, "services": {}}
100
+
101
+
102
+ def _register_exception_handlers(app: FastAPI):
103
+ """注册全局异常处理器"""
104
+
105
+ @app.exception_handler(Exception)
106
+ async def global_exception_handler(request, exc):
107
+ logger.error(f"未处理的异常: {exc}", exc_info=True)
108
+ return HTTPException(
109
+ status_code=500,
110
+ detail="内部服务器错误"
111
+ )
112
+
113
+
114
+ # 创建应用实例
115
+ app = create_app()
src/VoiceDialogue/api/core/__init__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .config import AppConfig, TTSConfigInitializer
2
+ from .lifespan import lifespan, LifespanManager
3
+ from .service_factories import ServiceFactories, get_service_definitions
4
+ from .service_manager import ServiceManager, ServiceDefinition
5
+
6
+ __all__ = [
7
+ 'ServiceManager',
8
+ 'ServiceDefinition',
9
+ 'ServiceFactories',
10
+ 'get_service_definitions',
11
+ 'AppConfig',
12
+ 'TTSConfigInitializer',
13
+ 'lifespan',
14
+ 'LifespanManager'
15
+ ]
src/VoiceDialogue/api/core/config.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from typing import Dict, Any
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+
7
+ class TTSConfigInitializer:
8
+ """TTS配置初始化器"""
9
+
10
+ @staticmethod
11
+ def initialize() -> Dict[str, Any]:
12
+ """初始化TTS配置"""
13
+ result = {
14
+ "tts_configs_loaded": False,
15
+ "tts_config_count": 0,
16
+ "tts_config_errors": []
17
+ }
18
+
19
+ try:
20
+ from services.audio.audio_generator import tts_config_registry
21
+ config_count = len(tts_config_registry.get_all_configs())
22
+
23
+ result.update({
24
+ "tts_configs_loaded": True,
25
+ "tts_config_count": config_count
26
+ })
27
+
28
+ logger.info(f"已加载 {config_count} 个TTS配置")
29
+
30
+ except ImportError as e:
31
+ error_msg = f"TTS模块导入失败: {e}"
32
+ logger.error(error_msg)
33
+ result["tts_config_errors"].append(error_msg)
34
+
35
+ except Exception as e:
36
+ error_msg = f"TTS配置加载失败: {e}"
37
+ logger.error(error_msg, exc_info=True)
38
+ result["tts_config_errors"].append(error_msg)
39
+
40
+ return result
41
+
42
+
43
+ class AppConfig:
44
+ """应用配置类"""
45
+
46
+ def __init__(self):
47
+ self.title = "VoiceDialogue API"
48
+ self.version = "1.0.0"
49
+ self.description = self._get_description()
50
+ self.docs_url = "/docs"
51
+ self.redoc_url = "/redoc"
52
+
53
+ def _get_description(self) -> str:
54
+ return """
55
+ 语音对话系统的HTTP API接口
56
+
57
+ ## 功能特性
58
+
59
+ * **TTS模型管理**: 查看、加载、删除TTS模型
60
+ * **模型状态监控**: 实时监控模型下载和加载状态
61
+ * **RESTful API**: 标准的REST接口设计
62
+ * **自动文档**: 自动生成的API文档和测试界面
63
+
64
+ ## 使用方法
65
+
66
+ 1. 查看所有可用的TTS模型: `GET /api/v1/tts/models`
67
+ 2. 加载指定模型: `POST /api/v1/tts/models/load`
68
+ 3. 查看模型状态: `GET /api/v1/tts/models/{model_id}/status`
69
+ 4. 删除模型: `DELETE /api/v1/tts/models/{model_id}`
70
+ """
71
+
72
+ def get_cors_config(self) -> dict:
73
+ """获取CORS配置"""
74
+ return {
75
+ "allow_origins": ["*"], # 生产环境中应该设置具体的域名
76
+ "allow_credentials": True,
77
+ "allow_methods": ["*"],
78
+ "allow_headers": ["*"],
79
+ }
src/VoiceDialogue/api/core/lifespan.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import time
3
+ from contextlib import asynccontextmanager
4
+
5
+ from fastapi import FastAPI
6
+
7
+ from utils import get_system_language
8
+ from .config import TTSConfigInitializer
9
+ from .service_factories import get_service_definitions
10
+ from .service_manager import ServiceManager
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class LifespanManager:
16
+ """应用生命周期管理器"""
17
+
18
+ def __init__(self, app: FastAPI):
19
+ self.app = app
20
+ self.service_manager = ServiceManager()
21
+
22
+ async def startup(self):
23
+ """应用启动逻辑"""
24
+ logger.info("正在启动VoiceDialogue API服务...")
25
+ startup_start_time = time.time()
26
+
27
+ try:
28
+ # 初始化系统语言
29
+ system_language = get_system_language()
30
+ logger.info(f"系统默认语言: {system_language}")
31
+
32
+ # 初始化TTS配置
33
+ tts_config = TTSConfigInitializer.initialize()
34
+ self._update_app_state(tts_config)
35
+
36
+ # 获取服务定义
37
+ service_definitions = get_service_definitions(system_language)
38
+
39
+ # 启动所有服务
40
+ await self._start_all_services(service_definitions)
41
+
42
+ # 更新应用状态
43
+ self._update_app_state({
44
+ "service_manager": self.service_manager,
45
+ "system_running": True,
46
+ "system_language": system_language
47
+ })
48
+
49
+ # 记录启动信息
50
+ startup_duration = time.time() - startup_start_time
51
+ service_status = self.service_manager.get_service_status()
52
+
53
+ logger.info(f"VoiceDialogue API服务启动完成")
54
+ logger.info(f"启动总耗时: {startup_duration:.2f}秒")
55
+ logger.info(f"启动的服务数量: {service_status['total_services']}")
56
+
57
+ if service_status['startup_errors']:
58
+ logger.warning(f"启动时发生 {service_status['startup_errors']} 个错误")
59
+
60
+ except Exception as e:
61
+ logger.error(f"服务启动失败: {e}", exc_info=True)
62
+ await self.shutdown()
63
+ raise
64
+
65
+ def _update_app_state(self, state_updates: dict):
66
+ """更新应用状态"""
67
+ for key, value in state_updates.items():
68
+ setattr(self.app.state, key, value)
69
+
70
+ async def _start_all_services(self, service_definitions):
71
+ """启动所有服务"""
72
+ for service_def in service_definitions:
73
+ success = self.service_manager.start_service(service_def)
74
+ if not success and service_def.required:
75
+ raise RuntimeError(f"必需服务 {service_def.name} 启动失败")
76
+
77
+ async def shutdown(self):
78
+ """应用关闭逻辑"""
79
+ logger.info("正在关闭VoiceDialogue API服务...")
80
+
81
+ # 更新状态
82
+ setattr(self.app.state, "system_running", False)
83
+
84
+ # 停止所有服务
85
+ self.service_manager.stop_all_services()
86
+
87
+ logger.info("VoiceDialogue API服务已关闭")
88
+
89
+
90
+ @asynccontextmanager
91
+ async def lifespan(app: FastAPI):
92
+ """FastAPI生命周期管理"""
93
+ # 创建生命周期管理器
94
+ lifespan_manager = LifespanManager(app)
95
+
96
+ try:
97
+ # 启动
98
+ await lifespan_manager.startup()
99
+ yield
100
+ finally:
101
+ # 关闭
102
+ await lifespan_manager.shutdown()
src/VoiceDialogue/api/core/service_factories.py ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+
3
+ from services.audio import EchoCancellingAudioCapture, TTSAudioGenerator, AudioStreamPlayer
4
+ from services.audio.audio_generator import BaseTTSConfig
5
+ from services.core.constants import (
6
+ transcribed_text_queue, text_input_queue, audio_output_queue,
7
+ audio_frames_queue, user_voice_queue
8
+ )
9
+ from services.speech import SpeechStateMonitor, ASRWorker
10
+ from services.text.text_generator import LLMResponseGenerator
11
+ from .service_manager import ServiceDefinition
12
+
13
+
14
+ class ServiceFactories:
15
+ """服务工厂类,封装所有服务的创建逻辑"""
16
+
17
+ @staticmethod
18
+ def create_audio_capture() -> EchoCancellingAudioCapture:
19
+ """创建音频捕获服务"""
20
+ return EchoCancellingAudioCapture(
21
+ audio_frames_queue=audio_frames_queue
22
+ )
23
+
24
+ @staticmethod
25
+ def create_speech_monitor() -> SpeechStateMonitor:
26
+ """创建语音监控服务"""
27
+ return SpeechStateMonitor(
28
+ audio_frame_queue=audio_frames_queue,
29
+ user_voice_queue=user_voice_queue,
30
+ )
31
+
32
+ @staticmethod
33
+ def create_asr_worker(language: str) -> ASRWorker:
34
+ """创建ASR服务"""
35
+ return ASRWorker(
36
+ user_voice_queue=user_voice_queue,
37
+ transcribed_text_queue=transcribed_text_queue,
38
+ language=language
39
+ )
40
+
41
+ @staticmethod
42
+ def create_llm_generator() -> LLMResponseGenerator:
43
+ """创建LLM文本生成服务"""
44
+ return LLMResponseGenerator(
45
+ user_question_queue=transcribed_text_queue,
46
+ generated_answer_queue=text_input_queue
47
+ )
48
+
49
+ @staticmethod
50
+ def create_tts_audio_generator(tts_speaker_config: BaseTTSConfig) -> TTSAudioGenerator:
51
+ """创建TTS音频生成服务"""
52
+ return TTSAudioGenerator(
53
+ text_input_queue=text_input_queue,
54
+ audio_output_queue=audio_output_queue,
55
+ tts_config=tts_speaker_config
56
+ )
57
+
58
+ @staticmethod
59
+ def create_audio_player() -> AudioStreamPlayer:
60
+ """创建音频播放服务"""
61
+ return AudioStreamPlayer(audio_playing_queue=audio_output_queue)
62
+
63
+ @staticmethod
64
+ def create_tts_config_loader() -> Any:
65
+ """创建TTS配置加载器的虚拟服务"""
66
+
67
+ class TTSConfigLoader:
68
+ def __init__(self):
69
+ self.is_ready = False
70
+ self._running = False
71
+
72
+ def start(self):
73
+ self._running = True
74
+ self.is_ready = True
75
+
76
+ def stop(self):
77
+ self._running = False
78
+
79
+ def is_alive(self):
80
+ return self._running
81
+
82
+ return TTSConfigLoader()
83
+
84
+
85
+ def get_service_definitions(system_language: str) -> list:
86
+ """获取服务定义配置"""
87
+
88
+ return [
89
+ ServiceDefinition(
90
+ name="tts_config_loader",
91
+ factory=ServiceFactories.create_tts_config_loader,
92
+ required=False,
93
+ startup_timeout=10
94
+ ),
95
+
96
+ ServiceDefinition(
97
+ name="speech_monitor",
98
+ factory=ServiceFactories.create_speech_monitor,
99
+ dependencies=[],
100
+ health_check=lambda service: hasattr(service, 'is_ready') and service.is_ready
101
+ ),
102
+
103
+ ServiceDefinition(
104
+ name="asr_worker",
105
+ factory=lambda: ServiceFactories.create_asr_worker(system_language),
106
+ dependencies=["speech_monitor"]
107
+ ),
108
+
109
+ ServiceDefinition(
110
+ name="llm_generator",
111
+ factory=ServiceFactories.create_llm_generator,
112
+ dependencies=["asr_worker"]
113
+ ),
114
+
115
+ ServiceDefinition(
116
+ name="audio_player",
117
+ factory=ServiceFactories.create_audio_player,
118
+ dependencies=["llm_generator"]
119
+ )
120
+ ]
src/VoiceDialogue/api/core/service_manager.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import time
3
+ from dataclasses import dataclass
4
+ from typing import Dict, List, Callable, Any, Optional
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ @dataclass
10
+ class ServiceDefinition:
11
+ """服务定义类,用于配置化管理服务"""
12
+ name: str
13
+ factory: Callable[[], Any]
14
+ dependencies: List[str] = None
15
+ required: bool = True
16
+ startup_timeout: int = 30 # 启动超时时间(秒)
17
+ health_check: Optional[Callable[[Any], bool]] = None
18
+
19
+ def __post_init__(self):
20
+ if self.dependencies is None:
21
+ self.dependencies = []
22
+
23
+
24
+ class ServiceManager:
25
+ """服务管理器,负责服务的统一启动、停止和监控"""
26
+
27
+ def __init__(self):
28
+ self.services: Dict[str, Any] = {}
29
+ self.startup_errors: Dict[str, str] = {}
30
+ self.startup_times: Dict[str, float] = {}
31
+ self._shutdown_hooks: List[Callable] = []
32
+
33
+ def add_shutdown_hook(self, hook: Callable):
34
+ """添加关闭钩子函数"""
35
+ self._shutdown_hooks.append(hook)
36
+
37
+ def start_service(self, service_def: ServiceDefinition) -> bool:
38
+ """启动单个服务"""
39
+ start_time = time.time()
40
+ try:
41
+ logger.info(f"正在启动服务: {service_def.name}")
42
+
43
+ # 检查依赖服务
44
+ if not self._check_dependencies(service_def.dependencies):
45
+ raise RuntimeError(f"服务 {service_def.name} 的依赖服务未就绪")
46
+
47
+ service = service_def.factory()
48
+ service.start()
49
+
50
+ # 等待服务就绪
51
+ if not self._wait_for_service_ready(service, service_def):
52
+ raise TimeoutError(f"服务 {service_def.name} 启动超时")
53
+
54
+ # 健康检查
55
+ if service_def.health_check and not service_def.health_check(service):
56
+ raise RuntimeError(f"服务 {service_def.name} 健康检查失败")
57
+
58
+ self.services[service_def.name] = service
59
+ self.startup_times[service_def.name] = time.time() - start_time
60
+
61
+ logger.info(f"服务 {service_def.name} 启动成功,耗时: {self.startup_times[service_def.name]:.2f}秒")
62
+ return True
63
+
64
+ except Exception as e:
65
+ error_msg = f"服务 {service_def.name} 启动失败: {e}"
66
+ logger.error(error_msg, exc_info=True)
67
+ self.startup_errors[service_def.name] = error_msg
68
+
69
+ if service_def.required:
70
+ raise RuntimeError(error_msg)
71
+ return False
72
+
73
+ def _check_dependencies(self, dependencies: List[str]) -> bool:
74
+ """检查依赖服务是否已启动并就绪"""
75
+ for dep in dependencies:
76
+ if dep not in self.services:
77
+ logger.error(f"依赖服务 {dep} 未启动")
78
+ return False
79
+ if not self.services[dep].is_ready:
80
+ logger.error(f"依赖服务 {dep} 未就绪")
81
+ return False
82
+ return True
83
+
84
+ def _wait_for_service_ready(self, service: Any, service_def: ServiceDefinition) -> bool:
85
+ """等待服务就绪"""
86
+ timeout = service_def.startup_timeout
87
+ start_time = time.time()
88
+
89
+ while not service.is_ready and (time.time() - start_time) < timeout:
90
+ time.sleep(0.1)
91
+
92
+ return service.is_ready
93
+
94
+ def stop_all_services(self):
95
+ """停止所有服务"""
96
+ logger.info("正在停止所有服务...")
97
+
98
+ # 执行关闭钩子
99
+ for hook in self._shutdown_hooks:
100
+ try:
101
+ hook()
102
+ except Exception as e:
103
+ logger.error(f"执行关闭钩子时发生错误: {e}", exc_info=True)
104
+
105
+ # 按启动顺序的逆序停止服务
106
+ for service_name in reversed(list(self.services.keys())):
107
+ self._stop_single_service(service_name)
108
+
109
+ self.services.clear()
110
+
111
+ def _stop_single_service(self, service_name: str):
112
+ """停止单个服务"""
113
+ try:
114
+ service = self.services[service_name]
115
+ logger.info(f"正在停止服务: {service_name}")
116
+
117
+ service.stop()
118
+
119
+ # 等待服务停止(最多等待5秒)
120
+ timeout = 5
121
+ start_time = time.time()
122
+ while service.is_alive() and (time.time() - start_time) < timeout:
123
+ time.sleep(0.1)
124
+
125
+ if service.is_alive():
126
+ logger.warning(f"服务 {service_name} 未能在超时时间内停止")
127
+ else:
128
+ logger.info(f"服务 {service_name} 已停止")
129
+
130
+ except Exception as e:
131
+ logger.error(f"停止服务 {service_name} 时发生错误: {e}", exc_info=True)
132
+
133
+ def get_service_status(self) -> dict:
134
+ """获取所有服务状态"""
135
+ return {
136
+ "total_services": len(self.services),
137
+ "startup_errors": len(self.startup_errors),
138
+ "startup_times": self.startup_times.copy(),
139
+ "errors": self.startup_errors.copy(),
140
+ "services": {
141
+ name: {
142
+ "running": service.is_alive(),
143
+ "ready": service.is_ready
144
+ }
145
+ for name, service in self.services.items()
146
+ }
147
+ }
148
+
149
+ def get_service(self, name: str) -> Optional[Any]:
150
+ """获取指定服务实例"""
151
+ return self.services.get(name)
152
+
153
+ def is_service_running(self, name: str) -> bool:
154
+ """检查服务是否正在运行"""
155
+ service = self.services.get(name)
156
+ return service is not None and service.is_alive()
src/VoiceDialogue/services/audio/__init__.py CHANGED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from .aec_audio_capture import EchoCancellingAudioCapture
2
+ from .audio_answer import TTSAudioGenerator
3
+ from .audio_player import AudioStreamPlayer
4
+
5
+ __all__ = (
6
+ "EchoCancellingAudioCapture",
7
+ "TTSAudioGenerator",
8
+ "AudioStreamPlayer",
9
+ )