Sign inSign up

k8bit/supertonic

By k8bit

•Updated 3 months ago

Image
0

3.5K

k8bit/supertonic repository overview

⁠Supertonic 3 TTS — Deployment Guide

⁠Overview

k8bit/supertonic is a Docker image providing an OpenAI-compatible REST API for Supertonic 3 TTS⁠ — a 99M-parameter, CPU-native TTS system powered by ONNX Runtime. It runs entirely on-device with no GPU required.

The API is a drop-in replacement for OpenAI's /v1/audio/speech endpoint.

Key specs:

  • Model: Supertone/supertonic-3 (~200 MB, downloaded automatically on first start)
  • Runtime: ONNX Runtime — CPU only, no GPU required
  • Languages: 31 (Arabic, Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Latvian, Lithuanian, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, Turkish, Ukrainian, Vietnamese)
  • Built-in voices: 10 (M1–M5 male, F1–F5 female)
  • Voice cloning: via Voice Builder JSON files
  • Audio output: 44.1 kHz WAV, FLAC, OGG
  • Sample rate: 44.1 kHz
  • Subwave Remote TTS bridge: built-in on port 5001 (no extra container needed)

⁠Quick Start — Try it in 60 seconds

No Unraid, no GPU, no configuration required. You just need Docker.

⁠Option A — Single docker run (instant test)
docker run --rm -p 8030:8000 \
  -v supertonic-models:/models \
  k8bit/supertonic:latest

The first run downloads the ONNX model (~200 MB). Watch the logs — when you see API endpoint : http://0.0.0.0:8000/v1/audio/speech it's ready.

Then test it:

# Health check
curl http://localhost:8030/v1/health

# List voices
curl http://localhost:8030/v1/styles | python3 -m json.tool

# Synthesise speech → test.wav
curl -X POST http://localhost:8030/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"model":"supertonic-3","input":"Hello! Supertonic is working.","voice":"F1","response_format":"wav"}' \
  --output test.wav

The named volume supertonic-models is reused on subsequent runs so the model is only downloaded once.


Save the following as docker-compose.yml (or use the provided supertonic-dockhand.yml directly with docker compose -f supertonic-dockhand.yml up -d):

name: supertonic

services:
  supertonic:
    image: k8bit/supertonic:latest
    container_name: supertonic
    restart: unless-stopped
    ports:
      - "${API_PORT:-8030}:8000"
    volumes:
      - ${MODELS_DIR:-./models}:/models
      - ${VOICES_DIR:-./voices}:/reference_voices:ro
    environment:
      SUPERTONIC_MODEL: ${SUPERTONIC_MODEL:-supertonic-3}
      CORS_ORIGINS:     ${CORS_ORIGINS:-*}
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:8000/v1/health"]
      interval: 30s
      timeout: 10s
      retries: 10
      start_period: 600s

Start:

mkdir -p models voices
docker compose up -d
docker compose logs -f

Stop:

docker compose down

The models/ directory is created locally and persists across restarts. Drop Voice Builder JSON files into voices/ to add custom voices (see Voice cloning⁠ below).

⁠Environment variables (.env or inline)
VariableDefaultDescription
API_PORT8030Host port to expose the API on
MODELS_DIR./modelsPath to persist the ONNX model cache
VOICES_DIR./voicesPath to a folder of Voice Builder JSON files
SUPERTONIC_MODELsupertonic-3Model version (supertonic-3 / supertonic-2 / supertonic)
CORS_ORIGINS*CORS origins; * is required for the browser-based HTML tools

Create a .env file next to docker-compose.yml to override any of these:

API_PORT=8030
MODELS_DIR=/opt/supertonic/models
VOICES_DIR=/opt/supertonic/voices
SUPERTONIC_MODEL=supertonic-3
⁠Interactive API docs

Once running, the full Swagger UI is available at:

http://localhost:8030/docs

⁠Unraid Deployment

