[真实链路自测]:完成完整流程自测和ACK缓冲修正,包含真实Provider验收、播放回声清理和回归测试
This commit is contained in:
@@ -134,6 +134,7 @@ def make_runtime(
|
||||
context: ConversationContext | None = None,
|
||||
partial_texts: list[list[str]] | None = None,
|
||||
audio_preprocessor: MarkerAudioPreprocessor | None = None,
|
||||
wake_ack_text: str = "我在",
|
||||
) -> tuple[VoiceAssistantPipeline, QueueSttProvider, MockLlmProvider, MemoryAudioTransport, RecordingReporter]:
|
||||
frames = []
|
||||
for idx, _text in enumerate(texts):
|
||||
@@ -142,14 +143,14 @@ def make_runtime(
|
||||
frames.append(wake_frame(base_id, base_ms))
|
||||
partials = partial_texts[idx] if partial_texts and idx < len(partial_texts) else None
|
||||
frames.extend(segment_frames(base_id + 1, base_ms + 20, partials=partials))
|
||||
transport = MemoryAudioTransport(frames)
|
||||
transport = MemoryAudioTransport(frames, flush_clears_input=False)
|
||||
stt = QueueSttProvider(texts)
|
||||
llm = MockLlmProvider(["这是答复。"])
|
||||
tts = SineTtsProvider()
|
||||
reporter = RecordingReporter()
|
||||
event_bus = PipelineEventBus()
|
||||
runtime = VoiceAssistantPipeline(
|
||||
config=AppConfig(llm_api_key="secret", speech_provider="cloud"),
|
||||
config=AppConfig(llm_api_key="secret", speech_provider="cloud", wake_ack_text=wake_ack_text),
|
||||
transport=transport,
|
||||
wakeword=KeywordWakeWordProvider(),
|
||||
vad_recorder=VadRecorder(EnergyVadProvider(), min_duration_ms=40, end_silence_ms=40),
|
||||
@@ -177,6 +178,7 @@ class LiveRuntimeTests(unittest.TestCase):
|
||||
self.assertEqual(len(stt.calls), 2)
|
||||
self.assertEqual(len(llm.calls), 2)
|
||||
self.assertEqual(len(transport.played_segments), 4)
|
||||
self.assertEqual(transport.flush_count, 4)
|
||||
self.assertEqual(reporter.transcripts, ["第一问", "第二问"])
|
||||
self.assertIn("应答中:我在", reporter.statuses)
|
||||
self.assertLess(reporter.statuses.index("唤醒命中"), reporter.statuses.index("应答中:我在"))
|
||||
@@ -201,6 +203,28 @@ class LiveRuntimeTests(unittest.TestCase):
|
||||
positions = [event_types.index(item) for item in expected_order]
|
||||
self.assertEqual(positions, sorted(positions))
|
||||
|
||||
def test_zero_post_playback_drain_flushes_without_dropping_prefilled_question(self) -> None:
|
||||
runtime, stt, _, transport, reporter = make_runtime(["第一问"])
|
||||
self.assertEqual(runtime.config.post_playback_drain_ms, 0)
|
||||
|
||||
summary = runtime.run(max_turns=1)
|
||||
|
||||
self.assertEqual(summary.completed_turns, 1)
|
||||
self.assertEqual(reporter.transcripts, ["第一问"])
|
||||
self.assertEqual(len(stt.calls), 1)
|
||||
self.assertEqual(transport.flush_count, 2)
|
||||
|
||||
def test_no_ack_text_does_not_drain_before_capture(self) -> None:
|
||||
runtime, stt, _, transport, reporter = make_runtime(["第一问"], wake_ack_text="")
|
||||
|
||||
summary = runtime.run(max_turns=1)
|
||||
|
||||
self.assertEqual(summary.completed_turns, 1)
|
||||
self.assertEqual(reporter.transcripts, ["第一问"])
|
||||
self.assertEqual(len(stt.calls), 1)
|
||||
self.assertEqual(len(transport.played_segments), 1)
|
||||
self.assertEqual(transport.flush_count, 1)
|
||||
|
||||
def test_temporary_context_is_sent_to_second_llm_call(self) -> None:
|
||||
runtime, _, llm, _, _ = make_runtime(["第一问", "第二问"])
|
||||
runtime.run(max_turns=2)
|
||||
|
||||
@@ -46,8 +46,16 @@ class TransportTests(unittest.TestCase):
|
||||
transport = MemoryAudioTransport([frame(1, 0), frame(2, 20)])
|
||||
transport.start_input()
|
||||
self.assertEqual(transport.flush_input(), 2)
|
||||
self.assertEqual(transport.flush_count, 1)
|
||||
self.assertEqual(transport.read_frames(10), [])
|
||||
|
||||
def test_memory_transport_can_preserve_prefilled_frames_on_flush(self) -> None:
|
||||
transport = MemoryAudioTransport([frame(1, 0), frame(2, 20)], flush_clears_input=False)
|
||||
transport.start_input()
|
||||
self.assertEqual(transport.flush_input(), 0)
|
||||
self.assertEqual(transport.flush_count, 1)
|
||||
self.assertEqual([f.frame_id for f in transport.read_frames(10)], [1])
|
||||
|
||||
def test_file_replay_roundtrip(self) -> None:
|
||||
frames = [frame(1, 0, {"wake": True}), frame(2, 20, {"speech": True})]
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
|
||||
Reference in New Issue
Block a user