Contrôle de la prosodie et du débit
Contrôle de la prosodie et du débit
La prosodie — l’intonation, le rythme, l’accentuation et les pauses — est ce qui distingue une voix synthétique robotique d’une voix naturelle. Bien que l’API TTS d’OpenAI ne propose pas de contrôles SSML explicites, plusieurs techniques permettent d’influencer finement le rendu vocal pour produire un résultat professionnel.
Contrôle du débit par le paramètre speed
L’API TTS propose un paramètre speed qui ajuste la vitesse de parole :
from openai import OpenAI
client = OpenAI()
# Vitesse normale (1.0)
response_normal = client.audio.speech.create(
model="tts-1",
voice="nova",
input="Votre rendez-vous est confirmé pour demain à quatorze heures.",
speed=1.0
)
# Plus lent (0.75) — pour les instructions complexes
response_slow = client.audio.speech.create(
model="tts-1",
voice="nova",
input="Votre rendez-vous est confirmé pour demain à quatorze heures.",
speed=0.75
)
# Plus rapide (1.25) — pour les notifications courtes
response_fast = client.audio.speech.create(
model="tts-1",
voice="nova",
input="Votre rendez-vous est confirmé pour demain à quatorze heures.",
speed=1.25
)
| Vitesse | Plage | Usage |
|---|---|---|
| Lent | 0.25 — 0.75 | Instructions complexes, accessibilité, personnes âgées |
| Normal | 0.9 — 1.1 | Conversations, formations, narration |
| Rapide | 1.25 — 2.0 | Notifications, confirmations, récapitulatifs |
Techniques de formatage du texte
Le principal levier pour contrôler la prosodie est le formatage du texte d’entrée. Le modèle TTS interprète la ponctuation et la structure pour adapter son débit et son intonation.
Pauses
# Pause courte : virgule
text_comma = "Première étape, vérifiez votre configuration."
# Pause moyenne : point-virgule ou tiret
text_semi = "Première étape — vérifiez votre configuration."
# Pause longue : point ou points de suspension
text_dots = "Première étape. Vérifiez votre configuration."
text_ellipsis = "Première étape... vérifiez votre configuration."
# Pause très longue : paragraphe séparé
text_para = "Première étape.\n\nVérifiez votre configuration."
Emphase et intonation
# Question (intonation montante)
text_question = "Souhaitez-vous confirmer cette réservation ?"
# Exclamation (emphase naturelle)
text_exclaim = "Félicitations ! Votre inscription est confirmée !"
# Emphase par capitalisation
text_caps = "C'est TRÈS important de ne pas sauter cette étape."
# Liste avec rythme (le modèle marque naturellement chaque élément)
text_list = "Vous aurez besoin de : un, votre identifiant. Deux, votre mot de passe. Trois, votre code de confirmation."
Adapter le texte au contexte vocal
Un texte écrit pour être lu et un texte écrit pour être prononcé sont très différents. Pour un agent vocal, reformatez systématiquement :
def format_for_speech(text: str) -> str:
"""Adapte un texte écrit pour une lecture vocale naturelle."""
import re
# Épeler les sigles courants
abbreviations = {
"API": "A P I",
"URL": "U R L",
"PDF": "P D F",
"SMS": "S M S",
}
for abbr, spelled in abbreviations.items():
text = text.replace(abbr, spelled)
# Écrire les nombres en toutes lettres pour les petits nombres
number_words = {
"1": "un", "2": "deux", "3": "trois", "4": "quatre",
"5": "cinq", "6": "six", "7": "sept", "8": "huit",
"9": "neuf", "10": "dix"
}
for digit, word in number_words.items():
text = re.sub(rf'\b{digit}\b', word, text)
# Écrire les heures de manière vocale
text = re.sub(r'(\d{1,2})h(\d{2})', r'\1 heures \2', text)
text = re.sub(r'(\d{1,2})h\b', r'\1 heures', text)
return text
original = "Votre RDV est à 14h30. Envoyez 1 SMS pour confirmer."
formatted = format_for_speech(original)
# → "Votre RDV est à 14 heures 30. Envoyez un S M S pour confirmer."
Vitesse adaptative selon le contenu
Un agent vocal intelligent adapte son débit au type de contenu :
def adaptive_speed(content_type: str, user_preference: float = 1.0) -> float:
"""Calcule la vitesse optimale selon le type de contenu."""
base_speeds = {
"greeting": 1.0,
"instructions": 0.85,
"confirmation": 1.1,
"error_message": 0.9,
"phone_number": 0.7,
"address": 0.75,
"summary": 1.15,
"farewell": 1.0,
}
base = base_speeds.get(content_type, 1.0)
# Ajuster avec la préférence utilisateur (0.5 à 1.5)
adjusted = base * user_preference
return max(0.25, min(4.0, adjusted)) # Borner aux limites API
# Utilisation
speed = adaptive_speed("phone_number", user_preference=0.9)
# → 0.63 (lent pour dicter un numéro)
Post-traitement audio
Pour un contrôle encore plus fin, traitez l’audio après génération :
from pydub import AudioSegment
def post_process_speech(audio_bytes: bytes, adjustments: dict) -> bytes:
"""Post-traitement audio pour ajustements fins."""
import io
audio = AudioSegment.from_mp3(io.BytesIO(audio_bytes))
# Ajuster le volume
if "volume_db" in adjustments:
audio = audio + adjustments["volume_db"]
# Ajouter un fondu d'entrée/sortie
if adjustments.get("fade_in_ms"):
audio = audio.fade_in(adjustments["fade_in_ms"])
if adjustments.get("fade_out_ms"):
audio = audio.fade_out(adjustments["fade_out_ms"])
# Ajouter du silence au début (pré-roll)
if adjustments.get("pre_silence_ms"):
silence = AudioSegment.silent(duration=adjustments["pre_silence_ms"])
audio = silence + audio
buffer = io.BytesIO()
audio.export(buffer, format="mp3")
return buffer.getvalue()
Points clés à retenir
- Le paramètre
speed(0.25 à 4.0) contrôle la vitesse globale de parole - La ponctuation est le levier principal pour les pauses : virgule (courte), point (longue), ellipses (dramatique)
- Adaptez le texte au contexte vocal : épelez les sigles, écrivez les nombres en lettres, reformulez les heures
- La vitesse doit varier selon le contenu : lente pour les numéros et adresses, rapide pour les confirmations
- Le post-traitement audio (volume, fondus, silences) affine le rendu final