Uniaff commited on
Commit
5967f17
·
verified ·
1 Parent(s): 6cd8aed

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -69
app.py CHANGED
@@ -10,6 +10,8 @@ import numpy as np
10
  import torch
11
  import torchaudio
12
  from resemble_enhance.enhancer.inference import denoise
 
 
13
 
14
  # Установка переменных окружения для принятия лицензионных условий
15
  os.environ["COQUI_TOS_AGREED"] = "1"
@@ -17,6 +19,17 @@ os.environ["COQUI_TOS_AGREED"] = "1"
17
  # Определение устройства (CUDA или CPU)
18
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
19
 
 
 
 
 
 
 
 
 
 
 
 
20
  # Глобальные переменные и настройки
21
  language_options = {
22
  "English (en)": "en",
@@ -63,23 +76,52 @@ def check_audio_length(audio_path, max_duration=120):
63
  print(f"Error while checking audio length: {e}")
64
  return False
65
 
66
- def synthesize_and_convert_voice(text, language_iso, voice_audio_path, speed):
67
- # Синтез речи с помощью TTS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  tts_synthesis = TTS(model_name=f"tts_models/{language_iso}/fairseq/vits")
69
  wav_data = tts_synthesis.tts(text, speed=speed)
70
 
71
- # Преобразование wav_data из списка в NumPy массив с типом float32
72
  wav_data_np = np.array(wav_data, dtype=np.float32)
 
73
 
74
- # Нормализация данных, если необходимо
75
- max_val = np.max(np.abs(wav_data_np))
76
- if max_val > 1.0:
77
- wav_data_np = wav_data_np / max_val
78
-
79
- # Масштабирование до int16 для записи в WAV файл
80
  wav_data_int16 = np.int16(wav_data_np * 32767)
81
-
82
- # Сохранение синтезированного аудио во временный файл
83
  with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_tts_wav_file:
84
  temp_tts_wav_path = temp_tts_wav_file.name
85
  write(temp_tts_wav_path, 22050, wav_data_int16)
@@ -87,41 +129,69 @@ def synthesize_and_convert_voice(text, language_iso, voice_audio_path, speed):
87
  # Загрузка синтезированного аудио
88
  wav_tensor, sample_rate = torchaudio.load(temp_tts_wav_path)
89
 
90
- # Преобразование в моно, если аудио стерео
91
- if wav_tensor.dim() > 1 and wav_tensor.size(0) > 1:
92
  wav_tensor = wav_tensor.mean(dim=0, keepdim=True)
93
 
94
- # Применение денойзинга (не перемещаем wav_tensor на устройство)
95
- denoised_wav_tensor, denoised_sample_rate = denoise(wav_tensor.squeeze(), sample_rate, device)
 
 
 
 
 
 
96
 
97
  # Сохранение денойзенного аудио во временный файл
98
  with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_denoised_wav_file:
99
  temp_denoised_wav_path = temp_denoised_wav_file.name
100
- torchaudio.save(temp_denoised_wav_path, denoised_wav_tensor.unsqueeze(0).cpu(), denoised_sample_rate)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
- # Преобразование голоса с использованием денойзенного аудио
103
- tts_conversion = TTS(model_name="voice_conversion_models/multilingual/vctk/freevc24", progress_bar=False)
 
 
104
 
105
- # Подготовка временного выходного файла
106
- with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_output_wav_file:
107
- temp_output_wav_path = temp_output_wav_file.name
108
 
109
- # Преобразование голоса
110
- tts_conversion.voice_conversion_to_file(temp_denoised_wav_path, target_wav=voice_audio_path,
111
- file_path=temp_output_wav_path)
112
 
113
- # Чтение преобразованного аудио
114
- output_sample_rate, output_audio_data = read(temp_output_wav_path)
115
 
116
- # Удаление временных файлов
117
- os.remove(temp_tts_wav_path)
118
- os.remove(temp_denoised_wav_path)
119
- os.remove(temp_output_wav_path)
120
 
121
- return (output_sample_rate, output_audio_data)
 
 
 
122
 
 
 
 
 
 
 
123
 
124
- def synthesize_speech(text, speaker_wav_path, language_iso, speed):
 
 
125
  # Загрузка аудио говорящего
126
  speaker_wav_tensor, speaker_sample_rate = torchaudio.load(speaker_wav_path)
127
 
@@ -161,38 +231,37 @@ def synthesize_speech(text, speaker_wav_path, language_iso, speed):
161
  if wav_tensor.dim() > 1 and wav_tensor.size(0) > 1:
162
  wav_tensor = wav_tensor.mean(dim=0, keepdim=True)
163
 
164
- # Сохранение сгенерированного аудио во временный файл для voice cloning
165
  with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_vc_input_file:
166
  temp_vc_input_path = temp_vc_input_file.name
167
  torchaudio.save(temp_vc_input_path, wav_tensor.cpu(), sample_rate)
168
 
169
- # Инициализация модели voice conversion
170
- tts_conversion = TTS(
171
- model_name="voice_conversion_models/multilingual/vctk/freevc24",
172
- progress_bar=False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  )
174
 
175
- # Подготовка временного выходного файла
176
- with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_output_wav_file:
177
- temp_output_wav_path = temp_output_wav_file.name
178
-
179
- # Преобразование голоса
180
- tts_conversion.voice_conversion_to_file(
181
- temp_vc_input_path,
182
- target_wav=temp_denoised_speaker_path,
183
- file_path=temp_output_wav_path
184
- )
185
-
186
- # Чтение преобразованного аудио
187
- output_sample_rate, output_audio_data = read(temp_output_wav_path)
188
-
189
  # Удаление временных файлов
190
  os.remove(temp_denoised_speaker_path)
191
  os.remove(temp_tts_output_path)
192
  os.remove(temp_vc_input_path)
193
- os.remove(temp_output_wav_path)
194
 
195
- return (output_sample_rate, output_audio_data)
196
 
197
  def get_language_code(selected_language):
198
  if selected_language in language_options:
@@ -203,30 +272,46 @@ def get_language_code(selected_language):
203
  return None
204
 
205
  def process_speech(text, speaker_wav_path, selected_language, speed):
 
 
 
 
206
  language_code = get_language_code(selected_language)
207
 
208
  if language_code is None:
209
  raise ValueError("Выбранный язык не поддерживается.")
210
 
211
  if speaker_wav_path is None:
212
- error_message = "Пожалуйста, загрузите аудио файл говорящего."
213
- error = gr.Error(error_message, duration=5)
214
- raise error
215
 
216
  # Проверка длины аудио
217
- audio = AudioSegment.from_file(speaker_wav_path)
218
- duration = audio.duration_seconds
219
- if duration > 120:
220
- error_message = "Длина аудио превышает допустимый лимит в 2 минуты."
221
- error = gr.Error(error_message, duration=5)
222
- raise error
223
-
224
- if selected_language in other_language:
225
- output_audio_data = synthesize_and_convert_voice(text, language_code, speaker_wav_path, speed)
226
- else:
227
- output_audio_data = synthesize_speech(text, speaker_wav_path, language_code, speed)
 
 
 
 
 
 
 
 
 
 
 
228
 
229
- return output_audio_data
 
 
 
230
 
231
  def restart_program():
232
  python = sys.executable
@@ -363,4 +448,4 @@ with gr.Blocks() as app:
363
  )
364
 
365
  if __name__ == "__main__":
366
- launch_gradio()
 
10
  import torch
11
  import torchaudio
12
  from resemble_enhance.enhancer.inference import denoise
13
+ from seedvc import voice_conversion
14
+
15
 
16
  # Установка переменных окружения для принятия лицензионных условий
17
  os.environ["COQUI_TOS_AGREED"] = "1"
 
19
  # Определение устройства (CUDA или CPU)
20
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
21
 
22
+ def normalize_audio(wave):
23
+ """
24
+ Нормализует аудиосигнал так, чтобы максимальное абсолютное значение было <= 1.0
25
+ """
26
+ max_val = np.max(np.abs(wave))
27
+ if max_val > 1.0:
28
+ wave = wave / max_val
29
+ return wave
30
+
31
+
32
+
33
  # Глобальные переменные и настройки
34
  language_options = {
35
  "English (en)": "en",
 
76
  print(f"Error while checking audio length: {e}")
77
  return False
78
 
79
+
80
+ def synthesize_and_convert_voice(text, language_iso, voice_audio_path, speed, device='cpu'):
81
+ """
82
+ Синтезирует речь на основе текста, выполняет денойзинг для клонируемого аудио и преобразование голоса.
83
+
84
+ Параметры:
85
+ - text (str): Текст для синтеза речи.
86
+ - language_iso (str): ISO-код языка для TTS.
87
+ - voice_audio_path (str): Путь к аудио-файлу для клонирования голоса.
88
+ - speed (float): Скорость синтеза речи.
89
+ - device (str): Устройство для обработки (например, 'cpu' или 'cuda').
90
+
91
+ Возвращает:
92
+ - tuple: (частота дискретизации, numpy массив аудио данных)
93
+ """
94
+ # Загрузка аудио для клонирования
95
+ voice_wav_tensor, voice_sample_rate = torchaudio.load(voice_audio_path)
96
+
97
+ # Преобразование в моно, если аудио стерео
98
+ if voice_wav_tensor.dim() > 1:
99
+ voice_wav_tensor = voice_wav_tensor.mean(dim=0, keepdim=True)
100
+
101
+ # Применение денойзинга к аудио для клонирования
102
+ denoised_voice_wav_tensor, denoised_voice_sample_rate = denoise(
103
+ voice_wav_tensor.squeeze(), voice_sample_rate, device=device
104
+ )
105
+
106
+ # Сохранение денойзенного аудио во временный файл
107
+ with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_denoised_voice_file:
108
+ temp_denoised_voice_path = temp_denoised_voice_file.name
109
+ torchaudio.save(
110
+ temp_denoised_voice_path,
111
+ denoised_voice_wav_tensor.unsqueeze(0).cpu(),
112
+ denoised_voice_sample_rate
113
+ )
114
+
115
+ # Синтез речи с использованием TTS
116
  tts_synthesis = TTS(model_name=f"tts_models/{language_iso}/fairseq/vits")
117
  wav_data = tts_synthesis.tts(text, speed=speed)
118
 
119
+ # Преобразование в NumPy массив и нормализация
120
  wav_data_np = np.array(wav_data, dtype=np.float32)
121
+ wav_data_np = wav_data_np / max(1.0, np.max(np.abs(wav_data_np)))
122
 
123
+ # Масштабирование до int16 и временное сохранение
 
 
 
 
 
124
  wav_data_int16 = np.int16(wav_data_np * 32767)
 
 
125
  with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_tts_wav_file:
126
  temp_tts_wav_path = temp_tts_wav_file.name
127
  write(temp_tts_wav_path, 22050, wav_data_int16)
 
129
  # Загрузка синтезированного аудио
130
  wav_tensor, sample_rate = torchaudio.load(temp_tts_wav_path)
131
 
132
+ # Преобразование в моно, если требуется
133
+ if wav_tensor.dim() > 1:
134
  wav_tensor = wav_tensor.mean(dim=0, keepdim=True)
135
 
136
+ # Применение денойзинга
137
+ denoised_wav_tensor, denoised_sample_rate = denoise(wav_tensor.squeeze(), sample_rate, device=device)
138
+
139
+ # Преобразование денойзенного тензора в NumPy массив
140
+ denoised_wav_np = denoised_wav_tensor.cpu().numpy()
141
+
142
+ # Масштабирование денойзенного аудио до int16
143
+ denoised_wav_int16 = np.int16(denoised_wav_np * 32767)
144
 
145
  # Сохранение денойзенного аудио во временный файл
146
  with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_denoised_wav_file:
147
  temp_denoised_wav_path = temp_denoised_wav_file.name
148
+ write(temp_denoised_wav_path, denoised_sample_rate, denoised_wav_int16)
149
+
150
+ # Параметры для voice_conversion
151
+ diffusion_steps = 30
152
+ length_adjust = 1.0
153
+ inference_cfg_rate = 0.6
154
+ f0_condition = True
155
+ auto_f0_adjust = True
156
+ pitch_shift = 0
157
+
158
+ # Вызов функции voice_conversion
159
+ output_sample_rate, output_audio_data = voice_conversion(
160
+ source=temp_denoised_wav_path,
161
+ target=temp_denoised_voice_path,
162
+ diffusion_steps=diffusion_steps,
163
+ length_adjust=length_adjust,
164
+ inference_cfg_rate=inference_cfg_rate,
165
+ f0_condition=f0_condition,
166
+ auto_f0_adjust=auto_f0_adjust,
167
+ pitch_shift=pitch_shift
168
+ )
169
 
170
+ # Очистка временных файлов
171
+ os.remove(temp_denoised_voice_path)
172
+ os.remove(temp_tts_wav_path)
173
+ os.remove(temp_denoised_wav_path)
174
 
175
+ return output_sample_rate, output_audio_data
 
 
176
 
 
 
 
177
 
 
 
178
 
 
 
 
 
179
 
180
+ def synthesize_speech(text, speaker_wav_path, language_iso, speed, device='cpu'):
181
+ """
182
+ Синтезирует речь на основе текста, предварительно очищая входящее аудио от шумов
183
+ и выполняя преобразование голоса с помощью функции voice_conversion.
184
 
185
+ Параметры:
186
+ - text (str): Текст для синтеза речи.
187
+ - speaker_wav_path (str): Путь к аудио говорящего для клонирования голоса.
188
+ - language_iso (str): ISO-код языка для TTS.
189
+ - speed (float): Скорость синтеза речи.
190
+ - device (str): Устройство для обработки (например, 'cpu' или 'cuda').
191
 
192
+ Возвращает:
193
+ - tuple: (частота дискретизации, numpy массив аудио данных)
194
+ """
195
  # Загрузка аудио говорящего
196
  speaker_wav_tensor, speaker_sample_rate = torchaudio.load(speaker_wav_path)
197
 
 
231
  if wav_tensor.dim() > 1 and wav_tensor.size(0) > 1:
232
  wav_tensor = wav_tensor.mean(dim=0, keepdim=True)
233
 
234
+ # Сохранение сгенерированного аудио во временный файл для voice_conversion
235
  with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_vc_input_file:
236
  temp_vc_input_path = temp_vc_input_file.name
237
  torchaudio.save(temp_vc_input_path, wav_tensor.cpu(), sample_rate)
238
 
239
+ # Параметры для voice_conversion
240
+ diffusion_steps = 30
241
+ length_adjust = 1.0
242
+ inference_cfg_rate = 0.6
243
+ f0_condition = True
244
+ auto_f0_adjust = True
245
+ pitch_shift = 0
246
+
247
+ # Вызов функции voice_conversion
248
+ output_sample_rate, output_audio_data = voice_conversion(
249
+ source=temp_vc_input_path,
250
+ target=temp_denoised_speaker_path,
251
+ diffusion_steps=diffusion_steps,
252
+ length_adjust=length_adjust,
253
+ inference_cfg_rate=inference_cfg_rate,
254
+ f0_condition=f0_condition,
255
+ auto_f0_adjust=auto_f0_adjust,
256
+ pitch_shift=pitch_shift
257
  )
258
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  # Удаление временных файлов
260
  os.remove(temp_denoised_speaker_path)
261
  os.remove(temp_tts_output_path)
262
  os.remove(temp_vc_input_path)
 
263
 
264
+ return output_sample_rate, output_audio_data
265
 
266
  def get_language_code(selected_language):
267
  if selected_language in language_options:
 
272
  return None
273
 
274
  def process_speech(text, speaker_wav_path, selected_language, speed):
275
+ """
276
+ Обрабатывает текст, выполняет синтез речи и голосовое клонирование,
277
+ а также возвращает путь к сгенерированному аудио-файлу.
278
+ """
279
  language_code = get_language_code(selected_language)
280
 
281
  if language_code is None:
282
  raise ValueError("Выбранный язык не поддерживается.")
283
 
284
  if speaker_wav_path is None:
285
+ raise ValueError("Пожалуйста, загрузите аудио файл говорящего.")
 
 
286
 
287
  # Проверка длины аудио
288
+ try:
289
+ audio = AudioSegment.from_file(speaker_wav_path)
290
+ duration = audio.duration_seconds
291
+ if duration > 120:
292
+ raise ValueError("Длина аудио превышает допустимый лимит в 2 минуты.")
293
+ except Exception as e:
294
+ raise ValueError(f"Ошибка при проверке аудио: {e}")
295
+
296
+ try:
297
+ if selected_language in other_language:
298
+ output_sample_rate, output_audio_data = synthesize_and_convert_voice(
299
+ text, language_code, speaker_wav_path, speed
300
+ )
301
+ else:
302
+ output_sample_rate, output_audio_data = synthesize_speech(
303
+ text, speaker_wav_path, language_code, speed
304
+ )
305
+
306
+ # Сохранение результата в файл для вывода
307
+ with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_output_file:
308
+ temp_output_path = temp_output_file.name
309
+ write(temp_output_path, output_sample_rate, output_audio_data)
310
 
311
+ return temp_output_path # Возвращаем путь к сгенерированному аудио
312
+
313
+ except Exception as e:
314
+ raise ValueError(f"Ошибка при обработке речи: {e}")
315
 
316
  def restart_program():
317
  python = sys.executable
 
448
  )
449
 
450
  if __name__ == "__main__":
451
+ launch_gradio()