Spaces:
Runtime error
Runtime error
File size: 5,325 Bytes
40d06ea |
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 149 150 151 152 153 154 155 156 |
# memory.py
# -*- coding: utf-8 -*-
"""
ذاكرة المستخدم/العامة + قاعدة المعرفة في ملف واحد، بدون أي استيراد عكسي (circular import).
يوفّر:
- load_memory(user_id) / save_memory(user_id, data)
- load_global_memory() / save_global_memory(data)
- load_knowledge_base() / save_knowledge_base(data)
- learn_from_unknown(prompt) / update_knowledge_base(prompt, answer)
"""
from __future__ import annotations
import json
import os
import tempfile
import threading
from typing import Any, Dict
# ========= مسارات التخزين =========
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
# مجلد بيانات الذاكرة
DATA_DIR = os.path.join(BASE_DIR, "data")
os.makedirs(DATA_DIR, exist_ok=True)
# ملفات الذاكرة
GLOBAL_MEMORY_FILE = os.path.join(DATA_DIR, "global_memory.json")
USER_MEMORY_PREFIX = "memory_" # memory_<user_id>.json
# ملف قاعدة المعرفة (متوافق مع نسختك السابقة)
knowledge_base_path = os.path.join(BASE_DIR, "knowledge_base.json")
# قفل للتزامن
_lock = threading.RLock()
# ========= أدوات JSON آمنة =========
def _safe_write_json(path: str, data: Dict[str, Any]) -> None:
"""
كتابة ذرّية لضمان عدم تلف الملف حتى مع انقطاع مفاجئ.
"""
with _lock:
os.makedirs(os.path.dirname(path), exist_ok=True)
fd, tmp_path = tempfile.mkstemp(prefix=".tmp_", dir=os.path.dirname(path))
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
f.flush()
os.fsync(f.fileno())
os.replace(tmp_path, path)
finally:
if os.path.exists(tmp_path):
try:
os.remove(tmp_path)
except OSError:
pass
def _read_json(path: str) -> Dict[str, Any]:
"""
قراءة JSON بأمان. يعيد dict فارغ عند عدم وجود الملف أو في حال تلفه.
"""
with _lock:
if not os.path.exists(path):
return {}
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except Exception:
return {}
def _user_file(user_id: str) -> str:
"""
تكوين اسم ملف آمن للمستخدم.
"""
safe_id = "".join(ch for ch in str(user_id) if ch.isalnum() or ch in ("-", "_")) or "default"
return os.path.join(DATA_DIR, f"{USER_MEMORY_PREFIX}{safe_id}.json")
# ========= واجهة الذاكرة (لـ learner.py) =========
def load_memory(user_id: str) -> Dict[str, Any]:
"""
قراءة ذاكرة مستخدم (dict).
"""
return _read_json(_user_file(user_id))
def save_memory(user_id: str, data: Dict[str, Any]) -> None:
"""
حفظ ذاكرة مستخدم (dict).
"""
if not isinstance(data, dict):
raise TypeError("save_memory expects a dict")
_safe_write_json(_user_file(user_id), data)
def load_global_memory() -> Dict[str, Any]:
"""
قراءة الذاكرة العامة (dict).
"""
return _read_json(GLOBAL_MEMORY_FILE)
def save_global_memory(data: Dict[str, Any]) -> None:
"""
حفظ الذاكرة العامة (dict).
"""
if not isinstance(data, dict):
raise TypeError("save_global_memory expects a dict")
_safe_write_json(GLOBAL_MEMORY_FILE, data)
# ========= واجهة قاعدة المعرفة (متوافقة مع نسختك السابقة) =========
def load_knowledge_base() -> Dict[str, Any]:
return _read_json(knowledge_base_path)
def save_knowledge_base(data: Dict[str, Any]) -> None:
if not isinstance(data, dict):
raise TypeError("save_knowledge_base expects a dict")
_safe_write_json(knowledge_base_path, data)
def learn_from_unknown(prompt: str):
"""
نفس السلوك السابق: يطبع رسالة ويطلب إجابة ليتم تعلمها.
"""
print("نورا: لا أملك إجابة لهذا السؤال حاليًا. سأبحث عن إجابة وأتعلم.")
answer = input("يرجى تزويدي بالإجابة المناسبة لأتعلمها: ")
if answer and answer.strip():
return answer
return None
def update_knowledge_base(prompt: str, answer: str) -> None:
kb = load_knowledge_base()
kb[prompt] = answer
save_knowledge_base(kb)
# ========= تصدير الأسماء =========
__all__ = [
"load_memory", "save_memory", "load_global_memory", "save_global_memory",
"load_knowledge_base", "save_knowledge_base",
"learn_from_unknown", "update_knowledge_base",
]
# ========= اختبار سريع =========
if __name__ == "__main__":
uid = "osama"
# اختبار ذاكرة المستخدم/العامة
u = load_memory(uid)
u["counter"] = u.get("counter", 0) + 1
save_memory(uid, u)
g = load_global_memory()
g["last_user"] = uid
save_global_memory(g)
print("User memory:", load_memory(uid))
print("Global memory:", load_global_memory())
# اختبار قاعدة المعرفة
update_knowledge_base("ما هي نورا؟", "مساعد ذكي")
print("KB size:", len(load_knowledge_base()))
|