Jedi09 commited on
Commit
0bf948d
·
verified ·
1 Parent(s): 988eb14

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +821 -168
app.py CHANGED
@@ -1,243 +1,896 @@
 
1
  """
 
2
  Ses Deşifre Pro - Türkçe Ses-Metin Dönüştürme
 
3
  Hugging Face Spaces için profesyonel arayüz.
4
- Gradio 6.x uyumlu + Gemini AI Özet Desteği + Streaming Output.
 
 
5
  """
6
 
 
 
7
  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
- DEFAULT_GEMINI_KEY = os.environ.get("GEMINI_API_KEY")
17
  # =======================================================
18
 
 
 
19
  # Load model once at startup
20
- print(f"🔄 Model yükleniyor ({MODEL_SIZE})... (Bu işlem birkaç dakika sürebilir)")
21
- try:
22
- model = WhisperModel(
23
- MODEL_SIZE,
24
- device="cpu",
25
- compute_type="int8"
26
- )
27
- print("✅ Model yüklendi!")
28
- except Exception as e:
29
- print(f"❌ Model yükleme hatası: {e}")
30
- model = None
31
 
32
- def get_api_key(user_key):
33
- """
34
- Kullanıcı anahtar girdiyse onu kullan, yoksa sistemdeki gizli anahtarı kullan.
35
- """
36
- if user_key and user_key.strip():
37
- return user_key.strip()
38
- return DEFAULT_GEMINI_KEY
39
 
 
40
 
41
- # ==================== GEMINI UTILS ====================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
- def call_gemini_with_retry(url, payload, max_retries=3):
44
- """
45
- Rate limit (429) ve Model Not Found (404) hatalarını yönetir.
46
- """
47
- for attempt in range(max_retries):
48
- try:
49
- response = requests.post(url, json=payload, timeout=60)
50
-
51
- if response.status_code == 200:
52
- return response.json()["candidates"][0]["content"]["parts"][0]["text"]
53
-
54
- elif response.status_code == 429:
55
- # Üstel bekleme (Exponential Backoff): 5s, 10s, 20s
56
- wait_time = 5 * (2 ** attempt)
57
- print(f"⚠️ API yoğun (429), {wait_time} saniye bekleniyor... (Deneme {attempt+1}/{max_retries})")
58
- time.sleep(wait_time)
59
- continue
60
-
61
- elif response.status_code == 404:
62
- return "404_NOT_FOUND"
63
-
64
- else:
65
- return f"❌ API Hatası: {response.status_code} - {response.text}"
66
-
67
- except Exception as e:
68
- return f"❌ Bağlantı Hatası: {str(e)}"
69
-
70
- return "⚠️ Sunucu çok yoğun. Lütfen 1-2 dakika bekleyip tekrar deneyin."
71
-
72
- def smart_gemini_request(prompt: str, api_key: str):
73
  """
74
- Farklı Gemini modellerini sırasıyla dener (Fallback mekanizması).
 
 
 
 
75
  """
