graphrag_sdk 0.2.0__tar.gz → 0.2.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.
- graphrag_sdk-0.2.2/LICENSE +21 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/PKG-INFO +17 -13
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/README.md +9 -9
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/agents/agent.py +2 -5
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/agents/kg_agent.py +5 -7
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/chat_session.py +4 -2
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/fixtures/prompts.py +61 -13
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/kg.py +0 -49
- graphrag_sdk-0.2.2/graphrag_sdk/models/azure_openai.py +229 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/models/gemini.py +12 -6
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/models/model.py +16 -13
- graphrag_sdk-0.2.2/graphrag_sdk/models/ollama.py +218 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/models/openai.py +13 -37
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/orchestrator_runner.py +3 -3
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/step.py +0 -1
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/steps/agent.py +2 -8
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/steps/summary.py +0 -1
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/steps/user_input.py +0 -1
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/steps/extract_data_step.py +14 -8
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/steps/graph_query_step.py +6 -1
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/pyproject.toml +4 -4
- graphrag_sdk-0.2.0/graphrag_sdk/models/ollama.py +0 -119
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/__init__.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/agents/__init__.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/attribute.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/__init__.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/csv.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/html.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/jsonl.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/pdf.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/text.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/document_loaders/url.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/entity.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/fixtures/regex.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/helpers.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/model_config.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/models/__init__.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/ontology.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/__init__.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/execution_plan.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/orchestrator.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/orchestrator_decision.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/step_result.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/steps/__init__.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/orchestrator/steps/parallel.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/relation.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/source.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/steps/Step.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/steps/create_ontology_step.py +0 -0
- {graphrag_sdk-0.2.0 → graphrag_sdk-0.2.2}/graphrag_sdk/steps/qa_step.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 FalkorDB
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: graphrag_sdk
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary:
|
|
5
5
|
Home-page: http://RAG-SDK.readthedocs.io
|
|
6
6
|
License: MIT
|
|
7
7
|
Keywords: RAG,Graph-RAG,KnowledgeGraph
|
|
8
8
|
Author: FalkorDB
|
|
9
9
|
Author-email: info@falkordb.com
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.9.0,<4.0.0
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
16
|
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
18
|
Requires-Dist: backoff (>=2.2.1,<3.0.0)
|
|
15
19
|
Requires-Dist: bs4 (>=0.0.2,<0.0.3)
|
|
16
|
-
Requires-Dist: falkordb (>=1.0.
|
|
20
|
+
Requires-Dist: falkordb (>=1.0.9,<2.0.0)
|
|
17
21
|
Requires-Dist: fix-busted-json (>=0.0.18,<0.0.19)
|
|
18
22
|
Requires-Dist: google-generativeai (>=0.8.1,<0.9.0)
|
|
19
23
|
Requires-Dist: ipykernel (>=6.29.5,<7.0.0)
|
|
@@ -25,14 +29,17 @@ Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
|
|
25
29
|
Requires-Dist: ratelimit (>=2.2.1,<3.0.0)
|
|
26
30
|
Requires-Dist: typing-extensions (>=4.12.1,<5.0.0)
|
|
27
31
|
Requires-Dist: vertexai (>=1.49.0,<2.0.0)
|
|
28
|
-
Project-URL: Repository, https://github.com/FalkorDB/
|
|
32
|
+
Project-URL: Repository, https://github.com/FalkorDB/GraphRAG-SDK
|
|
29
33
|
Description-Content-Type: text/markdown
|
|
30
34
|
|
|
35
|
+
[](https://hub.docker.com/r/falkordb/falkordb/)
|
|
36
|
+
[](https://pypi.org/project/graphrag_sdk/)
|
|
37
|
+
[](https://discord.gg/6M4QwDXn2w)
|
|
38
|
+
[](code_of_conduct.md)
|
|
39
|
+
|
|
31
40
|
# GraphRAG-SDK
|
|
32
41
|
|
|
33
42
|
[](https://app.falkordb.cloud)
|
|
34
|
-
[](https://hub.docker.com/r/falkordb/falkordb/)
|
|
35
|
-
[](https://discord.gg/6M4QwDXn2w)
|
|
36
43
|
|
|
37
44
|
GraphRAG-SDK is a comprehensive solution for building Graph Retrieval-Augmented Generation (GraphRAG) applications, leveraging [FalkorDB](https://www.falkordb.com/) for optimal performance.
|
|
38
45
|
|
|
@@ -91,10 +98,10 @@ The following example demonstrates the basic usage of this SDK to create a Graph
|
|
|
91
98
|
```python
|
|
92
99
|
from dotenv import load_dotenv
|
|
93
100
|
|
|
94
|
-
from graphrag_sdk.
|
|
101
|
+
from graphrag_sdk.source import URL
|
|
95
102
|
from graphrag_sdk import KnowledgeGraph, Ontology
|
|
96
103
|
from graphrag_sdk.models.openai import OpenAiGenerativeModel
|
|
97
|
-
from graphrag_sdk.
|
|
104
|
+
from graphrag_sdk.model_config import KnowledgeGraphModelConfig
|
|
98
105
|
load_dotenv()
|
|
99
106
|
|
|
100
107
|
# Import Data
|
|
@@ -150,7 +157,7 @@ The SDK supports the following file formats:
|
|
|
150
157
|
|
|
151
158
|
```python
|
|
152
159
|
import os
|
|
153
|
-
from graphrag_sdk.
|
|
160
|
+
from graphrag_sdk.source import Source
|
|
154
161
|
|
|
155
162
|
src_files = "data_folder"
|
|
156
163
|
sources = []
|
|
@@ -224,12 +231,9 @@ You can update the KG at any time by processing more sources with the `process_s
|
|
|
224
231
|
|
|
225
232
|
### Graph RAG
|
|
226
233
|
|
|
227
|
-
At this point, you have a Knowledge Graph that can be queried using this SDK.
|
|
234
|
+
At this point, you have a Knowledge Graph that can be queried using this SDK. Use the method `chat_session` for start a conversation.
|
|
228
235
|
|
|
229
236
|
```python
|
|
230
|
-
# Single question.
|
|
231
|
-
response = kg.ask("What were the last five fights? When were they? How many rounds did they have?")
|
|
232
|
-
print(response)
|
|
233
237
|
|
|
234
238
|
# Conversation.
|
|
235
239
|
chat = kg.chat_session()
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
[](https://hub.docker.com/r/falkordb/falkordb/)
|
|
2
|
+
[](https://pypi.org/project/graphrag_sdk/)
|
|
3
|
+
[](https://discord.gg/6M4QwDXn2w)
|
|
4
|
+
[](code_of_conduct.md)
|
|
5
|
+
|
|
1
6
|
# GraphRAG-SDK
|
|
2
7
|
|
|
3
8
|
[](https://app.falkordb.cloud)
|
|
4
|
-
[](https://hub.docker.com/r/falkordb/falkordb/)
|
|
5
|
-
[](https://discord.gg/6M4QwDXn2w)
|
|
6
9
|
|
|
7
10
|
GraphRAG-SDK is a comprehensive solution for building Graph Retrieval-Augmented Generation (GraphRAG) applications, leveraging [FalkorDB](https://www.falkordb.com/) for optimal performance.
|
|
8
11
|
|
|
@@ -61,10 +64,10 @@ The following example demonstrates the basic usage of this SDK to create a Graph
|
|
|
61
64
|
```python
|
|
62
65
|
from dotenv import load_dotenv
|
|
63
66
|
|
|
64
|
-
from graphrag_sdk.
|
|
67
|
+
from graphrag_sdk.source import URL
|
|
65
68
|
from graphrag_sdk import KnowledgeGraph, Ontology
|
|
66
69
|
from graphrag_sdk.models.openai import OpenAiGenerativeModel
|
|
67
|
-
from graphrag_sdk.
|
|
70
|
+
from graphrag_sdk.model_config import KnowledgeGraphModelConfig
|
|
68
71
|
load_dotenv()
|
|
69
72
|
|
|
70
73
|
# Import Data
|
|
@@ -120,7 +123,7 @@ The SDK supports the following file formats:
|
|
|
120
123
|
|
|
121
124
|
```python
|
|
122
125
|
import os
|
|
123
|
-
from graphrag_sdk.
|
|
126
|
+
from graphrag_sdk.source import Source
|
|
124
127
|
|
|
125
128
|
src_files = "data_folder"
|
|
126
129
|
sources = []
|
|
@@ -194,12 +197,9 @@ You can update the KG at any time by processing more sources with the `process_s
|
|
|
194
197
|
|
|
195
198
|
### Graph RAG
|
|
196
199
|
|
|
197
|
-
At this point, you have a Knowledge Graph that can be queried using this SDK.
|
|
200
|
+
At this point, you have a Knowledge Graph that can be queried using this SDK. Use the method `chat_session` for start a conversation.
|
|
198
201
|
|
|
199
202
|
```python
|
|
200
|
-
# Single question.
|
|
201
|
-
response = kg.ask("What were the last five fights? When were they? How many rounds did they have?")
|
|
202
|
-
print(response)
|
|
203
203
|
|
|
204
204
|
# Conversation.
|
|
205
205
|
chat = kg.chat_session()
|
|
@@ -144,18 +144,15 @@ class Agent(ABC):
|
|
|
144
144
|
pass
|
|
145
145
|
|
|
146
146
|
@abstractmethod
|
|
147
|
-
def run(
|
|
148
|
-
self, params: dict, session: GenerativeModelChatSession
|
|
149
|
-
) -> tuple[str, GenerativeModelChatSession]:
|
|
147
|
+
def run(self, params: dict) -> str:
|
|
150
148
|
"""
|
|
151
149
|
Run the agent with the given parameters and chat session.
|
|
152
150
|
|
|
153
151
|
Args:
|
|
154
152
|
params (Dict): The parameters for the agent.
|
|
155
|
-
session (GenerativeModelChatSession): The chat session.
|
|
156
153
|
|
|
157
154
|
Returns:
|
|
158
|
-
|
|
155
|
+
str: The agent's response.
|
|
159
156
|
"""
|
|
160
157
|
pass
|
|
161
158
|
|
|
@@ -43,6 +43,7 @@ class KGAgent(Agent):
|
|
|
43
43
|
self.agent_id = agent_id
|
|
44
44
|
self.introduction = introduction
|
|
45
45
|
self.kg = kg
|
|
46
|
+
self.chat_session = self._kg.chat_session()
|
|
46
47
|
|
|
47
48
|
@property
|
|
48
49
|
def agent_id(self) -> str:
|
|
@@ -123,22 +124,19 @@ class KGAgent(Agent):
|
|
|
123
124
|
"""
|
|
124
125
|
self._kg = value
|
|
125
126
|
|
|
126
|
-
def run(
|
|
127
|
-
self, params: dict, session: GenerativeModelChatSession | None = None
|
|
128
|
-
) -> tuple[str, GenerativeModelChatSession]:
|
|
127
|
+
def run(self, params: dict) -> str:
|
|
129
128
|
"""
|
|
130
129
|
Ask the agent a question.
|
|
131
130
|
|
|
132
131
|
Args:
|
|
133
132
|
params (dict): The parameters for the agent.
|
|
134
|
-
session (GenerativeModelChatSession | None): The chat session to use for the agent. Defaults to None.
|
|
135
133
|
|
|
136
134
|
Returns:
|
|
137
|
-
|
|
135
|
+
str: The agent's response.
|
|
138
136
|
|
|
139
137
|
"""
|
|
140
|
-
|
|
141
|
-
return
|
|
138
|
+
output = self.chat_session.send_message(params["prompt"])
|
|
139
|
+
return output
|
|
142
140
|
|
|
143
141
|
def __repr__(self):
|
|
144
142
|
"""
|
|
@@ -52,6 +52,7 @@ class ChatSession:
|
|
|
52
52
|
self.qa_chat_session = model_config.qa.with_system_instruction(
|
|
53
53
|
GRAPH_QA_SYSTEM
|
|
54
54
|
).start_chat()
|
|
55
|
+
self.last_answer = None
|
|
55
56
|
|
|
56
57
|
def send_message(self, message: str):
|
|
57
58
|
"""
|
|
@@ -67,6 +68,7 @@ class ChatSession:
|
|
|
67
68
|
graph=self.graph,
|
|
68
69
|
chat_session=self.cypher_chat_session,
|
|
69
70
|
ontology=self.ontology,
|
|
71
|
+
last_answer=self.last_answer,
|
|
70
72
|
)
|
|
71
73
|
|
|
72
74
|
(context, cypher) = cypher_step.run(message)
|
|
@@ -79,5 +81,5 @@ class ChatSession:
|
|
|
79
81
|
)
|
|
80
82
|
|
|
81
83
|
answer = qa_step.run(message, cypher, context)
|
|
82
|
-
|
|
83
|
-
return answer
|
|
84
|
+
self.last_answer = answer
|
|
85
|
+
return answer
|
|
@@ -188,7 +188,7 @@ Raw text:
|
|
|
188
188
|
"""
|
|
189
189
|
|
|
190
190
|
BOUNDARIES_PREFIX = """
|
|
191
|
-
Use the following instructions as boundaries for the ontology extraction process
|
|
191
|
+
Use the following instructions as boundaries for the ontology extraction process:
|
|
192
192
|
{user_boundaries}
|
|
193
193
|
"""
|
|
194
194
|
|
|
@@ -330,7 +330,7 @@ Schema:
|
|
|
330
330
|
}
|
|
331
331
|
```
|
|
332
332
|
|
|
333
|
-
|
|
333
|
+
Output example:
|
|
334
334
|
```{"entities":[{"label":"Person","attributes":{"name":"John Doe","age":30}},{"label":"Movie","attributes":{"title":"Inception","releaseYear":2010}}],"relations":[{"label":"ACTED_IN","source":{"label":"Person","attributes":{"name":"JohnDoe"}},"target":{"label":"Movie","attributes":{"title":"Inception"}},"attributes":{"role":"Cobb"}}]}```
|
|
335
335
|
|
|
336
336
|
Ontology:
|
|
@@ -338,18 +338,47 @@ Ontology:
|
|
|
338
338
|
"""
|
|
339
339
|
|
|
340
340
|
EXTRACT_DATA_PROMPT = """
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
341
|
+
You are tasked with extracting entities and relations from the text below, using the ontology provided.
|
|
342
|
+
|
|
343
|
+
**Output Format:**
|
|
344
|
+
|
|
345
|
+
- Provide the extracted data as a JSON object with two keys: `"entities"` and `"relations"`.
|
|
346
|
+
|
|
347
|
+
- **Entities**: Represent entities and concepts. Each entity should have a `"label"` and `"attributes"` field.
|
|
348
|
+
|
|
349
|
+
- **Relations**: Represent relations between entities or concepts. Each relation should have a `"label"`, `"source"`, `"target"`, and `"attributes"` field.
|
|
350
|
+
|
|
351
|
+
**Guidelines:**
|
|
352
|
+
- **Extract all entities and relations**: Capture all entities and relations mentioned in the text.
|
|
353
|
+
|
|
354
|
+
- **Use Only the Provided Ontology**: Utilize only the types of entities, relations, and attributes defined in the ontology.
|
|
355
|
+
|
|
356
|
+
- **Assign IDs Where Required**: Assign textual IDs to entities and relations as specified.
|
|
357
|
+
|
|
358
|
+
- **Avoid Duplicates**: Ensure each entity and relation is unique; do not include duplicates.
|
|
359
|
+
|
|
360
|
+
- **Formatting**:
|
|
361
|
+
- Do not include any introduction or explanation in the response, only the JSON.
|
|
362
|
+
|
|
363
|
+
- Use double quotes for all string values.
|
|
364
|
+
|
|
365
|
+
- Properly escape any special characters.
|
|
366
|
+
|
|
367
|
+
- Dates should be in the format `"YYYY-MM-DD"`.
|
|
368
|
+
|
|
369
|
+
- Correct any spacing or formatting issues in text fields as necessary.
|
|
370
|
+
|
|
371
|
+
- **Precision**: Be concise and precise in your extraction.
|
|
372
|
+
|
|
373
|
+
- **Token Limit**: Ensure your response does not exceed **{max_tokens} tokens**.
|
|
374
|
+
|
|
375
|
+
**User Instructions**:
|
|
350
376
|
{instructions}
|
|
351
377
|
|
|
352
|
-
|
|
378
|
+
**Ontology**:
|
|
379
|
+
{ontology}
|
|
380
|
+
|
|
381
|
+
**Raw Text**:
|
|
353
382
|
{text}
|
|
354
383
|
"""
|
|
355
384
|
|
|
@@ -363,6 +392,12 @@ JSON:
|
|
|
363
392
|
{json}
|
|
364
393
|
"""
|
|
365
394
|
|
|
395
|
+
# This constant is used as a follow-up prompt when the initial data extraction is incomplete or contains duplicates.
|
|
396
|
+
# It instructs the model to complete the answer and ensure uniqueness of entities and relations.
|
|
397
|
+
COMPLETE_DATA_EXTRACTION = """
|
|
398
|
+
Please complete your answer. Ensure that each entity and relations is unique. Do not include duplicates. Please be precise.
|
|
399
|
+
"""
|
|
400
|
+
|
|
366
401
|
CYPHER_GEN_SYSTEM = """
|
|
367
402
|
Task: Generate OpenCypher statement to query a graph database.
|
|
368
403
|
|
|
@@ -426,6 +461,19 @@ Do not include any apologies or other texts, except the generated OpenCypher sta
|
|
|
426
461
|
Question: {question}
|
|
427
462
|
"""
|
|
428
463
|
|
|
464
|
+
CYPHER_GEN_PROMPT_WITH_HISTORY = """
|
|
465
|
+
Using the ontology provided, generate an OpenCypher statement to query the graph database returning all relevant entities, relationships, and attributes to answer the question below.
|
|
466
|
+
|
|
467
|
+
First, determine if the last answers provided to the user over the entire conversation is relevant to the current question. If it is relevant, you may consider incorporating information from it into the query. If it is not relevant, ignore it and generate the query based solely on the question.
|
|
468
|
+
|
|
469
|
+
If you cannot generate an OpenCypher statement for any reason, return an empty string.
|
|
470
|
+
|
|
471
|
+
Respect the order of the relationships; the arrows should always point from the "source" to the "target".
|
|
472
|
+
|
|
473
|
+
Last Answer: {last_answer}
|
|
474
|
+
|
|
475
|
+
Question: {question}
|
|
476
|
+
"""
|
|
429
477
|
|
|
430
478
|
GRAPH_QA_SYSTEM = """
|
|
431
479
|
You are an assistant that helps to form nice and human understandable answers.
|
|
@@ -540,7 +588,7 @@ Choose between the following steps to create the execution plan:
|
|
|
540
588
|
|
|
541
589
|
|
|
542
590
|
ORCHESTRATOR_SUMMARY_PROMPT = """
|
|
543
|
-
Given the following execution log, generate the final answer to the user's question.
|
|
591
|
+
Given the following execution log and the history of this chat, generate the final answer to the user's question.
|
|
544
592
|
Be very polite and detailed in your response, always providing the reasoning behind the answer.
|
|
545
593
|
|
|
546
594
|
User question:
|
|
@@ -118,55 +118,6 @@ class KnowledgeGraph:
|
|
|
118
118
|
|
|
119
119
|
step.run(instructions)
|
|
120
120
|
|
|
121
|
-
def ask(
|
|
122
|
-
self, question: str, qa_chat_session: GenerativeModelChatSession | None = None
|
|
123
|
-
) -> tuple[str, GenerativeModelChatSession]:
|
|
124
|
-
"""
|
|
125
|
-
Query the knowledge graph using natural language.
|
|
126
|
-
Optionally, you can provide a qa_chat_session to use for the query.
|
|
127
|
-
|
|
128
|
-
Parameters:
|
|
129
|
-
question (str): question to ask the knowledge graph
|
|
130
|
-
qa_chat_session (GenerativeModelChatSession|None): qa_chat_session to use for the query
|
|
131
|
-
|
|
132
|
-
Returns:
|
|
133
|
-
tuple[str, GenerativeModelChatSession]: answer, qa_chat_session
|
|
134
|
-
|
|
135
|
-
Example:
|
|
136
|
-
>>> (ans, qa_chat_session) = kg.ask("List a few movies in which that actor played in")
|
|
137
|
-
>>> print(ans)
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
cypher_chat_session = (
|
|
141
|
-
self._model_config.cypher_generation.with_system_instruction(
|
|
142
|
-
CYPHER_GEN_SYSTEM.replace("#ONTOLOGY", str(self.ontology.to_json())),
|
|
143
|
-
).start_chat()
|
|
144
|
-
)
|
|
145
|
-
cypher_step = GraphQueryGenerationStep(
|
|
146
|
-
ontology=self.ontology,
|
|
147
|
-
chat_session=cypher_chat_session,
|
|
148
|
-
graph=self.graph,
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
(context, cypher) = cypher_step.run(question)
|
|
152
|
-
|
|
153
|
-
if not cypher or len(cypher) == 0:
|
|
154
|
-
return "I am sorry, I could not find the answer to your question"
|
|
155
|
-
|
|
156
|
-
qa_chat_session = (
|
|
157
|
-
qa_chat_session
|
|
158
|
-
or self._model_config.qa.with_system_instruction(
|
|
159
|
-
GRAPH_QA_SYSTEM
|
|
160
|
-
).start_chat()
|
|
161
|
-
)
|
|
162
|
-
qa_step = QAStep(
|
|
163
|
-
chat_session=qa_chat_session,
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
answer = qa_step.run(question, cypher, context)
|
|
167
|
-
|
|
168
|
-
return (answer, qa_chat_session)
|
|
169
|
-
|
|
170
121
|
def delete(self) -> None:
|
|
171
122
|
"""
|
|
172
123
|
Deletes the knowledge graph and any other related resource
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from openai import AzureOpenAI
|
|
4
|
+
from .model import (
|
|
5
|
+
OutputMethod,
|
|
6
|
+
GenerativeModel,
|
|
7
|
+
GenerativeModelConfig,
|
|
8
|
+
GenerationResponse,
|
|
9
|
+
FinishReason,
|
|
10
|
+
GenerativeModelChatSession,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
class AzureOpenAiGenerativeModel(GenerativeModel):
|
|
14
|
+
"""
|
|
15
|
+
A generative model that interfaces with Azure's OpenAI API for chat completions.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
client: AzureOpenAI = None
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
model_name: str,
|
|
23
|
+
generation_config: Optional[GenerativeModelConfig] = None,
|
|
24
|
+
system_instruction: Optional[str] = None,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Initialize the AzureOpenAiGenerativeModel with required parameters.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
model_name (str): Name of the Azure OpenAI model.
|
|
31
|
+
generation_config (Optional[GenerativeModelConfig]): Configuration settings for generation.
|
|
32
|
+
system_instruction (Optional[str]): System-level instruction for the model.
|
|
33
|
+
"""
|
|
34
|
+
self.model_name = model_name
|
|
35
|
+
self.generation_config = generation_config or GenerativeModelConfig()
|
|
36
|
+
self.system_instruction = system_instruction
|
|
37
|
+
|
|
38
|
+
# Credentials
|
|
39
|
+
self.api_key = os.getenv("AZURE_OPENAI_API_KEY")
|
|
40
|
+
self.azure_endpoint = os.getenv("AZURE_ENDPOINT")
|
|
41
|
+
self.api_version = os.getenv("AZURE_API_VERSION")
|
|
42
|
+
|
|
43
|
+
if not self.api_key or not self.azure_endpoint or not self.api_version:
|
|
44
|
+
raise ValueError(
|
|
45
|
+
"Missing credentials in the environment: AZURE_OPENAI_API_KEY, AZURE_ENDPOINT, or AZURE_API_VERSION."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _connect_to_model(self) -> None:
|
|
50
|
+
"""
|
|
51
|
+
Establish a connection to the Azure OpenAI model by initializing the AzureOpenAI client.
|
|
52
|
+
"""
|
|
53
|
+
self.client = AzureOpenAI(azure_endpoint=self.azure_endpoint,
|
|
54
|
+
api_version=self.api_version,
|
|
55
|
+
api_key=self.api_key,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def with_system_instruction(self, system_instruction: str) -> "GenerativeModel":
|
|
59
|
+
"""
|
|
60
|
+
Set or update the system instruction and connect to the Azure OpenAI model.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
system_instruction (str): System instructions for the model.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
GenerativeModel: The updated model instance.
|
|
67
|
+
"""
|
|
68
|
+
self.system_instruction = system_instruction
|
|
69
|
+
self._connect_to_model()
|
|
70
|
+
|
|
71
|
+
return self
|
|
72
|
+
|
|
73
|
+
def start_chat(self, args: Optional[dict] = None) -> GenerativeModelChatSession:
|
|
74
|
+
"""
|
|
75
|
+
Start a new chat session.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
args (Optional[dict]): Additional arguments for the chat session.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
GenerativeModelChatSession: A new instance of the chat session.
|
|
82
|
+
"""
|
|
83
|
+
return AzureOpenAiChatSession(self, args)
|
|
84
|
+
|
|
85
|
+
def ask(self, message: str) -> GenerationResponse:
|
|
86
|
+
"""
|
|
87
|
+
Send a message to the model and receive a response.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
message (str): The user's message input.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
GenerationResponse: The model's generated response.
|
|
94
|
+
"""
|
|
95
|
+
response = self.client.chat.completions.create(
|
|
96
|
+
model=self.model_name,
|
|
97
|
+
messages=[
|
|
98
|
+
{"role": "system", "content": self.system_instruction},
|
|
99
|
+
{"role": "user", "content": message[:14385]},
|
|
100
|
+
],
|
|
101
|
+
max_tokens=self.generation_config.max_output_tokens,
|
|
102
|
+
temperature=self.generation_config.temperature,
|
|
103
|
+
top_p=self.generation_config.top_p,
|
|
104
|
+
top_k=self.generation_config.top_k,
|
|
105
|
+
stop=self.generation_config.stop_sequences,
|
|
106
|
+
)
|
|
107
|
+
return self._parse_generate_content_response(response)
|
|
108
|
+
|
|
109
|
+
def _parse_generate_content_response(self, response: any) -> GenerationResponse:
|
|
110
|
+
"""
|
|
111
|
+
Parse the model's response and extract content for the user.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
response (any): The raw response from the model.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
GenerationResponse: Parsed response containing the generated text and finish reason.
|
|
118
|
+
"""
|
|
119
|
+
return GenerationResponse(
|
|
120
|
+
text=response.choices[0].message.content,
|
|
121
|
+
finish_reason=(
|
|
122
|
+
FinishReason.STOP
|
|
123
|
+
if response.choices[0].finish_reason == "stop"
|
|
124
|
+
else (
|
|
125
|
+
FinishReason.MAX_TOKENS
|
|
126
|
+
if response.choices[0].finish_reason == "length"
|
|
127
|
+
else FinishReason.OTHER
|
|
128
|
+
)
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def to_json(self) -> dict:
|
|
133
|
+
"""
|
|
134
|
+
Serialize the model's configuration and state to JSON format.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
dict: The serialized JSON data.
|
|
138
|
+
"""
|
|
139
|
+
return {
|
|
140
|
+
"model_name": self.model_name,
|
|
141
|
+
"generation_config": self.generation_config.to_json(),
|
|
142
|
+
"system_instruction": self.system_instruction,
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@staticmethod
|
|
146
|
+
def from_json(json: dict) -> "GenerativeModel":
|
|
147
|
+
"""
|
|
148
|
+
Deserialize a JSON object to create an instance of AzureOpenAiGenerativeModel.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
json (dict): The serialized JSON data.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
GenerativeModel: A new instance of the model.
|
|
155
|
+
"""
|
|
156
|
+
return AzureOpenAiGenerativeModel(
|
|
157
|
+
json["model_name"],
|
|
158
|
+
generation_config=GenerativeModelConfig.from_json(
|
|
159
|
+
json["generation_config"]
|
|
160
|
+
),
|
|
161
|
+
system_instruction=json["system_instruction"],
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class AzureOpenAiChatSession(GenerativeModelChatSession):
|
|
166
|
+
"""
|
|
167
|
+
A chat session for interacting with the Azure OpenAI model, maintaining conversation history.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
_history = []
|
|
172
|
+
|
|
173
|
+
def __init__(self, model: AzureOpenAiGenerativeModel, args: Optional[dict] = None):
|
|
174
|
+
"""
|
|
175
|
+
Initialize the chat session and set up the conversation history.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
model (AzureOpenAiGenerativeModel): The model instance for the session.
|
|
179
|
+
args (Optional[dict]): Additional arguments for customization.
|
|
180
|
+
"""
|
|
181
|
+
self._model = model
|
|
182
|
+
self._args = args
|
|
183
|
+
self._history = (
|
|
184
|
+
[{"role": "system", "content": self._model.system_instruction}]
|
|
185
|
+
if self._model.system_instruction is not None
|
|
186
|
+
else []
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def send_message(self, message: str, output_method: OutputMethod = OutputMethod.DEFAULT) -> GenerationResponse:
|
|
190
|
+
"""
|
|
191
|
+
Send a message in the chat session and receive the model's response.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
message (str): The message to send.
|
|
195
|
+
output_method (OutputMethod): Format for the model's output.
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
GenerationResponse: The generated response.
|
|
199
|
+
"""
|
|
200
|
+
generation_config = self._get_generation_config(output_method)
|
|
201
|
+
prompt = []
|
|
202
|
+
prompt.extend(self._history)
|
|
203
|
+
prompt.append({"role": "user", "content": message[:14385]})
|
|
204
|
+
response = self._model.client.chat.completions.create(
|
|
205
|
+
model=self._model.model_name,
|
|
206
|
+
messages=prompt,
|
|
207
|
+
**generation_config
|
|
208
|
+
)
|
|
209
|
+
content = self._model._parse_generate_content_response(response)
|
|
210
|
+
self._history.append({"role": "user", "content": message})
|
|
211
|
+
self._history.append({"role": "assistant", "content": content.text})
|
|
212
|
+
return content
|
|
213
|
+
|
|
214
|
+
def _get_generation_config(self, output_method: OutputMethod):
|
|
215
|
+
"""
|
|
216
|
+
Adjust the generation configuration based on the output method.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
output_method (OutputMethod): The desired output method (e.g., default or JSON).
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
dict: The configuration settings for generation.
|
|
223
|
+
"""
|
|
224
|
+
config = self._model.generation_config.to_json()
|
|
225
|
+
if output_method == OutputMethod.JSON:
|
|
226
|
+
config['temperature'] = 0
|
|
227
|
+
config['response_format'] = { "type": "json_object" }
|
|
228
|
+
|
|
229
|
+
return config
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from .model import (
|
|
3
|
+
OutputMethod,
|
|
3
4
|
GenerativeModel,
|
|
4
5
|
GenerativeModelConfig,
|
|
5
6
|
GenerationResponse,
|
|
@@ -61,10 +62,6 @@ class GeminiGenerativeModel(GenerativeModel):
|
|
|
61
62
|
def start_chat(self, args: dict | None = None) -> GenerativeModelChatSession:
|
|
62
63
|
return GeminiChatSession(self, args)
|
|
63
64
|
|
|
64
|
-
def ask(self, message: str) -> GenerationResponse:
|
|
65
|
-
response = self._model.generate_content(message)
|
|
66
|
-
return self.parse_generate_content_response(response)
|
|
67
|
-
|
|
68
65
|
def parse_generate_content_response(
|
|
69
66
|
self, response: types.generation_types.GenerateContentResponse
|
|
70
67
|
) -> GenerationResponse:
|
|
@@ -108,6 +105,15 @@ class GeminiChatSession(GenerativeModelChatSession):
|
|
|
108
105
|
history=args.get("history", []) if args is not None else [],
|
|
109
106
|
)
|
|
110
107
|
|
|
111
|
-
def send_message(self, message: str) -> GenerationResponse:
|
|
112
|
-
|
|
108
|
+
def send_message(self, message: str, output_method: OutputMethod = OutputMethod.DEFAULT) -> GenerationResponse:
|
|
109
|
+
generation_config = self._get_generation_config(output_method)
|
|
110
|
+
response = self._chat_session.send_message(message, generation_config=generation_config)
|
|
113
111
|
return self._model.parse_generate_content_response(response)
|
|
112
|
+
|
|
113
|
+
def _get_generation_config(self, output_method: OutputMethod):
|
|
114
|
+
if output_method == OutputMethod.JSON:
|
|
115
|
+
return {
|
|
116
|
+
"response_mime_type": "application/json",
|
|
117
|
+
"temperature": 0
|
|
118
|
+
}
|
|
119
|
+
return self._model._generation_config
|