# Text to Speech

> Ubah teks menjadi suara neural yang natural: 300+ voice dalam 70+ bahasa, termasuk Indonesia, Jawa, dan Sunda.

Ubah teks (maks. 5.000 karakter) menjadi audio MP3 dengan suara neural Microsoft Edge. Pilih dari 300+ voice dalam 70+ bahasa - termasuk Indonesia (Gadis, Ardi), Jawa, dan Sunda - lalu atur kecepatan, nada, dan volume. Hasilnya berkas audio/mpeg siap putar, atau amplop JSON base64 lengkap dengan waktu per kata dan subtitle SRT. Tersedia dua server (Server 1 bawaan dan Server 2) yang bisa dipilih bebas lewat field server; teks panjang dipecah otomatis per kalimat dan audionya disambung kembali.

- Base URL: `https://api.apipedia.id/v1/tts`
- Autentikasi: `Authorization: Bearer apk_…` (token dari console.apipedia.id)
- Kategori: AI
- Halaman: https://apipedia.id/docs/text-to-speech
- OpenAPI: https://console.apipedia.id/openapi/text-to-speech.yaml

Semua respons memakai amplop `{ "is_success", "message", "data" }` kecuali disebutkan lain. Kode error umum: lihat https://apipedia.id/docs#kode-status-error.

## Endpoint (3)

- `POST /`: Ubah teks menjadi audio MP3
- `GET /servers`: Daftar server Text to Speech
- `GET /voices`: Daftar voice Text to Speech

### Ubah teks menjadi audio MP3

`POST https://api.apipedia.id/v1/tts`

Mengubah teks menjadi suara neural (mesin Microsoft Edge TTS) dalam format MP3 24 kHz mono.

Body: `text` wajib, maks 5.000 karakter (teks panjang dipecah otomatis per kalimat dan audionya disambung); `voice` opsional, bawaan `id-ID-GadisNeural` (perempuan; `id-ID-ArdiNeural` laki-laki; daftar lengkap di GET /tts/voices); `rate` kecepatan -50 sampai 100 (persen relatif), `pitch` nada -50 sampai 50 (Hz relatif), `volume` -50 sampai 50 (persen relatif) — ketiganya menerima angka (`10`) atau teks (`"+10%"`, `"-5Hz"`), bawaan 0; `bitrate` `48` (bawaan) atau `96` kbps.

**Memilih server.** Ada dua server TTS: `server: 1` (bawaan) dan `server: 2`. Keduanya menghasilkan suara yang sama; bedanya hanya jalur jaringannya. Server yang dipakai selalu yang Anda minta — tidak ada perpindahan otomatis — dan tercantum di header `X-TTS-Server` (atau field `data.server`). Bila satu server menjawab 502/503/504, ulangi dengan server lainnya. Status tiap server ada di GET /tts/servers. `server` boleh dikirim di body atau sebagai query `?server=2`.

**Bentuk jawaban** (`output`, di body atau query):
- `audio` (bawaan): berkas `audio/mpeg` mentah, siap disimpan sebagai `.mp3` atau diputar langsung.
- `base64`: amplop JSON berisi `base64`, `size`, `voice`, `server`. Dengan `subtitles: true` (hanya pada output base64) ditambah `words` (waktu mulai/selesai tiap kata dalam milidetik) dan `srt` (subtitle siap pakai, 10 kata per baris).

Jawaban tidak pernah dicache (`Cache-Control: no-store`). Error: 400 masukan tidak valid; 502 server TTS gagal menyintesis (mis. nama voice tidak dikenal); 503 server yang dipilih sedang tidak tersedia atau sibuk (pesannya menyebut server lain yang bisa dicoba); 504 melewati batas waktu.

| Parameter | Lokasi | Tipe | Wajib | Keterangan |
|---|---|---|---|---|
| `output` | query | string | tidak | `audio` (bawaan, berkas audio/mpeg) atau `base64` (amplop JSON). Boleh juga dikirim di body. Pilihan: `audio`, `base64`. Default `audio`. |
| `server` | query | string | tidak | Server TTS: `1` (bawaan) atau `2`. Boleh juga dikirim di body. Pilihan: `1`, `2`. Default `1`. |

Body (`application/json`, wajib):

```json
{
  "text": "Halo, selamat datang di APIPedia. Ini contoh suara dari API Text to Speech.",
  "voice": "id-ID-GadisNeural",
  "rate": 0,
  "pitch": 0,
  "volume": 0,
  "bitrate": 48,
  "server": 1,
  "subtitles": true
}
```

Contoh request:

```bash
curl -X POST "https://api.apipedia.id/v1/tts?output=base64&server=1" \
  -H "Authorization: Bearer apk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"text":"Halo, selamat datang di APIPedia. Ini contoh suara dari API Text to Speech.","voice":"id-ID-GadisNeural","rate":0,"pitch":0,"volume":0,"bitrate":48,"server":1,"subtitles":true}'
```

