[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-80003":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":14,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":18,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":25,"readmeContent":26,"aiSummary":27,"trendingCount":15,"starSnapshotCount":15,"syncStatus":28,"lastSyncTime":29,"discoverSource":30},80003,"immich-pet-tagger","tedornitier\u002Fimmich-pet-tagger","tedornitier","Automatic pet tagging for Immich using CLIP embeddings and YOLO","",null,"Python",89,6,3,0,13,19,9,2.54,"MIT License",false,"main",true,[],"2026-06-12 02:03:56","# immich-pet-tagger\n\nAutomatic pet tagging for Immich. Identifies your pets in new photos and tags them as people in Immich, the same way Immich tags human faces, but for cats, dogs, or any visually distinct subject.\n\nUses CLIP embeddings and a few reference photos you provide. No cloud services, no training required, runs entirely on your own hardware as a Docker sidecar alongside Immich.\n\n![Pet Tagger UI showing a pet's possible missed photos and a past scan result](screenshot.png)\n\n## How it works\n\n1. You enroll your pets via a web UI: provide a few reference photos and a short description\n2. A logistic regression classifier is trained locally on CLIP embeddings of those references\n3. Every 5 minutes, new photos are classified and matching pets are tagged in Immich\n4. Pets appear in Immich's People section just like humans\n\n## Features\n\n- **Import from Immich**: if Immich already recognizes your pet as a person, import them in one click. The tool picks up to 20 evenly distributed reference photos automatically.\n- **Find similar photos**: uses a two-stage search to surface candidates. Your reference photos are used as visual queries against Immich's smart search, and the local classifier re-ranks the results by pet probability. Falls back to text search using your description when no refs exist yet.\n- **Find candidates for \"not my pets\"**: samples random photos from your library, scores them with the classifier, and surfaces the top 60 most likely to confuse it for bulk review.\n- **Negative samples**: mark photos that look like your pet but aren't, to sharpen the classifier's ability to reject false positives.\n- **Date ranges**: restrict a pet to photos taken within a specific period (useful for pets that have passed away or were adopted later).\n- **Scan controls**: set the scan start date and trigger a scan from the sidebar; the last scan stats are shown live.\n\n## Requirements\n\n- Immich running and reachable over HTTP (tested with v2.7.5)\n- Docker (on the same host or any machine that can reach Immich on the network)\n- An Immich API key with the following permissions:\n\n  | Permission | Reason |\n  |---|---|\n  | `asset.read` | Search results and asset metadata |\n  | `asset.view` | Loading thumbnails |\n  | `person.create` | Creating a new pet as a person in Immich |\n  | `person.read` | Reading existing persons and thumbnails |\n  | `person.update` | Renaming a pet |\n  | `person.delete` | Deleting a pet |\n  | `person.reassign` | Assigning a face to a person |\n  | `face.create` | Writing face entries (the actual tagging) |\n  | `face.read` | Checking existing faces on an asset |\n  | `face.delete` | Removing face entries on ref removal or pet deletion |\n\n## Setup\n\n### 1. Clone the repository\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Ftedornitier\u002Fimmich-pet-tagger\ncd immich-pet-tagger\n```\n\n### 2. Configure docker-compose.yml\n\nEdit the following values:\n\n```yaml\nenvironment:\n  - IMMICH_URL=http:\u002F\u002Fimmich-server:2283     # how this container reaches Immich\n  - IMMICH_API_KEY=your_api_key_here         # generate one in Immich: Account Settings → API Keys\n  - IMMICH_EXTERNAL_URL=http:\u002F\u002Flocalhost:2283 # how your browser reaches Immich (for photo links)\n```\n\n**Same Docker host as Immich:** use the container name as the hostname (e.g. `http:\u002F\u002Fimmich-server:2283`) and keep the shared network section at the bottom of the file. Find your Immich network name with `docker network ls`.\n\n**Immich on a separate machine:** use its IP or hostname instead (e.g. `http:\u002F\u002F192.168.1.100:2283`) and change `external: true` to `external: false` at the bottom of `docker-compose.yml`.\n\n### 4. Start the container\n\nThe default configuration runs on CPU, which works for any machine without extra setup.\n\n```bash\ndocker compose up -d\ndocker compose logs -f   # watch startup logs\n```\n\nIf you want GPU acceleration, see [GPU support](#gpu-support) before running.\n\nOn first start, the YOLO model (~6 MB) and CLIP model (~350 MB) are downloaded and cached. Subsequent starts are fast.\n\n### 5. Open the UI\n\nGo to **http:\u002F\u002Flocalhost:2287** in your browser.\n\nThe UI binds to `127.0.0.1` by default, so it is only reachable from the same machine. There is no authentication. To allow access from other devices on your network, or to use a different port, change the port binding in `docker-compose.yml`:\n\n```yaml\nports:\n  - \"0.0.0.0:2287:8000\"  # accessible from other devices on your network\n```\n\nTo use a different port, change only the first number. The second number (`8000`) is the container's internal port and must stay as-is:\n\n```yaml\nports:\n  - \"127.0.0.1:9000:8000\"  # serves on port 9000 instead\n```\n\nDo not expose this to the internet without putting an authenticated reverse proxy in front of it.\n\n## Updating\n\nTo update to a new version, pull the latest image and restart:\n\n```bash\ndocker compose pull\ndocker compose up -d\n```\n\nThis works for all variants since pre-built images are published for NVIDIA, AMD, and CPU-only.\n\n---\n\n## Getting started\n\nGetting good results takes a few iterations. Start by adding a pet, building up references, and adding some negatives. Run a short test scan, review the results, refine, and repeat until you're satisfied. Then run the full backfill.\n\n### Step 1: Add your pet\n\n**Import from Immich**: use this if Immich already recognizes your pet as a person from its own face detection. This is ideal when the person in Immich contains only photos of that pet, for example if you tagged them manually and are confident the assignments are correct. The tagger does not remove or correct existing Immich face assignments, so any misidentified photos already tagged in Immich will stay tagged. If Immich's recognition was noisy, consider adding your pet manually instead.\n\n1. Click **↓ Import from Immich** in the sidebar\n2. Find and click your pet in the grid\n3. Enter a short description (e.g. `orange tabby cat`) and an optional date range\n4. Click **Import**. Up to 20 reference photos are imported automatically.\n\n**Add manually**: use this if Immich doesn't know your pet yet.\n\n1. Click **+ Add pet**, fill in the name, a short description (e.g. `black labrador dog`), and an optional date range\n2. Click **Create**\n\nThe description is used by Immich's CLIP model to find the first batch of candidate photos. Keep it short: 2–4 descriptive keywords.\n\n### Step 2: Add reference photos\n\nReferences are what the classifier learns from. Quality matters more than quantity.\n\n1. Select your pet in the sidebar and click **Find references**\n2. Browse the results. They are ranked by visual similarity to your existing refs, or to your description if no refs exist yet.\n3. Aim for 20–30 to start; results improve up to around 50. For each photo:\n   - **Add to pet**: clear, close-up shot, your pet is the only subject.\n   - **Ignore**: blurry, distant, another person or animal visible alongside your pet, or a look-alike that is not yours. Ignored photos won't appear again.\n   - **Not a pet**: photos that could confuse the classifier. Empty rooms, other species, ambiguous shots. Around 50 is enough.\n\n### Step 3: Add \"not a pet\" samples\n\nThese teach the classifier what not to tag: empty rooms, other animals of a different species, ambiguous shots with no clear subject. Without them, the classifier will tag almost anything.\n\n1. In the **Not a pet** panel (bottom right of the screen), click **Find candidates** to automatically surface more photos that might confuse the classifier\n2. Select the relevant ones and click **Not a pet**\n\n\n### Step 4: Run a test scan\n\nStart with a recent date so the scan covers fewer photos, making it quicker to review and refine before committing to a full backfill.\n\n1. In the **Scan from** panel at the bottom of the sidebar, set a date 1–2 weeks back\n2. Click **Scan** and wait for the results\n3. If **Review N low confidence** appears in the results, click it to see photos the classifier identified as a match but wasn't fully confident about.\n4. Go through them: add correctly identified ones as references, and click **Ignore** on the rest. Ignored photos won't appear in future results.\n\n### Step 5: Iterate\n\nRepeat steps 2–4 a couple of times. Each round of added references and negatives improves accuracy. Results typically stabilize after 2–3 iterations.\n\n### Step 6: Run the full backfill\n\nOnce you're happy with the accuracy on the test window:\n\n1. Set the scan date to the earliest date you want to tag. A good starting point is the date you got your pet.\n2. Click **Scan** to process all photos in that range\n\nAfter that, the background poller runs every 5 minutes and tags new photos automatically. Your pets appear in Immich's **People** section.\n\n---\n\n## Environment variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `IMMICH_URL` | `http:\u002F\u002Fimmich-server:2283` | Immich URL for container-to-container communication |\n| `IMMICH_EXTERNAL_URL` | `http:\u002F\u002Flocalhost:2283` | Immich URL as seen from your browser, used for links |\n| `IMMICH_API_KEY` | required | Immich API key |\n| `POLL_INTERVAL` | `300` | Seconds between scans |\n| `SCAN_WORKERS` | `GPU_WORKERS × 32` | Concurrent thumbnail fetches. Auto-derived to keep GPU batches full. Override only if Immich feels slow during scans. |\n| `GPU_WORKERS` | `2` (GPU) \u002F `1` (CPU) | Parallel YOLO and CLIP inference threads. `2` is optimal for GPU; CPU defaults to `1` since a second worker just duplicates the models in RAM with no throughput gain. |\n| `YOLO_INPUT_SIZE` | `640` | YOLO detection resolution in pixels. Higher values improve detection of small animals at the cost of more memory and compute. Must be a multiple of 32. |\n| `YOLO_BATCH_SIZE` | `32` | Max images per YOLO inference batch. Reduce if you hit GPU out-of-memory errors. |\n| `EMBED_CACHE_SIZE` | `5000` | Max number of embeddings kept in the in-memory LRU cache. Older entries are evicted when the limit is reached. |\n| `THRESHOLD` | `0.8` | Min confidence (0–1) to tag a photo |\n\n---\n\n## GPU support\n\nThe default setup runs on CPU and requires no extra configuration. A GPU makes scans significantly faster but requires additional setup. Pre-built images are published for CPU, NVIDIA (default and legacy), and AMD\u002FROCm.\n\n**CPU (default):** no changes needed.\n\n**NVIDIA GPU:** install the [NVIDIA Container Toolkit](https:\u002F\u002Fdocs.nvidia.com\u002Fdatacenter\u002Fcloud-native\u002Fcontainer-toolkit\u002Flatest\u002Finstall-guide.html) on your host, then in `docker-compose.yml`:\n1. Change the image tag to `:latest` (default) or `:cuda-legacy` (Maxwell\u002FPascal\u002FVolta — see below)\n2. Uncomment the `deploy:` section\n3. Set `GPU_WORKERS=2`\n\n```yaml\nimage: ghcr.io\u002Ftedornitier\u002Fimmich-pet-tagger:latest\n```\n\nThe `:latest` image ships PyTorch's CUDA 12.8 wheels and supports Turing, Ampere, Ada Lovelace, Hopper, and Blackwell GPUs (compute capability 7.5–12.0, e.g. RTX 20xx\u002F30xx\u002F40xx\u002F50xx, Tesla T4\u002FA100\u002FH100). Pascal and older are not covered — see the legacy tag.\n\n**NVIDIA legacy GPU (`:cuda-legacy`):** for Maxwell, Pascal, and Volta cards (GTX 9xx\u002F10xx, Tesla P100\u002FV100, compute capability 5.0–7.0). Same setup as above but use the `:cuda-legacy` tag instead:\n\n```yaml\nimage: ghcr.io\u002Ftedornitier\u002Fimmich-pet-tagger:cuda-legacy\n```\n\nThis variant uses PyTorch's CUDA 12.6 wheels, which still include kernels for `sm_50` through `sm_90` but drop Blackwell (`sm_100`\u002F`sm_120`). If you see `CUDA error: no kernel image is available for execution on the device` with `:latest` on an NVIDIA card, switch to this tag.\n\n**AMD GPU:** install ROCm drivers, then in `docker-compose.yml`:\n1. Change the image tag to `:rocm`\n2. Uncomment the `deploy:` section and change the driver to `amdgpu`\n\n```yaml\nimage: ghcr.io\u002Ftedornitier\u002Fimmich-pet-tagger:rocm\n```\n```yaml\ndriver: amdgpu\n```\n\nCPU-only works fine for most home libraries. Expect roughly 10x slower processing compared to GPU.\n\n## Limitations\n\n- **YOLO fallback**: when no animals are detected by YOLO, the full image is classified as a whole and only one pet can be tagged per photo\n- **Polling only**: photos are processed within 5 minutes of upload, not instantly\n\n## Troubleshooting\n\n**Pet not appearing in Immich after enrollment**\nImmich only shows people with at least one face assigned. Add at least one reference photo and wait for a poll cycle.\n\n**Low accuracy \u002F wrong pet tagged**\nAdd more reference photos, add more negative samples, or lower the threshold in `docker-compose.yml`.\n\n**Container can't reach Immich**\nMake sure the network name in `docker-compose.yml` matches the output of `docker network ls`.\n\n**Thumbnail proxy returns 401**\nYour API key is missing `asset.view` permission.\n","immich-pet-tagger 是一个用于 Immich 的自动宠物标记工具，能够识别并标记照片中的宠物。它利用CLIP嵌入和YOLO技术，通过用户提供的少量参考照片训练本地分类器，每5分钟自动对新上传的照片进行分类，并将匹配的宠物作为人物标签添加到Immich中。此项目完全基于本地运行，无需云端服务或额外训练，保证了数据隐私安全。适用于家庭或个人使用场景下，希望在照片库中方便地管理和查找包含特定宠物图片的情况。此外，还支持从已有Immich人物导入、寻找相似照片等功能，提高了用户体验。",2,"2026-06-11 03:58:53","CREATED_QUERY"]