新增中翻英功能(记忆时间线)(用户摘要)(兴趣分布接口)(查询核心档案)(记忆洞察)-接口添加翻译字段
This commit is contained in:
@@ -32,7 +32,7 @@ async def add_chunk_statement_edges(chunks: List[Chunk], connector: Neo4jConnect
|
||||
"id": stable_edge_id,
|
||||
"source": chunk.id,
|
||||
"target": stmt.id,
|
||||
"group_id": getattr(stmt, 'group_id', None),
|
||||
"end_user_id": getattr(stmt, 'end_user_id', None),
|
||||
"user_id":getattr(stmt, 'user_id', None),
|
||||
"apply_id": getattr(stmt, 'apply_id', None),
|
||||
"run_id": getattr(stmt, 'run_id', None) or getattr(chunk, 'run_id', None),
|
||||
@@ -83,7 +83,7 @@ async def add_memory_summary_statement_edges(summaries: List[MemorySummaryNode],
|
||||
edges.append({
|
||||
"summary_id": s.id,
|
||||
"chunk_id": chunk_id,
|
||||
"group_id": s.group_id,
|
||||
"end_user_id": s.end_user_id,
|
||||
"run_id": s.run_id,
|
||||
"created_at": s.created_at.isoformat() if s.created_at else None,
|
||||
"expired_at": s.expired_at.isoformat() if s.expired_at else None,
|
||||
|
||||
@@ -6,10 +6,10 @@ from app.core.memory.models.graph_models import DialogueNode, StatementNode, Chu
|
||||
from app.repositories.neo4j.neo4j_connector import Neo4jConnector
|
||||
|
||||
|
||||
async def delete_all_nodes(group_id: str, connector: Neo4jConnector):
|
||||
async def delete_all_nodes(end_user_id: str, connector: Neo4jConnector):
|
||||
"""Delete all nodes in the database."""
|
||||
result = await connector.execute_query(f"MATCH (n {{group_id: '{group_id}'}}) DETACH DELETE n")
|
||||
print(f"All group_id: {group_id} node and edge deleted successfully")
|
||||
result = await connector.execute_query(f"MATCH (n {{end_user_id: '{end_user_id}'}}) DETACH DELETE n")
|
||||
print(f"All end_user_id: {end_user_id} node and edge deleted successfully")
|
||||
return result
|
||||
|
||||
async def add_dialogue_nodes(dialogues: List[DialogueNode], connector: Neo4jConnector) -> Optional[List[str]]:
|
||||
@@ -32,9 +32,7 @@ async def add_dialogue_nodes(dialogues: List[DialogueNode], connector: Neo4jConn
|
||||
for dialogue in dialogues:
|
||||
flattened_dialogues.append({
|
||||
"id": dialogue.id,
|
||||
"group_id": dialogue.group_id,
|
||||
"user_id": dialogue.user_id,
|
||||
"apply_id": dialogue.apply_id,
|
||||
"end_user_id": dialogue.end_user_id,
|
||||
"run_id": dialogue.run_id,
|
||||
"ref_id": dialogue.ref_id,
|
||||
"name": dialogue.name,
|
||||
@@ -79,9 +77,7 @@ async def add_statement_nodes(statements: List[StatementNode], connector: Neo4jC
|
||||
flattened_statement = {
|
||||
"id": statement.id,
|
||||
"name": statement.name,
|
||||
"group_id": statement.group_id,
|
||||
"user_id": statement.user_id,
|
||||
"apply_id": statement.apply_id,
|
||||
"end_user_id": statement.end_user_id,
|
||||
"run_id": statement.run_id,
|
||||
"chunk_id": statement.chunk_id,
|
||||
# "created_at": statement.created_at.isoformat(),
|
||||
@@ -154,9 +150,7 @@ async def add_chunk_nodes(chunks: List[ChunkNode], connector: Neo4jConnector) ->
|
||||
flattened_chunk = {
|
||||
"id": chunk.id,
|
||||
"name": chunk.name,
|
||||
"group_id": chunk.group_id,
|
||||
"user_id": chunk.user_id,
|
||||
"apply_id": chunk.apply_id,
|
||||
"end_user_id": chunk.end_user_id,
|
||||
"run_id": chunk.run_id,
|
||||
"created_at": chunk.created_at.isoformat() if chunk.created_at else None,
|
||||
"expired_at": chunk.expired_at.isoformat() if chunk.expired_at else None,
|
||||
@@ -206,9 +200,7 @@ async def add_memory_summary_nodes(summaries: List[MemorySummaryNode], connector
|
||||
flattened.append({
|
||||
"id": s.id,
|
||||
"name": s.name,
|
||||
"group_id": s.group_id,
|
||||
"user_id": s.user_id,
|
||||
"apply_id": s.apply_id,
|
||||
"end_user_id": s.end_user_id,
|
||||
"run_id": s.run_id,
|
||||
"created_at": s.created_at.isoformat() if s.created_at else None,
|
||||
"expired_at": s.expired_at.isoformat() if s.expired_at else None,
|
||||
|
||||
@@ -152,7 +152,7 @@ class BaseNeo4jRepository(BaseRepository[T]):
|
||||
|
||||
Example:
|
||||
>>> results = await repository.find(
|
||||
... {"group_id": "group_123", "user_id": "user_456"},
|
||||
... {"end_user_id": "group_123", "user_id": "user_456"},
|
||||
... limit=50
|
||||
... )
|
||||
"""
|
||||
|
||||
@@ -3,9 +3,7 @@ DIALOGUE_NODE_SAVE = """
|
||||
UNWIND $dialogues AS dialogue
|
||||
MERGE (n:Dialogue {id: dialogue.id})
|
||||
SET n.uuid = coalesce(n.uuid, dialogue.id),
|
||||
n.group_id = dialogue.group_id,
|
||||
n.user_id = dialogue.user_id,
|
||||
n.apply_id = dialogue.apply_id,
|
||||
n.end_user_id = dialogue.end_user_id,
|
||||
n.run_id = dialogue.run_id,
|
||||
n.ref_id = dialogue.ref_id,
|
||||
n.created_at = dialogue.created_at,
|
||||
@@ -22,9 +20,7 @@ SET s += {
|
||||
id: statement.id,
|
||||
run_id: statement.run_id,
|
||||
chunk_id: statement.chunk_id,
|
||||
group_id: statement.group_id,
|
||||
user_id: statement.user_id,
|
||||
apply_id: statement.apply_id,
|
||||
end_user_id: statement.end_user_id,
|
||||
stmt_type: statement.stmt_type,
|
||||
statement: statement.statement,
|
||||
emotion_intensity: statement.emotion_intensity,
|
||||
@@ -54,9 +50,7 @@ MERGE (c:Chunk {id: chunk.id})
|
||||
SET c += {
|
||||
id: chunk.id,
|
||||
name: chunk.name,
|
||||
group_id: chunk.group_id,
|
||||
user_id: chunk.user_id,
|
||||
apply_id: chunk.apply_id,
|
||||
end_user_id: chunk.end_user_id,
|
||||
run_id: chunk.run_id,
|
||||
created_at: chunk.created_at,
|
||||
expired_at: chunk.expired_at,
|
||||
@@ -76,9 +70,7 @@ EXTRACTED_ENTITY_NODE_SAVE = """
|
||||
UNWIND $entities AS entity
|
||||
MERGE (e:ExtractedEntity {id: entity.id})
|
||||
SET e.name = CASE WHEN entity.name IS NOT NULL AND entity.name <> '' THEN entity.name ELSE e.name END,
|
||||
e.group_id = CASE WHEN entity.group_id IS NOT NULL AND entity.group_id <> '' THEN entity.group_id ELSE e.group_id END,
|
||||
e.user_id = CASE WHEN entity.user_id IS NOT NULL AND entity.user_id <> '' THEN entity.user_id ELSE e.user_id END,
|
||||
e.apply_id = CASE WHEN entity.apply_id IS NOT NULL AND entity.apply_id <> '' THEN entity.apply_id ELSE e.apply_id END,
|
||||
e.end_user_id = CASE WHEN entity.end_user_id IS NOT NULL AND entity.end_user_id <> '' THEN entity.end_user_id ELSE e.end_user_id END,
|
||||
e.run_id = CASE WHEN entity.run_id IS NOT NULL AND entity.run_id <> '' THEN entity.run_id ELSE e.run_id END,
|
||||
e.created_at = CASE
|
||||
WHEN entity.created_at IS NOT NULL AND (e.created_at IS NULL OR entity.created_at < e.created_at)
|
||||
@@ -134,9 +126,9 @@ RETURN e.id AS uuid
|
||||
# Add back ENTITY_RELATIONSHIP_SAVE to be used by graph_saver.save_entities_and_relationships
|
||||
ENTITY_RELATIONSHIP_SAVE = """
|
||||
UNWIND $relationships AS rel
|
||||
// Match entities by stable id within group, do not constrain by run_id
|
||||
MATCH (subject:ExtractedEntity {id: rel.source_id, group_id: rel.group_id})
|
||||
MATCH (object:ExtractedEntity {id: rel.target_id, group_id: rel.group_id})
|
||||
// Match entities by stable id within end_user_id, do not constrain by run_id
|
||||
MATCH (subject:ExtractedEntity {id: rel.source_id, end_user_id: rel.end_user_id})
|
||||
MATCH (object:ExtractedEntity {id: rel.target_id, end_user_id: rel.end_user_id})
|
||||
// Avoid duplicate edges across runs for the same endpoints
|
||||
MERGE (subject)-[r:EXTRACTED_RELATIONSHIP]->(object)
|
||||
SET r.predicate = rel.predicate,
|
||||
@@ -148,7 +140,7 @@ SET r.predicate = rel.predicate,
|
||||
r.created_at = rel.created_at,
|
||||
r.expired_at = rel.expired_at,
|
||||
r.run_id = rel.run_id,
|
||||
r.group_id = rel.group_id
|
||||
r.end_user_id = rel.end_user_id
|
||||
RETURN elementId(r) AS uuid
|
||||
"""
|
||||
|
||||
@@ -160,7 +152,7 @@ UNWIND $weak_entities AS entity
|
||||
MERGE (e:ExtractedEntity {id: entity.id, run_id: entity.run_id})
|
||||
SET e += {
|
||||
name: entity.name,
|
||||
group_id: entity.group_id,
|
||||
end_user_id: entity.end_user_id,
|
||||
run_id: entity.run_id,
|
||||
description: entity.description,
|
||||
chunk_id: entity.chunk_id,
|
||||
@@ -175,11 +167,11 @@ RETURN e.id AS id
|
||||
SAVE_STRONG_TRIPLE_ENTITIES = """
|
||||
UNWIND $items AS item
|
||||
MERGE (s:ExtractedEntity {id: item.source_id, run_id: item.run_id})
|
||||
SET s += {name: item.subject, group_id: item.group_id, run_id: item.run_id}
|
||||
SET s += {name: item.subject, end_user_id: item.end_user_id, run_id: item.run_id}
|
||||
// Independent strong flag
|
||||
SET s.is_strong = true
|
||||
MERGE (o:ExtractedEntity {id: item.target_id, run_id: item.run_id})
|
||||
SET o += {name: item.object, group_id: item.group_id, run_id: item.run_id}
|
||||
SET o += {name: item.object, end_user_id: item.end_user_id, run_id: item.run_id}
|
||||
// Independent strong flag
|
||||
SET o.is_strong = true
|
||||
"""
|
||||
@@ -194,7 +186,7 @@ DIALOGUE_STATEMENT_EDGE_SAVE = """
|
||||
// 仅按端点去重,关系属性可更新
|
||||
MERGE (dialogue)-[e:MENTIONS]->(statement)
|
||||
SET e.uuid = edge.id,
|
||||
e.group_id = edge.group_id,
|
||||
e.end_user_id = edge.end_user_id,
|
||||
e.created_at = edge.created_at,
|
||||
e.expired_at = edge.expired_at
|
||||
RETURN e.uuid AS uuid
|
||||
@@ -208,7 +200,7 @@ CHUNK_STATEMENT_EDGE_SAVE = """
|
||||
MATCH (statement:Statement {id: edge.source, run_id: edge.run_id})
|
||||
MATCH (chunk:Chunk {id: edge.target, run_id: edge.run_id})
|
||||
MERGE (chunk)-[e:CONTAINS {id: edge.id}]->(statement)
|
||||
SET e.group_id = edge.group_id,
|
||||
SET e.end_user_id = edge.end_user_id,
|
||||
e.run_id = edge.run_id,
|
||||
e.created_at = edge.created_at,
|
||||
e.expired_at = edge.expired_at
|
||||
@@ -218,13 +210,12 @@ CHUNK_STATEMENT_EDGE_SAVE = """
|
||||
STATEMENT_ENTITY_EDGE_SAVE = """
|
||||
UNWIND $relationships AS rel
|
||||
// Statement nodes are per-run; keep run_id constraint on statements
|
||||
// Statement nodes are per-run; keep run_id constraint on statements
|
||||
MATCH (statement:Statement {id: rel.source, run_id: rel.run_id})
|
||||
// Entities are shared across runs within a group; do not constrain by run_id
|
||||
MATCH (entity:ExtractedEntity {id: rel.target, group_id: rel.group_id})
|
||||
// Entities are shared across runs within end_user_id; do not constrain by run_id
|
||||
MATCH (entity:ExtractedEntity {id: rel.target, end_user_id: rel.end_user_id})
|
||||
// Avoid duplicate edges across runs for same endpoints
|
||||
MERGE (statement)-[r:REFERENCES_ENTITY]->(entity)
|
||||
SET r.group_id = rel.group_id,
|
||||
SET r.end_user_id = rel.end_user_id,
|
||||
r.run_id = rel.run_id,
|
||||
r.created_at = rel.created_at,
|
||||
r.expired_at = rel.expired_at,
|
||||
@@ -236,10 +227,10 @@ ENTITY_EMBEDDING_SEARCH = """
|
||||
CALL db.index.vector.queryNodes('entity_embedding_index', $limit * 100, $embedding)
|
||||
YIELD node AS e, score
|
||||
WHERE e.name_embedding IS NOT NULL
|
||||
AND ($group_id IS NULL OR e.group_id = $group_id)
|
||||
AND ($end_user_id IS NULL OR e.end_user_id = $end_user_id)
|
||||
RETURN e.id AS id,
|
||||
e.name AS name,
|
||||
e.group_id AS group_id,
|
||||
e.end_user_id AS end_user_id,
|
||||
e.entity_type AS entity_type,
|
||||
COALESCE(e.activation_value, e.importance_score, 0.5) AS activation_value,
|
||||
COALESCE(e.importance_score, 0.5) AS importance_score,
|
||||
@@ -254,10 +245,10 @@ STATEMENT_EMBEDDING_SEARCH = """
|
||||
CALL db.index.vector.queryNodes('statement_embedding_index', $limit * 100, $embedding)
|
||||
YIELD node AS s, score
|
||||
WHERE s.statement_embedding IS NOT NULL
|
||||
AND ($group_id IS NULL OR s.group_id = $group_id)
|
||||
AND ($end_user_id IS NULL OR s.end_user_id = $end_user_id)
|
||||
RETURN s.id AS id,
|
||||
s.statement AS statement,
|
||||
s.group_id AS group_id,
|
||||
s.end_user_id AS end_user_id,
|
||||
s.chunk_id AS chunk_id,
|
||||
s.created_at AS created_at,
|
||||
s.expired_at AS expired_at,
|
||||
@@ -277,9 +268,9 @@ CHUNK_EMBEDDING_SEARCH = """
|
||||
CALL db.index.vector.queryNodes('chunk_embedding_index', $limit * 100, $embedding)
|
||||
YIELD node AS c, score
|
||||
WHERE c.chunk_embedding IS NOT NULL
|
||||
AND ($group_id IS NULL OR c.group_id = $group_id)
|
||||
AND ($end_user_id IS NULL OR c.end_user_id = $end_user_id)
|
||||
RETURN c.id AS chunk_id,
|
||||
c.group_id AS group_id,
|
||||
c.end_user_id AS end_user_id,
|
||||
c.content AS content,
|
||||
c.dialog_id AS dialog_id,
|
||||
COALESCE(c.activation_value, 0.5) AS activation_value,
|
||||
@@ -292,12 +283,12 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_BY_KEYWORD = """
|
||||
CALL db.index.fulltext.queryNodes("statementsFulltext", $q) YIELD node AS s, score
|
||||
WHERE ($group_id IS NULL OR s.group_id = $group_id)
|
||||
WHERE ($end_user_id IS NULL OR s.end_user_id = $end_user_id)
|
||||
OPTIONAL MATCH (c:Chunk)-[:CONTAINS]->(s)
|
||||
OPTIONAL MATCH (s)-[:REFERENCES_ENTITY]->(e:ExtractedEntity)
|
||||
RETURN s.id AS id,
|
||||
s.statement AS statement,
|
||||
s.group_id AS group_id,
|
||||
s.end_user_id AS end_user_id,
|
||||
s.chunk_id AS chunk_id,
|
||||
s.created_at AS created_at,
|
||||
s.expired_at AS expired_at,
|
||||
@@ -316,15 +307,13 @@ LIMIT $limit
|
||||
# 查询实体名称包含指定字符串的实体
|
||||
SEARCH_ENTITIES_BY_NAME = """
|
||||
CALL db.index.fulltext.queryNodes("entitiesFulltext", $q) YIELD node AS e, score
|
||||
WHERE ($group_id IS NULL OR e.group_id = $group_id)
|
||||
WHERE ($end_user_id IS NULL OR e.end_user_id = $end_user_id)
|
||||
OPTIONAL MATCH (s:Statement)-[:REFERENCES_ENTITY]->(e)
|
||||
OPTIONAL MATCH (c:Chunk)-[:CONTAINS]->(s)
|
||||
RETURN e.id AS id,
|
||||
e.name AS name,
|
||||
e.group_id AS group_id,
|
||||
e.end_user_id AS end_user_id,
|
||||
e.entity_type AS entity_type,
|
||||
e.apply_id AS apply_id,
|
||||
e.user_id AS user_id,
|
||||
e.created_at AS created_at,
|
||||
e.expired_at AS expired_at,
|
||||
e.entity_idx AS entity_idx,
|
||||
@@ -347,11 +336,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_CHUNKS_BY_CONTENT = """
|
||||
CALL db.index.fulltext.queryNodes("chunksFulltext", $q) YIELD node AS c, score
|
||||
WHERE ($group_id IS NULL OR c.group_id = $group_id)
|
||||
WHERE ($end_user_id IS NULL OR c.end_user_id = $end_user_id)
|
||||
OPTIONAL MATCH (c)-[:CONTAINS]->(s:Statement)
|
||||
OPTIONAL MATCH (s)-[:REFERENCES_ENTITY]->(e:ExtractedEntity)
|
||||
RETURN c.id AS chunk_id,
|
||||
c.group_id AS group_id,
|
||||
c.end_user_id AS end_user_id,
|
||||
c.content AS content,
|
||||
c.dialog_id AS dialog_id,
|
||||
c.sequence_number AS sequence_number,
|
||||
@@ -413,10 +402,10 @@ LIMIT $limit
|
||||
|
||||
SEARCH_DIALOGUE_BY_DIALOG_ID = """
|
||||
MATCH (d:Dialogue)
|
||||
WHERE ($group_id IS NULL OR d.group_id = $group_id)
|
||||
WHERE ($end_user_id IS NULL OR d.end_user_id = $end_user_id)
|
||||
AND d.id = $dialog_id
|
||||
RETURN d.id AS dialog_id,
|
||||
d.group_id AS group_id,
|
||||
d.end_user_id AS end_user_id,
|
||||
d.content AS content,
|
||||
d.created_at AS created_at,
|
||||
d.expired_at AS expired_at
|
||||
@@ -426,10 +415,10 @@ LIMIT $limit
|
||||
|
||||
SEARCH_CHUNK_BY_CHUNK_ID = """
|
||||
MATCH (c:Chunk)
|
||||
WHERE ($group_id IS NULL OR c.group_id = $group_id)
|
||||
WHERE ($end_user_id IS NULL OR c.end_user_id = $end_user_id)
|
||||
AND c.id = $chunk_id
|
||||
RETURN c.id AS chunk_id,
|
||||
c.group_id AS group_id,
|
||||
c.end_user_id AS end_user_id,
|
||||
c.content AS content,
|
||||
c.dialog_id AS dialog_id,
|
||||
c.created_at AS created_at,
|
||||
@@ -441,18 +430,14 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_BY_TEMPORAL = """
|
||||
MATCH (s:Statement)
|
||||
WHERE ($group_id IS NULL OR s.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR s.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR s.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR s.end_user_id = $end_user_id)
|
||||
AND ((($start_date IS NULL OR datetime(s.created_at) >= datetime($start_date))
|
||||
AND ($end_date IS NULL OR datetime(s.created_at) <= datetime($end_date)))
|
||||
OR (($valid_date IS NULL OR (s.valid_at IS NOT NULL AND datetime(s.valid_at) >= datetime($valid_date)))
|
||||
AND ($invalid_date IS NULL OR (s.invalid_at IS NOT NULL AND datetime(s.invalid_at) <= datetime($invalid_date)))))
|
||||
RETURN s.id AS id,
|
||||
s.statement AS statement,
|
||||
s.group_id AS group_id,
|
||||
s.apply_id AS apply_id,
|
||||
s.user_id AS user_id,
|
||||
s.end_user_id AS end_user_id,
|
||||
s.chunk_id AS chunk_id,
|
||||
s.created_at AS created_at,
|
||||
s.valid_at AS valid_at,
|
||||
@@ -468,9 +453,7 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_BY_KEYWORD_TEMPORAL = """
|
||||
CALL db.index.fulltext.queryNodes("statementsFulltext", $q) YIELD node AS s, score
|
||||
WHERE ($group_id IS NULL OR s.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR s.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR s.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR s.end_user_id = $end_user_id)
|
||||
AND ((($start_date IS NULL OR (s.created_at IS NOT NULL AND datetime(s.created_at) >= datetime($start_date)))
|
||||
AND ($end_date IS NULL OR (s.created_at IS NOT NULL AND datetime(s.created_at) <= datetime($end_date))))
|
||||
OR (($valid_date IS NULL OR (s.valid_at IS NOT NULL AND datetime(s.valid_at) >= datetime($valid_date)))
|
||||
@@ -479,9 +462,7 @@ OPTIONAL MATCH (c:Chunk)-[:CONTAINS]->(s)
|
||||
OPTIONAL MATCH (s)-[:REFERENCES_ENTITY]->(e:ExtractedEntity)
|
||||
RETURN s.id AS id,
|
||||
s.statement AS statement,
|
||||
s.group_id AS group_id,
|
||||
s.apply_id AS apply_id,
|
||||
s.user_id AS user_id,
|
||||
s.end_user_id AS end_user_id,
|
||||
s.chunk_id AS chunk_id,
|
||||
s.created_at AS created_at,
|
||||
s.valid_at AS valid_at,
|
||||
@@ -499,15 +480,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_BY_CREATED_AT = """
|
||||
MATCH (n:Statement)
|
||||
WHERE ($group_id IS NULL OR n.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR n.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR n.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR n.end_user_id = $end_user_id)
|
||||
AND ($created_at IS NOT NULL AND date(substring(n.created_at, 0, 10)) = date($created_at))
|
||||
RETURN n.id AS id,
|
||||
n.statement AS statement,
|
||||
n.group_id AS group_id,
|
||||
n.apply_id AS apply_id,
|
||||
n.user_id AS user_id,
|
||||
n.end_user_id AS end_user_id,
|
||||
n.chunk_id AS chunk_id,
|
||||
n.created_at AS created_at,
|
||||
n.valid_at AS valid_at,
|
||||
@@ -519,15 +496,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_BY_VALID_AT = """
|
||||
MATCH (n:Statement)
|
||||
WHERE ($group_id IS NULL OR n.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR n.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR n.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR n.end_user_id = $end_user_id)
|
||||
AND ($valid_at IS NOT NULL AND date(substring(n.valid_at, 0, 10)) = date($valid_at))
|
||||
RETURN n.id AS id,
|
||||
n.statement AS statement,
|
||||
n.group_id AS group_id,
|
||||
n.apply_id AS apply_id,
|
||||
n.user_id AS user_id,
|
||||
n.end_user_id AS end_user_id,
|
||||
n.chunk_id AS chunk_id,
|
||||
n.created_at AS created_at,
|
||||
n.valid_at AS valid_at,
|
||||
@@ -539,15 +512,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_G_CREATED_AT = """
|
||||
MATCH (n:Statement)
|
||||
WHERE ($group_id IS NULL OR n.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR n.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR n.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR n.end_user_id = $end_user_id)
|
||||
AND ($created_at IS NOT NULL AND date(substring(n.created_at, 0, 19)) = date($created_at))
|
||||
RETURN n.id AS id,
|
||||
n.statement AS statement,
|
||||
n.group_id AS group_id,
|
||||
n.apply_id AS apply_id,
|
||||
n.user_id AS user_id,
|
||||
n.end_user_id AS end_user_id,
|
||||
n.chunk_id AS chunk_id,
|
||||
n.created_at AS created_at,
|
||||
n.valid_at AS valid_at,
|
||||
@@ -559,15 +528,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_L_CREATED_AT = """
|
||||
MATCH (n:Statement)
|
||||
WHERE ($group_id IS NULL OR n.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR n.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR n.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR n.end_user_id = $end_user_id)
|
||||
AND ($created_at IS NOT NULL AND date(substring(n.created_at, 0, 19)) < date($created_at))
|
||||
RETURN n.id AS id,
|
||||
n.statement AS statement,
|
||||
n.group_id AS group_id,
|
||||
n.apply_id AS apply_id,
|
||||
n.user_id AS user_id,
|
||||
n.end_user_id AS end_user_id,
|
||||
n.chunk_id AS chunk_id,
|
||||
n.created_at AS created_at,
|
||||
n.valid_at AS valid_at,
|
||||
@@ -579,15 +544,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_G_VALID_AT = """
|
||||
MATCH (n:Statement)
|
||||
WHERE ($group_id IS NULL OR n.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR n.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR n.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR n.end_user_id = $end_user_id)
|
||||
AND ($valid_at IS NOT NULL AND date(substring(n.valid_at, 0, 10)) > date($valid_at))
|
||||
RETURN n.id AS id,
|
||||
n.statement AS statement,
|
||||
n.group_id AS group_id,
|
||||
n.apply_id AS apply_id,
|
||||
n.user_id AS user_id,
|
||||
n.end_user_id AS end_user_id,
|
||||
n.chunk_id AS chunk_id,
|
||||
n.created_at AS created_at,
|
||||
n.valid_at AS valid_at,
|
||||
@@ -599,15 +560,11 @@ LIMIT $limit
|
||||
|
||||
SEARCH_STATEMENTS_L_VALID_AT = """
|
||||
MATCH (n:Statement)
|
||||
WHERE ($group_id IS NULL OR n.group_id = $group_id)
|
||||
AND ($apply_id IS NULL OR n.apply_id = $apply_id)
|
||||
AND ($user_id IS NULL OR n.user_id = $user_id)
|
||||
WHERE ($end_user_id IS NULL OR n.end_user_id = $end_user_id)
|
||||
AND ($valid_at IS NOT NULL AND date(substring(n.valid_at, 0, 10)) < date($valid_at))
|
||||
RETURN n.id AS id,
|
||||
n.statement AS statement,
|
||||
n.group_id AS group_id,
|
||||
n.apply_id AS apply_id,
|
||||
n.user_id AS user_id,
|
||||
n.end_user_id AS end_user_id,
|
||||
n.chunk_id AS chunk_id,
|
||||
n.created_at AS created_at,
|
||||
n.valid_at AS valid_at,
|
||||
@@ -665,18 +622,18 @@ LIMIT $limit
|
||||
|
||||
# 根据id修改句子的invalid_at的值
|
||||
UPDATE_STATEMENT_INVALID_AT = """
|
||||
MATCH (n:Statement {group_id: $group_id, id: $id})
|
||||
MATCH (n:Statement {end_user_id: $end_user_id, id: $id})
|
||||
SET n.invalid_at = $new_invalid_at
|
||||
"""
|
||||
|
||||
# MemorySummary keyword search using fulltext index
|
||||
SEARCH_MEMORY_SUMMARIES_BY_KEYWORD = """
|
||||
CALL db.index.fulltext.queryNodes("summariesFulltext", $q) YIELD node AS m, score
|
||||
WHERE ($group_id IS NULL OR m.group_id = $group_id)
|
||||
WHERE ($end_user_id IS NULL OR m.end_user_id = $end_user_id)
|
||||
OPTIONAL MATCH (m)-[:DERIVED_FROM_STATEMENT]->(s:Statement)
|
||||
RETURN m.id AS id,
|
||||
m.name AS name,
|
||||
m.group_id AS group_id,
|
||||
m.end_user_id AS end_user_id,
|
||||
m.dialog_id AS dialog_id,
|
||||
m.chunk_ids AS chunk_ids,
|
||||
m.content AS content,
|
||||
@@ -695,10 +652,10 @@ MEMORY_SUMMARY_EMBEDDING_SEARCH = """
|
||||
CALL db.index.vector.queryNodes('summary_embedding_index', $limit * 100, $embedding)
|
||||
YIELD node AS m, score
|
||||
WHERE m.summary_embedding IS NOT NULL
|
||||
AND ($group_id IS NULL OR m.group_id = $group_id)
|
||||
AND ($end_user_id IS NULL OR m.end_user_id = $end_user_id)
|
||||
RETURN m.id AS id,
|
||||
m.name AS name,
|
||||
m.group_id AS group_id,
|
||||
m.end_user_id AS end_user_id,
|
||||
m.dialog_id AS dialog_id,
|
||||
m.chunk_ids AS chunk_ids,
|
||||
m.content AS content,
|
||||
@@ -718,9 +675,7 @@ MERGE (m:MemorySummary {id: summary.id})
|
||||
SET m += {
|
||||
id: summary.id,
|
||||
name: summary.name,
|
||||
group_id: summary.group_id,
|
||||
user_id: summary.user_id,
|
||||
apply_id: summary.apply_id,
|
||||
end_user_id: summary.end_user_id,
|
||||
run_id: summary.run_id,
|
||||
created_at: summary.created_at,
|
||||
expired_at: summary.expired_at,
|
||||
@@ -814,7 +769,7 @@ RETURN count(losing) as deleted
|
||||
|
||||
neo4j_statement_part = '''
|
||||
MATCH (n:Statement)
|
||||
WHERE n.group_id = "{}"
|
||||
WHERE n.end_user_id = "{}"
|
||||
AND datetime(n.created_at) >= datetime() - duration('P3D')
|
||||
RETURN
|
||||
n.statement as statement_name,
|
||||
@@ -824,7 +779,7 @@ RETURN
|
||||
'''
|
||||
neo4j_statement_all = '''
|
||||
MATCH (n:Statement)
|
||||
WHERE n.group_id = "{}"
|
||||
WHERE n.end_user_id = "{}"
|
||||
RETURN
|
||||
n.statement as statement_name,
|
||||
n.id as statement_id
|
||||
@@ -832,7 +787,7 @@ RETURN
|
||||
'''
|
||||
neo4j_query_part = """
|
||||
MATCH (n)-[r]-(m:ExtractedEntity)
|
||||
WHERE n.group_id = "{}"
|
||||
WHERE n.end_user_id = "{}"
|
||||
AND datetime(n.created_at) >= datetime() - duration('P3D')
|
||||
WITH DISTINCT m
|
||||
OPTIONAL MATCH (m)-[rel]-(other:ExtractedEntity)
|
||||
@@ -853,7 +808,7 @@ neo4j_query_part = """
|
||||
"""
|
||||
neo4j_query_all = """
|
||||
MATCH (n)-[r]-(m:ExtractedEntity)
|
||||
WHERE n.group_id = "{}"
|
||||
WHERE n.end_user_id = "{}"
|
||||
WITH DISTINCT m
|
||||
OPTIONAL MATCH (m)-[rel]-(other:ExtractedEntity)
|
||||
RETURN
|
||||
@@ -1027,14 +982,14 @@ RETURN DISTINCT
|
||||
|
||||
Memory_Space_User="""
|
||||
MATCH (n)-[r]->(m)
|
||||
WHERE n.group_id = $group_id AND m.name="用户"
|
||||
WHERE n.end_user_id = $end_user_id AND m.name="用户"
|
||||
return DISTINCT elementId(m) as id
|
||||
"""
|
||||
Memory_Space_Entity="""
|
||||
MATCH (n)-[]-(m)
|
||||
WHERE elementId(m) = $id AND m.entity_type = "Person"
|
||||
RETURN
|
||||
DISTINCT m.name as name,m.group_id as group_id
|
||||
DISTINCT m.name as name,m.end_user_id as end_user_id
|
||||
"""
|
||||
Memory_Space_Associative="""
|
||||
MATCH (u)-[]-(x)-[]-(h)
|
||||
|
||||
@@ -19,7 +19,7 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
"""对话仓储
|
||||
|
||||
管理对话节点的创建、查询、更新和删除操作。
|
||||
提供按group_id、user_id、ref_id等条件查询对话的方法。
|
||||
提供按end_user_id、user_id、ref_id等条件查询对话的方法。
|
||||
|
||||
Attributes:
|
||||
connector: Neo4j连接器实例
|
||||
@@ -54,17 +54,17 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
|
||||
return DialogueNode(**n)
|
||||
|
||||
async def find_by_group_id(self, group_id: str, limit: int = 100) -> List[DialogueNode]:
|
||||
"""根据group_id查询对话
|
||||
async def find_by_end_user_id(self, end_user_id: str, limit: int = 100) -> List[DialogueNode]:
|
||||
"""根据end_user_id查询对话
|
||||
|
||||
Args:
|
||||
group_id: 组ID
|
||||
end_user_id: 组ID
|
||||
limit: 返回结果的最大数量
|
||||
|
||||
Returns:
|
||||
List[DialogueNode]: 对话列表
|
||||
"""
|
||||
return await self.find({"group_id": group_id}, limit=limit)
|
||||
return await self.find({"end_user_id": end_user_id}, limit=limit)
|
||||
|
||||
async def find_by_user_id(self, user_id: str, limit: int = 100) -> List[DialogueNode]:
|
||||
"""根据user_id查询对话
|
||||
@@ -94,14 +94,14 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
|
||||
async def find_by_group_and_user(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
user_id: str,
|
||||
limit: int = 100
|
||||
) -> List[DialogueNode]:
|
||||
"""根据group_id和user_id查询对话
|
||||
"""根据end_user_id和user_id查询对话
|
||||
|
||||
Args:
|
||||
group_id: 组ID
|
||||
end_user_id: 组ID
|
||||
user_id: 用户ID
|
||||
limit: 返回结果的最大数量
|
||||
|
||||
@@ -109,20 +109,20 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
List[DialogueNode]: 对话列表
|
||||
"""
|
||||
return await self.find(
|
||||
{"group_id": group_id, "user_id": user_id},
|
||||
{"end_user_id": end_user_id, "user_id": user_id},
|
||||
limit=limit
|
||||
)
|
||||
|
||||
async def find_recent_dialogs(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
days: int = 7,
|
||||
limit: int = 100
|
||||
) -> List[DialogueNode]:
|
||||
"""查询最近的对话
|
||||
|
||||
Args:
|
||||
group_id: 组ID
|
||||
end_user_id: 组ID
|
||||
days: 查询最近多少天的对话
|
||||
limit: 返回结果的最大数量
|
||||
|
||||
@@ -131,7 +131,7 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
"""
|
||||
query = f"""
|
||||
MATCH (n:{self.node_label})
|
||||
WHERE n.group_id = $group_id
|
||||
WHERE n.end_user_id = $end_user_id
|
||||
AND n.created_at >= datetime() - duration({{days: $days}})
|
||||
RETURN n
|
||||
ORDER BY n.created_at DESC
|
||||
@@ -139,7 +139,7 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
"""
|
||||
results = await self.connector.execute_query(
|
||||
query,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
days=days,
|
||||
limit=limit
|
||||
)
|
||||
@@ -164,16 +164,16 @@ class DialogRepository(BaseNeo4jRepository[DialogueNode]):
|
||||
async def find_by_config_and_group(
|
||||
self,
|
||||
config_id: str,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
limit: int = 100
|
||||
) -> List[DialogueNode]:
|
||||
"""根据config_id和group_id查询对话
|
||||
"""根据config_id和end_user_id查询对话
|
||||
|
||||
支持按配置ID和组ID同时过滤,确保只返回使用特定配置处理的对话。
|
||||
|
||||
Args:
|
||||
config_id: 配置ID
|
||||
group_id: 组ID
|
||||
end_user_id: 组ID
|
||||
limit: 返回结果的最大数量
|
||||
|
||||
Returns:
|
||||
|
||||
@@ -40,7 +40,7 @@ class EmotionRepository:
|
||||
|
||||
async def get_emotion_tags(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
emotion_type: Optional[str] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
@@ -51,7 +51,7 @@ class EmotionRepository:
|
||||
查询指定用户的情绪类型分布,包括计数、百分比和平均强度。
|
||||
|
||||
Args:
|
||||
group_id: 用户组ID(宿主ID)
|
||||
end_user_id: 用户组ID(宿主ID)
|
||||
emotion_type: 可选的情绪类型过滤(joy/sadness/anger/fear/surprise/neutral)
|
||||
start_date: 可选的开始日期(ISO格式字符串)
|
||||
end_date: 可选的结束日期(ISO格式字符串)
|
||||
@@ -65,8 +65,8 @@ class EmotionRepository:
|
||||
- avg_intensity: 平均强度
|
||||
"""
|
||||
# 构建查询条件
|
||||
where_clauses = ["s.group_id = $group_id", "s.emotion_type IS NOT NULL"]
|
||||
params = {"group_id": group_id, "limit": limit}
|
||||
where_clauses = ["s.end_user_id = $end_user_id", "s.emotion_type IS NOT NULL"]
|
||||
params = {"end_user_id": end_user_id, "limit": limit}
|
||||
|
||||
if emotion_type:
|
||||
where_clauses.append("s.emotion_type = $emotion_type")
|
||||
@@ -119,7 +119,7 @@ class EmotionRepository:
|
||||
|
||||
async def get_emotion_wordcloud(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
emotion_type: Optional[str] = None,
|
||||
limit: int = 50
|
||||
) -> List[Dict[str, Any]]:
|
||||
@@ -128,7 +128,7 @@ class EmotionRepository:
|
||||
查询情绪关键词及其频率,用于生成词云可视化。
|
||||
|
||||
Args:
|
||||
group_id: 用户组ID(宿主ID)
|
||||
end_user_id: 用户组ID(宿主ID)
|
||||
emotion_type: 可选的情绪类型过滤
|
||||
limit: 返回关键词的最大数量
|
||||
|
||||
@@ -140,8 +140,8 @@ class EmotionRepository:
|
||||
- avg_intensity: 平均强度
|
||||
"""
|
||||
# 构建查询条件
|
||||
where_clauses = ["s.group_id = $group_id", "s.emotion_keywords IS NOT NULL"]
|
||||
params = {"group_id": group_id, "limit": limit}
|
||||
where_clauses = ["s.end_user_id = $end_user_id", "s.emotion_keywords IS NOT NULL"]
|
||||
params = {"end_user_id": end_user_id, "limit": limit}
|
||||
|
||||
if emotion_type:
|
||||
where_clauses.append("s.emotion_type = $emotion_type")
|
||||
@@ -186,7 +186,7 @@ class EmotionRepository:
|
||||
|
||||
async def get_emotions_in_range(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
time_range: str = "30d"
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""获取时间范围内的情绪数据
|
||||
@@ -194,7 +194,7 @@ class EmotionRepository:
|
||||
查询指定时间范围内的所有情绪数据,用于健康指数计算。
|
||||
|
||||
Args:
|
||||
group_id: 用户组ID(宿主ID)
|
||||
end_user_id: 用户组ID(宿主ID)
|
||||
time_range: 时间范围(7d/30d/90d)
|
||||
|
||||
Returns:
|
||||
@@ -214,7 +214,7 @@ class EmotionRepository:
|
||||
# 优化的 Cypher 查询:使用字符串比较避免时区问题
|
||||
query = """
|
||||
MATCH (s:Statement)
|
||||
WHERE s.group_id = $group_id
|
||||
WHERE s.end_user_id = $end_user_id
|
||||
AND s.emotion_type IS NOT NULL
|
||||
AND s.created_at >= $start_date
|
||||
RETURN s.id as statement_id,
|
||||
|
||||
@@ -44,9 +44,7 @@ async def save_entities_and_relationships(
|
||||
'created_at': edge.created_at.isoformat(),
|
||||
'expired_at': edge.expired_at.isoformat(),
|
||||
'run_id': edge.run_id,
|
||||
'group_id': edge.group_id,
|
||||
'user_id': edge.user_id,
|
||||
'apply_id': edge.apply_id,
|
||||
'end_user_id': edge.end_user_id,
|
||||
}
|
||||
all_relationships.append(relationship)
|
||||
|
||||
@@ -101,9 +99,7 @@ async def save_statement_chunk_edges(
|
||||
"id": edge.id,
|
||||
"source": edge.source,
|
||||
"target": edge.target,
|
||||
"group_id": edge.group_id,
|
||||
"user_id": edge.user_id,
|
||||
"apply_id": edge.apply_id,
|
||||
"end_user_id": edge.end_user_id,
|
||||
"run_id": edge.run_id,
|
||||
"created_at": edge.created_at.isoformat() if edge.created_at else None,
|
||||
"expired_at": edge.expired_at.isoformat() if edge.expired_at else None,
|
||||
@@ -132,9 +128,7 @@ async def save_statement_entity_edges(
|
||||
edge_data = {
|
||||
"source": edge.source,
|
||||
"target": edge.target,
|
||||
"group_id": edge.group_id,
|
||||
"user_id": edge.user_id,
|
||||
"apply_id": edge.apply_id,
|
||||
"end_user_id": edge.end_user_id,
|
||||
"run_id": edge.run_id,
|
||||
"connect_strength": edge.connect_strength,
|
||||
"created_at": edge.created_at.isoformat() if edge.created_at else None,
|
||||
|
||||
@@ -33,7 +33,7 @@ async def _update_activation_values_batch(
|
||||
connector: Neo4jConnector,
|
||||
nodes: List[Dict[str, Any]],
|
||||
node_label: str,
|
||||
group_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
max_retries: int = 3
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
@@ -46,7 +46,7 @@ async def _update_activation_values_batch(
|
||||
connector: Neo4j连接器
|
||||
nodes: 节点列表,每个节点必须包含 'id' 字段
|
||||
node_label: 节点标签(Statement, ExtractedEntity, MemorySummary)
|
||||
group_id: 组ID(可选)
|
||||
end_user_id: 组ID(可选)
|
||||
max_retries: 最大重试次数
|
||||
|
||||
Returns:
|
||||
@@ -97,7 +97,7 @@ async def _update_activation_values_batch(
|
||||
updated_nodes = await access_manager.record_batch_access(
|
||||
node_ids=unique_node_ids,
|
||||
node_label=node_label,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
logger.info(
|
||||
@@ -118,7 +118,7 @@ async def _update_activation_values_batch(
|
||||
async def _update_search_results_activation(
|
||||
connector: Neo4jConnector,
|
||||
results: Dict[str, List[Dict[str, Any]]],
|
||||
group_id: Optional[str] = None
|
||||
end_user_id: Optional[str] = None
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
"""
|
||||
更新搜索结果中所有知识节点的激活值
|
||||
@@ -129,7 +129,7 @@ async def _update_search_results_activation(
|
||||
Args:
|
||||
connector: Neo4j连接器
|
||||
results: 搜索结果字典,包含不同类型节点的列表
|
||||
group_id: 组ID(可选)
|
||||
end_user_id: 组ID(可选)
|
||||
|
||||
Returns:
|
||||
Dict[str, List[Dict[str, Any]]]: 更新后的搜索结果
|
||||
@@ -152,7 +152,7 @@ async def _update_search_results_activation(
|
||||
connector=connector,
|
||||
nodes=results[key],
|
||||
node_label=label,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
)
|
||||
update_keys.append(key)
|
||||
@@ -218,7 +218,7 @@ async def _update_search_results_activation(
|
||||
async def search_graph(
|
||||
connector: Neo4jConnector,
|
||||
q: str,
|
||||
group_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
limit: int = 50,
|
||||
include: List[str] = None,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -236,7 +236,7 @@ async def search_graph(
|
||||
Args:
|
||||
connector: Neo4j connector
|
||||
q: Query text
|
||||
group_id: Optional group filter
|
||||
end_user_id: Optional group filter
|
||||
limit: Max results per category
|
||||
include: List of categories to search (default: all)
|
||||
|
||||
@@ -254,7 +254,7 @@ async def search_graph(
|
||||
tasks.append(connector.execute_query(
|
||||
SEARCH_STATEMENTS_BY_KEYWORD,
|
||||
q=q,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("statements")
|
||||
@@ -263,7 +263,7 @@ async def search_graph(
|
||||
tasks.append(connector.execute_query(
|
||||
SEARCH_ENTITIES_BY_NAME,
|
||||
q=q,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("entities")
|
||||
@@ -272,7 +272,7 @@ async def search_graph(
|
||||
tasks.append(connector.execute_query(
|
||||
SEARCH_CHUNKS_BY_CONTENT,
|
||||
q=q,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("chunks")
|
||||
@@ -281,7 +281,7 @@ async def search_graph(
|
||||
tasks.append(connector.execute_query(
|
||||
SEARCH_MEMORY_SUMMARIES_BY_KEYWORD,
|
||||
q=q,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("summaries")
|
||||
@@ -305,19 +305,12 @@ async def search_graph(
|
||||
results[key] = _deduplicate_results(results[key])
|
||||
|
||||
# 更新知识节点的激活值(Statement, ExtractedEntity, MemorySummary)
|
||||
# Skip activation updates if only searching summaries (optimization)
|
||||
needs_activation_update = any(
|
||||
key in include and key in results and results[key]
|
||||
for key in ['statements', 'entities', 'chunks']
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
if needs_activation_update:
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
@@ -325,7 +318,7 @@ async def search_graph_by_embedding(
|
||||
connector: Neo4jConnector,
|
||||
embedder_client,
|
||||
query_text: str,
|
||||
group_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
limit: int = 50,
|
||||
include: List[str] = ["statements", "chunks", "entities","summaries"],
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -337,7 +330,7 @@ async def search_graph_by_embedding(
|
||||
|
||||
- Computes query embedding with the provided embedder_client
|
||||
- Ranks by cosine similarity in Cypher
|
||||
- Filters by group_id if provided
|
||||
- Filters by end_user_id if provided
|
||||
- Returns up to 'limit' per included type
|
||||
"""
|
||||
import time
|
||||
@@ -346,7 +339,7 @@ async def search_graph_by_embedding(
|
||||
embed_start = time.time()
|
||||
embeddings = await embedder_client.response([query_text])
|
||||
embed_time = time.time() - embed_start
|
||||
logger.info(f"[PERF] Embedding generation took: {embed_time:.4f}s")
|
||||
print(f"[PERF] Embedding generation took: {embed_time:.4f}s")
|
||||
|
||||
if not embeddings or not embeddings[0]:
|
||||
return {"statements": [], "chunks": [], "entities": [], "summaries": []}
|
||||
@@ -361,7 +354,7 @@ async def search_graph_by_embedding(
|
||||
tasks.append(connector.execute_query(
|
||||
STATEMENT_EMBEDDING_SEARCH,
|
||||
embedding=embedding,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("statements")
|
||||
@@ -371,7 +364,7 @@ async def search_graph_by_embedding(
|
||||
tasks.append(connector.execute_query(
|
||||
CHUNK_EMBEDDING_SEARCH,
|
||||
embedding=embedding,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("chunks")
|
||||
@@ -381,7 +374,7 @@ async def search_graph_by_embedding(
|
||||
tasks.append(connector.execute_query(
|
||||
ENTITY_EMBEDDING_SEARCH,
|
||||
embedding=embedding,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("entities")
|
||||
@@ -391,7 +384,7 @@ async def search_graph_by_embedding(
|
||||
tasks.append(connector.execute_query(
|
||||
MEMORY_SUMMARY_EMBEDDING_SEARCH,
|
||||
embedding=embedding,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=limit,
|
||||
))
|
||||
task_keys.append("summaries")
|
||||
@@ -400,7 +393,7 @@ async def search_graph_by_embedding(
|
||||
query_start = time.time()
|
||||
task_results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
query_time = time.time() - query_start
|
||||
logger.info(f"[PERF] Neo4j queries (parallel) took: {query_time:.4f}s")
|
||||
print(f"[PERF] Neo4j queries (parallel) took: {query_time:.4f}s")
|
||||
|
||||
# Build results dictionary
|
||||
results: Dict[str, List[Dict[str, Any]]] = {
|
||||
@@ -424,28 +417,19 @@ async def search_graph_by_embedding(
|
||||
results[key] = _deduplicate_results(results[key])
|
||||
|
||||
# 更新知识节点的激活值(Statement, ExtractedEntity, MemorySummary)
|
||||
# Skip activation updates if only searching summaries (optimization)
|
||||
needs_activation_update = any(
|
||||
key in include and key in results and results[key]
|
||||
for key in ['statements', 'entities', 'chunks']
|
||||
update_start = time.time()
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
if needs_activation_update:
|
||||
update_start = time.time()
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
)
|
||||
update_time = time.time() - update_start
|
||||
logger.info(f"[PERF] Activation value updates took: {update_time:.4f}s")
|
||||
else:
|
||||
logger.info(f"[PERF] Skipping activation updates (only summaries)")
|
||||
update_time = time.time() - update_start
|
||||
print(f"[PERF] Activation value updates took: {update_time:.4f}s")
|
||||
|
||||
return results
|
||||
async def get_dedup_candidates_for_entities( # 适配新版查询:使用全文索引按名称检索候选实体
|
||||
connector: Neo4jConnector,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
entities: List[Dict[str, Any]],
|
||||
use_contains_fallback: bool = True,
|
||||
batch_size: int = 500,
|
||||
@@ -453,7 +437,7 @@ async def get_dedup_candidates_for_entities( # 适配新版查询:使用全
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
"""
|
||||
为第二层去重消歧批量检索候选实体(适配新版 cypher_queries):
|
||||
- 使用全文索引查询 `SEARCH_ENTITIES_BY_NAME` 按 (group_id, name) 检索候选;
|
||||
- 使用全文索引查询 `SEARCH_ENTITIES_BY_NAME` 按 (end_user_id, name) 检索候选;
|
||||
- 保留并发控制与返回结构(incoming_id -> [db_entity_props...]);
|
||||
- 若提供 `entity_type`,在本地对返回结果做类型过滤;
|
||||
- `use_contains_fallback` 保留形参以兼容,必要时可扩展二次查询策略。
|
||||
@@ -477,7 +461,7 @@ async def get_dedup_candidates_for_entities( # 适配新版查询:使用全
|
||||
rows = await connector.execute_query(
|
||||
SEARCH_ENTITIES_BY_NAME,
|
||||
q=name,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=100,
|
||||
)
|
||||
except Exception:
|
||||
@@ -501,7 +485,7 @@ async def get_dedup_candidates_for_entities( # 适配新版查询:使用全
|
||||
rows = await connector.execute_query(
|
||||
SEARCH_ENTITIES_BY_NAME,
|
||||
q=name.lower(),
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
limit=100,
|
||||
)
|
||||
for r in rows:
|
||||
@@ -532,9 +516,7 @@ async def get_dedup_candidates_for_entities( # 适配新版查询:使用全
|
||||
async def search_graph_by_keyword_temporal(
|
||||
connector: Neo4jConnector,
|
||||
query_text: str,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
valid_date: Optional[str] = None,
|
||||
@@ -547,32 +529,30 @@ async def search_graph_by_keyword_temporal(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements containing query_text created between start_date and end_date
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
if not query_text:
|
||||
logger.warning(f"query_text cannot be empty")
|
||||
print(f"query_text不能为空")
|
||||
return {"statements": []}
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_BY_KEYWORD_TEMPORAL,
|
||||
q=query_text,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
valid_date=valid_date,
|
||||
invalid_date=invalid_date,
|
||||
limit=limit,
|
||||
)
|
||||
logger.debug(f"Temporal keyword search results: {len(statements)} statements found")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
@@ -580,9 +560,7 @@ async def search_graph_by_keyword_temporal(
|
||||
|
||||
async def search_graph_by_temporal(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
start_date: Optional[str] = None,
|
||||
end_date: Optional[str] = None,
|
||||
valid_date: Optional[str] = None,
|
||||
@@ -595,14 +573,12 @@ async def search_graph_by_temporal(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements created between start_date and end_date
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_BY_TEMPORAL,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
valid_date=valid_date,
|
||||
@@ -610,16 +586,16 @@ async def search_graph_by_temporal(
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Temporal search query: {SEARCH_STATEMENTS_BY_TEMPORAL}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, start_date={start_date}, end_date={end_date}, valid_date={valid_date}, invalid_date={invalid_date}, limit={limit}")
|
||||
logger.debug(f"Temporal search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_BY_TEMPORAL}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id}, start_date: {start_date}, end_date: {end_date}, valid_date: {valid_date}, invalid_date: {invalid_date}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
@@ -628,23 +604,23 @@ async def search_graph_by_temporal(
|
||||
async def search_graph_by_dialog_id(
|
||||
connector: Neo4jConnector,
|
||||
dialog_id: str,
|
||||
group_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
"""
|
||||
Temporal search across Dialogues.
|
||||
|
||||
- Matches dialogues with dialog_id
|
||||
- Optionally filters by group_id
|
||||
- Optionally filters by end_user_id
|
||||
- Returns up to 'limit' dialogues
|
||||
"""
|
||||
if not dialog_id:
|
||||
logger.warning(f"dialog_id cannot be empty")
|
||||
print(f"dialog_id不能为空")
|
||||
return {"dialogues": []}
|
||||
|
||||
dialogues = await connector.execute_query(
|
||||
SEARCH_DIALOGUE_BY_DIALOG_ID,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
dialog_id=dialog_id,
|
||||
limit=limit,
|
||||
)
|
||||
@@ -654,15 +630,15 @@ async def search_graph_by_dialog_id(
|
||||
async def search_graph_by_chunk_id(
|
||||
connector: Neo4jConnector,
|
||||
chunk_id : str,
|
||||
group_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
if not chunk_id:
|
||||
logger.warning(f"chunk_id cannot be empty")
|
||||
print(f"chunk_id不能为空")
|
||||
return {"chunks": []}
|
||||
chunks = await connector.execute_query(
|
||||
SEARCH_CHUNK_BY_CHUNK_ID,
|
||||
group_id=group_id,
|
||||
end_user_id=end_user_id,
|
||||
chunk_id=chunk_id,
|
||||
limit=limit,
|
||||
)
|
||||
@@ -671,9 +647,9 @@ async def search_graph_by_chunk_id(
|
||||
|
||||
async def search_graph_by_created_at(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
|
||||
|
||||
created_at: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -683,37 +659,37 @@ async def search_graph_by_created_at(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements created at created_at
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_BY_CREATED_AT,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
|
||||
|
||||
created_at=created_at,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Search by created_at query: {SEARCH_STATEMENTS_BY_CREATED_AT}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, created_at={created_at}, limit={limit}")
|
||||
logger.debug(f"Search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_BY_CREATED_AT}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id} created_at: {created_at}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
async def search_graph_by_valid_at(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
|
||||
|
||||
valid_at: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -723,37 +699,37 @@ async def search_graph_by_valid_at(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements valid at valid_at
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_BY_VALID_AT,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
|
||||
|
||||
valid_at=valid_at,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Search by valid_at query: {SEARCH_STATEMENTS_BY_VALID_AT}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, valid_at={valid_at}, limit={limit}")
|
||||
logger.debug(f"Search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_BY_VALID_AT}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id}, valid_at: {valid_at}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
async def search_graph_g_created_at(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
|
||||
|
||||
created_at: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -763,37 +739,37 @@ async def search_graph_g_created_at(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements created at created_at
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_G_CREATED_AT,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
|
||||
|
||||
created_at=created_at,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Search greater than created_at query: {SEARCH_STATEMENTS_G_CREATED_AT}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, created_at={created_at}, limit={limit}")
|
||||
logger.debug(f"Search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_G_CREATED_AT}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id}, created_at: {created_at}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
async def search_graph_g_valid_at(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
|
||||
|
||||
valid_at: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -803,37 +779,37 @@ async def search_graph_g_valid_at(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements valid at valid_at
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_G_VALID_AT,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
|
||||
|
||||
valid_at=valid_at,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Search greater than valid_at query: {SEARCH_STATEMENTS_G_VALID_AT}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, valid_at={valid_at}, limit={limit}")
|
||||
logger.debug(f"Search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_G_VALID_AT}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id}, valid_at: {valid_at}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
async def search_graph_l_created_at(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
|
||||
|
||||
created_at: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -843,37 +819,37 @@ async def search_graph_l_created_at(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements created at created_at
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_L_CREATED_AT,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
|
||||
|
||||
created_at=created_at,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Search less than created_at query: {SEARCH_STATEMENTS_L_CREATED_AT}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, created_at={created_at}, limit={limit}")
|
||||
logger.debug(f"Search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_L_CREATED_AT}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id}, created_at: {created_at}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
async def search_graph_l_valid_at(
|
||||
connector: Neo4jConnector,
|
||||
group_id: Optional[str] = None,
|
||||
apply_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
end_user_id: Optional[str] = None,
|
||||
|
||||
|
||||
valid_at: Optional[str] = None,
|
||||
limit: int = 1,
|
||||
) -> Dict[str, List[Dict[str, Any]]]:
|
||||
@@ -883,28 +859,28 @@ async def search_graph_l_valid_at(
|
||||
INTEGRATED: Updates activation values for Statement nodes before returning results
|
||||
|
||||
- Matches statements valid at valid_at
|
||||
- Optionally filters by group_id, apply_id, user_id
|
||||
- Optionally filters by end_user_id, apply_id, user_id
|
||||
- Returns up to 'limit' statements
|
||||
"""
|
||||
statements = await connector.execute_query(
|
||||
SEARCH_STATEMENTS_L_VALID_AT,
|
||||
group_id=group_id,
|
||||
apply_id=apply_id,
|
||||
user_id=user_id,
|
||||
end_user_id=end_user_id,
|
||||
|
||||
|
||||
valid_at=valid_at,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
logger.debug(f"Search less than valid_at query: {SEARCH_STATEMENTS_L_VALID_AT}")
|
||||
logger.debug(f"Query params: group_id={group_id}, apply_id={apply_id}, user_id={user_id}, valid_at={valid_at}, limit={limit}")
|
||||
logger.debug(f"Search results: {len(statements)} statements found")
|
||||
print(f"查询语句为:\n{SEARCH_STATEMENTS_L_VALID_AT}")
|
||||
print(f"查询参数为:\n{{end_user_id: {end_user_id}, valid_at: {valid_at}, limit: {limit}}}")
|
||||
print(f"查询结果为:\n{statements}")
|
||||
|
||||
# 更新 Statement 节点的激活值
|
||||
results = {"statements": statements}
|
||||
results = await _update_search_results_activation(
|
||||
connector=connector,
|
||||
results=results,
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
@@ -18,7 +18,7 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
"""Memory Summary Repository
|
||||
|
||||
Manages CRUD operations for MemorySummary nodes.
|
||||
Provides methods to query summaries by group_id, user_id, and time ranges.
|
||||
Provides methods to query summaries by end_user_id, user_id, and time ranges.
|
||||
|
||||
Attributes:
|
||||
connector: Neo4j connector instance
|
||||
@@ -51,17 +51,17 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
|
||||
return dict(n)
|
||||
|
||||
async def find_by_group_id(
|
||||
async def find_by_end_user_id(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
limit: int = 1000,
|
||||
start_date: Optional[datetime] = None,
|
||||
end_date: Optional[datetime] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Query memory summaries by group_id
|
||||
"""Query memory summaries by end_user_id
|
||||
|
||||
Args:
|
||||
group_id: Group ID to filter by
|
||||
end_user_id: Group ID to filter by
|
||||
limit: Maximum number of results to return
|
||||
start_date: Optional start date filter
|
||||
end_date: Optional end date filter
|
||||
@@ -71,10 +71,10 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
"""
|
||||
query = f"""
|
||||
MATCH (n:{self.node_label})
|
||||
WHERE n.group_id = $group_id
|
||||
WHERE n.end_user_id = $end_user_id
|
||||
"""
|
||||
|
||||
params = {"group_id": group_id, "limit": limit}
|
||||
params = {"end_user_id": end_user_id, "limit": limit}
|
||||
|
||||
# Add date range filters if provided
|
||||
if start_date:
|
||||
@@ -139,16 +139,16 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
|
||||
async def find_by_group_and_user(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
user_id: str,
|
||||
limit: int = 1000,
|
||||
start_date: Optional[datetime] = None,
|
||||
end_date: Optional[datetime] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Query memory summaries by both group_id and user_id
|
||||
"""Query memory summaries by both end_user_id and user_id
|
||||
|
||||
Args:
|
||||
group_id: Group ID to filter by
|
||||
end_user_id: Group ID to filter by
|
||||
user_id: User ID to filter by
|
||||
limit: Maximum number of results to return
|
||||
start_date: Optional start date filter
|
||||
@@ -159,10 +159,10 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
"""
|
||||
query = f"""
|
||||
MATCH (n:{self.node_label})
|
||||
WHERE n.group_id = $group_id AND n.user_id = $user_id
|
||||
WHERE n.end_user_id = $end_user_id AND n.user_id = $user_id
|
||||
"""
|
||||
|
||||
params = {"group_id": group_id, "user_id": user_id, "limit": limit}
|
||||
params = {"end_user_id": end_user_id, "user_id": user_id, "limit": limit}
|
||||
|
||||
# Add date range filters if provided
|
||||
if start_date:
|
||||
@@ -184,14 +184,14 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
|
||||
async def find_recent_summaries(
|
||||
self,
|
||||
group_id: str,
|
||||
end_user_id: str,
|
||||
days: int = 7,
|
||||
limit: int = 1000
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Query recent memory summaries
|
||||
|
||||
Args:
|
||||
group_id: Group ID to filter by
|
||||
end_user_id: Group ID to filter by
|
||||
days: Number of recent days to query
|
||||
limit: Maximum number of results to return
|
||||
|
||||
@@ -200,7 +200,7 @@ class MemorySummaryRepository(BaseNeo4jRepository):
|
||||
"""
|
||||
query = f"""
|
||||
MATCH (n:{self.node_label})
|
||||
WHERE n.group_id = $group_id
|
||||
WHERE n.end_user_id = $end_user_id
|
||||
AND n.created_at >= datetime() - duration({{days: $days}})
|
||||
RETURN n
|
||||
ORDER BY n.created_at DESC
|
||||
|
||||
@@ -141,14 +141,14 @@ class Neo4jConnector:
|
||||
async with self.driver.session(database="neo4j") as session:
|
||||
return await session.execute_read(transaction_func, **kwargs)
|
||||
|
||||
async def delete_group(self, group_id: str):
|
||||
async def delete_group(self, end_user_id: str):
|
||||
"""删除指定组的所有数据
|
||||
|
||||
删除所有属于指定group_id的节点和边。
|
||||
删除所有属于指定end_user_id的节点和边。
|
||||
这是一个危险操作,会永久删除数据。
|
||||
|
||||
Args:
|
||||
group_id: 要删除的组ID
|
||||
end_user_id: 要删除的组ID
|
||||
|
||||
Example:
|
||||
>>> connector = Neo4jConnector()
|
||||
@@ -157,14 +157,14 @@ class Neo4jConnector:
|
||||
"""
|
||||
# 删除节点(DETACH DELETE会同时删除相关的边)
|
||||
await self.driver.execute_query(
|
||||
"MATCH (n) WHERE n.group_id = $group_id DETACH DELETE n",
|
||||
"MATCH (n) WHERE n.end_user_id = $end_user_id DETACH DELETE n",
|
||||
database="neo4j",
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
# 删除独立的边(如果有的话)
|
||||
await self.driver.execute_query(
|
||||
"MATCH ()-[r]->() WHERE r.group_id = $group_id DELETE r",
|
||||
"MATCH ()-[r]->() WHERE r.end_user_id = $end_user_id DELETE r",
|
||||
database="neo4j",
|
||||
group_id=group_id
|
||||
end_user_id=end_user_id
|
||||
)
|
||||
print(f"Group {group_id} deleted.")
|
||||
print(f"Group {end_user_id} deleted.")
|
||||
|
||||
@@ -20,7 +20,7 @@ class StatementRepository(BaseNeo4jRepository[StatementNode]):
|
||||
"""陈述句仓储
|
||||
|
||||
管理陈述句节点的创建、查询、更新和删除操作。
|
||||
提供按chunk_id、group_id、向量相似度等条件查询陈述句的方法。
|
||||
提供按chunk_id、end_user_id、向量相似度等条件查询陈述句的方法。
|
||||
|
||||
Attributes:
|
||||
connector: Neo4j连接器实例
|
||||
|
||||
Reference in New Issue
Block a user