datbkpro commited on
Commit
835fc53
·
verified ·
1 Parent(s): d102321

Update services/streaming_voice_service.py

Browse files
Files changed (1) hide show
  1. services/streaming_voice_service.py +56 -34
services/streaming_voice_service.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
  import io
3
  import numpy as np
4
  import soundfile as sf
@@ -13,7 +12,6 @@ import zipfile
13
  from vosk import Model, KaldiRecognizer
14
  from groq import Groq
15
  from typing import Optional, Dict, Any, Callable
16
- from config.settings import settings
17
 
18
  class VoskStreamingASR:
19
  def __init__(self, model_path: str = None):
@@ -193,30 +191,15 @@ class StreamingVoiceService:
193
  self.is_listening = False
194
  self.current_callback = None
195
 
196
- # Latency tracking - FIXED
 
 
 
 
 
197
  self.latency_metrics = {
198
  'asr': [], 'llm': [], 'tts': [], 'total': []
199
  }
200
- self.last_processing_time = 0
201
-
202
- def start_listening(self, speech_callback: Callable) -> bool:
203
- """Bắt đầu lắng nghe"""
204
- if self.is_listening:
205
- return False
206
-
207
- self.current_callback = speech_callback
208
-
209
- if self.vosk_asr.model is None:
210
- print("❌ VOSK model không khả dụng")
211
- return False
212
-
213
- if not self.vosk_asr.start_stream():
214
- print("❌ Không thể khởi động VOSK stream")
215
- return False
216
-
217
- self.is_listening = True
218
- print("🎙️ Đã bắt đầu lắng nghe với VOSK")
219
- return True
220
 
221
  def process_streaming_audio(self, audio_data: tuple) -> Dict[str, Any]:
222
  """Xử lý audio streaming - FIXED LATENCY TRACKING"""
@@ -239,7 +222,7 @@ class StreamingVoiceService:
239
  result = self.vosk_asr.process_audio_chunk(audio_array, sample_rate)
240
  asr_time = time.time() - asr_start_time
241
 
242
- # Cập nhật latency metrics
243
  if 'processing_time' in result and result['processing_time'] > 0:
244
  self.latency_metrics['asr'].append(result['processing_time'])
245
  else:
@@ -252,6 +235,7 @@ class StreamingVoiceService:
252
 
253
  # LUÔN trả về text để hiển thị real-time
254
  if result['partial']:
 
255
  return {
256
  'transcription': result['partial'],
257
  'response': "",
@@ -260,6 +244,8 @@ class StreamingVoiceService:
260
  }
261
  elif result['is_final'] and result['text']:
262
  # Có kết quả cuối - tạo phản hồi AI với latency tracking
 
 
263
  print(f"📝 Final transcription: '{result['text']}'")
264
 
265
  llm_start_time = time.time()
@@ -294,9 +280,16 @@ class StreamingVoiceService:
294
  def _generate_ai_response(self, transcription: str) -> str:
295
  """Tạo phản hồi AI"""
296
  try:
 
 
 
 
 
 
 
297
  messages = [
298
  {"role": "system", "content": "Bạn là trợ lý AI. Trả lời ngắn gọn bằng tiếng Việt."},
299
- {"role": "user", "content": transcription}
300
  ]
301
 
302
  response = self.client.chat.completions.create(
@@ -306,7 +299,12 @@ class StreamingVoiceService:
306
  temperature=0.7
307
  )
308
 
309
- return response.choices[0].message.content.strip()
 
 
 
 
 
310
 
311
  except Exception as e:
312
  print(f"❌ Lỗi AI: {e}")
@@ -340,6 +338,23 @@ class StreamingVoiceService:
340
  'status': 'error'
341
  }
342
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  def stop_listening(self):
344
  """Dừng lắng nghe"""
345
  self.is_listening = False
@@ -349,13 +364,20 @@ class StreamingVoiceService:
349
 
350
  def clear_conversation(self):
351
  """Xóa lịch sử hội thoại"""
 
 
 
352
  print("🗑️ Đã xóa lịch sử hội thoại")
353
 
354
  def get_conversation_state(self) -> dict:
355
  """Lấy trạng thái hội thoại"""
356
  return {
357
  'is_listening': self.is_listening,
358
- 'vosk_active': self.vosk_asr.is_streaming if self.vosk_asr else False
 
 
 
 
359
  }
360
 
361
  def get_latency_stats(self) -> dict:
@@ -363,18 +385,18 @@ class StreamingVoiceService:
363
  stats = {}
364
  for component, latencies in self.latency_metrics.items():
365
  if latencies and len(latencies) > 0:
366
- # Lấy 10 giá trị gần nhất
367
- recent_latencies = latencies[-10:] if len(latencies) > 10 else latencies
368
  stats[component] = {
369
- 'avg': sum(recent_latencies) / len(recent_latencies),
370
- 'min': min(recent_latencies),
371
- 'max': max(recent_latencies),
372
  'count': len(recent_latencies),
373
- 'recent_values': [f"{x:.3f}s" for x in recent_latencies]
374
  }
375
  else:
376
  stats[component] = {
377
- 'avg': 0, 'min': 0, 'max': 0, 'count': 0, 'recent_values': []
378
  }
379
 
380
  print(f"📊 Latency stats: {stats}")
 
 
1
  import io
2
  import numpy as np
