Jedi09 commited on
Commit
29a8059
·
verified ·
1 Parent(s): d9ceebc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +106 -204
app.py CHANGED
@@ -8,180 +8,104 @@ import gradio as gr
8
  from faster_whisper import WhisperModel
9
  import tempfile
10
  import time
11
- import requests
12
  import os
 
 
 
13
 
14
- # ==================== CONFIGURATION ====================
15
- MODEL_SIZE = "medium" # Options: tiny, base, small, medium, large-v3
16
- # =======================================================
 
 
17
 
18
- # Load model once at startup
19
- print(f"🔄 Model yükleniyor ({MODEL_SIZE})... (Bu işlem birkaç dakika sürebilir)")
20
  try:
21
- model = WhisperModel(
22
- MODEL_SIZE,
23
- device="cpu",
24
- compute_type="int8"
25
- )
26
- print("✅ Model yüklendi!")
27
  except Exception as e:
28
- print(f"❌ Model yükleme hatası: {e}")
29
  model = None
30
 
31
-
32
-
33
- # ==================== AI PROVIDER UTILS ====================
34
-
35
- def call_gemini_with_retry(url, payload, max_retries=3):
36
- """
37
- Gemini API: Rate limit (429) ve Bağlantı hatalarını yönetir.
38
- """
39
- for attempt in range(max_retries):
40
- try:
41
- response = requests.post(url, json=payload, timeout=60)
42
-
43
- if response.status_code == 200:
44
- result = response.json()
45
- if "candidates" in result and len(result["candidates"]) > 0:
46
- candidate = result["candidates"][0]
47
- if "content" in candidate and "parts" in candidate["content"]:
48
- parts = candidate["content"]["parts"]
49
- if len(parts) > 0 and "text" in parts[0]:
50
- return parts[0]["text"]
51
- return "❌ Beklenmedik API yanıt formatı."
52
-
53
- elif response.status_code == 429:
54
- wait_time = 5 * (2 ** attempt)
55
- print(f"⚠️ API yoğun (429), {wait_time} saniye bekleniyor... (Deneme {attempt+1}/{max_retries})")
56
- time.sleep(wait_time)
57
- continue
58
-
59
- else:
60
- return f"❌ Gemini Hatası: {response.status_code} - {response.text}"
61
-
62
- except Exception as e:
63
- return f"❌ Bağlantı Hatası: {str(e)}"
64
-
65
- return "⚠️ Gemini sunucuları çok yoğun. Lütfen Hugging Face deneyin."
66
-
67
- def call_huggingface_api(prompt, api_key):
68
- """
69
- Hugging Face Inference API (Standart/Legacy).
70
- Standart 'Read' token ile çalışır. Öze ve basit yapıyı kullanır.
71
- """
72
- if not api_key.startswith("hf_"):
73
- return "⚠️ Geçersiz HF Token. 'hf_' ile başlamalıdır."
74
-
75
- # Free Tier için en sorunsuz çalışan modeller (Küçük ve Hızlı)
76
- models_to_try = [
77
- "HuggingFaceH4/zephyr-7b-beta",
78
- "microsoft/Phi-3-mini-4k-instruct",
79
- "mistralai/Mistral-7B-Instruct-v0.2"
80
- ]
81
-
82
- headers = {"Authorization": f"Bearer {api_key}"}
83
-
84
- for model in models_to_try:
85
- # Standart Inference Endpoint (Daha geniş uyumluluk)
86
- url = f"https://api-inference.huggingface.co/models/{model}"
87
-
88
- # Zephyr/Mistral için prompt formatı
89
- formatted_prompt = f"<|system|>\nSen yardımsever bir asistansın.\n<|user|>\n{prompt}\n<|assistant|>\n"
90
-
91
- payload = {
92
- "inputs": formatted_prompt,
93
- "parameters": {
94
- "max_new_tokens": 512,
95
- "return_full_text": False,
96
- "temperature": 0.7
97
- }
98
- }
99
-
100
- try:
101
- print(f"📡 HF Deneniyor (Legacy): {model}...")
102
- response = requests.post(url, headers=headers, json=payload, timeout=60)
103
-
104
- if response.status_code == 200:
105
- result = response.json()
106
- # Standart liste yanıtı: [{'generated_text': '...'}]
107
- if isinstance(result, list) and len(result) > 0 and "generated_text" in result[0]:
108
- return result[0]["generated_text"].strip()
109
- # Bazen sözlük dönebilir
110
- elif isinstance(result, dict) and "generated_text" in result:
111
- return result["generated_text"].strip()
112
-
113
- elif response.status_code in [404, 503, 500]:
114
- print(f"⚠️ {model} sunucusu yanıt vermedi ({response.status_code})...")
115
- continue
116
-
117
- elif response.status_code == 401:
118
- return "❌ Yetkisiz (401). Token hatalı veya 'Read' izni yok."
119
-
120
- else:
121
- print(f"⚠️ Hata ({model}): {response.status_code}")
122
- continue
123
-
124
- except Exception as e:
125
- print(f"⚠️ Bağlantı hatası ({model}): {e}")
126
- continue
127
-
128
- return "❌ Hiçbir model yanıt vermedi. Lütfen internetinizi kontrol edin veya daha sonra deneyin."
129
-
130
- # ==================== GENERIC AI INTERFACE ====================
131
-
132
- def summarize_with_ai(text: str, api_key: str, provider: str, custom_prompt: str = "") -> str:
133
- """Seçilen sağlayıcı ile metni özetler."""
134
- user_key = api_key.strip() if api_key else os.environ.get("GEMINI_API_KEY") if provider == "Google Gemini" else os.environ.get("HF_TOKEN")
135
-
136
- if not user_key: return f"⚠️ {provider} API Anahtarı bulunamadı."
137
  if not text or "⚠️" in text: return "⚠️ Önce geçerli bir metin oluşturun."
