[结束提示音优化]:完成Codex通知音资产内置,包含音频提取、配置默认值和回归测试

This commit is contained in:
mkbk
2026-06-18 14:10:34 +08:00
parent 80549fb312
commit d83f5a19cb
14 changed files with 102 additions and 8 deletions
+1
View File
@@ -47,6 +47,7 @@ class CliAcceptanceTests(unittest.TestCase):
self.assertEqual(data["realtime_transcript_idle_timeout_ms"], 1500)
self.assertEqual(data["context_mode"], "session_memory")
self.assertTrue(data["end_chime_enabled"])
self.assertEqual(data["end_chime_file"], "assets/sounds/codex-notification.wav")
self.assertEqual(data["end_chime_duration_ms"], 140)
self.assertNotIn("secret-value", str(data))
+16
View File
@@ -272,7 +272,9 @@ class LiveRuntimeTests(unittest.TestCase):
self.assertEqual(len(transport.played_segments), 6)
self.assertEqual(transport.flush_count, 6)
self.assertEqual(transport.played_segments[2].metadata["chime"], "end")
self.assertEqual(transport.played_segments[2].metadata["source"], "file")
self.assertEqual(transport.played_segments[5].metadata["chime"], "end")
self.assertEqual(transport.played_segments[5].metadata["source"], "file")
self.assertEqual(reporter.transcripts, ["第一问", "第二问"])
self.assertIn("应答中:我在", reporter.statuses)
self.assertLess(reporter.statuses.index("唤醒命中"), reporter.statuses.index("应答中:我在"))
@@ -339,6 +341,7 @@ class LiveRuntimeTests(unittest.TestCase):
self.assertEqual(len(stt.calls), 1)
self.assertEqual(transport.flush_count, 3)
self.assertEqual(transport.played_segments[-1].metadata["chime"], "end")
self.assertEqual(transport.played_segments[-1].metadata["source"], "file")
def test_no_ack_text_does_not_drain_before_capture(self) -> None:
runtime, stt, _, transport, reporter = make_runtime(["第一问"], wake_ack_text="")
@@ -351,6 +354,18 @@ class LiveRuntimeTests(unittest.TestCase):
self.assertEqual(len(transport.played_segments), 2)
self.assertEqual(transport.flush_count, 2)
self.assertEqual(transport.played_segments[-1].metadata["chime"], "end")
self.assertEqual(transport.played_segments[-1].metadata["source"], "file")
def test_end_chime_can_be_disabled(self) -> None:
runtime, _, _, transport, _ = make_runtime(["第一问"], wake_ack_text="")
runtime.config = AppConfig(llm_api_key="secret", speech_provider="cloud", wake_ack_text="", end_chime_enabled=False)
runtime.controller.config = runtime.config
summary = runtime.run(max_turns=1)
self.assertEqual(summary.completed_turns, 1)
self.assertEqual(len(transport.played_segments), 1)
self.assertNotIn("chime", transport.played_segments[-1].metadata)
def test_temporary_context_is_sent_to_second_llm_call(self) -> None:
runtime, _, llm, _, _ = make_runtime(["第一问", "第二问"])
@@ -598,6 +613,7 @@ class LiveRuntimeTests(unittest.TestCase):
self.assertEqual(event_types[-1], STANDBY_RESUMED)
self.assertEqual(len(llm.calls), 1)
self.assertEqual(transport.played_segments[-1].metadata["chime"], "end")
self.assertEqual(transport.played_segments[-1].metadata["source"], "file")
def test_completed_reply_returns_to_standby_without_cloud_classifier_delay(self) -> None:
frames = [wake_frame(0, 0)]
+1
View File
@@ -114,6 +114,7 @@ class ModelsConfigTests(unittest.TestCase):
self.assertEqual(config.barge_in_min_speech_ms, 250)
self.assertEqual(config.barge_in_echo_guard_ms, 500)
self.assertTrue(config.end_chime_enabled)
self.assertEqual(str(config.end_chime_file), "assets/sounds/codex-notification.wav")
self.assertEqual(config.end_chime_frequency_hz, 880)
self.assertEqual(config.end_chime_duration_ms, 140)
self.assertTrue(config.llm_stream)
+17 -1
View File
@@ -12,7 +12,7 @@ from owner_voice_pet.models import AudioFrame, ErrorCode, Message, PipelineState
from owner_voice_pet.pipeline import VoicePipeline
from owner_voice_pet.stt import MetadataSttProvider
from owner_voice_pet.transport import MemoryAudioTransport
from owner_voice_pet.tts import CloudTtsProvider, SentenceBuffer, SineTtsProvider, make_prompt_chime, sanitize_tts_text
from owner_voice_pet.tts import CloudTtsProvider, SentenceBuffer, SineTtsProvider, make_end_chime, make_prompt_chime, sanitize_tts_text
from owner_voice_pet.vad import EnergyVadProvider, VadRecorder
from owner_voice_pet.wakeword import KeywordWakeWordProvider
@@ -78,8 +78,24 @@ class PipelineLlmTtsTests(unittest.TestCase):
self.assertEqual(segment.duration_ms, 140)
self.assertEqual(segment.metadata["chime"], "end")
self.assertEqual(segment.metadata["source"], "synthetic")
self.assertGreater(len(segment.pcm), 0)
def test_end_chime_uses_file_when_present(self) -> None:
segment = make_end_chime(file_path="assets/sounds/codex-notification.wav")
self.assertEqual(segment.metadata["source"], "file")
self.assertEqual(segment.metadata["path"], "assets/sounds/codex-notification.wav")
self.assertEqual(segment.metadata["format"], "wav")
self.assertGreater(segment.duration_ms, 0)
def test_end_chime_falls_back_to_synthetic_when_file_missing(self) -> None:
segment = make_end_chime(file_path="/tmp/owner-voice-pet-missing-chime.wav", duration_ms=140)
self.assertEqual(segment.metadata["source"], "synthetic")
self.assertEqual(segment.metadata["chime"], "end")
self.assertEqual(segment.duration_ms, 140)
def test_cloud_tts_posts_speech_request(self) -> None:
class FakeResponse:
def __enter__(self):