fraunhofer commited on
Commit
f79b859
·
1 Parent(s): b58a541

analiz motoru ve küçük değişiklikler

Browse files
Files changed (4) hide show
  1. .gitignore +4 -0
  2. Dockerfile +5 -7
  3. main.py +58 -104
  4. phonology_engine.py +4 -1
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.pyo
4
+ *.pyd
Dockerfile CHANGED
@@ -2,14 +2,14 @@ FROM python:3.9
2
 
3
  WORKDIR /code
4
 
5
- # FFmpeg kurulumu (Ses işleme için şart)
6
  RUN apt-get update && apt-get install -y ffmpeg
7
 
8
  # Kütüphaneleri yükle
9
  COPY ./requirements.txt /code/requirements.txt
10
  RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
11
 
12
- # Kullanıcı yetkilerini ayarla (Hugging Face güvenlik kuralı)
13
  RUN useradd -m -u 1000 user
14
  USER user
15
  ENV HOME=/home/user \
@@ -18,10 +18,8 @@ ENV HOME=/home/user \
18
  WORKDIR $HOME/app
19
  COPY --chown=user . $HOME/app
20
 
21
- # --- DÜZELTİLEN KISIM BURASI ---
22
- # Eski 'import whisper' yerine 'faster_whisper' kullanıyoruz.
23
- # Modeli önbelleğe indiriyoruz ki her açılışta tekrar indirmesin.
24
- RUN python3 -c "from faster_whisper import WhisperModel; WhisperModel('large-v2', device='cpu', compute_type='int8')"
25
 
26
- # Uygulamayı başlat
27
  CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
 
2
 
3
  WORKDIR /code
4
 
5
+ # FFmpeg kurulumu (Ses işlemek için şart)
6
  RUN apt-get update && apt-get install -y ffmpeg
7
 
8
  # Kütüphaneleri yükle
9
  COPY ./requirements.txt /code/requirements.txt
10
  RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
11
 
12
+ # Kullanıcı ayarları
13
  RUN useradd -m -u 1000 user
14
  USER user
15
  ENV HOME=/home/user \
 
18
  WORKDIR $HOME/app
19
  COPY --chown=user . $HOME/app
20
 
21
+ # --- ÖNEMLİ ---
22
+ # Hem 'small' (Uygulama için) hem 'large-v2' (Karşılaştırma için) modellerini indiriyoruz.
23
+ RUN python3 -c "from faster_whisper import WhisperModel; WhisperModel('small', device='cpu', compute_type='int8'); WhisperModel('large-v2', device='cpu', compute_type='int8')"
 
24
 
 
25
  CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
main.py CHANGED
@@ -1,135 +1,89 @@
1
- from fastapi import FastAPI, UploadFile, File, Form, HTTPException
2
  from faster_whisper import WhisperModel
3
  from phonology_engine import FonolojikVaryasyonMotoru
4
- import difflib
5
- import os
6
  import shutil
 
7
  import uuid
 
8
 
9
- app = FastAPI(title="MnemAI Ses Analiz API")
10
 
11
- # --- MODEL AYARLARI ---
12
- # Hugging Face CPU'su için 'int8' en iyisidir.
13
- MODEL_SIZE = "large-v2"
14
- DEVICE = "cpu"
15
- COMPUTE_TYPE = "int8"
16
 
17
- print("⏳ Whisper modeli ve Varyasyon Motoru yükleniyor...")
18
- # Modeli global olarak bir kez yüklüyoruz
19
- model = WhisperModel(MODEL_SIZE, device=DEVICE, compute_type=COMPUTE_TYPE)
20
- motor = FonolojikVaryasyonMotoru()
21
- print("✅ Sistem hazır!")
22
 
23
- def kelime_analizi_yap(hedef: str, gelen: str):
24
- """
25
- Hedef kelime ile gelen kelimeyi karşılaştırır ve hataları raporlar.
26
- """
27
- hedef = hedef.lower().replace("İ", "i").strip()
28
- gelen = gelen.lower().replace("İ", "i").strip()
29
-
30
- # 1. Tam Eşleşme
31
- if hedef == gelen:
32
- return {
33
- "durum": "basarili",
34
- "skor": 100,
35
- "mesaj": "Harika! Tamamen doğru söyledin.",
36
- "hatalar": []
37
- }
38
 