3
  import soundfile as sf
 
12
  from vosk import Model, KaldiRecognizer
13
  from groq import Groq
14
  from typing import Optional, Dict, Any, Callable
 
15
 
16
  class VoskStreamingASR:
17
  def __init__(self, model_path: str = None):
 
191
  self.is_listening = False
192
  self.current_callback = None
193
 
194
+ # Conversation context
195
+ self.conversation_history = []
196
+ self.current_transcription = ""
197
+ self.partial_transcription = ""
198
+
199
+ # Latency tracking - FIXED: Đơn giản hoá
200
  self.latency_metrics = {
201
  'asr': [], 'llm': [], 'tts': [], 'total': []
202
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
  def process_streaming_audio(self, audio_data: tuple) -> Dict[str, Any]:
205
  """Xử lý audio streaming - FIXED LATENCY TRACKING"""
 
222
  result = self.vosk_asr.process_audio_chunk(audio_array, sample_rate)
223
  asr_time = time.time() - asr_start_time
224
 
225
+ # Cập nhật latency metrics - FIXED
226
  if 'processing_time' in result and result['processing_time'] > 0:
227
  self.latency_metrics['asr'].append(result['processing_time'])
228
  else:
 
235
 
236
  # LUÔN trả về text để hiển thị real-time
237
  if result['partial']:
238
+ self.partial_transcription = result['partial']
239
  return {
240
  'transcription': result['partial'],
241
  'response': "",
 
244
  }
245
  elif result['is_final'] and result['text']:
246
  # Có kết quả cuối - tạo phản hồi AI với latency tracking
247
+ self.current_transcription = result['text']
248
+ self.partial_transcription = ""
249
  print(f"📝 Final transcription: '{result['text']}'")
250
 
251
  llm_start_time = time.time()
 
280
  def _generate_ai_response(self, transcription: str) -> str:
281
  """Tạo phản hồi AI"""
282
  try:
283
+ # Thêm vào lịch sử hội thoại
284
+ self.conversation_history.append({"role": "user", "content": transcription})
285
+
286
+ # Giới hạn lịch sử hội thoại
287
+ if len(self.conversation_history) > 10:
288
+ self.conversation_history = self.conversation_history[-10:]
289
+
290
  messages = [
291
  {"role": "system", "content": "Bạn là trợ lý AI. Trả lời ngắn gọn bằng tiếng Việt."},
292
+ *self.conversation_history
293
  ]
294
 
295
  response = self.client.chat.completions.create(
 
299
  temperature=0.7
300
  )
301
 
302
+ ai_response = response.choices[0].message.content.strip()
303
+
304
+ # Thêm vào lịch sử
305
+ self.conversation_history.append({"role": "assistant", "content": ai_response})
306
+
307
+ return ai_response
308
 
309
  except Exception as e:
310
  print(f"❌ Lỗi AI: {e}")
 
338
  'status': 'error'
339
  }
340
 
341
+ def start_listening(self, speech_callback: Callable) -> bool:
342
+ """Bắt đầu lắng nghe - ĐƠN GIẢN HOÁ"""
343
+ if self.is_listening:
344
+ return False
345
+
346
+ self.current_callback = speech_callback
347
+
348
+ if self.vosk_asr.model is None:
349
+ return False
350
+
351
+ if not self.vosk_asr.start_stream():
352
+ return False
353
+
354
+ self.is_listening = True
355
+ print("🎙️ Đã bắt đầu lắng nghe với VOSK")
356
+ return True
357
+
358
  def stop_listening(self):
359
  """Dừng lắng nghe"""
360
  self.is_listening = False
 
364
 
365
  def clear_conversation(self):
366
  """Xóa lịch sử hội thoại"""
367
+ self.conversation_history = []
368
+ self.current_transcription = ""
369
+ self.partial_transcription = ""
370
  print("🗑️ Đã xóa lịch sử hội thoại")
371
 
372
  def get_conversation_state(self) -> dict:
373
  """Lấy trạng thái hội thoại"""
374
  return {
375
  'is_listening': self.is_listening,
376
+ 'history_length': len(self.conversation_history),
377
+ 'current_transcription': self.current_transcription,
378
+ 'partial_transcription': self.partial_transcription,
379
+ 'vosk_active': self.vosk_asr.is_streaming if self.vosk_asr else False,
380
+ 'last_update': time.strftime("%H:%M:%S")
381
  }
382
 
383
  def get_latency_stats(self) -> dict:
 
385
  stats = {}
386
  for component, latencies in self.latency_metrics.items():
387
  if latencies and len(latencies) > 0:
388
+ # Lấy 5 giá trị gần nhất
389
+ recent_latencies = latencies[-5:] if len(latencies) > 5 else latencies
390
  stats[component] = {
391
+ 'avg': f"{sum(recent_latencies) / len(recent_latencies):.3f}s",
392
+ 'min': f"{min(recent_latencies):.3f}s",
393
+ 'max': f"{max(recent_latencies):.3f}s",
394
  'count': len(recent_latencies),
395
+ 'recent': [f"{x:.3f}s" for x in recent_latencies]
396
  }
397
  else:
398
  stats[component] = {
399
+ 'avg': "0.000s", 'min': "0.000s", 'max': "0.000s", 'count': 0, 'recent': []
400
  }
401
 
402
  print(f"📊 Latency stats: {stats}")