# Eapil-Voice API Reference

## Defaults

- Base URL: `https://ades.playones.com`
- Override env: `QWEN3_VOICE_API_BASE_URL`
- API key env: `OPENAI_API_KEY`
- Auth header: `Authorization: Bearer <key>`
- If no key is available, get one from `https://kinfo.playones.com`.
- Audio-output media type: `audio/wav`
- Local source checkouts are source references only unless the user explicitly asks to run a local service.

## Endpoint Summary

| Task | Method | Path | Input | Output |
| --- | --- | --- | --- | --- |
| Voice design TTS | `POST` | `/v1/voice/design` | JSON | WAV |
| Base TTS synthesis | `POST` | `/v1/voice/synthesize` | JSON | WAV |
| Voice clone | `POST` | `/v1/voice/clone` | multipart form | WAV |
| Speech enhancement | `POST` | `/v1/audio/enhance` | multipart form | WAV |
| Denoise alias | `POST` | `/v1/audio/denoise` | multipart form | WAV |
| ASR transcription | `POST` | `/v1/asr/transcribe` | multipart form | JSON |
| Health | `GET` | `/health` | none | JSON |
| Models | `GET` | `/models` | none | JSON |

## Parameter Limits

- `provider`: `qwen` or `voxcpm2`
- `text`: 1 to 4096 characters
- `instruct`: 1 to 1024 characters; optional for clone
- `temperature`: 0 to 2
- `max_tokens`: 1 to 8192
- `top_k`: 0 to 1000
- `top_p`: 0 to 1
- `repetition_penalty`: 0.1 to 2
- `cfg_value`: 0 to 10
- `inference_timesteps`: 1 to 200
- Uploaded audio defaults to a 25 MB and 60 second server-side limit, depending on deployment environment variables.

## Voice Design

`POST /v1/voice/design`

Use this for text-to-speech driven by a style instruction. Body is JSON.

Required:
- `text`: text to speak
- `instruct`: style, emotion, voice, or delivery instruction

Common optional fields:
- `provider`: `qwen` default, or `voxcpm2`
- `language`: `auto` default, used by Qwen
- `temperature`: `0.9` default, used by Qwen
- `max_tokens`: `4096` default, used by Qwen
- `top_k`: `50` default, used by Qwen
- `top_p`: `1.0` default, used by Qwen
- `repetition_penalty`: `1.05` default, used by Qwen
- `cfg_value`: `2.0` default, used by VoxCPM2
- `inference_timesteps`: `10` default, used by VoxCPM2
- `normalize`: `false` default, used by VoxCPM2
- `denoise`: `false` default, used by VoxCPM2
- `retry_badcase`: `true` default, used by VoxCPM2

Qwen example:

```bash
curl -X POST https://ades.playones.com/v1/voice/design \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "provider": "qwen",
    "text": "Hello world",
    "instruct": "Warm, calm, natural narration",
    "language": "auto",
    "temperature": 0.9,
    "max_tokens": 4096,
    "top_k": 50,
    "top_p": 1.0,
    "repetition_penalty": 1.05
  }' \
  --output voice_design.wav
```

VoxCPM2 example:

```bash
curl -X POST https://ades.playones.com/v1/voice/design \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Hello world",
    "instruct": "Warm, calm, natural narration",
    "provider": "voxcpm2",
    "cfg_value": 2.0,
    "inference_timesteps": 10,
    "normalize": false,
    "denoise": false,
    "retry_badcase": true
  }' \
  --output voxcpm2_voice_design.wav
```

## Base TTS Synthesis

`POST /v1/voice/synthesize`

Use this for base Qwen TTS with an optional named speaker. Body is JSON. This endpoint does not accept `provider`.

Required:
- `text`

Optional:
- `speaker`: e.g. `Chelsie`; omit for model default
- `language`: `auto` default
- `temperature`: `0.9` default
- `max_tokens`: `4096` default
- `top_k`: `50` default
- `top_p`: `1.0` default
- `repetition_penalty`: `1.05` default

