diff --git a/README.md b/README.md index 5e57964..b983d89 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,68 @@ func main() { } ``` +### Messages Vision example usage: + +```go +package main + +import ( + "errors" + "fmt" + + "github.com/liushuangls/go-anthropic" +) + +func main() { + client := anthropic.NewClient("your anthropic apikey") + + imagePath := "xxx" + imageMediaType := "image/jpeg" + imageFile, err := os.Open(imagePath) + if err != nil { + panic(err) + } + imageData, err := io.ReadAll(imageFile) + if err != nil { + panic(err) + } + + resp, err := client.CreateMessages(context.Background(), anthropic.MessagesRequest{ + Model: anthropic.ModelClaude3Opus20240229, // only claude 3 model can use vision + Messages: []anthropic.Message{ + { + Role: anthropic.RoleUser, + Content: []any{ + anthropic.MessageImageContent{ + Type: "image", + Source: anthropic.MessageImageContentSource{ + Type: "base64", + MediaType: imageMediaType, + Data: imageData, + }, + }, + anthropic.MessageTextContent{ + Type: "text", + Text: "Describe this image.", + }, + }, + }, + }, + MaxTokens: 1000, + }) + if err != nil { + var e *anthropic.APIError + if errors.As(err, &e) { + fmt.Printf("Messages error, type: %s, message: %s", e.Type, e.Message) + } else { + fmt.Printf("Messages error: %v\n", err) + } + return + } + fmt.Println(resp.Content[0].Text) +} +``` + ## Acknowledgments The following project had particular influence on go-anthropic is design. diff --git a/internal/test/sources/ant.jpg b/internal/test/sources/ant.jpg new file mode 100644 index 0000000..37f5c02 Binary files /dev/null and b/internal/test/sources/ant.jpg differ diff --git a/message.go b/message.go index 6e27cb4..2185e87 100644 --- a/message.go +++ b/message.go @@ -42,7 +42,23 @@ func (m *MessagesRequest) SetTopK(k int) { type Message struct { Role string `json:"role"` - Content string `json:"content"` + Content any `json:"content"` // Content can be string, MessageTextContent or MessageImageContent or slice +} + +type MessageTextContent struct { + Type string `json:"type"` + Text string `json:"text"` +} + +type MessageImageContent struct { + Type string `json:"type"` + Source MessageImageContentSource `json:"source"` +} + +type MessageImageContentSource struct { + Type string `json:"type"` + MediaType string `json:"media_type"` + Data any `json:"data"` } type MessagesResponse struct { diff --git a/message_test.go b/message_test.go index f7cad8f..ca75695 100644 --- a/message_test.go +++ b/message_test.go @@ -2,6 +2,7 @@ package anthropic_test import ( "context" + "embed" "encoding/json" "errors" "io" @@ -15,6 +16,9 @@ import ( "github.com/liushuangls/go-anthropic/internal/test/checks" ) +//go:embed internal/test/sources/* +var sources embed.FS + func TestMessages(t *testing.T) { server := test.NewTestServer() server.RegisterHandler("/v1/messages", handleMessagesEndpoint) @@ -75,6 +79,60 @@ func TestMessagesTokenError(t *testing.T) { t.Logf("CreateMessages error: %s", err) } +func TestMessagesVision(t *testing.T) { + server := test.NewTestServer() + server.RegisterHandler("/v1/messages", handleMessagesEndpoint) + + ts := server.AnthropicTestServer() + ts.Start() + defer ts.Close() + + baseUrl := ts.URL + "/v1" + client := anthropic.NewClient( + test.GetTestToken(), + anthropic.WithBaseURL(baseUrl), + ) + + imagePath := "internal/test/sources/ant.jpg" + imageMediaType := "image/jpeg" + imageFile, err := sources.Open(imagePath) + if err != nil { + t.Fatal(err) + } + imageData, err := io.ReadAll(imageFile) + if err != nil { + t.Fatal(err) + } + + resp, err := client.CreateMessages(context.Background(), anthropic.MessagesRequest{ + Model: anthropic.ModelClaude3Opus20240229, + Messages: []anthropic.Message{ + { + Role: anthropic.RoleUser, + Content: []any{ + anthropic.MessageImageContent{ + Type: "image", + Source: anthropic.MessageImageContentSource{ + Type: "base64", + MediaType: imageMediaType, + Data: imageData, + }, + }, + anthropic.MessageTextContent{ + Type: "text", + Text: "Describe this image.", + }, + }, + }, + }, + MaxTokens: 1000, + }) + if err != nil { + t.Fatal(err) + } + t.Logf("CreateMessages resp: %+v", resp) +} + func handleMessagesEndpoint(w http.ResponseWriter, r *http.Request) { var err error var resBytes []byte