Spaces:
Running
Running
Upload advanced_term_correction.py
Browse files- advanced_term_correction.py +154 -0
advanced_term_correction.py
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
import difflib
|
3 |
+
from typing import Dict, List, Tuple, Any
|
4 |
+
import spacy
|
5 |
+
from fuzzywuzzy import fuzz
|
6 |
+
from medical_terms import load_turkish_medical_terms # .medical_terms -> medical_terms
|
7 |
+
|
8 |
+
# SpaCy modelini yükle (Türkçe model kurulu olmalı)
|
9 |
+
# pip install https://github.com/explosion/spacy-models/releases/download/tr_core_news_md-3.2.0/tr_core_news_md-3.2.0.tar.gz
|
10 |
+
try:
|
11 |
+
nlp = spacy.load("tr_core_news_md")
|
12 |
+
except:
|
13 |
+
# Eğer model yüklü değilse
|
14 |
+
print("Türkçe SpaCy modeli yüklü değil. Yüklemek için: pip install https://github.com/explosion/spacy-models/releases/download/tr_core_news_md-3.2.0/tr_core_news_md-3.2.0.tar.gz")
|
15 |
+
nlp = spacy.blank("tr")
|
16 |
+
|
17 |
+
try:
|
18 |
+
import python_Levenshtein # Opsiyonel hızlandırma
|
19 |
+
except ImportError:
|
20 |
+
pass # Olmasa da çalışır
|
21 |
+
|
22 |
+
class MedicalTermCorrector:
|
23 |
+
def __init__(self, medical_terms: Dict[str, str], threshold: int = 85):
|
24 |
+
"""
|
25 |
+
Tıbbi terimleri düzeltmek için gelişmiş bir düzeltici
|
26 |
+
|
27 |
+
Args:
|
28 |
+
medical_terms: Tıbbi terimler sözlüğü {yanlış_terim: doğru_terim}
|
29 |
+
threshold: Bulanık eşleşme için eşik değeri (0-100)
|
30 |
+
"""
|
31 |
+
self.medical_terms = medical_terms
|
32 |
+
self.threshold = threshold
|
33 |
+
|
34 |
+
# Terimler için regex kalıpları oluştur
|
35 |
+
self.regex_patterns = self._build_regex_patterns()
|
36 |
+
|
37 |
+
# Terim varyasyonları için indeks oluştur
|
38 |
+
self.term_variations = self._build_term_variations()
|
39 |
+
|
40 |
+
def _build_regex_patterns(self) -> Dict[str, re.Pattern]:
|
41 |
+
"""Tıbbi terimler için regex kalıpları oluşturur"""
|
42 |
+
patterns = {}
|
43 |
+
for term in self.medical_terms.keys():
|
44 |
+
# Basit varyasyon kalıpları: boşluk, tire, kesme işareti varyasyonları
|
45 |
+
pattern_str = term.replace(" ", r"\s*")
|
46 |
+
pattern_str = pattern_str.replace("-", r"[-\s]?")
|
47 |
+
# Türkçe karakter varyasyonları
|
48 |
+
pattern_str = re.sub(r'i', r'[iIıİ]', pattern_str)
|
49 |
+
pattern_str = re.sub(r'ü', r'[üÜuU]', pattern_str)
|
50 |
+
pattern_str = re.sub(r'ö', r'[öÖoO]', pattern_str)
|
51 |
+
pattern_str = re.sub(r'ç', r'[çÇcC]', pattern_str)
|
52 |
+
pattern_str = re.sub(r'ş', r'[şŞsS]', pattern_str)
|
53 |
+
pattern_str = re.sub(r'ğ', r'[ğĞgG]', pattern_str)
|
54 |
+
# Daha fazla esneklik için kelime sınırları
|
55 |
+
pattern = re.compile(r'\b' + pattern_str + r'\b', re.IGNORECASE)
|
56 |
+
patterns[term] = pattern
|
57 |
+
return patterns
|
58 |
+
|
59 |
+
def _build_term_variations(self) -> Dict[str, List[str]]:
|
60 |
+
"""Olası terim varyasyonları oluşturur"""
|
61 |
+
variations = {}
|
62 |
+
for term in self.medical_terms.keys():
|
63 |
+
term_vars = [term]
|
64 |
+
# Boşluk/tire varyasyonları
|
65 |
+
if " " in term:
|
66 |
+
term_vars.append(term.replace(" ", "-"))
|
67 |
+
term_vars.append(term.replace(" ", ""))
|
68 |
+
if "-" in term:
|
69 |
+
term_vars.append(term.replace("-", " "))
|
70 |
+
term_vars.append(term.replace("-", ""))
|
71 |
+
|
72 |
+
# Küçük/büyük harf varyasyonları
|
73 |
+
term_vars.append(term.lower())
|
74 |
+
term_vars.append(term.upper())
|
75 |
+
term_vars.append(term.capitalize())
|
76 |
+
|
77 |
+
variations[term] = list(set(term_vars)) # Benzersiz varyasyonlar
|
78 |
+
return variations
|
79 |
+
|
80 |
+
def find_term_candidates(self, text: str) -> List[Tuple[str, str, float]]:
|
81 |
+
"""
|
82 |
+
Metindeki olası tıbbi terim adaylarını bulur
|
83 |
+
|
84 |
+
Returns:
|
85 |
+
[(bulunan_terim, doğru_terim, benzerlik_skoru)]
|
86 |
+
"""
|
87 |
+
candidates = []
|
88 |
+
|
89 |
+
# 1. Regex ile kesin eşleşmeleri bul
|
90 |
+
for term, pattern in self.regex_patterns.items():
|
91 |
+
matches = pattern.finditer(text)
|
92 |
+
for match in matches:
|
93 |
+
correct_term = self.medical_terms[term]
|
94 |
+
candidates.append((match.group(), correct_term, 100))
|
95 |
+
|
96 |
+
# 2. NLP analizi ile tıbbi terimleri bul
|
97 |
+
doc = nlp(text)
|
98 |
+
for ent in doc.ents:
|
99 |
+
# Eğer varlık sağlık ile ilgiliyse veya sınıflandırılamadıysa
|
100 |
+
if ent.label_ in ["DISEASE", "BODY", "CHEMICAL", "MISC", ""]:
|
101 |
+
ent_text = ent.text.lower()
|
102 |
+
best_match = None
|
103 |
+
best_score = 0
|
104 |
+
|
105 |
+
# Sözlükteki terimlerle karşılaştır
|
106 |
+
for term, correct_term in self.medical_terms.items():
|
107 |
+
# Ana terim ve varyasyonlarla karşılaştır
|
108 |
+
for term_var in self.term_variations.get(term, [term]):
|
109 |
+
score = fuzz.ratio(ent_text, term_var.lower())
|
110 |
+
if score > best_score and score >= self.threshold:
|
111 |
+
best_score = score
|
112 |
+
best_match = correct_term
|
113 |
+
|
114 |
+
if best_match:
|
115 |
+
candidates.append((ent.text, best_match, best_score))
|
116 |
+
|
117 |
+
# Eğer SpaCy modeli basit ise farklı bir yol izleyelim
|
118 |
+
if isinstance(nlp, spacy.blank):
|
119 |
+
# Basit kelime tabanlı analiz yap
|
120 |
+
words = text.split()
|
121 |
+
for word in words:
|
122 |
+
# SpaCy'ye güvenmeden basit tıbbi terim kontrolü
|
123 |
+
for term, correct_term in self.medical_terms.items():
|
124 |
+
score = fuzz.ratio(word.lower(), term.lower())
|
125 |
+
if score >= self.threshold:
|
126 |
+
candidates.append((word, correct_term, score))
|
127 |
+
|
128 |
+
# Tekrarlananları kaldır, en yüksek skorları tut
|
129 |
+
unique_candidates = {}
|
130 |
+
for found, correct, score in candidates:
|
131 |
+
if found not in unique_candidates or score > unique_candidates[found][1]:
|
132 |
+
unique_candidates[found] = (correct, score)
|
133 |
+
|
134 |
+
return [(found, correct, score) for found, (correct, score) in unique_candidates.items()]
|
135 |
+
|
136 |
+
def correct_text(self, text: str) -> str:
|
137 |
+
"""Metindeki tıbbi terimleri düzeltir"""
|
138 |
+
# Terim adaylarını bul
|
139 |
+
candidates = self.find_term_candidates(text)
|
140 |
+
|
141 |
+
# En uzun terimlerden başlayarak değiştir (kısa terimlerin parçası olan uzun terimleri önceliklendir)
|
142 |
+
candidates.sort(key=lambda x: len(x[0]), reverse=True)
|
143 |
+
|
144 |
+
corrected_text = text
|
145 |
+
for found, correct, score in candidates:
|
146 |
+
# Eşleşme %100 değilse, orijinal metinde tam olarak nerede olduğunu bul
|
147 |
+
if score < 100:
|
148 |
+
# Kelimenin sınırlarını koru
|
149 |
+
corrected_text = re.sub(r'\b' + re.escape(found) + r'\b', correct, corrected_text)
|
150 |
+
else:
|
151 |
+
# Tam eşleşme durumu
|
152 |
+
corrected_text = corrected_text.replace(found, correct)
|
153 |
+
|
154 |
+
return corrected_text
|