Skip to content

OpenAI Audio API

mlxcel implements the OpenAI-compatible speech, transcription, and translation routes. Audio checkpoints occupy a dedicated audio-only server process: use Whisper for speech-to-text (STT) or Kokoro for text-to-speech (TTS), and run a separate process for chat or text generation.

Endpoints

Method Path Capability
POST /v1/audio/speech Kokoro text-to-speech; JSON in, WAV out
POST /v1/audio/transcriptions Whisper speech-to-text
POST /v1/audio/translations Whisper speech-to-English translation

Each route also has an alias with the /v1 prefix removed, such as /audio/speech.

If the loaded checkpoint does not provide the requested capability, the route returns HTTP 501 after validating the request.

Nemotron VoiceChat, a full-duplex speech-to-speech model, does not use these routes. It is served over a WebSocket; see Realtime VoiceChat API.

Starting an Audio Server

Whisper STT

The checkpoint must declare model_type: "whisper" and contain config.json, tokenizer.json, and SafeTensors weights. Native MLX and Hugging Face WhisperForConditionalGeneration key layouts are accepted.

mlxcel-server -m ./models/whisper-base

Input is currently WAV only. mlxcel converts PCM16 or float32 audio to mono, resamples it to 16 kHz, and splits audio longer than 30 seconds into consecutive windows. Whisper currently supports non-quantized fp16/f32 checkpoints and greedy decoding; beam search, timestamps, VAD chunking, MP3, and FLAC are not available.

Kokoro TTS

Kokoro is detected from the istftnet configuration block or kokoro-v1_0.safetensors. The directory must contain config.json, the Kokoro weights, and voices/*.safetensors voice packs. A Kokoro checkpoint needs no tokenizer file, because the phoneme vocabulary comes from config.json; /tokenize, /detokenize, and /apply-template answer 501 on such a server, like the generation routes. If the checkpoint cannot be loaded, for example because vocab or a weight file is missing, the server exits at startup instead of running without a TTS slot.

mlxcel-server -m ./models/kokoro-82m

The default voice is af_heart. A safe voice name selects voices/<name>.safetensors; unknown or unsafe names fall back to the default. The built-in grapheme-to-phoneme front end is American English. Input is truncated at 4,096 characters and the acoustic model consumes at most 510 phoneme tokens. WAV is the only output format.

Text-to-Speech

curl -s http://localhost:8080/v1/audio/speech \
  -H 'Content-Type: application/json' \
  -d '{"model":"kokoro","input":"Hello from mlxcel.","voice":"af_heart","speed":1.0,"response_format":"wav"}' \
  --output speech.wav
JSON field Required Default Description
model yes - API compatibility identifier; the loaded server checkpoint is used
input yes - Text to synthesize
voice no af_heart Kokoro voice-pack name
response_format no wav Only wav is accepted
speed no 1.0 Positive finite duration scale; values above 1 produce faster speech

A successful response is audio/wav with a PCM16 RIFF body.

Transcription and Translation

Both routes accept multipart/form-data:

curl -s http://localhost:8080/v1/audio/transcriptions \
  -F file=@recording.wav \
  -F model=whisper \
  -F language=ko \
  -F response_format=json
Multipart field Required Default Description
file yes - WAV audio, up to 25 MiB
model no - Compatibility identifier forwarded to the provider
language no auto ISO 639-1 source-language hint
response_format no json json, text, or verbose_json
temperature no provider default Finite floating-point sampling temperature

json returns {"text":"..."}. text returns plain UTF-8. verbose_json adds language and duration when available. The translation route uses the same request and response formats but asks Whisper for English output.

Admission Controls

Audio work is serialized through one MLX-owning worker thread. These server options bound memory use and wait time:

CLI option Environment variable Default Effect
--audio-queue-depth <N> MLXCEL_AUDIO_QUEUE_DEPTH 8 Maximum waiting audio commands; a full queue returns 503
--audio-request-timeout-secs <N> MLXCEL_AUDIO_REQUEST_TIMEOUT_SECS 120 Caller wait timeout; expiry returns 504 but does not cancel work already running

At the defaults, queued STT payloads can retain roughly 200 MiB plus the in-flight request, because each upload can be 25 MiB.

Errors and Limits

Status Meaning
400 Malformed JSON/multipart, missing file, unsupported format, or invalid audio
413 Upload exceeds 25 MiB
500 Server-side failure (server_error): the audio worker panicked, inference failed, or the response could not be built
501 The loaded checkpoint does not provide STT or TTS
503 Audio queue or generation admission queue is full
504 Audio worker response timeout

Bearer authentication, when configured, applies to audio routes just as it does to other API endpoints.