[本地语音降噪]:完成本地语音链路和噪音过滤,包含降噪模型、本地ASR和实时字幕稳定策略

This commit is contained in:
mkbk
2026-06-17 22:55:33 +08:00
parent a77a172412
commit 8c75fc5baf
22 changed files with 803 additions and 64 deletions
+41 -1
View File
@@ -1,7 +1,9 @@
from __future__ import annotations
import json
import tempfile
import unittest
from pathlib import Path
from owner_voice_pet.config import AppConfig
from owner_voice_pet.models import (
@@ -12,6 +14,12 @@ from owner_voice_pet.models import (
PipelineState,
ProviderError,
)
from owner_voice_pet.speech_models import (
DEFAULT_DENOISER_PATH,
default_manifest,
denoiser_model_path,
stt_model_paths,
)
class ModelsConfigTests(unittest.TestCase):
@@ -77,6 +85,9 @@ class ModelsConfigTests(unittest.TestCase):
self.assertEqual(config.post_playback_drain_ms, 0)
self.assertEqual(config.pipeline_mode, "live_turn_based")
self.assertEqual(config.endpoint_mode, "primary_speaker")
self.assertTrue(config.noise_filter_enabled)
self.assertEqual(config.noise_filter_provider, "sherpa_onnx_gtcrn")
self.assertFalse(config.wake_denoise_enabled)
self.assertEqual(config.speaker_profile_ms, 600)
self.assertEqual(config.speaker_profile_min_ms, 120)
self.assertEqual(config.speaker_absent_ms, 300)
@@ -88,7 +99,7 @@ class ModelsConfigTests(unittest.TestCase):
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.speech_provider, "local")
self.assertEqual(config.asr_model, "mimo-v2.5-asr")
self.assertEqual(config.tts_model, "mimo-v2.5-tts")
self.assertEqual(config.tts_voice, "mimo_default")
@@ -117,6 +128,11 @@ class ModelsConfigTests(unittest.TestCase):
errors = config.validate_basic()
self.assertTrue(any("OWNER_ENDPOINT_MODE" in error.message for error in errors))
def test_noise_filter_provider_must_be_gtcrn(self) -> None:
config = AppConfig(noise_filter_provider="invalid")
errors = config.validate_basic()
self.assertTrue(any("OWNER_NOISE_FILTER_PROVIDER" in error.message for error in errors))
def test_speaker_similarity_threshold_range_is_validated(self) -> None:
config = AppConfig(speaker_similarity_threshold=1.5)
errors = config.validate_basic()
@@ -153,6 +169,30 @@ class ModelsConfigTests(unittest.TestCase):
message = Message(role="user", content="你好", created_at=1.0)
self.assertEqual(message.role, "user")
def test_default_manifest_uses_ctc_stt_and_denoiser(self) -> None:
manifest = default_manifest()
stt = manifest["providers"]["stt"]
denoiser = manifest["providers"]["denoiser"]
self.assertEqual(stt["type"], "sherpa-onnx-streaming-zipformer2-ctc")
self.assertTrue(stt["model"].endswith("model.int8.onnx"))
self.assertEqual(denoiser["path"], DEFAULT_DENOISER_PATH)
self.assertIn(DEFAULT_DENOISER_PATH, manifest["required_files"])
def test_model_path_helpers_support_ctc_manifest_and_denoiser(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
manifest_path = root / "manifest.json"
manifest_path.write_text(
json.dumps(default_manifest(), ensure_ascii=False),
encoding="utf-8",
)
paths = stt_model_paths(root)
self.assertEqual(paths["type"], "sherpa-onnx-streaming-zipformer2-ctc")
self.assertTrue(str(paths["model"]).endswith("model.int8.onnx"))
self.assertTrue(str(denoiser_model_path(root)).endswith(DEFAULT_DENOISER_PATH))
if __name__ == "__main__":
unittest.main()