RubenPeeters commited on
Commit
69e0484
·
1 Parent(s): 51ef060

Woow agents

Browse files
Files changed (5) hide show
  1. .gitignore +1 -0
  2. agents.py +97 -0
  3. app.py +6 -4
  4. requirements.txt +2 -0
  5. tools.py +171 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .env
agents.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from smolagents import CodeAgent, OpenAIServerModel
3
+ from tools import (
4
+ validate_rdf_syntax,
5
+ get_entities_from_kg,
6
+ get_types_from_ontology,
7
+ get_relations_from_ontology,
8
+ )
9
+
10
+ from dotenv import load_dotenv
11
+
12
+ load_dotenv()
13
+
14
+
15
+ # model_id = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"
16
+
17
+ # model = TransformersModel(model_id=model_id)
18
+
19
+ model = OpenAIServerModel(
20
+ model_id="qwen/qwen-2.5-coder-32b-instruct:free",
21
+ # model_id="microsoft/mai-ds-r1:free",
22
+ api_base="https://openrouter.ai/api/v1",
23
+ api_key=os.environ["OPENROUTER_API_KEY"],
24
+ )
25
+
26
+ # web_agent = CodeAgent(
27
+ # tools=[DuckDuckGoSearchTool()],
28
+ # model=model,
29
+ # name="web_search_agent",
30
+ # description="Has the tools to run web searches for you. Give it your query as an argument."
31
+ # # prompt_templates=PromptTemplates(system_prompt="")
32
+ # )
33
+
34
+ # TODO: Add RDF specification tool, CACAO ontology tool, reasoning tool?
35
+ ner_agent = CodeAgent(
36
+ tools=[],
37
+ model=model,
38
+ name="named_entity_recognition_expert",
39
+ description="An agent that is an expert in Named Entity Recognition. Named Entity Recognition (NER) is a subfield of computer science and Natural Language Processing (NLP) that focuses on identifying and classifying entities in unstructured text into predefined categories, such as persons, geographical locations and organizations. Provide content to this agent to detect the entities inside.",
40
+ )
41
+
42
+ et_agent = CodeAgent(
43
+ tools=[get_types_from_ontology],
44
+ additional_authorized_imports=["rdflib"],
45
+ model=model,
46
+ name="entity_typing_expert",
47
+ description="An agent that is an expert in Entity Typing. tasks provide fine-grained and ultra-grained type information for entities such as scientists, clubs, and hotels and is the process of categorizing named entities into predefined types. Provide named entities to this agent and expect typed entities back.",
48
+ )
49
+
50
+ el_agent = CodeAgent(
51
+ tools=[get_entities_from_kg],
52
+ model=model,
53
+ additional_authorized_imports=["rdflib"],
54
+ name="entity_linking_expert",
55
+ description="An agent that is an expert in Entity Linking. Entity Linking (EL) tasks, or entity disambiguation, involves identifying named entities within a text and linking them to their corresponding entries in a knowledge graph. Provide typed entities to this agent to link them to an existing knowledge base.",
56
+ )
57
+
58
+ co_agent = CodeAgent(
59
+ tools=[],
60
+ additional_authorized_imports=["rdflib"],
61
+ model=model,
62
+ name="coreference_resolution_expert",
63
+ description="An agent that is an expert in Coreference Resolution. Coreference Resolution (CO) focuses on determining when two or more expressions refer to the same entity. Provide texts to this agent to find out which texts refer to the same entities.",
64
+ )
65
+
66
+ re_agent = CodeAgent(
67
+ tools=[get_relations_from_ontology],
68
+ model=model,
69
+ additional_authorized_imports=["rdflib"],
70
+ name="relation_extraction_expert",
71
+ description="An agent that is an expert in Relation Extraction. Relation Extraction (RE) involves identifying facts about relations between extracted entities. Provide a text and entities to this agent to find relations between the entities from the text.",
72
+ )
73
+
74
+ # ch_agent = CodeAgent(
75
+ # tools=[DuckDuckGoSearchTool()],
76
+ # additional_authorized_imports=["rdflib"],
77
+ # model=model,
78
+ # name="cultural_heritage_domain_expert",
79
+ # description="Has extensive knowledge of cultural heritage. Ask it about the correctness of facts and the interpretation of a knowledge graph. It also has access to the internet to check facts.",
80
+ # )
81
+
82
+ kg_agent = CodeAgent(
83
+ tools=[validate_rdf_syntax],
84
+ additional_authorized_imports=["rdflib"],
85
+ model=model,
86
+ name="knowledge_graph_expert",
87
+ description="Has extensive knowledge on knowledge graphs. Has the final say before writing the output to a file.",
88
+ )
89
+
90
+ manager_agent = CodeAgent(
91
+ # Using N = 2, following the example of the HF team: https://huggingface.co/blog/beating-gaia
92
+ tools=[],
93
+ additional_authorized_imports=["rdflib"],
94
+ model=model,
95
+ managed_agents=[ner_agent, et_agent, el_agent, co_agent, re_agent],
96
+ planning_interval=2,
97
+ )
app.py CHANGED
@@ -1,4 +1,6 @@
1
  import gradio as gr
 
 
2
 
3
  # Define a simple function that the Gradio app will use.
4
  # This function takes a string as input and returns its reverse.
@@ -22,11 +24,11 @@ def reverse_text(text):
22
  # - title: A title for the Gradio app.
23
  # - description: A brief description of the app.
24
  iface = gr.Interface(
25
- fn=reverse_text,
26
  inputs=gr.Textbox(lines=2, placeholder="Enter text here...", label="Input Text"),
27
- outputs=gr.Textbox(label="Reversed Text"),
28
- title="Text Reverser",
29
- description="Type some text into the input box, and the app will reverse it for you!"
30
  )
31
 
32
  # Launch the Gradio app.
 
1
  import gradio as gr
2
+ from agents import manager_agent
3
+
4
 
5
  # Define a simple function that the Gradio app will use.
6
  # This function takes a string as input and returns its reverse.
 
24
  # - title: A title for the Gradio app.
25
  # - description: A brief description of the app.
26
  iface = gr.Interface(
27
+ fn=manager_agent.run,
28
  inputs=gr.Textbox(lines=2, placeholder="Enter text here...", label="Input Text"),
29
+ outputs=gr.Textbox(label="Final output"),
30
+ title="KGC Agents",
31
+ description="Type some text into the input box, and the app will create a knowledge graph for you!"
32
  )
33
 
