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.

Files changed (35) hide show
  1. {mem_llm-1.0.4/mem_llm.egg-info → mem_llm-1.0.6}/PKG-INFO +1 -1
  2. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/__init__.py +1 -1
  3. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/mem_agent.py +81 -24
  4. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/memory_db.py +33 -7
  5. {mem_llm-1.0.4 → mem_llm-1.0.6/mem_llm.egg-info}/PKG-INFO +1 -1
  6. {mem_llm-1.0.4 → mem_llm-1.0.6}/setup.py +1 -1
  7. {mem_llm-1.0.4 → mem_llm-1.0.6}/CHANGELOG.md +0 -0
  8. {mem_llm-1.0.4 → mem_llm-1.0.6}/INTEGRATION_GUIDE.md +0 -0
  9. {mem_llm-1.0.4 → mem_llm-1.0.6}/MANIFEST.in +0 -0
  10. {mem_llm-1.0.4 → mem_llm-1.0.6}/QUICKSTART.md +0 -0
  11. {mem_llm-1.0.4 → mem_llm-1.0.6}/QUICKSTART_TR.md +0 -0
  12. {mem_llm-1.0.4 → mem_llm-1.0.6}/README.md +0 -0
  13. {mem_llm-1.0.4 → mem_llm-1.0.6}/STRUCTURE.md +0 -0
  14. {mem_llm-1.0.4 → mem_llm-1.0.6}/docs/CONFIG_GUIDE.md +0 -0
  15. {mem_llm-1.0.4 → mem_llm-1.0.6}/docs/INDEX.md +0 -0
  16. {mem_llm-1.0.4 → mem_llm-1.0.6}/docs/README.md +0 -0
  17. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/config.yaml.example +0 -0
  18. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/config_from_docs.py +0 -0
  19. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/config_manager.py +0 -0
  20. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/knowledge_loader.py +0 -0
  21. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/llm_client.py +0 -0
  22. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/memory_manager.py +0 -0
  23. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/memory_tools.py +0 -0
  24. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm/prompt_templates.py +0 -0
  25. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/SOURCES.txt +0 -0
  26. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/dependency_links.txt +0 -0
  27. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/requires.txt +0 -0
  28. {mem_llm-1.0.4 → mem_llm-1.0.6}/mem_llm.egg-info/top_level.txt +0 -0
  29. {mem_llm-1.0.4 → mem_llm-1.0.6}/requirements.txt +0 -0
  30. {mem_llm-1.0.4 → mem_llm-1.0.6}/setup.cfg +0 -0
  31. {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_integration.py +0 -0
  32. {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_llm_client.py +0 -0
  33. {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_mem_agent.py +0 -0
  34. {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_memory_manager.py +0 -0
  35. {mem_llm-1.0.4 → mem_llm-1.0.6}/tests/test_memory_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mem-llm
3
- Version: 1.0.4
3
+ Version: 1.0.6
4
4
  Summary: Memory-enabled AI assistant with local LLM support
5
5
  Home-page: https://github.com/emredeveloper/Mem-LLM
6
6
  Author: C. Emre Karataş
@@ -24,7 +24,7 @@ try:
24
24
  except ImportError:
25
25
  __all_pro__ = []
26
26
 
27
- __version__ = "1.0.4"
27
+ __version__ = "1.0.6"
28
28
  __author__ = "C. Emre Karataş"
29
29
 
30
30
  __all__ = [
@@ -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
- updates = {}
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
- # Simple name extraction
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
- updates['name'] = name.strip('.,!?')
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
- updates['favorite_food'] = food
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 "from" in msg_lower:
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
- updates['location'] = location.strip('.,!?')
440
+ extracted['location'] = location.strip('.,!?')
442
441
  break
443
442
 
444
443
  # Save updates
445
- if updates:
444
+ if extracted:
446
445
  try:
447
- self.memory.update_profile(user_id, updates)
448
- self.logger.debug(f"Profile updated for {user_id}: {updates}")
449
- except:
450
- pass
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
- memory_data = self.memory.load_memory(uid)
468
- return memory_data.get('profile', {})
469
- except:
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
- cursor.execute("""
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 (question LIKE ? OR answer LIKE ? OR keywords LIKE ?)
340
+ AND ({where_clause})
317
341
  ORDER BY priority DESC, id DESC
318
342
  LIMIT ?
319
- """, (category, f"%{query}%", f"%{query}%", f"%{query}%", limit))
343
+ """
344
+ cursor.execute(sql, [category] + params + [limit])
320
345
  else:
321
- cursor.execute("""
346
+ sql = f"""
322
347
  SELECT category, question, answer, priority
323
348
  FROM knowledge_base
324
349
  WHERE active = 1
325
- AND (question LIKE ? OR answer LIKE ? OR keywords LIKE ?)
350
+ AND ({where_clause})
326
351
  ORDER BY priority DESC, id DESC
327
352
  LIMIT ?
328
- """, (f"%{query}%", f"%{query}%", f"%{query}%", limit))
353
+ """
354
+ cursor.execute(sql, params + [limit])
329
355
 
330
356
  return [dict(row) for row in cursor.fetchall()]
331
357
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mem-llm
3
- Version: 1.0.4
3
+ Version: 1.0.6
4
4
  Summary: Memory-enabled AI assistant with local LLM support
5
5
  Home-page: https://github.com/emredeveloper/Mem-LLM
6
6
  Author: C. Emre Karataş
@@ -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.4",
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