mem-llm 1.3.1__py3-none-any.whl → 1.3.2__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.

@@ -0,0 +1,278 @@
1
+ """
2
+ Vector Store Abstraction Layer
3
+ Supports multiple vector databases (Chroma, FAISS, etc.)
4
+ """
5
+
6
+ from abc import ABC, abstractmethod
7
+ from typing import List, Dict, Optional, Any
8
+ import logging
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class VectorStore(ABC):
14
+ """Abstract interface for vector stores"""
15
+
16
+ @abstractmethod
17
+ def add_documents(self, documents: List[Dict[str, Any]]) -> None:
18
+ """
19
+ Add documents to vector store
20
+
21
+ Args:
22
+ documents: List of dicts with 'id', 'text', 'metadata'
23
+ """
24
+ pass
25
+
26
+ @abstractmethod
27
+ def search(self, query: str, limit: int = 5, filter_metadata: Optional[Dict] = None) -> List[Dict[str, Any]]:
28
+ """
29
+ Search similar documents
30
+
31
+ Args:
32
+ query: Search query text
33
+ limit: Maximum number of results
34
+ filter_metadata: Optional metadata filters
35
+
36
+ Returns:
37
+ List of similar documents with scores
38
+ """
39
+ pass
40
+
41
+ @abstractmethod
42
+ def delete_collection(self) -> None:
43
+ """Delete all vectors in collection"""
44
+ pass
45
+
46
+ @abstractmethod
47
+ def get_stats(self) -> Dict[str, Any]:
48
+ """Get statistics about the vector store"""
49
+ pass
50
+
51
+
52
+ try:
53
+ import chromadb
54
+ from chromadb.config import Settings
55
+ CHROMA_AVAILABLE = True
56
+ except ImportError:
57
+ CHROMA_AVAILABLE = False
58
+ logger.warning("ChromaDB not available. Install with: pip install chromadb")
59
+
60
+
61
+ class ChromaVectorStore(VectorStore):
62
+ """ChromaDB implementation of VectorStore"""
63
+
64
+ def __init__(self, collection_name: str = "knowledge_base",
65
+ persist_directory: Optional[str] = None,
66
+ embedding_model: str = "all-MiniLM-L6-v2"):
67
+ """
68
+ Initialize ChromaDB vector store
69
+
70
+ Args:
71
+ collection_name: Name of the collection
72
+ persist_directory: Directory to persist data (None = in-memory)
73
+ embedding_model: Embedding model name (sentence-transformers compatible)
74
+ """
75
+ if not CHROMA_AVAILABLE:
76
+ raise ImportError(
77
+ "ChromaDB is not installed. Install with: pip install chromadb"
78
+ )
79
+
80
+ self.collection_name = collection_name
81
+ self.persist_directory = persist_directory
82
+ self.embedding_model = embedding_model
83
+
84
+ # Initialize Chroma client
85
+ if persist_directory:
86
+ self.client = chromadb.PersistentClient(path=persist_directory)
87
+ else:
88
+ self.client = chromadb.Client()
89
+
90
+ # Lazy load embedding model
91
+ self._embedding_fn = None
92
+
93
+ # Get or create collection with embedding function
94
+ try:
95
+ # Create embedding function
96
+ embedding_fn = self._get_embedding_function()
97
+
98
+ self.collection = self.client.get_or_create_collection(
99
+ name=collection_name,
100
+ embedding_function=embedding_fn,
101
+ metadata={"hnsw:space": "cosine"}
102
+ )
103
+ except Exception as e:
104
+ logger.error(f"Failed to create Chroma collection: {e}")
105
+ raise
106
+
107
+ def _get_embedding_function(self):
108
+ """Lazy load embedding function"""
109
+ if self._embedding_fn is None:
110
+ try:
111
+ # Try to use ChromaDB's native SentenceTransformerEmbeddingFunction
112
+ try:
113
+ # Try different import paths for ChromaDB embedding functions
114
+ try:
115
+ from chromadb.utils import embedding_functions
116
+ embedding_fn_class = embedding_functions.SentenceTransformerEmbeddingFunction
117
+ except (ImportError, AttributeError):
118
+ try:
119
+ from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction as embedding_fn_class
120
+ except ImportError:
121
+ embedding_fn_class = None
122
+
123
+ if embedding_fn_class:
124
+ self._embedding_fn = embedding_fn_class(model_name=self.embedding_model)
125
+ logger.info(f"Loaded embedding model using ChromaDB native function: {self.embedding_model}")
126
+ else:
127
+ raise AttributeError("SentenceTransformerEmbeddingFunction not found")
128
+
129
+ except (ImportError, AttributeError, Exception) as e:
130
+ # Fallback: Custom embedding function wrapper compatible with ChromaDB
131
+ from sentence_transformers import SentenceTransformer
132
+ model = SentenceTransformer(self.embedding_model)
133
+
134
+ class CustomEmbeddingFunction:
135
+ def __init__(self, model, model_name):
136
+ self.model = model
137
+ self.model_name = model_name
138
+ self.name = model_name # ChromaDB may check for 'name' attribute
139
+
140
+ def __call__(self, texts: List[str]) -> List[List[float]]:
141
+ embeddings = self.model.encode(texts, show_progress_bar=False)
142
+ return embeddings.tolist()
143
+
144
+ def encode_queries(self, queries: List[str]) -> List[List[float]]:
145
+ return self.__call__(queries)
146
+
147
+ self._embedding_fn = CustomEmbeddingFunction(model, self.embedding_model)
148
+ logger.info(f"Loaded embedding model using custom wrapper: {self.embedding_model} (fallback: {e})")
149
+ except ImportError:
150
+ raise ImportError(
151
+ "sentence-transformers not installed. "
152
+ "Install with: pip install sentence-transformers"
153
+ )
154
+
155
+ return self._embedding_fn
156
+
157
+ def add_documents(self, documents: List[Dict[str, Any]]) -> None:
158
+ """Add documents to ChromaDB"""
159
+ if not documents:
160
+ return
161
+
162
+ # Prepare data
163
+ ids = []
164
+ texts = []
165
+ metadatas = []
166
+
167
+ for doc in documents:
168
+ doc_id = str(doc.get('id', doc.get('text', ''))[:100])
169
+ # Ensure unique IDs
170
+ if doc_id in ids:
171
+ doc_id = f"{doc_id}_{len(ids)}"
172
+ ids.append(doc_id)
173
+ texts.append(doc['text'])
174
+ # Ensure metadata values are JSON-serializable
175
+ metadata = doc.get('metadata', {})
176
+ clean_metadata = {}
177
+ for k, v in metadata.items():
178
+ if isinstance(v, (str, int, float, bool)) or v is None:
179
+ clean_metadata[k] = v
180
+ else:
181
+ clean_metadata[k] = str(v)
182
+ metadatas.append(clean_metadata)
183
+
184
+ # Add to collection (Chroma will use embedding function automatically)
185
+ try:
186
+ self.collection.add(
187
+ ids=ids,
188
+ documents=texts,
189
+ metadatas=metadatas
190
+ )
191
+
192
+ logger.debug(f"Added {len(documents)} documents to Chroma")
193
+ except Exception as e:
194
+ logger.error(f"Error adding documents to Chroma: {e}")
195
+ raise
196
+
197
+ def search(self, query: str, limit: int = 5,
198
+ filter_metadata: Optional[Dict] = None) -> List[Dict[str, Any]]:
199
+ """Search in ChromaDB"""
200
+ try:
201
+ # Build where clause for metadata filtering
202
+ where = None
203
+ if filter_metadata:
204
+ where = filter_metadata
205
+
206
+ # Search (Chroma will use embedding function automatically)
207
+ results = self.collection.query(
208
+ query_texts=[query],
209
+ n_results=limit,
210
+ where=where
211
+ )
212
+
213
+ # Format results
214
+ formatted_results = []
215
+ if results.get('documents') and len(results['documents']) > 0 and len(results['documents'][0]) > 0:
216
+ num_results = len(results['documents'][0])
217
+ distances = results.get('distances', [[0.0] * num_results])
218
+
219
+ for i in range(num_results):
220
+ # ChromaDB uses cosine distance (0 = identical, 1 = opposite)
221
+ # Convert to similarity score (1 = identical, 0 = opposite)
222
+ distance = distances[0][i] if distances and len(distances[0]) > i else 0.0
223
+ similarity = 1.0 - distance if distance <= 1.0 else max(0.0, 1.0 / (1.0 + distance))
224
+
225
+ formatted_results.append({
226
+ 'id': results['ids'][0][i] if results.get('ids') and len(results['ids'][0]) > i else f"doc_{i}",
227
+ 'text': results['documents'][0][i],
228
+ 'metadata': results['metadatas'][0][i] if results.get('metadatas') and len(results['metadatas'][0]) > i else {},
229
+ 'score': similarity
230
+ })
231
+
232
+ return formatted_results
233
+ except Exception as e:
234
+ logger.error(f"Error searching Chroma: {e}")
235
+ return []
236
+
237
+ def delete_collection(self) -> None:
238
+ """Delete collection"""
239
+ try:
240
+ self.client.delete_collection(self.collection_name)
241
+ logger.info(f"Deleted Chroma collection: {self.collection_name}")
242
+ except Exception as e:
243
+ logger.error(f"Error deleting collection: {e}")
244
+
245
+ def get_stats(self) -> Dict[str, Any]:
246
+ """Get collection statistics"""
247
+ try:
248
+ count = self.collection.count()
249
+ return {
250
+ 'total_documents': count,
251
+ 'collection_name': self.collection_name,
252
+ 'embedding_model': self.embedding_model
253
+ }
254
+ except Exception as e:
255
+ logger.error(f"Error getting stats: {e}")
256
+ return {'total_documents': 0}
257
+
258
+
259
+ def create_vector_store(store_type: str = "chroma", **kwargs) -> Optional[VectorStore]:
260
+ """
261
+ Factory function to create vector store
262
+
263
+ Args:
264
+ store_type: Type of vector store ('chroma', 'faiss', etc.)
265
+ **kwargs: Store-specific parameters
266
+
267
+ Returns:
268
+ VectorStore instance or None if not available
269
+ """
270
+ if store_type == "chroma":
271
+ if not CHROMA_AVAILABLE:
272
+ logger.warning("ChromaDB not available. Install with: pip install chromadb")
273
+ return None
274
+ return ChromaVectorStore(**kwargs)
275
+ else:
276
+ logger.warning(f"Unknown vector store type: {store_type}")
277
+ return None
278
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mem-llm
3
- Version: 1.3.1
3
+ Version: 1.3.2
4
4
  Summary: Memory-enabled AI assistant with multi-backend LLM support (Ollama, LM Studio, Gemini) - Local and cloud ready
