This commit is contained in:
@@ -94,9 +94,14 @@ User query: ` + query,
|
|||||||
return []string{query}, fmt.Errorf("gemini query expansion returned no candidates")
|
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
|
var parsed QueryExpansion
|
||||||
if err := json.Unmarshal([]byte(payload.Candidates[0].Content.Parts[0].Text), &parsed); err != nil {
|
if err := json.Unmarshal([]byte(jsonText), &parsed); err != nil {
|
||||||
return []string{query}, fmt.Errorf("gemini query expansion JSON parse failed: %w", err)
|
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}
|
queries := []string{query}
|
||||||
@@ -187,6 +192,11 @@ User query: ` + query,
|
|||||||
return nil, fmt.Errorf("gemini vision returned no candidates")
|
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 {
|
var parsed struct {
|
||||||
Recommendations []struct {
|
Recommendations []struct {
|
||||||
Index int `json:"index"`
|
Index int `json:"index"`
|
||||||
@@ -194,8 +204,8 @@ User query: ` + query,
|
|||||||
Recommended bool `json:"recommended"`
|
Recommended bool `json:"recommended"`
|
||||||
} `json:"recommendations"`
|
} `json:"recommendations"`
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal([]byte(payload.Candidates[0].Content.Parts[0].Text), &parsed); err != nil {
|
if err := json.Unmarshal([]byte(jsonText), &parsed); err != nil {
|
||||||
return nil, fmt.Errorf("gemini vision JSON parse failed: %w", err)
|
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))
|
recommendations := make([]AIRecommendation, 0, len(parsed.Recommendations))
|
||||||
@@ -260,3 +270,56 @@ func min(a, b int) int {
|
|||||||
}
|
}
|
||||||
return b
|
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