feat(explore): exclude WIP-tagged work from the Explore rabbit-hole

Explore's neighbour grid (/api/gallery/similar → gallery_service.similar) now
takes an Explore-only exclude_wip flag that drops `wip` system-tagged images
from the candidates, alongside the banner/editor presentation tags. The
gallery's own "similar" button is unchanged (keeps wip, #1274) — only the
Explore store passes exclude_wip=1. The anchor itself may still be a WIP; only
neighbours are filtered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 22:10:05 -04:00
parent d631ed023c
commit f8105046dc
5 changed files with 45 additions and 6 deletions
+9 -4
View File
@@ -31,7 +31,7 @@ from ..models import (
Tag,
TagPositiveConfirmation,
)
from ..models.tag import PRESENTATION_SYSTEM_TAGS, image_tag
from ..models.tag import PRESENTATION_SYSTEM_TAGS, WIP_SYSTEM_TAG, image_tag
from .pagination import decode_cursor, encode_cursor
from .tag_query import (
fandom_join_alias,
@@ -715,6 +715,7 @@ class GalleryService:
platform: str | None = None,
untagged: bool = False, no_artist: bool = False,
date_from: datetime | None = None, date_to: datetime | None = None,
exclude_wip: bool = False,
) -> list[GalleryImage] | None:
"""Visual "more like this": images near `image_id`'s SigLIP embedding
(pgvector, HNSW-indexed — alembic 0036), then DIVERSIFIED so the result
@@ -751,14 +752,18 @@ class GalleryService:
# Presentation images (banner / editor-screenshot system tags, #128)
# cluster on UI chrome rather than content, so near any one of them
# they'd fill the grid. Excluded from CANDIDATES only — the anchor
# itself may be a banner, and `wip` stays surfaced (real art; only
# the training pipelines exclude it).
# itself may be a banner. `wip` stays surfaced here by default (real art;
# only the training pipelines exclude it), but the Explore rabbit-hole
# passes exclude_wip to also drop work-in-progress (operator, 2026-07-08).
excluded_system_tags = PRESENTATION_SYSTEM_TAGS
if exclude_wip:
excluded_system_tags = (*PRESENTATION_SYSTEM_TAGS, WIP_SYSTEM_TAG)
presentation = (
select(image_tag.c.image_record_id)
.join(Tag, Tag.id == image_tag.c.tag_id)
.where(
Tag.is_system.is_(True),
Tag.name.in_(PRESENTATION_SYSTEM_TAGS),
Tag.name.in_(excluded_system_tags),
)
)
stmt = stmt.where(