> ## 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.

# Synthèse vocale (WebSocket)

> Convertir du texte en parole naturelle avec le SDK Gradium et WebSocket

Le modèle de synthèse vocale de Gradium produit une parole naturelle et
de haute qualité, avec une faible latence au premier octet. Ce guide
couvre la synthèse avec le SDK Python : sortie en streaming, voix
personnalisées, balises de contrôle dans le texte et dictionnaires de
prononciation.

<Card title="Synthèse ponctuelle d'un texte complet ?" icon="file-lines" href="/fr/guides/text-to-speech-rest">
  Pour un usage simple du type « texte en entrée, fichier en sortie »,
  utilisez l'endpoint REST POST : un seul appel HTTP, sans WebSocket à gérer.
</Card>

## Démarrage rapide

Ouvrez un flux TTS en temps réel, envoyez du texte et lisez les fragments
audio dès que le modèle les produit.

```python theme={null}
import asyncio
import gradium

async def main():
    client = gradium.client.GradiumClient(api_key="your-api-key")
    audio_chunks = []

    async with client.tts_realtime(
        voice_id="YTpq7expH9539ERJ",
        output_format="pcm",
    ) as tts:
        async def sender():
            await tts.send_text("Hello, world.")
            await tts.send_eos()

        async def receiver():
            async for msg in tts:
                if msg["type"] == "audio":
                    audio_chunks.append(msg["audio"])
                elif msg["type"] == "end_of_stream":
                    return

        await asyncio.gather(sender(), receiver())

    with open("output.pcm", "wb") as f:
        f.write(b"".join(audio_chunks))

asyncio.run(main())
```

Pour une vue plus bas niveau du protocole, consultez
[Cycle de vie WebSocket](/fr/guides/websocket-lifecycle). Pour du texte
généré par un LLM, consultez
[Des tokens LLM à la synthèse vocale en streaming](/fr/guides/recipes/llm-to-tts).

## Choisir l'API du SDK

Le SDK Python propose trois formes d'API TTS. Toutes les API WebSocket
communiquent avec `wss://api.gradium.ai/api/speech/tts`.

| Cas d'usage | Méthode |
| - | - |
| Vous produisez du texte en direct et voulez envoyer et recevoir en parallèle | `tts_realtime` |
| Vous disposez d'une chaîne, d'une liste ou d'un générateur asynchrone et voulez des fragments audio en streaming | `tts_stream` |
| Vous voulez l'intégralité des octets audio une fois la génération terminée | `tts` |

Utilisez `tts_realtime` pour les agents vocaux, le streaming de tokens
LLM, les passerelles navigateur ou téléphonie, et tout flux de travail
où les boucles d'envoi et de réception s'exécutent simultanément.
Utilisez `tts_stream` lorsque votre entrée prend la forme d'un itérable
et que vous n'avez qu'à consommer des octets. Utilisez `tts` pour les
scripts et les tests où attendre le résultat complet ne pose pas de
problème.

## Appel bufferisé simplifié

```python theme={null}
import gradium

client = gradium.client.GradiumClient()
result = await client.tts(
    setup={
        "model_name": "default",
        "voice_id": "YTpq7expH9539ERJ",
        "output_format": "wav"
    },
    text="Hello, world!"
)

with open("output.wav", "wb") as f:
    f.write(result.raw_data)

print(f"Sample rate: {result.sample_rate}")
print(f"Request ID: {result.request_id}")
```

`client.tts(...)` utilise toujours le protocole de streaming en interne ;
il met en tampon les fragments audio et renvoie un unique `TTSResult`.

## Choix du modèle

Définissez `model_name` au premier niveau du setup TTS, à côté de
`voice_id`, en dehors de `json_config`.

Le nouveau modèle TTS est sélectionné par `"default"`. Vous pouvez omettre
`model_name` pour l'utiliser. `"gradium-tts-beta"` redirige également vers
ce modèle jusqu'à la sortie de la prochaine bêta TTS. Conservez cet alias
pour suivre les futurs modèles bêta, ou passez à `"default"` pour rester
sur les versions stables.

