Spaces:
Sleeping
Sleeping
shahad altamimi commited on
Commit ·
f53136a
1
Parent(s): 1c48a5d
update2
Browse files- .gitignore +4 -0
- README.md +27 -0
- requirements.txt +15 -0
- reverse-dictionary/README_STREAMLIT_CLOUD.md +86 -0
- reverse-dictionary/backend/app/assets.py +73 -0
- reverse-dictionary/backend/app/models_loader.py +3 -1
- reverse-dictionary/backend/requirements.txt +1 -0
- reverse-dictionary/backend/scripts/upload_assets.py +61 -0
- reverse-dictionary/frontend/streamlit_app.py +14 -0
.gitignore
CHANGED
|
@@ -225,3 +225,7 @@ __marimo__/
|
|
| 225 |
**/.streamlit/secrets.toml
|
| 226 |
# قاعدة بيانات SQLite المحلية للتجربة
|
| 227 |
**/data/eval_local.db
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
**/.streamlit/secrets.toml
|
| 226 |
# قاعدة بيانات SQLite المحلية للتجربة
|
| 227 |
**/data/eval_local.db
|
| 228 |
+
|
| 229 |
+
# النماذج المُكمَّمة (ONNX) والنسخة الاحتياطية للـ embeddings — كبيرة، تُبنى محليًا
|
| 230 |
+
**/models_onnx/
|
| 231 |
+
**/data/embeddings_backup_fp32/
|
README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: القاموس العكسي للعربية
|
| 3 |
+
emoji: 🔍
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: gray
|
| 6 |
+
sdk: streamlit
|
| 7 |
+
sdk_version: 1.40.0
|
| 8 |
+
app_file: reverse-dictionary/frontend/streamlit_app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
# 🔍 القاموس العكسي للعربية — تقييم البحث الدلالي
|
| 13 |
+
|
| 14 |
+
تطبيق Streamlit يقارن 3 نماذج Embedding عربية: تُدخل تعريفًا، فتظهر أقرب
|
| 15 |
+
الكلمات في كل نموذج، ويقيّمها المستخدمون (صح/خطأ لكل كلمة)، وتُجمَّع
|
| 16 |
+
التقييمات في قاعدة Supabase.
|
| 17 |
+
|
| 18 |
+
- النماذج مُكمَّمة (ONNX int8) لتسريع التشغيل وتقليل الذاكرة على CPU.
|
| 19 |
+
- الملفات الكبيرة (النماذج + الـ embeddings) تُنزَّل تلقائيًا من Hugging Face Hub.
|
| 20 |
+
|
| 21 |
+
## النشر
|
| 22 |
+
راجع [README_STREAMLIT_CLOUD.md](reverse-dictionary/README_STREAMLIT_CLOUD.md)
|
| 23 |
+
و [README_DEPLOY.md](reverse-dictionary/README_DEPLOY.md).
|
| 24 |
+
|
| 25 |
+
## الأسرار المطلوبة (Space settings → Secrets)
|
| 26 |
+
- `HF_DATA_REPO` — مستودع HF الذي يحوي النماذج والـ embeddings.
|
| 27 |
+
- `DATABASE_URL` — رابط Supabase (Postgres pooler).
|
requirements.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ============================================================
|
| 2 |
+
# 📄 requirements.txt (جذر المستودع) — يقرأه Streamlit Cloud / HF Spaces.
|
| 3 |
+
# نسخة مطابقة لـ reverse-dictionary/backend/requirements.txt
|
| 4 |
+
# ============================================================
|
| 5 |
+
|
| 6 |
+
streamlit
|
| 7 |
+
python-dotenv
|
| 8 |
+
pandas
|
| 9 |
+
numpy
|
| 10 |
+
scikit-learn
|
| 11 |
+
sentence-transformers
|
| 12 |
+
torch
|
| 13 |
+
sqlalchemy
|
| 14 |
+
psycopg[binary]
|
| 15 |
+
huggingface_hub
|
reverse-dictionary/README_STREAMLIT_CLOUD.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚀 النشر على Streamlit Community Cloud (مجاني)
|
| 2 |
+
|
| 3 |
+
التطبيق ينشر برابط عام. الملفات الكبيرة (النماذج + الـ embeddings) تُخزَّن على
|
| 4 |
+
**Hugging Face Hub** (لأن GitHub المجاني يسمح بـ 1GB فقط)، والكود على **GitHub**،
|
| 5 |
+
والتقييمات في **Supabase**.
|
| 6 |
+
|
| 7 |
+
```
|
| 8 |
+
GitHub (الكود) → Streamlit Cloud (يشغّل التطبيق)
|
| 9 |
+
│
|
| 10 |
+
├─ ينزّل النماذج/الـ embeddings من Hugging Face Hub
|
| 11 |
+
└─ يحفظ التقييمات في Supabase
|
| 12 |
+
```
|
| 13 |
+
|
| 14 |
+
---
|
| 15 |
+
|
| 16 |
+
## 1) رفع الملفات الكبيرة إلى Hugging Face Hub
|
| 17 |
+
|
| 18 |
+
1. أنشئي حساب على <https://huggingface.co> (مجاني).
|
| 19 |
+
2. أنشئي **Access Token**: الصورة الشخصية → Settings → Access Tokens → New token
|
| 20 |
+
(نوع **Write**). انسخيه.
|
| 21 |
+
3. في الطرفية (من مجلد `reverse-dictionary/backend`):
|
| 22 |
+
```bash
|
| 23 |
+
export HF_TOKEN=hf_xxxxxxxx # التوكن من الخطوة 2
|
| 24 |
+
export HF_DATA_REPO="USERNAME/reverse-dictionary-assets" # بدّلي USERNAME
|
| 25 |
+
.venv/bin/python scripts/upload_assets.py
|
| 26 |
+
```
|
| 27 |
+
4. بعد الرفع: افتحي المستودع على HF → **Settings** → اجعليه **Public**.
|
| 28 |
+
|
| 29 |
+
> هذا يرفع ~1.7GB مرة واحدة. المستودع العام لا يحتاج توكن عند التنزيل.
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## 2) إعداد Supabase (لتخزين التقييمات)
|
| 34 |
+
|
| 35 |
+
اتبعي الخطوات في [README_DEPLOY.md](README_DEPLOY.md) قسم «إعداد Supabase»
|
| 36 |
+
للحصول على `DATABASE_URL` (نوع pooler، يبدأ بـ `postgresql://`).
|
| 37 |
+
|
| 38 |
+
---
|
| 39 |
+
|
| 40 |
+
## 3) رفع الكود على GitHub
|
| 41 |
+
|
| 42 |
+
من جذر المشروع (`semantic-search-system`):
|
| 43 |
+
```bash
|
| 44 |
+
git add -A
|
| 45 |
+
git commit -m "تجهيز للنشر على Streamlit Cloud"
|
| 46 |
+
git branch -M main
|
| 47 |
+
git remote add origin https://github.com/USERNAME/REPO.git # بدّلي
|
| 48 |
+
git push -u origin main
|
| 49 |
+
```
|
| 50 |
+
> الملفات الكبيرة مُستثناة من Git (في `.gitignore`) — لا تُرفع على GitHub.
|
| 51 |
+
|
| 52 |
+
---
|
| 53 |
+
|
| 54 |
+
## 4) النشر على Streamlit Cloud
|
| 55 |
+
|
| 56 |
+
1. ادخلي <https://share.streamlit.io> وسجّلي دخول بحساب GitHub.
|
| 57 |
+
2. **Create app** → **Deploy a public app from GitHub**.
|
| 58 |
+
3. عبّئي:
|
| 59 |
+
- **Repository:** مستودعك على GitHub.
|
| 60 |
+
- **Branch:** `main`.
|
| 61 |
+
- **Main file path:** `reverse-dictionary/frontend/streamlit_app.py`
|
| 62 |
+
- **Advanced settings → Python version:** `3.11`
|
| 63 |
+
4. في **Advanced settings → Secrets**، الصقي:
|
| 64 |
+
```toml
|
| 65 |
+
HF_DATA_REPO = "USERNAME/reverse-dictionary-assets"
|
| 66 |
+
DATABASE_URL = "postgresql://postgres.xxxx:PASSWORD@...pooler.supabase.com:6543/postgres"
|
| 67 |
+
```
|
| 68 |
+
5. **Deploy!**
|
| 69 |
+
|
| 70 |
+
> أول تشغيل بطيء: يثبّت المكتبات ثم ينزّل ~1.7GB من HF Hub. الإقلاعات اللاحقة أسرع.
|
| 71 |
+
|
| 72 |
+
---
|
| 73 |
+
|
| 74 |
+
## 5) متابعة التقييمات
|
| 75 |
+
|
| 76 |
+
من لوحة **Supabase → Table Editor → ratings** تشوفين كل التقييمات وتصدّرينها CSV.
|
| 77 |
+
|
| 78 |
+
---
|
| 79 |
+
|
| 80 |
+
## ⚠️ ملاحظات
|
| 81 |
+
- **الذاكرة:** Streamlit Cloud المجاني محدود الذاكرة. خفّفنا الاستهلاك (نماذج
|
| 82 |
+
مُكمَّمة + `mmap` للـ embeddings). لو ظهر خطأ ذاكرة (الرسالة "Oh no"/إعادة تشغيل
|
| 83 |
+
متكررة)، الحل الأأمن هو **Hugging Face Spaces** (ذاكرته 16GB) بنفس هذي الملفات.
|
| 84 |
+
- **عند تحديث الكود:** ادفعي على GitHub، و Streamlit Cloud يعيد النشر تلقائيًا.
|
| 85 |
+
- **عند تحديث النماذج/الـ embeddings:** أعيدي تشغيل `upload_assets.py`، ثم
|
| 86 |
+
أعيدي تشغيل التطبيق من لوحة Streamlit Cloud (Reboot) لإعادة التنزيل.
|
reverse-dictionary/backend/app/assets.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ============================================================
|
| 2 |
+
# 📄 الملف: app/assets.py
|
| 3 |
+
# 🎯 الغرض: تنزيل الملفات الكبيرة تلقائيًا عند النشر (Streamlit Cloud).
|
| 4 |
+
#
|
| 5 |
+
# الملفات الكبيرة (النماذج المُكمَّمة + الـ embeddings + البيانات) لا تُرفع
|
| 6 |
+
# على GitHub (تتجاوز حد 1GB). نخزّنها في مستودع Hugging Face Hub عام،
|
| 7 |
+
# والتطبيق ينزّلها أول تشغيل فقط إن لم تكن موجودة محليًا.
|
| 8 |
+
#
|
| 9 |
+
# اسم مستودع Hugging Face يُقرأ من الأسرار: st.secrets["HF_DATA_REPO"]
|
| 10 |
+
# (مثال: "username/reverse-dictionary-assets"). المستودع عام فلا يحتاج توكن.
|
| 11 |
+
#
|
| 12 |
+
# محليًا (الملفات موجودة) لا يحدث أي تنزيل — الدالة ترجع فورًا.
|
| 13 |
+
# ============================================================
|
| 14 |
+
|
| 15 |
+
import os
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
|
| 18 |
+
import streamlit as st
|
| 19 |
+
|
| 20 |
+
import config
|
| 21 |
+
|
| 22 |
+
# ما الذي نُنزّله (أنماط المسارات داخل مستودع HF):
|
| 23 |
+
# - data/embeddings/ : المتجهات المحفوظة (.npy)
|
| 24 |
+
# - data/processed/ : البيانات المنظّفة (data.csv)
|
| 25 |
+
# - models/ksaa_custom : النموذج الثالث المحلي (الأول والثاني يُنزَّلان تلقائيًا من HF)
|
| 26 |
+
DOWNLOAD_PATTERNS = [
|
| 27 |
+
"data/embeddings/**",
|
| 28 |
+
"data/processed/data.csv",
|
| 29 |
+
"models/ksaa_custom/**",
|
| 30 |
+
]
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _repo_id() -> str | None:
|
| 34 |
+
"""اسم مستودع HF الذي يحوي الملفات الكبيرة (من الأسرار أو البيئة)."""
|
| 35 |
+
try:
|
| 36 |
+
return st.secrets["HF_DATA_REPO"]
|
| 37 |
+
except Exception:
|
| 38 |
+
return os.getenv("HF_DATA_REPO")
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def assets_ready() -> bool:
|
| 42 |
+
"""هل كل الملفات الكبيرة موجودة محليًا؟"""
|
| 43 |
+
if not config.PROCESSED_DATA_PATH.exists():
|
| 44 |
+
return False
|
| 45 |
+
if not Path(config.MODEL_3_PATH).exists():
|
| 46 |
+
return False
|
| 47 |
+
for m in config.MODELS:
|
| 48 |
+
if not config.embedding_path(m["key"]).exists():
|
| 49 |
+
return False
|
| 50 |
+
return True
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def ensure_assets() -> None:
|
| 54 |
+
"""يُنزّل الملفات الكبيرة من Hugging Face Hub إن لم تكن موجودة."""
|
| 55 |
+
if assets_ready():
|
| 56 |
+
return
|
| 57 |
+
|
| 58 |
+
repo = _repo_id()
|
| 59 |
+
if not repo:
|
| 60 |
+
raise RuntimeError(
|
| 61 |
+
"الملفات الكبيرة (النماذج/الـ embeddings) غير موجودة، و HF_DATA_REPO "
|
| 62 |
+
"غير مضبوط في الأسرار. راجع README_STREAMLIT_CLOUD.md."
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
from huggingface_hub import snapshot_download
|
| 66 |
+
|
| 67 |
+
# تُنزَّل مباشرة إلى جذر المشروع بنفس البنية (data/، models/...)
|
| 68 |
+
snapshot_download(
|
| 69 |
+
repo_id=repo,
|
| 70 |
+
repo_type="model",
|
| 71 |
+
local_dir=str(config.BASE_DIR),
|
| 72 |
+
allow_patterns=DOWNLOAD_PATTERNS,
|
| 73 |
+
)
|
reverse-dictionary/backend/app/models_loader.py
CHANGED
|
@@ -52,7 +52,9 @@ class ResourceManager:
|
|
| 52 |
f"ملف الـ embeddings غير موجود: {path}\n"
|
| 53 |
"شغّل أولًا: python scripts/build_embeddings.py"
|
| 54 |
)
|
| 55 |
-
|
|
|
|
|
|
|
| 56 |
return self.embeddings[model_key]
|
| 57 |
|
| 58 |
# --------------------------------------------------------
|
|
|
|
| 52 |
f"ملف الـ embeddings غير موجود: {path}\n"
|
| 53 |
"شغّل أولًا: python scripts/build_embeddings.py"
|
| 54 |
)
|
| 55 |
+
# mmap_mode="r": تبقى المصفوفة على القرص ولا تُحمّل كاملة في
|
| 56 |
+
# الذاكرة — يوفّر ~مئات الميغابايت (مهم للنشر على ذاكرة محدودة).
|
| 57 |
+
self.embeddings[model_key] = np.load(path, mmap_mode="r")
|
| 58 |
return self.embeddings[model_key]
|
| 59 |
|
| 60 |
# --------------------------------------------------------
|
reverse-dictionary/backend/requirements.txt
CHANGED
|
@@ -13,3 +13,4 @@ sentence-transformers # نماذج الـ embedding + Cross-Encoder (reranker)
|
|
| 13 |
torch # محرّك التعلّم العميق (يأتي مع sentence-transformers)
|
| 14 |
sqlalchemy # التعامل مع قاعدة البيانات (Supabase / SQLite)
|
| 15 |
psycopg[binary] # موصّل Postgres لـ Supabase
|
|
|
|
|
|
| 13 |
torch # محرّك التعلّم العميق (يأتي مع sentence-transformers)
|
| 14 |
sqlalchemy # التعامل مع قاعدة البيانات (Supabase / SQLite)
|
| 15 |
psycopg[binary] # موصّل Postgres لـ Supabase
|
| 16 |
+
huggingface_hub # تنزيل الملفات الكبيرة من HF Hub عند النشر
|
reverse-dictionary/backend/scripts/upload_assets.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ============================================================
|
| 2 |
+
# 📄 الملف: scripts/upload_assets.py
|
| 3 |
+
# 🎯 الغرض: رفع الملفات الكبيرة إلى مستودع Hugging Face Hub (مرة واحدة).
|
| 4 |
+
#
|
| 5 |
+
# يرفع: data/embeddings/ (المتجهات) + data/processed/data.csv (البيانات)
|
| 6 |
+
# + models/ksaa_custom/ (النموذج الثالث المحلي).
|
| 7 |
+
# النموذجان الأول والثاني يُنزَّلان تلقائيًا من HuggingFace فلا يُرفعان.
|
| 8 |
+
# بعدها يقدر التطبيق المنشور ينزّل هذي الملفات تلقائيًا.
|
| 9 |
+
#
|
| 10 |
+
# قبل التشغيل:
|
| 11 |
+
# 1) سجّلي دخول HF مرة واحدة: huggingface-cli login
|
| 12 |
+
# (أو صدّري التوكن: export HF_TOKEN=hf_xxx)
|
| 13 |
+
# 2) حدّدي اسم المستودع: export HF_DATA_REPO="username/repo-name"
|
| 14 |
+
#
|
| 15 |
+
# ثم (من داخل مجلد backend):
|
| 16 |
+
# python scripts/upload_assets.py
|
| 17 |
+
# ============================================================
|
| 18 |
+
|
| 19 |
+
import os
|
| 20 |
+
import sys
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
|
| 23 |
+
sys.path.append(str(Path(__file__).resolve().parent.parent))
|
| 24 |
+
import config
|
| 25 |
+
|
| 26 |
+
from huggingface_hub import HfApi, create_repo
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def main():
|
| 30 |
+
repo = os.getenv("HF_DATA_REPO")
|
| 31 |
+
if not repo:
|
| 32 |
+
raise SystemExit("❌ حدّدي المستودع أولًا: export HF_DATA_REPO=\"username/repo\"")
|
| 33 |
+
|
| 34 |
+
print(f"📦 المستودع: {repo}")
|
| 35 |
+
create_repo(repo, repo_type="model", exist_ok=True)
|
| 36 |
+
api = HfApi()
|
| 37 |
+
|
| 38 |
+
# 1) الـ embeddings
|
| 39 |
+
print("⏫ رفع data/embeddings/ ...")
|
| 40 |
+
api.upload_folder(folder_path=str(config.EMBEDDINGS_DIR),
|
| 41 |
+
path_in_repo="data/embeddings",
|
| 42 |
+
repo_id=repo, repo_type="model")
|
| 43 |
+
|
| 44 |
+
# 2) البيانات المنظّفة
|
| 45 |
+
print("⏫ رفع data/processed/data.csv ...")
|
| 46 |
+
api.upload_file(path_or_fileobj=str(config.PROCESSED_DATA_PATH),
|
| 47 |
+
path_in_repo="data/processed/data.csv",
|
| 48 |
+
repo_id=repo, repo_type="model")
|
| 49 |
+
|
| 50 |
+
# 3) النموذج الثالث المحلي (ksaa)
|
| 51 |
+
print("⏫ رفع models/ksaa_custom/ ...")
|
| 52 |
+
api.upload_folder(folder_path=str(config.MODEL_3_PATH),
|
| 53 |
+
path_in_repo="models/ksaa_custom",
|
| 54 |
+
repo_id=repo, repo_type="model")
|
| 55 |
+
|
| 56 |
+
print(f"✅ تم الرفع. اجعلي المستودع عامًّا (Public) من إعداداته على HF.")
|
| 57 |
+
print(f" ثم في أسرار Streamlit Cloud: HF_DATA_REPO = \"{repo}\"")
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
if __name__ == "__main__":
|
| 61 |
+
main()
|
reverse-dictionary/frontend/streamlit_app.py
CHANGED
|
@@ -31,12 +31,26 @@ import streamlit as st
|
|
| 31 |
import config
|
| 32 |
from app.search import search_one_model
|
| 33 |
from app import database as db
|
|
|
|
| 34 |
|
| 35 |
# عدد الكلمات المعروضة لكل نموذج
|
| 36 |
TOP_N = 5
|
| 37 |
|
| 38 |
st.set_page_config(page_title="البحث الدلالي", layout="wide")
|
| 39 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
# ============================================================
|
| 41 |
# 🎨 التصميم — لوحة هادئة: رمادي محايد + نعناعي
|
| 42 |
# ============================================================
|
|
|
|
| 31 |
import config
|
| 32 |
from app.search import search_one_model
|
| 33 |
from app import database as db
|
| 34 |
+
from app import assets
|
| 35 |
|
| 36 |
# عدد الكلمات المعروضة لكل نموذج
|
| 37 |
TOP_N = 5
|
| 38 |
|
| 39 |
st.set_page_config(page_title="البحث الدلالي", layout="wide")
|
| 40 |
|
| 41 |
+
|
| 42 |
+
# ============================================================
|
| 43 |
+
# 📥 تجهيز الملفات الكبيرة (تنزيل من HF Hub أول تشغيل على السحابة)
|
| 44 |
+
# محليًا: الملفات موجودة فترجع فورًا بلا تنزيل.
|
| 45 |
+
# ============================================================
|
| 46 |
+
@st.cache_resource(show_spinner="⏳ تجهيز النماذج لأول مرة (تنزيل)… قد يأخذ دقائق")
|
| 47 |
+
def _bootstrap_assets():
|
| 48 |
+
assets.ensure_assets()
|
| 49 |
+
return True
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
_bootstrap_assets()
|
| 53 |
+
|
| 54 |
# ============================================================
|
| 55 |
# 🎨 التصميم — لوحة هادئة: رمادي محايد + نعناعي
|
| 56 |
# ============================================================
|