naas-abi 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.
Files changed (62) hide show
  1. naas_abi/__init__.py +35 -0
  2. naas_abi/agents/AbiAgent.py +442 -0
  3. naas_abi/agents/AbiAgent_test.py +157 -0
  4. naas_abi/agents/EntitytoSPARQLAgent.py +952 -0
  5. naas_abi/agents/EntitytoSPARQLAgent_test.py +66 -0
  6. naas_abi/agents/KnowledgeGraphBuilderAgent.py +321 -0
  7. naas_abi/agents/KnowledgeGraphBuilderAgent_test.py +86 -0
  8. naas_abi/agents/OntologyEngineerAgent.py +115 -0
  9. naas_abi/agents/OntologyEngineerAgent_test.py +42 -0
  10. naas_abi/apps/oxigraph_admin/main.py +392 -0
  11. naas_abi/apps/oxigraph_admin/terminal_style.py +151 -0
  12. naas_abi/apps/sparql_terminal/main.py +68 -0
  13. naas_abi/apps/sparql_terminal/terminal_style.py +236 -0
  14. naas_abi/apps/terminal_agent/main.py +553 -0
  15. naas_abi/apps/terminal_agent/terminal_style.py +175 -0
  16. naas_abi/cli.py +714 -0
  17. naas_abi/mappings.py +83 -0
  18. naas_abi/models/airgap_gemma.py +220 -0
  19. naas_abi/models/airgap_qwen.py +24 -0
  20. naas_abi/models/default.py +23 -0
  21. naas_abi/models/gpt_4_1.py +25 -0
  22. naas_abi/pipelines/AIAgentOntologyGenerationPipeline.py +635 -0
  23. naas_abi/pipelines/AIAgentOntologyGenerationPipeline_test.py +133 -0
  24. naas_abi/pipelines/AddIndividualPipeline.py +215 -0
  25. naas_abi/pipelines/AddIndividualPipeline_test.py +66 -0
  26. naas_abi/pipelines/InsertDataSPARQLPipeline.py +197 -0
  27. naas_abi/pipelines/InsertDataSPARQLPipeline_test.py +96 -0
  28. naas_abi/pipelines/MergeIndividualsPipeline.py +245 -0
  29. naas_abi/pipelines/MergeIndividualsPipeline_test.py +98 -0
  30. naas_abi/pipelines/RemoveIndividualPipeline.py +166 -0
  31. naas_abi/pipelines/RemoveIndividualPipeline_test.py +58 -0
  32. naas_abi/pipelines/UpdateCommercialOrganizationPipeline.py +198 -0
  33. naas_abi/pipelines/UpdateDataPropertyPipeline.py +175 -0
  34. naas_abi/pipelines/UpdateLegalNamePipeline.py +107 -0
  35. naas_abi/pipelines/UpdateLinkedInPagePipeline.py +179 -0
  36. naas_abi/pipelines/UpdatePersonPipeline.py +184 -0
  37. naas_abi/pipelines/UpdateSkillPipeline.py +118 -0
  38. naas_abi/pipelines/UpdateTickerPipeline.py +104 -0
  39. naas_abi/pipelines/UpdateWebsitePipeline.py +106 -0
  40. naas_abi/triggers.py +131 -0
  41. naas_abi/workflows/AgentRecommendationWorkflow.py +321 -0
  42. naas_abi/workflows/AgentRecommendationWorkflow_test.py +160 -0
  43. naas_abi/workflows/ArtificialAnalysisWorkflow.py +337 -0
  44. naas_abi/workflows/ArtificialAnalysisWorkflow_test.py +57 -0
  45. naas_abi/workflows/ConvertOntologyGraphToYamlWorkflow.py +210 -0
  46. naas_abi/workflows/ConvertOntologyGraphToYamlWorkflow_test.py +78 -0
  47. naas_abi/workflows/CreateClassOntologyYamlWorkflow.py +208 -0
  48. naas_abi/workflows/CreateClassOntologyYamlWorkflow_test.py +65 -0
  49. naas_abi/workflows/CreateIndividualOntologyYamlWorkflow.py +183 -0
  50. naas_abi/workflows/CreateIndividualOntologyYamlWorkflow_test.py +86 -0
  51. naas_abi/workflows/ExportGraphInstancesToExcelWorkflow.py +450 -0
  52. naas_abi/workflows/ExportGraphInstancesToExcelWorkflow_test.py +33 -0
  53. naas_abi/workflows/GetObjectPropertiesFromClassWorkflow.py +385 -0
  54. naas_abi/workflows/GetObjectPropertiesFromClassWorkflow_test.py +57 -0
  55. naas_abi/workflows/GetSubjectGraphWorkflow.py +84 -0
  56. naas_abi/workflows/GetSubjectGraphWorkflow_test.py +71 -0
  57. naas_abi/workflows/SearchIndividualWorkflow.py +190 -0
  58. naas_abi/workflows/SearchIndividualWorkflow_test.py +98 -0
  59. naas_abi-1.0.0.dist-info/METADATA +9 -0
  60. naas_abi-1.0.0.dist-info/RECORD +62 -0
  61. naas_abi-1.0.0.dist-info/WHEEL +5 -0
  62. naas_abi-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,133 @@
