feat(gallery): similar() hides presentation images (banner / editor screenshot)
Step 3 of milestone #128. Presentation-tagged images cluster on UI chrome rather than content, so near any one of them they fill the whole more-like-this grid. Excluded from candidates in the ONE whole-image similarity surface (gallery similar mode, explore walk, and RelatedStrip all ride GalleryService.similar) — the anchor itself may be a banner, and wip stays surfaced: only the training pipelines exclude it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
This commit is contained in:
@@ -4,6 +4,7 @@ precomputed SigLIP image embeddings. No query-time ML inference."""
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import select
|
||||
|
||||
from backend.app.models import ImageRecord, Tag, TagKind
|
||||
from backend.app.models.tag import image_tag
|
||||
@@ -72,6 +73,31 @@ async def test_similar_missing_source_returns_none(db):
|
||||
assert await svc.similar(99999, limit=10) is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_similar_excludes_presentation_tagged_images(db):
|
||||
"""banner / editor-screenshot system tags (#128) hide from similar
|
||||
RESULTS — they cluster on UI chrome, not content. A banner anchor still
|
||||
gets results; `wip`-tagged images stay in (real art)."""
|
||||
src = await _img(db, 1, _vec(1, 0))
|
||||
bannered = await _img(db, 2, _vec(1, 0.02)) # nearest, but a banner
|
||||
wipped = await _img(db, 3, _vec(1, 0.3))
|
||||
plain = await _img(db, 4, _vec(1, 0.6))
|
||||
banner_tag = (await db.execute(select(Tag).where(
|
||||
Tag.is_system.is_(True), Tag.name == "banner"))).scalar_one()
|
||||
wip_tag = (await db.execute(select(Tag).where(
|
||||
Tag.is_system.is_(True), Tag.name == "wip"))).scalar_one()
|
||||
await db.execute(image_tag.insert().values(
|
||||
image_record_id=bannered.id, tag_id=banner_tag.id, source="manual"))
|
||||
await db.execute(image_tag.insert().values(
|
||||
image_record_id=wipped.id, tag_id=wip_tag.id, source="manual"))
|
||||
svc = GalleryService(db)
|
||||
res = await svc.similar(src.id, limit=10)
|
||||
assert [i.id for i in res] == [wipped.id, plain.id]
|
||||
# A presentation-tagged ANCHOR still answers — only candidates hide.
|
||||
res_from_banner = await svc.similar(bannered.id, limit=10)
|
||||
assert {i.id for i in res_from_banner} == {src.id, wipped.id, plain.id}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_similar_composes_with_tag_filter(db):
|
||||
src = await _img(db, 1, _vec(1, 0))
|
||||
|
||||
Reference in New Issue
Block a user