mem-llm 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mem-llm might be problematic. Click here for more details.
- mem_llm-1.0.0.dist-info/METADATA +382 -0
- mem_llm-1.0.0.dist-info/RECORD +14 -0
- mem_llm-1.0.0.dist-info/WHEEL +5 -0
- mem_llm-1.0.0.dist-info/top_level.txt +1 -0
- memory_llm/__init__.py +34 -0
- memory_llm/config.yaml.example +52 -0
- memory_llm/config_manager.py +229 -0
- memory_llm/knowledge_loader.py +88 -0
- memory_llm/llm_client.py +162 -0
- memory_llm/mem_agent.py +512 -0
- memory_llm/memory_db.py +376 -0
- memory_llm/memory_manager.py +257 -0
- memory_llm/memory_tools.py +253 -0
- memory_llm/prompt_templates.py +244 -0
memory_llm/mem_agent.py
ADDED
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mem-Agent: Unified Powerful System
|
|
3
|
+
==================================
|
|
4
|
+
|
|
5
|
+
A powerful Mem-Agent that combines all features in a single system.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- ✅ SQL and JSON memory support
|
|
9
|
+
- ✅ Prompt templates system
|
|
10
|
+
- ✅ Knowledge base integration
|
|
11
|
+
- ✅ User tools system
|
|
12
|
+
- ✅ Configuration management
|
|
13
|
+
- ✅ Advanced logging
|
|
14
|
+
- ✅ Production-ready structure
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
```python
|
|
18
|
+
from memory_llm import MemAgent
|
|
19
|
+
|
|
20
|
+
# Simple usage
|
|
21
|
+
agent = MemAgent()
|
|
22
|
+
|
|
23
|
+
# Advanced usage
|
|
24
|
+
agent = MemAgent(
|
|
25
|
+
config_file="config.yaml",
|
|
26
|
+
use_sql=True,
|
|
27
|
+
load_knowledge_base=True
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from typing import Optional, Dict, List, Any, Union
|
|
33
|
+
from datetime import datetime
|
|
34
|
+
import logging
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
|
|
38
|
+
# Core dependencies
|
|
39
|
+
from .memory_manager import MemoryManager
|
|
40
|
+
from .llm_client import OllamaClient
|
|
41
|
+
|
|
42
|
+
# Advanced features (optional)
|
|
43
|
+
try:
|
|
44
|
+
from .memory_db import SQLMemoryManager
|
|
45
|
+
from .prompt_templates import prompt_manager
|
|
46
|
+
from .knowledge_loader import KnowledgeLoader
|
|
47
|
+
from .config_manager import get_config
|
|
48
|
+
from .memory_tools import ToolExecutor, MemoryTools
|
|
49
|
+
ADVANCED_AVAILABLE = True
|
|
50
|
+
except ImportError:
|
|
51
|
+
ADVANCED_AVAILABLE = False
|
|
52
|
+
print("⚠️ Advanced features not available (install additional packages)")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class MemAgent:
|
|
56
|
+
"""
|
|
57
|
+
Powerful and unified Mem-Agent system
|
|
58
|
+
|
|
59
|
+
Production-ready assistant that combines all features in one place.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __init__(self,
|
|
63
|
+
model: str = "granite4:tiny-h",
|
|
64
|
+
config_file: Optional[str] = None,
|
|
65
|
+
use_sql: bool = True,
|
|
66
|
+
memory_dir: Optional[str] = None,
|
|
67
|
+
load_knowledge_base: bool = True,
|
|
68
|
+
ollama_url: str = "http://localhost:11434"):
|
|
69
|
+
"""
|
|
70
|
+
Args:
|
|
71
|
+
model: LLM model to use
|
|
72
|
+
config_file: Configuration file (optional)
|
|
73
|
+
use_sql: Use SQL database (True) or JSON (False)
|
|
74
|
+
memory_dir: Memory directory
|
|
75
|
+
load_knowledge_base: Automatically load knowledge base
|
|
76
|
+
ollama_url: Ollama API URL
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
# Load configuration
|
|
80
|
+
self.config = None
|
|
81
|
+
if ADVANCED_AVAILABLE and config_file:
|
|
82
|
+
try:
|
|
83
|
+
self.config = get_config(config_file)
|
|
84
|
+
except Exception:
|
|
85
|
+
print("⚠️ Config file could not be loaded, using default settings")
|
|
86
|
+
|
|
87
|
+
# Determine usage mode
|
|
88
|
+
self.usage_mode = "business" # default
|
|
89
|
+
if self.config:
|
|
90
|
+
self.usage_mode = self.config.get("usage_mode", "business")
|
|
91
|
+
elif config_file:
|
|
92
|
+
# Config file exists but couldn't be loaded
|
|
93
|
+
self.usage_mode = "business"
|
|
94
|
+
else:
|
|
95
|
+
# No config file
|
|
96
|
+
self.usage_mode = "personal"
|
|
97
|
+
|
|
98
|
+
# Setup logging
|
|
99
|
+
self._setup_logging()
|
|
100
|
+
|
|
101
|
+
# Memory system selection
|
|
102
|
+
if use_sql and ADVANCED_AVAILABLE:
|
|
103
|
+
# SQL memory (advanced)
|
|
104
|
+
db_path = memory_dir or self.config.get("memory.db_path", "memories.db") if self.config else "memories.db"
|
|
105
|
+
self.memory = SQLMemoryManager(db_path)
|
|
106
|
+
self.logger.info(f"SQL memory system active: {db_path}")
|
|
107
|
+
else:
|
|
108
|
+
# JSON memory (simple)
|
|
109
|
+
json_dir = memory_dir or self.config.get("memory.json_dir", "memories") if self.config else "memories"
|
|
110
|
+
self.memory = MemoryManager(json_dir)
|
|
111
|
+
self.logger.info(f"JSON memory system active: {json_dir}")
|
|
112
|
+
|
|
113
|
+
# LLM client
|
|
114
|
+
self.llm = OllamaClient(model, ollama_url)
|
|
115
|
+
self.logger.info(f"LLM client ready: {model}")
|
|
116
|
+
|
|
117
|
+
# Advanced features (if available)
|
|
118
|
+
if ADVANCED_AVAILABLE:
|
|
119
|
+
self._setup_advanced_features(load_knowledge_base)
|
|
120
|
+
else:
|
|
121
|
+
print("⚠️ Load additional packages for advanced features")
|
|
122
|
+
|
|
123
|
+
# Active user and system prompt
|
|
124
|
+
self.current_user: Optional[str] = None
|
|
125
|
+
self.current_system_prompt: Optional[str] = None
|
|
126
|
+
|
|
127
|
+
# Tool system (always available)
|
|
128
|
+
self.tool_executor = ToolExecutor(self.memory)
|
|
129
|
+
|
|
130
|
+
self.logger.info("MemAgent successfully initialized")
|
|
131
|
+
|
|
132
|
+
# === UNIFIED SYSTEM METHODS ===
|
|
133
|
+
|
|
134
|
+
def _setup_logging(self) -> None:
|
|
135
|
+
"""Setup logging system"""
|
|
136
|
+
log_config = {}
|
|
137
|
+
if ADVANCED_AVAILABLE and hasattr(self, 'config') and self.config:
|
|
138
|
+
log_config = self.config.get("logging", {})
|
|
139
|
+
|
|
140
|
+
if log_config.get("enabled", True):
|
|
141
|
+
logging.basicConfig(
|
|
142
|
+
level=getattr(logging, log_config.get("level", "INFO")),
|
|
143
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
144
|
+
handlers=[
|
|
145
|
+
logging.FileHandler(log_config.get("file", "mem_agent.log")),
|
|
146
|
+
logging.StreamHandler()
|
|
147
|
+
]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
self.logger = logging.getLogger("MemAgent")
|
|
151
|
+
|
|
152
|
+
def _setup_advanced_features(self, load_knowledge_base: bool) -> None:
|
|
153
|
+
"""Setup advanced features"""
|
|
154
|
+
# Load knowledge base (according to usage mode)
|
|
155
|
+
if load_knowledge_base:
|
|
156
|
+
kb_loader = KnowledgeLoader(self.memory)
|
|
157
|
+
|
|
158
|
+
# Get KB settings from config
|
|
159
|
+
if hasattr(self, 'config') and self.config:
|
|
160
|
+
kb_config = self.config.get("knowledge_base", {})
|
|
161
|
+
|
|
162
|
+
# Select default KB according to usage mode
|
|
163
|
+
if self.usage_mode == "business":
|
|
164
|
+
default_kb = kb_config.get("default_kb", "business_tech_support")
|
|
165
|
+
else: # personal
|
|
166
|
+
default_kb = kb_config.get("default_kb", "personal_learning")
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
if default_kb == "ecommerce":
|
|
170
|
+
count = kb_loader.load_default_ecommerce_kb()
|
|
171
|
+
self.logger.info(f"E-commerce knowledge base loaded: {count} records")
|
|
172
|
+
elif default_kb == "tech_support":
|
|
173
|
+
count = kb_loader.load_default_tech_support_kb()
|
|
174
|
+
self.logger.info(f"Technical support knowledge base loaded: {count} records")
|
|
175
|
+
elif default_kb == "business_tech_support":
|
|
176
|
+
count = kb_loader.load_default_tech_support_kb()
|
|
177
|
+
self.logger.info(f"Corporate technical support knowledge base loaded: {count} records")
|
|
178
|
+
elif default_kb == "personal_learning":
|
|
179
|
+
# Simple KB for personal learning
|
|
180
|
+
count = kb_loader.load_default_ecommerce_kb() # Temporarily use the same KB
|
|
181
|
+
self.logger.info(f"Personal learning knowledge base loaded: {count} records")
|
|
182
|
+
except Exception as e:
|
|
183
|
+
self.logger.error(f"Knowledge base loading error: {e}")
|
|
184
|
+
|
|
185
|
+
# Load system prompt (according to usage mode)
|
|
186
|
+
if hasattr(self, 'config') and self.config:
|
|
187
|
+
prompt_config = self.config.get("prompt", {})
|
|
188
|
+
|
|
189
|
+
# Select default template according to usage mode
|
|
190
|
+
if self.usage_mode == "business":
|
|
191
|
+
default_template = "business_customer_service"
|
|
192
|
+
else: # personal
|
|
193
|
+
default_template = "personal_assistant"
|
|
194
|
+
|
|
195
|
+
template_name = prompt_config.get("template", default_template)
|
|
196
|
+
variables = prompt_config.get("variables", {})
|
|
197
|
+
|
|
198
|
+
# Additional variables for business mode
|
|
199
|
+
if self.usage_mode == "business":
|
|
200
|
+
business_config = self.config.get("business", {})
|
|
201
|
+
variables.update({
|
|
202
|
+
"company_name": business_config.get("company_name", "Our Company"),
|
|
203
|
+
"founded_year": business_config.get("founded_year", "2010"),
|
|
204
|
+
"employee_count": business_config.get("employee_count", "100+"),
|
|
205
|
+
"industry": business_config.get("industry", "Teknoloji")
|
|
206
|
+
})
|
|
207
|
+
else: # personal
|
|
208
|
+
personal_config = self.config.get("personal", {})
|
|
209
|
+
variables.update({
|
|
210
|
+
"user_name": personal_config.get("user_name", "User"),
|
|
211
|
+
"timezone": personal_config.get("timezone", "Europe/London")
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
variables['current_date'] = datetime.now().strftime("%Y-%m-%d")
|
|
216
|
+
self.current_system_prompt = prompt_manager.render_prompt(template_name, **variables)
|
|
217
|
+
self.logger.info(f"Prompt template loaded: {template_name} (Mode: {self.usage_mode})")
|
|
218
|
+
except Exception as e:
|
|
219
|
+
self.logger.error(f"Prompt template loading error: {e}")
|
|
220
|
+
self.current_system_prompt = f"You are a helpful assistant in {self.usage_mode} mode."
|
|
221
|
+
|
|
222
|
+
def check_setup(self) -> Dict[str, Any]:
|
|
223
|
+
"""Check system setup"""
|
|
224
|
+
ollama_running = self.llm.check_connection()
|
|
225
|
+
models = self.llm.list_models()
|
|
226
|
+
model_exists = self.llm.model in models
|
|
227
|
+
|
|
228
|
+
# Memory statistics
|
|
229
|
+
try:
|
|
230
|
+
if hasattr(self.memory, 'get_statistics'):
|
|
231
|
+
stats = self.memory.get_statistics()
|
|
232
|
+
else:
|
|
233
|
+
# Simple statistics for JSON memory
|
|
234
|
+
stats = {
|
|
235
|
+
"total_users": 0,
|
|
236
|
+
"total_interactions": 0,
|
|
237
|
+
"knowledge_base_entries": 0
|
|
238
|
+
}
|
|
239
|
+
except Exception:
|
|
240
|
+
stats = {
|
|
241
|
+
"total_users": 0,
|
|
242
|
+
"total_interactions": 0,
|
|
243
|
+
"knowledge_base_entries": 0
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
"ollama_running": ollama_running,
|
|
248
|
+
"available_models": models,
|
|
249
|
+
"target_model": self.llm.model,
|
|
250
|
+
"model_ready": model_exists,
|
|
251
|
+
"memory_backend": "SQL" if ADVANCED_AVAILABLE and isinstance(self.memory, SQLMemoryManager) else "JSON",
|
|
252
|
+
"total_users": stats.get('total_users', 0),
|
|
253
|
+
"total_interactions": stats.get('total_interactions', 0),
|
|
254
|
+
"kb_entries": stats.get('knowledge_base_entries', 0),
|
|
255
|
+
"status": "ready" if (ollama_running and model_exists) else "not_ready"
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
def set_user(self, user_id: str, name: Optional[str] = None) -> None:
|
|
259
|
+
"""
|
|
260
|
+
Set active user
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
user_id: User ID
|
|
264
|
+
name: User name (optional)
|
|
265
|
+
"""
|
|
266
|
+
self.current_user = user_id
|
|
267
|
+
|
|
268
|
+
# Add user for SQL memory
|
|
269
|
+
if ADVANCED_AVAILABLE and isinstance(self.memory, SQLMemoryManager):
|
|
270
|
+
self.memory.add_user(user_id, name)
|
|
271
|
+
|
|
272
|
+
# Update user name (if provided)
|
|
273
|
+
if name:
|
|
274
|
+
if hasattr(self.memory, 'update_user_profile'):
|
|
275
|
+
self.memory.update_user_profile(user_id, {"name": name})
|
|
276
|
+
|
|
277
|
+
self.logger.debug(f"Active user set: {user_id}")
|
|
278
|
+
|
|
279
|
+
def chat(self, message: str, user_id: Optional[str] = None,
|
|
280
|
+
metadata: Optional[Dict] = None) -> str:
|
|
281
|
+
"""
|
|
282
|
+
Chat with user
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
message: User's message
|
|
286
|
+
user_id: User ID (optional)
|
|
287
|
+
metadata: Additional information
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
Bot's response
|
|
291
|
+
"""
|
|
292
|
+
# Determine user
|
|
293
|
+
if user_id:
|
|
294
|
+
self.set_user(user_id)
|
|
295
|
+
elif not self.current_user:
|
|
296
|
+
return "Error: User ID not specified."
|
|
297
|
+
|
|
298
|
+
user_id = self.current_user
|
|
299
|
+
|
|
300
|
+
# Check tool commands first
|
|
301
|
+
tool_result = self.tool_executor.execute_user_command(message, user_id)
|
|
302
|
+
if tool_result:
|
|
303
|
+
return tool_result
|
|
304
|
+
|
|
305
|
+
# Knowledge base search (if using SQL)
|
|
306
|
+
kb_context = ""
|
|
307
|
+
if ADVANCED_AVAILABLE and isinstance(self.memory, SQLMemoryManager) and hasattr(self, 'config') and self.config:
|
|
308
|
+
if self.config.get("response.use_knowledge_base", True):
|
|
309
|
+
try:
|
|
310
|
+
kb_results = self.memory.search_knowledge(
|
|
311
|
+
query=message,
|
|
312
|
+
limit=self.config.get("knowledge_base.search_limit", 5)
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
if kb_results:
|
|
316
|
+
kb_context = "\n\nRelevant Information:\n"
|
|
317
|
+
for i, result in enumerate(kb_results, 1):
|
|
318
|
+
kb_context += f"{i}. S: {result['question']}\n C: {result['answer']}\n"
|
|
319
|
+
except Exception as e:
|
|
320
|
+
self.logger.error(f"Knowledge base search error: {e}")
|
|
321
|
+
|
|
322
|
+
# Get conversation history
|
|
323
|
+
messages = []
|
|
324
|
+
if self.current_system_prompt:
|
|
325
|
+
messages.append({"role": "system", "content": self.current_system_prompt})
|
|
326
|
+
|
|
327
|
+
# Add memory history
|
|
328
|
+
try:
|
|
329
|
+
if hasattr(self.memory, 'get_recent_conversations'):
|
|
330
|
+
recent_limit = self.config.get("response.recent_conversations_limit", 5) if hasattr(self, 'config') and self.config else 5
|
|
331
|
+
recent_convs = self.memory.get_recent_conversations(user_id, recent_limit)
|
|
332
|
+
|
|
333
|
+
for conv in reversed(recent_convs):
|
|
334
|
+
messages.append({"role": "user", "content": conv.get('user_message', '')})
|
|
335
|
+
messages.append({"role": "assistant", "content": conv.get('bot_response', '')})
|
|
336
|
+
except Exception as e:
|
|
337
|
+
self.logger.error(f"Memory history loading error: {e}")
|
|
338
|
+
|
|
339
|
+
# Add knowledge base context
|
|
340
|
+
if kb_context:
|
|
341
|
+
messages.append({
|
|
342
|
+
"role": "system",
|
|
343
|
+
"content": f"You can use this information when answering the user's question:{kb_context}"
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
# Add current message
|
|
347
|
+
messages.append({"role": "user", "content": message})
|
|
348
|
+
|
|
349
|
+
# Get response from LLM
|
|
350
|
+
try:
|
|
351
|
+
response = self.llm.chat(
|
|
352
|
+
messages=messages,
|
|
353
|
+
temperature=self.config.get("llm.temperature", 0.7) if hasattr(self, 'config') and self.config else 0.7,
|
|
354
|
+
max_tokens=self.config.get("llm.max_tokens", 500) if hasattr(self, 'config') and self.config else 500
|
|
355
|
+
)
|
|
356
|
+
except Exception as e:
|
|
357
|
+
self.logger.error(f"LLM response error: {e}")
|
|
358
|
+
response = "Sorry, I cannot respond right now. Please try again later."
|
|
359
|
+
|
|
360
|
+
# Save interaction
|
|
361
|
+
try:
|
|
362
|
+
if hasattr(self.memory, 'add_interaction'):
|
|
363
|
+
self.memory.add_interaction(
|
|
364
|
+
user_id=user_id,
|
|
365
|
+
user_message=message,
|
|
366
|
+
bot_response=response,
|
|
367
|
+
metadata=metadata
|
|
368
|
+
)
|
|
369
|
+
except Exception as e:
|
|
370
|
+
self.logger.error(f"Interaction saving error: {e}")
|
|
371
|
+
|
|
372
|
+
return response
|
|
373
|
+
|
|
374
|
+
def add_knowledge(self, category: str, question: str, answer: str,
|
|
375
|
+
keywords: Optional[List[str]] = None, priority: int = 0) -> int:
|
|
376
|
+
"""Add new record to knowledge base"""
|
|
377
|
+
if not ADVANCED_AVAILABLE or not isinstance(self.memory, SQLMemoryManager):
|
|
378
|
+
return 0
|
|
379
|
+
|
|
380
|
+
try:
|
|
381
|
+
kb_id = self.memory.add_knowledge(category, question, answer, keywords, priority)
|
|
382
|
+
self.logger.info(f"New knowledge added: {category} - {kb_id}")
|
|
383
|
+
return kb_id
|
|
384
|
+
except Exception as e:
|
|
385
|
+
self.logger.error(f"Knowledge adding error: {e}")
|
|
386
|
+
return 0
|
|
387
|
+
|
|
388
|
+
def get_statistics(self) -> Dict[str, Any]:
|
|
389
|
+
"""Returns general statistics"""
|
|
390
|
+
try:
|
|
391
|
+
if hasattr(self.memory, 'get_statistics'):
|
|
392
|
+
return self.memory.get_statistics()
|
|
393
|
+
else:
|
|
394
|
+
# Simple statistics for JSON memory
|
|
395
|
+
return {
|
|
396
|
+
"total_users": 0,
|
|
397
|
+
"total_interactions": 0,
|
|
398
|
+
"memory_backend": "JSON"
|
|
399
|
+
}
|
|
400
|
+
except Exception as e:
|
|
401
|
+
self.logger.error(f"Statistics retrieval error: {e}")
|
|
402
|
+
return {}
|
|
403
|
+
|
|
404
|
+
def search_history(self, keyword: str, user_id: Optional[str] = None) -> List[Dict]:
|
|
405
|
+
"""Search in user history"""
|
|
406
|
+
uid = user_id or self.current_user
|
|
407
|
+
if not uid:
|
|
408
|
+
return []
|
|
409
|
+
|
|
410
|
+
try:
|
|
411
|
+
if hasattr(self.memory, 'search_conversations'):
|
|
412
|
+
return self.memory.search_conversations(uid, keyword)
|
|
413
|
+
else:
|
|
414
|
+
return []
|
|
415
|
+
except Exception as e:
|
|
416
|
+
self.logger.error(f"History search error: {e}")
|
|
417
|
+
return []
|
|
418
|
+
|
|
419
|
+
def show_user_info(self, user_id: Optional[str] = None) -> str:
|
|
420
|
+
"""Shows user information"""
|
|
421
|
+
uid = user_id or self.current_user
|
|
422
|
+
if not uid:
|
|
423
|
+
return "User ID not specified."
|
|
424
|
+
|
|
425
|
+
try:
|
|
426
|
+
if hasattr(self.memory, 'get_user_profile'):
|
|
427
|
+
profile = self.memory.get_user_profile(uid)
|
|
428
|
+
if profile:
|
|
429
|
+
return f"User: {uid}\nName: {profile.get('name', 'Unknown')}\nFirst conversation: {profile.get('first_seen', 'Unknown')}"
|
|
430
|
+
else:
|
|
431
|
+
return f"User {uid} not found."
|
|
432
|
+
else:
|
|
433
|
+
return "This feature is not available."
|
|
434
|
+
except Exception as e:
|
|
435
|
+
return f"Error: {str(e)}"
|
|
436
|
+
|
|
437
|
+
def export_memory(self, user_id: Optional[str] = None, format: str = "json") -> str:
|
|
438
|
+
"""Export user data"""
|
|
439
|
+
uid = user_id or self.current_user
|
|
440
|
+
if not uid:
|
|
441
|
+
return "User ID not specified."
|
|
442
|
+
|
|
443
|
+
try:
|
|
444
|
+
if hasattr(self.memory, 'get_recent_conversations') and hasattr(self.memory, 'get_user_profile'):
|
|
445
|
+
conversations = self.memory.get_recent_conversations(uid, 1000)
|
|
446
|
+
profile = self.memory.get_user_profile(uid)
|
|
447
|
+
|
|
448
|
+
if format == "json":
|
|
449
|
+
export_data = {
|
|
450
|
+
"user_id": uid,
|
|
451
|
+
"export_date": datetime.now().isoformat(),
|
|
452
|
+
"profile": profile,
|
|
453
|
+
"conversations": conversations
|
|
454
|
+
}
|
|
455
|
+
return json.dumps(export_data, ensure_ascii=False, indent=2)
|
|
456
|
+
elif format == "txt":
|
|
457
|
+
result = f"{uid} user conversation history\n"
|
|
458
|
+
result += f"Export date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
|
|
459
|
+
result += "=" * 60 + "\n\n"
|
|
460
|
+
|
|
461
|
+
for i, conv in enumerate(conversations, 1):
|
|
462
|
+
result += f"Conversation {i}:\n"
|
|
463
|
+
result += f"Date: {conv.get('timestamp', 'Unknown')}\n"
|
|
464
|
+
result += f"User: {conv.get('user_message', '')}\n"
|
|
465
|
+
result += f"Bot: {conv.get('bot_response', '')}\n"
|
|
466
|
+
result += "-" * 40 + "\n"
|
|
467
|
+
|
|
468
|
+
return result
|
|
469
|
+
else:
|
|
470
|
+
return "Unsupported format. Use json or txt."
|
|
471
|
+
else:
|
|
472
|
+
return "This feature is not available."
|
|
473
|
+
except Exception as e:
|
|
474
|
+
return f"Export error: {str(e)}"
|
|
475
|
+
|
|
476
|
+
def clear_user_data(self, user_id: Optional[str] = None, confirm: bool = False) -> str:
|
|
477
|
+
"""Delete user data"""
|
|
478
|
+
uid = user_id or self.current_user
|
|
479
|
+
if not uid:
|
|
480
|
+
return "User ID not specified."
|
|
481
|
+
|
|
482
|
+
if not confirm:
|
|
483
|
+
return "Use confirm=True parameter to delete data."
|
|
484
|
+
|
|
485
|
+
try:
|
|
486
|
+
if hasattr(self.memory, 'clear_memory'):
|
|
487
|
+
self.memory.clear_memory(uid)
|
|
488
|
+
return f"All data for user {uid} has been deleted."
|
|
489
|
+
else:
|
|
490
|
+
return "This feature is not available."
|
|
491
|
+
except Exception as e:
|
|
492
|
+
return f"Deletion error: {str(e)}"
|
|
493
|
+
|
|
494
|
+
def list_available_tools(self) -> str:
|
|
495
|
+
"""List available tools"""
|
|
496
|
+
if ADVANCED_AVAILABLE:
|
|
497
|
+
return self.tool_executor.memory_tools.list_available_tools()
|
|
498
|
+
else:
|
|
499
|
+
return "Tool system not available."
|
|
500
|
+
|
|
501
|
+
def close(self) -> None:
|
|
502
|
+
"""Clean up resources"""
|
|
503
|
+
if hasattr(self.memory, 'close'):
|
|
504
|
+
self.memory.close()
|
|
505
|
+
self.logger.info("MemAgent closed")
|
|
506
|
+
|
|
507
|
+
def __enter__(self):
|
|
508
|
+
return self
|
|
509
|
+
|
|
510
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
511
|
+
self.close()
|
|
512
|
+
|