diff --git a/Dockerfile b/Dockerfile index 0a40434..b8c1d01 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,38 +1,11 @@ -# Use an official Python runtime as a parent image -FROM python:3.9-slim AS builder +FROM python:3.12-slim@sha256:9e01bf1ae5db7649a236da7be1e94ffbbbdd7a93f867dd0d8d5720d9e1f89fab -# Set environment variables -ENV PYTHONDONTWRITEBYTECODE=1 -ENV PYTHONUNBUFFERED=1 - -# Install system dependencies -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential \ - curl \ - && rm -rf /var/lib/apt/lists/* - -# Upgrade pip -RUN pip install --upgrade pip - -# Create app directory WORKDIR /app - -# Install Python dependencies in a virtual environment COPY requirements.txt . -RUN python -m venv /opt/venv && \ - /opt/venv/bin/pip install -r requirements.txt - -# Copy the application code to the image +RUN grep -v amf.fast.inference requirements.txt > /tmp/reqs.txt && \ + pip install -r /tmp/reqs.txt && \ + pip install --no-deps amf-fast-inference==0.0.3 COPY . . -# Use a non-root user for security -#RUN useradd --create-home appuser -#USER appuser - -# Expose the port the app runs on EXPOSE 5002 - -# Set the entry point for the container -ENTRYPOINT ["/opt/venv/bin/python"] -CMD ["./main.py"] +CMD ["gunicorn", "--workers", "1", "--bind", "0.0.0.0:5002", "main:app"] diff --git a/docker-compose.yml b/docker-compose.yml index b950ca4..08a0c61 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,6 @@ -version: '3.8' - -services: # +services: bert-te: container_name: bert_te - build: - context: . # Specify the build context - dockerfile: Dockerfile # Specify the Dockerfile if it's not named 'Dockerfile' + build: . ports: - - "5002:5002" # Map port 5002 on the host to port 5002 in the container - + - "5002:5002" diff --git a/requirements.txt b/requirements.txt index 52ef3cc..6f46956 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,113 @@ -flask -flask_uploads -prometheus_flask_exporter -torch -numpy -transformers -Cython +about-time==4.2.1 +aiohappyeyeballs==2.6.1 +aiohttp==3.13.3 +aiosignal==1.4.0 +alive-progress==3.3.0 +anyio==4.12.1 +attrs==25.4.0 +autograd==1.8.0 +blinker==1.9.0 +certifi==2026.1.4 +cffi==2.0.0 +charset-normalizer==3.4.4 +click==8.3.1 +cma==4.4.2 +coloredlogs==15.0.1 +contourpy==1.3.3 +cycler==0.12.1 +Cython==3.2.4 +datasets==4.5.0 +Deprecated==1.3.1 +dill==0.4.0 +filelock==3.24.3 +Flask==3.1.3 +Flask-Uploads==0.2.1 +flatbuffers==25.12.19 +fonttools==4.61.1 +frozenlist==1.8.0 +fsspec==2025.10.0 +graphemeu==0.7.2 +gunicorn==25.1.0 +h11==0.16.0 +hf-xet==1.2.0 +httpcore==1.0.9 +httpx==0.28.1 +huggingface_hub==0.36.2 +humanfriendly==10.0 +idna==3.11 +itsdangerous==2.2.0 +Jinja2==3.1.6 +joblib==1.5.3 +jsonschema==4.26.0 +jsonschema-specifications==2025.9.1 +kiwisolver==1.4.9 +markdown-it-py==4.0.0 +markdown2==2.5.4 +MarkupSafe==3.0.3 +matplotlib==3.10.8 +mdurl==0.1.2 +ml_dtypes==0.5.4 +moocore==0.2.0 +mpmath==1.3.0 +multidict==6.7.1 +multiprocess==0.70.18 +natsort==8.4.0 +networkx==3.4.2 +ninja==1.13.0 +nncf==2.19.0 +numpy==2.2.6 +onnx==1.20.1 +onnxruntime==1.24.2 +onnxruntime-tools==1.7.0 +openvino==2025.4.1 +openvino-telemetry==2025.2.0 +optimum==1.18.0 +optimum-intel==1.16.1 +packaging==26.0 +pandas==2.3.3 +pillow==12.1.1 +platformdirs==4.9.2 +prometheus_client==0.24.1 +prometheus_flask_exporter==0.23.2 +propcache==0.4.1 +protobuf==6.33.5 +psutil==7.2.2 +py-cpuinfo==9.0.0 +py3nvml==0.2.7 +pyarrow==23.0.1 +pycparser==3.0 +pydot==3.0.4 +Pygments==2.19.2 +pymoo==0.6.1.6 +pyparsing==3.3.2 +python-dateutil==2.9.0.post0 +pytz==2025.2 +PyYAML==6.0.3 +referencing==0.37.0 +regex==2026.2.19 +requests==2.32.5 +rich==14.3.3 +rpds-py==0.30.0 +safetensors==0.7.0 +scikit-learn==1.8.0 +scipy==1.17.1 +sentencepiece==0.2.1 +setuptools==82.0.0 +six==1.17.0 +sympy==1.14.0 +tabulate==0.9.0 +threadpoolctl==3.6.0 +tokenizers==0.15.2 +torch==2.10.0 +tqdm==4.67.3 +transformers==4.39.3 +typing_extensions==4.15.0 +tzdata==2025.3 +urllib3==2.6.3 +Werkzeug==3.1.6 +wrapt==2.1.1 xaif_eval==0.0.9 +xmltodict==1.0.4 +xxhash==3.6.0 +yarl==1.22.0 amf-fast-inference==0.0.3 -markdown2 - diff --git a/tests/api-requests/BERT TE/GET Info.bru b/tests/api-requests/BERT TE/GET Info.bru new file mode 100644 index 0000000..5e2523b --- /dev/null +++ b/tests/api-requests/BERT TE/GET Info.bru @@ -0,0 +1,22 @@ +meta { + name: GET Info + type: http + seq: 2 +} + +get { + url: {{baseUrl}}/bert-te + auth: inherit +} + +tests { + test("Response status should be 200", function () { + expect(res.status).to.equal(200); + }); + + test("Response should contain service description", function () { + const body = res.getBody(); + expect(body).to.be.a('string'); + expect(body).to.include('BART'); + }); +} diff --git a/tests/api-requests/BERT TE/XAIF Argumentation.bru b/tests/api-requests/BERT TE/XAIF Argumentation.bru new file mode 100644 index 0000000..607baa6 --- /dev/null +++ b/tests/api-requests/BERT TE/XAIF Argumentation.bru @@ -0,0 +1,83 @@ +meta { + name: XAIF Argumentation + type: http + seq: 3 +} + +post { + url: {{baseUrl}}/bert-te + body: multipartForm + auth: inherit +} + +headers { + Content-Type: multipart/form-data +} + +body:multipart-form { + file: @file(test-inputs/xaif_argumentation.json) +} + +tests { + // Three I-nodes about energy policy: + // I-node 4: "Renewable energy is essential for reducing carbon emissions." + // I-node 6: "Solar and wind power significantly reduce greenhouse gas output." + // I-node 8: "Fossil fuels are the only reliable source of energy for modern economies." + // + // The model identifies 2 conflict (CA) relations: + // (4, 8): renewables vs fossil fuels → CA + // (6, 8): solar/wind vs fossil fuels → CA + // The (4, 6) pair is neutral (both pro-renewable, no entailment). + + const expectedData = { + "AIF": { + "descriptorfulfillments": null, + "edges": [ + { "edgeID": 0, "fromID": 0, "toID": 3 }, + { "edgeID": 1, "fromID": 3, "toID": 4 }, + { "edgeID": 2, "fromID": 1, "toID": 5 }, + { "edgeID": 3, "fromID": 5, "toID": 6 }, + { "edgeID": 4, "fromID": 2, "toID": 7 }, + { "edgeID": 5, "fromID": 7, "toID": 8 }, + { "edgeID": 6, "fromID": 4, "toID": 9 }, + { "edgeID": 7, "fromID": 9, "toID": 8 }, + { "edgeID": 8, "fromID": 6, "toID": 10 }, + { "edgeID": 9, "fromID": 10, "toID": 8 } + ], + "locutions": [ + { "nodeID": 0, "personID": 0 }, + { "nodeID": 1, "personID": 1 }, + { "nodeID": 2, "personID": 2 } + ], + "nodes": [ + { "nodeID": 0, "text": "Renewable energy is essential for reducing carbon emissions.", "type": "L" }, + { "nodeID": 1, "text": "Solar and wind power significantly reduce greenhouse gas output.", "type": "L" }, + { "nodeID": 2, "text": "Fossil fuels are the only reliable source of energy for modern economies.", "type": "L" }, + { "nodeID": 3, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 4, "text": "Renewable energy is essential for reducing carbon emissions.", "type": "I" }, + { "nodeID": 5, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 6, "text": "Solar and wind power significantly reduce greenhouse gas output.", "type": "I" }, + { "nodeID": 7, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 8, "text": "Fossil fuels are the only reliable source of energy for modern economies.", "type": "I" }, + { "nodeID": 9, "text": "Default Conflict", "type": "CA" }, + { "nodeID": 10, "text": "Default Conflict", "type": "CA" } + ], + "participants": [ + { "firstname": "Speaker", "participantID": 0, "surname": "A" }, + { "firstname": "Speaker", "participantID": 1, "surname": "B" }, + { "firstname": "Speaker", "participantID": 2, "surname": "C" } + ], + "schemefulfillments": null + }, + "dialog": true, + "ova": [], + "text": { + "txt": " Speaker A Renewable energy is essential for reducing carbon emissions..