138
 
139
  clean_text = text.split("───────────────────────────────────")[0].strip()
 
140
 
141
- if provider == "Google Gemini":
142
- base_instruction = "Aşağıdaki Türkçe metni analiz et, ana başlıkları çıkar ve detaylıca özetle."
143
- full_prompt = f"{custom_prompt if custom_prompt else base_instruction}\n\nMetin:\n{clean_text}"
144
 
145
- # Gemini 2.0 Flash
146
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={user_key}"
147
- headers = {"Content-Type": "application/json"}
148
- payload = {
149
- "contents": [{"parts": [{"text": full_prompt}]}],
150
- "generationConfig": {"temperature": 0.7, "maxOutputTokens": 2048}
151
- }
152
- return call_gemini_with_retry(url, payload)
153
 
154
- else: # Hugging Face
155
- base_instruction = "Aşağıdaki metni Türkçe olarak maddeler halinde özetle:"
156
- full_prompt = f"{custom_prompt if custom_prompt else base_instruction}\n\n{clean_text}"
157
- return call_huggingface_api(full_prompt, user_key)
158
 
159
- def translate_with_ai(text: str, api_key: str, provider: str, target_language: str) -> str:
160
- """Seçilen sağlayıcı ile çeviri yapar."""
161
- user_key = api_key.strip() if api_key else os.environ.get("GEMINI_API_KEY") if provider == "Google Gemini" else os.environ.get("HF_TOKEN")
162
 
163
- if not user_key: return f"⚠️ {provider} API Anahtarı eksik."
164
-
165
  clean_text = text.split("───────────────────────────────────")[0].strip()
166
- target_lang_eng = {"Türkçe": "Turkish", "İngilizce": "English", "Almanca": "German", "Fransızca": "French"}.get(target_language, "English")
167
 
