Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3f52296
CU-8698up3x0: Now depends on medcatv2
mart-r Apr 23, 2025
8c01777
Move to MedCAT v2-based approach
mart-r Apr 23, 2025
a04403d
Show that this is v2 on the base template
mart-r Apr 23, 2025
ae09a37
CU-8698up3x0: Update python to 3.11 and add git installation
mart-r Apr 24, 2025
302dbe3
CU-8698up3x0: Fix json-serialisation for numpy.float32
mart-r Apr 24, 2025
9874791
CU-8698up3x0: Use multi-stage build to lower image size
mart-r Apr 25, 2025
67dce0c
CU-8698up3x0: Make sure to keep pip cache for 2nd stage
mart-r Apr 25, 2025
de143d6
CU-8698up3x0: Update pip before installing requirements
mart-r Apr 25, 2025
78d65af
CU-8698up3x0: Use fewer layers
mart-r Apr 25, 2025
ef2f93c
CU-8698up3x0: Make sure installed python packages are available in st…
mart-r Apr 25, 2025
04437f1
CU-8698up3x0: Allow building image with no GPU components
mart-r Apr 29, 2025
cbe27c2
CU-8698up3x0: Fix requirements file path in new dockerfile
mart-r Apr 29, 2025
265d737
CU-8698up3x0: Bump dependency to v0.2.3
mart-r Apr 30, 2025
9ca1606
CU-8698up3x0: Fix medcat2 install - remove non-existent optional part
mart-r May 1, 2025
42dd64b
CU-8698up3x0: Update demo webapp to v0.3.0
mart-r May 9, 2025
e186c40
CU-8698up3x0: Update requirements to v0.3.1
mart-r May 9, 2025
1fec4fd
Move to MedCAT v2 0.3.3
mart-r May 13, 2025
d916c67
CU-8698up3x0: Small whitespace fix
mart-r May 13, 2025
039324d
CU-8698up3x0: Add running MedCAT (v2) version to header
mart-r May 13, 2025
38d7747
CU-8698up3x0: Fix version string in base render
mart-r May 13, 2025
3c7dcf8
CU-8698up3x0: Update medcat installation version (to v0.8.0)
mart-r Jun 19, 2025
f54f9bc
CU-8698up3x0: Fix imports to correct root package
mart-r Jun 19, 2025
d497096
CU-8698up3x0: Fix medcat version context
mart-r Jun 19, 2025
3ff5446
CU-8698up3x0: Clear things after install
mart-r Jun 19, 2025
93ccb00
CU-8698up3x0: Add default for version being run in template
mart-r Jun 19, 2025
455d1ca
Merge branch 'CU-8698up3x0-demo-webapp-medcat-v2' of github.com:CogSt…
mart-r Jun 19, 2025
a844e40
CU-8698up3x0: Fix renamed ents attribute
mart-r Jun 19, 2025
3ea2aa9
CU-8699gb53b: Add endpoint for UMLS api-key validation
mart-r Jun 20, 2025
9bd559b
CU-8699gb53b: Update requirements to latest medcat
mart-r Jun 20, 2025
0dfc3a9
CU-8699gb53b: Use latest compatible python (3.12)
mart-r Jun 20, 2025
2ce68ec
CU-8699gb53b: Update Dockerfile to use a smaller build / image
mart-r Jun 20, 2025
9f6d065
CU-8699gb53b: Update Dockerfile to use python 3.12 correctly
mart-r Jun 20, 2025
e1ce7e7
CU-8699gb53b: Add template for UMLS API key entry
mart-r Jun 20, 2025
fcc4a8c
CU-8699gb53b: Fix UMLS API validation
mart-r Jun 20, 2025
668f618
Merge remote-tracking branch 'origin/CU-8698up3x0-demo-webapp-medcat-…
mart-r Jun 27, 2025
a3cef74
Merge remote-tracking branch 'origin/CU-8699gb53b-api-key-model-dl' i…
mart-r Jun 27, 2025
2e722f6
CU-8699k4eem: Update dependency to latest / v2 based
mart-r Jun 27, 2025
9963267
CU-8699k4eem: Add a simple workflow to check demo web app
mart-r Jun 27, 2025
0ccf0b2
CU-8699k4eem: Make integration tests executable
mart-r Jun 30, 2025
2559e0c
CU-8699k4eemL Fix workflow time test for demo
mart-r Jun 30, 2025
d98426f
CU-8699k4eem: Move bulk of tests to python script
mart-r Jun 30, 2025
313bde7
CU-8699k4eem: Add response output to tests
mart-r Jun 30, 2025
86c2d3c
CU-8699k4eem: Fix teardown step (typo in compose file name)
mart-r Jun 30, 2025
fb7c7b6
CU-8699k4eem: Add more robust test for output
mart-r Jun 30, 2025
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
35 changes: 35 additions & 0 deletions .github/workflows/medcat-demo-app_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: medcat-demo - Test

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

