File size: 9,908 Bytes
dfdd9cb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/usr/bin/env python3
"""
اختبار مبسط لمعالج النصوص بدون تحميل نموذج Whisper
"""

import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

import logging
from collections import Counter
import nltk
from nltk.tokenize import word_tokenize
import textdistance
from diff_match_patch import diff_match_patch
import Levenshtein as lev
import re

# إعداد التسجيل
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# تحميل بيانات NLTK المطلوبة
try:
    nltk.data.find('tokenizers/punkt')
except LookupError:
    nltk.download('punkt')

try:
    nltk.data.find('tokenizers/punkt_tab')
except LookupError:
    nltk.download('punkt_tab')

class SimpleTextProcessor:
    """
    معالج نصوص مبسط للاختبار بدون نموذج Whisper
    """
    
    def __init__(self):
        self.dictionary = {}
    
    def create_dictionary(self, texts):
        """إنشاء قاموس من النصوص المرجعية"""
        words = []
        for text in texts:
            words.extend(word_tokenize(text))
        
        word_counts = Counter(words)
        self.dictionary = word_counts
        
        logger.info(f"تم إنشاء قاموس يحتوي على {len(word_counts)} كلمة")
        return word_counts
    
    def dl_distance(self, word1, word2):
        """حساب مسافة Damerau-Levenshtein بين كلمتين"""
        return textdistance.damerau_levenshtein(word1, word2)
    
    def find_closest_words(self, misspelled_word, max_distance=2):
        """البحث عن أقرب الكلمات في القاموس"""
        candidates = []
        
        for word, freq in self.dictionary.items():
            if word in ['.', '،', '(', ')', ':', '؟', '!']:  # تجاهل علامات الترقيم
                continue
                
            distance = self.dl_distance(misspelled_word, word)
            if distance <= max_distance:
                candidates.append((word, freq, distance))
        
        # ترتيب حسب: المسافة، ثم التكرار، ثم التقارب في الطول، ثم نفس الحرف الأول
        candidates.sort(key=lambda x: (
            x[2],                                           # أقل مسافة أولاً
            -x[1],                                          # أكثر تكراراً
            abs(len(x[0]) - len(misspelled_word)),          # تقارب الطول
            x[0][0] != misspelled_word[0] if x[0] and misspelled_word else False  # يبدأ بنفس الحرف
        ))
        
        return candidates
    
    def correct_text(self, text, max_distance=3, threshold_freq=1):
        """تصحيح النص باستخدام القاموس المرجعي"""
        if not self.dictionary:
            logger.warning("لم يتم إنشاء قاموس مرجعي بعد")
            return text, []
        
        words = word_tokenize(text)
        corrected_words = []
        corrections = []
        
        for word in words:
            suggestions = self.find_closest_words(word, max_distance)
            
            if suggestions:
                best_suggestion, freq, dist = suggestions[0]
                
                if best_suggestion != word and freq > threshold_freq:
                    corrected_words.append(best_suggestion)
                    corrections.append({
                        "original": word,
                        "corrected": best_suggestion,
                        "frequency": freq,
                        "distance": dist
                    })
                else:
                    corrected_words.append(word)
            else:
                corrected_words.append(word)
        
        corrected_text = " ".join(corrected_words)
        
        # تنظيف المسافات الزائدة حول علامات الترقيم
        corrected_text = re.sub(r'\s+([.،؟!])', r'\1', corrected_text)
        
        logger.info(f"تم تصحيح {len(corrections)} كلمة")
        return corrected_text, corrections
    
    def compare_texts(self, reference_text, transcribed_text):
        """مقارنة النصوص وإظهار الاختلافات"""
        # معالجة أولية للنصوص
        ref_processed = re.sub(r'[.،؟!]', '', reference_text).lower().strip()
        trans_processed = re.sub(r'[.،؟!]', '', transcribed_text).lower().strip()
        
        # حساب مسافة Levenshtein للكلمات (WER)
        ref_words = ref_processed.split()
        trans_words = trans_processed.split()
        
        wer = lev.distance(ref_words, trans_words) / len(ref_words) if ref_words else 0
        
        # حساب مسافة Levenshtein للأحرف (CER)
        cer = lev.distance(ref_processed, trans_processed) / len(ref_processed) if ref_processed else 0
        
        # إنشاء HTML للاختلافات
        dmp = diff_match_patch()
        diffs = dmp.diff_main(ref_processed, trans_processed)
        dmp.diff_cleanupSemantic(diffs)
        html_diff = dmp.diff_prettyHtml(diffs)
        
        return {
            "wer": wer,
            "cer": cer,
            "wer_percentage": f"{wer:.2%}",
            "cer_percentage": f"{cer:.2%}",
            "html_diff": html_diff,
            "reference_words": len(ref_words),
            "transcribed_words": len(trans_words),
            "word_differences": abs(len(ref_words) - len(trans_words))
        }

