liumaolin commited on
Commit
94c7b78
·
1 Parent(s): a28f7e3

Enhance system management and audio capture services: implement `SystemStatusResponse` updates with detailed state tracking, add `audio_capture` service creation and lifecycle management, and refactor API `/system` routes for improved status and control handling.

Browse files
src/VoiceDialogue/api/app.py CHANGED
@@ -8,7 +8,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
12
 
13
  # 配置日志
14
  logging.basicConfig(
@@ -56,7 +56,8 @@ def _register_routes(app: FastAPI):
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
  # 根路径和健康检查
 
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, system_routes
12
 
13
  # 配置日志
14
  logging.basicConfig(
 
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
+ v1_router.include_router(system_routes.router, prefix="/system", tags=["系统管理"])
60
+
61
  app.include_router(v1_router)
62
 
63
  # 根路径和健康检查
src/VoiceDialogue/api/core/service_factories.py CHANGED
@@ -1,5 +1,3 @@
1
- from typing import Any
2
-
3
  from services.audio import EchoCancellingAudioCapture, TTSAudioGenerator, AudioStreamPlayer
4
  from services.audio.audio_generator import BaseTTSConfig, tts_config_registry
5
  from services.core.constants import (
@@ -127,6 +125,16 @@ def get_core_voice_service_definitions(system_language: str, tts_config: BaseTTS
127
  ]
128
 
129
 
 
 
 
 
 
 
 
 
 
 
130
  def get_service_health_checkers() -> dict:
131
  """获取服务健康检查器映射"""
132
  return {
 
 
 
1
  from services.audio import EchoCancellingAudioCapture, TTSAudioGenerator, AudioStreamPlayer
2
  from services.audio.audio_generator import BaseTTSConfig, tts_config_registry
3
  from services.core.constants import (
 
125
  ]
126
 
127
 
128
+ def get_audio_capture_service_definition() -> ServiceDefinition:
129
+ """获取音频捕获服务定义"""
130
+ return ServiceDefinition(
131
+ name="audio_capture",
132
+ factory=ServiceFactories.create_audio_capture,
133
+ dependencies=[],
134
+ health_check=lambda service: hasattr(service, 'is_ready') and service.is_ready
135
+ )
136
+
137
+
138
  def get_service_health_checkers() -> dict:
139
  """获取服务健康检查器映射"""
140
  return {
src/VoiceDialogue/api/routes/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- from . import tts_routes, asr_routes
2
 
3
- __all__ = ["tts_routes", "asr_routes"]
 
1
+ from . import tts_routes, asr_routes, system_routes
2
 
3
+ __all__ = ["tts_routes", "asr_routes", "system_routes"]
src/VoiceDialogue/api/routes/system_routes.py CHANGED
@@ -2,8 +2,9 @@ import asyncio
2
  import logging
3
  import time
4
 
5
- from fastapi import APIRouter, HTTPException, BackgroundTasks
6
 
 
7
  from ..schemas.system_schemas import (
8
  SystemStatusResponse, SystemConfig,
9
  SystemStartRequest, SystemResponse
@@ -21,42 +22,54 @@ _system_status = {
21
  }
22
 
23
 
24
- # @router.get("/status", response_model=SystemStatusResponse, summary="获取系统状态")
25
- # async def get_system_status():
26
- # """
27
- # 获取系统整体状态,不包含语言模型信息
28
- # """
29
- # try:
30
- # # 获取TTS模型统计
31
- # all_configs = tts_config_registry.get_all_configs()
32
- # downloaded_count = sum(1 for config in all_configs if config.is_model_complete())
33
- #
34
- # # 获取TTS引擎状态
35
- # available_engines = list(tts_manager.list_registered_tts().keys())
36
- #
37
- # status = SystemStatusResponse(
38
- # system_status="running",
39
- # tts_models_total=len(all_configs),
40
- # tts_models_downloaded=downloaded_count,
41
- # available_tts_engines=available_engines,
42
- # memory_usage=_get_memory_usage(),
43
- # disk_usage=_get_disk_usage()
44
- # )
45
- #
46
- # return status
47
- #
48
- # except Exception as e:
49
- # logger.error(f"获取系统状态失败: {e}", exc_info=True)
50
- # raise HTTPException(status_code=500, detail=f"获取系统状态失败: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
51
 
52
 
53
  @router.post("/start", response_model=SystemResponse, summary="启动系统")
54
  async def start_system(
55
  request: SystemStartRequest,
 
56
  background_tasks: BackgroundTasks
57
  ):
58
  """
59
- 启动语音对话系统
60
  """
61
  try:
62
  if _system_status["status"] in ["running", "starting"]:
@@ -72,7 +85,8 @@ async def start_system(
72
  # 在后台启动系统
73
  background_tasks.add_task(
74
  _start_system_background,
75
- request.config
 
76
  )
77
 
78
  return SystemResponse(
@@ -87,9 +101,9 @@ async def start_system(
87
 
88
 
89
  @router.post("/stop", response_model=SystemResponse, summary="停止系统")
90
- async def stop_system():
91
  """
92
- 停止语音对话系统
93
  """
94
  try:
95
  if _system_status["status"] == "stopped":
@@ -101,8 +115,29 @@ async def stop_system():
101
  # 更新状态
102
  _system_status["status"] = "stopping"
103
 
104
- # 模拟停止过程
105
- await asyncio.sleep(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  _system_status["status"] = "stopped"
108
  _system_status["start_time"] = None
@@ -122,6 +157,7 @@ async def stop_system():
122
  @router.post("/restart", response_model=SystemResponse, summary="重启系统")
123
  async def restart_system(
124
  request: SystemStartRequest,
 
125
  background_tasks: BackgroundTasks
126
  ):
127
  """
@@ -130,28 +166,41 @@ async def restart_system(
130
  try:
131
  # 先停止
132
  if _system_status["status"] != "stopped":
133
- await stop_system()
134
 
135
  # 再启动
136
- return await start_system(request, background_tasks)
137
 
138
  except Exception as e:
139
  logger.error(f"系统重启失败: {e}", exc_info=True)
140
  raise HTTPException(status_code=500, detail=f"系统重启失败: {str(e)}")
141
 
142
 
143
- async def _start_system_background(config: SystemConfig):
144
  """
145
- 后台启动系统的实际逻辑
146
  """
147
  try:
148
  logger.info("开始启动语音对话系统...")
149
 
150
- # 模拟启动过程
151
- await asyncio.sleep(2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
- # 这里应该调用实际的系统启动逻辑
154
- # 类似于原来main.py中的launch_system函数
155
 
156
  _system_status["status"] = "running"
157
  _system_status["start_time"] = time.time()
 
2
  import logging
3
  import time
4
 
5
+ from fastapi import APIRouter, HTTPException, BackgroundTasks, Request
6
 
7
+ from ..core.service_factories import get_audio_capture_service_definition
8
  from ..schemas.system_schemas import (
9
  SystemStatusResponse, SystemConfig,
10
  SystemStartRequest, SystemResponse
 
22
  }
23
 
24
 
25
+ @router.get("/status", response_model=SystemStatusResponse, summary="获取系统状态")
26
+ async def get_system_status(request: Request):
27
+ """
28
+ 获取系统整体状态,包含服务运行状态
29
+ """
30
+ try:
31
+ # 从应用状态获取服务管理器
32
+ service_manager = getattr(request.app.state, "service_manager", None)
33
+ system_running = getattr(request.app.state, "system_running", False)
34
+
35
+ # 获取服务状态
36
+ services_status = {}
37
+ if service_manager:
38
+ services_status = service_manager.get_service_status()
39
+
40
+ # 检查audio_capture服务状态
41
+ audio_capture_running = False
42
+ audio_capture_ready = False
43
+ if service_manager and service_manager.is_service_running("audio_capture"):
44
+ audio_capture_service = service_manager.get_service("audio_capture")
45
+ if audio_capture_service:
46
+ audio_capture_running = True
47
+ audio_capture_ready = audio_capture_service.is_ready
48
+
49
+ return SystemStatusResponse(
50
+ status=_system_status["status"],
51
+ uptime=time.time() - _system_status["start_time"] if _system_status["start_time"] else None,
52
+ active_sessions=_system_status["active_sessions"],
53
+ system_running=system_running,
54
+ services_count=services_status.get("total_services", 0),
55
+ audio_capture_running=audio_capture_running,
56
+ audio_capture_ready=audio_capture_ready,
57
+ services_details=services_status
58
+ )
59
+
60
+ except Exception as e:
61
+ logger.error(f"获取系统状态失败: {e}", exc_info=True)
62
+ raise HTTPException(status_code=500, detail=f"获取系统状态失败: {str(e)}")
63
 
64
 
65
  @router.post("/start", response_model=SystemResponse, summary="启动系统")
66
  async def start_system(
67
  request: SystemStartRequest,
68
+ fastapi_request: Request,
69
  background_tasks: BackgroundTasks
70
  ):
71
  """
72
+ 启动语音对话系统 - 创建audio_capture服务
73
  """
74
  try:
75
  if _system_status["status"] in ["running", "starting"]:
 
85
  # 在后台启动系统
86
  background_tasks.add_task(
87
  _start_system_background,
88
+ request.config,
89
+ fastapi_request
90
  )
91
 
92
  return SystemResponse(
 
101
 
102
 
103
  @router.post("/stop", response_model=SystemResponse, summary="停止系统")
104
+ async def stop_system(request: Request):
105
  """
106
+ 停止语音对话系统 - 停止audio_capture服务
107
  """
108
  try:
109
  if _system_status["status"] == "stopped":
 
115
  # 更新状态
116
  _system_status["status"] = "stopping"
117
 
118
+ # 获取服务管理器
119
+ service_manager = getattr(request.app.state, "service_manager", None)
120
+ if service_manager:
121
+ # 停止audio_capture服务
122
+ if service_manager.is_service_running("audio_capture"):
123
+ audio_capture_service = service_manager.get_service("audio_capture")
124
+ if audio_capture_service:
125
+ try:
126
+ audio_capture_service.stop()
127
+ logger.info("音频捕获服务已停止")
128
+
129
+ # 等待服务停止
130
+ timeout = 5
131
+ start_time = time.time()
132
+ while audio_capture_service.is_alive() and (time.time() - start_time) < timeout:
133
+ await asyncio.sleep(0.1)
134
+
135
+ # 从服务管理器中移除
136
+ if "audio_capture" in service_manager.services:
137
+ del service_manager.services["audio_capture"]
138
+
139
+ except Exception as e:
140
+ logger.error(f"停止音频捕获服务时发生错误: {e}", exc_info=True)
141
 
142
  _system_status["status"] = "stopped"
143
  _system_status["start_time"] = None
 
157
  @router.post("/restart", response_model=SystemResponse, summary="重启系统")
158
  async def restart_system(
159
  request: SystemStartRequest,
160
+ fastapi_request: Request,
161
  background_tasks: BackgroundTasks
162
  ):
163
  """
 
166
  try:
167
  # 先停止
168
  if _system_status["status"] != "stopped":
169
+ await stop_system(fastapi_request)
170
 
171
  # 再启动
172
+ return await start_system(request, fastapi_request, background_tasks)
173
 
174
  except Exception as e:
175
  logger.error(f"系统重启失败: {e}", exc_info=True)
176
  raise HTTPException(status_code=500, detail=f"系统重启失败: {str(e)}")
177
 
178
 
179
+ async def _start_system_background(config: SystemConfig, request: Request):
180
  """
181
+ 后台启动系统的实际逻辑 - 创建并启动audio_capture服务
182
  """
183
  try:
184
  logger.info("开始启动语音对话系统...")
185
 
186
+ # 获取服务管理器
187
+ service_manager = getattr(request.app.state, "service_manager", None)
188
+ if not service_manager:
189
+ raise RuntimeError("服务管理器未初始化")
190
+
191
+ # 检查audio_capture服务是否已存在
192
+ if service_manager.is_service_running("audio_capture"):
193
+ logger.info("音频捕获服务已在运行")
194
+ else:
195
+ # 创建audio_capture服务定义
196
+ audio_capture_def = get_audio_capture_service_definition()
197
+
198
+ # 启动audio_capture服务
199
+ success = service_manager.start_service(audio_capture_def)
200
+ if not success:
201
+ raise RuntimeError("音频捕获服务启动失败")
202
 
203
+ logger.info("音频捕获服务启动成功")
 
204
 
205
  _system_status["status"] = "running"
206
  _system_status["start_time"] = time.time()
src/VoiceDialogue/api/schemas/system_schemas.py CHANGED
@@ -1,22 +1,25 @@
1
- from typing import Optional, Literal
2
 
3
  from pydantic import BaseModel, Field
4
 
5
 
6
  class SystemStatusResponse(BaseModel):
7
- """系统状态"""
8
  status: Literal['running', 'stopped', 'starting', 'stopping'] = Field(..., description="系统状态")
9
  uptime: Optional[float] = Field(None, description="运行时间(秒)")
10
  active_sessions: int = Field(default=0, description="活跃会话数")
11
- memory_usage: Optional[float] = Field(None, description="内存使用率")
 
 
 
 
12
 
13
 
14
  class SystemConfig(BaseModel):
15
  """系统配置"""
16
- user_language: Literal['zh', 'en'] = Field(default='zh', description="用户语言")
17
- system_prompt: str = Field(..., description="系统提示词")
18
- tts_speaker: str = Field(default='沈逸', description="TTS语音角色")
19
- llm_model: Literal['7B', '14B'] = Field(default='14B', description="语言模型规模")
20
 
21
 
22
  class SystemStartRequest(BaseModel):
@@ -25,7 +28,6 @@ class SystemStartRequest(BaseModel):
25
 
26
 
27
  class SystemResponse(BaseModel):
28
- """系统响应"""
29
  success: bool = Field(..., description="操作是否成功")
30
  message: str = Field(..., description="响应消息")
31
- status: Optional[SystemStatusResponse] = Field(None, description="系统状态")
 
1
+ from typing import Optional, Literal, Dict, Any
2
 
3
  from pydantic import BaseModel, Field
4
 
5
 
6
  class SystemStatusResponse(BaseModel):
7
+ """系统状态响应"""
8
  status: Literal['running', 'stopped', 'starting', 'stopping'] = Field(..., description="系统状态")
9
  uptime: Optional[float] = Field(None, description="运行时间(秒)")
10
  active_sessions: int = Field(default=0, description="活跃会话数")
11
+ system_running: bool = Field(default=False, description="系统是否运行中")
12
+ services_count: int = Field(default=0, description="运行中的服务数量")
13
+ audio_capture_running: bool = Field(default=False, description="音频捕获服务是否运行")
14
+ audio_capture_ready: bool = Field(default=False, description="音频捕获服务是否就绪")
15
+ services_details: Optional[Dict[str, Any]] = Field(None, description="服务详细状态信息")
16
 
17
 
18
  class SystemConfig(BaseModel):
19
  """系统配置"""
20
+ language: Optional[str] = Field(default="zh", description="系统语言")
21
+ sample_rate: Optional[int] = Field(default=16000, description="音频采样率")
22
+ enable_logging: Optional[bool] = Field(default=True, description="是否启用日志")
 
23
 
24
 
25
  class SystemStartRequest(BaseModel):
 
28
 
29
 
30
  class SystemResponse(BaseModel):
31
+ """系统操作响应"""
32
  success: bool = Field(..., description="操作是否成功")
33
  message: str = Field(..., description="响应消息")