defaults:
run:
working-directory: ./medcat-demo-app

jobs:
integration-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Set up Docker Compose
run: sudo apt-get update && sudo apt-get install -y docker-compose

- name: Build and start containers
run: docker-compose -f docker-compose-test.yml up -d --build

- name: Run integration test
run: ./tests/test_integration.sh

- name: Check container logs for errors
run: |
docker-compose logs medcatweb
docker-compose logs medcatweb | grep -i 'error' && exit 1 || true

- name: Tear down
run: docker-compose -f docker-compose-test.yml down
16 changes: 16 additions & 0 deletions medcat-demo-app/docker-compose-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: '3.4'

services:
medcatweb:
build:
context: ./webapp
command: >
bash -c "/etc/init.d/cron start &&
python /webapp/manage.py runserver 0.0.0.0:8000"
volumes:
- ../medcat-v2/tests/resources:/webapp/models
ports:
- "8000:8000"
env_file:
- ./envs/env_medmen_test
tty: true
1 change: 1 addition & 0 deletions medcat-demo-app/envs/env_medmen_test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MODEL_PACK_PATH=/webapp/models/mct2_model_pack.zip
33 changes: 33 additions & 0 deletions medcat-demo-app/tests/test_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# tests/test_integration.py

import requests

from bs4 import BeautifulSoup

URL = "http://localhost:8000/"
session = requests.Session()

# GET the page to get the CSRF token
resp = session.get(URL)
soup = BeautifulSoup(resp.text, "html.parser")
csrf = soup.find("input", {"name": "csrfmiddlewaretoken"}).get("value")

disease = "kidney failure"

text = f"Patient had been diagnosed with acute {disease} the week before"

# POST with the token and same session (cookies preserved)
resp = session.post(URL, data={
"text": text,
"csrfmiddlewaretoken": csrf})

print(f"RESPOONSE:\n{resp.text}")

soup = BeautifulSoup(resp.text, "html.parser")

annotations = soup.select("div.entities mark.entity")
assert annotations, "No annotations found in the response"
assert any(disease in mark.text.lower() for mark in annotations), (
f"Disease '{disease}' not found in annotations")

assert disease in resp.text
20 changes: 20 additions & 0 deletions medcat-demo-app/tests/test_integration.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash
set -euo pipefail

echo "Waiting for service to start..."

# install bs4 for tests
python -m pip install beautifulsoup4

# Wait until curl doesn't fail
for i in {1..60}; do
if curl -s --fail http://localhost:8000 > /dev/null; then
echo "Service is up"
break
else
echo "Waiting ($i)..."
sleep 2
fi
done

python tests/test_integration.py
64 changes: 48 additions & 16 deletions medcat-demo-app/webapp/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,37 +1,69 @@
FROM python:3.7
# Stage 1: Build stage (dependencies and compilation)
FROM python:3.12-slim as build

# Create the required folders
RUN mkdir -p /webapp/models

# Copy everything
# Copy the application code
COPY . /webapp

# Install dependencies for building (git, etc.)
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
build-essential \
apt-utils \
cron \
sqlite3 \
libsqlite3-dev

# Install Python dependencies
ARG USE_CPU_TORCH=false
# NOTE: Allow building without GPU so as to lower image size (disabled by default)
RUN pip install -U pip && if [ "$USE_CPU_TORCH" = "true" ]; then \
pip install -r /webapp/requirements.txt --extra-index-url https://download.pytorch.org/whl/cpu/; \
else \
pip install -r /webapp/requirements.txt; \
fi

# Get the spacy model (for later copy)
RUN python -m spacy download en_core_web_md

# Stage 2: Final (production) image
FROM python:3.12-slim as final

