Fallback query expansion and bust frontend cache
build-push / docker (push) Successful in 4m14s

This commit is contained in:
AI Assistant
2026-03-13 11:27:31 +09:00
parent 0941f60a0c
commit c7261edc7d
3 changed files with 44 additions and 18 deletions
+1 -10
View File
@@ -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}) 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 { if len(queryVariants) == 0 {
queryVariants = []string{req.Query} queryVariants = []string{req.Query}
} }
@@ -274,9 +274,6 @@ func (a *App) searchMedia(c *gin.Context) {
} }
if len(results) == 0 { if len(results) == 0 {
warning := "SearXNG returned no renderable results." 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}) 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}) c.JSON(http.StatusOK, gin.H{"results": []services.AIRecommendation{}, "warning": warning})
return return
@@ -300,18 +297,12 @@ func (a *App) searchMedia(c *gin.Context) {
}) })
} }
warning := err.Error() 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}) 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}) c.JSON(http.StatusOK, gin.H{"results": fallback, "warning": warning, "queries": queryVariants})
return return
} }
response := gin.H{"results": mergeRecommendations(recommended, scored, 20), "queries": queryVariants} 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}) a.Hub.Broadcast("progress", gin.H{"type": "search", "status": "search complete", "progress": 100})
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)
} }
+42 -7
View File
@@ -39,7 +39,7 @@ func NewGeminiService(apiKey string) *GeminiService {
func (g *GeminiService) ExpandQuery(query string) ([]string, error) { func (g *GeminiService) ExpandQuery(query string) ([]string, error) {
if g.APIKey == "" { if g.APIKey == "" {
return []string{query}, nil return fallbackQueryExpansion(query), nil
} }
body := map[string]any{ body := map[string]any{
@@ -79,7 +79,7 @@ User query: ` + query,
rawText, err := g.generateText(body) rawText, err := g.generateText(body)
if err != nil { if err != nil {
return []string{query}, err return fallbackQueryExpansion(query), nil
} }
jsonText, err := extractJSONObject(rawText) jsonText, err := extractJSONObject(rawText)
@@ -120,21 +120,24 @@ User query: ` + query,
} }
rawText, retryErr := g.generateText(strictBody) rawText, retryErr := g.generateText(strictBody)
if retryErr != nil { if retryErr != nil {
return []string{query}, retryErr return fallbackQueryExpansion(query), nil
} }
jsonText, err = extractJSONObject(rawText) jsonText, err = extractJSONObject(rawText)
if err != nil { 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 var parsed QueryExpansion
if err := json.Unmarshal([]byte(jsonText), &parsed); err != nil { 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} queries := fallbackQueryExpansion(query)
seen := map[string]bool{strings.ToLower(strings.TrimSpace(query)): true} seen := map[string]bool{}
for _, existing := range queries {
seen[strings.ToLower(strings.TrimSpace(existing))] = true
}
for _, item := range parsed.Querywords { for _, item := range parsed.Querywords {
trimmed := strings.TrimSpace(item) trimmed := strings.TrimSpace(item)
if trimmed == "" { if trimmed == "" {
@@ -384,3 +387,35 @@ func truncateForError(text string, limit int) string {
} }
return trimmed[:limit] + "..." 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
}
+1 -1
View File
@@ -136,6 +136,6 @@
</a> </a>
</template> </template>
<script src="/app.js" defer></script> <script src="/app.js?v=20260313b" defer></script>
</body> </body>
</html> </html>