/* https://docs.anthropic.com/zh-CN/api/claude-on-vertex-ai MODEL_ID=claude-3-5-sonnet@20240620 REGION=us-east5 PROJECT_ID=MY_PROJECT_ID curl \ -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ https://$LOCATION-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/anthropic/models/${MODEL_ID}:streamRawPredict \ -d '{ "anthropic_version": "vertex-2023-10-16", "messages": [{ "role": "user", "content": "介绍一下你自己" }], "stream": true, "max_tokens": 4096 }' quota: https://console.cloud.google.com/iam-admin/quotas?hl=zh-cn */ package vertexai import ( "crypto/rsa" "crypto/x509" "encoding/json" "encoding/pem" "fmt" "net/http" "net/url" "os" "time" "github.com/golang-jwt/jwt" ) // json文件存储在ApiKey.ApiSecret中 type VertexSecretKey struct { Type string `json:"type"` ProjectID string `json:"project_id"` PrivateKeyID string `json:"private_key_id"` PrivateKey string `json:"private_key"` ClientEmail string `json:"client_email"` ClientID string `json:"client_id"` AuthURI string `json:"auth_uri"` TokenURI string `json:"token_uri"` AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"` ClientX509CertURL string `json:"client_x509_cert_url"` UniverseDomain string `json:"universe_domain"` } type VertexClaudeModel struct { VertexName string Region string } var VertexClaudeModelMap = map[string]VertexClaudeModel{ "claude-3-opus": { VertexName: "claude-3-opus@20240229", Region: "us-east5", }, "claude-3-sonnet": { VertexName: "claude-3-sonnet@20240229", Region: "us-central1", // Region: "asia-southeast1", }, "claude-3-haiku": { VertexName: "claude-3-haiku@20240307", Region: "us-central1", // Region: "europe-west4", }, "claude-3-opus-20240229": { VertexName: "claude-3-opus@20240229", Region: "us-east5", }, "claude-3-sonnet-20240229": { VertexName: "claude-3-sonnet@20240229", Region: "us-central1", // Region: "asia-southeast1", }, "claude-3-haiku-20240307": { VertexName: "claude-3-haiku@20240307", Region: "us-central1", // Region: "europe-west4", }, "claude-3-5-sonnet": { VertexName: "claude-3-5-sonnet@20240620", Region: "us-east5", // Region: "europe-west1", }, "claude-3-5-sonnet-20240620": { VertexName: "claude-3-5-sonnet@20240620", Region: "us-east5", // Region: "europe-west1", }, "claude-3-5-sonnet-20241022": { VertexName: "claude-3-5-sonnet-v2@20241022", Region: "us-east5", }, "claude-3-5-sonnet-latest": { //可能没有容量,指向老模型 VertexName: "claude-3-5-sonnet@20240620", Region: "us-east5", }, } func createSignedJWT(email, privateKeyPEM string) (string, error) { block, _ := pem.Decode([]byte(privateKeyPEM)) if block == nil { return "", fmt.Errorf("failed to parse PEM block containing the private key") } privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return "", err } rsaKey, ok := privateKey.(*rsa.PrivateKey) if !ok { return "", fmt.Errorf("not an RSA private key") } now := time.Now() claims := jwt.MapClaims{ "iss": email, "aud": "https://www.googleapis.com/oauth2/v4/token", "iat": now.Unix(), "exp": now.Add(10 * time.Minute).Unix(), "scope": "https://www.googleapis.com/auth/cloud-platform", } token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims) return token.SignedString(rsaKey) } func exchangeJwtForAccessToken(signedJWT string) (string, error) { authURL := "https://www.googleapis.com/oauth2/v4/token" data := url.Values{} data.Set("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer") data.Set("assertion", signedJWT) client := http.DefaultClient if os.Getenv("LOCAL_PROXY") != "" { if proxyUrl, err := url.Parse(os.Getenv("LOCAL_PROXY")); err == nil { client.Transport = &http.Transport{Proxy: http.ProxyURL(proxyUrl)} } } resp, err := client.PostForm(authURL, data) if err != nil { return "", err } defer resp.Body.Close() var result map[string]interface{} if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { return "", err } accessToken, ok := result["access_token"].(string) if !ok { return "", fmt.Errorf("access token not found in response") } return accessToken, nil } // 获取gcloud auth token func GcloudAuth(ClientEmail, PrivateKey string) (string, error) { signedJWT, err := createSignedJWT(ClientEmail, PrivateKey) if err != nil { return "", err } token, err := exchangeJwtForAccessToken(signedJWT) if err != nil { return "", fmt.Errorf("Invalid jwt token: %v\n", err) } return token, nil }