Comparaison Multi-Modèles Audio

Module : 03-Audio-Orchestration
Niveau : Avance
Technologies : Whisper API vs local, OpenAI TTS vs Chatterbox vs Kokoro, ~12 GB VRAM
Duree estimee : 60 minutes

Objectifs d’Apprentissage

Prerequis

  • Notebooks 01-1 a 01-5 recommandes (fondamentaux audio)
  • Notebooks 02-1 recommande (Chatterbox)
  • GPU NVIDIA avec au moins 12 GB VRAM (pour tous les modèles locaux)
  • Cle API OpenAI configuree (OPENAI_API_KEY dans .env)
  • pip install faster-whisper chatterbox-tts kokoro soundfile matplotlib

Navigation : << 02-4 | Index | Suivant >>

# 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 benchmark
run_stt_benchmark = True           # Executer le benchmark STT
run_tts_benchmark = True           # Executer le benchmark TTS
stt_models = ["whisper-1", "large-v3-turbo"]  # Modeles STT a comparer
tts_models = ["openai", "chatterbox", "kokoro"]  # Modeles TTS a comparer
device = "cuda"                    # "cuda" ou "cpu"

# Configuration
save_results = True                # Sauvegarder les fichiers generes
num_runs = 3                       # Nombre de runs par modele pour moyenner

Introduction : Comparaison multi-modèles audio

En 2026, l’ecosysteme des modèles audio a atteint une maturite remarquable. Plusieurs approches coexistent :

Approches API cloud (Whisper, OpenAI TTS, ElevenLabs) : - Avantages : simplicité d’intégration, pas d’infrastructure GPU à gérer, qualité premium - Inconvenients : cout recurrent, latence reseau, dépendance au fournisseur, confidentialité des données

Approches open-source locales (faster-whisper, Kokoro, Chatterbox) : - Avantages : gratuit (après investissement GPU), latence predictable, hors-ligne, souveraineté des données - Inconvenients : installation complexe, maintenance GPU, VRAM limitee

Approches hybrides : - Combiner API cloud pour le prototypage et modèles locaux pour la production - Basculer vers l’API en cas de pic de charge (failover)

Ce notebook propose un cadre systématique pour comparer ces approches sur des metriques objectives : latence, qualite, cout, consommation GPU. Les résultats vous permettront de prendre une décision éclairée selon votre cas d’usage et vos contraintes (budget, infrastructure, confidentialité).

# Parameters
skip_widgets = True

L’environnement de travail est configure avec les paramètres Papermill. La cellule suivante charge les bibliotheques Python necessaires : mesure de performances, appels API audio et utilitaires de benchmark.

# 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_bundle, display_audio_array
        print("Helpers audio importes")
    except ImportError:
        print("Helpers audio non disponibles - mode autonome")

# Repertoires
OUTPUT_DIR = GENAI_ROOT / 'outputs' / 'audio' / 'comparison'
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

# Configuration logging
logging.basicConfig(level=getattr(logging, debug_level))
logger = logging.getLogger('audio_comparison')

# 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 - les modeles locaux seront plus lents")
        if device == "cuda":
            device = "cpu"
            print("Fallback vers CPU")
except ImportError:
    print("torch non installe")
    device = "cpu"

print(f"\nComparaison Multi-Modeles Audio")
print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Mode : {notebook_mode}, Device : {device}")
print(f"STT : {stt_models}")
print(f"TTS : {tts_models}")
print(f"Sortie : {OUTPUT_DIR.name}")
Helpers audio importes
GPU : NVIDIA GeForce RTX 3090 (24.0 GB VRAM)

Comparaison Multi-Modeles Audio
Date : 2026-09-04 14:34:49
Mode : interactive, Device : cuda
STT : ['whisper-1', 'large-v3-turbo']
TTS : ['openai', 'chatterbox', 'kokoro']
Sortie : comparison

Les modules Python sont importes. Cette cellule charge les cles API depuis le fichier .env en remontant l’arborescence de repertoires pour s’adapter aux différents contextes d’exécution.

# Chargement robuste de la configuration .env (Pattern A - Papermill-safe)
from dotenv import load_dotenv
import os
from pathlib import Path

current_path = Path.cwd()
genai_path = None

# Remonter jusqu'au dossier GenAI
while len(current_path.parts) > 1:
    if current_path.name == "GenAI":
        genai_path = current_path
        break
    current_path = current_path.parent

if genai_path:
    env_path = genai_path / ".env"
    if env_path.exists():
        load_dotenv(env_path)
        print(f".env charge depuis: {env_path.name}")
    else:
        print(f"WARNING: .env non trouve a {env_path.name}")
else:
    print("WARNING: Dossier GenAI non trouve, utilisation variables environnement")

# Verification des API disponibles
openai_key = os.environ.get('OPENAI_API_KEY')
openai_available = bool(openai_key and not openai_key.startswith('sk-or-'))

if openai_available:
    print("OPENAI_API_KEY valide - API disponible")
    from openai import OpenAI
    client = OpenAI(api_key=openai_key)
else:
    print("OPENAI_API_KEY non disponible ou invalide (cle OpenRouter)")
    openai_key = None
    client = None

# Ajuster les modeles actifs selon les API disponibles
if not openai_available:
    # Retirer les modeles API de la liste
    if "whisper-1" in stt_models:
        stt_models.remove("whisper-1")
    if "openai" in tts_models:
        tts_models.remove("openai")
    print(f"Modeles STT actifs : {stt_models}")
    print(f"Modeles TTS actifs : {tts_models}")
.env charge depuis: .env
OPENAI_API_KEY valide - API disponible

Section 1 : Framework de benchmark

Avant de comparer les modèles, nous devons définir un framework de mesure rigoureux. Chaque modèle sera evalue selon des metriques standardisees.

Metriques STT (Speech-to-Text)

Metrique Description Unite
WER Word Error Rate (taux d’erreur par mot) %
Latence Temps de transcription secondes
RTF Real-Time Factor (temps traitement / duree audio) ratio
Cout Cout par minute d’audio USD
VRAM Memoire GPU utilisee GB

Metriques TTS (Text-to-Speech)

Metrique Description Unite
Latence Temps de generation (premier byte) secondes
RTF Real-Time Factor ratio
Sample Rate Frequence d’echantillonnage Hz
Cout Cout par 1000 caractères USD
VRAM Memoire GPU utilisee GB
# Framework de benchmark
print("FRAMEWORK DE BENCHMARK")
print("=" * 45)

class BenchmarkResult:
    """Resultat d'un benchmark pour un modele."""
    def __init__(self, model_name: str, category: str):
        self.model_name = model_name
        self.category = category  # 'stt' ou 'tts'
        self.latencies: List[float] = []
        self.vram_mb: float = 0.0
        self.cost_per_unit: float = 0.0  # par minute (STT) ou par 1K chars (TTS)
        self.quality_score: float = 0.0  # WER (STT) ou MOS estime (TTS)
        self.sample_rate: int = 0
        self.output_data: Any = None

    @property
    def avg_latency(self) -> float:
        return np.mean(self.latencies) if self.latencies else 0.0

    @property
    def std_latency(self) -> float:
        return np.std(self.latencies) if len(self.latencies) > 1 else 0.0

    def to_dict(self) -> Dict:
        return {
            "model": self.model_name,
            "category": self.category,
            "avg_latency_s": round(self.avg_latency, 3),
            "std_latency_s": round(self.std_latency, 3),
            "vram_mb": round(self.vram_mb, 1),
            "cost_per_unit": self.cost_per_unit,
            "quality_score": round(self.quality_score, 3),
            "sample_rate": self.sample_rate
        }


def measure_vram() -> float:
    """Mesurer la VRAM actuellement utilisee en MB."""
    if gpu_available:
        return torch.cuda.memory_allocated(0) / (1024**2)
    return 0.0


def word_error_rate(reference: str, hypothesis: str) -> float:
    """Calculer le WER entre reference et hypothese (Levenshtein sur les mots)."""
    ref_words = reference.lower().split()
    hyp_words = hypothesis.lower().split()
    if not ref_words:
        return 0.0 if not hyp_words else 1.0

    # Distance de Levenshtein sur les mots
    d = np.zeros((len(ref_words) + 1, len(hyp_words) + 1), dtype=int)
    for i in range(len(ref_words) + 1):
        d[i][0] = i
    for j in range(len(hyp_words) + 1):
        d[0][j] = j
    for i in range(1, len(ref_words) + 1):
        for j in range(1, len(hyp_words) + 1):
            cost = 0 if ref_words[i-1] == hyp_words[j-1] else 1
            d[i][j] = min(d[i-1][j] + 1, d[i][j-1] + 1, d[i-1][j-1] + cost)

    return d[len(ref_words)][len(hyp_words)] / len(ref_words)


# Stocker tous les resultats
all_results: Dict[str, BenchmarkResult] = {}

print("Framework de benchmark initialise")
print(f"Nombre de runs par modele : {num_runs}")
print(f"Modeles STT : {stt_models}")
print(f"Modeles TTS : {tts_models}")
FRAMEWORK DE BENCHMARK
=============================================
Framework de benchmark initialise
Nombre de runs par modele : 3
Modeles STT : ['whisper-1', 'large-v3-turbo']
Modeles TTS : ['openai', 'chatterbox', 'kokoro']

Architecture du framework de benchmark

Cette section définit les classes et fonctions utilitaires qui seront utilisees tout au long du notebook pour mesurer et comparer les performances des modèles audio.

Classe BenchmarkResult : - Structure de données pour stocker les résultats d’un benchmark - Attributs : latences, VRAM, cout, qualite, sample rate - Méthodes : avg_latency, std_latency pour l’analyse statistique - Conversion en dictionnaire pour export JSON

Fonctions utilitaires : - measure_vram() : mesure la consommation GPU actuelle via PyTorch - word_error_rate() : implementation de l’algorithme de Levenshtein pour calculer le WER entre reference et hypothèse

Stratégie de stockage : - Dictionnaire all_results indexé par des cles comme "stt_whisper-1" ou "tts_kokoro" - Permet d’ajouter dynamiquement des résultats sans connaitre à l’avance les modèles disponibles - Export en JSON à la fin du notebook pour reutilisation future

Ce framework est generique et peut etre réutilise pour d’autres benchmarks de modèles audio.

Section 2 : Preparation des données de test

Pour une comparaison equitable, nous utilisons les mêmes données de test pour tous les modèles.

Donnee Description Usage
Audio de test STT Fichier WAV avec texte connu Benchmark STT
Texte de test TTS Texte standardise en anglais et francais Benchmark TTS
Reference ground truth Transcription exacte de l’audio Calcul du WER
# Preparation des donnees de test
print("PREPARATION DES DONNEES DE TEST")
print("=" * 45)

# Texte de reference pour le STT (on va le synthetiser puis le retranscrire)
stt_reference_text = (
    "Artificial intelligence is transforming the way we interact with technology. "
    "Speech recognition and synthesis are among the most impactful applications, "
    "enabling natural conversations between humans and machines."
)

# Texte de test pour le TTS
tts_test_text = (
    "Welcome to the multi-model audio comparison benchmark. "
    "This test evaluates the quality, speed, and cost of different "
    "text-to-speech engines across various metrics."
)

# Generer l'audio de test STT avec OpenAI TTS (source fiable)
stt_test_path = OUTPUT_DIR / "stt_test_audio.wav"

if openai_available:
    print("Generation de l'audio de test STT via OpenAI TTS...")
    response = client.audio.speech.create(
        model="tts-1-hd",
        voice="alloy",
        input=stt_reference_text,
        response_format="wav"
    )
    with open(stt_test_path, 'wb') as f:
        f.write(response.content)
    print(f"Audio de test STT : {stt_test_path.name} ({len(response.content)/1024:.1f} KB)")
    display_audio_bundle(response.content)
else:
    # Generer un audio synthetique si pas d'API
    print("Pas d'API OpenAI - generation d'un audio synthetique...")
    sr = 16000
    duration = 5.0
    t = np.linspace(0, duration, int(sr * duration), endpoint=False)
    # Signal vocal simule (sinusoides modulees)
    audio = 0.5 * np.sin(2 * np.pi * (200 + 100 * np.sin(2 * np.pi * 3 * t)) * t)
    audio *= (1 + 0.3 * np.sin(2 * np.pi * 1.5 * t))
    sf.write(str(stt_test_path), audio, sr)
    stt_reference_text = "[audio synthetique - WER non significatif]"
    print(f"Audio synthetique cree : {stt_test_path.name}")

print(f"\nReference STT : {stt_reference_text[:80]}...")
print(f"Texte TTS : {tts_test_text[:80]}...")
print(f"Longueur texte TTS : {len(tts_test_text)} caracteres")
PREPARATION DES DONNEES DE TEST
=============================================
Generation de l'audio de test STT via OpenAI TTS...
Audio de test STT : stt_test_audio.wav (624.1 KB)

Reference STT : Artificial intelligence is transforming the way we interact with technology. Spe...
Texte TTS : Welcome to the multi-model audio comparison benchmark. This test evaluates the q...
Longueur texte TTS : 163 caracteres

Generation des données de test

Cette section prepare un environnement de test controlé pour comparer équitablement les différents modèles audio.

Stratégie de test STT : - Generer un audio de test avec OpenAI TTS (tts-1-hd, voix “alloy”) - Utiliser un texte de référence anglais clair (mots de vocabulaire courant) - L’audio généré sert de “ground truth” pour tous les modèles STT - Le WER (Word Error Rate) mesure la fidélité de la transcription par rapport au texte original

Stratégie de test TTS : - Texte de 163 caractères contenant des termes techniques (“benchmark”, “metrics”) - Ce texte permet d’evaluer la prononciation précise et la fluidité - Même texte pour tous les modèles TTS pour garantir la comparabilité

Fallback sans API : - Si OpenAI API n’est pas disponible, générer un audio synthetique (sinusoïdes modulées) - Le WER n’est pas significatif dans ce cas, mais le protocole reste fonctionnel

Cette approche garantit que les différences observees entre modèles proviennent bien des modèles eux-mêmes, et non des données de test.

Section 3 : Benchmark STT (Speech-to-Text)

Nous comparons deux approches pour la transcription vocale :

Modèle Type Avantages Inconvenients
Whisper API (whisper-1) Cloud (OpenAI) Simple, pas de GPU, haute qualite Cout par minute, latence reseau
faster-whisper (large-v3-turbo) Local (GPU) Gratuit, rapide, hors-ligne GPU requis, installation complexe

Tarification Whisper API

Modèle Cout Unite
whisper-1 $0.006 par minute d’audio
# Benchmark STT
print("BENCHMARK STT (Speech-to-Text)")
print("=" * 45)

if run_stt_benchmark and stt_test_path.exists():
    audio_data, audio_sr = sf.read(str(stt_test_path))
    audio_duration = len(audio_data) / audio_sr
    print(f"Audio de test : {audio_duration:.1f}s, {audio_sr} Hz")

    # --- Whisper API ---
    if "whisper-1" in stt_models and openai_available:
        print(f"\n--- Whisper API (whisper-1) ---")
        result = BenchmarkResult("whisper-1", "stt")
        result.cost_per_unit = 0.006  # par minute
        result.sample_rate = audio_sr

        for run in range(num_runs):
            start_time = time.time()
            with open(stt_test_path, "rb") as f:
                transcript = client.audio.transcriptions.create(
                    model="whisper-1",
                    file=f,
                    response_format="text"
                )
            latency = time.time() - start_time
            result.latencies.append(latency)
            print(f"  Run {run+1}/{num_runs} : {latency:.2f}s")

        result.output_data = transcript
        result.quality_score = word_error_rate(stt_reference_text, transcript)
        all_results["stt_whisper-1"] = result

        print(f"  Transcription : {transcript[:100]}...")
        print(f"  WER : {result.quality_score:.3f}")
        print(f"  Latence moyenne : {result.avg_latency:.2f}s (+/- {result.std_latency:.2f}s)")
        print(f"  RTF : {result.avg_latency / audio_duration:.2f}")
        print(f"  Cout : ${audio_duration / 60 * result.cost_per_unit:.4f}")

    # --- faster-whisper local ---
    if "large-v3-turbo" in stt_models:
        print(f"\n--- faster-whisper (large-v3-turbo) ---")
        result = BenchmarkResult("large-v3-turbo", "stt")
        result.cost_per_unit = 0.0  # gratuit (GPU local)

        try:
            from faster_whisper import WhisperModel

            vram_before = measure_vram()
            print(f"  Chargement du modele...")
            stt_model = WhisperModel(
                "large-v3-turbo",
                device=device,
                compute_type="float16" if device == "cuda" else "int8"
            )
            vram_after = measure_vram()
            result.vram_mb = vram_after - vram_before
            print(f"  VRAM modele : {result.vram_mb:.0f} MB")

            for run in range(num_runs):
                start_time = time.time()
                segments, info = stt_model.transcribe(
                    str(stt_test_path),
                    beam_size=5
                )
                transcript_local = " ".join([s.text.strip() for s in segments])
                latency = time.time() - start_time
                result.latencies.append(latency)
                print(f"  Run {run+1}/{num_runs} : {latency:.2f}s")

            result.output_data = transcript_local
            result.quality_score = word_error_rate(stt_reference_text, transcript_local)
            result.sample_rate = int(info.language_probability * 16000)  # approximation
            all_results["stt_large-v3-turbo"] = result

            print(f"  Transcription : {transcript_local[:100]}...")
            print(f"  WER : {result.quality_score:.3f}")
            print(f"  Latence moyenne : {result.avg_latency:.2f}s (+/- {result.std_latency:.2f}s)")
            print(f"  RTF : {result.avg_latency / audio_duration:.2f}")

            # Liberer la memoire
            del stt_model
            gc.collect()
            if gpu_available:
                torch.cuda.empty_cache()
            print(f"  Modele libere")

        except ImportError:
            print("  faster-whisper non installe")
            print("  Installation : pip install faster-whisper")
        except Exception as e:
            print(f"  Erreur : {type(e).__name__} - {str(e)[:150]}")

    # Tableau recapitulatif STT
    stt_results = {k: v for k, v in all_results.items() if v.category == "stt"}
    if stt_results:
        print(f"\nRecapitulatif STT :")
        print(f"{'Modele':<20} {'Latence (s)':<14} {'WER':<8} {'Cout/min':<10} {'VRAM (MB)':<10}")
        print("-" * 62)
        for k, r in stt_results.items():
            cost_str = f"${r.cost_per_unit:.3f}" if r.cost_per_unit > 0 else "Gratuit"
            vram_str = f"{r.vram_mb:.0f}" if r.vram_mb > 0 else "N/A"
            print(f"{r.model_name:<20} {r.avg_latency:<14.2f} {r.quality_score:<8.3f} {cost_str:<10} {vram_str:<10}")
else:
    print("Benchmark STT desactive ou fichier de test manquant")
BENCHMARK STT (Speech-to-Text)
=============================================
Audio de test : 13.3s, 24000 Hz

--- Whisper API (whisper-1) ---
  Run 1/3 : 1.68s
  Run 2/3 : 1.44s
  Run 3/3 : 1.47s
  Transcription : Artificial intelligence is transforming the way we interact with technology. Speech recognition and ...
  WER : 0.000
  Latence moyenne : 1.53s (+/- 0.11s)
  RTF : 0.12
  Cout : $0.0013

--- faster-whisper (large-v3-turbo) ---
  Chargement du modele...
  VRAM modele : 0 MB
  Run 1/3 : 1.28s
  Run 2/3 : 0.57s
  Run 3/3 : 0.57s
  Transcription : Artificial intelligence is transforming the way we interact with technology. Speech recognition and ...
  WER : 0.000
  Latence moyenne : 0.81s (+/- 0.34s)
  RTF : 0.06
  Modele libere

Recapitulatif STT :
Modele               Latence (s)    WER      Cout/min   VRAM (MB) 
--------------------------------------------------------------
whisper-1            1.53           0.000    $0.006     N/A       
large-v3-turbo       0.81           0.000    Gratuit    N/A       

Methodologie de benchmark STT

Cette section implemente un protocole de benchmark rigoureux pour les modèles Speech-to-Text :

Preparation des données : - Audio de test généré par OpenAI TTS (garantit une qualité de reference constante) - Texte de référence connu pour calculer le WER (Word Error Rate)

Protocol de mesure : 1. Pour chaque modèle, executer num_runs transcriptions (3 par défaut) 2. Mesurer la latence totale (temps de requête HTTP ou traitement GPU) 3. Calculer la moyenne et l’ecart-type des latences 4. Comparer la transcription à la référence pour le WER

Metriques cles : - Latence : temps de traitement (incluant le reseau pour les API) - WER : taux d’erreur par mot (0 = parfait, 1 = tout faux) - RTF : Real-Time Factor = latence / duree audio (< 1 = temps reel possible) - VRAM : consommation GPU pour les modèles locaux

Le code inclut la gestion d’erreur pour les modèles non installes ou les problemes de connexion reseau.

Interpretation : Benchmark STT

Aspect Whisper API faster-whisper local
Precision (WER) Très bonne (< 5%) Equivalente ou meilleure
Latence runtime machine-dep : Depend du reseau (1-3s) runtime machine-dep : Depend du GPU (0.5-2s)
Cout $0.006/min Gratuit (GPU amortit)
VRAM 0 (cloud) ~3-6 GB
Hors-ligne Non Oui

Points cles : 1. faster-whisper large-v3-turbo offre un excellent compromis vitesse/qualite 2. L’API Whisper est plus simple a deployer mais a un cout recurrent 3. Pour du traitement en masse, le local est nettement plus economique


Exercice : Evaluation de la precision STT avec vos propres données

Duree estimee : 15 minutes

Objectif

Tester la robustesse d’un modèle STT en calculant le Word Error Rate (WER) sur des phrases de longueur et complexite variees.

Instructions

  1. Créer une liste de 5 phrases de reference de complexite croissante
  2. Implementer une fonction qui simule des erreurs de transcription (substitution, insertion, omission de mots)
  3. Calculer le WER pour chaque phrase avec la fonction word_error_rate() du notebook
  4. Analyser comment la longueur et la complexite des phrases influencent le WER

Indices : - # Étape 1 : Inclure des phrases simples (“Hello world”), moyennes et techniques (“The RTX 3090 has 24GB of GDDR6X VRAM”) - # Étape 2 : Simuler des erreurs en modifiant aleatoirement des mots de la reference - # Indice : Le WER = (substitutions + insertions + deletions) / nombre de mots de reference - # Indice : Les noms propres et termes techniques sont plus sujets aux erreurs de transcription

# TODO etudiant : Creer des phrases de test de complexite croissante
test_phrases = [
    "Hello world",  # TODO etudiant : phrase simple
    None,  # TODO etudiant : phrase moyenne (15-20 mots)
    None,  # TODO etudiant : phrase avec noms propres
    None,  # TODO etudiant : phrase technique (termes informatiques)
    None,  # TODO etudiant : phrase longue (30+ mots)
]

# TODO etudiant : Implementer la simulation d'erreurs
def simulate_transcription_errors(reference: str, error_rate: float = 0.1) -> str:
    """
    Simule des erreurs de transcription sur une phrase de reference.
    
    Args:
        reference: Phrase de reference
        error_rate: Proportion de mots a modifier (0.0 a 1.0)
    
    Returns:
        Phrase avec erreurs simulees
    """
    # TODO etudiant : Decouper la reference en mots
    # Indice : reference.split()
    pass
    
    # TODO etudiant : Modifier aleatoirement error_rate % des mots
    # Indice : utiliser random.choice() pour choisir entre substitution, insertion, omission
    pass
    
    # TODO etudiant : Retourner la phrase modifiee
    pass

# TODO etudiant : Calculer le WER pour chaque phrase
# for phrase in test_phrases:
#     if phrase:
#         hypo = simulate_transcription_errors(phrase, error_rate=0.15)
#         wer = word_error_rate(phrase, hypo)
#         print(f"Reference : {phrase}")
#         print(f"Hypothese : {hypo}")
#         print(f"WER       : {wer:.3f}")
#         print()

# TODO etudiant : Analyser l'impact de la complexite sur le WER
print("Exercice a completer")
Exercice a completer

Analyse des résultats STT

Precision de transcription : - WER (Word Error Rate) de 0.000 pour Whisper API sur ce texte propre - En pratique sur des audio reels (bruit, accents), le WER varie de 5% (audio propre) à 25% (audio difficile) - faster-whisper large-v3-turbo atteint des performances comparables, parfois meilleures sur les accents non-americains

Real-Time Factor (RTF) : - RTF < 1.0 signifie que la transcription est plus rapide que la duree de l’audio (traitement en temps reel possible) - Whisper API : RTF ~ 0.14 (transcrit 13s d’audio en runtime machine-dep : ~2s) - faster-whisper : RTF ~ 0.05-0.10 sur GPU RTX 3090 (transcrit 13s d’audio en runtime machine-dep : ~0.7s)

Impact du reseau : - La variabilité des latences Whisper API (runtime machine-dep : 1.05s à 2.77s) illustre l’impact de la latence reseau - Les modèles locaux offrent une latence plus predictable

Conclusion : pour un usage intensif (> 1h/jour), le cout de l’API (runtime machine-dep : $18/mois) justifie l’investissement dans un GPU local (runtime machine-dep : ~$30/mois amorti sur 2 ans).

Section 4 : Benchmark TTS (Text-to-Speech)

Nous comparons trois moteurs TTS avec des approches différentes :

Modèle Type VRAM Sample Rate Licence
OpenAI TTS Cloud API 0 24 kHz Proprietaire
Chatterbox Local GPU ~8 GB 24 kHz MIT
Kokoro 82M Local GPU ~2 GB 24 kHz MIT

Tarification TTS

Modèle Cout / 1M caractères Cout / 1 heure narration
OpenAI tts-1 $15.00 ~$0.75
OpenAI tts-1-hd $30.00 ~$1.50
Chatterbox Gratuit Electricite GPU
Kokoro Gratuit Electricite GPU
# Benchmark TTS
print("BENCHMARK TTS (Text-to-Speech)")
print("=" * 45)