⁠Prerequisites
  • Unraid 6.12+ (no GPU plugin required — this container is CPU-only)
  • Community Applications plugin
⁠Installing the container
⁠Option A — via Community Applications

Search for supertonic in the CA store. If not yet listed, use Option B.

⁠Option B — manual XML template
  1. In Unraid, go to Docker → Add Container → Template URL and paste:
https://raw.githubusercontent.com/k8bit/docker-templates/main/supertonic.xml

Or download supertonic-unraid.xml and import it manually: go to Docker → Templates → Add New Template, paste the XML contents into the editor, then save.

  1. Review the settings below before starting the container.
⁠Required path mappings
Container pathSuggested host pathPurpose
/models/mnt/user/ai/supertonic/modelsONNX model cache (~200 MB) and custom voice styles
/reference_voices/mnt/user/ai/voicesVoice Builder JSON files for custom voices

The /reference_voices path can be shared with Fish Speech and Higgs Audio — all three services look for files in the same directory (other services' .s2voice files and .wav/.txt pairs are simply ignored by Supertonic).

⁠Key settings
SettingDefaultNotes
API Port8030Host port for the OpenAI-compat API — change if in use
Subwave Bridge Port5001Host port for the Subwave Remote bridge — change if in use
Model Versionsupertonic-331-language latest; options: supertonic-2 (5 langs), supertonic (English only)
CORS Origins*Leave as * for browser-based HTML tools
Bridge LanguageenBCP-47 language code sent to Supertonic for Subwave speech (e.g. fr, ja, na)
Bridge Speed1.0Speed multiplier for Subwave TTS output (0.7–2.0)
⁠First start

On first launch the container downloads the ONNX model (~200 MB). This takes 1–3 minutes depending on connection speed.

Watch progress:

docker logs -f supertonic

Ready when you see:

API endpoint    : http://0.0.0.0:8000/v1/audio/speech  (OpenAI-compat)
Subwave bridge  : http://0.0.0.0:5001/speak             (Remote engine)
Interactive docs: http://0.0.0.0:8000/docs

⁠Docker Deployment (standalone)

⁠Prerequisites
  • Docker Engine ≥ 24 with the Compose plugin
  • No NVIDIA toolkit needed — this is a CPU-only image
⁠Directory layout
/mnt/user/ai/
├── supertonic/
│   └── models/       # ONNX model cache + custom voice styles (~200 MB total)
└── voices/           # Voice Builder JSON files: VOICENAME.json
⁠docker-compose.yml
name: supertonic

services:
  supertonic:
    image: k8bit/supertonic:latest
    container_name: supertonic
    restart: unless-stopped
    ports:
      - "${API_PORT:-8030}:8000"
      - "${BRIDGE_PORT:-5001}:5001"
    volumes:
      - ${MODELS_DIR:-/mnt/user/ai/supertonic/models}:/models
      - ${VOICES_DIR:-/mnt/user/ai/voices}:/reference_voices:ro
    environment:
      SUPERTONIC_MODEL: ${SUPERTONIC_MODEL:-supertonic-3}
      CORS_ORIGINS:     ${CORS_ORIGINS:-*}
      BRIDGE_LANG:      ${BRIDGE_LANG:-en}
      BRIDGE_SPEED:     ${BRIDGE_SPEED:-1.0}
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:8000/v1/health"]
      interval: 30s
      timeout: 10s
      retries: 10
      start_period: 600s
⁠.env
# Volumes
MODELS_DIR=/mnt/user/ai/supertonic/models
VOICES_DIR=/mnt/user/ai/voices

# Ports
API_PORT=8030    # OpenAI-compat API
BRIDGE_PORT=5001 # Subwave Remote bridge

# Model version: supertonic-3 | supertonic-2 | supertonic
SUPERTONIC_MODEL=supertonic-3

# CORS origins (* = allow all; required for browser tools)
CORS_ORIGINS=*

# Subwave bridge settings
BRIDGE_LANG=en   # BCP-47 language code (en, fr, ja, …) or na for auto
BRIDGE_SPEED=1.0 # Speed multiplier (0.7 = slow, 1.0 = normal, 2.0 = fast)
⁠Starting
docker compose up -d
docker logs -f supertonic

⁠Subwave integration

SUB/WAVE⁠ is a self-hosted AI radio station (Icecast + Liquidsoap + AI DJ). Its Remote TTS engine speaks a simple HTTP contract:

GET  /health  →  { "ok": true }
POST /speak   →  { "text": "...", "voice": "..." }  →  WAV bytes

This image includes a built-in bridge (bridge.py) that listens on port 5001 and translates that contract into Supertonic's native /v1/tts API. No extra container or sidecar needed — just expose the port and point Subwave at it.

⁠Why not use the OpenAI engine in Subwave?

Subwave's Cloud/OpenAI engine sends response_format: "mp3" which Supertonic cannot produce (the ONNX model outputs 44.1 kHz audio; libsndfile's MP3 encoder is pinned to standard sample rates). Using the Remote engine and the built-in bridge sidesteps this entirely.

