Lorenzob commited on
Commit
b5b5037
·
verified ·
1 Parent(s): d98c95d

Completely revised approach using direct Microsoft SpeechT5 model

Browse files
Files changed (1) hide show
  1. app.py +95 -172
app.py CHANGED
@@ -2,11 +2,10 @@
2
  import gradio as gr
3
  import torch
4
  import os
5
- import json
6
  import numpy as np
7
  from scipy import signal
8
  import warnings
9
- from transformers import AutoConfig, AutoProcessor, SpeechT5ForTextToSpeech, set_seed
10
  import requests
11
  import tempfile
12
  from pathlib import Path
@@ -17,39 +16,44 @@ warnings.filterwarnings("ignore")
17
  set_seed(42)
18
 
19
  # Definizioni di variabili globali
20
- MODEL_REPO = "Lorenzob/aurora-1.6b-complete" # Repository del modello completo
21
  CACHE_DIR = "./model_cache" # Directory per la cache del modello
22
- SAMPLE_RATE = 24000 # Frequenza di campionamento
23
 
24
- # Cache per il modello, processor e speaker embeddings
25
  processor = None
26
  model = None
 
27
  speaker_embeddings_cache = {}
28
 
29
  def download_file(url, save_path):
30
  """Scarica un file da un URL"""
31
- response = requests.get(url, stream=True)
32
- response.raise_for_status()
33
-
34
- os.makedirs(os.path.dirname(save_path), exist_ok=True)
35
- with open(save_path, 'wb') as f:
36
- for chunk in response.iter_content(chunk_size=8192):
37
- f.write(chunk)
38
-
39
- return save_path
 
 
 
 
40
 
41
- def get_speaker_embeddings(speaker_id=0):
42
- """Ottieni gli speaker embeddings dal dataset CMU Arctic"""
43
  global speaker_embeddings_cache
44
 
 
 
 
 
45
  if speaker_id in speaker_embeddings_cache:
46
  return speaker_embeddings_cache[speaker_id]
47
 
48
  try:
49
- # Limita lo speaker_id a un intervallo valido (0-9)
50
- speaker_id = max(0, min(9, speaker_id))
51
-
52
- # Genera l'URL per gli embeddings
53
  url = f"https://huggingface.co/datasets/Matthijs/cmu-arctic-xvectors/resolve/main/cmu_us_{speaker_id:02d}_xvector.pt"
54
 
55
  # Crea un file temporaneo per gli embeddings
@@ -60,7 +64,9 @@ def get_speaker_embeddings(speaker_id=0):
60
  # Scarica gli embeddings se non esistono già
61
  if not os.path.exists(tmp_file):
62
  print(f"Scaricamento degli speaker embeddings per lo speaker {speaker_id}...")
63
- download_file(url, tmp_file)
 
 
64
 
65
  # Carica gli embeddings
66
  speaker_embeddings = torch.load(tmp_file)
@@ -72,94 +78,46 @@ def get_speaker_embeddings(speaker_id=0):
72
  return speaker_embeddings
73
  except Exception as e:
74
  print(f"Errore nel caricamento degli speaker embeddings: {e}")
75
- # Crea dei default embeddings
76
- default_embeddings = torch.zeros(1, 512)
77
- speaker_embeddings_cache[speaker_id] = default_embeddings
78
- return default_embeddings
79
-
80
- def ensure_model_config():
81
- """Assicura che il modello abbia una configurazione corretta"""
82
- try:
83
- # Crea la directory cache se non esiste
84
- os.makedirs(CACHE_DIR, exist_ok=True)
85
 
86
- # Percorso per il file di configurazione locale
87
- config_path = os.path.join(CACHE_DIR, "config.json")
88
-
89
- # Controlla se il file di configurazione esiste già
90
- if not os.path.exists(config_path):
91
- # URL del file di configurazione su Hugging Face
92
- config_url = f"https://huggingface.co/{MODEL_REPO}/raw/main/config.json"
93
 