168
- request_text = f"Translate the following text to {target_lang_eng}. Only provide the translation, no extra text.\n\nText:\n{clean_text}"
 
 
 
 
 
 
 
 
169
 
170
- if provider == "Google Gemini":
171
- url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={user_key}"
172
- headers = {"Content-Type": "application/json"}
173
- payload = {
174
- "contents": [{"parts": [{"text": request_text}]}],
175
- "generationConfig": {"temperature": 0.3, "maxOutputTokens": 4096}
176
- }
177
- return call_gemini_with_retry(url, payload)
178
 
179
- else: # Hugging Face
180
- return call_huggingface_api(request_text, user_key)
 
 
 
 
 
181
 
182
  def transcribe(audio_path: str, progress=gr.Progress()):
183
  if model is None:
184
- yield "❌ Hata: Model yüklenemedi.", None
185
  return
186
 
187
  if audio_path is None:
@@ -192,110 +116,88 @@ def transcribe(audio_path: str, progress=gr.Progress()):
192
  start_time = time.time()
193
  progress(0, desc="Ses işleniyor...")
194
 
195
- # 1. Transkripsiyon (Hızlandırılmış Ayarlar)
196
  segments, info = model.transcribe(
197
  audio_path,
198
  language="tr",
199
- beam_size=1, # Hız için 1 (Streaming ile uyumlu)
200
- vad_filter=True, # Sessizliği atla
201
  word_timestamps=False
202
  )
203
 
204
  duration = info.duration
205
  full_text = ""
206
 
207
- # 2. Streaming Döngüsü
208
  for segment in segments:
209
  full_text += segment.text + " "
210
-
211
- # İlerleme Çubuğu
212
  if duration > 0:
213
  prog = min(segment.end / duration, 0.99)
214
- progress(prog, desc=f"Çevriliyor... ({int(segment.end)}/{int(duration)} sn)")
215
-
216
- # Anlık Çıktı (Henüz dosya yok)
217
  yield full_text.strip(), None
218
 
219
  elapsed = time.time() - start_time
220
  final_result = full_text.strip()
221
 
222
  if not final_result:
223
- yield "⚠️ Ses anlaşılamadı.", None
224
  return
225
 
226
- # 3. Dosya Kaydetme
227
  progress(0.99, desc="Dosya kaydediliyor...")
228
- txt_file = tempfile.NamedTemporaryFile(
229
- mode='w', suffix='.txt', delete=False, encoding='utf-8'
230
- )
231
  txt_file.write(final_result)
232
  txt_file.close()
233
 
234
- # İstatistik Ekleme
235
  stats = f"\n\n───────────────────────────────────\n📊 İstatistikler\n• Süre: {duration:.1f} sn\n• İşlem: {elapsed:.1f} sn\n• Hız: {duration/elapsed:.1f}x\n───────────────────────────────────"
236
 
237
  yield final_result + stats, txt_file.name
238
 
239
  except Exception as e:
240
- yield f"❌ Hata: {str(e)}", None
241
 
242
- # --- ARAYÜZ ---
243
- with gr.Blocks(title="Ses Deşifre Pro") as demo:
 
244
 
245
  gr.HTML("""
246
  <style>
247
  footer { display: none !important; }
248
  .gradio-container { max-width: 900px !important; margin: auto !important; }
249
  </style>
250
- <div style="text-align: center; padding: 30px; background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); border-radius: 20px; margin-bottom: 20px; color: white;">
251
- <h1 style="font-size: 2.2rem; margin: 0;">🎙️ Ses Deşifre & AI Asistan</h1>
252
- <p style="opacity: 0.9;">Canlı TranskripsiyonMulti-Model AI (Gemini + HF) • Streaming</p>
253
  </div>
254
  """)
255
 
256
  with gr.Row():
257
  with gr.Column():
258
- audio_input = gr.Audio(label="Ses Kaynağı", type="filepath", sources=["upload", "microphone"])
259
- submit_btn = gr.Button(" Başlat (Canlı)", variant="primary", size="lg")
260
 
