🌊 Aqua-TTS: GPT-SoVITS Low-Latency Inference Runtime on GPU
Built for low-latency voice conversation with your LoRA characters
中文 | English
Aqua-TTS is a GPU-optimized inference runtime purpose-built for real-time voice conversation — specifically, low-latency streaming TTS with your own GPT-SoVITS v3 LoRA character voices. It does not replace model weights — it replaces the execution strategy: static KV cache buffers, bucketed CUDA Graph capture/replay, and pre-compiled BigVGAN CUDA kernels. On an RTX 4070 Ti SUPER, this reaches 440–470 it/s T2S throughput and reduces model-side first-audio latency from 1.0–3.6 s to ~0.26–0.40 s. In the full streaming player pipeline, practical first-audio latency is typically 0.4–0.7 s depending on chunk length, audio device startup, cache state, and scheduling overhead — see Highlights for the full comparison.
Highlights
Latency definitions: TTFP benchmark = model-side first audio latency under warm-cache (table below). E2E first-audio = full pipeline including audio buffer and playback startup, typically 0.4–0.7 s in practice. Cold start = init + model load + first inference, dominated by BigVGAN CUDA kernel compilation (~2 min on first run, then cached).
| GPT-SoVITS (official) | + CUDA Graph | Aqua-TTS | |
|---|---|---|---|
| T2S throughput | ~80-90 it/s | ~230 it/s | 440-470 it/s |
| TTFP (short, 3 chars) | 1061ms | 1016ms | ~257ms |
| TTFP (medium, 19 chars) | 1599ms | 1476ms | ~301ms |
| TTFP (long, 64 chars) | 3598ms | 2852ms | ~404ms |
| KV cache | Dynamic torch.cat |
Static scatter_ |
Static scatter_ buffer |
| CUDA Graph | None | Single lazy graph | 17 pre-captured graphs, 6 buckets |
| BigVGAN vocoder | PyTorch JIT | PyTorch JIT | Pre-compiled CUDA kernel |
| KV-cache allocation | Unbounded growth | Unbounded growth | Bounded per bucket config |
TTFP benchmark: NVIDIA GeForce RTX 4070 Ti SUPER (16 GB), PyTorch 2.5.1+cu121, float16, warm cache, static KV cache enabled, bucketed CUDA Graph pre-captured. Aqua-TTS numbers are median of 5 runs. Official baseline uses the same GPT checkpoint; TTFP for non-streaming baselines coincides with full utterance completion. See benchmarks/README.md for full methodology and raw repeats.
https://github.com/user-attachments/assets/581cef5f-f8ce-4570-81ae-a6c092698223
Features
- Static KV cache — pre-allocated scatter buffers eliminate per-step
torch.catoverhead - Bucketed CUDA Graph — 13 pre-captured graphs across 6 bucket sizes, no warmup jitter
- Pre-compiled BigVGAN — NVIDIA CUDA kernel auto-loaded from pre-built
.pyd, with torch fallback - Optional FlashAttention2 KV cache — experimental
flash_attn_with_kvcacheT2S path, disabled by default - Streaming API — generator-based
infer_stream()with early first-audio yield - Built-in presets — fast / balanced / quality generation presets; full / minimal / lazy / off CUDA Graph presets
- Voice registry — map voice names to reference audio + prompt, with JSON persistence
- HTTP server — lightweight FastAPI server with streaming TTS endpoint, voice management, and health check
- PyPI install —
pip install "aqua-tts[runtime]"→from aquatts import TTSInferencer
Scope notice — Aqua-TTS is a self-contained runtime for GPT-SoVITS v3. It is not a plugin and does not track upstream changes. The techniques here — static KV cache, bucketed CUDA Graph, pre-compiled BigVGAN kernel — are documented in TECHNICAL.md and designed to be portable. If you need v4 support,
aquatts/modeling/andaquatts/_vendor/are the right starting points for adaptation.
Known limitations — Windows + CUDA is the primary tested path. Linux passes unit tests but GPU-dependent paths (CUDA Graph, BigVGAN kernel) have not been validated on Linux hardware. macOS is not supported. TTFP varies with GPU model, audio device, chunk size, and model weights — numbers in this README are measured on an RTX 4070 Ti SUPER with specific v3 LoRA weights and should not be treated as universal. Only GPT-SoVITS v3 is supported.
Supported Languages
Aqua-TTS inherits GPT-SoVITS v3's language support. Pass the code to text_language / prompt_language — reference audio and target text can use different languages.
| Language | Code |
|---|---|
| Japanese | 日文 |
| Chinese | 中文 |
| English | 英文 |
How it works
Aqua-TTS vendors overrides for two GPT-SoVITS files inside aquatts/_vendor/ using Python namespace packages (pkgutil.extend_path). When you import aquatts, the package automatically configures sys.path so the vendored files take precedence over the main GPT-SoVITS repo. Set GPT_SOVITS_HOME to point at your GPT-SoVITS installation — Aqua-TTS handles the rest:
aqua-tts/
├── aquatts/ # Pure Python package (pip-installable)
│ ├── __init__.py # sys.path configuration + lazy exports
│ ├── inferencer.py # TTSInferencer — main entry point
│ ├── server.py # FastAPI HTTP server
│ ├── voice_registry.py # Voice name → audio path mapping
│ ├── modeling/
│ │ ├── t2s_streaming.py # T2SBlockWithStaticCache, CUDA Graph patch
│ │ └── t2s_flash_attn.py # Optional FlashAttention2 KV-cache patch
│ ├── bigvgan/
│ │ ├── cuda/ # Standalone CUDA kernel loader + sources
│ │ └── torch/ # Pure-PyTorch fallback (resample, filter, act)
│ ├── inference/
│ │ ├── streaming.py # Audio post-processing (fade, chunk finalization)
│ │ ├── params.py # SoVITS parameter presets
│ │ └── presets.py # Named presets (generation + CUDA Graph)
│ └── _vendor/
│ └── GPT_SoVITS/ # Vendored overrides (namespace packages)
│ ├── AR/models/
│ │ └── t2s_model.py # Static KV + CUDA Graph T2S decoder
│ └── BigVGAN/alias_free_activation/cuda/
│ ├── load.py # Pre-compiled kernel loader (MSVC auto-discovery)
│ ├── activation1d.py # Fused anti-alias activation
│ └── *.cpp, *.cu, *.h # NVIDIA BigVGAN CUDA kernel sources
├── benchmarks/ # TTFP, T2S comparison, BigVGAN raw benchmarks
├── examples/ # basic_usage.py, streaming_inference.py
└── tests/ # Unit tests
See TECHNICAL.md for deep technical documentation.
Requirements
| Entry | Recommended | |
|---|---|---|
| GPU | RTX 3060 6 GB | RTX 4060 / 4070 8 GB+ |
| CUDA | 11.8+ | 12.x |
| RAM | 8 GB | 16 GB+ |
| Python | 3.10 | 3.11 / 3.12 |
| OS | Windows 10+ | Windows 11 |
Linux CI (Ubuntu) passes for all unit tests. GPU-dependent paths (CUDA Graph, BigVGAN kernel) have not been tested on Linux hardware. macOS is not supported — Aqua-TTS requires CUDA.
On 6 GB cards, use
cuda_graph_preset="lazy"or"off"to reduce VRAM pressure from pre-captured graphs.
Installation
1. Install GPT-SoVITS
You need a working GPT-SoVITS v3 installation. Aqua-TTS imports from it.
git clone https://github.com/RVC-Boss/GPT-SoVITS.git
cd GPT-SoVITS
pip install -r requirements.txt
Aqua-TTS has been tested against GPT-SoVITS v3 (2025-04-01 release).
2. Install PyTorch
Install PyTorch matching your CUDA version before installing Aqua-TTS — it is not included in the package dependencies so you can pick the right CUDA wheel:
# Example for CUDA 12.1 — see https://pytorch.org/get-started/locally/ for other versions
pip install torch --index-url https://download.pytorch.org/whl/cu121
Aqua-TTS has been tested with PyTorch 2.5.1+cu121 on an RTX 4070 Ti SUPER.
3. Install Aqua-TTS
# Core + runtime dependencies from PyPI
pip install "aqua-tts[runtime]"
# Or with HTTP server support
pip install "aqua-tts[server]"
# Or with local playback support
pip install "aqua-tts[playback]"
For development or unreleased changes, install from source instead:
git clone https://github.com/Lucas1479/Aqua-TTS.git
cd Aqua-TTS
pip install -e ".[runtime]"
Extras:
[runtime]— soundfile, librosa, peft (needed byTTSInferencer)[server]— FastAPI + uvicorn (includes[runtime]automatically)[playback]— PyAudio (includes[runtime]automatically)
4. Configure GPT-SoVITS path
Set the GPT_SOVITS_HOME environment variable to your GPT-SoVITS repo root:
# Windows (PowerShell)
$env:GPT_SOVITS_HOME = "C:\path\to\GPT-SoVITS"
# Linux / macOS
export GPT_SOVITS_HOME=/path/to/GPT-SoVITS
5. Download pretrained models
Aqua-TTS needs BigVGAN v2 pretrained weights from Hugging Face. Download them directly into your GPT-SoVITS repo with huggingface_hub:
pip install huggingface_hub
python -c "
from huggingface_hub import snapshot_download
snapshot_download(
repo_id='nvidia/bigvgan_v2_24khz_100band_256x',
local_dir='GPT_SoVITS/pretrained_models/models--nvidia--bigvgan_v2_24khz_100band_256x',
)
"
The models--nvidia--bigvgan_v2_24khz_100band_256x directory name is the HuggingFace Hub cache format — use it exactly as shown.
6. Prepare model weights
- GPT weights (T2S): A
Text2SemanticLightningModulecheckpoint (e.g.,s1v3.ckptor self-trainedxxx-e15.ckpt). - SoVITS weights (vocoder): A
SynthesizerTrncheckpoint with optional LoRA (e.g.,xxx_e2_s174_l32.pth). - Reference audio: A 3-10 second 24 kHz WAV file with known transcript.
Quick sanity check
Once GPT_SOVITS_HOME is set and models are in place, verify the package loads correctly:
python -c "from aquatts import TTSInferencer; print('aquatts OK')"
If this prints aquatts OK, the install is good. If it errors, check that GPT_SOVITS_HOME points to the right directory and all pretrained models are downloaded.
Usage
Python API
import os
os.environ["GPT_SOVITS_HOME"] = "/path/to/GPT-SoVITS"
os.environ["ENABLE_CUDA_GRAPH"] = "1"
from aquatts import TTSInferencer
tts = TTSInferencer(
device="cuda",
gpt_path="GPT_weights_v3/s1v3.ckpt",
sovits_path="SoVITS_weights_v3/your_model.pth",
cuda_graph_preset="full", # "full", "minimal", "lazy", or "off"
)
# Streaming generation — yields (sample_rate, audio_chunk, text) tuples
for sr, chunk, text in tts.infer_stream(
text="こんにちは、世界!",
ref_audio_path="reference audio/ref_audio.wav",
prompt_text="こんにちは。今日はいい天気ですね。",
text_language="日文",
prompt_language="日文",
preset="fast", # "fast", "balanced", or "quality"
):
# chunk is float32 numpy array at `sr` Hz
# text is the text segment being spoken
pass
See examples/basic_usage.py and examples/streaming_inference.py for runnable examples.
Presets
Two layers of presets control quality/speed trade-offs:
Generation presets (per-request, via infer_stream(preset=...)):
| Preset | Speed | Sample Steps | Top-K | Temperature |
|---|---|---|---|---|
fast |
1.3x | 4 | 3 | 0.6 |
balanced |
1.1x | 4 | 5 | 0.6 |
quality |
1.0x | 16 | 8 | 0.8 |
CUDA Graph presets (system-level, via TTSInferencer(cuda_graph_preset=...)):
| Preset | Pre-capture | Buckets | Description |
|---|---|---|---|
full |
Yes | 128, 256, 448, 512, 768, 1024 | All lengths covered |
minimal |
Yes | 256, 512, 1024 | Common lengths only |
lazy |
No | on-the-fly | Lower memory, slower TTFP |
off |
Disabled | none | Static KV only, no graphs |
Optional FlashAttention2 T2S path (experimental, disabled by default):
Aqua-TTS can replace the q_len=1 T2S static-KV attention step with
flash_attn_with_kvcache. This is an opt-in path because the useful valid
mode attends over the true KV length rather than the full zero-padded bucket,
so output can differ slightly from the default SDPA bucket path.
Enable it for long first-sentence or long-form T2S throughput experiments:
export AQUATTS_T2S_FLASH_ATTN=1
export AQUATTS_T2S_FLASH_ATTN_MODE=valid # valid | bucket
or from Python:
tts = TTSInferencer(..., use_flash_attn=True, flash_attn_mode="valid")
Keep it off for short demo lines, early-cut first-sentence demos, or strict regression comparisons. On short 448/512-bucket shapes the extra path is often within noise or slightly slower; it becomes more interesting on longer 768+ bucket decode.
Directional AB test on the shared Aqua/Amadeus v3 T2S path (RTX 4070 Ti SUPER, PyTorch 2.5.1+cu124, flash-attn 2.7.0.post2, CUDA Graph pre-captured, BigVGAN CUDA kernel cached):
| Case | Flash off | Flash on (valid) |
Note |
|---|---|---|---|
| T2S short, 3 chars | ~427 it/s | ~414 it/s | no benefit |
| T2S medium, 19 chars | ~448 it/s | ~478 it/s | small win |
| T2S long, 64 chars | ~461 it/s | ~500 it/s | ~8% throughput win |
| TTFP short | ~290ms | ~297ms | no benefit |
| TTFP medium | ~396ms | ~413ms | no benefit in this run |
| TTFP long | ~687ms | ~659ms | ~28ms model-side win |
| TTFP long early-cut | ~317ms | ~336ms | keep off for early-cut |
Treat these as guidance rather than headline numbers: FlashAttention2 helps most when attention bucket length is the bottleneck, while Aqua's default CUDA-Graph SDPA path is already very fast for short conversational turns.
from aquatts import apply_preset, list_presets
print(list_presets()) # ["balanced", "fast", "quality"]
params = apply_preset("fast", overrides={"top_k": 5})
HTTP Server
Start a lightweight inference server:
python -m aquatts.server \
--gpt-model GPT_weights_v3/s1v3.ckpt \
--sovits-model SoVITS_weights_v3/model.pth \
--cuda-graph-preset full \
--host 127.0.0.1 --port 8000
# With authentication (required when binding to a non-loopback address)
python -m aquatts.server ... --host 0.0.0.0 --api-key mysecrettoken
# or: export AQUA_API_KEY=mysecrettoken
Endpoints:
| Method | Path | Description |
|---|---|---|
GET |
/health |
Model load status |
GET |
/presets |
List available presets |
POST |
/tts |
Streaming TTS (float32 PCM chunks) |
POST |
/tts/file |
One-shot TTS (downloadable .wav) |
GET |
/voices |
List registered voices |
POST |
/voices/add |
Register a new voice |
DELETE |
/voices/{name} |
Remove a registered voice |
# Streaming TTS — returns raw float32 PCM (24kHz, mono, little-endian)
curl -X POST "http://127.0.0.1:8000/tts?text=Hello&voice=alice" --output - \
| play -t raw -r 24k -e floating-point -b 32 -c 1 -
# Download WAV file
curl -X POST "http://127.0.0.1:8000/tts/file?text=Hello&voice=alice" -o output.wav
Voice Registry
Manage multiple characters/voices without repeating paths:
from aquatts import Voice, VoiceRegistry
registry = VoiceRegistry(json_path="./voices.json")
registry.add(Voice(
name="alice",
ref_audio_path="./voices/alice_ref.wav",
prompt_text="こんにちは。今日はいい天気ですね。",
prompt_language="日文",
))
voice = registry.get("alice")
for sr, chunk, text in tts.infer_stream(
text="Hello world",
ref_audio_path=voice.ref_audio_path,
prompt_text=voice.prompt_text,
prompt_language=voice.prompt_language,
):
pass
On the HTTP server, pass voice instead of ref_audio_path:
curl -X POST "http://127.0.0.1:8000/tts?text=Hello&voice=alice"
For production deployments, pass an explicit registry path:
python -m aquatts.server ... --voice-registry /data/voices.json
# or
export AQUA_VOICE_JSON=/data/voices.json
Configuration
| Env variable | Default | Description |
|---|---|---|
GPT_SOVITS_HOME |
(required) | Path to GPT-SoVITS repo root |
AQUA_API_KEY |
(unset) | Bearer token for all server endpoints; unset = no auth |
AQUA_VOICE_JSON |
./voices.json |
Path to voice registry JSON file. Always set this — default is relative to process CWD and will be lost on directory change |
AQUA_SESSION_CACHE_MAX |
8 |
Max number of cached reference audio sessions |
ENABLE_CUDA_GRAPH |
1 |
Enable CUDA Graph replay |
ENABLE_CUDA_GRAPH_PRECAPTURE |
1 |
Pre-capture all bucket graphs at startup |
AQUATTS_T2S_FLASH_ATTN |
0 |
Enable experimental FlashAttention2 flash_attn_with_kvcache path for T2S |
AQUATTS_T2S_FLASH_ATTN_MODE |
valid |
FlashAttention mode: valid uses true KV length; bucket preserves zero-padded bucket length |
TTS_OUTPUT_LANGUAGE |
日文 |
Default output language. Change to 中文 or 英文 if not using Japanese |
TTS_REF_TEXT_JA |
こんにちは。今日はいい天気ですね。 |
Default Japanese reference text |
TTS_REF_TEXT_EN |
(empty) | Default English reference text |
TTS_STREAM_SYNC_TIMING |
0 |
Enable per-step CFM timing (adds GPU sync overhead) |
Benchmarks
# T2S comparison (official vs official+CUDA Graph vs Aqua-TTS)
# Replace with your own GPT checkpoint (s1v3.ckpt or a self-trained .ckpt)
python benchmarks/t2s_comparison_bench.py --gpt-model GPT_weights_v3/xxx-e15.ckpt
# TTFP benchmark (streaming end-to-end)
python benchmarks/aqua_ttfp.py \
--gpt-model GPT_weights_v3/xxx-e15.ckpt \
--sovits-model SoVITS_weights_v3/xxx_e2_s174_l32.pth \
--ref-audio "reference audio/ref_audio.wav" \
--ref-text "transcript of reference audio"
# BigVGAN raw kernel timing
python benchmarks/bigvgan_raw_bench.py
See benchmarks/README.md for full methodology and results.
Speaker Demo
pip install -e ".[playback]"
python examples/play_ete.py --gpt-sovits-home /path/to/GPT-SoVITS-v3lora
The demo plays three Kurisu-style Japanese utterances (short, medium, long) through PyAudio and prints TTFP plus live T2S throughput for each scripted line. Pass --show-total to also print audio duration, wall time, and RTF.
Playback demos default to the low-latency live profile (--top-p 1 --speed 1.1 --sample-steps 4 --how-to-cut 按标点符号切) with queue-based playback, chunk merging, short fades, and padding to reduce chunk-boundary artifacts. To inspect whole-utterance T2S throughput without punctuation splitting, pass --how-to-cut 不切.
For recording an interactive demo, load the voice once and type any Japanese text:
python examples/live_talk.py --gpt-sovits-home /path/to/GPT-SoVITS-v3lora
Acknowledgements
Aqua-TTS was inspired by GENIE-TTS, which demonstrated that a focused, self-contained inference runtime could meaningfully close the latency gap in GPT-SoVITS. That framing — optimise the runtime, not the model — shaped the direction of this project.
License
MIT — see LICENSE.
Third-party code:
- GPT-SoVITS: vendored
aquatts/_vendor/GPT_SoVITS/AR/models/t2s_model.pyis based on GPT-SoVITS (MIT) — see NOTICE. - NVIDIA BigVGAN: CUDA kernel sources under Apache 2.0 — see NOTICE.
- alias-free-torch:
aquatts/bigvgan/torch/adapted under Apache 2.0 — see NOTICE.
Development
git clone https://github.com/Lucas1479/Aqua-TTS.git
cd Aqua-TTS
pip install -e ".[runtime]"
pip install -r requirements-dev.txt
export GPT_SOVITS_HOME=/path/to/GPT-SoVITS
python -m pytest tests/ -v
See CONTRIBUTING.md for contribution guidelines and CHANGELOG.md for release history. Release maintainers should follow PUBLISHING.md.
Metadata
Release files for aqua-tts 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| aqua_tts-0.2.0.tar.gz | 110.9 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aqua_tts-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 210.1 kB
Release files / aqua_tts-0.2.0.tar.gz
| Download URL | aqua_tts-0.2.0.tar.gz |
|---|---|
| Size | 110.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ee0e085d463d5854eef22dfb9eb72d82c1229f6d12e2d31a93df0cddc58d2b24
|
|
BLAKE2b-256 checksum How to use checksums |
6348fe7d601eb2b98460e6bf9ff94cbae7bdc079fae3eed2c48c3350203e7b00
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.
Transparency logRelease files / aqua_tts-0.2.0-py3-none-any.whl
| Download URL | aqua_tts-0.2.0-py3-none-any.whl |
|---|---|
| Size | 99.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3958561d39d81436fa4cd3272f67989a6a5ef354a87336769e7c99001796e19b
|
|
BLAKE2b-256 checksum How to use checksums |
c583ba7c3bf99cfdd3a4a0f7f758ea5ec9c7b2e063793f68913a24b10edfa376
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.
Transparency logSecurity for aqua-tts 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for aqua_tts-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.