diff --git a/memori/__init__.py b/memori/__init__.py index 59d95e88..1611fa4d 100644 --- a/memori/__init__.py +++ b/memori/__init__.py @@ -123,5 +123,16 @@ def set_session(self, id): self.config.session_id = id return self - def recall(self, query: str, limit: int = 5): - return Recall(self.config).search_facts(query, limit) + def recall(self, query: str, limit: int = 5, page: int = 1, per_page: int | None = None): + """Search for relevant facts based on query. + + Args: + query: Search query string + limit: Maximum number of results to return + page: Page number for pagination (1-based) + per_page: Number of results per page (None to disable pagination) + + Returns: + List of fact dictionaries with id, content, and similarity score + """ + return Recall(self.config).search_facts(query, limit, page=page, per_page=per_page) diff --git a/memori/_config.py b/memori/_config.py index ea8dcfcf..bd15cdb6 100644 --- a/memori/_config.py +++ b/memori/_config.py @@ -41,6 +41,8 @@ def __init__(self): self.recall_embeddings_limit = 1000 self.recall_facts_limit = 5 self.recall_relevance_threshold = 0.1 + self.recall_default_page = 1 # Default page number (1-based) + self.recall_default_per_page = 10 # Default results per page self.request_backoff_factor = 1 self.request_num_backoff = 5 self.request_secs_timeout = 5 diff --git a/memori/_search.py b/memori/_search.py index 3539ffb2..95df690d 100644 --- a/memori/_search.py +++ b/memori/_search.py @@ -40,6 +40,8 @@ def find_similar_embeddings( embeddings: list[tuple[int, Any]], query_embedding: list[float], limit: int = 5, + page: int = 1, + per_page: int | None = None, ) -> list[tuple[int, float]]: """Find most similar embeddings using FAISS cosine similarity. @@ -89,6 +91,11 @@ def find_similar_embeddings( if embedding_idx >= 0 and embedding_idx < len(id_list): results.append((id_list[embedding_idx], float(similarities[0][result_idx]))) + # Apply pagination if per_page is specified + if per_page is not None: + offset = page * per_page + results = results[offset:offset + per_page] + return results @@ -98,6 +105,8 @@ def search_entity_facts( query_embedding: list[float], limit: int, embeddings_limit: int, + page: int = 1, + per_page: int | None = None, ) -> list[dict]: """Search entity facts by embedding similarity. @@ -117,7 +126,7 @@ def search_entity_facts( return [] embeddings = [(row["id"], row["content_embedding"]) for row in results] - similar = find_similar_embeddings(embeddings, query_embedding, limit) + similar = find_similar_embeddings(embeddings, query_embedding, limit, per_page=per_page) if not similar: return [] diff --git a/memori/memory/recall.py b/memori/memory/recall.py index c171fb9c..282682e6 100644 --- a/memori/memory/recall.py +++ b/memori/memory/recall.py @@ -25,7 +25,8 @@ def __init__(self, config: Config) -> None: self.config = config def search_facts( - self, query: str, limit: int | None = None, entity_id: int | None = None + self, query: str, limit: int | None = None, entity_id: int | None = None, + page: int | None = None, per_page: int | None = None ) -> list[dict]: if self.config.storage is None or self.config.storage.driver is None: return [] @@ -41,6 +42,12 @@ def search_facts( if limit is None: limit = self.config.recall_facts_limit + if page is None: + page = self.config.recall_default_page + + if per_page is None: + per_page = self.config.recall_default_per_page + query_embedding = embed_texts(query)[0] facts = [] @@ -52,6 +59,7 @@ def search_facts( query_embedding, limit, self.config.recall_embeddings_limit, + page=page, ) break except OperationalError as e: