graphiti-core 0.8.7__py3-none-any.whl → 0.9.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of graphiti-core might be problematic. Click here for more details.

@@ -1,4 +1,8 @@
1
1
  from .client import EmbedderClient
2
2
  from .openai import OpenAIEmbedder, OpenAIEmbedderConfig
3
3
 
4
- __all__ = ['EmbedderClient', 'OpenAIEmbedder', 'OpenAIEmbedderConfig']
4
+ __all__ = [
5
+ 'EmbedderClient',
6
+ 'OpenAIEmbedder',
7
+ 'OpenAIEmbedderConfig',
8
+ ]
@@ -0,0 +1,68 @@
1
+ """
2
+ Copyright 2024, Zep Software, Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ from collections.abc import Iterable
18
+
19
+ from google import genai # type: ignore
20
+ from google.genai import types # type: ignore
21
+ from pydantic import Field
22
+
23
+ from .client import EmbedderClient, EmbedderConfig
24
+
25
+ DEFAULT_EMBEDDING_MODEL = 'embedding-001'
26
+
27
+
28
+ class GeminiEmbedderConfig(EmbedderConfig):
29
+ embedding_model: str = Field(default=DEFAULT_EMBEDDING_MODEL)
30
+ api_key: str | None = None
31
+
32
+
33
+ class GeminiEmbedder(EmbedderClient):
34
+ """
35
+ Google Gemini Embedder Client
36
+ """
37
+
38
+ def __init__(self, config: GeminiEmbedderConfig | None = None):
39
+ if config is None:
40
+ config = GeminiEmbedderConfig()
41
+ self.config = config
42
+
43
+ # Configure the Gemini API
44
+ self.client = genai.Client(
45
+ api_key=config.api_key,
46
+ )
47
+
48
+ async def create(
49
+ self, input_data: str | list[str] | Iterable[int] | Iterable[Iterable[int]]
50
+ ) -> list[float]:
51
+ """
52
+ Create embeddings for the given input data using Google's Gemini embedding model.
53
+
54
+ Args:
55
+ input_data: The input data to create embeddings for. Can be a string, list of strings,
56
+ or an iterable of integers or iterables of integers.
57
+
58
+ Returns:
59
+ A list of floats representing the embedding vector.
60
+ """
61
+ # Generate embeddings
62
+ result = await self.client.aio.models.embed_content(
63
+ model=self.config.embedding_model or DEFAULT_EMBEDDING_MODEL,
64
+ contents=[input_data],
65
+ config=types.EmbedContentConfig(output_dimensionality=self.config.embedding_dim),
66
+ )
67
+
68
+ return result.embeddings[0].values
graphiti_core/errors.py CHANGED
@@ -65,3 +65,11 @@ class SearchRerankerError(GraphitiError):
65
65
  def __init__(self, text: str):
66
66
  self.message = text
67
67
  super().__init__(self.message)
68
+
69
+
70
+ class EntityTypeValidationError(GraphitiError):
71
+ """Raised when an entity type uses protected attribute names."""
72
+
73
+ def __init__(self, entity_type: str, entity_type_attribute: str):
74
+ self.message = f'{entity_type_attribute} cannot be used as an attribute for {entity_type} as it is a protected attribute name.'
75
+ super().__init__(self.message)
graphiti_core/graphiti.py CHANGED
@@ -71,11 +71,9 @@ from graphiti_core.utils.maintenance.graph_data_operations import (
71
71
  build_indices_and_constraints,
72
72
  retrieve_episodes,
73
73
  )
74
- from graphiti_core.utils.maintenance.node_operations import (
75
- extract_nodes,
76
- resolve_extracted_nodes,
77
- )
74
+ from graphiti_core.utils.maintenance.node_operations import extract_nodes, resolve_extracted_nodes
78
75
  from graphiti_core.utils.maintenance.temporal_operations import get_edge_contradictions
76
+ from graphiti_core.utils.ontology_utils.entity_types_utils import validate_entity_types
79
77
 
80
78
  logger = logging.getLogger(__name__)
81
79
 
@@ -319,6 +317,8 @@ class Graphiti:
319
317
  entity_edges: list[EntityEdge] = []
320
318
  now = utc_now()
321
319
 
320
+ validate_entity_types(entity_types)
321
+
322
322
  previous_episodes = (
323
323
  await self.retrieve_episodes(
324
324
  reference_time, last_n=RELEVANT_SCHEMA_LIMIT, group_ids=[group_id]
@@ -0,0 +1,186 @@
1
+ """
2
+ Copyright 2024, Zep Software, Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ import json
18
+ import logging
19
+ import typing
20
+
21
+ from google import genai # type: ignore
22
+ from google.genai import types # type: ignore
23
+ from pydantic import BaseModel
24
+
25
+ from ..prompts.models import Message
26
+ from .client import LLMClient
27
+ from .config import DEFAULT_MAX_TOKENS, LLMConfig
28
+ from .errors import RateLimitError
29
+
30
+ logger = logging.getLogger(__name__)
31
+
32
+ DEFAULT_MODEL = 'gemini-2.0-flash'
33
+
34
+
35
+ class GeminiClient(LLMClient):
36
+ """
37
+ GeminiClient is a client class for interacting with Google's Gemini language models.
38
+
39
+ This class extends the LLMClient and provides methods to initialize the client
40
+ and generate responses from the Gemini language model.
41
+
42
+ Attributes:
43
+ model (str): The model name to use for generating responses.
44
+ temperature (float): The temperature to use for generating responses.
45
+ max_tokens (int): The maximum number of tokens to generate in a response.
46
+
47
+ Methods:
48
+ __init__(config: LLMConfig | None = None, cache: bool = False):
49
+ Initializes the GeminiClient with the provided configuration and cache setting.
50
+
51
+ _generate_response(messages: list[Message]) -> dict[str, typing.Any]:
52
+ Generates a response from the language model based on the provided messages.
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ config: LLMConfig | None = None,
58
+ cache: bool = False,
59
+ max_tokens: int = DEFAULT_MAX_TOKENS,
60
+ ):
61
+ """
62
+ Initialize the GeminiClient with the provided configuration and cache setting.
63
+
64
+ Args:
65
+ config (LLMConfig | None): The configuration for the LLM client, including API key, model, temperature, and max tokens.
66
+ cache (bool): Whether to use caching for responses. Defaults to False.
67
+ """
68
+ if config is None:
69
+ config = LLMConfig()
70
+
71
+ super().__init__(config, cache)
72
+
73
+ self.model = config.model
74
+ # Configure the Gemini API
75
+ self.client = genai.Client(
76
+ api_key=config.api_key,
77
+ )
78
+ self.max_tokens = max_tokens
79
+
80
+ async def _generate_response(
81
+ self,
82
+ messages: list[Message],
83
+ response_model: type[BaseModel] | None = None,
84
+ max_tokens: int = DEFAULT_MAX_TOKENS,
85
+ ) -> dict[str, typing.Any]:
86
+ """
87
+ Generate a response from the Gemini language model.
88
+
89
+ Args:
90
+ messages (list[Message]): A list of messages to send to the language model.
91
+ response_model (type[BaseModel] | None): An optional Pydantic model to parse the response into.
92
+ max_tokens (int): The maximum number of tokens to generate in the response.
93
+
94
+ Returns:
95
+ dict[str, typing.Any]: The response from the language model.
96
+
97
+ Raises:
98
+ RateLimitError: If the API rate limit is exceeded.
99
+ RefusalError: If the content is blocked by the model.
100
+ Exception: If there is an error generating the response.
101
+ """
102
+ try:
103
+ gemini_messages: list[types.Content] = []
104
+ # If a response model is provided, add schema for structured output
105
+ system_prompt = ''
106
+ if response_model is not None:
107
+ # Get the schema from the Pydantic model
108
+ pydantic_schema = response_model.model_json_schema()
109
+
110
+ # Create instruction to output in the desired JSON format
111
+ system_prompt += (
112
+ f'Output ONLY valid JSON matching this schema: {json.dumps(pydantic_schema)}.\n'
113
+ 'Do not include any explanatory text before or after the JSON.\n\n'
114
+ )
115
+
116
+ # Add messages content
117
+ # First check for a system message
118
+ if messages and messages[0].role == 'system':
119
+ system_prompt = f'{messages[0].content}\n\n {system_prompt}'
120
+ messages = messages[1:]
121
+
122
+ # Add the rest of the messages
123
+ for m in messages:
124
+ m.content = self._clean_input(m.content)
125
+ gemini_messages.append(
126
+ types.Content(role=m.role, parts=[types.Part.from_text(text=m.content)])
127
+ )
128
+
129
+ # Create generation config
130
+ generation_config = types.GenerateContentConfig(
131
+ temperature=self.temperature,
132
+ max_output_tokens=max_tokens or self.max_tokens,
133
+ response_mime_type='application/json' if response_model else None,
134
+ response_schema=response_model if response_model else None,
135
+ system_instruction=system_prompt,
136
+ )
137
+
138
+ # Generate content using the simple string approach
139
+ response = await self.client.aio.models.generate_content(
140
+ model=self.model or DEFAULT_MODEL,
141
+ contents=gemini_messages,
142
+ config=generation_config,
143
+ )
144
+
145
+ # If this was a structured output request, parse the response into the Pydantic model
146
+ if response_model is not None:
147
+ try:
148
+ validated_model = response_model.model_validate(json.loads(response.text))
149
+
150
+ # Return as a dictionary for API consistency
151
+ return validated_model.model_dump()
152
+ except Exception as e:
153
+ raise Exception(f'Failed to parse structured response: {e}') from e
154
+
155
+ # Otherwise, return the response text as a dictionary
156
+ return {'content': response.text}
157
+
158
+ except Exception as e:
159
+ # Check if it's a rate limit error
160
+ if 'rate limit' in str(e).lower() or 'quota' in str(e).lower():
161
+ raise RateLimitError from e
162
+ logger.error(f'Error in generating LLM response: {e}')
163
+ raise
164
+
165
+ async def generate_response(
166
+ self,
167
+ messages: list[Message],
168
+ response_model: type[BaseModel] | None = None,
169
+ max_tokens: int = DEFAULT_MAX_TOKENS,
170
+ ) -> dict[str, typing.Any]:
171
+ """
172
+ Generate a response from the Gemini language model.
173
+ This method overrides the parent class method to provide a direct implementation.
174
+
175
+ Args:
176
+ messages (list[Message]): A list of messages to send to the language model.
177
+ response_model (type[BaseModel] | None): An optional Pydantic model to parse the response into.
178
+ max_tokens (int): The maximum number of tokens to generate in the response.
179
+
180
+ Returns:
181
+ dict[str, typing.Any]: The response from the language model.
182
+ """
183
+ # Call the internal _generate_response method
184
+ return await self._generate_response(
185
+ messages=messages, response_model=response_model, max_tokens=max_tokens
186
+ )
@@ -16,63 +16,27 @@ limitations under the License.
16
16
 
17
17
  from typing import Any, Protocol, TypedDict
18
18
 
19
- from .dedupe_edges import (
20
- Prompt as DedupeEdgesPrompt,
21
- )
22
- from .dedupe_edges import (
23
- Versions as DedupeEdgesVersions,
24
- )
25
- from .dedupe_edges import (
26
- versions as dedupe_edges_versions,
27
- )
28
- from .dedupe_nodes import (
29
- Prompt as DedupeNodesPrompt,
30
- )
31
- from .dedupe_nodes import (
32
- Versions as DedupeNodesVersions,
33
- )
34
- from .dedupe_nodes import (
35
- versions as dedupe_nodes_versions,
36
- )
19
+ from .dedupe_edges import Prompt as DedupeEdgesPrompt
20
+ from .dedupe_edges import Versions as DedupeEdgesVersions
21
+ from .dedupe_edges import versions as dedupe_edges_versions
22
+ from .dedupe_nodes import Prompt as DedupeNodesPrompt
23
+ from .dedupe_nodes import Versions as DedupeNodesVersions
24
+ from .dedupe_nodes import versions as dedupe_nodes_versions
37
25
  from .eval import Prompt as EvalPrompt
38
26
  from .eval import Versions as EvalVersions
39
27
  from .eval import versions as eval_versions
40
- from .extract_edge_dates import (
41
- Prompt as ExtractEdgeDatesPrompt,
42
- )
43
- from .extract_edge_dates import (
44
- Versions as ExtractEdgeDatesVersions,
45
- )
46
- from .extract_edge_dates import (
47
- versions as extract_edge_dates_versions,
48
- )
49
- from .extract_edges import (
50
- Prompt as ExtractEdgesPrompt,
51
- )
52
- from .extract_edges import (
53
- Versions as ExtractEdgesVersions,
54
- )
55
- from .extract_edges import (
56
- versions as extract_edges_versions,
57
- )
58
- from .extract_nodes import (
59
- Prompt as ExtractNodesPrompt,
60
- )
61
- from .extract_nodes import (
62
- Versions as ExtractNodesVersions,
63
- )
64
- from .extract_nodes import (
65
- versions as extract_nodes_versions,
66
- )
67
- from .invalidate_edges import (
68
- Prompt as InvalidateEdgesPrompt,
69
- )
70
- from .invalidate_edges import (
71
- Versions as InvalidateEdgesVersions,
72
- )
73
- from .invalidate_edges import (
74
- versions as invalidate_edges_versions,
75
- )
28
+ from .extract_edge_dates import Prompt as ExtractEdgeDatesPrompt
29
+ from .extract_edge_dates import Versions as ExtractEdgeDatesVersions
30
+ from .extract_edge_dates import versions as extract_edge_dates_versions
31
+ from .extract_edges import Prompt as ExtractEdgesPrompt
32
+ from .extract_edges import Versions as ExtractEdgesVersions
33
+ from .extract_edges import versions as extract_edges_versions
34
+ from .extract_nodes import Prompt as ExtractNodesPrompt
35
+ from .extract_nodes import Versions as ExtractNodesVersions
36
+ from .extract_nodes import versions as extract_nodes_versions
37
+ from .invalidate_edges import Prompt as InvalidateEdgesPrompt
38
+ from .invalidate_edges import Versions as InvalidateEdgesVersions
39
+ from .invalidate_edges import versions as invalidate_edges_versions
76
40
  from .models import Message, PromptFunction
77
41
  from .prompt_helpers import DO_NOT_ESCAPE_UNICODE
78
42
  from .summarize_nodes import Prompt as SummarizeNodesPrompt
@@ -1,8 +1,5 @@
1
1
  from .edge_operations import build_episodic_edges, extract_edges
2
- from .graph_data_operations import (
3
- clear_data,
4
- retrieve_episodes,
5
- )
2
+ from .graph_data_operations import clear_data, retrieve_episodes
6
3
  from .node_operations import extract_nodes
7
4
 
8
5
  __all__ = [
@@ -9,11 +9,7 @@ from graphiti_core.edges import CommunityEdge
9
9
  from graphiti_core.embedder import EmbedderClient
10
10
  from graphiti_core.helpers import DEFAULT_DATABASE, semaphore_gather
11
11
  from graphiti_core.llm_client import LLMClient
12
- from graphiti_core.nodes import (
13
- CommunityNode,
14
- EntityNode,
15
- get_community_node_from_record,
16
- )
12
+ from graphiti_core.nodes import CommunityNode, EntityNode, get_community_node_from_record
17
13
  from graphiti_core.prompts import prompt_library
18
14
  from graphiti_core.prompts.summarize_nodes import Summary, SummaryDescription
19
15
  from graphiti_core.utils.datetime_utils import utc_now
@@ -26,11 +26,7 @@ from graphiti_core.llm_client import LLMClient
26
26
  from graphiti_core.nodes import EntityNode, EpisodeType, EpisodicNode
27
27
  from graphiti_core.prompts import prompt_library
28
28
  from graphiti_core.prompts.dedupe_nodes import NodeDuplicate
29
- from graphiti_core.prompts.extract_nodes import (
30
- EntityClassification,
31
- ExtractedNodes,
32
- MissedEntities,
33
- )
29
+ from graphiti_core.prompts.extract_nodes import EntityClassification, ExtractedNodes, MissedEntities
34
30
  from graphiti_core.prompts.summarize_nodes import Summary
35
31
  from graphiti_core.utils.datetime_utils import utc_now
36
32
 
@@ -0,0 +1,37 @@
1
+ """
2
+ Copyright 2024, Zep Software, Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ from pydantic import BaseModel
18
+
19
+ from graphiti_core.errors import EntityTypeValidationError
20
+ from graphiti_core.nodes import EntityNode
21
+
22
+
23
+ def validate_entity_types(
24
+ entity_types: dict[str, BaseModel] | None,
25
+ ) -> bool:
26
+ if entity_types is None:
27
+ return True
28
+
29
+ entity_node_field_names = EntityNode.model_fields.keys()
30
+
31
+ for entity_type_name, entity_type_model in entity_types.items():
32
+ entity_type_field_names = entity_type_model.model_fields.keys()
33
+ for entity_type_field_name in entity_type_field_names:
34
+ if entity_type_field_name in entity_node_field_names:
35
+ raise EntityTypeValidationError(entity_type_name, entity_type_field_name)
36
+
37
+ return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: graphiti-core
3
- Version: 0.8.7
3
+ Version: 0.9.0
4
4
  Summary: A temporal graph building library
5
5
  License: Apache-2.0
6
6
  Author: Paul Paliychuk
@@ -11,7 +11,9 @@ Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
- Requires-Dist: anthropic (>=0.49.0,<0.50.0)
14
+ Provides-Extra: anthropic
15
+ Provides-Extra: google-genai
16
+ Provides-Extra: groq
15
17
  Requires-Dist: diskcache (>=5.6.3,<6.0.0)
16
18
  Requires-Dist: neo4j (>=5.23.0,<6.0.0)
17
19
  Requires-Dist: numpy (>=1.0.0)
@@ -58,8 +60,8 @@ Use Graphiti to:
58
60
 
59
61
  <br />
60
62
 
61
- A knowledge graph is a network of interconnected facts, such as _Kendra loves Adidas shoes.”_ Each fact is a triplet represented by two entities, or
62
- nodes (_”Kendra”_, _“Adidas shoes”_), and their relationship, or edge (_”loves”_). Knowledge Graphs have been explored
63
+ A knowledge graph is a network of interconnected facts, such as _"Kendra loves Adidas shoes."_ Each fact is a "triplet" represented by two entities, or
64
+ nodes ("Kendra", "Adidas shoes"), and their relationship, or edge ("loves"). Knowledge Graphs have been explored
63
65
  extensively for information retrieval. What makes Graphiti unique is its ability to autonomously build a knowledge graph