if run_tts_benchmark:
    print(f"Texte de test : {tts_test_text[:60]}...")
    print(f"Longueur : {len(tts_test_text)} caracteres")

    # --- OpenAI TTS ---
    if "openai" in tts_models and openai_available:
        print(f"\n--- OpenAI TTS (tts-1) ---")
        result = BenchmarkResult("openai-tts-1", "tts")
        result.cost_per_unit = 0.015  # par 1K caracteres
        result.sample_rate = 24000

        for run in range(num_runs):
            start_time = time.time()
            response = client.audio.speech.create(
                model="tts-1",
                voice="alloy",
                input=tts_test_text,
                response_format="wav"
            )
            latency = time.time() - start_time
            result.latencies.append(latency)
            print(f"  Run {run+1}/{num_runs} : {latency:.2f}s")

        result.output_data = response.content
        result.quality_score = 4.5  # MOS estime (reference industrie)
        all_results["tts_openai"] = result

        # Sauvegarder et ecouter
        tts_path = OUTPUT_DIR / "tts_openai.wav"
        with open(tts_path, 'wb') as f:
            f.write(response.content)
        print(f"  Latence moyenne : {result.avg_latency:.2f}s")
        print(f"  Taille : {len(response.content)/1024:.1f} KB")
        display_audio_bundle(response.content)

    # --- Chatterbox ---
    if "chatterbox" in tts_models:
        print(f"\n--- Chatterbox TTS ---")
        result = BenchmarkResult("chatterbox", "tts")
        result.cost_per_unit = 0.0

        try:
            from chatterbox.tts import ChatterboxTTS

            vram_before = measure_vram()
            print(f"  Chargement du modele...")
            cb_model = ChatterboxTTS.from_pretrained(device=device)
            vram_after = measure_vram()
            result.vram_mb = vram_after - vram_before
            result.sample_rate = cb_model.sr
            print(f"  VRAM : {result.vram_mb:.0f} MB")

            for run in range(num_runs):
                start_time = time.time()
                wav = cb_model.generate(
                    text=tts_test_text,
                    exaggeration=0.5,
                    cfg_weight=0.5
                )
                latency = time.time() - start_time
                result.latencies.append(latency)
                print(f"  Run {run+1}/{num_runs} : {latency:.2f}s")

            if hasattr(wav, 'cpu'):
                samples = wav.cpu().numpy().squeeze()
            else:
                samples = np.array(wav).squeeze()

            result.output_data = samples
            result.quality_score = 4.2  # MOS estime
            all_results["tts_chatterbox"] = result

            tts_path = OUTPUT_DIR / "tts_chatterbox.wav"
            sf.write(str(tts_path), samples, cb_model.sr)
            print(f"  Latence moyenne : {result.avg_latency:.2f}s")
            print(f"  Duree audio : {len(samples)/cb_model.sr:.1f}s")
            display_audio_array(samples, cb_model.sr)

            del cb_model
            gc.collect()
            if gpu_available:
                torch.cuda.empty_cache()
            print(f"  Modele libere")

        except ImportError:
            print("  chatterbox-tts non installe")
        except Exception as e:
            print(f"  Erreur : {type(e).__name__} - {str(e)[:150]}")

    # --- Kokoro ---
    if "kokoro" in tts_models:
        print(f"\n--- Kokoro TTS (82M) ---")
        result = BenchmarkResult("kokoro-82m", "tts")
        result.cost_per_unit = 0.0

        try:
            from kokoro_onnx import Kokoro as KokoroOnnx

            vram_before = measure_vram()
            print(f"  Chargement du modele...")
            kokoro_cache = Path.home() / '.cache' / 'kokoro-onnx'
            kokoro_pipe = KokoroOnnx(str(kokoro_cache / 'kokoro-v1.0.onnx'), str(kokoro_cache / 'voices-v1.0.bin'))
            vram_after = measure_vram()
            result.vram_mb = vram_after - vram_before
            result.sample_rate = 24000
            print(f"  VRAM : {result.vram_mb:.0f} MB")

            for run in range(num_runs):
                start_time = time.time()
                samples, _kokoro_sr = kokoro_pipe.create(tts_test_text, voice='af_heart', speed=1.0)
                latency = time.time() - start_time
                result.latencies.append(latency)
                print(f"  Run {run+1}/{num_runs} : {latency:.2f}s")

            result.output_data = samples
            result.quality_score = 4.0  # MOS estime
            all_results["tts_kokoro"] = result

            tts_path = OUTPUT_DIR / "tts_kokoro.wav"
            sf.write(str(tts_path), samples, 24000)
            print(f"  Latence moyenne : {result.avg_latency:.2f}s")
            print(f"  Duree audio : {len(samples)/24000:.1f}s")
            display_audio_array(samples, 24000)

            del kokoro_pipe
            gc.collect()
            if gpu_available:
                torch.cuda.empty_cache()
            print(f"  Modele libere")

        except ImportError:
            print("  kokoro non installe")
        except Exception as e:
            print(f"  Erreur : {type(e).__name__} - {str(e)[:150]}")

    # Tableau recapitulatif TTS
    tts_results = {k: v for k, v in all_results.items() if v.category == "tts"}
    if tts_results:
        print(f"\nRecapitulatif TTS :")
        print(f"{'Modele':<18} {'Latence (s)':<14} {'MOS est.':<10} {'Cout/1K ch.':<12} {'VRAM (MB)':<10}")
        print("-" * 64)
        for k, r in tts_results.items():
            cost_str = f"${r.cost_per_unit:.3f}" if r.cost_per_unit > 0 else "Gratuit"
            vram_str = f"{r.vram_mb:.0f}" if r.vram_mb > 0 else "N/A (API)"
            print(f"{r.model_name:<18} {r.avg_latency:<14.2f} {r.quality_score:<10.1f} {cost_str:<12} {vram_str:<10}")
else:
    print("Benchmark TTS desactive")
BENCHMARK TTS (Text-to-Speech)
=============================================
Texte de test : Welcome to the multi-model audio comparison benchmark. This ...
Longueur : 163 caracteres

--- OpenAI TTS (tts-1) ---
  Run 1/3 : 2.02s
  Run 2/3 : 1.47s
  Run 3/3 : 1.55s
  Latence moyenne : 1.68s
  Taille : 462.9 KB

--- Chatterbox TTS ---
  Chargement du modele...
loaded PerthNet (Implicit) at step 250,000
  VRAM : 3059 MB
  Run 1/3 : 10.49s
  Run 2/3 : 7.00s
  Run 3/3 : 6.72s
  Latence moyenne : 8.07s
  Duree audio : 8.0s
  Modele libere

--- Kokoro TTS (82M) ---
  Chargement du modele...
  VRAM : 0 MB
  Run 1/3 : 6.92s
  Run 2/3 : 3.11s
  Run 3/3 : 3.04s
  Latence moyenne : 4.36s
  Duree audio : 10.9s
  Modele libere

Recapitulatif TTS :
Modele             Latence (s)    MOS est.   Cout/1K ch.  VRAM (MB) 
----------------------------------------------------------------
openai-tts-1       1.68           4.5        $0.015       N/A (API) 
chatterbox         8.07           4.2        Gratuit      3059      
kokoro-82m         4.36           4.0        Gratuit      N/A (API) 

Protocole de benchmark TTS

Cette section execute un benchmark systématique des moteurs TTS. Pour chaque modèle :

  1. Chargement du modèle avec mesure de la VRAM avant/après
  2. Generation de l’audio sur le texte de test standard (163 caractères)
  3. Mesures multiples (3 runs par modèle) pour obtenir une moyenne et un ecart-type
  4. Liberation de la mémoire avec gc.collect() et torch.cuda.empty_cache()

Metriques collectees : - Latence : temps de generation (premier octet) - Qualite : Mean Opinion Score (MOS) estimé (4.0-4.5 selon modèles) - VRAM : consommation GPU du modèle charge - Cout : normalisé pour 1000 caractères

Le code gere gracieusement les absences de modèles (ImportError) et les erreurs d’exécution, permettant au notebook de fonctionner même avec un sous-ensemble de modèles disponibles.

Interpretation : Benchmark TTS

Aspect OpenAI TTS Chatterbox Kokoro
Qualite (MOS) ~4.5 (meilleur) ~4.2 (expressif) ~4.0 (bon)
Latence runtime machine-dep : 1-3s (reseau) runtime machine-dep : 2-5s (GPU) runtime machine-dep : 0.5-1s (leger)
VRAM 0 (cloud) ~8 GB ~2 GB
Cout $15/1M chars Gratuit Gratuit
Emotions Non Oui (exaggeration) Non
Voice cloning Non Oui (6s clip) Non

Points cles : 1. OpenAI TTS offre la meilleure qualite brute mais a un cout recurrent 2. Chatterbox se distingue par le contrôle emotionnel et le voice conditioning 3. Kokoro est le plus leger et rapide, ideal pour du TTS simple en masse


Exercice : Estimation des couts pour un cas d’usage reel

Duree estimee : 15 minutes

Objectif

Calculer le cout mensuel d’un pipeline audio complet (STT + TTS) pour un scénario de production, en comparant les approches cloud vs locale.

Instructions

  1. Définir un scénario d’usage (ex : service client vocal, podcast automatique, assistant)
  2. Estimer le volume mensuel (heures d’audio en entree, caractères en sortie)
  3. Calculer le cout pour chaque combinaison (Whisper API vs local, OpenAI TTS vs Kokoro vs Chatterbox)
  4. Presenter les résultats dans un tableau comparatif

Indices : - # Étape 1 : Choisir un scénario avec un volume mensuel realiste - # Étape 2 : Whisper API = $0.006/min, OpenAI TTS = $15/1M caractères, local = electricite GPU (~$0.001/min) - # Indice : Un service client traite typiquement 2-4h d’appels/jour - # Indice : 1 minute de parole ~= 150 mots ~= 800 caractères

# TODO etudiant : Definir votre scenario d'usage
scenario_name = "service_client"  # ou "podcast", "assistant_vocal", "formation_en_ligne"
daily_hours = 3  # heures d'utilisation par jour
jours_par_mois = 22  # jours ouvrables

