mirror of
https://github.com/getzep/graphiti.git
synced 2025-07-03 23:20:30 +00:00
129 lines
4.2 KiB
Python
129 lines
4.2 KiB
Python
![]() |
import json
|
||
|
from typing import List
|
||
|
from datetime import datetime
|
||
|
|
||
|
from core.nodes import EntityNode, EpisodicNode
|
||
|
from core.edges import EpisodicEdge, EntityEdge
|
||
|
import logging
|
||
|
|
||
|
from core.prompts import prompt_library
|
||
|
from core.llm_client import LLMClient
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
|
||
|
def build_episodic_edges(
|
||
|
semantic_nodes: List[EntityNode],
|
||
|
episode: EpisodicNode,
|
||
|
transaction_from: datetime,
|
||
|
) -> List[EpisodicEdge]:
|
||
|
edges: List[EpisodicEdge] = []
|
||
|
|
||
|
for node in semantic_nodes:
|
||
|
edge = EpisodicEdge(
|
||
|
source_node=episode, target_node=node, created_at=transaction_from
|
||
|
)
|
||
|
edges.append(edge)
|
||
|
|
||
|
return edges
|
||
|
|
||
|
|
||
|
async def extract_new_edges(
|
||
|
llm_client: LLMClient,
|
||
|
episode: EpisodicNode,
|
||
|
new_nodes: list[EntityNode],
|
||
|
relevant_schema: dict[str, any],
|
||
|
previous_episodes: list[EpisodicNode],
|
||
|
) -> list[EntityEdge]:
|
||
|
# Prepare context for LLM
|
||
|
context = {
|
||
|
"episode_content": episode.content,
|
||
|
"episode_timestamp": (
|
||
|
episode.valid_at.isoformat() if episode.valid_at else None
|
||
|
),
|
||
|
"relevant_schema": json.dumps(relevant_schema, indent=2),
|
||
|
"new_nodes": [
|
||
|
{"name": node.name, "summary": node.summary} for node in new_nodes
|
||
|
],
|
||
|
"previous_episodes": [
|
||
|
{
|
||
|
"content": ep.content,
|
||
|
"timestamp": ep.valid_at.isoformat() if ep.valid_at else None,
|
||
|
}
|
||
|
for ep in previous_episodes
|
||
|
],
|
||
|
}
|
||
|
|
||
|
llm_response = await llm_client.generate_response(
|
||
|
prompt_library.extract_edges.v1(context)
|
||
|
)
|
||
|
new_edges_data = llm_response.get("new_edges", [])
|
||
|
|
||
|
# Convert the extracted data into EntityEdge objects
|
||
|
new_edges = []
|
||
|
for edge_data in new_edges_data:
|
||
|
source_node = next(
|
||
|
(node for node in new_nodes if node.name == edge_data["source_node"]),
|
||
|
None,
|
||
|
)
|
||
|
target_node = next(
|
||
|
(node for node in new_nodes if node.name == edge_data["target_node"]),
|
||
|
None,
|
||
|
)
|
||
|
|
||
|
# If source or target is not in new_nodes, check if it's an existing node
|
||
|
if source_node is None and edge_data["source_node"] in relevant_schema["nodes"]:
|
||
|
existing_node_data = relevant_schema["nodes"][edge_data["source_node"]]
|
||
|
source_node = EntityNode(
|
||
|
uuid=existing_node_data["uuid"],
|
||
|
name=edge_data["source_node"],
|
||
|
labels=[existing_node_data["label"]],
|
||
|
summary="",
|
||
|
created_at=datetime.now(),
|
||
|
)
|
||
|
if target_node is None and edge_data["target_node"] in relevant_schema["nodes"]:
|
||
|
existing_node_data = relevant_schema["nodes"][edge_data["target_node"]]
|
||
|
target_node = EntityNode(
|
||
|
uuid=existing_node_data["uuid"],
|
||
|
name=edge_data["target_node"],
|
||
|
labels=[existing_node_data["label"]],
|
||
|
summary="",
|
||
|
created_at=datetime.now(),
|
||
|
)
|
||
|
|
||
|
if (
|
||
|
source_node
|
||
|
and target_node
|
||
|
and not (
|
||
|
source_node.name.startswith("Message")
|
||
|
or target_node.name.startswith("Message")
|
||
|
)
|
||
|
):
|
||
|
valid_at = (
|
||
|
datetime.fromisoformat(edge_data["valid_at"])
|
||
|
if edge_data["valid_at"]
|
||
|
else episode.valid_at or datetime.now()
|
||
|
)
|
||
|
invalid_at = (
|
||
|
datetime.fromisoformat(edge_data["invalid_at"])
|
||
|
if edge_data["invalid_at"]
|
||
|
else None
|
||
|
)
|
||
|
|
||
|
new_edge = EntityEdge(
|
||
|
source_node=source_node,
|
||
|
target_node=target_node,
|
||
|
name=edge_data["relation_type"],
|
||
|
fact=edge_data["fact"],
|
||
|
episodes=[episode.uuid],
|
||
|
created_at=datetime.now(),
|
||
|
valid_at=valid_at,
|
||
|
invalid_at=invalid_at,
|
||
|
)
|
||
|
new_edges.append(new_edge)
|
||
|
logger.info(
|
||
|
f"Created new edge: {new_edge.name} from {source_node.name} (UUID: {source_node.uuid}) to {target_node.name} (UUID: {target_node.uuid})"
|
||
|
)
|
||
|
|
||
|
return new_edges
|