[唤醒应答加速]:完成ACK音频预热缓存,包含唤醒后复用播放和回归测试
This commit is contained in:
@@ -122,6 +122,8 @@ class TurnController:
|
||||
self.sentence_buffer = sentence_buffer or SentenceBuffer()
|
||||
self._states: list[PipelineState] = []
|
||||
self._pending_capture_frames: list[AudioFrame] = []
|
||||
self._cached_ack_text: str | None = None
|
||||
self._cached_ack_segment: AudioSegment | None = None
|
||||
|
||||
def run_turn(self, turn_id: int) -> TurnResult:
|
||||
self._states = []
|
||||
@@ -139,6 +141,15 @@ class TurnController:
|
||||
except ProviderError as exc:
|
||||
return self._recover(exc, turn_id)
|
||||
|
||||
def prepare_ack_audio(self) -> None:
|
||||
text = self.config.wake_ack_text.strip()
|
||||
if not text:
|
||||
self._cached_ack_text = None
|
||||
self._cached_ack_segment = None
|
||||
return
|
||||
self._cached_ack_text = text
|
||||
self._cached_ack_segment = self.ack_tts.synthesize(text)
|
||||
|
||||
def _wait_for_wake_and_user_text(self, turn_id: int) -> str | ProviderError:
|
||||
wake_error = self._wait_for_local_wake()
|
||||
if wake_error is not None:
|
||||
@@ -300,7 +311,7 @@ class TurnController:
|
||||
return None
|
||||
try:
|
||||
self._event(ACK_STARTED, PipelineState.SPEAKING, f"应答中:{text}", turn_id=turn_id)
|
||||
segment = self.ack_tts.synthesize(text)
|
||||
segment = self._ack_segment(text)
|
||||
playback = self.transport.play_pcm(segment)
|
||||
if playback.error:
|
||||
return playback.error
|
||||
@@ -309,6 +320,12 @@ class TurnController:
|
||||
except ProviderError as exc:
|
||||
return exc
|
||||
|
||||
def _ack_segment(self, text: str) -> AudioSegment:
|
||||
if self._cached_ack_text != text or self._cached_ack_segment is None:
|
||||
self._cached_ack_text = text
|
||||
self._cached_ack_segment = self.ack_tts.synthesize(text)
|
||||
return self._cached_ack_segment
|
||||
|
||||
def _reply_to_user(self, user_text: str, turn_id: int) -> TurnResult:
|
||||
completed_turns = 0
|
||||
current_user_text = user_text
|
||||
@@ -664,6 +681,7 @@ class VoiceAssistantPipeline:
|
||||
self.tts.load()
|
||||
if self.ack_tts is not self.tts:
|
||||
self.ack_tts.load()
|
||||
self.controller.prepare_ack_audio()
|
||||
|
||||
def run(self, *, once: bool = False, max_turns: int | None = None) -> RuntimeSummary:
|
||||
completed = 0
|
||||
|
||||
@@ -115,6 +115,8 @@ class LiveVoiceRuntime:
|
||||
self.event_bus.subscribe(self._report_event)
|
||||
self.sentence_buffer = sentence_buffer or SentenceBuffer()
|
||||
self._states: list[PipelineState] = []
|
||||
self._cached_ack_text: str | None = None
|
||||
self._cached_ack_segment: AudioSegment | None = None
|
||||
|
||||
def load(self) -> None:
|
||||
self.wakeword.load()
|
||||
@@ -123,6 +125,16 @@ class LiveVoiceRuntime:
|
||||
self.tts.load()
|
||||
if self.ack_tts is not self.tts:
|
||||
self.ack_tts.load()
|
||||
self.prepare_ack_audio()
|
||||
|
||||
def prepare_ack_audio(self) -> None:
|
||||
text = self.config.wake_ack_text.strip()
|
||||
if not text:
|
||||
self._cached_ack_text = None
|
||||
self._cached_ack_segment = None
|
||||
return
|
||||
self._cached_ack_text = text
|
||||
self._cached_ack_segment = self.ack_tts.synthesize(text)
|
||||
|
||||
def run(self, *, once: bool = False, max_turns: int | None = None) -> RuntimeSummary:
|
||||
completed = 0
|
||||
@@ -243,7 +255,7 @@ class LiveVoiceRuntime:
|
||||
return None
|
||||
try:
|
||||
self._event(ACK_STARTED, PipelineState.SPEAKING, f"应答中:{text}", turn_id=turn_id)
|
||||
segment = self.ack_tts.synthesize(text)
|
||||
segment = self._ack_segment(text)
|
||||
playback = self.transport.play_pcm(segment)
|
||||
if playback.error:
|
||||
return playback.error
|
||||
@@ -252,6 +264,12 @@ class LiveVoiceRuntime:
|
||||
except ProviderError as exc:
|
||||
return exc
|
||||
|
||||
def _ack_segment(self, text: str) -> AudioSegment:
|
||||
if self._cached_ack_text != text or self._cached_ack_segment is None:
|
||||
self._cached_ack_text = text
|
||||
self._cached_ack_segment = self.ack_tts.synthesize(text)
|
||||
return self._cached_ack_segment
|
||||
|
||||
def _drain_input_after_playback(self) -> None:
|
||||
self.transport.flush_input()
|
||||
if self.config.post_playback_drain_ms <= 0:
|
||||
|
||||
Reference in New Issue
Block a user