image search test

This commit is contained in:
2026-09-16 11:52:35 +05:30
parent 42ea007fe7
commit 28af3e05f2
5 changed files with 181 additions and 6 deletions

View File

@@ -501,3 +501,55 @@ func TestConfirmReportsDistanceToTheChosenStore(t *testing.T) {
t.Fatalf("no position at all is -1; got %v", resp.Store)
}
}
var parleG = repositories.CatalogueHit{Brand: "parle", ID: 1, ProductName: "Parle-G Original Glucose Biscuits 250g", Title: "Parle-G", VariantKey: "parle_g", ImageID: "parle_parle_g_250g", Distance: 0.20}
var monaco = repositories.CatalogueHit{Brand: "parle", ID: 2, ProductName: "Parle Monaco Classic Regular 200g", Title: "Monaco", VariantKey: "monaco", ImageID: "parle_monaco_200g", Distance: 0.20}
// Lens reads "Parle-G" off the packet and the customer types "Parle G". Both
// spellings, and the run-together one, have to reach the biscuit — not the
// salted cracker that merely shares a brand. In production "Parle G" returned
// "Parle Monaco Classic Regular 200g" at a confident 0.9.
func TestLookupMatchesAHyphenatedNameHoweverItIsWritten(t *testing.T) {
for _, label := range []string{"Parle G", "Parle-G", "ParleG", "parle g"} {
repo := newLookupFixture()
repo.vector = []repositories.CatalogueHit{monaco, parleG} // model puts the cracker first
repo.text = []repositories.CatalogueHit{monaco, parleG}
svc := NewScanService(repo, fakeEmbedder{vec: []float32{0.1}})
resp, err := svc.Lookup(context.Background(), models.ScanLookupRequest{Customerid: 5, Label: label})
if err != nil {
t.Fatal(err)
}
if resp.Match == nil {
t.Fatalf("%q: a stocked product went unrecognised", label)
}
if resp.Match.Catalogueid != parleG.ID {
t.Fatalf("%q: matched %q (%.3f), want Parle-G", label, resp.Match.ProductName, resp.Match.Score)
}
}
}
// Equal blended scores used to be settled by product name, which let ASCII
// decide relevance: a space sorts before a hyphen, so "Parle Monaco …" beat
// "Parle-G …". The model's own similarity settles it instead.
func TestSortHitsBreaksTiesOnSimilarityNotPunctuation(t *testing.T) {
near := parleG
near.Distance = 0.10 // the model is surer about this one
far := monaco
far.Distance = 0.40
hits := []scoredHit{{CatalogueHit: far, score: 0.9}, {CatalogueHit: near, score: 0.9}}
sortHits(hits)
if hits[0].ID != near.ID {
t.Fatalf("the nearer vector should win a tie, got %q", hits[0].ProductName)
}
// A row the model never scored (-1, text-only) ranks behind one it did.
textOnly := parleG
textOnly.Distance = -1
hits = []scoredHit{{CatalogueHit: textOnly, score: 0.9}, {CatalogueHit: far, score: 0.9}}
sortHits(hits)
if hits[0].ID != far.ID {
t.Fatalf("a scored row outranks an unscored one, got %q", hits[0].ProductName)
}
}