mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-25 01:59:52 +08:00
fix: chat with screenshot
This commit is contained in:
@@ -1 +1 @@
|
|||||||
v5.0.0-beta-2505211805
|
v5.0.0-beta-2505212235
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/cloudwego/eino/schema"
|
"github.com/cloudwego/eino/schema"
|
||||||
"github.com/httprunner/httprunner/v5/uixt/ai"
|
"github.com/httprunner/httprunner/v5/uixt/ai"
|
||||||
"github.com/httprunner/httprunner/v5/uixt/option"
|
"github.com/httprunner/httprunner/v5/uixt/option"
|
||||||
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
@@ -174,24 +175,46 @@ func (c *Chat) handleToolCalls(ctx context.Context, toolCalls []schema.ToolCall)
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format tool result
|
// Format tool result, append message to history
|
||||||
resultStr := ""
|
renderStr := ""
|
||||||
if result != nil && len(result.Content) > 0 {
|
if result != nil && len(result.Content) > 0 {
|
||||||
for _, item := range result.Content {
|
for _, item := range result.Content {
|
||||||
resultStr += fmt.Sprintf("%v\n", item)
|
if contentMap, ok := item.(mcp.TextContent); ok {
|
||||||
|
renderStr += contentMap.Text + "\n"
|
||||||
|
toolMsg := &schema.Message{
|
||||||
|
Role: schema.Tool,
|
||||||
|
ToolCallID: toolCall.ID,
|
||||||
|
Content: contentMap.Text,
|
||||||
|
}
|
||||||
|
c.planner.History().Append(toolMsg)
|
||||||
|
} else if contentMap, ok := item.(mcp.ImageContent); ok {
|
||||||
|
renderStr += "<data:image/base64...>\n" // base64-encoded image data
|
||||||
|
toolMsg := &schema.Message{
|
||||||
|
Role: schema.Tool,
|
||||||
|
ToolCallID: toolCall.ID,
|
||||||
|
MultiContent: []schema.ChatMessagePart{
|
||||||
|
{
|
||||||
|
Type: schema.ChatMessagePartTypeImageURL,
|
||||||
|
ImageURL: &schema.ChatMessageImageURL{
|
||||||
|
URL: contentMap.Data,
|
||||||
|
MIMEType: contentMap.MIMEType,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c.planner.History().Append(toolMsg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resultStr = fmt.Sprintf("%+v", result)
|
renderStr = fmt.Sprintf("%+v", result)
|
||||||
|
toolMsg := &schema.Message{
|
||||||
|
Role: schema.Tool,
|
||||||
|
ToolCallID: toolCall.ID,
|
||||||
|
Content: renderStr,
|
||||||
|
}
|
||||||
|
c.planner.History().Append(toolMsg)
|
||||||
}
|
}
|
||||||
c.renderContent("Tool Result", resultStr)
|
c.renderContent("Tool Result", renderStr)
|
||||||
|
|
||||||
// Add tool result to history
|
|
||||||
toolMsg := &schema.Message{
|
|
||||||
Role: schema.Tool,
|
|
||||||
Content: resultStr,
|
|
||||||
ToolCallID: toolCall.ID,
|
|
||||||
}
|
|
||||||
c.planner.History().Append(toolMsg)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,14 +95,12 @@ func GetModelConfig(modelType option.LLMServiceType) (*ModelConfig, error) {
|
|||||||
"env %s missed", EnvModelName)
|
"env %s missed", EnvModelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
maxTokens := 4096
|
|
||||||
temperature := float32(0.7)
|
temperature := float32(0.7)
|
||||||
modelConfig := &openai.ChatModelConfig{
|
modelConfig := &openai.ChatModelConfig{
|
||||||
BaseURL: openaiBaseURL,
|
BaseURL: openaiBaseURL,
|
||||||
APIKey: openaiAPIKey,
|
APIKey: openaiAPIKey,
|
||||||
Model: modelName,
|
Model: modelName,
|
||||||
Timeout: defaultTimeout,
|
Timeout: defaultTimeout,
|
||||||
MaxTokens: &maxTokens,
|
|
||||||
Temperature: &temperature,
|
Temperature: &temperature,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,15 @@ func logRequest(messages ConversationHistory) {
|
|||||||
func logResponse(message *schema.Message) {
|
func logResponse(message *schema.Message) {
|
||||||
logger := log.Info().Str("role", string(message.Role)).
|
logger := log.Info().Str("role", string(message.Role)).
|
||||||
Str("content", message.Content)
|
Str("content", message.Content)
|
||||||
|
|
||||||
|
var toolCalls []string
|
||||||
|
if len(message.ToolCalls) > 0 {
|
||||||
|
for _, toolCall := range message.ToolCalls {
|
||||||
|
toolCalls = append(toolCalls, toolCall.Function.Name)
|
||||||
|
}
|
||||||
|
logger = logger.Strs("tool_calls", toolCalls)
|
||||||
|
}
|
||||||
|
|
||||||
if message.ResponseMeta != nil {
|
if message.ResponseMeta != nil {
|
||||||
logger = logger.Str("finish_reason", message.ResponseMeta.FinishReason)
|
logger = logger.Str("finish_reason", message.ResponseMeta.FinishReason)
|
||||||
// Log usage statistics
|
// Log usage statistics
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ func saveScreenShot(raw *bytes.Buffer, screenshotPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error) {
|
func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error) {
|
||||||
|
rawSize := raw.Len()
|
||||||
// decode image from buffer
|
// decode image from buffer
|
||||||
img, format, err := image.Decode(raw)
|
img, format, err := image.Decode(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -312,6 +313,10 @@ func compressImageBuffer(raw *bytes.Buffer) (compressed *bytes.Buffer, err error
|
|||||||
return nil, fmt.Errorf("unsupported image format: %s", format)
|
return nil, fmt.Errorf("unsupported image format: %s", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compressedSize := buf.Len()
|
||||||
|
log.Debug().Int("rawSize", rawSize).Int("compressedSize", compressedSize).
|
||||||
|
Msg("compress image buffer")
|
||||||
|
|
||||||
// return compressed image buffer
|
// return compressed image buffer
|
||||||
return &buf, nil
|
return &buf, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user