mr-don88 commited on
Commit
d3c917b
·
verified ·
1 Parent(s): 426105c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -124
app.py CHANGED
@@ -3,15 +3,12 @@ import os, re, time, random, zipfile, requests, natsort
3
  import gradio as gr
4
  from pydub import AudioSegment
5
 
6
- # ====================== API CHECK (GIỐNG COLAB GỐC) ======================
7
  def check_api_key(api_key):
8
  try:
9
  r = requests.get(
10
  "https://api.elevenlabs.io/v1/user",
11
- headers={
12
- "xi-api-key": api_key,
13
- "User-Agent": "Mozilla/5.0"
14
- },
15
  timeout=10
16
  )
17
  if r.status_code != 200:
@@ -20,41 +17,33 @@ def check_api_key(api_key):
20
  sub = r.json().get("subscription", {})
21
  limit = sub.get("character_limit")
22
  used = sub.get("character_count")
23
-
24
- # GIỐNG CODE CŨ: thiếu field → coi như key lỗi
25
  if limit is None or used is None:
26
  return {"valid": False}
27
 
28
- remaining = limit - used
29
  return {
30
- "valid": remaining > 0,
31
- "remaining": remaining,
32
- "total": limit
33
  }
34
  except:
35
  return {"valid": False}
36
 
37
 
38
- # ====================== TIỆN ÍCH ======================
39
- def estimate_credit(text):
40
- return len(text) + 50
41
-
42
-
43
  def split_text(text, max_len=200):
44
- blocks, cur = [], ""
45
  for s in re.split(r'(?<=[.!?])\s+', text):
46
  if len(cur) + len(s) <= max_len:
47
  cur += " " + s
48
  else:
49
- blocks.append(cur.strip())
50
  cur = s
51
  if cur:
52
- blocks.append(cur.strip())
53
- return blocks
54
 
55
 
 
56
  def tts(text, api_key, voice_id, model):
