import websocket
import json
import base64
import threading
import pyaudio
WS_URL = 'wss://api.withperf.pro/v1/voice/conversation'
API_KEY = 'YOUR_API_KEY'
AGENT_ID = 'YOUR_AGENT_ID'
RATE = 16000
CHUNK = 2048
ready = False
# Audio setup
pa = pyaudio.PyAudio()
mic_stream = pa.open(format=pyaudio.paInt16, channels=1, rate=RATE,
input=True, frames_per_buffer=CHUNK)
spk_stream = pa.open(format=pyaudio.paInt16, channels=1, rate=RATE,
output=True, frames_per_buffer=CHUNK)
def on_message(ws, message):
global ready
data = json.loads(message)
msg_type = data.get('type', '')
if msg_type == 'conversation_initiation_metadata':
ready = True
conv_id = data.get('conversation_initiation_metadata_event', {}).get('conversation_id')
print(f'Session started: {conv_id}')
elif msg_type == 'audio':
audio_b64 = data.get('audio_event', {}).get('audio_base_64', '')
if audio_b64:
spk_stream.write(base64.b64decode(audio_b64))
elif msg_type == 'agent_response':
text = data.get('agent_response_event', {}).get('agent_response', '')
if text:
print(f'Agent: {text}')
elif msg_type == 'user_transcript':
text = data.get('user_transcription_event', {}).get('user_transcript', '')
if text:
print(f'You: {text}')
elif msg_type == 'ping':
event_id = data.get('ping_event', {}).get('event_id')
ws.send(json.dumps({'type': 'pong', 'event_id': event_id}))
def send_audio(ws):
"""Stream microphone audio as base64 PCM16 chunks."""
while ws.sock and ws.sock.connected:
if not ready:
continue
pcm_data = mic_stream.read(CHUNK, exception_on_overflow=False)
b64 = base64.b64encode(pcm_data).decode('utf-8')
ws.send(json.dumps({'user_audio_chunk': b64}))
def on_open(ws):
threading.Thread(target=send_audio, args=(ws,), daemon=True).start()
print('Connected — speak now')
def on_close(ws, code, reason):
print(f'Disconnected (code={code}, reason={reason})')
def on_error(ws, error):
print(f'Error: {error}')
url = f'{WS_URL}?api_key={API_KEY}&agent_id={AGENT_ID}'
ws = websocket.WebSocketApp(url,
on_message=on_message,
on_open=on_open,
on_close=on_close,
on_error=on_error)
ws.run_forever()