261
  with gr.Row():
262
  with gr.Column():
263
- output_text = gr.Textbox(label="Sonuç (Canlı Akış)", placeholder="Konuşmalar buraya akacak...", lines=12, interactive=False)
264
- download_file = gr.File(label="İndir (.txt)")
265
 
266
- # --- AI ARAÇLARI ---
267
- gr.HTML("<h3 style='margin-top: 20px; border-bottom: 1px solid #ddd; padding-bottom: 10px;'>🧠 Yapay Zeka Araçları</h3>")
268
-
269
- with gr.Row():
270
- with gr.Column(scale=1):
271
- provider_select = gr.Radio(
272
- ["Google Gemini", "Hugging Face (Bedava)"],
273
- label="AI Sağlayıcısı",
274
- value="Google Gemini",
275
- info="Gemini limit hatası verirse Hugging Face seçin."
276
- )
277
- with gr.Column(scale=2):
278
- api_key_input = gr.Textbox(
279
- label="🔑 API Anahtarı (Gemini Key veya HF Token)",
280
- placeholder="Seçili sağlayıcıya ait anahtar...",
281
- type="password"
282
- )
283
 
284
  with gr.Tabs():
285
- with gr.TabItem("✨ Özetle"):
286
- gemini_prompt = gr.Textbox(label="Komut (Opsiyonel)", placeholder="Örn: Madde madde özetle...")
287
- gemini_btn = gr.Button("🤖 AI ile Özetle")
288
- gemini_output = gr.Textbox(label="Özet", lines=8)
289
 
290
- with gr.TabItem("🌍 Çevir"):
291
- target_lang = gr.Dropdown(["İngilizce", "Almanca", "Fransızca", "Türkçe"], label="Hedef Dil", value="İngilizce")
292
- translate_btn = gr.Button("A Çevir")
293
- translate_output = gr.Textbox(label="Çeviri", lines=8)
 
294
 
295
  # --- BAĞLANTILAR ---
296
  submit_btn.click(transcribe, inputs=[audio_input], outputs=[output_text, download_file])
297
- gemini_btn.click(summarize_with_ai, inputs=[output_text, api_key_input, provider_select, gemini_prompt], outputs=gemini_output)
298
- translate_btn.click(translate_with_ai, inputs=[output_text, api_key_input, provider_select, target_lang], outputs=translate_output)
 
299
 
300
  if __name__ == "__main__":
301
  demo.launch(share=False)
 
8
  from faster_whisper import WhisperModel
9
  import tempfile
10
  import time
 
11
  import os
12
+ # import requests # Artık gerek yok
13
+ from transformers import pipeline
14
+ import torch
15
 
16
+ # ==================== CONFIG & MODELS ====================
17
+
18
+ # 1. WHISPER MODEL (Ses Deşifre)
19
+ MODEL_SIZE = "medium"
20
+ model = None
21
 
 
 
22
  try:
23
+ print(f"� Whisper {MODEL_SIZE} modeli yükleniyor...")
24
+ model = WhisperModel(MODEL_SIZE, device="cpu", compute_type="int8")
25
+ print("✅ Whisper Modeli Hazır!")
 
 
 
26
  except Exception as e:
27
+ print(f"❌ Whisper Yükleme Hatası: {e}")
28
  model = None
29
 
