This commit is contained in:
@@ -82,6 +82,7 @@ type PreviewResponse struct {
|
||||
|
||||
type searchDebugSummary struct {
|
||||
Total int `json:"total"`
|
||||
VisibleCount int `json:"visibleCount,omitempty"`
|
||||
BySource map[string]int `json:"bySource"`
|
||||
WithPreview int `json:"withPreview"`
|
||||
WithThumbnail int `json:"withThumbnail"`
|
||||
@@ -477,16 +478,16 @@ func (a *App) searchMedia(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
merged := services.MergeRecommendations(recommended, scored, 20)
|
||||
merged := services.MergeRecommendations(recommended, scored, 16)
|
||||
if geminiErr != nil {
|
||||
merged = services.BackfillRecommendations(
|
||||
merged,
|
||||
scored,
|
||||
12,
|
||||
16,
|
||||
"Gemini 배치 일부가 실패해 미리보기 가능한 상위 후보를 보강했습니다.",
|
||||
)
|
||||
}
|
||||
merged = services.RandomizeTopRecommendations(merged, 8)
|
||||
merged = services.RandomizeTopRecommendations(merged, 6)
|
||||
for idx := range merged {
|
||||
merged[idx] = services.DecorateRecommendationMedia(merged[idx])
|
||||
}
|
||||
@@ -665,6 +666,7 @@ func summarizeSearchResults(results []services.SearchResult, duration time.Durat
|
||||
}
|
||||
return searchDebugSummary{
|
||||
Total: len(results),
|
||||
VisibleCount: len(results),
|
||||
BySource: bySource,
|
||||
WithPreview: withPreview,
|
||||
WithThumbnail: withThumbnail,
|
||||
@@ -717,6 +719,7 @@ func summarizeRecommendationResults(results []services.AIRecommendation, duratio
|
||||
}
|
||||
return searchDebugSummary{
|
||||
Total: len(results),
|
||||
VisibleCount: len(results),
|
||||
BySource: bySource,
|
||||
WithPreview: withPreview,
|
||||
WithThumbnail: withThumbnail,
|
||||
|
||||
+21
-12
@@ -88,7 +88,7 @@ func (s *SearchService) SearchMediaWithDeadline(queries []string, enabledPlatfor
|
||||
results := make([]SearchResult, 0, 90)
|
||||
var lastErr error
|
||||
|
||||
baseQueries := limitQueries(queries, 6)
|
||||
baseQueries := limitQueries(queries, 8)
|
||||
shuffleStrings(baseQueries)
|
||||
primaryQueries := baseQueries[:minInt(len(baseQueries), 3)]
|
||||
runSearchPass := func(bases []string, onlyMissing bool) {
|
||||
@@ -190,7 +190,7 @@ func (s *SearchService) EnrichResults(results []SearchResult) []SearchResult {
|
||||
}
|
||||
|
||||
func (s *SearchService) EnrichResultsWithDeadline(results []SearchResult, deadline time.Time) []SearchResult {
|
||||
limit := minInt(len(results), 14)
|
||||
limit := minInt(len(results), 18)
|
||||
if limit == 0 {
|
||||
return results
|
||||
}
|
||||
@@ -722,13 +722,10 @@ func defaultMediaMode(source, link, previewURL, thumbnailURL string) (string, st
|
||||
embedURL := buildEmbedURL(source, link)
|
||||
switch source {
|
||||
case "Google Video":
|
||||
if embedURL != "" {
|
||||
return "embed", embedURL, ""
|
||||
}
|
||||
if hasUsableThumbnail(thumbnailURL) {
|
||||
return "thumbnail", "", "missing_google_embed"
|
||||
return "thumbnail", embedURL, "webpage_like_preview_preferred"
|
||||
}
|
||||
return "none", "", "missing_google_embed"
|
||||
return "none", embedURL, "webpage_like_preview_preferred"
|
||||
case "Envato":
|
||||
if strings.TrimSpace(previewURL) != "" {
|
||||
return "preview_video", embedURL, "provider_embed_blocked"
|
||||
@@ -741,12 +738,12 @@ func defaultMediaMode(source, link, previewURL, thumbnailURL string) (string, st
|
||||
}
|
||||
return "none", "", "provider_embed_blocked"
|
||||
case "Artgrid":
|
||||
if hasUsableThumbnail(thumbnailURL) {
|
||||
return "thumbnail", embedURL, "provider_preview_unavailable"
|
||||
}
|
||||
if strings.TrimSpace(previewURL) != "" {
|
||||
return "preview_video", embedURL, "provider_preview_unavailable"
|
||||
}
|
||||
if hasUsableThumbnail(thumbnailURL) {
|
||||
return "thumbnail", embedURL, "provider_preview_unavailable"
|
||||
}
|
||||
if embedURL != "" {
|
||||
return "embed", embedURL, ""
|
||||
}
|
||||
@@ -774,6 +771,18 @@ func DecorateRecommendationMedia(item AIRecommendation) AIRecommendation {
|
||||
if item.MediaMode == "thumbnail" && !hasUsableThumbnail(item.ThumbnailURL) && strings.TrimSpace(item.PreviewVideoURL) != "" {
|
||||
item.MediaMode = "preview_video"
|
||||
}
|
||||
switch item.Source {
|
||||
case "Google Video":
|
||||
item.ActionType = "download"
|
||||
item.ActionLabel = "Direct Download"
|
||||
item.SecondaryActionLabel = "Open Source"
|
||||
case "Envato", "Artgrid":
|
||||
item.ActionType = "open_source"
|
||||
item.ActionLabel = "Open Source"
|
||||
default:
|
||||
item.ActionType = "open_source"
|
||||
item.ActionLabel = "Open Source"
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
@@ -1380,9 +1389,9 @@ func limitCollectorQueries(collector string, queries []string, onlyMissing bool)
|
||||
limit := 2
|
||||
switch collector {
|
||||
case "Envato", "Artgrid":
|
||||
limit = 3
|
||||
limit = 4
|
||||
case "Google Video":
|
||||
limit = 2
|
||||
limit = 3
|
||||
}
|
||||
if onlyMissing {
|
||||
limit--
|
||||
|
||||
@@ -144,13 +144,13 @@ func TestLimitCollectorQueriesUsesSmallerBudgetForMissingPass(t *testing.T) {
|
||||
queries := []string{"a", "b", "c", "d"}
|
||||
|
||||
got := limitCollectorQueries("Artgrid", queries, true)
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("expected 2 queries for missing-pass Artgrid collector, got %d", len(got))
|
||||
if len(got) != 3 {
|
||||
t.Fatalf("expected 3 queries for missing-pass Artgrid collector, got %d", len(got))
|
||||
}
|
||||
|
||||
got = limitCollectorQueries("Google Video", queries, false)
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("expected 2 queries for Google Video collector, got %d", len(got))
|
||||
if len(got) != 3 {
|
||||
t.Fatalf("expected 3 queries for Google Video collector, got %d", len(got))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@ type AIRecommendation struct {
|
||||
MediaMode string `json:"mediaMode,omitempty"`
|
||||
EmbedURL string `json:"embedUrl,omitempty"`
|
||||
PreviewBlockedReason string `json:"previewBlockedReason,omitempty"`
|
||||
ActionLabel string `json:"actionLabel,omitempty"`
|
||||
ActionType string `json:"actionType,omitempty"`
|
||||
SecondaryActionLabel string `json:"secondaryActionLabel,omitempty"`
|
||||
}
|
||||
|
||||
type QueryExpansion struct {
|
||||
|
||||
@@ -118,15 +118,19 @@ func TestGeminiExpansionCacheRoundTrip(t *testing.T) {
|
||||
|
||||
func TestDecorateRecommendationMediaUsesEmbedForGoogleVideo(t *testing.T) {
|
||||
item := DecorateRecommendationMedia(AIRecommendation{
|
||||
Source: "Google Video",
|
||||
Link: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
Source: "Google Video",
|
||||
Link: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
||||
ThumbnailURL: "https://i.ytimg.com/vi/dQw4w9WgXcQ/hqdefault.jpg",
|
||||
})
|
||||
if item.MediaMode != "embed" {
|
||||
t.Fatalf("expected embed media mode, got %q", item.MediaMode)
|
||||
if item.MediaMode != "thumbnail" {
|
||||
t.Fatalf("expected thumbnail media mode, got %q", item.MediaMode)
|
||||
}
|
||||
if item.EmbedURL == "" || !strings.Contains(item.EmbedURL, "youtube-nocookie.com/embed/") {
|
||||
t.Fatalf("unexpected embed url: %q", item.EmbedURL)
|
||||
}
|
||||
if item.ActionType != "download" || item.ActionLabel != "Direct Download" {
|
||||
t.Fatalf("unexpected Google Video actions: %#v", item)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankSearchResultsPrefersUsableVisuals(t *testing.T) {
|
||||
|
||||
@@ -427,9 +427,9 @@ func MergeRecommendations(recommended []AIRecommendation, ranked []SearchResult,
|
||||
merged = append(merged, DecorateRecommendationMedia(item))
|
||||
}
|
||||
|
||||
if len(merged) < min(12, limit) {
|
||||
if len(merged) < min(16, limit) {
|
||||
for _, item := range ranked {
|
||||
if len(merged) >= min(12, limit) || item.Link == "" || seen[item.Link] {
|
||||
if len(merged) >= min(16, limit) || item.Link == "" || seen[item.Link] {
|
||||
continue
|
||||
}
|
||||
if fillerCount >= maxFiller {
|
||||
|
||||
@@ -15,7 +15,7 @@ type searchCollector interface {
|
||||
type envatoCollector struct{}
|
||||
|
||||
func (envatoCollector) Name() string { return "Envato" }
|
||||
func (envatoCollector) MaxResults() int { return 10 }
|
||||
func (envatoCollector) MaxResults() int { return 12 }
|
||||
func (envatoCollector) Enabled(enabledPlatforms map[string]bool) bool {
|
||||
return len(enabledPlatforms) == 0 || enabledPlatforms["envato"]
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func (envatoCollector) Enrich(searcher *SearchService, result SearchResult) Sear
|
||||
type artgridCollector struct{}
|
||||
|
||||
func (artgridCollector) Name() string { return "Artgrid" }
|
||||
func (artgridCollector) MaxResults() int { return 10 }
|
||||
func (artgridCollector) MaxResults() int { return 12 }
|
||||
func (artgridCollector) Enabled(enabledPlatforms map[string]bool) bool {
|
||||
return len(enabledPlatforms) == 0 || enabledPlatforms["artgrid"]
|
||||
}
|
||||
@@ -47,7 +47,7 @@ func (artgridCollector) Enrich(searcher *SearchService, result SearchResult) Sea
|
||||
type googleVideoCollector struct{}
|
||||
|
||||
func (googleVideoCollector) Name() string { return "Google Video" }
|
||||
func (googleVideoCollector) MaxResults() int { return 6 }
|
||||
func (googleVideoCollector) MaxResults() int { return 8 }
|
||||
func (googleVideoCollector) Enabled(enabledPlatforms map[string]bool) bool {
|
||||
return len(enabledPlatforms) == 0 || enabledPlatforms["google video"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user