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
+6 -12
View File
@@ -164,16 +164,21 @@ User query: ` + query,
}
maxImages := min(len(candidates), 10)
visualCount := 0
for idx := 0; idx < maxImages; idx++ {
img, mimeType, err := fetchCandidateVisualInlineData(g.Client, candidates[idx])
if err != nil {
continue
}
visualCount++
parts = append(parts,
geminiPart{"text": fmt.Sprintf("Candidate %d: title=%s source=%s link=%s", idx, candidates[idx].Title, candidates[idx].Source, candidates[idx].Link)},
geminiPart{"inlineData": map[string]string{"mimeType": mimeType, "data": img}},
)
}
if visualCount == 0 {
return nil, fmt.Errorf("no candidate thumbnails or preview frames could be fetched for gemini vision")
}
body := map[string]any{
"contents": []map[string]any{
@@ -248,18 +253,7 @@ User query: ` + query,
}
if len(recommendations) == 0 {
for _, candidate := range candidates[:min(8, len(candidates))] {
recommendations = append(recommendations, AIRecommendation{
Title: candidate.Title,
Link: candidate.Link,
Snippet: candidate.Snippet,
ThumbnailURL: candidate.ThumbnailURL,
PreviewVideoURL: candidate.PreviewVideoURL,
Source: candidate.Source,
Reason: "Gemini Vision 평가를 받지 못해 키워드 기준으로 보강된 결과입니다.",
Recommended: false,
})
}
recommendations = BuildFallbackRecommendations(candidates, 8, "Gemini Vision 평가를 받지 못해 키워드 기준으로 보강된 결과입니다.")
}
return recommendations, nil
+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,
})
}