mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-10 23:12:41 +08:00
feat: extractJSONFromContent
This commit is contained in:
@@ -1 +1 @@
|
|||||||
v5.0.0-beta-2506101402
|
v5.0.0-beta-2506101408
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package ai
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cloudwego/eino-ext/components/model/openai"
|
"github.com/cloudwego/eino-ext/components/model/openai"
|
||||||
@@ -169,7 +167,7 @@ func validateAssertionInput(opts *AssertOptions) error {
|
|||||||
// parseAssertionResult parses the model response into AssertionResponse
|
// parseAssertionResult parses the model response into AssertionResponse
|
||||||
func parseAssertionResult(content string) (*AssertionResult, error) {
|
func parseAssertionResult(content string) (*AssertionResult, error) {
|
||||||
// Extract JSON content from response
|
// Extract JSON content from response
|
||||||
jsonContent := extractJSON(content)
|
jsonContent := extractJSONFromContent(content)
|
||||||
if jsonContent == "" {
|
if jsonContent == "" {
|
||||||
return nil, errors.New("could not extract JSON from response")
|
return nil, errors.New("could not extract JSON from response")
|
||||||
}
|
}
|
||||||
@@ -182,38 +180,3 @@ func parseAssertionResult(content string) (*AssertionResult, error) {
|
|||||||
|
|
||||||
return &result, nil
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -46,69 +46,11 @@ func (p *JSONContentParser) SystemPrompt() string {
|
|||||||
return p.systemPrompt
|
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) {
|
func (p *JSONContentParser) Parse(content string, size types.Size) (*PlanningResult, error) {
|
||||||
content = strings.TrimSpace(content)
|
content = strings.TrimSpace(content)
|
||||||
|
|
||||||
// Extract JSON content from markdown code blocks
|
// Extract JSON content from markdown code blocks
|
||||||
jsonContent := p.extractJSONContent(content)
|
jsonContent := extractJSONFromContent(content)
|
||||||
if jsonContent == "" {
|
if jsonContent == "" {
|
||||||
return nil, fmt.Errorf("no valid JSON content found in response")
|
return nil, fmt.Errorf("no valid JSON content found in response")
|
||||||
}
|
}
|
||||||
|
|||||||
76
uixt/ai/utils.go
Normal file
76
uixt/ai/utils.go
Normal 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 ""
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user