RafaG commited on
Commit
52cb8ec
·
verified ·
1 Parent(s): a9a81fd

Update tiktokTTS.py

Browse files
Files changed (1) hide show
  1. tiktokTTS.py +146 -145
tiktokTTS.py CHANGED
@@ -1,146 +1,147 @@
1
- # tiktokTTS.py
2
-
3
- import os
4
- import sys
5
- from pathlib import Path
6
- import gradio as gr
7
- import asyncio
8
- import pysrt
9
- from tqdm import tqdm
10
- import shutil
11
-
12
- # Importa funções utilitárias
13
- from utils import remove_silence, timetoms, merge_audio_files, adjust_audio_speed
14
-
15
- # --- Configuração e Imports da Biblioteca TikTok ---
16
- try:
17
- sys.path.append(str(Path(__file__).parent / "TikTok_TTS"))
18
- from TikTok_TTS.tiktok_voice import Voice, tts
19
- TIKTOK_TTS_AVAILABLE = True
20
- print("Biblioteca TikTok TTS carregada com sucesso.")
21
- except ImportError:
22
- TIKTOK_TTS_AVAILABLE = False
23
- print("Aviso: Biblioteca TikTok TTS não encontrada. A funcionalidade estará desabilitada.")
24
- class Voice: pass
25
- def tts(*args, **kwargs): pass
26
-
27
- # --- DICIONÁRIO DE VOZES CATEGORIZADAS ---
28
- TIKTOK_VOICES_CATEGORIZED = {
29
- 'Português (Brasil)': [
30
- 'BR_FEMALE_1', 'BR_FEMALE_2', 'BR_FEMALE_3', 'BR_MALE',
31
- 'BP_FEMALE_IVETE', 'BP_FEMALE_LUDMILLA', 'PT_FEMALE_LHAYS', 'PT_FEMALE_LAIZZA', 'PT_MALE_BUENO'
32
- ],
33
- 'Inglês (EUA)': [
34
- 'US_FEMALE_1', 'US_FEMALE_2', 'US_MALE_1', 'US_MALE_2', 'US_MALE_3', 'US_MALE_4'
35
- ],
36
- 'Inglês (Reino Unido)': ['UK_MALE_1', 'UK_MALE_2'],
37
- 'Inglês (Austrália)': ['AU_FEMALE_1', 'AU_MALE_1'],
38
- 'Inglês (Personagens Especiais)': [
39
- 'MALE_JOMBOY', 'MALE_CODY', 'FEMALE_SAMC', 'FEMALE_MAKEUP', 'FEMALE_RICHGIRL',
40
- 'MALE_ASHMAGIC', 'MALE_OLANTERKKERS', 'MALE_UKNEIGHBOR', 'MALE_UKBUTLER',
41
- 'FEMALE_SHENNA', 'FEMALE_PANSINO', 'MALE_TREVOR', 'FEMALE_BETTY', 'MALE_CUPID',
42
- 'FEMALE_GRANDMA', 'MALE_NARRATION', 'MALE_FUNNY', 'FEMALE_EMOTIONAL'
43
- ],
44
- 'Inglês Personagens (Filmes e Outros)': [
45
- 'GHOSTFACE', 'CHEWBACCA', 'C3PO', 'STITCH', 'STORMTROOPER', 'ROCKET',
46
- 'MADAME_LEOTA', 'GHOST_HOST', 'PIRATE', 'MALE_GRINCH', 'MALE_DEADPOOL', 'MALE_JARVIS'
47
- ],
48
- 'Inglês Personagens (Festivos)': [
49
- 'MALE_XMXS_CHRISTMAS', 'MALE_SANTA_NARRATION', 'MALE_SANTA_EFFECT',
50
- 'FEMALE_HT_NEYEAR', 'MALE_WIZARD', 'FEMALE_HT_HALLOWEEN'
51
- ],
52
- 'Inglês Cantores / Músicas': [
53
- 'MALE_SING_DEEP_JINGLE', 'SING_FEMALE_ALTO', 'SING_MALE_TENOR', 'SING_FEMALE_WARMY_BREEZE',
54
- 'SING_MALE_SUNSHINE_SOON', 'SING_FEMALE_GLORIOUS', 'SING_MALE_IT_GOES_UP',
55
- 'SING_MALE_CHIPMUNK', 'SING_FEMALE_WONDERFUL_WORLD', 'SING_MALE_FUNNY_THANKSGIVING'
56
- ],
57
- 'Japonês': [
58
- 'JP_FEMALE_1', 'JP_FEMALE_2', 'JP_FEMALE_3', 'JP_MALE', 'JP_FEMALE_FUJICOCHAN',
59
- 'JP_FEMALE_HASEGAWARIONA', 'JP_MALE_KEIICHINAKANO', 'JP_FEMALE_OOMAEAIIKA',
60
- 'JP_MALE_YUJINCHIGUSA', 'JP_FEMALE_SHIROU', 'JP_MALE_TAMAWAKAZUKI',
61
- 'JP_FEMALE_KAORISHOJI', 'JP_FEMALE_YAGISHAKI', 'JP_MALE_HIKAKIN', 'JP_FEMALE_REI',
62
- 'JP_MALE_SHUICHIRO', 'JP_MALE_MATSUDAKE', 'JP_FEMALE_MACHIKORIIITA',
63
- 'JP_MALE_MATSUO', 'JP_MALE_OSADA'
64
- ],
65
- 'Coreano': ['KR_MALE_1', 'KR_FEMALE', 'KR_MALE_2'],
66
- 'Espanhol': ['ES_MALE', 'ES_MX_MALE'],
67
- 'Francês': ['FR_MALE_1', 'FR_MALE_2'],
68
- 'Alemão': ['DE_FEMALE', 'DE_MALE'],
69
- 'Indonésio': ['ID_FEMALE']
70
- }
71
-
72
- def get_tiktok_voice_options(language):
73
- return TIKTOK_VOICES_CATEGORIZED.get(language, [])
74
-
75
- # --- Função Controladora de Texto/Arquivo ---
76
- def controlador_generate_audio_tiktok(voice_str, text, text_file, cut_silence):
77
- if not TIKTOK_TTS_AVAILABLE:
78
- raise gr.Error("A biblioteca TikTok TTS não está instalada ou configurada corretamente.")
79
- if not text and text_file is None:
80
- raise gr.Error("Por favor, forneça um texto ou um arquivo .txt para gerar o áudio.")
81
-
82
- output_dir = "output"; os.makedirs(output_dir, exist_ok=True)
83
- output_file = os.path.join(output_dir, "tiktok_audio.mp3")
84
- input_text = text if text else Path(text_file.name).read_text(encoding='utf-8')
85
-
86
- try:
87
- print(f"Gerando áudio com a voz TikTok: {voice_str}...")
88
- tts(input_text, Voice[voice_str], output_file)
89
- print("Áudio TikTok gerado com sucesso!")
90
- if cut_silence:
91
- print("Removendo silêncio do áudio TikTok..."); remove_silence(output_file, output_file); print("Silêncio removido.")
92
- return output_file
93
-
94
- except requests.exceptions.RequestException as e:
95
- print(f"!!! TIKTOK TTS NETWORK ERROR DETECTED: {e}")
96
- raise gr.Error(TIKTOK_CONNECTION_ERROR_MSG)
97
- except KeyError:
98
- raise gr.Error(f"A voz '{voice_str}' não foi encontrada.")
99
- except Exception as e:
100
- print(f"!!! TIKTOK TTS UNEXPECTED ERROR: {type(e).__name__} - {e}")
101
- raise gr.Error(f"Ocorreu um erro inesperado no TikTok TTS, se tiver usando GRADIO, mude pra Google Colab: {e}")
102
-
103
- # --- NOVA LÓGICA DE PROCESSAMENTO DE SRT PARA TIKTOK ---
104
-
105
- async def process_srt_file_tiktok(srt_file_path, voice_str, output_dir_str, srt_temp_deleta):
106
- """Função principal assíncrona para processar SRT com TikTok TTS."""
107
- subs = pysrt.open(srt_file_path)
108
- output_dir = Path(output_dir_str)
109
- output_dir.mkdir(parents=True, exist_ok=True)
110
-
111
- with tqdm(total=len(subs), desc="Gerando e ajustando áudios com TikTok", unit="segmento") as pbar:
112
- for sub in subs:
113
- temp_file = output_dir / f"{sub.index:02d}_temp.mp3"
114
- output_file = output_dir / f"{sub.index:02d}.mp3"
115
- target_duration_ms = timetoms(sub.end) - timetoms(sub.start)
116
-
117
- if not output_file.exists() or output_file.stat().st_size == 0:
118
- # Roda a função síncrona 'tts' em uma thread separada para não bloquear o asyncio
119
- await asyncio.to_thread(tts, sub.text, Voice[voice_str], str(temp_file))
120
-
121
- if temp_file.exists():
122
- await adjust_audio_speed(str(temp_file), str(output_file), target_duration_ms)
123
- os.remove(temp_file)
124
- pbar.update(1)
125
-
126
- final_audio = await merge_audio_files(output_dir, srt_file_path)
127
-
128
- if srt_temp_deleta:
129
- shutil.rmtree(output_dir, ignore_errors=True)
130
- print(f"Pasta temporária {output_dir} apagada.")
131
-
132
- return final_audio
133
-
134
- def controlador_process_srt_file_tiktok(srt_file, voice_str, srt_temp_deleta):
135
- if not srt_file: return None
136
- output_dir = "output/srt_temp"
137
-
138
- try:
139
- return asyncio.run(process_srt_file_tiktok(srt_file.name, voice_str, output_dir, srt_temp_deleta))
140
-
141
- except requests.exceptions.RequestException as e:
142
- print(f"!!! TIKTOK TTS NETWORK ERROR (SRT): {e}")
143
- raise gr.Error(TIKTOK_CONNECTION_ERROR_MSG)
144
- except Exception as e:
145
- print(f"!!! TIKTOK TTS UNEXPECTED ERROR (SRT): {e}")
 
