File size: 4,852 Bytes
4a920c4
4dd6144
4a920c4
 
 
4dd6144
 
 
 
3ae62ae
 
 
4dd6144
3ae62ae
 
4dd6144
 
4a920c4
 
 
4dd6144
3ae62ae
4a920c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
abccfa9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4dd6144
 
 
 
 
 
 
 
4a920c4
 
 
 
 
4dd6144
4a920c4
 
 
 
 
 
 
 
4dd6144
 
4a920c4
 
4dd6144
4a920c4
 
 
4dd6144
3ae62ae
4a920c4
3ae62ae
4a920c4
 
3ae62ae
4a920c4
 
 
 
4dd6144
 
 
 
dab9648
abccfa9
 
4dd6144
4a920c4
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
سكربت تجهيز بيانات المعجم: يحوّل ملف خام (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()