Tolerate Gemini image expansion drift
build-push / docker (push) Successful in 4m23s

This commit is contained in:
GHStaK
2026-03-24 16:29:36 +09:00
parent 1fb9919ec3
commit 3c6df2e777
6 changed files with 68 additions and 49 deletions
+33
View File
@@ -147,6 +147,11 @@ func (g *GeminiService) ExpandImageQueries(query string) ([]string, error) {
}
jsonText, err := extractJSONObject(rawText)
if err != nil {
if looseQueries := parseLooseImageExpansionLines(rawText); len(looseQueries) == 5 {
g.setCachedExpansion(cacheKey, looseQueries, 15*time.Minute)
g.debug("gemini:image_expand_success", map[string]any{"query": trimmed, "queries": looseQueries, "mode": "loose_text"})
return looseQueries, nil
}
g.debug("gemini:image_expand_parse_error", map[string]any{"query": trimmed, "error": err.Error()})
g.setCachedExpansion(cacheKey, fallback, 15*time.Minute)
return fallback, err
@@ -801,6 +806,34 @@ func truncateForError(text string, limit int) string {
return trimmed[:limit] + "..."
}
func parseLooseImageExpansionLines(text string) []string {
candidates := make([]string, 0, 8)
for _, line := range strings.Split(text, "\n") {
trimmed := strings.TrimSpace(line)
if trimmed == "" {
continue
}
trimmed = strings.TrimPrefix(trimmed, "- ")
trimmed = strings.TrimPrefix(trimmed, "* ")
trimmed = strings.TrimPrefix(trimmed, "1. ")
trimmed = strings.TrimPrefix(trimmed, "2. ")
trimmed = strings.TrimPrefix(trimmed, "3. ")
trimmed = strings.TrimPrefix(trimmed, "4. ")
trimmed = strings.TrimPrefix(trimmed, "5. ")
trimmed = strings.TrimSpace(strings.Trim(trimmed, "\"'`"))
lower := strings.ToLower(trimmed)
if strings.HasPrefix(lower, "here is") || strings.HasPrefix(lower, "json") || strings.HasPrefix(lower, "output") {
continue
}
candidates = append(candidates, trimmed)
}
queries := normalizeImageExpansionQueries(candidates)
if len(queries) < 5 {
return nil
}
return queries[:5]
}
func normalizeKoreanReason(reason string) string {
trimmed := strings.TrimSpace(reason)
if trimmed == "" {
+20
View File
@@ -145,6 +145,26 @@ func TestExpandImageQueriesFallsBackWhenGeminiFails(t *testing.T) {
}
}
func TestExpandImageQueriesAcceptsLoosePlainTextList(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"candidates":[{"content":{"parts":[{"text":"Here is the JSON requested\n1. cute cat\n2. cute cat gif\n3. cat reaction gif\n4. cat meme gif\n5. animated cat sticker"}]}}]}`))
}))
defer server.Close()
service := NewGeminiService("dummy-key", "gemini-2.5-flash")
service.Client = &http.Client{Timeout: 2 * time.Second}
service.GenerateEndpoint = server.URL
queries, err := service.ExpandImageQueries("고양이")
if err != nil {
t.Fatalf("expected loose plain-text list to be accepted, got %v", err)
}
if len(queries) != 5 || queries[0] != "cute cat" || queries[4] != "animated cat sticker" {
t.Fatalf("unexpected loose parsed queries: %#v", queries)
}
}
func TestSelectUnevaluatedCandidatesSkipsReviewedLinks(t *testing.T) {
ranked := []SearchResult{
{Link: "https://a.example"},
-1
View File
@@ -168,7 +168,6 @@ func (s *GiphyService) SearchImages(query string, requestedMax int) (GiphySearch
expandedQueries, expansionErr := s.expandQueries(response.OriginalQuery)
response.ExpandedQueries = expandedQueries
if expansionErr != nil {
response.Warning = "Query expansion failed, using fallback search terms."
s.debug("giphy:query_expansion_fallback", map[string]any{
"query": response.OriginalQuery,
"queries": expandedQueries,