94
- # Scarica il file di configurazione
95
- print(f"Scaricamento della configurazione da {config_url}...")
96
- download_file(config_url, config_path)
97
-
98
- # Leggi il file di configurazione
99
- with open(config_path, "r") as f:
100
- config = json.load(f)
101
-
102
- # Modifica la configurazione per SpeechT5
103
- config["model_type"] = "speecht5"
104
- if "architectures" not in config or not config["architectures"]:
105
- config["architectures"] = ["SpeechT5ForTextToSpeech"]
106
-
107
- # Salva la configurazione modificata
108
- with open(config_path, "w") as f:
109
- json.dump(config, f, indent=2)
110
-
111
- print(f"Configurazione aggiornata salvata in {config_path}")
112
- return config_path
113
- except Exception as e:
114
- print(f"Errore nella configurazione del modello: {e}")
115
- return None
116
 
117
- def load_model_and_processor():
118
- """Carica il modello e il processor con caricamento manuale della configurazione"""
119
- global model, processor
120
 
121
- if model is None or processor is None:
122
  try:
123
- print(f"📂 Caricamento del modello Aurora-1.6b-complete...")
124
-
125
- # Configura il modello manualmente
126
- config_path = ensure_model_config()
127
- if not config_path:
128
- raise ValueError("Impossibile creare la configurazione del modello")
129
-
130
- # Carica la configurazione
131
- config = AutoConfig.from_pretrained(config_path)
132
-
133
- # Carica il processor
134
- processor = AutoProcessor.from_pretrained(MODEL_REPO)
135
-
136
- # Carica il modello con la configurazione corretta
137
- model = SpeechT5ForTextToSpeech.from_pretrained(
138
- MODEL_REPO,
139
- config=config,
140
- torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
141
- device_map="auto"
142
- )
143
-
144
- print("✅ Modello e processor caricati con successo!")
145
 
 
 
146
  except Exception as e:
147
- print(f"❌ Errore nel caricamento del modello Aurora: {str(e)}")
148
  traceback_str = traceback.format_exc()
149
  print(f"Traceback completo:\n{traceback_str}")
150
-
151
- try:
152
- # Fallback al modello di Microsoft (più affidabile)
153
- print("⚠️ Tentativo di fallback al modello Microsoft...")
154
- from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech
155
- processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
156
- model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
157
- print("✅ Modello di fallback caricato con successo!")
158
- except Exception as e2:
159
- print(f"❌ Errore anche nel caricamento del modello di fallback: {str(e2)}")
160
- raise RuntimeError("Impossibile caricare alcun modello TTS")
161
-
162
- return model, processor
163
 
164
  def text_to_speech(text, language="it", speaker_id=0, speed=1.0, show_log=False):
165
  """Converte testo in voce utilizzando il modello TTS"""
@@ -171,72 +129,41 @@ def text_to_speech(text, language="it", speaker_id=0, speed=1.0, show_log=False)
171
  print(f"Richiesta TTS ricevuta: '{text}' (Lingua: {language}, Speaker: {speaker_id}, Velocità: {speed})")
172
 
173
  try:
174
- # Carica il modello e il processor
175
- model, processor = load_model_and_processor()
 
176
 
177
  # Ottieni gli speaker embeddings
178
- speaker_emb = get_speaker_embeddings(speaker_id)
179
-
180
- # Controlla se stiamo usando il modello di Microsoft
181
- is_microsoft_model = "microsoft" in str(type(model))
182
 
183
- if is_microsoft_model:
184
- # Usa il modello Microsoft
185
- if show_log:
186
- print("Utilizzo del modello Microsoft SpeechT5...")
187
 
188
- # Crea input IDs dal testo
189
- inputs = processor(text=text, return_tensors="pt")
 
 
 
 
190
 
 
 
 
 
 
191
  # Genera l'audio
192
- with torch.no_grad():
193
- speech = model.generate_speech(
194
- inputs["input_ids"],
195
- speaker_emb
196
- )
197
-
198
- # Imposta la frequenza di campionamento
199
- sample_rate = 16000 # Microsoft usa 16kHz
200
- else:
201
- # Usa il modello Aurora
202
- if show_log:
203
- print("Utilizzo del modello Aurora-1.6b-complete...")
204
-
205
- # Prepara gli input
206
- inputs = processor(
207
- text=text,
208
- language=language,
209
- return_tensors="pt"
210
  )
