> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gradium.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Voice Localization

> Adaptez une voix existante à une autre langue ou à un autre accent

<Note>
  Voice Localization est disponible uniquement via l'API.
  Écoutez chaque candidat avant de l'enregistrer comme voix permanente.
</Note>

Choisissez une voix phare, un clone ou une voix conçue avec Voice Design, puis
sélectionnez une langue et un accent cibles. Voice Localization génère des
candidats que vous pouvez écouter puis enregistrer dans votre bibliothèque de voix.

<CardGroup cols={2}>
  <Card title="Vous partez d'une description ?" icon="wand-magic-sparkles" href="/fr/guides/voices/voice-design">
    Voice Design crée une nouvelle voix à partir d'un texte descriptif. La localisation modifie une voix que vous possédez déjà.
  </Card>

  <Card title="Vous partez d'un enregistrement ?" icon="microphone" href="/fr/guides/voices/custom-voices">
    Clonez d'abord le locuteur, puis localisez le clone.
  </Card>
</CardGroup>

## Fonctionnement

<CardGroup cols={2}>
  <Card title="1. Choisir une source" icon="user">
    Une voix phare, l'un de vos clones ou un candidat Voice Design.
  </Card>

  <Card title="2. Localiser" icon="language">
    Choisissez une langue cible et un accent pour générer des candidats.
  </Card>

  <Card title="3. Écouter" icon="headphones">
    Écoutez chaque candidat sur une phrase de synthèse vocale (TTS) dans la langue cible.
  </Card>

  <Card title="4. Convertir" icon="bookmark">
    Enregistrez un candidat comme voix permanente dans votre bibliothèque.
  </Card>
</CardGroup>

Chaque requête crée `n_samples` candidats sans modifier la source.
Un candidat est une voix temporaire dotée d'un ID `vox_emb_`. Écoutez-le avec la
synthèse vocale REST, puis utilisez `POST /voices/from-embedding` pour l'enregistrer
comme voix permanente. Le champ `uid` de la réponse est le `voice_id` à utiliser
avec REST, WebSocket et Speech-to-Speech. Les candidats non enregistrés expirent
au bout de 30 jours.

Pour ne changer que l'accent, conservez la langue source comme `target_language`
et choisissez un autre accent. Par exemple, utilisez `en` et `Australian` pour une
source en anglais britannique.

## Accès

URL de base `https://api.gradium.ai/api`, clé API dans l'en-tête `x-api-key`.

| Appel | Endpoint |
| :- | :- |
| Lister les accents disponibles | `GET /voice-generator/available-accents` |
| Localiser une voix | `POST /voice-generator/localize` |
| Vérifier la disponibilité ou lister les candidats | `GET /voice-generator/embeddings` |
| Écouter un candidat | `POST /post/speech/tts` |
| Convertir un candidat | `POST /voices/from-embedding` |
| Supprimer un candidat | `DELETE /voice-generator/embeddings/{embedding_id}` |

## Démarrage rapide

Cet exemple localise un clone français en anglais américain. Définissez
`GRADIUM_API_KEY` et `SOURCE` dans votre environnement. `SOURCE` peut être une
voix ou un candidat prêt qui vous appartient, ou l'ID d'une voix phare. Les
exemples shell nécessitent `jq` ; les exemples Python nécessitent `requests`.
Exécutez les étapes dans l'ordre, dans un seul langage.

