Jedi09 commited on
Commit
9c8785c
·
verified ·
1 Parent(s): f9f38cb

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +323 -0
  2. packages.txt +1 -0
  3. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,323 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.
5
+ """
6
+
7
+ import gradio as gr
8
+ from faster_whisper import WhisperModel
9
+ import tempfile
10
+ import time
11
+ import requests
12
+
13
+ # ==================== CONFIGURATION ====================
14
+ MODEL_SIZE = "medium" # Options: tiny, base, small, medium, large-v3
15
+ # =======================================================
16
+
17
+ # Load model once at startup
18
+ print("🔄 Model yükleniyor... (Bu işlem birkaç dakika sürebilir)")
19
+ model = WhisperModel(
20
+ MODEL_SIZE,
21
+ device="cpu",
22
+ compute_type="int8"
23
+ )
24
+ print("✅ Model yüklendi!")
25
+
26
+
27
+ def summarize_with_gemini(text: str, api_key: str, custom_prompt: str = "") -> str:
28
+ """
29
+ Summarize text using Google Gemini API.
30
+ API key is not stored - used only for this single request.
31
+ """
32
+ if not api_key or not api_key.strip():
33
+ return "⚠️ Gemini API anahtarı girilmedi."
34
+
35
+ if not text or text.strip() == "" or text.startswith("⚠️") or text.startswith("❌"):
36
+ return "⚠️ Önce bir transkripsiyon oluşturun."
37
+
38
+ # Extract only the transcription text (remove stats section)
39
+ clean_text = text.split("───────────────────────────────────")[0].strip()
40
+ if not clean_text:
41
+ return "⚠️ Özetlenecek metin bulunamadı."
42
+
43
+ # Build the prompt
44
+ base_instruction = "Aşağıdaki Türkçe metni analiz et ve özetle."
45
+ if custom_prompt and custom_prompt.strip():
46
+ full_prompt = f"{custom_prompt.strip()}\n\nMetin:\n{clean_text}"
47
+ else:
48
+ full_prompt = f"{base_instruction}\n\nMetin:\n{clean_text}"
49
+
50
+ # Gemini API endpoint
51
+ url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}"
52
+
53
+ headers = {"Content-Type": "application/json"}
54
+
55
+ payload = {
56
+ "contents": [{"parts": [{"text": full_prompt}]}],
57
+ "generationConfig": {
58
+ "temperature": 0.7,
59
+ "maxOutputTokens": 2048
60
+ }
61
+ }
62
+
63
+ try:
64
+ response = requests.post(url, headers=headers, json=payload, timeout=60)
65
+
66
+ if response.status_code == 200:
67
+ result = response.json()
68
+ if "candidates" in result and len(result["candidates"]) > 0:
69
+ candidate = result["candidates"][0]
70
+ if "content" in candidate and "parts" in candidate["content"]:
71
+ parts = candidate["content"]["parts"]
72
+ if len(parts) > 0 and "text" in parts[0]:
73
+ return parts[0]["text"]
74
+ return "❌ Gemini yanıtı beklenmedik formatta."
75
+ elif response.status_code == 400:
76
+ return "❌ Geçersiz istek. API anahtarını kontrol edin."
77
+ elif response.status_code in [401, 403]:
78
+ return "❌ API anahtarı geçersiz veya yetkisiz."
79
+ elif response.status_code == 429:
80
+ return "❌ API kullanım limiti aşıldı. Lütfen bekleyin."
81
+ else:
82
+ return f"❌ Gemini API hatası: {response.status_code}"
83
+
84
+ except requests.exceptions.Timeout:
85
+ return "❌ Gemini API zaman aşımı. Tekrar deneyin."
86
+ except requests.exceptions.RequestException as e:
87
+ return f"❌ Bağlantı hatası: {str(e)}"
88
+ except Exception as e:
89
+ return f"❌ Beklenmeyen hata: {str(e)}"
90
+
91
+
92
+ def transcribe(audio_path: str):
93
+ """
94
+ Transcribe audio file to Turkish text.
95
+ Returns: (transcription_text, download_file_path)
96
+ """
97
+
98
+ if audio_path is None:
99
+ return "⚠️ Lütfen bir ses dosyası yükleyin veya mikrofonla kayıt yapın.", None
100
+
101
+ try:
102
+ start_time = time.time()
103
+
104
+ # Transcribe with Turkish language
105
+ segments, info = model.transcribe(
106
+ audio_path,
107
+ language="tr",
108
+ beam_size=5
109
+ )
110
+
111
+ # Collect all segments
112
+ full_text = []
113
+ for segment in segments:
114
+ full_text.append(segment.text)
115
+
116
+ result = " ".join(full_text).strip()
117
+ elapsed = time.time() - start_time
118
+
119
+ if not result:
120
+ return "⚠️ Ses dosyasında konuşma algılanamadı. Lütfen daha net bir kayıt deneyin.", None
121
+
122
+ # Create downloadable TXT file
123
+ txt_file = tempfile.NamedTemporaryFile(
124
+ mode='w',
125
+ suffix='.txt',
126
+ delete=False,
127
+ encoding='utf-8'
128
+ )
129
+ txt_file.write(result)
130
+ txt_file.close()
131
+
132
+ # Format display text with stats
133
+ display_text = f"""{result}
134
+
135
+ ───────────────────────────────────
136
+ 📊 İstatistikler
137
+ • Algılanan dil: Türkçe
138
+ • Ses süresi: {info.duration:.1f} saniye
139
+ • İşlem süresi: {elapsed:.1f} saniye
140
+ • Hız: {info.duration/elapsed:.1f}x gerçek zamanlı
141
+ ───────────────────────────────────"""
142
+
143
+ return display_text, txt_file.name
144
+
145
+ except Exception as e:
146
+ error_msg = str(e)
147
+ if "ffmpeg" in error_msg.lower():
148
+ return "❌ Ses dosyası işlenemedi. Desteklenen formatlar: MP3, WAV, M4A, OGG, FLAC", None
149
+ return f"❌ Bir hata oluştu: {error_msg}", None
150
+
151
+
152
+ # Build Interface (Gradio 6.x compatible)
153
+ with gr.Blocks(title="Ses Deşifre Pro") as demo:
154
+
155
+ # Header via HTML
156
+ gr.HTML("""
157
+ <style>
158
+ footer { display: none !important; }
159
+ .gradio-container { max-width: 900px !important; margin: auto !important; }
160
+ </style>
161
+ <div style="text-align: center; padding: 40px 20px 30px;
162
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
163
+ border-radius: 20px; margin-bottom: 24px; color: white;">
164
+ <h1 style="font-size: 2.5rem; font-weight: 700; margin: 0 0 8px 0;">
165
+ 🎙️ Ses Deşifre Pro
166
+ </h1>
167
+ <p style="font-size: 1.1rem; opacity: 0.95; margin: 0;">
168
+ Yapay zeka ile Türkçe ses kayıtlarını metne dönüştürün
169
+ </p>
170
+ </div>
171
+ """)
172
+
173
+ # Main content
174
+ with gr.Row():
175
+ with gr.Column():
176
+ gr.HTML('<div style="font-weight: 600; margin-bottom: 12px;">📤 Ses Kaynağı</div>')
177
+
178
+ audio_input = gr.Audio(
179
+ label="Ses Dosyası veya Mikrofon",
180
+ type="filepath",
181
+ sources=["upload", "microphone"]
182
+ )
183
+
184
+ submit_btn = gr.Button(
185
+ "✨ Transkripsiyon Başlat",
186
+ variant="primary",
187
+ size="lg"
188
+ )
189
+
190
+ # Tips
191
+ gr.HTML("""
192
+ <div style="background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
193
+ border: 1px solid #86efac; border-radius: 12px;
194
+ padding: 16px 20px; margin-top: 16px;">
195
+ <p style="margin: 0; color: #166534; font-size: 14px;">
196
+ 💡 <strong>İpucu:</strong> En iyi sonuç için net, gürültüsüz ses kayıtları kullanın.
197
+ Desteklenen formatlar: MP3, WAV, M4A, OGG, FLAC
198
+ </p>
199
+ </div>
200
+ """)
201
+
202
+ # Results section
203
+ with gr.Row():
204
+ with gr.Column():
205
+ gr.HTML('<div style="font-weight: 600; margin-bottom: 12px;">📝 Transkripsiyon Sonucu</div>')
206
+
207
+ output_text = gr.Textbox(
208
+ label="",
209
+ placeholder="Sonuç burada görünecek...",
210
+ lines=12,
211
+ interactive=False
212
+ )
213
+
214
+ download_file = gr.File(
215
+ label="📥 Sonucu İndir (.txt)"
216
+ )
217
+
218
+ # ==================== GEMINI AI SECTION ====================
219
+ gr.HTML("""
220
+ <div style="margin-top: 32px; padding: 24px;
221
+ background: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%);
222
+ border-radius: 16px; border: 1px solid #4338ca;">
223
+ <div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
224
+ <span style="font-size: 28px;">✨</span>
225
+ <div>
226
+ <h2 style="color: white; margin: 0; font-size: 1.3rem;">Gemini AI ile Özet</h2>
227
+ <p style="color: #a5b4fc; margin: 4px 0 0 0; font-size: 0.85rem;">
228
+ Opsiyonel • API anahtarınız saklanmaz
229
+ </p>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ """)
234
+
235
+ with gr.Row():
236
+ with gr.Column(scale=1):
237
+ gemini_api_key = gr.Textbox(
238
+ label="🔑 Gemini API Anahtarı",
239
+ placeholder="AIza... şeklinde API anahtarınızı girin",
240
+ type="password",
241
+ info="Güvenli: Anahtarınız sunucuda saklanmaz, yalnızca bu istek için kullanılır."
242
+ )
243
+
244
+ gemini_prompt = gr.Textbox(
245
+ label="📝 Gemini'ye Not (Opsiyonel)",
246
+ placeholder="Örn: Sınavım için özet yap, En önemli 5 maddeyi listele, Bu metnin raporunu çıkar...",
247
+ lines=2,
248
+ info="Boş bırakırsanız genel bir özet oluşturulur."
249
+ )
250
+
251
+ gemini_btn = gr.Button(
252
+ "🤖 Gemini ile Özetle",
253
+ variant="secondary",
254
+ size="lg"
255
+ )
256
+
257
+ with gr.Column(scale=1):
258
+ gemini_output = gr.Textbox(
259
+ label="Gemini Özet Sonucu",
260
+ placeholder="Özet burada görünecek...",
261
+ lines=10,
262
+ show_copy_button=True
263
+ )
264
+
265
+ gr.HTML("""
266
+ <div style="background: #fef3c7; border: 1px solid #f59e0b; border-radius: 8px;
267
+ padding: 12px 16px; margin-top: 16px;">
268
+ <p style="margin: 0; color: #92400e; font-size: 13px;">
269
+ 🔒 <strong>Gizlilik:</strong> API anahtarınız sunucuda saklanmaz.
270
+ "Gemini ile Özetle" butonuna basmadığınız sürece hiçbir veri dışarıya gönderilmez.
271
+ <a href="https://aistudio.google.com/apikey" target="_blank"
272
+ style="color: #1d4ed8; text-decoration: underline;">
273
+ Ücretsiz API anahtarı alın →
274
+ </a>
275
+ </p>
276
+ </div>
277
+ """)
278
+
279
+ # Features
280
+ gr.HTML("""
281
+ <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-top: 32px;">
282
+ <div style="text-align: center; padding: 20px; background: #f9fafb; border-radius: 12px;">
283
+ <div style="font-size: 28px; margin-bottom: 8px;">🚀</div>
284
+ <div style="font-size: 13px; color: #6b7280; font-weight: 500;">Hızlı İşlem</div>
285
+ </div>
286
+ <div style="text-align: center; padding: 20px; background: #f9fafb; border-radius: 12px;">
287
+ <div style="font-size: 28px; margin-bottom: 8px;">🎯</div>
288
+ <div style="font-size: 13px; color: #6b7280; font-weight: 500;">Yüksek Doğruluk</div>
289
+ </div>
290
+ <div style="text-align: center; padding: 20px; background: #f9fafb; border-radius: 12px;">
291
+ <div style="font-size: 28px; margin-bottom: 8px;">🔒</div>
292
+ <div style="font-size: 13px; color: #6b7280; font-weight: 500;">Gizlilik Odaklı</div>
293
+ </div>
294
+ <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #ede9fe 0%, #ddd6fe 100%); border-radius: 12px;">
295
+ <div style="font-size: 28px; margin-bottom: 8px;">✨</div>
296
+ <div style="font-size: 13px; color: #5b21b6; font-weight: 500;">AI Özet</div>
297
+ </div>
298
+ </div>
299
+ """)
300
+
301
+ # Footer
302
+ gr.HTML("""
303
+ <div style="text-align: center; padding: 24px 0; color: #9ca3af; font-size: 13px;">
304
+ <p>Powered by Faster-Whisper & Gemini AI • CPU Optimized • Made with ❤️</p>
305
+ </div>
306
+ """)
307
+
308
+ # Event handling
309
+ submit_btn.click(
310
+ fn=transcribe,
311
+ inputs=[audio_input],
312
+ outputs=[output_text, download_file]
313
+ )
314
+
315
+ gemini_btn.click(
316
+ fn=summarize_with_gemini,
317
+ inputs=[output_text, gemini_api_key, gemini_prompt],
318
+ outputs=gemini_output
319
+ )
320
+
321
+ # Launch
322
+ if __name__ == "__main__":
323
+ demo.launch(share=False, show_error=True)
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ffmpeg
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio>=4.0.0
2
+ faster-whisper
3
+ requests