From 4b84076540f5bec6655d7ffe0e4b2b41b156145c Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 23 Apr 2026 20:11:21 -0400 Subject: [PATCH] =?UTF-8?q?fix(suggestions):=20pill=20=C3=97=20removal=20a?= =?UTF-8?q?lso=20suppresses=20re-auto-accept?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix only covered the suggestion-chip ✕ flow (which calls /suggestions/reject). Removing a tag via the pill × in the Tags section goes through /tags/remove and wrote no feedback row, so the per-image rejection filter in get_suggestions had nothing to match on — auto-accept would re-apply the tag on the next modal load. /tags/remove now writes SuggestionFeedback(decision='rejected', suggestion_source='manual_removal', confidence=0) alongside the image_tags delete. The suggestion_source value distinguishes these rows from chip-reject rejections in the feedback log without complicating the get_suggestions filter (it matches on decision alone). Co-Authored-By: Claude Opus 4.7 --- app/main.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/app/main.py b/app/main.py index 7a37511..9d21c17 100644 --- a/app/main.py +++ b/app/main.py @@ -1211,14 +1211,28 @@ def add_tag(image_id): @main.post("/image//tags/remove") def remove_tag(image_id): + """Remove a tag from an image. + + Also logs a SuggestionFeedback rejection so the auto-suggest + auto-accept + systems treat this as 'the user said no to this tag for this image'. + Without the rejection row, a removed tag whose WD14 prediction still sits + at/above the auto-accept threshold would re-apply itself on the next + modal load. """ - Minimal JSON endpoint to remove a tag from an image. - """ + from app.models import SuggestionFeedback + name = (request.form.get("name") or "").strip() img = ImageRecord.query.get_or_404(image_id) tag = Tag.query.filter_by(name=name).first() if tag and tag in img.tags: img.tags.remove(tag) + db.session.add(SuggestionFeedback( + image_id=image_id, + tag_name=name, + suggestion_source='manual_removal', + confidence=0.0, + decision='rejected', + )) db.session.commit() return jsonify(ok=True)