feat: integrate OCI agent streaming and web voice client
This commit is contained in:
@@ -1698,3 +1698,105 @@ def test_websocket_registration_failure_awaits_task_before_abort():
|
||||
assert len(tasks) == 1
|
||||
assert tasks[0].done()
|
||||
assert abort_checked
|
||||
|
||||
|
||||
def test_websocket_streaming_agent_and_tts():
|
||||
"""
|
||||
Verify streaming Agent text and TTS audio through WebSocket.
|
||||
|
||||
The first audio segment must be delivered before the
|
||||
Agent's complete response.
|
||||
"""
|
||||
created_stt.clear()
|
||||
|
||||
class StreamingTestAgent:
|
||||
async def stream(self, session_id, turn_id, text):
|
||||
yield "Olá, como posso ajudar?"
|
||||
yield " Estou à disposição."
|
||||
|
||||
class StreamingTestTTS:
|
||||
async def synthesize(self, text):
|
||||
yield text.encode("utf-8")
|
||||
|
||||
with patch.object(
|
||||
main,
|
||||
"create_agent_adapter",
|
||||
return_value=StreamingTestAgent(),
|
||||
):
|
||||
with patch.object(
|
||||
main,
|
||||
"create_tts_adapter",
|
||||
return_value=StreamingTestTTS(),
|
||||
):
|
||||
with client.websocket_connect("/ws/audio") as websocket:
|
||||
websocket.send_json(
|
||||
{
|
||||
"type": "session.start",
|
||||
"audio": {
|
||||
"encoding": AUDIO_ENCODING,
|
||||
"sample_rate": AUDIO_SAMPLE_RATE,
|
||||
"channels": AUDIO_CHANNELS,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
session_ready = websocket.receive_json()
|
||||
assert session_ready["type"] == "session.ready"
|
||||
|
||||
websocket.send_json({"type": "audio.start"})
|
||||
|
||||
turn_started = websocket.receive_json()
|
||||
assert turn_started["type"] == "turn.started"
|
||||
|
||||
turn_id = turn_started["turn_id"]
|
||||
stt = created_stt[0]
|
||||
|
||||
stt.emit_final_now("Olá")
|
||||
|
||||
received_text = []
|
||||
received_audio = []
|
||||
received_complete_response = False
|
||||
|
||||
# The streaming path emits two deltas and
|
||||
# two TTS audio segments.
|
||||
for _ in range(20):
|
||||
message = websocket.receive()
|
||||
|
||||
if message.get("bytes") is not None:
|
||||
received_audio.append(message["bytes"])
|
||||
else:
|
||||
import json
|
||||
|
||||
event = json.loads(message["text"])
|
||||
|
||||
if event["type"] == "agent.delta":
|
||||
received_text.append(event["text"])
|
||||
|
||||
elif event["type"] == "agent.response":
|
||||
received_complete_response = True
|
||||
|
||||
elif event["type"] == "error":
|
||||
raise AssertionError(
|
||||
f"Gateway returned error: {event}"
|
||||
)
|
||||
|
||||
if received_complete_response and len(received_audio) >= 2:
|
||||
break
|
||||
|
||||
assert "".join(received_text) == (
|
||||
"Olá, como posso ajudar?"
|
||||
" Estou à disposição."
|
||||
)
|
||||
|
||||
assert received_audio
|
||||
assert received_complete_response
|
||||
|
||||
websocket.send_json(
|
||||
{
|
||||
"type": "audio.stop",
|
||||
"turn_id": turn_id,
|
||||
}
|
||||
)
|
||||
|
||||
turn_ended = websocket.receive_json()
|
||||
assert turn_ended["type"] == "turn.ended"
|
||||
|
||||
Reference in New Issue
Block a user