|
| 1 | +import uuid |
| 2 | + |
| 3 | +from memos import log |
| 4 | +from memos.configs.embedder import EmbedderConfigFactory |
| 5 | +from memos.configs.graph_db import GraphDBConfigFactory |
| 6 | +from memos.configs.llm import LLMConfigFactory |
| 7 | +from memos.embedders.factory import EmbedderFactory |
| 8 | +from memos.graph_dbs.factory import GraphStoreFactory |
| 9 | +from memos.graph_dbs.item import GraphDBNode |
| 10 | +from memos.llms.factory import LLMFactory |
| 11 | +from memos.memories.textual.item import TreeNodeTextualMemoryMetadata |
| 12 | +from memos.memories.textual.tree_text_memory.organize.relation_reason_detector import ( |
| 13 | + RelationAndReasoningDetector, |
| 14 | +) |
| 15 | + |
| 16 | + |
| 17 | +logger = log.get_logger(__name__) |
| 18 | + |
| 19 | +# === Step 1: Initialize embedder === |
| 20 | +embedder_config = EmbedderConfigFactory.model_validate( |
| 21 | + { |
| 22 | + "backend": "ollama", |
| 23 | + "config": { |
| 24 | + "model_name_or_path": "nomic-embed-text:latest", |
| 25 | + }, |
| 26 | + } |
| 27 | +) |
| 28 | +embedder = EmbedderFactory.from_config(embedder_config) |
| 29 | + |
| 30 | +# === Step 2: Initialize Neo4j GraphStore === |
| 31 | +graph_config = GraphDBConfigFactory( |
| 32 | + backend="neo4j", |
| 33 | + config={ |
| 34 | + "uri": "bolt://localhost:7687", |
| 35 | + "user": "neo4j", |
| 36 | + "password": "12345678", |
| 37 | + "db_name": "lucy4", |
| 38 | + "auto_create": True, |
| 39 | + }, |
| 40 | +) |
| 41 | +graph_store = GraphStoreFactory.from_config(graph_config) |
| 42 | + |
| 43 | +# === Step 3: Initialize LLM for pairwise relation detection === |
| 44 | +# Step 1: Load LLM config and instantiate |
| 45 | +config = LLMConfigFactory.model_validate( |
| 46 | + { |
| 47 | + "backend": "ollama", |
| 48 | + "config": { |
| 49 | + "model_name_or_path": "qwen3:0.6b", |
| 50 | + "temperature": 0.7, |
| 51 | + "max_tokens": 1024, |
| 52 | + }, |
| 53 | + } |
| 54 | +) |
| 55 | +llm = LLMFactory.from_config(config) |
| 56 | + |
| 57 | +# === Step 4: Create a mock GraphDBNode to test relation detection === |
| 58 | + |
| 59 | +node_a = GraphDBNode( |
| 60 | + id=str(uuid.uuid4()), |
| 61 | + memory="Caroline faced increased workload stress during the project deadline.", |
| 62 | + metadata=TreeNodeTextualMemoryMetadata( |
| 63 | + memory_type="LongTermMemory", |
| 64 | + embedding=[0.1] * 10, |
| 65 | + key="Workload stress", |
| 66 | + tags=["stress", "workload"], |
| 67 | + type="fact", |
| 68 | + background="Project", |
| 69 | + confidence=0.95, |
| 70 | + updated_at="2024-06-28T09:00:00Z", |
| 71 | + ), |
| 72 | +) |
| 73 | + |
| 74 | +node_b = GraphDBNode( |
| 75 | + id=str(uuid.uuid4()), |
| 76 | + memory="After joining the support group, Caroline reported improved mental health.", |
| 77 | + metadata=TreeNodeTextualMemoryMetadata( |
| 78 | + memory_type="LongTermMemory", |
| 79 | + embedding=[0.1] * 10, |
| 80 | + key="Improved mental health", |
| 81 | + tags=["mental health", "support group"], |
| 82 | + type="fact", |
| 83 | + background="Personal follow-up", |
| 84 | + confidence=0.95, |
| 85 | + updated_at="2024-07-10T12:00:00Z", |
| 86 | + ), |
| 87 | +) |
| 88 | + |
| 89 | +node_c = GraphDBNode( |
| 90 | + id=str(uuid.uuid4()), |
| 91 | + memory="Peer support groups are effective in reducing stress for LGBTQ individuals.", |
| 92 | + metadata=TreeNodeTextualMemoryMetadata( |
| 93 | + memory_type="LongTermMemory", |
| 94 | + embedding=[0.1] * 10, |
| 95 | + key="Support group benefits", |
| 96 | + tags=["LGBTQ", "support group", "stress"], |
| 97 | + type="fact", |
| 98 | + background="General research", |
| 99 | + confidence=0.95, |
| 100 | + updated_at="2024-06-29T14:00:00Z", |
| 101 | + ), |
| 102 | +) |
| 103 | + |
| 104 | +# === D: Work pressure ➜ stress === |
| 105 | +node_d = GraphDBNode( |
| 106 | + id=str(uuid.uuid4()), |
| 107 | + memory="Excessive work pressure increases stress levels among employees.", |
| 108 | + metadata=TreeNodeTextualMemoryMetadata( |
| 109 | + memory_type="LongTermMemory", |
| 110 | + embedding=[0.1] * 10, |
| 111 | + key="Work pressure impact", |
| 112 | + tags=["stress", "work pressure"], |
| 113 | + type="fact", |
| 114 | + background="Workplace study", |
| 115 | + confidence=0.9, |
| 116 | + updated_at="2024-06-15T08:00:00Z", |
| 117 | + ), |
| 118 | +) |
| 119 | + |
| 120 | +# === E: Stress ➜ poor sleep === |
| 121 | +node_e = GraphDBNode( |
| 122 | + id=str(uuid.uuid4()), |
| 123 | + memory="High stress levels often result in poor sleep quality.", |
| 124 | + metadata=TreeNodeTextualMemoryMetadata( |
| 125 | + memory_type="LongTermMemory", |
| 126 | + embedding=[0.1] * 10, |
| 127 | + key="Stress and sleep", |
| 128 | + tags=["stress", "sleep"], |
| 129 | + type="fact", |
| 130 | + background="Health study", |
| 131 | + confidence=0.9, |
| 132 | + updated_at="2024-06-18T10:00:00Z", |
| 133 | + ), |
| 134 | +) |
| 135 | + |
| 136 | +# === F: Poor sleep ➜ low performance === |
| 137 | +node_f = GraphDBNode( |
| 138 | + id=str(uuid.uuid4()), |
| 139 | + memory="Employees with poor sleep show reduced work performance.", |
| 140 | + metadata=TreeNodeTextualMemoryMetadata( |
| 141 | + memory_type="LongTermMemory", |
| 142 | + embedding=[0.1] * 10, |
| 143 | + key="Sleep and performance", |
| 144 | + tags=["sleep", "performance"], |
| 145 | + type="fact", |
| 146 | + background="HR report", |
| 147 | + confidence=0.9, |
| 148 | + updated_at="2024-06-20T12:00:00Z", |
| 149 | + ), |
| 150 | +) |
| 151 | + |
| 152 | +node = GraphDBNode( |
| 153 | + id="a88db9ce-3c77-4e83-8d61-aa9ef95c957e", |
| 154 | + memory="Caroline joined an LGBTQ support group to cope with work-related stress.", |
| 155 | + metadata=TreeNodeTextualMemoryMetadata( |
| 156 | + memory_type="LongTermMemory", |
| 157 | + embedding=embedder.embed( |
| 158 | + ["Caroline joined an LGBTQ support group to cope with work-related stress."] |
| 159 | + )[0], |
| 160 | + key="Caroline LGBTQ stress", |
| 161 | + tags=["LGBTQ", "support group", "stress"], |
| 162 | + type="fact", |
| 163 | + background="Personal", |
| 164 | + confidence=0.95, |
| 165 | + updated_at="2024-07-01T10:00:00Z", |
| 166 | + ), |
| 167 | +) |
| 168 | + |
| 169 | + |
| 170 | +for n in [node, node_a, node_b, node_c, node_d, node_e, node_f]: |
| 171 | + graph_store.add_node(n.id, n.memory, n.metadata.dict()) |
| 172 | + |
| 173 | + |
| 174 | +# === Step 5: Initialize RelationDetector and run detection === |
| 175 | +relation_detector = RelationAndReasoningDetector( |
| 176 | + graph_store=graph_store, llm=llm, embedder=embedder |
| 177 | +) |
| 178 | + |
| 179 | +results = relation_detector.process_node( |
| 180 | + node=node, |
| 181 | + exclude_ids=[node.id], # Exclude self when searching for neighbors |
| 182 | + top_k=5, |
| 183 | +) |
| 184 | + |
| 185 | +# === Step 6: Print detected relations === |
| 186 | +print("\n=== Detected Global Relations ===") |
| 187 | + |
| 188 | + |
| 189 | +# === Step 6: Pretty-print detected results === |
| 190 | +print("\n=== Detected Pairwise Relations ===") |
| 191 | +for rel in results["relations"]: |
| 192 | + print(f" Source ID: {rel['source_id']}") |
| 193 | + print(f" Target ID: {rel['target_id']}") |
| 194 | + print(f" Relation Type: {rel['relation_type']}") |
| 195 | + print("------") |
| 196 | + |
| 197 | +print("\n=== Inferred Nodes ===") |
| 198 | +for node in results["inferred_nodes"]: |
| 199 | + print(f" New Fact: {node.memory}") |
| 200 | + print(f" Sources: {node.metadata.sources}") |
| 201 | + print("------") |
| 202 | + |
| 203 | +print("\n=== Sequence Links (FOLLOWS) ===") |
| 204 | +for link in results["sequence_links"]: |
| 205 | + print(f" From: {link['from_id']} -> To: {link['to_id']}") |
| 206 | + print("------") |
| 207 | + |
| 208 | +print("\n=== Aggregate Concepts ===") |
| 209 | +for agg in results["aggregate_nodes"]: |
| 210 | + print(f" Concept Key: {agg.metadata.key}") |
| 211 | + print(f" Concept Memory: {agg.memory}") |
| 212 | + print(f" Sources: {agg.metadata.sources}") |
| 213 | + print("------") |
0 commit comments