# ============================================================ # 📄 الملف: scripts/build_embeddings.py # 🎯 الغرض: بناء وحفظ الـ embeddings للنماذج الثلاثة (يُشغّل مرة واحدة). # # يقابل خلية "بناء وحفظ Embeddings" في النوتبوك. لكل نموذج: # 1. يحمّل النموذج. # 2. يرمّز عمود combined_text إلى متجهات. # 3. يحفظها في data/embeddings/{model_key}.npy # # إذا كان ملف الـ embeddings موجودًا مسبقًا، يتخطّاه (توفيرًا للوقت). # لإعادة البناء، احذف الملف المعني من data/embeddings/. # # ⚠️ مهم: شغّل scripts/prepare_data.py أولًا. # # طريقة التشغيل (من داخل مجلد backend): # python scripts/build_embeddings.py # ============================================================ import sys from pathlib import Path import numpy as np import pandas as pd from sentence_transformers import SentenceTransformer sys.path.append(str(Path(__file__).resolve().parent.parent)) import config def main(): if not config.PROCESSED_DATA_PATH.exists(): raise FileNotFoundError( "❌ البيانات المنظّفة غير موجودة.\n" "شغّل أولًا: python scripts/prepare_data.py" ) df = pd.read_csv(config.PROCESSED_DATA_PATH) texts = df["combined_text"].fillna("").tolist() print(f"📊 عدد النصوص: {len(texts)}") print(f"🖥️ الجهاز: {config.DEVICE.upper()}\n") config.EMBEDDINGS_DIR.mkdir(parents=True, exist_ok=True) for cfg in config.MODELS: out_path = config.embedding_path(cfg["key"]) if out_path.exists(): print(f"♻️ موجود مسبقًا، تخطّي: {cfg['display_name']}") continue print(f"⏳ بناء embeddings لـ: {cfg['display_name']} ...") model = SentenceTransformer(cfg["hf_id"], device=config.DEVICE) # نماذج e5 تتطلّب بادئة "passage:" للمستندات prepared = [f"passage: {t}" for t in texts] if cfg["use_prefix"] else texts embeds = model.encode( prepared, normalize_embeddings=True, show_progress_bar=True, batch_size=config.BATCH_SIZE, convert_to_numpy=True, ) np.save(out_path, embeds) print(f"✅ حُفظ: {out_path} — الشكل: {embeds.shape}\n") print("🎉 تم بناء كل الـ embeddings بنجاح") if __name__ == "__main__": main()