ca1c17446c
The rail's Suggestions now come from the trained per-concept heads. SuggestionService.for_image scores the image's frozen SigLIP embedding against every head (heads.score_image) and surfaces concepts above each head's own suggest threshold; the typed-dropdown's min=0 "show everything" mode maps to a flat floor so any head-scored concept can still be picked. Already-applied tags drop; rejected tags stay flagged + reversible (unchanged). REMOVED from the suggestion path (rule 22, no fallback): the Camie ImagePrediction candidate/alias/merge pipeline and the per-tag centroid augmentation, plus the now-dead SuggestionService internals (_load_predictions, _threshold_for, _settings, self.aliases, self.centroids). Head suggestions are always canonical tags, so raw_name/via_alias are null/false and the rail's alias kebab is inert by data (its removal + the Camie ingest-tagger rip are the flagged follow-up). for_selection (bulk consensus) now aggregates head suggestions unchanged. Tests rewritten to the head path: test_ml_suggestions (surfaces/applied/ rejected-reversible/override/no-embedding/no-heads), test_suggestions_bulk (consensus), test_api_suggestions (get + dropped the Camie-alias roundtrip), and test_ml_artist_retired (artist not head-eligible via _HEAD_KINDS). DEPLOY NOTE: after this lands, the rail is empty until you run Train heads (Settings → Tagging → Concept heads) — deploy, train, then the rail populates. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa
26 lines
834 B
Python
26 lines
834 B
Python
import pytest
|
|
|
|
pytestmark = pytest.mark.integration
|
|
|
|
|
|
def test_artist_not_surfaced():
|
|
from backend.app.services.ml.tagger import SURFACED_CATEGORIES
|
|
assert "artist" not in SURFACED_CATEGORIES
|
|
|
|
|
|
def test_artist_not_centroid_eligible():
|
|
from backend.app.models import TagKind
|
|
from backend.app.services.ml.centroids import ELIGIBLE_KINDS
|
|
assert TagKind.artist not in ELIGIBLE_KINDS
|
|
|
|
|
|
def test_artist_not_head_eligible():
|
|
# Tagging-v2: suggestions come from heads, and heads are only trained for
|
|
# general/character concepts — so 'artist' (and any other kind) can't surface.
|
|
from backend.app.models import TagKind
|
|
from backend.app.services.ml.heads import _HEAD_KINDS
|
|
|
|
assert TagKind.general in _HEAD_KINDS
|
|
assert TagKind.character in _HEAD_KINDS
|
|
assert TagKind.artist not in _HEAD_KINDS
|