65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
"""Exercise "Voice + tools" over the WebSocket: typed requests, then a spoken one (made with the server's TTS)."""
|
|
|
|
import asyncio
|
|
import json
|
|
|
|
import numpy as np
|
|
import websockets
|
|
|
|
URL = "ws://127.0.0.1:8000/ws"
|
|
PROMPTS = [
|
|
"What's the weather like in Paris right now?",
|
|
"What is 17 times 23, divided by 4?",
|
|
"Please make the screen green.",
|
|
"What time is it in Tokyo?",
|
|
"Tell me a fun fact about octopuses.", # should answer without a tool
|
|
]
|
|
|
|
|
|
async def turn(ws, send):
|
|
await send()
|
|
pcm, events = [], []
|
|
while True:
|
|
m = await ws.recv()
|
|
if isinstance(m, bytes):
|
|
pcm.append(np.frombuffer(m, dtype=np.float32))
|
|
continue
|
|
m = json.loads(m)
|
|
if m["type"] in ("tool_call", "tool_result", "ui"):
|
|
events.append({k: v for k, v in m.items() if k not in ("t_ms",)})
|
|
if m["type"] in ("done", "error"):
|
|
return m, events, np.concatenate(pcm) if pcm else np.zeros(0, np.float32)
|
|
|
|
|
|
async def main():
|
|
async with websockets.connect(URL, max_size=None) as ws:
|
|
await ws.recv()
|
|
await ws.send(json.dumps({"type": "settings", "mode": "tools", "keep_history": False}))
|
|
for p in PROMPTS:
|
|
done, events, pcm = await turn(ws, lambda: ws.send(json.dumps({"type": "text", "text": p})))
|
|
print(f"\n> {p}")
|
|
for e in events:
|
|
print(" ", e)
|
|
s = done.get("stats", {})
|
|
print(f" reply: {done.get('text')!r}\n rounds={s.get('rounds')} audio={s.get('audio_out_s')}s "
|
|
f"first_text={s.get('first_text_ms')}ms gen={s.get('gen_ms')}ms")
|
|
|
|
# spoken request: synthesize it with TTS, then send it as mic audio
|
|
q = "What's the weather in Stockholm?"
|
|
_, _, speech = await turn(ws, lambda: ws.send(json.dumps({"type": "tts", "text": q})))
|
|
|
|
async def speak():
|
|
await ws.send(json.dumps({"type": "start", "rate": 24000}))
|
|
for i in range(0, len(speech), 2048):
|
|
await ws.send(speech[i:i + 2048].tobytes())
|
|
await ws.send(json.dumps({"type": "stop"}))
|
|
|
|
done, events, _ = await turn(ws, speak)
|
|
print(f"\n> (spoken) {q}")
|
|
for e in events:
|
|
print(" ", e)
|
|
print(f" reply: {done.get('text')!r} rounds={done['stats'].get('rounds')}")
|
|
|
|
|
|
asyncio.run(main())
|