Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/memos/api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ def create_user_config(user_name: str, user_id: str) -> tuple["MOSConfig", "Gene
"fast_graph": bool(os.getenv("FAST_GRAPH", "false") == "true"),
"bm25": bool(os.getenv("BM25_CALL", "false") == "true"),
"cot": bool(os.getenv("VEC_COT_CALL", "false") == "true"),
"fulltext": bool(os.getenv("FULLTEXT_CALL", "false") == "true"),
},
"include_embedding": bool(
os.getenv("INCLUDE_EMBEDDING", "false") == "true"
Expand Down Expand Up @@ -1096,6 +1097,7 @@ def get_default_cube_config() -> "GeneralMemCubeConfig | None":
"fast_graph": bool(os.getenv("FAST_GRAPH", "false") == "true"),
"bm25": bool(os.getenv("BM25_CALL", "false") == "true"),
"cot": bool(os.getenv("VEC_COT_CALL", "false") == "true"),
"fulltext": bool(os.getenv("FULLTEXT_CALL", "false") == "true"),
},
"mode": os.getenv("ASYNC_MODE", "sync"),
"include_embedding": bool(
Expand Down
12 changes: 6 additions & 6 deletions src/memos/api/product_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ class ChatRequest(BaseRequest):
manager_user_id: str | None = Field(None, description="Manager User ID")
project_id: str | None = Field(None, description="Project ID")
relativity: float = Field(
0.0,
0.45,
ge=0,
description=(
"Relevance threshold for recalled memories. "
"Only memories with metadata.relativity >= relativity will be returned. "
"Use 0 to disable threshold filtering. Default: 0.3."
"Use 0 to disable threshold filtering. Default: 0.45."
),
)

Expand Down Expand Up @@ -339,12 +339,12 @@ class APISearchRequest(BaseRequest):
)

relativity: float = Field(
0.0,
0.45,
ge=0,
description=(
"Relevance threshold for recalled memories. "
"Only memories with metadata.relativity >= relativity will be returned. "
"Use 0 to disable threshold filtering. Default: 0.3."
"Use 0 to disable threshold filtering. Default: 0.45."
),
)

Expand Down Expand Up @@ -785,12 +785,12 @@ class APIChatCompleteRequest(BaseRequest):
manager_user_id: str | None = Field(None, description="Manager User ID")
project_id: str | None = Field(None, description="Project ID")
relativity: float = Field(
0.0,
0.45,
ge=0,
description=(
"Relevance threshold for recalled memories. "
"Only memories with metadata.relativity >= relativity will be returned. "
"Use 0 to disable threshold filtering. Default: 0.3."
"Use 0 to disable threshold filtering. Default: 0.45."
),
)

Expand Down
20 changes: 20 additions & 0 deletions src/memos/graph_dbs/neo4j.py
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,26 @@ def search_by_embedding(

return records

def search_by_fulltext(
self,
query_words: list[str],
top_k: int = 10,
scope: str | None = None,
status: str | None = None,
threshold: float | None = None,
search_filter: dict | None = None,
user_name: str | None = None,
filter: dict | None = None,
knowledgebase_ids: list[str] | None = None,
tsquery_config: str | None = None,
**kwargs,
) -> list[dict]:
"""
TODO: Implement fulltext search for Neo4j to be compatible with TreeTextMemory's keyword/fulltext recall path.
Currently, return an empty list to avoid runtime errors due to missing methods when switching to Neo4j.
"""
return []

def get_by_metadata(
self,
filters: list[dict[str, Any]],
Expand Down
20 changes: 20 additions & 0 deletions src/memos/graph_dbs/neo4j_community.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,26 @@ def search_by_embedding(

return filtered_results

def search_by_fulltext(
self,
query_words: list[str],
top_k: int = 10,
scope: str | None = None,
status: str | None = None,
threshold: float | None = None,
search_filter: dict | None = None,
user_name: str | None = None,
filter: dict | None = None,
knowledgebase_ids: list[str] | None = None,
tsquery_config: str | None = None,
**kwargs,
) -> list[dict]:
"""
TODO: Implement fulltext search for Neo4j to be compatible with TreeTextMemory's keyword/fulltext recall path.
Currently, return an empty list to avoid runtime errors due to missing methods when switching to Neo4j.
"""
return []

def _normalize_date_string(self, date_str: str) -> str:
"""
Normalize date string to ISO 8601 format for Neo4j datetime() function.
Expand Down
54 changes: 31 additions & 23 deletions src/memos/memories/textual/tree_text_memory/retrieve/searcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def __init__(
self.internet_retriever = internet_retriever
self.vec_cot = search_strategy.get("cot", False) if search_strategy else False
self.use_fast_graph = search_strategy.get("fast_graph", False) if search_strategy else False
self.use_fulltext = search_strategy.get("fulltext", False) if search_strategy else False
self.manual_close_internet = manual_close_internet
self.tokenizer = tokenizer
self._usage_executor = ContextThreadPoolExecutor(max_workers=4, thread_name_prefix="usage")
Expand Down Expand Up @@ -380,20 +381,21 @@ def _retrieve_paths(
user_name,
)
)
tasks.append(
executor.submit(
self._retrieve_from_keyword,
query,
parsed_goal,
query_embedding,
top_k,
memory_type,
search_filter,
search_priority,
user_name,
id_filter,
if self.use_fulltext:
tasks.append(
executor.submit(
self._retrieve_from_keyword,
query,
parsed_goal,
query_embedding,
top_k,
memory_type,
search_filter,
search_priority,
user_name,
id_filter,
)
)
)
if search_tool_memory:
tasks.append(
executor.submit(
Expand Down Expand Up @@ -511,16 +513,22 @@ def _retrieve_from_keyword(

id_to_score: dict[str, float] = {}
for scope in scopes:
hits = self.graph_store.search_by_fulltext(
query_words=tsquery_terms,
top_k=top_k * 2,
status="activated",
scope=scope,
search_filter=None,
filter=search_filter,
user_name=user_name,
tsquery_config="jiebaqry",
)
try:
hits = self.graph_store.search_by_fulltext(
query_words=tsquery_terms,
top_k=top_k * 2,
status="activated",
scope=scope,
search_filter=None,
filter=search_filter,
user_name=user_name,
tsquery_config="jiebaqry",
)
except Exception as e:
logger.warning(
f"[PATH-KEYWORD] search_by_fulltext failed, scope={scope}, user_name={user_name}"
)
hits = []
for h in hits or []:
hid = str(h.get("id") or "").strip().strip("'\"")
if not hid:
Expand Down