Avec le SDK Python, passez `model_name` à `tts_realtime`, ou dans `setup`
pour `tts` et `tts_stream`. Avec une connexion WebSocket directe,
incluez-le dans le premier message `setup`. Avec
[REST POST](/fr/guides/text-to-speech-rest), incluez-le au premier niveau
du corps JSON de la requête.

## Paramètres de setup

* **`model_name`** : le modèle TTS à utiliser (par défaut : `"default"`).
  Voir [Choix du modèle](#choix-du-modèle).
* **`voice_id`** : l'identifiant de la voix à utiliser. Vous le trouverez dans la section bibliothèque de voix de cette documentation ou dans le Studio.
* **`output_format`** : format audio des données de sortie (formats pris
  en charge : `"pcm"`, `"wav"`, `"opus"`, ...)
* **`json_config`** : réglages avancés de la voix, comme la température,
  la vitesse et les règles de réécriture. Voir
  [Réglages de la voix](/fr/guides/voice-settings).
* **`pronunciation_id`** : dictionnaire de prononciation facultatif à
  appliquer à cette requête.
* **`client_req_id`** et **`close_ws_on_eos`** : utilisés pour les
  connexions WebSocket réutilisables et multiplexées. Voir
  [Multiplexage](/fr/guides/multiplexing).

Avec le format de sortie `"pcm"`, l'audio respecte les spécifications
suivantes :

* **Fréquence d'échantillonnage** : 48000 Hz (48kHz)
* **Format** : PCM (Pulse Code Modulation)
* **Profondeur de bits** : entier signé 16 bits
* **Canaux** : canal unique (mono)
* **Taille des fragments** : 3840 échantillons par fragment (80ms à 48kHz)

Avec le format de sortie `"wav"`, les fragments audio sont au format WAV,
à 48kHz, en entier signé 16 bits, mono.

Avec le format de sortie `"opus"`, les fragments audio utilisent le codec
Opus encapsulé dans un conteneur Ogg.

Les autres formats de sortie disponibles sont `"ulaw_8000"`, `"alaw_8000"`,
`"pcm_8000"`, `"pcm_16000"` et `"pcm_24000"`.

## Synthèse vocale en streaming

Utilisez `tts_stream` lorsque vous disposez d'une chaîne, d'une liste ou
d'un générateur asynchrone et que vous voulez un itérateur asynchrone
d'octets audio.

```python theme={null}
stream = await client.tts_stream(
    setup={
        "model_name": "default",
        "voice_id": "LFZvm12tW_z0xfGo",
        "output_format": "pcm"
    },
    text="This is a longer text that will be streamed."
)

async for audio_chunk in stream.iter_bytes():
    print(f"Received {len(audio_chunk)} bytes")
```

## Utiliser des voix personnalisées

```python theme={null}
result = await client.tts(
    setup={
        "model_name": "default",
        "voice_id": "YTpq7expH9539ERJ",
        "output_format": "wav"
    },
    text="Hello with my custom voice!"
)
```

## Formats de sortie

```python theme={null}
# WAV format
result = await client.tts(setup={"voice_id": "YTpq7expH9539ERJ", "output_format": "wav"}, text="Hello")

# PCM format: the data is sampled at 48kHz, 16-bit signed integer, mono
result = await client.tts(setup={"voice_id": "YTpq7expH9539ERJ", "output_format": "pcm"}, text="Hello")

# Get numpy array from PCM
pcm_array = result.pcm()
pcm16_array = result.pcm16()
```

## Flush et pauses

Le modèle ne génère de l'audio que lorsqu'il dispose de suffisamment de
contexte : l'audio a donc généralement quelques mots de retard sur le
texte reçu. La balise `<flush>` permet de forcer le modèle à produire
l'audio de tout le texte reçu jusqu'ici.

```python theme={null}
sample_text = "Hello, this is a test from the Gradium Text to Speech system. <flush> We are testing the flush."
test_audio = await client.tts(
    setup={'voice_id': 'YTpq7expH9539ERJ', 'output_format': 'wav'},
    text=sample_text,
)
```

Vous pouvez générer des pauses en insérant une balise « break time »,
comme ci-dessous. La durée de la pause est exprimée en secondes et doit
être comprise entre 0,1 et 2,0 s. La balise doit être précédée et suivie
d'une espace.

```python theme={null}
sample_text = 'Hello, this is a test from the Gradium Text to Speech system. <break time="1.5s" /> We are testing the pause.'

test_audio = await client.tts(
    setup={'voice_id': 'YTpq7expH9539ERJ', 'output_format': 'wav'},
    text=sample_text,
)
```

## Texte horodaté

Le modèle renvoie des horodatages pour chaque segment de texte émis
(généralement alignés sur les limites de mots).

```python theme={null}
result = await client.tts(
    setup={"voice_id": "YTpq7expH9539ERJ", "output_format": "wav"},
    text="Hello, world!"
)

for item in result.text_with_timestamps:
    print(f"{item.text}: {item.start_s:.2f}s - {item.stop_s:.2f}s")
```

Chaque élément contient `text`, `start_s` et `stop_s` : les instants de
début et de fin, en secondes, dans l'audio généré. Au cours d'une session
de streaming, les mêmes informations sont transmises sous forme de
messages `text` (voir la
[référence TTS WebSocket](/fr/api-reference/endpoint/tts-websocket)).

Les horodatages sont émis à la granularité du **segment** (généralement
alignés sur les limites de mots). Pour obtenir des positions plus fines,
au niveau du caractère, déduisez-les du texte du segment.

## Entrée par générateur asynchrone

Utilisez un générateur asynchrone lorsque le texte est produit au fur et
à mesure, par exemple par un LLM ou un autre service de streaming.

```python theme={null}
async def text_generator():
    yield "Hello, "
    yield "this is "
    yield "a streaming "
    yield "example."

stream = await client.tts_stream(
    setup={"voice_id": "YTpq7expH9539ERJ", "output_format": "pcm"},
    text=text_generator()
)

async for chunk in stream.iter_bytes():
    pass
```

<Note>
  **Découpez les fragments de texte sur les espaces, jamais au milieu d'un
  mot ni juste avant un signe de ponctuation.** Lorsque le texte est envoyé
  progressivement (par des appels successifs à `send_text` sur le flux
  temps réel Python, par un générateur asynchrone comme ci-dessus, ou par
  plusieurs messages `{"type": "text"}` via l'API WebSocket), le serveur
  insère une espace entre les contenus de deux messages consécutifs.

  Ainsi, envoyer `"foo"` puis `"bar"` revient à envoyer `"foo bar"` (une
  espace est ajoutée entre les deux), et **non** `"foobar"`. Couper un mot
  sur deux messages modifie sa prononciation.

  Pour la même raison, n'isolez pas la ponctuation dans un message
  distinct : envoyer `"foo"` puis `"."` produit `"foo ."` et non `"foo."`.
  Laissez la ponctuation finale attachée au mot qui la précède (par exemple,
  envoyez `"foo."` en un seul message, ou `"foo. "` suivi du fragment
  suivant).
</Note>

## Dictionnaires de prononciation

Les dictionnaires de prononciation vous permettent de personnaliser la prononciation de certains mots ou expressions dans la sortie TTS. Ils sont particulièrement utiles pour :

* les noms de marque, termes techniques ou noms propres ;
* les acronymes qui doivent être prononcés d'une façon précise ;
* les mots dont la prononciation est inhabituelle dans votre cas d'usage.

Le plus simple pour créer et gérer des dictionnaires de prononciation est de passer par Gradium Studio, sur la page de prononciation.
Une fois le dictionnaire créé et son identifiant obtenu, vous pouvez l'utiliser dans vos requêtes TTS en passant le paramètre `pronunciation_id` dans le message de setup, comme pour le voice\_id :

```python theme={null}
import gradium

client = gradium.client.GradiumClient()

result = await client.tts(
    setup={
        "voice_id": "YTpq7expH9539ERJ",
        "output_format": "wav",
        "pronunciation_id": "bb1ckYhNHCcIJjdK",  # Whatever your ID is.
    },
    text="The text you want to generate."
)

with open("output.wav", "wb") as f:
    f.write(result.raw_data)
```

## WebSocket direct

Si vous ne souhaitez pas utiliser le SDK gradium, par exemple parce que
vous appelez l'API depuis un autre environnement que Python ou que vous
voulez un contrôle total sur les échanges, vous pouvez utiliser
directement le protocole WebSocket. Les messages ont exactement la même
forme que ceux envoyés par le SDK.

Pour tester de façon interactive depuis un terminal,
[`wscat`](https://github.com/websockets/wscat) est le moyen le plus rapide
de vérifier la connectivité et d'envoyer les messages un par un à la
main :

```bash theme={null}
wscat -c "wss://api.gradium.ai/api/speech/tts" \
  -H "x-api-key: your_api_key"
# After connection, type:
# {"type":"setup","voice_id":"YTpq7expH9539ERJ","model_name":"default","output_format":"wav"}
# {"type":"text","text":"Hello, world!"}
# {"type":"end_of_stream"}
```

Pour un client sans le SDK, utilisez n'importe quelle bibliothèque
WebSocket (ici [`websockets`](https://websockets.readthedocs.io/) en
Python) :

```python theme={null}
import asyncio
import base64
import json

import websockets


async def synthesise(api_key: str, voice_id: str, text: str) -> bytes:
    setup = {
        "type": "setup",
        "voice_id": voice_id,
        "model_name": "default",
        "output_format": "wav",
    }
    audio_chunks = []

    async with websockets.connect(
        "wss://api.gradium.ai/api/speech/tts",
        additional_headers={"x-api-key": api_key},
    ) as ws:
        await ws.send(json.dumps(setup))
        ready = json.loads(await ws.recv())
        assert ready["type"] == "ready"

        await ws.send(json.dumps({"type": "text", "text": text}))
        await ws.send(json.dumps({"type": "end_of_stream"}))

        while True:
            msg = json.loads(await ws.recv())
            if msg["type"] == "audio":
                audio_chunks.append(base64.b64decode(msg["audio"]))
            elif msg["type"] == "end_of_stream":
                break
            elif msg["type"] == "error":
                raise RuntimeError(msg["message"])

    return b"".join(audio_chunks)


audio = asyncio.run(synthesise("your_api_key", "YTpq7expH9539ERJ", "Hello, world!"))
with open("output.wav", "wb") as f:
    f.write(audio)
```

Pour le schéma complet des messages (chaque champ, chaque code d'erreur),
consultez la [référence TTS WebSocket](/fr/api-reference/endpoint/tts-websocket).

## Étapes suivantes

<CardGroup cols={2}>
  <Card title="Référence TTS WebSocket" icon="code" href="/fr/api-reference/endpoint/tts-websocket">
    Schéma complet du protocole : chaque type de message, chaque champ,
    chaque code d'erreur.
  </Card>

  <Card title="REST en un appel" icon="file-lines" href="/fr/guides/text-to-speech-rest">
    Synthétisez un bloc de texte complet en une seule requête HTTP.
  </Card>

  <Card title="Multiplexage" icon="layer-group" href="/fr/guides/multiplexing">
    Exécutez plusieurs requêtes de synthèse simultanées sur une seule
    session WebSocket.
  </Card>

  <Card title="Réglages de la voix" icon="sliders" href="/fr/guides/voice-settings">
    Vitesse, température et règles de réécriture.
  </Card>
</CardGroup>


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