efe0a15b8c
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>
26 lines
1.0 KiB
Python
26 lines
1.0 KiB
Python
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy import DateTime, Integer, Text
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from fabledassistant.models import Base
|
|
|
|
|
|
class ImageCache(Base):
|
|
"""Metadata for an image fetched from the web and stored locally on disk."""
|
|
|
|
__tablename__ = "image_cache"
|
|
|
|
id: Mapped[int] = mapped_column(Integer, primary_key=True)
|
|
url_hash: Mapped[str] = mapped_column(Text, unique=True, nullable=False, index=True)
|
|
original_url: Mapped[str] = mapped_column(Text, nullable=False)
|
|
source_domain: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
title: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
content_type: Mapped[str] = mapped_column(Text, nullable=False, default="image/jpeg")
|
|
file_size: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
file_ext: Mapped[str] = mapped_column(Text, nullable=False, default="jpg")
|
|
fetched_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True),
|
|
default=lambda: datetime.now(timezone.utc),
|
|
)
|