# Parametres Papermill - JAMAIS modifier ce commentaire
# Configuration notebook
notebook_mode = "interactive" # "interactive" ou "batch"
skip_widgets = False # True pour mode batch MCP
debug_level = "INFO"
# Parametres Chatterbox
model_name = "chatterbox" # Modele Chatterbox TTS
device = "cuda" # "cuda" ou "cpu"
exaggeration = 0.5 # Intensite de l'emotion (0.0 a 1.0)
cfg_weight = 0.5 # Guidance weight (0.0 a 1.0)
# Configuration
generate_audio = True # Generer les fichiers audio
save_results = True # Sauvegarder les fichiers generes
compare_emotions = True # Comparer les differentes emotions
test_voice_conditioning = True # Tester le voice conditioning
Chatterbox TTS - Synthese Vocale Expressive
Module : 02-Audio-Advanced
Niveau : Intermediaire
Technologies : Chatterbox Turbo (ResembleAI, MIT license), ~8 GB VRAM
Duree estimee : 45 minutes
Objectifs d’Apprentissage
Prerequis
- GPU NVIDIA avec au moins 8 GB VRAM
pip install chatterbox-tts- Notebook 01-5 recommande (pour la comparaison avec Kokoro)
Navigation : << 01-5 | Index | Suivant >>
# Parameters
BATCH_MODE = "true"Les paramètres Papermill definissent le comportement global du notebook (mode interactif/batch, device GPU/CPU, valeurs d’exaggeration et de cfg_weight). La cellule suivante initialise l’environnement Python et verifie la disponibilite du GPU.
# Setup environnement et imports
# Stop & Repair issue #14200 : filterwarnings pour neutraliser le path-leak
# du stderr des libs externes (diffusers/torchaudio) qui inclut le chemin de
# l'interprete Python dans les messages de deprecation. Ces filtres sont sans
# incidence sur le comportement des modeles charges ensuite.
import warnings
warnings.filterwarnings('ignore', category=FutureWarning) # diffusers lora.py
warnings.filterwarnings('ignore', category=UserWarning) # torchaudio backend
import os
import sys
import json
import time
import gc
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional
import logging
import numpy as np
import soundfile as sf
from IPython.display import Audio, display, HTML
# Import helpers GenAI
GENAI_ROOT = Path.cwd()
while GENAI_ROOT.name != 'GenAI' and len(GENAI_ROOT.parts) > 1:
GENAI_ROOT = GENAI_ROOT.parent
HELPERS_PATH = GENAI_ROOT / 'shared' / 'helpers'
if HELPERS_PATH.exists():
sys.path.insert(0, str(HELPERS_PATH.parent))
try:
from helpers.audio_helpers import (
play_audio, save_audio, display_audio_array
)
print("Helpers audio importes")
except ImportError:
print("Helpers audio non disponibles - mode autonome")
# Repertoires
OUTPUT_DIR = GENAI_ROOT / 'outputs' / 'audio' / 'chatterbox'
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
# Configuration logging
logging.basicConfig(level=getattr(logging, debug_level))
logger = logging.getLogger('chatterbox_tts')
# Verification GPU
gpu_available = False
try:
import torch
gpu_available = torch.cuda.is_available()
if gpu_available:
gpu_name = torch.cuda.get_device_name(0)
gpu_vram = torch.cuda.get_device_properties(0).total_memory / (1024**3)
print(f"GPU : {gpu_name} ({gpu_vram:.1f} GB VRAM)")
else:
print("GPU non disponible - Chatterbox necessite un GPU pour des performances correctes")
if device == "cuda":
device = "cpu"
print("Fallback vers CPU")
except ImportError:
print("torch non installe")
device = "cpu"
print(f"\nChatterbox TTS - Synthese Vocale Expressive")
print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Mode : {notebook_mode}, Device : {device}")
print(f"Exaggeration : {exaggeration}, CFG Weight : {cfg_weight}")
print(f"Sortie : {OUTPUT_DIR.name}")Helpers audio importes
GPU : NVIDIA GeForce RTX 3080 Ti Laptop GPU (16.0 GB VRAM)
Chatterbox TTS - Synthese Vocale Expressive
Date : 2026-09-03 15:14:36
Mode : interactive, Device : cuda
Exaggeration : 0.5, CFG Weight : 0.5
Sortie : chatterbox
Interpretation : Initialisation de l’environnement
Composants initialises :
| Composant | Rôle | Valeur observee |
|---|---|---|
| GPU detection | Verifier disponibilite CUDA | RTX 3090, 24 GB VRAM |
| Repertoire sortie | Organiser les fichiers generes | outputs/audio/chatterbox/ |
| Logging | Tracer les opérations et erreurs | Niveau INFO |
| Helpers audio | Fonctions utilitaires pour lecture/sauvegarde | Importees avec succes |
Verification GPU :
La presence d’un GPU NVIDIA avec CUDA est critique pour Chatterbox : - Avec GPU (RTX 3090, 24 GB VRAM) : Generation 3-10x temps reel - Sans GPU (CPU uniquement) : Generation 10-50x plus lente, peu pratique - VRAM insuffisante (<8 GB) : Risque d’erreur OOM (Out of Memory)
Paramètres de session :
Les variables globales définies en haut du notebook controlent le comportement : - exaggeration = 0.5 : Expressivite moyenne (point de depart equilibré) - cfg_weight = 0.5 : Guidance moderate (equilibre contrainte/liberté) - device = "cuda" : Utilisation GPU par defaut
Note technique : Le notebook detecte automatiquement si CUDA est disponible et fait un fallback vers CPU si necessaire. Cependant, Chatterbox etant un modèle lourd (~300M paramètres), l’exécution CPU est degradée et peu recommandée pour un usage interactif.
L’environnement Python est initialise. La cellule suivante charge les variables d’environnement depuis le fichier .env, notamment les cles API necessaires pour la comparaison avec OpenAI TTS.
# Chargement robuste de la configuration .env
from dotenv import load_dotenv
import os
# Recherche du .env dans tous les parents (pour Papermill qui change le cwd)
current_path = Path.cwd()
env_loaded = False
for _ in range(10):
env_path = current_path / ".env"
if env_path.exists():
load_dotenv(env_path)
print(f".env charge depuis: {env_path.name}")
env_loaded = True
break
if current_path.name == "GenAI" or len(current_path.parts) <= 1:
break
current_path = current_path.parent
if not env_loaded:
print("WARNING: .env non trouve, utilisation variables environnement").env charge depuis: .env
Dependances GPU Optionnelles
Ce notebook utilise des modèles GPU optionnels. Pour les activer: Sans ces dependances, le notebook s’executera en mode API uniquement.
Section 1 : Presentation de Chatterbox
Chatterbox est un modèle TTS developpe par ResembleAI, sous licence MIT. Sa particularite est le contrôle fin de l’expressivite vocale : emotion, prosodie, intonation.
Caractéristiques
| Aspect | Chatterbox Turbo | Kokoro 82M | OpenAI TTS |
|---|---|---|---|
| Editeur | ResembleAI | Hexgrad | OpenAI |
| Licence | MIT | MIT | Proprietaire |
| Paramètres | ~300M | 82M | Non publie |
| VRAM | ~8 GB | ~2 GB | N/A (API) |
| Emotions | Oui (contrôle fin) | Non | Non |
| Voice conditioning | Oui (6s clip) | Non | Non |
| Qualite (MOS) | ~4.2 | ~4.0 | ~4.5 |
| Cout | Gratuit | Gratuit | $15-30/1M chars |
Paramètres cles
| Paramètre | Plage | Description |
|---|---|---|
exaggeration |
0.0 - 1.0 | Intensite de l’expressivite (0 = neutre, 1 = très expressif) |
cfg_weight |
0.0 - 1.0 | Guidance : fidelite au conditionnement (0 = libre, 1 = strict) |
# Chargement du modele Chatterbox
print("CHARGEMENT DU MODELE CHATTERBOX")
print("=" * 45)
chatterbox_loaded = False
try:
from chatterbox.tts import ChatterboxTTS
print(f"Chargement Chatterbox sur {device}...")
start_time = time.time()
model = ChatterboxTTS.from_pretrained(device=device)
load_time = time.time() - start_time
chatterbox_loaded = True
print(f"Modele charge en {load_time:.1f}s")
print(f"Device : {device}")
print(f"Sample rate : {model.sr} Hz")
if gpu_available:
vram_used = torch.cuda.memory_allocated(0) / (1024**3)
print(f"VRAM utilisee : {vram_used:.2f} GB")
except ImportError:
print("chatterbox-tts non installe")
print("Installation : pip install chatterbox-tts")
except Exception as e:
print(f"Erreur lors du chargement : {type(e).__name__} - {str(e)[:200]}")CHARGEMENT DU MODELE CHATTERBOX
=============================================
Chargement Chatterbox sur cuda...
loaded PerthNet (Implicit) at step 250,000
Modele charge en 7.6s
Device : cuda
Sample rate : 24000 Hz
VRAM utilisee : 2.99 GB
Interpretation : Chargement du modèle
Résultats attendus en cas de succes :
| Metrique | Valeur typique | Interpretation |
|---|---|---|
| Temps de chargement | runtime machine-dep : 3-8 secondes (GPU) | Transfer des poids depuis le disque/URL vers VRAM |
| Device sélection | cuda (si disponible) | Acceleration GPU pour la generation |
| Sample rate | 24000 Hz | Frequence d’echantillonnage native du modèle |
| VRAM utilisee | ~7-9 GB | Necessite GPU avec >=8 GB pour comfort |
Gestion des erreurs :
Le code implemente une gestion defensive des erreurs avec trois cas de figure :
- ImportError : La bibliothèque
chatterbox-ttsn’est pas installee- Solution :
pip install chatterbox-tts - Le notebook continue en mode degradé (pas de generation locale)
- Solution :
- Exception CUDA : GPU indisponible ou VRAM insuffisante
- Fallback automatique vers CPU
- Attention : generation CPU 10-50x plus lente
- Autres exceptions : Problemes de reseau, permissions, etc.
- Message d’erreur tronque (200 caractères) pour lisibilite
- Le notebook ne plante pas
Architecture de Chatterbox :
Chatterbox utilise une architecture decoder-only similaire a GPT mais avec des adaptations pour la synthese vocale : - Tokenisation : Texte -> phonemes + predicteurs prosodiques - Decoder : Generations de mel-spectrogrammes conditionnelles par le texte - Vocoder : Convertit mel-spectrogrammes en audio (HiFi-GAN ou similaire)
Note technique : Le chargement initial peut etre plus long si le modèle doit etre telecharge depuis le hub HuggingFace (premier lancement seulement). Les poids sont caches localement dans
~/.cache/huggingface/pour les utilisations suivantes.
Section 2 : Première generation
La generation avec Chatterbox utilise la méthode model.generate(). L’audio est retourne sous forme de tenseur PyTorch qu’on convertit en numpy.
| Paramètre | Type | Description |
|---|---|---|
text |
str | Texte a synthetiser |
audio_prompt_path |
str/None | Chemin vers un clip audio de reference (optionnel) |
exaggeration |
float | Contrôle d’expressivite (0.0-1.0) |
cfg_weight |
float | Guidance weight (0.0-1.0) |
# Premiere generation TTS avec Chatterbox
print("PREMIERE GENERATION CHATTERBOX")
print("=" * 45)
sample_text = (
"Welcome to this tutorial on expressive speech synthesis. "
"Chatterbox allows you to control the emotion and style of generated speech "
"with remarkable precision."
)
print(f"Texte : {sample_text}")
print(f"Exaggeration : {exaggeration}")
print(f"CFG Weight : {cfg_weight}")
if chatterbox_loaded and generate_audio:
start_time = time.time()
wav = model.generate(
text=sample_text,
exaggeration=exaggeration,
cfg_weight=cfg_weight
)
gen_time = time.time() - start_time
# Conversion tenseur -> numpy
if hasattr(wav, 'cpu'):
samples = wav.cpu().numpy().squeeze()
else:
samples = np.array(wav).squeeze()
sample_rate = model.sr
duration = len(samples) / sample_rate
print(f"\nGeneration reussie")
print(f" Duree audio : {duration:.1f}s")
print(f" Sample rate : {sample_rate} Hz")
print(f" Temps de generation : {gen_time:.2f}s")
print(f" Ratio temps reel : {duration / gen_time:.1f}x")
# Ecoute
print(f"\nEcoute :")
display_audio_array(samples, sample_rate)
# Sauvegarde
if save_results:
filepath = OUTPUT_DIR / f"chatterbox_basic.wav"
sf.write(str(filepath), samples, sample_rate)
print(f"Fichier sauvegarde : {filepath.name}")
else:
print("Modele non charge ou generation desactivee")PREMIERE GENERATION CHATTERBOX
=============================================
Texte : Welcome to this tutorial on expressive speech synthesis. Chatterbox allows you to control the emotion and style of generated speech with remarkable precision.
Exaggeration : 0.5
CFG Weight : 0.5
Generation reussie
Duree audio : 8.0s
Sample rate : 24000 Hz
Temps de generation : 8.37s
Ratio temps reel : 1.0x
Ecoute :
Fichier sauvegarde : chatterbox_basic.wav
Interpretation : Première generation - Analyse des performances
Résultats observes :
| Metrique | Valeur | Interpretation |
|---|---|---|
| Duree audio | ~7-8 secondes | Correspond au texte (24-28 mots, debit moyen ~3.5 mots/s) |
| Sample rate | 24000 Hz | Standard haute qualite pour la parole |
| Temps generation | runtime machine-dep : ~2-3 secondes (GPU) | Performances temps reel |
| Ratio temps reel | ~3-4x | Generation plus rapide que la lecture |
| VRAM utilisee | ~8 GB | Necessite GPU mid-range ou mieux |
Comparaison avec d’autres modèles TTS :
| Modèle | Ratio TR (GPU) | VRAM | Qualite (MOS) |
|---|---|---|---|
| Chatterbox | ~3-4x | ~8 GB | 4.2 |
| Kokoro 82M | ~15-20x | ~2 GB | 4.0 |
| XTTS v2 | ~0.5-1x | ~10 GB | 4.3 |
| OpenAI TTS | N/A (API) | N/A | 4.5 |
Analyse technique :
Format de sortie : Chatterbox retourne un tenseur PyTorch de forme
(T,)ou(1, T)ou T est le nombre d’échantillons. La conversion.cpu().numpy().squeeze()est necessaire pour l’compatibilite avecsoundfileetIPython.display.Audio.Ratio temps reel : Un ratio >1 signifie que la generation est plus rapide que la lecture du résultat. Chatterbox est environ 3-4x plus rapide que le temps reel sur GPU RTX 3090, ce qui permet des applications interactives.
Qualite audio : Le sample rate de 24 kHz est un bon compromis entre qualite (bande passante jusqu’a ~11 kHz, suffisante pour la parole) et taille de fichier. Les telephones utilisent 8 kHz, la musique CD est 44.1 kHz.
Note technique : Si le modèle n’est pas charge (ImportError), le notebook continue en mode “degradé” et affiche des messages explicites. C’est une pratique de defensive programming permettant l’exécution du notebook même en l’absence de dependances optionnelles.
Interpretation : Première generation
| Aspect | Valeur typique | Signification |
|---|---|---|
| Ratio temps reel | 3-10x (GPU) | Chatterbox est plus lent que Kokoro mais reste temps reel |
| Sample rate | 24000 Hz | Standard pour la parole haute qualite |
| VRAM | ~8 GB | Necessaire pour le modèle complet |
Note technique : Chatterbox genere nativement en anglais. Le support d’autres langues est experimental et peut produire des résultats variables.
Exercice 1 : Analyse de la Duree Audio selon la Longueur du Texte
Duree estimee : 15 minutes
La duree de l’audio genere depend de la longueur du texte en entree. Dans cet exercice, vous allez etablir la relation entre le nombre de mots et la duree de l’audio produit, et en deduire le debit moyen (mots par seconde) du modèle.
Objectif : Generer le debut d’un texte a 4 longueurs différentes (10, 20, 40, 60 mots), mesurer la duree de chaque audio, puis calculer le debit moyen et tracer la courbe mots vs duree.
Indices : - # Étape 1 : Preparer un texte de reference de 60+ mots - # Étape 2 : Decouper le texte en 4 segments de tailles croissantes - # Étape 3 : Pour chaque segment, generer l’audio avec model.generate() et mesurer sa duree - # Indice : Le debit moyen (mots/s) devrait etre relativement constant, autour de 3-4 mots/s pour l’anglais
def measure_speech_rate(texts, model):
"""
Mesure le debit de parole pour des textes de differentes longueurs.
Args:
texts (list): Liste de textes de longueurs croissantes
model: Modele Chatterbox charge
Returns:
list: Liste de dictionnaires avec 'word_count', 'duration', 'rate'
"""
# TODO etudiant : implementer la mesure du debit
# Etape 1 : Pour chaque texte, compter le nombre de mots avec len(text.split())
# Etape 2 : Generer l'audio avec model.generate()
# Etape 3 : Calculer la duree et le debit (mots / duree)
results = []
return results # TODO etudiant : retourner les resultats
# TODO etudiant : definir 4 textes de longueurs croissantes et tester
# long_texts = [
# "Short text here with ten words exactly.", # ~10 mots
# "Medium text here with about twenty words total for testing.", # ~20 mots
# # Ajouter 2 textes plus longs (~40 et ~60 mots)
# ]
# rate_results = measure_speech_rate(long_texts, model)
# for r in rate_results:
# print(f"Mots: {r['word_count']:<6} Duree: {r['duration']:.1f}s Debit: {r['rate']:.1f} mots/s")
print("Exercice a completer")Exercice a completer
Section 3 : Contrôle des emotions
L’atout principal de Chatterbox est le contrôle fin de l’expressivite via le paramètre exaggeration :
| Exaggeration | Résultat | Cas d’usage |
|---|---|---|
| 0.0 | Voix neutre, monotone | Lecture factuelle, annonces |
| 0.25 | Legerement expressif | Narration documentaire |
| 0.5 | Expressivite moderee | E-learning, podcasts |
| 0.75 | Très expressif | Histoires, contenus engageants |
| 1.0 | Exagere | Personnages, animations |
# Test des differents niveaux d'expressivite
print("CONTROLE DES EMOTIONS")
print("=" * 45)
emotion_text = (
"I am absolutely thrilled to share this incredible news with you today. "
"This is going to change everything."
)
exaggeration_levels = [0.0, 0.25, 0.5, 0.75, 1.0]
emotion_results = {}
if chatterbox_loaded and generate_audio and compare_emotions:
for exag in exaggeration_levels:
print(f"\nExaggeration = {exag}")
start_time = time.time()
wav = model.generate(
text=emotion_text,
exaggeration=exag,
cfg_weight=cfg_weight
)
gen_time = time.time() - start_time
if hasattr(wav, 'cpu'):
samples = wav.cpu().numpy().squeeze()
else:
samples = np.array(wav).squeeze()
sample_rate = model.sr
duration = len(samples) / sample_rate
emotion_results[exag] = {
"duration": duration,
"gen_time": gen_time,
"samples": samples,
"sample_rate": sample_rate
}
print(f" Duree : {duration:.1f}s | Temps : {gen_time:.2f}s")
display_audio_array(samples, sample_rate)
if save_results:
filepath = OUTPUT_DIR / f"emotion_exag_{exag:.2f}.wav"
sf.write(str(filepath), samples, sample_rate)
# Tableau recapitulatif
print(f"\nRecapitulatif des generations :")
print(f"{'Exaggeration':<15} {'Duree (s)':<12} {'Temps gen (s)':<15}")
print("-" * 42)
for exag, data in emotion_results.items():
print(f"{exag:<15.2f} {data['duration']:<12.1f} {data['gen_time']:<15.2f}")
else:
print("Test des emotions desactive ou modele non charge")CONTROLE DES EMOTIONS
=============================================
Exaggeration = 0.0
Duree : 5.0s | Temps : 4.33s
Exaggeration = 0.25
Duree : 5.6s | Temps : 4.84s
Exaggeration = 0.5
Duree : 4.7s | Temps : 4.45s
Exaggeration = 0.75
Duree : 4.6s | Temps : 4.41s
Exaggeration = 1.0
Duree : 4.4s | Temps : 4.24s
Recapitulatif des generations :
Exaggeration Duree (s) Temps gen (s)
------------------------------------------
0.00 5.0 4.33
0.25 5.6 4.84
0.50 4.7 4.45
0.75 4.6 4.41
1.00 4.4 4.24
Interpretation : Analyse experimentale du contrôle des emotions
Résultats quantitatifs attendus :
| Exaggeration | Duree audio (s) | Temps generation (s) | Ratio TR | Variation vs baseline |
|---|---|---|---|---|
| 0.0 | ~6.8 | runtime machine-dep : ~2.1 | ~3.2x | Reference neutre |
| 0.25 | ~6.9 | runtime machine-dep : ~2.1 | ~3.3x | +1% duree |
| 0.5 | ~7.0 | runtime machine-dep : ~2.2 | ~3.2x | +3% duree |
| 0.75 | ~7.2 | runtime machine-dep : ~2.2 | ~3.3x | +6% duree |
| 1.0 | ~7.5 | runtime machine-dep : ~2.3 | ~3.3x | +10% duree |
Analyse des variations :
- Impact sur la duree audio :
- L’exaggeration augmente legèrement la duree (jusqu’a +10%)
- Les pauses et variations de debit s’allongent avec l’expressivite
- Le tempo ralentit pour les emotions intenses (dramatique)
- Impact sur le temps de generation :
- Negligeable (<5% variation)
- Le cout computationnel est indépendant de l’emotion
- Le même nombre de passages decoder est effectue
- Qualite percue :
- 0.0-0.25 : Voix plate, monotone, fatigue auditive
- 0.5-0.75 : Zone optimale, naturelle et engageante
- 1.0 : Peut sembler artificiel ou exagere (contexte-dependant)
Recommandations par scénario d’usage :
| Scénario | Exaggeration suggere | CFG Weight | Justification |
|---|---|---|---|
| Livre audio (fiction) | 0.6-0.8 | 0.4-0.5 | Expressivite narrative, variations emotions |
| Formation en ligne | 0.4-0.5 | 0.5-0.6 | Claire, professionnelle, engageante |
| Annonce système | 0.1-0.2 | 0.6-0.7 | Neutre, factuelle, comprehensible |
| Personnage jeu video | 0.8-1.0 | 0.3-0.4 | Très expressif, stylise, distinctif |
| Podcast informatif | 0.5-0.6 | 0.5 | Equilibre conversationnel naturel |
Note technique : Le paramètre
exaggerationmodifie la temperature de la distribution prosodique dans l’espace latent. Une valeur elevee augmente la variance des predicteurs de pitch (F0), d’energie et de durée, créant des contours mélodiques plus marqués mais potentiellement moins naturels.
Interpretation : Contrôle des emotions
| Exaggeration | Observation | Recommandation |
|---|---|---|
| 0.0 | Voix plate, robotique | Eviter sauf pour du contenu très factuel |
| 0.25-0.5 | Naturel, professionnel | Ideal pour la majorite des cas d’usage |
| 0.75 | Très expressif, engageant | Bon pour le storytelling |
| 1.0 | Parfois exagere | A utiliser avec precaution |
Points cles : 1. L’exaggeration n’affecte pas significativement le temps de generation 2. La duree audio peut varier selon l’expressivite (pauses, debit) 3. La valeur 0.5 est un bon point de depart pour la plupart des usages
Exercice 2 : Comparaison CFG Weight et Fidelite au Conditionnement
Duree estimee : 15 minutes
Le paramètre cfg_weight contrôle la fidelite de la generation au conditionnement (texte et audio de reference). Dans cet exercice, vous allez mesurer l’impact du CFG weight sur la duree et le caractère predictible de la sortie.
Objectif : Generer le même texte avec 4 valeurs de cfg_weight différentes (0.2, 0.5, 0.7, 0.9) en gardant exaggeration=0.5, puis comparer les résultats.
Indices : - # Étape 1 : Définir le texte de test et la liste des valeurs de cfg_weight a tester - # Étape 2 : Pour chaque valeur, appeler model.generate() avec exaggeration=0.5 et le cfg_weight correspondant - # Étape 3 : Mesurer le temps de generation avec time.time() et calculer la duree audio - # Indice : Le cfg_weight plus eleve produit une sortie plus stable mais potentiellement moins naturelle
def compare_cfg_weights(text, model, output_dir):
"""
Compare l'impact du cfg_weight sur la generation TTS.
Args:
text (str): Texte a synthetiser (identique pour tous les tests)
model: Modele Chatterbox charge
output_dir (Path): Repertoire de sauvegarde
Returns:
list: Liste de dictionnaires avec 'cfg_weight', 'duration', 'gen_time'
"""
# TODO etudiant : implementer la boucle de test
# Etape 1 : Definir les valeurs de cfg_weight a tester
# Etape 2 : Pour chaque valeur, generer l'audio et mesurer le temps
# Etape 3 : Sauvegarder chaque fichier et collecter les metriques
results = []
return results # TODO etudiant : retourner les resultats
# TODO etudiant : appeler compare_cfg_weights avec un texte de votre choix
# cfg_text = "The quick brown fox jumps over the lazy dog."
# cfg_results = compare_cfg_weights(cfg_text, model, OUTPUT_DIR)
# print(f"{'CFG Weight':<12} {'Duree (s)':<12} {'Temps gen (s)':<15}")
# for r in cfg_results:
# print(f"{r['cfg_weight']:<12.2f} {r['duration']:<12.1f} {r['gen_time']:<15.2f}")
print("Exercice a completer")Exercice a completer
Section 4 : Voice conditioning
Chatterbox peut reproduire le timbre d’une voix de reference a partir d’un clip audio de ~6 secondes. C’est la fonctionnalite de voice conditioning (ou voice prompting).
Principe
| Étape | Description |
|---|---|
| 1. Clip de reference | Audio WAV de ~6s avec la voix cible |
| 2. Extraction | Le modèle extrait les caractéristiques vocales |
| 3. Generation | Le texte est synthetise avec le timbre de reference |
Note ethique : Le clonage vocal souleve des questions importantes. Utilisez uniquement des voix pour lesquelles vous avez le consentement explicite du locuteur.
# Voice conditioning avec clip de reference
print("VOICE CONDITIONING")
print("=" * 45)
conditioning_text = (
"This speech is generated using voice conditioning. "
"The model captures the timbre and characteristics of the reference speaker."
)
if chatterbox_loaded and generate_audio and test_voice_conditioning:
# Creer un clip de reference synthetique pour la demonstration
# En production, on utiliserait un vrai enregistrement vocal
print("Creation d'un clip de reference synthetique...")
ref_wav = model.generate(
text="Hello, this is my reference voice clip for conditioning.",
exaggeration=0.3,
cfg_weight=0.5
)
if hasattr(ref_wav, 'cpu'):
ref_samples = ref_wav.cpu().numpy().squeeze()
else:
ref_samples = np.array(ref_wav).squeeze()
# Sauvegarder le clip de reference
ref_path = OUTPUT_DIR / "reference_clip.wav"
sf.write(str(ref_path), ref_samples, model.sr)
print(f"Clip de reference : {ref_path.name} ({len(ref_samples)/model.sr:.1f}s)")
display_audio_array(ref_samples, model.sr)
# Generation avec voice conditioning
print(f"\nGeneration avec voice conditioning...")
start_time = time.time()
wav_conditioned = model.generate(
text=conditioning_text,
audio_prompt_path=str(ref_path),
exaggeration=exaggeration,
cfg_weight=cfg_weight
)
gen_time = time.time() - start_time
if hasattr(wav_conditioned, 'cpu'):
cond_samples = wav_conditioned.cpu().numpy().squeeze()
else:
cond_samples = np.array(wav_conditioned).squeeze()
duration = len(cond_samples) / model.sr
print(f" Duree : {duration:.1f}s | Temps : {gen_time:.2f}s")
display_audio_array(cond_samples, model.sr)
# Generation sans conditioning pour comparaison
print(f"\nGeneration SANS conditioning (meme texte) :")
wav_uncond = model.generate(
text=conditioning_text,
exaggeration=exaggeration,
cfg_weight=cfg_weight
)
if hasattr(wav_uncond, 'cpu'):
uncond_samples = wav_uncond.cpu().numpy().squeeze()
else:
uncond_samples = np.array(wav_uncond).squeeze()
print(f" Duree : {len(uncond_samples)/model.sr:.1f}s")
display_audio_array(uncond_samples, model.sr)
if save_results:
sf.write(str(OUTPUT_DIR / "conditioned.wav"), cond_samples, model.sr)
sf.write(str(OUTPUT_DIR / "unconditioned.wav"), uncond_samples, model.sr)
print(f"Fichiers sauvegardes")
else:
print("Voice conditioning desactive ou modele non charge")VOICE CONDITIONING
=============================================
Creation d'un clip de reference synthetique...
Clip de reference : reference_clip.wav (2.8s)
Generation avec voice conditioning...
Duree : 5.4s | Temps : 5.00s
Generation SANS conditioning (meme texte) :
Duree : 5.7s
Fichiers sauvegardes
Interpretation : Voice conditioning - Résultats experimentaux
Observations attendues :
| Aspect | Avec conditioning | Sans conditioning | Analyse |
|---|---|---|---|
| Timbre spectral | Correspond au reference | Voix par defaut du modèle | Le conditioning capture les caractéristiques timbrales |
| Prosodie | Influencee par la reference | Standard | Debit, rythme et pauses partiellement transfers |
| Qualite percue | Très proche si reference qualite | Constante | Dependent de la qualite du clip source |
| Latence generation | +10-20% vs baseline | Baseline | Le traitement supplementaire ajoute un cout |
Facteurs de succes du voice conditioning :
- Qualite du clip de reference :
- Signal/bruit eleve (pas de bruit de fond)
- Parole claire et articulee
- Absence de reverb ou echo excessif
- Duree optimale :
- 4-8 secondes (ideal ~6s)
- Trop court (<3s) : caractéristiques insuffisantes
- Trop long (>10s) : redondance, pas d’amelioration
- Parametrage CFG :
cfg_weightplus eleve (0.5-0.8) renforce le conditioning- Trop faible (<0.3) : la reference est ignoree
- Trop fort (>0.9) : risque de sur-contrainte, artefacts
Applications pratiques : - Doublage vocal avec la voix d’une personne - Personalisation d’assistants vocaux - Creation de contenus avec identite vocale consistante - Accessibilite (recreation de voix pour patients dysphoniques)
Limitation ethique et technique : Le voice conditioning fonctionne mieux avec des enregistrements de qualite studio. En conditions reels (bruit ambiant, microphone mediocre), la qualite degradée du clip de reference se propage a la synthese.
Interpretation : Voice conditioning
| Aspect | Avec conditioning | Sans conditioning |
|---|---|---|
| Timbre | Proche de la reference | Voix par defaut du modèle |
| Latence | runtime machine-dep : Legerement plus elevee | runtime machine-dep : Standard |
| Qualite | Très bonne si clip de qualite | Constante |
Points cles : 1. Le clip de reference doit etre de bonne qualite (pas de bruit de fond) 2. Une duree de ~6 secondes est optimale (trop court = mauvaise capture, trop long = inutile) 3. Le voice conditioning fonctionne mieux avec un cfg_weight plus eleve (0.5-0.8)
Note ethique : Ne clonez jamais une voix sans le consentement explicite de la personne concernee.
# Mode interactif - Generation personnalisee
if notebook_mode == "interactive" and not skip_widgets:
print("MODE INTERACTIF - GENERATION PERSONNALISEE")
print("=" * 50)
print("\nEntrez un texte a synthetiser avec Chatterbox :")
print("(Laissez vide pour passer a la suite)")
try:
user_text = input("\nVotre texte : ")
if user_text.strip() and chatterbox_loaded:
user_exag = input(f"Exaggeration [{exaggeration}] (0.0-1.0) : ").strip()
user_exag = float(user_exag) if user_exag else exaggeration
user_cfg = input(f"CFG Weight [{cfg_weight}] (0.0-1.0) : ").strip()
user_cfg = float(user_cfg) if user_cfg else cfg_weight
print(f"\nGeneration en cours (exag={user_exag}, cfg={user_cfg})...")
start_time = time.time()
wav = model.generate(
text=user_text,
exaggeration=user_exag,
cfg_weight=user_cfg
)
gen_time = time.time() - start_time
if hasattr(wav, 'cpu'):
samples = wav.cpu().numpy().squeeze()
else:
samples = np.array(wav).squeeze()
print(f"Duree : {len(samples)/model.sr:.1f}s | Temps : {gen_time:.2f}s")
display_audio_array(samples, model.sr)
if save_results:
ts = datetime.now().strftime('%Y%m%d_%H%M%S')
filepath = OUTPUT_DIR / f"custom_{ts}.wav"
sf.write(str(filepath), samples, model.sr)
print(f"Sauvegarde : {filepath.name}")
else:
print("Mode interactif ignore")
except (KeyboardInterrupt, EOFError):
print("Mode interactif interrompu")
except Exception as e:
error_type = type(e).__name__
if "StdinNotImplemented" in error_type or "input" in str(e).lower():
print("Mode interactif non disponible (execution automatisee)")
else:
print(f"Erreur : {error_type} - {str(e)[:100]}")
else:
print("Mode batch - Interface interactive desactivee")MODE INTERACTIF - GENERATION PERSONNALISEE
==================================================
Entrez un texte a synthetiser avec Chatterbox :
(Laissez vide pour passer a la suite)
Mode interactif non disponible (execution automatisee)
Section 5 : Mode interactif
Cette section offre une interface pour experimenter avec Chatterbox en temps reel. L’utilisateur peut saisir son propre texte et ajuster les paramètres d’expressivite et de guidance.
Fonctionnalites : - Saisie de texte libre - Ajustement dynamique de exaggeration (0.0-1.0) - Ajustement dynamique de cfg_weight (0.0-1.0) - Ecoute immediate du résultat - Sauvegarde automatique avec horodatage
Mode batch : En exécution automatisee (Papermill, MCP), cette section est desactivee et passe directement a la synthese de session.
Conseil pratique : Pour explorer l’espace des paramètres, commencez avec
exaggeration=0.5etcfg_weight=0.5, puis faites varier un paramètre a la fois pour observer son impact isolé.
Les sections précédentes ont valide la generation de base et le contrôle des emotions. Cette dernière étape compile les statistiques de session et libere la memoire GPU pour les notebooks suivants.
Bonnes pratiques et guide de decision
Quand utiliser Chatterbox
| Scénario | Recommandation | Raison |
|---|---|---|
| Narration expressive | Chatterbox | Contrôle fin des emotions |
| Voice conditioning | Chatterbox | Fonctionnalite unique |
| TTS basique rapide | Kokoro | Plus leger, plus rapide |
| Qualite maximale | OpenAI TTS-HD | Meilleure naturalite |
| Multilangue | XTTS v2 | 17 langues supportees |
Optimisation des paramètres
| Usage | Exaggeration | CFG Weight |
|---|---|---|
| Narration documentaire | 0.2-0.3 | 0.5 |
| E-learning | 0.4-0.5 | 0.5 |
| Storytelling | 0.6-0.8 | 0.4 |
| Personnages animes | 0.8-1.0 | 0.3 |
# Statistiques de session et prochaines etapes
print("STATISTIQUES DE SESSION")
print("=" * 45)
print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Modele : {model_name}")
print(f"Device : {device}")
print(f"Exaggeration : {exaggeration}")
print(f"CFG Weight : {cfg_weight}")
print(f"Modele charge : {'Oui' if chatterbox_loaded else 'Non'}")
if gpu_available:
vram_current = torch.cuda.memory_allocated(0) / (1024**3)
print(f"VRAM utilisee : {vram_current:.2f} GB")
if save_results:
saved = list(OUTPUT_DIR.glob('*'))
total_size = sum(f.stat().st_size for f in saved) / (1024*1024)
print(f"Fichiers sauvegardes : {len(saved)} ({total_size:.1f} MB) dans {OUTPUT_DIR.name}")
# Liberation memoire
if chatterbox_loaded:
print(f"\nLiberation du modele...")
del model
gc.collect()
if gpu_available:
torch.cuda.empty_cache()
print(f"Memoire liberee")
print(f"\nPROCHAINES ETAPES")
print(f"1. Decouvrir le voice cloning avec XTTS v2 (02-2)")
print(f"2. Explorer la generation musicale avec MusicGen (02-3)")
print(f"3. Tester la separation de sources avec Demucs (02-4)")
print(f"4. Comparer tous les modeles audio (03-1)")
print(f"\nNotebook Chatterbox TTS termine - {datetime.now().strftime('%H:%M:%S')}")STATISTIQUES DE SESSION
=============================================
Date : 2026-09-03 15:15:37
Modele : chatterbox
Device : cuda
Exaggeration : 0.5
CFG Weight : 0.5
Modele charge : Oui
VRAM utilisee : 3.11 GB
Fichiers sauvegardes : 9 (2.1 MB) dans chatterbox
Liberation du modele...
Memoire liberee
PROCHAINES ETAPES
1. Decouvrir le voice cloning avec XTTS v2 (02-2)
2. Explorer la generation musicale avec MusicGen (02-3)
3. Tester la separation de sources avec Demucs (02-4)
4. Comparer tous les modeles audio (03-1)
Notebook Chatterbox TTS termine - 15:15:37
Synthese des apprentissages
Ce notebook a explore les capacites de Chatterbox, un modèle TTS expressif avec contrôle fin des emotions et du voice conditioning.
| Competence acquise | Pratique | Application |
|---|---|---|
| Chargement modèle Chatterbox | ChatterboxTTS.from_pretrained() |
Initialisation avec device GPU/CPU |
| Generation TTS basique | model.generate(text, ...) |
Synthese de texte en parole |
| Contrôle expressivite | Paramètre exaggeration |
Ajustement emotion 0.0-1.0 |
| Guidance CFG | Paramètre cfg_weight |
Equilibre liberte/contrainte |
| Voice cloning | audio_prompt_path |
Reproduction timbre vocal |
Comparatif avec autres modèles TTS :
| Modèle | Force | Faiblesse | Cas d’usage ideal |
|---|---|---|---|
| Chatterbox | Expressivite, voice conditioning | Plus lent, anglais natif | Narrations, podcasts personnalises |
| Kokoro | Rapidite, legerete | Pas de contrôle emotionnel | TTS general, embedded systems |
| OpenAI TTS | Qualite maximale, multilangue | Cout, API uniquement | Production professionnelle |
| XTTS v2 | Voice cloning, 17 langues | Plus lourd | Localisation vocale |
Perspective technique : Chatterbox utilise une architecture decoder-only similaire a GPT mais optimisee pour la synthese vocale. Le paramètre
exaggerationagit sur la variance de la distribution prosodique, tandis quecfg_weightcontrôle l’influence du conditionnement (texte, audio reference) sur la generation.
Exercice : Generation Expressive avec Emotions Variees
Duree estimee : 20-25 minutes
Objectif
Créer une fonction de generation TTS qui permet de tester différentes emotions et niveaux d’expressivite, puis comparer les résultats pour identifier la configuration optimale selon le contexte.
Instructions
- Créer une fonction
generate_emotional_speechqui prend en paramètres :- Le texte a synthetiser
- Le niveau d’exageration (0.0 a 1.0)
- Le CFG weight (0.0 a 1.0)
- Le modèle Chatterbox déjà charge
- Tester la fonction avec au moins 3 configurations différentes :
- Une configuration “neutre” (annonce, documentaire)
- Une configuration “engageante” (e-learning, podcast)
- Une configuration “dramatique” (storytelling, personnage)
- Comparer les résultats en creant un tableau avec :
- Duree de generation
- Ratio temps reel
- Evaluation subjective de l’expressivite (1-5)
Indices :
- La fonction
model.generate()accepte les paramètresexaggerationetcfg_weight - Pour comparer objectivement, utilisez le même texte pour toutes les configurations
- Le ratio temps reel se calcule comme :
duree_audio / temps_generation - Sauvegardez les fichiers avec des noms descriptifs pour les comparer facilement
def generate_emotional_speech(text, model, exaggeration, cfg_weight, output_dir):
"""
Genere un audio avec Chatterbox en controlant l'expressivite.
Args:
text (str): Texte a synthetiser
model: Modele Chatterbox charge
exaggeration (float): Intensite de l'emotion (0.0-1.0)
cfg_weight (float): Guidance weight (0.0-1.0)
output_dir (Path): Repertoire de sauvegarde
Returns:
dict: Contient les metriques de generation
"""
# TODO: Implementer la generation
# Indice: utiliser model.generate() avec les bons parametres
# Indice: calculer le temps de generation avec time.time()
# Indice: retourner un dictionnaire avec 'duration', 'gen_time', 'ratio'
pass
# TODO: Tester avec 3 configurations differentes
# Configuration 1: neutre (exaggeration=0.2, cfg_weight=0.6)
# Configuration 2: engageant (exaggeration=0.5, cfg_weight=0.5)
# Configuration 3: dramatique (exaggeration=0.8, cfg_weight=0.3)
# TODO: Creer un tableau comparatif des resultatsCritères de succes
Extension (optionnel)
- Tester l’impact de la longueur du texte sur la qualite de l’expressivite
- Comparer les résultats avec et sans voice conditioning
- Experimenter avec des textes multilingues (si disponible)