Skip to content
ferges123Public

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

📸 DailyFX for Immich

DailyFX logo

Turn your static photo library into a dynamic, AI-powered creative playground.


TLDR: DailyFX is a self-hosted web app for Immich that automatically picks photos, applies creative effects or AI transformations, lets you review the results, and uploads accepted images back to Immich with metadata preserved.


DailyFX is a self-hosted creative companion designed specifically for Immich. It breathes new life into your photo archives by automatically transforming your pictures into stunning artistic masterpieces—from vintage film strips and pop-art collages to next-gen AI-generated transformations. Review them daily, approve your favorites with one click, and seamlessly upload them back to Immich with all original EXIF metadata (camera, GPS, and timestamp) perfectly preserved.

Unlike generic photo filters that strip away metadata or require tedious manual work, DailyFX acts as an automated background curator. It connects directly to your Immich instance, retrieves assets based on your custom schedules, and applies any of its 40+ built-in creative modules. You can choose classic darkroom simulations like Cyanotype and Polaroid, high-dynamic-range enhancements, or leverage state-of-the-art Generative AI models to reimagine your photos in comic book, cyberpunk, or claymation styles.

The entire process is designed with the self-hoster in mind. Running completely on your own hardware via Docker, it ensures your private memories remain entirely under your control unless you explicitly enable external cloud-based AI features. It features a metadata pipeline that supports AI-powered caption and title generation, automatically analyzing the final image so the stored title, summary, and tags match what you actually review. For more information on data sharing, see the Data Privacy & Cloud AI Providers section below.

Once an effect is generated, you are notified through your preferred channel, whether that is an interactive Telegram message, a Home Assistant alert, a Gotify/ntfy notification, or a standard Web Push. With a single tap from the notification, you can compare the original and styled version, then choose to upload it back to Immich or discard it completely. For a concise run-through of the workflow, see docs/how-it-works.md.

⚖️ License: Source-available under the PolyForm Noncommercial License 1.0.0. Free for personal and non-commercial use.


Features & Creative Effects

DailyFX has over 40 built-in creative modules and Generative AI effects to transform your photos.

👉 See the full list of available effects and AI modules in docs/effects.md

Workflow:

  1. Scheduler picks a weighted random effect and fetches photos from your Immich library
  2. Generated image appears in the web UI for review
  3. Accept → uploads to Immich with original EXIF (date, camera, GPS, etc.) and adds to album
  4. Reject → logged in history, not uploaded

CLI handoff:

  • Run scheduled generation on the host using ./dailyfx-agent --schedule-id 1 --target agy.
  • For the full orchestrator CLI reference, including daemon mode, custom templates, vision pipelines, and troubleshooting, see the dailyfx-agent documentation.

Other features:

  • Push notifications (Web Push, ntfy, Gotify, Telegram Bot, Home Assistant, Slack, Discord, Apprise) with image preview
  • Mobile-friendly review page linked from notification
  • Per-effect enable/disable and weight
  • Filter by Immich album, person, date range, media type
  • Schedules: daily, specific days, time of day
  • Optional AI vision analysis (via OpenAI, Gemini, OpenRouter, or Xiaomi) for titles and captions; for ai_* effects, the final generated image is analyzed again so the stored title, summary, and tags match the result you actually review. See docs/api.md for the metadata pipeline, including metadata_provenance, people_context, task_trace, and API Rate Limits. For API-key setup links, see docs/api.md.

Screenshots

Desktop

History desktop

Settings desktop


Requirements

  • Docker and Docker Compose
  • A running Immich instance

Quick start

There are two ways to run DailyFX: using pre-built images from GitHub Container Registry (recommended), or building from source.

Option A: Running Pre-built Images (Recommended)

You do not need to clone the repository to run DailyFX. You can run it directly using Docker Compose:

  1. Create a docker-compose.yml file in an empty directory. You can choose either a minimal version or a production-ready version with healthchecks and limits:

Minimal Version

services:
  api:
    image: ghcr.io/ferges123/dailyfx-api:latest
    restart: unless-stopped
    user: "${UID:-1000}:${GID:-1000}"
    env_file: .env
    volumes:
      - ./data:/data
    ports:
      - "127.0.0.1:8438:8438"

  web:
    image: ghcr.io/ferges123/dailyfx-web:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8439:8080"

Production-Ready Version (with healthchecks & limits)

