feat(tag-eval): inline confirm/reject actions on example thumbnails
Closes the learn-from-tags loop directly on the eval lists (operator-flagged: no surface to confirm/refine the head's suggestions). Each thumbnail gets a green ✓ / red ✗ that writes the SAME tables the head trains on: - suggest + ✓ → apply tag (new positive, POST /images/<id>/tags) - suggest + ✗ → record rejection (hard negative, suggestions/dismiss) - doubt + ✗ → remove tag + record rejection (kill bad positive, add negative) - doubt + ✓ → keep (stays a positive, no write) Acted thumbs grey out with a badge; re-run to see the head sharpen. Thumb still links to /explore/<id>. All endpoints already existed — no backend change. Inline is the starting point; longer-term the modal Suggestions rail gets the red "No" (negative) so per-image rejection is native there too (next slice). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,5 +23,29 @@ export const useTagEvalStore = defineStore('tagEval', () => {
|
||||
return (body.runs && body.runs[0]) || null
|
||||
}
|
||||
|
||||
return { start, getRun, latest }
|
||||
// --- Acting on the head's example lists (closes the learn-from-tags loop).
|
||||
// These write the SAME tables the head trains on: image_tag (positives) and
|
||||
// tag_suggestion_rejection (negatives, via the dismiss endpoint).
|
||||
|
||||
// "Yes, it is this" — apply the tag (new positive).
|
||||
async function applyTag(imageId, tagId) {
|
||||
return await api.post(`/api/images/${imageId}/tags`,
|
||||
{ body: { tag_id: tagId, source: 'manual' } })
|
||||
}
|
||||
|
||||
// "No, it's not" on an UNtagged suggestion — record a rejection (hard negative).
|
||||
async function rejectTag(imageId, tagId) {
|
||||
return await api.post(`/api/images/${imageId}/suggestions/dismiss`,
|
||||
{ body: { tag_id: tagId } })
|
||||
}
|
||||
|
||||
// "Not it" on one of YOUR positives the head doubts — remove the tag AND
|
||||
// record the rejection (kills the bad positive, leaves a hard negative).
|
||||
async function removeTag(imageId, tagId) {
|
||||
await api.delete(`/api/images/${imageId}/tags/${tagId}`)
|
||||
return await api.post(`/api/images/${imageId}/suggestions/dismiss`,
|
||||
{ body: { tag_id: tagId } })
|
||||
}
|
||||
|
||||
return { start, getRun, latest, applyTag, rejectTag, removeTag }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user