mem-llm 1.0.4__tar.gz → 1.0.6__tar.gz
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.4/mem_llm.egg-info → mem_llm-1.0.6}/PKG-INFO +1 -1
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/__init__.py +1 -1
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/mem_agent.py +81 -24
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/memory_db.py +33 -7
- {mem_llm-1.0.4 → mem_llm-1.0.6/mem_llm.egg-info}/PKG-INFO +1 -1
- {mem_llm-1.0.4 → mem_llm-1.0.6}/setup.py +1 -1
- {mem_llm-1.0.4 → mem_llm-1.0.6}/CHANGELOG.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/INTEGRATION_GUIDE.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/MANIFEST.in +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/QUICKSTART.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/QUICKSTART_TR.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/README.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/STRUCTURE.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/docs/CONFIG_GUIDE.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/docs/INDEX.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/docs/README.md +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/config.yaml.example +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/config_from_docs.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/config_manager.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/knowledge_loader.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/llm_client.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/memory_manager.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/memory_tools.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/prompt_templates.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/SOURCES.txt +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/dependency_links.txt +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/requires.txt +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/top_level.txt +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/requirements.txt +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/setup.cfg +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_integration.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_llm_client.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_mem_agent.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_memory_manager.py +0 -0
- {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_memory_tools.py +0 -0
|
@@ -407,47 +407,76 @@ REMEMBER: Knowledge base = truth. Always use it when provided!"""
|
|
|
407
407
|
|
|
408
408
|
def _update_user_profile(self, user_id: str, message: str, response: str):
|
|
409
409
|
"""Extract user info from conversation and update profile"""
|
|
410
|
-
if not hasattr(self.memory, 'update_profile'):
|
|
411
|
-
return
|
|
412
|
-
|
|
413
410
|
msg_lower = message.lower()
|
|
414
|
-
|
|
411
|
+
|
|
412
|
+
# Extract information
|
|
413
|
+
extracted = {}
|
|
415
414
|
|
|
416
415
|
# Extract name
|
|
417
|
-
if "my name is" in msg_lower or "i am" in msg_lower or "i'm" in msg_lower:
|
|
418
|
-
|
|
419
|
-
for phrase in ["my name is ", "i am ", "i'm "]:
|
|
416
|
+
if "my name is" in msg_lower or "i am" in msg_lower or "i'm" in msg_lower or "adım" in msg_lower or "ismim" in msg_lower:
|
|
417
|
+
for phrase in ["my name is ", "i am ", "i'm ", "adım ", "ismim ", "benim adım "]:
|
|
420
418
|
if phrase in msg_lower:
|
|
421
419
|
name_part = message[msg_lower.index(phrase) + len(phrase):].strip()
|
|
422
420
|
name = name_part.split()[0] if name_part else None
|
|
423
421
|
if name and len(name) > 1:
|
|
424
|
-
|
|
422
|
+
extracted['name'] = name.strip('.,!?')
|
|
425
423
|
break
|
|
426
424
|
|
|
427
425
|
# Extract favorite food
|
|
428
|
-
if "favorite food" in msg_lower or "favourite food" in msg_lower:
|
|
429
|
-
if "is" in msg_lower:
|
|
430
|
-
food = msg_lower.split("is")[-1].strip().strip(
|
|
426
|
+
if "favorite food" in msg_lower or "favourite food" in msg_lower or "sevdiğim yemek" in msg_lower or "en sevdiğim" in msg_lower:
|
|
427
|
+
if "is" in msg_lower or ":" in msg_lower:
|
|
428
|
+
food = msg_lower.split("is")[-1].strip() if "is" in msg_lower else msg_lower.split(":")[-1].strip()
|
|
429
|
+
food = food.strip('.,!?')
|
|
431
430
|
if food and len(food) < 50:
|
|
432
|
-
|
|
431
|
+
extracted['favorite_food'] = food
|
|
433
432
|
|
|
434
433
|
# Extract location
|
|
435
|
-
if "i live in" in msg_lower or "i'm from" in msg_lower or "
|
|
436
|
-
for phrase in ["i live in ", "i'm from ", "from "]:
|
|
434
|
+
if "i live in" in msg_lower or "i'm from" in msg_lower or "yaşıyorum" in msg_lower or "yaşadığım" in msg_lower:
|
|
435
|
+
for phrase in ["i live in ", "i'm from ", "from ", "yaşıyorum", "yaşadığım yer", "yaşadığım şehir"]:
|
|
437
436
|
if phrase in msg_lower:
|
|
438
437
|
loc = message[msg_lower.index(phrase) + len(phrase):].strip()
|
|
439
438
|
location = loc.split()[0] if loc else None
|
|
440
439
|
if location and len(location) > 2:
|
|
441
|
-
|
|
440
|
+
extracted['location'] = location.strip('.,!?')
|
|
442
441
|
break
|
|
443
442
|
|
|
444
443
|
# Save updates
|
|
445
|
-
if
|
|
444
|
+
if extracted:
|
|
446
445
|
try:
|
|
447
|
-
|
|
448
|
-
self.
|
|
449
|
-
|
|
450
|
-
|
|
446
|
+
# SQL memory - store in preferences JSON
|
|
447
|
+
if hasattr(self.memory, 'update_user_profile'):
|
|
448
|
+
# Get current profile
|
|
449
|
+
profile = self.memory.get_user_profile(user_id) or {}
|
|
450
|
+
|
|
451
|
+
# Update name directly if extracted
|
|
452
|
+
updates = {}
|
|
453
|
+
if 'name' in extracted:
|
|
454
|
+
updates['name'] = extracted.pop('name')
|
|
455
|
+
|
|
456
|
+
# Store other info in preferences
|
|
457
|
+
if extracted:
|
|
458
|
+
current_prefs = profile.get('preferences')
|
|
459
|
+
if current_prefs:
|
|
460
|
+
try:
|
|
461
|
+
prefs = json.loads(current_prefs) if isinstance(current_prefs, str) else current_prefs
|
|
462
|
+
except:
|
|
463
|
+
prefs = {}
|
|
464
|
+
else:
|
|
465
|
+
prefs = {}
|
|
466
|
+
|
|
467
|
+
prefs.update(extracted)
|
|
468
|
+
updates['preferences'] = json.dumps(prefs)
|
|
469
|
+
|
|
470
|
+
if updates:
|
|
471
|
+
self.memory.update_user_profile(user_id, updates)
|
|
472
|
+
self.logger.debug(f"Profile updated for {user_id}: {extracted}")
|
|
473
|
+
|
|
474
|
+
# JSON memory - direct update
|
|
475
|
+
elif hasattr(self.memory, 'update_profile'):
|
|
476
|
+
self.memory.update_profile(user_id, extracted)
|
|
477
|
+
self.logger.debug(f"Profile updated for {user_id}: {extracted}")
|
|
478
|
+
except Exception as e:
|
|
479
|
+
self.logger.error(f"Error updating profile: {e}")
|
|
451
480
|
|
|
452
481
|
def get_user_profile(self, user_id: Optional[str] = None) -> Dict:
|
|
453
482
|
"""
|
|
@@ -457,16 +486,44 @@ REMEMBER: Knowledge base = truth. Always use it when provided!"""
|
|
|
457
486
|
user_id: User ID (uses current_user if not specified)
|
|
458
487
|
|
|
459
488
|
Returns:
|
|
460
|
-
User profile dictionary
|
|
489
|
+
User profile dictionary with all info (name, favorite_food, location, etc.)
|
|
461
490
|
"""
|
|
462
491
|
uid = user_id or self.current_user
|
|
463
492
|
if not uid:
|
|
464
493
|
return {}
|
|
465
494
|
|
|
466
495
|
try:
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
496
|
+
# Check if SQL or JSON memory
|
|
497
|
+
if hasattr(self.memory, 'get_user_profile'):
|
|
498
|
+
# SQL memory - merge preferences into main dict
|
|
499
|
+
profile = self.memory.get_user_profile(uid)
|
|
500
|
+
if not profile:
|
|
501
|
+
return {}
|
|
502
|
+
|
|
503
|
+
# Parse preferences JSON if exists
|
|
504
|
+
result = {
|
|
505
|
+
'user_id': profile.get('user_id'),
|
|
506
|
+
'name': profile.get('name'),
|
|
507
|
+
'first_seen': profile.get('first_seen'),
|
|
508
|
+
'last_interaction': profile.get('last_interaction'),
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
# Merge preferences
|
|
512
|
+
prefs_str = profile.get('preferences')
|
|
513
|
+
if prefs_str:
|
|
514
|
+
try:
|
|
515
|
+
prefs = json.loads(prefs_str) if isinstance(prefs_str, str) else prefs_str
|
|
516
|
+
result.update(prefs) # Add favorite_food, location, etc.
|
|
517
|
+
except:
|
|
518
|
+
pass
|
|
519
|
+
|
|
520
|
+
return result
|
|
521
|
+
else:
|
|
522
|
+
# JSON memory
|
|
523
|
+
memory_data = self.memory.load_memory(uid)
|
|
524
|
+
return memory_data.get('profile', {})
|
|
525
|
+
except Exception as e:
|
|
526
|
+
self.logger.error(f"Error getting user profile: {e}")
|
|
470
527
|
return {}
|
|
471
528
|
|
|
472
529
|
def add_knowledge(self, category: str, question: str, answer: str,
|
|
@@ -295,7 +295,7 @@ class SQLMemoryManager:
|
|
|
295
295
|
def search_knowledge(self, query: str, category: Optional[str] = None,
|
|
296
296
|
limit: int = 5) -> List[Dict]:
|
|
297
297
|
"""
|
|
298
|
-
Bilgi bankasında arama yapar
|
|
298
|
+
Bilgi bankasında arama yapar (gelişmiş keyword matching)
|
|
299
299
|
|
|
300
300
|
Args:
|
|
301
301
|
query: Arama sorgusu
|
|
@@ -307,25 +307,51 @@ class SQLMemoryManager:
|
|
|
307
307
|
"""
|
|
308
308
|
cursor = self.conn.cursor()
|
|
309
309
|
|
|
310
|
+
# Extract important keywords from query (remove question words)
|
|
311
|
+
import re
|
|
312
|
+
stopwords = ['ne', 'kadar', 'nedir', 'nasıl', 'için', 'mı', 'mi', 'mu', 'mü',
|
|
313
|
+
'what', 'how', 'when', 'where', 'is', 'are', 'the', 'a', 'an']
|
|
314
|
+
|
|
315
|
+
# Clean query and extract keywords
|
|
316
|
+
query_lower = query.lower()
|
|
317
|
+
words = re.findall(r'\w+', query_lower)
|
|
318
|
+
keywords = [w for w in words if w not in stopwords and len(w) > 2]
|
|
319
|
+
|
|
320
|
+
# If no keywords, use original query
|
|
321
|
+
if not keywords:
|
|
322
|
+
keywords = [query_lower]
|
|
323
|
+
|
|
324
|
+
# Build search conditions for each keyword
|
|
325
|
+
conditions = []
|
|
326
|
+
params = []
|
|
327
|
+
|
|
328
|
+
for keyword in keywords[:5]: # Max 5 keywords
|
|
329
|
+
conditions.append("(question LIKE ? OR answer LIKE ? OR keywords LIKE ?)")
|
|
330
|
+
params.extend([f"%{keyword}%", f"%{keyword}%", f"%{keyword}%"])
|
|
331
|
+
|
|
332
|
+
where_clause = " OR ".join(conditions) if conditions else "1=1"
|
|
333
|
+
|
|
310
334
|
if category:
|
|
311
|
-
|
|
335
|
+
sql = f"""
|
|
312
336
|
SELECT category, question, answer, priority
|
|
313
337
|
FROM knowledge_base
|
|
314
338
|
WHERE active = 1
|
|
315
339
|
AND category = ?
|
|
316
|
-
AND (
|
|
340
|
+
AND ({where_clause})
|
|
317
341
|
ORDER BY priority DESC, id DESC
|
|
318
342
|
LIMIT ?
|
|
319
|
-
"""
|
|
343
|
+
"""
|
|
344
|
+
cursor.execute(sql, [category] + params + [limit])
|
|
320
345
|
else:
|
|
321
|
-
|
|
346
|
+
sql = f"""
|
|
322
347
|
SELECT category, question, answer, priority
|
|
323
348
|
FROM knowledge_base
|
|
324
349
|
WHERE active = 1
|
|
325
|
-
AND (
|
|
350
|
+
AND ({where_clause})
|
|
326
351
|
ORDER BY priority DESC, id DESC
|
|
327
352
|
LIMIT ?
|
|
328
|
-
"""
|
|
353
|
+
"""
|
|
354
|
+
cursor.execute(sql, params + [limit])
|
|
329
355
|
|
|
330
356
|
return [dict(row) for row in cursor.fetchall()]
|
|
331
357
|
|
|
@@ -11,7 +11,7 @@ long_description = (this_directory / "README.md").read_text(encoding='utf-8')
|
|
|
11
11
|
|
|
12
12
|
setup(
|
|
13
13
|
name="mem-llm",
|
|
14
|
-
version="1.0.
|
|
14
|
+
version="1.0.6",
|
|
15
15
|
author="C. Emre Karataş",
|
|
16
16
|
author_email="karatasqemre@gmail.com", # PyPI için gerekli - kendi emailinizi yazın
|
|
17
17
|
description="Memory-enabled AI assistant with local LLM support",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|