Knowledge2Model/question2sparql.py

241 lines
7.4 KiB
Python

from langchain_openai import ChatOpenAI
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
import rdflib
g = rdflib.Graph()
g.parse("GraphEditingTool/CustomGraph.ttl")
ml_goal_query = """
PREFIX sc: <http://purl.org/science/owl/sciencecommons/>
SELECT ?o
WHERE { ?s sc:mlgoal ?o }
"""
def construct_schema(graph):
query_classes = """
SELECT DISTINCT ?class WHERE {
?s a ?class.
}
"""
query_properties = """
SELECT DISTINCT ?property WHERE {
?s ?property ?o.
}
"""
classes = graph.query(query_classes)
class_list = []
for row in classes:
class_list.append(str(row['class']))
# Execute the query for properties
properties = graph.query(query_properties)
property_list = []
for row in properties:
property_list.append(str(row['property']))
namespaces_list = []
prefix_list = []
for prefix, namespace in graph.namespaces():
namespaces_list.append(str(namespace))
prefix_list.append(str(prefix))
used_ns_list = []
updated_class_list = []
for element in class_list:
for ns in namespaces_list:
if ns in element:
updated = class_list[class_list.index(element)].replace(ns, prefix_list[namespaces_list.index(ns)]+":")
used_ns_list.append(namespaces_list.index(ns))
updated_class_list.append(updated)
updated_prop_list = []
for element in property_list:
for ns in namespaces_list:
if ns in element:
update = property_list[property_list.index(element)].replace(ns, prefix_list[namespaces_list.index(ns)]+":")
used_ns_list.append(namespaces_list.index(ns))
updated_prop_list.append(update)
used_ns_list = list(set(used_ns_list))
cleaned_ns_str = ""
for index, e in enumerate(namespaces_list):
if index in used_ns_list:
cleaned_ns_str += '@prefix ' + prefix_list[index] + ": " + namespaces_list[index] + " .\n"
final_schema = "Prefixes:\n" + cleaned_ns_str + "\nClasses:\n"
for c in updated_class_list:
final_schema += c + "\n"
final_schema += "\nProperties:\n"
for p in updated_prop_list:
final_schema += p + "\n"
return final_schema, prefix_list, namespaces_list
clean_schema, prefix_list, namespaces_list = construct_schema(g)
print(prefix_list)
print(namespaces_list)
def query_graph(query, graph):
q_res = graph.query(query)
res_set = set()
for row in q_res:
obj = None
if not row["o"] is None:
obj = row["o"].rsplit("/", 1)[1]
res_set.add(obj)
return list(res_set)
def query_all_graphs(query, graph, prefixes, namespaces, show_prefix=True):
q_result = graph.query(query)
result_str = ""
for row in q_result:
print(row)
result_str += str(row)
res = result_str.replace("(rdflib.term.URIRef(", "").replace("'", "").replace("),)", ",")
res_list = res.split(",")
final_res = []
for res in res_list:
for name in namespaces:
if name in res:
if show_prefix:
clean_name = res.replace(name, prefixes[namespaces.index(name)]+":")
else:
clean_name = res.replace(name, "")
final_res.append(clean_name)
break
return list(set(final_res))
def result_parser(input_str):
clean = input_str.content.replace("`", "")
return clean.replace("sparql", "")
# ------------------------------------
sparql_tool_description = """This tool is used to generate a SPARQL SELECT statement for querying a graph database.
For instance, to find all email addresses of John Doe, the following query in backticks would be suitable:
```
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?email
WHERE {{
?person foaf:name "John Doe" .
?person foaf:mbox ?email .
}}
```
If you want to find all pairs of people where person a knows person b you could write a query like this:
'''
SELECT DISTINCT ?aname ?bname
WHERE {
?a foaf:knows ?b .
?a foaf:name ?aname .
?b foaf:name ?bname .
}'''
"""
prompt = """ You are a SPARQL query generator agent. You job is to use the tools available to you to construct
and execute viable search queries on a provided knowledge graph.
When creating a SPARQL query make sure to only the node types and properties provided in the schema.
Do not use any node types and properties that are not explicitly provided.
Include all necessary prefixes.
Schema:
{schema}
Note: Be as concise as possible.
Do not include any explanations or apologies in your responses.
Do not respond to any questions that ask for anything else than for you to construct a SPARQL query.
Do not include any text except the SPARQL query generated.
The question is:
{input}"""
query_generator_prompt = """ You are a SPARQL query generator. You job is to to construct viable search queries.
When creating a SPARQL query make sure to only use the node types and properties provided in the schema.
Do not use any node types and properties that are not explicitly provided.
Include all necessary prefixes.
Schema:
{schema}
Examples:
{examples}
Note: Be as concise as possible.
Do not include any explanations or apologies in your responses.
Do not respond to any questions that ask for anything else than for you to construct a SPARQL query.
Do not include any text except the SPARQL query generated.
The question is:
{input}"""
sparql_examples = [
{'question': 'how can I find all email addresses of John Doe?',
'answer': '''PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?email
WHERE {{
?person foaf:name "John Doe" .
?person foaf:mbox ?email .
}}'''
},
{
'question': 'What are the machine learning goals in the KG?',
'answer': '''PREFIX sc: <http://purl.org/science/owl/sciencecommons/>
SELECT ?o
WHERE {{
?s sc:mlgoal ?o
}}
'''
}]
prefix_prompt = """ You are a SPARQL query generator. You job is to to construct viable SPARQL queries.
When creating a SPARQL query make sure to only use the node types and properties provided in the schema.
Do not use any node types and properties that are not explicitly provided.
Include all necessary prefixes.
Schema:
{schema}""".format(schema=clean_schema)
suffix_template = """Note: Be as concise as possible.
Do not include any explanations or apologies in your responses.
Do not respond to any questions that ask for anything else than for you to construct a SPARQL query.
Do not include any text except the SPARQL query generated.
Question:{input}
Answer:"""
llm = ChatOpenAI(model="gpt-4o", temperature=0)
example_prompt = PromptTemplate(
input_variables=["question", "answer"], template="Question: {question}\nAnswer:{answer}"
)
prefix_template = PromptTemplate(
input_variables=['schema'], template=prefix_prompt
)
few_shot_prompt = FewShotPromptTemplate(
prefix=prefix_prompt,
examples=sparql_examples,
example_prompt=example_prompt,
suffix=suffix_template,
input_variables=["input", 'schema'],
)
chain = few_shot_prompt | llm | result_parser
#result = chain.invoke({'input': 'What are the machine learning goals in the KG?'})
#print(result)
#q_res = g.query(result)
#for row in q_res:
# print(row)
a = """PREFIX sc: <http://purl.org/science/owl/sciencecommons/>
SELECT ?o
WHERE {
?s sc:mlgoal ?o
}"""
g_result = query_all_graphs(a, g, prefix_list, namespaces_list) # -> doesn't work if o not select operator
print(g_result)