Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,132 +1,212 @@
|
|
1 |
-
from fastapi import FastAPI, Depends, HTTPException, status, UploadFile, File
|
2 |
-
from fastapi.middleware.cors import CORSMiddleware
|
3 |
-
import gradio as gr
|
4 |
import os
|
5 |
import tempfile
|
6 |
import json
|
7 |
-
|
|
|
8 |
import spacy
|
9 |
from preprocessing import clean_audio
|
10 |
-
from asr import transcribe_file
|
11 |
from diarization import diarize_segments
|
12 |
from privacy import MedicalPrivacyProcessor
|
13 |
from config import settings
|
14 |
|
15 |
-
# HuggingFace token'ını ayarla
|
16 |
-
|
17 |
-
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
)
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
|
26 |
# SpaCy modelini yükle
|
27 |
-
|
28 |
-
nlp = spacy.load("tr_core_news_sm")
|
29 |
-
except OSError:
|
30 |
-
nlp = spacy.blank("tr")
|
31 |
|
32 |
-
#
|
33 |
-
|
34 |
-
|
35 |
-
try:
|
36 |
-
if audio_file is None:
|
37 |
-
return "Lütfen bir ses dosyası yükleyin."
|
38 |
-
|
39 |
-
asr_model = get_asr_model()
|
40 |
-
result = asr_model.transcribe(
|
41 |
-
audio_file,
|
42 |
-
speaker_diarization=diarize,
|
43 |
-
enhance_audio=enhance_audio
|
44 |
-
)
|
45 |
-
|
46 |
-
output = "📝 Transkripsiyon:\n\n"
|
47 |
-
|
48 |
-
if "diarization" in result:
|
49 |
-
for segment in result["diarization"]:
|
50 |
-
output += f"🗣️ {segment['speaker']} ({segment['start']:.1f}s - {segment['end']:.1f}s):\n"
|
51 |
-
output += f"{segment['text']}\n\n"
|
52 |
-
else:
|
53 |
-
output += result["text"]
|
54 |
-
|
55 |
-
if result.get("anonymized"):
|
56 |
-
output += "\n🔒 Kişisel veriler anonimleştirildi."
|
57 |
-
|
58 |
-
return output
|
59 |
-
except Exception as e:
|
60 |
-
return f"Bir hata oluştu: {str(e)}"
|
61 |
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
gr.Checkbox(label="Konuşmacı Ayrımı", value=True),
|
67 |
-
gr.Checkbox(label="Ses İyileştirme", value=True),
|
68 |
-
gr.Checkbox(label="Kişisel Verileri Anonimleştir", value=True)
|
69 |
-
],
|
70 |
-
outputs=gr.Textbox(label="Transkripsiyon Sonucu", lines=10),
|
71 |
-
title="🏥 Tıbbi Konuşma Transkripsiyon Servisi",
|
72 |
-
description="Bu servis, doktor vizitelerindeki konuşmaları yazıya döker ve konuşmacıları ayırt eder.",
|
73 |
-
theme=gr.themes.Soft(primary_hue="indigo", secondary_hue="blue"),
|
74 |
-
allow_flagging="never"
|
75 |
-
)
|
76 |
-
return demo
|
77 |
|
78 |
-
|
79 |
-
app = FastAPI(title="Pediatrik ASR API")
|
80 |
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
allow_credentials=True,
|
86 |
-
allow_methods=["*"],
|
87 |
-
allow_headers=["*"],
|
88 |
-
)
|
89 |
|
90 |
-
#
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
98 |
|
99 |
-
|
100 |
-
@app.post("/api/v1/transcribe")
|
101 |
-
async def transcribe_audio_api(
|
102 |
-
file: UploadFile = File(...),
|
103 |
-
diarize: bool = True,
|
104 |
-
enhance_audio: bool = True,
|
105 |
-
anonymize: Optional[bool] = None,
|
106 |
-
asr_model: MedicalASR = Depends(get_asr_model)
|
107 |
-
):
|
108 |
try:
|
109 |
-
|
110 |
-
|
111 |
-
|
|
|
112 |
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
)
|
118 |
|
119 |
-
|
120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
|
122 |
except Exception as e:
|
123 |
-
|
|
|
124 |
|
125 |
-
#
|
126 |
-
|
127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
|
129 |
-
#
|
130 |
if __name__ == "__main__":
|
131 |
-
|
132 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|
|
|
|
1 |
import os
|
2 |
import tempfile
|
3 |
import json
|
4 |
+
import time
|
5 |
+
import gradio as gr
|
6 |
import spacy
|
7 |
from preprocessing import clean_audio
|
8 |
+
from asr import transcribe_file
|
9 |
from diarization import diarize_segments
|
10 |
from privacy import MedicalPrivacyProcessor
|
11 |
from config import settings
|
12 |
|
13 |
+
# HuggingFace token'ını ayarla
|
14 |
+
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
15 |
+
if not HF_TOKEN:
|
16 |
+
print("Warning: HF_TOKEN not set!")
|
17 |
|
18 |
+
def load_spacy_model():
|
19 |
+
"""SpaCy modelini yükle veya indir"""
|
20 |
+
try:
|
21 |
+
# Önce mevcut modelleri kontrol et
|
22 |
+
available_models = spacy.util.get_installed_models()
|
23 |
+
if "tr_core_news_md" in available_models:
|
24 |
+
print("Türkçe SpaCy modeli bulundu, yükleniyor...")
|
25 |
+
return spacy.load("tr_core_news_md")
|
26 |
+
elif "tr_core_news_sm" in available_models:
|
27 |
+
print("Küçük Türkçe SpaCy modeli bulundu, yükleniyor...")
|
28 |
+
return spacy.load("tr_core_news_sm")
|
29 |
+
else:
|
30 |
+
print("Türkçe SpaCy modeli bulunamadı, indiriliyor...")
|
31 |
+
os.system("python -m spacy download tr_core_news_md")
|
32 |
+
return spacy.load("tr_core_news_md")
|
33 |
+
except Exception as e:
|
34 |
+
print(f"SpaCy model yükleme hatası: {str(e)}")
|
35 |
+
print("Boş Türkçe model oluşturuluyor...")
|
36 |
+
return spacy.blank("tr")
|
37 |
|
38 |
# SpaCy modelini yükle
|
39 |
+
nlp = load_spacy_model()
|
|
|
|
|
|
|
40 |
|
41 |
+
# Yardım metni
|
42 |
+
usage_tips = """
|
43 |
+
## Kullanım İpuçları
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
+
1. **Dosya formatı**: WAV formatında ses dosyaları en iyi sonuçları verir.
|
46 |
+
2. **Ses kalitesi**: Gürültüsüz ortamlarda kaydedilen sesler daha iyi sonuç verir.
|
47 |
+
3. **Konuşmacı ayrımı**: Konuşmacı sayısı arttıkça tanıma doğruluğu düşebilir.
|
48 |
+
4. **Hata durumlarında**: Sistem hata verirse, ses dosyasının formatını ve boyutunu kontrol edin.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
+
## Pediatrik Uzmanlar İçin
|
|
|
51 |
|
52 |
+
Sistem, çocuk hastalıkları, aşılar, ilaçlar ve muayene terimleri içeren
|
53 |
+
geniş bir tıbbi terim sözlüğü kullanır. Bu sayede pediatri vizitelerindeki
|
54 |
+
terminolojinin doğru transkribe edilmesini sağlar.
|
55 |
+
"""
|
|
|
|
|
|
|
|
|
56 |
|
57 |
+
# CSS stilleri
|
58 |
+
css = """
|
59 |
+
.container {padding: 20px; border-radius: 10px; box-shadow: 0 4px 8px rgba(0,0,0,0.1);}
|
60 |
+
.result-text {margin-top: 10px; padding: 15px; background: #f8f9fa; border-radius: 5px; white-space: pre-wrap;}
|
61 |
+
.speaker {font-weight: bold; color: #1a5fb4;}
|
62 |
+
.timestamp {color: #666; font-size: 0.9em;}
|
63 |
+
.success {color: green; font-weight: bold;}
|
64 |
+
.error {color: red; font-weight: bold;}
|
65 |
+
.footer {margin-top: 50px; text-align: center; color: #666; font-size: 0.9em;}
|
66 |
+
.tips {background: #e7f5ff; padding: 15px; border-radius: 5px; margin-top: 20px;}
|
67 |
+
"""
|
68 |
|
69 |
+
async def process_audio(audio_file, diarize=True, enhance=True, anonymize=True, progress=gr.Progress()):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
try:
|
71 |
+
if audio_file is None:
|
72 |
+
return {"error": "Lütfen bir ses dosyası yükleyin."}, None
|
73 |
+
|
74 |
+
progress(0, desc="Ses dosyası hazırlanıyor...")
|
75 |
|
76 |
+
# Ses dosyasını temizle
|
77 |
+
if enhance:
|
78 |
+
progress(0.1, desc="Ses iyileştiriliyor...")
|
79 |
+
audio_file = clean_audio(audio_file)
|
80 |
+
|
81 |
+
# Transkripsiyon yap
|
82 |
+
progress(0.3, desc="Ses metne dönüştürülüyor...")
|
83 |
+
result = transcribe_file(
|
84 |
+
audio_file,
|
85 |
+
language="tr",
|
86 |
+
model_name=settings.ASR_MODEL
|
87 |
)
|
88 |
|
89 |
+
# Konuşmacı ayrımı
|
90 |
+
if diarize:
|
91 |
+
progress(0.6, desc="Konuşmacılar ayrıştırılıyor...")
|
92 |
+
diarization_result = diarize_segments(result["segments"])
|
93 |
+
result["diarization"] = diarization_result
|
94 |
+
|
95 |
+
# Kişisel verileri anonimleştir
|
96 |
+
if anonymize:
|
97 |
+
progress(0.8, desc="Kişisel veriler anonimleştiriliyor...")
|
98 |
+
privacy_processor = MedicalPrivacyProcessor()
|
99 |
+
result["text"] = privacy_processor.anonymize_text(result["text"])
|
100 |
+
result["anonymized"] = True
|
101 |
+
|
102 |
+
# Sonucu formatla
|
103 |
+
progress(0.9, desc="Sonuçlar hazırlanıyor...")
|
104 |
+
formatted_text = ""
|
105 |
+
if diarize and "diarization" in result:
|
106 |
+
for segment in result["diarization"]:
|
107 |
+
speaker = segment["speaker"]
|
108 |
+
text = segment["text"]
|
109 |
+
start = segment["start"]
|
110 |
+
end = segment["end"]
|
111 |
+
formatted_text += f"[{speaker}] ({start:.1f}s - {end:.1f}s): {text}\n\n"
|
112 |
+
else:
|
113 |
+
formatted_text = result["text"]
|
114 |
+
|
115 |
+
if result.get("anonymized"):
|
116 |
+
formatted_text += "\n🔒 Kişisel veriler anonimleştirildi."
|
117 |
+
|
118 |
+
progress(1.0, desc="Tamamlandı!")
|
119 |
+
return result, formatted_text
|
120 |
|
121 |
except Exception as e:
|
122 |
+
print(f"Error in process_audio: {str(e)}")
|
123 |
+
return {"error": f"İşlem sırasında hata: {str(e)}"}, None
|
124 |
|
125 |
+
# Ana arayüz
|
126 |
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", secondary_hue="blue"), css=css) as demo:
|
127 |
+
gr.HTML(f"""
|
128 |
+
<div style="text-align: center; max-height: 150px; margin-bottom: 30px">
|
129 |
+
<h1>Türkçe Pediatrik Konuşma Tanıma Sistemi</h1>
|
130 |
+
<p>Çocuk doktorları için geliştirilmiş, pediatri alanına özel tıbbi terminoloji tanıma özellikli transkripsiyon sistemi</p>
|
131 |
+
</div>
|
132 |
+
""")
|
133 |
+
|
134 |
+
with gr.Row():
|
135 |
+
with gr.Column(scale=1):
|
136 |
+
audio_input = gr.Audio(
|
137 |
+
label="Ses Dosyası Yükleyin veya Kaydedin",
|
138 |
+
type="filepath",
|
139 |
+
elem_classes="container"
|
140 |
+
)
|
141 |
+
|
142 |
+
with gr.Group():
|
143 |
+
with gr.Row():
|
144 |
+
diarize = gr.Checkbox(value=True, label="Konuşmacı Ayrımı")
|
145 |
+
enhance = gr.Checkbox(value=True, label="Ses İyileştirme")
|
146 |
+
|
147 |
+
with gr.Row():
|
148 |
+
anonymize = gr.Checkbox(value=True, label="Kişisel Verileri Anonimleştir")
|
149 |
+
clear_btn = gr.Button("Temizle", variant="secondary")
|
150 |
+
|
151 |
+
process_btn = gr.Button("Transkribe Et", variant="primary")
|
152 |
+
gr.HTML('<div class="tips"><b>💡 İpucu:</b> En iyi sonuçlar için gürültüsüz ortamlarda kayıt yapın.</div>')
|
153 |
+
|
154 |
+
with gr.Column(scale=2, elem_classes="container"):
|
155 |
+
with gr.Tabs():
|
156 |
+
with gr.TabItem("Konuşma Metni"):
|
157 |
+
result_text = gr.Markdown(label="Transkripsiyon Sonucu", elem_classes="result-text")
|
158 |
+
|
159 |
+
with gr.TabItem("JSON Sonucu"):
|
160 |
+
json_output = gr.JSON(label="API Yanıtı")
|
161 |
+
|
162 |
+
with gr.TabItem("Kullanım Kılavuzu"):
|
163 |
+
gr.Markdown(usage_tips)
|
164 |
+
|
165 |
+
status = gr.Markdown("Sistem hazır.")
|
166 |
+
|
167 |
+
# Uyarı mesajı
|
168 |
+
gr.HTML("""
|
169 |
+
<div style="background-color: #fff3cd; color: #856404; padding: 15px; margin: 15px 0; border-radius: 5px; border: 1px solid #ffeeba;">
|
170 |
+
<h3>⚠️ Önemli Gizlilik Uyarısı</h3>
|
171 |
+
<p>
|
172 |
+
Bu demo uygulaması <strong>yalnızca eğitim amaçlıdır</strong> ve gerçek hasta verilerinin işlenmesi için tasarlanmamıştır.
|
173 |
+
Lütfen hasta bilgisi içeren ses kayıtlarını yüklemeyin. Sistemde paylaşılan ses kayıtları üçüncü şahıslar tarafından erişilebilir
|
174 |
+
ve gizlilik/güvenlik garantisi yoktur.
|
175 |
+
</p>
|
176 |
+
<p>
|
177 |
+
Bu aracı kullanarak, yüklediğiniz verilerin <a href="https://huggingface.co/terms-of-service" target="_blank">Hugging Face Kullanım Koşulları</a>'na
|
178 |
+
uygun olduğunu kabul etmiş olursunuz.
|
179 |
+
</p>
|
180 |
+
</div>
|
181 |
+
""")
|
182 |
+
|
183 |
+
# İzin onayı
|
184 |
+
with gr.Group():
|
185 |
+
privacy_agreement = gr.Checkbox(label="Gizlilik koşullarını okudum ve kabul ediyorum", value=False)
|
186 |
+
|
187 |
+
# Onay olmadan işlem yapılmasını engelle
|
188 |
+
def check_agreement(agreement, *args):
|
189 |
+
if not agreement:
|
190 |
+
return {"error": "Devam etmek için gizlilik koşullarını kabul etmelisiniz."}, "Lütfen gizlilik koşullarını kabul edin."
|
191 |
+
return process_audio(*args)
|
192 |
+
|
193 |
+
process_btn.click(
|
194 |
+
fn=check_agreement,
|
195 |
+
inputs=[privacy_agreement, audio_input, diarize, enhance, anonymize],
|
196 |
+
outputs=[json_output, result_text]
|
197 |
+
)
|
198 |
+
|
199 |
+
clear_btn.click(
|
200 |
+
lambda: (None, None, "Sistem hazır."),
|
201 |
+
outputs=[audio_input, result_text, status]
|
202 |
+
)
|
203 |
+
|
204 |
+
gr.HTML("""
|
205 |
+
<div class="footer">
|
206 |
+
<p>© 2023 Türkçe Pediatrik Konuşma Tanıma Sistemi | Çocuk doktorları için geliştirilmiştir.</p>
|
207 |
+
</div>
|
208 |
+
""")
|
209 |
|
210 |
+
# Hugging Face Spaces için gerekli
|
211 |
if __name__ == "__main__":
|
212 |
+
demo.queue().launch(server_name="0.0.0.0", server_port=7860, share=False)
|
|