photoram is a CLI photo classifier powered by ImageNet-21K. It is designed as a modern, scriptable successor to photils-cli. The installed command is photoram-cli.
- ImageNet-21K classification with 21k-class label space.
- Offline inference after first-run model download.
- Batch inference (
--batch-size) with streaming mini-batch loading. - Stable JSON output contract:
--format jsonalways returns a list. - Standardized exit codes and validation errors.
- Service-layer architecture (
TaggingService) that decouples CLI from model internals. - photils compatibility flags:
--image,--output_file,--with_confidence.
- Deterministic model selection: pinned default model id (
vit_base_patch16_224.augreg_in21k). - Image safety checks: decompression-bomb protection is enabled (
PHOTORAM_MAX_IMAGE_PIXELS, default120000000). - Metadata subprocess hardening: exiftool invocation uses
--before image path to prevent option parsing. - Streaming batch loader: avoids preloading all tensors for large jobs.
- CI security gates:
bandit(SAST) andpip-audit(dependency CVEs).
- Python 3.9+
pipgit(for source installs)
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -e .
photoram-cli --helppip install -c constraints.txt -e .# Metadata fallback support (pyexiv2)
pip install -e ".[metadata]"
# Dev + test + security tooling
pip install -c constraints.txt -e ".[dev]"If you use --write-metadata, installing exiftool is recommended:
# macOS
brew install exiftool
# Debian/Ubuntu
sudo apt install libimage-exiftool-perl# Tag one image
photoram-cli tag photo.jpg
# Include confidence scores
photoram-cli tag photo.jpg --confidence
# Recursive directory tagging
photoram-cli tag ./photos --recursive
# Batch inference (faster on GPU, higher VRAM use)
photoram-cli tag ./photos --recursive --batch-size 32
# Write metadata
photoram-cli tag photo.jpg --write-metadata
# JSON output (always a list)
photoram-cli tag photo.jpg --format json
# Print timing summary (model load, tagging, total)
photoram-cli tag photo.jpg -T
# Show environment/model cache info
photoram-cli infoNote: first run requires internet access to download the ImageNet-21K model into the Hugging Face cache.
photoram-cli tag [OPTIONS] INPUT...
Arguments:
INPUT Image file(s) or directory to tag
Options:
-t, --threshold FLOAT Minimum class probability 0.0-1.0 (default: 0.0)
-n, --top-n INTEGER Maximum number of tags to return
-c, --confidence Show confidence scores
-f, --format FORMAT Output format: text, json, csv (default: json)
-o, --output FILE Write results to file
-r, --recursive Recursively scan directories
-w, --write-metadata Write tags to image EXIF/XMP/IPTC metadata
--overrides FILE Tag override/translation JSON file
--batch-size INT Images per inference batch (default: 16)
-T, --timings Print basic timings (load, tagging, total)
-q, --quiet Suppress progress output
-h, --help Show help
Compatibility alias for photils-dt-style calls:
photoram-cli tag --image "$FILE"Prints package version, torch/runtime capability, resolved default device, and model cache information.
A multi-image darktable plugin is included at:
darktable/photoram.lua
What it does:
- Works on all selected images in one action (not single-image only).
- Exposes tunable parameters in darktable preferences:
photoram: executable-> command/path tophotoram-cliphotoram: max tags->--top-nphotoram: threshold (%)->--thresholdphotoram: batch size->--batch-sizephotoram: write metadata->--write-metadataphotoram: quiet output->--quietphotoram: show timings->--timingsphotoram: device->--devicephotoram: overrides file->--overrides
Install:
mkdir -p ~/.config/darktable/lua
cp darktable/photoram.lua ~/.config/darktable/lua/photoram.lua
echo 'require "photoram"' >> ~/.config/darktable/luarcThen restart darktable and run the selected-images action:
photoram auto-tag
The plugin also registers a visible panel module:
- Name:
photoram auto-tagger - Location: right panel in lighttable (or left panel in darkroom)
- Button:
auto-tag selected
Troubleshooting:
- Check darktable Lua logs for load errors:
- Linux/macOS: start darktable from terminal and inspect stderr output.
- Ensure the panel is enabled in darktable module visibility settings.
- Confirm plugin is in the exact path:
~/.config/darktable/lua/photoram.lua
- Confirm
luarccontains:
require "photoram"
- If
photoram-cliis not on PATH, set preference:
photoram: executableto full binary path (for example/usr/local/bin/photoram-cli).
Always returns a list, even for one image.
[
{
"file": "photo.jpg",
"tags": ["tree", "sky"]
}
]- Add
--confidenceto includeconfidences. - Failed files include an
errorfield.
- One image:
tag1 | tag2 | tag3 - Multiple images:
<file>\t<tags>per line
- Base columns:
file,tags - Optional columns:
confidences
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | No images found |
| 2 | Invalid arguments |
| 3 | Model/download/load error |
| 4 | Other runtime error |
Create override_labels.json:
{
"blackbackground": "black background",
"art": "kunst",
"shadow": "schatten"
}Lookup order:
- Explicit
--overrides <file> ~/.config/photoram/override_labels.json
cli.py -> service.py -> model.py
\-> utils.py
\-> schemas.py
\-> errors.py
\-> metadata.py
src/photoram/cli.py: Click commands, progress, output and exit handling.src/photoram/service.py: orchestration layer (collection, dispatch, post-processing).src/photoram/model.py: ImageNet-21K model loading, preprocessing, inference, safety checks.src/photoram/schemas.py: result schemas (TagResult,BatchResult).src/photoram/errors.py: exception hierarchy and exit codes.src/photoram/metadata.py: metadata writing adapters.src/photoram/utils.py: file discovery, overrides, format helpers.
pip install -c constraints.txt -e ".[dev]"
pytestSecurity scans:
bandit -q -r src
pip-auditMain CLI contract tests:
tests/test_cli.pytests/test_cli_integration.py
MIT