Skip to content

Commit

Permalink
Merge branch 'main' of github.com:getzep/graphiti into extract-dates-…
Browse files Browse the repository at this point in the history
…from-context

# Conflicts:
#	core/graphiti.py
#	core/prompts/dedupe_edges.py
#	core/prompts/invalidate_edges.py
#	core/utils/bulk_utils.py
#	core/utils/maintenance/edge_operations.py
#	core/utils/maintenance/node_operations.py
#	core/utils/maintenance/temporal_operations.py
#	core/utils/search/search_utils.py
#	runner.py
  • Loading branch information
paul-paliychuk committed Aug 22, 2024
2 parents 7eb836e + 6ae9c4e commit 3b23f6b
Show file tree
Hide file tree
Showing 46 changed files with 2,751 additions and 2,241 deletions.
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
24 changes: 24 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Lint with Ruff

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
ruff:
environment: development
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install "ruff>0.1.7"
- name: Run Ruff linting
run: ruff check --output-format=github
2 changes: 2 additions & 0 deletions .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on:
jobs:
test:
runs-on: ubuntu-latest
environment:
name: development
steps:
- uses: actions/checkout@v3
- name: Set up Python
Expand Down
32 changes: 32 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.PHONY: install format lint test all check

# Define variables
PYTHON = python3
POETRY = poetry
PYTEST = $(POETRY) run pytest
RUFF = $(POETRY) run ruff
MYPY = $(POETRY) run mypy

# Default target
all: format lint test

# Install dependencies
install:
$(POETRY) install --with dev

# Format code
format:
$(RUFF) check --select I --fix
$(RUFF) format

# Lint code
lint:
$(RUFF) check
# $(MYPY) .

# Run tests
test:
$(PYTEST)

# Run format, lint, and test
check: format lint test
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ graphiti.close()

## License

(Add license information)
(Add license information)
15 changes: 15 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Security Policy

## Supported Versions

Use this section to tell people about which versions of your project are
currently being supported with security updates.

| Version | Supported |
|---------|--------------------|
| 0.x | :white_check_mark: |


## Reporting a Vulnerability

Please use GitHub's Private Vulnerability Reporting mechanism found in the Security section of this repo.
2 changes: 1 addition & 1 deletion conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import sys
import os
import sys

# This code adds the project root directory to the Python path, allowing imports to work correctly when running tests.
# Without this file, you might encounter ModuleNotFoundError when trying to import modules from your project, especially when running tests.
Expand Down
2 changes: 1 addition & 1 deletion core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .graphiti import Graphiti

__all__ = ["Graphiti"]
__all__ = ['Graphiti']
151 changes: 74 additions & 77 deletions core/edges.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import logging
from abc import ABC, abstractmethod
from pydantic import BaseModel, Field
from datetime import datetime
from time import time
from neo4j import AsyncDriver
from uuid import uuid4
import logging

from neo4j import AsyncDriver
from pydantic import BaseModel, Field

from core.llm_client.config import EMBEDDING_DIM
from core.nodes import Node
Expand All @@ -13,104 +14,100 @@


class Edge(BaseModel, ABC):
uuid: str = Field(default_factory=lambda: uuid4().hex)
source_node_uuid: str
target_node_uuid: str
created_at: datetime
uuid: str = Field(default_factory=lambda: uuid4().hex)
source_node_uuid: str
target_node_uuid: str
created_at: datetime

@abstractmethod
async def save(self, driver: AsyncDriver): ...
@abstractmethod
async def save(self, driver: AsyncDriver): ...

def __hash__(self):
return hash(self.uuid)
def __hash__(self):
return hash(self.uuid)

def __eq__(self, other):
if isinstance(other, Node):
return self.uuid == other.uuid
return False
def __eq__(self, other):
if isinstance(other, Node):
return self.uuid == other.uuid
return False


