Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 5 additions & 32 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
11 changes: 3 additions & 8 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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"
120 changes: 111 additions & 9 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -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

22 changes: 22 additions & 0 deletions tests/api-requests/BERT TE/GET Info.bru
Original file line number Diff line number Diff line change
@@ -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');
});
}
83 changes: 83 additions & 0 deletions tests/api-requests/BERT TE/XAIF Argumentation.bru
Original file line number Diff line number Diff line change
@@ -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 <span class=\"highlighted\" id=\"0\">Renewable energy is essential for reducing carbon emissions.</span>.<br><br> Speaker B <span class=\"highlighted\" id=\"1\">Solar and wind power significantly reduce greenhouse gas output.</span>.<br><br> Speaker C <span class=\"highlighted\" id=\"2\">Fossil fuels are the only reliable source of energy for modern economies.</span>.<br><br>"
}
};

test("Response should match expected value", function () {
const receivedData = res.getBody();
expect(receivedData).to.deep.equal(expectedData);
});
}
73 changes: 73 additions & 0 deletions tests/api-requests/BERT TE/XAIF Sample.bru
Original file line number Diff line number Diff line change
@@ -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 <span class=\"highlighted\" id=\"0\">disagreements between party members are entirely to be expected.</span>.<br><br> Speaker 2 <span class=\"highlighted\" id=\"1\">the SNP has disagreements.</span>.<br><br> Speaker 1 <span class=\"highlighted\" id=\"2\">it's not uncommon for there to be disagreements between party members. </span>.<br><br>"
}
};

test("Response should match expected value", function () {
const receivedData = res.getBody();
expect(receivedData).to.deep.equal(expectedData);
});
}
9 changes: 9 additions & 0 deletions tests/api-requests/BERT TE/bruno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": "1",
"name": "BERT TE",
"type": "collection",
"ignore": [
"node_modules",
".git"
]
}
3 changes: 3 additions & 0 deletions tests/api-requests/BERT TE/environments/(1) local.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vars {
baseUrl: http://localhost:5002
}
3 changes: 3 additions & 0 deletions tests/api-requests/BERT TE/environments/(2) staging.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vars {
baseUrl: http://bert-te.amfws.staging.arg.tech
}
3 changes: 3 additions & 0 deletions tests/api-requests/BERT TE/environments/(3) production.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vars {
baseUrl: http://bert-te.amfws.arg.tech
}
Loading
Loading