feat: extractJSONFromContent

This commit is contained in:
lilong.129
2025-06-10 14:08:44 +08:00
parent 7dc0f869be
commit 4959c2e47e
4 changed files with 79 additions and 98 deletions

View File

@@ -3,8 +3,6 @@ package ai
import (
"context"
"fmt"
"regexp"
"strings"
"time"
"github.com/cloudwego/eino-ext/components/model/openai"
@@ -169,7 +167,7 @@ func validateAssertionInput(opts *AssertOptions) error {
// parseAssertionResult parses the model response into AssertionResponse
func parseAssertionResult(content string) (*AssertionResult, error) {
// Extract JSON content from response
jsonContent := extractJSON(content)
jsonContent := extractJSONFromContent(content)
if jsonContent == "" {
return nil, errors.New("could not extract JSON from response")
}
@@ -182,38 +180,3 @@ func parseAssertionResult(content string) (*AssertionResult, error) {
return &result, nil
}
// extractJSON extracts JSON content from a string that might contain markdown or other formatting
func extractJSON(content string) string {
content = strings.TrimSpace(content)
// If the content is already a valid JSON, return it
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
return content
}
// Try to extract JSON from markdown code blocks
jsonRegex := regexp.MustCompile(`(?:json)?\s*({[\s\S]*?})\s*`)
matches := jsonRegex.FindStringSubmatch(content)
if len(matches) > 1 {
return strings.TrimSpace(matches[1])
}
// Try a more robust approach for JSON with Chinese characters
startIdx := strings.Index(content, "{")
if startIdx >= 0 {
depth := 1
for i := startIdx + 1; i < len(content); i++ {
if content[i] == '{' {
depth++
} else if content[i] == '}' {
depth--
if depth == 0 {
return content[startIdx : i+1]
}
}
}
}
return content
}

View File

@@ -46,69 +46,11 @@ func (p *JSONContentParser) SystemPrompt() string {
return p.systemPrompt
}
// extractJSONContent extracts JSON content from various formats in the response
func (p *JSONContentParser) extractJSONContent(content string) string {
content = strings.TrimSpace(content)
// Case 1: Content wrapped in ```json ... ```
if strings.Contains(content, "```json") {
start := strings.Index(content, "```json")
if start != -1 {
start += 7 // length of "```json"
end := strings.Index(content[start:], "```")
if end != -1 {
jsonContent := strings.TrimSpace(content[start : start+end])
return jsonContent
}
}
}
// Case 2: Content wrapped in ``` ... ``` (without json specifier)
if strings.HasPrefix(content, "```") && strings.HasSuffix(content, "```") {
lines := strings.Split(content, "\n")
if len(lines) >= 3 {
// Remove first and last lines (the ``` markers)
jsonLines := lines[1 : len(lines)-1]
jsonContent := strings.Join(jsonLines, "\n")
jsonContent = strings.TrimSpace(jsonContent)
// Check if it looks like JSON
if strings.HasPrefix(jsonContent, "{") && strings.HasSuffix(jsonContent, "}") {
return jsonContent
}
}
}
// Case 3: Look for JSON object in the content
start := strings.Index(content, "{")
if start != -1 {
// Find the matching closing brace
braceCount := 0
for i := start; i < len(content); i++ {
if content[i] == '{' {
braceCount++
} else if content[i] == '}' {
braceCount--
if braceCount == 0 {
jsonContent := strings.TrimSpace(content[start : i+1])
return jsonContent
}
}
}
}
// Case 4: If content itself looks like JSON
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
return content
}
return ""
}
func (p *JSONContentParser) Parse(content string, size types.Size) (*PlanningResult, error) {
content = strings.TrimSpace(content)
// Extract JSON content from markdown code blocks
jsonContent := p.extractJSONContent(content)
jsonContent := extractJSONFromContent(content)
if jsonContent == "" {
return nil, fmt.Errorf("no valid JSON content found in response")
}

76
uixt/ai/utils.go Normal file
View File

@@ -0,0 +1,76 @@
package ai
import (
"regexp"
"strings"
)
// extractJSONFromContent extracts JSON content from various formats in the response
// This function handles multiple formats:
// 1. ```json ... ``` markdown code blocks
// 2. ``` ... ``` generic code blocks
// 3. JSON objects embedded in text
// 4. Plain JSON content
func extractJSONFromContent(content string) string {
content = strings.TrimSpace(content)
// Case 1: Content wrapped in ```json ... ```
if strings.Contains(content, "```json") {
start := strings.Index(content, "```json")
if start != -1 {
start += 7 // length of "```json"
end := strings.Index(content[start:], "```")
if end != -1 {
jsonContent := strings.TrimSpace(content[start : start+end])
return jsonContent
}
}
}
// Case 2: Content wrapped in ``` ... ``` (without json specifier)
if strings.HasPrefix(content, "```") && strings.HasSuffix(content, "```") {
lines := strings.Split(content, "\n")
if len(lines) >= 3 {
// Remove first and last lines (the ``` markers)
jsonLines := lines[1 : len(lines)-1]
jsonContent := strings.Join(jsonLines, "\n")
jsonContent = strings.TrimSpace(jsonContent)
// Check if it looks like JSON
if strings.HasPrefix(jsonContent, "{") && strings.HasSuffix(jsonContent, "}") {
return jsonContent
}
}
}
// Case 3: Try regex approach for markdown-like formats
jsonRegex := regexp.MustCompile(`(?:json)?\s*({[\s\S]*?})\s*`)
matches := jsonRegex.FindStringSubmatch(content)
if len(matches) > 1 {
return strings.TrimSpace(matches[1])
}
// Case 4: Look for JSON object in the content using brace counting
start := strings.Index(content, "{")
if start != -1 {
// Find the matching closing brace
braceCount := 0
for i := start; i < len(content); i++ {
if content[i] == '{' {
braceCount++
} else if content[i] == '}' {
braceCount--
if braceCount == 0 {
jsonContent := strings.TrimSpace(content[start : i+1])
return jsonContent
}
}
}
}
// Case 5: If content itself looks like JSON
if strings.HasPrefix(content, "{") && strings.HasSuffix(content, "}") {
return content
}
return ""
}