# TODO etudiant : Calculer le volume mensuel
monthly_minutes = None  # TODO etudiant : calculer a partir de daily_hours et jours_par_mois
monthly_chars = None    # TODO etudiant : estimer (1 min ~= 800 caracteres pour la sortie TTS)

# TODO etudiant : Calculer le cout pour chaque combinaison
def calculate_monthly_cost(stt_method: str, tts_method: str,
                           minutes_per_month: float,
                           chars_per_month: float) -> dict:
    """
    Calcule le cout mensuel pour une combinaison STT + TTS.
    
    Args:
        stt_method: "whisper_api" ou "faster_whisper"
        tts_method: "openai", "kokoro", ou "chatterbox"
        minutes_per_month: Minutes d'audio a transcrire
        chars_per_month: Caracteres a synthetiser
    
    Returns:
        Dict avec: stt_cost, tts_cost, total_cost, method_name
    """
    # TODO etudiant : Calculer le cout STT
    # Indice : whisper_api = $0.006/min, faster_whisper = $0.001/min (electricite)
    pass
    
    # TODO etudiant : Calculer le cout TTS
    # Indice : openai = $15/1M chars, kokoro/chatterbox = $0.001/min (electricite)
    pass
    
    # TODO etudiant : Retourner le total
    pass

# TODO etudiant : Comparer toutes les combinaisons
# combinations = [
#     ("whisper_api", "openai"),
#     ("whisper_api", "kokoro"),
#     ("faster_whisper", "openai"),
#     ("faster_whisper", "kokoro"),
# ]
# for stt, tts in combinations:
#     cost = calculate_monthly_cost(stt, tts, monthly_minutes, monthly_chars)
#     print(f"{stt} + {tts}: ${cost['total_cost']:.2f}/mois")

# TODO etudiant : Afficher le tableau comparatif
print("Exercice a completer")
Exercice a completer

Details techniques des modèles TTS

OpenAI TTS (tts-1 / tts-1-hd) : - Architecture proprietaire basee sur des modèles de type Bark/YourTTS - Avantage : qualité vocale premium avec 6 voix pre-entrainées (alloy, echo, fable, onyx, nova, shimmer) - Limite : pas de contrôle emotionnel, pas de voice cloning

Chatterbox : - Modèle neuronal de type VITS avec contrôle de la prosodie (paramètre exaggeration) - Innovation : voice conditioning a partir de 6 secondes d’audio (zero-shot voice cloning) - Usage ideal : assistants virtuels avec personnalité vocale cohérente

Kokoro 82M : - Architecture légere (82M paramètres vs plusieurs milliards pour les concurrents) - Performance : latence runtime machine-dep : < 1s sur GPU moderne pour un texte standard - Compromis : qualite vocale legèrement inferieure, pas de contrôle emotionnel

Le choix depend donc de votre priorite : qualité absolue (OpenAI), personnalisation (Chatterbox) ou performance (Kokoro).

Section 5 : Visualisation des résultats

Les graphiques permettent de comparer visuellement les performances des modèles sur plusieurs axes simultanement.

# Visualisation des resultats
print("VISUALISATION DES RESULTATS")
print("=" * 45)

try:
    import matplotlib.pyplot as plt
    from matplotlib.gridspec import GridSpec

    fig = plt.figure(figsize=(16, 10))
    gs = GridSpec(2, 2, figure=fig, hspace=0.35, wspace=0.3)

    # --- 1. Bar chart latence STT ---
    ax1 = fig.add_subplot(gs[0, 0])
    stt_results = {k: v for k, v in all_results.items() if v.category == "stt"}
    if stt_results:
        names = [r.model_name for r in stt_results.values()]
        latencies = [r.avg_latency for r in stt_results.values()]
        errors = [r.std_latency for r in stt_results.values()]
        colors = ['#3498db', '#e74c3c']
        bars = ax1.bar(names, latencies, yerr=errors, color=colors[:len(names)], capsize=5, alpha=0.8)
        ax1.set_ylabel('Latence (s)')
        ax1.set_title('Latence STT par modele')
        for bar, lat in zip(bars, latencies):
            ax1.text(bar.get_x() + bar.get_width()/2., bar.get_height() + 0.05,
                    f'{lat:.2f}s', ha='center', va='bottom', fontsize=10)
    else:
        ax1.text(0.5, 0.5, 'Pas de resultats STT', ha='center', va='center', transform=ax1.transAxes)

    # --- 2. Bar chart latence TTS ---
    ax2 = fig.add_subplot(gs[0, 1])
    tts_results = {k: v for k, v in all_results.items() if v.category == "tts"}
    if tts_results:
        names = [r.model_name for r in tts_results.values()]
        latencies = [r.avg_latency for r in tts_results.values()]
        errors = [r.std_latency for r in tts_results.values()]
        colors = ['#2ecc71', '#f39c12', '#9b59b6']
        bars = ax2.bar(names, latencies, yerr=errors, color=colors[:len(names)], capsize=5, alpha=0.8)
        ax2.set_ylabel('Latence (s)')
        ax2.set_title('Latence TTS par modele')
        for bar, lat in zip(bars, latencies):
            ax2.text(bar.get_x() + bar.get_width()/2., bar.get_height() + 0.05,
                    f'{lat:.2f}s', ha='center', va='bottom', fontsize=10)
    else:
        ax2.text(0.5, 0.5, 'Pas de resultats TTS', ha='center', va='center', transform=ax2.transAxes)

    # --- 3. Analyse des couts (bar chart) ---
    ax3 = fig.add_subplot(gs[1, 0])
    all_names = []
    all_costs = []
    cost_colors = []
    for k, r in all_results.items():
        all_names.append(r.model_name)
        # Normaliser : cout pour 1 heure d'utilisation
        if r.category == "stt":
            hourly_cost = r.cost_per_unit * 60  # 60 minutes
        else:
            hourly_cost = r.cost_per_unit * 50  # ~50K caracteres/heure
        all_costs.append(hourly_cost)
        cost_colors.append('#e74c3c' if hourly_cost > 0 else '#2ecc71')
    if all_names:
        bars = ax3.barh(all_names, all_costs, color=cost_colors, alpha=0.8)
        ax3.set_xlabel('Cout par heure (USD)')
        ax3.set_title('Analyse des couts (USD/heure)')
        for bar, cost in zip(bars, all_costs):
            label = f'${cost:.2f}' if cost > 0 else 'Gratuit'
            ax3.text(bar.get_width() + 0.01, bar.get_y() + bar.get_height()/2.,
                    label, ha='left', va='center', fontsize=10)

    # --- 4. Radar plot TTS (qualite, vitesse, cout, VRAM) ---
    ax4 = fig.add_subplot(gs[1, 1], polar=True)
    if tts_results:
        categories_radar = ['Qualite', 'Vitesse', 'Economie', 'Legerete']
        N = len(categories_radar)
        angles = [n / float(N) * 2 * np.pi for n in range(N)]
        angles += angles[:1]

        radar_colors = ['#2ecc71', '#f39c12', '#9b59b6']
        for idx, (k, r) in enumerate(tts_results.items()):
            # Normaliser chaque metrique sur 0-1
            quality = r.quality_score / 5.0  # MOS max = 5
            speed = 1.0 / (1.0 + r.avg_latency)  # inverse de la latence
            economy = 1.0 if r.cost_per_unit == 0 else 0.3  # gratuit = 1.0
            lightness = 1.0 / (1.0 + r.vram_mb / 1000)  # inverse de la VRAM

            values = [quality, speed, economy, lightness]
            values += values[:1]

            ax4.plot(angles, values, 'o-', linewidth=2, label=r.model_name,
                    color=radar_colors[idx % len(radar_colors)])
            ax4.fill(angles, values, alpha=0.1, color=radar_colors[idx % len(radar_colors)])

        ax4.set_xticks(angles[:-1])
        ax4.set_xticklabels(categories_radar)
        ax4.set_title('Profil TTS multi-criteres')
        ax4.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1), fontsize=9)
    else:
        ax4.text(0, 0, 'Pas de resultats TTS', ha='center', va='center')

    plt.savefig(str(OUTPUT_DIR / "benchmark_results.png"), dpi=120, bbox_inches='tight')
    plt.show()
    print(f"Graphique sauvegarde : benchmark_results.png")

