Simple Example Agent

This commit is contained in:
2024-10-30 23:47:34 +01:00
parent ebe4a58f90
commit 7199cfc714
7 changed files with 261 additions and 20 deletions

View File

@ -8,32 +8,71 @@
# source code released under the terms of GNU Public License Version 3
# https://www.gnu.org/licenses/gpl-3.0.txt
import re
from typing import Callable
from ums.agent import ExtractAudioAgent, ExtractImageAgent, ExtractTextAgent
from ums.utils.types import RiddleData, AgentMessage
from ums.utils.schema import ExtractedData, ExtractedContent, ExtractedPositions
class SimpleExtractAudioAgent(ExtractAudioAgent):
# here we do not have an implementation for extracting audio,
# normally, we would not have this class, but here as example
def handle(self, data: RiddleData) -> RiddleData:
print("Audio Process:", data.file_plain)
return data
class SimpleExtractImageAgent(ExtractImageAgent):
# equally, we would not have this class without implementation
def before_response(self, response: AgentMessage, send_it: Callable[[], None]) -> bool:
# agents are able to prevent sending response messages to the management
# or send this messages later via `send_it()``
print("The response would be:", response)
# just stop the response from being sent
return False
def handle(self, data: RiddleData) -> RiddleData:
print("Image Process:", data.file_plain)
return data
class SimpleExtractTextAgent(ExtractTextAgent):
def before_response(self, response: AgentMessage, send_it: Callable[[], None]) -> bool:
print("The response will be:", response)
return True
def handle(self, data: RiddleData) -> RiddleData:
print("Text Process:", data.file_plain)
# here we extract the variables assigned with numbers
found = False
with open(data.file_plain) as f:
for i, line in enumerate(f):
if "=" in line:
match = re.match(r"([a-z]{1})\s*=\s*(\d+)", line.strip())
if not match is None:
variable = match.group(1)
value = int(match.group(2))
found = True
line_no = i
if found:
extracted = ExtractedData(
contents=[
ExtractedContent(type="variable",content=variable),
ExtractedContent(type="value",content=value)
],
positions=[
ExtractedPositions(type="line",position=line_no),
ExtractedPositions(type="line",position=line_no)
],
other={
"variable" : variable,
"value" : value
}
)
data.file_extracted = self.store_extracted(data, extracted)
return data
AGENT_CLASSES = [

View File

@ -9,20 +9,91 @@
# https://www.gnu.org/licenses/gpl-3.0.txt
from ums.agent import SolveAgent
import re, random
from ums.utils.types import Riddle, RiddleData, RiddleSolution, RiddleStatus
from typing import Callable
from ums.agent import SolveAgent
from ums.utils.types import Riddle, RiddleData, RiddleSolution, RiddleDataType, RiddleStatus, AgentMessage
class SimpleSolveAgent(SolveAgent):
def handle(self, riddle: Riddle, data: RiddleData) -> RiddleSolution:
if self.message().id == "test":
status = RiddleStatus()
status.extract.required = False
self.sub_riddle(riddle=Riddle(context="Haha", question="Blubber"), status=status)
def before_response(self, response: AgentMessage, send_it: Callable[[], None]) -> bool:
# do not send a response, if this is not a calculator riddle!
return not self.stop_response
return RiddleSolution(solution="Huii", explanation="Blubb")
def handle(self, riddle: Riddle, data: RiddleData) -> RiddleSolution:
# remove whitespace
expression = riddle.question.strip()
# this is a very simple calculator, if the riddle it not for the calculator
# just do not try to solve it and do not answer management!
if "[Taschenrechner]" in riddle.context:
self.stop_response = False
# get all the extracted values
var_vals = {}
used_data = []
for d in data:
e = self.get_extracted(d)
if not e is None \
and "variable" in e.other and "value" in e.other \
and e.other["variable"] in expression:
used_data.append(d)
var_vals[e.other["variable"]] = e.other["value"]
# require "=" at the end
if not expression[-1] == "=":
return RiddleSolution(solution="Error", explanation="No = at the end of the expression!")
# solve the expression
# remove the = and whitespace
expression = expression[:-1].strip()
for var, val in var_vals.items():
# replace the variables by values
expression = expression.replace(var, str(val))
# check the expression
if re.match(r"^[0-9+\-*\/ ]+$", expression) is None:
return RiddleSolution(solution="Error", explanation="Missing data or faulty expression")
try:
# using eval is a bad idea, but this is only for demonstration
# and expression may only contain "0-9 +-*/"
result = eval(expression)
except:
return RiddleSolution(solution="Error", explanation="Unable to calculate value of expression")
# add some noise and invalidate result (for gatekeeper to check)
if random.random() > 0.5:
print("UPPS UPPS")
result += 1 + int(random.random()*9)
return RiddleSolution(
solution=str(result),
explanation="{} = {}".format(expression, result),
used_data=used_data
)
else:
self.stop_response = True
# but we will start a nice riddle, we can solve :D
self.sub_riddle(
riddle=Riddle(
context="[Taschenrechner]",
question="x * x ="
),
data=[
RiddleData(
type=RiddleDataType.TEXT,
file_plain="./example/x.txt"
)
]
)
return RiddleSolution(solution="Error", explanation="No context [Taschenrechner]!")
AGENT_CLASSES = [

View File

@ -8,17 +8,58 @@
# source code released under the terms of GNU Public License Version 3
# https://www.gnu.org/licenses/gpl-3.0.txt
import re
from typing import Callable
from ums.agent import GatekeeperAgent
from ums.utils.types import Riddle, RiddleSolution
from ums.utils.types import Riddle, RiddleSolution, AgentMessage
class SimpleSolveAgent(GatekeeperAgent):
def before_response(self, response: AgentMessage, send_it: Callable[[], None]) -> bool:
# do not send a response, if this is not a calculator riddle!
return not self.stop_response
def handle(self, solution: RiddleSolution, riddle: Riddle) -> RiddleSolution:
solution.accepted = True
solution.review = "Ok"
self.stop_response = False
# first check for errors
if solution.solution == "Error":
solution.accepted = True
solution.review = "An error of the riddle can not be fixed!"
return solution
# this is just a simple check, we check if solution and explanation match to the expression
match = re.match(r"^([0-9+\-*\/ ]+)\s*=\s*(\d+)$", solution.explanation)
if match is None:
self.stop_response = True
return solution
expression, result = match.group(1), match.group(2)
if result != solution.solution:
solution.accepted = False
solution.review = "Inconsistent values"
return solution
try:
# using eval is a bad idea, but this is only for demonstration
# and expression may only contain "0-9 +-*/"
own_result = eval(expression)
except:
solution.accepted = False
solution.review = "Unsolvable expression"
return solution
# check the values
if str(own_result) != solution.solution:
solution.accepted = False
solution.review = "Value of expression does not match solution!"
else:
solution.accepted = True
solution.review = "Yes, {}".format(solution.explanation)
return solution