This commit is contained in:
@@ -94,9 +94,14 @@ User query: ` + query,
|
||||
return []string{query}, fmt.Errorf("gemini query expansion returned no candidates")
|
||||
}
|
||||
|
||||
jsonText, err := extractJSONObject(payload.Candidates[0].Content.Parts[0].Text)
|
||||
if err != nil {
|
||||
return []string{query}, fmt.Errorf("gemini query expansion JSON extraction failed: %w", err)
|
||||
}
|
||||
|
||||
var parsed QueryExpansion
|
||||
if err := json.Unmarshal([]byte(payload.Candidates[0].Content.Parts[0].Text), &parsed); err != nil {
|
||||
return []string{query}, fmt.Errorf("gemini query expansion JSON parse failed: %w", err)
|
||||
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(payload.Candidates[0].Content.Parts[0].Text, 200))
|
||||
}
|
||||
|
||||
queries := []string{query}
|
||||
@@ -187,6 +192,11 @@ User query: ` + query,
|
||||
return nil, fmt.Errorf("gemini vision returned no candidates")
|
||||
}
|
||||
|
||||
jsonText, err := extractJSONObject(payload.Candidates[0].Content.Parts[0].Text)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gemini vision JSON extraction failed: %w", err)
|
||||
}
|
||||
|
||||
var parsed struct {
|
||||
Recommendations []struct {
|
||||
Index int `json:"index"`
|
||||
@@ -194,8 +204,8 @@ User query: ` + query,
|
||||
Recommended bool `json:"recommended"`
|
||||
} `json:"recommendations"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(payload.Candidates[0].Content.Parts[0].Text), &parsed); err != nil {
|
||||
return nil, fmt.Errorf("gemini vision JSON parse failed: %w", err)
|
||||
if err := json.Unmarshal([]byte(jsonText), &parsed); err != nil {
|
||||
return nil, fmt.Errorf("gemini vision JSON parse failed: %w; raw=%q", err, truncateForError(payload.Candidates[0].Content.Parts[0].Text, 200))
|
||||
}
|
||||
|
||||
recommendations := make([]AIRecommendation, 0, len(parsed.Recommendations))
|
||||
@@ -260,3 +270,56 @@ func min(a, b int) int {
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func extractJSONObject(text string) (string, error) {
|
||||
cleaned := strings.TrimSpace(text)
|
||||
cleaned = strings.TrimPrefix(cleaned, "```json")
|
||||
cleaned = strings.TrimPrefix(cleaned, "```")
|
||||
cleaned = strings.TrimSuffix(cleaned, "```")
|
||||
cleaned = strings.TrimSpace(cleaned)
|
||||
|
||||
start := strings.Index(cleaned, "{")
|
||||
if start == -1 {
|
||||
return "", fmt.Errorf("no JSON object start found in %q", truncateForError(cleaned, 200))
|
||||
}
|
||||
|
||||
depth := 0
|
||||
inString := false
|
||||
escaped := false
|
||||
for i := start; i < len(cleaned); i++ {
|
||||
ch := cleaned[i]
|
||||
if escaped {
|
||||
escaped = false
|
||||
continue
|
||||
}
|
||||
if ch == '\\' && inString {
|
||||
escaped = true
|
||||
continue
|
||||
}
|
||||
if ch == '"' {
|
||||
inString = !inString
|
||||
continue
|
||||
}
|
||||
if inString {
|
||||
continue
|
||||
}
|
||||
switch ch {
|
||||
case '{':
|
||||
depth++
|
||||
case '}':
|
||||
depth--
|
||||
if depth == 0 {
|
||||
return cleaned[start : i+1], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("no complete JSON object found in %q", truncateForError(cleaned, 200))
|
||||
}
|
||||
|
||||
func truncateForError(text string, limit int) string {
|
||||
trimmed := strings.TrimSpace(text)
|
||||
if len(trimmed) <= limit {
|
||||
return trimmed
|
||||
}
|
||||
return trimmed[:limit] + "..."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user