except ImportError:
    print("matplotlib non disponible pour la visualisation")
except Exception as e:
    print(f"Erreur visualisation : {type(e).__name__} - {str(e)[:150]}")
VISUALISATION DES RESULTATS
=============================================

Graphique sauvegarde : benchmark_results.png

Cette section utilise matplotlib pour générer quatre visualisations distinctes qui synthétisent les résultats des benchmarks. Chaque graphique apporte une perspective différente sur les performances des modèles.

Layout en grille 2x2 : 1. Bar chart STT (haut gauche) : comparaison des latences avec barres d’erreur (ecart-type) 2. Bar chart TTS (haut droite) : même approche pour les moteurs de synthese vocale 3. Couts horaires (bas gauche) : visualisation horizontale de l’impact budget 4. Radar plot TTS (bas droite) : diagramme polaire multi-axes pour profil global

Le code utilise GridSpec de matplotlib pour un contrôle précis de la disposition et des espacements entre les sous-graphiques. Les résultats sont sauvegardes en PNG pour inclusion dans des rapports.

Interpretation : Visualisation

Graphique Ce qu’il montre Lecture
Bar chart STT Latence par modèle avec ecart-type Plus bas = plus rapide
Bar chart TTS Latence par moteur TTS Plus bas = plus rapide
Couts horaires Comparaison economique Vert = gratuit, Rouge = payant
Radar TTS Profil multi-critères normalise Plus grand = meilleur

Points cles : 1. Le radar plot permet de voir les forces et faiblesses de chaque modèle en un coup d’oeil 2. Les modèles locaux dominent sur l’axe economie mais peuvent perdre en qualite 3. Le choix optimal depend du cas d’usage (temps reel vs batch, budget vs qualite)

Analyse approfondie des résultats

Les visualisations produites dans cette section permettent de prendre des décisions éclairées sur le choix d’un modèle audio. Cependant, quelques precautions s’imposent :

Limites du benchmark : - Les latences mesurees dependent fortement de votre connexion internet (pour les API) - Le WER n’est pas la seule metrique de qualité STT : la ponctuation, les noms propres, les accents impactent la qualité perçue - Le MOS (Mean Opinion Score) pour le TTS est subjectif et necessiterait une étude utilisateur pour être fiable

Facteurs non considerés : - Temps de froid (cold start) : premier appel plus lent (chargement du modèle) - Consommation énergétique : impact environnemental du GPU local vs datacenters - Robustesse : bruit de fond, accents, vocabulaire spécifique

Pour une application en production, il est recommandé de valider les résultats de ce benchmark sur des données representatives de votre cas d’usage réel.

# Mode interactif - Choix des modeles a comparer
if notebook_mode == "interactive" and not skip_widgets:
    print("MODE INTERACTIF - COMPARAISON PERSONNALISEE")
    print("=" * 50)
    print("\nChoisissez les modeles a comparer :")
    print("  STT : whisper-1, large-v3-turbo")
    print("  TTS : openai, chatterbox, kokoro")
    print("(Laissez vide pour passer a la suite)")

    try:
        user_text = input("\nTexte personnalise pour TTS (ou vide) : ")

        if user_text.strip():
            print(f"\nGeneration avec les modeles TTS disponibles...")
            for k, r in all_results.items():
                if r.category == "tts":
                    print(f"\n  {r.model_name} : resultats du benchmark")
                    print(f"    Latence moyenne : {r.avg_latency:.2f}s")
                    print(f"    Qualite estimee : {r.quality_score:.1f}/5.0")
                    if r.output_data is not None and isinstance(r.output_data, np.ndarray):
                        display_audio_array(r.output_data, r.sample_rate)

            print(f"\nPour une comparaison sur votre texte, re-executez")
            print(f"le notebook avec un texte modifie dans la cellule de test.")
        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 batch - Interface interactive desactivee

Guide de decision et bonnes pratiques

Arbre de decision pour le choix du modèle

Critere Recommandation STT Recommandation TTS
Budget limite faster-whisper local Kokoro ou Chatterbox
Qualite maximale Whisper API OpenAI tts-1-hd
Temps reel faster-whisper (GPU) Kokoro (plus leger)
Hors-ligne faster-whisper Kokoro ou Chatterbox
Emotions/prosodie N/A Chatterbox
Voice cloning N/A Chatterbox ou XTTS
Production a grande echelle faster-whisper Kokoro (leger)

Estimation des couts mensuels

Usage Volume Cout API Cout local (electricite)
Prototype 10 min/jour ~$2/mois ~$0
Application 1h/jour ~$15/mois runtime machine-dep : ~$5/mois (GPU)
Production 10h/jour ~$150/mois runtime machine-dep : ~$30/mois (GPU)

Comprendre les compromis architecturels

Le choix d’une architecture audio (API vs local) impacte plusieurs dimensions non techniques :

Aspect juridique : - API cloud : données envoyées vers des serveurs tiers (RGPD a considérer) - Local : données restent sur votre infrastructure (conformité facilitée)

Aspect operationnel : - API cloud : dépendance à la connexion internet, SLA du fournisseur - Local : maintenance GPU, mises à jour de modèles à gérer

Aspect scalabilite : - API cloud : scalabilite infinie (théorique), mais facturation exponentielle - Local : scalabilite limitée par le GPU, mais cout predictible

En pratique, les architectures hybrides sont frequentes : API cloud pour le prototypage et les pics de charge, modèles locaux pour la production régulière.

# 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"Device : {device}")
print(f"Modeles STT testes : {[r.model_name for r in all_results.values() if r.category == 'stt']}")
print(f"Modeles TTS testes : {[r.model_name for r in all_results.values() if r.category == 'tts']}")
print(f"Runs par modele : {num_runs}")

if gpu_available:
    vram_current = torch.cuda.memory_allocated(0) / (1024**3)
    print(f"VRAM actuelle : {vram_current:.2f} GB")

# Resume complet
if all_results:
    print(f"\nResume des benchmarks :")
    for k, r in all_results.items():
        print(f"  {r.model_name:<20} : latence={r.avg_latency:.2f}s, qualite={r.quality_score:.2f}")

    # Sauvegarder les resultats en JSON
    if save_results:
        results_json = {k: v.to_dict() for k, v in all_results.items()}
        json_path = OUTPUT_DIR / "benchmark_results.json"
        with open(json_path, 'w') as f:
            json.dump(results_json, f, indent=2)
        print(f"\nResultats sauvegardes : {json_path.name}")

if save_results:
    saved = list(OUTPUT_DIR.glob('*'))
    total_size = sum(f.stat().st_size for f in saved if f.is_file()) / (1024*1024)
    print(f"Fichiers sauvegardes : {len(saved)} ({total_size:.1f} MB) dans {OUTPUT_DIR.name}")

# Liberation memoire
gc.collect()
if gpu_available:
    torch.cuda.empty_cache()
    print(f"Memoire GPU liberee")

print(f"\nPROCHAINES ETAPES")
print(f"1. Construire des pipelines audio complets STT->LLM->TTS (03-2)")
print(f"2. Explorer l'API Realtime d'OpenAI pour la voix (03-3)")
print(f"3. Creer du contenu educatif audio automatise (04-1)")

print(f"\nNotebook Comparaison Multi-Modeles termine - {datetime.now().strftime('%H:%M:%S')}")
STATISTIQUES DE SESSION
=============================================
Date : 2026-09-04 14:36:21
Device : cuda
Modeles STT testes : ['whisper-1', 'large-v3-turbo']
Modeles TTS testes : ['openai-tts-1', 'chatterbox', 'kokoro-82m']
Runs par modele : 3
VRAM actuelle : 0.01 GB

Resume des benchmarks :
  whisper-1            : latence=1.53s, qualite=0.00
  large-v3-turbo       : latence=0.81s, qualite=0.00
  openai-tts-1         : latence=1.68s, qualite=4.50
  chatterbox           : latence=8.07s, qualite=4.20
  kokoro-82m           : latence=4.36s, qualite=4.00

Resultats sauvegardes : benchmark_results.json
Fichiers sauvegardes : 6 (2.1 MB) dans comparison
Memoire GPU liberee

PROCHAINES ETAPES
1. Construire des pipelines audio complets STT->LLM->TTS (03-2)
2. Explorer l'API Realtime d'OpenAI pour la voix (03-3)
3. Creer du contenu educatif audio automatise (04-1)

Notebook Comparaison Multi-Modeles termine - 14:36:21

Synthese des apprentissages

Ce notebook a explore l’ecosysteme des modèles audio STT/TTS en 2026. Le paysage a considérablement evolve : les modèles open-source comme faster-whisper et Kokoro rivalisent maintenant avec les solutions cloud commerciales.

Evolution du marche : - 2022-2023 : Domination des API cloud (Whisper, ElevenLabs, OpenAI) - 2024-2025 : Emergence de modèles locaux performants (faster-whisper, Kokoro, Chatterbox) - 2026 : Maturite du ecosysteme open-source avec qualite equivalente

Prochaine revolution : les modèles multimodaux end-to-end (GPT-4o Audio, Gemini 2.0) qui unifient STT, LLM et TTS dans une seule architecture, eliminant les pertes de qualité aux frontières.

Ce notebook pose les bases pour construire des pipelines audio complexes, que nous explorerons dans le prochain notebook sur l’orchestration de pipelines audio complets.


Exemple guide : Benchmark Personnalise

Duree estimee : 20-25 minutes

Objectif

Créer un benchmark personnalise pour comparer les modèles STT et TTS sur vos propres données.

Instructions

  1. Choisir un fichier audio personnel (WAV ou MP3, 10-30 secondes)
  2. Créer une fonction de benchmark qui mesure :
    • Latence (temps de transcription/generation)
    • Qualite (WER pour STT, MOS subjectif pour TTS)
    • Cout (estime)
  3. Comparer au moins 2 modèles STT et 2 modèles TTS
  4. Generer un tableau recapitulatif et une visualisation

Indices : - Utilisez la classe BenchmarkResult du notebook comme modèle - Pour le WER, utilisez la fonction word_error_rate() déjà définie - Pour le cout, consultez les tarifs dans les tables du notebook - Pour la visualisation, inspirez-vous de la section 5

# Exercice: Choisir votre fichier audio
my_audio_path = "chemin/vers/votre/audio.wav"

# Exercice: Definir votre reference textuelle (pour WER)
my_reference_text = "Votre texte de reference ici..."

def my_benchmark_stt(audio_path, reference_text):
    """
    Benchmark STT personnalise.
    
    Args:
        audio_path: Chemin vers le fichier audio
        reference_text: Texte de reference pour calculer le WER
    
    Returns:
        Dict avec metriques: latence, wer, cout
    """
    # Exercice: Transcrire avec whisper-1 (API) si disponible
    # Indice: utiliser client.audio.transcriptions.create()
    # Indice: mesurer le temps avec time.time()
    pass

def my_benchmark_tts(text, models_to_test):
    """
    Benchmark TTS personnalise.
    
    Args:
        text: Texte a synthetiser
        models_to_test: Liste des modeles a tester
    
    Returns:
        Dict avec metriques: latence, duree_audio, cout
    """
    # Exercice: Generer avec chaque modele TTS
    # Indice: mesurer le temps de generation
    # Indice: evaluer subjectivement la qualite (MOS 1-5)
    pass

# Exercice: Executer le benchmark STT et afficher les resultats
# resultats_stt = my_benchmark_stt(my_audio_path, my_reference_text)

# Exercice: Executer le benchmark TTS et afficher les resultats
# resultats_tts = my_benchmark_tts("Texte de test pour TTS", ["openai", "kokoro"])

# Exercice: Creer un tableau comparatif avec pandas ou formatage manuel
# Exercice: Generer une visualisation (bar chart des latences)

Structure de l’Exemple guide

Le notebook fournit tous les outils necessaires pour realiser ce benchmark personnalise :

  1. Classes et fonctions utilitaires : BenchmarkResult, word_error_rate(), measure_vram()
  2. Modèles disponibles : Whisper API, faster-whisper, OpenAI TTS, Chatterbox, Kokoro
  3. Visualisations : bar charts, radar plots, graphiques de couts

L’objectif est de reinvestir les concepts appris dans les sections précédentes pour construire votre propre protocole de benchmark.

Exercice 3 : Analyse cout-qualite et recommandation

Comparez les modèles audio selon un rapport cout/qualite. Recommandez le meilleur rapport qualite-prix.

Indice : Calculer le ratio qualite/cout pour chaque modèle et trier par valeur decroissante.

def recommend_best_model(models_data, budget_per_minute=None):
    # Etape 1 : Calculer le ratio qualite/cout de chaque modele
    # Etape 2 : Filtrer par budget si specifie
    # Etape 3 : Trier et retourner le top-3
    pass

result = None  # TODO etudiant
print("Exercice a completer")
Exercice a completer

Critères de reussite

Critere Description
Fonction my_benchmark_stt Mesure latence et WER pour au moins 2 modèles
Fonction my_benchmark_tts Mesure latence et qualite pour au moins 2 modèles
Tableau comparatif Resume clair des metriques (Modèle, Latence, Qualite, Cout)
Visualisation Bar chart ou graphique des résultats

Extensions possibles

  • Ajouter une comparaison TTS avec votre propre texte
  • Generer un radar plot multi-critères (latence, qualite, cout, VRAM)
  • Sauvegarder les résultats en JSON pour comparaison future
  • Implementer un test de charge avec plusieurs fichiers audio
Retour au sommet