Добавил выбор из кандидатов, если LLM не уверена в раскладке

This commit is contained in:
2026-06-14 16:43:50 +03:00
parent 4af3ad2dde
commit 7f7f5f69d4
16 changed files with 831 additions and 88 deletions
+52 -8
View File
@@ -44,7 +44,7 @@ func TestMatchMetadata_SingleStrong(t *testing.T) {
{Provider: "tmdb", ID: "604", Title: "The Matrix Reloaded", Year: 2003},
}}
r := recognizerWith(p)
m := r.matchMetadata(context.Background(),
m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaMovie, Title: "The Matrix", Year: 1999})
if m == nil {
t.Fatal("expected match")
@@ -61,16 +61,60 @@ func TestMatchMetadata_AmbiguousNoMatch(t *testing.T) {
{ID: "2", Title: "Fargo", Year: 2014},
}}
r := recognizerWith(p)
if m := r.matchMetadata(context.Background(),
if m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaSeries, Title: "Fargo", Year: 2014}); m != nil {
t.Errorf("ambiguous must not match, got %+v", m)
}
}
func TestMatchMetadata_ReturnsCandidates(t *testing.T) {
// Нет сильного матча (разные названия), но кандидаты собраны для выбора.
p := &fakeProvider{name: "tvmaze", candidates: []metadata.Candidate{
{Provider: "tvmaze", ID: "1", Title: "Fargo", Year: 2014, TagProvider: "tvdb", TagID: "269613"},
{Provider: "tvmaze", ID: "2", Title: "Fargo Idaho", Year: 2010},
{Provider: "tvmaze", ID: "1", Title: "Fargo", Year: 2014}, // дубль по id
}}
r := recognizerWith(p)
m, cands := r.matchMetadata(context.Background(),
Plan{Type: MediaSeries, Title: "Совсем другое", Year: 2014})
if m != nil {
t.Errorf("strong match не ожидался: %+v", m)
}
if len(cands) != 2 { // дубль отброшен
t.Fatalf("candidates = %d, want 2: %+v", len(cands), cands)
}
// CandidateTag даёт внешний TVDB-id для первого.
prov, id := CandidateTag(cands[0])
if prov != "tvdb" || id != "269613" {
t.Errorf("tag = %s/%s", prov, id)
}
}
func TestRecognize_PopulatesCandidates(t *testing.T) {
in := Input{Name: "Show.S01", Files: []File{{Path: "e1.mkv", Size: 1}}}
resp := `{"type":"series","title":"Show","year":2020,"confidence":0.9,
"files":[{"src":"e1.mkv","role":"episode","season":1,"episode":1}]}`
p := &fakeProvider{name: "tvmaze", candidates: []metadata.Candidate{
{Provider: "tvmaze", ID: "1", Title: "Show One", Year: 2020},
{Provider: "tvmaze", ID: "2", Title: "Show Two", Year: 2019},
}}
r := New(&fakeLLM{responses: []string{resp}}, []metadata.Provider{p}, Config{}, testLogger())
res, err := r.Recognize(context.Background(), in)
if err != nil {
t.Fatalf("Recognize: %v", err)
}
if res.Match != nil {
t.Errorf("strong match не ожидался")
}
if len(res.Candidates) != 2 {
t.Errorf("Result.Candidates = %d, want 2", len(res.Candidates))
}
}
func TestMatchMetadata_YearMismatch(t *testing.T) {
p := &fakeProvider{candidates: []metadata.Candidate{{ID: "1", Title: "X", Year: 1990}}}
r := recognizerWith(p)
if m := r.matchMetadata(context.Background(),
if m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaMovie, Title: "X", Year: 2020}); m != nil {
t.Errorf("year mismatch must not match, got %+v", m)
}
@@ -81,7 +125,7 @@ func TestMatchMetadata_OriginalTitle(t *testing.T) {
{ID: "1", Title: "Leon", OriginalTitle: "Léon", Year: 1994},
}}
r := recognizerWith(p)
m := r.matchMetadata(context.Background(),
m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaMovie, Title: "Léon", Year: 1994})
if m == nil || m.ProviderID != "1" {
t.Errorf("should match by original title, got %+v", m)
@@ -98,7 +142,7 @@ func TestMatchMetadata_TagFromExternal(t *testing.T) {
counts: map[int]int{1: 10},
}
r := recognizerWith(p)
m := r.matchMetadata(context.Background(),
m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaSeries, Title: "Fargo", Year: 2014})
if m == nil {
t.Fatal("expected match")
@@ -118,7 +162,7 @@ func TestMatchMetadata_SeriesFetchesCounts(t *testing.T) {
counts: map[int]int{1: 10, 2: 10},
}
r := recognizerWith(p)
m := r.matchMetadata(context.Background(),
m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaSeries, Title: "Fargo", Year: 2014})
if m == nil || m.SeasonEpisodeCounts[1] != 10 {
t.Errorf("counts not fetched: %+v", m)
@@ -128,7 +172,7 @@ func TestMatchMetadata_SeriesFetchesCounts(t *testing.T) {
func TestMatchMetadata_ProviderErrorNoMatch(t *testing.T) {
p := &fakeProvider{searchErr: errors.New("upstream down")}
r := recognizerWith(p)
if m := r.matchMetadata(context.Background(),
if m, _ := r.matchMetadata(context.Background(),
Plan{Type: MediaMovie, Title: "X", Year: 2000}); m != nil {
t.Errorf("provider error must yield no match, got %+v", m)
}
@@ -136,7 +180,7 @@ func TestMatchMetadata_ProviderErrorNoMatch(t *testing.T) {
func TestMatchMetadata_Disabled(t *testing.T) {
r := recognizerWith(nil)
if m := r.matchMetadata(context.Background(), Plan{Type: MediaMovie, Title: "X"}); m != nil {
if m, _ := r.matchMetadata(context.Background(), Plan{Type: MediaMovie, Title: "X"}); m != nil {
t.Errorf("no providers → no match, got %+v", m)
}
}