shahdAI's picture
Upload scripts/prepare_data.py with huggingface_hub
abccfa9 verified
Raw
History Blame Contribute Delete
4.85 kB
"""
سكربت تجهيز بيانات المعجم: يحوّل ملف خام (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()