graphiti-core 0.7.0__tar.gz → 0.7.2__tar.gz
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.
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/PKG-INFO +18 -14
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/README.md +17 -13
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/graphiti.py +6 -3
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search.py +10 -4
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_filters.py +23 -4
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_utils.py +56 -21
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/bulk_utils.py +2 -1
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/pyproject.toml +1 -1
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/LICENSE +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/bge_reranker_client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/openai_reranker_client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/edges.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/openai.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/embedder/voyage.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/errors.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/helpers.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/anthropic_client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/config.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/errors.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/groq_client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/openai_client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/openai_generic_client.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/utils.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/edges/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/edges/edge_db_queries.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/nodes/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/models/nodes/node_db_queries.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/nodes.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/dedupe_edges.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/dedupe_nodes.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/eval.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/extract_edge_dates.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/extract_edges.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/extract_nodes.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/invalidate_edges.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/lib.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/models.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/prompt_helpers.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/prompts/summarize_nodes.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/py.typed +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_config.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/search/search_config_recipes.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/datetime_utils.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/__init__.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/community_operations.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/edge_operations.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/graph_data_operations.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/node_operations.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/temporal_operations.py +0 -0
- {graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: graphiti-core
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: A temporal graph building library
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Author: Paul Paliychuk
|
|
@@ -20,12 +20,16 @@ Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
|
20
20
|
Requires-Dist: tenacity (==9.0.0)
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
<p align="center">
|
|
24
|
+
<a href="https://www.getzep.com/">
|
|
25
|
+
<img src="https://github.com/user-attachments/assets/119c5682-9654-4257-8922-56b7cb8ffd73" width="150" alt="Zep Logo">
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
28
|
|
|
29
|
+
<h1 align="center">
|
|
30
|
+
Graphiti
|
|
31
|
+
</h1>
|
|
32
|
+
<h2 align="center"> Temporal Knowledge Graphs for Agentic Applications</h2>
|
|
29
33
|
<br />
|
|
30
34
|
|
|
31
35
|
[](https://discord.com/invite/W8Kw6bsgXQ)
|
|
@@ -34,10 +38,9 @@ Description-Content-Type: text/markdown
|
|
|
34
38
|
[](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml)
|
|
35
39
|
[](https://codespaces.new/getzep/Graphiti)
|
|
36
40
|
|
|
41
|
+
:star: *Help us reach more developers and grow the Graphiti community. Star this repo!*
|
|
37
42
|
<br />
|
|
38
43
|
|
|
39
|
-
</div>
|
|
40
|
-
|
|
41
44
|
Graphiti builds dynamic, temporally aware Knowledge Graphs that represent complex, evolving relationships between
|
|
42
45
|
entities over time. Graphiti ingests both unstructured and structured data, and the resulting graph may be queried using
|
|
43
46
|
a fusion of time, full-text, semantic, and graph algorithm approaches.
|
|
@@ -69,7 +72,8 @@ recall and state-based reasoning for both assistants and agents.
|
|
|
69
72
|
|
|
70
73
|
Graphiti powers the core of [Zep's memory layer](https://www.getzep.com) for LLM-powered Assistants and Agents.
|
|
71
74
|
|
|
72
|
-
Using Graphiti, we've demonstrated Zep is
|
|
75
|
+
Using Graphiti, we've demonstrated Zep is
|
|
76
|
+
the [State of the Art in Agent Memory](https://blog.getzep.com/state-of-the-art-agent-memory/).
|
|
73
77
|
|
|
74
78
|
Read our paper: [Zep: A Temporal Knowledge Graph Architecture for Agent Memory](https://arxiv.org/abs/2501.13956).
|
|
75
79
|
|
|
@@ -108,7 +112,7 @@ scale:
|
|
|
108
112
|
Requirements:
|
|
109
113
|
|
|
110
114
|
- Python 3.10 or higher
|
|
111
|
-
- Neo4j 5.
|
|
115
|
+
- Neo4j 5.26 or higher
|
|
112
116
|
- OpenAI API key (for LLM inference and embedding)
|
|
113
117
|
|
|
114
118
|
Optional:
|
|
@@ -133,7 +137,8 @@ poetry add graphiti-core
|
|
|
133
137
|
|
|
134
138
|
> [!IMPORTANT]
|
|
135
139
|
> Graphiti uses OpenAI for LLM inference and embedding. Ensure that an `OPENAI_API_KEY` is set in your environment.
|
|
136
|
-
> Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
|
|
140
|
+
> Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
|
|
141
|
+
> compatible APIs.
|
|
137
142
|
|
|
138
143
|
```python
|
|
139
144
|
from graphiti_core import Graphiti
|
|
@@ -198,7 +203,6 @@ graphiti.close()
|
|
|
198
203
|
```
|
|
199
204
|
|
|
200
205
|
## Graph Service
|
|
201
|
-
|
|
202
206
|
The `server` directory contains an API service for interacting with the Graphiti API. It is built using FastAPI.
|
|
203
207
|
|
|
204
208
|
Please see the [server README](./server/README.md) for more information.
|
|
@@ -225,8 +229,8 @@ as such this feature is off by default.
|
|
|
225
229
|
Graphiti is under active development. We aim to maintain API stability while working on:
|
|
226
230
|
|
|
227
231
|
- [ ] Supporting custom graph schemas:
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
- Allow developers to provide their own defined node and edge classes when ingesting episodes
|
|
233
|
+
- Enable more flexible knowledge representation tailored to specific use cases
|
|
230
234
|
- [x] Enhancing retrieval capabilities with more robust and configurable options
|
|
231
235
|
- [ ] Expanding test coverage to ensure reliability and catch edge cases
|
|
232
236
|
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.getzep.com/">
|
|
3
|
+
<img src="https://github.com/user-attachments/assets/119c5682-9654-4257-8922-56b7cb8ffd73" width="150" alt="Zep Logo">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
6
|
|
|
7
|
+
<h1 align="center">
|
|
8
|
+
Graphiti
|
|
9
|
+
</h1>
|
|
10
|
+
<h2 align="center"> Temporal Knowledge Graphs for Agentic Applications</h2>
|
|
7
11
|
<br />
|
|
8
12
|
|
|
9
13
|
[](https://discord.com/invite/W8Kw6bsgXQ)
|
|
@@ -12,10 +16,9 @@
|
|
|
12
16
|
[](https://github.com/getzep/Graphiti/actions/workflows/typecheck.yml)
|
|
13
17
|
[](https://codespaces.new/getzep/Graphiti)
|
|
14
18
|
|
|
19
|
+
:star: *Help us reach more developers and grow the Graphiti community. Star this repo!*
|
|
15
20
|
<br />
|
|
16
21
|
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
22
|
Graphiti builds dynamic, temporally aware Knowledge Graphs that represent complex, evolving relationships between
|
|
20
23
|
entities over time. Graphiti ingests both unstructured and structured data, and the resulting graph may be queried using
|
|
21
24
|
a fusion of time, full-text, semantic, and graph algorithm approaches.
|
|
@@ -47,7 +50,8 @@ recall and state-based reasoning for both assistants and agents.
|
|
|
47
50
|
|
|
48
51
|
Graphiti powers the core of [Zep's memory layer](https://www.getzep.com) for LLM-powered Assistants and Agents.
|
|
49
52
|
|
|
50
|
-
Using Graphiti, we've demonstrated Zep is
|
|
53
|
+
Using Graphiti, we've demonstrated Zep is
|
|
54
|
+
the [State of the Art in Agent Memory](https://blog.getzep.com/state-of-the-art-agent-memory/).
|
|
51
55
|
|
|
52
56
|
Read our paper: [Zep: A Temporal Knowledge Graph Architecture for Agent Memory](https://arxiv.org/abs/2501.13956).
|
|
53
57
|
|
|
@@ -86,7 +90,7 @@ scale:
|
|
|
86
90
|
Requirements:
|
|
87
91
|
|
|
88
92
|
- Python 3.10 or higher
|
|
89
|
-
- Neo4j 5.
|
|
93
|
+
- Neo4j 5.26 or higher
|
|
90
94
|
- OpenAI API key (for LLM inference and embedding)
|
|
91
95
|
|
|
92
96
|
Optional:
|
|
@@ -111,7 +115,8 @@ poetry add graphiti-core
|
|
|
111
115
|
|
|
112
116
|
> [!IMPORTANT]
|
|
113
117
|
> Graphiti uses OpenAI for LLM inference and embedding. Ensure that an `OPENAI_API_KEY` is set in your environment.
|
|
114
|
-
> Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
|
|
118
|
+
> Support for Anthropic and Groq LLM inferences is available, too. Other LLM providers may be supported via OpenAI
|
|
119
|
+
> compatible APIs.
|
|
115
120
|
|
|
116
121
|
```python
|
|
117
122
|
from graphiti_core import Graphiti
|
|
@@ -176,7 +181,6 @@ graphiti.close()
|
|
|
176
181
|
```
|
|
177
182
|
|
|
178
183
|
## Graph Service
|
|
179
|
-
|
|
180
184
|
The `server` directory contains an API service for interacting with the Graphiti API. It is built using FastAPI.
|
|
181
185
|
|
|
182
186
|
Please see the [server README](./server/README.md) for more information.
|
|
@@ -203,8 +207,8 @@ as such this feature is off by default.
|
|
|
203
207
|
Graphiti is under active development. We aim to maintain API stability while working on:
|
|
204
208
|
|
|
205
209
|
- [ ] Supporting custom graph schemas:
|
|
206
|
-
|
|
207
|
-
|
|
210
|
+
- Allow developers to provide their own defined node and edge classes when ingesting episodes
|
|
211
|
+
- Enable more flexible knowledge representation tailored to specific use cases
|
|
208
212
|
- [x] Enhancing retrieval capabilities with more robust and configurable options
|
|
209
213
|
- [ ] Expanding test coverage to ensure reliability and catch edge cases
|
|
210
214
|
|
|
@@ -351,7 +351,10 @@ class Graphiti:
|
|
|
351
351
|
# Find relevant nodes already in the graph
|
|
352
352
|
existing_nodes_lists: list[list[EntityNode]] = list(
|
|
353
353
|
await semaphore_gather(
|
|
354
|
-
*[
|
|
354
|
+
*[
|
|
355
|
+
get_relevant_nodes(self.driver, SearchFilters(), [node])
|
|
356
|
+
for node in extracted_nodes
|
|
357
|
+
]
|
|
355
358
|
)
|
|
356
359
|
)
|
|
357
360
|
|
|
@@ -732,8 +735,8 @@ class Graphiti:
|
|
|
732
735
|
self.llm_client,
|
|
733
736
|
[source_node, target_node],
|
|
734
737
|
[
|
|
735
|
-
await get_relevant_nodes(self.driver, [source_node]),
|
|
736
|
-
await get_relevant_nodes(self.driver, [target_node]),
|
|
738
|
+
await get_relevant_nodes(self.driver, SearchFilters(), [source_node]),
|
|
739
|
+
await get_relevant_nodes(self.driver, SearchFilters(), [target_node]),
|
|
737
740
|
],
|
|
738
741
|
)
|
|
739
742
|
|
|
@@ -100,6 +100,7 @@ async def search(
|
|
|
100
100
|
query_vector,
|
|
101
101
|
group_ids,
|
|
102
102
|
config.node_config,
|
|
103
|
+
search_filter,
|
|
103
104
|
center_node_uuid,
|
|
104
105
|
bfs_origin_node_uuids,
|
|
105
106
|
config.limit,
|
|
@@ -233,6 +234,7 @@ async def node_search(
|
|
|
233
234
|
query_vector: list[float],
|
|
234
235
|
group_ids: list[str] | None,
|
|
235
236
|
config: NodeSearchConfig | None,
|
|
237
|
+
search_filter: SearchFilters,
|
|
236
238
|
center_node_uuid: str | None = None,
|
|
237
239
|
bfs_origin_node_uuids: list[str] | None = None,
|
|
238
240
|
limit=DEFAULT_SEARCH_LIMIT,
|
|
@@ -243,11 +245,13 @@ async def node_search(
|
|
|
243
245
|
search_results: list[list[EntityNode]] = list(
|
|
244
246
|
await semaphore_gather(
|
|
245
247
|
*[
|
|
246
|
-
node_fulltext_search(driver, query, group_ids, 2 * limit),
|
|
248
|
+
node_fulltext_search(driver, query, search_filter, group_ids, 2 * limit),
|
|
247
249
|
node_similarity_search(
|
|
248
|
-
driver, query_vector, group_ids, 2 * limit, config.sim_min_score
|
|
250
|
+
driver, query_vector, search_filter, group_ids, 2 * limit, config.sim_min_score
|
|
251
|
+
),
|
|
252
|
+
node_bfs_search(
|
|
253
|
+
driver, bfs_origin_node_uuids, search_filter, config.bfs_max_depth, 2 * limit
|
|
249
254
|
),
|
|
250
|
-
node_bfs_search(driver, bfs_origin_node_uuids, config.bfs_max_depth, 2 * limit),
|
|
251
255
|
]
|
|
252
256
|
)
|
|
253
257
|
)
|
|
@@ -255,7 +259,9 @@ async def node_search(
|
|
|
255
259
|
if NodeSearchMethod.bfs in config.search_methods and bfs_origin_node_uuids is None:
|
|
256
260
|
origin_node_uuids = [node.uuid for result in search_results for node in result]
|
|
257
261
|
search_results.append(
|
|
258
|
-
await node_bfs_search(
|
|
262
|
+
await node_bfs_search(
|
|
263
|
+
driver, origin_node_uuids, search_filter, config.bfs_max_depth, 2 * limit
|
|
264
|
+
)
|
|
259
265
|
)
|
|
260
266
|
|
|
261
267
|
search_result_uuids = [[node.uuid for node in result] for result in search_results]
|
|
@@ -39,18 +39,37 @@ class DateFilter(BaseModel):
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
class SearchFilters(BaseModel):
|
|
42
|
+
node_labels: list[str] | None = Field(
|
|
43
|
+
default=None, description='List of node labels to filter on'
|
|
44
|
+
)
|
|
42
45
|
valid_at: list[list[DateFilter]] | None = Field(default=None)
|
|
43
46
|
invalid_at: list[list[DateFilter]] | None = Field(default=None)
|
|
44
47
|
created_at: list[list[DateFilter]] | None = Field(default=None)
|
|
45
48
|
expired_at: list[list[DateFilter]] | None = Field(default=None)
|
|
46
49
|
|
|
47
50
|
|
|
48
|
-
def
|
|
51
|
+
def node_search_filter_query_constructor(
|
|
52
|
+
filters: SearchFilters,
|
|
53
|
+
) -> tuple[LiteralString, dict[str, Any]]:
|
|
54
|
+
filter_query: LiteralString = ''
|
|
55
|
+
filter_params: dict[str, Any] = {}
|
|
56
|
+
|
|
57
|
+
if filters.node_labels is not None:
|
|
58
|
+
node_labels = ':'.join(filters.node_labels)
|
|
59
|
+
node_label_filter = ' AND n:' + node_labels
|
|
60
|
+
filter_query += node_label_filter
|
|
61
|
+
|
|
62
|
+
return filter_query, filter_params
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def edge_search_filter_query_constructor(
|
|
66
|
+
filters: SearchFilters,
|
|
67
|
+
) -> tuple[LiteralString, dict[str, Any]]:
|
|
49
68
|
filter_query: LiteralString = ''
|
|
50
69
|
filter_params: dict[str, Any] = {}
|
|
51
70
|
|
|
52
71
|
if filters.valid_at is not None:
|
|
53
|
-
valid_at_filter = 'AND ('
|
|
72
|
+
valid_at_filter = ' AND ('
|
|
54
73
|
for i, or_list in enumerate(filters.valid_at):
|
|
55
74
|
for j, date_filter in enumerate(or_list):
|
|
56
75
|
filter_params['valid_at_' + str(j)] = date_filter.date
|
|
@@ -75,7 +94,7 @@ def search_filter_query_constructor(filters: SearchFilters) -> tuple[LiteralStri
|
|
|
75
94
|
filter_query += valid_at_filter
|
|
76
95
|
|
|
77
96
|
if filters.invalid_at is not None:
|
|
78
|
-
invalid_at_filter = 'AND ('
|
|
97
|
+
invalid_at_filter = ' AND ('
|
|
79
98
|
for i, or_list in enumerate(filters.invalid_at):
|
|
80
99
|
for j, date_filter in enumerate(or_list):
|
|
81
100
|
filter_params['invalid_at_' + str(j)] = date_filter.date
|
|
@@ -100,7 +119,7 @@ def search_filter_query_constructor(filters: SearchFilters) -> tuple[LiteralStri
|
|
|
100
119
|
filter_query += invalid_at_filter
|
|
101
120
|
|
|
102
121
|
if filters.created_at is not None:
|
|
103
|
-
created_at_filter = 'AND ('
|
|
122
|
+
created_at_filter = ' AND ('
|
|
104
123
|
for i, or_list in enumerate(filters.created_at):
|
|
105
124
|
for j, date_filter in enumerate(or_list):
|
|
106
125
|
filter_params['created_at_' + str(j)] = date_filter.date
|
|
@@ -38,7 +38,11 @@ from graphiti_core.nodes import (
|
|
|
38
38
|
get_community_node_from_record,
|
|
39
39
|
get_entity_node_from_record,
|
|
40
40
|
)
|
|
41
|
-
from graphiti_core.search.search_filters import
|
|
41
|
+
from graphiti_core.search.search_filters import (
|
|
42
|
+
SearchFilters,
|
|
43
|
+
edge_search_filter_query_constructor,
|
|
44
|
+
node_search_filter_query_constructor,
|
|
45
|
+
)
|
|
42
46
|
|
|
43
47
|
logger = logging.getLogger(__name__)
|
|
44
48
|
|
|
@@ -148,13 +152,13 @@ async def edge_fulltext_search(
|
|
|
148
152
|
if fuzzy_query == '':
|
|
149
153
|
return []
|
|
150
154
|
|
|
151
|
-
filter_query, filter_params =
|
|
155
|
+
filter_query, filter_params = edge_search_filter_query_constructor(search_filter)
|
|
152
156
|
|
|
153
157
|
cypher_query = Query(
|
|
154
158
|
"""
|
|
155
159
|
CALL db.index.fulltext.queryRelationships("edge_name_and_fact", $query, {limit: $limit})
|
|
156
160
|
YIELD relationship AS rel, score
|
|
157
|
-
MATCH (:
|
|
161
|
+
MATCH (:Entity)-[r:RELATES_TO]->(:Entity)
|
|
158
162
|
WHERE r.group_id IN $group_ids"""
|
|
159
163
|
+ filter_query
|
|
160
164
|
+ """\nWITH r, score, startNode(r) AS n, endNode(r) AS m
|
|
@@ -207,7 +211,7 @@ async def edge_similarity_search(
|
|
|
207
211
|
|
|
208
212
|
query_params: dict[str, Any] = {}
|
|
209
213
|
|
|
210
|
-
filter_query, filter_params =
|
|
214
|
+
filter_query, filter_params = edge_search_filter_query_constructor(search_filter)
|
|
211
215
|
query_params.update(filter_params)
|
|
212
216
|
|
|
213
217
|
group_filter_query: LiteralString = ''
|
|
@@ -225,8 +229,8 @@ async def edge_similarity_search(
|
|
|
225
229
|
|
|
226
230
|
query: LiteralString = (
|
|
227
231
|
"""
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
MATCH (n:Entity)-[r:RELATES_TO]->(m:Entity)
|
|
233
|
+
"""
|
|
230
234
|
+ group_filter_query
|
|
231
235
|
+ filter_query
|
|
232
236
|
+ """\nWITH DISTINCT r, vector.similarity.cosine(r.fact_embedding, $search_vector) AS score
|
|
@@ -278,7 +282,7 @@ async def edge_bfs_search(
|
|
|
278
282
|
if bfs_origin_node_uuids is None:
|
|
279
283
|
return []
|
|
280
284
|
|
|
281
|
-
filter_query, filter_params =
|
|
285
|
+
filter_query, filter_params = edge_search_filter_query_constructor(search_filter)
|
|
282
286
|
|
|
283
287
|
query = Query(
|
|
284
288
|
"""
|
|
@@ -325,6 +329,7 @@ async def edge_bfs_search(
|
|
|
325
329
|
async def node_fulltext_search(
|
|
326
330
|
driver: AsyncDriver,
|
|
327
331
|
query: str,
|
|
332
|
+
search_filter: SearchFilters,
|
|
328
333
|
group_ids: list[str] | None = None,
|
|
329
334
|
limit=RELEVANT_SCHEMA_LIMIT,
|
|
330
335
|
) -> list[EntityNode]:
|
|
@@ -333,10 +338,17 @@ async def node_fulltext_search(
|
|
|
333
338
|
if fuzzy_query == '':
|
|
334
339
|
return []
|
|
335
340
|
|
|
341
|
+
filter_query, filter_params = node_search_filter_query_constructor(search_filter)
|
|
342
|
+
|
|
336
343
|
records, _, _ = await driver.execute_query(
|
|
337
344
|
"""
|
|
338
345
|
CALL db.index.fulltext.queryNodes("node_name_and_summary", $query, {limit: $limit})
|
|
339
|
-
YIELD node AS
|
|
346
|
+
YIELD node AS node, score
|
|
347
|
+
MATCH (n:Entity)
|
|
348
|
+
WHERE n.uuid = node.uuid
|
|
349
|
+
"""
|
|
350
|
+
+ filter_query
|
|
351
|
+
+ """
|
|
340
352
|
RETURN
|
|
341
353
|
n.uuid AS uuid,
|
|
342
354
|
n.group_id AS group_id,
|
|
@@ -349,6 +361,7 @@ async def node_fulltext_search(
|
|
|
349
361
|
ORDER BY score DESC
|
|
350
362
|
LIMIT $limit
|
|
351
363
|
""",
|
|
364
|
+
filter_params,
|
|
352
365
|
query=fuzzy_query,
|
|
353
366
|
group_ids=group_ids,
|
|
354
367
|
limit=limit,
|
|
@@ -363,6 +376,7 @@ async def node_fulltext_search(
|
|
|
363
376
|
async def node_similarity_search(
|
|
364
377
|
driver: AsyncDriver,
|
|
365
378
|
search_vector: list[float],
|
|
379
|
+
search_filter: SearchFilters,
|
|
366
380
|
group_ids: list[str] | None = None,
|
|
367
381
|
limit=RELEVANT_SCHEMA_LIMIT,
|
|
368
382
|
min_score: float = DEFAULT_MIN_SCORE,
|
|
@@ -379,12 +393,16 @@ async def node_similarity_search(
|
|
|
379
393
|
group_filter_query += 'WHERE n.group_id IN $group_ids'
|
|
380
394
|
query_params['group_ids'] = group_ids
|
|
381
395
|
|
|
396
|
+
filter_query, filter_params = node_search_filter_query_constructor(search_filter)
|
|
397
|
+
query_params.update(filter_params)
|
|
398
|
+
|
|
382
399
|
records, _, _ = await driver.execute_query(
|
|
383
400
|
runtime_query
|
|
384
401
|
+ """
|
|
385
402
|
MATCH (n:Entity)
|
|
386
403
|
"""
|
|
387
404
|
+ group_filter_query
|
|
405
|
+
+ filter_query
|
|
388
406
|
+ """
|
|
389
407
|
WITH n, vector.similarity.cosine(n.name_embedding, $search_vector) AS score
|
|
390
408
|
WHERE score > $min_score
|
|
@@ -416,6 +434,7 @@ async def node_similarity_search(
|
|
|
416
434
|
async def node_bfs_search(
|
|
417
435
|
driver: AsyncDriver,
|
|
418
436
|
bfs_origin_node_uuids: list[str] | None,
|
|
437
|
+
search_filter: SearchFilters,
|
|
419
438
|
bfs_max_depth: int,
|
|
420
439
|
limit: int,
|
|
421
440
|
) -> list[EntityNode]:
|
|
@@ -423,21 +442,28 @@ async def node_bfs_search(
|
|
|
423
442
|
if bfs_origin_node_uuids is None:
|
|
424
443
|
return []
|
|
425
444
|
|
|
445
|
+
filter_query, filter_params = node_search_filter_query_constructor(search_filter)
|
|
446
|
+
|
|
426
447
|
records, _, _ = await driver.execute_query(
|
|
427
448
|
"""
|
|
428
449
|
UNWIND $bfs_origin_node_uuids AS origin_uuid
|
|
429
450
|
MATCH (origin:Entity|Episodic {uuid: origin_uuid})-[:RELATES_TO|MENTIONS]->{1,3}(n:Entity)
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
451
|
+
WHERE n.group_id = origin.group_id
|
|
452
|
+
"""
|
|
453
|
+
+ filter_query
|
|
454
|
+
+ """
|
|
455
|
+
RETURN DISTINCT
|
|
456
|
+
n.uuid As uuid,
|
|
457
|
+
n.group_id AS group_id,
|
|
458
|
+
n.name AS name,
|
|
459
|
+
n.name_embedding AS name_embedding,
|
|
460
|
+
n.created_at AS created_at,
|
|
461
|
+
n.summary AS summary,
|
|
462
|
+
labels(n) AS labels,
|
|
463
|
+
properties(n) AS attributes
|
|
464
|
+
LIMIT $limit
|
|
465
|
+
""",
|
|
466
|
+
filter_params,
|
|
441
467
|
bfs_origin_node_uuids=bfs_origin_node_uuids,
|
|
442
468
|
depth=bfs_max_depth,
|
|
443
469
|
limit=limit,
|
|
@@ -539,6 +565,7 @@ async def hybrid_node_search(
|
|
|
539
565
|
queries: list[str],
|
|
540
566
|
embeddings: list[list[float]],
|
|
541
567
|
driver: AsyncDriver,
|
|
568
|
+
search_filter: SearchFilters,
|
|
542
569
|
group_ids: list[str] | None = None,
|
|
543
570
|
limit: int = RELEVANT_SCHEMA_LIMIT,
|
|
544
571
|
) -> list[EntityNode]:
|
|
@@ -583,8 +610,14 @@ async def hybrid_node_search(
|
|
|
583
610
|
start = time()
|
|
584
611
|
results: list[list[EntityNode]] = list(
|
|
585
612
|
await semaphore_gather(
|
|
586
|
-
*[
|
|
587
|
-
|
|
613
|
+
*[
|
|
614
|
+
node_fulltext_search(driver, q, search_filter, group_ids, 2 * limit)
|
|
615
|
+
for q in queries
|
|
616
|
+
],
|
|
617
|
+
*[
|
|
618
|
+
node_similarity_search(driver, e, search_filter, group_ids, 2 * limit)
|
|
619
|
+
for e in embeddings
|
|
620
|
+
],
|
|
588
621
|
)
|
|
589
622
|
)
|
|
590
623
|
|
|
@@ -604,6 +637,7 @@ async def hybrid_node_search(
|
|
|
604
637
|
|
|
605
638
|
async def get_relevant_nodes(
|
|
606
639
|
driver: AsyncDriver,
|
|
640
|
+
search_filter: SearchFilters,
|
|
607
641
|
nodes: list[EntityNode],
|
|
608
642
|
) -> list[EntityNode]:
|
|
609
643
|
"""
|
|
@@ -635,6 +669,7 @@ async def get_relevant_nodes(
|
|
|
635
669
|
[node.name for node in nodes],
|
|
636
670
|
[node.name_embedding for node in nodes if node.name_embedding is not None],
|
|
637
671
|
driver,
|
|
672
|
+
search_filter,
|
|
638
673
|
[node.group_id for node in nodes],
|
|
639
674
|
)
|
|
640
675
|
|
|
@@ -37,6 +37,7 @@ from graphiti_core.models.nodes.node_db_queries import (
|
|
|
37
37
|
EPISODIC_NODE_SAVE_BULK,
|
|
38
38
|
)
|
|
39
39
|
from graphiti_core.nodes import EntityNode, EpisodeType, EpisodicNode
|
|
40
|
+
from graphiti_core.search.search_filters import SearchFilters
|
|
40
41
|
from graphiti_core.search.search_utils import get_relevant_edges, get_relevant_nodes
|
|
41
42
|
from graphiti_core.utils.datetime_utils import utc_now
|
|
42
43
|
from graphiti_core.utils.maintenance.edge_operations import (
|
|
@@ -188,7 +189,7 @@ async def dedupe_nodes_bulk(
|
|
|
188
189
|
|
|
189
190
|
existing_nodes_chunks: list[list[EntityNode]] = list(
|
|
190
191
|
await semaphore_gather(
|
|
191
|
-
*[get_relevant_nodes(driver, node_chunk) for node_chunk in node_chunks]
|
|
192
|
+
*[get_relevant_nodes(driver, SearchFilters(), node_chunk) for node_chunk in node_chunks]
|
|
192
193
|
)
|
|
193
194
|
)
|
|
194
195
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/bge_reranker_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/cross_encoder/openai_reranker_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/llm_client/openai_generic_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/community_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/edge_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/graph_data_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/node_operations.py
RENAMED
|
File without changes
|
{graphiti_core-0.7.0 → graphiti_core-0.7.2}/graphiti_core/utils/maintenance/temporal_operations.py
RENAMED
|
File without changes
|
|
File without changes
|