Patient Treatment Planner Demonstration
A key use case for the VALAWAI architecture, as described in Medical Protocols, involves incorporating value considerations into medical protocols. This demonstration simplifies this use case, showcasing how a doctor can define patients, specify their current health status, and design a set of actions (a treatment plan) to achieve a desired outcome. After defining the treatment, the doctor receives feedback, including:
- Whether the treatment adheres to the NIT protocol.
- How well the treatment aligns with various values associated with the chosen actions.
This demonstration utilizes the Master Of VALAWAI (MOV) as the implementation of the VALAWAI Architecture, along with the following components:
- C0 Patient Treatment UI: Provides the user interface for doctors to manage patients, define treatments, and visualize feedback.
- C1 NIT Protocol Manager: Checks if the actions of a treatment follow the NIT protocol.
- C2 Treatment Autonomy Evaluator: Calculates the autonomy value alignment of a treatment.
- C2 Treatment Beneficence Evaluator: Calculates the beneficence value alignment of a treatment.
- C2 Treatment Justice Evaluator: Calculates the justice value alignment of a treatment.
- C2 Treatment Nonmaleficence Evaluator: Calculates the nonmaleficence value alignment of a treatment.
Prerequisites
Before deploying this demonstration, ensure you have Docker installed on your system. Installation instructions and platform-specific guides are available on the official Docker website: https://www.docker.com/.
Build the Docker Containers
Instructions for building Docker containers for each VALAWAI software component
are detailed in their respective documentation. To streamline this process,
a buildContainers.sh
script is provided below. This script automates the container
build process, downloading the latest code and building the Docker images as needed.
#!/bin/bash
# Define the components and their repositories
components=(
"MOV"
"C0_patient_treatment_ui"
"C1_nit_protocol_manager"
"C2_treatment_autonomy_valuator"
"C2_treatment_beneficence_valuator"
"C2_treatment_justice_valuator"
"C2_treatment_nonmaleficence_valuator"
)
function docker_git () {
(docker run -ti --rm -v ${HOME}:/root -v $(pwd):/git alpine/git "$@")
}
# Iterate through the components
for component_name in "${components[@]}"; do
if [ -d "$component_name" ]; then
echo "Directory $component_name exists. Checking for updates."
pushd "$component_name" >/dev/null
docker_git pull origin main || { echo "Error updating $component_name"; exit 1; }
else
echo "Directory $component_name does not exist. Cloning repository."
component_repo="https://github.com/VALAWAI/${component_name}.git"
docker run -ti --rm -v "${HOME}:/root" -v "$(pwd):/git" alpine/git clone $component_repo
pushd "$component_name" >/dev/null
fi
lowercase_component_name=$(echo "$component_name" | tr 'A-Z' 'a-z')
image_name="valawai/${lowercase_component_name}:latest"
if docker images -q $image_name >/dev/null; then
image_timestamp=$(docker inspect -f '{{ .Created }}' $image_name)
latest_commit_timestamp=$(docker_git shortlog -1 --since=\"$image_timestamp\")
popd >/dev/null
if [ $(echo "$latest_commit_timestamp" | wc -l) -gt 1 ] ; then
echo "Docker image $image_name is older than last commit. Rebuilding."
build_image=true
else
echo "Docker image $image_name is up to date. Skipping build."
build_image=false
fi
else
echo "Docker image $image_name does not exist. Building image."
build_image=true
fi
if [[ "$build_image" == true ]]; then
pushd "$component_name" >/dev/null
./buildDockerImages.sh -t latest || { echo "Error building $component_name"; exit 1; }
popd >/dev/null
echo "Built Docker image for $component_name"
fi
done
echo "Finished processing all components."
How to use the script:
-
Save the script: Copy the code above and save it as
buildContainers.sh
in your VALAWAI project directory. -
Make it executable: Open a terminal and navigate to the directory where you saved the script. Then, make the script executable by running the following command:
chmod +x buildContainers.sh
- Run the script: Execute the script using the following command:
./buildContainers.sh
After that, the script will download the latest code of each component and build its Docker image if necessary.
Create Docker Compose file
To deploy the demo components, a docker-compose.yml
file will be used. This file
defines the services that Docker Compose will start to orchestrate the demonstration.
Create a file named docker-compose.yml in your project directory and copy the following
code into it.
services:
mov:
image: valawai/mov:${MOV_TAG:-latest}
container_name: treatment_demo_mov
profiles: [mov,all]
depends_on:
mongo:
condition: service_healthy
restart: true
mq:
condition: service_healthy
restart: true
ports:
- ${MOV_UI_PORT:-8080}:8080
networks:
- treatment_demo_net
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
QUARKUS_MONGODB_DATABASE: ${MOV_DB_NAME:-movDB}
QUARKUS_MONGODB_CREDENTIALS_USERNAME: ${MOV_DB_USER_NAME:-mov}
QUARKUS_MONGODB_CREDENTIALS_PASSWORD: ${MOV_DB_USER_PASSWORD:-password}
QUARKUS_MONGODB_HOSTS: ${DB_HOST:-mongo}:${MONGO_PORT:-27017}
MOV_UI_URL: http://localhost:${MOV_UI_PORT:-8080}
healthcheck:
test:
[
"CMD-SHELL",
"curl -s http://localhost:8080/q/health | grep -m 1 -P \"^[\\s|\\{|\\\"]+status[\\s|\\:|\\\"]+.+\\\"\" |grep -q \"\\\"UP\\\"\"",
]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
mq:
image: rabbitmq:${RABBITMQ_TAG:-management}
container_name: treatment_demo_mq
profiles: [mov,all]
hostname: ${MQ_HOST:-mq}
ports:
- ${MQ_LOCAL_PORT:-5672}:5672
- ${MQ_LOCAL_UI_PORT:-8081}:15672
networks:
- treatment_demo_net
environment:
RABBITMQ_DEFAULT_USER: ${MQ_USER:-mov}
RABBITMQ_DEFAULT_PASS: ${MQ_PASSWORD:-password}
healthcheck:
test: ["CMD-SHELL", "rabbitmq-diagnostics -q ping"]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
mongo:
image: mongo:${MONGODB_TAG:-latest}
container_name: treatment_demo_mongo
profiles: [mov,all]
hostname: ${DB_HOST:-mongo}
ports:
- ${MONGO_LOCAL_PORT:-27017}:27017
networks:
- treatment_demo_net
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER:-root}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD:-password}
MONGO_INITDB_DATABASE: ${DB_NAME:-movDB}
MOV_DB_NAME: ${MOV_DB_NAME:-movDB}
MOV_DB_USER_NAME: ${MOV_DB_USER_NAME:-mov}
MOV_DB_USER_PASSWORD: ${MOV_DB_USER_PASSWORD:-password}
volumes:
- ${MONGO_LOCAL_DATA:-~/.mongo_data/treatment_demo_db}:/data/db
healthcheck:
test:
[
"CMD-SHELL",
"mongosh --quiet localhost/${DB_NAME:-movDB} --eval 'quit(db.runCommand({ ping: 1 }).ok ? 0 : 2)'",
]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
configs:
- source: initialize-movDB.js
target: /docker-entrypoint-initdb.d/init-mongo.js
pg:
image: postgres:${POSTGRES_TAG:-17}
container_name: treatment_demo_C0_pg
profiles: [C0, all]
ports:
- ${PG_PORT:-5432}:5432
networks:
- treatment_demo_net
environment:
POSTGRES_USER: ${PG_USER_NAME:-c0_patient_treatment_ui}
POSTGRES_PASSWORD: ${PG_USER_PASSWORD:-password}
POSTGRES_DB: ${PG_DB_NAME:-c0_patient_treatment_ui_db}
volumes:
- ${PG_LOCAL_DATA:-~/.pg_data/treatment_demo_db}:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
patient_treatment_ui:
image: valawai/c0_patient_treatment_ui:${C0_PATIENT_TREATMENT_UI_TAG:-latest}
container_name: treatment_demo_c0_component
profiles: [C0, all]
networks:
- treatment_demo_net
ports:
- ${C0_PATIENT_TREATMENT_UI_PORT:-8082}:8080
depends_on:
pg:
condition: service_healthy
restart: true
mov:
condition: service_healthy
required: false
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
C0_PATIENT_TREATMENT_UI_URL: http://localhost:${C0_PATIENT_TREATMENT_UI_PORT:-8082}
healthcheck:
test:
[
"CMD-SHELL",
"curl -s http://localhost:8080/q/health | grep -m 1 -P \"^[\\s|\\{|\\\"]+status[\\s|\\:|\\\"]+.+\\\"\" |grep -q \"\\\"UP\\\"\"",
]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
nit_protocol_manager:
image: valawai/c1_nit_protocol_manager:${C1_NIT_PROTOCOL_MANAGER_TAG:-latest}
container_name: treatment_demo_c1_component
profiles: [C1, all]
depends_on:
mov:
condition: service_healthy
required: false
networks:
- treatment_demo_net
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
healthcheck:
test:
[
"CMD-SHELL",
"curl -s http://localhost:8080/q/health | grep -m 1 -P \"^[\\s|\\{|\\\"]+status[\\s|\\:|\\\"]+.+\\\"\" |grep -q \"\\\"UP\\\"\"",
]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
treatment_autonomy_valuator:
image: valawai/c2_treatment_autonomy_valuator:${C2_TREATMENT_AUTONOMY_VALUATOR_TAG:-latest}
container_name: treatment_demo_c2_component_autonomy
profiles: [C2, all]
depends_on:
mov:
condition: service_healthy
required: false
networks:
- treatment_demo_net
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
LOG_CONSOLE_LEVEL: ${LOG_LEVEL:-INFO}
healthcheck:
test: ["CMD-SHELL", "test -s /app/logs/component_id.json"]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
treatment_beneficence_valuator:
image: valawai/c2_treatment_beneficence_valuator:${C2_TREATMENT_BENEFICENCE_VALUATOR_TAG:-latest}
container_name: treatment_demo_c2_component_beneficence
profiles: [C2, all]
depends_on:
mov:
condition: service_healthy
required: false
networks:
- treatment_demo_net
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
LOG_CONSOLE_LEVEL: ${LOG_LEVEL:-INFO}
healthcheck:
test: ["CMD-SHELL", "test -s /app/logs/component_id.json"]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
treatment_justice_valuator:
image: valawai/c2_treatment_justice_valuator:${C2_TREATMENT_JUSTICE_VALUATOR_TAG:-latest}
container_name: treatment_demo_c2_component_justice
profiles: [C2, all]
depends_on:
mov:
condition: service_healthy
required: false
networks:
- treatment_demo_net
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
LOG_CONSOLE_LEVEL: ${LOG_LEVEL:-INFO}
healthcheck:
test: ["CMD-SHELL", "test -s /app/logs/component_id.json"]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
treatment_nonmaleficence_valuator:
image: valawai/c2_treatment_nonmaleficence_valuator:${C2_TREATMENT_NONMALEFICENCE_VALUATOR_TAG:-latest}
container_name: treatment_demo_c2_component_nonmaleficence
profiles: [C2, all]
depends_on:
mov:
condition: service_healthy
required: false
networks:
- treatment_demo_net
environment:
RABBITMQ_HOST: ${MQ_HOST:-mq}
RABBITMQ_PORT: ${MQ_PORT:-5672}
RABBITMQ_USERNAME: ${MQ_USER:-mov}
RABBITMQ_PASSWORD: ${MQ_PASSWORD:-password}
LOG_CONSOLE_LEVEL: ${LOG_LEVEL:-INFO}
healthcheck:
test: ["CMD-SHELL", "test -s /app/logs/component_id.json"]
interval: 1m
timeout: 10s
retries: 5
start_period: 1m
start_interval: 5s
networks:
treatment_demo_net:
configs:
initialize-movDB.js:
content: |
db.createUser({
user: process.env.MOV_DB_USER_NAME,
pwd: process.env.MOV_DB_USER_PASSWORD,
roles: [{
role: 'readWrite',
db: process.env.MOV_DB_NAME
}]
})
On the code above, the docker-compose.yml
, defines the following services:
- Line 2: Defines the Master of VALAWAI (MOV) service. See the MOV Deployment documentation for more details.
- Lines 34 and 55: Define the services required by MOV: RabbitMQ and MongoDB, respectively.
- Line 82: Configures the C0 Patient Treatment UI. See the C0 Patient Treatment UI Deployment documentation for more information.
- Line 110: Configures the PostgreSQL database required by the C0 Patient Treatment UI.
- Line 132: Configures the C1 NIT Protocol Manager. See the C1 NIT Protocol Manager Deployment documentation for details.
- Lines 155, 179, 203, and 227: Configure the C2 Treatment Value Evaluators:
- Autonomy Evaluator (Deployment documentation)
- Beneficence Evaluator (Deployment documentation)
- Justice Evaluator (Deployment documentation)
- Nonmaleficence Evaluator (Deployment documentation)
Running the Demonstration
The following steps demonstrate the VALAWAI Architecture and the Master Of VALAWAI (MOV).
-
Start MOV: Launch the MOV with:
COMPOSE_PROFILES=mov docker compose up -d
.
Access the MOV user interface at http://localhost:8080. Initially, no components or connections will be visible. -
Start the Doctor UI: Launch the doctor's user interface with:
COMPOSE_PROFILES=C0 docker compose up -d
. Refresh the MOV UI (http://localhost:8080) to see the newly registered C0 component. No topology connections will be present yet. -
Using the Doctor UI: Open the doctor's user interface in your browser at http://localhost:8081 and perform the following steps:
3.1 Add a Patient: Go to "Patients" and add a new patient, providing the name and status.
3.2 Add a Treatment: Click the three dots next to the patient's name, select "Add treatment to patient," review the current status, click "Next," select the actions to apply, define the expected status after the treatment, and then add the treatment. Note that the treatment will not have any feedback information at this point because the C1 and C2 components are not yet running.
-
Start the NIT Protocol Manager (C1): Launch the C1 component with:
COMPOSE_PROFILES=C1 docker compose up -d
. Refresh the MOV UI (http://localhost:8080) to see the registered C1 component and the connection between C1 and C0 in the topology. -
Check NIT Protocol Adherence: Once the C1 component is ready, return to the doctor's user interface (http://localhost:8081), go to the previously created treatment, and click the reload icon. After a few seconds, you will see whether the treatment actions follow the NIT protocol.
-
Start the Value Evaluators (C2): Launch the C2 components with:
COMPOSE_PROFILES=C2 docker compose up -d
. Refresh the MOV UI (http://localhost:8080) to see the four registered C2 components and their connections to the C0 component. -
Check Value Alignment: Once the C2 components are ready, return to the doctor's UI (http://localhost:8081), go to the created treatment, and click the reload icon. After a few seconds, you will see the value alignment feedback for the treatment.
Convenience Commands:
- Start All Components:
COMPOSE_PROFILES=all docker compose up -d
- Stop All Components:
COMPOSE_PROFILES=all docker compose down
(Note: this command will stop all services regardless of the profile used to start them). If you only want to stop themov
profile you can useCOMPOSE_PROFILES=mov docker compose down