Refactor search fallback and preview flows
build-push / docker (push) Failing after 20m32s

This commit is contained in:
AI Assistant
2026-03-16 11:12:43 +09:00
parent b43886e950
commit 8101f17f5b
5 changed files with 150 additions and 88 deletions
+47 -3
View File
@@ -1,11 +1,14 @@
package services
import (
"fmt"
"sort"
"strings"
"sync"
)
const GeminiFallbackReason = "Gemini Vision 응답이 부족해 키워드 기준으로 보강된 결과입니다."
type GeminiBatchStats struct {
CandidateCap int `json:"candidateCap"`
Requested int `json:"requested"`
@@ -84,9 +87,13 @@ func GeminiCandidateLimit(total int) int {
return total
}
func EvaluateAllCandidatesWithGemini(service *GeminiService, query string, ranked []SearchResult) ([]AIRecommendation, GeminiBatchStats) {
func EvaluateAllCandidatesWithGemini(service *GeminiService, query string, ranked []SearchResult) ([]AIRecommendation, GeminiBatchStats, error) {
const chunkSize = 8
const maxConcurrentBatches = 2
if service == nil {
return nil, GeminiBatchStats{}, fmt.Errorf("gemini service is not configured")
}
limit := GeminiCandidateLimit(len(ranked))
stats := GeminiBatchStats{
CandidateCap: limit,
@@ -106,6 +113,9 @@ func EvaluateAllCandidatesWithGemini(service *GeminiService, query string, ranke
batches = append(batches, ranked[start:end])
}
stats.Batches = len(batches)
if len(batches) == 0 {
return []AIRecommendation{}, stats, nil
}
results := make([]batchResult, len(batches))
var wg sync.WaitGroup
@@ -146,7 +156,41 @@ func EvaluateAllCandidatesWithGemini(service *GeminiService, query string, ranke
}
}
stats.RecommendedCount = len(merged)
return merged, stats
switch {
case len(merged) > 0 && stats.Failed == 0:
return merged, stats, nil
case len(merged) > 0 && stats.Failed > 0:
return merged, stats, fmt.Errorf("gemini vision partially failed on %d of %d batches", stats.Failed, stats.Batches)
case stats.Failed == stats.Batches:
if len(stats.Errors) > 0 {
return nil, stats, fmt.Errorf("gemini vision failed for all batches: %s", strings.Join(stats.Errors, "; "))
}
return nil, stats, fmt.Errorf("gemini vision failed for all batches")
default:
return nil, stats, fmt.Errorf("gemini vision returned no candidate evaluations")
}
}
func BuildFallbackRecommendations(ranked []SearchResult, limit int, reason string) []AIRecommendation {
if strings.TrimSpace(reason) == "" {
reason = GeminiFallbackReason
}
fallback := make([]AIRecommendation, 0, min(limit, len(ranked)))
for _, item := range ranked[:min(limit, len(ranked))] {
fallback = append(fallback, AIRecommendation{
Title: item.Title,
Link: item.Link,
Snippet: item.Snippet,
ThumbnailURL: item.ThumbnailURL,
PreviewVideoURL: item.PreviewVideoURL,
Source: item.Source,
Reason: reason,
Recommended: false,
})
}
return fallback
}
func MergeRecommendations(recommended []AIRecommendation, ranked []SearchResult, limit int) []AIRecommendation {
@@ -184,7 +228,7 @@ func MergeRecommendations(recommended []AIRecommendation, ranked []SearchResult,
ThumbnailURL: item.ThumbnailURL,
PreviewVideoURL: item.PreviewVideoURL,
Source: item.Source,
Reason: "Gemini Vision 응답이 부족해 키워드 기준으로 보강된 결과입니다.",
Reason: GeminiFallbackReason,
Recommended: false,
})
}