def test_text_correction():
    """اختبار تصحيح النصوص"""
    logger.info("🧪 بدء اختبار تصحيح النصوص")
    
    # إنشاء معالج النصوص
    processor = SimpleTextProcessor()
    
    # نصوص مرجعية لبناء القاموس
    reference_texts = [
        "يهتز غشاء الطبل تنتقل عظيمات السمع الاهتزازات إلى النافذة البيضية",
        "يهتز غشاء النافذة البيضية يهتز اللمف الخارجي في القناة الدهليزية",
        "يهتز غشاء رايسنر تنتقل الاهتزازات إلى اللمف الداخلي في القناة القوقعية",
        "اهتزاز الغشاء القاعدي بشكل موجي"
    ]
    
    # إنشاء القاموس
    dictionary = processor.create_dictionary(reference_texts)
    logger.info(f"تم إنشاء قاموس يحتوي على {len(dictionary)} كلمة")
    
    # نص للاختبار (يحتوي على أخطاء)
    test_text = "يحتاز غشاء الطبل تنتقل عظيمات السماء الاحتزازات إلى النافذة البيضية يحتاز الملف الخارجي"
    
    logger.info(f"النص الأصلي: {test_text}")
    
    # تصحيح النص
    corrected_text, corrections = processor.correct_text(test_text, max_distance=3, threshold_freq=1)
    
    logger.info(f"النص المصحح: {corrected_text}")
    logger.info(f"عدد التصحيحات: {len(corrections)}")
    
    for correction in corrections:
        logger.info(f"  تصحيح: '{correction['original']}' → '{correction['corrected']}' "
                   f"(تكرار: {correction['frequency']}, مسافة: {correction['distance']})")
    
    return corrected_text, corrections

def test_text_comparison():
    """اختبار مقارنة النصوص"""
    logger.info("🧪 بدء اختبار مقارنة النصوص")
    
    processor = SimpleTextProcessor()
    
    # نصوص للمقارنة
    reference_text = "يهتز غشاء الطبل تنتقل عظيمات السمع الاهتزازات إلى النافذة البيضية"
    transcribed_text = "يحتاز غشاء الطبل تنتقل عظيمات السماء الاحتزازات إلى النافذة البيضية"
    
    # مقارنة النصوص
    comparison_result = processor.compare_texts(reference_text, transcribed_text)
    
    logger.info(f"معدل خطأ الكلمات (WER): {comparison_result['wer_percentage']}")
    logger.info(f"معدل خطأ الأحرف (CER): {comparison_result['cer_percentage']}")
    logger.info(f"عدد كلمات النص المرجعي: {comparison_result['reference_words']}")
    logger.info(f"عدد كلمات النص المستخرج: {comparison_result['transcribed_words']}")
    logger.info(f"فرق عدد الكلمات: {comparison_result['word_differences']}")
    
    return comparison_result

def main():
    """الدالة الرئيسية للاختبار"""
    logger.info("🚀 بدء اختبارات معالج النصوص المبسط")
    
    try:
        # اختبار تصحيح النصوص
        corrected_text, corrections = test_text_correction()
        
        # اختبار مقارنة النصوص
        comparison_result = test_text_comparison()
        
        logger.info("✅ تم إنجاز جميع الاختبارات بنجاح!")
        
        # عرض ملخص النتائج
        print("\n" + "="*60)
        print("📊 ملخص نتائج الاختبارات")
        print("="*60)
        print(f"عدد التصحيحات المطبقة: {len(corrections)}")
        print(f"معدل خطأ الكلمات: {comparison_result['wer_percentage']}")
        print(f"معدل خطأ الأحرف: {comparison_result['cer_percentage']}")
        print("="*60)
        
        return True
        
    except Exception as e:
        logger.error(f"❌ فشل في الاختبارات: {str(e)}")
        return False

if __name__ == "__main__":
    success = main()
    if success:
        print("✅ جميع الاختبارات نجحت!")
    else:
        print("❌ فشلت بعض الاختبارات!")
        sys.exit(1)