Spaces:
Sleeping
Sleeping
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)
|