# Install runtime dependencies (you don’t need git in production)
RUN apt-get update && apt-get install -y --no-install-recommends \
cron \
sqlite3 \
libsqlite3-dev && apt-get autoremove

# Create the required folders (if not created already)
RUN mkdir -p /webapp/models && mkdir -p /medcat_data

# Copy only necessary files from build stage
COPY --from=build /webapp /webapp
# COPY --from=build /root/.cache /root/.cache # Copy pip cache if needed

# Copy Python site-packages (installed by pip) from build stage
COPY --from=build /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages

# Set environment variables
ENV VOCAB_URL=https://medcat.rosalind.kcl.ac.uk/media/vocab.dat
ENV CDB_URL=https://medcat.rosalind.kcl.ac.uk/media/cdb-medmen-v1.dat

ENV CDB_PATH=/webapp/models/cdb.dat
ENV VOCAB_PATH=/webapp/models/vocab.dat

# Create the data directory
RUN mkdir -p /medcat_data

# Set the pythonpath
WORKDIR /webapp

RUN pip install -r requirements.txt

# Get the spacy model
RUN python -m spacy download en_core_web_md
# Create the db backup cron job (copied from your setup)
COPY etc/cron.d/db-backup-cron /etc/cron.d/db-backup-cron
RUN chmod 0644 /etc/cron.d/db-backup-cron && crontab /etc/cron.d/db-backup-cron

# Build the db
# Run migrations and collect static (could be in entrypoint script)
RUN python manage.py makemigrations && \
python manage.py makemigrations demo && \
python manage.py migrate && \
python manage.py migrate demo && \
python manage.py collectstatic --noinput

# Create the db backup cron job
RUN apt-get update && apt-get install -y --no-install-recommends apt-utils cron sqlite3 libsqlite3-dev
COPY etc/cron.d/db-backup-cron /etc/cron.d/db-backup-cron
RUN chmod 0644 /etc/cron.d/db-backup-cron
RUN crontab /etc/cron.d/db-backup-cron
5 changes: 5 additions & 0 deletions medcat-demo-app/webapp/demo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ class Meta:
"funder": forms.TextInput(attrs={"size": 40}),
"use_case": forms.Textarea(attrs={"rows": 5, "cols": 40}),
}


class UMLSApiKeyForm(forms.Form):
apikey = forms.CharField(label='UMLS API Key',
widget=forms.TextInput(attrs={'size': 50}))
2 changes: 1 addition & 1 deletion medcat-demo-app/webapp/demo/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">MedCAT</a>
<a class="navbar-brand" href="/">MedCAT v2 (running v{{ medcat_version|default:"N/A" }})</a>

<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
Expand Down
49 changes: 49 additions & 0 deletions medcat-demo-app/webapp/demo/templates/umls_api_key_entry.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{% extends 'base.html' %}
{% load static %}

{% block style %}
<link rel="stylesheet" href="{% static 'css/home.css' %}">
<link rel="stylesheet" href="{% static 'css/annotations.css' %}">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css" integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
<link rel="icon" href="{% static 'image/favicon.ico' %}">
{% endblock %}

{% block body %}
<div class="container-fluid">
<h5>Please enter your UMLS API key to verify your license:</h5>

{% if message %}
<div class="alert alert-info">
{{ message }}
</div>
{% endif %}

{% if form.errors %}
<div class="alert alert-danger">
<ul>
{% for field in form %}
{% for error in field.errors %}
<li><strong>{{ field.label }}:</strong> {{ error }}</li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}

<form method="post">
{% csrf_token %}
<div class="form-group">
{{ form.apikey.label_tag }}
{{ form.apikey }}
</div>
<button type="submit" class="btn btn-primary">Verify API Key</button>
</form>

<p class="mt-3 text-muted">
You can find your API key by logging into your UMLS account and visiting your <a href="https://uts.nlm.nih.gov/uts/profile" target="_blank">UMLS Profile</a>.
</p>
</div>
{% endblock %}
1 change: 1 addition & 0 deletions medcat-demo-app/webapp/demo/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
urlpatterns = [
path('', show_annotations, name='train_annotations'),
path('auth-callback', validate_umls_user, name='validate-umls-user'),
path('auth-callback-api', validate_umls_api_key, name='validate-umls-api-key'),
path('download-model', download_model, name="download-model")
]
Loading