Spaces:
Sleeping
Sleeping
| """ | |
| سكربت تجهيز بيانات المعجم: يحوّل ملف خام (raw_lexicon.csv) إلى الصيغة الموحَّدة | |
| data/lexicon_source.json التي يستخدمها scripts/build_embeddings.py. | |
| المدخل المتوقع: data/raw_lexicon.csv | |
| أعمدة الملف: _id, sense_id, lemma, stem, definition, example, translation, pos_label | |
| lemma -> الكلمة العربية (مُشكَّلة) | |
| definition -> نص التعريف (مُشكَّل) | |
| stem -> نص JSON لمصفوفة بعنصر واحد أو لا شيء، مثل '["ش ر ب"]' أو '[null]' | |
| المخرج: data/lexicon_source.json | |
| [ | |
| {"word": "...", "definition": "...", "stem": "..." | null}, | |
| ... | |
| ] | |
| word وdefinition يُحفظان بتشكيلهما الكامل كما في المصدر؛ إزالة التشكيل | |
| تتم فقط عند حساب متجهات الـembedding في build_embeddings.py، وليس هنا. | |
| ملاحظات التنظيف المطبَّقة: | |
| - إزالة المسافات الزائدة من بداية/نهاية النصوص | |
| - تجاهل الصفوف الفارغة (lemma أو definition خاليان) | |
| - إزالة التكرارات المتطابقة تماماً (نفس الكلمة + نفس التعريف) | |
| الاستخدام: | |
| python -m scripts.prepare_data | |
| """ | |
| import csv | |
| import json | |
| import sys | |
| from pathlib import Path | |
| sys.path.append(str(Path(__file__).resolve().parent.parent)) | |
| from app import config # noqa: E402 | |
| def get_pos_group(pos_label: str) -> str: | |
| if not pos_label or str(pos_label).strip() in ("", "nan", "غير معروف"): | |
| return "غير معروف" | |
| pos = str(pos_label).strip() | |
| NOUN = { | |
| "اسم", "أداة", "اسم آلة", "اسم جنس", "اسم ذات", | |
| "اسم زمان", "اسم مبهم", "اسم مرة", "اسم معنى", | |
| "اسم مكان", "اسم هيئة", | |
| } | |
| VERB = { | |
| "فعل", "فعل لازم", "فعل متعدي", | |
| "أفعل تفضيل", "انفعال تعجب", "انفعال ذم", | |
| "انفعال صوتي", "انفعال فعلي", "انفعال مدح", | |
| } | |
| ADJ = { | |
| "صفة", "صفة فاعل", "صفة مشبهة", | |
| "صفة مفعول", "صيغة مبالغة", "منسوب", | |
| } | |
| PRON = {"ضمير إشارة", "ضمير شخصي", "ضمير موصول"} | |
| ADV = {"ظرف", "ظرف زمان", "ظرف مكان"} | |
| if pos in NOUN: return "اسم" | |
| if pos in VERB: return "فعل" | |
| if pos in ADJ: return "صفة" | |
| if pos in PRON: return "ضمير" | |
| if pos in ADV: return "ظرف" | |
| return "غير معروف" | |
| def parse_stem(raw_stem: str) -> str | None: | |
| try: | |
| items = json.loads(raw_stem) | |
| except (json.JSONDecodeError, TypeError): | |
| return None | |
| return items[0] if items else None | |
| def main() -> None: | |
| raw_path = config.DATA_DIR / "raw_lexicon.csv" | |
| if not raw_path.exists(): | |
| raise FileNotFoundError( | |
| f"الملف الخام غير موجود: {raw_path}\n" | |
| "ضعي ملف raw_lexicon.csv بأعمدة: lemma, stem, definition" | |
| ) | |
| seen: set[tuple[str, str]] = set() | |
| lexicon: list[dict] = [] | |
| with open(raw_path, "r", encoding="utf-8") as f: | |
| reader = csv.DictReader(f) | |
| required = {"lemma", "stem", "definition"} | |
| if not required.issubset(reader.fieldnames or []): | |
| raise ValueError( | |
| f"أعمدة الملف غير صحيحة: {reader.fieldnames}\n" | |
| f"يجب أن يحتوي الملف على الأعمدة: {required}" | |
| ) | |
| for row in reader: | |
| word = (row.get("lemma") or "").strip() | |
| definition = (row.get("definition") or "").strip() | |
| if not word or not definition: | |
| continue | |
| key = (word, definition) | |
| if key in seen: | |
| continue | |
| seen.add(key) | |
| lexicon.append({ | |
| "word": word, | |
| "definition": definition, | |
| "stem": parse_stem(row.get("stem") or ""), | |
| "sense_id": (row.get("sense_id") or "").strip(), | |
| "pos_label": (row.get("pos_label") or "").strip(), | |
| "pos_group": get_pos_group(row.get("pos_label") or ""), | |
| }) | |
| if not lexicon: | |
| raise ValueError("لم يتم العثور على أي صفوف صالحة في الملف الخام") | |
| output_path = config.DATA_DIR / "lexicon_source.json" | |
| with open(output_path, "w", encoding="utf-8") as f: | |
| json.dump(lexicon, f, ensure_ascii=False, indent=2) | |
| print(f"تم حفظ {len(lexicon)} عنصر في: {output_path}") | |
| print("اكتمل التجهيز بنجاح ✅") | |
| if __name__ == "__main__": | |
| main() | |