30
+ # 2. LOCAL AI PIPELINES (Cache)
31
+ summarizer_pipe = None
32
+ translator_pipe = None
33
+
34
+ def load_summarizer():
35
+ global summarizer_pipe
36
+ if summarizer_pipe is None:
37
+ print("📥 Özetleme Modeli (mT5-Small) yükleniyor...")
38
+ device = "cpu" # GPU varsa 0 yapabilirsiniz
39
+ summarizer_pipe = pipeline("summarization", model="ozcangundes/mt5-small-turkish-summarization", device=-1)
40
+ print("✅ Özetleme Modeli Hazır!")
41
+ return summarizer_pipe
42
+
43
+ def load_translator():
44
+ global translator_pipe
45
+ if translator_pipe is None:
46
+ print(" Çeviri Modeli (NLLB-200) yükleniyor...")
47
+ # NLLB cpu'da biraz yavaş olabilir ama kalitelidir
48
+ translator_pipe = pipeline("translation", model="facebook/nllb-200-distilled-600M", device=-1)
49
+ print("✅ Çeviri Modeli Hazır!")
50
+ return translator_pipe
51
+
52
+ # ==================== AI FUNCTIONS (LOCAL) ====================
53
+
54
+ def summarize_locally(text: str, progress=gr.Progress()) -> str:
55
+ """Yerel model (mT5) ile özetleme."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  if not text or "⚠️" in text: return "⚠️ Önce geçerli bir metin oluşturun."
57
 
58
  clean_text = text.split("───────────────────────────────────")[0].strip()
59
+ if len(clean_text) < 50: return "⚠️ Metin özetlemek için çok kısa."
60
 
61
+ try:
62
+ progress(0.2, desc="Özetleme modeli yükleniyor...")
63
+ pipe = load_summarizer()
64
 
65
+ progress(0.5, desc="Metin özetleniyor...")
66
+ # Maksimum girdi uzunluğunu ve çıktı uzunluğunu ayarla
67
+ result = pipe(clean_text, max_length=150, min_length=40, do_sample=False)
 
 
 
 
 
68
 
69
+ return result[0]['summary_text']
70
+
71
+ except Exception as e:
72
+ return f"❌ Özetleme Hatası: {str(e)}"
73
 
74
+ def translate_locally(text: str, target_language: str, progress=gr.Progress()) -> str:
75
+ """Yerel model (NLLB) ile çeviri."""
76
+ if not text or "⚠️" in text: return "⚠️ Çevrilecek metin yok."
77
 
 
 
78
  clean_text = text.split("───────────────────────────────────")[0].strip()
 
79
 
80
+ # NLLB Dil Kodları
81
+ lang_map = {
82
+ "İngilizce": "eng_Latn",
83
+ "Almanca": "deu_Latn",
84
+ "Fransızca": "fra_Latn",
85
+ "Türkçe": "tur_Latn"
86
+ }
87
+ src_lang = "tur_Latn" # Varsayılan giriş Türkçe
88
+ tgt_lang = lang_map.get(target_language, "eng_Latn")
89
 
90
+ try:
91
+ progress(0.2, desc="Çeviri modeli yükleniyor...")
92
+ pipe = load_translator()
93
+
94
+ progress(0.5, desc=f"Çeviriliyor ({target_language})...")
95
+ # NLLB pipeline kullanımı: src_lang ve tgt_lang belirtilmeli
96
+ result = pipe(clean_text, src_lang=src_lang, tgt_lang=tgt_lang, max_length=512)
 
97
 
98
+ return result[0]['translation_text']
99
+
100
+ except Exception as e:
101
+ return f"❌ Çeviri Hatası: {str(e)}"
102
+
103
+
104
+ # ==================== TRANSCRIPTION (WHISPER) ====================
105
 
106
  def transcribe(audio_path: str, progress=gr.Progress()):
107
  if model is None:
108
+ yield "❌ Hata: Whisper modeli yüklenemedi.", None
109
  return
110
 
111
  if audio_path is None:
 
116
  start_time = time.time()
117
  progress(0, desc="Ses işleniyor...")
118
 
 
119
  segments, info = model.transcribe(
120
  audio_path,
121
  language="tr",
122
+ beam_size=1,
123
+ vad_filter=True,
124
  word_timestamps=False
125
  )
126
 
127
  duration = info.duration
128
  full_text = ""
129
 
 
130
  for segment in segments:
131
  full_text += segment.text + " "
 
 
132
  if duration > 0:
133
  prog = min(segment.end / duration, 0.99)
134
+ progress(prog, desc=f"Dönüştürülüyor... ({int(segment.end)}/{int(duration)} sn)")
 
 
135
  yield full_text.strip(), None
136
 
137
  elapsed = time.time() - start_time
138
  final_result = full_text.strip()
139
 
140
  if not final_result:
141
+ yield "⚠️ Ses anlaşılamadı veya sessiz.", None
142
  return
143
 
144
+ # Dosya Kaydetme
145
  progress(0.99, desc="Dosya kaydediliyor...")
146
+ txt_file = tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False, encoding='utf-8')
 
 
147
  txt_file.write(final_result)
148
  txt_file.close()
149
 
 
150
  stats = f"\n\n───────────────────────────────────\n📊 İstatistikler\n• Süre: {duration:.1f} sn\n• İşlem: {elapsed:.1f} sn\n• Hız: {duration/elapsed:.1f}x\n───────────────────────────────────"
151
 
152
  yield final_result + stats, txt_file.name
153
 
154
  except Exception as e:
155
+ yield f"❌ Transkripsiyon Hatası: {str(e)}", None
156
 
157
+ # ==================== UI (GRADIO) ====================
158
+
159
+ with gr.Blocks(title="Ses Deşifre Pro (Local AI)") as demo:
160
 
161
  gr.HTML("""
