File size: 2,614 Bytes
cdc6248
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# ============================================================
# 📄 الملف: 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()