shahdAI's picture
ربط المشروع الفعلي بالـSpace (استبدال قالب Streamlit الافتراضي)
4a920c4 verified
Raw
History Blame Contribute Delete
4.59 kB
"""
التعامل مع MongoDB Atlas: تسجيل المقيّمين، حفظ التقييمات، وقراءة الإحصائيات.
"""
from __future__ import annotations
import logging
from datetime import datetime, timezone
from functools import lru_cache
import certifi
from pymongo import MongoClient
from pymongo.collection import Collection
from pymongo.database import Database
from app import config
logger = logging.getLogger(__name__)
@lru_cache(maxsize=1)
def get_database() -> Database:
if not config.MONGODB_URI:
raise RuntimeError(
"متغير البيئة MONGODB_URI غير مُعرَّف."
)
uri = config.MONGODB_URI
use_tls = "mongodb+srv" in uri.lower()
kwargs = {"tlsCAFile": certifi.where()} if use_tls else {}
client = MongoClient(uri, serverSelectionTimeoutMS=5000, **kwargs)
client.admin.command("ping")
return client[config.MONGODB_DB_NAME]
def _evaluators_collection() -> Collection:
return get_database()[config.EVALUATORS_COLLECTION]
def _evaluations_collection() -> Collection:
return get_database()[config.EVALUATIONS_COLLECTION]
# ============================================================
# المقيّمون
# ============================================================
def register_evaluator(name: str, email: str) -> None:
"""تسجيل/تحديث بيانات المقيّم (upsert حسب البريد الإلكتروني)."""
_evaluators_collection().update_one(
{"email": email},
{
"$set": {"name": name, "email": email},
"$setOnInsert": {"created_at": datetime.now(timezone.utc)},
},
upsert=True,
)
# ============================================================
# التقييمات
# ============================================================
def save_evaluation(
evaluator_email: str,
query_definition: str,
results: list[dict],
) -> None:
"""
حفظ نتيجة استعلام واحد مع تقييم المقيّم لكل نتيجة.
شكل `results` المتوقع:
[
{
"word": "...",
"definition": "...",
"retrieval_score": 0.83,
"rerank_score": 4.12,
"rank": 1,
"is_correct": True,
},
...
]
"""
_evaluations_collection().insert_one(
{
"evaluator_email": evaluator_email,
"query_definition": query_definition,
"results": results,
"created_at": datetime.now(timezone.utc),
}
)
# ============================================================
# الإحصائيات
# ============================================================
def get_stats(evaluator_email: str | None = None) -> dict:
"""
إحصائيات مجمَّعة: عدد الاستعلامات، عدد النتائج الصحيحة، وعدد الخاطئة.
لو تم تمرير `evaluator_email`، تُحسب الإحصائيات لذلك المقيّم فقط.
"""
query: dict = {}
if evaluator_email:
query["evaluator_email"] = evaluator_email
cursor = _evaluations_collection().find(query, {"results": 1})
total_queries = 0
correct = 0
incorrect = 0
for doc in cursor:
total_queries += 1
for r in doc.get("results", []):
if r.get("is_correct"):
correct += 1
else:
incorrect += 1
return {
"total_queries": total_queries,
"correct": correct,
"incorrect": incorrect,
}
# ============================================================
# سجلّ الاستعلامات
# ============================================================
def log_search(query: str, path: str, results: list[dict]) -> None:
"""
يُخزِّن سجل بحث بعد ظهور النتائج للمستخدم مباشرة.
path: "ROOT" أو "DEFINITION"
results: قائمة بالنتائج الظاهرة فعلاً للمستخدم، كل عنصر:
{"rank": int, "word": str, "definition": str}
يعمل بصمت — لو فشل الاتصال بـMongoDB لا يوقف التطبيق.
"""
try:
db = get_database()
db["search_logs"].insert_one({
"timestamp": datetime.now(timezone.utc),
"query": query,
"path": path,
"results": results,
})
except Exception as exc:
logger.warning("MongoDB log_search failed: %s", exc)