Update all dependencies and migrate to new Google genai SDK
- Update all Go dependencies to latest versions - Migrate from github.com/google/generative-ai-go/genai to google.golang.org/genai - Fix google.go to use the new SDK API (NewPartFromText, NewContentFromParts, etc.) - Update schema package imports to use the new genai package - Add CLAUDE.md with README maintenance guideline Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
89
google.go
89
google.go
@@ -8,8 +8,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/generative-ai-go/genai"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
type google struct {
|
||||
@@ -23,11 +22,12 @@ func (g google) ModelVersion(modelVersion string) (ChatCompletion, error) {
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g google) requestToChatHistory(in Request, model *genai.GenerativeModel) (*genai.GenerativeModel, *genai.ChatSession, []genai.Part) {
|
||||
res := *model
|
||||
func (g google) requestToContents(in Request) ([]*genai.Content, *genai.GenerateContentConfig) {
|
||||
var contents []*genai.Content
|
||||
var cfg genai.GenerateContentConfig
|
||||
|
||||
for _, tool := range in.Toolbox.functions {
|
||||
res.Tools = append(res.Tools, &genai.Tool{
|
||||
cfg.Tools = append(cfg.Tools, &genai.Tool{
|
||||
FunctionDeclarations: []*genai.FunctionDeclaration{
|
||||
{
|
||||
Name: tool.Name,
|
||||
@@ -38,48 +38,44 @@ func (g google) requestToChatHistory(in Request, model *genai.GenerativeModel) (
|
||||
})
|
||||
}
|
||||
|
||||
if !in.Toolbox.RequiresTool() {
|
||||
res.ToolConfig = &genai.ToolConfig{FunctionCallingConfig: &genai.FunctionCallingConfig{
|
||||
Mode: genai.FunctionCallingAny,
|
||||
if in.Toolbox.RequiresTool() {
|
||||
cfg.ToolConfig = &genai.ToolConfig{FunctionCallingConfig: &genai.FunctionCallingConfig{
|
||||
Mode: genai.FunctionCallingConfigModeAny,
|
||||
}}
|
||||
}
|
||||
|
||||
cs := res.StartChat()
|
||||
|
||||
for i, c := range in.Messages {
|
||||
content := genai.NewUserContent(genai.Text(c.Text))
|
||||
|
||||
for _, c := range in.Messages {
|
||||
var role genai.Role
|
||||
switch c.Role {
|
||||
case RoleAssistant, RoleSystem:
|
||||
content.Role = "model"
|
||||
|
||||
role = genai.RoleModel
|
||||
case RoleUser:
|
||||
content.Role = "user"
|
||||
role = genai.RoleUser
|
||||
}
|
||||
|
||||
var parts []*genai.Part
|
||||
if c.Text != "" {
|
||||
parts = append(parts, genai.NewPartFromText(c.Text))
|
||||
}
|
||||
|
||||
for _, img := range c.Images {
|
||||
if img.Url != "" {
|
||||
// gemini does not support URLs, so we need to download the image and convert it to a blob
|
||||
|
||||
// Download the image from the URL
|
||||
resp, err := http.Get(img.Url)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error downloading image: %v", err))
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check the Content-Length to ensure it's not over 20MB
|
||||
if resp.ContentLength > 20*1024*1024 {
|
||||
panic(fmt.Sprintf("image size exceeds 20MB: %d bytes", resp.ContentLength))
|
||||
}
|
||||
|
||||
// Read the content into a byte slice
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error reading image data: %v", err))
|
||||
}
|
||||
|
||||
// Ensure the MIME type is appropriate
|
||||
mimeType := http.DetectContentType(data)
|
||||
switch mimeType {
|
||||
case "image/jpeg", "image/png", "image/gif":
|
||||
@@ -88,35 +84,21 @@ func (g google) requestToChatHistory(in Request, model *genai.GenerativeModel) (
|
||||
panic(fmt.Sprintf("unsupported image MIME type: %s", mimeType))
|
||||
}
|
||||
|
||||
// Create a genai.Blob using the validated image data
|
||||
content.Parts = append(content.Parts, genai.Blob{
|
||||
MIMEType: mimeType,
|
||||
Data: data,
|
||||
})
|
||||
|
||||
parts = append(parts, genai.NewPartFromBytes(data, mimeType))
|
||||
} else {
|
||||
// convert base64 to blob
|
||||
b, e := base64.StdEncoding.DecodeString(img.Base64)
|
||||
if e != nil {
|
||||
panic(fmt.Sprintf("error decoding base64: %v", e))
|
||||
}
|
||||
|
||||
content.Parts = append(content.Parts, genai.Blob{
|
||||
MIMEType: img.ContentType,
|
||||
Data: b,
|
||||
})
|
||||
parts = append(parts, genai.NewPartFromBytes(b, img.ContentType))
|
||||
}
|
||||
}
|
||||
|
||||
// if this is the last message, we want to add to history, we want it to be the parts
|
||||
if i == len(in.Messages)-1 {
|
||||
return &res, cs, content.Parts
|
||||
}
|
||||
|
||||
cs.History = append(cs.History, content)
|
||||
contents = append(contents, genai.NewContentFromParts(parts, role))
|
||||
}
|
||||
|
||||
return &res, cs, nil
|
||||
return contents, &cfg
|
||||
}
|
||||
|
||||
func (g google) responseToLLMResponse(in *genai.GenerateContentResponse) (Response, error) {
|
||||
@@ -127,15 +109,12 @@ func (g google) responseToLLMResponse(in *genai.GenerateContentResponse) (Respon
|
||||
var set = false
|
||||
if c.Content != nil {
|
||||
for _, p := range c.Content.Parts {
|
||||
switch p.(type) {
|
||||
case genai.Text:
|
||||
choice.Content = string(p.(genai.Text))
|
||||
if p.Text != "" {
|
||||
set = true
|
||||
|
||||
case genai.FunctionCall:
|
||||
v := p.(genai.FunctionCall)
|
||||
choice.Content = p.Text
|
||||
} else if p.FunctionCall != nil {
|
||||
v := p.FunctionCall
|
||||
b, e := json.Marshal(v.Args)
|
||||
|
||||
if e != nil {
|
||||
return Response{}, fmt.Errorf("error marshalling args: %w", e)
|
||||
}
|
||||
@@ -150,8 +129,6 @@ func (g google) responseToLLMResponse(in *genai.GenerateContentResponse) (Respon
|
||||
|
||||
choice.Calls = append(choice.Calls, call)
|
||||
set = true
|
||||
default:
|
||||
return Response{}, fmt.Errorf("unknown part type: %T", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,22 +143,18 @@ func (g google) responseToLLMResponse(in *genai.GenerateContentResponse) (Respon
|
||||
}
|
||||
|
||||
func (g google) ChatComplete(ctx context.Context, req Request) (Response, error) {
|
||||
cl, err := genai.NewClient(ctx, option.WithAPIKey(g.key))
|
||||
cl, err := genai.NewClient(ctx, &genai.ClientConfig{
|
||||
APIKey: g.key,
|
||||
Backend: genai.BackendGeminiAPI,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return Response{}, fmt.Errorf("error creating genai client: %w", err)
|
||||
}
|
||||
|
||||
model := cl.GenerativeModel(g.model)
|
||||
|
||||
_, cs, parts := g.requestToChatHistory(req, model)
|
||||
|
||||
resp, err := cs.SendMessage(ctx, parts...)
|
||||
|
||||
//parts := g.requestToGoogleRequest(req, model)
|
||||
|
||||
//resp, err := model.GenerateContent(ctx, parts...)
|
||||
contents, cfg := g.requestToContents(req)
|
||||
|
||||
resp, err := cl.Models.GenerateContent(ctx, g.model, contents, cfg)
|
||||
if err != nil {
|
||||
return Response{}, fmt.Errorf("error generating content: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user