class EpisodicEdge(Edge):
async def save(self, driver: AsyncDriver):
result = await driver.execute_query(
"""
async def save(self, driver: AsyncDriver):
result = await driver.execute_query(
"""
MATCH (episode:Episodic {uuid: $episode_uuid})
MATCH (node:Entity {uuid: $entity_uuid})
MERGE (episode)-[r:MENTIONS {uuid: $uuid}]->(node)
SET r = {uuid: $uuid, created_at: $created_at}
RETURN r.uuid AS uuid""",
episode_uuid=self.source_node_uuid,
entity_uuid=self.target_node_uuid,
uuid=self.uuid,
created_at=self.created_at,
)
episode_uuid=self.source_node_uuid,
entity_uuid=self.target_node_uuid,
uuid=self.uuid,
created_at=self.created_at,
)

logger.info(f"Saved edge to neo4j: {self.uuid}")
logger.info(f'Saved edge to neo4j: {self.uuid}')

return result
return result


# TODO: Neo4j doesn't support variables for edge types and labels.
# Right now we have all edge nodes as type RELATES_TO


class EntityEdge(Edge):
name: str = Field(description="name of the edge, relation name")
fact: str = Field(
description="fact representing the edge and nodes that it connects"
)
fact_embedding: list[float] | None = Field(
default=None, description="embedding of the fact"
)
episodes: list[str] | None = Field(
default=None,
description="list of episode ids that reference these entity edges",
)
expired_at: datetime | None = Field(
default=None, description="datetime of when the node was invalidated"
)
valid_at: datetime | None = Field(
default=None, description="datetime of when the fact became true"
)
invalid_at: datetime | None = Field(
default=None, description="datetime of when the fact stopped being true"
)

async def generate_embedding(self, embedder, model="text-embedding-3-small"):
start = time()

text = self.fact.replace("\n", " ")
embedding = (await embedder.create(input=[text], model=model)).data[0].embedding
self.fact_embedding = embedding[:EMBEDDING_DIM]

end = time()
logger.info(f"embedded {text} in {end-start} ms")

return embedding

async def save(self, driver: AsyncDriver):
result = await driver.execute_query(
"""
name: str = Field(description='name of the edge, relation name')
fact: str = Field(description='fact representing the edge and nodes that it connects')
fact_embedding: list[float] | None = Field(default=None, description='embedding of the fact')
episodes: list[str] | None = Field(
default=None,
description='list of episode ids that reference these entity edges',
)
expired_at: datetime | None = Field(
default=None, description='datetime of when the node was invalidated'
)
valid_at: datetime | None = Field(
default=None, description='datetime of when the fact became true'
)
invalid_at: datetime | None = Field(
default=None, description='datetime of when the fact stopped being true'
)

async def generate_embedding(self, embedder, model='text-embedding-3-small'):
start = time()

text = self.fact.replace('\n', ' ')
embedding = (await embedder.create(input=[text], model=model)).data[0].embedding
self.fact_embedding = embedding[:EMBEDDING_DIM]

end = time()
logger.info(f'embedded {text} in {end-start} ms')

return embedding

async def save(self, driver: AsyncDriver):
result = await driver.execute_query(
"""
MATCH (source:Entity {uuid: $source_uuid})
MATCH (target:Entity {uuid: $target_uuid})
MERGE (source)-[r:RELATES_TO {uuid: $uuid}]->(target)
SET r = {uuid: $uuid, name: $name, fact: $fact, fact_embedding: $fact_embedding,
episodes: $episodes, created_at: $created_at, expired_at: $expired_at,
valid_at: $valid_at, invalid_at: $invalid_at}
RETURN r.uuid AS uuid""",
source_uuid=self.source_node_uuid,
target_uuid=self.target_node_uuid,
uuid=self.uuid,
name=self.name,
fact=self.fact,
fact_embedding=self.fact_embedding,
episodes=self.episodes,
created_at=self.created_at,
expired_at=self.expired_at,
valid_at=self.valid_at,
invalid_at=self.invalid_at,
)

logger.info(f"Saved edge to neo4j: {self.uuid}")

return result
source_uuid=self.source_node_uuid,
target_uuid=self.target_node_uuid,
uuid=self.uuid,
name=self.name,
fact=self.fact,
fact_embedding=self.fact_embedding,
episodes=self.episodes,
created_at=self.created_at,
expired_at=self.expired_at,
valid_at=self.valid_at,
invalid_at=self.invalid_at,
)

logger.info(f'Saved edge to neo4j: {self.uuid}')

return result
Loading

0 comments on commit 3b23f6b

Please sign in to comment.