Mem0 1.0.0 (#3545)
This commit is contained in:
@@ -254,14 +254,79 @@ class ChromaDB(VectorStoreBase):
|
||||
Returns:
|
||||
dict[str, any]: Properly formatted where clause for ChromaDB.
|
||||
"""
|
||||
# If only one filter is supplied, return it as is
|
||||
# (no need to wrap in $and based on chroma docs)
|
||||
if where is None:
|
||||
return {}
|
||||
if len(where.keys()) <= 1:
|
||||
return where
|
||||
where_filters = []
|
||||
for k, v in where.items():
|
||||
if isinstance(v, str):
|
||||
where_filters.append({k: v})
|
||||
return {"$and": where_filters}
|
||||
|
||||
def convert_condition(key: str, value: any) -> dict:
|
||||
"""Convert universal filter format to ChromaDB format."""
|
||||
if value == "*":
|
||||
# Wildcard - match any value (ChromaDB doesn't have direct wildcard, so we skip this filter)
|
||||
return None
|
||||
elif isinstance(value, dict):
|
||||
# Handle comparison operators
|
||||
chroma_condition = {}
|
||||
for op, val in value.items():
|
||||
if op == "eq":
|
||||
chroma_condition[key] = {"$eq": val}
|
||||
elif op == "ne":
|
||||
chroma_condition[key] = {"$ne": val}
|
||||
elif op == "gt":
|
||||
chroma_condition[key] = {"$gt": val}
|
||||
elif op == "gte":
|
||||
chroma_condition[key] = {"$gte": val}
|
||||
elif op == "lt":
|
||||
chroma_condition[key] = {"$lt": val}
|
||||
elif op == "lte":
|
||||
chroma_condition[key] = {"$lte": val}
|
||||
elif op == "in":
|
||||
chroma_condition[key] = {"$in": val}
|
||||
elif op == "nin":
|
||||
chroma_condition[key] = {"$nin": val}
|
||||
elif op in ["contains", "icontains"]:
|
||||
# ChromaDB doesn't support contains, fallback to equality
|
||||
chroma_condition[key] = {"$eq": val}
|
||||
else:
|
||||
# Unknown operator, treat as equality
|
||||
chroma_condition[key] = {"$eq": val}
|
||||
return chroma_condition
|
||||
else:
|
||||
# Simple equality
|
||||
return {key: {"$eq": value}}
|
||||
|
||||
processed_filters = []
|
||||
|
||||
for key, value in where.items():
|
||||
if key == "$or":
|
||||
# Handle OR conditions
|
||||
or_conditions = []
|
||||
for condition in value:
|
||||
or_condition = {}
|
||||
for sub_key, sub_value in condition.items():
|
||||
converted = convert_condition(sub_key, sub_value)
|
||||
if converted:
|
||||
or_condition.update(converted)
|
||||
if or_condition:
|
||||
or_conditions.append(or_condition)
|
||||
|
||||
if len(or_conditions) > 1:
|
||||
processed_filters.append({"$or": or_conditions})
|
||||
elif len(or_conditions) == 1:
|
||||
processed_filters.append(or_conditions[0])
|
||||
|
||||
elif key == "$not":
|
||||
# Handle NOT conditions - ChromaDB doesn't have direct NOT, so we'll skip for now
|
||||
continue
|
||||
|
||||
else:
|
||||
# Regular condition
|
||||
converted = convert_condition(key, value)
|
||||
if converted:
|
||||
processed_filters.append(converted)
|
||||
|
||||
# Return appropriate format based on number of conditions
|
||||
if len(processed_filters) == 0:
|
||||
return {}
|
||||
elif len(processed_filters) == 1:
|
||||
return processed_filters[0]
|
||||
else:
|
||||
return {"$and": processed_filters}
|
||||
|
||||
@@ -113,15 +113,26 @@ class OpenSearchDB(VectorStoreBase):
|
||||
if payloads is None:
|
||||
payloads = [{} for _ in range(len(vectors))]
|
||||
|
||||
results = []
|
||||
for i, (vec, id_) in enumerate(zip(vectors, ids)):
|
||||
body = {
|
||||
"vector_field": vec,
|
||||
"payload": payloads[i],
|
||||
"id": id_,
|
||||
}
|
||||
self.client.index(index=self.collection_name, body=body)
|
||||
|
||||
results = []
|
||||
try:
|
||||
self.client.index(index=self.collection_name, body=body)
|
||||
# Force refresh to make documents immediately searchable for tests
|
||||
self.client.indices.refresh(index=self.collection_name)
|
||||
|
||||
results.append(OutputData(
|
||||
id=id_,
|
||||
score=1.0, # No score for inserts
|
||||
payload=payloads[i]
|
||||
))
|
||||
except Exception as e:
|
||||
logger.error(f"Error inserting vector {id_}: {e}")
|
||||
raise
|
||||
|
||||
return results
|
||||
|
||||
@@ -157,15 +168,19 @@ class OpenSearchDB(VectorStoreBase):
|
||||
else:
|
||||
query_body["query"] = knn_query
|
||||
|
||||
# Execute search
|
||||
response = self.client.search(index=self.collection_name, body=query_body)
|
||||
try:
|
||||
# Execute search
|
||||
response = self.client.search(index=self.collection_name, body=query_body)
|
||||
|
||||
hits = response["hits"]["hits"]
|
||||
results = [
|
||||
OutputData(id=hit["_source"].get("id"), score=hit["_score"], payload=hit["_source"].get("payload", {}))
|
||||
for hit in hits
|
||||
]
|
||||
return results
|
||||
hits = response["hits"]["hits"]
|
||||
results = [
|
||||
OutputData(id=hit["_source"].get("id"), score=hit["_score"], payload=hit["_source"].get("payload", {}))
|
||||
for hit in hits[:limit] # Ensure we don't exceed limit
|
||||
]
|
||||
return results
|
||||
except Exception as e:
|
||||
logger.error(f"Error during search: {e}")
|
||||
return []
|
||||
|
||||
def delete(self, vector_id: str) -> None:
|
||||
"""Delete a vector by custom ID."""
|
||||
@@ -213,12 +228,6 @@ class OpenSearchDB(VectorStoreBase):
|
||||
def get(self, vector_id: str) -> Optional[OutputData]:
|
||||
"""Retrieve a vector by ID."""
|
||||
try:
|
||||
# First check if index exists
|
||||
if not self.client.indices.exists(index=self.collection_name):
|
||||
logger.info(f"Index {self.collection_name} does not exist, creating it...")
|
||||
self.create_col(self.collection_name, self.embedding_model_dims)
|
||||
return None
|
||||
|
||||
search_query = {"query": {"term": {"id": vector_id}}}
|
||||
response = self.client.search(index=self.collection_name, body=search_query)
|
||||
|
||||
@@ -265,14 +274,16 @@ class OpenSearchDB(VectorStoreBase):
|
||||
response = self.client.search(index=self.collection_name, body=query)
|
||||
hits = response["hits"]["hits"]
|
||||
|
||||
return [
|
||||
[
|
||||
OutputData(id=hit["_source"].get("id"), score=1.0, payload=hit["_source"].get("payload", {}))
|
||||
for hit in hits
|
||||
]
|
||||
# Return a flat list, not a nested array
|
||||
results = [
|
||||
OutputData(id=hit["_source"].get("id"), score=1.0, payload=hit["_source"].get("payload", {}))
|
||||
for hit in hits
|
||||
]
|
||||
except Exception:
|
||||
return [results] # VectorStore expects tuple/list format
|
||||
except Exception as e:
|
||||
logger.error(f"Error listing vectors: {e}")
|
||||
return []
|
||||
|
||||
|
||||
def reset(self):
|
||||
"""Reset the index by deleting and recreating it."""
|
||||
|
||||
@@ -65,10 +65,16 @@ class GoogleMatchingEngine(VectorStoreBase):
|
||||
"project": self.project_id,
|
||||
"location": self.region,
|
||||
}
|
||||
|
||||
# Support both credentials_path and service_account_json
|
||||
if hasattr(config, "credentials_path") and config.credentials_path:
|
||||
logger.debug("Using credentials from: %s", config.credentials_path)
|
||||
logger.debug("Using credentials from file: %s", config.credentials_path)
|
||||
credentials = service_account.Credentials.from_service_account_file(config.credentials_path)
|
||||
init_args["credentials"] = credentials
|
||||
elif hasattr(config, "service_account_json") and config.service_account_json:
|
||||
logger.debug("Using credentials from provided JSON dict")
|
||||
credentials = service_account.Credentials.from_service_account_info(config.service_account_json)
|
||||
init_args["credentials"] = credentials
|
||||
|
||||
try:
|
||||
aiplatform.init(**init_args)
|
||||
|
||||
Reference in New Issue
Block a user