⁠Setup

1. Expose the bridge port

The bridge runs on port 5001 inside the container. Map it to your host:

  • Unraid: the template includes a "Subwave Bridge Port" field (default 5001) — it is already there, just confirm the port isn't in use.

  • docker-compose: ${BRIDGE_PORT:-5001}:5001 is already in the generated compose file.

  • docker run:

    docker run --rm \
      -p 8030:8000 \
      -p 5001:5001 \
      -v supertonic-models:/models \
      k8bit/supertonic:latest
    

2. Verify the bridge is up

curl http://192.168.1.100:5001/health
# → {"ok":true}

3. Configure Subwave

In the Subwave admin UI:

  • Go to Settings → TTS Voice
  • Set Engine to Remote
  • Set URL to http://192.168.1.100:5001 (use the IP your Subwave controller can reach; not 127.0.0.1 unless they're on the same host)
  • Save — the Remote badge should turn green within 30 seconds

4. Set voices on personas

Each Subwave persona has a voice field. The bridge forwards this string verbatim to Supertonic as the voice parameter. Use any built-in or custom imported voice:

VoiceCharacter
M1Lively, upbeat male
M2Deep, serious male
M3Polished, authoritative male
M4Soft, friendly male
M5Warm, soft-spoken male
F1Calm, composed female
F2Bright, cheerful female
F3Clear, announcer-style female
F4Crisp, confident female
F5Kind, gentle female

Custom voices imported from Voice Builder are also valid — use the filename stem (e.g. a file named milo.json in /reference_voices/ is available as voice milo).

⁠Bridge environment variables
VariableDefaultDescription
BRIDGE_PORT5001Host and container port the bridge listens on
BRIDGE_LANGenBCP-47 language code sent to Supertonic (e.g. en, fr, ja, na)
BRIDGE_SPEED1.0Playback speed multiplier (0.7 = slow, 1.0 = normal, 2.0 = fast)

BRIDGE_LANG is a station-wide setting — all DJ speech uses the same language code. Use na (language-agnostic mode) if your station plays multilingual content and you want Supertonic to infer the language from the text automatically.


⁠Voice cloning with Voice Builder

Supertonic's open-weight release uses fixed built-in voices. Custom voice cloning is provided through Supertone Voice Builder⁠, which converts a short recording into a downloadable JSON voice profile.

