[唤醒应答与快速端点]:完成唤醒后我在播报和本地VAD端点优化,包含缓冲清理、配置项和测试覆盖
This commit is contained in:
@@ -80,7 +80,7 @@ def make_runtime(texts: list[str], context: ConversationContext | None = None) -
|
||||
tts = SineTtsProvider()
|
||||
reporter = RecordingReporter()
|
||||
runtime = LiveVoiceRuntime(
|
||||
config=AppConfig(llm_api_key="secret", speech_provider="cloud"),
|
||||
config=AppConfig(llm_api_key="secret", speech_provider="cloud", post_playback_drain_ms=0),
|
||||
transport=transport,
|
||||
wakeword=KeywordWakeWordProvider(),
|
||||
vad_recorder=VadRecorder(EnergyVadProvider(), min_duration_ms=40, end_silence_ms=40),
|
||||
@@ -101,8 +101,9 @@ class LiveRuntimeTests(unittest.TestCase):
|
||||
self.assertEqual(summary.completed_turns, 2)
|
||||
self.assertEqual(len(stt.calls), 2)
|
||||
self.assertEqual(len(llm.calls), 2)
|
||||
self.assertEqual(len(transport.played_segments), 2)
|
||||
self.assertEqual(len(transport.played_segments), 4)
|
||||
self.assertEqual(reporter.transcripts, ["第一问", "第二问"])
|
||||
self.assertIn("应答中:我在", reporter.statuses)
|
||||
self.assertIn("恢复待机:可继续唤醒", reporter.statuses[-1])
|
||||
|
||||
def test_temporary_context_is_sent_to_second_llm_call(self) -> None:
|
||||
|
||||
@@ -72,6 +72,14 @@ class ModelsConfigTests(unittest.TestCase):
|
||||
self.assertEqual(config.wake_provider, "local_kws")
|
||||
self.assertEqual(config.wake_kws_threshold, 0.25)
|
||||
self.assertEqual(config.wake_kws_score, 1.0)
|
||||
self.assertEqual(config.wake_ack_text, "我在")
|
||||
self.assertEqual(config.post_playback_drain_ms, 250)
|
||||
self.assertEqual(config.vad_provider, "local")
|
||||
self.assertEqual(config.vad_threshold, 0.5)
|
||||
self.assertEqual(config.vad_min_duration_ms, 250)
|
||||
self.assertEqual(config.vad_end_silence_ms, 350)
|
||||
self.assertEqual(config.vad_no_speech_timeout_ms, 5000)
|
||||
self.assertEqual(config.vad_max_recording_ms, 12000)
|
||||
self.assertEqual(config.speech_provider, "cloud")
|
||||
self.assertEqual(config.asr_model, "mimo-v2.5-asr")
|
||||
self.assertEqual(config.tts_model, "mimo-v2.5-tts")
|
||||
@@ -90,6 +98,11 @@ class ModelsConfigTests(unittest.TestCase):
|
||||
errors = config.validate_basic()
|
||||
self.assertTrue(any("OWNER_WAKE_PROVIDER" in error.message for error in errors))
|
||||
|
||||
def test_vad_provider_must_be_local_or_energy(self) -> None:
|
||||
config = AppConfig(vad_provider="invalid")
|
||||
errors = config.validate_basic()
|
||||
self.assertTrue(any("OWNER_VAD_PROVIDER" in error.message for error in errors))
|
||||
|
||||
def test_missing_dotenv_uses_non_secret_defaults(self) -> None:
|
||||
config = AppConfig.from_dotenv("/tmp/owner-voice-pet-missing.env")
|
||||
self.assertEqual(config.llm_base_url, "https://token-plan-cn.xiaomimimo.com/v1")
|
||||
|
||||
@@ -42,6 +42,12 @@ class TransportTests(unittest.TestCase):
|
||||
self.assertFalse(result.played)
|
||||
self.assertEqual(result.error.code, ErrorCode.AUDIO_OUTPUT_DEVICE_MISSING)
|
||||
|
||||
def test_memory_transport_flushes_input_frames(self) -> None:
|
||||
transport = MemoryAudioTransport([frame(1, 0), frame(2, 20)])
|
||||
transport.start_input()
|
||||
self.assertEqual(transport.flush_input(), 2)
|
||||
self.assertEqual(transport.read_frames(10), [])
|
||||
|
||||
def test_file_replay_roundtrip(self) -> None:
|
||||
frames = [frame(1, 0, {"wake": True}), frame(2, 20, {"speech": True})]
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
@@ -76,6 +82,14 @@ class TransportTests(unittest.TestCase):
|
||||
self.assertEqual(frames[0].pcm, b"\x01\x00\x02\x00")
|
||||
self.assertEqual(frames[0].sample_rate, 16000)
|
||||
|
||||
def test_sounddevice_transport_flushes_queued_input(self) -> None:
|
||||
fake = FakeSoundDevice()
|
||||
transport = SoundDeviceAudioTransport(sounddevice_module=fake)
|
||||
transport.start_input(sample_rate=16000, channels=1)
|
||||
self.assertEqual(transport.flush_input(), 1)
|
||||
self.assertEqual(transport.read_frames(0), [])
|
||||
transport.stop()
|
||||
|
||||
def test_sounddevice_transport_plays_pcm_to_raw_output_stream(self) -> None:
|
||||
fake = FakeSoundDevice()
|
||||
transport = SoundDeviceAudioTransport(sounddevice_module=fake)
|
||||
|
||||
Reference in New Issue
Block a user