5
5
  Author-email: "C. Emre Karataş" <karatasqemre@gmail.com>
6
6
  License: MIT
@@ -70,7 +70,14 @@ Mem-LLM is a powerful Python library that brings persistent memory capabilities
70
70
  - **Issues**: https://github.com/emredeveloper/Mem-LLM/issues
71
71
  - **Documentation**: See examples/ directory
72
72
 
73
- ## 🆕 What's New in v1.3.0
73
+ ## 🆕 What's New in v1.3.2
74
+
75
+ - 📊 **Response Metrics** (v1.3.1+) – Track confidence, latency, KB usage, and quality analytics
76
+ - 🔍 **Vector Search** (v1.3.2+) – Semantic search with ChromaDB, cross-lingual support
77
+ - 🎯 **Quality Monitoring** – Production-ready metrics for response quality
78
+ - 🌐 **Semantic Understanding** – Understands meaning, not just keywords
79
+
80
+ ## What's New in v1.3.0
74
81
 
75
82
  - 🔌 **Multi-Backend Support**: Choose between Ollama (local), LM Studio (local), or Google Gemini (cloud)
76
83
  - 🏗️ **Factory Pattern**: Clean, extensible architecture for easy backend switching
@@ -79,12 +86,14 @@ Mem-LLM is a powerful Python library that brings persistent memory capabilities
79
86
  - 📚 **New Examples**: 4 additional examples showing multi-backend usage
