EMMA commited on
Commit
dfc4683
·
1 Parent(s): 30dc71e

update code

Browse files
Backup code/build_memory_index_22.py ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # Memory Indexing Utility for LlamaIndex
3
+ #
4
+ # This script provides functionalities to build and manage memory indices for a conversational AI
5
+ # using the LlamaIndex framework. It supports creating structured memory documents from raw
6
+ # conversation data and persisting them as vector indices for efficient retrieval.
7
+ #
8
+
9
+ # --- Standard Library Imports ---
10
+ import json
11
+ import os
12
+
13
+ # --- Third-Party Imports ---
14
+ import tiktoken
15
+ from llama_index.core import (
16
+ Document,
17
+ PromptHelper,
18
+ Settings, # Replaces the deprecated ServiceContext
19
+ StorageContext,
20
+ VectorStoreIndex,
21
+ load_index_from_storage,
22
+ )
23
+ from llama_index.llms.openai import OpenAI
24
+ # If a specific embedding model is needed (e.g., from OpenAI), uncomment the line below
25
+ # from llama_index.embeddings.openai import OpenAIEmbedding
26
+
27
+
28
+ # --- Global Variables ---
29
+ # A dictionary to hold the loaded or newly created indices in memory.
30
+ index_set = {}
31
+
32
+ # پشتیبانی هوشمند از Persistent Storage در Hugging Face (/data) یا مسیر محلی
33
+ BASE_DIR = "/data" if os.path.exists("/data") else os.path.dirname(os.path.abspath(__file__))
34
+
35
+ # اصلاح مسیر دقیق بر اساس ساختار ریپازیتوری شما (حذف پوشه memories و پرانتز اضافه)
36
+ _INDEX_BASE_DIR = os.getenv("EMMA_INDEX_DIR", os.path.join(BASE_DIR, "memory_index", "llamaindex"))
37
+
38
+ # اطمینان از وجود دایرکتوری در صورت ساخت ایندکس جدید
39
+ os.makedirs(_INDEX_BASE_DIR, exist_ok=True)
40
+
41
+ #*************************************************************
42
+
43
+ #***************************************************************************
44
+
45
+
46
+ # --- Core Functions ---
47
+
48
+ def setup_global_settings():
49
+ """
50
+ Configures global settings for LlamaIndex (v0.10+).
51
+
52
+ This function replaces the deprecated `build_service_context` pattern by directly
53
+ configuring the global `Settings` object for the LLM, tokenizer, and other components.
54
+ """
55
+ # 1. Set Tokenizer (to resolve potential tiktoken errors)
56
+ try:
57
+ # This encoding is commonly used by OpenAI models like GPT-4.
58
+ Settings.tokenizer = tiktoken.get_encoding("cl100k_base").encode
59
+ except Exception as e:
60
+ print(f"Warning: Could not set the tokenizer. This might lead to issues. Error: {e}")
61
+
62
+ # 2. Configure the Language Model (LLM)
63
+ # Use the LlamaIndex-specific OpenAI class to avoid conflicts with other libraries.
64
+ # It automatically reads the API key from the "OPENAI_API_KEY" environment variable.
65
+ Settings.llm = OpenAI(
66
+ model="gpt-4o",
67
+ temperature=1.0,
68
+ max_tokens=1024,
69
+ api_key=os.environ.get("GAPGPT_API_KEY"),
70
+ api_base="https://api.gapgpt.app/v1",
71
+ additional_kwargs={
72
+ "top_p": 0.95,
73
+ "frequency_penalty": 0.4,
74
+ "presence_penalty": 0.2
75
+ }
76
+ )
77
+
78
+ # 3. Configure the Prompt Helper (with updated parameter names)
79
+ # This helps manage context window size, number of outputs, etc.
80
+ Settings.prompt_helper = PromptHelper(
81
+ context_window=4096,
82
+ num_output=256,
83
+ chunk_overlap_ratio=0.1
84
+ )
85
+
86
+ # 4. Configure Chunk Size for document processing
87
+ Settings.chunk_size = 512
88
+ Settings.chunk_overlap = 20
89
+
90
+ # Optional: Configure the embedding model if needed.
91
+ # If not set, LlamaIndex defaults to a compatible model (e.g., OpenAI's text-embedding-ada-002).
92
+ # Settings.embed_model = OpenAIEmbedding(api_key=..., api_base=...)
93
+
94
+
95
+ def generate_memory_docs(data, language):
96
+ """
97
+ Generates structured LlamaIndex Document objects from a nested dictionary of user memories.
98
+
99
+ This function processes different types of memory (sessions, episodic, semantic) and
100
+ formats them into Document objects suitable for indexing.
101
+
102
+ Args:
103
+ data (dict): A dictionary where keys are user names and values contain their memories.
104
+ language (str): The language code (e.g., "en"), currently used for formatting.
105
+
106
+ Returns:
107
+ dict: A dictionary where keys are user names and values are dicts containing
108
+ lists of Document objects for each memory type.
109
+ """
110
+ all_user_memories = {}
111
+
112
+ for user_name, user_memory in data.items():
113
+ all_user_memories[user_name] = {
114
+ "sessions": [],
115
+ "episodic_memory": [],
116
+ "semantic_memory": [],
117
+ }
118
+
119
+ # Process session history
120
+ if "sessions" in user_memory:
121
+ for session in user_memory["sessions"]:
122
+ date = session["date"]
123
+ content = session["conversation"]
124
+
125
+ memory_str = f"Session on {date}:\n"
126
+ for dialog in content:
127
+ query = dialog.get("query", "")
128
+ response = dialog.get("response", "")
129
+ memory_str += f"\n{user_name}: {query.strip()}"
130
+ memory_str += f"\nAI: {response.strip()}"
131
+ memory_str += "\n"
132
+
133
+ if "summary" in user_memory and date in user_memory["summary"]:
134
+ summary = f'The summary of the conversation on {date} is: {user_memory["summary"][date]}'
135
+ memory_str += summary
136
+
137
+ # Use the 'text' argument for the Document object
138
+ all_user_memories[user_name]["sessions"].append(Document(text=memory_str))
139
+
140
+ # Process episodic memory
141
+ if "episodic_memory" in user_memory:
142
+ episodic_str = "Recent experiences:\n"
143
+ for event in user_memory["episodic_memory"]:
144
+ episodic_str += f"- {event}\n"
145
+ all_user_memories[user_name]["episodic_memory"].append(Document(text=episodic_str))
146
+
147
+ # Process semantic memory (long-term facts and personality)
148
+ if "semantic_memory" in user_memory:
149
+ semantic_str = "Long-term personality traits and facts:\n"
150
+ if isinstance(user_memory["semantic_memory"], dict):
151
+ for trait, value in user_memory["semantic_memory"].items():
152
+ semantic_str += f"- {trait}: {value}\n"
153
+ elif isinstance(user_memory["semantic_memory"], list):
154
+ for item in user_memory["semantic_memory"]:
155
+ semantic_str += f"- {item}\n"
156
+ else:
157
+ print(f"WARNING: semantic_memory for user '{user_name}' has an unexpected format: {type(user_memory['semantic_memory'])}")
158
+
159
+ all_user_memories[user_name]["semantic_memory"].append(Document(text=semantic_str))
160
+
161
+ return all_user_memories
162
+
163
+
164
+ def build_memory_index(all_user_memories, data_args, name=None):
165
+ """
166
+ Build and persist memory indices for each user and memory type.
167
+ """
168
+ structured_docs = generate_memory_docs(
169
+ all_user_memories, data_args.language
170
+ )
171
+
172
+ setup_global_settings()
173
+
174
+ for user_name, memories_by_type in structured_docs.items():
175
+ if name and user_name != name:
176
+ continue
177
+
178
+ print(f"Building indices for user '{user_name}'...")
179
+
180
+ base_path = os.path.join(_INDEX_BASE_DIR, user_name)
181
+
182
+ path_map = {
183
+ "sessions": os.path.join(base_path, "sessions"),
184
+ "episodic_memory": os.path.join(base_path, "episodic_memory"),
185
+ "semantic_memory": os.path.join(base_path, "semantic_memory"),
186
+ }
187
+
188
+ for memory_type, docs in memories_by_type.items():
189
+ if not docs:
190
+ print(f" -> Skipping '{memory_type}' index (no documents found).")
191
+ continue
192
+
193
+ if memory_type not in path_map:
194
+ print(f" -> Skipping unknown memory type: '{memory_type}'")
195
+ continue
196
+
197
+ print(f" -> Building '{memory_type}' index...")
198
+
199
+ cur_index = VectorStoreIndex.from_documents(docs)
200
+
201
+ index_dir = path_map[memory_type]
202
+ os.makedirs(index_dir, exist_ok=True)
203
+
204
+ cur_index.storage_context.persist(persist_dir=index_dir)
205
+ print(f" + Saved '{memory_type}' index to: {index_dir}")
206
+
207
+ index_set[f"{user_name}_{memory_type}"] = cur_index
208
+
209
+
210
+ # --- Deprecated Functions (Kept for reference) ---
211
+
212
+ def generate_memory_docs_old(data, language):
213
+ """
214
+ DEPRECATED: An older version of the document generation function.
215
+
216
+ This function had a simpler structure and contained Chinese string literals.
217
+ It is replaced by `generate_memory_docs`.
218
+ """
219
+ all_user_memories = {}
220
+ for user_name, user_memory in data.items():
221
+ all_user_memories[user_name] = []
222
+ if "history" not in user_memory:
223
+ continue
224
+ for date, content in user_memory["history"].items():
225
+ memory_str = f"Conversation on {date}:"
226
+
227
+ for dialog in content:
228
+ query = dialog.get("query", "")
229
+ response = dialog.get("response", "")
230
+ memory_str += f"\n{user_name}: {query.strip()}"
231
+ memory_str += f"\nAI: {response.strip()}"
232
+ memory_str += "\n"
233
+ if "summary" in user_memory and date in user_memory["summary"]:
234
+ summary = f'The summary of the conversation on {date} is: {user_memory["summary"][date]}'
235
+ memory_str += summary
236
+
237
+ all_user_memories[user_name].append(Document(text=memory_str))
238
+ return all_user_memories
239
+
240
+
241
+ def build_memory_index_old(all_user_memories, data_args, name=None):
242
+ """
243
+ DEPRECATED: An older version of the index building function.
244
+
245
+ This function used a flatter memory structure and is replaced by the more
246
+ comprehensive `build_memory_index`.
247
+ """
248
+ # The function name is a typo in the original code, corrected here for clarity.
249
+ all_user_memories_docs = generate_memory_docs(
250
+ all_user_memories, data_args.language
251
+ )
252
+
253
+ # Apply global settings
254
+ setup_global_settings()
255
+
256
+ for user_name, memories in all_user_memories_docs.items():
257
+ if name and user_name != name:
258
+ continue
259
+ print(f"Building index for user {user_name} (using old method)...")
260
+
261
+ # The service_context argument is removed in newer versions.
262
+ cur_index = VectorStoreIndex.from_documents(memories)
263
+ index_set[user_name] = cur_index
264
+
265
+ # استفاده از مسیر داینامیک و امن
266
+ save_dir = os.path.join(_INDEX_BASE_DIR, f"{user_name}_store")
267
+ os.makedirs(save_dir, exist_ok=True)
268
+ cur_index.storage_context.persist(persist_dir=save_dir)
memory_bank/build_memory_index.py CHANGED
@@ -32,13 +32,10 @@ index_set = {}
32
  # پشتیبانی هوشمند از Persistent Storage در Hugging Face (/data) یا مسیر محلی
33
  BASE_DIR = "/data" if os.path.exists("/data") else os.path.dirname(os.path.abspath(__file__))
34
 
35
- # اصلاح مسیر دقیق بر اساس ساختار ریپازیتوری شما (حذف پوشه memories و پرانتز اضافه)
36
- _INDEX_BASE_DIR = os.getenv(
37
- "EMMA_INDEX_DIR",
38
- os.path.join(BASE_DIR, "memory_index", "llamaindex")
39
- )
40
 
41
- # اطمینان از وجود دایرکتوری در صورت ساخت ایندکس جدید
42
  os.makedirs(_INDEX_BASE_DIR, exist_ok=True)
43
 
44
 
@@ -88,7 +85,7 @@ def setup_global_settings():
88
 
89
  # Optional: Configure the embedding model if needed.
90
  # If not set, LlamaIndex defaults to a compatible model (e.g., OpenAI's text-embedding-ada-002).
91
- # Settings.embed_model = OpenAIEmbedding(api_key=..., api_base=...)
92
 
93
 
94
  def generate_memory_docs(data, language):
@@ -174,7 +171,7 @@ def build_memory_index(all_user_memories, data_args, name=None):
174
  if name and user_name != name:
175
  continue
176
 
177
- print(f"Building indices for user '{user_name}'...")
178
 
