MemoryOS 2.0.3__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.
- memoryos-2.0.3.dist-info/METADATA +418 -0
- memoryos-2.0.3.dist-info/RECORD +315 -0
- memoryos-2.0.3.dist-info/WHEEL +4 -0
- memoryos-2.0.3.dist-info/entry_points.txt +3 -0
- memoryos-2.0.3.dist-info/licenses/LICENSE +201 -0
- memos/__init__.py +20 -0
- memos/api/client.py +571 -0
- memos/api/config.py +1018 -0
- memos/api/context/dependencies.py +50 -0
- memos/api/exceptions.py +53 -0
- memos/api/handlers/__init__.py +62 -0
- memos/api/handlers/add_handler.py +158 -0
- memos/api/handlers/base_handler.py +194 -0
- memos/api/handlers/chat_handler.py +1401 -0
- memos/api/handlers/component_init.py +388 -0
- memos/api/handlers/config_builders.py +190 -0
- memos/api/handlers/feedback_handler.py +93 -0
- memos/api/handlers/formatters_handler.py +237 -0
- memos/api/handlers/memory_handler.py +316 -0
- memos/api/handlers/scheduler_handler.py +497 -0
- memos/api/handlers/search_handler.py +222 -0
- memos/api/handlers/suggestion_handler.py +117 -0
- memos/api/mcp_serve.py +614 -0
- memos/api/middleware/request_context.py +101 -0
- memos/api/product_api.py +38 -0
- memos/api/product_models.py +1206 -0
- memos/api/routers/__init__.py +1 -0
- memos/api/routers/product_router.py +477 -0
- memos/api/routers/server_router.py +394 -0
- memos/api/server_api.py +44 -0
- memos/api/start_api.py +433 -0
- memos/chunkers/__init__.py +4 -0
- memos/chunkers/base.py +24 -0
- memos/chunkers/charactertext_chunker.py +41 -0
- memos/chunkers/factory.py +24 -0
- memos/chunkers/markdown_chunker.py +62 -0
- memos/chunkers/sentence_chunker.py +54 -0
- memos/chunkers/simple_chunker.py +50 -0
- memos/cli.py +113 -0
- memos/configs/__init__.py +0 -0
- memos/configs/base.py +82 -0
- memos/configs/chunker.py +59 -0
- memos/configs/embedder.py +88 -0
- memos/configs/graph_db.py +236 -0
- memos/configs/internet_retriever.py +100 -0
- memos/configs/llm.py +151 -0
- memos/configs/mem_agent.py +54 -0
- memos/configs/mem_chat.py +81 -0
- memos/configs/mem_cube.py +105 -0
- memos/configs/mem_os.py +83 -0
- memos/configs/mem_reader.py +91 -0
- memos/configs/mem_scheduler.py +385 -0
- memos/configs/mem_user.py +70 -0
- memos/configs/memory.py +324 -0
- memos/configs/parser.py +38 -0
- memos/configs/reranker.py +18 -0
- memos/configs/utils.py +8 -0
- memos/configs/vec_db.py +80 -0
- memos/context/context.py +355 -0
- memos/dependency.py +52 -0
- memos/deprecation.py +262 -0
- memos/embedders/__init__.py +0 -0
- memos/embedders/ark.py +95 -0
- memos/embedders/base.py +106 -0
- memos/embedders/factory.py +29 -0
- memos/embedders/ollama.py +77 -0
- memos/embedders/sentence_transformer.py +49 -0
- memos/embedders/universal_api.py +51 -0
- memos/exceptions.py +30 -0
- memos/graph_dbs/__init__.py +0 -0
- memos/graph_dbs/base.py +274 -0
- memos/graph_dbs/factory.py +27 -0
- memos/graph_dbs/item.py +46 -0
- memos/graph_dbs/nebular.py +1794 -0
- memos/graph_dbs/neo4j.py +1942 -0
- memos/graph_dbs/neo4j_community.py +1058 -0
- memos/graph_dbs/polardb.py +5446 -0
- memos/hello_world.py +97 -0
- memos/llms/__init__.py +0 -0
- memos/llms/base.py +25 -0
- memos/llms/deepseek.py +13 -0
- memos/llms/factory.py +38 -0
- memos/llms/hf.py +443 -0
- memos/llms/hf_singleton.py +114 -0
- memos/llms/ollama.py +135 -0
- memos/llms/openai.py +222 -0
- memos/llms/openai_new.py +198 -0
- memos/llms/qwen.py +13 -0
- memos/llms/utils.py +14 -0
- memos/llms/vllm.py +218 -0
- memos/log.py +237 -0
- memos/mem_agent/base.py +19 -0
- memos/mem_agent/deepsearch_agent.py +391 -0
- memos/mem_agent/factory.py +36 -0
- memos/mem_chat/__init__.py +0 -0
- memos/mem_chat/base.py +30 -0
- memos/mem_chat/factory.py +21 -0
- memos/mem_chat/simple.py +200 -0
- memos/mem_cube/__init__.py +0 -0
- memos/mem_cube/base.py +30 -0
- memos/mem_cube/general.py +240 -0
- memos/mem_cube/navie.py +172 -0
- memos/mem_cube/utils.py +169 -0
- memos/mem_feedback/base.py +15 -0
- memos/mem_feedback/feedback.py +1192 -0
- memos/mem_feedback/simple_feedback.py +40 -0
- memos/mem_feedback/utils.py +230 -0
- memos/mem_os/client.py +5 -0
- memos/mem_os/core.py +1203 -0
- memos/mem_os/main.py +582 -0
- memos/mem_os/product.py +1608 -0
- memos/mem_os/product_server.py +455 -0
- memos/mem_os/utils/default_config.py +359 -0
- memos/mem_os/utils/format_utils.py +1403 -0
- memos/mem_os/utils/reference_utils.py +162 -0
- memos/mem_reader/__init__.py +0 -0
- memos/mem_reader/base.py +47 -0
- memos/mem_reader/factory.py +53 -0
- memos/mem_reader/memory.py +298 -0
- memos/mem_reader/multi_modal_struct.py +965 -0
- memos/mem_reader/read_multi_modal/__init__.py +43 -0
- memos/mem_reader/read_multi_modal/assistant_parser.py +311 -0
- memos/mem_reader/read_multi_modal/base.py +273 -0
- memos/mem_reader/read_multi_modal/file_content_parser.py +826 -0
- memos/mem_reader/read_multi_modal/image_parser.py +359 -0
- memos/mem_reader/read_multi_modal/multi_modal_parser.py +252 -0
- memos/mem_reader/read_multi_modal/string_parser.py +139 -0
- memos/mem_reader/read_multi_modal/system_parser.py +327 -0
- memos/mem_reader/read_multi_modal/text_content_parser.py +131 -0
- memos/mem_reader/read_multi_modal/tool_parser.py +210 -0
- memos/mem_reader/read_multi_modal/user_parser.py +218 -0
- memos/mem_reader/read_multi_modal/utils.py +358 -0
- memos/mem_reader/simple_struct.py +912 -0
- memos/mem_reader/strategy_struct.py +163 -0
- memos/mem_reader/utils.py +157 -0
- memos/mem_scheduler/__init__.py +0 -0
- memos/mem_scheduler/analyzer/__init__.py +0 -0
- memos/mem_scheduler/analyzer/api_analyzer.py +714 -0
- memos/mem_scheduler/analyzer/eval_analyzer.py +219 -0
- memos/mem_scheduler/analyzer/mos_for_test_scheduler.py +571 -0
- memos/mem_scheduler/analyzer/scheduler_for_eval.py +280 -0
- memos/mem_scheduler/base_scheduler.py +1319 -0
- memos/mem_scheduler/general_modules/__init__.py +0 -0
- memos/mem_scheduler/general_modules/api_misc.py +137 -0
- memos/mem_scheduler/general_modules/base.py +80 -0
- memos/mem_scheduler/general_modules/init_components_for_scheduler.py +425 -0
- memos/mem_scheduler/general_modules/misc.py +313 -0
- memos/mem_scheduler/general_modules/scheduler_logger.py +389 -0
- memos/mem_scheduler/general_modules/task_threads.py +315 -0
- memos/mem_scheduler/general_scheduler.py +1495 -0
- memos/mem_scheduler/memory_manage_modules/__init__.py +5 -0
- memos/mem_scheduler/memory_manage_modules/memory_filter.py +306 -0
- memos/mem_scheduler/memory_manage_modules/retriever.py +547 -0
- memos/mem_scheduler/monitors/__init__.py +0 -0
- memos/mem_scheduler/monitors/dispatcher_monitor.py +366 -0
- memos/mem_scheduler/monitors/general_monitor.py +394 -0
- memos/mem_scheduler/monitors/task_schedule_monitor.py +254 -0
- memos/mem_scheduler/optimized_scheduler.py +410 -0
- memos/mem_scheduler/orm_modules/__init__.py +0 -0
- memos/mem_scheduler/orm_modules/api_redis_model.py +518 -0
- memos/mem_scheduler/orm_modules/base_model.py +729 -0
- memos/mem_scheduler/orm_modules/monitor_models.py +261 -0
- memos/mem_scheduler/orm_modules/redis_model.py +699 -0
- memos/mem_scheduler/scheduler_factory.py +23 -0
- memos/mem_scheduler/schemas/__init__.py +0 -0
- memos/mem_scheduler/schemas/analyzer_schemas.py +52 -0
- memos/mem_scheduler/schemas/api_schemas.py +233 -0
- memos/mem_scheduler/schemas/general_schemas.py +55 -0
- memos/mem_scheduler/schemas/message_schemas.py +173 -0
- memos/mem_scheduler/schemas/monitor_schemas.py +406 -0
- memos/mem_scheduler/schemas/task_schemas.py +132 -0
- memos/mem_scheduler/task_schedule_modules/__init__.py +0 -0
- memos/mem_scheduler/task_schedule_modules/dispatcher.py +740 -0
- memos/mem_scheduler/task_schedule_modules/local_queue.py +247 -0
- memos/mem_scheduler/task_schedule_modules/orchestrator.py +74 -0
- memos/mem_scheduler/task_schedule_modules/redis_queue.py +1385 -0
- memos/mem_scheduler/task_schedule_modules/task_queue.py +162 -0
- memos/mem_scheduler/utils/__init__.py +0 -0
- memos/mem_scheduler/utils/api_utils.py +77 -0
- memos/mem_scheduler/utils/config_utils.py +100 -0
- memos/mem_scheduler/utils/db_utils.py +50 -0
- memos/mem_scheduler/utils/filter_utils.py +176 -0
- memos/mem_scheduler/utils/metrics.py +125 -0
- memos/mem_scheduler/utils/misc_utils.py +290 -0
- memos/mem_scheduler/utils/monitor_event_utils.py +67 -0
- memos/mem_scheduler/utils/status_tracker.py +229 -0
- memos/mem_scheduler/webservice_modules/__init__.py +0 -0
- memos/mem_scheduler/webservice_modules/rabbitmq_service.py +485 -0
- memos/mem_scheduler/webservice_modules/redis_service.py +380 -0
- memos/mem_user/factory.py +94 -0
- memos/mem_user/mysql_persistent_user_manager.py +271 -0
- memos/mem_user/mysql_user_manager.py +502 -0
- memos/mem_user/persistent_factory.py +98 -0
- memos/mem_user/persistent_user_manager.py +260 -0
- memos/mem_user/redis_persistent_user_manager.py +225 -0
- memos/mem_user/user_manager.py +488 -0
- memos/memories/__init__.py +0 -0
- memos/memories/activation/__init__.py +0 -0
- memos/memories/activation/base.py +42 -0
- memos/memories/activation/item.py +56 -0
- memos/memories/activation/kv.py +292 -0
- memos/memories/activation/vllmkv.py +219 -0
- memos/memories/base.py +19 -0
- memos/memories/factory.py +42 -0
- memos/memories/parametric/__init__.py +0 -0
- memos/memories/parametric/base.py +19 -0
- memos/memories/parametric/item.py +11 -0
- memos/memories/parametric/lora.py +41 -0
- memos/memories/textual/__init__.py +0 -0
- memos/memories/textual/base.py +92 -0
- memos/memories/textual/general.py +236 -0
- memos/memories/textual/item.py +304 -0
- memos/memories/textual/naive.py +187 -0
- memos/memories/textual/prefer_text_memory/__init__.py +0 -0
- memos/memories/textual/prefer_text_memory/adder.py +504 -0
- memos/memories/textual/prefer_text_memory/config.py +106 -0
- memos/memories/textual/prefer_text_memory/extractor.py +221 -0
- memos/memories/textual/prefer_text_memory/factory.py +85 -0
- memos/memories/textual/prefer_text_memory/retrievers.py +177 -0
- memos/memories/textual/prefer_text_memory/spliter.py +132 -0
- memos/memories/textual/prefer_text_memory/utils.py +93 -0
- memos/memories/textual/preference.py +344 -0
- memos/memories/textual/simple_preference.py +161 -0
- memos/memories/textual/simple_tree.py +69 -0
- memos/memories/textual/tree.py +459 -0
- memos/memories/textual/tree_text_memory/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/organize/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/organize/handler.py +184 -0
- memos/memories/textual/tree_text_memory/organize/manager.py +518 -0
- memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +238 -0
- memos/memories/textual/tree_text_memory/organize/reorganizer.py +622 -0
- memos/memories/textual/tree_text_memory/retrieve/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/retrieve/advanced_searcher.py +364 -0
- memos/memories/textual/tree_text_memory/retrieve/bm25_util.py +186 -0
- memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +419 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +270 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +102 -0
- memos/memories/textual/tree_text_memory/retrieve/reasoner.py +61 -0
- memos/memories/textual/tree_text_memory/retrieve/recall.py +497 -0
- memos/memories/textual/tree_text_memory/retrieve/reranker.py +111 -0
- memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +16 -0
- memos/memories/textual/tree_text_memory/retrieve/retrieve_utils.py +472 -0
- memos/memories/textual/tree_text_memory/retrieve/searcher.py +848 -0
- memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +135 -0
- memos/memories/textual/tree_text_memory/retrieve/utils.py +54 -0
- memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +387 -0
- memos/memos_tools/dinding_report_bot.py +453 -0
- memos/memos_tools/lockfree_dict.py +120 -0
- memos/memos_tools/notification_service.py +44 -0
- memos/memos_tools/notification_utils.py +142 -0
- memos/memos_tools/singleton.py +174 -0
- memos/memos_tools/thread_safe_dict.py +310 -0
- memos/memos_tools/thread_safe_dict_segment.py +382 -0
- memos/multi_mem_cube/__init__.py +0 -0
- memos/multi_mem_cube/composite_cube.py +86 -0
- memos/multi_mem_cube/single_cube.py +874 -0
- memos/multi_mem_cube/views.py +54 -0
- memos/parsers/__init__.py +0 -0
- memos/parsers/base.py +15 -0
- memos/parsers/factory.py +21 -0
- memos/parsers/markitdown.py +28 -0
- memos/reranker/__init__.py +4 -0
- memos/reranker/base.py +25 -0
- memos/reranker/concat.py +103 -0
- memos/reranker/cosine_local.py +102 -0
- memos/reranker/factory.py +72 -0
- memos/reranker/http_bge.py +324 -0
- memos/reranker/http_bge_strategy.py +327 -0
- memos/reranker/noop.py +19 -0
- memos/reranker/strategies/__init__.py +4 -0
- memos/reranker/strategies/base.py +61 -0
- memos/reranker/strategies/concat_background.py +94 -0
- memos/reranker/strategies/concat_docsource.py +110 -0
- memos/reranker/strategies/dialogue_common.py +109 -0
- memos/reranker/strategies/factory.py +31 -0
- memos/reranker/strategies/single_turn.py +107 -0
- memos/reranker/strategies/singleturn_outmem.py +98 -0
- memos/settings.py +10 -0
- memos/templates/__init__.py +0 -0
- memos/templates/advanced_search_prompts.py +211 -0
- memos/templates/cloud_service_prompt.py +107 -0
- memos/templates/instruction_completion.py +66 -0
- memos/templates/mem_agent_prompts.py +85 -0
- memos/templates/mem_feedback_prompts.py +822 -0
- memos/templates/mem_reader_prompts.py +1096 -0
- memos/templates/mem_reader_strategy_prompts.py +238 -0
- memos/templates/mem_scheduler_prompts.py +626 -0
- memos/templates/mem_search_prompts.py +93 -0
- memos/templates/mos_prompts.py +403 -0
- memos/templates/prefer_complete_prompt.py +735 -0
- memos/templates/tool_mem_prompts.py +139 -0
- memos/templates/tree_reorganize_prompts.py +230 -0
- memos/types/__init__.py +34 -0
- memos/types/general_types.py +151 -0
- memos/types/openai_chat_completion_types/__init__.py +15 -0
- memos/types/openai_chat_completion_types/chat_completion_assistant_message_param.py +56 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_image_param.py +27 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_input_audio_param.py +23 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_param.py +43 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_refusal_param.py +16 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_text_param.py +16 -0
- memos/types/openai_chat_completion_types/chat_completion_message_custom_tool_call_param.py +27 -0
- memos/types/openai_chat_completion_types/chat_completion_message_function_tool_call_param.py +32 -0
- memos/types/openai_chat_completion_types/chat_completion_message_param.py +18 -0
- memos/types/openai_chat_completion_types/chat_completion_message_tool_call_union_param.py +15 -0
- memos/types/openai_chat_completion_types/chat_completion_system_message_param.py +36 -0
- memos/types/openai_chat_completion_types/chat_completion_tool_message_param.py +30 -0
- memos/types/openai_chat_completion_types/chat_completion_user_message_param.py +34 -0
- memos/utils.py +123 -0
- memos/vec_dbs/__init__.py +0 -0
- memos/vec_dbs/base.py +117 -0
- memos/vec_dbs/factory.py +23 -0
- memos/vec_dbs/item.py +50 -0
- memos/vec_dbs/milvus.py +654 -0
- memos/vec_dbs/qdrant.py +355 -0
memos/api/config.py
ADDED
|
@@ -0,0 +1,1018 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import hashlib
|
|
3
|
+
import hmac
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import time
|
|
9
|
+
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
import requests
|
|
13
|
+
|
|
14
|
+
from dotenv import load_dotenv
|
|
15
|
+
|
|
16
|
+
from memos.context.context import ContextThread
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from memos.configs.mem_cube import GeneralMemCubeConfig
|
|
21
|
+
from memos.configs.mem_os import MOSConfig
|
|
22
|
+
from memos.mem_cube.general import GeneralMemCube
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Load environment variables
|
|
26
|
+
load_dotenv(override=True)
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _update_env_from_dict(data: dict[str, Any]) -> None:
|
|
32
|
+
"""Apply a dict to environment variables, with change logging."""
|
|
33
|
+
|
|
34
|
+
def _is_sensitive(name: str) -> bool:
|
|
35
|
+
n = name.upper()
|
|
36
|
+
return any(s in n for s in ["PASSWORD", "SECRET", "AK", "SK", "TOKEN", "KEY"])
|
|
37
|
+
|
|
38
|
+
for k, v in data.items():
|
|
39
|
+
if isinstance(v, dict):
|
|
40
|
+
new_val = json.dumps(v, ensure_ascii=False)
|
|
41
|
+
elif isinstance(v, bool):
|
|
42
|
+
new_val = "true" if v else "false"
|
|
43
|
+
elif v is None:
|
|
44
|
+
new_val = ""
|
|
45
|
+
else:
|
|
46
|
+
new_val = str(v)
|
|
47
|
+
|
|
48
|
+
old_val = os.environ.get(k)
|
|
49
|
+
os.environ[k] = new_val
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
log_old = "***" if _is_sensitive(k) else (old_val if old_val is not None else "<unset>")
|
|
53
|
+
log_new = "***" if _is_sensitive(k) else new_val
|
|
54
|
+
if old_val != new_val:
|
|
55
|
+
logger.info(f"Nacos config update: {k}={log_new} (was {log_old})")
|
|
56
|
+
except Exception as e:
|
|
57
|
+
# Avoid logging failures blocking config updates
|
|
58
|
+
logger.debug(f"Skip logging change for {k}: {e}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_config_json(name: str, default: Any | None = None) -> Any:
|
|
62
|
+
"""Read JSON object/array from env and parse. Returns default on missing/invalid."""
|
|
63
|
+
raw = os.getenv(name)
|
|
64
|
+
if not raw:
|
|
65
|
+
return default
|
|
66
|
+
try:
|
|
67
|
+
return json.loads(raw)
|
|
68
|
+
except Exception:
|
|
69
|
+
logger.warning(f"Invalid JSON in env '{name}', returning default.")
|
|
70
|
+
return default
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_config_value(path: str, default: Any | None = None) -> Any:
|
|
74
|
+
"""Read value from env with optional dot-path for structured configs.
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
- get_config_value("MONGODB_CONFIG.base_uri")
|
|
78
|
+
- get_config_value("MONGODB_BASE_URI")
|
|
79
|
+
"""
|
|
80
|
+
if "." not in path:
|
|
81
|
+
val = os.getenv(path)
|
|
82
|
+
return val if val is not None else default
|
|
83
|
+
root, *subkeys = path.split(".")
|
|
84
|
+
data = get_config_json(root, default=None)
|
|
85
|
+
if not isinstance(data, dict):
|
|
86
|
+
return default
|
|
87
|
+
cur: Any = data
|
|
88
|
+
for key in subkeys:
|
|
89
|
+
if isinstance(cur, dict) and key in cur:
|
|
90
|
+
cur = cur[key]
|
|
91
|
+
else:
|
|
92
|
+
return default
|
|
93
|
+
return cur
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class NacosConfigManager:
|
|
97
|
+
_client = None
|
|
98
|
+
_data_id = None
|
|
99
|
+
_group = None
|
|
100
|
+
_enabled = False
|
|
101
|
+
|
|
102
|
+
# Pre-compile regex patterns for better performance
|
|
103
|
+
_KEY_VALUE_PATTERN = re.compile(r"^([^=]+)=(.*)$")
|
|
104
|
+
_INTEGER_PATTERN = re.compile(r"^[+-]?\d+$")
|
|
105
|
+
_FLOAT_PATTERN = re.compile(r"^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$")
|
|
106
|
+
|
|
107
|
+
@classmethod
|
|
108
|
+
def _sign(cls, secret_key: str, data: str) -> str:
|
|
109
|
+
"""HMAC-SHA1 sgin"""
|
|
110
|
+
signature = hmac.new(secret_key.encode("utf-8"), data.encode("utf-8"), hashlib.sha1)
|
|
111
|
+
return base64.b64encode(signature.digest()).decode()
|
|
112
|
+
|
|
113
|
+
@staticmethod
|
|
114
|
+
def _parse_value(value: str) -> Any:
|
|
115
|
+
"""Parse string value to appropriate Python type.
|
|
116
|
+
|
|
117
|
+
Supports: bool, int, float, and string.
|
|
118
|
+
"""
|
|
119
|
+
if not value:
|
|
120
|
+
return value
|
|
121
|
+
|
|
122
|
+
val_lower = value.lower()
|
|
123
|
+
|
|
124
|
+
# Boolean
|
|
125
|
+
if val_lower in ("true", "false"):
|
|
126
|
+
return val_lower == "true"
|
|
127
|
+
|
|
128
|
+
# Integer
|
|
129
|
+
if NacosConfigManager._INTEGER_PATTERN.match(value):
|
|
130
|
+
try:
|
|
131
|
+
return int(value)
|
|
132
|
+
except (ValueError, OverflowError):
|
|
133
|
+
return value
|
|
134
|
+
|
|
135
|
+
# Float
|
|
136
|
+
if NacosConfigManager._FLOAT_PATTERN.match(value):
|
|
137
|
+
try:
|
|
138
|
+
return float(value)
|
|
139
|
+
except (ValueError, OverflowError):
|
|
140
|
+
return value
|
|
141
|
+
|
|
142
|
+
# Default to string
|
|
143
|
+
return value
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def parse_properties(content: str) -> dict[str, Any]:
|
|
147
|
+
"""Parse properties file content to dictionary with type inference.
|
|
148
|
+
|
|
149
|
+
Supports:
|
|
150
|
+
- Comments (lines starting with #)
|
|
151
|
+
- Key-value pairs (KEY=VALUE)
|
|
152
|
+
- Type inference (bool, int, float, string)
|
|
153
|
+
"""
|
|
154
|
+
data: dict[str, Any] = {}
|
|
155
|
+
|
|
156
|
+
for line in content.splitlines():
|
|
157
|
+
line = line.strip()
|
|
158
|
+
|
|
159
|
+
# Skip empty lines and comments
|
|
160
|
+
if not line or line.startswith("#"):
|
|
161
|
+
continue
|
|
162
|
+
|
|
163
|
+
# Parse key-value pair
|
|
164
|
+
match = NacosConfigManager._KEY_VALUE_PATTERN.match(line)
|
|
165
|
+
if match:
|
|
166
|
+
key = match.group(1).strip()
|
|
167
|
+
value = match.group(2).strip()
|
|
168
|
+
data[key] = NacosConfigManager._parse_value(value)
|
|
169
|
+
|
|
170
|
+
return data
|
|
171
|
+
|
|
172
|
+
@classmethod
|
|
173
|
+
def start_config_watch(cls):
|
|
174
|
+
while True:
|
|
175
|
+
cls.init()
|
|
176
|
+
time.sleep(60)
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def start_watch_if_enabled(cls) -> None:
|
|
180
|
+
enable = os.getenv("NACOS_ENABLE_WATCH", "false").lower() == "true"
|
|
181
|
+
logger.info(f"NACOS_ENABLE_WATCH: {enable}")
|
|
182
|
+
if not enable:
|
|
183
|
+
return
|
|
184
|
+
interval = int(os.getenv("NACOS_WATCH_INTERVAL", "60"))
|
|
185
|
+
|
|
186
|
+
def _loop() -> None:
|
|
187
|
+
while True:
|
|
188
|
+
try:
|
|
189
|
+
cls.init()
|
|
190
|
+
except Exception as e:
|
|
191
|
+
logger.error(f"❌ Nacos watch loop error: {e}")
|
|
192
|
+
time.sleep(interval)
|
|
193
|
+
|
|
194
|
+
ContextThread(target=_loop, daemon=True).start()
|
|
195
|
+
logger.info(f"Nacos watch thread started (interval={interval}s).")
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def init(cls) -> None:
|
|
199
|
+
server_addr = os.getenv("NACOS_SERVER_ADDR")
|
|
200
|
+
data_id = os.getenv("NACOS_DATA_ID")
|
|
201
|
+
group = os.getenv("NACOS_GROUP", "DEFAULT_GROUP")
|
|
202
|
+
namespace = os.getenv("NACOS_NAMESPACE", "")
|
|
203
|
+
ak = os.getenv("AK")
|
|
204
|
+
sk = os.getenv("SK")
|
|
205
|
+
|
|
206
|
+
if not (server_addr and data_id and ak and sk):
|
|
207
|
+
logger.warning("missing NACOS_SERVER_ADDR / AK / SK / DATA_ID")
|
|
208
|
+
return
|
|
209
|
+
|
|
210
|
+
base_url = f"http://{server_addr}/nacos/v1/cs/configs"
|
|
211
|
+
|
|
212
|
+
def _auth_headers():
|
|
213
|
+
ts = str(int(time.time() * 1000))
|
|
214
|
+
|
|
215
|
+
sign_data = namespace + "+" + group + "+" + ts if namespace else group + "+" + ts
|
|
216
|
+
signature = cls._sign(sk, sign_data)
|
|
217
|
+
return {
|
|
218
|
+
"Spas-AccessKey": ak,
|
|
219
|
+
"Spas-Signature": signature,
|
|
220
|
+
"timeStamp": ts,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try:
|
|
224
|
+
params = {
|
|
225
|
+
"dataId": data_id,
|
|
226
|
+
"group": group,
|
|
227
|
+
"tenant": namespace,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
headers = _auth_headers()
|
|
231
|
+
resp = requests.get(base_url, headers=headers, params=params, timeout=10)
|
|
232
|
+
|
|
233
|
+
if resp.status_code != 200:
|
|
234
|
+
logger.error(f"Nacos AK/SK fail: {resp.status_code} {resp.text}")
|
|
235
|
+
return
|
|
236
|
+
|
|
237
|
+
content = resp.text.strip()
|
|
238
|
+
if not content:
|
|
239
|
+
logger.warning("⚠️ Nacos is empty")
|
|
240
|
+
return
|
|
241
|
+
try:
|
|
242
|
+
data_props = cls.parse_properties(content)
|
|
243
|
+
logger.info("nacos config:", data_props)
|
|
244
|
+
_update_env_from_dict(data_props)
|
|
245
|
+
logger.info("✅ parse Nacos setting is Properties ")
|
|
246
|
+
except Exception as e:
|
|
247
|
+
logger.error(f"⚠️ Nacos parse fail(not JSON/YAML/Properties): {e}")
|
|
248
|
+
raise Exception(f"Nacos configuration parsing failed: {e}") from e
|
|
249
|
+
|
|
250
|
+
except Exception as e:
|
|
251
|
+
logger.error(f"❌ Nacos AK/SK init fail: {e}")
|
|
252
|
+
raise Exception(f"❌ Nacos AK/SK init fail: {e}") from e
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# init Nacos
|
|
256
|
+
NacosConfigManager.init()
|
|
257
|
+
NacosConfigManager.start_watch_if_enabled()
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class APIConfig:
|
|
261
|
+
"""Centralized configuration management for MemOS APIs."""
|
|
262
|
+
|
|
263
|
+
@staticmethod
|
|
264
|
+
def get_openai_config() -> dict[str, Any]:
|
|
265
|
+
"""Get OpenAI configuration."""
|
|
266
|
+
return {
|
|
267
|
+
"model_name_or_path": os.getenv("MOS_CHAT_MODEL", "gpt-4o-mini"),
|
|
268
|
+
"temperature": float(os.getenv("MOS_CHAT_TEMPERATURE", "0.8")),
|
|
269
|
+
"max_tokens": int(os.getenv("MOS_MAX_TOKENS", "8000")),
|
|
270
|
+
"top_p": float(os.getenv("MOS_TOP_P", "0.9")),
|
|
271
|
+
"top_k": int(os.getenv("MOS_TOP_K", "50")),
|
|
272
|
+
"remove_think_prefix": True,
|
|
273
|
+
"api_key": os.getenv("OPENAI_API_KEY", "your-api-key-here"),
|
|
274
|
+
"api_base": os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1"),
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
@staticmethod
|
|
278
|
+
def qwen_config() -> dict[str, Any]:
|
|
279
|
+
"""Get Qwen configuration."""
|
|
280
|
+
return {
|
|
281
|
+
"model_name_or_path": os.getenv("MOS_CHAT_MODEL", "Qwen/Qwen3-1.7B"),
|
|
282
|
+
"temperature": float(os.getenv("MOS_CHAT_TEMPERATURE", "0.8")),
|
|
283
|
+
"max_tokens": int(os.getenv("MOS_MAX_TOKENS", "4096")),
|
|
284
|
+
"remove_think_prefix": True,
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@staticmethod
|
|
288
|
+
def vllm_config() -> dict[str, Any]:
|
|
289
|
+
"""Get Qwen configuration."""
|
|
290
|
+
return {
|
|
291
|
+
"model_name_or_path": os.getenv("MOS_CHAT_MODEL", "Qwen/Qwen3-1.7B"),
|
|
292
|
+
"temperature": float(os.getenv("MOS_CHAT_TEMPERATURE", "0.8")),
|
|
293
|
+
"max_tokens": int(os.getenv("MOS_MAX_TOKENS", "4096")),
|
|
294
|
+
"remove_think_prefix": True,
|
|
295
|
+
"api_key": os.getenv("VLLM_API_KEY", ""),
|
|
296
|
+
"api_base": os.getenv("VLLM_API_BASE", "http://localhost:8088/v1"),
|
|
297
|
+
"model_schema": os.getenv("MOS_MODEL_SCHEMA", "memos.configs.llm.VLLMLLMConfig"),
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
@staticmethod
|
|
301
|
+
def get_activation_config() -> dict[str, Any]:
|
|
302
|
+
"""Get Ollama configuration."""
|
|
303
|
+
return {
|
|
304
|
+
"backend": "kv_cache",
|
|
305
|
+
"config": {
|
|
306
|
+
"memory_filename": "activation_memory.pickle",
|
|
307
|
+
"extractor_llm": {
|
|
308
|
+
"backend": "huggingface_singleton",
|
|
309
|
+
"config": {
|
|
310
|
+
"model_name_or_path": os.getenv("MOS_CHAT_MODEL", "Qwen/Qwen3-1.7B"),
|
|
311
|
+
"temperature": 0.8,
|
|
312
|
+
"max_tokens": 1024,
|
|
313
|
+
"top_p": 0.9,
|
|
314
|
+
"top_k": 50,
|
|
315
|
+
"add_generation_prompt": True,
|
|
316
|
+
"remove_think_prefix": False,
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@staticmethod
|
|
323
|
+
def get_memreader_config() -> dict[str, Any]:
|
|
324
|
+
"""Get MemReader configuration."""
|
|
325
|
+
return {
|
|
326
|
+
"backend": "openai",
|
|
327
|
+
"config": {
|
|
328
|
+
"model_name_or_path": os.getenv("MEMRADER_MODEL", "gpt-4o-mini"),
|
|
329
|
+
"temperature": 0.6,
|
|
330
|
+
"max_tokens": int(os.getenv("MEMRADER_MAX_TOKENS", "8000")),
|
|
331
|
+
"top_p": 0.95,
|
|
332
|
+
"top_k": 20,
|
|
333
|
+
"api_key": os.getenv("MEMRADER_API_KEY", "EMPTY"),
|
|
334
|
+
# Default to OpenAI base URL when env var is not provided to satisfy pydantic
|
|
335
|
+
# validation requirements during tests/import.
|
|
336
|
+
"api_base": os.getenv("MEMRADER_API_BASE", "https://api.openai.com/v1"),
|
|
337
|
+
"remove_think_prefix": True,
|
|
338
|
+
"extra_body": {"chat_template_kwargs": {"enable_thinking": False}},
|
|
339
|
+
},
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@staticmethod
|
|
343
|
+
def get_activation_vllm_config() -> dict[str, Any]:
|
|
344
|
+
"""Get Ollama configuration."""
|
|
345
|
+
return {
|
|
346
|
+
"backend": "vllm_kv_cache",
|
|
347
|
+
"config": {
|
|
348
|
+
"memory_filename": "activation_memory.pickle",
|
|
349
|
+
"extractor_llm": {
|
|
350
|
+
"backend": "vllm",
|
|
351
|
+
"config": APIConfig.vllm_config(),
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
@staticmethod
|
|
357
|
+
def get_preference_memory_config() -> dict[str, Any]:
|
|
358
|
+
"""Get preference memory configuration."""
|
|
359
|
+
return {
|
|
360
|
+
"backend": "pref_text",
|
|
361
|
+
"config": {
|
|
362
|
+
"extractor_llm": APIConfig.get_memreader_config(),
|
|
363
|
+
"vector_db": {
|
|
364
|
+
"backend": "milvus",
|
|
365
|
+
"config": APIConfig.get_milvus_config(),
|
|
366
|
+
},
|
|
367
|
+
"embedder": APIConfig.get_embedder_config(),
|
|
368
|
+
"reranker": APIConfig.get_reranker_config(),
|
|
369
|
+
"extractor": {"backend": "naive", "config": {}},
|
|
370
|
+
"adder": {"backend": "naive", "config": {}},
|
|
371
|
+
"retriever": {"backend": "naive", "config": {}},
|
|
372
|
+
},
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@staticmethod
|
|
376
|
+
def get_reranker_config() -> dict[str, Any]:
|
|
377
|
+
"""Get embedder configuration."""
|
|
378
|
+
embedder_backend = os.getenv("MOS_RERANKER_BACKEND", "http_bge")
|
|
379
|
+
|
|
380
|
+
if embedder_backend in ["http_bge", "http_bge_strategy"]:
|
|
381
|
+
return {
|
|
382
|
+
"backend": embedder_backend,
|
|
383
|
+
"config": {
|
|
384
|
+
"url": os.getenv("MOS_RERANKER_URL", "localhost:8000/v1/rerank"),
|
|
385
|
+
"model": os.getenv("MOS_RERANKER_MODEL", "bge-reranker-v2-m3"),
|
|
386
|
+
"timeout": 10,
|
|
387
|
+
"headers_extra": json.loads(os.getenv("MOS_RERANKER_HEADERS_EXTRA", "{}")),
|
|
388
|
+
"rerank_source": os.getenv("MOS_RERANK_SOURCE"),
|
|
389
|
+
"reranker_strategy": os.getenv("MOS_RERANKER_STRATEGY", "single_turn"),
|
|
390
|
+
},
|
|
391
|
+
}
|
|
392
|
+
else:
|
|
393
|
+
return {
|
|
394
|
+
"backend": "cosine_local",
|
|
395
|
+
"config": {
|
|
396
|
+
"level_weights": {"topic": 1.0, "concept": 1.0, "fact": 1.0},
|
|
397
|
+
"level_field": "background",
|
|
398
|
+
},
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
@staticmethod
|
|
402
|
+
def get_feedback_reranker_config() -> dict[str, Any]:
|
|
403
|
+
"""Get embedder configuration."""
|
|
404
|
+
embedder_backend = os.getenv("MOS_FEEDBACK_RERANKER_BACKEND", "http_bge")
|
|
405
|
+
|
|
406
|
+
if embedder_backend in ["http_bge", "http_bge_strategy"]:
|
|
407
|
+
return {
|
|
408
|
+
"backend": embedder_backend,
|
|
409
|
+
"config": {
|
|
410
|
+
"url": os.getenv("MOS_RERANKER_URL", "localhost:8000/v1/rerank"),
|
|
411
|
+
"model": os.getenv("MOS_FEEDBACK_RERANKER_MODEL", "bge-reranker-v2-m3"),
|
|
412
|
+
"timeout": 10,
|
|
413
|
+
"max_query_tokens": int(os.getenv("MOS_RERANKER_MAX_TOKENS", 8000)),
|
|
414
|
+
"concate_len": int(os.getenv("MOS_RERANKER_CONCAT_LEN", 1000)),
|
|
415
|
+
"headers_extra": json.loads(os.getenv("MOS_RERANKER_HEADERS_EXTRA", "{}")),
|
|
416
|
+
"rerank_source": os.getenv("MOS_RERANK_SOURCE"),
|
|
417
|
+
"reranker_strategy": os.getenv("MOS_RERANKER_STRATEGY", "single_turn"),
|
|
418
|
+
},
|
|
419
|
+
}
|
|
420
|
+
else:
|
|
421
|
+
return {
|
|
422
|
+
"backend": "cosine_local",
|
|
423
|
+
"config": {
|
|
424
|
+
"level_weights": {"topic": 1.0, "concept": 1.0, "fact": 1.0},
|
|
425
|
+
"level_field": "background",
|
|
426
|
+
},
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
@staticmethod
|
|
430
|
+
def get_embedder_config() -> dict[str, Any]:
|
|
431
|
+
"""Get embedder configuration."""
|
|
432
|
+
embedder_backend = os.getenv("MOS_EMBEDDER_BACKEND", "ollama")
|
|
433
|
+
|
|
434
|
+
if embedder_backend == "universal_api":
|
|
435
|
+
return {
|
|
436
|
+
"backend": "universal_api",
|
|
437
|
+
"config": {
|
|
438
|
+
"provider": os.getenv("MOS_EMBEDDER_PROVIDER", "openai"),
|
|
439
|
+
"api_key": os.getenv("MOS_EMBEDDER_API_KEY", "sk-xxxx"),
|
|
440
|
+
"model_name_or_path": os.getenv("MOS_EMBEDDER_MODEL", "text-embedding-3-large"),
|
|
441
|
+
"headers_extra": json.loads(os.getenv("MOS_EMBEDDER_HEADERS_EXTRA", "{}")),
|
|
442
|
+
"base_url": os.getenv("MOS_EMBEDDER_API_BASE", "http://openai.com"),
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
else: # ollama
|
|
446
|
+
return {
|
|
447
|
+
"backend": "ollama",
|
|
448
|
+
"config": {
|
|
449
|
+
"model_name_or_path": os.getenv(
|
|
450
|
+
"MOS_EMBEDDER_MODEL", "nomic-embed-text:latest"
|
|
451
|
+
),
|
|
452
|
+
"api_base": os.getenv("OLLAMA_API_BASE", "http://localhost:11434"),
|
|
453
|
+
},
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@staticmethod
|
|
457
|
+
def get_reader_config() -> dict[str, Any]:
|
|
458
|
+
"""Get reader configuration."""
|
|
459
|
+
return {
|
|
460
|
+
"backend": os.getenv("MEM_READER_BACKEND", "multimodal_struct"),
|
|
461
|
+
"config": {
|
|
462
|
+
"chunk_type": os.getenv("MEM_READER_CHAT_CHUNK_TYPE", "default"),
|
|
463
|
+
"chunk_length": int(os.getenv("MEM_READER_CHAT_CHUNK_TOKEN_SIZE", 1600)),
|
|
464
|
+
"chunk_session": int(os.getenv("MEM_READER_CHAT_CHUNK_SESS_SIZE", 10)),
|
|
465
|
+
"chunk_overlap": int(os.getenv("MEM_READER_CHAT_CHUNK_OVERLAP", 2)),
|
|
466
|
+
},
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
@staticmethod
|
|
470
|
+
def get_internet_config() -> dict[str, Any]:
|
|
471
|
+
"""Get embedder configuration."""
|
|
472
|
+
reader_config = APIConfig.get_reader_config()
|
|
473
|
+
return {
|
|
474
|
+
"backend": "bocha",
|
|
475
|
+
"config": {
|
|
476
|
+
"api_key": os.getenv("BOCHA_API_KEY", "bocha"),
|
|
477
|
+
"max_results": 15,
|
|
478
|
+
"num_per_request": 10,
|
|
479
|
+
"reader": {
|
|
480
|
+
"backend": reader_config["backend"],
|
|
481
|
+
"config": {
|
|
482
|
+
"llm": {
|
|
483
|
+
"backend": "openai",
|
|
484
|
+
"config": {
|
|
485
|
+
"model_name_or_path": os.getenv("MEMRADER_MODEL"),
|
|
486
|
+
"temperature": 0.6,
|
|
487
|
+
"max_tokens": 5000,
|
|
488
|
+
"top_p": 0.95,
|
|
489
|
+
"top_k": 20,
|
|
490
|
+
"api_key": os.getenv("MEMRADER_API_KEY", "EMPTY"),
|
|
491
|
+
"api_base": os.getenv("MEMRADER_API_BASE"),
|
|
492
|
+
"remove_think_prefix": True,
|
|
493
|
+
"extra_body": {"chat_template_kwargs": {"enable_thinking": False}},
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
"embedder": APIConfig.get_embedder_config(),
|
|
497
|
+
"chunker": {
|
|
498
|
+
"backend": "sentence",
|
|
499
|
+
"config": {
|
|
500
|
+
"tokenizer_or_token_counter": "gpt2",
|
|
501
|
+
"chunk_size": 512,
|
|
502
|
+
"chunk_overlap": 128,
|
|
503
|
+
"min_sentences_per_chunk": 1,
|
|
504
|
+
},
|
|
505
|
+
},
|
|
506
|
+
"chat_chunker": reader_config,
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
@staticmethod
|
|
513
|
+
def get_neo4j_community_config(user_id: str | None = None) -> dict[str, Any]:
|
|
514
|
+
"""Get Neo4j community configuration."""
|
|
515
|
+
return {
|
|
516
|
+
"uri": os.getenv("NEO4J_URI", "bolt://localhost:7687"),
|
|
517
|
+
"user": os.getenv("NEO4J_USER", "neo4j"),
|
|
518
|
+
"db_name": os.getenv("NEO4J_DB_NAME", "neo4j"),
|
|
519
|
+
"password": os.getenv("NEO4J_PASSWORD", "12345678"),
|
|
520
|
+
"user_name": f"memos{user_id.replace('-', '')}",
|
|
521
|
+
"auto_create": False,
|
|
522
|
+
"use_multi_db": False,
|
|
523
|
+
"embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 1024)),
|
|
524
|
+
"vec_config": {
|
|
525
|
+
# Pass nested config to initialize external vector DB
|
|
526
|
+
# If you use qdrant, please use Server instead of local mode.
|
|
527
|
+
"backend": "qdrant",
|
|
528
|
+
"config": {
|
|
529
|
+
"collection_name": "neo4j_vec_db",
|
|
530
|
+
"vector_dimension": int(os.getenv("EMBEDDING_DIMENSION", 1024)),
|
|
531
|
+
"distance_metric": "cosine",
|
|
532
|
+
"host": os.getenv("QDRANT_HOST", "localhost"),
|
|
533
|
+
"port": int(os.getenv("QDRANT_PORT", "6333")),
|
|
534
|
+
"path": os.getenv("QDRANT_PATH"),
|
|
535
|
+
"url": os.getenv("QDRANT_URL"),
|
|
536
|
+
"api_key": os.getenv("QDRANT_API_KEY"),
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
@staticmethod
|
|
542
|
+
def get_neo4j_config(user_id: str | None = None) -> dict[str, Any]:
|
|
543
|
+
"""Get Neo4j configuration."""
|
|
544
|
+
if os.getenv("MOS_NEO4J_SHARED_DB", "false").lower() == "true":
|
|
545
|
+
return APIConfig.get_neo4j_shared_config(user_id)
|
|
546
|
+
else:
|
|
547
|
+
return APIConfig.get_noshared_neo4j_config(user_id)
|
|
548
|
+
|
|
549
|
+
@staticmethod
|
|
550
|
+
def get_noshared_neo4j_config(user_id) -> dict[str, Any]:
|
|
551
|
+
"""Get Neo4j configuration."""
|
|
552
|
+
return {
|
|
553
|
+
"uri": os.getenv("NEO4J_URI", "bolt://localhost:7687"),
|
|
554
|
+
"user": os.getenv("NEO4J_USER", "neo4j"),
|
|
555
|
+
"db_name": f"memos{user_id.replace('-', '')}",
|
|
556
|
+
"password": os.getenv("NEO4J_PASSWORD", "12345678"),
|
|
557
|
+
"auto_create": True,
|
|
558
|
+
"use_multi_db": True,
|
|
559
|
+
"embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
@staticmethod
|
|
563
|
+
def get_neo4j_shared_config(user_id: str | None = None) -> dict[str, Any]:
|
|
564
|
+
"""Get Neo4j configuration."""
|
|
565
|
+
return {
|
|
566
|
+
"uri": os.getenv("NEO4J_URI", "bolt://localhost:7687"),
|
|
567
|
+
"user": os.getenv("NEO4J_USER", "neo4j"),
|
|
568
|
+
"db_name": os.getenv("NEO4J_DB_NAME", "shared-tree-textual-memory"),
|
|
569
|
+
"password": os.getenv("NEO4J_PASSWORD", "12345678"),
|
|
570
|
+
"user_name": f"memos{user_id.replace('-', '')}",
|
|
571
|
+
"auto_create": True,
|
|
572
|
+
"use_multi_db": False,
|
|
573
|
+
"embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
@staticmethod
|
|
577
|
+
def get_nebular_config(user_id: str | None = None) -> dict[str, Any]:
|
|
578
|
+
"""Get Nebular configuration."""
|
|
579
|
+
return {
|
|
580
|
+
"uri": json.loads(os.getenv("NEBULAR_HOSTS", '["localhost"]')),
|
|
581
|
+
"user": os.getenv("NEBULAR_USER", "root"),
|
|
582
|
+
"password": os.getenv("NEBULAR_PASSWORD", "xxxxxx"),
|
|
583
|
+
"space": os.getenv("NEBULAR_SPACE", "shared-tree-textual-memory"),
|
|
584
|
+
"user_name": f"memos{user_id.replace('-', '')}",
|
|
585
|
+
"use_multi_db": False,
|
|
586
|
+
"auto_create": True,
|
|
587
|
+
"embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
@staticmethod
|
|
591
|
+
def get_milvus_config():
|
|
592
|
+
return {
|
|
593
|
+
"collection_name": [
|
|
594
|
+
"explicit_preference",
|
|
595
|
+
"implicit_preference",
|
|
596
|
+
],
|
|
597
|
+
"vector_dimension": int(os.getenv("EMBEDDING_DIMENSION", 1024)),
|
|
598
|
+
"distance_metric": "cosine",
|
|
599
|
+
"uri": os.getenv("MILVUS_URI", "http://localhost:19530"),
|
|
600
|
+
"user_name": os.getenv("MILVUS_USER_NAME", "root"),
|
|
601
|
+
"password": os.getenv("MILVUS_PASSWORD", "12345678"),
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
@staticmethod
|
|
605
|
+
def get_polardb_config(user_id: str | None = None) -> dict[str, Any]:
|
|
606
|
+
"""Get PolarDB configuration."""
|
|
607
|
+
use_multi_db = os.getenv("POLAR_DB_USE_MULTI_DB", "false").lower() == "true"
|
|
608
|
+
|
|
609
|
+
if use_multi_db:
|
|
610
|
+
# Multi-DB mode: each user gets their own database (physical isolation)
|
|
611
|
+
db_name = f"memos{user_id.replace('-', '')}" if user_id else "memos_default"
|
|
612
|
+
user_name = None
|
|
613
|
+
else:
|
|
614
|
+
# Shared-DB mode: all users share one database with user_name tag (logical isolation)
|
|
615
|
+
db_name = os.getenv("POLAR_DB_DB_NAME", "shared_memos_db")
|
|
616
|
+
user_name = f"memos{user_id.replace('-', '')}" if user_id else "memos_default"
|
|
617
|
+
|
|
618
|
+
return {
|
|
619
|
+
"host": os.getenv("POLAR_DB_HOST", "localhost"),
|
|
620
|
+
"port": int(os.getenv("POLAR_DB_PORT", "5432")),
|
|
621
|
+
"user": os.getenv("POLAR_DB_USER", "root"),
|
|
622
|
+
"password": os.getenv("POLAR_DB_PASSWORD", "123456"),
|
|
623
|
+
"db_name": db_name,
|
|
624
|
+
"maxconn": int(os.getenv("POLARDB_POOL_MAX_CONN", "100")),
|
|
625
|
+
"user_name": user_name,
|
|
626
|
+
"use_multi_db": use_multi_db,
|
|
627
|
+
"auto_create": True,
|
|
628
|
+
"embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 1024)),
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
@staticmethod
|
|
632
|
+
def get_mysql_config() -> dict[str, Any]:
|
|
633
|
+
"""Get MySQL configuration."""
|
|
634
|
+
return {
|
|
635
|
+
"host": os.getenv("MYSQL_HOST", "localhost"),
|
|
636
|
+
"port": int(os.getenv("MYSQL_PORT", "3306")),
|
|
637
|
+
"username": os.getenv("MYSQL_USERNAME", "root"),
|
|
638
|
+
"password": os.getenv("MYSQL_PASSWORD", "12345678"),
|
|
639
|
+
"database": os.getenv("MYSQL_DATABASE", "memos_users"),
|
|
640
|
+
"charset": os.getenv("MYSQL_CHARSET", "utf8mb4"),
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
@staticmethod
|
|
644
|
+
def get_scheduler_config() -> dict[str, Any]:
|
|
645
|
+
"""Get scheduler configuration."""
|
|
646
|
+
return {
|
|
647
|
+
"backend": "optimized_scheduler",
|
|
648
|
+
"config": {
|
|
649
|
+
"top_k": int(os.getenv("MOS_SCHEDULER_TOP_K", "10")),
|
|
650
|
+
"act_mem_update_interval": int(
|
|
651
|
+
os.getenv("MOS_SCHEDULER_ACT_MEM_UPDATE_INTERVAL", "300")
|
|
652
|
+
),
|
|
653
|
+
"context_window_size": int(os.getenv("MOS_SCHEDULER_CONTEXT_WINDOW_SIZE", "5")),
|
|
654
|
+
"thread_pool_max_workers": int(
|
|
655
|
+
os.getenv("MOS_SCHEDULER_THREAD_POOL_MAX_WORKERS", "10000")
|
|
656
|
+
),
|
|
657
|
+
"consume_interval_seconds": float(
|
|
658
|
+
os.getenv("MOS_SCHEDULER_CONSUME_INTERVAL_SECONDS", "0.01")
|
|
659
|
+
),
|
|
660
|
+
"enable_parallel_dispatch": os.getenv(
|
|
661
|
+
"MOS_SCHEDULER_ENABLE_PARALLEL_DISPATCH", "true"
|
|
662
|
+
).lower()
|
|
663
|
+
== "true",
|
|
664
|
+
"enable_activation_memory": os.getenv(
|
|
665
|
+
"MOS_SCHEDULER_ENABLE_ACTIVATION_MEMORY", "false"
|
|
666
|
+
).lower()
|
|
667
|
+
== "true",
|
|
668
|
+
},
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
@staticmethod
|
|
672
|
+
def is_scheduler_enabled() -> bool:
|
|
673
|
+
"""Check if scheduler is enabled via environment variable."""
|
|
674
|
+
return os.getenv("MOS_ENABLE_SCHEDULER", "false").lower() == "true"
|
|
675
|
+
|
|
676
|
+
@staticmethod
|
|
677
|
+
def is_default_cube_config_enabled() -> bool:
|
|
678
|
+
"""Check if default cube config is enabled via environment variable."""
|
|
679
|
+
return os.getenv("MOS_ENABLE_DEFAULT_CUBE_CONFIG", "true").lower() == "true"
|
|
680
|
+
|
|
681
|
+
@staticmethod
|
|
682
|
+
def is_dingding_bot_enabled() -> bool:
|
|
683
|
+
"""Check if DingDing bot is enabled via environment variable."""
|
|
684
|
+
return os.getenv("ENABLE_DINGDING_BOT", "false").lower() == "true"
|
|
685
|
+
|
|
686
|
+
@staticmethod
|
|
687
|
+
def get_dingding_bot_config() -> dict[str, Any] | None:
|
|
688
|
+
"""Get DingDing bot configuration if enabled."""
|
|
689
|
+
if not APIConfig.is_dingding_bot_enabled():
|
|
690
|
+
return None
|
|
691
|
+
|
|
692
|
+
return {
|
|
693
|
+
"enabled": True,
|
|
694
|
+
"access_token_user": os.getenv("DINGDING_ACCESS_TOKEN_USER", ""),
|
|
695
|
+
"secret_user": os.getenv("DINGDING_SECRET_USER", ""),
|
|
696
|
+
"access_token_error": os.getenv("DINGDING_ACCESS_TOKEN_ERROR", ""),
|
|
697
|
+
"secret_error": os.getenv("DINGDING_SECRET_ERROR", ""),
|
|
698
|
+
"robot_code": os.getenv("DINGDING_ROBOT_CODE", ""),
|
|
699
|
+
"app_key": os.getenv("DINGDING_APP_KEY", ""),
|
|
700
|
+
"app_secret": os.getenv("DINGDING_APP_SECRET", ""),
|
|
701
|
+
"oss_endpoint": os.getenv("OSS_ENDPOINT", ""),
|
|
702
|
+
"oss_region": os.getenv("OSS_REGION", ""),
|
|
703
|
+
"oss_bucket_name": os.getenv("OSS_BUCKET_NAME", ""),
|
|
704
|
+
"oss_access_key_id": os.getenv("OSS_ACCESS_KEY_ID", ""),
|
|
705
|
+
"oss_access_key_secret": os.getenv("OSS_ACCESS_KEY_SECRET", ""),
|
|
706
|
+
"oss_public_base_url": os.getenv("OSS_PUBLIC_BASE_URL", ""),
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
@staticmethod
|
|
710
|
+
def get_product_default_config() -> dict[str, Any]:
|
|
711
|
+
"""Get default configuration for Product API."""
|
|
712
|
+
openai_config = APIConfig.get_openai_config()
|
|
713
|
+
qwen_config = APIConfig.qwen_config()
|
|
714
|
+
vllm_config = APIConfig.vllm_config()
|
|
715
|
+
reader_config = APIConfig.get_reader_config()
|
|
716
|
+
|
|
717
|
+
backend_model = {
|
|
718
|
+
"openai": openai_config,
|
|
719
|
+
"huggingface": qwen_config,
|
|
720
|
+
"vllm": vllm_config,
|
|
721
|
+
}
|
|
722
|
+
backend = os.getenv("MOS_CHAT_MODEL_PROVIDER", "openai")
|
|
723
|
+
mysql_config = APIConfig.get_mysql_config()
|
|
724
|
+
config = {
|
|
725
|
+
"user_id": os.getenv("MOS_USER_ID", "root"),
|
|
726
|
+
"chat_model": {"backend": backend, "config": backend_model[backend]},
|
|
727
|
+
"mem_reader": {
|
|
728
|
+
"backend": reader_config["backend"],
|
|
729
|
+
"config": {
|
|
730
|
+
"llm": APIConfig.get_memreader_config(),
|
|
731
|
+
"embedder": APIConfig.get_embedder_config(),
|
|
732
|
+
"chunker": {
|
|
733
|
+
"backend": "sentence",
|
|
734
|
+
"config": {
|
|
735
|
+
"tokenizer_or_token_counter": "gpt2",
|
|
736
|
+
"chunk_size": 512,
|
|
737
|
+
"chunk_overlap": 128,
|
|
738
|
+
"min_sentences_per_chunk": 1,
|
|
739
|
+
},
|
|
740
|
+
},
|
|
741
|
+
"chat_chunker": reader_config,
|
|
742
|
+
"direct_markdown_hostnames": [
|
|
743
|
+
h.strip()
|
|
744
|
+
for h in os.getenv(
|
|
745
|
+
"FILE_PARSER_DIRECT_MARKDOWN_HOSTNAMES", "139.196.232.20"
|
|
746
|
+
).split(",")
|
|
747
|
+
if h.strip()
|
|
748
|
+
],
|
|
749
|
+
},
|
|
750
|
+
},
|
|
751
|
+
"enable_textual_memory": True,
|
|
752
|
+
"enable_activation_memory": os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower()
|
|
753
|
+
== "true",
|
|
754
|
+
"enable_preference_memory": os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower()
|
|
755
|
+
== "true",
|
|
756
|
+
"top_k": int(os.getenv("MOS_TOP_K", "50")),
|
|
757
|
+
"max_turns_window": int(os.getenv("MOS_MAX_TURNS_WINDOW", "20")),
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
# Add scheduler configuration if enabled
|
|
761
|
+
if APIConfig.is_scheduler_enabled():
|
|
762
|
+
config["mem_scheduler"] = APIConfig.get_scheduler_config()
|
|
763
|
+
config["enable_mem_scheduler"] = True
|
|
764
|
+
else:
|
|
765
|
+
config["enable_mem_scheduler"] = False
|
|
766
|
+
|
|
767
|
+
# Add user manager configuration if enabled
|
|
768
|
+
if os.getenv("MOS_USER_MANAGER_BACKEND", "sqlite").lower() == "mysql":
|
|
769
|
+
config["user_manager"] = {
|
|
770
|
+
"backend": "mysql",
|
|
771
|
+
"config": mysql_config,
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return config
|
|
775
|
+
|
|
776
|
+
@staticmethod
|
|
777
|
+
def get_start_default_config() -> dict[str, Any]:
|
|
778
|
+
"""Get default configuration for Start API."""
|
|
779
|
+
config = {
|
|
780
|
+
"user_id": os.getenv("MOS_USER_ID", "default_user"),
|
|
781
|
+
"session_id": os.getenv("MOS_SESSION_ID", "default_session"),
|
|
782
|
+
"enable_textual_memory": True,
|
|
783
|
+
"enable_activation_memory": os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower()
|
|
784
|
+
== "true",
|
|
785
|
+
"enable_preference_memory": os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower()
|
|
786
|
+
== "true",
|
|
787
|
+
"top_k": int(os.getenv("MOS_TOP_K", "5")),
|
|
788
|
+
"chat_model": {
|
|
789
|
+
"backend": os.getenv("MOS_CHAT_MODEL_PROVIDER", "openai"),
|
|
790
|
+
"config": {
|
|
791
|
+
"model_name_or_path": os.getenv("MOS_CHAT_MODEL", "gpt-4o-mini"),
|
|
792
|
+
"api_key": os.getenv("OPENAI_API_KEY", "sk-xxxxxx"),
|
|
793
|
+
"temperature": float(os.getenv("MOS_CHAT_TEMPERATURE", 0.7)),
|
|
794
|
+
"api_base": os.getenv("OPENAI_API_BASE", "http://xxxxxx:3000/v1"),
|
|
795
|
+
"max_tokens": int(os.getenv("MOS_MAX_TOKENS", 1024)),
|
|
796
|
+
"top_p": float(os.getenv("MOS_TOP_P", 0.9)),
|
|
797
|
+
"top_k": int(os.getenv("MOS_TOP_K", 50)),
|
|
798
|
+
"remove_think_prefix": True,
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
# Add scheduler configuration if enabled
|
|
804
|
+
if APIConfig.is_scheduler_enabled():
|
|
805
|
+
config["mem_scheduler"] = APIConfig.get_scheduler_config()
|
|
806
|
+
config["enable_mem_scheduler"] = True
|
|
807
|
+
else:
|
|
808
|
+
config["enable_mem_scheduler"] = False
|
|
809
|
+
|
|
810
|
+
return config
|
|
811
|
+
|
|
812
|
+
@staticmethod
|
|
813
|
+
def create_user_config(user_name: str, user_id: str) -> tuple["MOSConfig", "GeneralMemCube"]:
|
|
814
|
+
"""Create configuration for a specific user."""
|
|
815
|
+
from memos.configs.mem_cube import GeneralMemCubeConfig
|
|
816
|
+
from memos.configs.mem_os import MOSConfig
|
|
817
|
+
from memos.mem_cube.general import GeneralMemCube
|
|
818
|
+
|
|
819
|
+
openai_config = APIConfig.get_openai_config()
|
|
820
|
+
qwen_config = APIConfig.qwen_config()
|
|
821
|
+
vllm_config = APIConfig.vllm_config()
|
|
822
|
+
mysql_config = APIConfig.get_mysql_config()
|
|
823
|
+
reader_config = APIConfig.get_reader_config()
|
|
824
|
+
backend = os.getenv("MOS_CHAT_MODEL_PROVIDER", "openai")
|
|
825
|
+
backend_model = {
|
|
826
|
+
"openai": openai_config,
|
|
827
|
+
"huggingface": qwen_config,
|
|
828
|
+
"vllm": vllm_config,
|
|
829
|
+
}
|
|
830
|
+
# Create MOSConfig
|
|
831
|
+
config_dict = {
|
|
832
|
+
"user_id": user_id,
|
|
833
|
+
"chat_model": {
|
|
834
|
+
"backend": backend,
|
|
835
|
+
"config": backend_model[backend],
|
|
836
|
+
},
|
|
837
|
+
"mem_reader": {
|
|
838
|
+
"backend": reader_config["backend"],
|
|
839
|
+
"config": {
|
|
840
|
+
"llm": APIConfig.get_memreader_config(),
|
|
841
|
+
"embedder": APIConfig.get_embedder_config(),
|
|
842
|
+
"chunker": {
|
|
843
|
+
"backend": "sentence",
|
|
844
|
+
"config": {
|
|
845
|
+
"tokenizer_or_token_counter": "gpt2",
|
|
846
|
+
"chunk_size": 512,
|
|
847
|
+
"chunk_overlap": 128,
|
|
848
|
+
"min_sentences_per_chunk": 1,
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
"chat_chunker": reader_config,
|
|
852
|
+
},
|
|
853
|
+
},
|
|
854
|
+
"enable_textual_memory": True,
|
|
855
|
+
"enable_activation_memory": os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower()
|
|
856
|
+
== "true",
|
|
857
|
+
"enable_preference_memory": os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower()
|
|
858
|
+
== "true",
|
|
859
|
+
"top_k": 30,
|
|
860
|
+
"max_turns_window": 20,
|
|
861
|
+
}
|
|
862
|
+
# Add scheduler configuration if enabled
|
|
863
|
+
if APIConfig.is_scheduler_enabled():
|
|
864
|
+
config_dict["mem_scheduler"] = APIConfig.get_scheduler_config()
|
|
865
|
+
config_dict["enable_mem_scheduler"] = True
|
|
866
|
+
else:
|
|
867
|
+
config_dict["enable_mem_scheduler"] = False
|
|
868
|
+
|
|
869
|
+
# Add user manager configuration if enabled
|
|
870
|
+
if os.getenv("MOS_USER_MANAGER_BACKEND", "sqlite").lower() == "mysql":
|
|
871
|
+
config_dict["user_manager"] = {
|
|
872
|
+
"backend": "mysql",
|
|
873
|
+
"config": mysql_config,
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
default_config = MOSConfig(**config_dict)
|
|
877
|
+
|
|
878
|
+
neo4j_community_config = APIConfig.get_neo4j_community_config(user_id)
|
|
879
|
+
neo4j_config = APIConfig.get_neo4j_config(user_id)
|
|
880
|
+
nebular_config = APIConfig.get_nebular_config(user_id)
|
|
881
|
+
polardb_config = APIConfig.get_polardb_config(user_id)
|
|
882
|
+
internet_config = (
|
|
883
|
+
APIConfig.get_internet_config()
|
|
884
|
+
if os.getenv("ENABLE_INTERNET", "false").lower() == "true"
|
|
885
|
+
else None
|
|
886
|
+
)
|
|
887
|
+
graph_db_backend_map = {
|
|
888
|
+
"neo4j-community": neo4j_community_config,
|
|
889
|
+
"neo4j": neo4j_config,
|
|
890
|
+
"nebular": nebular_config,
|
|
891
|
+
"polardb": polardb_config,
|
|
892
|
+
}
|
|
893
|
+
graph_db_backend = os.getenv("NEO4J_BACKEND", "neo4j-community").lower()
|
|
894
|
+
if graph_db_backend in graph_db_backend_map:
|
|
895
|
+
# Create MemCube config
|
|
896
|
+
|
|
897
|
+
default_cube_config = GeneralMemCubeConfig.model_validate(
|
|
898
|
+
{
|
|
899
|
+
"user_id": user_id,
|
|
900
|
+
"cube_id": f"{user_name}_default_cube",
|
|
901
|
+
"text_mem": {
|
|
902
|
+
"backend": "tree_text",
|
|
903
|
+
"config": {
|
|
904
|
+
"extractor_llm": {"backend": "openai", "config": openai_config},
|
|
905
|
+
"dispatcher_llm": {"backend": "openai", "config": openai_config},
|
|
906
|
+
"graph_db": {
|
|
907
|
+
"backend": graph_db_backend,
|
|
908
|
+
"config": graph_db_backend_map[graph_db_backend],
|
|
909
|
+
},
|
|
910
|
+
"embedder": APIConfig.get_embedder_config(),
|
|
911
|
+
"internet_retriever": internet_config,
|
|
912
|
+
"reranker": APIConfig.get_reranker_config(),
|
|
913
|
+
"reorganize": os.getenv("MOS_ENABLE_REORGANIZE", "false").lower()
|
|
914
|
+
== "true",
|
|
915
|
+
"memory_size": {
|
|
916
|
+
"WorkingMemory": int(os.getenv("NEBULAR_WORKING_MEMORY", 20)),
|
|
917
|
+
"LongTermMemory": int(os.getenv("NEBULAR_LONGTERM_MEMORY", 1e6)),
|
|
918
|
+
"UserMemory": int(os.getenv("NEBULAR_USER_MEMORY", 1e6)),
|
|
919
|
+
},
|
|
920
|
+
"search_strategy": {
|
|
921
|
+
"fast_graph": bool(os.getenv("FAST_GRAPH", "false") == "true"),
|
|
922
|
+
"bm25": bool(os.getenv("BM25_CALL", "false") == "true"),
|
|
923
|
+
"cot": bool(os.getenv("VEC_COT_CALL", "false") == "true"),
|
|
924
|
+
},
|
|
925
|
+
"include_embedding": bool(
|
|
926
|
+
os.getenv("INCLUDE_EMBEDDING", "false") == "true"
|
|
927
|
+
),
|
|
928
|
+
},
|
|
929
|
+
},
|
|
930
|
+
"act_mem": {}
|
|
931
|
+
if os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower() == "false"
|
|
932
|
+
else APIConfig.get_activation_vllm_config(),
|
|
933
|
+
"para_mem": {},
|
|
934
|
+
"pref_mem": {}
|
|
935
|
+
if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "false"
|
|
936
|
+
else APIConfig.get_preference_memory_config(),
|
|
937
|
+
}
|
|
938
|
+
)
|
|
939
|
+
else:
|
|
940
|
+
raise ValueError(f"Invalid Neo4j backend: {graph_db_backend}")
|
|
941
|
+
default_mem_cube = GeneralMemCube(default_cube_config)
|
|
942
|
+
return default_config, default_mem_cube
|
|
943
|
+
|
|
944
|
+
@staticmethod
|
|
945
|
+
def get_default_cube_config() -> "GeneralMemCubeConfig | None":
|
|
946
|
+
"""Get default cube configuration for product initialization.
|
|
947
|
+
|
|
948
|
+
Returns:
|
|
949
|
+
GeneralMemCubeConfig | None: Default cube configuration if enabled, None otherwise.
|
|
950
|
+
"""
|
|
951
|
+
from memos.configs.mem_cube import GeneralMemCubeConfig
|
|
952
|
+
|
|
953
|
+
if not APIConfig.is_default_cube_config_enabled():
|
|
954
|
+
return None
|
|
955
|
+
|
|
956
|
+
openai_config = APIConfig.get_openai_config()
|
|
957
|
+
neo4j_community_config = APIConfig.get_neo4j_community_config(user_id="default")
|
|
958
|
+
neo4j_config = APIConfig.get_neo4j_config(user_id="default")
|
|
959
|
+
nebular_config = APIConfig.get_nebular_config(user_id="default")
|
|
960
|
+
polardb_config = APIConfig.get_polardb_config(user_id="default")
|
|
961
|
+
graph_db_backend_map = {
|
|
962
|
+
"neo4j-community": neo4j_community_config,
|
|
963
|
+
"neo4j": neo4j_config,
|
|
964
|
+
"nebular": nebular_config,
|
|
965
|
+
"polardb": polardb_config,
|
|
966
|
+
}
|
|
967
|
+
internet_config = (
|
|
968
|
+
APIConfig.get_internet_config()
|
|
969
|
+
if os.getenv("ENABLE_INTERNET", "false").lower() == "true"
|
|
970
|
+
else None
|
|
971
|
+
)
|
|
972
|
+
graph_db_backend = os.getenv("NEO4J_BACKEND", "neo4j-community").lower()
|
|
973
|
+
if graph_db_backend in graph_db_backend_map:
|
|
974
|
+
return GeneralMemCubeConfig.model_validate(
|
|
975
|
+
{
|
|
976
|
+
"user_id": "default",
|
|
977
|
+
"cube_id": "default_cube",
|
|
978
|
+
"text_mem": {
|
|
979
|
+
"backend": "tree_text",
|
|
980
|
+
"config": {
|
|
981
|
+
"extractor_llm": {"backend": "openai", "config": openai_config},
|
|
982
|
+
"dispatcher_llm": {"backend": "openai", "config": openai_config},
|
|
983
|
+
"graph_db": {
|
|
984
|
+
"backend": graph_db_backend,
|
|
985
|
+
"config": graph_db_backend_map[graph_db_backend],
|
|
986
|
+
},
|
|
987
|
+
"embedder": APIConfig.get_embedder_config(),
|
|
988
|
+
"reranker": APIConfig.get_reranker_config(),
|
|
989
|
+
"reorganize": os.getenv("MOS_ENABLE_REORGANIZE", "false").lower()
|
|
990
|
+
== "true",
|
|
991
|
+
"internet_retriever": internet_config,
|
|
992
|
+
"memory_size": {
|
|
993
|
+
"WorkingMemory": int(os.getenv("NEBULAR_WORKING_MEMORY", 20)),
|
|
994
|
+
"LongTermMemory": int(os.getenv("NEBULAR_LONGTERM_MEMORY", 1e6)),
|
|
995
|
+
"UserMemory": int(os.getenv("NEBULAR_USER_MEMORY", 1e6)),
|
|
996
|
+
},
|
|
997
|
+
"search_strategy": {
|
|
998
|
+
"fast_graph": bool(os.getenv("FAST_GRAPH", "false") == "true"),
|
|
999
|
+
"bm25": bool(os.getenv("BM25_CALL", "false") == "true"),
|
|
1000
|
+
"cot": bool(os.getenv("VEC_COT_CALL", "false") == "true"),
|
|
1001
|
+
},
|
|
1002
|
+
"mode": os.getenv("ASYNC_MODE", "sync"),
|
|
1003
|
+
"include_embedding": bool(
|
|
1004
|
+
os.getenv("INCLUDE_EMBEDDING", "false") == "true"
|
|
1005
|
+
),
|
|
1006
|
+
},
|
|
1007
|
+
},
|
|
1008
|
+
"act_mem": {}
|
|
1009
|
+
if os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower() == "false"
|
|
1010
|
+
else APIConfig.get_activation_vllm_config(),
|
|
1011
|
+
"para_mem": {},
|
|
1012
|
+
"pref_mem": {}
|
|
1013
|
+
if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "false"
|
|
1014
|
+
else APIConfig.get_preference_memory_config(),
|
|
1015
|
+
}
|
|
1016
|
+
)
|
|
1017
|
+
else:
|
|
1018
|
+
raise ValueError(f"Invalid Neo4j backend: {graph_db_backend}")
|