diff --git a/Dockerfile b/agent-extract/Dockerfile similarity index 100% rename from Dockerfile rename to agent-extract/Dockerfile diff --git a/src/__init__.py b/agent-extract/src/__init__.py similarity index 100% rename from src/__init__.py rename to agent-extract/src/__init__.py diff --git a/agent-extract/src/agent.py b/agent-extract/src/agent.py new file mode 100644 index 0000000..b8f1c20 --- /dev/null +++ b/agent-extract/src/agent.py @@ -0,0 +1,37 @@ +# Agenten Plattform +# +# (c) 2024 Magnus Bender +# Institute of Humanities-Centered Artificial Intelligence (CHAI) +# Universitaet Hamburg +# https://www.chai.uni-hamburg.de/~bender +# +# source code released under the terms of GNU Public License Version 3 +# https://www.gnu.org/licenses/gpl-3.0.txt + +from ums.agent import ExtractAudioAgent, ExtractImageAgent + +from ums.utils.types import RiddleData + +""" + Examples for simple agents. + + Each agent is represented by its own class. The handling of tasks is done by `handle()` in each agent. + + Finally `AGENT_CLASSES` contains the classes of the agents in a list. Via environmental variables this list is specified to the ums.agent system. +""" + +class MyExtractAudioAgent(ExtractAudioAgent): + + def handle(self, data: RiddleData) -> RiddleData: + print("Audio Process:", data.file_plain) + return data + +class MyExtractImageAgent(ExtractImageAgent): + + def handle(self, data: RiddleData) -> RiddleData: + print("Image Process:", data.file_plain) + return data + +AGENT_CLASSES = [ + MyExtractAudioAgent, MyExtractImageAgent +] \ No newline at end of file diff --git a/agent-solve/Dockerfile b/agent-solve/Dockerfile new file mode 100644 index 0000000..adc6384 --- /dev/null +++ b/agent-solve/Dockerfile @@ -0,0 +1,15 @@ +ARG IMAGE_FROM +FROM $IMAGE_FROM + +# become root +USER root + +# do somthing as root, e.g. install packages, set up things ... +# RUN ... + +# copy the source of the agent in this repo +COPY --chown=user:user ./src/ /ums-agenten/project/src/ +# fix permissions +RUN chown -R user:user /ums-agenten +# switch back to user +USER user \ No newline at end of file diff --git a/agent-solve/src/__init__.py b/agent-solve/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/agent-solve/src/agent.py b/agent-solve/src/agent.py new file mode 100644 index 0000000..281a8d8 --- /dev/null +++ b/agent-solve/src/agent.py @@ -0,0 +1,59 @@ +# Agenten Plattform +# +# (c) 2024 Magnus Bender +# Institute of Humanities-Centered Artificial Intelligence (CHAI) +# Universitaet Hamburg +# https://www.chai.uni-hamburg.de/~bender +# +# source code released under the terms of GNU Public License Version 3 +# https://www.gnu.org/licenses/gpl-3.0.txt + +from typing import Callable +from ums.agent import ExtractTextAgent, SolveAgent, GatekeeperAgent + +from ums.utils.types import AgentMessage, Riddle, RiddleData, RiddleSolution, RiddleStatus + +""" + Examples for simple agents. + + Each agent is represented by its own class. The handling of tasks is done by `handle()` in each agent. + + Finally `AGENT_CLASSES` contains the classes of the agents in a list. Via environmental variables this list is specified to the ums.agent system. +""" + +class MyExtractTextAgent(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) + return data + + +class MySolveAgent(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) + + return RiddleSolution(solution="Huii", explanation="Blubb") + + +class MyGatekeeperAgent(GatekeeperAgent): + + def handle(self, solution: RiddleSolution, riddle: Riddle) -> RiddleSolution: + solution.accepted = True + solution.review = "Ok" + + return solution + +AGENT_CLASSES = [ + MyExtractTextAgent, + MySolveAgent, + MyGatekeeperAgent +] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 2ce3ba9..8dda606 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,35 +6,72 @@ services: #image: git.chai.uni-hamburg.de/ums-agenten/management:amd64 ports: # external (to host) http port + # open: http://localhost:8080/ ! - 8080:80 environment: + # limit number of trials for solving a riddle + - SOLUTION_MAX_TRIALS=5 + # how to access management (the host name is the name of the service in this file) + - MANAGEMENT_URL=http://management # *register* the agents to the management - - AGENTS_PROCESS=http://agent_process_1:3001,http://agent_process_2:3001 - - AGENTS_SOLVE=http://agent_solve_1:3001 - - AGENTS_GATEKEEPER=http://agent_gatekeeper_1:3001 + - AGENTS_PROCESS=http://agent_extract_1:8000,http://agent_extract_2:8000 + - AGENTS_SOLVE=http://agent_solve:8000 + - AGENTS_GATEKEEPER=http://agent_gatekeeper:8000 volumes: # all data is bind-mounted from ./data on the host into the containers - # the folder *share* is shared with all agents, it can be used to pass large data via files + # the folder *share* is shared with all agents, it can be used to pass the data via files - ./data/share/:/ums-agenten/share/ - # the folder *persist* is different for each container and can be used to store data permanently + # the folder *persist* is different for each container and is used to store data permanently - ./data/persist-management/:/ums-agenten/persist/ - agent_process_1: + agent_solve: # this allow to do installs etc. in the docker image (a new image will be built on top of the provided one) build: - context: . + context: ./agent-solve dockerfile: Dockerfile args: # select the correct one base on platform this is running on - IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-arm64 #- IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-amd64 #- IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:gpu-amd64 + ports: + # this port is only for access from the host, the management can always use 8000 + - 8081:8000 environment: + # python package:variable_name of the list of agents implemeted here + - AGENTS_LIST=src.agent:AGENT_CLASSES # tell the agent where the management is accessible - - MANAGEMENT=http://management + - MANAGEMENT_URL=http://management volumes: - ./data/share/:/ums-agenten/share/ - - ./data/persist-process-1/:/ums-agenten/persist/ + - ./data/persist-solve/:/ums-agenten/persist/ # this is for development (s.t. the changes in ./src/ are directly applied) - - ./src/:/ums-agenten/project/src/:ro - entrypoint: ... # TODO \ No newline at end of file + - ./agent-solve/src/:/ums-agenten/project/src/:ro + # for development: will detect file changes and reload server with new source + entrypoint: bash -c "SERVE=true uvicorn ums.agent.main:app --host 0.0.0.0 --port 8000 --reload --reload-dir /ums-agenten/project/src/" + networks: + # this is a trick: we add multiple host names to the same container + # later, each agent will get its own container, but for testing, by this + # one container can become *all* agents + default: + aliases: + - agent_extract_2 + - agent_gatekeeper + + agent_extract_1: + build: + context: ./agent-extract + dockerfile: Dockerfile + args: + - IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-arm64 + #- IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:cpu-amd64 + #- IMAGE_FROM=git.chai.uni-hamburg.de/ums-agenten/base-agent:gpu-amd64 + ports: + - 8082:8000 + environment: + - AGENTS_LIST=src.agent:AGENT_CLASSES + - MANAGEMENT_URL=http://management + volumes: + - ./data/share/:/ums-agenten/share/ + - ./data/persist-extract/:/ums-agenten/persist/ + - ./agent-extract/src/:/ums-agenten/project/src/:ro \ No newline at end of file