Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
8ffdf4e
feat: delete custom_logger_handler (#289)
CarltonXiang Sep 10, 2025
541191f
fix: change env model name (#292)
fridayL Sep 10, 2025
99d8e19
fix:#286:https://github.com/MemTensor/MemOS/issues/286 (#293)
kakack Sep 11, 2025
6b8cf85
Feat:add self defined memcube id for reg user (#295)
fridayL Sep 11, 2025
709f87c
update: test branch ci
fridayL Sep 15, 2025
5285829
Feat/add opentelmetry (#298)
CarltonXiang Sep 15, 2025
0b0cad8
feat: add orginal context for reranking (#284)
fridayL Sep 15, 2025
7b245b9
revert: nebular require_python (#300)
CarltonXiang Sep 15, 2025
8f87b33
feat: chat bot api (#294)
CaralHsi Sep 15, 2025
c688ead
feat: chat bot api (#302)
CaralHsi Sep 16, 2025
778c3b4
feat: chat bot api, add reranker filter; fix pydantic bug (#303)
CaralHsi Sep 16, 2025
30cfdbf
fix: bug in internet pydantic error (#304)
CaralHsi Sep 16, 2025
065a378
Feat/add opentelmetry (#307)
CarltonXiang Sep 16, 2025
02b0983
feat: update nebula to nebula 5.1.1 (#311)
CaralHsi Sep 17, 2025
9be4cb5
fix: nebula multi db bug (#313)
CaralHsi Sep 17, 2025
05dac26
Feat/memos client (#312)
CarltonXiang Sep 18, 2025
663c157
Feat: add time log for threaddict and change openai packacge singleto…
fridayL Sep 18, 2025
6304368
rebase to address conflicts
tangg555 Jul 25, 2025
6f8963a
fix bugs: fix a bug in retriever, and add new auth info for neo4j db
tangg555 Jul 29, 2025
d62ff33
fix bugs & new feat: fix bugs in mem_scheduler examples, and remove i…
tangg555 Jul 31, 2025
945c44b
fix bugs: modify configs, examples, schedule handlers of mem_schedule…
tangg555 Aug 6, 2025
f930506
new feat: allow load auth config from env
tangg555 Aug 7, 2025
9deb368
finish the first verion code of orm, but it still has some problems w…
tangg555 Aug 28, 2025
e4fa4f2
new version of scheduler: 1. orm support for monitors 2. refined sear…
tangg555 Sep 10, 2025
44f0138
refactor: refactor the eval function of the scheduler
tangg555 Sep 11, 2025
cb9519d
fix bugs caused by auth config in tests
tangg555 Sep 11, 2025
e024fea
modify scheduler evaluation codes
tangg555 Sep 16, 2025
020e6c6
add the first version of scheduler test by creating temporal locomo b…
tangg555 Sep 16, 2025
391b422
fix bugs in temporal locomo codes in evaluation
tangg555 Sep 18, 2025
fcdb21c
fix bugs in text mem with neo4j backend, and set huggingface backend …
tangg555 Sep 19, 2025
c407987
Feat/add timerlog (#317)
fridayL Sep 19, 2025
f8e972d
Feat/add opentelmetry (#315)
CarltonXiang Sep 19, 2025
1dc230a
feat: add api client (#316)
CarltonXiang Sep 19, 2025
267a0c1
Feat: add segment lock dict (#319)
fridayL Sep 20, 2025
1dc3b2e
fix:fix dump parallel for dumps cubes (#320)
fridayL Sep 21, 2025
beb0e07
feat: add sinlgleton (#321)
fridayL Sep 22, 2025
301178d
feat: nebula&reorganize update (#322)
CaralHsi Sep 22, 2025
5639a91
fix: nebula reset bug (#323)
CaralHsi Sep 22, 2025
5b27384
feat: add default processing in mem-reader (#325)
CaralHsi Sep 22, 2025
ee89e68
feat:add time step (#326)
fridayL Sep 23, 2025
bb63d7a
Feat:add time step (#327)
fridayL Sep 23, 2025
a4de6bd
docker start (#324)
pursues Sep 23, 2025
46406ea
Feat: remove json (#328)
fridayL Sep 23, 2025
b25f68b
feat: remove (#329)
fridayL Sep 23, 2025
312223c
fix: not include embedding (#330)
CaralHsi Sep 23, 2025
3646712
Feat/add time step (#331)
fridayL Sep 23, 2025
8c1e4ee
Feat/add time step (#332)
fridayL Sep 23, 2025
94ec427
new feat: add a rule-based baseline which uses historical evidences t…
tangg555 Sep 22, 2025
4fa115b
new feat: add eval and metric codes into the pipeline, and fix the bu…
tangg555 Sep 23, 2025
7119091
Fix/default add (#333)
CaralHsi Sep 23, 2025
4a4abca
fix the bugs in rule-based baselines, and change the temporal data so…
tangg555 Sep 23, 2025
73c9fa1
feat: recall and searcher use parallel (#337)
lijicode Sep 24, 2025
1f57a62
feat: api client (#334)
CarltonXiang Sep 24, 2025
a75af07
Merge branch 'dev' into test
CaralHsi Sep 24, 2025
f8d8c60
feat: API 1.0 (#339)
CaralHsi Sep 24, 2025
62cce47
fix: format (#341)
CaralHsi Sep 24, 2025
6f1159f
Merge branch 'main' into dev
CaralHsi Sep 24, 2025
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
Prev Previous commit
Next Next commit
feat: add sinlgleton (#321)
* feat: add  logs for cube

* feat: add loggers for mem

* add dict timer log

* fix: change ci code

* update size

* fix ci

* feat: add update threading dict

* fix:ci code

* fix:fix mem dumps for cube

* feat: add

---------

Co-authored-by: CaralHsi <[email protected]>
  • Loading branch information
fridayL and CaralHsi authored Sep 22, 2025
commit beb0e077fb2d5554d07b3218ce7615456924b459
2 changes: 2 additions & 0 deletions src/memos/embedders/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from memos.embedders.ollama import OllamaEmbedder
from memos.embedders.sentence_transformer import SenTranEmbedder
from memos.embedders.universal_api import UniversalAPIEmbedder
from memos.memos_tools.singleton import singleton_factory


class EmbedderFactory(BaseEmbedder):
Expand All @@ -19,6 +20,7 @@ class EmbedderFactory(BaseEmbedder):
}

@classmethod
@singleton_factory()
def from_config(cls, config_factory: EmbedderConfigFactory) -> BaseEmbedder:
backend = config_factory.backend
if backend not in cls.backend_to_class:
Expand Down
2 changes: 2 additions & 0 deletions src/memos/llms/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from memos.llms.openai import AzureLLM, OpenAILLM
from memos.llms.qwen import QwenLLM
from memos.llms.vllm import VLLMLLM
from memos.memos_tools.singleton import singleton_factory


class LLMFactory(BaseLLM):
Expand All @@ -26,6 +27,7 @@ class LLMFactory(BaseLLM):
}

@classmethod
@singleton_factory()
def from_config(cls, config_factory: LLMConfigFactory) -> BaseLLM:
backend = config_factory.backend
if backend not in cls.backend_to_class:
Expand Down
2 changes: 2 additions & 0 deletions src/memos/mem_reader/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from memos.configs.mem_reader import MemReaderConfigFactory
from memos.mem_reader.base import BaseMemReader
from memos.mem_reader.simple_struct import SimpleStructMemReader
from memos.memos_tools.singleton import singleton_factory


class MemReaderFactory(BaseMemReader):
Expand All @@ -13,6 +14,7 @@ class MemReaderFactory(BaseMemReader):
}

@classmethod
@singleton_factory()
def from_config(cls, config_factory: MemReaderConfigFactory) -> BaseMemReader:
backend = config_factory.backend
if backend not in cls.backend_to_class:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
InternetGoogleRetriever,
)
from memos.memories.textual.tree_text_memory.retrieve.xinyusearch import XinyuSearchRetriever
from memos.memos_tools.singleton import singleton_factory


class InternetRetrieverFactory:
Expand All @@ -23,6 +24,7 @@ class InternetRetrieverFactory:
}

@classmethod
@singleton_factory()
def from_config(
cls, config_factory: InternetRetrieverConfigFactory, embedder: BaseEmbedder
) -> InternetGoogleRetriever | None:
Expand Down
174 changes: 174 additions & 0 deletions src/memos/memos_tools/singleton.py
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: maybe resolve 'time-related' config later.

Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"""
Singleton decorator module for caching factory instances to avoid excessive memory usage
from repeated initialization.
"""

import hashlib
import json

from collections.abc import Callable
from functools import wraps
from typing import Any, TypeVar
from weakref import WeakValueDictionary


T = TypeVar("T")


class FactorySingleton:
"""Factory singleton manager that caches instances based on configuration parameters"""

def __init__(self):
# Use weak reference dictionary for automatic cleanup when instances are no longer referenced
self._instances: dict[str, WeakValueDictionary] = {}

def _generate_cache_key(self, config: Any, *args, **kwargs) -> str:
"""Generate cache key based on configuration only (ignoring other parameters)"""

# Handle configuration objects - only use the config parameter
if hasattr(config, "model_dump"): # Pydantic model
config_data = config.model_dump()
elif hasattr(config, "dict"): # Legacy Pydantic model
config_data = config.dict()
elif isinstance(config, dict):
config_data = config
else:
# For other types, try to convert to string
config_data = str(config)

# Filter out time-related fields that shouldn't affect caching
filtered_config = self._filter_temporal_fields(config_data)

# Generate hash key based only on config
try:
cache_str = json.dumps(filtered_config, sort_keys=True, ensure_ascii=False, default=str)
except (TypeError, ValueError):
# If JSON serialization fails, convert the entire config to string
cache_str = str(filtered_config)

return hashlib.md5(cache_str.encode("utf-8")).hexdigest()

def _filter_temporal_fields(self, config_data: Any) -> Any:
"""Filter out temporal fields that shouldn't affect instance caching"""
if isinstance(config_data, dict):
filtered = {}
for key, value in config_data.items():
# Skip common temporal field names
if key.lower() in {
"created_at",
"updated_at",
"timestamp",
"time",
"date",
"created_time",
"updated_time",
"last_modified",
"modified_at",
"start_time",
"end_time",
"execution_time",
"run_time",
}:
continue
# Recursively filter nested dictionaries
filtered[key] = self._filter_temporal_fields(value)
return filtered
elif isinstance(config_data, list):
# Recursively filter lists
return [self._filter_temporal_fields(item) for item in config_data]
else:
# For primitive types, return as-is
return config_data

def get_or_create(self, factory_class: type, cache_key: str, creator_func: Callable) -> Any:
"""Get or create instance"""
class_name = factory_class.__name__

if class_name not in self._instances:
self._instances[class_name] = WeakValueDictionary()

class_cache = self._instances[class_name]

if cache_key in class_cache:
return class_cache[cache_key]

# Create new instance
instance = creator_func()
class_cache[cache_key] = instance
return instance

def clear_cache(self, factory_class: type | None = None):
"""Clear cache"""
if factory_class:
class_name = factory_class.__name__
if class_name in self._instances:
self._instances[class_name].clear()
else:
for cache in self._instances.values():
cache.clear()


# Global singleton manager
_factory_singleton = FactorySingleton()


def singleton_factory(factory_class: type | str | None = None):
"""
Factory singleton decorator

Usage:
@singleton_factory()
def from_config(cls, config):
return SomeClass(config)

Or specify factory class:
@singleton_factory(EmbedderFactory)
def from_config(cls, config):
return SomeClass(config)
"""

def decorator(func: Callable[..., T]) -> Callable[..., T]:
@wraps(func)
def wrapper(*args, **kwargs) -> T:
# Determine factory class and config parameter
target_factory_class = factory_class
config = None

# Simple logic: check if first parameter is a class or config
if args:
if hasattr(args[0], "__name__") and hasattr(args[0], "__module__"):
# First parameter is a class (cls), so this is a @classmethod
if target_factory_class is None:
target_factory_class = args[0]
config = args[1] if len(args) > 1 else None
else:
# First parameter is config, so this is a @staticmethod
if target_factory_class is None:
raise ValueError(
"Factory class must be explicitly specified for static methods"
)
if isinstance(target_factory_class, str):
# Convert string to a mock class for caching purposes
class MockFactoryClass:
__name__ = target_factory_class

target_factory_class = MockFactoryClass
config = args[0]

if config is None:
# If no configuration parameter, call original function directly
return func(*args, **kwargs)

# Generate cache key based only on config
cache_key = _factory_singleton._generate_cache_key(config)

# Function to create instance
def creator():
return func(*args, **kwargs)

# Get or create instance
return _factory_singleton.get_or_create(target_factory_class, cache_key, creator)

return wrapper

return decorator
2 changes: 2 additions & 0 deletions src/memos/parsers/factory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Any, ClassVar

from memos.configs.parser import ParserConfigFactory
from memos.memos_tools.singleton import singleton_factory
from memos.parsers.base import BaseParser
from memos.parsers.markitdown import MarkItDownParser

Expand All @@ -11,6 +12,7 @@ class ParserFactory(BaseParser):
backend_to_class: ClassVar[dict[str, Any]] = {"markitdown": MarkItDownParser}

@classmethod
@singleton_factory()
def from_config(cls, config_factory: ParserConfigFactory) -> BaseParser:
backend = config_factory.backend
if backend not in cls.backend_to_class:
Expand Down
4 changes: 4 additions & 0 deletions src/memos/reranker/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

from typing import TYPE_CHECKING, Any

# Import singleton decorator
from memos.memos_tools.singleton import singleton_factory

from .cosine_local import CosineLocalReranker
from .http_bge import HTTPBGEReranker
from .noop import NoopReranker
Expand All @@ -16,6 +19,7 @@

class RerankerFactory:
@staticmethod
@singleton_factory("RerankerFactory")
def from_config(cfg: RerankerConfigFactory | None) -> BaseReranker | None:
if not cfg:
return None
Expand Down
Loading