Make speech streaming default to SSE (#4679)
Signed-off-by: syd520zy <529477025@qq.com>
This commit is contained in:
1 parent
c45ac74d43
commit
11f6a0b72e
39 files changed
+146
-58
No files matched your search
@@ -79,7 +79,7 @@ response = client.audio.speech.create(
|
||||
response.stream_to_file("output.wav")
|
||||
```
|
||||
|
||||
Streaming PCM output (where supported) — set `stream=true` with `response_format="pcm"`:
|
||||
Streaming PCM output (where supported) — set `stream=true`, `stream_format="audio"`, and `response_format="pcm"`:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8091/v1/audio/speech \
|
||||
@@ -88,6 +88,7 @@ curl -X POST http://localhost:8091/v1/audio/speech \
|
||||
"input": "Hello, how are you?",
|
||||
"voice": "default",
|
||||
"stream": true,
|
||||
"stream_format": "audio",
|
||||
"response_format": "pcm"
|
||||
}' --no-buffer | play -t raw -r 24000 -e signed -b 16 -c 1 -
|
||||
```
|
||||
@@ -363,6 +364,7 @@ curl -X POST http://localhost:8091/v1/audio/speech \
|
||||
\"input\": \"Hello, streaming output from MOSS-TTS-Nano.\",
|
||||
\"ref_audio\": \"data:audio/wav;base64,${REF_AUDIO}\",
|
||||
\"stream\": true,
|
||||
\"stream_format\": \"audio\",
|
||||
\"response_format\": \"pcm\"
|
||||
}" --no-buffer | play -t raw -r 48000 -e signed -b 16 -c 1 -
|
||||
```
|
||||
@@ -528,10 +530,11 @@ curl -X POST http://localhost:8091/v1/audio/speech \
|
||||
"voice": "vivian",
|
||||
"language": "English",
|
||||
"stream": true,
|
||||
"stream_format": "audio",
|
||||
"response_format": "pcm"
|
||||
}' --no-buffer | play -t raw -r 24000 -e signed -b 16 -c 1 -
|
||||
```
|
||||
Streaming requires `response_format="pcm"` and `async_chunk: true` on the stage config (default in `qwen3_tts.yaml`). `speed` is not supported when streaming.
|
||||
Raw PCM streaming requires `stream_format="audio"`, `response_format="pcm"`, and `async_chunk: true` on the stage config (default in `qwen3_tts.yaml`). `speed` is not supported when streaming.
|
||||
|
||||
### Streaming WebSocket
|
||||
The `/v1/audio/speech/stream` endpoint accepts text incrementally, splits it at sentence boundaries, and emits one PCM stream per sentence:
|
||||
@@ -632,7 +635,7 @@ After startup, `/v1/audio/voices` lists `alice`, and `/v1/audio/speech` can use
|
||||
```bash
|
||||
python voxcpm2/gradio_demo.py
|
||||
```
|
||||
Uses an AudioWorklet-based player adapted from the Qwen3-TTS demo for gap-free playback. Audio is streamed from the OpenAI Speech endpoint with `stream=true`.
|
||||
Uses an AudioWorklet-based player adapted from the Qwen3-TTS demo for gap-free playback. Raw PCM audio is streamed from the OpenAI Speech endpoint with `stream=true` and `stream_format="audio"`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ def run_tts(args) -> None:
|
||||
|
||||
if args.stream:
|
||||
payload["stream"] = True
|
||||
payload["stream_format"] = "audio"
|
||||
payload["response_format"] = "pcm"
|
||||
|
||||
print(f"Model: {args.model}")
|
||||
|
||||
@@ -66,6 +66,8 @@ def build_payload(
|
||||
"response_format": "pcm" if stream else response_format,
|
||||
"stream": stream,
|
||||
}
|
||||
if stream:
|
||||
payload["stream_format"] = "audio"
|
||||
|
||||
# Voice cloning: ref_audio takes priority over URL.
|
||||
ref_url_stripped = ref_audio_url.strip() if ref_audio_url else ""
|
||||
|
||||
@@ -53,6 +53,7 @@ def run_tts(args) -> None:
|
||||
|
||||
if args.stream:
|
||||
payload["stream"] = True
|
||||
payload["stream_format"] = "audio"
|
||||
payload["response_format"] = "pcm"
|
||||
|
||||
print(f"Model: {args.model}")
|
||||
|
||||
@@ -64,6 +64,8 @@ def build_payload(
|
||||
"stream": stream,
|
||||
"max_new_tokens": max_new_tokens,
|
||||
}
|
||||
if stream:
|
||||
payload["stream_format"] = "audio"
|
||||
|
||||
# Voice cloning: ref_audio takes priority over URL.
|
||||
ref_url_stripped = ref_audio_url.strip() if ref_audio_url else ""
|
||||
|
||||
@@ -40,6 +40,9 @@ def run_tts_generation(args) -> None:
|
||||
"ref_audio": args.ref_audio,
|
||||
"ref_text": args.ref_text,
|
||||
}
|
||||
if args.stream:
|
||||
payload["stream_format"] = "audio"
|
||||
payload["response_format"] = "pcm"
|
||||
if args.max_new_tokens:
|
||||
payload["max_new_tokens"] = args.max_new_tokens
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ def run_tts(args) -> None:
|
||||
payload["max_new_tokens"] = args.max_new_tokens
|
||||
if args.stream:
|
||||
payload["stream"] = True
|
||||
payload["stream_format"] = "audio"
|
||||
payload["response_format"] = "pcm"
|
||||
|
||||
api_url = f"{args.api_base}/v1/audio/speech"
|
||||
|
||||
@@ -65,6 +65,7 @@ PY
|
||||
\"model\": \"${MODEL}\",
|
||||
\"input\": \"${TEXT}\",
|
||||
\"stream\": true,
|
||||
\"stream_format\": \"audio\",
|
||||
\"response_format\": \"pcm\"
|
||||
}" "$STREAM_OUTPUT"
|
||||
;;
|
||||
|
||||
@@ -335,6 +335,7 @@ def build_payload(
|
||||
"ref_audio": encode_audio_to_base64(ref_audio),
|
||||
"response_format": "pcm" if stream else response_format,
|
||||
"stream": stream,
|
||||
**({"stream_format": "audio"} if stream else {}),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -93,6 +93,8 @@ def build_payload(
|
||||
"response_format": "pcm" if stream else response_format,
|
||||
"stream": stream,
|
||||
}
|
||||
if stream:
|
||||
payload["stream_format"] = "audio"
|
||||
if not stream:
|
||||
payload["speed"] = speed
|
||||
|
||||
|
||||
@@ -515,6 +515,8 @@ def create_app(api_base: str):
|
||||
"response_format": "pcm" if stream_enabled else "wav",
|
||||
"stream": stream_enabled,
|
||||
}
|
||||
if stream_enabled:
|
||||
payload["stream_format"] = "audio"
|
||||
|
||||
# Reference audio for cloning
|
||||
ref_url_s = ref_url.strip() if ref_url else ""
|
||||
|
||||
Reference in new issue
Block a user