Weekly batch tagger for Immich, powered by RAM++ (Recognize Anything Plus)
  • Python 89.5%
  • Dockerfile 10.5%
Find a file
LostSynapse e626c4e5bc
All checks were successful
build / Validate (PR build-only) (push) Has been skipped
build / Build and push multi-arch image (push) Successful in 7m58s
i really want to murder claude
2026-04-30 11:54:12 -04:00
.forgejo/workflows fix buildx network 2026-04-30 09:14:03 -04:00
Dockerfile i really want to murder claude 2026-04-30 11:54:12 -04:00
LICENSE Initial commit 2026-04-30 00:51:25 +00:00
README.md redesign 2026-04-30 11:12:23 -04:00
requirements.txt i really want to murder claude 2026-04-30 11:54:12 -04:00
tagger.py redesign 2026-04-30 11:12:23 -04:00

immich-ram-tagger

Weekly batch tagger for Immich, powered by RAM++ (Recognize Anything Plus). Adds hierarchical AI tags (AI/RAM++/<tag>) to every image asset in your Immich library so they're distinguishable from human-curated tags and bulk- deletable later.

This repo only produces the container image. The Kubernetes deployment manifests live in the synapse cluster repo at kubernetes/infrastructure/immich-tagger/.

What it does

  1. Connects directly to Immich Postgres (read of asset table + this script's own tagger_state table for resumability).
  2. For each pending asset: fetches the preview via Immich API, runs RAM++ inference (CPU), collects tags above the configured threshold, posts each tag via Immich API as AI/RAM++/<tag>, marks the asset done.
  3. Exits when there are no more pending assets, or when MAX_ASSETS is hit.

Designed as the entrypoint of a weekly Kubernetes CronJob. Resumable across runs - the state table ensures previously-tagged assets aren't re-tagged unless RAM_MODEL_VERSION is bumped.

Configuration

All via environment variables:

Variable Default Notes
RAM_MODEL_URL HuggingFace URL for ram_plus_swin_large_14m.pth Source for first-run download
RAM_MODEL_PATH /cache/ram-plus/ram_plus_swin_large_14m.pth Where to cache (NFS-backed in cluster)
RAM_MODEL_VERSION ram_plus_swin_large_14m Stored per-asset; bump to force re-tagging
RAM_IMAGE_SIZE 384 Inference resolution (RAM++ default)
RAM_THRESHOLD 0.55 Per-class sigmoid threshold; upstream default is 0.68
RAM_TAG_PREFIX AI/RAM++ Hierarchy root for tags created by this tool
IMMICH_BASE_URL http://immich-server.immich.svc.cluster.local:2283
IMMICH_API_KEY required Library-owner API key
DB_HOSTNAME required
DB_PORT 5432
DB_DATABASE_NAME immich
DB_USERNAME immich
DB_PASSWORD required
BATCH_SIZE 200 Rows per pending-asset query
MAX_ASSETS 0 (unlimited) Cap per run if predictable runtime needed
OMP_NUM_THREADS 4 Torch CPU thread count

API key permissions

Generate the API key in Immich UI as the library-owning user with:

  • asset.read (preview download)
  • tag.create, tag.read, tag.update (upsert + attach tags)

Tags in Immich are per-user; only the library owner's API key can attach tags to assets in their library.

Building locally

podman build -t git.lost-synapse.com/lostsynapse/immich-ram-tagger:dev .
podman push   git.lost-synapse.com/lostsynapse/immich-ram-tagger:dev

State table

CREATE TABLE IF NOT EXISTS tagger_state (
    asset_id   UUID PRIMARY KEY,
    tagged_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    model_ver  TEXT        NOT NULL,
    tag_count  INT         NOT NULL
);

Lives in the Immich database. Auto-created on first run. Not touched by Immich migrations (Immich has no tagger_state table of its own).

To force re-tag of everything: bump RAM_MODEL_VERSION env in the CronJob to a new string. The query joins on model_ver, so non-matching rows are treated as pending.

To wipe state entirely: TRUNCATE tagger_state;.

License & attribution