211
-
212
- # Sposta gli input sul dispositivo di calcolo
213
- for k, v in inputs.items():
214
- if hasattr(v, "to"):
215
- inputs[k] = v.to(model.device)
216
-
217
- # Sposta gli speaker embeddings sul dispositivo di calcolo
218
- speaker_emb = speaker_emb.to(model.device)
219
-
220
- # Genera il speech
221
- with torch.no_grad():
222
- if hasattr(model, "generate_speech") and callable(model.generate_speech):
223
- # Usa generate_speech se disponibile
224
- speech = model.generate_speech(
225
- inputs["input_ids"],
226
- speaker_emb
227
- )
228
- else:
229
- # Prova a passare gli speaker embeddings come parametro
230
- speech = model.generate(
231
- **inputs,
232
- speaker_embeddings=speaker_emb
233
- )
234
-
235
- # Imposta la frequenza di campionamento
236
- sample_rate = SAMPLE_RATE
237
 
238
  # Converti il tensore in un array numpy
239
- speech_array = speech.cpu().numpy().squeeze()
240
 
241
  # Applica il controllo della velocità
242
  if speed != 1.0:
@@ -257,21 +184,21 @@ def text_to_speech(text, language="it", speaker_id=0, speed=1.0, show_log=False)
257
  # Esempi predefiniti per l'interfaccia
258
  examples = [
259
  ["Ciao, mi chiamo Aurora e sono un assistente vocale italiano.", "it", 0, 1.0, False],
260
- ["Hello, my name is Aurora and I'm an Italian voice assistant.", "en", 2, 1.0, False],
261
- ["Hola, me llamo Aurora y soy un asistente de voz italiano.", "es", 4, 1.0, False],
262
- ["La vita è bella e il sole splende nel cielo azzurro.", "it", 0, 1.0, False],
263
- ["Mi piace viaggiare e scoprire nuove città e culture.", "it", 7, 1.2, False],
264
- ["L'intelligenza artificiale sta trasformando il modo in cui interagiamo con i computer e con il mondo che ci circonda.", "it", 9, 0.9, False]
265
  ]
266
 
267
  # Definizione dell'interfaccia Gradio
268
- with gr.Blocks(title="Aurora-1.6b TTS Demo", theme=gr.themes.Soft()) as demo:
269
  gr.Markdown("""
270
- # 🎙️ Aurora-1.6b Text-to-Speech Demo
271
 
272
- Questa demo utilizza il modello **Aurora-1.6b-complete** per la sintesi vocale (TTS), un modello fine-tuned basato su Dia-1.6B con pesi completi.
273
 
274
- Il modello supporta italiano, inglese, spagnolo, francese e tedesco, ma è stato ottimizzato per l'italiano.
275
  """)
276
 
277
  with gr.Row():
@@ -288,7 +215,7 @@ with gr.Blocks(title="Aurora-1.6b TTS Demo", theme=gr.themes.Soft()) as demo:
288
  choices=["it", "en", "es", "fr", "de"],
289
  label="Lingua",
290
  value="it",
291
- info="Seleziona la lingua del testo"
292
  )
