Spaces:
Sleeping
Sleeping
File size: 4,586 Bytes
4a920c4 | 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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | """
التعامل مع 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)
|