trigger endpoint and retry suggestions

This commit is contained in:
2026-04-25 15:21:09 +02:00
parent 20ebe5a49f
commit 846083e230
6 changed files with 103 additions and 37 deletions

View File

@@ -79,42 +79,58 @@ func (r *Recommender) RunWithCount(count int) ([]model.Recommendation, error) {
}
}
// 3. Get raw suggestions
var suggestions []model.MovieSuggestion
if r.cfg.LLMEnabled && r.llm != nil {
prompt := client.BuildPrompt(favorites, watchedMovies, library, count)
suggestions, err = r.llm.Recommend(prompt)
if err != nil {
return nil, fmt.Errorf("llm recommendation failed: %w", err)
}
log.Info().Msgf("LLM returned %d suggestions", len(suggestions))
} else {
suggestions = r.tmdbFallback(signalMovies, exclude, count)
log.Info().Msgf("TMDb fallback returned %d suggestions", len(suggestions))
}
// 4. Resolve suggestions via TMDb and apply exclusions
// 3. Retry loop: each attempt requests only the remaining needed count.
// `seen` accumulates every TMDb-resolved movie across attempts so the
// LLM prompt excludes them by name, not just by ID.
var recommendations []model.Recommendation
for _, s := range suggestions {
if len(recommendations) >= count {
var seen []model.Movie
for attempt := 0; attempt <= r.cfg.RecommendMaxRetry && len(recommendations) < count; attempt++ {
remaining := count - len(recommendations)
if attempt > 0 {
log.Info().Msgf("Retry %d/%d: need %d more recommendations", attempt, r.cfg.RecommendMaxRetry, remaining)
}
var suggestions []model.MovieSuggestion
if r.cfg.LLMEnabled && r.llm != nil {
prompt := client.BuildPrompt(favorites, watchedMovies, library, seen, remaining)
suggestions, err = r.llm.Recommend(prompt)
if err != nil {
return recommendations, fmt.Errorf("llm recommendation failed: %w", err)
}
log.Info().Msgf("LLM returned %d suggestions (attempt %d)", len(suggestions), attempt+1)
} else {
suggestions = r.tmdbFallback(signalMovies, exclude, remaining)
log.Info().Msgf("TMDb fallback returned %d suggestions (attempt %d)", len(suggestions), attempt+1)
}
before := len(recommendations)
for _, s := range suggestions {
if len(recommendations) >= count {
break
}
tm, err := r.tmdb.SearchMovie(s.Title, s.Year)
if err != nil || tm == nil {
log.Debug().Msgf("Could not resolve: %s (%d)", s.Title, s.Year)
continue
}
seen = append(seen, model.Movie{Name: tm.Title, Year: tm.Year, TMDbID: strconv.Itoa(tm.ID)})
if exclude[tm.ID] {
log.Debug().Msgf("Skipping (already in library): %s", tm.Title)
continue
}
exclude[tm.ID] = true
recommendations = append(recommendations, model.Recommendation{
Title: tm.Title,
Year: tm.Year,
TMDbID: tm.ID,
Reason: s.Reason,
})
}
if len(recommendations) == before {
log.Warn().Msgf("No new recommendations found on attempt %d, stopping retries", attempt+1)
break
}
tm, err := r.tmdb.SearchMovie(s.Title, s.Year)
if err != nil || tm == nil {
log.Debug().Msgf("Could not resolve: %s (%d)", s.Title, s.Year)
continue
}
if exclude[tm.ID] {
log.Debug().Msgf("Skipping (already in library): %s", tm.Title)
continue
}
exclude[tm.ID] = true
recommendations = append(recommendations, model.Recommendation{
Title: tm.Title,
Year: tm.Year,
TMDbID: tm.ID,
Reason: s.Reason,
})
}
return recommendations, nil