naas-abi-core 1.0.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.
- naas_abi_core/__init__.py +1 -0
- naas_abi_core/apps/api/api.py +242 -0
- naas_abi_core/apps/api/api_test.py +281 -0
- naas_abi_core/apps/api/openapi_doc.py +307 -0
- naas_abi_core/apps/mcp/mcp_server.py +243 -0
- naas_abi_core/apps/mcp/mcp_server_test.py +163 -0
- naas_abi_core/apps/terminal_agent/main.py +555 -0
- naas_abi_core/apps/terminal_agent/terminal_style.py +175 -0
- naas_abi_core/cli/__init__.py +53 -0
- naas_abi_core/cli/agent.py +30 -0
- naas_abi_core/cli/chat.py +26 -0
- naas_abi_core/cli/config.py +49 -0
- naas_abi_core/cli/init.py +13 -0
- naas_abi_core/cli/module.py +28 -0
- naas_abi_core/cli/new.py +13 -0
- naas_abi_core/cli/secret.py +79 -0
- naas_abi_core/engine/Engine.py +87 -0
- naas_abi_core/engine/EngineProxy.py +109 -0
- naas_abi_core/engine/Engine_test.py +6 -0
- naas_abi_core/engine/IEngine.py +91 -0
- naas_abi_core/engine/conftest.py +45 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration.py +160 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_GenericLoader.py +49 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService.py +131 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService_test.py +26 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_SecretService.py +116 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_TripleStoreService.py +171 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_VectorStoreService.py +65 -0
- naas_abi_core/engine/engine_configuration/EngineConfiguration_test.py +9 -0
- naas_abi_core/engine/engine_configuration/utils/PydanticModelValidator.py +15 -0
- naas_abi_core/engine/engine_loaders/EngineModuleLoader.py +302 -0
- naas_abi_core/engine/engine_loaders/EngineOntologyLoader.py +16 -0
- naas_abi_core/engine/engine_loaders/EngineServiceLoader.py +47 -0
- naas_abi_core/integration/__init__.py +7 -0
- naas_abi_core/integration/integration.py +28 -0
- naas_abi_core/models/Model.py +198 -0
- naas_abi_core/models/OpenRouter.py +15 -0
- naas_abi_core/models/OpenRouter_test.py +36 -0
- naas_abi_core/module/Module.py +245 -0
- naas_abi_core/module/ModuleAgentLoader.py +49 -0
- naas_abi_core/module/ModuleUtils.py +20 -0
- naas_abi_core/modules/templatablesparqlquery/README.md +196 -0
- naas_abi_core/modules/templatablesparqlquery/__init__.py +39 -0
- naas_abi_core/modules/templatablesparqlquery/ontologies/TemplatableSparqlQueryOntology.ttl +116 -0
- naas_abi_core/modules/templatablesparqlquery/workflows/GenericWorkflow.py +48 -0
- naas_abi_core/modules/templatablesparqlquery/workflows/TemplatableSparqlQueryLoader.py +192 -0
- naas_abi_core/pipeline/__init__.py +6 -0
- naas_abi_core/pipeline/pipeline.py +70 -0
- naas_abi_core/services/__init__.py +0 -0
- naas_abi_core/services/agent/Agent.py +1619 -0
- naas_abi_core/services/agent/AgentMemory_test.py +28 -0
- naas_abi_core/services/agent/Agent_test.py +214 -0
- naas_abi_core/services/agent/IntentAgent.py +1171 -0
- naas_abi_core/services/agent/IntentAgent_test.py +139 -0
- naas_abi_core/services/agent/beta/Embeddings.py +180 -0
- naas_abi_core/services/agent/beta/IntentMapper.py +119 -0
- naas_abi_core/services/agent/beta/LocalModel.py +88 -0
- naas_abi_core/services/agent/beta/VectorStore.py +89 -0
- naas_abi_core/services/agent/test_agent_memory.py +278 -0
- naas_abi_core/services/agent/test_postgres_integration.py +145 -0
- naas_abi_core/services/cache/CacheFactory.py +31 -0
- naas_abi_core/services/cache/CachePort.py +63 -0
- naas_abi_core/services/cache/CacheService.py +246 -0
- naas_abi_core/services/cache/CacheService_test.py +85 -0
- naas_abi_core/services/cache/adapters/secondary/CacheFSAdapter.py +39 -0
- naas_abi_core/services/object_storage/ObjectStorageFactory.py +57 -0
- naas_abi_core/services/object_storage/ObjectStoragePort.py +47 -0
- naas_abi_core/services/object_storage/ObjectStorageService.py +41 -0
- naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterFS.py +52 -0
- naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterNaas.py +131 -0
- naas_abi_core/services/object_storage/adapters/secondary/ObjectStorageSecondaryAdapterS3.py +171 -0
- naas_abi_core/services/ontology/OntologyPorts.py +36 -0
- naas_abi_core/services/ontology/OntologyService.py +17 -0
- naas_abi_core/services/ontology/adaptors/secondary/OntologyService_SecondaryAdaptor_NERPort.py +37 -0
- naas_abi_core/services/secret/Secret.py +138 -0
- naas_abi_core/services/secret/SecretPorts.py +40 -0
- naas_abi_core/services/secret/Secret_test.py +65 -0
- naas_abi_core/services/secret/adaptors/secondary/Base64Secret.py +57 -0
- naas_abi_core/services/secret/adaptors/secondary/Base64Secret_test.py +39 -0
- naas_abi_core/services/secret/adaptors/secondary/NaasSecret.py +81 -0
- naas_abi_core/services/secret/adaptors/secondary/NaasSecret_test.py +25 -0
- naas_abi_core/services/secret/adaptors/secondary/dotenv_secret_secondaryadaptor.py +26 -0
- naas_abi_core/services/triple_store/TripleStoreFactory.py +116 -0
- naas_abi_core/services/triple_store/TripleStorePorts.py +223 -0
- naas_abi_core/services/triple_store/TripleStoreService.py +419 -0
- naas_abi_core/services/triple_store/adaptors/secondary/AWSNeptune.py +1284 -0
- naas_abi_core/services/triple_store/adaptors/secondary/AWSNeptune_test.py +284 -0
- naas_abi_core/services/triple_store/adaptors/secondary/Oxigraph.py +597 -0
- naas_abi_core/services/triple_store/adaptors/secondary/Oxigraph_test.py +1474 -0
- naas_abi_core/services/triple_store/adaptors/secondary/TripleStoreService__SecondaryAdaptor__Filesystem.py +223 -0
- naas_abi_core/services/triple_store/adaptors/secondary/TripleStoreService__SecondaryAdaptor__ObjectStorage.py +234 -0
- naas_abi_core/services/triple_store/adaptors/secondary/base/TripleStoreService__SecondaryAdaptor__FileBase.py +18 -0
- naas_abi_core/services/vector_store/IVectorStorePort.py +101 -0
- naas_abi_core/services/vector_store/IVectorStorePort_test.py +189 -0
- naas_abi_core/services/vector_store/VectorStoreFactory.py +47 -0
- naas_abi_core/services/vector_store/VectorStoreService.py +171 -0
- naas_abi_core/services/vector_store/VectorStoreService_test.py +185 -0
- naas_abi_core/services/vector_store/__init__.py +13 -0
- naas_abi_core/services/vector_store/adapters/QdrantAdapter.py +251 -0
- naas_abi_core/services/vector_store/adapters/QdrantAdapter_test.py +57 -0
- naas_abi_core/utils/Expose.py +53 -0
- naas_abi_core/utils/Graph.py +182 -0
- naas_abi_core/utils/JSON.py +49 -0
- naas_abi_core/utils/LazyLoader.py +44 -0
- naas_abi_core/utils/Logger.py +12 -0
- naas_abi_core/utils/OntologyReasoner.py +141 -0
- naas_abi_core/utils/OntologyYaml.disabled.py +679 -0
- naas_abi_core/utils/SPARQL.py +256 -0
- naas_abi_core/utils/Storage.py +33 -0
- naas_abi_core/utils/StorageUtils.py +398 -0
- naas_abi_core/utils/String.py +52 -0
- naas_abi_core/utils/Workers.py +114 -0
- naas_abi_core/utils/__init__.py +0 -0
- naas_abi_core/utils/onto2py/README.md +0 -0
- naas_abi_core/utils/onto2py/__init__.py +10 -0
- naas_abi_core/utils/onto2py/__main__.py +29 -0
- naas_abi_core/utils/onto2py/onto2py.py +611 -0
- naas_abi_core/utils/onto2py/tests/ttl2py_test.py +271 -0
- naas_abi_core/workflow/__init__.py +5 -0
- naas_abi_core/workflow/workflow.py +48 -0
- naas_abi_core-1.0.0.dist-info/METADATA +75 -0
- naas_abi_core-1.0.0.dist-info/RECORD +124 -0
- naas_abi_core-1.0.0.dist-info/WHEEL +4 -0
- naas_abi_core-1.0.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Templatable SPARQL Query Module
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
### Description
|
|
6
|
+
|
|
7
|
+
The Templatable SPARQL Query Module provides a dynamic system for creating reusable SPARQL queries through ontology-based definitions. This module enables developers to define SPARQL query templates in RDF/TTL format with arguments and validation patterns, which are then automatically converted into executable workflows and tools at runtime.
|
|
8
|
+
|
|
9
|
+
This module enables:
|
|
10
|
+
- Dynamic SPARQL query generation from ontology definitions
|
|
11
|
+
- Automatic argument validation using regex patterns and formats
|
|
12
|
+
- Runtime tool creation for AI agents without writing Python boilerplate
|
|
13
|
+
- Template-based query execution using Jinja2 syntax
|
|
14
|
+
- Integration with knowledge graphs and triple stores
|
|
15
|
+
|
|
16
|
+
### Requirements
|
|
17
|
+
|
|
18
|
+
Triple Store Setup:
|
|
19
|
+
1. Ensure you have a running triple store service configured in your ABI instance
|
|
20
|
+
2. The module uses `services.triple_store_service` to query ontology definitions
|
|
21
|
+
|
|
22
|
+
### TL;DR
|
|
23
|
+
|
|
24
|
+
To get started with the Templatable SPARQL Query module:
|
|
25
|
+
|
|
26
|
+
1. Define your SPARQL queries in TTL format using the provided ontology
|
|
27
|
+
2. Load the TTL file into your triple store
|
|
28
|
+
3. The module automatically creates tools from your query definitions
|
|
29
|
+
|
|
30
|
+
Access tools using:
|
|
31
|
+
```python
|
|
32
|
+
from src.core.modules.templatablesparqlquery import get_tools
|
|
33
|
+
tools = get_tools()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Structure
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
src/core/templatablesparqlquery/
|
|
40
|
+
|
|
41
|
+
├── ontologies/
|
|
42
|
+
│ └── TemplatableSparqlQueryOntology.ttl
|
|
43
|
+
├── workflows/
|
|
44
|
+
│ ├── GenericWorkflow.py
|
|
45
|
+
│ └── TemplatableSparqlQuery.py
|
|
46
|
+
└── README.md
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Core Components
|
|
50
|
+
|
|
51
|
+
The module provides a declarative approach to SPARQL query definition and execution through ontology-based configuration.
|
|
52
|
+
|
|
53
|
+
### Workflows
|
|
54
|
+
|
|
55
|
+
#### Templatable SPARQL Query Workflow
|
|
56
|
+
Dynamically loads query definitions from the triple store and creates executable workflows with proper argument validation and Jinja2 template rendering.
|
|
57
|
+
|
|
58
|
+
**Capabilities:**
|
|
59
|
+
- Loads query definitions from triple store using SPARQL
|
|
60
|
+
- Creates Pydantic models for argument validation
|
|
61
|
+
- Renders SPARQL templates with user parameters
|
|
62
|
+
- Executes queries against the triple store
|
|
63
|
+
- Returns formatted results
|
|
64
|
+
|
|
65
|
+
**Use Cases:**
|
|
66
|
+
- Dynamic query generation without hardcoded Python workflows
|
|
67
|
+
- Reusable query templates with parameter validation
|
|
68
|
+
- AI agent tool creation from ontology definitions
|
|
69
|
+
|
|
70
|
+
#### Generic Workflow
|
|
71
|
+
A generic wrapper class that handles the execution of templated SPARQL queries with type-safe argument validation.
|
|
72
|
+
|
|
73
|
+
**Configuration:**
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from src.core.modules.templatablesparqlquery.workflows.GenericWorkflow import GenericWorkflow
|
|
77
|
+
from pydantic import BaseModel, Field
|
|
78
|
+
|
|
79
|
+
# Define argument model
|
|
80
|
+
class MyQueryArguments(BaseModel):
|
|
81
|
+
department_id: str = Field(..., description="Department identifier", pattern="^[A-Z0-9]{3,}$")
|
|
82
|
+
employee_name: str = Field(..., description="Employee name filter")
|
|
83
|
+
|
|
84
|
+
# Create workflow
|
|
85
|
+
workflow = GenericWorkflow[MyQueryArguments](
|
|
86
|
+
name="find_employees",
|
|
87
|
+
description="Find employees in a department",
|
|
88
|
+
sparql_template=sparql_query_template,
|
|
89
|
+
arguments_model=MyQueryArguments
|
|
90
|
+
)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Run
|
|
94
|
+
Execute workflows by calling the module's tool loading functions:
|
|
95
|
+
```python
|
|
96
|
+
from src.core.modules.templatablesparqlquery import get_tools
|
|
97
|
+
tools = get_tools()
|
|
98
|
+
# Tools are automatically created from ontology definitions
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Testing
|
|
102
|
+
Currently no dedicated test files are present in the module structure.
|
|
103
|
+
|
|
104
|
+
### Ontologies
|
|
105
|
+
|
|
106
|
+
#### Templatable SPARQL Query Ontology
|
|
107
|
+
|
|
108
|
+
The core ontology defining the structure for templatable SPARQL queries and their arguments:
|
|
109
|
+
|
|
110
|
+
**Key Classes:**
|
|
111
|
+
- `abi:TemplatableSparqlQuery`: Represents a SPARQL query template with intent information
|
|
112
|
+
- `abi:QueryArgument`: Represents an argument for query templating
|
|
113
|
+
|
|
114
|
+
**Key Properties:**
|
|
115
|
+
- `abi:intentDescription`: Natural language description of query purpose
|
|
116
|
+
- `abi:sparqlTemplate`: The SPARQL query template with Jinja2 variables
|
|
117
|
+
- `abi:hasArgument`: Links queries to their arguments
|
|
118
|
+
- `abi:argumentName`: Argument name used in templates
|
|
119
|
+
- `abi:validationPattern`: Regex pattern for argument validation
|
|
120
|
+
- `abi:validationFormat`: Expected format description
|
|
121
|
+
|
|
122
|
+
#### Example Query Definition
|
|
123
|
+
|
|
124
|
+
```turtle
|
|
125
|
+
@prefix abi: <http://ontology.naas.ai/abi/> .
|
|
126
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
127
|
+
|
|
128
|
+
abi:findEmployeesQuery a abi:TemplatableSparqlQuery ;
|
|
129
|
+
rdfs:label "Find Employees"@en ;
|
|
130
|
+
abi:intentDescription "Find all employees working in a specific department" ;
|
|
131
|
+
abi:sparqlTemplate """
|
|
132
|
+
SELECT ?employee ?name
|
|
133
|
+
WHERE {
|
|
134
|
+
?employee :worksIn :{{ department_id }} ;
|
|
135
|
+
:hasName ?name .
|
|
136
|
+
{% if employee_name %}
|
|
137
|
+
FILTER(CONTAINS(LCASE(?name), LCASE("{{ employee_name }}")))
|
|
138
|
+
{% endif %}
|
|
139
|
+
}
|
|
140
|
+
""" ;
|
|
141
|
+
abi:hasArgument abi:departmentArg .
|
|
142
|
+
|
|
143
|
+
abi:departmentArg a abi:QueryArgument ;
|
|
144
|
+
abi:argumentName "department_id" ;
|
|
145
|
+
abi:argumentDescription "The unique identifier of the department" ;
|
|
146
|
+
abi:validationPattern "^[A-Z0-9]{3,}$" ;
|
|
147
|
+
abi:validationFormat "department_id" .
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## How to Add New Queries
|
|
151
|
+
|
|
152
|
+
### Step 1: Define Query in TTL Format
|
|
153
|
+
Create or update a TTL file with your query definition using the templatable SPARQL query ontology.
|
|
154
|
+
|
|
155
|
+
### Step 2: Define Arguments
|
|
156
|
+
Specify all required arguments with proper validation patterns and descriptions.
|
|
157
|
+
|
|
158
|
+
### Step 3: Load into Triple Store
|
|
159
|
+
Ensure your TTL file is loaded into the triple store during application initialization.
|
|
160
|
+
|
|
161
|
+
### Step 4: Access Generated Tools
|
|
162
|
+
The module automatically creates tools from your definitions:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from src.core.modules.templatablesparqlquery import get_tools
|
|
166
|
+
tools = get_tools()
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Dependencies
|
|
170
|
+
|
|
171
|
+
### Python Libraries
|
|
172
|
+
- `pydantic`: Data validation and serialization for argument models
|
|
173
|
+
- `rdflib`: RDF graph processing and SPARQL query execution
|
|
174
|
+
- `jinja2`: Template rendering for SPARQL queries
|
|
175
|
+
- `langchain_core`: Tool integration for AI agents
|
|
176
|
+
- `asyncio`: Asynchronous processing support
|
|
177
|
+
|
|
178
|
+
### Internal Modules
|
|
179
|
+
- `src.utils.SPARQL`: SPARQL result processing utilities
|
|
180
|
+
- `src.services`: Triple store service integration
|
|
181
|
+
|
|
182
|
+
### External Services
|
|
183
|
+
- **Triple Store**: Required for storing and querying ontology definitions
|
|
184
|
+
- **Knowledge Graph**: Source data for SPARQL query execution
|
|
185
|
+
|
|
186
|
+
## Technical Implementation
|
|
187
|
+
|
|
188
|
+
The module uses a sophisticated runtime generation process:
|
|
189
|
+
|
|
190
|
+
1. **Query Discovery**: Scans the triple store for `TemplatableSparqlQuery` instances
|
|
191
|
+
2. **Argument Resolution**: Retrieves associated `QueryArgument` definitions
|
|
192
|
+
3. **Model Generation**: Creates Pydantic models with validation patterns
|
|
193
|
+
4. **Tool Creation**: Generates LangChain tools for AI agent integration
|
|
194
|
+
5. **Template Execution**: Uses Jinja2 to render SPARQL templates with parameters
|
|
195
|
+
|
|
196
|
+
This approach eliminates the need for writing repetitive Python code for similar query patterns, allowing developers to focus on query logic and ontology design.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from naas_abi_core.module.Module import (
|
|
2
|
+
BaseModule,
|
|
3
|
+
ModuleConfiguration,
|
|
4
|
+
ModuleDependencies,
|
|
5
|
+
)
|
|
6
|
+
from naas_abi_core.modules.templatablesparqlquery.workflows.TemplatableSparqlQueryLoader import (
|
|
7
|
+
TemplatableSparqlQueryLoader,
|
|
8
|
+
)
|
|
9
|
+
from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ABIModule(BaseModule):
|
|
13
|
+
__workflows: list = []
|
|
14
|
+
__tools: list = []
|
|
15
|
+
|
|
16
|
+
dependencies: ModuleDependencies = ModuleDependencies(
|
|
17
|
+
modules=[], services=[TripleStoreService]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
class Configuration(ModuleConfiguration):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def on_initialized(self):
|
|
24
|
+
self.__templatable_sparql_query_loader = TemplatableSparqlQueryLoader(
|
|
25
|
+
self.engine.services.triple_store
|
|
26
|
+
)
|
|
27
|
+
self.__workflows = self.__templatable_sparql_query_loader.load_workflows()
|
|
28
|
+
self.__tools = [
|
|
29
|
+
tool for workflow in self.__workflows for tool in workflow.as_tools()
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
def get_workflows(self):
|
|
33
|
+
return self.__workflows
|
|
34
|
+
|
|
35
|
+
def get_tools(self, tool_names: list[str] = []):
|
|
36
|
+
if len(tool_names) == 0:
|
|
37
|
+
return self.__tools
|
|
38
|
+
else:
|
|
39
|
+
return [tool for tool in self.__tools if tool.name in tool_names]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
2
|
+
@prefix dc11: <http://purl.org/dc/elements/1.1/> .
|
|
3
|
+
@prefix dc: <http://purl.org/dc/terms/> .
|
|
4
|
+
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
|
5
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
6
|
+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
|
7
|
+
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
|
|
8
|
+
@prefix bfo: <http://purl.obolibrary.org/obo/> .
|
|
9
|
+
@prefix cco: <https://www.commoncoreontologies.org/> .
|
|
10
|
+
@prefix abi: <http://ontology.naas.ai/abi/> .
|
|
11
|
+
|
|
12
|
+
<http://ontology.naas.ai/abi/TemplatableSparqlQueryOntology> a owl:Ontology ;
|
|
13
|
+
owl:versionIRI <https://github.com/jupyter-naas/abi/tree/cli/src/core/modules/abi/ontologies/domain-level/TemplatableSparqlQueryOntology.ttl> ;
|
|
14
|
+
dc11:contributor "Jeremy Ravenel" , "Maxime Jublou" , "Florent Ravenel" ;
|
|
15
|
+
dc:description "Templatable Sparql Query Ontology."@en ;
|
|
16
|
+
dc:license "" ;
|
|
17
|
+
dc:title "Templatable Sparql Query Ontology" .
|
|
18
|
+
|
|
19
|
+
#################################################################
|
|
20
|
+
# Classes
|
|
21
|
+
#################################################################
|
|
22
|
+
|
|
23
|
+
abi:TemplatableSparqlQuery a owl:Class ;
|
|
24
|
+
rdfs:subClassOf bfo:BFO_0000031 ;
|
|
25
|
+
rdfs:label "Templatable SPARQL Query"@en ;
|
|
26
|
+
rdfs:comment "A class representing a SPARQL query that can be templated with variables and includes intent information."@en .
|
|
27
|
+
|
|
28
|
+
abi:QueryArgument a owl:Class ;
|
|
29
|
+
rdfs:subClassOf bfo:BFO_0000031 ;
|
|
30
|
+
rdfs:label "Query Argument"@en ;
|
|
31
|
+
rdfs:comment "A class representing an argument that can be used to template a SPARQL query."@en .
|
|
32
|
+
|
|
33
|
+
#################################################################
|
|
34
|
+
# Object Properties
|
|
35
|
+
#################################################################
|
|
36
|
+
|
|
37
|
+
abi:hasArgument a owl:ObjectProperty ;
|
|
38
|
+
rdfs:label "has argument"@en ;
|
|
39
|
+
rdfs:domain abi:TemplatableSparqlQuery ;
|
|
40
|
+
rdfs:range abi:QueryArgument ;
|
|
41
|
+
rdfs:comment "Links a templatable SPARQL query to its arguments."@en .
|
|
42
|
+
|
|
43
|
+
#################################################################
|
|
44
|
+
# Data Properties
|
|
45
|
+
#################################################################
|
|
46
|
+
|
|
47
|
+
abi:intentDescription a owl:DatatypeProperty ;
|
|
48
|
+
rdfs:label "intent description"@en ;
|
|
49
|
+
rdfs:domain abi:TemplatableSparqlQuery ;
|
|
50
|
+
rdfs:range xsd:string ;
|
|
51
|
+
rdfs:comment "A natural language description of the query's intent."@en .
|
|
52
|
+
|
|
53
|
+
abi:sparqlTemplate a owl:DatatypeProperty ;
|
|
54
|
+
rdfs:label "SPARQL template"@en ;
|
|
55
|
+
rdfs:domain abi:TemplatableSparqlQuery ;
|
|
56
|
+
rdfs:range xsd:string ;
|
|
57
|
+
rdfs:comment "The SPARQL query template with variable placeholders."@en .
|
|
58
|
+
|
|
59
|
+
abi:argumentName a owl:DatatypeProperty ;
|
|
60
|
+
rdfs:label "argument name"@en ;
|
|
61
|
+
rdfs:domain abi:QueryArgument ;
|
|
62
|
+
rdfs:range xsd:string ;
|
|
63
|
+
rdfs:comment "The name of the argument used in the template."@en .
|
|
64
|
+
|
|
65
|
+
abi:argumentDescription a owl:DatatypeProperty ;
|
|
66
|
+
rdfs:label "argument description"@en ;
|
|
67
|
+
rdfs:domain abi:QueryArgument ;
|
|
68
|
+
rdfs:range xsd:string ;
|
|
69
|
+
rdfs:comment "A description of what the argument represents."@en .
|
|
70
|
+
|
|
71
|
+
abi:validationPattern a owl:DatatypeProperty ;
|
|
72
|
+
rdfs:label "validation pattern"@en ;
|
|
73
|
+
rdfs:domain abi:QueryArgument ;
|
|
74
|
+
rdfs:range xsd:string ;
|
|
75
|
+
rdfs:comment "A regex pattern for validating the argument value."@en .
|
|
76
|
+
|
|
77
|
+
abi:validationFormat a owl:DatatypeProperty ;
|
|
78
|
+
rdfs:label "validation format"@en ;
|
|
79
|
+
rdfs:domain abi:QueryArgument ;
|
|
80
|
+
rdfs:range xsd:string ;
|
|
81
|
+
rdfs:comment "The expected format of the argument value (e.g., date, number, URI)."@en .
|
|
82
|
+
|
|
83
|
+
#################################################################
|
|
84
|
+
# Example Usage
|
|
85
|
+
#################################################################
|
|
86
|
+
|
|
87
|
+
# # Example of a query to find employees in a department with optional name filter:
|
|
88
|
+
# abi:findEmployeesQuery a abi:TemplatableSparqlQuery ;
|
|
89
|
+
# rdfs:label "findEmployeesQuery"@en ;
|
|
90
|
+
# abi:intentDescription "Find all employees working in a specific department, optionally filtered by name" ;
|
|
91
|
+
# abi:sparqlTemplate """
|
|
92
|
+
# SELECT ?employee ?name
|
|
93
|
+
# WHERE {
|
|
94
|
+
# ?employee :worksIn :{{ department_id }} ;
|
|
95
|
+
# :hasName ?name .
|
|
96
|
+
# {% if employee_name %}
|
|
97
|
+
# FILTER(CONTAINS(LCASE(?name), LCASE("{{ employee_name }}")))
|
|
98
|
+
# {% endif %}
|
|
99
|
+
# }
|
|
100
|
+
# """ ;
|
|
101
|
+
# abi:hasArgument abi:departmentArg, abi:nameArg .
|
|
102
|
+
|
|
103
|
+
# abi:departmentArg a abi:QueryArgument ;
|
|
104
|
+
# abi:argumentName "department_id" ;
|
|
105
|
+
# abi:argumentDescription "The unique identifier of the department" ;
|
|
106
|
+
# abi:validationPattern "^[A-Z0-9]{3,}$" ;
|
|
107
|
+
# abi:validationFormat "department_id" .
|
|
108
|
+
|
|
109
|
+
# abi:nameArg a abi:QueryArgument ;
|
|
110
|
+
# abi:argumentName "employee_name" ;
|
|
111
|
+
# abi:argumentDescription "Optional name to filter employees (case-insensitive partial match)" ;
|
|
112
|
+
# abi:validationPattern "^[a-zA-Z0-9\\s-]{2,50}$" ;
|
|
113
|
+
# abi:validationFormat "employee_name" .
|
|
114
|
+
|
|
115
|
+
# #################################################################
|
|
116
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from typing import Generic, Type, TypeVar
|
|
2
|
+
|
|
3
|
+
from langchain_core.tools import BaseTool, StructuredTool
|
|
4
|
+
from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
|
|
5
|
+
from naas_abi_core.utils.SPARQL import SPARQLUtils
|
|
6
|
+
from pydantic import BaseModel
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T", bound=BaseModel)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GenericWorkflow(Generic[T]):
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
name: str,
|
|
15
|
+
description: str,
|
|
16
|
+
sparql_template: str,
|
|
17
|
+
arguments_model: Type[T],
|
|
18
|
+
triple_store_service: TripleStoreService,
|
|
19
|
+
):
|
|
20
|
+
self.name = name
|
|
21
|
+
self.description = description
|
|
22
|
+
self.sparql_template = sparql_template
|
|
23
|
+
self.arguments_model = arguments_model
|
|
24
|
+
self.triple_store_service = triple_store_service
|
|
25
|
+
|
|
26
|
+
def run(self, parameters: T):
|
|
27
|
+
try:
|
|
28
|
+
# Template the sparql template with the parameters using jinja2
|
|
29
|
+
from jinja2 import Template
|
|
30
|
+
|
|
31
|
+
template = Template(self.sparql_template)
|
|
32
|
+
sparql_query = template.render(parameters.model_dump())
|
|
33
|
+
# print(sparql_query)
|
|
34
|
+
results = self.triple_store_service.query(sparql_query)
|
|
35
|
+
|
|
36
|
+
return SPARQLUtils(self.triple_store_service).results_to_list(results)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
return [{"error": str(e)}]
|
|
39
|
+
|
|
40
|
+
def as_tools(self) -> list[BaseTool]:
|
|
41
|
+
return [
|
|
42
|
+
StructuredTool(
|
|
43
|
+
name=self.name,
|
|
44
|
+
description=self.description,
|
|
45
|
+
func=lambda **kwargs: self.run(self.arguments_model(**kwargs)),
|
|
46
|
+
args_schema=self.arguments_model,
|
|
47
|
+
)
|
|
48
|
+
]
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from naas_abi_core import logger
|
|
4
|
+
from naas_abi_core.services.triple_store.TripleStoreService import TripleStoreService
|
|
5
|
+
from pydantic import Field, create_model
|
|
6
|
+
from rdflib import RDF, Graph, URIRef
|
|
7
|
+
|
|
8
|
+
from .GenericWorkflow import GenericWorkflow
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def async_asyncio_thread_jobs(jobs):
|
|
12
|
+
tasks = []
|
|
13
|
+
for job in jobs:
|
|
14
|
+
task = asyncio.create_task(asyncio.to_thread(*job))
|
|
15
|
+
tasks.append(task)
|
|
16
|
+
return await asyncio.gather(*tasks)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def asyncio_thread_job(jobs):
|
|
20
|
+
return asyncio.run(async_asyncio_thread_jobs(jobs))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class TemplatableSparqlQueryLoader:
|
|
24
|
+
triple_store_service: TripleStoreService
|
|
25
|
+
|
|
26
|
+
def __init__(self, triple_store_service: TripleStoreService):
|
|
27
|
+
self.triple_store_service = triple_store_service
|
|
28
|
+
|
|
29
|
+
def templatable_queries(self):
|
|
30
|
+
results = self.triple_store_service.query("""
|
|
31
|
+
PREFIX intentMapping: <http://ontology.naas.ai/intentMapping/>
|
|
32
|
+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
|
|
33
|
+
SELECT ?query ?label ?description ?sparqlTemplate ?hasArgument
|
|
34
|
+
WHERE {
|
|
35
|
+
?query a intentMapping:TemplatableSparqlQuery ;
|
|
36
|
+
intentMapping:intentDescription ?description ;
|
|
37
|
+
intentMapping:sparqlTemplate ?sparqlTemplate ;
|
|
38
|
+
intentMapping:hasArgument ?hasArgument ;
|
|
39
|
+
rdfs:label ?label .
|
|
40
|
+
}
|
|
41
|
+
""")
|
|
42
|
+
|
|
43
|
+
queries = {}
|
|
44
|
+
|
|
45
|
+
for result in results:
|
|
46
|
+
query, label, description, sparqlTemplate, hasArgument = result
|
|
47
|
+
queries[query] = {
|
|
48
|
+
"label": label,
|
|
49
|
+
"description": description,
|
|
50
|
+
"sparqlTemplate": sparqlTemplate,
|
|
51
|
+
"hasArgument": [hasArgument]
|
|
52
|
+
if (query not in queries or queries[query].get("hasArgument") is None)
|
|
53
|
+
else queries[query].get("hasArgument") + [hasArgument],
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
arguments = {}
|
|
57
|
+
|
|
58
|
+
argument_graph = Graph()
|
|
59
|
+
argument_graph.bind(
|
|
60
|
+
"intentMapping", URIRef("http://ontology.naas.ai/intentMapping/")
|
|
61
|
+
)
|
|
62
|
+
results = self.triple_store_service.query("""
|
|
63
|
+
PREFIX intentMapping: <http://ontology.naas.ai/intentMapping/>
|
|
64
|
+
|
|
65
|
+
SELECT ?argument ?name ?description ?validationPattern ?validationFormat
|
|
66
|
+
WHERE {
|
|
67
|
+
?argument a intentMapping:QueryArgument ;
|
|
68
|
+
intentMapping:argumentName ?name ;
|
|
69
|
+
intentMapping:argumentDescription ?description ;
|
|
70
|
+
intentMapping:validationPattern ?validationPattern ;
|
|
71
|
+
intentMapping:validationFormat ?validationFormat .
|
|
72
|
+
}
|
|
73
|
+
""")
|
|
74
|
+
|
|
75
|
+
for argument, name, description, validationPattern, validationFormat in results:
|
|
76
|
+
argument_graph.add(
|
|
77
|
+
(
|
|
78
|
+
argument,
|
|
79
|
+
RDF.type,
|
|
80
|
+
URIRef("http://ontology.naas.ai/intentMapping/QueryArgument"),
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
argument_graph.add(
|
|
84
|
+
(
|
|
85
|
+
argument,
|
|
86
|
+
URIRef("http://ontology.naas.ai/intentMapping/argumentName"),
|
|
87
|
+
name,
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
argument_graph.add(
|
|
91
|
+
(
|
|
92
|
+
argument,
|
|
93
|
+
URIRef("http://ontology.naas.ai/intentMapping/argumentDescription"),
|
|
94
|
+
description,
|
|
95
|
+
)
|
|
96
|
+
)
|
|
97
|
+
argument_graph.add(
|
|
98
|
+
(
|
|
99
|
+
argument,
|
|
100
|
+
URIRef("http://ontology.naas.ai/intentMapping/validationPattern"),
|
|
101
|
+
validationPattern,
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
argument_graph.add(
|
|
105
|
+
(
|
|
106
|
+
argument,
|
|
107
|
+
URIRef("http://ontology.naas.ai/intentMapping/validationFormat"),
|
|
108
|
+
validationFormat,
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
arguments = {}
|
|
113
|
+
for templatableQuery in queries:
|
|
114
|
+
for argument in queries[templatableQuery].get("hasArgument"):
|
|
115
|
+
q = (
|
|
116
|
+
"""
|
|
117
|
+
PREFIX intentMapping: <http://ontology.naas.ai/intentMapping/>
|
|
118
|
+
|
|
119
|
+
SELECT ?argument ?name ?description ?validationPattern ?validationFormat
|
|
120
|
+
WHERE {
|
|
121
|
+
BIND(<"""
|
|
122
|
+
+ str(argument)
|
|
123
|
+
+ """> AS ?argument)
|
|
124
|
+
?argument a intentMapping:QueryArgument ;
|
|
125
|
+
intentMapping:argumentName ?name ;
|
|
126
|
+
intentMapping:argumentDescription ?description ;
|
|
127
|
+
intentMapping:validationPattern ?validationPattern ;
|
|
128
|
+
intentMapping:validationFormat ?validationFormat .
|
|
129
|
+
}
|
|
130
|
+
"""
|
|
131
|
+
)
|
|
132
|
+
# logger.debug(f"Query: {q}")
|
|
133
|
+
results = argument_graph.query(q)
|
|
134
|
+
|
|
135
|
+
for result in results:
|
|
136
|
+
argument, name, description, validationPattern, validationFormat = (
|
|
137
|
+
result
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
arguments[argument] = {
|
|
141
|
+
"name": name,
|
|
142
|
+
"description": description,
|
|
143
|
+
"validationPattern": validationPattern,
|
|
144
|
+
"validationFormat": validationFormat,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return queries, arguments
|
|
148
|
+
|
|
149
|
+
def load_workflows(self):
|
|
150
|
+
workflows = []
|
|
151
|
+
|
|
152
|
+
queries, arguments = self.templatable_queries()
|
|
153
|
+
|
|
154
|
+
# workflows = asyncio.run(__load_queries(queries, arguments))
|
|
155
|
+
|
|
156
|
+
# Now for each query, we need to create a Pydantic BaseModel based on the arguments
|
|
157
|
+
for _query in queries:
|
|
158
|
+
try:
|
|
159
|
+
query = queries[_query]
|
|
160
|
+
|
|
161
|
+
# Arguments Model with validation patterns
|
|
162
|
+
arguments_model = create_model(
|
|
163
|
+
f"{str(query['label']).capitalize()}Arguments",
|
|
164
|
+
**{
|
|
165
|
+
str(arguments[argument]["name"]): (
|
|
166
|
+
str,
|
|
167
|
+
Field(
|
|
168
|
+
...,
|
|
169
|
+
description=str(arguments[argument]["description"]),
|
|
170
|
+
pattern=str(arguments[argument]["validationPattern"]),
|
|
171
|
+
# You could also add additional metadata from validationFormat if needed
|
|
172
|
+
example=str(arguments[argument]["validationFormat"]),
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
for argument in query.get("hasArgument")
|
|
176
|
+
},
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
p = GenericWorkflow[arguments_model](
|
|
180
|
+
str(query["label"]),
|
|
181
|
+
str(query["description"]),
|
|
182
|
+
str(query["sparqlTemplate"]),
|
|
183
|
+
arguments_model,
|
|
184
|
+
self.triple_store_service,
|
|
185
|
+
)
|
|
186
|
+
workflows.append(p)
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.warning(
|
|
189
|
+
f"Error loading workflow for query {query['label']}\nMessage: {e}"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
return workflows
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from naas_abi_core.pipeline.pipeline import Graph as Graph
|
|
2
|
+
from naas_abi_core.pipeline.pipeline import Pipeline as Pipeline
|
|
3
|
+
from naas_abi_core.pipeline.pipeline import (
|
|
4
|
+
PipelineConfiguration as PipelineConfiguration,
|
|
5
|
+
)
|
|
6
|
+
from naas_abi_core.pipeline.pipeline import PipelineParameters as PipelineParameters
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
from rdflib import Graph
|
|
7
|
+
|
|
8
|
+
from naas_abi_core.services.triple_store.TripleStorePorts import OntologyEvent
|
|
9
|
+
from naas_abi_core.utils.Expose import Expose
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PipelineConfiguration:
|
|
14
|
+
"""Base configuration class for pipelines.
|
|
15
|
+
|
|
16
|
+
This class serves as the base configuration for all pipeline classes.
|
|
17
|
+
Concrete pipeline implementations should extend this class and add their
|
|
18
|
+
specific configuration attributes.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PipelineParameters(BaseModel):
|
|
25
|
+
"""Base parameters class for pipeline execution.
|
|
26
|
+
|
|
27
|
+
This class serves as the base parameters for all pipeline executions.
|
|
28
|
+
Concrete pipeline implementations should extend this class and add their
|
|
29
|
+
specific runtime parameters.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Pipeline(Expose):
|
|
36
|
+
__configuration: PipelineConfiguration
|
|
37
|
+
|
|
38
|
+
def __init__(self, configuration: PipelineConfiguration):
|
|
39
|
+
self.__configuration = configuration
|
|
40
|
+
|
|
41
|
+
# TODO: Make this an abstract method
|
|
42
|
+
# @abstractmethod
|
|
43
|
+
def trigger(
|
|
44
|
+
self, event: OntologyEvent, ontology_name: str, triple: tuple[Any, Any, Any]
|
|
45
|
+
) -> Graph:
|
|
46
|
+
"""Trigger the pipeline with the given event and triple.
|
|
47
|
+
|
|
48
|
+
This method should be implemented by concrete pipeline classes to process data
|
|
49
|
+
according to their specific logic and configuration.
|
|
50
|
+
"""
|
|
51
|
+
raise NotImplementedError()
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def run(self, parameters: PipelineParameters) -> Graph:
|
|
55
|
+
"""Execute the pipeline with the given parameters.
|
|
56
|
+
|
|
57
|
+
This method should be implemented by concrete pipeline classes to process data
|
|
58
|
+
according to their specific logic and configuration.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
parameters (PipelineParameters): Runtime parameters for pipeline execution
|
|
62
|
+
that control how the pipeline processes data
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Graph: An RDF graph containing the processed data and relationships
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
NotImplementedError: If the concrete class does not implement this method
|
|
69
|
+
"""
|
|
70
|
+
raise NotImplementedError()
|
|
File without changes
|