Automatically tag your photo library using AI vision models. The script analyzes images and writes descriptive tags directly to photo metadata (EXIF/PNG properties), making your photos searchable in any file explorer or photo management app.
- AI-Powered Tagging: Identifies up to 15 objects, people, animals, scenes, and activities per photo
- Dual AI Provider Support: Choose between Google Gemini or Mistral Pixtral models
- Universal Storage Support: Works with local disks, external drives, NAS (Synology, QNAP, etc.), and network shares
- Cross-Platform: Runs on Windows and Linux without reprocessing photos
- Metadata Integration: Writes tags to EXIF (JPEG) and PNG metadata fields (Description, Title, UserComment)
- Incremental Processing: Smart tracking prevents reprocessing already-tagged photos
- Two Scanning Modes:
- Backlog Mode: Process entire existing photo library
- Incremental Mode: Only scan and process new/modified photos
- Rate Limiting: Respects API limits with configurable batch sizes
- Kill-Safe: Resume from exactly where you left off after interruption
- Detailed Logging: Separate logs for processing status and errors
pip install google-genai mistralai python-dotenv Pillow piexif# AI Provider: "gemini" or "mistral"
AI_PROVIDER=gemini
# Scan Mode: "backlog" (all files) or "incremental" (new files only)
SCAN_MODE=backlog
# API Keys (get from respective providers)
API_KEY=your_google_api_key_here
MISTRAL_API_KEY=your_mistral_api_key_here
# Photos Location (see examples below)
PHOTOS_BASE_PATH=/path/to/your/Photos
# Processing Limits
DAILY_BATCH_LIMIT=500
REQUESTS_PER_MINUTE=15
# Tracking Files (optional, uses defaults if not specified)
COMPLETED_FILES_LOG=completed_files.log
PROCESSING_LIST_FILE=processing_list.json
APPLICATION_LOG=application.log
STATE_FILE=scan_state.jsonLocal Disk (Windows):
PHOTOS_BASE_PATH=C:\Users\YourName\Pictures\PhotosLocal Disk (Linux/Mac):
PHOTOS_BASE_PATH=/home/yourname/Pictures/PhotosExternal Hard Drive (Windows):
PHOTOS_BASE_PATH=E:\PhotosExternal Hard Drive (Linux/Mac):
PHOTOS_BASE_PATH=/mnt/external/Photos
PHOTOS_BASE_PATH=/Volumes/MyDrive/PhotosNetwork Share/NAS (Windows):
PHOTOS_BASE_PATH=\\synology_nas\home\Photos
PHOTOS_BASE_PATH=\\192.168.1.100\photos\PhotosNetwork Share/NAS (Linux - mounted):
PHOTOS_BASE_PATH=/mnt/synology/Photos
PHOTOS_BASE_PATH=/mnt/nas/Photospython PhotoTagger.py- Set
SCAN_MODE=backlogin.env - Run script - it will scan all photos recursively in all nested folders
- Processes up to
DAILY_BATCH_LIMITphotos per run - If failed or killed - run again to process next batch (automatically handles processed photos)
- Repeat until all photos are tagged
- After backlog complete, set
SCAN_MODE=incremental - Script only scans for new/modified photos since last run
- Schedule with cron/Task Scheduler for automatic tagging
- Processing List: Maintains complete list of all discovered photos
- Completed List: Tracks all successfully processed photos
- Delta Calculation:
processing_list - completed_list = files_to_process - Batch Processing: Processes delta up to daily limit
- Metadata Writing: Tags written to photo file properties
- Resume on Restart: Always continues from last position to handle resuming from failures
- β Internal hard drives (HDD/SSD)
- β External USB drives
- β SD cards, portable storage, and just anything.
- β Synology NAS (SMB/CIFS mount)
- β QNAP NAS
- β FreeNAS/TrueNAS
- β Windows Network Shares
- β Any SMB/NFS mounted storage
- β Dropbox, Google Drive, OneDrive (local sync folders)
β οΈ Note: Tags written to local files will sync to cloud
Move your project between Windows, MacBook and Linux without reprocessing:
-
Copy tracking files:
processing_list.jsoncompleted_files.logscan_state.json
-
Update
.envwith new platform path -
Run script - skips already completed photos automatically
Works because paths are normalized starting from "Photos" folder.
processing_list.json: All discovered photos (never removes files)completed_files.log: Successfully tagged photos (never removes files)application.log: Errors and exceptions onlyscan_state.json: Last scan timestamp (incremental mode)
- Fast and efficient
- Good for large batches
- Requires Google AI API key
- Excellent vision capabilities
- Strong object detection
- Requires Mistral API key
dog, beach, sunset, family, ocean, sand, golden retriever, waves, summer, vacation
Tags are written to:
- JPEG: EXIF ImageDescription and UserComment fields
- PNG: Description, Title, and Comment metadata
- HEIC: Not supported (logged as warning)
Windows: Right-click photo β Properties β Details tab
Mac: Get Info β More Info section
Linux: Use exiftool command
Photo Apps: Most display Description/Title in info panels
| Variable | Default | Description |
|---|---|---|
AI_PROVIDER |
gemini |
AI model to use (gemini or mistral) |
SCAN_MODE |
backlog |
Scanning mode (backlog or incremental) |
DAILY_BATCH_LIMIT |
500 |
Max photos to process per run |
REQUESTS_PER_MINUTE |
15 |
API rate limit |
PHOTOS_BASE_PATH |
Required | Root path to your photos |
Network path not found (Windows):
# Test access first
dir \\synology_nas\home\PhotosPermission denied (Linux):
# Check mount permissions
ls -la /mnt/nas/Photos
chmod -R u+rw /mnt/nas/PhotosAPI rate limits:
- Adjust
REQUESTS_PER_MINUTEin.env - Reduce
DAILY_BATCH_LIMITif needed
MIT License - Feel free to use and modify
Issues and pull requests welcome!
Made with β€οΈ for organizing photo libraries