graphiti-core 0.21.0rc3__py3-none-any.whl → 0.21.0rc5__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.
- graphiti_core/driver/driver.py +9 -0
- graphiti_core/driver/falkordb_driver.py +111 -0
- graphiti_core/graph_queries.py +35 -6
- graphiti_core/graphiti.py +2 -2
- graphiti_core/helpers.py +2 -2
- graphiti_core/search/search_utils.py +2 -0
- graphiti_core/utils/maintenance/node_operations.py +6 -2
- {graphiti_core-0.21.0rc3.dist-info → graphiti_core-0.21.0rc5.dist-info}/METADATA +1 -1
- {graphiti_core-0.21.0rc3.dist-info → graphiti_core-0.21.0rc5.dist-info}/RECORD +11 -11
- {graphiti_core-0.21.0rc3.dist-info → graphiti_core-0.21.0rc5.dist-info}/WHEEL +0 -0
- {graphiti_core-0.21.0rc3.dist-info → graphiti_core-0.21.0rc5.dist-info}/licenses/LICENSE +0 -0
graphiti_core/driver/driver.py
CHANGED
|
@@ -311,3 +311,12 @@ class GraphDriver(ABC):
|
|
|
311
311
|
return success if failed == 0 else success
|
|
312
312
|
|
|
313
313
|
return 0
|
|
314
|
+
|
|
315
|
+
def build_fulltext_query(
|
|
316
|
+
self, query: str, group_ids: list[str] | None = None, max_query_length: int = 128
|
|
317
|
+
) -> str:
|
|
318
|
+
"""
|
|
319
|
+
Specific fulltext query builder for database providers.
|
|
320
|
+
Only implemented by providers that need custom fulltext query building.
|
|
321
|
+
"""
|
|
322
|
+
raise NotImplementedError(f'build_fulltext_query not implemented for {self.provider}')
|
|
@@ -36,6 +36,42 @@ from graphiti_core.utils.datetime_utils import convert_datetimes_to_strings
|
|
|
36
36
|
|
|
37
37
|
logger = logging.getLogger(__name__)
|
|
38
38
|
|
|
39
|
+
STOPWORDS = [
|
|
40
|
+
'a',
|
|
41
|
+
'is',
|
|
42
|
+
'the',
|
|
43
|
+
'an',
|
|
44
|
+
'and',
|
|
45
|
+
'are',
|
|
46
|
+
'as',
|
|
47
|
+
'at',
|
|
48
|
+
'be',
|
|
49
|
+
'but',
|
|
50
|
+
'by',
|
|
51
|
+
'for',
|
|
52
|
+
'if',
|
|
53
|
+
'in',
|
|
54
|
+
'into',
|
|
55
|
+
'it',
|
|
56
|
+
'no',
|
|
57
|
+
'not',
|
|
58
|
+
'of',
|
|
59
|
+
'on',
|
|
60
|
+
'or',
|
|
61
|
+
'such',
|
|
62
|
+
'that',
|
|
63
|
+
'their',
|
|
64
|
+
'then',
|
|
65
|
+
'there',
|
|
66
|
+
'these',
|
|
67
|
+
'they',
|
|
68
|
+
'this',
|
|
69
|
+
'to',
|
|
70
|
+
'was',
|
|
71
|
+
'will',
|
|
72
|
+
'with',
|
|
73
|
+
]
|
|
74
|
+
|
|
39
75
|
|
|
40
76
|
class FalkorDriverSession(GraphDriverSession):
|
|
41
77
|
provider = GraphProvider.FALKORDB
|
|
@@ -167,3 +203,78 @@ class FalkorDriver(GraphDriver):
|
|
|
167
203
|
cloned = FalkorDriver(falkor_db=self.client, database=database)
|
|
168
204
|
|
|
169
205
|
return cloned
|
|
206
|
+
|
|
207
|
+
def sanitize(self, query: str) -> str:
|
|
208
|
+
"""
|
|
209
|
+
Replace FalkorDB special characters with whitespace.
|
|
210
|
+
Based on FalkorDB tokenization rules: ,.<>{}[]"':;!@#$%^&*()-+=~
|
|
211
|
+
"""
|
|
212
|
+
# FalkorDB separator characters that break text into tokens
|
|
213
|
+
separator_map = str.maketrans(
|
|
214
|
+
{
|
|
215
|
+
',': ' ',
|
|
216
|
+
'.': ' ',
|
|
217
|
+
'<': ' ',
|
|
218
|
+
'>': ' ',
|
|
219
|
+
'{': ' ',
|
|
220
|
+
'}': ' ',
|
|
221
|
+
'[': ' ',
|
|
222
|
+
']': ' ',
|
|
223
|
+
'"': ' ',
|
|
224
|
+
"'": ' ',
|
|
225
|
+
':': ' ',
|
|
226
|
+
';': ' ',
|
|
227
|
+
'!': ' ',
|
|
228
|
+
'@': ' ',
|
|
229
|
+
'#': ' ',
|
|
230
|
+
'$': ' ',
|
|
231
|
+
'%': ' ',
|
|
232
|
+
'^': ' ',
|
|
233
|
+
'&': ' ',
|
|
234
|
+
'*': ' ',
|
|
235
|
+
'(': ' ',
|
|
236
|
+
')': ' ',
|
|
237
|
+
'-': ' ',
|
|
238
|
+
'+': ' ',
|
|
239
|
+
'=': ' ',
|
|
240
|
+
'~': ' ',
|
|
241
|
+
'?': ' ',
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
sanitized = query.translate(separator_map)
|
|
245
|
+
# Clean up multiple spaces
|
|
246
|
+
sanitized = ' '.join(sanitized.split())
|
|
247
|
+
return sanitized
|
|
248
|
+
|
|
249
|
+
def build_fulltext_query(
|
|
250
|
+
self, query: str, group_ids: list[str] | None = None, max_query_length: int = 128
|
|
251
|
+
) -> str:
|
|
252
|
+
"""
|
|
253
|
+
Build a fulltext query string for FalkorDB using RedisSearch syntax.
|
|
254
|
+
FalkorDB uses RedisSearch-like syntax where:
|
|
255
|
+
- Field queries use @ prefix: @field:value
|
|
256
|
+
- Multiple values for same field: (@field:value1|value2)
|
|
257
|
+
- Text search doesn't need @ prefix for content fields
|
|
258
|
+
- AND is implicit with space: (@group_id:value) (text)
|
|
259
|
+
- OR uses pipe within parentheses: (@group_id:value1|value2)
|
|
260
|
+
"""
|
|
261
|
+
if group_ids is None or len(group_ids) == 0:
|
|
262
|
+
group_filter = ''
|
|
263
|
+
else:
|
|
264
|
+
group_values = '|'.join(group_ids)
|
|
265
|
+
group_filter = f'(@group_id:{group_values})'
|
|
266
|
+
|
|
267
|
+
sanitized_query = self.sanitize(query)
|
|
268
|
+
|
|
269
|
+
# Remove stopwords from the sanitized query
|
|
270
|
+
query_words = sanitized_query.split()
|
|
271
|
+
filtered_words = [word for word in query_words if word.lower() not in STOPWORDS]
|
|
272
|
+
sanitized_query = ' | '.join(filtered_words)
|
|
273
|
+
|
|
274
|
+
# If the query is too long return no query
|
|
275
|
+
if len(sanitized_query.split(' ')) + len(group_ids or '') >= max_query_length:
|
|
276
|
+
return ''
|
|
277
|
+
|
|
278
|
+
full_query = group_filter + ' (' + sanitized_query + ')'
|
|
279
|
+
|
|
280
|
+
return full_query
|
graphiti_core/graph_queries.py
CHANGED
|
@@ -71,12 +71,41 @@ def get_range_indices(provider: GraphProvider) -> list[LiteralString]:
|
|
|
71
71
|
|
|
72
72
|
def get_fulltext_indices(provider: GraphProvider) -> list[LiteralString]:
|
|
73
73
|
if provider == GraphProvider.FALKORDB:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
from typing import cast
|
|
75
|
+
|
|
76
|
+
from graphiti_core.driver.falkordb_driver import STOPWORDS
|
|
77
|
+
|
|
78
|
+
# Convert to string representation for embedding in queries
|
|
79
|
+
stopwords_str = str(STOPWORDS)
|
|
80
|
+
|
|
81
|
+
# Use type: ignore to satisfy LiteralString requirement while maintaining single source of truth
|
|
82
|
+
return cast(
|
|
83
|
+
list[LiteralString],
|
|
84
|
+
[
|
|
85
|
+
f"""CALL db.idx.fulltext.createNodeIndex(
|
|
86
|
+
{{
|
|
87
|
+
label: 'Episodic',
|
|
88
|
+
stopwords: {stopwords_str}
|
|
89
|
+
}},
|
|
90
|
+
'content', 'source', 'source_description', 'group_id'
|
|
91
|
+
)""",
|
|
92
|
+
f"""CALL db.idx.fulltext.createNodeIndex(
|
|
93
|
+
{{
|
|
94
|
+
label: 'Entity',
|
|
95
|
+
stopwords: {stopwords_str}
|
|
96
|
+
}},
|
|
97
|
+
'name', 'summary', 'group_id'
|
|
98
|
+
)""",
|
|
99
|
+
f"""CALL db.idx.fulltext.createNodeIndex(
|
|
100
|
+
{{
|
|
101
|
+
label: 'Community',
|
|
102
|
+
stopwords: {stopwords_str}
|
|
103
|
+
}},
|
|
104
|
+
'name', 'group_id'
|
|
105
|
+
)""",
|
|
106
|
+
"""CREATE FULLTEXT INDEX FOR ()-[e:RELATES_TO]-() ON (e.name, e.fact, e.group_id)""",
|
|
107
|
+
],
|
|
108
|
+
)
|
|
80
109
|
|
|
81
110
|
if provider == GraphProvider.KUZU:
|
|
82
111
|
return [
|
graphiti_core/graphiti.py
CHANGED
|
@@ -456,12 +456,12 @@ class Graphiti:
|
|
|
456
456
|
start = time()
|
|
457
457
|
now = utc_now()
|
|
458
458
|
|
|
459
|
-
# if group_id is None, use the default group id by the provider
|
|
460
|
-
group_id = group_id or get_default_group_id(self.driver.provider)
|
|
461
459
|
validate_entity_types(entity_types)
|
|
462
460
|
|
|
463
461
|
validate_excluded_entity_types(excluded_entity_types, entity_types)
|
|
464
462
|
validate_group_id(group_id)
|
|
463
|
+
# if group_id is None, use the default group id by the provider
|
|
464
|
+
group_id = group_id or get_default_group_id(self.driver.provider)
|
|
465
465
|
|
|
466
466
|
previous_episodes = (
|
|
467
467
|
await self.retrieve_episodes(
|
graphiti_core/helpers.py
CHANGED
|
@@ -54,7 +54,7 @@ def get_default_group_id(provider: GraphProvider) -> str:
|
|
|
54
54
|
For most databases, the default group id is an empty string, while there are database types that require a specific default group id.
|
|
55
55
|
"""
|
|
56
56
|
if provider == GraphProvider.FALKORDB:
|
|
57
|
-
return '_'
|
|
57
|
+
return '\\_'
|
|
58
58
|
else:
|
|
59
59
|
return ''
|
|
60
60
|
|
|
@@ -116,7 +116,7 @@ async def semaphore_gather(
|
|
|
116
116
|
return await asyncio.gather(*(_wrap_coroutine(coroutine) for coroutine in coroutines))
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def validate_group_id(group_id: str) -> bool:
|
|
119
|
+
def validate_group_id(group_id: str | None) -> bool:
|
|
120
120
|
"""
|
|
121
121
|
Validate that a group_id contains only ASCII alphanumeric characters, dashes, and underscores.
|
|
122
122
|
|
|
@@ -92,6 +92,8 @@ def fulltext_query(query: str, group_ids: list[str] | None, driver: GraphDriver)
|
|
|
92
92
|
if len(query.split(' ')) > MAX_QUERY_LENGTH:
|
|
93
93
|
return ''
|
|
94
94
|
return query
|
|
95
|
+
elif driver.provider == GraphProvider.FALKORDB:
|
|
96
|
+
return driver.build_fulltext_query(query, group_ids, MAX_QUERY_LENGTH)
|
|
95
97
|
group_ids_filter_list = (
|
|
96
98
|
[driver.fulltext_syntax + f'group_id:"{g}"' for g in group_ids]
|
|
97
99
|
if group_ids is not None
|
|
@@ -362,6 +362,10 @@ async def extract_attributes_from_node(
|
|
|
362
362
|
'ensure_ascii': ensure_ascii,
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
has_entity_attributes: bool = bool(
|
|
366
|
+
entity_type is not None and len(entity_type.model_fields) != 0
|
|
367
|
+
)
|
|
368
|
+
|
|
365
369
|
llm_response = (
|
|
366
370
|
(
|
|
367
371
|
await llm_client.generate_response(
|
|
@@ -370,7 +374,7 @@ async def extract_attributes_from_node(
|
|
|
370
374
|
model_size=ModelSize.small,
|
|
371
375
|
)
|
|
372
376
|
)
|
|
373
|
-
if
|
|
377
|
+
if has_entity_attributes
|
|
374
378
|
else {}
|
|
375
379
|
)
|
|
376
380
|
|
|
@@ -380,7 +384,7 @@ async def extract_attributes_from_node(
|
|
|
380
384
|
model_size=ModelSize.small,
|
|
381
385
|
)
|
|
382
386
|
|
|
383
|
-
if entity_type is not None:
|
|
387
|
+
if has_entity_attributes and entity_type is not None:
|
|
384
388
|
entity_type(**llm_response)
|
|
385
389
|
|
|
386
390
|
node.summary = summary_response.get('summary', '')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: graphiti-core
|
|
3
|
-
Version: 0.21.
|
|
3
|
+
Version: 0.21.0rc5
|
|
4
4
|
Summary: A temporal graph building library
|
|
5
5
|
Project-URL: Homepage, https://help.getzep.com/graphiti/graphiti/overview
|
|
6
6
|
Project-URL: Repository, https://github.com/getzep/graphiti
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
graphiti_core/__init__.py,sha256=e5SWFkRiaUwfprYIeIgVIh7JDedNiloZvd3roU-0aDY,55
|
|
2
2
|
graphiti_core/edges.py,sha256=PhJm_s28cHLEaIqcw66wP16hOq4P4bVQbC_sESHQkXU,20919
|
|
3
3
|
graphiti_core/errors.py,sha256=cH_v9TPgEPeQE6GFOHIg5TvejpUCBddGarMY2Whxbwc,2707
|
|
4
|
-
graphiti_core/graph_queries.py,sha256=
|
|
5
|
-
graphiti_core/graphiti.py,sha256=
|
|
4
|
+
graphiti_core/graph_queries.py,sha256=ZWMqAo5pwb8PO5ddg4zZ0ArhHWuWV42g3R9ULIxsHOs,8058
|
|
5
|
+
graphiti_core/graphiti.py,sha256=Uxppvzjc-jFO6JCRE3PUlU5B5zUo-jBrC02uETb0-x0,42072
|
|
6
6
|
graphiti_core/graphiti_types.py,sha256=C_p2XwScQlCzo7ets097TrSLs9ATxPZQ4WCsxDS7QHc,1066
|
|
7
|
-
graphiti_core/helpers.py,sha256=
|
|
7
|
+
graphiti_core/helpers.py,sha256=q8kbL9gz8igdlh-oMUS-ylUyeMlXZb-ccf-HQkrES_0,5184
|
|
8
8
|
graphiti_core/nodes.py,sha256=wYLQcVEXvQMxTpTc9LWSoPTzzaoUOm0rl07c9wS1XSY,30323
|
|
9
9
|
graphiti_core/py.typed,sha256=vlmmzQOt7bmeQl9L3XJP4W6Ry0iiELepnOrinKz5KQg,79
|
|
10
10
|
graphiti_core/cross_encoder/__init__.py,sha256=hry59vz21x-AtGZ0MJ7ugw0HTwJkXiddpp_Yqnwsen0,723
|
|
@@ -13,8 +13,8 @@ graphiti_core/cross_encoder/client.py,sha256=KLsbfWKOEaAV3adFe3XZlAeb-gje9_sVKCV
|
|
|
13
13
|
graphiti_core/cross_encoder/gemini_reranker_client.py,sha256=hmITG5YIib52nrKvINwRi4xTfAO1U4jCCaEVIwImHw0,6208
|
|
14
14
|
graphiti_core/cross_encoder/openai_reranker_client.py,sha256=WHMl6Q6gEslR2EzjwpFSZt2Kh6bnu8alkLvzmi0MDtg,4674
|
|
15
15
|
graphiti_core/driver/__init__.py,sha256=kCWimqQU19airu5gKwCmZtZuXkDfaQfKSUhMDoL-rTA,626
|
|
16
|
-
graphiti_core/driver/driver.py,sha256=
|
|
17
|
-
graphiti_core/driver/falkordb_driver.py,sha256=
|
|
16
|
+
graphiti_core/driver/driver.py,sha256=EO9Aj5O2vpH7iyvQQcE5uJGQ8eA-_i6f8NwfAlW8r74,10831
|
|
17
|
+
graphiti_core/driver/falkordb_driver.py,sha256=Q-dImfK4O2bkikqFzo0Wg2g7iFFRSuzy_c6u82tX6-M,9361
|
|
18
18
|
graphiti_core/driver/kuzu_driver.py,sha256=RcWu8E0CCdofrFe34NmCeqfuhaZr_7ZN5jqDkI3VQMI,5453
|
|
19
19
|
graphiti_core/driver/neo4j_driver.py,sha256=E93PdOZaH7wzEbIfoiDSYht49jr6zSzvMMyo1INGEOw,4096
|
|
20
20
|
graphiti_core/driver/neptune_driver.py,sha256=akNLHhFHPEeQu-xO3PM51RomklntT6k5eA2CQ4AFbCc,10311
|
|
@@ -60,7 +60,7 @@ graphiti_core/search/search_config.py,sha256=v_rUHsu1yo5OuPfEm21lSuXexQs-o8qYwSS
|
|
|
60
60
|
graphiti_core/search/search_config_recipes.py,sha256=4GquRphHhJlpXQhAZOySYnCzBWYoTwxlJj44eTOavZQ,7443
|
|
61
61
|
graphiti_core/search/search_filters.py,sha256=DOAmYkc6A0z20EZId5fJZj1RvLz4WeQcoPANk9k-Sh8,10304
|
|
62
62
|
graphiti_core/search/search_helpers.py,sha256=wj3ARlCNnZixNNntgCdAqzGoE4de4lW3r4rSG-3WyGw,2877
|
|
63
|
-
graphiti_core/search/search_utils.py,sha256=
|
|
63
|
+
graphiti_core/search/search_utils.py,sha256=ak1aBeKNuxS7szydNHwva2ABWSRlQ0S_v8ZOx7k0wc4,76958
|
|
64
64
|
graphiti_core/telemetry/__init__.py,sha256=5kALLDlU9bb2v19CdN7qVANsJWyfnL9E60J6FFgzm3o,226
|
|
65
65
|
graphiti_core/telemetry/telemetry.py,sha256=47LrzOVBCcZxsYPsnSxWFiztHoxYKKxPwyRX0hnbDGc,3230
|
|
66
66
|
graphiti_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -70,11 +70,11 @@ graphiti_core/utils/maintenance/__init__.py,sha256=vW4H1KyapTl-OOz578uZABYcpND4w
|
|
|
70
70
|
graphiti_core/utils/maintenance/community_operations.py,sha256=XMiokEemn96GlvjkOvbo9hIX04Fea3eVj408NHG5P4o,11042
|
|
71
71
|
graphiti_core/utils/maintenance/edge_operations.py,sha256=sejfmlbXCiMFcLAKFsw70_FHY1lVX0tLpdk4UCzuU-4,21418
|
|
72
72
|
graphiti_core/utils/maintenance/graph_data_operations.py,sha256=42icj3S_ELAJ-NK3jVS_rg_243dmnaZOyUitJj_uJ-M,6085
|
|
73
|
-
graphiti_core/utils/maintenance/node_operations.py,sha256=
|
|
73
|
+
graphiti_core/utils/maintenance/node_operations.py,sha256=vKvJeg8SATM2axfUrWGIl4Dbhu35Sj_WPoxUHbabrs4,13786
|
|
74
74
|
graphiti_core/utils/maintenance/temporal_operations.py,sha256=IIaVtShpVkOYe6haxz3a1x3v54-MzaEXG8VsxFUNeoY,3582
|
|
75
75
|
graphiti_core/utils/maintenance/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
76
76
|
graphiti_core/utils/ontology_utils/entity_types_utils.py,sha256=4eVgxLWY6Q8k9cRJ5pW59IYF--U4nXZsZIGOVb_yHfQ,1285
|
|
77
|
-
graphiti_core-0.21.
|
|
78
|
-
graphiti_core-0.21.
|
|
79
|
-
graphiti_core-0.21.
|
|
80
|
-
graphiti_core-0.21.
|
|
77
|
+
graphiti_core-0.21.0rc5.dist-info/METADATA,sha256=4lD2ulRL9RzAlwQf-LAdSuOovBKeXxsQpr6EKwJClFI,26933
|
|
78
|
+
graphiti_core-0.21.0rc5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
79
|
+
graphiti_core-0.21.0rc5.dist-info/licenses/LICENSE,sha256=KCUwCyDXuVEgmDWkozHyniRyWjnWUWjkuDHfU6o3JlA,11325
|
|
80
|
+
graphiti_core-0.21.0rc5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|