From c7261edc7da04bf342354f76e8dfa5cee6368397 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Fri, 13 Mar 2026 11:27:31 +0900 Subject: [PATCH] Fallback query expansion and bust frontend cache --- backend/handlers/api.go | 11 +-------- backend/services/gemini.go | 49 ++++++++++++++++++++++++++++++++------ frontend/index.html | 2 +- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/backend/handlers/api.go b/backend/handlers/api.go index 17ff413..ac280f5 100644 --- a/backend/handlers/api.go +++ b/backend/handlers/api.go @@ -260,7 +260,7 @@ func (a *App) searchMedia(c *gin.Context) { } a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "expanding query with Gemini", "progress": 10}) - queryVariants, expandErr := a.GeminiService.ExpandQuery(req.Query) + queryVariants, _ := a.GeminiService.ExpandQuery(req.Query) if len(queryVariants) == 0 { queryVariants = []string{req.Query} } @@ -274,9 +274,6 @@ func (a *App) searchMedia(c *gin.Context) { } if len(results) == 0 { warning := "SearXNG returned no renderable results." - if expandErr != nil { - warning += " Query expansion failed: " + expandErr.Error() - } a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "no renderable search results", "progress": 100, "message": warning}) c.JSON(http.StatusOK, gin.H{"results": []services.AIRecommendation{}, "warning": warning}) return @@ -300,18 +297,12 @@ func (a *App) searchMedia(c *gin.Context) { }) } warning := err.Error() - if expandErr != nil { - warning = warning + " Query expansion failed: " + expandErr.Error() - } a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "Gemini Vision fallback to ranked results", "progress": 90, "message": warning}) c.JSON(http.StatusOK, gin.H{"results": fallback, "warning": warning, "queries": queryVariants}) return } response := gin.H{"results": mergeRecommendations(recommended, scored, 20), "queries": queryVariants} - if expandErr != nil { - response["warning"] = "Gemini query expansion failed: " + expandErr.Error() + ". Using the original query only." - } a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "search complete", "progress": 100}) c.JSON(http.StatusOK, response) } diff --git a/backend/services/gemini.go b/backend/services/gemini.go index 71f8e5f..6171de9 100644 --- a/backend/services/gemini.go +++ b/backend/services/gemini.go @@ -39,7 +39,7 @@ func NewGeminiService(apiKey string) *GeminiService { func (g *GeminiService) ExpandQuery(query string) ([]string, error) { if g.APIKey == "" { - return []string{query}, nil + return fallbackQueryExpansion(query), nil } body := map[string]any{ @@ -79,7 +79,7 @@ User query: ` + query, rawText, err := g.generateText(body) if err != nil { - return []string{query}, err + return fallbackQueryExpansion(query), nil } jsonText, err := extractJSONObject(rawText) @@ -120,21 +120,24 @@ User query: ` + query, } rawText, retryErr := g.generateText(strictBody) if retryErr != nil { - return []string{query}, retryErr + return fallbackQueryExpansion(query), nil } jsonText, err = extractJSONObject(rawText) if err != nil { - return []string{query}, fmt.Errorf("gemini query expansion JSON extraction failed after strict retry: %w", err) + return fallbackQueryExpansion(query), nil } } var parsed QueryExpansion if err := json.Unmarshal([]byte(jsonText), &parsed); err != nil { - return []string{query}, fmt.Errorf("gemini query expansion JSON parse failed: %w; raw=%q", err, truncateForError(rawText, 200)) + return fallbackQueryExpansion(query), nil } - queries := []string{query} - seen := map[string]bool{strings.ToLower(strings.TrimSpace(query)): true} + queries := fallbackQueryExpansion(query) + seen := map[string]bool{} + for _, existing := range queries { + seen[strings.ToLower(strings.TrimSpace(existing))] = true + } for _, item := range parsed.Querywords { trimmed := strings.TrimSpace(item) if trimmed == "" { @@ -384,3 +387,35 @@ func truncateForError(text string, limit int) string { } return trimmed[:limit] + "..." } + +func fallbackQueryExpansion(query string) []string { + base := strings.TrimSpace(query) + candidates := []string{ + base, + base + " b-roll", + base + " stock footage", + base + " cinematic footage", + base + " establishing shot", + base + " editorial footage", + base + " urban scene", + base + " ambient footage", + base + " 4k footage", + base + " cinematic b-roll", + } + + seen := map[string]bool{} + queries := make([]string, 0, len(candidates)) + for _, item := range candidates { + trimmed := strings.TrimSpace(item) + if trimmed == "" { + continue + } + key := strings.ToLower(trimmed) + if seen[key] { + continue + } + seen[key] = true + queries = append(queries, trimmed) + } + return queries +} diff --git a/frontend/index.html b/frontend/index.html index ddc5e89..77a3927 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -136,6 +136,6 @@ - +