services:
  api:
    image: ghcr.io/ferges123/dailyfx-api:latest
    restart: unless-stopped
    user: "${UID:-1000}:${GID:-1000}"
    env_file: .env
    volumes:
      - ./data:/data
    ports:
      - "127.0.0.1:8438:8438"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    mem_limit: 2g
    cpus: 2.0
    healthcheck:
      test: ["CMD", "python", "healthcheck.py"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s

  web:
    image: ghcr.io/ferges123/dailyfx-web:latest
    restart: unless-stopped
    ports:
      - "127.0.0.1:8439:8080"
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"
    mem_limit: 512m
    cpus: 1.0
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s
    depends_on:
      api:
        condition: service_healthy
  1. Create a .env file next to your docker-compose.yml and add a secure random key:
APP_SECRET_KEY=    # generate with: openssl rand -hex 32
  1. Start the containers:
docker compose up -d

Option B: Building from Source

If you want to clone the repository and build the images locally:

  1. Clone the repository and copy .env.example:
git clone https://github.com/ferges123/dailyFX.git
cd dailyFX
cp .env.example .env
  1. Edit .env to generate a secure secret key:
APP_SECRET_KEY=    # generate with: openssl rand -hex 32
  1. Build and start:
docker compose up --build -d

Open http://localhost:8439 in your browser. Go to the Settings tab to configure your Immich URL and API Key, plus any optional AI API keys (OpenAI, Gemini, OpenRouter, BytePlus for image generation, or Xiaomi).

If you want the simplest walkthrough, start with docs/getting-started.md. For the short operator flow summary, see docs/how-it-works.md. If you want the full deployment guide, see docs/self-hosting.md.

Local backend tooling

Use the repository Makefile for backend commands so you do not depend on global python or pytest being on your PATH:

make backend-install
make backend-test

backend-test runs python3 -m pytest inside backend/.


Configuration

All connections (Immich, AI keys) and preferences are configured directly via the web UI (Settings and Presets tabs). The .env file is only used for system-level configuration at startup.

.env reference

Variable Required Description
APP_SECRET_KEY yes Random secret used to encrypt stored API keys. Generate with openssl rand -hex 32. Must not be the default placeholder value in production.
APP_ENV no Application environment (production or development, default: development).
APP_HOST no Host binding address (default: 0.0.0.0).
APP_PORT no Backend API port (default: 8438).
DATA_DIR no Directory for SQLite DB, results, and caches (default: ./data).
DATABASE_URL no Database connection string (default: sqlite:///./data/app.db).
APP_ACCESS_TOKEN no If set, all API endpoints require Authorization: Bearer <token>. Recommended for internet-exposed instances.
REQUIRE_AUTH_FOR_REVIEW no If set to true, history review and image endpoints will also require auth (default: false).
APP_EXTERNAL_URL no Public/External URL of your DailyFX instance (required for images and action buttons in notifications).
APP_CONTACT_EMAIL no Email to contact the administrator (default: dailyfx@localhost).
EXAMPLE_ASSET_ID no Any asset ID from your library — enables effect preview images in the Effects tab.
CORS_ORIGINS no Comma-separated allowed origins (default: localhost and frontend ports).
LOG_JSON no If set to true, use structured JSON logging instead of plain text (default: false).
CONCURRENCY_LIMIT no Maximum simultaneous image-generation tasks (default: 1). Raise only after measuring peak memory for the effects and image sizes in use.
IMMICH_THUMBNAIL_CACHE_TTL no TTL for cached Immich asset thumbnails (default: 7d). Supports time units: d (days), h (hours), m (minutes), s (seconds), w (weeks).
IMMICH_THUMBNAIL_CACHE_RETENTION no Retention period for local thumbnail cleanup (default: 30d). Supports time units: d (days), h (hours), m (minutes), s (seconds), w (weeks).

Note

Immich connection details (IMMICH_URL and IMMICH_API_KEY), AI API keys, and notification integrations are managed dynamically in the web UI settings/presets instead of the .env file.

Ports

Port Service
8439 Web UI (nginx)
8438 Backend API

To change ports, edit docker-compose.yml.

API Documentation

The backend ships with interactive API documentation available at:

Path Description
http://localhost:8438/docs Swagger UI — interactive API explorer with live requests
http://localhost:8438/redoc ReDoc — clean, readable API reference
http://localhost:8438/openapi.json OpenAPI 3.1 spec — machine-readable schema

Note

When APP_ACCESS_TOKEN is set, Swagger UI and ReDoc require the token to explore authenticated endpoints. Enter it in the Authorize button on the Swagger page.


Automation

Set up schedules in the Schedules tab:

  • Daily at a specific time
  • Specific days of the week
  • With optional source filters (album, people, date range)

The scheduler runs inside the backend container. If automation is disabled, you can still trigger a selected schedule manually with the Run now button in the Schedules tab. Manual Run now requests are added to History immediately as Queued, then switch to Running when the worker starts processing them. For a practical explanation of what happens after a schedule fires, see docs/how-it-works.md.


Notifications

Notification channels can be configured in the Notifications tab (on desktop) or under Presets -> Notifications (on mobile).

Web Push

Subscribe from the browser on the Settings or Notifications page. Notifications include a preview of the generated image with a direct link to the review page.

ntfy

Set your ntfy server URL, topic name, and optional token. When APP_EXTERNAL_URL is configured, DailyFX also attaches the generated image and a click target back to the review page.

Gotify

Set your Gotify server URL and app token.

Telegram Bot

Get interactive notifications with action buttons (Accept & Upload / Reject) directly on your phone. See the Telegram Setup Guide for details.

Home Assistant

Send notifications to Home Assistant via REST API. Supports push notifications (via mobile app services) and persistent sidebar notifications. See the Home Assistant Setup Guide for details.


Adding a custom effect

  1. Create backend/app/services/generation/modules/myeffect.py:
from app.models.settings import SettingsModel
from app.services.generation.modules.base import GenerationResult

class MyEffectModule:
    name = "my_effect"
    label = "My Effect"
    description = "Does something cool."
    default_weight = 1
    default_config = {}
    config_schema = []

    async def run(self, page_items, config, client, settings: SettingsModel) -> GenerationResult:
        asset = page_items[0]
        image_bytes, _ = await client.get_asset_thumbnail(asset.id, size="preview")
        # ... process image_bytes ...
        return GenerationResult(
            title=f"My Effect: {asset.original_file_name}",
            summary="Applied my custom effect.",
            image_bytes=processed_bytes,
            generation_type=self.name,
            provider="local",
            model="pil",
            config={},
            source_asset_ids=[asset.id],
        )
  1. Register it in backend/app/services/generation/modules/__init__.py:
from app.services.generation.modules.myeffect import MyEffectModule

LOCAL_MODULE_CLASSES = [
    ...,
    MyEffectModule,
]

The effect will appear automatically in the Effects tab — no other changes needed.


Data

All persistent data is stored in ./data/:

Path Contents
data/app.db SQLite database (settings, presets, schedules, history)
data/results/ Generated PNG files (deleted on reject, cleaned up after 7 days)
data/generation-examples/ Cached effect preview images

Scripts

  • scripts/measure_dailyfx_preset.py reproduces the request-timing test against the local API. Example:
    python3 scripts/measure_dailyfx_preset.py --preset TestA --count 50
    It prints a markdown table with request time, asset name, date, and people, plus mean/min/max timing at the end.
  • scripts/render_filters_showcase.py renders a showcase/contact sheet of all active filters and generation modules.

Frontend Documentation

For a screen-by-screen overview of the UI, data flow, and browser state, see docs/frontend.md.

Architecture

For the backend layering, generation pipeline, and history/review flow, see docs/architecture.md.

Self-Hosting Guide

For a complete guide to running DailyFX on your own network, see docs/self-hosting.md.

FAQ

Do I need AI keys to use DailyFX?

No. AI keys are only needed for AI image effects. The rest of the app works with Immich alone.

Where do generated images go?

They are stored in data/results/ until you accept or reject them.

Can I use DailyFX only inside my home network?

Yes. That is the intended use case for self-hosting.

What should I back up?

Back up the data/ directory, especially data/app.db.


Architecture

backend/          FastAPI + SQLAlchemy + Alembic
  app/
    api/          Routes: settings, generation, health, push, debug, presets, schedules, metrics, ai-effects, studio, immich
    immich/       Immich API client
    notifications/ Web Push, ntfy, Gotify, Telegram, Home Assistant
      providers/  Split channel integrations (telegram, home_assistant, slack, discord, etc.)
    services/
      generation/
        engine.py         Compatibility entry points
        pipeline/         Decoupled staged pipeline package (planning, assets, execution, etc.)
        vision/           Modular AI vision provider adapters (gemini, openai, openrouter, etc.)
        config_validation.py API-boundary config schema validator
        persistence.py    Result persistence and history writes
        output.py         Notifications and webhooks
        modules/          Effect plugin system
      settings/           Settings response/connection helpers
      notifications/      Notification preset test helpers
    workers/
      scheduler.py        Automation loop
  healthcheck.py  Dedicated multi-check API & scheduler health status script

frontend/         React 19 + Vite + Tailwind CSS
  src/
    pages/        Modular route views:
      History/, Login.tsx, Presets/, Schedules/, Settings/
    api/          API client (typed)
    components/   RouteErrorBoundary.tsx (graceful route failure recovery)
    version.ts    Single source of truth version metadata

Data Privacy & Cloud AI Providers

DailyFX is designed to keep your private memories secure, running locally on your own hardware via Docker.

Depending on your configuration, certain features require sending images and metadata to external cloud-based AI providers:

  • Local Processing: If you only use built-in classic modules (e.g., Collage, Filmstrip, Polaroid, Cyanotype, Instafilter, Glitch, etc.) and do not configure any cloud API keys, all image processing and curation runs 100% locally on your machine. No data leaves your network.
  • AI Image Generation: If you enable AI-powered image generation effects:
    • OpenAI / Gemini / OpenRouter: The selected source photo and prompts are transmitted to their respective servers to generate the styled image.
    • BytePlus: Your source photo is sent to BytePlus (TikTok/ByteDance) APIs for image styling.
    • Xiaomi: Your source photo is sent to Xiaomi Cloud APIs.
  • AI Vision Analysis (Metadata Generation): If you enable automated captioning, title, or tag generation:
    • OpenAI / Gemini / OpenRouter / Xiaomi: The final styled image is uploaded to their respective APIs so that the vision model can analyze what actually appears in it and generate descriptive metadata.

You are in full control of which providers are enabled. External API keys can be added, updated, or removed at any time in the Settings tab.

License

Source-available for non-commercial use under the PolyForm Noncommercial License 1.0.0.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages