Some checks failed
Validate / Hassfest (push) Has been cancelled
Integrate Claude AI into the notification system for intelligent conversational interactions and AI-powered captions. New modules: - ai/service.py: Claude API client with conversation history, caption generation, and album activity summarization - ai/telegram_webhook.py: Telegram webhook handler for incoming bot messages, routes to AI service for responses Features: - Conversational bot: users chat with the bot about albums - AI captions: intelligent notification messages based on album context (people, locations, dates) - enabled per target via "ai_captions" config flag - Album summaries: "what's new?" triggers AI-generated overview - /start command with welcome message - Webhook register/unregister endpoints Architecture: - Per-chat conversation history (in-memory, capped at 20 messages) - Graceful degradation: AI features completely disabled without IMMICH_WATCHER_ANTHROPIC_API_KEY env var (zero impact) - AI caption failure falls back to Jinja2 template rendering - Health endpoint reports ai_enabled status Config: IMMICH_WATCHER_ANTHROPIC_API_KEY, IMMICH_WATCHER_AI_MODEL, IMMICH_WATCHER_AI_MAX_TOKENS Server now has 45 API routes (was 42 after Phase 5). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
2.7 KiB
Python
100 lines
2.7 KiB
Python
"""FastAPI application entry point."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from contextlib import asynccontextmanager
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from .config import settings
|
|
from .database.engine import init_db
|
|
from .services.scheduler import start_scheduler, stop_scheduler
|
|
|
|
from .auth.routes import router as auth_router
|
|
from .api.servers import router as servers_router
|
|
from .api.trackers import router as trackers_router
|
|
from .api.templates import router as templates_router
|
|
from .api.targets import router as targets_router
|
|
from .api.users import router as users_router
|
|
from .api.status import router as status_router
|
|
from .api.sync import router as sync_router
|
|
from .ai.telegram_webhook import router as telegram_ai_router
|
|
|
|
logging.basicConfig(
|
|
level=logging.DEBUG if settings.debug else logging.INFO,
|
|
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
|
|
)
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Application lifespan: startup and shutdown."""
|
|
# Startup
|
|
settings.data_dir.mkdir(parents=True, exist_ok=True)
|
|
await init_db()
|
|
_LOGGER.info("Database initialized at %s", settings.effective_database_url)
|
|
|
|
await start_scheduler()
|
|
|
|
yield
|
|
|
|
# Shutdown
|
|
await stop_scheduler()
|
|
|
|
|
|
app = FastAPI(
|
|
title="Immich Watcher",
|
|
description="Standalone Immich album change notification server",
|
|
version="0.1.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
# CORS for frontend dev server
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# API routes
|
|
app.include_router(auth_router)
|
|
app.include_router(servers_router)
|
|
app.include_router(trackers_router)
|
|
app.include_router(templates_router)
|
|
app.include_router(targets_router)
|
|
app.include_router(users_router)
|
|
app.include_router(status_router)
|
|
app.include_router(sync_router)
|
|
app.include_router(telegram_ai_router)
|
|
|
|
# Serve frontend static files if available
|
|
_frontend_dist = Path(__file__).parent / "frontend"
|
|
if _frontend_dist.is_dir():
|
|
app.mount("/", StaticFiles(directory=_frontend_dist, html=True), name="frontend")
|
|
|
|
|
|
@app.get("/api/health")
|
|
async def health():
|
|
"""Health check endpoint."""
|
|
from .ai.service import is_ai_enabled
|
|
return {"status": "ok", "version": "0.1.0", "ai_enabled": is_ai_enabled()}
|
|
|
|
|
|
def run():
|
|
"""Run the server (entry point for `immich-watcher` CLI command)."""
|
|
import uvicorn
|
|
|
|
uvicorn.run(
|
|
"immich_watcher_server.main:app",
|
|
host=settings.host,
|
|
port=settings.port,
|
|
reload=settings.debug,
|
|
)
|