daiemon12 commited on
Commit
899a643
·
verified ·
1 Parent(s): 78021e3

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +64 -3
  2. handler.py +136 -0
  3. requirements.txt +8 -0
README.md CHANGED
@@ -1,3 +1,64 @@
1
- ---
2
- license: apache-2.0
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Kyutai TTS Handler pour Hugging Face Endpoints
2
+
3
+ ## Déploiement rapide
4
+
5
+ 1. **Créez un nouveau repo sur Hugging Face** : `daiemon12/kyutai-tts-endpoint`
6
+
7
+ 2. **Uploadez ces fichiers** :
8
+ - `handler.py`
9
+ - `requirements.txt`
10
+ - `README.md`
11
+
12
+ 3. **Configuration de l'endpoint** :
13
+
14
+ ```
15
+ Model Repository: daiemon12/kyutai-tts-endpoint
16
+
17
+ Hardware: Intel Sapphire Rapids - 8 vCPUs · 16 GB
18
+ ($0.268/h)
19
+
20
+ Ou mieux (recommandé pour production):
21
+ Hardware: NVIDIA T4 · 16GB VRAM
22
+ (~$0.60/h mais BEAUCOUP plus rapide)
23
+
24
+ Security: Protected ✅
25
+ Autoscaling: 0 to 2 replicas
26
+ Scale-to-zero: après 60 min ✅
27
+ ```
28
+
29
+ ## Utilisation
30
+
31
+ ```python
32
+ import requests
33
+
34
+ response = requests.post(
35
+ "https://xxxxx.endpoints.huggingface.cloud",
36
+ headers={"Authorization": f"Bearer {HF_TOKEN}"},
37
+ json={
38
+ "inputs": "Bonjour, ceci est un test de synthèse vocale.",
39
+ "parameters": {
40
+ "language": "fr", # ou "en", ou "auto"
41
+ "speed": 1.0
42
+ }
43
+ }
44
+ )
45
+
46
+ audio_base64 = response.json()["audio"]
47
+ ```
48
+
49
+ ## Performances attendues
50
+
51
+ - **Latence première requête** : ~10-15s (chargement modèle)
52
+ - **Latence suivantes** : 200-400ms
53
+ - **Qualité** : État de l'art pour FR/EN
54
+ - **Streaming** : 220ms du texte au premier audio
55
+
56
+ ## Alternative simple
57
+
58
+ Si vous voulez tester rapidement sans créer de repo :
59
+
60
+ 1. Allez sur https://huggingface.co/spaces
61
+ 2. Duplicate un Space TTS existant
62
+ 3. Modifiez pour utiliser Kyutai
63
+
64
+ Mais pour production, utilisez l'endpoint avec ce handler !
handler.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Handler direct pour Kyutai TTS - Charge le modèle depuis le repo original
3
+ Pas besoin de dupliquer le modèle !
4
+ """
5
+
6
+ import torch
7
+ import base64
8
+ import io
9
+ import numpy as np
10
+ from typing import Dict, Any
11
+ import soundfile as sf
12
+
13
+ class EndpointHandler:
14
+ def __init__(self, path=""):
15
+ """
16
+ Initialise le handler en chargeant directement depuis kyutai/tts-1.6b-en_fr
17
+ """
18
+ from moshi.models import loaders
19
+
20
+ # Détection du device
21
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
22
+ print(f"🔧 Initialisation sur {self.device}")
23
+
24
+ # Charger le modèle directement depuis le repo original
25
+ print("📥 Chargement du modèle kyutai/tts-1.6b-en_fr...")
26
+ self.lm_model = loaders.get_pretrained_lm_model(
27
+ device=self.device,
28
+ repo_id="kyutai/tts-1.6b-en_fr" # Charge depuis le repo original !
29
+ )
30
+
31
+ print("✅ Modèle chargé avec succès!")
32
+
33
+ # Config par défaut
34
+ self.sample_rate = 24000
35
+ self.default_speed = 1.0
36
+
37
+ def __call__(self, data: Dict[str, Any]) -> Dict[str, Any]:
38
+ """
39
+ Traite les requêtes TTS
40
+
41
+ Args:
42
+ data: {
43
+ "inputs": str - Le texte à synthétiser
44
+ "parameters": {
45
+ "language": str - "fr", "en" ou "auto" (défaut: auto)
46
+ "speed": float - Vitesse de parole (défaut: 1.0)
47
+ "voice": int - ID du locuteur (défaut: 0)
48
+ }
49
+ }
50
+
51
+ Returns:
52
+ {
53
+ "audio": str - Audio en base64 (WAV)
54
+ "sampling_rate": int - Taux d'échantillonnage
55
+ "duration": float - Durée en secondes
56
+ }
57
+ """
58
+ # Extraction des paramètres
59
+ text = data.get("inputs", "")
60
+ if not text:
61
+ raise ValueError("Le paramètre 'inputs' (texte) est requis")
62
+
63
+ params = data.get("parameters", {})
64
+ language = params.get("language", "auto")
65
+ speed = params.get("speed", self.default_speed)
66
+ voice_id = params.get("voice", 0)
67
+
68
+ # Détection automatique de la langue
69
+ if language == "auto":
70
+ # Détection simple basée sur les caractères
71
+ fr_chars = set("àâäéèêëïîôùûçœ")
72
+ has_french = any(c in text.lower() for c in fr_chars)
73
+ language = "fr" if has_french else "en"
74
+ print(f"🌍 Langue détectée: {language}")
75
+
76
+ # Validation de la langue
77
+ if language not in ["fr", "en"]:
78
+ raise ValueError(f"Langue non supportée: {language}. Utilisez 'fr', 'en' ou 'auto'")
79
+
80
+ try:
81
+ # Synthèse vocale
82
+ print(f"🎤 Synthèse TTS: {len(text)} caractères en {language}")
83
+
84
+ with torch.no_grad():
85
+ # Générer l'audio
86
+ audio_tensor = self.lm_model.synthesize(
87
+ text=text,
88
+ language=language,
89
+ speaker_id=voice_id,
90
+ speed=speed
91
+ )
92
+
93
+ # Convertir en numpy array
94
+ audio_np = audio_tensor.cpu().numpy()
95
+
96
+ # Normaliser l'audio
97
+ audio_np = audio_np / np.max(np.abs(audio_np))
98
+
99
+ # Convertir en WAV
100
+ buffer = io.BytesIO()
101
+ sf.write(buffer, audio_np, self.sample_rate, format='WAV')
102
+ buffer.seek(0)
103
+
104
+ # Encoder en base64
105
+ audio_base64 = base64.b64encode(buffer.read()).decode('utf-8')
106
+
107
+ # Calculer la durée
108
+ duration = len(audio_np) / self.sample_rate
109
+
110
+ print(f"✅ Synthèse réussie: {duration:.2f}s d'audio généré")
111
+
112
+ return {
113
+ "audio": audio_base64,
114
+ "sampling_rate": self.sample_rate,
115
+ "duration": duration,
116
+ "metadata": {
117
+ "language": language,
118
+ "voice_id": voice_id,
119
+ "speed": speed,
120
+ "text_length": len(text)
121
+ }
122
+ }
123
+
124
+ except Exception as e:
125
+ print(f"❌ Erreur TTS: {str(e)}")
126
+ raise RuntimeError(f"Erreur lors de la synthèse: {str(e)}")
127
+
128
+ def health_check(self) -> Dict[str, Any]:
129
+ """Vérification de santé de l'endpoint"""
130
+ return {
131
+ "status": "healthy",
132
+ "model": "kyutai/tts-1.6b-en_fr",
133
+ "device": str(self.device),
134
+ "languages": ["fr", "en"],
135
+ "sample_rate": self.sample_rate
136
+ }
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Requirements pour Kyutai TTS Handler
2
+ torch>=2.0.0
3
+ torchaudio>=2.0.0
4
+ moshi>=0.2.6
5
+ numpy>=1.24.0
6
+ huggingface-hub>=0.19.0
7
+ safetensors>=0.4.0
8
+ wave