Example:

```bash
curl -X POST https://ades.playones.com/v1/voice/synthesize \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Hello world",
    "speaker": "Chelsie",
    "language": "auto",
    "temperature": 0.9,
    "max_tokens": 4096,
    "top_k": 50,
    "top_p": 1.0,
    "repetition_penalty": 1.05
  }' \
  --output synthesize.wav
```

## Voice Clone

`POST /v1/voice/clone`

Use this for cloning from reference audio. Send multipart form upload with `file=@reference.wav`.

Audio input:
- `file`: reference audio upload

Shared fields:
- `text`: required output text
- `provider`: `qwen` default, or `voxcpm2`
- `language`: `auto` default, used by Qwen

Qwen required fields:
- `text`
- `ref_text`: transcript of the reference audio
- `file`

Qwen optional fields:
- `temperature`: default `0.9`
- `max_tokens`: default `4096`
- `top_k`: default `50`
- `top_p`: default `1.0`
- `repetition_penalty`: default `1.05`

VoxCPM2 required fields:
- `text`
- `file`
- `provider=voxcpm2`

VoxCPM2 optional fields:
- `ref_text`: when present, enables transcript-guided Hi-Fi clone
- `instruct`: used only when `ref_text` is absent
- `cfg_value`: default `2.0`
- `inference_timesteps`: default `10`
- `normalize`: default `false`
- `denoise`: default `false`
- `retry_badcase`: default `true`

Qwen clone example:

```bash
curl -X POST https://ades.playones.com/v1/voice/clone \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -F 'file=@reference.wav' \
  -F 'provider=qwen' \
  -F 'text=This is the cloned sentence.' \
  -F 'ref_text=This is the transcript of the reference audio.' \
  -F 'language=auto' \
  -F 'temperature=0.9' \
  -F 'max_tokens=4096' \
  -F 'top_k=50' \
  -F 'top_p=1.0' \
  -F 'repetition_penalty=1.05' \
  --output voice_clone.wav
```

VoxCPM2 controllable clone without transcript:

```bash
curl -X POST https://ades.playones.com/v1/voice/clone \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -F 'file=@reference.wav' \
  -F 'text=This is the cloned sentence.' \
  -F 'instruct=Keep the same speaker identity with a calm delivery.' \
  -F 'provider=voxcpm2' \
  -F 'cfg_value=2.0' \
  -F 'inference_timesteps=10' \
  -F 'normalize=false' \
  -F 'denoise=false' \
  -F 'retry_badcase=true' \
  --output voxcpm2_controllable_clone.wav
```

VoxCPM2 Hi-Fi clone with transcript:

```bash
curl -X POST https://ades.playones.com/v1/voice/clone \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -F 'file=@reference.wav' \
  -F 'text=This is the cloned sentence.' \
  -F 'ref_text=This is the transcript of the reference audio.' \
  -F 'provider=voxcpm2' \
  -F 'cfg_value=2.0' \
  -F 'inference_timesteps=10' \
  -F 'normalize=false' \
  -F 'denoise=false' \
  -F 'retry_badcase=true' \
  --output voxcpm2_hifi_clone.wav
```

## Speech Enhancement And Denoise

`POST /v1/audio/enhance`

`POST /v1/audio/denoise`

These two paths call the same service and return `enhanced.wav`. Send multipart form upload with `file=@noisy.wav`.

Optional:
- `chunked`: form or query bool. Accepted truthy values include `1`, `true`, `yes`, `on`; falsy values include `0`, `false`, `no`, `off`.

Example:

```bash
curl -X POST https://ades.playones.com/v1/audio/enhance \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -F 'file=@noisy.wav' \
  -F 'chunked=false' \
  --output enhanced.wav
```

Denoise alias:

```bash
curl -X POST https://ades.playones.com/v1/audio/denoise \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -F 'file=@noisy.wav' \
  -F 'chunked=false' \
  --output denoise.wav
```

## ASR Transcription

`POST /v1/asr/transcribe`

This is not audio generation. It returns JSON:

```json
{
  "text": "...",
  "segments": [],
  "language": "English",
  "prompt_tokens": 0,
  "generation_tokens": 0,
  "total_tokens": 0,
  "prompt_tps": 0,
  "generation_tps": 0,
  "total_time": 0
}
```

Input is multipart form upload with `file=@speech.wav`.

Optional fields can be form or query params:
- `language`: normalized aliases include `zh`, `zh-cn`, `en`, `ja`, `ko`; default is `English`
- `temperature`: default `0.0`
- `max_tokens`: default `8192`
- `top_k`: default `0`
- `top_p`: default `1.0`
- `repetition_penalty`: default omitted

Example:

```bash
curl -X POST https://ades.playones.com/v1/asr/transcribe \
  -H 'Authorization: Bearer $OPENAI_API_KEY' \
  -F 'file=@speech.wav' \
  -F 'language=auto' \
  -F 'temperature=0.0' \
  -F 'max_tokens=8192' \
  -F 'top_k=0' \
  -F 'top_p=1.0'
```

## Health And Models

```bash
curl -H 'Authorization: Bearer $OPENAI_API_KEY' https://ades.playones.com/health
curl -H 'Authorization: Bearer $OPENAI_API_KEY' https://ades.playones.com/models
```

Model status keys:
- `voice_design_tts`
- `base_tts`
- `asr`
- `speech_enhancement`
- `voxcpm2`

Models are lazy-loaded on first request, so `loaded: false` can be normal before use.

## Errors And Troubleshooting

- `401 unauthorized`: the request lacks a valid `Authorization: Bearer <key>`. Use `OPENAI_API_KEY`, pass `--token`, or get a key from `https://kinfo.playones.com`.
- `400 provider must be one of: qwen, voxcpm2`: invalid or empty provider.
- `400 audio file is required`: missing audio input for enhancement or ASR.
- `400 reference audio file is required`: missing clone reference audio.
- `400 text and ref_text are required`: Qwen clone requires both.
- `400 text is required`: VoxCPM2 clone requires `text`.
- `400 denoise=true requires VOXCPM2_LOAD_DENOISER=true`: retry with `denoise=false` or reconfigure server.
- `501 VOXCPM2_BACKEND=vllm_omni is not implemented in this build`: local ARM Mac path supports `official`.
- `503 failed to load ... model`: model package, model id, local weights, or optional `voxcpm` dependency is unavailable.
- `504 Gateway Time-out`: the request passed HTTP validation but generation exceeded the gateway timeout. Retry after model warmup, reduce `max_tokens` for short test requests, or inspect server logs.
- `500 Internal Server Error`: the request reached the application but failed internally. Re-run with `curl -i` and no `--output` to capture the response body; if the body is only `Internal Server Error`, inspect server logs.

## Environment Variables

Server-side:

```env
OPENAI_API_KEY=your_key_here
TTS_MODEL_ID=mlx-community/Qwen3-TTS-12Hz-1.7B-VoiceDesign-bf16
BASE_TTS_MODEL_ID=mlx-community/Qwen3-TTS-12Hz-0.6B-Base-8bit
ASR_MODEL_ID=mlx-community/Qwen3-ASR-1.7B-8bit
SE_MODEL_ID=starkdmi/MossFormer2_SE_48K_MLX
SE_MODEL_PRECISION=int8
VOXCPM2_MODEL_ID=openbmb/VoxCPM2
VOXCPM2_BACKEND=official
VOXCPM2_LOAD_DENOISER=false
VOXCPM2_DEVICE=auto
VOXCPM2_OPTIMIZE=true
```

Client-side convenience:

```env
QWEN3_VOICE_API_BASE_URL=https://ades.playones.com
OPENAI_API_KEY=your_key_here
```
