refactor: merge ai parser

This commit is contained in:
lilong.129
2025-05-24 00:25:44 +08:00
parent 19ddcb40cc
commit 81c854f963
7 changed files with 929 additions and 256 deletions
+28 -91
View File
@@ -2,8 +2,6 @@ package ai
import (
"fmt"
"regexp"
"strconv"
"strings"
"github.com/httprunner/httprunner/v5/internal/json"
@@ -49,109 +47,48 @@ func (p *JSONContentParser) Parse(content string, size types.Size) (*PlanningRes
}
content = strings.TrimSpace(content)
var response PlanningResult
if err := json.Unmarshal([]byte(content), &response); err != nil {
// Define a temporary struct to parse the expected JSON format
var jsonResponse struct {
Actions []Action `json:"actions"`
Summary string `json:"summary"`
Error string `json:"error"`
}
if err := json.Unmarshal([]byte(content), &jsonResponse); err != nil {
return nil, fmt.Errorf("failed to parse VLM response: %v", err)
}
if response.Error != "" {
return nil, errors.New(response.Error)
if jsonResponse.Error != "" {
return nil, errors.New(jsonResponse.Error)
}
if len(response.Actions) == 0 {
if len(jsonResponse.Actions) == 0 {
return nil, errors.New("no actions returned from VLM")
}
// normalize actions
// normalize actions using unified function from ui-tars parser
var normalizedActions []Action
for i := range response.Actions {
for i := range jsonResponse.Actions {
// create a new variable, avoid implicit memory aliasing in for loop.
action := response.Actions[i]
if err := normalizeAction(&action); err != nil {
return nil, errors.Wrap(err, "failed to normalize action")
action := jsonResponse.Actions[i]
// Process and normalize arguments (from JSON parser)
processedArgs, err := processActionArguments(action.ActionInputs, size)
if err != nil {
return nil, errors.Wrap(err, "failed to process action arguments")
}
action.ActionInputs = processedArgs
normalizedActions = append(normalizedActions, action)
}
// Convert actions to tool calls using function from parser_ui_tars.go
toolCalls := convertActionsToToolCalls(normalizedActions)
return &PlanningResult{
Actions: normalizedActions,
ActionSummary: response.ActionSummary,
ToolCalls: toolCalls,
ActionSummary: jsonResponse.Summary,
Thought: jsonResponse.Summary,
Content: content,
}, nil
}
// normalizeAction normalizes the coordinates in the action
func normalizeAction(action *Action) error {
switch action.ActionType {
case "click", "drag":
// handle click and drag action coordinates
if startBox, ok := action.ActionInputs["startBox"].(string); ok {
normalized, err := normalizeCoordinates(startBox)
if err != nil {
return fmt.Errorf("failed to normalize startBox: %w", err)
}
action.ActionInputs["startBox"] = normalized
}
if endBox, ok := action.ActionInputs["endBox"].(string); ok {
normalized, err := normalizeCoordinates(endBox)
if err != nil {
return fmt.Errorf("failed to normalize endBox: %w", err)
}
action.ActionInputs["endBox"] = normalized
}
}
return nil
}
// normalizeCoordinates normalizes the coordinates based on the factor
func normalizeCoordinates(coordStr string) (coords []float64, err error) {
// check empty string
if coordStr == "" {
return nil, fmt.Errorf("empty coordinate string")
}
// handle BBox format: <bbox>x1 y1 x2 y2</bbox>
bboxRegex := regexp.MustCompile(`<bbox>(\d+\s+\d+\s+\d+\s+\d+)</bbox>`)
bboxMatches := bboxRegex.FindStringSubmatch(coordStr)
if len(bboxMatches) > 1 {
// Extract space-separated values from inside the bbox tags
bboxContent := bboxMatches[1]
// Split by whitespace
parts := strings.Fields(bboxContent)
if len(parts) == 4 {
coords = make([]float64, 4)
for i, part := range parts {
val, e := strconv.ParseFloat(part, 64)
if e != nil {
return nil, fmt.Errorf("failed to parse coordinate value '%s': %w", part, e)
}
coords[i] = val
}
// 将 val 转换为 [x,y] 坐标
x := (coords[0] + coords[2]) / 2
y := (coords[1] + coords[3]) / 2
return []float64{x, y}, nil
}
}
// handle coordinate string, e.g. "[100, 200]", "(100, 200)"
if strings.Contains(coordStr, ",") {
// remove possible brackets and split coordinates
coordStr = strings.Trim(coordStr, "[]() \t")
// try parsing JSON array
jsonStr := coordStr
if !strings.HasPrefix(jsonStr, "[") {
jsonStr = "[" + coordStr + "]"
}
err = json.Unmarshal([]byte(jsonStr), &coords)
if err != nil {
return nil, fmt.Errorf("failed to parse coordinate string: %w", err)
}
return coords, nil
}
return nil, fmt.Errorf("invalid coordinate string format: %s", coordStr)
}