[唤醒灵敏度与端点恢复]:完成唤醒提示顺序和Hybrid VAD优化,包含阈值默认值、缓冲时序和测试覆盖
This commit is contained in:
@@ -104,6 +104,9 @@ class LiveRuntimeTests(unittest.TestCase):
|
||||
self.assertEqual(len(transport.played_segments), 4)
|
||||
self.assertEqual(reporter.transcripts, ["第一问", "第二问"])
|
||||
self.assertIn("应答中:我在", reporter.statuses)
|
||||
self.assertLess(reporter.statuses.index("唤醒命中"), reporter.statuses.index("应答中:我在"))
|
||||
self.assertLess(reporter.statuses.index("应答中:我在"), reporter.statuses.index("请说出问题"))
|
||||
self.assertLess(reporter.statuses.index("请说出问题"), reporter.statuses.index("录音中:正在听取问题"))
|
||||
self.assertIn("恢复待机:可继续唤醒", reporter.statuses[-1])
|
||||
|
||||
def test_temporary_context_is_sent_to_second_llm_call(self) -> None:
|
||||
|
||||
@@ -70,11 +70,11 @@ class ModelsConfigTests(unittest.TestCase):
|
||||
self.assertEqual(config.llm_api_key, "secret-value")
|
||||
self.assertEqual(config.llm_model, "test-model")
|
||||
self.assertEqual(config.wake_provider, "local_kws")
|
||||
self.assertEqual(config.wake_kws_threshold, 0.25)
|
||||
self.assertEqual(config.wake_kws_threshold, 0.15)
|
||||
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.post_playback_drain_ms, 50)
|
||||
self.assertEqual(config.vad_provider, "hybrid")
|
||||
self.assertEqual(config.vad_threshold, 0.5)
|
||||
self.assertEqual(config.vad_min_duration_ms, 250)
|
||||
self.assertEqual(config.vad_end_silence_ms, 350)
|
||||
@@ -98,7 +98,7 @@ 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:
|
||||
def test_vad_provider_must_be_hybrid_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))
|
||||
|
||||
@@ -7,7 +7,7 @@ import unittest
|
||||
from owner_voice_pet.models import AudioFrame, AudioSegment, ErrorCode, ProviderError
|
||||
from owner_voice_pet.config import AppConfig
|
||||
from owner_voice_pet.stt import CloudAsrSttProvider, MetadataSttProvider, SherpaOnnxSttProvider, is_valid_transcript_text
|
||||
from owner_voice_pet.vad import EnergyVadProvider, VadRecorder
|
||||
from owner_voice_pet.vad import EnergyVadProvider, HybridVadProvider, VadRecorder
|
||||
from owner_voice_pet.wakeword import (
|
||||
KeywordWakeWordProvider,
|
||||
MissingWakeWordModelProvider,
|
||||
@@ -87,6 +87,30 @@ class WakeVadSttTests(unittest.TestCase):
|
||||
self.assertIsInstance(result, ProviderError)
|
||||
self.assertEqual(result.code, ErrorCode.VAD_TIMEOUT_NO_SPEECH)
|
||||
|
||||
def test_hybrid_vad_accepts_energy_fallback_speech(self) -> None:
|
||||
class SilentVadProvider:
|
||||
def __init__(self) -> None:
|
||||
self.loaded = False
|
||||
|
||||
def load(self) -> None:
|
||||
self.loaded = True
|
||||
|
||||
def analyze(self, frame: AudioFrame):
|
||||
return type(
|
||||
"Result",
|
||||
(),
|
||||
{"is_speech": False, "confidence": 0.1, "speech_ms": 0, "silence_ms": 20},
|
||||
)()
|
||||
|
||||
def reset(self) -> None:
|
||||
return None
|
||||
|
||||
provider = HybridVadProvider(SilentVadProvider(), EnergyVadProvider())
|
||||
provider.load()
|
||||
result = provider.analyze(make_frame(1, 0, speech=True))
|
||||
self.assertTrue(result.is_speech)
|
||||
self.assertEqual(result.speech_ms, 20)
|
||||
|
||||
def test_metadata_stt_transcribes_fixture_text(self) -> None:
|
||||
provider = MetadataSttProvider()
|
||||
provider.load()
|
||||
|
||||
Reference in New Issue
Block a user