# 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"
# Choix des modeles
test_fish_s2_pro = True # Fish S2 Pro (service HTTP self-hosted quantise)
test_dia_tts = True # Dia TTS (1.7B, ~6 GB VRAM)
# Service HTTP Fish S2 Pro : Docker self-hosted, BnB 4-bit NF4, GPU1 (RTX 3090)
# docker-configurations/services/tts-fishaudio/ -- port 8197 host -> 8080 container
# Aucune cle API requise : le modele tourne dans le conteneur (quantise ~5 GB VRAM)
fish_http_url = "http://localhost:8197"
fish_reference_id = "v4_comtesse_cold" # voix de reference pour le voice cloning
# Configuration generale
device = "cuda" # "cuda" ou "cpu"
save_results = True # Sauvegarder les fichiers audio
test_voice_cloning = True # Tester le voice cloning
test_multilingual = True # Tester la generation multilingueTTS Expressif : Fish S2 Pro et Modèles SOTA
Module : 02-Audio-Advanced
Niveau : Avance
Technologies : Fish S2 Pro (5B), Dia TTS (1.7B), tags d’expressivite
Duree estimee : 50 minutes
Objectifs d’Apprentissage
Prerequis
- GPU NVIDIA avec 6+ GB VRAM (Dia TTS) ou 14+ GB (Fish S2 Pro)
pip install fish-speechoupip install fish-audio-sdk(API cloud)- Connaissances TTS de base (notebooks 01-1, 01-5, 02-1)
Navigation : << 02-7 | Index | 03-1 >>
# Parameters
notebook_mode = "batch"
skip_widgets = TrueLes paramètres Papermill selectionnent les moteurs TTS (Fish S2 Pro, Dia TTS), configurent le device et les options de voice cloning. La cellule suivante initialise l’environnement Python et detecte le GPU disponible.
# Setup environnement et imports
import os
import sys
import time
import gc
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional
import logging
import warnings
# Filtrer les warnings de bibliotheques (tqdm IProgress, torch weight_norm FutureWarning)
# qui sinon exposent le chemin absolu de l'environnement conda dans les sorties
warnings.filterwarnings("ignore", category=FutureWarning)
warnings.filterwarnings("ignore", message=".*IProgress not found.*")
import numpy as np
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' / 'expressive-tts'
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
# Configuration logging
logging.basicConfig(level=getattr(logging, debug_level))
logger = logging.getLogger('expressive-tts')
# Verification GPU
gpu_available = False
gpu_vram = 0
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")
if device == "cuda":
device = "cpu"
except ImportError:
print("torch non installe")
device = "cpu"
print(f"\nTTS Expressif - Fish S2 Pro & Modeles SOTA")
print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Mode : {notebook_mode}, Device : {device}")
print(f"Fish S2 Pro : {'actif' if test_fish_s2_pro else 'desactive'}")
print(f"Dia TTS : {'actif' if test_dia_tts else 'desactive'}")
print(f"Sortie : {OUTPUT_DIR.relative_to(GENAI_ROOT)}")Helpers audio importes
GPU : NVIDIA GeForce RTX 3090 (24.0 GB VRAM)
TTS Expressif - Fish S2 Pro & Modeles SOTA
Date : 2026-08-30 11:16:38
Mode : batch, Device : cuda
Fish S2 Pro : actif
Dia TTS : actif
Sortie : outputs\audio\expressive-tts
Interprétation : Configuration de l’environnement
Sortie obtenue : Détection réussie du GPU RTX 3090 avec 24 GB VRAM.
| Composant | État | VRAM disponible |
|---|---|---|
| GPU NVIDIA | RTX 3090 | 24.0 GB |
| Device cible | cuda | runtime machine-dep : suffisant pour Fish S2 Pro |
| Helpers audio | Importés | Fonctions play/save disponibles |
Points clés : 1. Les 24 GB VRAM permettent runtime machine-dep : executer Fish S2 Pro (14-18 GB requis) et Dia TTS (~6 GB) 2. Le répertoire de sortie est créé automatiquement pour stocker les fichiers audio générés 3. Le niveau de logging est configurable via debug_level
Note technique : Si VRAM < 14 GB, utiliser l’API cloud Fish Audio ou Dia TTS à la place.
L’environnement Python est configure. La cellule suivante charge le fichier .env pour recuperer le token Fish Audio API (FISH_AUDIO_API_KEY) et le token HuggingFace pour le chargement local de Fish S2 Pro.
# Chargement robuste de la configuration .env
from dotenv import load_dotenv
import os
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.relative_to(GENAI_ROOT)}")
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")
# URL du service HTTP Fish S2 Pro (self-hosted quantise) -- aucun token requis
# Le modele S2-Pro tourne deja dans le conteneur Docker (BnB NF4 4-bit, GPU1).
fish_http_url = os.environ.get("FISH_HTTP_URL", fish_http_url)
fish_reference_id = os.environ.get("FISH_REFERENCE_ID", fish_reference_id)
print(f"Service Fish S2 Pro : {fish_http_url} (aucune cle API requise)")
print(f"Reference voice cloning : {fish_reference_id}")WARNING: .env non trouve, utilisation variables environnement
Service Fish S2 Pro : http://localhost:8197 (aucune cle API requise)
Reference voice cloning : v4_comtesse_cold
Interpretation : Chargement des variables d’environnement
Sortie obtenue : .env non trouve (fallback variables environnement) ; le service Fish S2 Pro est adresse via FISH_HTTP_URL (defaut http://localhost:8197).
| Variable | Statut | Impact |
|---|---|---|
FISH_HTTP_URL |
http://localhost:8197 |
Service HTTP self-hosted quantise (Docker) |
FISH_REFERENCE_ID |
v4_comtesse_cold |
Voix de reference pour le voice cloning |
FISH_AUDIO_API_KEY |
Non requise | Le modele tourne dans le conteneur (aucune cle API cloud) |
Points cles : 1. Le notebook appelle le service HTTP local : aucune cle API cloud, aucun import Python du moteur 2. Le modele S2-Pro est quantise (BnB NF4 4-bit) et tourne dans le conteneur Docker sur GPU1 3. Dia TTS reste charge en local (GPU device 0)
Note technique : le service est deja deploye dans
docker-configurations/services/tts-fishaudio/. Ce chemin (service HTTP quantise) etait la voie deja disponible sur cette lane et est reutilise ici.
Dependances GPU Optionnelles
Ce notebook teste plusieurs modèles TTS avec des besoins VRAM différents :
| Modèle | VRAM (fp16) | VRAM (int8) | Alternative |
|---|---|---|---|
| Fish S2 Pro | ~14-18 GB | ~10-12 GB | API cloud (pas de GPU) |
| Dia TTS | ~6-8 GB | - | - |
| Kokoro (ref) | ~2 GB | - | Service tts-api.myia.io |
Section 1 : Evolution du TTS vers l’expressivite
Le TTS a evolue en trois generations :
| Generation | Exemples | Contrôle expressif |
|---|---|---|
| Concatenatif | Google TTS classique | Aucun |
| Neural basique | Tacotron, VITS | Voix + vitesse |
| Neural avance | Kokoro, XTTS | Style tokens, clonage |
| LLM-based (2024-2025) | Fish S2 Pro, Dia | Tags inline, multi-speaker, emotions |
Panorama des modèles expressifs (2025)
| Modèle | Params | Tags inline | Voice clone | Langues | VRAM |
|---|---|---|---|---|---|
| Fish S2 Pro | 5B | 15000+ tags | Zero-shot | 80+ | ~14-18 GB |
| Dia TTS | 1.7B | [laugh], (action) | Limite | ~10 | ~6-8 GB |
| Parler TTS | 2.4B | Description NL | Non | EN | ~8-10 GB |
| Sesame CSM | ~1B | Contextuel | Conditioning | ~5 | ~4-6 GB |
| Kokoro | 82M | Style tokens | Non | ~5 | ~2 GB |
| XTTS v2 | 500M | Limite | Zero-shot | ~16 | ~6 GB |
| Chatterbox | 400M | Emotions | Zero-shot | EN | ~8 GB |
Section 2 : Fish S2 Pro - Architecture et installation
Fish S2 Pro utilise une architecture Dual-AR (Dual Autoregressive) :
| Composant | Paramètres | Rôle |
|---|---|---|
| Slow AR | 4B | Genere les tokens sémantiques (contexte long) |
| Fast AR | 400M | Genere les tokens acoustiques (details fins) |
| RVQ Codec | - | 10 codebooks, ~21 Hz |
| Vocodeur | - | Tokens -> audio 44.1 kHz |
Texte + [tags] --> [Slow AR, 4B] --> tokens sémantiques
|
[Fast AR, 400M] --> tokens acoustiques
|
[Vocodeur] --> audio 44.1kHz
Performances : RTF 0.195 sur H200, ~100ms time-to-first-audio.
Le diagramme ci-dessous rend ce pipeline TTS en deux etages autoregressifs suivis du vocodeur, sous forme de graphe.
flowchart LR
T["Texte + [tags]"] --> S["Slow AR (4B)"] --> TS["tokens sémantiques"]
TS --> F["Fast AR (400M)"] --> TA["tokens acoustiques"]
TA --> V["Vocodeur"] --> O(["audio 44.1kHz"])
classDef core fill:#fff3cd,stroke:#b8860b,color:#5c4400
classDef io fill:#cfe2ff,stroke:#084298,color:#052c65
classDef out fill:#d1e7dd,stroke:#0f5132,color:#0a3622
class S,F,V core
class TS,TA io
class T io
class O out
Lecture. Le texte (enrichi de tags expressifs) passe par un gros modèle autoregressif lent (4B) qui produit des tokens sémantiques – le quoi dire et comment l’intoner – puis par un modèle rapide et leger (400M) qui les raffine en tokens acoustiques – le grain fin du signal. Le vocodeur reconstruit enfin la forme d’onde. Decoupler un gros modèle sémantique d’un petit modèle acoustique est le compromis classique qualite vs latence du TTS expressif moderne.
# Verification des dependances et du service HTTP Fish S2 Pro
print("VERIFICATION DES DEPENDANCES")
print("=" * 45)
fish_http_ok = False
dia_available = False
# Service HTTP Fish S2 Pro (self-hosted quantise : pas d'import Python, appel REST)
try:
import requests
http_lib_ok = True
except ImportError:
http_lib_ok = False
print("requests non installe (pip install requests)")
if http_lib_ok:
try:
r = requests.get(f"{fish_http_url.rstrip('/')}/v1/health", timeout=10)
fish_http_ok = (r.status_code == 200 and r.json().get("status") == "ok")
print(f"Service Fish S2 Pro HTTP : {'OPERATIONNEL' if fish_http_ok else 'injoignable'} ({fish_http_url})")
if not fish_http_ok:
print(f" /v1/health -> HTTP {r.status_code}")
except Exception as e:
fish_http_ok = False
print(f" Service HTTP injoignable : {type(e).__name__} - {str(e)[:100]}")
else:
print("Service Fish S2 Pro : non testable (requests manquant)")
# Dia TTS (modele local, GPU device 0)
try:
import dia
dia_available = True
print("dia-tts installe")
except ImportError:
print("dia-tts non installe (pip install dia-tts)")
# Dependances communes
import soundfile as sf
print("soundfile disponible")
print(f"\nModeles disponibles :")
print(f" Fish S2 Pro : {'service HTTP operationnel' if fish_http_ok else 'injoignable'}")
print(f" Dia TTS : {'disponible' if dia_available else 'non disponible'}")VERIFICATION DES DEPENDANCES
=============================================
Service Fish S2 Pro HTTP : OPERATIONNEL (http://localhost:8197)
dia-tts installe
soundfile disponible
Modeles disponibles :
Fish S2 Pro : service HTTP operationnel
Dia TTS : disponible
Interpretation : Verification des dependances
Sortie obtenue : le service HTTP Fish S2 Pro est operationnel (GB et port 8197) ; dia-tts est installe.
| Composant | Statut | Voie |
|---|---|---|
| Service Fish S2 Pro HTTP | Operationnel | REST POST /v1/tts (conteneur Docker, GPU1) |
| dia-tts | Installe | Import local, GPU device 0 |
| soundfile | Disponible | OK |
Points cles : 1. Fish S2 Pro ne s’importe plus : le moteur tourne dans le conteneur, le notebook appelle l’API HTTP 2. Le package PyPI fish-speech (0.1.0 stale) ne contient pas fish_speech.inference : le chemin Python local est inutilisable, le service HTTP est la voie reelle 3. Dia TTS est execute reellement en local pour la comparaison
Note technique : la voie “service HTTP self-hosted quantise” remplace l’API cloud (qui aurait requis une cle) et le moteur Python local (stale/Linux-only).
Les dependances sont verifiees (fish-speech, fish-audio-sdk, dia-tts). La cellule suivante tente de charger Fish S2 Pro : d’abord en local runtime machine-dep : GPU 14+ GB, puis via l’API cloud si use_fish_api=True.
# Disposition du service HTTP Fish S2 Pro
print("DISPONIBILITE DU SERVICE FISH S2 PRO")
print("=" * 45)
fish_model = None
fish_session = None
if test_fish_s2_pro:
if fish_http_ok:
print(f"Service HTTP operationnel : {fish_http_url}")
print(" Modele S2-Pro quantise (BnB NF4 4-bit) deja charge dans le conteneur (GPU1)")
print(" Le notebook appelle POST /v1/tts : aucune VRAM notebook consommee pour Fish")
try:
import torch as _t
if _t.cuda.is_available():
free0 = _t.cuda.mem_get_info(0)
print(f" GPU notebook (device 0) : {_t.cuda.get_device_name(0)} - {free0[0]/(1024**3):.1f} GB libres")
print(" (Fish S2 Pro tourne sur le device 1, dans le conteneur Docker)")
except Exception:
pass
else:
print(f"Service HTTP Fish non operationnel sur {fish_http_url}")
print(" Demarrer le service : docker compose up -d dans docker-configurations/services/tts-fishaudio/")
print(" ou definir FISH_HTTP_URL vers un endpoint /v1/tts joignable")
else:
print("Test Fish S2 Pro desactive")DISPONIBILITE DU SERVICE FISH S2 PRO
=============================================
Service HTTP operationnel : http://localhost:8197
Modele S2-Pro quantise (BnB NF4 4-bit) deja charge dans le conteneur (GPU1)
Le notebook appelle POST /v1/tts : aucune VRAM notebook consommee pour Fish
GPU notebook (device 0) : NVIDIA GeForce RTX 3090 - 22.8 GB libres
(Fish S2 Pro tourne sur le device 1, dans le conteneur Docker)
Interpretation : Disponibilite du service Fish S2 Pro
Sortie obtenue : le service HTTP est operationnel sur http://localhost:8197.
| Methode | Statut | Voie |
|---|---|---|
| Service HTTP self-hosted | Operationnel | Docker tts-fishaudio, BnB NF4 4-bit, GPU1 (RTX 3090) |
| API cloud (SDK + cle) | Non utilisee | Aucune cle requise : le modele est local |
Moteur Python local (fish_speech) |
Remplace | Package PyPI stale (0.1.0) sans TTSInference |
Points cles : 1. Le modele S2-Pro est deja charge dans le conteneur : le notebook n’utilise aucune VRAM pour Fish 2. L’architecture Dual-AR (Slow AR 4B + Fast AR 400M) reste celle documentee ; la quantisation NF4 4-bit reduit la VRAM de ~18 GB a ~5 GB 3. Cette voie (service HTTP deja deploye) etait disponible sur cette lane et n’avait pas ete reutilisee par le run precedent (qui cherchait une cle API ou le moteur Python Linux-only)
Note technique : le service est declare dans
docker-configurations/services/tts-fishaudio/docker-compose.yml(imagefishaudio/fish-speech:server-cuda-bnb4).
Section 4 : Dia TTS - Alternative legere
Dia TTS (Nari Labs) est une alternative plus legere qui supporte également les tags expressifs et le multi-speaker natif.
| Aspect | Fish S2 Pro | Dia TTS |
|---|---|---|
| Paramètres | 5B | 1.7B |
| VRAM | ~14-18 GB | ~6-8 GB |
| Tags inline | 15000+ | ~10-20 |
| Multi-speaker | Non natif | Natif (S1/S2) |
| Voice cloning | Zero-shot | Limite |
| Langues | 80+ | ~10 |
Introduction : Tests Dia TTS
Cette section charge et teste Dia TTS, une alternative plus légère à Fish S2 Pro avec des caractéristiques différentes :
Avantages de Dia TTS : - Multi-speaker natif : Syntaxe [S1], [S2] pour les dialogues - VRAM réduite : ~6-8 GB contre 14-18 GB pour Fish S2 Pro - Actions expressives : Syntaxe (laughs), (sighs), (pause) plus naturelle - Licence Apache 2.0 : Usage commercial sans restriction
Tests effectués : 1. Dialogue : Deux speakers avec actions (laughs) 2. Expression : Émotions (sighs), (pause), [laugh] 3. Narration : Texte narratif avec ton dramatique
Note technique : Dia TTS utilise une syntaxe différente de Fish S2 Pro. Les actions sont entre parenthèses
(action)et les speakers entre crochets[S1].
# Chargement et test de Dia TTS
print("DIA TTS - ALTERNATIVE LEGERE")
print("=" * 45)
dia_model = None
dia_results = {}
if test_dia_tts and dia_available and gpu_available:
print("Chargement de Dia TTS...")
try:
from dia.model import Dia, DEFAULT_SAMPLE_RATE
start_time = time.time()
dia_model = Dia.from_pretrained("nari-labs/Dia-1.6B-0626", compute_dtype="float16")
load_time = time.time() - start_time
print(f" Charge en {load_time:.1f}s")
if gpu_available:
vram_used = torch.cuda.memory_allocated(0) / (1024**3)
print(f" VRAM utilisee : {vram_used:.2f} GB")
# Tests expressifs Dia
dia_tests = [
{
"name": "Dialogue",
"text": "[S1] Have you seen the latest AI model? [S2] (laughs) Yes, it's incredible! [S1] I know, right?",
},
{
"name": "Expression",
"text": "[S1] (sighs) Another Monday morning. (pause) But at least the coffee is good. [laugh]",
},
{
"name": "Narration",
"text": "[S1] In a world where machines can speak with emotion, the line between human and artificial grows ever thinner.",
},
]
for test in dia_tests:
print(f"\n--- {test['name']} ---")
print(f" Texte : {test['text'][:80]}...")
start_time = time.time()
audios = dia_model.generate(test["text"])
gen_time = time.time() - start_time
if audios is not None:
# Dia generate() retourne list[np.ndarray] (DAC @ 44100 Hz) ou ndarray
audio_np = np.asarray(audios[0] if isinstance(audios, list) else audios)
# Sauvegarder
sr = DEFAULT_SAMPLE_RATE # Dia = 44100 Hz (codec DAC)
safe_name = test['name'].lower().replace(' ', '_')
filepath = OUTPUT_DIR / f"dia_{safe_name}.wav"
sf.write(str(filepath), audio_np, sr)
duration = len(audio_np) / sr
dia_results[test["name"]] = {
"duration": duration,
"gen_time": gen_time,
"sample_rate": sr,
}
print(f" Duree : {duration:.1f}s | Temps : {gen_time:.2f}s")
_preview = min(int(sr * 3), len(audio_np)) # ~3s (decision b)
display_audio_array(audio_np[:_preview], sr)
if dia_results:
print(f"\nRecapitulatif Dia TTS :")
print(f"{'Test':<16} {'Duree (s)':<12} {'Temps gen (s)':<15}")
print("-" * 43)
for name, data in dia_results.items():
print(f"{name:<16} {data['duration']:<12.1f} {data['gen_time']:<15.2f}")
except Exception as e:
print(f" Erreur : {type(e).__name__} - {str(e)[:150]}")
elif test_dia_tts and not dia_available:
print("Dia TTS non installe")
print(" pip install dia-tts")
print(f"\nExemples de syntaxe Dia TTS :")
print(f" Multi-speaker : [S1] Hello! [S2] Hi there!")
print(f" Action : (laughs) That's great!")
print(f" Emotion : (sighs) Well, here we go again.")
elif not test_dia_tts:
print("Test Dia TTS desactive")
else:
print("GPU non disponible")DIA TTS - ALTERNATIVE LEGERE
=============================================
Chargement de Dia TTS...
Charge en 11.4s
VRAM utilisee : 3.29 GB
--- Dialogue ---
Texte : [S1] Have you seen the latest AI model? [S2] (laughs) Yes, it's incredible! [S1]...
Duree : 7.7s | Temps : 33.04s
--- Expression ---
Texte : [S1] (sighs) Another Monday morning. (pause) But at least the coffee is good. [l...
Duree : 29.9s | Temps : 103.86s
--- Narration ---
Texte : [S1] In a world where machines can speak with emotion, the line between human an...
Duree : 8.3s | Temps : 30.86s
Recapitulatif Dia TTS :
Test Duree (s) Temps gen (s)
-------------------------------------------
Dialogue 7.7 33.04
Expression 29.9 103.86
Narration 8.3 30.86
Interpretation : Dia TTS
| Aspect | Observation |
|---|---|
| Multi-speaker | Transition fluide entre S1 et S2 |
Actions (laughs) |
Plus naturel que les tags explicites |
| VRAM | ~6 GB, accessible sur la plupart des GPU |
| Qualite | Bonne, inferieure a Fish S2 Pro |
Avantage principal de Dia TTS : le support multi-speaker natif. Un seul appel genere un dialogue complet avec des voix différentes.
Section 5 : Voice cloning
Le voice cloning zero-shot permet de reproduire une voix a partir d’un court echantillon audio (10-30s). Fish S2 Pro excelle dans ce domaine.
| Modèle | Reference min | Qualite clonage | Cross-lingual |
|---|---|---|---|
| Fish S2 Pro | 10-15s | Excellente | Oui (80+ langues) |
| XTTS v2 | 6s | Bonne | Oui (16 langues) |
| Chatterbox | 5s | Très bonne | Non (EN) |
| Dia TTS | Non supporte | - | - |
# Voice cloning avec Fish S2 Pro (reference_id)
print("VOICE CLONING")
print("=" * 45)
if test_voice_cloning and fish_http_ok and fish_reference_id:
print(f"Reference utilisee : {fish_reference_id} (references/{fish_reference_id}/sample.wav)")
clone_tests = [
"The weather today is absolutely beautiful. I think we should go for a walk.",
"[whisper] This is a secret message, spoken in the cloned voice.",
]
for i, text in enumerate(clone_tests):
print(f"\n--- Clone test {i+1} ---")
print(f" Texte : {text}")
generate_fish_tts(
text,
f"fish_clone_{i+1}",
reference_id=fish_reference_id
)
else:
if test_voice_cloning:
print("Fish S2 Pro non disponible pour le voice cloning")
print(" Service HTTP injoignable ou reference_id manquant")
else:
print("Test voice cloning desactive")VOICE CLONING
=============================================
Reference utilisee : v4_comtesse_cold (references/v4_comtesse_cold/sample.wav)
--- Clone test 1 ---
Texte : The weather today is absolutely beautiful. I think we should go for a walk.
Duree : 5.2s | Temps : 44.13s | SR : 44100 Hz | 448 KB
--- Clone test 2 ---
Texte : [whisper] This is a secret message, spoken in the cloned voice.
Duree : 3.8s | Temps : 31.45s | SR : 44100 Hz | 328 KB
Introduction : Voice Cloning Zero-Shot
Le voice cloning permet de reproduire une voix à partir d’un court échantillon audio (10-30 secondes). Fish S2 Pro excelle dans cette tâche grâce à sa grande capacité et son entraînement sur des données multi-speakers.
Processus de clonage : 1. Enregistrement de référence : Audio de 10-30s avec transcription 2. Conditionnement : Le modèle utilise l’audio comme référence de style 3. Génération : Nouveau texte dans la voix clonée
Paramètres clés : - reference_audio : Chemin vers le fichier audio de référence - reference_text : Transcription exacte de l’audio (améliore la fidélité)
Applications : - Doublage personnalisé - Narration avec une voix spécifique - Accessibilité (synthèse de la voix de l’utilisateur) - Localization audio dans la langue de l’audio original
Note technique : La qualité du clonage dépend de la qualité de l’audio de référence (bruit, articulation, durée optimale 15-25s).
Section 6 : Generation multilingue
Fish S2 Pro supporte 80+ langues avec detection automatique. Le cross-lingual cloning permet de cloner une voix dans une langue et de parler dans une autre.
| Tier | Langues | Qualite |
|---|---|---|
| Tier 1 | Japonais, Anglais, Chinois | Excellente |
| Tier 2 | Coreen, Espagnol, Portugais, Arabe, Russe, Francais, Allemand | Très bonne |
| Tier 3+ | 70+ autres langues | Variable |
# Test multilingue
print("GENERATION MULTILINGUE")
print("=" * 45)
multilingual_tests = [
{"lang": "Anglais", "text": "Hello! This is a demonstration of multilingual speech synthesis."},
{"lang": "Francais", "text": "Bonjour ! Voici une demonstration de la synthese vocale multilingue."},
{"lang": "Japonais", "text": "\u3053\u3093\u306b\u3061\u306f\uff01\u591a\u8a00\u8a9e\u97f3\u58f0\u5408\u6210\u306e\u30c7\u30e2\u30f3\u30b9\u30c8\u30ec\u30fc\u30b7\u30e7\u30f3\u3067\u3059\u3002"},
{"lang": "Espagnol", "text": "Hola! Esta es una demostracion de sintesis de voz multilingue."},
]
multilingual_results = {}
if test_multilingual and fish_http_ok:
for test in multilingual_tests:
print(f"\n--- {test['lang']} ---")
print(f" {test['text']}")
result = generate_fish_tts(test["text"], f"fish_lang_{test['lang'].lower()}")
if result:
multilingual_results[test["lang"]] = result
if multilingual_results:
print(f"\nRecapitulatif multilingue :")
print(f"{'Langue':<12} {'Duree (s)':<12} {'Temps gen (s)':<15}")
print("-" * 39)
for lang, data in multilingual_results.items():
print(f"{lang:<12} {data['duration']:<12.1f} {data['gen_time']:<15.2f}")
else:
if test_multilingual:
print("Service Fish S2 Pro injoignable")
print(f"\nExemples multilingues (detection automatique) :")
for test in multilingual_tests:
print(f" {test['lang']} : {test['text'][:60]}...")
else:
print("Test multilingue desactive")GENERATION MULTILINGUE
=============================================
--- Anglais ---
Hello! This is a demonstration of multilingual speech synthesis.
Duree : 4.9s | Temps : 38.75s | SR : 44100 Hz | 424 KB
--- Francais ---
Bonjour ! Voici une demonstration de la synthese vocale multilingue.
Duree : 4.6s | Temps : 36.19s | SR : 44100 Hz | 396 KB
--- Japonais ---
こんにちは!多言語音声合成のデモンストレーションです。
Duree : 4.0s | Temps : 32.45s | SR : 44100 Hz | 348 KB
--- Espagnol ---
Hola! Esta es una demostracion de sintesis de voz multilingue.
Duree : 3.9s | Temps : 31.42s | SR : 44100 Hz | 332 KB
Recapitulatif multilingue :
Langue Duree (s) Temps gen (s)
---------------------------------------
Anglais 4.9 38.75
Francais 4.6 36.19
Japonais 4.0 32.45
Espagnol 3.9 31.42
Introduction : Génération Multilingue
Fish S2 Pro supporte plus de 80 langues avec détection automatique. Le modèle identifie la langue du texte source et adapte la prononciation et l’intonation accordingly.
Hiérarchie des langues (Fish S2 Pro) : - Tier 1 : Japonais, Anglais, Chinois (meilleure qualité) - Tier 2 : Coréen, Espagnol, Portugais, Arabe, Russe, Français, Allemand - Tier 3+ : 70+ autres langues (qualité variable)
Cross-lingual cloning : Il est possible de cloner une voix en anglais et de générer du texte en japonais, français, etc. La voix est préservée mais l’accent s’adapte à la langue cible.
Tests effectués : 1. Anglais (Tier 1) : Référence pour la qualité 2. Français (Tier 2) : Test de langue secondaire 3. Japonais (Tier 1) : Test de langue non-latine 4. Espagnol (Tier 2) : Test de langue romane
Note technique : La détection automatique fonctionne bien pour les textes monolingues. Pour un texte contenant plusieurs langues, il est préférable de séparer les segments.
Section 7 : Comparaison et benchmark
Tableau comparatif des modèles TTS expressifs testes et references dans la serie Audio.
# Tableau comparatif complet
print("COMPARAISON DES MODELES TTS")
print("=" * 55)
comparison = {
"Critere": [
"Parametres",
"VRAM (fp16)",
"Sample rate",
"Tags expressifs",
"Voice cloning",
"Multi-speaker",
"Langues",
"Licence",
"Cas d'usage ideal",
],
"Fish S2 Pro": [
"5B",
"~14-18 GB",
"44.1 kHz",
"15000+ tags",
"Zero-shot, excellent",
"Non natif",
"80+",
"Fish Audio Research",
"Production, narration, clonage",
],
"Dia TTS": [
"1.7B",
"~6-8 GB",
"24 kHz",
"~10-20 tags",
"Limite",
"Natif (S1/S2)",
"~10",
"Apache 2.0",
"Dialogues, podcasts",
],
"Kokoro (ref)": [
"82M",
"~2 GB",
"24 kHz",
"Style tokens",
"Non",
"Non",
"~5",
"Apache 2.0",
"TTS rapide, embarque",
],
}
# Afficher
print(f"{'Critere':<22} {'Fish S2 Pro':<30} {'Dia TTS':<25} {'Kokoro':<20}")
print("-" * 97)
for i, critere in enumerate(comparison["Critere"]):
fish = comparison["Fish S2 Pro"][i]
dia = comparison["Dia TTS"][i]
kokoro = comparison["Kokoro (ref)"][i]
print(f"{critere:<22} {fish:<30} {dia:<25} {kokoro:<20}")
# Recommandations
print(f"\n\nRECOMMANDATIONS PAR BESOIN")
print("=" * 55)
recommendations = [
("Meilleure qualite", "Fish S2 Pro"),
("Dialogues multi-speaker", "Dia TTS"),
("GPU limite (<8 GB)", "Dia TTS ou Kokoro"),
("Pas de GPU", "Fish S2 Pro (API cloud) ou OpenAI TTS"),
("Voice cloning", "Fish S2 Pro > Chatterbox > XTTS"),
("Multilingue (FR, JA)", "Fish S2 Pro"),
("Latence minimale", "Kokoro (~2 GB, tres rapide)"),
("Usage commercial", "Dia TTS ou Kokoro (Apache 2.0)"),
]
print(f"{'Besoin':<30} {'Recommandation':<40}")
print("-" * 70)
for need, rec in recommendations:
print(f"{need:<30} {rec:<40}")
# Comparaison empirique mesuree (Fish via HTTP quantise vs Dia local, ce run)
print(f"\n\nCOMPARAISON EMPIRIQUE (mesuree dans ce run)")
print("=" * 55)
def _mean_metrics(d):
if not d:
return None
vals = [v["duration"] for v in d.values()]
gens = [v["gen_time"] for v in d.values()]
return len(d), sum(vals) / len(vals), sum(gens) / len(gens)
fstat = _mean_metrics(fish_results)
dstat = _mean_metrics(dia_results)
if fstat:
print(f" Fish S2 Pro (quantise, HTTP) : {fstat[0]} echantillons | duree moy. {fstat[1]:.1f}s | gen moy. {fstat[2]:.1f}s | RTF {fstat[2]/max(fstat[1],1e-9):.2f}")
if dstat:
print(f" Dia TTS (local, GPU0) : {dstat[0]} echantillons | duree moy. {dstat[1]:.1f}s | gen moy. {dstat[2]:.1f}s | RTF {dstat[2]/max(dstat[1],1e-9):.2f}")
if fstat and dstat:
print(f" => Fish plus expresif/multilingue, Dia plus rapide en RTF sur les courts textes (multi-speaker natif).")COMPARAISON DES MODELES TTS
=======================================================
Critere Fish S2 Pro Dia TTS Kokoro
-------------------------------------------------------------------------------------------------
Parametres 5B 1.7B 82M
VRAM (fp16) ~14-18 GB ~6-8 GB ~2 GB
Sample rate 44.1 kHz 24 kHz 24 kHz
Tags expressifs 15000+ tags ~10-20 tags Style tokens
Voice cloning Zero-shot, excellent Limite Non
Multi-speaker Non natif Natif (S1/S2) Non
Langues 80+ ~10 ~5
Licence Fish Audio Research Apache 2.0 Apache 2.0
Cas d'usage ideal Production, narration, clonage Dialogues, podcasts TTS rapide, embarque
RECOMMANDATIONS PAR BESOIN
=======================================================
Besoin Recommandation
----------------------------------------------------------------------
Meilleure qualite Fish S2 Pro
Dialogues multi-speaker Dia TTS
GPU limite (<8 GB) Dia TTS ou Kokoro
Pas de GPU Fish S2 Pro (API cloud) ou OpenAI TTS
Voice cloning Fish S2 Pro > Chatterbox > XTTS
Multilingue (FR, JA) Fish S2 Pro
Latence minimale Kokoro (~2 GB, tres rapide)
Usage commercial Dia TTS ou Kokoro (Apache 2.0)
COMPARAISON EMPIRIQUE (mesuree dans ce run)
=======================================================
Fish S2 Pro (quantise, HTTP) : 5 echantillons | duree moy. 5.0s | gen moy. 40.6s | RTF 8.19
Dia TTS (local, GPU0) : 3 echantillons | duree moy. 15.3s | gen moy. 55.9s | RTF 3.66
=> Fish plus expresif/multilingue, Dia plus rapide en RTF sur les courts textes (multi-speaker natif).
Interpretation : Comparaison des modeles TTS
Important (c.1331p177) : ce run execute reellement Fish S2 Pro (via le service HTTP quantise) ET Dia TTS. Les mesures de duree/temps proviennent de la section “COMPARAISON EMPIRIQUE” ci-dessus. Le tableau spec (params, VRAM, langues, licence) est tire de la documentation officielle des modeles ; les metriques d’execution sont mesurees dans ce run.
| Critere decisif | Modele recommande | Justification | Statut execution |
|---|---|---|---|
| Meilleure qualite declaree | Fish S2 Pro | 5B parametres, 44.1 kHz, 15000+ tags | Execute (Section 3, HTTP) |
| Dialogues multi-speakers | Dia TTS | Support natif [S1]/[S2] sans post-traitement |
Execute (Section 4) |
| GPU limite (<8 GB) | Dia TTS ou Kokoro | 6-8 GB max vs ~5 GB (quantise) pour Fish | Dia execute, Fish quantise ~5GB |
| Pas de GPU disponible | Fish S2 Pro (API cloud) | Qualite SOTA via API HTTP | Execute ici via service local HTTP |
| Voice cloning | Fish S2 Pro | Zero-shot excellent, cross-lingual | Execute (Section 5, reference_id) |
| Usage commercial | Dia TTS ou Kokoro | Licence Apache 2.0 permissive | Dia TTS execute |
| Latence minimale | Kokoro | 82M parametres, tres rapide | Documente par ailleurs (01-5) |
Points cles : 1. Fish S2 Pro : execute reellement via le service HTTP quantise – tags, multilingue (FR/JA/ES) et voice cloning (reference_id) produisent des WAV valides 2. Dia TTS : execute reellement en local – multi-speaker fluide, ~6 GB VRAM 3. Comparaison empirique : mesuree dans ce run (voir cellule precedente) – Fish plus polyvalent (tags + langues + cloning), Dia plus rapide en RTF sur les courts textes multi-speaker
Limites du run : la comparaison de qualite percu n’est pas machine-verifiable ; ce notebook rapporte des mesures objectives (duree, RTF). La qualite percu des tags Fish est documentee, pas mesuree.
Exercice 2 : Grille de sélection de modèle TTS
Objectif : Créer une fonction qui recommande automatiquement le meilleur modèle TTS en fonction d’un cahier des charges (cas d’usage, contraintes techniques, budget).
Les modèles TTS couverts dans cette serie (Kokoro, Chatterbox, Fish S2 Pro, Dia TTS, XTTS v2) ont des forces et faiblesses différentes. Le choix optimal depend du contexte d’utilisation.
Indices : - Les critères cles sont : VRAM disponible, besoin de voice cloning, multi-speaker, langues, licence - Un cas d’usage “podcast” privilegie le multi-speaker (Dia TTS) - Un cas d’usage “doublage” privilegie le voice cloning (Fish S2 Pro) - Kokoro est le seul modèle qui fonctionne avec moins de 2 GB VRAM - # Étape 1 : Définir les critères de sélection et leurs valeurs possibles - # Étape 2 : Implementer la logique de filtrage par contraintes materielles - # Étape 3 : Ajouter les préférences fonctionnelles (cloning, multi-speaker, langues) - # Étape 4 : Retourner le modèle recommande avec une justification - # Indice : Commencez par eliminer les modèles qui ne satisfont pas les contraintes hard (VRAM, GPU)
# Exercice 2 : Grille de selection de modele TTS
# TODO etudiant : Implementer un selecteur automatique de modele TTS
def recommend_tts_model(use_case="narration", vram_gb=6, gpu_available=True,
need_cloning=False, need_multilingual=False,
need_multi_speaker=False, commercial_use=False):
"""
Recommande le meilleur modele TTS selon le cahier des charges.
Args:
use_case: "narration", "podcast", "doublage", "embarque", "demo"
vram_gb: VRAM disponible en GB
gpu_available: GPU disponible ou non
need_cloning: Voice cloning requis
need_multilingual: Support multilingue requis
need_multi_speaker: Multi-speaker natif requis
commercial_use: Licence commerciale requise
Returns:
dict: {"model": str, "reason": str, "alternatives": list}
"""
# TODO etudiant : Definir les specifications de chaque modele
models_spec = {} # TODO etudiant : dictionnaire des modeles avec leurs capacites
# TODO etudiant : Filtrer les modeles par contraintes hard (VRAM, GPU)
# Indice : Eliminer d'abord les modeles qui depassent la VRAM disponible
# TODO etudiant : Filtrer par besoins fonctionnels
# Indice : need_cloning=True elimine Kokoro et Dia TTS
# TODO etudiant : Selectionner le meilleur parmi les eligibles
recommendation = None # TODO etudiant
reason = None # TODO etudiant
alternatives = [] # TODO etudiant
return {
"model": recommendation,
"reason": reason,
"alternatives": alternatives,
}
# Test avec differents cas d'usage
test_cases = [
{"use_case": "podcast", "vram_gb": 8, "need_multi_speaker": True},
{"use_case": "doublage", "vram_gb": 24, "need_cloning": True, "need_multilingual": True},
{"use_case": "embarque", "vram_gb": 2, "gpu_available": False},
]
for tc in test_cases:
result = recommend_tts_model(**tc)
if result["model"]:
print(f"{tc['use_case']} -> {result['model']} : {result['reason']}")
else:
print(f"{tc['use_case']} -> Exercice a completer")podcast -> Exercice a completer
doublage -> Exercice a completer
embarque -> Exercice a completer
Exercice 3 : Analyse de la vitesse de parole et de la prosodie
Objectif : Créer une fonction qui analyse un texte en entree pour estimer la duree de synthese approximative et proposer un placement optimal des tags de prosodie ([pause], [breath]) pour un résultat naturel.
Les modèles TTS expressifs permettent de contrôler la prosodie via des tags inline. Cependant, un texte sans tag produit souvent une sortie trop monotone, tandis qu’un texte surcharge de tags sonne artificiel. L’objectif est de trouver un placement equilibre en fonction de la longueur et de la structure du texte.
Indices : - La vitesse moyenne d’un modèle TTS est de ~150 mots/minute (2.5 mots/seconde) - Les pauses naturelles se placent aux virgules, points et points-virgules - [breath] est plus subtil que [pause] et convient aux pauses courtes - Une phrase de plus de 15 mots beneficie généralement d’un [pause] au milieu - # Étape 1 : Decouper le texte en phrases (separateurs : . ! ?) - # Étape 2 : Estimer la duree de chaque phrase (nombre de mots / 2.5) - # Étape 3 : Inserer des [pause] aux virgules et [breath] aux points-virgules - # Étape 4 : Calculer la duree totale estimee avec et sans tags - # Indice : Un texte de 50 mots dure environ 20 secondes sans pause supplementaire
# Exercice 1 : Analyse de la vitesse de parole et de la prosodie
# TODO etudiant : Analyser un texte et proposer un placement de tags de prosodie
def estimate_speech_duration_and_pauses(text, words_per_minute=150):
"""
Analyse un texte pour estimer la duree de synthese et proposer
un placement optimal des tags de prosodie.
Args:
text: Texte brut (sans tags)
words_per_minute: Vitesse de parole estimee
Returns:
dict: Duree estimee, texte annote, nombre de pauses proposees
"""
# TODO etudiant : Decouper le texte en phrases
sentences = [] # TODO etudiant
# TODO etudiant : Estimer la duree par phrase
durations = [] # TODO etudiant
# TODO etudiant : Inserer des pauses aux endroits naturels
annotated_text = None # TODO etudiant
# TODO etudiant : Calculer la duree totale (avec pauses de ~0.3s)
total_duration = None # TODO etudiant
return {
"original_text": text,
"annotated_text": annotated_text,
"num_sentences": len(sentences),
"num_words": len(text.split()),
"duration_no_pauses": None, # TODO etudiant
"duration_with_pauses": total_duration,
}
# Test
sample = "Bienvenue dans ce tutoriel sur la synthese vocale. Nous allons explorer les differentes techniques, les modeles disponibles, et les cas d'usage pratiques."
result = estimate_speech_duration_and_pauses(sample)
if result["annotated_text"]:
print(f"Phrases : {result['num_sentences']}")
print(f"Mots : {result['num_words']}")
print(f"Texte annote : {result['annotated_text']}")
else:
print("Exercice a completer")Exercice a completer
Le tableau comparatif Fish S2 Pro / Dia TTS / Kokoro est affiche. La cellule suivante ouvre le mode interactif pour tester des phrases personnalisees avec les tags d’expressivite disponibles.
# Mode interactif
if notebook_mode == "interactive" and not skip_widgets:
print("MODE INTERACTIF")
print("=" * 45)
print("\nEntrez du texte avec des tags expressifs :")
print(" Tags disponibles : [laugh], [whisper], [sigh], [gasp], [pause], [shout]")
print(" Exemple : 'Hello [laugh] that was funny! [whisper] But seriously...'")
print(" (Laissez vide pour passer)")
try:
user_text = input("\nTexte : ").strip()
if user_text and fish_http_ok:
print(f"\nGeneration...")
generate_fish_tts(
user_text,
"fish_custom",
)
elif user_text:
print(f"\nTexte enregistre : {user_text}")
print("Modele non disponible - service Fish HTTP injoignable")
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
Introduction : Mode interactif
Cette section permet de tester manuellement les tags d’expressivité en entrant du texte librement. C’est l’occasion d’expérimenter avec :
Combinaisons de tags : - [whisper] [pause] Secret revealed... - [laugh] That's amazing! [gasp] Wait, really? - [professional broadcast tone] Breaking news: [pause] ...
Stratégies d’utilisation : 1. Modération : 2-3 tags maximum par phrase pour éviter la surcharge 2. Positionnement : Placer le tag juste avant le texte affecté 3. Combinaison : Certains tags peuvent être combinés pour des effets complexes
Cas d’usage : - Narration de livres audio - Création de podcasts - Doublage de vidéos - Accessibilité (lecteurs d’écran expressifs)
Note technique : En mode batch (Papermill), cette section est automatiquement désactivée via
skip_widgets=True.
La session interactive avec les tags d’expressivite est terminee. La cellule suivante recapitule les statistiques de session et libere la memoire occupee par les modèles Fish S2 Pro et Dia TTS.
# Statistiques de session
print("STATISTIQUES DE SESSION")
print("=" * 45)
print(f"Date : {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"Device : {device}")
print(f"Fish S2 Pro : {'execute' if fish_results else 'non execute'}")
print(f"Dia TTS : {'execute' if dia_results else 'non execute'}")
if gpu_available:
vram_current = torch.cuda.memory_allocated(0) / (1024**3)
print(f"VRAM utilisee : {vram_current:.2f} GB")
if save_results:
all_audio = list(OUTPUT_DIR.glob('*.wav'))
total_size = sum(f.stat().st_size for f in all_audio) / (1024*1024)
print(f"\nFichiers audio : {len(all_audio)} ({total_size:.1f} MB)")
print(f"Repertoire : {OUTPUT_DIR.relative_to(GENAI_ROOT)}")
# Liberation memoire
if fish_model is not None:
del fish_model
if dia_model is not None:
del dia_model
gc.collect()
if gpu_available:
torch.cuda.empty_cache()
print(f"\nPROCHAINES ETAPES")
print(f"1. Comparer avec Kokoro (01-5) et Chatterbox (02-1) pour le voice cloning")
print(f"2. Integrer dans un pipeline vocal complet (03-2)")
print(f"3. Utiliser pour la narration educative (04-1)")
print(f"4. Explorer le self-hosting Fish S2 Pro comme service Docker")
print(f"\nNotebook TTS Expressif termine - {datetime.now().strftime('%H:%M:%S')}")STATISTIQUES DE SESSION
=============================================
Date : 2026-08-30 11:26:42
Device : cuda
Fish S2 Pro : execute
Dia TTS : execute
VRAM utilisee : 3.50 GB
Fichiers audio : 14 (8.2 MB)
Repertoire : outputs\audio\expressive-tts
PROCHAINES ETAPES
1. Comparer avec Kokoro (01-5) et Chatterbox (02-1) pour le voice cloning
2. Integrer dans un pipeline vocal complet (03-2)
3. Utiliser pour la narration educative (04-1)
4. Explorer le self-hosting Fish S2 Pro comme service Docker
Notebook TTS Expressif termine - 11:26:44
Introduction : Statistiques de session et nettoyage
Cette section finale effectue plusieurs tâches importantes :
- Bilan de la session : Résumé des exécutions (Fish S2 Pro, Dia TTS)
- Métriques VRAM : Mémoire GPU utilisée avant libération
- Fichiers générés : Comptage et taille totale des fichiers audio
- Nettoyage mémoire : Suppression des modèles de la RAM/VRAM
- Prochaines étapes : Liens vers les notebooks connexes
Pourquoi le nettoyage est important : - Les modèles TTS occupent plusieurs GB de VRAM - Libérer la mémoire permet d’exécuter d’autres notebooks dans la même session - Le garbage collector Python nettoie les objets en mémoire - torch.cuda.empty_cache() libère la VRAM pour d’autres tâches
Continuité pédagogique : - 03-2 : Pipeline vocal complet (ASR → TTS → traitement) - 04-1 : Narration éducative avec TTS expressif - Docker Compose pour self-hosting Fish S2 Pro
Note technique : Dans un environnement Jupyter persistant, il est recommandé de redémarrer le kernel après avoir chargé plusieurs modèles lourds pour éviter les fuites de mémoire.
EXERCICE - Narration expressive
Objectif
Créer une narration expressive qui utilise au moins 3 tags différents pour raconter une courte histoire.
Consignes
- Ecrire un court texte narratif (5-10 phrases) incluant :
- Au moins 3 tags différents (
[laugh],[whisper],[pause],[gasp], etc.) - Un changement d’emotion ou de ton dans le texte
- Un contexte coherent (histoire, anecdote, presentation)
- Au moins 3 tags différents (
- Generer 2 versions :
- Version A : Avec la voix par defaut
- Version B : Avec voice cloning (utiliser un audio de reference)
- Evaluer :
- Naturel des expressions (1-5)
- Coherence du ton (1-5)
- Qualite audio (1-5)
Indices :
- Placez les tags juste avant le texte qu’ils doivent affecter
- Evitez de surcharger avec trop de tags dans une même phrase
[pause]est utile pour créer du suspense- Fish S2 Pro via API cloud ne necessite pas de GPU
Critères de succes
Soumission : PR avec titre “Exercice TTS Expressif - [Votre Nom]”, texte, fichiers audio et evaluation
Verdict SOTA : Fish S2 Pro = SOTA-OK (execute via service HTTP quantise, #13114)
L’etiquette RECOVERABLE-USER-HAND posee au run precedent (c.1331p177) etait mal etablie : elle cherchait une cle API cloud et un moteur Python Linux-only, alors qu’un service HTTP self-hosted quantise etait deja deploye sur cette lane (docker-configurations/services/tts-fishaudio/). Requalification mesuree firsthand le 2026-08-30.
Faits mesures (2026-08-30)
| Fait | Mesure |
|---|---|
| Service HTTP quantise | OPERATIONNEL – http://localhost:8197/v1/health renvoie {"status":"ok"} ; modele S2-Pro BnB NF4 4-bit charge (GPU1, RTX 3090, ~5GB VRAM quantise vs ~18GB fp16) |
| API TTS | POST /v1/tts (ServeTTSRequest) – teste : TTS texte (HTTP 200, WAV valide), tags expressifs [laugh]/(whisper), japonais, voice cloning reference_id |
| Reference voices | references/{id}/sample.wav + sample.lab (ex. v4_comtesse_cold) |
| Chemin Python local | Package PyPI fish-speech 0.1.0 stale : ne contient pas fish_speech.inference (import du run precedent leverait ImportError) – remplace par le service HTTP |
| Cle API | Aucune requise – le modele tourne dans le conteneur, pas dans l’API cloud |
Checklist 6 axes (regle d’etablissement, obligatoire)
| # | Axe | Question | Reponse |
|---|---|---|---|
| 1 | Binding .NET / NuGet | Package officiel existe-t-il ? | N/A – modeles Python (service REST) |
| 2 | P/Invoke |
API C stable exposee ? | N/A – Python natif (conteneur) |
| 3 | CLI Process.Start |
Binaire invocable ? | Service HTTP (POST /v1/tts) – voie retenue, lancable via docker compose |
| 4 | IKVM (pont Java) |
Lib en Java shadee ? | N/A |
| 5 | PythonNet (pont CPython) |
Binding Python disponible ? | N/A – Python natif, mais via REST, pas d’import direct |
| 6 | Lib differente a role equivalent | Autre moteur SOTA tient le role ? | Dia TTS (1.7B, ~6 GB VRAM) execute reellement (Section 4) pour la comparaison |
Conclusion SOTA-OK : le vrai service (S2-Pro quantise, self-hosted) est invoque et sa sortie est commitee dans ce notebook. Le run precedent ne l’a pas reutilise : il cherchait une cle API cloud (FISH_AUDIO_API_KEY absente = mauvais cadrage) ou le moteur Python Linux-only (fish_speech stale). La voie deja disponible – le service Docker tts-fishaudio – est celle reutilisee ici.
Bounding honnete : les mesures objectives (duree, RTF, generation multilingue, voice cloning) sont empiriques et commitees. La qualite percu des tags n’est pas machine-verifiable et reste documentee comme telle.
Conclusion
Ce notebook presente l’evolution du TTS vers l’expressivite et le controle granulaire de la prosodie. Dia TTS est execute reellement en local (Section 4, GPU0) et Fish S2 Pro est execute reellement via le service HTTP quantise (Sections 3, 5, 6, GPU1 / conteneur) – les deux moteurs SOTA sont invoques et leur sortie commitee.
Recapitulatif des apprentissages
| Concept | Points cles | Statut execution |
|---|---|---|
| Tags d’expressivite | 15000+ tags (Fish) : [laugh], [whisper], [pause], emotions, tons professionnels |
Fish : execute (Section 3) / Dia : execute |
| Architecture Dual-AR | Slow AR (4B) + Fast AR (400M) pour generation rapide et haute qualite | Service HTTP quantise (BnB NF4 4-bit) |
| Voice cloning | Zero-shot avec 10-30s de reference, cross-lingual (reference_id) |
Fish : execute (Section 5) |
| Multi-speaker | Support natif (Dia) ou via voice cloning (Fish) | Dia : execute reellement |
| Multilingue | 80+ langues avec detection automatique | Fish : execute (Section 6, FR/JA/ES) |
Choix du modele selon le cas d’usage (theorique, base sur documentation + mesures)
| Cas d’usage | Modele | Raison | Statut execution |
|---|---|---|---|
| Production haut de gamme | Fish S2 Pro | Qualite SOTA declaree, tags exhaustifs | Execute (HTTP quantise) |
| Dialogues temps reel | Dia TTS | Multi-speaker natif, VRAM reduite | Execute Section 4 |
| Applications embarquees | Kokoro | 82M parametres, latence minimale | Documente par ailleurs (01-5) |
| Voice cloning | Fish S2 Pro | Meilleure fidelite declaree, cross-lingual | Execute Section 5 |
| Usage commercial | Dia TTS / Kokoro | Licence Apache 2.0 | Dia execute |
Chemin retenu vs run precedent (c.1331p177)
- Avant : Fish S2 Pro cherche une cle API cloud (
FISH_AUDIO_API_KEYabsente = RECOVERABLE-USER-HAND) ou le moteur Python Linux-only (fish_speechstale) – les deux fausses pistes. - Maintenant : un service HTTP self-hosted quantise (
docker-configurations/services/tts-fishaudio/, imagefishaudio/fish-speech:server-cuda-bnb4, port 8197) etait deja deploye sur cette lane et n’avait pas ete reutilise. Il est ici la voie reelle :POST /v1/tts, aucune cle API requise. - Verdict SOTA : voir section verdict ci-dessus (SOTA-OK – le vrai service est invoque, sa sortie commitee).
Limites actuelles (Run c.1331p177)
- Quantisation NF4 4-bit : reduit la VRAM (~18GB -> ~5GB) mais peut legerement degrader la qualite vs fp16 (non mesure objectivement ici)
- Qualite percu : non machine-verifiable – ce notebook rapporte des mesures objectives (duree, RTF, generation multilingue, voice cloning)
- Langues Tier 3 : qualite variable pour les langues peu representees (non mesure)