Improve Vertex search result extraction
Some checks are pending
build-push / docker (push) Waiting to run

This commit is contained in:
AI Assistant
2026-03-12 16:55:42 +09:00
parent 5b53cc6e11
commit 6734887fc6
2 changed files with 65 additions and 9 deletions

View File

@@ -263,6 +263,10 @@ func (a *App) searchMedia(c *gin.Context) {
c.JSON(http.StatusBadGateway, gin.H{"error": err.Error()})
return
}
if len(results) == 0 {
c.JSON(http.StatusOK, gin.H{"results": []services.AIRecommendation{}, "warning": "Vertex AI Search returned no renderable results. Check your website indexing fields and thumbnails."})
return
}
recommended, err := a.GeminiService.Recommend(req.Query, results)
if err != nil {

View File

@@ -6,6 +6,7 @@ import (
"io"
"net/http"
neturl "net/url"
"regexp"
"strings"
"time"
)
@@ -121,15 +122,33 @@ func (s *SearchService) searchLite(query string, imageSearch bool) ([]SearchResu
results := make([]SearchResult, 0, len(payload.Results))
for _, item := range payload.Results {
link := firstString(item.Document.StructData, "link", "url", "uri")
title := firstString(item.Document.StructData, "title", "name")
displayLink := firstString(item.Document.StructData, "site_name", "displayLink")
snippet := firstString(item.Document.DerivedStructData, "snippets", "snippet")
thumb := firstString(item.Document.DerivedStructData, "link", "thumbnail", "image", "image_url")
link := firstNonEmpty(
firstString(item.Document.DerivedStructData, "link", "url", "uri"),
firstString(item.Document.StructData, "link", "url", "uri"),
)
title := firstNonEmpty(
firstString(item.Document.DerivedStructData, "title", "name"),
firstString(item.Document.StructData, "title", "name"),
)
displayLink := firstNonEmpty(
firstString(item.Document.DerivedStructData, "displayLink", "site_name"),
firstString(item.Document.StructData, "displayLink", "site_name"),
)
snippet := firstNonEmpty(
firstString(item.Document.DerivedStructData, "snippets", "snippet", "extractive_answers"),
firstString(item.Document.StructData, "snippets", "snippet", "description"),
)
thumb := firstNonEmpty(
firstString(item.Document.DerivedStructData, "thumbnail", "image", "image_url", "link"),
firstString(item.Document.StructData, "thumbnail", "image", "image_url"),
)
if thumb == "" {
thumb = firstString(item.Document.StructData, "thumbnail", "image", "image_url")
thumb = deriveThumbnail(link)
}
if thumb == "" || link == "" {
if title == "" {
title = displayLink
}
if link == "" {
continue
}
results = append(results, SearchResult{
@@ -144,6 +163,15 @@ func (s *SearchService) searchLite(query string, imageSearch bool) ([]SearchResu
return results, nil
}
func firstNonEmpty(values ...string) string {
for _, value := range values {
if strings.TrimSpace(value) != "" {
return value
}
}
return ""
}
func firstString(values map[string]any, keys ...string) string {
for _, key := range keys {
value, ok := values[key]
@@ -161,13 +189,13 @@ func firstString(values map[string]any, keys ...string) string {
return text
}
if mapped, ok := item.(map[string]any); ok {
if text := firstString(mapped, "snippet", "htmlSnippet", "url"); text != "" {
if text := firstString(mapped, "snippet", "htmlSnippet", "url", "link", "value", "content"); text != "" {
return text
}
}
}
case map[string]any:
if text := firstString(typed, "snippet", "htmlSnippet", "url"); text != "" {
if text := firstString(typed, "snippet", "htmlSnippet", "url", "link", "value", "content"); text != "" {
return text
}
}
@@ -175,6 +203,30 @@ func firstString(values map[string]any, keys ...string) string {
return ""
}
func deriveThumbnail(link string) string {
if link == "" {
return ""
}
if videoID := extractYouTubeID(link); videoID != "" {
return "https://i.ytimg.com/vi/" + videoID + "/hqdefault.jpg"
}
return ""
}
func extractYouTubeID(link string) string {
patterns := []*regexp.Regexp{
regexp.MustCompile(`(?:v=|\/shorts\/|\/embed\/)([A-Za-z0-9_-]{11})`),
regexp.MustCompile(`youtu\.be\/([A-Za-z0-9_-]{11})`),
}
for _, pattern := range patterns {
matches := pattern.FindStringSubmatch(link)
if len(matches) == 2 {
return matches[1]
}
}
return ""
}
func inferSource(displayLink string) string {
switch {
case strings.Contains(displayLink, "youtube"):