39
- # 2. Hata Analizi (Difflib)
40
- matcher = difflib.SequenceMatcher(None, hedef, gelen)
41
- hatalar = []
42
-
43
- # Opcodes: 'replace', 'delete', 'insert', 'equal'
44
- for tag, i1, i2, j1, j2 in matcher.get_opcodes():
45
- if tag == 'replace':
46
- beklenen = hedef[i1:i2]
47
- soylenen = gelen[j1:j2]
48
- hatalar.append(f"'{beklenen.upper()}' yerine '{soylenen.upper()}' dedin.")
49
- elif tag == 'delete':
50
- beklenen = hedef[i1:i2]
51
- hatalar.append(f"'{beklenen.upper()}' sesini yuttun.")
52
- elif tag == 'insert':
53
- fazla = gelen[j1:j2]
54
- hatalar.append(f"Fazladan '{fazla.upper()}' sesi çıkardın.")
55
 
 
 
 
56
  skor = int(matcher.ratio() * 100)
57
-
58
- return {
59
- "durum": "hatali",
60
- "skor": skor,
61
- "mesaj": "Bazı sesleri düzeltmemiz gerekiyor.",
62
- "hatalar": hatalar,
63
- "detayli_fark": {
64
- "beklenen": hedef,
65
- "algilanan": gelen
66
- }
67
- }
68
 
 
69
  @app.post("/analiz")
70
- async def ses_analiz(
71
  file: UploadFile = File(...),
72
  hedef_kelime: str = Form(...)
73
  ):
74
- """
75
- Endpoint: Ses dosyasını ve hedeflenen kelimeyi alır, analiz sonucunu döner.
76
- """
77
-
78
- # 1. Dosyayı Geçici Kaydet
79
- if not file.filename.lower().endswith(('.wav', '.mp3', '.m4a', '.ogg')):
80
- raise HTTPException(status_code=400, detail="Geçersiz dosya formatı.")
81
-
82
  temp_filename = f"temp_{uuid.uuid4()}.wav"
83
 
 
 
 
 
84
  try:
85
- with open(temp_filename, "wb") as buffer:
86
- shutil.copyfileobj(file.file, buffer)
87
-
88
- # 2. Fonolojik Prompt Üret (Whisper'ı yönlendirmek için)
89
- prompt_metni = motor.varyasyonlari_uret(hedef_kelime)
90
-
91
- # 3. Whisper Transkripsiyon
92
- # initial_prompt: Whisper'a bu kelimenin varyasyonlu olabileceğini söylüyoruz.
93
- segments, _ = model.transcribe(
94
  temp_filename,
95
  language="tr",
96
- initial_prompt=f"Bu çocuk şu kelimeleri söyleyebilir: {prompt_metni}",
97
-
98
- # --- YENİ EKLENEN AYARLAR ---
99
- beam_size=5, # Daha fazla olasılığı değerlendir
100
- vad_filter=False, # Sessizlik filtresini KAPAT (Çok önemli)
101
- word_timestamps=False, # Tek kelime için gereksiz, hız kazandırır
102
-
103
- # Whisper'ın "Emin değilim" deyip susmasını engellemek için filtreleri kapatıyoruz:
104
- no_speech_threshold=0.95, # Sessizlik eşiğini yükselt
105
- log_prob_threshold=None, # Düşük olasılıklı tahminleri de kabul et (Silme)
106
- compression_ratio_threshold=None, # Tekrar eden bozuk sesleri de al
107
- temperature=0 # Yaratıcılığı kapat, en net duyduğunu ver
108
  )
 
109
 
110
- # Generator'dan metni al
111
- algilanan_metin = " ".join([s.text for s in segments]).strip()
112
-
113
- # Noktalama temizliği
114
- algilanan_metin = algilanan_metin.replace(".", "").replace("?", "").replace("!", "")
115
-
116
- # 4. Karşılaştırma ve Raporlama
117
- sonuc = kelime_analizi_yap(hedef_kelime, algilanan_metin)
118
-
 
 
 
 
 
119
  return {
120
  "hedef_kelime": hedef_kelime,
121
- "algilanan_metin": algilanan_metin,
122
- "analiz_sonucu": sonuc
 
 
 
 
123
  }
124
 
125
  except Exception as e:
126
- return {"hata": str(e)}
127
 
128
  finally:
129
- # Geçici dosyayı temizle
130
  if os.path.exists(temp_filename):
131
- os.remove(temp_filename)
132
-
133
- @app.get("/")
134
- def root():
135
- return {"durum": "MnemAI Sunucusu Calisiyor"}
 
1
+ from fastapi import FastAPI, UploadFile, File, Form
2
  from faster_whisper import WhisperModel
3
  from phonology_engine import FonolojikVaryasyonMotoru
 
 
4
  import shutil
5
+ import os
6
  import uuid
7
+ import difflib
8
 
9
+ app = FastAPI()
10
 
11
+ # --- MODELLERİ YÜKLEME ---
12
+ print("⏳ Modeller yükleniyor (Lütfen bekleyin)...")
 
 
 
13
 