179
  base_path = os.path.join(_INDEX_BASE_DIR, user_name)
180
 
@@ -255,7 +252,7 @@ def build_memory_index_old(all_user_memories, data_args, name=None):
255
  for user_name, memories in all_user_memories_docs.items():
256
  if name and user_name != name:
257
  continue
258
- print(f"Building index for user {user_name} (using old method)...")
259
 
260
  # The service_context argument is removed in newer versions.
261
  cur_index = VectorStoreIndex.from_documents(memories)
 
32
  # پشتیبانی هوشمند از Persistent Storage در Hugging Face (/data) یا مسیر محلی
33
  BASE_DIR = "/data" if os.path.exists("/data") else os.path.dirname(os.path.abspath(__file__))
34
 
35
+ # تنظیم مسیر دقیق بر اساس ساختار ریپازیتوری (memory_index/llamaindex)
36
+ _INDEX_BASE_DIR = os.getenv("EMMA_INDEX_DIR", os.path.join(BASE_DIR, "memory_index", "llamaindex"))
 
 
 
37
 
38
+ # اطمینان از وجود دایرکتوری اصلی در صورت ساخت ایندکس جدید
39
  os.makedirs(_INDEX_BASE_DIR, exist_ok=True)
40
 
41
 
 
85
 
86
  # Optional: Configure the embedding model if needed.
87
  # If not set, LlamaIndex defaults to a compatible model (e.g., OpenAI's text-embedding-ada-002).
88
+ # Settings.embed_model = OpenAIEmbedding(api_key=GAPGPTMASKTOKENlgicihcumgiX0X, api_base=GAPGPTMASKTOKENlgicihcumgiX1X)
89
 
90
 
91
  def generate_memory_docs(data, language):
 
171
  if name and user_name != name:
172
  continue
173
 
174
+ print(f"Building indices for user '{user_name}'")
175
 
176
  base_path = os.path.join(_INDEX_BASE_DIR, user_name)
177
 
 
252
  for user_name, memories in all_user_memories_docs.items():
253
  if name and user_name != name:
254
  continue
255
+ print(f"Building index for user {user_name} (using old method)")
256
 
257
  # The service_context argument is removed in newer versions.
258
  cur_index = VectorStoreIndex.from_documents(memories)