Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2f5f644
CU-869bepjj9 Add gliner for medcat (#165)
mart-r Dec 15, 2025
b8688f3
CU-869bepjj9: Adopt rename of external (to MedCAT) projects as plugin…
mart-r Jan 5, 2026
7bbc7ad
Add NER recall comparison section to README (#196)
mart-r Jan 6, 2026
8620d20
Merge remote-tracking branch 'temp-source-for-gliner/main' into chore…
mart-r Feb 10, 2026
884ba50
CU-869c3bvm0: Add workflow for gliner
mart-r Feb 10, 2026
28f8dd3
CU-869c3bvm0: Add release workflow for gliner
mart-r Feb 10, 2026
f549067
CU-869c3bvm0: Only do lazy registration for gliner
mart-r Feb 10, 2026
6dff54b
CU-869c3bvm0: Update pyproject toml to only support medcat 2.5 and up…
mart-r Feb 10, 2026
393ad21
CU-869c3bvm0: Add publish to TestPyPI to workflow
mart-r Feb 10, 2026
f10a918
CU-869c3bvm0: Update version scheme in pyproject.toml
mart-r Feb 10, 2026
ce819a8
CU-869c3bvm0: Update pyproject.toml with root / git path for gliner
mart-r Feb 10, 2026
7a7a18e
CU-869c3bvm0: Update pyproject.toml with git describe command
mart-r Feb 10, 2026
f09b22e
CU-869c3bvm0: Setup dev version before dep install
mart-r Feb 10, 2026
25f2b8e
CU-869c3bvm0: Update some of the actions
mart-r Feb 10, 2026
b9c5f81
CU-869c36ruk: Update tag regex
mart-r Feb 10, 2026
2c15273
CU-869c3bvm0: [TODO: REMOVE] Add debug output regarding tags to main …
mart-r Feb 10, 2026
42ad9f0
CU-869c3bvm0: Fix workflow actions version issue
mart-r Feb 10, 2026
88c0f8e
Revert "CU-869c3bvm0: [TODO: REMOVE] Add debug output regarding tags …
mart-r Feb 10, 2026
d912335
CU-869c3bvm0: Fix linting issue
mart-r Feb 10, 2026
9fae9d9
CU-869c3bvm0: Fix permissions issue with workflow PyPI push
mart-r Feb 10, 2026
2b3102c
CU-869c3bvm0: Update gliner plugin details in plugin catalog
mart-r Feb 11, 2026
dfdec2f
CU-869c3bvm0: Fix small issue with plugin catalog
mart-r Feb 11, 2026
8ee4b78
CU-869c3bvm0: Update docstring for clarity in gliner_ner.py
mart-r Feb 11, 2026
64362a9
CU-869c3bvm0: Rename workflow file
mart-r Feb 11, 2026
230494e
CU-869c3bvm0: Centralise workflow file
mart-r Feb 11, 2026
89bbd71
CU-869c3bvm0: Remove unnecessary line
mart-r Feb 11, 2026
d0bed62
CU-869c3bvm0: Moved to uv in workflows
mart-r Feb 11, 2026
eebb351
CU-869c3bvm0: Add transitive dependency (with description) to pyproje…
mart-r Feb 11, 2026
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
88 changes: 88 additions & 0 deletions .github/workflows/medcat-gliner_main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: MedCAT-Gliner-main

on:
push:
branches: [ main ]
paths:
- 'medcat-plugins/medcat-gliner/**'
- '.github/workflows/medcat-gliner**'
pull_request:
paths:
- 'medcat-plugins/medcat-gliner/**'
- '.github/workflows/medcat-gliner**'

defaults:
run:
working-directory: ./medcat-plugins/medcat-gliner

jobs:
tests:

runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
max-parallel: 4

steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
df -h # check spaces before
python -m pip install --upgrade pip
pip install -e ".[dev]" --extra-index-url https://download.pytorch.org/whl/cpu/
df -h # check spaces after
- name: Check types
run: |
python -m mypy --follow-imports=normal src/medcat_gliner --follow-untyped-imports
- name: Lint
run: |
ruff check src/medcat_gliner --preview
- name: Test
run: |
python -m unittest discover
Comment thread Fixed

publish-to-test-PyPI:
Comment thread Fixed
runs-on: ubuntu-latest
needs: tests
steps:
- name: Checkout main
uses: actions/checkout@v6
with:
fetch-depth: 0 # fetch all history
fetch-tags: true # fetch tags explicitly

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade build

- name: Set timestamp-based dev version
run: |
TS=$(date -u +"%Y%m%d%H%M%S")
echo "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_MEDCAT_GLINER=0.2.2.dev${TS}" >> $GITHUB_ENV

- name: Install package in development mode
run: |
pip install -e .

- name: Build package
run: |
python -m build

- name: Publish distribution to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository_url: https://test.pypi.org/legacy/
packages_dir: medcat-plugins/medcat-gliner/dist

51 changes: 51 additions & 0 deletions .github/workflows/medcat-gliner_release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: medcat-gliner release-build

on:
push:
tags:
- 'medcat-gliner/v*.*.*'

permissions:
id-token: write

defaults:
run:
working-directory: ./medcat-plugins/medcat-gliner

jobs:
test-and-publish-to-PyPI:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v6

- name: Release Tag
# If GITHUB_REF=refs/tags/medcat-gliner/v0.1.2, this returns v0.1.2. Note it's including the "v" though it probably shouldnt
run: echo "RELEASE_VERSION=${GITHUB_REF##refs/*/}" >> $GITHUB_ENV

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.10'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade build

- name: Install client package in development mode
run: |
pip install -e ".[dev]"

- name: Test
run: |
pytest tests

- name: Build client package
run: |
python -m build

- name: Publish production distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages_dir: medcat-plugins/medcat-gliner/dist
38 changes: 38 additions & 0 deletions medcat-plugins/medcat-gliner/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# MedCAT-gliner

This provides [gliner](https://github.com/urchade/GLiNER) based NER step for MedCAT core library.

# Usage

First install from PyPI, e.g:
```
pip install medcat-gliner
```
Subsequently, if you have an existing model, you should be able to just change the NER component:
```
cat = CAT.load_model_pack("path/to/existing/model")
# change component
from medcat_gliner import GLiNERConfig
cat.config.components.ner.comp_name = "gliner_ner"
cat.config.components.ner.custom_cnf = GLiNERConfig()
# recreate pipe with new NER component
cat._recreate_pipe()
# use as needed
```

## NER recall comparison (linkable SNOMED entities)

The following results compare the existing NER (vocab based NER with spell checking) implementation with the gliner implementation when used as the NER component within MedCAT.
Evaluation was performed on the **2023 SNOMED CT Linking Challenge** dataset.

> **Important caveat**
> This is **not a measure of general NER quality**.
> Recall is computed only with respect to annotated, linkable SNOMED CT entities present in the linking dataset.
> Mentions outside the annotation scope are treated as false positives by construction, so precision is not meaningful here.

| Implementation | True Positives | False Negatives | Recall | Runtime |
| ---------------------- | -------------- | --------------- | ------ | ------- |
| Vocab based NER | 10,545 | 3,917 | 0.729 | ~5m 50s |
| GliNER implementation | 7,971 | 6,491 | 0.551 | ~34m |

As we can see, for this dataset, GliNER is significantly slower and performs worse than the standard vocab based implementation. This is likely because the vocab based NER step has been configured and tuned to work best within the MedCAT pipeline. It is likely that with additional tuning the GliNER implementation could perform as good or better than the vocab based linker does.
60 changes: 60 additions & 0 deletions medcat-plugins/medcat-gliner/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
[build-system]
requires = ["setuptools>=61.0", "wheel", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"

[project]
name = "medcat_gliner"
dynamic = ["version"]
description = ""
readme = "README.md"
license = { text = "Apache-2.0" }
authors = [
{ name="Mart Ratas", email="mart.ratas@kcl.ac.uk" }
]
requires-python = ">=3.10"

keywords = ["NLP", "NER", "medical", "MedCAT", "gliner"]

classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"License :: OSI Approved :: Apache Software License"
]

dependencies = [
"medcat>=2.5",
"gliner",
]

[project.optional-dependencies]
dev = [
"ruff",
"mypy",
]

# entry-points to add onto medcat
[project.entry-points."medcat.plugins"]
ner_gliner = "medcat_gliner"

[project.urls]
Homepage = "https://github.com/CogStack/medcat-ops/tree/main/medcat-gliner"
Repository = "https://github.com/CogStack/medcat-ops/tree/main/medcat-gliner"
Issues = "https://github.com/CogStack/medcat-ops/issues"

[tool.setuptools_scm]
root = ".."
tag_regex = "^medcat-gliner/v(?P<version>[0-9]+(?:\\.[0-9]+)*)$"
version_scheme = "post-release"
local_scheme = "no-local-version"

[tool.setuptools.packages.find]
where = ["src"]

[tool.setuptools.package-data]
"medcat_gliner" = ["py.typed"]
3 changes: 3 additions & 0 deletions medcat-plugins/medcat-gliner/src/medcat_gliner/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .registration import do_registration as __register

__register()
Loading
Loading