fix(explore): diversify "more like this" so it stops getting stuck (#1188)
Pure nearest-cosine piled near-identical images into the neighbour grid — a reposted banner filled all 24 slots, and once you wandered into a B&W / comic-panel cluster every neighbour was more of the same with no way back to colour without the Random button (operator-reported, with screenshot). similar() now over-fetches a wide candidate pool (5x the requested limit, cap 200), then diversifies down to `limit`: - pHash near-duplicate collapse: drop candidates within 6 Hamming bits of the anchor or an already-kept candidate, so a repost (and the anchor's own clones) appears at most once. - MMR re-rank: greedily pick for closeness-to-anchor minus similarity-to-already -picked (lambda 0.55), so the result SPANS clusters instead of returning 40 variations of one image. Falls back to nearest-order on any failure / small pool, so existing nearest-first behaviour is unchanged when there's nothing to diversify. Frontend forwardTarget drops the now-redundant skip-nearest-third hack (the list is already diversified server-side) — plain random-over-unvisited gives the variance now. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa
This commit is contained in:
@@ -93,13 +93,11 @@ export const useExploreStore = defineStore('explore', () => {
|
||||
// a crumb (which snaps the cursor back into the trail — the "loops back"
|
||||
// report). Fall back to the full set only if every neighbour's been seen.
|
||||
const seen = new Set(breadcrumb.value.map((c) => c.id))
|
||||
let pool = neighbors.value.filter((n) => !seen.has(n.id))
|
||||
if (!pool.length) pool = neighbors.value
|
||||
// neighbors come similarity-sorted (nearest first). Skip the closest slice —
|
||||
// those near-duplicates are exactly what you get stuck cycling through — and
|
||||
// pick from the more-varied remainder, for real variance in the walk.
|
||||
const skip = pool.length >= 6 ? Math.floor(pool.length / 3) : 0
|
||||
const cands = pool.slice(skip)
|
||||
const pool = neighbors.value.filter((n) => !seen.has(n.id))
|
||||
const cands = pool.length ? pool : neighbors.value
|
||||
// The list is already pHash-deduped + MMR-diversified server-side (it spans
|
||||
// clusters, not 40 near-dupes), so a plain random pick gives real variance —
|
||||
// no need to skip the nearest slice the way the raw nearest-list required.
|
||||
return cands[Math.floor(Math.random() * cands.length)].id
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user