76
- # Denenecek modeller sırasıyla:
77
- models = [
78
- "gemini-1.5-flash", # Öncelikli
79
- "gemini-1.5-flash-latest", # Alternatif
80
- "gemini-1.5-flash-001", # Versiyonlu
81
- "gemini-pro" # Eski stabil (Fallback)
82
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
 
84
  headers = {"Content-Type": "application/json"}
 
 
 
85
  payload = {
86
- "contents": [{"parts": [{"text": prompt}]}],
87
- "generationConfig": {"temperature": 0.7, "maxOutputTokens": 2048}
 
 
 
 
 
 
 
 
 
88
  }
89
 
90
- for model in models:
91
- print(f"🤖 Model deneniyor: {model}...")
92
- url = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={api_key}"
93
-
94
- result = call_gemini_with_retry(url, payload)
 
95
 
96
- if result == "404_NOT_FOUND":
97
- print(f"⚠️ {model} bulunamadı, bir sonraki model deneniyor...")
98
- continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
- return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
- return "❌ Hiçbir model uygun değil. Lütfen API anahtarınızı kontrol edin."
103
 
104
- def summarize_with_gemini(text: str, user_api_key: str, custom_prompt: str = "") -> str:
105
- """Gemini ile özetle."""
106
- api_key = get_api_key(user_api_key)
107
- if not api_key: return "⚠️ API Anahtarı bulunamadı."
108
- if not text or "⚠️" in text: return "⚠️ Önce geçerli bir metin oluşturun."
109
 
 
 
 
110
  clean_text = text.split("───────────────────────────────────")[0].strip()
111
- base_instruction = "Aşağıdaki Türkçe metni analiz et, ana başlıkları çıkar ve detaylıca özetle."
112
- full_prompt = f"{custom_prompt if custom_prompt else base_instruction}\n\nMetin:\n{clean_text}"
 
 
 
113
 
114
- return smart_gemini_request(full_prompt, api_key)
115
 
116
- def translate_with_gemini(text: str, user_api_key: str, target_language: str) -> str:
117
- """Gemini ile çevir."""
118
- api_key = get_api_key(user_api_key)
119
- if not api_key: return "⚠️ API Anahtarı eksik."
120
-
121
- clean_text = text.split("───────────────────────────────────")[0].strip()
122
- target_lang_eng = {"Türkçe": "Turkish", "İngilizce": "English", "Almanca": "German", "Fransızca": "French"}.get(target_language, "English")
123
- full_prompt = f"Translate the following text to {target_lang_eng}. Only provide the translation.\n\nText:\n{clean_text}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
- return smart_gemini_request(full_prompt, api_key)
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- def transcribe(audio_path: str, progress=gr.Progress()):
129
  """
130
- Transcribe audio file with streaming output.
 
 
 
 
131
  """
132
- if model is None:
133
- yield "❌ Hata: Model yüklenemedi.", None
134
- return
135
 
136
  if audio_path is None:
137
- yield "⚠️ Lütfen bir ses dosyası yükleyin.", None
138
- return
 
 
139
 
140
  try:
 
141
  start_time = time.time()
142
- progress(0, desc="Ses işleniyor...")
143
 
144
- # 1. Transkripsiyon (Hızlandırılmış Ayarlar)
 
 
145
  segments, info = model.transcribe(
 
146
  audio_path,
 
147
  language="tr",
148
- beam_size=1, # Hız için 1 (Streaming ile uyumlu)
149
- vad_filter=True, # Sessizliği atla
150
- word_timestamps=False
151
  )
 
152
 
153
- duration = info.duration
154
- full_text = ""
155
-
156
- # 2. Streaming Döngüsü
 
157
  for segment in segments:
158
- full_text += segment.text + " "
159
-
160
- # İlerleme Çubuğu
161
- if duration > 0:
162
- prog = min(segment.end / duration, 0.99)
163
- progress(prog, desc=f"Çevriliyor... ({int(segment.end)}/{int(duration)} sn)")
164
-
165
- # Anlık Çıktı (Henüz dosya yok)
166
- yield full_text.strip(), None
167
 
168
  elapsed = time.time() - start_time
169
- final_result = full_text.strip()
 
 
 
 
 
 
170
 
171
- if not final_result:
172
- yield "⚠️ Ses anlaşılamadı.", None
173
- return
174
 
175
- # 3. Dosya Kaydetme
176
- progress(0.99, desc="Dosya kaydediliyor...")
177
  txt_file = tempfile.NamedTemporaryFile(
178
- mode='w', suffix='.txt', delete=False, encoding='utf-8'
 
 
 
 
 
 
 
 
179
  )
180
- txt_file.write(final_result)
 
 
181
  txt_file.close()
 
182
 
183
- # İstatistik Ekleme
184
- 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───────────────────────────────────"
185
-
186
- yield final_result + stats, txt_file.name
187
-
188
- except Exception as e:
189
- yield f"❌ Hata: {str(e)}", None
190
 
191
- # --- ARAYÜZ ---
192
- with gr.Blocks(title="Ses Deşifre Pro") as demo:
193
-
194
- gr.HTML("""
195
- <style>
196
- footer { display: none !important; }
197
- .gradio-container { max-width: 900px !important; margin: auto !important; }
198
- </style>
199
- <div style="text-align: center; padding: 30px; background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); border-radius: 20px; margin-bottom: 20px; color: white;">
200
- <h1 style="font-size: 2.2rem; margin: 0;">🎙️ Ses Deşifre & AI Asistan</h1>
201
- <p style="opacity: 0.9;">Canlı Transkripsiyon Özetleme Çeviri (v2.0 Fixed)</p>
202
- </div>
203
- """)
204
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  with gr.Row():
 
206
  with gr.Column():
207
- audio_input = gr.Audio(label="Ses Kaynağı", type="filepath", sources=["upload", "microphone"])
208
- submit_btn = gr.Button(" Başlat (Canlı)", variant="primary", size="lg")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  with gr.Row():
 
211
  with gr.Column():
212
- output_text = gr.Textbox(label="Sonuç (Canlı Akış)", placeholder="Konuşmalar buraya akacak...", lines=12, interactive=False)
213
- download_file = gr.File(label="İndir (.txt)")
214
 
215
- # --- GEMINI ARAÇLARI ---
216
- gr.HTML("<h3 style='margin-top: 20px; border-bottom: 1px solid #ddd; padding-bottom: 10px;'>🧠 Yapay Zeka Araçları</h3>")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  with gr.Row():
219
- with gr.Column():
220
- api_key_input = gr.Textbox(
221
- label="🔑 Kendi API Anahtarınız (Opsiyonel)",
222
- placeholder="Boş bırakırsanız sistem anahtarı kullanılır",
223
- type="password"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
- with gr.Tabs():
227
- with gr.TabItem("✨ Özetle"):
228
- gemini_prompt = gr.Textbox(label="Komut (Opsiyonel)", placeholder="Örn: Madde madde özetle...")
229
- gemini_btn = gr.Button("🤖 Özetle")
230
- gemini_output = gr.Textbox(label="Özet", lines=8)
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
- with gr.TabItem("🌍 Çevir"):
233
- target_lang = gr.Dropdown(["İngilizce", "Almanca", "Fransızca", "Türkçe"], label="Hedef Dil", value="İngilizce")
234
- translate_btn = gr.Button("A Çevir")
235
- translate_output = gr.Textbox(label="Çeviri", lines=8)
236
 
237
- # --- BAĞLANTILAR ---
238
- submit_btn.click(transcribe, inputs=[audio_input], outputs=[output_text, download_file])
239
- gemini_btn.click(summarize_with_gemini, inputs=[output_text, api_key_input, gemini_prompt], outputs=gemini_output)
240
- translate_btn.click(translate_with_gemini, inputs=[output_text, api_key_input, target_lang], outputs=translate_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
  if __name__ == "__main__":
243
- demo.launch(share=False)
 
 
1
+
2
  """
3
+
4
  Ses Deşifre Pro - Türkçe Ses-Metin Dönüştürme
5
+
6
  Hugging Face Spaces için profesyonel arayüz.
7
+
8
+ Gradio 6.x uyumlu + Gemini AI Özet Desteği.
9
+
10
  """
11
 
12
+
13
+
14
  import gradio as gr
15
+
16
  from faster_whisper import WhisperModel
17
+
18
  import tempfile
19
+
20
  import time
21
+
22
  import requests
23
+
24
+
25
 
26
  # ==================== CONFIGURATION ====================
27
+
28
  MODEL_SIZE = "medium" # Options: tiny, base, small, medium, large-v3
29
+
30
  # =======================================================
31
 
32
+
33
+
34
  # Load model once at startup
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ print("🔄 Model yükleniyor... (Bu işlem birkaç dakika sürebilir)")
 
 
 
 
 
 
37
 
38
+ model = WhisperModel(
39
 
40
+ MODEL_SIZE,
41
+
42
+ device="cpu",
43
+
44
+ compute_type="int8"
45
+
46
+ )
47
+
48
+ print("✅ Model yüklendi!")
49
+
50
+
51
+
52
+
53
+
54
+ def summarize_with_gemini(text: str, api_key: str, custom_prompt: str = "") -> str:
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  """
57
+
58
+ Summarize text using Google Gemini API.
59
+
60
+ API key is not stored - used only for this single request.
61
+
62
  """
63
+
64
+ if not api_key or not api_key.strip():
65
+
66
+ return "⚠️ Gemini API anahtarı girilmedi."
67
+
68
+
69
+
70
+ if not text or text.strip() == "" or text.startswith("⚠️") or text.startswith("❌"):
71
+
72
+ return "⚠️ Önce bir transkripsiyon oluşturun."
73
+
74
+
75
+
76
+ # Extract only the transcription text (remove stats section)
77
+
78
+ clean_text = text.split("───────────────────────────────────")[0].strip()
79
+
80
+ if not clean_text:
81
+
82
+ return "⚠️ Özetlenecek metin bulunamadı."
83
+
84
+
85
+
86
+ # Build the prompt
87
+
88
+ base_instruction = "Aşağıdaki Türkçe metni analiz et ve özetle."
89
+
90
+ if custom_prompt and custom_prompt.strip():
91
+
92
+ full_prompt = f"{custom_prompt.strip()}\n\nMetin:\n{clean_text}"
93
+
94
+ else:
95
+
96
+ full_prompt = f"{base_instruction}\n\nMetin:\n{clean_text}"
97
+
98
+
99
+
100
+ # Gemini API endpoint
101
+
102
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}"
103
+
104
 
105
+
106
  headers = {"Content-Type": "application/json"}
107
+
108
+
109
+
110
  payload = {
111
+
112
+ "contents": [{"parts": [{"text": full_prompt}]}],
113
+
114
+ "generationConfig": {
115
+
116
+ "temperature": 0.7,
117
+
118
+ "maxOutputTokens": 2048
119
+
120
+ }
121
+
122
  }
123
 
124
+
125
+
126
+ try:
127
+
128
+ response = requests.post(url, headers=headers, json=payload, timeout=60)
129
+
130
 
131
+
132
+ if response.status_code == 200:
133
+
134
+ result = response.json()
135
+
136
+ if "candidates" in result and len(result["candidates"]) > 0:
137
+
138
+ candidate = result["candidates"][0]
139
+
140
+ if "content" in candidate and "parts" in candidate["content"]:
141
+
142
+ parts = candidate["content"]["parts"]
143
+
144
+ if len(parts) > 0 and "text" in parts[0]:
145
+
146
+ return parts[0]["text"]
147
+
148
+ return "❌ Gemini yanıtı beklenmedik formatta."
149
+
150
+ elif response.status_code == 400:
151
+
152
+ return "❌ Geçersiz istek. API anahtarını kontrol edin."
153
+
154
+ elif response.status_code in [401, 403]:
155
+
156
+ return "❌ API anahtarı geçersiz veya yetkisiz."
157
+
158
+ elif response.status_code == 429:
159
+
160
+ return "❌ API kullanım limiti aşıldı. Lütfen bekleyin."
161
+
162
+ else:
163
+
164
+ return f"❌ Gemini API hatası: {response.status_code}"
165
+
166
 
167
+
168
+ except requests.exceptions.Timeout:
169
+
170
+ return "❌ Gemini API zaman aşımı. Tekrar deneyin."
171
+
172
+ except requests.exceptions.RequestException as e:
173
+
174
+ return f"❌ Bağlantı hatası: {str(e)}"
175
+
176
+ except Exception as e:
177
+
178
+ return f"❌ Beklenmeyen hata: {str(e)}"
179
+
180
+
181
+
182
+
183
+
184
+ # Language options for translation
185
+
186
+ LANGUAGE_OPTIONS = {
187
+
188
+ "Türkçe": "Turkish",
189
+
190
+ "İngilizce": "English",
191
+
192
+ "Almanca": "German",
193
+
194
+ "Fransızca": "French"
195
+
196
+ }
197
+
198
+
199
+
200
+
201
+
202
+ def translate_with_gemini(text: str, api_key: str, target_language: str) -> str:
203
+
204
+ """
205
+
206
+ Translate text using Google Gemini API.
207
+
208
+ API key is not stored - used only for this single request.
209
+
210
+ """
211
+
212
+ if not api_key or not api_key.strip():
213
+
214
+ return "⚠️ Gemini API anahtarı girilmedi."
215
+
216
 
 
217
 
218
+ if not text or text.strip() == "" or text.startswith("⚠️") or text.startswith("❌"):
219
+
220
+ return "⚠️ Önce bir transkripsiyon oluşturun."
221
+
 
222
 
223
+
224
+ # Extract only the transcription text (remove stats section)
225
+
226
  clean_text = text.split("───────────────────────────────────")[0].strip()
227
+
228
+ if not clean_text:
229
+
230
+ return "⚠️ Çevrilecek metin bulunamadı."
231
+
232
 
 
233
 
234
+ # Get English name for the language
235
+
236
+ target_lang_english = LANGUAGE_OPTIONS.get(target_language, "English")
237
+
238
+
239
+
240
+ # Build the prompt
241
+
242
+ full_prompt = f"""Translate the following text to {target_lang_english}.
243
+
244
+ Only provide the translation, no explanations or additional text.
245
+
246
+
247
+
248
+ Text to translate:
249
+
250
+ {clean_text}"""
251
+
252
+
253
+
254
+ # Gemini API endpoint
255
+
256
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}"
257
+
258
+
259
+
260
+ headers = {"Content-Type": "application/json"}
261
+
262
+
263
+
264
+ payload = {
265
+
266
+ "contents": [{"parts": [{"text": full_prompt}]}],
267
+
268
+ "generationConfig": {
269
+
270
+ "temperature": 0.3,
271
+
272
+ "maxOutputTokens": 4096
273
+
274
+ }
275
+
276
+ }
277
+
278
 
 
279
 
280
+ try:
281
+
282
+ response = requests.post(url, headers=headers, json=payload, timeout=60)
283
+
284
+
285
+
286
+ if response.status_code == 200:
287
+
288
+ result = response.json()
289
+
290
+ if "candidates" in result and len(result["candidates"]) > 0:
291
+
292
+ candidate = result["candidates"][0]
293
+
294
+ if "content" in candidate and "parts" in candidate["content"]:
295
+
296
+ parts = candidate["content"]["parts"]
297
+
298
+ if len(parts) > 0 and "text" in parts[0]:
299
+
300
+ return parts[0]["text"]
301
+
302
+ return "❌ Gemini yanıtı beklenmedik formatta."
303
+
304
+ elif response.status_code == 400:
305
+
306
+ return "❌ Geçersiz istek. API anahtarını kontrol edin."
307
+
308
+ elif response.status_code in [401, 403]:
309
+
310
+ return "❌ API anahtarı geçersiz veya yetkisiz."
311
+
312
+ elif response.status_code == 429:
313
+
314
+ return "❌ API kullanım limiti aşıldı. Lütfen bekleyin."
315
+
316
+ else:
317
+
318
+ return f"❌ Gemini API hatası: {response.status_code}"
319
+
320
+
321
+
322
+ except requests.exceptions.Timeout:
323
+
324
+ return "❌ Gemini API zaman aşımı. Tekrar deneyin."
325
+
326
+ except requests.exceptions.RequestException as e:
327
+
328
+ return f"❌ Bağlantı hatası: {str(e)}"
329
+
330
+ except Exception as e:
331
+
332
+ return f"❌ Beklenmeyen hata: {str(e)}"
333
+
334
+
335
+
336
+
337
+
338
+ def transcribe(audio_path: str):
339
 
 
340
  """
341
+
342
+ Transcribe audio file to Turkish text.
343
+
344
+ Returns: (transcription_text, download_file_path)
345
+
346
  """
347
+
348
+
 
349
 
350
  if audio_path is None:
351
+
352
+ return "⚠️ Lütfen bir ses dosyası yükleyin veya mikrofonla kayıt yapın.", None
353
+
354
+
355
 
356
  try:
357
+
358
  start_time = time.time()
359
+
360
 
361
+
362
+ # Transcribe with Turkish language
363
+
364
  segments, info = model.transcribe(
365
+
366
  audio_path,
367
+
368
  language="tr",
369
+
370
+ beam_size=5
371
+
372
  )
373
+
374
 
375
+
376
+ # Collect all segments
377
+
378
+ full_text = []
379
+
380
  for segment in segments:
381
+
382
+ full_text.append(segment.text)
383
+
384
+
385
+
386
+ result = " ".join(full_text).strip()
 
 
 
387
 
388
  elapsed = time.time() - start_time
389
+
390
+
391
+
392
+ if not result:
393
+
394
+ return "⚠️ Ses dosyasında konuşma algılanamadı. Lütfen daha net bir kayıt deneyin.", None
395
+
396
 
 
 
 
397
 
398
+ # Create downloadable TXT file
399
+
400
  txt_file = tempfile.NamedTemporaryFile(
401
+
402
+ mode='w',
403
+
404
+ suffix='.txt',
405
+
406
+ delete=False,
407
+
408
+ encoding='utf-8'
409
+
410
  )
411
+
412
+ txt_file.write(result)
413
+
414
  txt_file.close()
415
+
416
 
 
 
 
 
 
 
 
417
 
418
+ # Format display text with stats
419
+
420
+ display_text = f"""{result}
421
+
422
+
423
+
424
+ ───────────────────────────────────
425
+
426
+ 📊 İstatistikler
427
+
428
+ Alg��lanan dil: Türkçe
429
+
430
+ • Ses süresi: {info.duration:.1f} saniye
431
+
432
+ • İşlem süresi: {elapsed:.1f} saniye
433
+
434
+ • Hız: {info.duration/elapsed:.1f}x gerçek zamanlı
435
+
436
+ ───────────────────────────────────"""
437
+
438
+
439
+
440
+ return display_text, txt_file.name
441
+
442
+
443
+
444
+ except Exception as e:
445
+
446
+ error_msg = str(e)
447
+
448
+ if "ffmpeg" in error_msg.lower():
449
+
450
+ return "❌ Ses dosyası işlenemedi. Desteklenen formatlar: MP3, WAV, M4A, OGG, FLAC", None
451
+
452
+ return f"❌ Bir hata oluştu: {error_msg}", None
453
+
454
+
455
+
456
+
457
+
458
+ # Build Interface (Gradio 6.x compatible)
459
+
460
+ with gr.Blocks(title="Ses Deşifre Pro") as demo:
461
+
462
+
463
+
464
+ # Header via HTML
465
+
466
+ gr.HTML("""
467
+
468
+ <style>
469
+
470
+ footer { display: none !important; }
471
+
472
+ .gradio-container { max-width: 900px !important; margin: auto !important; }
473
+
474
+ </style>
475
+
476
+ <div style="text-align: center; padding: 40px 20px 30px;
477
+
478
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
479
+
480
+ border-radius: 20px; margin-bottom: 24px; color: white;">
481
+
482
+ <h1 style="font-size: 2.5rem; font-weight: 700; margin: 0 0 8px 0;">
483
+
484
+ 🎙️ Ses Deşifre Pro
485
+
486
+ </h1>
487
+
488
+ <p style="font-size: 1.1rem; opacity: 0.95; margin: 0;">
489
+
490
+ Yapay zeka ile Türkçe ses kayıtlarını metne dönüştürün
491
+
492
+ </p>
493
+
494
+ </div>
495
+
496
+ """)
497
+
498
+
499
+
500
+ # Main content
501
+
502
  with gr.Row():
503
+
504
  with gr.Column():
505
+
506
+ gr.HTML('<div style="font-weight: 600; margin-bottom: 12px;">📤 Ses Kaynağı</div>')
507
+
508
+
509
+
510
+ audio_input = gr.Audio(
511
+
512
+ label="Ses Dosyası veya Mikrofon",
513
+
514
+ type="filepath",
515
+
516
+ sources=["upload", "microphone"]
517
+
518
+ )
519
+
520
+
521
+
522
+ submit_btn = gr.Button(
523
+
524
+ "✨ Transkripsiyon Başlat",
525
+
526
+ variant="primary",
527
+
528
+ size="lg"
529
+
530
+ )
531
+
532
 
533
+
534
+ # Tips
535
+
536
+ gr.HTML("""
537
+
538
+ <div style="background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
539
+
540
+ border: 1px solid #86efac; border-radius: 12px;
541
+
542
+ padding: 16px 20px; margin-top: 16px;">
543
+
544
+ <p style="margin: 0; color: #166534; font-size: 14px;">
545
+
546
+ 💡 <strong>İpucu:</strong> En iyi sonuç için net, gürültüsüz ses kayıtları kullanın.
547
+
548
+ Desteklenen formatlar: MP3, WAV, M4A, OGG, FLAC
549
+
550
+ </p>
551
+
552
+ </div>
553
+
554
+ """)
555
+
556
+
557
+
558
+ # Results section
559
+
560
  with gr.Row():
561
+
562
  with gr.Column():
 
 
563
 
564
+ gr.HTML('<div style="font-weight: 600; margin-bottom: 12px;">📝 Transkripsiyon Sonucu</div>')
565
+
566
+
567
+
568
+ output_text = gr.Textbox(
569
+
570
+ label="",
571
+
572
+ placeholder="Sonuç burada görünecek...",
573
+
574
+ lines=12,
575
+
576
+ interactive=False
577
+
578
+ )
579
+
580
+
581
+
582
+ download_file = gr.File(
583
+
584
+ label="📥 Sonucu İndir (.txt)"
585
+
586
+ )
587
+
588
 
589
+
590
+ # ==================== GEMINI AI SECTION ====================
591
+
592
+ gr.HTML("""
593
+
594
+ <div style="margin-top: 32px; padding: 24px;
595
+
596
+ background: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%);
597
+
598
+ border-radius: 16px; border: 1px solid #4338ca;">
599
+
600
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
601
+
602
+ <span style="font-size: 28px;">✨</span>
603
+
604
+ <div>
605
+
606
+ <h2 style="color: white; margin: 0; font-size: 1.3rem;">Gemini AI ile Özet</h2>
607
+
608
+ <p style="color: #a5b4fc; margin: 4px 0 0 0; font-size: 0.85rem;">
609
+
610
+ Opsiyonel • API anahtarınız saklanmaz
611
+
612
+ </p>
613
+
614
+ </div>
615
+
616
+ </div>
617
+
618
+ </div>
619
+
620
+ """)
621
+
622
+
623
+
624
  with gr.Row():
625
+
626
+ with gr.Column(scale=1):
627
+
628
+ gemini_api_key = gr.Textbox(
629
+
630
+ label="🔑 Gemini API Anahtarı",
631
+
632
+ placeholder="AIza... şeklinde API anahtarınızı girin",
633
+
634
+ type="password",
635
+
636
+ info="Güvenli: Anahtarınız sunucuda saklanmaz, yalnızca bu istek için kullanılır."
637
+
638
+ )
639
+
640
+
641
+
642
+ gemini_prompt = gr.Textbox(
643
+
644
+ label="📝 Gemini'ye Not (Opsiyonel)",
645
+
646
+ placeholder="Örn: Sınavım için özet yap, En önemli 5 maddeyi listele, Bu metnin raporunu çıkar...",
647
+
648
+ lines=2,
649
+
650
+ info="Boş bırakırsanız genel bir özet oluşturulur."
651
+
652
+ )
653
+
654
+
655
+
656
+ gemini_btn = gr.Button(
657
+
658
+ "🤖 Gemini ile Özetle",
659
+
660
+ variant="secondary",
661
+
662
+ size="lg"
663
+
664
  )
665
+
666
+
667
+
668
+ with gr.Column(scale=1):
669
+
670
+ gemini_output = gr.Textbox(
671
+
672
+ label="Gemini Özet Sonucu",
673
+
674
+ placeholder="Özet burada görünecek...",
675
+
676
+ lines=10
677
+
678
+ )
679
+
680
+
681
+
682
+ # ==================== TRANSLATION SECTION ====================
683
+
684
+ gr.HTML("""
685
+
686
+ <div style="margin-top: 24px; padding: 24px;
687
+
688
+ background: linear-gradient(135deg, #064e3b 0%, #047857 100%);
689
+
690
+ border-radius: 16px; border: 1px solid #10b981;">
691
+
692
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
693
+
694
+ <span style="font-size: 28px;">🌍</span>
695
+
696
+ <div>
697
+
698
+ <h2 style="color: white; margin: 0; font-size: 1.3rem;">Gemini AI ile Çeviri</h2>
699
+
700
+ <p style="color: #a7f3d0; margin: 4px 0 0 0; font-size: 0.85rem;">
701
+
702
+ Türkçe • İngilizce • Almanca • Fransızca
703
+
704
+ </p>
705
+
706
+ </div>
707
+
708
+ </div>
709
+
710
+ </div>
711
+
712
+ """)
713
+
714
 
715
+
716
+ with gr.Row():
717
+
718
+ with gr.Column(scale=1):
719
+
720
+ translate_target_lang = gr.Dropdown(
721
+
722
+ label="🎯 Hedef Dil",
723
+
724
+ choices=["Türkçe", "İngilizce", "Almanca", "Fransızca"],
725
+
726
+ value="İngilizce",
727
+
728
+ info="Metni hangi dile çevirmek istiyorsunuz?"
729
+
730
+ )
731
+
732
 
 
 
 
 
733
 
734
+ translate_btn = gr.Button(
735
+
736
+ "🌍 Çevir",
737
+
738
+ variant="secondary",
739
+
740
+ size="lg"
741
+
742
+ )
743
+
744
+
745
+
746
+ with gr.Column(scale=2):
747
+
748
+ translate_output = gr.Textbox(
749
+
750
+ label="Çeviri Sonucu",
751
+
752
+ placeholder="Çeviri burada görünecek...",
753
+
754
+ lines=8
755
+
756
+ )
757
+
758
+
759
+
760
+ gr.HTML("""
761
+
762
+ <div style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 8px;
763
+
764
+ padding: 12px 16px; margin-top: 16px;">
765
+
766
+ <p style="margin: 0; color: #92400e; font-size: 13px;">
767
+
768
+ 🔒 <strong>Gizlilik:</strong> API anahtarınız sunucuda saklanmaz.
769
+
770
+ Butonlara basmadığınız sürece hiçbir veri dışarıya gönderilmez.
771
+
772
+ <a href="https://aistudio.google.com/apikey" target="_blank"
773
+
774
+ style="color: #1d4ed8; text-decoration: underline;">
775
+
776
+ Ücretsiz API anahtarı alın →
777
+
778
+ </a>
779
+
780
+ </p>
781
+
782
+ </div>
783
+
784
+ """)
785
+
786
+
787
+
788
+ # Features
789
+
790
+ gr.HTML("""
791
+
792
+ <div style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; margin-top: 32px;">
793
+
794
+ <div style="text-align: center; padding: 16px; background: #f9fafb; border-radius: 12px;">
795
+
796
+ <div style="font-size: 24px; margin-bottom: 6px;">🚀</div>
797
+
798
+ <div style="font-size: 12px; color: #6b7280; font-weight: 500;">Hızlı İşlem</div>
799
+
800
+ </div>
801
+
802
+ <div style="text-align: center; padding: 16px; background: #f9fafb; border-radius: 12px;">
803
+
804
+ <div style="font-size: 24px; margin-bottom: 6px;">🎯</div>
805
+
806
+ <div style="font-size: 12px; color: #6b7280; font-weight: 500;">Yüksek Doğruluk</div>
807
+
808
+ </div>
809
+
810
+ <div style="text-align: center; padding: 16px; background: #f9fafb; border-radius: 12px;">
811
+
812
+ <div style="font-size: 24px; margin-bottom: 6px;">🔒</div>
813
+
814
+ <div style="font-size: 12px; color: #6b7280; font-weight: 500;">Gizlilik Odaklı</div>
815
+
816
+ </div>
817
+
818
+ <div style="text-align: center; padding: 16px; background: linear-gradient(135deg, #ede9fe 0%, #ddd6fe 100%); border-radius: 12px;">
819
+
820
+ <div style="font-size: 24px; margin-bottom: 6px;">✨</div>
821
+
822
+ <div style="font-size: 12px; color: #5b21b6; font-weight: 500;">AI Özet</div>
823
+
824
+ </div>
825
+
826
+ <div style="text-align: center; padding: 16px; background: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%); border-radius: 12px;">
827
+
828
+ <div style="font-size: 24px; margin-bottom: 6px;">🌍</div>
829
+
830
+ <div style="font-size: 12px; color: #047857; font-weight: 500;">4 Dil Çeviri</div>
831
+
832
+ </div>
833
+
834
+ </div>
835
+
836
+ """)
837
+
838
+
839
+
840
+ # Footer
841
+
842
+ gr.HTML("""
843
+
844
+ <div style="text-align: center; padding: 24px 0; color: #9ca3af; font-size: 13px;">
845
+
846
+ <p>Powered by Faster-Whisper & Gemini AI • CPU Optimized • Made with ❤️</p>
847
+
848
+ </div>
849
+
850
+ """)
851
+
852
+
853
+
854
+ # Event handling
855
+
856
+ submit_btn.click(
857
+
858
+ fn=transcribe,
859
+
860
+ inputs=[audio_input],
861
+
862
+ outputs=[output_text, download_file]
863
+
864
+ )
865
+
866
+
867
+
868
+ gemini_btn.click(
869
+
870
+ fn=summarize_with_gemini,
871
+
872
+ inputs=[output_text, gemini_api_key, gemini_prompt],
873
+
874
+ outputs=gemini_output
875
+
876
+ )
877
+
878
+
879
+
880
+ translate_btn.click(
881
+
882
+ fn=translate_with_gemini,
883
+
884
+ inputs=[output_text, gemini_api_key, translate_target_lang],
885
+
886
+ outputs=translate_output
887
+
888
+ )
889
+
890
+
891
+
892
+ # Launch
893
 
894
  if __name__ == "__main__":
895
+
896
+ demo.launch(share=False, show_error=True)