liumaolin commited on
Commit
d701b8a
·
1 Parent(s): fdf6e7b

Add pause and resume functionality to voice dialogue system

Browse files

- Implement `pause` and `resume` methods in audio capture service.
- Add `/pause` and `/resume` API endpoints to manage system state.
- Update system schema to include `paused` and `resuming` statuses.

src/voice_dialogue/api/routes/system_routes.py CHANGED
@@ -205,3 +205,159 @@ async def _start_system_background(request: Request):
205
  except Exception as e:
206
  logger.error(f"后台启动系统失败: {e}", exc_info=True)
207
  _system_status["status"] = "stopped"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  except Exception as e:
206
  logger.error(f"后台启动系统失败: {e}", exc_info=True)
207
  _system_status["status"] = "stopped"
208
+
209
+
210
+ @router.post("/pause", response_model=SystemResponse, summary="暂停系统")
211
+ async def pause_system(request: Request):
212
+ """
213
+ 暂停语音对话系统
214
+ """
215
+ try:
216
+ # 检查当前状态是否允许暂停
217
+ if _system_status["status"] == "stopped":
218
+ return SystemResponse(
219
+ success=False,
220
+ message="系统未启动,无法暂停"
221
+ )
222
+
223
+ if _system_status["status"] == "paused":
224
+ return SystemResponse(
225
+ success=False,
226
+ message="系统已经暂停"
227
+ )
228
+
229
+ if _system_status["status"] in ["starting", "stopping"]:
230
+ return SystemResponse(
231
+ success=False,
232
+ message="系统正在启动或停止中,请稍后再试"
233
+ )
234
+
235
+ # 获取服务管理器
236
+ service_manager = getattr(request.app.state, "service_manager", None)
237
+ if not service_manager:
238
+ return SystemResponse(
239
+ success=False,
240
+ message="服务管理器未初始化"
241
+ )
242
+
243
+ # 获取音频捕获服务
244
+ audio_capture_service = service_manager.get_service("audio_capture")
245
+ if not audio_capture_service:
246
+ return SystemResponse(
247
+ success=False,
248
+ message="音频捕获服务未找到"
249
+ )
250
+
251
+ # 检查服务是否正在运行
252
+ if not service_manager.is_service_running("audio_capture"):
253
+ return SystemResponse(
254
+ success=False,
255
+ message="音频捕获服务未运行"
256
+ )
257
+
258
+ # 暂停音频捕获服务
259
+ try:
260
+ audio_capture_service.pause()
261
+ logger.info("音频捕获服务已暂停")
262
+ except Exception as e:
263
+ logger.error(f"暂停音频捕获服务失败: {e}", exc_info=True)
264
+ return SystemResponse(
265
+ success=False,
266
+ message=f"暂停音频捕获服务失败: {str(e)}"
267
+ )
268
+
269
+ # 更新系统状态
270
+ _system_status["status"] = "paused"
271
+
272
+ return SystemResponse(
273
+ success=True,
274
+ message="语音对话系统已成功暂停"
275
+ )
276
+
277
+ except Exception as e:
278
+ logger.error(f"暂停语音对话系统失败: {e}", exc_info=True)
279
+ # 恢复状态
280
+ if _system_status["status"] == "paused":
281
+ _system_status["status"] = "running"
282
+ raise HTTPException(status_code=500, detail=f"暂停语音对话系统失败: {str(e)}")
283
+
284
+
285
+ @router.post("/resume", response_model=SystemResponse, summary="恢复系统")
286
+ async def resume_system(request: Request):
287
+ """
288
+ 恢复语音对话系统
289
+ """
290
+ try:
291
+ # 检查当前状态是否允许恢复
292
+ if _system_status["status"] == "stopped":
293
+ return SystemResponse(
294
+ success=False,
295
+ message="系统未启动,请先启动系统"
296
+ )
297
+
298
+ if _system_status["status"] == "running":
299
+ return SystemResponse(
300
+ success=False,
301
+ message="系统已经在运行中"
302
+ )
303
+
304
+ if _system_status["status"] in ["starting", "stopping"]:
305
+ return SystemResponse(
306
+ success=False,
307
+ message="系统正在启动或停止中,请稍后再试"
308
+ )
309
+
310
+ if _system_status["status"] != "paused":
311
+ return SystemResponse(
312
+ success=False,
313
+ message="只有暂停状态的系统才能恢复"
314
+ )
315
+
316
+ # 获取服务管理器
317
+ service_manager = getattr(request.app.state, "service_manager", None)
318
+ if not service_manager:
319
+ return SystemResponse(
320
+ success=False,
321
+ message="服务管理器未初始化"
322
+ )
323
+
324
+ # 获取音频捕获服务
325
+ audio_capture_service = service_manager.get_service("audio_capture")
326
+ if not audio_capture_service:
327
+ return SystemResponse(
328
+ success=False,
329
+ message="音频捕获服务未找到"
330
+ )
331
+
332
+ # 检查服务是否存在(可能已被停止)
333
+ if not service_manager.is_service_running("audio_capture"):
334
+ return SystemResponse(
335
+ success=False,
336
+ message="音频捕获服务未运行,请重新启动系统"
337
+ )
338
+
339
+ # 恢复音频捕获服务
340
+ try:
341
+ audio_capture_service.resume()
342
+ logger.info("音频捕获服务已恢复运行")
343
+ except Exception as e:
344
+ logger.error(f"恢复音频捕获服务失败: {e}", exc_info=True)
345
+ return SystemResponse(
346
+ success=False,
347
+ message=f"恢复音频捕获服务失败: {str(e)}"
348
+ )
349
+
350
+ # 更新系统状态为运行中
351
+ _system_status["status"] = "running"
352
+
353
+ return SystemResponse(
354
+ success=True,
355
+ message="语音对话系统已成功恢复运行"
356
+ )
357
+
358
+ except Exception as e:
359
+ logger.error(f"恢复语音对话系统失败: {e}", exc_info=True)
360
+ # 恢复状态
361
+ if _system_status["status"] == "running":
362
+ _system_status["status"] = "paused"
363
+ raise HTTPException(status_code=500, detail=f"恢复语音对话系统失败: {str(e)}")
src/voice_dialogue/api/schemas/system_schemas.py CHANGED
@@ -5,7 +5,7 @@ from pydantic import BaseModel, Field
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="系统是否运行中")
 
5
 
6
  class SystemStatusResponse(BaseModel):
7
  """系统状态响应"""
8
+ status: Literal['running', 'stopped', 'paused', 'starting', 'stopping', 'resuming'] = 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="系统是否运行中")
src/voice_dialogue/services/audio/capture.py CHANGED
@@ -5,6 +5,7 @@
5
 
6
  import ctypes
7
  import time
 
8
 
9
  import numpy as np
10
 
@@ -23,6 +24,17 @@ class EchoCancellingAudioCapture(BaseThread):
23
  super().__init__(group, target, name, args, kwargs, daemon=daemon)
24
 
25
  self.audio_frames_queue = audio_frames_queue
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  def run(self):
28
  """主运行循环,持续获取音频数据"""
@@ -45,7 +57,8 @@ class EchoCancellingAudioCapture(BaseThread):
45
  audio_data = bytes(data_ptr[: size.value])
46
  audio_frame = np.frombuffer(audio_data, dtype=np.int16).astype(np.float32) / np.iinfo(np.int16).max
47
 
48
- self.audio_frames_queue.put((audio_frame, is_voice_active.value))
 
49
 
50
  # 使用完数据后释放内存
51
  audio_recorder.freeAudioData(data_ptr)
 
5
 
6
  import ctypes
7
  import time
8
+ import threading
9
 
10
  import numpy as np
11
 
 
24
  super().__init__(group, target, name, args, kwargs, daemon=daemon)
25
 
26
  self.audio_frames_queue = audio_frames_queue
27
+ self.pause_event = threading.Event()
28
+
29
+ @property
30
+ def is_paused(self):
31
+ return self.pause_event.is_set()
32
+
33
+ def pause(self):
34
+ self.pause_event.set()
35
+
36
+ def resume(self):
37
+ self.pause_event.clear()
38
 
39
  def run(self):
40
  """主运行循环,持续获取音频数据"""
 
57
  audio_data = bytes(data_ptr[: size.value])
58
  audio_frame = np.frombuffer(audio_data, dtype=np.int16).astype(np.float32) / np.iinfo(np.int16).max
59
 
60
+ if not self.is_paused:
61
+ self.audio_frames_queue.put((audio_frame, is_voice_active.value))
62
 
63
  # 使用完数据后释放内存
64
  audio_recorder.freeAudioData(data_ptr)