Speaker B Solar and wind power significantly reduce greenhouse gas output..

Speaker C Fossil fuels are the only reliable source of energy for modern economies..

" + } + }; + + test("Response should match expected value", function () { + const receivedData = res.getBody(); + expect(receivedData).to.deep.equal(expectedData); + }); +} diff --git a/tests/api-requests/BERT TE/XAIF Sample.bru b/tests/api-requests/BERT TE/XAIF Sample.bru new file mode 100644 index 0000000..4a7a5ac --- /dev/null +++ b/tests/api-requests/BERT TE/XAIF Sample.bru @@ -0,0 +1,73 @@ +meta { + name: XAIF Sample + type: http + seq: 1 +} + +post { + url: {{baseUrl}}/bert-te + body: multipartForm + auth: inherit +} + +headers { + Content-Type: multipart/form-data +} + +body:multipart-form { + file: @file(test-inputs/xaif_sample.json) +} + +tests { + // From the README: the model should identify 1 RA relation + // between I-node 3 ("disagreements between party members are entirely to be expected") + // and I-node 7 ("it's not uncommon for there to be disagreements between party members") + // because they entail each other. + const expectedData = { + "AIF": { + "descriptorfulfillments": null, + "edges": [ + { "edgeID": 0, "fromID": 0, "toID": 4 }, + { "edgeID": 1, "fromID": 4, "toID": 3 }, + { "edgeID": 2, "fromID": 1, "toID": 6 }, + { "edgeID": 3, "fromID": 6, "toID": 5 }, + { "edgeID": 4, "fromID": 2, "toID": 8 }, + { "edgeID": 5, "fromID": 8, "toID": 7 }, + { "edgeID": 6, "fromID": 3, "toID": 9 }, + { "edgeID": 7, "fromID": 9, "toID": 7 } + ], + "locutions": [ + { "nodeID": 0, "personID": 0 }, + { "nodeID": 1, "personID": 1 }, + { "nodeID": 2, "personID": 2 } + ], + "nodes": [ + { "nodeID": 0, "text": "disagreements between party members are entirely to be expected.", "type": "L" }, + { "nodeID": 1, "text": "the SNP has disagreements.", "type": "L" }, + { "nodeID": 2, "text": "it's not uncommon for there to be disagreements between party members.", "type": "L" }, + { "nodeID": 3, "text": "disagreements between party members are entirely to be expected.", "type": "I" }, + { "nodeID": 4, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 5, "text": "the SNP has disagreements.", "type": "I" }, + { "nodeID": 6, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 7, "text": "it's not uncommon for there to be disagreements between party members.", "type": "I" }, + { "nodeID": 8, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 9, "text": "Default Inference", "type": "RA" } + ], + "participants": [ + { "firstname": "Speaker", "participantID": 0, "surname": "1" }, + { "firstname": "Speaker", "participantID": 1, "surname": "2" } + ], + "schemefulfillments": null + }, + "dialog": true, + "ova": [], + "text": { + "txt": " Speaker 1 disagreements between party members are entirely to be expected..

Speaker 2 the SNP has disagreements..

Speaker 1 it's not uncommon for there to be disagreements between party members. .

" + } + }; + + test("Response should match expected value", function () { + const receivedData = res.getBody(); + expect(receivedData).to.deep.equal(expectedData); + }); +} diff --git a/tests/api-requests/BERT TE/bruno.json b/tests/api-requests/BERT TE/bruno.json new file mode 100644 index 0000000..4941ccc --- /dev/null +++ b/tests/api-requests/BERT TE/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "BERT TE", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/tests/api-requests/BERT TE/environments/(1) local.bru b/tests/api-requests/BERT TE/environments/(1) local.bru new file mode 100644 index 0000000..1f63896 --- /dev/null +++ b/tests/api-requests/BERT TE/environments/(1) local.bru @@ -0,0 +1,3 @@ +vars { + baseUrl: http://localhost:5002 +} diff --git a/tests/api-requests/BERT TE/environments/(2) staging.bru b/tests/api-requests/BERT TE/environments/(2) staging.bru new file mode 100644 index 0000000..cabf000 --- /dev/null +++ b/tests/api-requests/BERT TE/environments/(2) staging.bru @@ -0,0 +1,3 @@ +vars { + baseUrl: http://bert-te.amfws.staging.arg.tech +} diff --git a/tests/api-requests/BERT TE/environments/(3) production.bru b/tests/api-requests/BERT TE/environments/(3) production.bru new file mode 100644 index 0000000..56de895 --- /dev/null +++ b/tests/api-requests/BERT TE/environments/(3) production.bru @@ -0,0 +1,3 @@ +vars { + baseUrl: http://bert-te.amfws.arg.tech +} diff --git a/tests/api-requests/BERT TE/test-inputs/xaif_argumentation.json b/tests/api-requests/BERT TE/test-inputs/xaif_argumentation.json new file mode 100644 index 0000000..06bf0ad --- /dev/null +++ b/tests/api-requests/BERT TE/test-inputs/xaif_argumentation.json @@ -0,0 +1,40 @@ +{ + "AIF": { + "descriptorfulfillments": null, + "edges": [ + { "edgeID": 0, "fromID": 0, "toID": 3 }, + { "edgeID": 1, "fromID": 3, "toID": 4 }, + { "edgeID": 2, "fromID": 1, "toID": 5 }, + { "edgeID": 3, "fromID": 5, "toID": 6 }, + { "edgeID": 4, "fromID": 2, "toID": 7 }, + { "edgeID": 5, "fromID": 7, "toID": 8 } + ], + "locutions": [ + { "nodeID": 0, "personID": 0 }, + { "nodeID": 1, "personID": 1 }, + { "nodeID": 2, "personID": 2 } + ], + "nodes": [ + { "nodeID": 0, "text": "Renewable energy is essential for reducing carbon emissions.", "type": "L" }, + { "nodeID": 1, "text": "Solar and wind power significantly reduce greenhouse gas output.", "type": "L" }, + { "nodeID": 2, "text": "Fossil fuels are the only reliable source of energy for modern economies.", "type": "L" }, + { "nodeID": 3, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 4, "text": "Renewable energy is essential for reducing carbon emissions.", "type": "I" }, + { "nodeID": 5, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 6, "text": "Solar and wind power significantly reduce greenhouse gas output.", "type": "I" }, + { "nodeID": 7, "text": "Default Illocuting", "type": "YA" }, + { "nodeID": 8, "text": "Fossil fuels are the only reliable source of energy for modern economies.", "type": "I" } + ], + "participants": [ + { "firstname": "Speaker", "participantID": 0, "surname": "A" }, + { "firstname": "Speaker", "participantID": 1, "surname": "B" }, + { "firstname": "Speaker", "participantID": 2, "surname": "C" } + ], + "schemefulfillments": null + }, + "dialog": true, + "ova": [], + "text": { + "txt": " Speaker A Renewable energy is essential for reducing carbon emissions..

Speaker B Solar and wind power significantly reduce greenhouse gas output..

Speaker C Fossil fuels are the only reliable source of energy for modern economies..

" + } +} \ No newline at end of file diff --git a/tests/api-requests/BERT TE/test-inputs/xaif_sample.json b/tests/api-requests/BERT TE/test-inputs/xaif_sample.json new file mode 100644 index 0000000..f7841ca --- /dev/null +++ b/tests/api-requests/BERT TE/test-inputs/xaif_sample.json @@ -0,0 +1,116 @@ +{ + "AIF": { + "descriptorfulfillments": null, + "edges": [ + { + "edgeID": 0, + "fromID": 0, + "toID": 4 + }, + { + "edgeID": 1, + "fromID": 4, + "toID": 3 + }, + { + "edgeID": 2, + "fromID": 1, + "toID": 6 + }, + { + "edgeID": 3, + "fromID": 6, + "toID": 5 + }, + { + "edgeID": 4, + "fromID": 2, + "toID": 8 + }, + { + "edgeID": 5, + "fromID": 8, + "toID": 7 + } + ], + "locutions": [ + { + "nodeID": 0, + "personID": 0 + }, + { + "nodeID": 1, + "personID": 1 + }, + { + "nodeID": 2, + "personID": 2 + } + ], + "nodes": [ + { + "nodeID": 0, + "text": "disagreements between party members are entirely to be expected.", + "type": "L" + }, + { + "nodeID": 1, + "text": "the SNP has disagreements.", + "type": "L" + }, + { + "nodeID": 2, + "text": "it's not uncommon for there to be disagreements between party members.", + "type": "L" + }, + { + "nodeID": 3, + "text": "disagreements between party members are entirely to be expected.", + "type": "I" + }, + { + "nodeID": 4, + "text": "Default Illocuting", + "type": "YA" + }, + { + "nodeID": 5, + "text": "the SNP has disagreements.", + "type": "I" + }, + { + "nodeID": 6, + "text": "Default Illocuting", + "type": "YA" + }, + { + "nodeID": 7, + "text": "it's not uncommon for there to be disagreements between party members.", + "type": "I" + }, + { + "nodeID": 8, + "text": "Default Illocuting", + "type": "YA" + } + ], + "participants": [ + { + "firstname": "Speaker", + "participantID": 0, + "surname": "1" + }, + { + "firstname": "Speaker", + "participantID": 1, + "surname": "2" + } + ], + "schemefulfillments": null + }, + "dialog": true, + "ova": [], + "text": { + "txt": " Speaker 1 disagreements between party members are entirely to be expected..

Speaker 2 the SNP has disagreements..

Speaker 1 it's not uncommon for there to be disagreements between party members. .

" + } +} \ No newline at end of file