34
  # Launch the Gradio app.
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ smolagents[all]
2
+ rdflib
tools.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from rdflib import Graph, RDF, RDFS, OWL, term, URIRef
2
+
3
+ from rdflib.exceptions import ParserError
4
+ from smolagents import tool
5
+
6
+
7
+ @tool
8
+ def validate_rdf_syntax(
9
+ file_path: str, file_format: str = "turtle"
10
+ ) -> tuple[bool, str]:
11
+ """
12
+ Validates the syntax of an RDF file.
13
+
14
+ This function parses an RDF file using the specified format and checks if it
15
+ is syntactically valid. It handles potential parsing errors and other
16
+ exceptions that may occur during the validation process.
17
+
18
+ Args:
19
+ file_path (str): The path to the RDF file to validate.
20
+ file_format (str, optional): The RDF file format.
21
+ Defaults to "turtle". Other common formats include "xml" (for RDF/XML),
22
+ "nt" (for N-Triples), and "nq" (for N-Quads).
23
+
24
+ Returns:
25
+ tuple: A tuple containing two elements:
26
+ - bool: True if the RDF syntax is valid, False otherwise.
27
+ - str: A message describing the validation result. If the syntax is
28
+ valid, the message is "RDF syntax is valid.". If there is an error,
29
+ the message provides details about the error.
30
+
31
+ Raises:
32
+ ParserError: If the RDF file has invalid syntax according to the specified format.
33
+ Exception: For any other unexpected error during file processing or parsing.
34
+ """
35
+ g = Graph()
36
+ try:
37
+ g.parse(file_path, format=file_format)
38
+ return True, "RDF syntax is valid."
39
+ except ParserError as e:
40
+ return False, f"RDF syntax error: {e}"
41
+ except Exception as e:
42
+ return False, f"An unexpected error occurred: {e}"
43
+
44
+
45
+ @tool
46
+ def write_rdf_to_file(filename: str, text: str) -> None:
47
+ """
48
+ Writes the given text to a file.
49
+
50
+ Args:
51
+ filename (str): The name of the file to write to, without extension.
52
+ text (str): The text to write to the file.
53
+ """
54
+ try:
55
+ with open(f"{filename}.ttl", "w") as file:
56
+ file.write(text)
57
+ print(f"Successfully wrote text to {filename}")
58
+ except Exception as e:
59
+ print(f"An error occurred while writing to {filename}: {e}")
60
+
61
+
62
+ @tool
63
+ def get_entities_from_kg() -> list:
64
+ """
65
+ Loads a knowledge graph and returns a list of identified entity URIs.
66
+ Entities are typically resources with an rdf:type linking them to a class,
67
+ or those explicitly declared as owl:NamedIndividual.
68
+
69
+ Args:
70
+ graph_path (str): The path to the knowledge graph file (local path or URL).
71
+ format (str, optional): The format of the graph file (e.g., 'xml', 'turtle', 'json-ld').
72
+ If None, rdflib will try to guess the format based on the file extension.
73
+
74
+ Returns:
75
+ list: A list of rdflib.URIRef or rdflib.BNode objects representing the entities.
76
+ """
77
+ return []
78
+
79
+
80
+ def parse_types_graph(g):
81
+ types = set()
82
+
83
+ # Query for classes defined using rdfs:Class
84
+ for s, p, o in g.triples((None, RDF.type, RDFS.Class)):
85
+ types.add(s)
86
+
87
+ # Query for classes defined using owl:Class
88
+ for s, p, o in g.triples((None, RDF.type, OWL.Class)):
89
+ types.add(s)
90
+
91
+ # You might also find classes as subjects of rdfs:subClassOf triples
92
+ # Although this doesn't strictly define a class, it implies the subject is a class
93
+ for s, p, o in g.triples((None, RDFS.subClassOf, None)):
94
+ types.add(s)
95
+ # Also add the object, as it must also be a class
96
+ if isinstance(o, term.URIRef) or isinstance(o, term.BNode):
97
+ types.add(o)
98
+
99
+ return sorted(list(types))
100
+
101
+
102
+ def parse_relations_graph(g):
103
+ predicates = set()
104
+
105
+ # Query for resources explicitly typed as properties
106
+ property_types = [
107
+ RDF.Property,
108
+ OWL.ObjectProperty,
109
+ OWL.DatatypeProperty,
110
+ OWL.AnnotationProperty,
111
+ ]
112
+
113
+ for prop_type in property_types:
114
+ for s, p, o in g.triples((None, RDF.type, prop_type)):
115
+ predicates.add(s)
116
+
117
+ # Also consider any URI or BNode that is used as a predicate in any triple
118
+ # These are implicitly properties, even if not explicitly typed
119
+ for s, p, o in g.triples((None, None, None)):
120
+ if isinstance(p, term.URIRef) or isinstance(p, term.BNode):
121
+ predicates.add(p)
122
+
123
+ return sorted(list(predicates))
124
+
125
+
126
+ @tool
127
+ def get_types_from_ontology() -> list[URIRef]:
128
+ """
129
+ Loads an ontology and returns a list of defined class URIs.
130
+
131
+ Args:
132
+ ontology_path (str): The path to the ontology file (local path or URL).
133
+ format (str, optional): The format of the ontology file (e.g., 'xml', 'turtle', 'json-ld').
134
+ If None, rdflib will try to guess the format based on the file extension.
135
+
136
+ Returns:
137
+ list: A list of rdflib.URIRef objects representing the defined classes.
138
+ """
139
+ g = Graph()
140
+
141
+ try:
142
+ g.parse("./sources/cacao.owl", format=None)
143
+ except Exception as e:
144
+ print(f"Error loading ontology: {e}")
145
+ return []
146
+
147
+ return parse_types_graph(g)
148
+
149
+
150
+ @tool
151
+ def get_relations_from_ontology() -> list[URIRef]:
152
+ """
153
+ Loads an ontology and returns a list of defined predicate (property) URIs.
154
+
155
+ Args:
156
+ ontology_path (str): The path to the ontology file (local path or URL).
157
+ format (str, optional): The format of the ontology file (e.g., 'xml', 'turtle', 'json-ld').
158
+ If None, rdflib will try to guess the format based on the file extension.
159
+
160
+ Returns:
161
+ list: A list of rdflib.URIRef objects representing the defined predicates.
162
+ """
163
+ g = Graph()
164
+
165
+ try:
166
+ g.parse("./sources/cacao.owl", format=None)
167
+ except Exception as e:
168
+ print(f"Error loading ontology: {e}")
169
+ return []
170
+
171
+ return parse_relations_graph(g)