⁠Creating a custom voice
  1. Go to https://supertonic.supertone.ai/voice-builder⁠
  2. Record or upload a clean speech sample (10–60 seconds recommended)
  3. Give your voice a name and complete the creation process
  4. From My Page (https://supertonic.supertone.ai/my-page⁠), download the Supertonic 3 JSON for your voice
⁠Adding the voice to the container

Place the downloaded JSON file in your /reference_voices/ host directory:

/mnt/user/ai/voices/
└── myvoice.json      ← Voice Builder export (Supertonic 3 version)

The filename stem (myvoice) becomes the voice name used in API calls. Restart the container to import new voices:

docker restart supertonic

Or import at runtime without restarting:

curl -X POST http://trogdor:8030/v1/styles/import \
  -F "file=@/path/to/myvoice.json"
⁠Listing available voices
curl http://trogdor:8030/v1/styles | jq '.styles[].name'

Returns all voices — both built-in (M1–M5, F1–F5) and any imported custom voices.


⁠Built-in voices

VoiceCharacterBest for
M1Lively, upbeat malePromotional videos, casual narration
M2Deep, serious maleCorporate content, documentaries
M3Polished, authoritative maleBusiness presentations, high-trust narration
M4Soft, friendly maleEducational content, onboarding guides
M5Warm, soft-spoken maleAudiobooks, relaxation, bedtime stories
F1Calm, composed femaleCustomer service, guided instructions
F2Bright, cheerful femaleYouth content, playful ads
F3Clear, announcer-style femaleCommercials, news narration
F4Crisp, confident femaleBusiness explainers, pitch decks
F5Kind, gentle femaleAudiobooks, wellness content

⁠API Reference

⁠Health check
curl http://trogdor:8030/v1/health
{
  "status": "ok",
  "model": "supertonic-3",
  "sample_rate": 44100,
  "version": "1.3.1",
  "voices_loaded": 12
}
⁠List voices
curl http://trogdor:8030/v1/styles | jq '.styles[] | {name: .name, gender: .gender}'
⁠Synthesise speech — OpenAI-compatible endpoint
curl -X POST http://trogdor:8030/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{
    "model": "supertonic-3",
    "input": "Hello, this is a test of the Supertonic TTS system.",
    "voice": "F1",
    "response_format": "wav"
  }' \
  --output test.wav

Request fields:

FieldTypeDefaultDescription
modelstring—Any value accepted (supertonic-3, tts-1, etc.)
inputstring—Text to synthesise. Supports expression tags (see below)
voicestringM1Built-in voice name or custom voice stem from Voice Builder JSON
response_formatstringwavwav, flac, or ogg
speedfloat1.0Playback speed (passed through; see /v1/tts for full control)
⁠Synthesise speech — native endpoint (full control)
curl -X POST http://trogdor:8030/v1/tts \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Supertonic 3 runs fast even on a Raspberry Pi.",
    "voice": "M1",
    "lang": "en",
    "total_steps": 8,
    "speed": 1.05
  }' \
  --output output.wav

Native-only fields:

FieldTypeDefaultDescription
langstringenLanguage code (e.g. en, fr, ja). Use na for language-agnostic mode
total_stepsint8Quality steps: 5 (fast/low) to 12 (slow/high). Default 8 is a good balance
speedfloat1.0Speed multiplier (0.7–2.0)
⁠Expression tags

Inline tags add natural expression to speech. Place them in the input/text field:

{
  "input": "Wait, really? <laugh> I can't believe it! <breath> Okay, let me think about this."
}

Available tags: <laugh>, <breath>, <sigh>, and 7 additional tags. See the Supertonic 3 model card⁠ for the full list.

⁠Batch synthesis
curl -X POST http://trogdor:8030/v1/tts/batch \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {"text": "First sentence.", "voice": "M1", "lang": "en"},
      {"text": "Second sentence.", "voice": "F1", "lang": "en"}
    ]
  }'

Returns up to 64 items as base64-encoded audio per item. See /docs for the full schema.

⁠Import a custom voice at runtime
curl -X POST http://trogdor:8030/v1/styles/import \
  -F "file=@/path/to/myvoice.json"

The voice becomes available immediately without a restart.


⁠Environment variable reference