162
  <style>
163
  footer { display: none !important; }
164
  .gradio-container { max-width: 900px !important; margin: auto !important; }
165
  </style>
166
+ <div style="text-align: center; padding: 30px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); border-radius: 20px; margin-bottom: 20px; color: white;">
167
+ <h1 style="font-size: 2.2rem; margin: 0;">🎙️ Ses Deşifre & Local AI</h1>
168
+ <p style="opacity: 0.9;">%100 ÇevrimdışıToken Yok Limit Yok</p>
169
  </div>
170
  """)
171
 
172
  with gr.Row():
173
  with gr.Column():
174
+ audio_input = gr.Audio(label="Ses Dosyası", type="filepath", sources=["upload", "microphone"])
175
+ submit_btn = gr.Button("🚀 Başlat", variant="primary", size="lg")
176
 
177
  with gr.Row():
178
  with gr.Column():
179
+ output_text = gr.Textbox(label="Deşifre Metni", placeholder="Sonuçlar burada görünecek...", lines=10, interactive=False)
180
+ download_file = gr.File(label="Metni İndir (.txt)")
181
 
182
+ # --- LOCAL AI ARAÇLARI ---
183
+ gr.HTML("<h3 style='margin-top: 20px; border-bottom: 1px solid #ddd; padding-bottom: 10px;'>🧠 Yerel Yapay Zeka (CPU)</h3>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
 
185
  with gr.Tabs():
186
+ with gr.TabItem("✨ Özetle (mT5)"):
187
+ summary_btn = gr.Button("📝 Metni Özetle")
188
+ summary_output = gr.Textbox(label="Özet Sonucu", lines=6)
 
189
 
190
+ with gr.TabItem("🌍 Çevir (NLLB)"):
191
+ with gr.Row():
192
+ target_lang = gr.Dropdown(["İngilizce", "Almanca", "Fransızca"], label="Hedef Dil", value="İngilizce")
193
+ translate_btn = gr.Button("A Çevir")
194
+ translate_output = gr.Textbox(label="Çeviri Sonucu", lines=6)
195
 
196
  # --- BAĞLANTILAR ---
197
  submit_btn.click(transcribe, inputs=[audio_input], outputs=[output_text, download_file])
198
+
199
+ summary_btn.click(summarize_locally, inputs=[output_text], outputs=summary_output)
200
+ translate_btn.click(translate_locally, inputs=[output_text, target_lang], outputs=translate_output)
201
 
202
  if __name__ == "__main__":
203
  demo.launch(share=False)