14
+ # 1. Uygulama Modeli (Small - Hızlı ve Manipüle Edilmiş)
15
+ model_small = WhisperModel("small", device="cpu", compute_type="int8")
 
 
 
16
 
17
+ # 2. Kontrol Modeli (Large v2 - Yavaş ve Saf)
18
+ model_large = WhisperModel("large-v2", device="cpu", compute_type="int8")
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ motor = FonolojikVaryasyonMotoru()
21
+ print("✅ İki model de RAM'e yüklendi ve hazır!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ # --- YARDIMCI FONKSİYON ---
24
+ def kelime_analizi_yap(hedef, gelen):
25
+ matcher = difflib.SequenceMatcher(None, hedef.lower(), gelen.lower())
26
  skor = int(matcher.ratio() * 100)
27
+ durum = "basarili" if skor >= 80 else "hatali"
28
+ return {"skor": skor, "durum": durum}
 
 
 
 
 
 
 
 
 
29
 
30
+ # --- API ENDPOINT ---
31
  @app.post("/analiz")
32
+ async def analiz(
33
  file: UploadFile = File(...),
34
  hedef_kelime: str = Form(...)
35
  ):
36
+ # Geçici dosya ismi
 
 
 
 
 
 
 
37
  temp_filename = f"temp_{uuid.uuid4()}.wav"
38
 
39
+ # Dosyayı diske kaydet
40
+ with open(temp_filename, "wb") as buffer:
41
+ shutil.copyfileobj(file.file, buffer)
42
+
43
  try:
44
+ # --- ADIM 1: SMALL MODEL (PROMPTLU) ---
45
+ # Hedef kelimeye göre varyasyonları üret
46
+ varyasyonlar = motor.varyasyonlari_uret(hedef_kelime)
47
+ prompt_metni = f"Şu kelimelerden birini seç: {', '.join(varyasyonlar)}"
48
+
49
+ segments_small, _ = model_small.transcribe(
 
 
 
50
  temp_filename,
51
  language="tr",
52
+ initial_prompt=prompt_metni, # <-- Müdahale var
53
+ beam_size=1, # Hızlı olsun
54
+ best_of=1,
55
+ vad_filter=False
 
 
 
 
 
 
 
 
56
  )
57
+ small_sonuc = " ".join([s.text for s in segments_small]).strip()
58
 
59
+ # --- ADIM 2: LARGE MODEL (SAF/PROMPTSUZ) ---
60
+ # Burada modele hiçbir ipucu vermiyoruz.
61
+ segments_large, _ = model_large.transcribe(
62
+ temp_filename,
63
+ language="tr",
64
+ beam_size=5, # Kaliteli olsun (Biraz yavaşlar)
65
+ vad_filter=False
66
+ )
67
+ large_sonuc = " ".join([s.text for s in segments_large]).strip()
68
+
69
+ # --- ADIM 3: SONUÇLARI KARŞILAŞTIR ---
70
+ analiz_sonucu = kelime_analizi_yap(hedef_kelime, small_sonuc)
71
+
72
+ # JSON DÖNÜŞÜ
73
  return {
74
  "hedef_kelime": hedef_kelime,
75
+ "analiz": analiz_sonucu,
76
+ "modeller": {
77
+ "small_model_tahmini": small_sonuc, # Uygulamanın kullandığı
78
+ "large_model_tahmini": large_sonuc, # Gerçekte duyulan (Saf)
79
+ "varyasyonlar_prompt": varyasyonlar # Modele verdiğimiz ipuçları
80
+ }
81
  }
82
 
83
  except Exception as e:
84
+ return {"error": str(e)}
85
 
86
  finally:
87
+ # İşlem bitince dosyayı sil
88
  if os.path.exists(temp_filename):
89
+ os.remove(temp_filename)
 
 
 
 
phonology_engine.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import itertools
2
 
3
  class FonolojikVaryasyonMotoru:
@@ -25,7 +26,9 @@ class FonolojikVaryasyonMotoru:
25
  'ğ': ['ğ', 'y', ''],
26
  'h': ['h', '']
27
  }
28
-
 
 
29
  def varyasyonlari_uret(self, hedef_kelime, max_limit=150):
30
  """
31
  Hedef kelimenin olası yanlış telaffuz varyasyonlarını üretir.
 
1
+ from functools import lru_cache
2
  import itertools
3
 
4
  class FonolojikVaryasyonMotoru:
 
26
  'ğ': ['ğ', 'y', ''],
27
  'h': ['h', '']
28
  }
29
+
30
+ # Son 100 kelimenin varyasyonlarını hafızada tut
31
+ @lru_cache(maxsize=100)
32
  def varyasyonlari_uret(self, hedef_kelime, max_limit=150):
33
  """
34
  Hedef kelimenin olası yanlış telaffuz varyasyonlarını üretir.