VariableDefaultDescription
SUPERTONIC_MODELsupertonic-3Model version: supertonic-3 | supertonic-2 | supertonic
CORS_ORIGINS*CORS origins for browser clients. * = allow all
PORT8000Internal container port (do not change unless you know why)
HF_HOME/models/hfHuggingFace hub cache directory
XDG_CACHE_HOME/models/cacheLinux XDG cache directory — supertonic caches ONNX model files and custom voice styles here

⁠Audio output formats

Supertonic 3 natively supports WAV, FLAC, and OGG output. MP3 is not available because the underlying ONNX model outputs 44.1 kHz audio and the libsndfile Opus/MP3 encoders are pinned to standard sample rates (8/16/24/48 kHz). To get MP3, transcode after receipt:

curl -X POST http://trogdor:8030/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"model":"supertonic-3","input":"Hello world","voice":"M1","response_format":"wav"}' \
  | ffmpeg -i pipe:0 -codec:a libmp3lame -q:a 2 output.mp3

⁠Troubleshooting

⁠First start is slow — model not found

Symptom: Long pause before "Server ready" message; or timeout.

Cause: On first run, the container downloads the Supertonic 3 ONNX model files (~200 MB) from Hugging Face. On a fast connection this takes 1–3 minutes; on a slow connection it can take longer.

Fix: Wait. The startup timeout in the entrypoint is 10 minutes. Watch the logs:

docker logs -f supertonic

Once downloaded, the model is cached in /models/cache/ and subsequent starts are fast.

⁠Voice import fails at startup

Symptom: ✗ Failed: myvoice in the startup log.

Cause A: The JSON file is a Supertonic 2 export, not a Supertonic 3 export. They are not interchangeable — download the correct version from My Page on Voice Builder.

Cause B: The voice name conflicts with a built-in voice (M1–M5, F1–F5). Rename the JSON file to avoid these names.

Fix: Check that the JSON was downloaded as the Supertonic 3 variant, rename if needed, and restart the container.

⁠CORS errors in browser — "Failed to fetch"

Symptom: API calls from a locally-opened HTML file return "Failed to fetch".

Fix: Ensure CORS_ORIGINS=* is set in the container environment (the default). This is passed to supertonic serve --cors "*" which enables the CORS middleware in the built-in FastAPI server.

⁠Audio has clicks or artefacts

Cause: total_steps is too low. The default of 8 is a good balance; increase to 10–12 for higher quality at the cost of speed.

Use the native /v1/tts endpoint to set total_steps directly:

curl -X POST http://trogdor:8030/v1/tts \
  -d '{"text":"Hello","voice":"M1","lang":"en","total_steps":12}' \
  --output output.wav
⁠Speech is too fast or too slow

Use the speed parameter (0.7 = slow, 1.0 = normal, 2.0 = fast):

{"model":"supertonic-3","input":"Hello","voice":"M1","speed":0.85}

⁠Sharing the voice library with Fish Speech and Higgs Audio

All three containers can share the same host /mnt/user/ai/voices/ directory:

# Fish Speech
- /mnt/user/ai/voices:/reference_voices:ro

# Higgs Audio
- /mnt/user/ai/voices:/reference_voices:ro

# Supertonic
- /mnt/user/ai/voices:/reference_voices:ro

Each service only reads the file types it understands:

File typeUsed by
NAME.wav + NAME.txtFish Speech (pre-encoded), Higgs Audio (zero-shot cloning)
NAME.json (Voice Builder export)Supertonic
NAME.s2voiceFish Speech internal profile (ignored by others)

There is no conflict — the extra files are silently ignored.


⁠Interactive API docs

Once running, the full interactive API documentation is available at:

http://[UNRAID_IP]:8030/docs

This Swagger UI lets you test all endpoints directly from the browser, including voice listing, synthesis, and voice import.

Tag summary

Content type

Image

Digest

sha256:5471d9cf2…

Size

114.4 MB

Last updated

3 months ago

docker pull k8bit/supertonic