<Steps>
  <Step title="Lister les accents">
    ```bash cURL theme={null}
    curl --fail --silent --show-error --max-time 30 -H "x-api-key: $GRADIUM_API_KEY" \
      https://api.gradium.ai/api/voice-generator/available-accents
    ```

    ```json 200 OK (abbreviated) theme={null}
    {
      "languages": {
        "en": ["General American", "Standard British", "Irish", "..."],
        "fr": ["General French", "Quebecois French"],
        "...": ["..."]
      }
    }
    ```

    Lisez la liste depuis cet endpoint à l'exécution plutôt que de la recopier
    depuis cette documentation : elle va s'allonger. Vous pouvez la mettre en
    cache. Le premier accent de chaque langue est utilisé par défaut lorsqu'une
    requête omet `accent`. Orthographiez les accents tels qu'ils sont listés ;
    la correspondance ignore la casse et les espaces en début et en fin, mais
    « British », « Quebecois » ou « Québécois French » sont refusés.
  </Step>

  <Step title="Localiser la voix">
    <CodeGroup>
      ```bash cURL theme={null}
      curl --fail --silent --show-error --max-time 30 -X POST https://api.gradium.ai/api/voice-generator/localize \
        -H "x-api-key: $GRADIUM_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{
          \"src_voice\": \"$SOURCE\",
          \"target_language\": \"en\",
          \"accent\": \"General American\",
          \"gender\": \"female\",
          \"n_samples\": 2
        }" > candidates.json

      CAND0=$(jq -r '.embeddings[0].embedding_id' candidates.json)
      ```

      ```python Python theme={null}
      import os
      import requests

      API_KEY = os.environ["GRADIUM_API_KEY"]
      BASE = "https://api.gradium.ai/api"
      SOURCE = os.environ["SOURCE"]  # a voice id or a vox_emb_ candidate id

      resp = requests.post(
          f"{BASE}/voice-generator/localize",
          json={
              "src_voice": SOURCE,
              "target_language": "en",
              "accent": "General American",
              "gender": "female",
              "n_samples": 2,
          },
          headers={"x-api-key": API_KEY},
          timeout=30,
      )
      resp.raise_for_status()
      candidates = [e["embedding_id"] for e in resp.json()["embeddings"]]
      ```
    </CodeGroup>

    ```json 201 Created theme={null}
    {
      "embeddings": [
        { "embedding_id": "vox_emb_XeBcXDgoigTfL9Cv", "ready": false, "expires_at": "2026-10-21T13:03:52Z" },
        { "embedding_id": "vox_emb_ni8lehVHTb35siXI", "ready": false, "expires_at": "2026-10-21T13:03:53Z" }
      ]
    }
    ```

    | Champ | Obligatoire | Description |
    | :- | :- | :- |
    | `src_voice` | obligatoire | Un ID de voix (votre clone, un candidat converti ou une voix phare) ou un ID de candidat `vox_emb_`. |
    | `target_language` | obligatoire | `en`, `fr`, `es`, `pt` ou `de`. Peut être identique à la langue source pour un changement d'accent. |
    | `accent` | facultatif | L'un des accents listés pour `target_language`. Par défaut, le premier. |
    | `gender` | facultatif | `male` ou `female`. Voir [Genre](#genre). |
    | `n_samples` | facultatif | De 1 à 5 candidats, 1 par défaut. |

    La requête est vérifiée avant toute mise en file d'attente : un accent
    invalide, une source inconnue ou une source impossible à localiser échoue
    dès cette étape avec `422`, `404` ou `409`, et rien n'est facturé.
  </Step>

  <Step title="Attendre les candidats">
    <CodeGroup>
      ```bash cURL theme={null}
      wait_for_candidate() {
        local deadline=$((SECONDS + 120))
        local result
        while (( SECONDS < deadline )); do
          result=$(curl --fail --silent --show-error --max-time 10 \
            -H "x-api-key: $GRADIUM_API_KEY" \
            "https://api.gradium.ai/api/voice-generator/embeddings?embedding_id=$1") || return 1
          if ! jq -e '.embeddings | length > 0' <<< "$result" > /dev/null; then
            echo "Candidate not found: $1" >&2
            return 1
          fi
          if jq -e '.embeddings[0].ready' <<< "$result" > /dev/null; then
            return 0
          fi
          sleep 2
        done
        echo "Timed out waiting for candidate: $1" >&2
        return 1
      }
      wait_for_candidate "$CAND0"
      ```

      ```python Python theme={null}
      import time

      def wait_until_ready(embedding_id, timeout_s=120):
          deadline = time.monotonic() + timeout_s
          while time.monotonic() < deadline:
              resp = requests.get(
                  f"{BASE}/voice-generator/embeddings",
                  params={"embedding_id": embedding_id},
                  headers={"x-api-key": API_KEY},
                  timeout=min(10, max(0.1, deadline - time.monotonic())),
              )
              resp.raise_for_status()
              found = resp.json()["embeddings"]
              if not found:
                  raise RuntimeError(f"candidate {embedding_id} not found")
              if found and found[0]["ready"]:
                  return found[0]
              time.sleep(2)
          raise TimeoutError(embedding_id)

      for embedding_id in candidates:
          wait_until_ready(embedding_id)
      ```
    </CodeGroup>

    ```json 200 OK theme={null}
    {
      "embeddings": [{
        "embedding_id": "vox_emb_XeBcXDgoigTfL9Cv",
        "ready": true,
        "kind": "edit_language",
        "language": "en",
        "created_at": "2026-09-21T13:03:52.591128",
        "expires_at": "2026-10-21T13:03:52.495534",
        "generate_config": null,
        "edit_language_config": {
          "src_voice": "H5oin0KHqRTAxaeL",
          "src_language": "fr",
          "target_language": "en",
          "accent": "General American",
          "gender": "female"
        },
        "enhance_config": null,
        "prompt": "Feminine. General American accent."
      }]
    }
    ```

    Les candidats localisés sont généralement prêts en deux à huit secondes.
    Interrogez l'endpoint jusqu'à ce que `ready` vaille `true` avant de demander
    de l'audio. Un candidat inconnu renvoie une liste `embeddings` vide.
    L'exemple shell attend le premier candidat ; répétez l'opération pour chaque
    autre candidat que vous souhaitez écouter.

    `kind` vaut `edit_language` pour un candidat localisé (`generate` et `enhance`
    pour les autres). L'objet de configuration correspondant, ici
    `edit_language_config`, contient les paramètres de la requête, et `language`
    est la langue cible du candidat. Lisez les objets de configuration plutôt que
    le champ obsolète `prompt`.
  </Step>

  <Step title="Écouter un candidat">
    Passez l'ID du candidat comme `voice_id` sur l'endpoint de synthèse vocale,
    avec un texte **dans la langue cible**.

    <CodeGroup>
      ```bash cURL theme={null}
      curl --fail --silent --show-error --max-time 30 -X POST https://api.gradium.ai/api/post/speech/tts \
        -H "x-api-key: $GRADIUM_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{
          \"text\": \"Hi, this is Constance. Same voice, new language, and hopefully the same personality.\",
          \"voice_id\": \"$CAND0\",
          \"model_name\": \"default\",
          \"output_format\": \"wav\",
          \"only_audio\": true
        }" --output candidate-0.wav
      ```

      ```python Python theme={null}
      resp = requests.post(
          f"{BASE}/post/speech/tts",
          json={
              "text": "Hi, this is Constance. Same voice, new language, and hopefully the same personality.",
              "voice_id": candidates[0],
              "model_name": "default",
              "output_format": "wav",
              "only_audio": True,
          },
          headers={"x-api-key": API_KEY},
          timeout=30,
      )
      resp.raise_for_status()
      with open("candidate-0.wav", "wb") as f:
          f.write(resp.content)
      ```
    </CodeGroup>

    Comparez le candidat avec la source lisant le même texte. Les écoutes de
    candidats passent uniquement par REST et acceptent jusqu'à 300 caractères
    (`400 input text too long` au-delà). Un candidat pas encore prêt renvoie
    `404 Embedding not found` ; un candidat inconnu ou supprimé renvoie `400`.

    <Warning>
      Utilisez un texte dans la langue cible du candidat. Un texte dans une autre
      langue peut donner une mauvaise prononciation. Conservez une voix localisée
      par langue.
    </Warning>
  </Step>

  <Step title="Convertir le candidat en voix">
    La conversion enregistre le candidat comme voix permanente dans votre
    bibliothèque. Utilisez le champ `uid` de la réponse comme `voice_id` pour les
    requêtes de synthèse suivantes.

    <CodeGroup>
      ```bash cURL theme={null}
      curl --fail --silent --show-error --max-time 30 -X POST https://api.gradium.ai/api/voices/from-embedding \
        -H "x-api-key: $GRADIUM_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{
          \"voxium_embedding_id\": \"$CAND0\",
          \"name\": \"Constance EN\",
          \"description\": \"French support voice, localized to General American\"
        }" > voice.json

      VOICE=$(jq -r '.uid' voice.json)
      ```

      ```python Python theme={null}
      resp = requests.post(
          f"{BASE}/voices/from-embedding",
          json={
              "voxium_embedding_id": candidates[0],
              "name": "Constance EN",
              "description": "French support voice, localized to General American",
          },
          headers={"x-api-key": API_KEY},
          timeout=30,
      )
      resp.raise_for_status()
      voice_id = resp.json()["uid"]
      ```
    </CodeGroup>

    ```json 201 Created theme={null}
    {
      "uid": "w0F73K2fcf3X2Vcn",
      "name": "Constance EN",
      "description": "French support voice, localized to General American",
      "filename": "vox_emb_XeBcXDgoigTfL9Cv",
      "start_s": 0.0,
      "is_catalog": false,
      "is_pro_clone": false,
      "language": "en",
      "tags": []
    }
    ```

    La voix enregistrée conserve la `language` cible et peut être localisée à
    nouveau. La conversion est gratuite, occupe un emplacement de voix
    personnalisée et supprime l'expiration du candidat. Enregistrez un candidat
    qui vous plaît : une nouvelle requête produit des résultats différents.
  </Step>
</Steps>

## Exemple complet

Définissez `GRADIUM_API_KEY` et `SOURCE`, puis exécutez cet exemple pour générer
des candidats et des fichiers audio de comparaison dans trois langues. Écoutez
les fichiers avant de choisir les candidats à enregistrer. Chaque voix
enregistrée occupe un emplacement de voix personnalisée.

```python voice_localization.py theme={null}
import os
import time

import requests

BASE_URL = "https://api.gradium.ai/api"
HEADERS = {"x-api-key": os.environ["GRADIUM_API_KEY"]}
SOURCE = os.environ["SOURCE"]

TARGETS = [  # (language, accent, audition line)
    ("en", "General American", "Hi, this is your assistant. How can I help you today?"),
    ("de", "Standard German", "Hallo, hier ist Ihre Assistentin. Wie kann ich Ihnen heute helfen?"),
    ("es", "Mexican Spanish", "Hola, soy tu asistente. ¿En qué puedo ayudarte hoy?"),
]


def check(resp):
    if not resp.ok:
        raise RuntimeError(f"HTTP {resp.status_code}: {resp.text}")
    return resp


def localize(src_voice, language, accent, gender=None, n_samples=1):
    body = {"src_voice": src_voice, "target_language": language, "accent": accent, "n_samples": n_samples}
    if gender:
        body["gender"] = gender
    resp = check(requests.post(f"{BASE_URL}/voice-generator/localize", headers=HEADERS, json=body, timeout=30))
    return [c["embedding_id"] for c in resp.json()["embeddings"]]


def wait_until_ready(candidate_ids, timeout_s=120.0):
    deadline = time.monotonic() + timeout_s
    pending = set(candidate_ids)
    while pending:
        for candidate_id in sorted(pending):
            resp = check(requests.get(
                f"{BASE_URL}/voice-generator/embeddings",
                headers=HEADERS,
                params={"embedding_id": candidate_id},
                timeout=10,
            ))
            embeddings = resp.json()["embeddings"]
            if not embeddings:
                raise RuntimeError(f"candidate {candidate_id} not found")
            if embeddings[0]["ready"]:
                pending.discard(candidate_id)
        if pending:
            if time.monotonic() > deadline:
                raise TimeoutError(f"still not ready: {sorted(pending)}")
            time.sleep(2.0)


def synthesise(voice_id, text, path):
    resp = check(requests.post(
        f"{BASE_URL}/post/speech/tts",
        headers=HEADERS,
        timeout=30,
        json={"text": text, "voice_id": voice_id, "output_format": "wav", "only_audio": True},
    ))
    with open(path, "wb") as f:
        f.write(resp.content)


def convert(candidate_id, name, description=None):
    resp = check(requests.post(
        f"{BASE_URL}/voices/from-embedding",
        headers=HEADERS,
        timeout=30,
        json={"voxium_embedding_id": candidate_id, "name": name, "description": description},
    ))
    return resp.json()["uid"]


if __name__ == "__main__":
    accents = check(requests.get(f"{BASE_URL}/voice-generator/available-accents", headers=HEADERS, timeout=30)).json()["languages"]
    for language, accent, _ in TARGETS:
        assert accent in accents[language], f"{accent} is not an accent for {language}"

    print("[1/4] localizing")
    plan = {language: localize(SOURCE, language, accent)[0] for language, accent, _ in TARGETS}

    print("[2/4] waiting until ready")
    wait_until_ready(plan.values())

    print("[3/4] auditioning")
    for language, accent, line in TARGETS:
        synthesise(plan[language], line, f"candidate-{language}.wav")
        synthesise(SOURCE, line, f"source-{language}.wav")  # the same line without localization
        print(f"      candidate-{language}.wav vs source-{language}.wav  ({accent})")

    print("[4/4] listen to the files, then choose which voices to save")
    for language, accent, _ in TARGETS:
        if input(f"Save the {language} candidate as a permanent voice? [y/N] ").strip().lower() != "y":
            continue
        voice_id = convert(plan[language], f"Assistant {language.upper()}", f"Localized from {SOURCE}: {accent}")
        print(f"      {language}: voice_id={voice_id}")
    print("done")
```

## Choisir un accent

`GET /voice-generator/available-accents` renvoie les accents disponibles,
regroupés par langue, l'accent par défaut en premier. À l'heure où nous écrivons
ces lignes, la liste couvre les cinq langues prises en charge avec deux à six
accents chacune, y compris des variantes régionales comme le français québécois,
l'espagnol mexicain ou l'allemand suisse. Lisez la liste depuis l'endpoint plutôt
que de la coder en dur, et présentez-la à vos utilisateurs sous forme de
sélecteur : les accents en texte libre ne sont pas acceptés. Les accents
régionaux absents de la liste, comme « Bristolian » ou « Texan », relèvent de
[Voice Design](/fr/guides/voices/voice-design), où ils se décrivent dans la
description.

## Genre

Utilisez `gender` pour indiquer `male` ou `female`. Si vous l'omettez :

1. Une voix phare utilise son propre tag de genre.
2. Un candidat reprend le genre avec lequel sa propre localisation a été faite.
3. Sinon, aucun genre n'est spécifié. Les clones ont rarement un tag de genre,
   et les voix converties n'en ont pas : envoyez `gender` pour ces sources.

Vous pouvez demander un genre différent de celui de la source. Écoutez le
résultat pour vérifier qu'il correspond toujours au locuteur souhaité.

## Sources localisables

| Source | Compatible | Remarques |
| :- | :- | :- |
| Voix phare | Oui | N'importe quel ID de la page [Voix phares](/fr/guides/voices/flagship-voices). |
| Clone instantané | Oui, s'il a une langue | Les clones créés sans `language` renvoient `409 The source voice has no language`. Définissez-la une fois avec [`PUT /voices/{voice_id}`](/fr/guides/voices/manage-voices#modifier-une-voix), puis réessayez. La langue doit être celle parlée dans l'enregistrement : un tag erroné est accepté et dégrade discrètement le résultat. |
| Candidat Voice Design ou voix convertie | Oui | Utilisez l'ID `vox_emb_` ou le `voice_id` converti. |
| Candidat localisé | Oui | Les localisations s'enchaînent : un candidat français issu d'une voix anglaise peut être localisé en allemand. Le candidat doit être prêt (`409` sinon). |
| Clone pro | Non | `409 This voice has no embedding the voice generator can edit.` |
| Voix d'un autre compte | Non | `404` opaque. |

## Évaluer les candidats

* Comparez la source et le candidat lisant le même texte dans la langue cible.
  Soyez attentif à la prononciation, à l'accent et au fait de reconnaître encore
  le locuteur.
* Pour comparer uniquement l'accent, conservez la langue source et choisissez
  explicitement l'accent cible. L'accent par défaut peut différer de celui de la
  source.
* Comparez plusieurs candidats avant d'en enregistrer un. Répéter une requête ne
  reproduit pas un candidat précédent.
* Utilisez un texte dans la langue cible du candidat. Conservez une voix
  localisée distincte pour chaque langue dont vous avez besoin.
* Pour nettoyer une source bruitée plutôt que changer son accent, utilisez
  [Voice Enhance](/fr/guides/voices/voice-enhance).

## Cycle de vie des candidats

Les candidats expirent au bout de 30 jours, sauf si vous les enregistrez comme
voix permanentes avec `POST /voices/from-embedding`. L'enregistrement d'un
candidat supprime son expiration et renvoie le `uid` de la voix permanente.
Consultez l'[étape de conversion](#démarrage-rapide) pour la requête et la réponse.

Pour supprimer un candidat avant son expiration, utilisez
`DELETE /voice-generator/embeddings/{embedding_id}`. Une voix convertie possède
sa propre copie. Les candidats localisés conservent aussi une copie de leur
source : supprimer la source après l'acceptation de la requête n'annule donc pas
la génération. Consultez le
[cycle de vie des candidats Voice Design](/fr/guides/voices/voice-design#cycle-de-vie-des-candidats)
pour le listage et le nettoyage.

## Limites

| Limite | Valeur |
| - | - |
| Candidats par requête | De 1 à 5, 1 par défaut |
| Langues cibles | `en`, `fr`, `es`, `pt`, `de` |
| Accents | Liste dynamique, lire `GET /voice-generator/available-accents` |
| `gender` | `male` ou `female` |
| Texte d'écoute | 300 caractères, REST uniquement |
| Conservation des candidats | 30 jours, levée après conversion |
| Voix converties | Décomptées du quota de voix personnalisées |

## Erreurs

Les erreurs ont la forme `{"detail": "..."}`, sauf `422`, qui contient une liste
d'erreurs par champ, dont les accents valides pour la langue demandée.

| Statut | Où | Signification |
| - | - | - |
| `401` | Partout | Clé API invalide ou expirée |
| `404` | Localisation | Source inconnue, ou voix ou candidat d'un autre compte |
| `404` | Écoute | Candidat pas encore prêt |
| `400` | Écoute | Candidat inconnu ou supprimé, ou texte de plus de 300 caractères |
| `409` | Localisation | La source n'a pas de langue, est un candidat pas encore prêt, est un clone pro ou une voix dans une langue non prise en charge. `detail` précise le cas. |
| `409` | Conversion | Déjà convertie, pas prête, ou quota de voix personnalisées atteint |
| `422` | Localisation | `target_language`, `accent`, `gender` ou `n_samples` invalide, ou `src_voice` vide |
| `503` | Localisation | L'audio source n'a pas pu être copié, ou aucun générateur de voix n'est disponible. Réessayez. |

## Étapes suivantes

<CardGroup cols={2}>
  <Card title="Voice Design" icon="wand-magic-sparkles" href="/fr/guides/voices/voice-design">
    Créez plutôt la voix source à partir d'une description.
  </Card>

  <Card title="Voix personnalisées" icon="microphone" href="/fr/guides/voices/custom-voices">
    Clonez un locuteur, avec une langue, pour que le clone puisse être localisé.
  </Card>

  <Card title="Gérer les voix" icon="sliders" href="/fr/guides/voices/manage-voices">
    Définissez la langue d'un ancien clone, listez et supprimez des voix.
  </Card>

  <Card title="Référence API" icon="code" href="/fr/api-reference/endpoint/localize-voice">
    Tous les endpoints de localisation en détail.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.