64
66
  while handling changing relationships and maintaining historical context.
65
67
 
@@ -119,7 +121,7 @@ Requirements:
119
121
 
120
122
  Optional:
121
123
 
122
- - Anthropic or Groq API key (for alternative LLM providers)
124
+ - Google Gemini, Anthropic, or Groq API key (for alternative LLM providers)
123
125
 
124
126
  > [!TIP]
125
127
  > The simplest way to install Neo4j is via [Neo4j Desktop](https://neo4j.com/download/). It provides a user-friendly
@@ -135,6 +137,22 @@ or
135
137
  poetry add graphiti-core
136
138
  ```
137
139
 
140
+ You can also install optional LLM providers as extras:
141
+
142
+ ```bash
143
+ # Install with Anthropic support
144
+ pip install graphiti-core[anthropic]
145
+
146
+ # Install with Groq support
147
+ pip install graphiti-core[groq]
148
+
149
+ # Install with Google Gemini support
150
+ pip install graphiti-core[google-genai]
151
+
152
+ # Install with multiple providers
153
+ pip install graphiti-core[anthropic,groq,google-genai]
154
+ ```
155
+
138
156
  ## Quick Start
139
157
 
140
158
  > [!IMPORTANT]
@@ -142,67 +160,16 @@ poetry add graphiti-core
142
160
  > Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
143
161
  > compatible APIs.
144
162
 
145
- ```python
146
- from graphiti_core import Graphiti
147
- from graphiti_core.nodes import EpisodeType
148
- from datetime import datetime, timezone
149
-
150
- # Initialize Graphiti as Your Memory Layer
151
- graphiti = Graphiti("bolt://localhost:7687", "neo4j", "password")
152
-
153
- # Initialize the graph database with Graphiti's indices. This only needs to be done once.
154
- graphiti.build_indices_and_constraints()
155
-
156
- # Add episodes
157
- episodes = [
158
- "Kamala Harris is the Attorney General of California. She was previously "
159
- "the district attorney for San Francisco.",
160
- "As AG, Harris was in office from January 3, 2011 – January 3, 2017",
161
- ]
162
- for i, episode in enumerate(episodes):
163
- await graphiti.add_episode(
164
- name=f"Freakonomics Radio {i}",
165
- episode_body=episode,
166
- source=EpisodeType.text,
167
- source_description="podcast",
168
- reference_time=datetime.now(timezone.utc)
169
- )
163
+ For a complete working example, see the [Quickstart Example](./examples/quickstart/README.md) in the examples directory. The quickstart demonstrates:
170
164
 
171
- # Search the graph for semantic memory retrieval
172
- # Execute a hybrid search combining semantic similarity and BM25 retrieval
173
- # Results are combined and reranked using Reciprocal Rank Fusion
174
- results = await graphiti.search('Who was the California Attorney General?')
175
- [
176
- EntityEdge(
177
- │ uuid = '3133258f738e487383f07b04e15d4ac0',
178
- │ source_node_uuid = '2a85789b318d4e418050506879906e62',
179
- │ target_node_uuid = 'baf7781f445945989d6e4f927f881556',
180
- │ created_at = datetime.datetime(2024, 8, 26, 13, 13, 24, 861097),
181
- │ name = 'HELD_POSITION',
182
- # the fact reflects the updated state that Harris is
183
- # no longer the AG of California
184
- │ fact = 'Kamala Harris was the Attorney General of California',
185
- │ fact_embedding = [
186
- │ │ -0.009955154731869698,
187
- │ ...
188
- │ │ 0.00784289836883545
189
- │],
190
- │ episodes = ['b43e98ad0a904088a76c67985caecc22'],
191
- │ expired_at = datetime.datetime(2024, 8, 26, 20, 18, 1, 53812),
192
- # These dates represent the date this edge was true.
193
- │ valid_at = datetime.datetime(2011, 1, 3, 0, 0, tzinfo= < UTC >),
194
- │ invalid_at = datetime.datetime(2017, 1, 3, 0, 0, tzinfo= < UTC >)
195
- )
196
- ]
165
+ 1. Connecting to a Neo4j database
166
+ 2. Initializing Graphiti indices and constraints
167
+ 3. Adding episodes to the graph (both text and structured JSON)
168
+ 4. Searching for relationships (edges) using hybrid search
169
+ 5. Reranking search results using graph distance
170
+ 6. Searching for nodes using predefined search recipes
197
171
 
198
- # Rerank search results based on graph distance
199
- # Provide a node UUID to prioritize results closer to that node in the graph.
200
- # Results are weighted by their proximity, with distant edges receiving lower scores.
201
- await graphiti.search('Who was the California Attorney General?', center_node_uuid)
202
-
203
- # Close the connection when chat state management is complete
204
- graphiti.close()
205
- ```
172
+ The example is fully documented with clear explanations of each functionality and includes a comprehensive README with setup instructions and next steps.
206
173
 
207
174
  ## Graph Service
208
175
 
@@ -285,6 +252,42 @@ graphiti = Graphiti(
285
252
 
286
253
  Make sure to replace the placeholder values with your actual Azure OpenAI credentials and specify the correct embedding model name that's deployed in your Azure OpenAI service.
287
254
 
255
+ ## Using Graphiti with Google Gemini
256
+
257
+ Graphiti supports Google's Gemini models for both LLM inference and embeddings. To use Gemini, you'll need to configure both the LLM client and embedder with your Google API key.
258
+
259
+ ```python
260
+ from graphiti_core import Graphiti
261
+ from graphiti_core.llm_client.gemini_client import GeminiClient, LLMConfig
262
+ from graphiti_core.embedder.gemini import GeminiEmbedder, GeminiEmbedderConfig
263
+
264
+ # Google API key configuration
265
+ api_key = "<your-google-api-key>"
266
+
267
+ # Initialize Graphiti with Gemini clients
268
+ graphiti = Graphiti(
269
+ "bolt://localhost:7687",
270
+ "neo4j",
271
+ "password",
272
+ llm_client=GeminiClient(
273
+ config=LLMConfig(
274
+ api_key=api_key,
275
+ model="gemini-2.0-flash"
276
+ )
277
+ ),
278
+ embedder=GeminiEmbedder(
279
+ config=GeminiEmbedderConfig(
280
+ api_key=api_key,
281
+ embedding_model="embedding-001"
282
+ )
283
+ )
284
+ )
285
+
286
+ # Now you can use Graphiti with Google Gemini
287
+ ```
288
+
289
+ Make sure to replace the placeholder value with your actual Google API key. You can find more details in the example file at `examples/gemini_example.py`.
290
+
288
291
  ## Documentation
289
292
 
290
293
  - [Guides and API documentation](https://help.getzep.com/graphiti).
@@ -4,18 +4,20 @@ graphiti_core/cross_encoder/bge_reranker_client.py,sha256=xgXZqB_qoaWQPjnmuf1ne3
4
4
  graphiti_core/cross_encoder/client.py,sha256=KLsbfWKOEaAV3adFe3XZlAeb-gje9_sVKCVZTaJP3ac,1441
5
5
  graphiti_core/cross_encoder/openai_reranker_client.py,sha256=e-QCftckZ7GLQgJ-ijljw6vzVa6H417cZ3cISB70M5g,4377
6
6
  graphiti_core/edges.py,sha256=pVaQUmxUH7ZwETdaTaoBsmmd5MMis1v7L-0tHBzUuHc,15657
7
- graphiti_core/embedder/__init__.py,sha256=eWd-0sPxflnYXLoWNT9sxwCIFun5JNO9Fk4E-ZXXf8Y,164
7
+ graphiti_core/embedder/__init__.py,sha256=EL564ZuE-DZjcuKNUK_exMn_XHXm2LdO9fzdXePVKL4,179
8
8
  graphiti_core/embedder/client.py,sha256=HKIlpPLnzFT81jurPkry6z8F8nxfZVfejdcfxHVUSFU,995
9
+ graphiti_core/embedder/gemini.py,sha256=nE0XH8wYVGcPSO7DaNQ7kdsQLFSoH4FQOu2HMQUy2ss,2200
9
10
  graphiti_core/embedder/openai.py,sha256=23BnPA10eiaa1HkxHKYSj75-0PymczPK2FNNIz8Txbc,1910
10
11
  graphiti_core/embedder/voyage.py,sha256=7kqrLG75J3Q6cdA2Nlx1JSYtpk2141ckdl3OtDDw0vU,1882
11
- graphiti_core/errors.py,sha256=cSOXXkydihNd6OHXzkwJvciRmR7EoFMq57AzUYVg0gc,2040
12
- graphiti_core/graphiti.py,sha256=FXkfgaib_JcVPHCBnJP__a4kJBlDs00ctvrtDCLHyoE,29588
12
+ graphiti_core/errors.py,sha256=Nib1uQx2cO_VOizupmRjpFfmuRg-hFAVqTtZAuBehR8,2405
13
+ graphiti_core/graphiti.py,sha256=hygm_1MPbi4jlAplAoLjrzC_45_0VKcIrZ3ll3Fi3bo,29712
13
14
  graphiti_core/helpers.py,sha256=7BQzUBFmoBDA2OIDdFtoN4W-vXOhPRIsF0uDb7PsNi0,2913
14
15
  graphiti_core/llm_client/__init__.py,sha256=PA80TSMeX-sUXITXEAxMDEt3gtfZgcJrGJUcyds1mSo,207
15
16
  graphiti_core/llm_client/anthropic_client.py,sha256=dTM8rKhk9TZAU4O-0jFMivOwJvWM-gHpp5gLmuJHiGQ,2723
16
17
  graphiti_core/llm_client/client.py,sha256=sqtdkySL_QnlZUyMhLvtbSPzGI1y8Ryq5a0IqOPZ2Ps,5252
17
18
  graphiti_core/llm_client/config.py,sha256=PxbjQWNjYQJKA7Pws28jJ0TsSZijOUds8GD9Yvu7xUE,2338
18
19
  graphiti_core/llm_client/errors.py,sha256=Vk0mj2SgNDg8E8p7m1UyUaerqLPNLCDKPVsMEnOSBdQ,1028
20
+ graphiti_core/llm_client/gemini_client.py,sha256=uibmwppDgkEv60FsIhS-oakuafTUFgpu3qr5Kdcbhz4,7321
19
21
  graphiti_core/llm_client/groq_client.py,sha256=EesX0_iFOIvvIc3ql6Xa8EOm0dbGJ_o3VpqyDM83mKg,2498
20
22
  graphiti_core/llm_client/openai_client.py,sha256=_kLK35oSwhP20RQ9n20P8m5QxjmqqqmvU4UlOOhoLhw,6798
21
23
  graphiti_core/llm_client/openai_generic_client.py,sha256=PtMtOaophf2T2-W_O7KitsQIN2C2pl7Qzs-ToYADurM,6648
@@ -34,7 +36,7 @@ graphiti_core/prompts/extract_edge_dates.py,sha256=td2yx2wnX-nLioMa0mtla3WcRyO71
34
36
  graphiti_core/prompts/extract_edges.py,sha256=vyEdW7JAPOT_eLWUi6nRmxbvucyVoyoYX2SxXfknRUg,3467
35
37
  graphiti_core/prompts/extract_nodes.py,sha256=fSi07hGnlo7L5t9c0Q5zcBxDSki7QQKWhex9DFsVWW8,7048
36
38
  graphiti_core/prompts/invalidate_edges.py,sha256=DV2mEyIhhjc0hdKEMFLQMeG0FiUCkv_X0ctCliYjQ2c,3577
37
- graphiti_core/prompts/lib.py,sha256=oxhlpGEgV15VOLEZiwirxmIJBIdfzfiyL58iyzFDskE,4254
39
+ graphiti_core/prompts/lib.py,sha256=DCyHePM4_q-CptTpEXGO_dBv9k7xDtclEaB1dGu7EcI,4092
38
40
  graphiti_core/prompts/models.py,sha256=cvx_Bv5RMFUD_5IUawYrbpOKLPHogai7_bm7YXrSz84,867
39
41
  graphiti_core/prompts/prompt_helpers.py,sha256=-9TABwIcIQUVHcNANx6wIZd-FT2DgYKyGTfx4IGYq2I,64
40
42
  graphiti_core/prompts/summarize_nodes.py,sha256=PeA1Taov5KBNNBKgrCPeF1tLg4_SMgT-Ilz2P6xbx-M,4051
@@ -48,14 +50,15 @@ graphiti_core/search/search_utils.py,sha256=Bywp7trqP_gEwqH8I-JHuj3Mljw9P2K6_Xoo
48
50
  graphiti_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
51
  graphiti_core/utils/bulk_utils.py,sha256=P4LKO46Yle4tBdNcQ3hDHcSQFaR8UBLfoL-z1M2Wua0,14690
50
52
  graphiti_core/utils/datetime_utils.py,sha256=Ti-2tnrDFRzBsbfblzsHybsM3jaDLP4-VT2t0VhpIzU,1357
51
- graphiti_core/utils/maintenance/__init__.py,sha256=TRY3wWWu5kn3Oahk_KKhltrWnh0NACw0FskjqF6OtlA,314
52
- graphiti_core/utils/maintenance/community_operations.py,sha256=gIw1M5HGgc2c3TXag5ygPPpAv5WsG-yoC8Lhmfr6FMs,10011
53
+ graphiti_core/utils/maintenance/__init__.py,sha256=vW4H1KyapTl-OOz578uZABYcpND4wPx3Vt6aAPaXh78,301
54
+ graphiti_core/utils/maintenance/community_operations.py,sha256=KV5TmpQoBLHDAE5BatUPdzjWYr-DG3ypfXKgbZUMSAA,9994
53
55
  graphiti_core/utils/maintenance/edge_operations.py,sha256=tNw56vN586JYZMgie6RLRTiHZ680-kWzDIxW8ucL6SU,12780
54
56
  graphiti_core/utils/maintenance/graph_data_operations.py,sha256=UJlIAawswJ7eO70oS5ueX-zjGHSaTWLsMbeYje67WTY,6895
55
- graphiti_core/utils/maintenance/node_operations.py,sha256=yo5Qt7i5WN3J3rB_9RJ0TJ1ZG1cGFWUKGrktMDwmXyE,15521
57
+ graphiti_core/utils/maintenance/node_operations.py,sha256=gtc5EhEUqC57VPBMOLsRFsJITyM2Sxsn0fJ99JMBWio,15504
56
58
  graphiti_core/utils/maintenance/temporal_operations.py,sha256=RdNtubCyYhOVrvcOIq2WppHls1Q-BEjtsN8r38l-Rtc,3691
57
59
  graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
- graphiti_core-0.8.7.dist-info/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
59
- graphiti_core-0.8.7.dist-info/METADATA,sha256=XrGUFhTTqF1IyDIuugdQeUTPaxyXEk-FkuyhqbBQmMw,14351
60
- graphiti_core-0.8.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
61
- graphiti_core-0.8.7.dist-info/RECORD,,
60
+ graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=QJX5cG0GSSNF_Mm_yrldr69wjVAbN_MxLhOSznz85Hk,1279
61
+ graphiti_core-0.9.0.dist-info/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
62
+ graphiti_core-0.9.0.dist-info/METADATA,sha256=0jvS49ZVOwOiP-r5WmLVohmZaqs0ZnuwdbxQZzjTmr4,14064
63
+ graphiti_core-0.9.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
64
+ graphiti_core-0.9.0.dist-info/RECORD,,