Spaces:
Sleeping
Sleeping
Update utils/memory_utils.py
Browse files- utils/memory_utils.py +37 -37
utils/memory_utils.py
CHANGED
|
@@ -10,7 +10,6 @@ import gradio as gr
|
|
| 10 |
from llama_index.core import StorageContext, load_index_from_storage
|
| 11 |
|
| 12 |
# Local Imports setup
|
| 13 |
-
# فرض بر این است که مسیرها درست تنظیم شدهاند
|
| 14 |
bank_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../memory_bank')
|
| 15 |
sys.path.append(bank_path)
|
| 16 |
|
|
@@ -18,16 +17,14 @@ try:
|
|
| 18 |
from build_memory_index import build_memory_index
|
| 19 |
from summarize_memory import summarize_memory
|
| 20 |
except ImportError:
|
| 21 |
-
# print("Warning: Could not import memory build/summary modules.")
|
| 22 |
def build_memory_index(*args, **kwargs): pass
|
| 23 |
def summarize_memory(*args, **kwargs): return {}
|
| 24 |
|
| 25 |
# ==========================================
|
| 26 |
# 1. تنظیمات مسیر (Single Source of Truth)
|
| 27 |
# ==========================================
|
| 28 |
-
# مسیردهی نسبی برای سازگاری با Hugging Face Spaces (Linux)
|
| 29 |
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 30 |
-
BASE_DIR = os.path.dirname(CURRENT_DIR)
|
| 31 |
MEMORIES_DIR = os.path.join(BASE_DIR, "memories")
|
| 32 |
MEMORY_FILE_PATH = os.path.join(MEMORIES_DIR, "update_memory_0512_eng.json")
|
| 33 |
|
|
@@ -38,51 +35,59 @@ os.makedirs(MEMORIES_DIR, exist_ok=True)
|
|
| 38 |
# 2. توابع اصلی I/O (خواندن و نوشتن)
|
| 39 |
# ==========================================
|
| 40 |
|
| 41 |
-
def load_memory():
|
| 42 |
-
"""
|
| 43 |
-
حافظه را از فایل JSON بارگذاری میکند.
|
| 44 |
-
اگر فایل وجود نداشته باشد یا خراب باشد، یک دیکشنری خالی برمیگرداند.
|
| 45 |
-
"""
|
| 46 |
-
if os.path.exists(MEMORY_FILE_PATH):
|
| 47 |
-
try:
|
| 48 |
-
with open(MEMORY_FILE_PATH, 'r', encoding='utf-8') as f:
|
| 49 |
-
return json.load(f)
|
| 50 |
-
except (json.JSONDecodeError, FileNotFoundError):
|
| 51 |
-
print("⚠️ Memory file is corrupted or not found. Starting with empty memory.")
|
| 52 |
-
return {}
|
| 53 |
-
return {}
|
| 54 |
-
|
| 55 |
-
|
| 56 |
def save_memory(data):
|
| 57 |
"""
|
| 58 |
کل آبجکت حافظه را به صورت ایمن (Atomic Write) در فایل JSON ذخیره میکند.
|
| 59 |
"""
|
| 60 |
try:
|
| 61 |
-
# ن
|
|
|
|
|
|
|
|
|
|
| 62 |
temp_file = MEMORY_FILE_PATH + ".tmp"
|
| 63 |
with open(temp_file, "w", encoding="utf-8") as f:
|
| 64 |
json.dump(data, f, ensure_ascii=False, indent=4)
|
| 65 |
|
| 66 |
-
# جایگزینی فایل اصلی
|
| 67 |
os.replace(temp_file, MEMORY_FILE_PATH)
|
| 68 |
# print(f"✅ Memory successfully saved to {MEMORY_FILE_PATH}")
|
| 69 |
except Exception as e:
|
| 70 |
print(f"❌ CRITICAL ERROR saving memory: {e}")
|
| 71 |
|
| 72 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
# ==========================================
|
| 74 |
# 3. توابع منطق حافظه (Memory Logic)
|
| 75 |
# ==========================================
|
| 76 |
|
| 77 |
def enter_name_llamaindex(name, memory_data, data_args, update_memory_index=True):
|
| 78 |
"""
|
| 79 |
-
کاربر را د
|
| 80 |
-
|
| 81 |
-
IMPORTANT: این تابع دیگر فایل را نمیخواند/نمینویسد. فقط روی آبجکت memory_data در حافظه RAM کار میکند.
|
| 82 |
-
ذخیرهسازی باید توسط فراخواننده (caller) انجام شود.
|
| 83 |
"""
|
| 84 |
|
| 85 |
-
# 1. مدیریت ساختار دیکشنری
|
|
|
|
| 86 |
if name not in memory_data:
|
| 87 |
print(f"🆕 Creating new user profile for: {name}")
|
| 88 |
memory_data[name] = {
|
|
@@ -92,15 +97,19 @@ def enter_name_llamaindex(name, memory_data, data_args, update_memory_index=True
|
|
| 92 |
"semantic_memory": {},
|
| 93 |
"profile": {}
|
| 94 |
}
|
|
|
|
| 95 |
|
| 96 |
user_memory = memory_data[name]
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
# 2. مدیریت ایندکسهای وکتوری (LlamaIndex)
|
| 99 |
sessions_memory = None
|
| 100 |
episodic_memory = None
|
| 101 |
semantic_memory = None
|
| 102 |
|
| 103 |
-
# مسیردهی برای ایندکسها (نسبی و لینوکسی)
|
| 104 |
base_index_dir = os.path.join(MEMORIES_DIR, "memory_index", "llamaindex", name)
|
| 105 |
|
| 106 |
sessions_path = os.path.join(base_index_dir, "sessions_index.json")
|
|
@@ -113,16 +122,11 @@ def enter_name_llamaindex(name, memory_data, data_args, update_memory_index=True
|
|
| 113 |
os.path.exists(semantic_path)
|
| 114 |
)
|
| 115 |
|
| 116 |
-
# ساخت ایندکس اگر وجود ندارد یا درخواست آپدیت شده است
|
| 117 |
if update_memory_index or not indices_exist:
|
| 118 |
-
# print(f'Initializing memory indices for {name}...')
|
| 119 |
try:
|
| 120 |
os.makedirs(base_index_dir, exist_ok=True)
|
| 121 |
-
# توجه: build_memory_index ممکن است نیاز به خواندن فایل داشته باشد،
|
| 122 |
-
# اما فعلاً فرض میکنیم درست کار میکند یا safe fail میشود.
|
| 123 |
build_memory_index(memory_data, data_args, name=name)
|
| 124 |
except Exception as e:
|
| 125 |
-
# خطای بیلد ایندکس نباید برنامه را متوقف کند
|
| 126 |
print(f"Warning: Error building memory index (skipping): {e}")
|
| 127 |
|
| 128 |
# بارگذاری ایندکسها
|
|
@@ -148,14 +152,10 @@ def enter_name_llamaindex(name, memory_data, data_args, update_memory_index=True
|
|
| 148 |
|
| 149 |
|
| 150 |
def summarize_memory_event_personality(data_args, memory_data, user_name):
|
| 151 |
-
|
| 152 |
-
Wrapper برای تابع summarize_memory.
|
| 153 |
-
"""
|
| 154 |
-
# ابتدا مطمئن میشویم دادههای فعلی ذخیره شدهاند تا summarizer فایل بهروز را بخواند
|
| 155 |
save_memory(memory_data)
|
| 156 |
|
| 157 |
try:
|
| 158 |
-
# تابع summarize_memory احتمالاً خودش فایل را میخواند
|
| 159 |
updated_memory = summarize_memory(MEMORY_FILE_PATH, user_name, language='en')
|
| 160 |
return updated_memory.get(user_name, {})
|
| 161 |
except Exception as e:
|
|
|
|
| 10 |
from llama_index.core import StorageContext, load_index_from_storage
|
| 11 |
|
| 12 |
# Local Imports setup
|
|
|
|
| 13 |
bank_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../memory_bank')
|
| 14 |
sys.path.append(bank_path)
|
| 15 |
|
|
|
|
| 17 |
from build_memory_index import build_memory_index
|
| 18 |
from summarize_memory import summarize_memory
|
| 19 |
except ImportError:
|
|
|
|
| 20 |
def build_memory_index(*args, **kwargs): pass
|
| 21 |
def summarize_memory(*args, **kwargs): return {}
|
| 22 |
|
| 23 |
# ==========================================
|
| 24 |
# 1. تنظیمات مسیر (Single Source of Truth)
|
| 25 |
# ==========================================
|
|
|
|
| 26 |
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| 27 |
+
BASE_DIR = os.path.dirname(CURRENT_DIR)
|
| 28 |
MEMORIES_DIR = os.path.join(BASE_DIR, "memories")
|
| 29 |
MEMORY_FILE_PATH = os.path.join(MEMORIES_DIR, "update_memory_0512_eng.json")
|
| 30 |
|
|
|
|
| 35 |
# 2. توابع اصلی I/O (خواندن و نوشتن)
|
| 36 |
# ==========================================
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
def save_memory(data):
|
| 39 |
"""
|
| 40 |
کل آبجکت حافظه را به صورت ایمن (Atomic Write) در فایل JSON ذخیره میکند.
|
| 41 |
"""
|
| 42 |
try:
|
| 43 |
+
# اطمینان مجدد از وجود پوشه
|
| 44 |
+
os.makedirs(MEMORIES_DIR, exist_ok=True)
|
| 45 |
+
|
| 46 |
+
# نوشتن در فایل موقت
|
| 47 |
temp_file = MEMORY_FILE_PATH + ".tmp"
|
| 48 |
with open(temp_file, "w", encoding="utf-8") as f:
|
| 49 |
json.dump(data, f, ensure_ascii=False, indent=4)
|
| 50 |
|
| 51 |
+
# جایگزینی فایل اصلی
|
| 52 |
os.replace(temp_file, MEMORY_FILE_PATH)
|
| 53 |
# print(f"✅ Memory successfully saved to {MEMORY_FILE_PATH}")
|
| 54 |
except Exception as e:
|
| 55 |
print(f"❌ CRITICAL ERROR saving memory: {e}")
|
| 56 |
|
| 57 |
|
| 58 |
+
def load_memory():
|
| 59 |
+
"""
|
| 60 |
+
حافظه را بارگذاری میکند. اگر فایل نباشد، آن را میسازد.
|
| 61 |
+
"""
|
| 62 |
+
if not os.path.exists(MEMORY_FILE_PATH):
|
| 63 |
+
print(f"⚠️ Memory file not found. Creating new file at: {MEMORY_FILE_PATH}")
|
| 64 |
+
# ایجاد فایل خالی فیزیکی
|
| 65 |
+
save_memory({})
|
| 66 |
+
return {}
|
| 67 |
+
|
| 68 |
+
try:
|
| 69 |
+
with open(MEMORY_FILE_PATH, 'r', encoding='utf-8') as f:
|
| 70 |
+
# اگر فایل خالی بود، هندل شود
|
| 71 |
+
content = f.read()
|
| 72 |
+
if not content.strip():
|
| 73 |
+
return {}
|
| 74 |
+
return json.loads(content)
|
| 75 |
+
except (json.JSONDecodeError, FileNotFoundError):
|
| 76 |
+
print("⚠️ Memory file is corrupted. Starting with empty memory.")
|
| 77 |
+
return {}
|
| 78 |
+
|
| 79 |
+
|
| 80 |
# ==========================================
|
| 81 |
# 3. توابع منطق حافظه (Memory Logic)
|
| 82 |
# ==========================================
|
| 83 |
|
| 84 |
def enter_name_llamaindex(name, memory_data, data_args, update_memory_index=True):
|
| 85 |
"""
|
| 86 |
+
کاربر را ایجاد کرده و فایل را فوراً ذخیره میکند تا از دست نرود.
|
|
|
|
|
|
|
|
|
|
| 87 |
"""
|
| 88 |
|
| 89 |
+
# 1. مدیریت ساختار دیکشنری
|
| 90 |
+
is_new_user = False
|
| 91 |
if name not in memory_data:
|
| 92 |
print(f"🆕 Creating new user profile for: {name}")
|
| 93 |
memory_data[name] = {
|
|
|
|
| 97 |
"semantic_memory": {},
|
| 98 |
"profile": {}
|
| 99 |
}
|
| 100 |
+
is_new_user = True
|
| 101 |
|
| 102 |
user_memory = memory_data[name]
|
| 103 |
|
| 104 |
+
# نکته مهم: اگر کاربر جدید است، همین الان ذخیره کن تا اگر برنامه کرش کرد، نام بماند
|
| 105 |
+
if is_new_user:
|
| 106 |
+
save_memory(memory_data)
|
| 107 |
+
|
| 108 |
# 2. مدیریت ایندکسهای وکتوری (LlamaIndex)
|
| 109 |
sessions_memory = None
|
| 110 |
episodic_memory = None
|
| 111 |
semantic_memory = None
|
| 112 |
|
|
|
|
| 113 |
base_index_dir = os.path.join(MEMORIES_DIR, "memory_index", "llamaindex", name)
|
| 114 |
|
| 115 |
sessions_path = os.path.join(base_index_dir, "sessions_index.json")
|
|
|
|
| 122 |
os.path.exists(semantic_path)
|
| 123 |
)
|
| 124 |
|
|
|
|
| 125 |
if update_memory_index or not indices_exist:
|
|
|
|
| 126 |
try:
|
| 127 |
os.makedirs(base_index_dir, exist_ok=True)
|
|
|
|
|
|
|
| 128 |
build_memory_index(memory_data, data_args, name=name)
|
| 129 |
except Exception as e:
|
|
|
|
| 130 |
print(f"Warning: Error building memory index (skipping): {e}")
|
| 131 |
|
| 132 |
# بارگذاری ایندکسها
|
|
|
|
| 152 |
|
| 153 |
|
| 154 |
def summarize_memory_event_personality(data_args, memory_data, user_name):
|
| 155 |
+
# ذخیره قبل از سامرایز برای اطمینان
|
|
|
|
|
|
|
|
|
|
| 156 |
save_memory(memory_data)
|
| 157 |
|
| 158 |
try:
|
|
|
|
| 159 |
updated_memory = summarize_memory(MEMORY_FILE_PATH, user_name, language='en')
|
| 160 |
return updated_memory.get(user_name, {})
|
| 161 |
except Exception as e:
|