1
+ import json
2
+
3
+ import pytest
4
+ from naas_abi.pipelines.AIAgentOntologyGenerationPipeline import (
5
+ AIAgentOntologyGenerationConfiguration,
6
+ AIAgentOntologyGenerationParameters,
7
+ AIAgentOntologyGenerationPipeline,
8
+ )
9
+
10
+
11
+ @pytest.fixture
12
+ def pipeline() -> AIAgentOntologyGenerationPipeline:
13
+ from naas_abi import services
14
+
15
+ pipeline_configuration = AIAgentOntologyGenerationConfiguration(
16
+ triple_store=services.triple_store,
17
+ datastore_path="storage/datastore/test/ai_agent_ontology_generation",
18
+ source_datastore_path="storage/datastore/test/artificial_analysis_workflow",
19
+ )
20
+
21
+ return AIAgentOntologyGenerationPipeline(pipeline_configuration)
22
+
23
+
24
+ @pytest.fixture
25
+ def mock_aa_data():
26
+ """Mock Artificial Analysis data for testing."""
27
+ return {
28
+ "llms": [
29
+ {
30
+ "name": "GPT-4o",
31
+ "slug": "gpt-4o",
32
+ "model_creator": {"name": "OpenAI", "slug": "openai"},
33
+ "pricing": {
34
+ "input_cost": 5.0,
35
+ "output_cost": 15.0,
36
+ "blended_cost": 10.0,
37
+ },
38
+ "performance": {
39
+ "output_speed": 25.5,
40
+ "time_to_first_token": 0.5,
41
+ "time_to_first_answer_token": 1.2,
42
+ },
43
+ "evaluations": {"index": 85, "coding_index": 90, "math_index": 80},
44
+ },
45
+ {
46
+ "name": "Claude 3.5 Sonnet",
47
+ "slug": "claude-35-sonnet",
48
+ "model_creator": {"name": "Anthropic", "slug": "anthropic"},
49
+ "pricing": {
50
+ "input_cost": 3.0,
51
+ "output_cost": 15.0,
52
+ "blended_cost": 9.0,
53
+ },
54
+ "performance": {
55
+ "output_speed": 22.1,
56
+ "time_to_first_token": 0.8,
57
+ "time_to_first_answer_token": 1.5,
58
+ },
59
+ "evaluations": {"index": 88, "coding_index": 85, "math_index": 82},
60
+ },
61
+ ]
62
+ }
63
+
64
+
65
+ def test_pipeline_basic_functionality(
66
+ pipeline: AIAgentOntologyGenerationPipeline, mock_aa_data, tmp_path
67
+ ):
68
+ """Test basic pipeline functionality with mock data."""
69
+
70
+ # Setup test paths
71
+ source_path = tmp_path / "source"
72
+ source_path.mkdir()
73
+ output_path = tmp_path / "output"
74
+
75
+ # Create mock data file
76
+ mock_file = source_path / "20250811T120000_llms_data.json"
77
+ with open(mock_file, "w") as f:
78
+ json.dump(mock_aa_data, f)
79
+
80
+ # Update configuration paths
81
+ config = pipeline.get_configuration()
82
+ config.source_datastore_path = str(source_path)
83
+ config.datastore_path = str(output_path)
84
+
85
+ # Run pipeline
86
+ parameters = AIAgentOntologyGenerationParameters(force_regenerate=True)
87
+ graph = pipeline.run(parameters)
88
+
89
+ assert graph is not None
90
+
91
+ # Verify triples were added
92
+ triples = list(graph)
93
+ assert len(triples) > 0
94
+
95
+ for s, p, o in triples:
96
+ assert s is not None
97
+ assert p is not None
98
+ assert o is not None
99
+
100
+
101
+ def test_model_mapping_logic(pipeline: AIAgentOntologyGenerationPipeline):
102
+ """Test the model to agent mapping logic."""
103
+
104
+ # Test GPT model mapping
105
+ gpt_model = {
106
+ "name": "GPT-4o",
107
+ "slug": "gpt-4o",
108
+ "model_creator": {"name": "OpenAI"},
109
+ }
110
+ assert pipeline._determine_ai_agent_module(gpt_model) == "chatgpt"
111
+
112
+ # Test Claude model mapping
113
+ claude_model = {
114
+ "name": "Claude 3.5 Sonnet",
115
+ "slug": "claude-35-sonnet",
116
+ "model_creator": {"name": "Anthropic"},
117
+ }
118
+ assert pipeline._determine_ai_agent_module(claude_model) == "claude"
119
+
120
+ # Test Gemini vs Gemma mapping
121
+ gemini_model = {
122
+ "name": "Gemini 2.0",
123
+ "slug": "gemini-2-0",
124
+ "model_creator": {"name": "Google"},
125
+ }
126
+ assert pipeline._determine_ai_agent_module(gemini_model) == "gemini"
127
+
128
+ gemma_model = {
129
+ "name": "Gemma 3 27B",
130
+ "slug": "gemma-3-27b",
131
+ "model_creator": {"name": "Google"},
132
+ }
133
+ assert pipeline._determine_ai_agent_module(gemma_model) == "gemma"
@@ -0,0 +1,215 @@
1
+ import uuid
2
+ from dataclasses import dataclass
3
+ from enum import Enum
4
+ from typing import Annotated, Optional
5
+
6
+ from fastapi import APIRouter
7
+ from langchain_core.tools import BaseTool, StructuredTool
8
+ from naas_abi.workflows.SearchIndividualWorkflow import (
9
+ SearchIndividualWorkflow,
10
+ SearchIndividualWorkflowConfiguration,
11
+ SearchIndividualWorkflowParameters,
12
+ )
13
+ from naas_abi_core import logger
14
+ from naas_abi_core.pipeline import Pipeline, PipelineConfiguration, PipelineParameters
15
+ from naas_abi_core.services.triple_store.TripleStorePorts import ITripleStoreService
16
+ from pydantic import Field
17
+ from rdflib import DCTERMS, OWL, RDF, RDFS, Graph, Literal, Namespace, URIRef
18
+
19
+ BFO = Namespace("http://purl.obolibrary.org/obo/")
20
+ CCO = Namespace("https://www.commoncoreontologies.org/")
21
+ ABI = Namespace("http://ontology.naas.ai/abi/")
22
+ URI_REGEX = r"http:\/\/ontology\.naas\.ai\/abi\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
23
+
24
+
25
+ @dataclass
26
+ class AddIndividualPipelineConfiguration(PipelineConfiguration):
27
+ """Configuration for AddIndividualPipeline.
28
+
29
+ Attributes:
30
+ triple_store (ITripleStoreService): The ontology store service to use
31
+ search_individual_workflow (SearchIndividualWorkflow): The search individual workflow to use
32
+ """
33
+
34
+ triple_store: ITripleStoreService
35
+ search_individual_configuration: SearchIndividualWorkflowConfiguration
36
+
37
+
38
+ class AddIndividualPipelineParameters(PipelineParameters):
39
+ individual_label: Annotated[
40
+ str,
41
+ Field(
42
+ description="Individual label to add to the ontology.", example="Naas.ai"
43
+ ),
44
+ ]
45
+ class_uri: Annotated[
46
+ str,
47
+ Field(
48
+ description="Class URI to add the individual to. Use tool `search_class` to search for a class URI in the ontology.",
49
+ example="https://www.commoncoreontologies.org/ont00000443",
50
+ ),
51
+ ]
52
+ threshold: Annotated[
53
+ Optional[int],
54
+ Field(
55
+ description="Threshold to use for the search individual workflow.",
56
+ ge=0,
57
+ le=100,
58
+ ),
59
+ ] = 80
60
+
61
+
62
+ class AddIndividualPipeline(Pipeline):
63
+ """Pipeline for adding a named individual."""
64
+
65
+ __configuration: AddIndividualPipelineConfiguration
66
+
67
+ def __init__(self, configuration: AddIndividualPipelineConfiguration):
68
+ super().__init__(configuration)
69
+ self.__configuration = configuration
70
+ self.__search_individual_workflow = SearchIndividualWorkflow(
71
+ configuration.search_individual_configuration
72
+ )
73
+
74
+ def run(self, parameters: PipelineParameters) -> Graph:
75
+ if not isinstance(parameters, AddIndividualPipelineParameters):
76
+ raise ValueError(
77
+ "Parameters must be of type AddIndividualPipelineParameters"
78
+ )
79
+
80
+ # Search for individual
81
+ search_individual_result = self.__search_individual_workflow.search_individual(
82
+ SearchIndividualWorkflowParameters(
83
+ class_uri=parameters.class_uri,
84
+ search_label=parameters.individual_label,
85
+ )
86
+ )
87
+ filtered_results = [
88
+ result
89
+ for result in search_individual_result
90
+ if parameters.threshold is not None
91
+ and int(result["score"]) >= parameters.threshold
92
+ ]
93
+ if len(filtered_results) > 0:
94
+ individual_uri = filtered_results[0]["individual_uri"]
95
+ logger.debug(
96
+ f"🔍 Found individual '{parameters.individual_label}' in the ontology: {individual_uri} from class: {parameters.class_uri}"
97
+ )
98
+ return self.__configuration.triple_store.get_subject_graph(individual_uri)
99
+
100
+ # Init graph
101
+ graph = Graph()
102
+ graph.bind("bfo", BFO)
103
+ graph.bind("cco", CCO)
104
+ graph.bind("abi", ABI)
105
+ graph.bind("dcterms", DCTERMS)
106
+
107
+ # Add individual
108
+ individual_uri = ABI[str(uuid.uuid4())]
109
+ graph.add((individual_uri, RDF.type, OWL.NamedIndividual))
110
+ graph.add((individual_uri, RDF.type, URIRef(parameters.class_uri)))
111
+ graph.add((individual_uri, RDFS.label, Literal(parameters.individual_label)))
112
+ self.__configuration.triple_store.insert(graph)
113
+ return graph
114
+
115
+ def as_tools(self) -> list[BaseTool]:
116
+ return [
117
+ StructuredTool(
118
+ name="add_individual_to_triple_store",
119
+ description="Add a new individual/instance to triple store.",
120
+ func=lambda **kwargs: self.run(
121
+ AddIndividualPipelineParameters(**kwargs)
122
+ ),
123
+ args_schema=AddIndividualPipelineParameters,
124
+ ),
125
+ StructuredTool(
126
+ name="add_commercial_organization",
127
+ description="Add a new commercial organization to ontology.",
128
+ func=lambda **kwargs: self.run(
129
+ AddIndividualPipelineParameters(
130
+ class_uri="https://www.commoncoreontologies.org/ont00000443",
131
+ individual_label=kwargs["individual_label"],
132
+ )
133
+ ),
134
+ args_schema=AddIndividualPipelineParameters,
135
+ ),
136
+ StructuredTool(
137
+ name="add_person",
138
+ description="Add a new person to ontology.",
139
+ func=lambda **kwargs: self.run(
140
+ AddIndividualPipelineParameters(
141
+ class_uri="https://www.commoncoreontologies.org/ont00001262",
142
+ individual_label=kwargs["individual_label"],
143
+ )
144
+ ),
145
+ args_schema=AddIndividualPipelineParameters,
146
+ ),
147
+ StructuredTool(
148
+ name="add_website",
149
+ description="Add a new website to ontology.",
150
+ func=lambda **kwargs: self.run(
151
+ AddIndividualPipelineParameters(
152
+ class_uri=ABI.Website,
153
+ individual_label=kwargs["individual_label"],
154
+ )
155
+ ),
156
+ args_schema=AddIndividualPipelineParameters,
157
+ ),
158
+ StructuredTool(
159
+ name="add_skill",
160
+ description="Add a new skill to ontology.",
161
+ func=lambda **kwargs: self.run(
162
+ AddIndividualPipelineParameters(
163
+ class_uri=CCO.ont00000089,
164
+ individual_label=kwargs["individual_label"],
165
+ )
166
+ ),
167
+ args_schema=AddIndividualPipelineParameters,
168
+ ),
169
+ StructuredTool(
170
+ name="add_legal_name",
171
+ description="Add a new legal name of a commercial organization.",
172
+ func=lambda **kwargs: self.run(
173
+ AddIndividualPipelineParameters(
174
+ class_uri=CCO.ont00001331,
175
+ individual_label=kwargs["individual_label"],
176
+ )
177
+ ),
178
+ args_schema=AddIndividualPipelineParameters,
179
+ ),
180
+ StructuredTool(
181
+ name="add_ticker_symbol",
182
+ description="Add a new ticker symbol to triple store.",
183
+ func=lambda **kwargs: self.run(
184
+ AddIndividualPipelineParameters(
185
+ class_uri=ABI.Ticker,
186
+ individual_label=kwargs["individual_label"],
187
+ )
188
+ ),
189
+ args_schema=AddIndividualPipelineParameters,
190
+ ),
191
+ StructuredTool(
192
+ name="add_linkedin_page",
193
+ description="Add a new LinkedIn page represented by a profile or organization to triple store.",
194
+ func=lambda **kwargs: self.run(
195
+ AddIndividualPipelineParameters(
196
+ class_uri=ABI.LinkedInProfilePage,
197
+ individual_label=kwargs["individual_label"],
198
+ )
199
+ ),
200
+ args_schema=AddIndividualPipelineParameters,
201
+ ),
202
+ ]
203
+
204
+ def as_api(
205
+ self,
206
+ router: APIRouter,
207
+ route_name: str = "",
208
+ name: str = "",
209
+ description: str = "",
210
+ description_stream: str = "",
211
+ tags: list[str | Enum] | None = None,
212
+ ) -> None:
213
+ if tags is None:
214
+ tags = []
215
+ return None
@@ -0,0 +1,66 @@
1
+ import pytest
2
+ from naas_abi import services
3
+ from naas_abi.pipelines.AddIndividualPipeline import (
4
+ AddIndividualPipeline,
5
+ AddIndividualPipelineConfiguration,
6
+ AddIndividualPipelineParameters,
7
+ )
8
+ from naas_abi.workflows.SearchIndividualWorkflow import (
9
+ SearchIndividualWorkflowConfiguration,
10
+ )
11
+
12
+
13
+ @pytest.fixture
14
+ def pipeline() -> AddIndividualPipeline:
15
+ search_individual_workflow_configuration = SearchIndividualWorkflowConfiguration(
16
+ triple_store=services.triple_store_service
17
+ )
18
+ pipeline = AddIndividualPipeline(
19
+ configuration=AddIndividualPipelineConfiguration(
20
+ triple_store=services.triple_store_service,
21
+ search_individual_configuration=search_individual_workflow_configuration,
22
+ )
23
+ )
24
+ return pipeline
25
+
26
+
27
+ def test_add_individual_pipeline(pipeline: AddIndividualPipeline):
28
+ from naas_abi.utils.SPARQL import results_to_list
29
+ from rdflib import OWL, RDF, RDFS, Literal, URIRef
30
+
31
+ label = "Naas.ai"
32
+ class_uri = "https://www.commoncoreontologies.org/ont00000443"
33
+ graph = pipeline.run(
34
+ AddIndividualPipelineParameters(individual_label=label, class_uri=class_uri)
35
+ )
36
+
37
+ individual_uri = list(graph.triples((None, RDF.type, OWL.NamedIndividual)))[0][0]
38
+
39
+ assert graph is not None, graph.serialize(format="turtle")
40
+ assert len(list(graph.triples((None, RDFS.label, Literal(label))))) == 1, (
41
+ graph.serialize(format="turtle")
42
+ )
43
+ assert len(list(graph.triples((None, RDF.type, URIRef(class_uri))))) == 1, (
44
+ graph.serialize(format="turtle")
45
+ )
46
+
47
+ # Remove graph
48
+ services.triple_store_service.remove(graph)
49
+
50
+ # Check triples are removed from the triple store
51
+ sparql_query = """
52
+ PREFIX abi: <http://ontology.naas.ai/abi/>
53
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
54
+ PREFIX cco: <https://www.commoncoreontologies.org/>
55
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
56
+
57
+ SELECT ?s ?p ?o
58
+ WHERE {
59
+ ?s ?p ?o .
60
+ FILTER(?s = <{{individual_uri}}>)
61
+ }
62
+ """
63
+ sparql_query = sparql_query.replace("{{individual_uri}}", str(individual_uri))
64
+ results = services.triple_store_service.query(sparql_query)
65
+ results_list = results_to_list(results)
66
+ assert results_list is None, results_list
@@ -0,0 +1,197 @@
1
+ from dataclasses import dataclass
2
+ from enum import Enum
3
+ from typing import Annotated
4
+
5
+ from fastapi import APIRouter
6
+ from langchain_core.tools import BaseTool, StructuredTool
7
+ from naas_abi_core import logger
8
+ from naas_abi_core.pipeline import Pipeline, PipelineConfiguration, PipelineParameters
9
+ from naas_abi_core.services.triple_store.TripleStorePorts import ITripleStoreService
10
+ from pydantic import Field
11
+ from rdflib import Graph, Namespace
12
+
13
+ BFO = Namespace("http://purl.obolibrary.org/obo/")
14
+ CCO = Namespace("https://www.commoncoreontologies.org/")
15
+ ABI = Namespace("http://ontology.naas.ai/abi/")
16
+
17
+
18
+ @dataclass
19
+ class InsertDataSPARQLPipelineConfiguration(PipelineConfiguration):
20
+ """Configuration for InsertDataSPARQLPipeline.
21
+
22
+ Attributes:
23
+ triple_store (ITripleStoreService): The triple store service to use
24
+ """
25
+
26
+ triple_store: ITripleStoreService
27
+
28
+
29
+ class InsertDataSPARQLPipelineParameters(PipelineParameters):
30
+ """Parameters for InsertDataSPARQLPipeline execution.
31
+
32
+ Attributes:
33
+ sparql_statement (str): The SPARQL INSERT DATA statement to execute
34
+ """
35
+
36
+ sparql_statement: Annotated[
37
+ str,
38
+ Field(
39
+ description="SPARQL INSERT DATA statement to execute. Must be a valid SPARQL INSERT DATA query."
40
+ ),
41
+ ]
42
+
43
+
44
+ class InsertDataSPARQLPipeline(Pipeline):
45
+ """Pipeline for executing SPARQL INSERT DATA statements on the ontology."""
46
+
47
+ __configuration: InsertDataSPARQLPipelineConfiguration
48
+
49
+ def __init__(self, configuration: InsertDataSPARQLPipelineConfiguration):
50
+ super().__init__(configuration)
51
+ self.__configuration = configuration
52
+
53
+ def get_sparql_from_text(
54
+ self, parameters: InsertDataSPARQLPipelineParameters
55
+ ) -> str:
56
+ """Get the SPARQL INSERT DATA statement from the text.
57
+
58
+ Args:
59
+ text (str): The text to extract the SPARQL INSERT DATA statement from
60
+
61
+ Returns:
62
+ str: The SPARQL INSERT DATA statement
63
+ """
64
+ text = parameters.sparql_statement
65
+
66
+ # Clean the statement from the ```sparql and ```
67
+ text = text.split("```sparql")[-1].split("```")[0].strip()
68
+ if "INSERT DATA" in text:
69
+ logger.info(f"✅ SPARQL INSERT DATA statement found: {text}")
70
+ return text
71
+ return f"No SPARQL INSERT DATA statement found in statement: {parameters.sparql_statement}"
72
+
73
+ def run(self, parameters: PipelineParameters) -> Graph:
74
+ """Execute the SPARQL INSERT DATA statement.
75
+
76
+ Args:
77
+ parameters (PipelineParameters): Must be InsertDataSPARQLPipelineParameters
78
+
79
+ Returns:
80
+ Graph: The graph with the inserted data
81
+
82
+ Raises:
83
+ ValueError: If parameters are not of the correct type
84
+ """
85
+ if not isinstance(parameters, InsertDataSPARQLPipelineParameters):
86
+ raise ValueError(
87
+ "Parameters must be of type InsertDataSPARQLPipelineParameters"
88
+ )
89
+
90
+ logger.info("Executing SPARQL INSERT DATA statement...")
91
+
92
+ # Initialize a new graph with common namespace bindings
93
+ graph = Graph()
94
+ graph.bind("bfo", BFO)
95
+ graph.bind("cco", CCO)
96
+ graph.bind("abi", ABI)
97
+
98
+ # Execute the SPARQL INSERT DATA statement
99
+ try:
100
+ sparql_statement = self.get_sparql_from_text(parameters)
101
+ graph.update(sparql_statement)
102
+ logger.info("✅ SPARQL INSERT DATA is valid.")
103
+ except Exception as e:
104
+ logger.error(f"❌ Failed to execute SPARQL INSERT DATA: {e}")
105
+ return Graph()
106
+
107
+ # Insert the graph into the triple store
108
+ if len(graph) > 0:
109
+ logger.info("✅ Inserting data to triplestore:")
110
+ logger.info(graph.serialize(format="turtle"))
111
+ self.__configuration.triple_store.insert(graph)
112
+ else:
113
+ logger.info("❌ No data to insert")
114
+ return graph
115
+
116
+ def as_tools(self) -> list[BaseTool]:
117
+ """Returns a list of LangChain tools for this pipeline.
118
+
119
+ Returns:
120
+ list[BaseTool]: List containing the pipeline tool
121
+ """
122
+ return [
123
+ StructuredTool(
124
+ name="insert_data_sparql",
125
+ description="Execute a SPARQL INSERT DATA statement to add triples to the triple store",
126
+ func=lambda **kwargs: self.run(
127
+ InsertDataSPARQLPipelineParameters(**kwargs)
128
+ ),
129
+ args_schema=InsertDataSPARQLPipelineParameters,
130
+ ),
131
+ StructuredTool(
132
+ name="extract_sparql_from_text",
133
+ description="Extract a SPARQL INSERT DATA statement from the text",
134
+ func=lambda **kwargs: self.get_sparql_from_text(
135
+ InsertDataSPARQLPipelineParameters(**kwargs)
136
+ ),
137
+ args_schema=InsertDataSPARQLPipelineParameters,
138
+ ),
139
+ ]
140
+
141
+ def as_api(
142
+ self,
143
+ router: APIRouter,
144
+ route_name: str = "",
145
+ name: str = "",
146
+ description: str = "",
147
+ description_stream: str = "",
148
+ tags: list[str | Enum] | None = None,
149
+ ) -> None:
150
+ """Register API endpoints for this pipeline.
151
+
152
+ Args:
153
+ router: FastAPI router to register endpoints on
154
+ route_name: Name for the route
155
+ name: Display name for the endpoint
156
+ description: Description for the endpoint
157
+ description_stream: Description for streaming endpoint
158
+ tags: Tags for the endpoint
159
+ """
160
+ if tags is None:
161
+ tags = []
162
+ return None
163
+
164
+
165
+ if __name__ == "__main__":
166
+ from naas_abi import services
167
+
168
+ sparql_statement = """
169
+ PREFIX abi: <http://ontology.naas.ai/abi/>
170
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
171
+ PREFIX cco: <https://www.commoncoreontologies.org/>
172
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
173
+
174
+ INSERT DATA {
175
+ abi:john a cco:ont00001262, owl:NamedIndividual ;
176
+ abi:name "John Doe" ;
177
+ abi:age 30 ;
178
+ abi:email "john.doe@example.com" .
179
+
180
+ abi:jane a cco:ont00001262, owl:NamedIndividual ;
181
+ abi:name "Jane Smith" ;
182
+ abi:age 28 ;
183
+ abi:email "jane.smith@example.com" .
184
+ }
185
+ """
186
+ pipeline = InsertDataSPARQLPipeline(
187
+ InsertDataSPARQLPipelineConfiguration(
188
+ triple_store=services.triple_store_service
189
+ )
190
+ )
191
+ # result = pipeline.get_sparql_from_text(InsertDataSPARQLPipelineParameters(sparql_statement=sparql_statement))
192
+ # logger.info(result)
193
+
194
+ result = pipeline.run(
195
+ InsertDataSPARQLPipelineParameters(sparql_statement=sparql_statement)
196
+ )
197
+ logger.info(result)