How to send a PDF file to Claude.ai with Go SDK

Native PDF support in Go SDK for Anthropic API

PDF Support

Couple days ago Alex Albert from Anthropic announced that they’ve rolled out a PDF support directly in prompt’s message. Until now it was possible to upload a PDF documents only in the Claude’s interface, but wasn’t from the API’s PoV - you had to extract data manually and provide it in the prompt’s payload (the same way as the Anthropic was doing when accepting documents from the UI requests).

As always you can find a code snippets on how to manage this use case directly on the Anthropic website. Unfortunatelly there’re only examples for Shell, Python and TypeScript. If you’re using anthropic-sdk-go for Golang, there’s lack of such examples. That’s the reason for this article.

PDF in Go SDK

Install Anthropic SDK:

go get -u 'github.com/anthropics/anthropic-sdk-go@v0.2.0-alpha.4'

Initialize Anthropic client with the anthropic-beta header:

client := anthropic.NewClient(
    option.WithAPIKey("API_KEY"),
    option.WithHeader("anthropic-beta", "pdfs-2024-09-25"),
)

The API_KEY you can obtain in the Antrhopic Console.

Convert a PDF document into the base64 format string:

file, err := os.Open("./dogs.pdf")
if err != nil {
    panic(fmt.Errorf("failed to open file: %w", err))
}

fileBytes, err := io.ReadAll(file)
if err != nil {
    panic(err)
}

fileEncoded := base64.StdEncoding.EncodeToString(fileBytes)

Send a document altogether with a prompt via SDK:

message, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
    MaxTokens: anthropic.Int(1024),
    Messages: anthropic.F([]anthropic.BetaMessageParam{{
        Role: anthropic.F(anthropic.BetaMessageParamRoleUser),
        Content: anthropic.F(
            []anthropic.BetaContentBlockParamUnion{
                anthropic.BetaTextBlockParam{
                    Text: anthropic.F(content),
                    Type: anthropic.F(anthropic.BetaTextBlockParamTypeText),
                },
                anthropic.BetaBase64PDFBlockParam{
                    Source: anthropic.F(anthropic.BetaBase64PDFSourceParam{
                        Data:      anthropic.F(fileEncoded),
                        MediaType: anthropic.F[anthropic.BetaBase64PDFSourceMediaType](anthropic.BetaBase64PDFSourceMediaTypeApplicationPDF),
                        Type:      anthropic.F[anthropic.BetaBase64PDFSourceType]("base64"),
                    }),
                    Type: anthropic.F(anthropic.BetaBase64PDFBlockTypeDocument),
                },
            },
        ),
    }}),
    Model: anthropic.F(anthropic.ModelClaude3_5Sonnet20241022),
})

Be sure to use the model anthropic.ModelClaude3_5Sonnet20241022!

And that’s it!

Working example

Here’s the full working example:

package main

import (
    "context"
    "encoding/base64"
    "fmt"
    "io"
    "os"

    "github.com/anthropics/anthropic-sdk-go"
    "github.com/anthropics/anthropic-sdk-go/option"
)

func main() {
    client := anthropic.NewClient(
        option.WithAPIKey("API_KEY"),
        option.WithHeader("anthropic-beta", "pdfs-2024-09-25"),
    )

    content := "How many dogs are in the attached document?"

    println("[user]: " + content)

    file, err := os.Open("./dogs.pdf")
    if err != nil {
        panic(fmt.Errorf("failed to open file: %w", err))
    }

    fileBytes, err := io.ReadAll(file)
    if err != nil {
        panic(err)
    }

    fileEncoded := base64.StdEncoding.EncodeToString(fileBytes)

    message, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{
        MaxTokens: anthropic.Int(1024),
        Messages: anthropic.F([]anthropic.BetaMessageParam{{
            Role: anthropic.F(anthropic.BetaMessageParamRoleUser),
            Content: anthropic.F(
                []anthropic.BetaContentBlockParamUnion{
                    anthropic.BetaTextBlockParam{
                        Text: anthropic.F(content),
                        Type: anthropic.F(anthropic.BetaTextBlockParamTypeText),
                    },
                    anthropic.BetaBase64PDFBlockParam{
                        Source: anthropic.F(anthropic.BetaBase64PDFSourceParam{
                            Data:      anthropic.F(fileEncoded),
                            MediaType: anthropic.F[anthropic.BetaBase64PDFSourceMediaType](anthropic.BetaBase64PDFSourceMediaTypeApplicationPDF),
                            Type:      anthropic.F[anthropic.BetaBase64PDFSourceType]("base64"),
                        }),
                        Type: anthropic.F(anthropic.BetaBase64PDFBlockTypeDocument),
                    },
                },
            ),
        }}),
        Model: anthropic.F(anthropic.ModelClaude3_5Sonnet20241022),
    })
    if err != nil {
        panic(err)
    }

    println("[assistant]: " + message.Content[0].Text + message.StopSequence)
}

The output should looks like this:

➜  pdf2claude git:(main) ✗ go run main.go
[user]: How many dogs are in the attached document?
[assistant]: In this document, there are 5 dogs shown in black and white silhouette/portrait style. The breeds appear to be:

1. What appears to be a Jack Russell Terrier or similar mixed breed (top left)
2. An Australian Shepherd or similar long-haired herding dog (top right)
3. A French Bulldog (bottom left)
4. What looks like a Jack Russell Terrier or similar terrier breed (bottom middle)
5. A Chihuahua (bottom right)

The images are stylized in a high contrast black and white design, showing distinctive features of each breed.

The complete example you can find here on the GitHub.

Sources