293
  speaker_input = gr.Slider(
294
  label="Speaker ID",
@@ -329,16 +256,12 @@ with gr.Blocks(title="Aurora-1.6b TTS Demo", theme=gr.themes.Soft()) as demo:
329
  ## 📝 Note sull'utilizzo
330
 
331
  - Il modello funziona meglio con frasi di lunghezza media (fino a 20-30 parole)
332
- - Per l'italiano, il modello è stato ottimizzato per una pronuncia naturale
333
  - Puoi cambiare lo Speaker ID per ottenere voci con caratteristiche diverse
334
  - La velocità di generazione dipende dalle risorse disponibili sul server
335
 
336
  ## 🔗 Crediti
337
 
338
- Questo modello è una combinazione di:
339
- - [Lorenzob/aurora-1.6b](https://huggingface.co/Lorenzob/aurora-1.6b) (versione fine-tuned)
340
- - [Lorenzob/aurora-1.6b-complete](https://huggingface.co/Lorenzob/aurora-1.6b-complete) (versione completa con pesi)
341
- - [nari-labs/Dia-1.6B](https://huggingface.co/nari-labs/Dia-1.6B) (modello base originale)
342
  - [CMU Arctic XVectors](https://huggingface.co/datasets/Matthijs/cmu-arctic-xvectors) (speaker embeddings)
343
  """)
344
 
 
2
  import gradio as gr
3
  import torch
4
  import os
 
5
  import numpy as np
6
  from scipy import signal
7
  import warnings
8
+ from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan, set_seed
9
  import requests
10
  import tempfile
11
  from pathlib import Path
 
16
  set_seed(42)
17
 
18
  # Definizioni di variabili globali
 
19
  CACHE_DIR = "./model_cache" # Directory per la cache del modello
20
+ SAMPLE_RATE = 16000 # Frequenza di campionamento per il modello Microsoft
21
 
22
+ # Cache per i componenti del modello
23
  processor = None
24
  model = None
25
+ vocoder = None
26
  speaker_embeddings_cache = {}
27
 
28
  def download_file(url, save_path):
29
  """Scarica un file da un URL"""
30
+ try:
31
+ response = requests.get(url, stream=True)
32
+ response.raise_for_status()
33
+
34
+ os.makedirs(os.path.dirname(save_path), exist_ok=True)
35
+ with open(save_path, 'wb') as f:
36
+ for chunk in response.iter_content(chunk_size=8192):
37
+ f.write(chunk)
38
+
39
+ return save_path
40
+ except Exception as e:
41
+ print(f"Errore nel download del file: {e}")
42
+ return None
43
 
44
+ def get_correct_speaker_embeddings(speaker_id):
45
+ """Ottieni gli speaker embeddings corretti per il modello SpeechT5"""
46
  global speaker_embeddings_cache
47
 
48
+ # Correggi il valore di speaker_id per essere tra 1 e 10 (e non 0-9)
49
+ # poiché i file su Hugging Face sono numerati da 01 a 24
50
+ speaker_id = max(1, min(10, speaker_id + 1))
51
+
52
  if speaker_id in speaker_embeddings_cache:
53
  return speaker_embeddings_cache[speaker_id]
54
 
55
  try:
56
+ # Url corretto per gli speaker embeddings
 
 
 
57
  url = f"https://huggingface.co/datasets/Matthijs/cmu-arctic-xvectors/resolve/main/cmu_us_{speaker_id:02d}_xvector.pt"
58
 
59
  # Crea un file temporaneo per gli embeddings
 
64
  # Scarica gli embeddings se non esistono già
65
  if not os.path.exists(tmp_file):
66
  print(f"Scaricamento degli speaker embeddings per lo speaker {speaker_id}...")
67
+ filepath = download_file(url, tmp_file)
68
+ if not filepath:
69
+ raise ValueError(f"Impossibile scaricare gli embeddings per lo speaker {speaker_id}")
70
 
71
  # Carica gli embeddings
72
  speaker_embeddings = torch.load(tmp_file)
 
78
  return speaker_embeddings
79
  except Exception as e:
80
  print(f"Errore nel caricamento degli speaker embeddings: {e}")
 
 
 
 
 
 
 
 
 
 
81
 
82
+ # Prova a utilizzare un embedding predefinito dal speaker 1
83
+ try:
84
+ fallback_id = 1
85
+ url = f"https://huggingface.co/datasets/Matthijs/cmu-arctic-xvectors/resolve/main/cmu_us_{fallback_id:02d}_xvector.pt"
86
+ tmp_file = os.path.join(tmp_dir, f"speaker_{fallback_id:02d}.pt")
 
 
87
 
88
+ if not os.path.exists(tmp_file):
89
+ download_file(url, tmp_file)
90
+
91
+ speaker_embeddings = torch.load(tmp_file)
92
+ speaker_embeddings_cache[speaker_id] = speaker_embeddings
93
+ print(f"Utilizzando speaker embeddings di fallback (speaker {fallback_id})")
94
+ return speaker_embeddings
95
+ except:
96
+ # Se tutto fallisce, crea una embedding vuota
97
+ print("Creazione di embeddings vuoti")
98
+ default_embeddings = torch.zeros((1, 512))
99
+ speaker_embeddings_cache[speaker_id] = default_embeddings
100
+ return default_embeddings
 
 
 
 
 
 
 
 
 
101
 
102
+ def load_tts_components():
103
+ """Carica tutti i componenti TTS"""
104
+ global processor, model, vocoder
105
 
106
+ if processor is None or model is None or vocoder is None:
107
  try:
108
+ print("📂 Caricamento dei componenti TTS...")
109
+ # Carica il processor, modello e vocoder
110
+ processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
111
+ model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
112
+ vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ print("✅ Componenti TTS caricati con successo!")
115
+ return True
116
  except Exception as e:
117
+ print(f"❌ Errore nel caricamento dei componenti TTS: {e}")
118
  traceback_str = traceback.format_exc()
119
  print(f"Traceback completo:\n{traceback_str}")
120
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  def text_to_speech(text, language="it", speaker_id=0, speed=1.0, show_log=False):
123
  """Converte testo in voce utilizzando il modello TTS"""
 
129
  print(f"Richiesta TTS ricevuta: '{text}' (Lingua: {language}, Speaker: {speaker_id}, Velocità: {speed})")
130
 
131
  try:
132
+ # Carica i componenti se non già caricati
133
+ if not load_tts_components():
134
+ return None, "Errore nel caricamento dei componenti TTS. Riprova più tardi."
135
 
136
  # Ottieni gli speaker embeddings
137
+ speaker_emb = get_correct_speaker_embeddings(speaker_id)
 
 
 
138
 
139
+ # Microsoft SpeechT5 non supporta il parametro language, quindi lo ignoriamo
140
+ if show_log:
141
+ print(f"Elaborazione del testo: '{text}'")
 
142
 
143
+ # Crea input IDs dal testo
144
+ inputs = processor(text=text, return_tensors="pt")
145
+
146
+ # Genera l'audio con speaker embeddings
147
+ if show_log:
148
+ print("Generazione dell'audio...")
149
 
150
+ with torch.no_grad():
151
+ # Sposta gli speaker embeddings sul dispositivo di calcolo
152
+ if hasattr(model, "device"):
153
+ speaker_emb = speaker_emb.to(model.device)
154
+
155
  # Genera l'audio
156
+ speech = model.generate_speech(
157
+ inputs["input_ids"],
158
+ speaker_emb,
159
+ vocoder=vocoder
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  )
161
+
162
+ # Imposta la frequenza di campionamento
163
+ sample_rate = SAMPLE_RATE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
  # Converti il tensore in un array numpy
166
+ speech_array = speech.numpy()
167
 
168
  # Applica il controllo della velocità
169
  if speed != 1.0:
 
184
  # Esempi predefiniti per l'interfaccia
185
  examples = [
186
  ["Ciao, mi chiamo Aurora e sono un assistente vocale italiano.", "it", 0, 1.0, False],
187
+ ["Hello, my name is Aurora and I'm an Italian voice assistant.", "en", 1, 1.0, False],
188
+ ["Hola, me llamo Aurora y soy un asistente de voz italiano.", "es", 2, 1.0, False],
189
+ ["La vita è bella e il sole splende nel cielo azzurro.", "it", 3, 1.0, False],
190
+ ["Mi piace viaggiare e scoprire nuove città e culture.", "it", 4, 1.2, False],
191
+ ["L'intelligenza artificiale sta trasformando il modo in cui interagiamo con i computer e con il mondo che ci circonda.", "it", 5, 0.9, False]
192
  ]
193
 
194
  # Definizione dell'interfaccia Gradio
195
+ with gr.Blocks(title="Aurora TTS Demo", theme=gr.themes.Soft()) as demo:
196
  gr.Markdown("""
197
+ # 🎙️ Text-to-Speech Demo
198
 
199
+ Questa demo utilizza il modello Microsoft SpeechT5 per la sintesi vocale (TTS).
200
 
201
+ Puoi selezionare diversi stili di voce cambiando lo Speaker ID.
202
  """)
203
 
204
  with gr.Row():
 
215
  choices=["it", "en", "es", "fr", "de"],
216
  label="Lingua",
217
  value="it",
218
+ info="Seleziona la lingua del testo (nota: il modello attuale si comporta meglio con l'inglese)"
219
  )
220
  speaker_input = gr.Slider(
221
  label="Speaker ID",
 
256
  ## 📝 Note sull'utilizzo
257
 
258
  - Il modello funziona meglio con frasi di lunghezza media (fino a 20-30 parole)
 
259
  - Puoi cambiare lo Speaker ID per ottenere voci con caratteristiche diverse
260
  - La velocità di generazione dipende dalle risorse disponibili sul server
261
 
262
  ## 🔗 Crediti
263
 
264
+ - [Microsoft SpeechT5](https://huggingface.co/microsoft/speecht5_tts) (modello base)
 
 
 
265
  - [CMU Arctic XVectors](https://huggingface.co/datasets/Matthijs/cmu-arctic-xvectors) (speaker embeddings)
266
  """)
267