Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions demo/web/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,22 @@ def streaming_tts(text: str, **kwargs) -> Iterator[np.ndarray]:
@app.websocket("/stream")
async def websocket_stream(ws: WebSocket) -> None:
await ws.accept()
text = ws.query_params.get("text", "")
print(f"Client connected, text={text!r}")
cfg_param = ws.query_params.get("cfg")
steps_param = ws.query_params.get("steps")
voice_param = ws.query_params.get("voice")

# Receive initial configuration message from client
try:
config_message = await ws.receive_text()
config = json.loads(config_message)
except Exception as e:
print(f"Error receiving config: {e}")
await ws.close(code=1003, reason="Invalid configuration")
return

text = config.get("text", "")
cfg_param = config.get("cfg")
steps_param = config.get("steps")
voice_param = config.get("voice")

print(f"Client connected, text length={len(text)}, cfg={cfg_param}, steps={steps_param}, voice={voice_param}")
Comment on lines +368 to +381
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After json.loads, config can be any JSON type (string/list/null/etc). The subsequent config.get(...) calls and len(text) will raise (AttributeError/TypeError) for valid-but-unexpected payloads like "foo" or { "text": null }, resulting in a 500 and leaving the socket in a bad state. Validate config is a dict and that text is a string (or coerce/reject) before accessing .get/len, and close the websocket with an appropriate code/reason on invalid types.

Copilot uses AI. Check for mistakes.

try:
cfg_scale = float(cfg_param) if cfg_param is not None else 1.5
Expand Down
20 changes: 14 additions & 6 deletions demo/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -918,22 +918,30 @@ <h1>VibeVoice-Realtime TTS Demo</h1>
updateButtonLabel();
createAudioChain();

const params = new URLSearchParams();
params.set('text', textValue);
// Prepare configuration object to send via WebSocket message instead of URL
const config = {
text: textValue,
};
if (!Number.isNaN(cfgValue)) {
params.set('cfg', cfgValue.toFixed(3));
config.cfg = cfgValue.toFixed(3);
}
if (!Number.isNaN(stepsValue)) {
params.set('steps', stepsValue.toString());
config.steps = stepsValue.toString();
}
if (voiceValue) {
params.set('voice', voiceValue);
config.voice = voiceValue;
}
const wsUrl = `${location.origin.replace(/^http/, 'ws')}/stream?${params.toString()}`;

const wsUrl = `${location.origin.replace(/^http/, 'ws')}/stream`;

socket = new WebSocket(wsUrl);
socket.binaryType = 'arraybuffer';

socket.onopen = () => {
// Send configuration as first message after connection opens
socket.send(JSON.stringify(config));
Comment on lines +940 to +942
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

socket.onopen closes over the mutable global socket variable, but closeSocket() sets socket = null even when the WebSocket is still CONNECTING. If the user stops quickly (or other code calls closeSocket) around the time the connection opens, this handler can run with socket === null and throw when calling socket.send(...). Capture the WebSocket instance in a local const (or use the event.target) inside the handler to avoid races with socket being reassigned/nullified.

Suggested change
socket.onopen = () => {
// Send configuration as first message after connection opens
socket.send(JSON.stringify(config));
socket.onopen = event => {
// Send configuration as first message after connection opens
const ws = event.target;
ws.send(JSON.stringify(config));

Copilot uses AI. Check for mistakes.
};

socket.onmessage = event => {
if (typeof event.data === 'string') {
handleLogMessage(event.data);
Expand Down
Loading