seslikitap1 / app.py
Zatimm's picture
Update app.py
675632f verified
import os
import tempfile
import warnings
import traceback
import fitz # PyMuPDF
from ebooklib import epub
from bs4 import BeautifulSoup
import gradio as gr
import torch
# Coqui TTS lisans onayı istemini atlamak için ortam değişkenini ayarla.
os.environ['COQUI_TOS_AGREED'] = '1'
from TTS.api import TTS
# Hataları ve uyarıları gizle
warnings.filterwarnings("ignore")
print("📚 Kütüphaneler ve modüller başarıyla yüklendi!")
# Cihaz (GPU/CPU) kontrolü
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"🖥️ Uygulama `{device.upper()}` üzerinde çalışacak.")
# TTS modelini yükle
model_type = "none"
tts_model = None
print("🤖 Yüksek kaliteli XTTS v2 modeli yükleniyor... (Bu işlem birkaç dakika sürebilir)")
try:
# Sadece yüksek kaliteli, çok dilli xtts_v2 modelini yüklemeyi dene.
tts_model = TTS("tts_models/multilingual/multi-dataset/xtts_v2", progress_bar=True).to(device)
model_type = "xtts"
print("✅ Yüksek kaliteli XTTS v2 modeli başarıyla yüklendi!")
except Exception as e:
# Eğer model yüklenemezse, hata ver ve uygulamayı başlatma.
print(f"❌ Kritik Hata: XTTS v2 modeli yüklenemedi. Hata: {e}")
traceback.print_exc()
print("💡 Bellek yetersizliği veya sürüm uyumsuzluğu gibi bir sorun olabilir. Space loglarını ve donanım ayarlarını kontrol edin.")
def extract_text_from_file(file_obj):
"""Verilen dosya nesnesinden (PDF, TXT, EPUB) metin içeriğini çıkarır."""
if file_obj is None:
return "⚠️ Lütfen bir dosya seçin."
try:
file_path = file_obj.name
ext = os.path.splitext(file_path)[1].lower()
text = ""
print(f"📄 '{os.path.basename(file_path)}' adlı dosya işleniyor...")
if ext == ".pdf":
with fitz.open(file_path) as doc:
for page in doc:
text += page.get_text("text") + " "
elif ext == ".txt":
encodings = ['utf-8', 'utf-8-sig', 'windows-1254', 'iso-8859-9']
for encoding in encodings:
try:
with open(file_path, 'r', encoding=encoding) as f:
text = f.read()
print(f"✅ Metin dosyası '{encoding}' kodlaması ile okundu.")
break
except UnicodeDecodeError:
continue
elif ext == ".epub":
book = epub.read_epub(file_path)
for item in book.get_items_of_type(epub.EpubHtml):
soup = BeautifulSoup(item.get_content(), "html.parser")
text += soup.get_text() + " "
else:
return f"⚠️ Desteklenmeyen dosya türü: '{ext}'. Lütfen PDF, TXT veya EPUB formatında bir dosya yükleyin."
cleaned_text = ' '.join(text.split())
if not cleaned_text:
return "⚠️ Dosya boş veya metin içeriği okunamadı."
print(f"✅ Dosyadan {len(cleaned_text)} karakter metin çıkarıldı.")
return cleaned_text
except Exception as e:
print(f"❌ Dosya okuma hatası: {e}")
traceback.print_exc()
return f"⚠️ Dosya işlenirken bir hata oluştu: {str(e)}"
def synthesize_audio(text_to_process):
"""Verilen metni seslendirerek bir WAV dosyası oluşturur."""
if not text_to_process or len(text_to_process.strip()) < 5:
return "⚠️ Seslendirme için en az 5 karakterlik anlamlı bir metin girin.", None
if tts_model is None:
return "⚠️ TTS modeli yüklenemediği için seslendirme yapılamıyor.", None
try:
max_chars = 1500
if len(text_to_process) > max_chars:
print(f"✂️ Metin çok uzun, ilk {max_chars} karaktere kırpıldı.")
text_to_process = text_to_process[:max_chars]
print(f"🎙️ Ses sentezi başlıyor... (Model: {model_type.upper()}, Karakter: {len(text_to_process)})")
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
output_path = tmp_file.name
# --- YENİ VE DOĞRU DÜZELTME ---
# Önceki 'speaker_manager' denemesi yanlıştı çünkü 'TTS' nesnesinde böyle bir özellik yok.
# Orijinal hata, 'speaker' parametresinin eksik olduğunu belirtiyordu.
# Şimdi bu parametreyi, modelin içinde yer alan varsayılan bir konuşmacı adıyla doğrudan sağlıyoruz.
tts_model.tts_to_file(
text=text_to_process,
file_path=output_path,
speaker="Claribel Dervla", # Doğrudan varsayılan konuşmacıyı belirtiyoruz
language="tr"
)
print(f"✅ Ses dosyası başarıyla oluşturuldu: {output_path}")
return f"✅ Ses oluşturuldu ({len(text_to_process)} karakter)", output_path
except Exception as e:
print(f"❌ Ses oluşturma sırasında kritik hata: {e}")
traceback.print_exc()
return f"⚠️ Ses oluşturma hatası: {str(e)}", None
def process_file_and_speak(file_obj):
if file_obj is None:
return "⚠️ Lütfen bir dosya seçin.", None, None
extracted_text = extract_text_from_file(file_obj)
if extracted_text.startswith("⚠️"):
return extracted_text, extracted_text, None
status, audio_path = synthesize_audio(extracted_text)
display_text = extracted_text
if len(display_text) > 500:
display_text = display_text[:500] + "..."
return status, display_text, audio_path
def process_text_and_speak(text_input):
status, audio_path = synthesize_audio(text_input)
return status, audio_path
def create_ui():
with gr.Blocks(
title="🔊 Türkçe Kitap Seslendirici",
theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"),
css="""
.main-header {
text-align: center; padding: 20px; background: linear-gradient(135deg, #007BFF 0%, #00BFFF 100%);
color: white; border-radius: 15px; margin-bottom: 25px; box-shadow: 0 4px 15px rgba(0,0,0,0.1);
}
.main-header h1 { font-size: 2.5em; } .main-header p { font-size: 1.1em; opacity: 0.9; }
.gr-button { min-width: 150px; } footer { display: none !important; }
"""
) as app:
gr.HTML(f"""
<div class="main-header">
<h1>🔊 Türkçe Kitap Seslendirici</h1>
<p>Yüklenen Model: <strong>{model_type.upper()}</strong> | Çalışan Cihaz: <strong>{device.upper()}</strong></p>
</div>
""")
with gr.Tabs():
with gr.TabItem("📁 Dosyadan Seslendir"):
with gr.Row(variant="panel"):
with gr.Column(scale=1):
file_input = gr.File(label="PDF, TXT veya EPUB Dosyası Yükle", file_types=[".pdf", ".txt", ".epub"])
file_btn = gr.Button("🔊 Dosyayı Seslendir", variant="primary", scale=1)
with gr.Column(scale=2):
file_status = gr.Textbox(label="📊 İşlem Durumu", interactive=False)
file_text = gr.Textbox(label="📝 Dosyadan Çıkarılan Metin (Önizleme)", lines=8, interactive=False)
file_audio = gr.Audio(label="🎵 Oluşturulan Ses", type="filepath")
with gr.TabItem("✍️ Metinden Seslendir"):
with gr.Row(variant="panel"):
with gr.Column(scale=2):
text_input = gr.Textbox(
label="Seslendirilecek Metni Buraya Yazın", lines=10, placeholder="Merhaba dünya...",
value="Yapay zeka ve ses sentezi teknolojileri her geçen gün gelişiyor. Bu da Türkçe için harika bir gelişme.")
with gr.Column(scale=1):
text_btn = gr.Button("🔊 Metni Seslendir", variant="primary")
text_status = gr.Textbox(label="📊 İşlem Durumu", interactive=False)
text_audio = gr.Audio(label="🎵 Oluşturulan Ses", type="filepath")
file_btn.click(fn=process_file_and_speak, inputs=[file_input], outputs=[file_status, file_text, file_audio])
text_btn.click(fn=process_text_and_speak, inputs=[text_input], outputs=[text_status, text_audio])
gr.Markdown("""
---
### 💡 İpuçları ve Bilgiler
- **Model:** Sadece yüksek kaliteli `XTTS` modeli kullanılmaktadır. CPU üzerinde ses üretimi biraz zaman alabilir.
- **Karakter Sınırı:** Performans için metinler ilk 1500 karakter ile sınırlandırılmıştır.
""")
return app
if __name__ == "__main__":
if model_type != "none":
app = create_ui()
app.launch()
else:
with gr.Blocks() as error_app:
gr.Markdown("""
# ❌ Uygulama Başlatılamadı
Yüksek kaliteli TTS (XTTS v2) modeli yüklenemedi.
Lütfen Space loglarını kontrol edin veya daha sonra tekrar deneyin.
""")
error_app.launch()