"""客户长期记忆的 Neo4j 关系镜像。""" from __future__ import annotations from config.database.neo4j import client as configured_client class Neo4jMemoryStore: """保存客户节点、记忆节点及其 HAS_MEMORY 关系。""" def __init__(self, driver=None): self.driver = driver or configured_client() async def upsert(self, memory) -> str: """写入客户和记忆节点,返回图谱记忆节点 ID。""" memory_id = str(memory.id) query = """ MERGE (c:Customer {customer_id: $customer_id}) MERGE (m:CustomerMemory {memory_id: $memory_id}) SET m.memory_type = $memory_type, m.tag = $tag, m.content = $content, m.status = $status MERGE (c)-[:HAS_MEMORY]->(m) RETURN m.memory_id AS memory_id """ async with self.driver.session() as session: record = await session.run( query, customer_id=int(memory.customer_id), memory_id=memory_id, memory_type=memory.memory_type, tag=memory.tag, content=memory.content, status=memory.status, ) row = await record.single() return row["memory_id"] if row else memory_id async def list_by_customer(self, customer_id: int, *, limit: int = 100) -> list[dict]: """按客户查询图谱记忆关系。""" query = """ MATCH (c:Customer {customer_id: $customer_id})-[:HAS_MEMORY]->(m:CustomerMemory) RETURN m.memory_id AS memory_id, m.memory_type AS memory_type, m.tag AS tag, m.content AS content, m.status AS status LIMIT $limit """ async with self.driver.session() as session: result = await session.run(query, customer_id=int(customer_id), limit=limit) return [dict(record) async for record in result] async def delete(self, memory_id: int | str) -> None: """删除记忆节点及其关系。""" query = "MATCH (m:CustomerMemory {memory_id: $memory_id}) DETACH DELETE m" async with self.driver.session() as session: await session.run(query, memory_id=str(memory_id)) __all__ = ["Neo4jMemoryStore"]