mr-don88's picture
Update app.py
3bde1c8 verified
# app-elevenlab-huggingface.py
# -*- coding: utf-8 -*-
import os, re, time, random, json, base64
import requests
import uuid
import platform
import warnings
from typing import List, Dict, Optional, Tuple
import concurrent.futures
import urllib3
import gradio as gr
from datetime import datetime
import threading
import subprocess
import sys
warnings.filterwarnings("ignore")
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# ==================== FIXED FUNCTIONS FROM COLAB ====================
try:
from pydub import AudioSegment
import natsort
PYDUB_AVAILABLE = True
except ImportError:
print("⚠️ pydub không khả dụng, cài đặt bằng: pip install pydub")
PYDUB_AVAILABLE = False
def merge_audio_files(input_folder, format, output_filename, silence_ms=300):
"""Hàm merge audio từ Colab - đã fix"""
if not PYDUB_AVAILABLE:
raise ImportError("pydub chưa được cài đặt")
audio_files = [f for f in os.listdir(input_folder) if f.endswith(f".{format.lower()}")]
if not audio_files:
print("❌ Không có file âm thanh nào trong thư mục")
return None
audio_files = natsort.natsorted(audio_files)
# Mở file âm thanh đầu tiên để tạo đối tượng AudioSegment
try:
combined = AudioSegment.from_file(os.path.join(input_folder, audio_files[0]), format=format.lower())
except Exception as e:
print(f"❌ Lỗi khi đọc file đầu tiên: {e}")
return None
# Lặp qua các file còn lại và nối chúng lại
for audio_file in audio_files[1:]:
try:
audio = AudioSegment.from_file(os.path.join(input_folder, audio_file), format=format.lower())
combined += AudioSegment.silent(duration=silence_ms) # Thêm khoảng nghỉ
combined += audio # Nối âm thanh vào cuối
except Exception as e:
print(f"❌ Lỗi khi xử lý file {audio_file}: {e}")
continue
# Lưu file âm thanh đã gộp lại
output_path = f"{output_filename}.{format.lower()}"
try:
combined.export(output_path, format=format.lower())
# Kiểm tra file lỗi 1KB
if os.path.exists(output_path) and os.path.getsize(output_path) <= 1024:
print(f"⚠️ File {output_path} chỉ có {os.path.getsize(output_path)} bytes, tạo lại...")
os.remove(output_path)
combined.export(output_path, format=format.lower())
print(f"✅ Đã tạo lại file {output_path}, kích thước mới: {os.path.getsize(output_path)} bytes")
return output_path
except Exception as e:
print(f"❌ Lỗi khi export file: {e}")
return None
def parse_text_blocks(raw_text, max_length=200):
"""Phân chia văn bản thành các đoạn nhỏ - từ Colab"""
blocks = []
sentences = re.split(r'(?<=[.!?])\s+', raw_text)
current_block = ""
for sentence in sentences:
if len(current_block) + len(sentence) + 1 <= max_length:
if current_block:
current_block += " " + sentence
else:
current_block = sentence
else:
if current_block:
blocks.append(current_block.strip())
current_block = sentence
if current_block.strip():
blocks.append(current_block.strip())
return blocks
def estimate_credit(text):
"""Ước tính credit cần thiết - từ Colab"""
return len(text) + 50
def ms_to_srt_time(ms):
"""Chuyển milliseconds sang định dạng thời gian SRT"""
h = ms // 3600000
m = (ms % 3600000) // 60000
s = (ms % 60000) // 1000
ms = ms % 1000
return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
def create_srt(voice_dir, texts, silence_ms=300):
"""Tạo file phụ đề SRT - từ Colab"""
if not PYDUB_AVAILABLE:
return None
files_audio = natsort.natsorted([f for f in os.listdir(voice_dir) if f.startswith("voice_")])
if not files_audio:
return None
current_time = 0
srt_lines = []
for idx, (fname, text) in enumerate(zip(files_audio, texts), start=1):
try:
audio = AudioSegment.from_file(os.path.join(voice_dir, fname))
start = current_time
end = start + len(audio)
srt_lines.append(str(idx))
srt_lines.append(f"{ms_to_srt_time(start)} --> {ms_to_srt_time(end)}")
srt_lines.append(text.strip())
srt_lines.append("")
current_time = end + silence_ms
except Exception as e:
print(f"❌ Lỗi khi xử lý file {fname}: {e}")
continue
if srt_lines:
srt_path = os.path.join(voice_dir, "output_full.srt")
try:
with open(srt_path, "w", encoding="utf-8") as f:
f.write("\n".join(srt_lines))
return srt_path
except Exception as e:
print(f"❌ Lỗi khi tạo file SRT: {e}")
return None
# ==================== ENHANCED SECURITY AND PROXY FUNCTIONS ====================
class PrivacyProtector:
"""Lớp bảo vệ quyền riêng tư nâng cao"""
@staticmethod
def get_random_user_agent():
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
]
return random.choice(user_agents)
@staticmethod
def get_obfuscated_headers(api_key):
return {
"xi-api-key": api_key,
"Content-Type": "application/json",
"User-Agent": PrivacyProtector.get_random_user_agent(),
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Cache-Control": "no-cache",
"Pragma": "no-cache"
}
@staticmethod
def create_secure_session(proxy_manager=None, use_proxy=False):
session = requests.Session()
session.timeout = 30
session.headers.update({
"User-Agent": PrivacyProtector.get_random_user_agent(),
"Accept-Encoding": "gzip, deflate",
"Connection": "keep-alive"
})
return session
class EnhancedProxyManager:
"""Quản lý proxy nâng cao với khả năng kiểm tra với ElevenLabs"""
def __init__(self):
self.proxy_list = []
self.alive_proxies = []
self.current_proxy = None
self.timeout = 10
self.api_key_for_check = None
self.test_url = "https://api.elevenlabs.io/v1/user"
def add_proxy(self, proxy):
if proxy and proxy not in self.proxy_list:
if '://' not in proxy:
proxy = f"http://{proxy}"
self.proxy_list.append(proxy)
def load_from_file(self, file_path):
try:
with open(file_path, 'r', encoding='utf-8') as f:
proxies = [line.strip() for line in f if line.strip()]
self.proxy_list.extend(proxies)
return True
except Exception as e:
print(f"❌ Lỗi đọc file proxy: {e}")
return False
def check_with_elevenlabs(self, proxy, api_key):
"""Kiểm tra proxy với ElevenLabs (nhanh 1-5 giây)"""
try:
proxies = {
'http': proxy,
'https': proxy
}
headers = {
'xi-api-key': api_key,
'User-Agent': PrivacyProtector.get_random_user_agent()
}
start_time = time.time()
timeout = random.uniform(1, 3) # Timeout ngắn để kiểm tra nhanh
try:
response = requests.get(
self.test_url,
headers=headers,
proxies=proxies,
timeout=timeout,
verify=False
)
response_time = time.time() - start_time
if response.status_code == 200:
return True, f"✅ ElevenLabs OK ({response_time:.2f}s)"
else:
return False, f"❌ API Error: {response.status_code}"
except requests.exceptions.Timeout:
return False, f"⏱️ Timeout ({timeout:.1f}s)"
except requests.exceptions.ConnectionError:
return False, f"🔌 Connection failed"
except Exception as e:
return False, f"❌ Error: {str(e)[:30]}"
except Exception as e:
return False, f"❌ Check Error: {str(e)[:30]}"
def check_all_with_elevenlabs(self, api_key, max_workers=10):
"""Kiểm tra tất cả proxy với ElevenLabs"""
if not self.proxy_list:
return []
self.api_key_for_check = api_key
self.alive_proxies = []
print(f"🔍 Kiểm tra {len(self.proxy_list)} proxy với ElevenLabs...")
def check_single(proxy):
return self.check_with_elevenlabs(proxy, api_key)
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_proxy = {executor.submit(check_single, proxy): proxy for proxy in self.proxy_list}
for future in concurrent.futures.as_completed(future_to_proxy):
proxy = future_to_proxy[future]
try:
is_alive, message = future.result()
if is_alive:
self.alive_proxies.append(proxy)
print(f"✅ {proxy} - {message}")
else:
print(f"❌ {proxy} - {message}")
except Exception as e:
print(f"❌ {proxy} - Exception: {e}")
print(f"✅ Tìm thấy {len(self.alive_proxies)} proxy sống với ElevenLabs")
return self.alive_proxies
def get_random_proxy(self):
if self.alive_proxies:
proxy = random.choice(self.alive_proxies)
self.current_proxy = proxy
return proxy
return None
def get_stats(self):
total = len(self.proxy_list)
alive = len(self.alive_proxies)
return {
"total": total,
"alive": alive,
"dead": total - alive,
"percentage": (alive / total * 100) if total > 0 else 0
}
# ==================== CORE TTS FUNCTIONS ====================
def check_api_key(api_key, proxy_manager=None, use_proxy=False):
"""Kiểm tra API key - FIXED VERSION"""
try:
session = PrivacyProtector.create_secure_session()
headers = PrivacyProtector.get_obfuscated_headers(api_key)
# Thêm proxy nếu cần
proxies = None
if use_proxy and proxy_manager and proxy_manager.current_proxy:
proxies = {
'http': proxy_manager.current_proxy,
'https': proxy_manager.current_proxy
}
time.sleep(random.uniform(1, 2))
response = session.get(
"https://api.elevenlabs.io/v1/user",
headers=headers,
proxies=proxies,
timeout=15,
verify=False
)
if response.status_code == 200:
data = response.json()
sub = data.get("subscription", {})
remaining = sub.get("character_limit", 0) - sub.get("character_count", 0)
return {
"valid": True,
"remaining": remaining,
"total": sub.get("character_limit", 0),
"character_count": sub.get("character_count", 0)
}
else:
return {"valid": False, "error": f"HTTP {response.status_code}"}
except Exception as e:
return {"valid": False, "error": str(e)}
def generate_voice(text, api_key, voice_id, model_id, stability=0.95, similarity=0.8,
style=0.4, speed=0.8, speaker_boost=True, proxy_manager=None, use_proxy=False):
"""Tạo giọng nói - FIXED VERSION"""
# Độ trễ ngẫu nhiên
time.sleep(random.uniform(2, 4))
url = f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
headers = PrivacyProtector.get_obfuscated_headers(api_key)
payload = {
"text": text,
"model_id": model_id,
"voice_settings": {
"stability": stability,
"similarity_boost": similarity,
"style": style,
"speed": speed,
"use_speaker_boost": speaker_boost
}
}
try:
session = PrivacyProtector.create_secure_session()
# Thêm proxy nếu cần
proxies = None
if use_proxy and proxy_manager and proxy_manager.current_proxy:
proxies = {
'http': proxy_manager.current_proxy,
'https': proxy_manager.current_proxy
}
# Xoay proxy mỗi lần request
proxy_manager.current_proxy = proxy_manager.get_random_proxy()
response = session.post(
url,
headers=headers,
json=payload,
proxies=proxies,
timeout=60,
verify=False
)
if response.status_code == 200:
return response.content
elif response.status_code == 429:
# Rate limit, đợi lâu hơn
time.sleep(random.uniform(30, 60))
return None
else:
print(f"❌ API Error: {response.status_code}")
return None
except Exception as e:
print(f"❌ Request Error: {e}")
return None
# ==================== GRADIO INTERFACE ====================
class ElevenLabsTTSApp:
def __init__(self):
self.proxy_manager = EnhancedProxyManager()
self.use_proxy = False
self.output_dir = "voices"
os.makedirs(self.output_dir, exist_ok=True)
self.current_process = None
self.logs = ["===== ElevenLabs TTS Pro - Khởi động ứng dụng ====="]
def log_message(self, message, msg_type="info"):
timestamp = datetime.now().strftime("%H:%M:%S")
log_entry = f"[{timestamp}] {message}"
self.logs.append(log_entry)
print(log_entry)
return "\n".join(self.logs[-50:]) # Giữ 50 dòng gần nhất
def check_api_keys(self, api_keys_text):
"""Kiểm tra API keys"""
api_keys = [k.strip() for k in api_keys_text.splitlines() if k.strip()]
if not api_keys:
return self.log_message("❌ Vui lòng nhập API key!", "error")
results = []
self.log_message("🔍 Đang kiểm tra API keys...")
for i, key in enumerate(api_keys, 1):
info = check_api_key(key, self.proxy_manager, self.use_proxy)
if info.get("valid"):
remaining = info.get("remaining", 0)
results.append(f"✅ Key {i}: Hợp lệ, còn {remaining} ký tự")
self.log_message(f"✅ Key {i} hợp lệ: {remaining} ký tự còn lại")
else:
results.append(f"❌ Key {i}: Không hợp lệ ({info.get('error', 'Lỗi')})")
self.log_message(f"❌ Key {i} không hợp lệ: {info.get('error', 'Lỗi')}")
return "\n".join(results)
def check_proxies(self, api_key, proxies_text):
"""Kiểm tra proxy với ElevenLabs"""
if not api_key.strip():
return self.log_message("❌ Vui lòng nhập API key để kiểm tra proxy!", "error")
proxies = [p.strip() for p in proxies_text.splitlines() if p.strip()]
if not proxies:
return self.log_message("❌ Không có proxy để kiểm tra!", "error")
# Cập nhật proxy manager
self.proxy_manager.proxy_list = proxies
self.log_message(f"🔍 Đang kiểm tra {len(proxies)} proxy với ElevenLabs...")
alive_proxies = self.proxy_manager.check_all_with_elevenlabs(api_key.strip())
result = f"Kết quả kiểm tra:\n"
result += f"✅ Proxy sống: {len(alive_proxies)}\n"
result += f"❌ Proxy chết: {len(proxies) - len(alive_proxies)}\n"
result += f"📊 Tỉ lệ sống: {(len(alive_proxies)/len(proxies)*100):.1f}%\n\n"
if alive_proxies:
result += "Proxy sống:\n"
for i, proxy in enumerate(alive_proxies[:10], 1):
result += f"{i}. {proxy}\n"
if len(alive_proxies) > 10:
result += f"... và {len(alive_proxies) - 10} proxy khác"
return result
def generate_voices(self, api_keys_text, voice_id, text, model, fmt,
stability, similarity, style, speed, speaker_boost, progress=gr.Progress()):
"""Tạo giọng nói"""
try:
# Parse inputs
api_keys = [k.strip() for k in api_keys_text.splitlines() if k.strip()]
voice_id = voice_id.strip()
text = text.strip()
if not api_keys:
return None, self.log_message("❌ Vui lòng nhập API key!", "error")
if not voice_id:
return None, self.log_message("❌ Vui lòng nhập Voice ID!", "error")
if not text:
return None, self.log_message("❌ Vui lòng nhập văn bản!", "error")
self.log_message("=" * 60)
self.log_message("🚀 BẮT ĐẦU QUÁ TRÌNH TẠO GIỌNG NÓI")
self.log_message(f"🔑 Số API keys: {len(api_keys)}")
self.log_message(f"🎤 Voice ID: {voice_id}")
self.log_message(f"🤖 Model: {model}")
self.log_message(f"📁 Format: {fmt}")
self.log_message("=" * 60)
# Parse text blocks
texts = parse_text_blocks(text)
if not texts:
return None, self.log_message("❌ Không thể phân tích văn bản!", "error")
self.log_message(f"📝 Số đoạn văn bản: {len(texts)}")
# Create output directory
output_dir = os.path.join(self.output_dir, f"output_{int(time.time())}")
os.makedirs(output_dir, exist_ok=True)
# Check API keys
valid_keys = []
for i, key in enumerate(api_keys, 1):
progress((i-1)/len(api_keys), f"Kiểm tra API key {i}/{len(api_keys)}")
info = check_api_key(key, self.proxy_manager, self.use_proxy)
if info.get("valid"):
remaining = info.get("remaining", 0)
valid_keys.append([key, remaining])
self.log_message(f"✅ Key {i} hợp lệ: {remaining} ký tự còn lại")
else:
self.log_message(f"❌ Key {i} không hợp lệ: {info.get('error', 'Lỗi')}")
if not valid_keys:
return None, self.log_message("❌ Không có API key hợp lệ!", "error")
# Generate voices
current_key_index = 0
generated_files = []
for i, text_block in enumerate(texts, 1):
progress((i-1)/len(texts), f"Đang tạo file {i}/{len(texts)}")
self.log_message(f"🎤 Đang tạo file {i}/{len(texts)}...")
success = False
for attempt in range(3): # Thử 3 lần
key, remaining = valid_keys[current_key_index]
need = estimate_credit(text_block)
if remaining < need:
self.log_message(f"⚠ Key không đủ ngạch: {remaining}/{need}")
current_key_index = (current_key_index + 1) % len(valid_keys)
continue
audio_data = generate_voice(
text_block, key, voice_id, model,
stability=stability,
similarity=similarity,
style=style,
speed=speed,
speaker_boost=speaker_boost,
proxy_manager=self.proxy_manager if self.use_proxy else None,
use_proxy=self.use_proxy
)
if audio_data:
filename = f"voice_{i:03d}.{fmt.lower()}"
filepath = os.path.join(output_dir, filename)
with open(filepath, "wb") as f:
f.write(audio_data)
if os.path.getsize(filepath) > 1024:
generated_files.append(filepath)
remaining -= need
valid_keys[current_key_index][1] = remaining
current_key_index = (current_key_index + 1) % len(valid_keys)
success = True
self.log_message(f"✅ Tạo thành công: {filename}")
break
else:
self.log_message(f"⚠ File {filename} lỗi 1KB, thử lại...")
else:
self.log_message(f"⚠ Không thể tạo file {i}, thử lại...")
time.sleep(random.uniform(2, 3))
if not success:
self.log_message(f"❌ Không thể tạo file {i} sau 3 lần thử")
# Merge files
if generated_files:
self.log_message("🔗 Đang merge file audio...")
progress(0.9, "Đang merge file audio...")
merged_file = merge_audio_files(output_dir, fmt, os.path.join(output_dir, "output_full"))
if merged_file and os.path.exists(merged_file):
self.log_message("📝 Đang tạo file phụ đề...")
progress(0.95, "Đang tạo file phụ đề...")
srt_file = create_srt(output_dir, texts)
if srt_file:
self.log_message(f"✅ Đã tạo file phụ đề: {os.path.basename(srt_file)}")
self.log_message(f"🎉 Hoàn thành! File: {os.path.basename(merged_file)}")
progress(1.0, "Hoàn thành!")
return merged_file, self.log_message("✅ Quá trình hoàn tất!")
else:
return None, self.log_message("❌ Không thể merge file audio", "error")
else:
return None, self.log_message("❌ Không có file nào được tạo thành công", "error")
except Exception as e:
return None, self.log_message(f"❌ Lỗi: {str(e)}", "error")
def toggle_proxy(self, use_proxy):
"""Bật/tắt proxy"""
self.use_proxy = use_proxy
if use_proxy:
return self.log_message("✅ Đã bật chế độ sử dụng proxy")
else:
return self.log_message("🔌 Đã tắt chế độ sử dụng proxy")
def clear_logs(self):
"""Xóa logs"""
self.logs = ["===== Logs đã được xóa ====="]
return "Logs đã được xóa."
def get_logs(self):
"""Lấy logs hiện tại"""
return "\n".join(self.logs[-20:])
# ==================== GRADIO UI ====================
def create_gradio_interface():
app = ElevenLabsTTSApp()
with gr.Blocks(title="🎤 ElevenLabs TTS Pro - Hugging Face Edition", theme=gr.themes.Soft()) as demo:
gr.Markdown("# 🎤 ElevenLabs TTS Pro - Hugging Face Edition")
gr.Markdown("Công cụ chuyển văn bản thành giọng nói sử dụng ElevenLabs API")
with gr.Tabs():
with gr.TabItem("⚙️ Cấu hình chính"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### 🔑 API Keys")
api_keys = gr.Textbox(
label="API Keys (mỗi key một dòng)",
placeholder="sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nsk_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
lines=4
)
check_api_btn = gr.Button("🔍 Kiểm tra API Keys")
api_check_result = gr.Textbox(label="Kết quả kiểm tra", interactive=False)
gr.Markdown("### 🎤 Voice Settings")
voice_id = gr.Textbox(
label="Voice ID",
placeholder="21m00Tcm4TlvDq8ikWAM",
value="21m00Tcm4TlvDq8ikWAM"
)
with gr.Row():
model = gr.Dropdown(
label="Model",
choices=[
"eleven_turbo_v2_5",
"eleven_flash_v2_5",
"eleven_multilingual_v2"
],
value="eleven_multilingual_v2"
)
fmt = gr.Dropdown(
label="Format",
choices=["MP3", "WAV"],
value="MP3"
)
stability = gr.Slider(label="Stability", minimum=0, maximum=1, value=0.95, step=0.01)
similarity = gr.Slider(label="Similarity Boost", minimum=0, maximum=1, value=0.8, step=0.01)
style = gr.Slider(label="Style", minimum=0, maximum=1, value=0.4, step=0.01)
speed = gr.Slider(label="Speed", minimum=0.5, maximum=1.5, value=0.8, step=0.01)
speaker_boost = gr.Checkbox(label="Speaker Boost", value=True)
with gr.Column(scale=1):
gr.Markdown("### 📝 Văn bản")
text_input = gr.Textbox(
label="Văn bản cần chuyển đổi",
placeholder="Nhập văn bản cần chuyển đổi tại đây...",
lines=15
)
generate_btn = gr.Button("🚀 Bắt đầu tạo giọng nói", variant="primary")
gr.Markdown("### 📤 Kết quả")
audio_output = gr.Audio(label="File âm thanh đã tạo", type="filepath")
gr.Markdown("### 📊 Logs")
log_output = gr.Textbox(label="Logs", lines=10, interactive=False)
with gr.Row():
clear_log_btn = gr.Button("🗑️ Xóa logs")
refresh_log_btn = gr.Button("🔄 Làm mới logs")
with gr.TabItem("🌐 Proxy Management"):
gr.Markdown("### Proxy Settings")
use_proxy = gr.Checkbox(label="Sử dụng proxy", value=False)
proxy_status = gr.Textbox(label="Trạng thái proxy", value="TẮT", interactive=False)
gr.Markdown("### Danh sách Proxy")
proxies_input = gr.Textbox(
label="Proxy (mỗi proxy một dòng)",
placeholder="http://ip:port\nhttp://user:pass@ip:port\nsocks5://ip:port",
lines=6
)
gr.Markdown("### Kiểm tra Proxy")
with gr.Row():
proxy_api_key = gr.Textbox(
label="API Key để kiểm tra",
placeholder="Nhập API key để kiểm tra proxy",
type="password"
)
check_proxy_btn = gr.Button("🔍 Kiểm tra với ElevenLabs")
proxy_check_result = gr.Textbox(label="Kết quả kiểm tra proxy", lines=8, interactive=False)
with gr.TabItem("📖 Hướng dẫn"):
gr.Markdown("""
## 📖 Hướng dẫn sử dụng
### 1. Cấu hình API Keys
- Lấy API key từ [ElevenLabs](https://elevenlabs.io/)
- Nhập mỗi key trên một dòng
- Có thể sử dụng nhiều key để tăng hạn ngạch
### 2. Voice Settings
- **Voice ID**: ID của giọng nói từ ElevenLabs
- **Model**: Chọn model phù hợp
- `eleven_multilingual_v2`: Hỗ trợ đa ngôn ngữ
- `eleven_turbo_v2_5`: Tốc độ cao
- `eleven_flash_v2_5`: Tốc độ cực nhanh
- **Format**: MP3 hoặc WAV
### 3. Voice Parameters
- **Stability**: Độ ổn định giọng nói (0-1)
- **Similarity Boost**: Độ tương tự với giọng gốc (0-1)
- **Style**: Phong cách giọng nói (0-1)
- **Speed**: Tốc độ nói (0.5-1.5)
- **Speaker Boost**: Tăng cường chất lượng giọng nói
### 4. Proxy (Tùy chọn)
- Thêm proxy để tránh bị rate limit
- Kiểm tra proxy với ElevenLabs trước khi sử dụng
- Mỗi proxy trên một dòng
### 5. Sử dụng
1. Nhập API keys
2. Nhập Voice ID
3. Nhập văn bản cần chuyển đổi
4. Điều chỉnh thông số nếu cần
5. Nhấn "🚀 Bắt đầu tạo giọng nói"
### ⚠️ Lưu ý
- Giữ logs để debug nếu có lỗi
- Kiểm tra API keys và proxy trước khi sử dụng
- File âm thanh sẽ tự động download khi hoàn thành
- Cần có API key hợp lệ từ ElevenLabs để sử dụng
""")
# Event handlers
check_api_btn.click(
fn=app.check_api_keys,
inputs=[api_keys],
outputs=[api_check_result]
)
check_proxy_btn.click(
fn=app.check_proxies,
inputs=[proxy_api_key, proxies_input],
outputs=[proxy_check_result]
)
use_proxy.change(
fn=app.toggle_proxy,
inputs=[use_proxy],
outputs=[log_output]
).then(
fn=lambda x: "BẬT" if x else "TẮT",
inputs=[use_proxy],
outputs=[proxy_status]
)
generate_btn.click(
fn=app.generate_voices,
inputs=[
api_keys, voice_id, text_input, model, fmt,
stability, similarity, style, speed, speaker_boost
],
outputs=[audio_output, log_output]
)
clear_log_btn.click(
fn=app.clear_logs,
inputs=[],
outputs=[log_output]
)
refresh_log_btn.click(
fn=app.get_logs,
inputs=[],
outputs=[log_output]
)
# Initial load of logs
demo.load(
fn=app.get_logs,
inputs=[],
outputs=[log_output]
)
return demo
# ==================== MAIN ====================
if __name__ == "__main__":
print("=" * 60)
print("🔄 Đang khởi động ElevenLabs TTS Pro - Hugging Face Edition")
print("=" * 60)
# Tạo thư mục voices nếu chưa tồn tại
os.makedirs("voices", exist_ok=True)
# Tạo và chạy Gradio app
demo = create_gradio_interface()
# Lấy port từ environment variable (cần cho Hugging Face Spaces)
port = int(os.environ.get("PORT", 7860))
print(f"🌐 Ứng dụng đang chạy tại: http://0.0.0.0:{port}")
print("✅ Sẵn sàng sử dụng!")
# Chạy ứng dụng
demo.launch(
server_name="0.0.0.0",
server_port=port,
share=False,
debug=True
)