AI-powered image description generator for Immich photo management system
Immich Analyze automatically generates detailed descriptions for images in your Immich library using AI vision models via Ollama or llama.cpp server. This enhances search capabilities and organization by providing semantic understanding of image content.
The application supports two data access modes:
- Database mode: Direct PostgreSQL database access for reading/writing Immich metadata. Note: this mode is planned for removal in a future release (0.5.0 or 0.6.0) since the Immich team does not support direct database access, and schema changes may break compatibility without notice.
- API mode: Uses the Immich API (requires
IMMICH_API_URL+IMMICH_API_KEY; supports multiple comma-separated keys for multi-user setups)
- AI-powered image analysis using Ollama or llama.cpp server with vision-capable models
- Multiple operation modes: batch processing, folder monitoring, or combined mode
- Multi-host support with automatic failover for AI service endpoints
- Dual data access modes: Direct PostgreSQL database access OR Immich API integration (database mode is planned for removal in 0.5.0 or 0.6.0)
- Concurrent processing with configurable parallelism
- Configurable retry logic with max retries and delay between attempts
- Internationalization support (English and Russian)
- Docker container support
- Prompt enrichment: optionally enrich AI prompts with asset metadata (EXIF, location, camera info, people with ages, tags, resolution, MIME type) - works only in Immich API mode
- Selective description updates: use
--preserve-humanwith any overwrite policy to preserve human-written text outside[AI]...[/AI]blocks; use--overwrite-policy missing-aito process only assets without existing AI blocks - Structured logging via
env_logger(configure withRUST_LOGenvironment variable) - Wait for Immich to become available on startup (API mode only, configurable timeout)
- Immich instance with either:
- PostgreSQL database access (planned for removal in 0.5.0 or 0.6.0), OR
- Immich API endpoint with API key
- AI service running a vision-capable model:
- Ollama server (e.g.,
qwen3-vl:4b-thinking-q4_K_M), OR - llama.cpp server with OpenAI-compatible API endpoint
- Ollama server (e.g.,
To integrate Immich Analyze directly into your Immich setup, add the following service to your docker-compose.yaml file:
services:
# Optional: Ollama service (you can use external Ollama or llama.cpp server instead)
# This section is optional - remove it if you want to use external AI service
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ./ollama:/root/.ollama
networks:
- immich-network
# Optional: GPU acceleration for NVIDIA cards
# deploy:
# resources:
# reservations:
# devices:
# - driver: nvidia
# count: 1
# capabilities: [gpu]
immich-analyze:
image: ghcr.io/timasoft/immich-analyze:main
container_name: immich-analyze
restart: unless-stopped
volumes:
# Only required for database mode (to access /data/upload, /data/thumbs)
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
environment:
# AI service configuration
- IMMICH_ANALYZE_INTERFACE=ollama # or "llamacpp"
- IMMICH_ANALYZE_HOSTS=http://ollama:11434
# For llama.cpp server with authentication:
# - IMMICH_ANALYZE_INTERFACE=llamacpp
# - IMMICH_ANALYZE_HOSTS=http://llamacpp-server:8080
# - IMMICH_ANALYZE_API_KEY=your-api-key-here
# Or use multiple hosts with automatic failover:
# - IMMICH_ANALYZE_HOSTS=http://primary:11434,http://backup:11434
depends_on:
- database
# Comment the next line if using external AI service
- ollama
networks:
- immich-network
networks:
immich-network:
external: trueImportant notes about configuration:
- Data Access Mode: You must provide EITHER:
- Database credentials (
DB_USERNAME,DB_PASSWORD,DB_DATABASE_NAME) for direct PostgreSQL access (planned for removal in 0.5.0 or 0.6.0), OR - API credentials (
IMMICH_API_URL,IMMICH_API_KEY) for Immich API access
- Database credentials (
- Volume mounts: The
/datavolume mount is only required when using database mode (to accessupload/andthumbs/directories). When using API mode, this volume can be omitted. - The
ollamaservice is optional - you can remove it and use an external Ollama or llama.cpp server instead - Set
IMMICH_ANALYZE_INTERFACEtoollama(default) orllamacppdepending on your backend - If using external service, modify
IMMICH_ANALYZE_HOSTSto point to your server(s) - For llama.cpp server, provide
IMMICH_ANALYZE_API_KEYif authentication is enabled - After adding the Ollama service, you need to pull the model manually by executing:
docker exec -it ollama ollama pull qwen3-vl:4b-thinking-q4_K_M - For GPU acceleration with NVIDIA cards, uncomment the deploy section and ensure you have NVIDIA Container Toolkit installed
Make sure to:
- Add the service(s) to your existing
docker-compose.ymlfile - Ensure the
immich-networkexists or create a new network - Add the required environment variables to your
.envfile
After adding the service, run:
docker-compose up -d immich-analyze
# If using internal Ollama service:
# docker-compose up -d ollamaIf you're using Nix or NixOS, you can build and run the application directly:
Database mode (planned for removal in 0.5.0 or 0.6.0):
nix run github:timasoft/immich-analyze -- --data-access-mode database --immich-root /path/to/immich/data --postgres-url "host=localhost user=your_postgres_user dbname=immich password=your_postgres_password" -cAPI mode:
IMMICH_API_URL=http://localhost:2283 IMMICH_API_KEY=your_key nix run github:timasoft/immich-analyze -- --data-access-mode immich-api -c-
Install Rust toolchain:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
Install the project:
cargo install immich-analyze
-
Run the application:
Database mode (planned for removal in 0.5.0 or 0.6.0):
immich-analyze --data-access-mode database --immich-root /path/to/immich/data --postgres-url "host=localhost user=your_postgres_user dbname=immich password=your_postgres_password" -cAPI mode:
IMMICH_API_URL=http://localhost:2283 IMMICH_API_KEY=your_key immich-analyze --data-access-mode immich-api -c
| Variable | Description | Default | Required For |
|---|---|---|---|
DB_USERNAME |
PostgreSQL username | - | Database mode (planned for removal in 0.5.0 or 0.6.0) |
DB_PASSWORD |
PostgreSQL password | - | Database mode (planned for removal in 0.5.0 or 0.6.0) |
DB_DATABASE_NAME |
PostgreSQL database name | - | Database mode (planned for removal in 0.5.0 or 0.6.0) |
DB_HOSTNAME |
PostgreSQL hostname | database |
Database mode (planned for removal in 0.5.0 or 0.6.0) |
DB_PORT |
PostgreSQL port | 5432 |
Database mode (planned for removal in 0.5.0 or 0.6.0) |
IMMICH_API_URL |
Immich API base URL | - | API mode |
IMMICH_API_KEY |
Immich API authentication key(s) (comma-separated for multi-user setups) | - | API mode |
| Variable | Description | Default |
|---|---|---|
IMMICH_ANALYZE_INTERFACE |
AI service interface type (ollama or llamacpp) |
ollama |
IMMICH_ANALYZE_HOSTS |
Comma-separated AI service host URLs | http://localhost:11434 |
IMMICH_ANALYZE_API_KEY |
API key for llama.cpp server authentication | (none) |
IMMICH_ANALYZE_MODEL_NAME |
Model name for image analysis | qwen3-vl:4b-thinking-q4_K_M |
IMMICH_ANALYZE_PROMPT |
Prompt for generating image descriptions | See below |
IMMICH_ANALYZE_ENRICH_PROMPT |
Enable prompt enrichment with asset metadata (API mode only) | false |
IMMICH_ANALYZE_API_POLL_INTERVAL |
Poll interval for API mode in seconds | 10 |
| Variable | Description | Default |
|---|---|---|
IMMICH_ANALYZE_MODE |
Operating mode: monitor, combined, or batch |
combined |
IMMICH_ANALYZE_OVERWRITE_EXISTING |
If true, overwrite existing descriptions (alias for --overwrite-policy all) |
false |
IMMICH_ANALYZE_OVERWRITE_POLICY |
Overwrite policy: none (skip any with description), all (process everything), missing-ai (process only if no [AI]...[/AI] block). Overrides IMMICH_ANALYZE_OVERWRITE_EXISTING |
none |
IMMICH_ANALYZE_PRESERVE_HUMAN |
If true, preserve human text outside [AI]...[/AI] blocks by only replacing the AI block. Incompatible with --disable-ai-wrapper |
false |
IMMICH_ANALYZE_LANG |
Interface language for the application (en, ru) | en |
IMMICH_ANALYZE_MAX_CONCURRENT |
Max concurrent AI requests | 4 |
IMMICH_ANALYZE_UNAVAILABLE_DURATION |
Host availability check interval in seconds | 60 |
IMMICH_ANALYZE_TIMEOUT |
AI request timeout in seconds | 300 |
IMMICH_ANALYZE_DISABLE_AI_WRAPPER |
If true, disable [AI]...[/AI] wrapper, storing description as plain text. Incompatible with --preserve-human. When combined with missing-ai overwrite policy, every asset will be re-analyzed (no [AI] tag to detect) |
false |
IMMICH_ANALYZE_NO_FINAL_OUTPUT |
If true, disable final output with analysis results and statistics after batch processing | false |
IMMICH_ANALYZE_MAX_RETRIES |
Maximum retry attempts (0 = infinite) | 0 |
IMMICH_ANALYZE_RETRY_DELAY_SECONDS |
Delay between retry cycles in seconds | 5 |
IMMICH_ANALYZE_HEALTH_PORT |
Port for health check HTTP server (0 to disable) | 3000 |
IMMICH_ANALYZE_WAIT_FOR_IMMICH |
Wait for Immich to become available on startup (API mode only) | true |
IMMICH_ANALYZE_WAIT_TIMEOUT |
Maximum time in seconds to wait for Immich (0 = no limit) | 120 |
IMMICH_ANALYZE_WAIT_RETRY_INTERVAL |
Interval in seconds between retry attempts when waiting | 5 |
RUST_LOG |
Logging level (error, warn, info, debug, trace) |
info |
Default prompt:
Create a detailed description for the image for proper image search functionality. In the response, provide only the description without introductory words. Also specify the image format (Wallpaper, Screenshot, Drawing, City photo, Selfie, etc.). The format must be correct. If in doubt, name the most likely option and don't think too long.
Backwards Compatibility: The deprecated
IMMICH_ANALYZE_OLLAMA_HOSTSvariable is still supported and will be automatically mapped toIMMICH_ANALYZE_HOSTSwhenIMMICH_ANALYZE_INTERFACE=ollama.
Usage: immich-analyze [OPTIONS]
Options:
-m, --monitor
Enable folder monitoring mode
-c, --combined
Enable combined mode: process existing images then monitor for new ones
-o, --overwrite-existing
Overwrite existing entries in database (process all files regardless of existing descriptions) (same as --overwrite-policy all)
-O, --overwrite-policy <OVERWRITE_POLICY>
Overwrite policy [default: none]: none (skip any with description), all (process everything), missing-ai (process only if no [AI]...[/AI] block). Takes precedence over --overwrite-existing [possible values: none, all, missing-ai]
-p, --preserve-human
When overwriting or adding, preserve human-entered text by only replacing the [AI]...[/AI] block
--immich-root <IMMICH_ROOT>
Path to Immich root directory (containing upload/, thumbs/ folders) [default: /var/lib/immich]
--postgres-url <POSTGRES_URL>
`PostgreSQL` connection string (used only in database mode) [default: "host=localhost user=postgres dbname=immich password=your_password"]
-d, --data-access-mode <DATA_ACCESS_MODE>
Data access mode: database (direct `PostgreSQL`) or api (Immich REST API) [default: database] [possible values: database, immich-api]
--immich-api-url <IMMICH_API_URL>
Immich API base URL (required when using api access mode) [env: IMMICH_API_URL=]
--immich-api-keys <IMMICH_API_KEYS>
Immich API authentication key(s) (required when using api access mode). Provide multiple keys comma-separated for multi-user setups [env: IMMICH_API_KEY]
--api-poll-interval <API_POLL_INTERVAL>
API poll interval in seconds (for Immich API mode) [default: 10]
--model-name <MODEL_NAME>
Ollama model name for image analysis [default: qwen3-vl:4b-thinking-q4_K_M]
--interface <INTERFACE>
AI service interface type [default: ollama] [possible values: ollama, llamacpp]
--hosts <HOSTS>
Host URLs (Ollama or llama.cpp server) [default: http://localhost:11434]
--api-key <API_KEY>
API key for authentication (llama.cpp server) [env: IMMICH_ANALYZE_API_KEY]
--max-concurrent <MAX_CONCURRENT>
Maximum number of concurrent requests [default: 4]
--unavailable-duration <UNAVAILABLE_DURATION>
Host availability check interval in seconds [default: 60]
--timeout <TIMEOUT>
HTTP request timeout in seconds [default: 300]
--file-write-timeout <FILE_WRITE_TIMEOUT>
File write timeout in seconds [default: 30]
--file-check-interval <FILE_CHECK_INTERVAL>
File stability check interval in milliseconds [default: 500]
--event-cooldown <EVENT_COOLDOWN>
Minimum time between processing identical events in seconds [default: 2]
--prompt <PROMPT>
Prompt for generating image description [default: "Create a detailed description for the image for proper image search functionality. In the response, provide only the description without introductory words. Also specify the image format (Wallpaper, Screenshot, Drawing, City photo, Selfie, etc.). The format must be correct. If in doubt, name the most likely option and don't think too long."]
--lang <LANG>
Interface language (ru, en) [default: ""]
--max-retries <MAX_RETRIES>
Maximum number of retry attempts (0 = infinite) [default: 0]
--retry-delay-seconds <RETRY_DELAY_SECONDS>
Delay between retry cycles in seconds (fixed) [default: 5]
--enrich-prompt
Enable prompt enrichment with asset metadata (date, location, camera info)
--disable-ai-wrapper
Disable [AI]...[/AI] wrapper around AI-generated description
--no-final-output
Disable final output with analysis results and statistics after batch processing
--no-wait-for-immich
Disable waiting for Immich to become available on startup (API mode only)
--wait-timeout <WAIT_TIMEOUT>
Maximum time in seconds to wait for Immich to become available (0 = no limit) [default: 120]
--wait-retry-interval <WAIT_RETRY_INTERVAL>
Interval in seconds between retry attempts when waiting for Immich [default: 5]
--health-port <HEALTH_PORT>
Port for health check HTTP server (0 to disable) [default: 3000]
-h, --help
Print help (see more with '--help')
-V, --version
Print versionNote:
IMMICH_API_URLandIMMICH_API_KEYare read from environment variables by clap when using--data-access-mode immich-api- no need to pass them as command-line arguments.IMMICH_API_KEYsupports multiple comma-separated keys for multi-user setups.
Basic Batch Processing with Ollama
immich-analyze \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama-server:11434"Basic Batch Processing with llama.cpp Server
immich-analyze \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface llamacpp \
--hosts "http://llamacpp-server:8080"Batch Processing with Human Text Preservation (Overwrite All)
immich-analyze \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama-server:11434" \
--overwrite-existing \
--preserve-humanSelective Processing: Add AI Blocks to Human-Only Descriptions
immich-analyze \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama-server:11434" \
--overwrite-policy missing-ai \
--preserve-humanMonitor Mode (Watch for new images)
immich-analyze \
--monitor \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama:11434,http://ollama-backup:11434"Monitor Mode with Infinite Retries
immich-analyze \
--monitor \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama:11434" \
--retry-delay-seconds 10Batch Processing with Limited Retries
immich-analyze \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama-server:11434" \
--max-retries 3 \
--retry-delay-seconds 10Basic Batch Processing via Immich API
IMMICH_API_URL=http://immich:2283 \
IMMICH_API_KEY=your_api_key \
immich-analyze \
--data-access-mode immich-api \
--interface ollama \
--hosts "http://ollama-server:11434"Multi-User Batch Processing (Multiple API Keys)
IMMICH_API_URL=http://immich:2283 \
IMMICH_API_KEY=user1_key,user2_key,user3_key \
immich-analyze \
--data-access-mode immich-api \
--interface ollama \
--hosts "http://ollama-server:11434"Combined Mode with API Access and llama.cpp
IMMICH_API_URL=http://immich:2283 \
IMMICH_API_KEY=your_api_key \
IMMICH_ANALYZE_API_KEY=your-llamacpp-api-key \
immich-analyze \
--combined \
--data-access-mode immich-api \
--interface llamacpp \
--hosts "http://llamacpp-primary:8080,http://llamacpp-secondary:8080" \
--api-poll-interval 30Monitor Mode with Infinite Retries
IMMICH_API_URL=http://immich:2283 \
IMMICH_API_KEY=your_api_key \
immich-analyze \
--data-access-mode immich-api \
--interface ollama \
--hosts "http://ollama:11434" \
--monitorBatch Processing with Prompt Enrichment
IMMICH_API_URL=http://immich:2283 \
IMMICH_API_KEY=your_api_key \
immich-analyze \
--data-access-mode immich-api \
--interface ollama \
--hosts "http://ollama-server:11434" \
--enrich-promptBatch Processing with Limited Retries
IMMICH_API_URL=http://immich:2283 \
IMMICH_API_KEY=your_api_key \
immich-analyze \
--data-access-mode immich-api \
--interface llamacpp \
--hosts "http://llamacpp-server:8080" \
--max-retries 5 \
--retry-delay-seconds 15Batch Processing Without Final Results Output
immich-analyze \
--data-access-mode database \
--postgres-url "host=localhost user=postgres dbname=immich password=password" \
--interface ollama \
--hosts "http://ollama-server:11434" \
--no-final-outputRUST_LOG=debug immich-analyze --combined --data-access-mode database --postgres-url "..." --interface ollamaqwen3-vl:4b-thinking-q4_K_M(Default) - Good balance of speed and accuracyqwen3-vl:30b-a3b-thinking-q4_K_M- Higher accuracy for complex imagesqwen3-vl:2b-instruct-q4_K_M- Faster processing for simpler descriptions
- Any GGUF vision model served via llama.cpp's OpenAI-compatible API
- Recommended:
qwen3-vl-4b-instruct-q4_k_m.ggufor similar quantized variants
Install Ollama models using:
ollama pull qwen3-vl:4b-thinking-q4_K_MThe application integrates with your Immich instance by analyzing preview images and storing generated descriptions. It supports multiple operation modes:
- Batch Mode: Process all existing images in your library
- Monitor Mode: Automatically process new images as they're added to Immich
- Combined Mode: Process existing images in background while simultaneously monitoring for new additions
- Direct access to Immich PostgreSQL database for reading/writing metadata
- Direct filesystem access to
thumbs/directory for image analysis - Uses filesystem events for monitoring new images
- Requires
--immich-rootand--postgres-urlconfiguration
- Uses Immich REST API for all data operations
- No direct database or filesystem access required
- Polls Immich API for new assets at configurable interval (
--api-poll-interval) - Requires
IMMICH_API_URLandIMMICH_API_KEYenvironment variables (supports multiple comma-separated keys)
- Automatic retry logic with multiple AI service hosts and automatic failover
- Configurable maximum retry attempts (
--max-retries, 0 = infinite) - Configurable delay between retry cycles (
--retry-delay-seconds) - Smart error classification: only retryable errors (5xx HTTP, timeouts, host unavailable) trigger retries
- Non-retryable errors (invalid UUID, empty response, JSON parsing) fail immediately
- Configurable maximum retry attempts (
- Host unavailability tracking with configurable recovery duration
- File stability checks (database mode) to ensure images are fully written before processing
- Event cooldown (database mode) to prevent duplicate processing of rapid filesystem events
- Prompt enrichment: optionally enrich AI prompts with asset metadata (EXIF metadata, location, camera info, recognized people with ages, tags, resolution, MIME type) via the Immich API for more detailed descriptions
- Selective description preservation: when using
--preserve-human, only the[AI]...[/AI]block in the description is replaced, preserving any human-written text outside this block. If no[AI]...[/AI]block exists, the AI-generated block is appended to the existing description - Overwrite policies: use
--overwrite-policy allto process everything,--overwrite-policy noneto skip existing (default), or--overwrite-policy missing-aito skip only assets with an existing[AI]...[/AI]block (processes human-only and empty descriptions) - Structured logging via
env_loggerfor easier debugging and monitoring
Set the RUST_LOG environment variable to see detailed logs:
RUST_LOG=debug immich-analyze --combined ...- For Ollama:
systemctl status ollamaorcurl http://localhost:11434/api/tags - For llama.cpp:
curl http://localhost:8080/health
- Verify
IMMICH_API_URLis reachable:curl $IMMICH_API_URL/api/server/ping - Verify API key has sufficient permissions in Immich admin panel
- Check Immich server logs for authentication errors
- Add llama.cpp support
- Add support for Immich API
-
Add waiting listAdd retry logic - Rename ignore-existing option/variable to overwrite-existing
- Add support for multiple Immich API keys
- Add JWT support
- Add NixOS service module
- Add video support