57
- time.sleep(random.uniform(1, 2))
58
  r = requests.post(
59
  f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
60
  headers={
@@ -79,7 +68,7 @@ def tts(text, api_key, voice_id, model):
79
  return None
80
 
81
 
82
- # ====================== AUDIO + SRT ======================
83
  def merge_audio(folder, fmt):
84
  files = natsort.natsorted(f for f in os.listdir(folder) if f.endswith(fmt))
85
  audio = AudioSegment.from_file(os.path.join(folder, files[0]))
@@ -91,155 +80,93 @@ def merge_audio(folder, fmt):
91
  return out
92
 
93
 
94
- def ms(ms):
95
- return f"{ms//3600000:02}:{(ms%3600000)//60000:02}:{(ms%60000)//1000:02},{ms%1000:03}"
96
-
97
-
98
  def create_srt(folder, texts):
99
- t = 0
100
- lines = []
101
  files = natsort.natsorted(f for f in os.listdir(folder) if f.startswith("voice_"))
102
  for i, (f, txt) in enumerate(zip(files, texts), 1):
103
  a = AudioSegment.from_file(os.path.join(folder, f))
104
- lines += [str(i), f"{ms(t)} --> {ms(t+len(a))}", txt, ""]
 
 
105
  t += len(a) + 500
106
  with open(os.path.join(folder, "output_full.srt"), "w", encoding="utf-8") as f:
107
  f.write("\n".join(lines))
108
 
109
 
110
- # ====================== RUN CORE ======================
111
- def run(
112
- api_text, api_file,
113
- voice_text, voice_file,
114
- text_text, text_file,
115
- model, fmt
116
- ):
117
- log = []
118
-
119
- # ---- API KEYS ----
120
- if api_file:
121
- api_keys = api_file.decode().splitlines()
122
- else:
123
- api_keys = api_text.splitlines()
124
-
125
- api_keys = [k.strip() for k in api_keys if k.strip()]
126
- if not api_keys:
127
- return "❌ Thiếu API key", None, None, ""
128
-
129
- # ---- VOICE ID ----
130
- voice_id = voice_text.strip()
131
- if not voice_id and voice_file:
132
- voice_id = voice_file.decode().strip()
133
- if not voice_id:
134
- return "❌ Thiếu Voice ID", None, None, ""
135
-
136
- # ---- TEXT ----
137
- raw_text = text_text.strip()
138
- if not raw_text and text_file:
139
- raw_text = text_file.decode()
140
- if not raw_text:
141
- return "❌ Thiếu Text", None, None, ""
142
-
143
- # ---- CHECK API CREDIT (>600) ----
144
  valid = []
145
- table = "| API KEY | REMAINING |\n|---|---|\n"
146
 
147
- for k in api_keys:
148
  info = check_api_key(k)
149
  show = f"{k[:6]}...{k[-4:]}"
150
- if info["valid"]:
151
- rem = info["remaining"]
152
- table += f"| {show} | {rem} |\n"
153
- if rem > 600:
154
- valid.append([k, rem])
155
  else:
156
  table += f"| {show} | ❌ |\n"
157
 
158
  if not valid:
159
- return "❌ Không có API key nào >600 credit", None, None, table
160
 
161
- # ---- PREP ----
162
- texts = split_text(raw_text)
163
  os.makedirs("voices", exist_ok=True)
164
  for f in os.listdir("voices"):
165
  os.remove(os.path.join("voices", f))
166
 
167
- idx = 0
168
 
169
- # ---- GENERATE ----
170
  for i, t in enumerate(texts):
171
- need = estimate_credit(t)
172
- ok = False
173
-
174
  while valid:
175
- key, remain = valid[idx]
176
- if remain < need:
177
- log.append(f"🔄 {key[:6]}... hết credit → đổi key")
178
- valid.pop(idx)
179
- idx %= max(len(valid), 1)
180
- continue
181
-
182
  audio = tts(t, key, voice_id, model)
183
  if audio:
184
  with open(f"voices/voice_{i+1:03d}.{fmt}", "wb") as f:
185
  f.write(audio)
186
- valid[idx][1] -= need
187
- ok = True
188
  break
189
  else:
190
- log.append(f"❌ {key[:6]}... lỗi → loại")
191
- valid.pop(idx)
192
- idx %= max(len(valid), 1)
193
 
194
- if not ok:
195
- return "❌ Hết toàn bộ API key khi chạy", None, None, table
196
 
197
- # ---- OUTPUT ----
198
  merged = merge_audio("voices", fmt)
199
  create_srt("voices", texts)
200
 
201
- zip_path = "output.zip"
202
- with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as z:
203
  for f in os.listdir("voices"):
204
  z.write(os.path.join("voices", f), f)
205
  z.write(merged)
206
 
207
- return "✅ HOÀN TẤT", merged, zip_path, table
208
 
209
 
210
- # ====================== UI ======================
211
  with gr.Blocks() as app:
212
- gr.Markdown("## 🔊 ElevenLabs TTS – Logic Colab Gốc")
213
-
214
- with gr.Row():
215
- api_text = gr.Textbox(lines=4, label="API key (mỗi dòng 1 key)")
216
- api_file = gr.File(label="Upload API file (.txt)", type="binary")
217
-
218
- with gr.Row():
219
- voice_text = gr.Textbox(label="Voice ID")
220
- voice_file = gr.File(label="Upload voice_id.txt", type="binary")
221
 
222
- with gr.Row():
223
- text_text = gr.Textbox(lines=6, label="Text")
224
- text_file = gr.File(label="Upload text.txt", type="binary")
225
-
226
- model = gr.Dropdown(
227
- ["eleven_multilingual_v2", "eleven_turbo_v2_5", "eleven_flash_v2_5"],
228
- value="eleven_multilingual_v2",
229
- label="Model"
230
- )
231
- fmt = gr.Dropdown(["mp3", "wav"], value="mp3", label="Format")
232
 
233
  btn = gr.Button("🎧 TẠO GIỌNG")
234
- status = gr.Textbox(label="Trạng thái")
235
- audio = gr.Audio(type="filepath", label="Audio")
236
- zipf = gr.File(label="ZIP Download")
237
  table = gr.Markdown()
238
 
239
- btn.click(
240
- run,
241
- [api_text, api_file, voice_text, voice_file, text_text, text_file, model, fmt],
242
- [status, audio, zipf, table]
243
- )
244
 
245
  app.launch()
 
3
  import gradio as gr
4
  from pydub import AudioSegment
5
 
6
+ # ================= API CHECK (GIỐNG COLAB) =================
7
  def check_api_key(api_key):
8
  try:
9
  r = requests.get(
10
  "https://api.elevenlabs.io/v1/user",
11
+ headers={"xi-api-key": api_key},
 
 
 
12
  timeout=10
13
  )
14
  if r.status_code != 200:
 
17
  sub = r.json().get("subscription", {})
18
  limit = sub.get("character_limit")
19
  used = sub.get("character_count")
 
 
20
  if limit is None or used is None:
21
  return {"valid": False}
22
 
 
23
  return {
24
+ "valid": True,
25
+ "remaining": limit - used
 
26
  }
27
  except:
28
  return {"valid": False}
29
 
30
 
31
+ # ================= TEXT =================
 
 
 
 
32
  def split_text(text, max_len=200):
33
+ out, cur = [], ""
34
  for s in re.split(r'(?<=[.!?])\s+', text):
35
  if len(cur) + len(s) <= max_len:
36
  cur += " " + s
37
  else:
38
+ out.append(cur.strip())
39
  cur = s
40
  if cur:
41
+ out.append(cur.strip())
42
+ return out
43
 
44
 
45
+ # ================= TTS =================
46
  def tts(text, api_key, voice_id, model):
 
47
  r = requests.post(
48
  f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
49
  headers={
 
68
  return None
69
 
70
 
71
+ # ================= AUDIO + SRT =================
72
  def merge_audio(folder, fmt):
73
  files = natsort.natsorted(f for f in os.listdir(folder) if f.endswith(fmt))
74
  audio = AudioSegment.from_file(os.path.join(folder, files[0]))
 
80
  return out
81
 
82
 
 
 
 
 
83
  def create_srt(folder, texts):
84
+ t, lines = 0, []
 
85
  files = natsort.natsorted(f for f in os.listdir(folder) if f.startswith("voice_"))
86
  for i, (f, txt) in enumerate(zip(files, texts), 1):
87
  a = AudioSegment.from_file(os.path.join(folder, f))
88
+ lines += [str(i),
89
+ f"00:00:{t//1000:02},{t%1000:03} --> 00:00:{(t+len(a))//1000:02},{(t+len(a))%1000:03}",
90
+ txt, ""]
91
  t += len(a) + 500
92
  with open(os.path.join(folder, "output_full.srt"), "w", encoding="utf-8") as f:
93
  f.write("\n".join(lines))
94
 
95
 
96
+ # ================= RUN =================
97
+ def run(api_text, api_file, voice_id, text, model, fmt):
98
+ keys = api_file.decode().splitlines() if api_file else api_text.splitlines()
99
+ keys = [k.strip() for k in keys if k.strip()]
100
+
101
+ table = "| API KEY | REMAIN |\n|---|---|\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  valid = []
 
103
 
104
+ for k in keys:
105
  info = check_api_key(k)
106
  show = f"{k[:6]}...{k[-4:]}"
107
+ if info.get("valid") and info["remaining"] > 600:
108
+ valid.append(k)
109
+ table += f"| {show} | {info['remaining']} |\n"
 
 
110
  else:
111
  table += f"| {show} | ❌ |\n"
112
 
113
  if not valid:
114
+ return "❌ Không có API key >600", None, None, table
115
 
116
+ texts = split_text(text)
 
117
  os.makedirs("voices", exist_ok=True)
118
  for f in os.listdir("voices"):
119
  os.remove(os.path.join("voices", f))
120
 
121
+ key_idx = 0
122
 
 
123
  for i, t in enumerate(texts):
124
+ success = False
 
 
125
  while valid:
126
+ key = valid[key_idx]
 
 
 
 
 
 
127
  audio = tts(t, key, voice_id, model)
128
  if audio:
129
  with open(f"voices/voice_{i+1:03d}.{fmt}", "wb") as f:
130
  f.write(audio)
131
+ success = True
 
132
  break
133
  else:
134
+ valid.pop(key_idx)
135
+ key_idx %= max(len(valid), 1)
 
136
 
137
+ if not success:
138
+ return "❌ Hết API key khi chạy", None, None, table
139
 
 
140
  merged = merge_audio("voices", fmt)
141
  create_srt("voices", texts)
142
 
143
+ zipf = "output.zip"
144
+ with zipfile.ZipFile(zipf, "w") as z:
145
  for f in os.listdir("voices"):
146
  z.write(os.path.join("voices", f), f)
147
  z.write(merged)
148
 
149
+ return "✅ HOÀN TẤT", merged, zipf, table
150
 
151
 
152
+ # ================= UI =================
153
  with gr.Blocks() as app:
154
+ gr.Markdown("## 🔊 ElevenLabs TTS – FIX HẾT API KEY")
 
 
 
 
 
 
 
 
155
 
156
+ api_text = gr.Textbox(lines=4, label="API key")
157
+ api_file = gr.File(type="binary", label="Upload API file")
158
+ voice_id = gr.Textbox(label="Voice ID")
159
+ text = gr.Textbox(lines=6, label="Text")
160
+ model = gr.Dropdown(["eleven_multilingual_v2"], value="eleven_multilingual_v2")
161
+ fmt = gr.Dropdown(["mp3", "wav"], value="mp3")
 
 
 
 
162
 
163
  btn = gr.Button("🎧 TẠO GIỌNG")
164
+ status = gr.Textbox()
165
+ audio = gr.Audio(type="filepath")
166
+ zipf = gr.File()
167
  table = gr.Markdown()
168
 
169
+ btn.click(run, [api_text, api_file, voice_id, text, model, fmt],
170
+ [status, audio, zipf, table])
 
 
 
171
 
172
  app.launch()