85 lines
3.3 KiB
Python
85 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Logging WebSocket proxy for Qwen3-TTS streaming calls."""
|
|
import argparse
|
|
import asyncio
|
|
import datetime as dt
|
|
import json
|
|
import websockets
|
|
|
|
|
|
def now():
|
|
return dt.datetime.now().isoformat(timespec="seconds")
|
|
|
|
|
|
def shorten(value, limit=500):
|
|
text = value if isinstance(value, str) else repr(value)
|
|
return text if len(text) <= limit else text[:limit] + "..."
|
|
|
|
|
|
async def proxy(client_ws, upstream_url):
|
|
conn_id = f"ws-{id(client_ws):x}"
|
|
print(f"[{now()}] {conn_id} open -> {upstream_url}", flush=True)
|
|
async with websockets.connect(upstream_url, max_size=None) as upstream_ws:
|
|
async def client_to_upstream():
|
|
async for msg in client_ws:
|
|
if isinstance(msg, str):
|
|
try:
|
|
data = json.loads(msg)
|
|
typ = data.get("type")
|
|
if typ == "session.config":
|
|
log_data = dict(data)
|
|
if "speaker_embedding" in log_data:
|
|
emb = log_data["speaker_embedding"] or []
|
|
log_data["speaker_embedding"] = f"<{len(emb)} floats>"
|
|
print(f"[{now()}] {conn_id} C->S config {json.dumps(log_data, ensure_ascii=False, sort_keys=True)}", flush=True)
|
|
elif typ == "input.text":
|
|
print(f"[{now()}] {conn_id} C->S text {data.get('text')!r}", flush=True)
|
|
else:
|
|
print(f"[{now()}] {conn_id} C->S {shorten(msg)}", flush=True)
|
|
except Exception:
|
|
print(f"[{now()}] {conn_id} C->S {shorten(msg)}", flush=True)
|
|
else:
|
|
print(f"[{now()}] {conn_id} C->S binary {len(msg)} bytes", flush=True)
|
|
await upstream_ws.send(msg)
|
|
|
|
async def upstream_to_client():
|
|
async for msg in upstream_ws:
|
|
if isinstance(msg, str):
|
|
try:
|
|
data = json.loads(msg)
|
|
print(f"[{now()}] {conn_id} S->C {data}", flush=True)
|
|
except Exception:
|
|
print(f"[{now()}] {conn_id} S->C {shorten(msg)}", flush=True)
|
|
else:
|
|
print(f"[{now()}] {conn_id} S->C binary {len(msg)} bytes", flush=True)
|
|
await client_ws.send(msg)
|
|
|
|
await asyncio.gather(client_to_upstream(), upstream_to_client())
|
|
|
|
|
|
async def handler(client_ws):
|
|
try:
|
|
await proxy(client_ws, handler.upstream_url)
|
|
except Exception as exc:
|
|
print(f"[{now()}] proxy error: {exc}", flush=True)
|
|
try:
|
|
await client_ws.close()
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
async def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--host", default="0.0.0.0")
|
|
parser.add_argument("--port", type=int, default=8094)
|
|
parser.add_argument("--upstream", default="ws://localhost:8091/v1/audio/speech/stream")
|
|
args = parser.parse_args()
|
|
handler.upstream_url = args.upstream
|
|
print(f"WS log proxy: ws://{args.host}:{args.port}/v1/audio/speech/stream -> {args.upstream}", flush=True)
|
|
async with websockets.serve(handler, args.host, args.port, max_size=None):
|
|
await asyncio.Future()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|