ускоренная работа
This commit is contained in:
@@ -13,7 +13,7 @@ import sys
|
||||
import json
|
||||
import pyaudio
|
||||
from vosk import Model, KaldiRecognizer
|
||||
from ..core.config import VOSK_MODEL_PATH, SAMPLE_RATE
|
||||
from config import VOSK_MODEL_PATH, SAMPLE_RATE
|
||||
|
||||
|
||||
class LocalRecognizer:
|
||||
|
||||
@@ -20,6 +20,7 @@ from deepgram import (
|
||||
)
|
||||
import deepgram.clients.common.v1.abstract_sync_websocket as sdk_ws
|
||||
import websockets.sync.client
|
||||
from ..core.audio_manager import get_audio_manager
|
||||
|
||||
# --- Патч (исправление) для библиотеки websockets ---
|
||||
# По умолчанию Deepgram SDK использует слишком короткий таймаут подключения.
|
||||
@@ -63,7 +64,7 @@ class SpeechRecognizer:
|
||||
)
|
||||
self.dg_client = DeepgramClient(DEEPGRAM_API_KEY, config)
|
||||
|
||||
self.pa = pyaudio.PyAudio()
|
||||
self.pa = get_audio_manager().get_pyaudio()
|
||||
print("✅ Deepgram клиент готов")
|
||||
|
||||
def _get_stream(self):
|
||||
@@ -135,38 +136,71 @@ class SpeechRecognizer:
|
||||
channels=1,
|
||||
sample_rate=SAMPLE_RATE,
|
||||
interim_results=True,
|
||||
utterance_end_ms=1200, # Пауза 1.2с считается концом фразы
|
||||
utterance_end_ms=1000, # Пауза 1.0с считается концом фразы (было 1.2)
|
||||
vad_events=True,
|
||||
)
|
||||
|
||||
if dg_connection.start(options) is False:
|
||||
print("Failed to start Deepgram connection")
|
||||
return
|
||||
|
||||
# --- Задача отправки аудио ---
|
||||
# --- Задача отправки аудио с буферизацией ---
|
||||
async def send_audio():
|
||||
chunks_sent = 0
|
||||
audio_buffer = [] # Буфер для накопления звука во время подключения
|
||||
|
||||
try:
|
||||
# 1. Сразу начинаем захват звука, не дожидаясь сети!
|
||||
stream.start_stream()
|
||||
print("🎤 Stream started, sending audio...")
|
||||
print("🎤 Stream started (buffering)...")
|
||||
|
||||
# 2. Запускаем подключение к Deepgram в фоне (через ThreadPool, т.к. start() блокирующий)
|
||||
# Но в данном SDK start() возвращает bool, он может быть блокирующим.
|
||||
# Deepgram Python SDK v3+ start() делает handshake.
|
||||
|
||||
connect_future = loop.run_in_executor(
|
||||
None, lambda: dg_connection.start(options)
|
||||
)
|
||||
|
||||
# Пока подключаемся, копим данные
|
||||
while not connect_future.done():
|
||||
if stream.is_active():
|
||||
data = stream.read(4096, exception_on_overflow=False)
|
||||
audio_buffer.append(data)
|
||||
await asyncio.sleep(0.001)
|
||||
|
||||
# Проверяем результат подключения
|
||||
if connect_future.result() is False:
|
||||
print("Failed to start Deepgram connection")
|
||||
return
|
||||
|
||||
print(f"🚀 Connected! Sending buffer ({len(audio_buffer)} chunks)...")
|
||||
|
||||
# 3. Отправляем накопленный буфер
|
||||
for chunk in audio_buffer:
|
||||
dg_connection.send(chunk)
|
||||
chunks_sent += 1
|
||||
|
||||
audio_buffer = None # Освобождаем память
|
||||
|
||||
# 4. Продолжаем стримить в реальном времени
|
||||
while not stop_event.is_set():
|
||||
if stream.is_active():
|
||||
data = stream.read(4096, exception_on_overflow=False)
|
||||
# Отправка данных (синхронная в этой версии SDK)
|
||||
dg_connection.send(data)
|
||||
chunks_sent += 1
|
||||
if chunks_sent % 50 == 0:
|
||||
print(f".", end="", flush=True)
|
||||
# Уступаем время другим задачам
|
||||
await asyncio.sleep(0.005)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Audio send error: {e}")
|
||||
finally:
|
||||
stream.stop_stream()
|
||||
if stream.is_active():
|
||||
stream.stop_stream()
|
||||
print(f"\n🛑 Stream stopped. Chunks sent: {chunks_sent}")
|
||||
|
||||
sender_task = asyncio.create_task(send_audio())
|
||||
|
||||
if False: # dg_connection.start(options) перенесен внутрь send_audio
|
||||
pass
|
||||
|
||||
try:
|
||||
# 1. Ждем начала речи (если задан detection_timeout)
|
||||
if detection_timeout:
|
||||
@@ -254,8 +288,7 @@ class SpeechRecognizer:
|
||||
self.stream.stop_stream()
|
||||
self.stream.close()
|
||||
self.stream = None
|
||||
if self.pa:
|
||||
self.pa.terminate()
|
||||
# self.pa.terminate() - Используем общий менеджер
|
||||
|
||||
|
||||
# Глобальный экземпляр
|
||||
|
||||
@@ -10,6 +10,7 @@ import pvporcupine
|
||||
import pyaudio
|
||||
import struct
|
||||
from ..core.config import PORCUPINE_ACCESS_KEY, PORCUPINE_KEYWORD_PATH
|
||||
from ..core.audio_manager import get_audio_manager
|
||||
|
||||
|
||||
class WakeWordDetector:
|
||||
@@ -28,7 +29,8 @@ class WakeWordDetector:
|
||||
access_key=PORCUPINE_ACCESS_KEY, keyword_paths=[str(PORCUPINE_KEYWORD_PATH)]
|
||||
)
|
||||
|
||||
self.pa = pyaudio.PyAudio()
|
||||
# Используем общий экземпляр PyAudio
|
||||
self.pa = get_audio_manager().get_pyaudio()
|
||||
self._open_stream()
|
||||
print("🎤 Ожидание wake word 'Alexandr'...")
|
||||
|
||||
@@ -138,8 +140,7 @@ class WakeWordDetector:
|
||||
def cleanup(self):
|
||||
"""Освобождение ресурсов при выходе."""
|
||||
self.stop_monitoring()
|
||||
if self.pa:
|
||||
self.pa.terminate()
|
||||
# self.pa.terminate() - Не делаем этого, так как PyAudio общий
|
||||
if self.porcupine:
|
||||
self.porcupine.delete()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user