80
87
  - 🎯 **Backward Compatible**: All v1.2.0 code still works without changes
81
88
 
82
- [See full changelog](CHANGELOG.md#130---2025-10-31)
89
+ [See full changelog](CHANGELOG.md)
83
90
 
84
91
  ## ✨ Key Features
85
92
 
86
93
  - 🔌 **Multi-Backend Support** (v1.3.0+) - Choose Ollama, LM Studio, or Gemini with unified API
87
94
  - 🔍 **Auto-Detection** (v1.3.0+) - Automatically find and use available LLM services
95
+ - 📊 **Response Metrics** (v1.3.1+) - Track confidence, latency, KB usage, and quality analytics
96
+ - 🔍 **Vector Search** (v1.3.2+) - Semantic search with ChromaDB, cross-lingual support
88
97
  - 🧠 **Persistent Memory** - Remembers conversations across sessions
89
98
  - 🤖 **Universal Model Support** - Works with 100+ Ollama models, LM Studio models, and Gemini
90
99
  - 💾 **Dual Storage Modes** - JSON (simple) or SQLite (advanced) memory backends
@@ -1,9 +1,9 @@
1
- mem_llm/__init__.py,sha256=e65UMPGqGj69SwDeUkvVE_W4KijKAtI8Jxfn_40Xuc4,2636
1
+ mem_llm/__init__.py,sha256=fKHDaLkOUE4uFqaTkqfKcop4Ckz9qfFOTKGcfz6BGlE,2918
2
2
  mem_llm/base_llm_client.py,sha256=aCpr8ZnvOsu-a-zp9quTDP42XvjAC1uci6r11s0QdVA,5218
3
3
  mem_llm/cli.py,sha256=DiqQyBZknN8pVagY5jXH85_LZ6odVGopfpa-7DILNNE,8666
4
4
  mem_llm/config.yaml.example,sha256=lgmfaU5pxnIm4zYxwgCcgLSohNx1Jw6oh3Qk0Xoe2DE,917
5
5
  mem_llm/config_from_docs.py,sha256=YFhq1SWyK63C-TNMS73ncNHg8sJ-XGOf2idWVCjxFco,4974
6
- mem_llm/config_manager.py,sha256=is4m0ISBIfv4PInGjrpvhxy0A7p9_BQ_UoJeayaIT3A,7084
6
+ mem_llm/config_manager.py,sha256=QwkZz8qNBj5KI0h7t45PQmvJ7Orqnx3iOIUbU5yAVoo,7255
7
7
  mem_llm/conversation_summarizer.py,sha256=yCG2pKrAJf7xjaG6DPXL0i9eesMZnnzjKTpuyLHMTPQ,12509
8
8
  mem_llm/data_export_import.py,sha256=gQIdD0hBY23qcRvx139yE15RWHXPinL_EoRNY7iabj0,22592
9
9
  mem_llm/dynamic_prompt.py,sha256=8H99QVDRJSVtGb_o4sdEPnG1cJWuer3KiD-nuL1srTA,10244
@@ -11,19 +11,21 @@ mem_llm/knowledge_loader.py,sha256=oSNhfYYcx7DlZLVogxnbSwaIydq_Q3__RDJFeZR2XVw,2
11
11
  mem_llm/llm_client.py,sha256=3F04nlnRWRlhkQ3aZO-OfsxeajB2gwbIDfClu04cyb0,8709
12
12
  mem_llm/llm_client_factory.py,sha256=jite-4CkgFBd9e0b2cIaZzP-zTqA7tjNqXnJ5CQgcbs,9325
13
13
  mem_llm/logger.py,sha256=dZUmhGgFXtDsDBU_D4kZlJeMp6k-VNPaBcyTt7rZYKE,4507
14
- mem_llm/mem_agent.py,sha256=Y4qCHNtdPlOJssQLG1GJdy02FsztYe9sjnbh54qAWWU,37221
15
- mem_llm/memory_db.py,sha256=4HbxgfhPrijbBKsEv4ncmjZeK-RhtLkyWBrg-quCsNE,14715
16
- mem_llm/memory_manager.py,sha256=CZI3A8pFboHQIgeiXB1h2gZK7mgfbVSU3IxuqE-zXtc,9978
14
+ mem_llm/mem_agent.py,sha256=8R0oAtXzD_X99QVVsfMjZl_wkiCCHdKNWrTrsrbpzdY,52771
15
+ mem_llm/memory_db.py,sha256=yY_afim1Rpk3mOz-qI5WvDDAwWoVd-NucBMBLVUNpwg,21711
16
+ mem_llm/memory_manager.py,sha256=BtzI1o-NYZXMkZHtc36xEZizgNn9fAu6cBkGzNXa-uI,10373
17
17
  mem_llm/memory_tools.py,sha256=ARANFqu_bmL56SlV1RzTjfQsJj-Qe2QvqY0pF92hDxU,8678
18
18
  mem_llm/prompt_security.py,sha256=ehAi6aLiXj0gFFhpyjwEr8LentSTJwOQDLbINV7SaVM,9960
19
+ mem_llm/response_metrics.py,sha256=nMegWV7brNOmptjxGJfYEqRKvAj_302MIw8Ky1PzEy8,7912
19
20
  mem_llm/retry_handler.py,sha256=z5ZcSQKbvVeNK7plagTLorvOeoYgRpQcsX3PpNqUjKM,6389
20
21
  mem_llm/thread_safe_db.py,sha256=Fq-wSn4ua1qiR6M4ZTIy7UT1IlFj5xODNExgub1blbU,10328
22
+ mem_llm/vector_store.py,sha256=7fzvxLjfJrspN1Tcety4JtcKksxnkM0E5es0UtBgI-c,10816
21
23
  mem_llm/clients/__init__.py,sha256=Nvr4NuL9ZlDF_dUjr-ZMFxRRrBdHoUOjqncZs3n5Wow,475
22
24
  mem_llm/clients/gemini_client.py,sha256=dmRZRd8f-x6J2W7luzcB1BOx_4UpXpCF4YiPGUccWCw,14432
23
25
  mem_llm/clients/lmstudio_client.py,sha256=IxUX3sVRfXN46hfEUTCrspGTOeqsn4YAu9WzFuGh940,10156
24
26
  mem_llm/clients/ollama_client.py,sha256=2BfYSBiOowhFg9UiCXkILlBG9_4Vri3-Iny_gH6-um0,9710
25
- mem_llm-1.3.1.dist-info/METADATA,sha256=d6sfUEBBg7Ir7y2495WAg6rqrKO9how5d3AgD-1NxU0,18217
26
- mem_llm-1.3.1.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
27
- mem_llm-1.3.1.dist-info/entry_points.txt,sha256=z9bg6xgNroIobvCMtnSXeFPc-vI1nMen8gejHCdnl0U,45
28
- mem_llm-1.3.1.dist-info/top_level.txt,sha256=_fU1ML-0JwkaxWdhqpwtmTNaJEOvDMQeJdA8d5WqDn8,8
29
- mem_llm-1.3.1.dist-info/RECORD,,
27
+ mem_llm-1.3.2.dist-info/METADATA,sha256=6KYvn0Y00gcxzyU45tkckwW991IqSDpLoAvSfubeypY,18774
28
+ mem_llm-1.3.2.dist-info/WHEEL,sha256=beeZ86-EfXScwlR_HKu4SllMC9wUEj_8Z_4FJ3egI2w,91
29
+ mem_llm-1.3.2.dist-info/entry_points.txt,sha256=z9bg6xgNroIobvCMtnSXeFPc-vI1nMen8gejHCdnl0U,45
30
+ mem_llm-1.3.2.dist-info/top_level.txt,sha256=_fU1ML-0JwkaxWdhqpwtmTNaJEOvDMQeJdA8d5WqDn8,8
31
+ mem_llm-1.3.2.dist-info/RECORD,,