Files
bvandeusen efe0a15b8c Add image search with local cache (Phase 23)
Images found via SearXNG are fetched server-side, stored on disk, and
served from /api/images/<id> — the user's browser never contacts the
original image host.  Original URLs are preserved for citation.

New files:
- alembic/versions/0016_add_image_cache.py  — image_cache table
- src/fabledassistant/models/image_cache.py — SQLAlchemy model
- src/fabledassistant/services/images.py    — fetch/store/serve logic
- src/fabledassistant/routes/images.py      — GET /api/images/<id>

Modified:
- config.py: IMAGE_CACHE_DIR (/data/images), IMAGE_MAX_BYTES (5 MB)
- research.py: _search_searxng_images() — SearXNG categories=images
- tools.py: _IMAGE_TOOLS def + search_images branch in execute_tool
- intent.py: search_images routing rule (explicit visual language only)
- app.py: register images_bp
- docker-compose.yml: image_cache named volume mounted at /data/images
- ToolCallCard.vue: "image_search" label

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 12:55:10 -05:00

31 lines
905 B
Python

"""Add image_cache table for locally-stored images fetched from the web."""
from alembic import op
revision = "0016"
down_revision = "0015"
def upgrade() -> None:
op.execute("""
CREATE TABLE IF NOT EXISTS image_cache (
id SERIAL PRIMARY KEY,
url_hash TEXT UNIQUE NOT NULL,
original_url TEXT NOT NULL,
source_domain TEXT,
title TEXT,
content_type TEXT NOT NULL DEFAULT 'image/jpeg',
file_size INTEGER,
file_ext TEXT NOT NULL DEFAULT 'jpg',
fetched_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
)
""")
op.execute(
"CREATE INDEX IF NOT EXISTS ix_image_cache_url_hash ON image_cache(url_hash)"
)
def downgrade() -> None:
op.execute("DROP INDEX IF EXISTS ix_image_cache_url_hash")
op.execute("DROP TABLE IF EXISTS image_cache")