Contoh respons (200):

```json
{
  "is_success": true,
  "message": "Audio berhasil dibuat.",
  "data": {
    "server": 1,
    "voice": "id-ID-GadisNeural",
    "format": "mp3",
    "contentType": "audio/mpeg",
    "bitrate": 48,
    "size": 38880,
    "characters": 75,
    "base64": "//NkxAAAAAANIAAAAAExBTUUzLjEwMFVVVVVVVVVVVVVV...",
    "words": [
      {
        "text": "Halo",
        "startMs": 100,
        "endMs": 512
      },
      {
        "text": "selamat",
        "startMs": 750,
        "endMs": 1187
      },
      {
        "text": "datang",
        "startMs": 1200,
        "endMs": 1562
      }
    ],
    "srt": "1\n00:00:00,100 --> 00:00:03,450\nHalo selamat datang di APIPedia Ini contoh suara dari API\n\n2\n00:00:03,462 --> 00:00:04,900\nText to Speech\n"
  }
}
```

Error khusus endpoint ini:

- **503**: Server yang dipilih sedang tidak tersedia atau antreannya penuh. Header `Retry-After: 60`; pesannya menyebut server lain yang bisa dicoba (`Server 2 sedang tidak tersedia. Coba "server": 1.`)

### Daftar server Text to Speech

`GET https://api.apipedia.id/v1/tts/servers`

Daftar server TTS yang bisa dipilih lewat field `server` POST /tts. `default: true` menandai server yang dipakai bila `server` tidak dikirim; `available: false` berarti server itu sedang dimatikan dan permintaan ke sana dijawab 503. Kedua server menghasilkan suara yang sama — pilih bebas, dan pindah ke server lain bila salah satunya lambat atau gagal.

Contoh request:

```bash
curl -X GET "https://api.apipedia.id/v1/tts/servers" \
  -H "Authorization: Bearer apk_xxxxxxxxxxxxxxxx"
```

Contoh respons (200):

```json
{
  "is_success": true,
  "message": "2 dari 2 server tersedia.",
  "data": {
    "defaultServer": 1,
    "servers": [
      {
        "id": 1,
        "name": "Server 1",
        "default": true,
        "available": true
      },
      {
        "id": 2,
        "name": "Server 2",
        "default": false,
        "available": true
      }
    ],
    "note": "Pilih server lewat field \"server\" (1 atau 2) pada POST /v1/tts. Kedua server menghasilkan suara yang sama; pindah server bila salah satunya lambat atau gagal."
  }
}
```

### Daftar voice Text to Speech

`GET https://api.apipedia.id/v1/tts/voices`

Daftar voice yang bisa dipakai di field `voice` POST /tts: nama (`name`), locale, gender, nama tampilan, serta kategori dan karakter suaranya. Saring dengan `locale` (kode bahasa `id` cocok dengan semua `id-*`; locale penuh `en-US` hanya cocok dengan dirinya), `gender` (`Male`/`Female`), dan `q` (kata kunci pada nama). Daftar di-cache 12 jam di server; jawaban juga memuat `servers` dan batas masukan.

| Parameter | Lokasi | Tipe | Wajib | Keterangan |
|---|---|---|---|---|
| `locale` | query | string | tidak | Kode bahasa (`id`, `jv`, `su`, `en`) atau locale penuh (`id-ID`, `en-US`). |
| `gender` | query | string | tidak | `Male` atau `Female`. Pilihan: `Male`, `Female`. |
| `q` | query | string | tidak | Kata kunci pada nama voice, mis. `gadis` atau `multilingual`. |

Contoh request:

```bash
curl -X GET "https://api.apipedia.id/v1/tts/voices?locale=id&gender=Female&q=gadis" \
  -H "Authorization: Bearer apk_xxxxxxxxxxxxxxxx"
```

Contoh respons (200):

```json
{
  "is_success": true,
  "message": "1 voice ditemukan.",
  "data": {
    "count": 1,
    "total": 322,
    "defaultVoice": "id-ID-GadisNeural",
    "servers": [
      {
        "id": 1,
        "name": "Server 1",
        "default": true,
        "available": true
      },
      {
        "id": 2,
        "name": "Server 2",
        "default": false,
        "available": true
      }
    ],
    "voices": [
      {
        "name": "id-ID-GadisNeural",
        "locale": "id-ID",
        "gender": "Female",
        "displayName": "Gadis - Indonesian (Indonesia)",
        "categories": [
          "General"
        ],
        "personalities": [
          "Friendly",
          "Positive"
        ]
      }
    ],
    "limits": {
      "maxChars": 5000,
      "bitrates": [
        48,
        96
      ],
      "rate": [
        -50,
        100
      ],
      "pitch": [
        -50,
        50
      ],
      "volume": [
        -50,
        50
      ]
    }
  }
}
```