146
  raise gr.Error(f"Ocorreu um erro inesperado no TikTok TTS, se tiver usando GRADIO, mude pra Google Colab: {e}")
 
1
+ # tiktokTTS.py
2
+
3
+ import os
4
+ import sys
5
+ from pathlib import Path
6
+ import gradio as gr
7
+ import asyncio
8
+ import pysrt
9
+ from tqdm import tqdm
10
+ import shutil
11
+ import requests
12
+
13
+ # Importa funções utilitárias
14
+ from utils import remove_silence, timetoms, merge_audio_files, adjust_audio_speed
15
+
16
+ # --- Configuração e Imports da Biblioteca TikTok ---
17
+ try:
18
+ sys.path.append(str(Path(__file__).parent / "TikTok_TTS"))
19
+ from TikTok_TTS.tiktok_voice import Voice, tts
20
+ TIKTOK_TTS_AVAILABLE = True
21
+ print("Biblioteca TikTok TTS carregada com sucesso.")
22
+ except ImportError:
23
+ TIKTOK_TTS_AVAILABLE = False
24
+ print("Aviso: Biblioteca TikTok TTS não encontrada. A funcionalidade estará desabilitada.")
25
+ class Voice: pass
26
+ def tts(*args, **kwargs): pass
27
+
28
+ # --- DICIONÁRIO DE VOZES CATEGORIZADAS ---
29
+ TIKTOK_VOICES_CATEGORIZED = {
30
+ 'Português (Brasil)': [
31
+ 'BR_FEMALE_1', 'BR_FEMALE_2', 'BR_FEMALE_3', 'BR_MALE',
32
+ 'BP_FEMALE_IVETE', 'BP_FEMALE_LUDMILLA', 'PT_FEMALE_LHAYS', 'PT_FEMALE_LAIZZA', 'PT_MALE_BUENO'
33
+ ],
34
+ 'Inglês (EUA)': [
35
+ 'US_FEMALE_1', 'US_FEMALE_2', 'US_MALE_1', 'US_MALE_2', 'US_MALE_3', 'US_MALE_4'
36
+ ],
37
+ 'Inglês (Reino Unido)': ['UK_MALE_1', 'UK_MALE_2'],
38
+ 'Inglês (Austrália)': ['AU_FEMALE_1', 'AU_MALE_1'],
39
+ 'Inglês (Personagens Especiais)': [
40
+ 'MALE_JOMBOY', 'MALE_CODY', 'FEMALE_SAMC', 'FEMALE_MAKEUP', 'FEMALE_RICHGIRL',
41
+ 'MALE_ASHMAGIC', 'MALE_OLANTERKKERS', 'MALE_UKNEIGHBOR', 'MALE_UKBUTLER',
42
+ 'FEMALE_SHENNA', 'FEMALE_PANSINO', 'MALE_TREVOR', 'FEMALE_BETTY', 'MALE_CUPID',
43
+ 'FEMALE_GRANDMA', 'MALE_NARRATION', 'MALE_FUNNY', 'FEMALE_EMOTIONAL'
44
+ ],
45
+ 'Inglês Personagens (Filmes e Outros)': [
46
+ 'GHOSTFACE', 'CHEWBACCA', 'C3PO', 'STITCH', 'STORMTROOPER', 'ROCKET',
47
+ 'MADAME_LEOTA', 'GHOST_HOST', 'PIRATE', 'MALE_GRINCH', 'MALE_DEADPOOL', 'MALE_JARVIS'
48
+ ],
49
+ 'Inglês Personagens (Festivos)': [
50
+ 'MALE_XMXS_CHRISTMAS', 'MALE_SANTA_NARRATION', 'MALE_SANTA_EFFECT',
51
+ 'FEMALE_HT_NEYEAR', 'MALE_WIZARD', 'FEMALE_HT_HALLOWEEN'
52
+ ],
53
+ 'Inglês Cantores / Músicas': [
54
+ 'MALE_SING_DEEP_JINGLE', 'SING_FEMALE_ALTO', 'SING_MALE_TENOR', 'SING_FEMALE_WARMY_BREEZE',
55
+ 'SING_MALE_SUNSHINE_SOON', 'SING_FEMALE_GLORIOUS', 'SING_MALE_IT_GOES_UP',
56
+ 'SING_MALE_CHIPMUNK', 'SING_FEMALE_WONDERFUL_WORLD', 'SING_MALE_FUNNY_THANKSGIVING'
57
+ ],
58
+ 'Japonês': [
59
+ 'JP_FEMALE_1', 'JP_FEMALE_2', 'JP_FEMALE_3', 'JP_MALE', 'JP_FEMALE_FUJICOCHAN',
60
+ 'JP_FEMALE_HASEGAWARIONA', 'JP_MALE_KEIICHINAKANO', 'JP_FEMALE_OOMAEAIIKA',
61
+ 'JP_MALE_YUJINCHIGUSA', 'JP_FEMALE_SHIROU', 'JP_MALE_TAMAWAKAZUKI',
62
+ 'JP_FEMALE_KAORISHOJI', 'JP_FEMALE_YAGISHAKI', 'JP_MALE_HIKAKIN', 'JP_FEMALE_REI',
63
+ 'JP_MALE_SHUICHIRO', 'JP_MALE_MATSUDAKE', 'JP_FEMALE_MACHIKORIIITA',
64
+ 'JP_MALE_MATSUO', 'JP_MALE_OSADA'
65
+ ],
66
+ 'Coreano': ['KR_MALE_1', 'KR_FEMALE', 'KR_MALE_2'],
67
+ 'Espanhol': ['ES_MALE', 'ES_MX_MALE'],
68
+ 'Francês': ['FR_MALE_1', 'FR_MALE_2'],
69
+ 'Alemão': ['DE_FEMALE', 'DE_MALE'],
70
+ 'Indonésio': ['ID_FEMALE']
71
+ }
72
+
73
+ def get_tiktok_voice_options(language):
74
+ return TIKTOK_VOICES_CATEGORIZED.get(language, [])
75
+
76
+ # --- Função Controladora de Texto/Arquivo ---
77
+ def controlador_generate_audio_tiktok(voice_str, text, text_file, cut_silence):
78
+ if not TIKTOK_TTS_AVAILABLE:
79
+ raise gr.Error("A biblioteca TikTok TTS não está instalada ou configurada corretamente.")
80
+ if not text and text_file is None:
81
+ raise gr.Error("Por favor, forneça um texto ou um arquivo .txt para gerar o áudio.")
82
+
83
+ output_dir = "output"; os.makedirs(output_dir, exist_ok=True)
84
+ output_file = os.path.join(output_dir, "tiktok_audio.mp3")
85
+ input_text = text if text else Path(text_file.name).read_text(encoding='utf-8')
86
+
87
+ try:
88
+ print(f"Gerando áudio com a voz TikTok: {voice_str}...")
89
+ tts(input_text, Voice[voice_str], output_file)
90
+ print("Áudio TikTok gerado com sucesso!")
91
+ if cut_silence:
92
+ print("Removendo silêncio do áudio TikTok..."); remove_silence(output_file, output_file); print("Silêncio removido.")
93
+ return output_file
94
+
95
+ except requests.exceptions.RequestException as e:
96
+ print(f"!!! TIKTOK TTS NETWORK ERROR DETECTED: {e}")
97
+ raise gr.Error(TIKTOK_CONNECTION_ERROR_MSG)
98
+ except KeyError:
99
+ raise gr.Error(f"A voz '{voice_str}' não foi encontrada.")
100
+ except Exception as e:
101
+ print(f"!!! TIKTOK TTS UNEXPECTED ERROR: {type(e).__name__} - {e}")
102
+ raise gr.Error(f"Ocorreu um erro inesperado no TikTok TTS, se tiver usando GRADIO, mude pra Google Colab: {e}")
103
+
104
+ # --- NOVA LÓGICA DE PROCESSAMENTO DE SRT PARA TIKTOK ---
105
+
106
+ async def process_srt_file_tiktok(srt_file_path, voice_str, output_dir_str, srt_temp_deleta):
107
+ """Função principal assíncrona para processar SRT com TikTok TTS."""
108
+ subs = pysrt.open(srt_file_path)
109
+ output_dir = Path(output_dir_str)
110
+ output_dir.mkdir(parents=True, exist_ok=True)
111
+
112
+ with tqdm(total=len(subs), desc="Gerando e ajustando áudios com TikTok", unit="segmento") as pbar:
113
+ for sub in subs:
114
+ temp_file = output_dir / f"{sub.index:02d}_temp.mp3"
115
+ output_file = output_dir / f"{sub.index:02d}.mp3"
116
+ target_duration_ms = timetoms(sub.end) - timetoms(sub.start)
117
+
118
+ if not output_file.exists() or output_file.stat().st_size == 0:
119
+ # Roda a função síncrona 'tts' em uma thread separada para não bloquear o asyncio
120
+ await asyncio.to_thread(tts, sub.text, Voice[voice_str], str(temp_file))
121
+
122
+ if temp_file.exists():
123
+ await adjust_audio_speed(str(temp_file), str(output_file), target_duration_ms)
124
+ os.remove(temp_file)
125
+ pbar.update(1)
126
+
127
+ final_audio = await merge_audio_files(output_dir, srt_file_path)
128
+
129
+ if srt_temp_deleta:
130
+ shutil.rmtree(output_dir, ignore_errors=True)
131
+ print(f"Pasta temporária {output_dir} apagada.")
132
+
133
+ return final_audio
134
+
135
+ def controlador_process_srt_file_tiktok(srt_file, voice_str, srt_temp_deleta):
136
+ if not srt_file: return None
137
+ output_dir = "output/srt_temp"
138
+
139
+ try:
140
+ return asyncio.run(process_srt_file_tiktok(srt_file.name, voice_str, output_dir, srt_temp_deleta))
141
+
142
+ except requests.exceptions.RequestException as e:
143
+ print(f"!!! TIKTOK TTS NETWORK ERROR (SRT): {e}")
144
+ raise gr.Error(TIKTOK_CONNECTION_ERROR_MSG)
145
+ except Exception as e:
146
+ print(f"!!! TIKTOK TTS UNEXPECTED ERROR (SRT): {e}")
147
  raise gr.Error(f"Ocorreu um erro inesperado no TikTok TTS, se tiver usando GRADIO, mude pra Google Colab: {e}")