Giter VIP home page Giter VIP logo

generative-ai-go's Introduction

Go SDK for Google Generative AI

Go Go Reference

This SDK enables developers to use Google's state-of-the-art generative AI models (like Gemini) to build AI-powered features and applications. It supports use cases like:

  • Generate text from text-only input
  • Generate text from text-and-images input (multimodal)
  • Build multi-turn conversations (chat)
  • Embedding

Try out the API

  1. Obtain an API key to use with the Google AI SDKs.
  2. Add the SDK to your module with go get github.com/google/generative-ai-go
  3. Follow the examples

Documentation

The documentation of the Google AI Go SDK is on pkg.go.dev

Find complete documentation for the Google AI SDKs and the Gemini model in the Google documentation: https://ai.google.dev/docs

For a list of the supported models and their capabilities, see https://ai.google.dev/models/gemini

Getting help

For general Gemini API questions (not specific to the Go SDK), check out the public discussion forum.

For questions specific to the Go SDK, create a new issue and tag it with a question label.

Contributing

See Contributing for more information on contributing to the Google AI Go SDK.

License

The contents of this repository are licensed under the Apache License, version 2.0.

generative-ai-go's People

Contributors

andersonjoseph avatar dbudworth avatar dependabot[bot] avatar eliben avatar fredsa avatar google-admin avatar jba avatar kasugamirai avatar markdaoust avatar ymodak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

generative-ai-go's Issues

Error 400: Unsupported MIME type when trying to upload files to GenerateContent (.docx)

Description of the bug:

Using the below snippet getting error while trying to upload files to generate content. Using model gemini-1.5-flash

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/google/generative-ai-go/genai"
	"github.com/joho/godotenv"
	"google.golang.org/api/option"
)

func main() {
	fmt.Println("Hello World!")

	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env key")
	}
	// Retrieve API key
	api_key := os.Getenv("GEMINI_API_KEY")
	// Initialize Gemini client
	ctx := context.Background()
	client, err := genai.NewClient(ctx, option.WithAPIKey(api_key))
	if err != nil {
		log.Fatal("Error Creatign Client: ", err)
	}
	defer client.Close()

	// Use Client.UploadFile to Upload a file to the service.
	// Pass it an io.Reader.
	f, err := os.Open("files/ResumeSample03.docx")
	if err != nil {
		log.Fatal("File Opening Error: ", err)
	}
	defer f.Close()
	// You can choose a name, or pass the empty string to generate a unique one.
	file, err := client.UploadFile(ctx, "", f, nil)
	if err != nil {
		log.Fatal("File Uploading Error: :", err)
	}

	// Connect to Gemini model
	model := client.GenerativeModel("gemini-1.5-flash")

	resp, err := model.GenerateContent(ctx, genai.FileData{URI: file.URI})
	if err != nil {
		log.Fatal("Error Getting Response: ", err)
	}

	printResponse(resp)
}

func printResponse(resp *genai.GenerateContentResponse) {
	for _, cand := range resp.Candidates {
		if cand.Content != nil {
			for _, part := range cand.Content.Parts {
				fmt.Println(part)
			}
		}
	}
	fmt.Println("---")
}

Actual vs expected behavior:

Getting Below errors.

For pdf format
googleapi: Error 400: Unsupported MIME type: application/pdf

For docx format.
googleapi: Error 400: Unsupported MIME type: application/zip

Any other information you'd like to share?

No response

Can I only adjust 4 elements of safety settings for now?

According to the official documentation, the type HarmCategory says These categories cover various kinds of harms that developers may wish to adjust. and it enumerates 11 categories like below.

// HarmCategory specifies the category of a rating.
//
// These categories cover various kinds of harms that developers
// may wish to adjust.
type HarmCategory int32

const (
	// HarmCategoryUnspecified means category is unspecified.
	HarmCategoryUnspecified HarmCategory = 0
	// HarmCategoryDerogatory means negative or harmful comments targeting identity and/or protected attribute.
	HarmCategoryDerogatory HarmCategory = 1
	// HarmCategoryToxicity means content that is rude, disrepspectful, or profane.
	HarmCategoryToxicity HarmCategory = 2
	// HarmCategoryViolence means describes scenarios depictng violence against an individual or group, or
	// general descriptions of gore.
	HarmCategoryViolence HarmCategory = 3
	// HarmCategorySexual means contains references to sexual acts or other lewd content.
	HarmCategorySexual HarmCategory = 4
	// HarmCategoryMedical means promotes unchecked medical advice.
	HarmCategoryMedical HarmCategory = 5
	// HarmCategoryDangerous means dangerous content that promotes, facilitates, or encourages harmful acts.
	HarmCategoryDangerous HarmCategory = 6
	// HarmCategoryHarassment means harasment content.
	HarmCategoryHarassment HarmCategory = 7
	// HarmCategoryHateSpeech means hate speech and content.
	HarmCategoryHateSpeech HarmCategory = 8
	// HarmCategorySexuallyExplicit means sexually explicit content.
	HarmCategorySexuallyExplicit HarmCategory = 9
	// HarmCategoryDangerousContent means dangerous content.
	HarmCategoryDangerousContent HarmCategory = 10
)

However, currently, I can only adjust 4 parameters among them as below, not corresponding to the annotation in the source code or an explanation of the SDK document, and I receive a 400 error if I add more adjustments for other defined categories in HarmCategory int32 like genai.HarmCategoryMedical. Can I get some explanation or advice about this? I wonder if I misunderstood about this feature.

model.SafetySettings = []*genai.SafetySetting{
		{
			Category:  genai.HarmCategoryDangerousContent,
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategoryHarassment,
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategoryHateSpeech,
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategorySexuallyExplicit,
			Threshold: genai.HarmBlockNone,
		},
	}

Thanks is advance!

Difference between cs.SendMessage() and cs.SendMessageStream()

Hello
I noticed that the output results in the two methods are different. In this case, the normal method returns the full result, and the stream method performs 2-3 iterations and fails with an error (when resp.Candidates[0].Content = nil).

Example of initialization:

`gen_ctx = context.Background()
gen_client, _ = genai.NewClient(gen_ctx, option.WithAPIKey(Cfg.GeminiKey))
gen_TextModel = gen_client.GenerativeModel("gemini-1.0-pro")

text := "напиши первые 3000 сиволов из библии"

// 1 type
cs := gen_TextModel.StartChat()
resp, err := cs.SendMessage(gen_ctx, genai.Text(text))

// 2 type
cs := gen_TextModel.StartChat()
iter := cs.SendMessageStream(gen_ctx, genai.Text(text))`

Please tell me, is this normal behavior or can I somehow fix it so that the capabilities of the streaming method are not inferior to the usual one?

Could you please add support for BatchEmbedContents

I see BatchEmbedContents is available on the generated veneer client v0.3.0 already.

I'm just not sure what parameter would be optimal for the "parts..." for the batch API. Let me know and I'll create a PR since it looks straightforward

Issue with `SetCandidateCount` Method - Only Receiving One Candidate

Description of the bug:

When using the SetCandidateCount method to set the number of candidates to 2 for the gemini-1.5-flash-latest model, the response still only returns 1 candidate. This issue occurs consistently and is not aligned with the expected behavior of the API.

Steps to reproduce:

  1. Create a client using the genai.NewClient method.
  2. Set the candidate count to 2 using model.SetCandidateCount(2).
  3. Start a chat session and send a message to the model.
  4. Observe the number of candidates in the response.

Code snippet:

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/joho/godotenv"
    "google.golang.org/api/option"
    "github.com/google/generative-ai-go/genai"
)

const (
    defaultModel  = "gemini-1.5-flash-latest"
    numCandidates = 2
)

func main() {
    // Load environment variables from the .env file.
    err := godotenv.Load()
    if err != nil {
        log.Fatalf("Error loading .env file: %v", err)
    }

    // Get the API key from the environment variable.
    apiKey := os.Getenv("GOOGLE_API_KEY")
    if apiKey == "" {
        log.Fatal("GOOGLE_API_KEY environment variable is not set")
    }

    ctx := context.Background()
    client, err := genai.NewClient(ctx, option.WithAPIKey(apiKey))
    if err != nil {
        log.Fatalf("Failed to create client: %v", err)
    }
    defer client.Close()

    model := client.GenerativeModel(defaultModel)
    model.SetTemperature(0)
    model.SetCandidateCount(numCandidates) 

    // Log the model settings
    fmt.Printf("Model: %s\nTemperature: %.1f\nCandidates: %d\n", defaultModel, 0.0, numCandidates)

    // Create a chat session.
    session := model.StartChat()

    // Send a message and get a response.
    msg := "Tell me a joke."
    resp, err := session.SendMessage(ctx, genai.Text(msg))
    if err != nil {
        log.Fatalf("Failed to send message: %v", err)
    }

    // Log the number of candidates received
    fmt.Printf("Received %d candidates\n", len(resp.Candidates))

    // Ensure we have the correct number of candidates.
    if len(resp.Candidates) != numCandidates {
        log.Fatalf("Expected %d candidates, got %d", numCandidates, len(resp.Candidates))
    }

    // Print the responses.
    for i, candidate := range resp.Candidates {
        fmt.Printf("Candidate %d: %s\n", i+1, candidate.Content)
    }
}

Actual vs expected behavior:

Expected: The response should contain 2 candidates as specified by SetCandidateCount.
Actual: The response only contains 1 candidate.

Any other information you'd like to share?

The issue occurs consistently, regardless of the input message or context.
This behavior may indicate a potential bug in the SetCandidateCount method or an API configuration issue.

How to fetch textual data from *genai.GenerateContentResponse - Parts interface

I am writing a function which will take *genai.GenerateContentResponse and return the textual data generated.

func getFirstResponse(resp *genai.GenerateContentResponse) {
for _, value := range resp.Candidates[0].Content.Parts {
// each value is a Part interface but I am confused how can I use the textual part it contains
// I went through the github code and couldn't found out anything significant
}
}

session.SendMessage without any parts.

Description of the feature request:

Ability to "complete" a history/session without needing to specify the last message.

What problem are you trying to solve with this feature?

Now you would need to specify the last message and insert it into in SendMessage().
Seems pointless if you already have the entire history set. And SendMessage appends it to the history in the end anyway.

unsure how the api handles the requests as any message in the SendMessage gets given the user role.
But you are expected to pass the result of function calls through here. Have not seen it impacted.

Any other information you'd like to share?

adding a check if any parts are send with seems to "resolve" the issue.
Normally it returns a 400 when no parts are send, possibly due to an empty user part in the request.

// SendMessage sends a request to the model as part of a chat session.
func (cs *ChatSession) SendMessage(ctx context.Context, parts ...Part) (*GenerateContentResponse, error) {
	// Call the underlying client with the entire history plus the argument Content.

        // ! adding check before adding new content
	if len(parts) > 0 {
		cs.History = append(cs.History, newUserContent(parts))
	}
	req, err := cs.m.newGenerateContentRequest(cs.History...)

How can I manage the safety settings? (Question)

Unlike the other parameters, the safety settings parameter doesn't have it's own method in *genai.GenerativeModel so I don't really understand how I should configure that.
I tried the following code but ended up with this error: googleapi: Error 400: * GenerateContentRequest.safety_settings[0]: element predicate failed: $.category in (HarmCategory.HARM_CATEGORY_HATE_SPEECH, HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, HarmCategory.HARM_CATEGORY_HARASSMENT)

model = gemini.GenerativeModel("gemini-pro")
	model.SafetySettings = []*genai.SafetySetting{
		{
			Category:  genai.HarmCategory(1),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(2),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(3),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(4),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(5),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(6),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(7),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(8),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(9),
			Threshold: genai.HarmBlockNone,
		},
		{
			Category:  genai.HarmCategory(10),
			Threshold: genai.HarmBlockNone,
		},
	}

SetTemperature() followed by Info()

Description of the bug:

I set an arbitrary temperature using SetTemperature then query model information with Info but I only see "1.0" returned. Is Info() only returning default model values?

Actual vs expected behavior:

model.SetTemperature(float32(*tempVal))
followed by
info, err := model.Info(ctx) where info.Tempterature always returns 1

Any other information you'd like to share?

No response

[Bug] Authentication Error with CountTokens in generative-ai-go Client Library

Description

When using the CountTokens function from the generative-ai-go client library, I am experiencing an authentication error. This occurs even though my API key is valid and works as expected for other interactions with the AI, such as sending and receiving chat messages.

Error Message

The error message I receive is as follows:

oauth2: "invalid_grant" "reauth related error (invalid_rapt)"

Steps to Reproduce

  1. Initialize a new generative AI client using a valid API key.
  2. Call the CountTokens function with a sample input string.
  3. Observe the authentication error.

Expected Behavior

The CountTokens function should return the number of tokens in the input string without any authentication issues, similar to other functions in the library that interact with the AI.

Actual Behavior

The function returns an authentication error, indicating an issue with the token grant or reauthentication process.

Code Snippet

Here is the code snippet I am using to count tokens:

func CountTokens(apiKey, input string) (int, error) {
	ctx := context.Background()
	client, err := genai.NewClient(ctx, option.WithAPIKey(apiKey))
	if err != nil {
		return 0, err
	}
	defer client.Close()

	model := client.GenerativeModel(ModelAi)

	resp, err := model.CountTokens(ctx, genai.Text(input))
	if err != nil {
		return 0, err
	}

	return int(resp.TotalTokens), nil
}

Screenshots

image

  • Error message received:

image

How to pass location to the client?

Disclaimer: I'm only dabbling with golang so likely there's something obvious missing. Apologies for this. However, I was not able to find much information through traditional search, nor using most LLMs.

Question

How can I specify a location when instantiating the Client? The vertexai/genai seems to allow the location as one of the parameters. I'm guessing that with your client, it needs to come through one of the Options, maybe the Endpoint? If so, what's the endpoint? I tried https://{region}-aiplatform.googleapis.com per Vertex AI doc, though, now that I'm thinking about it, I'm not sure if that's the same service (is it?).

As you might tell, I have very little experience with GCP. If there's a canonical way on setting the location on the client/session then I'm keen learning.

connect error

I try to use python api to utility gemini model , but it give connection error like below:
image

the complete error info:
Retrying langchain_google_genai.chat_models._chat_with_retry.<locals>._chat_with_retry in 2.0 seconds as it raised RetryError: Deadline of 60.0s exceeded while calling target function, last exception: 503 failed to connect to all addresses; last error: UNAVAILABLE: ipv4:142.251.43.10:443: Failed to connect to remote host: FD shutdown.

ps: I using a proxy to send request.

proto: (line 34:3): unknown field "usageMetadata"

Description of the bug:

When using the StartChat() and SendMessage() API, one gets the "proto: (line 34:3): unknown field "usageMetadata"
" error.

You can reproduce the problem with:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/google/generative-ai-go/genai"
	"google.golang.org/api/option"
)

func main() {
	ctx := context.Background()
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()
	model := client.GenerativeModel("gemini-1.0-pro")
	cs := model.StartChat()

	msg := "hello"
	fmt.Printf("== Me: %s\n== Model:\n", msg)
	_, err = cs.SendMessage(ctx, genai.Text(msg))
	if err != nil {
		log.Fatal(err)
	}
}

Actual vs expected behavior:

Actual behavior:
The SDK returns an error

Expected behavior:
No errors from the SDK.

Any other information you'd like to share?

Maybe the underlying problem has to do with a new field added to https://github.com/googleapis/googleapis/blob/master/google/ai/generativelanguage/v1beta/generative_service.proto?

The error message suggests it may be a new field named "usageMetadata" on the "GenerateContentResponse" message. I don't see it referenced in the generative_service.proto, so maybe it's not published yet? I am reporting it here mainly because it surfaced through the Go SDK.

Issue with custom proxy client and required API key

Hi guys!
I've tried to setting up a proxy client following this previous issue suggestions by passing a custom http client with the proxy address and api key configured to the genai.NewClient, but I've got an error:

You need an API key to use this client.
Visit https://ai.google.dev to get one, put it in an environment variable like GEMINI_API_KEY,
then pass it as an option:
    genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
(If you're doing that already, then maybe the environment variable is empty or unset.)
Import the option package as "google.golang.org/api/option".

After looking through the source I've noticed a change made 2 months ago that makes the api key always required in the options struct. It ignores that the custom client is setting the api key in the RoundTrip method.

As commented in the previous issue here, there's a problem if you use both fields (option.WithAPIKey and option.WithHTTPClient) generating an error googleapi: Error 403:.

Is there any other way to configure a proxy client, or is this a bug?

Who can help me? How should I set up the proxy?

"I really want to use this SDK package and don't want to implement the API interface myself anymore. I'm begging the experts, please teach me how to set up the proxy. Thank you."

this's my code

var Proxy = "http://127.0.0.1:7890"

func main() {
	test2(SetProxy())
}

func test2(c *http.Client) {
	ctx := context.Background()
	// Access your API key as an environment variable (see "Set up your API key" above)
	client, err := genai.NewClient(ctx, option.WithHTTPClient(c), option.WithAPIKey("AIzaSyBMwViEE"))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	// For text-only input, use the gemini-pro model
	model := client.GenerativeModel("gemini-pro")
	resp, err := model.GenerateContent(ctx, genai.Text("你好"))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp)
}

// SetAiClientSteam 设置ai 代理
func SetProxy() *http.Client {
	var transport *http.Transport
	if Proxy != "" {
		proxyURL, err := url.Parse(Proxy)
		if err != nil {
			fmt.Println("出现错误:" + err.Error())
			return nil
		}
		transport = &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	} else {
		transport = &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
	}
	client := &http.Client{Transport: transport}
	return client
}

the response is
2023/12/17 21:19:52 googleapi: Error 403: Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API. exit status 1

and i can get response by postman (use proxy)
image

Null Pointer Exception in addToHistory

A null pointer exception occurs in the addToHistory method of the ChatSession struct. This issue is triggered when the Content field of a Candidate struct's first element is nil, and the method attempts to access its Role property (c.Role).

//  github.com/google/[email protected]/genai/client.go:183
func (iter *GenerateContentResponseIterator) Next() (*GenerateContentResponse, error) {
...
    resp, err := iter.sc.Recv()
    iter.err = err
    if err == io.EOF {
        if iter.cs != nil && iter.merged != nil {
            iter.cs.addToHistory(iter.merged.Candidates)
        }
        return nil, iterator.Done
    }
...
}

//  cloud.google.com/go/[email protected]/generativelanguage/apiv1/generative_client.go:746
func (c *streamGenerateContentRESTClient) Recv() (*generativelanguagepb.GenerateContentResponse, error) {
    if err := c.ctx.Err(); err != nil {
        defer c.stream.Close()
        return nil, err
    }
    msg, err := c.stream.Recv()    // msg.Candidates[0].Content is nil
    if err != nil {
        defer c.stream.Close()
        return nil, err
    }
    res := msg.(*generativelanguagepb.GenerateContentResponse)
    return res, nil
}

// Cause the following function to throw a NullPointerException
// github.com/google/[email protected]/genai/chat.go:63
func (cs *ChatSession) addToHistory(cands []*Candidate) bool {
	if len(cands) > 0 {
		c := cands[0].Content // c is nil
		c.Role = roleModel 
		cs.History = append(cs.History, c)
		return true
	}
	return false
}

截屏2024-04-26 10 32 52

type Tool example fails

Description of the bug:

https://pkg.go.dev/github.com/google/[email protected]/genai#example-Tool

OS: Windows 10
Go: 1.22.4

at this line:
res, err := session.SendMessage(ctx, genai.Text("What is the weather like in New York?"))
if err != nil {
log.Fatal(err)
}

returns "googleapi: Error 400: exit status 1"

Actual vs expected behavior:

no error

Any other information you'd like to share?

Confirmed same GOOGLE_API_KEY working on a Python code.
https://colab.research.google.com/github/google/generative-ai-docs/blob/main/site/en/gemini-api/docs/function-calling/python.ipynb

Problems running protoveneer

Description of the bug:

The instructions in genai/client.go for running protoveneer are difficult to repdoruce.

First, installing protoveneer as instructed fails:

$ go install cloud.google.com/go/internal/protoveneer/cmd/protoveneer@latest
go: cloud.google.com/go/internal/protoveneer/cmd/protoveneer@latest: module cloud.google.com/go@latest found (v0.113.0), but does not contain package cloud.google.com/go/internal/protoveneer/cmd/protoveneer

Also, the path ../../../googleapis/google-cloud-go/ai/generativelanguage/apiv1beta/generativelanguagepb assumes a specific local directory structure. It should be encoded in a way that's easier to reproduce on different machines.

(other issues resolved)

Any way to add System Prompt like OpenAI

We(current org) are building an aggregation platform which has number of genAI models and want to to in a way standardise our chat model and system prompt is an important part of it, so just wanted to check is there any way I can add something like a system prompt

When is available for mp3/mp4 support?

Description of the feature request:

When is available for mp3/mp4 support?

What problem are you trying to solve with this feature?

No response

Any other information you'd like to share?

No response

Can PDF data be passed as a Blob

This is not a bug. I am just wondering if PDF buffer can be passed?

part := genai.Blob{
		MIMEType: "application/pdf",
		Data:     pdfBytes,
	}

When trying to do so, I get following error:

googleapi: Error 400: Request contains an invalid argument.

Thanks for your help

can't set proxy

I want to set a proxy client. but it didn't work.
i need U help
like: client, _ = genai.NewClient(g.ctx, option.WithAPIKey("AIzaSyBwDX0zNmutFMwViEE"), option.WithHTTPClient(httpclientByProxy))

"httpclientByProxy" is a *httpclient

transport := &http.Transport{
		Proxy: http.ProxyURL(proxyURL),
	}
	client := &http.Client{
		Transport: transport,
	}

ACCESS_TOKEN_SCOPE_INSUFFICIENT error

I've copied the code directly from the quicstart-guide for golang

package main

import (
	"context"
	"fmt"
	"github.com/google/generative-ai-go/genai"
	"google.golang.org/api/option"
	"log"
	"os"
)

func main() {
	ctx := context.Background()
	// Access your API key as an environment variable (see "Set up your API key" above)
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("AIzaSyB1Nx3jxDqWOflvh---JnyEndKx3kWYwefbvw")))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	// For text-only input, use the gemini-pro model
	model := client.GenerativeModel("gemini-pro")
	resp, err := model.GenerateContent(ctx, genai.Text("Write a story about a magic backpack."))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp)
}

this is identical with the one one shown i guide throws this error

error details: name = ErrorInfo 
reason = ACCESS_TOKEN_SCOPE_INSUFFICIENT 
domain = googleapis.com 
metadata = map[method:google.ai.generativelanguage.v1.GenerativeService.GenerateContent service:generativelanguage.googleapis.com]
exit status 1

but this runs fine if I try this in python

import google.generativeai as genai

genai.configure(api_key="AIzaSyA25dW4h_UcxwgWkOXeq2zpOqeudqdces3XMU")

for m in genai.list_models():
  if 'generateContent' in m.supported_generation_methods:
    print(m.name)


model = genai.GenerativeModel('gemini-pro')
response = model.generate_content("What is the meaning of life?")

print(response.text)

i don't know why is this happening if there was some prereqvisits is should have been mentioned in the quick-start guide if anyone can give an solution please help

invalid memory address or nil pointer dereference while `FileIterator.Next()`

Description of the bug:

(affected by v0.14.0)

Listing uploaded video files with FileIterator.Next() leads to 'invalid memory address or nil pointer deference' error.

Actual vs expected behavior:

Expected:
It should iterate through uploaded video files,

Actual:
but when calling Next(), it panics with 'invalid memory address or nil pointer deference' error.

Any other information you'd like to share?

f.Metadata = nil
if p == nil || p.Metadata == nil {
return
}
if f.Metadata.Video != nil {

f.Metadata is set to nil here,

so subsequent access to it (f.Metadata.Video) leads to nil pointer dereference.

Nil Pointer Exception in CitationSources slice

Dear maintainer,

after digging deeper to the library, i found out that all of the source is generated by protoc-gen-go and has the label do not edit.

While I don't have access to the real source code from citation.pb.go , i saw that there's a potential nil pointer error based on the generated code. For example in apiv1/generativelanguagepb/citation.pb.go line 81-86

func (x *CitationMetadata) GetCitationSources() []*CitationSource {
	if x != nil {
		return x.CitationSources
	}
	return nil
}

instead of returning nil, the slice need to be initialized first to avoid nil pointer exception of the CitationMetadata struct.

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.32.0
// 	protoc        v4.25.2
// source: google/ai/generativelanguage/v1/citation.proto

I'm still learning about pointers, and led to a question. Does the nil handling implemented at clientside (as user), at the library level, at the protoc-gen-go, at the compiler (go programming it self), or at go-pls (adding warning ?

continuing from PR #59

Best Regards,

Support for context caching

Description of the feature request:

I'm excited to use the new Gemini context caching feature from Golang. Is this planned to be added to this SDK? It look like it was added to the Python and JS SDKs only a few days ago, so I'm curious if/when it will be added to this project.

Also, I'm curious why this project is in the google organization and the others are in the google-gemini organization? Is this a quasi-supported SDK? Either way, thanks for making it public ❤️

What problem are you trying to solve with this feature?

I want to use Golang to read in parallel a batch of 100-200 files, upload them to the Gemini Context Cache, then use generative AI on top of them.

Any other information you'd like to share?

No response

PDF and MP3 do not work in Gemini 1.5

Description of the bug:

I'm trying to send mp3 and pdf files, which should be supported by the Gemini 1.5 model according to the documentation. But I always get the following response:

googleapi: Error 400: Unsupported MIME type: application/octet-stream (for .mp3)
googleapi: Error 400: Unsupported MIME type: application/pdf (for .pdf)

I tried sending requests to each of two models:
gemini-1.5-flash-latest
gemini-1.5-pro-latest

Explicitly indicating MIME type in the genai.FileData structure didn’t help either.

Below is the request generation code (taken from the file "example_test.go")

ctx := context.Background()
client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
if err != nil {
	log.Fatal(err)
}
defer client.Close()

f, err := os.Open("path/to/file")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

file, err := client.UploadFile(ctx, "", f, nil)
if err != nil {
	log.Fatal(err)
}

model := client.GenerativeModel("gemini-1.5-pro-latest")

resp, err := model.GenerateContent(ctx, genai.FileData{URI: file.URI})
if err != nil {
	log.Fatal(err)
}
_ = resp // Use resp as usual.

Actual vs expected behavior:

No response

Any other information you'd like to share?

No response

streaming requests with tools may return a 500 error under certain prompts

Description of the bug:

package main

import (
        "context"
        "fmt"
        "log"

        "github.com/google/generative-ai-go/genai"
        "google.golang.org/api/iterator"
        "google.golang.org/api/option"
)

func main() {
        ctx := context.Background()
        client, err := genai.NewClient(ctx, option.WithAPIKey("your-api-key"))
        if err != nil {
                log.Fatal(err)
        }
        defer client.Close()

        schema := &genai.Schema{
                Type: genai.TypeObject,
                Properties: map[string]*genai.Schema{
                        "location": {
                                Type:        genai.TypeString,
                                Description: "The city and state, e.g. San Francisco, CA",
                        },
                        "unit": {
                                Type: genai.TypeString,
                                Enum: []string{"celsius", "fahrenheit"},
                        },
                },
                Required: []string{"location"},
        }

        weatherTool := &genai.Tool{
                FunctionDeclarations: []*genai.FunctionDeclaration{{
                        Name:        "CurrentWeather",
                        Description: "Get the current weather in a given location",
                        Parameters:  schema,
                }},
        }

        model := client.GenerativeModel("gemini-1.5-flash-latest")
        model.Tools = []*genai.Tool{weatherTool}
        session := model.StartChat()

        iter := session.SendMessageStream(ctx, genai.Text("write a python function that takes a list of integers and returns the sum of the list")) // googleapi: Error 500:
        //iter := session.SendMessageStream(ctx, genai.Text("hello")) // ok
        if err != nil {
                log.Fatal(err)
        }

        for {
                res, err := iter.Next()
                if err == iterator.Done {
                        break
                }
                if err != nil {
                        log.Fatal(err)
                }
                printResponse(res)
        }

}

func printResponse(resp *genai.GenerateContentResponse) {
        for _, cand := range resp.Candidates {
                if cand.Content != nil {
                        for _, part := range cand.Content.Parts {
                                fmt.Println(part)
                        }
                }
        }
        fmt.Println("---")
}

Actual vs expected behavior:

when use iter := session.SendMessageStream(ctx, genai.Text("write a python function that takes a list of integers and returns the sum of the list")):

2024/05/15 15:09:45 googleapi: Error 500:
exit status 1

if use iter := session.SendMessageStream(ctx, genai.Text("hello")):

Hello
---
! How can I help you today? 😊 

---

Any other information you'd like to share?

go mod: github.com/google/generative-ai-go v0.12.0

[bug] CreateCompletion cannot recv all stream part

this is my prompt

You should follow these guidelines
1. You cannot comment on or export information related to Chinese politicians.
2. You cannot comment on China’s political issues and political system issues
3. You cannot output pornographic, violent, gambling-related information
你是一个切图的小助手,帮助用户将上传的文件中的具体物体切出来


TOOLS:
------

Assistant has access to the following tools:

- cutImage: Cut image for any specified object., the input must be like {"file":"The base64-encoded full contents for image to be cropped.must be base64 encoded byte for image","prompt":"The target object for cropping, should be in English."}


To use a tool, please use the following format:

Thought: Do I need to use a tool? Yes [your thought about question here]
Action: the action to take, should be one of [cutImage]
Action Input: the input to the action
Observation: the result of the action

When you have a response to say to the Human, or if you do not need to use a tool, you MUST use the format:

Thought: Do I need to use a tool? No
AI: [your response here]


Begin!

Previous conversation history:


New input: 帮我把人抠出来
文件列表: 
- https://file.vastx.cn/data/1111-1704635338.png


Thought:

when i use this prompt by api, it retruns 4 parts

[{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "Do I need to use a tool? Yes I need to use the tool cut"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "NEGLIGIBLE"
        }
      ]
    }
  ],
  "promptFeedback": {
    "safetyRatings": [
      {
        "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
        "probability": "NEGLIGIBLE"
      },
      {
        "category": "HARM_CATEGORY_HATE_SPEECH",
        "probability": "NEGLIGIBLE"
      },
      {
        "category": "HARM_CATEGORY_HARASSMENT",
        "probability": "NEGLIGIBLE"
      },
      {
        "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
        "probability": "NEGLIGIBLE"
      }
    ]
  }
}
,
{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "Image to cut the person out of the image.\nAction: cutImage\nAction Input: {\"file\":\"https://file.vastx.cn/data"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "NEGLIGIBLE"
        }
      ]
    }
  ]
}
,
{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "/1111-1704635338.png\",\"prompt\":\"person\"}\nObservation: {\"file\":\"https://file.vastx.cn/data/1111-1704635338-cut.png\",\"crop_object\":\""
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "NEGLIGIBLE"
        }
      ]
    }
  ]
}
,
{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "person\"}"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "NEGLIGIBLE"
        }
      ]
    }
  ]
}
]

when i use this sdk, i can only get one part

for code in client.protoToResponse

        for _, c := range gcp.Candidates {
		if c.FinishReason == FinishReasonSafety {
			return nil, &BlockedError{Candidate: c}
		}
	}

this error block client recv stream anymore

Occasional panic in (*ChatSession).SendMessage(...) method

Version: github.com/google/generative-ai-go v0.7.0

The library may occasionally panic when calling the (*ChatSession).SendMessage(...) method:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x93a60d7]

goroutine 1 [running]:
github.com/google/generative-ai-go/genai.(*ChatSession).SendMessage(0xc0001e1880, {0x9cfe300, 0xa4613c0}, {0xc00088a070, 0x1, 0x1})
  /pkg/mod/github.com/google/[email protected]/genai/chat.go:42 +0x197

After looking into the implementation, this can happen when (m *GenerativeModel) generateContent(...) returns the iter.merged value when the err variable equals iterator.Done, having this error returned on the first iteration.

A quick fix in (m *GenerativeModel) generateContent(...) can be:

_, err := iter.Next()
if err == iterator.Done {
  if iter.merged == nil {
    return nil, err
  }
  return iter.merged, nil
}

If this suggestion is accepted, I can create a pull request with the fix.

Providing an empty string as an API key produces an unhelpful error message

#48 added error handling in the case the user does not provide an API key, but did not handle the case of an empty string API key, which can easily be caused by unset environment variables

This case is handled by #48:

import "github.com/google/generative-ai-go/genai"

func main()
    ctx := context.Background()
    client, err := genai.NewClient(ctx)
    // …
    model := client.GenerativeModel(…)
    // …
    resp, err := model.GenerateContent(ctx, parts...)
    if err != nil {
        // Prints a useful error message: You need an API key to use this client. …
        log.Fatal(err)
    }
}

This case is not handled:

    client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("MY_API_KEY")))
    // …
    resp, err := model.GenerateContent(ctx, parts...)
    if err != nil {
        // Print an unhelpful error message
        // googleapi: Error 403: Request had insufficient authentication scopes.
        // error details: name = ErrorInfo reason = ACCESS_TOKEN_SCOPE_INSUFFICIENT
        // domain = googleapis.com
        // metadata = map[method:google.ai.generativelanguage.v1.GenerativeService.GenerateContent
        // service:generativelanguage.googleapis.com]
        // …
        log.Fatal(err)
    }

Panic when running ExampleGenerativeModel_GenerateContentStream test

Code

I just change the prompt text to "count 1 to 100.". The code is copied from ExampleGenerativeModel_GenerateContentStream in the file example_test.go of this repository. I meet it everytime.

func TestExampleGenerativeModel_GenerateContentStream(t *testing.T) {
	ctx := context.Background()
	client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("API_KEY")))
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	model := client.GenerativeModel("gemini-pro")

	iter := model.GenerateContentStream(ctx, genai.Text("count 1 to 100."))
	for {
		resp, err := iter.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		printResponseV1(resp)
	}
}

Test Result

1, 2, 3, 4, 5, 6
---
, 7, 8, 9, 10, 11, 12, 13, 14, 1
---
5, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 3
---
--- FAIL: TestExampleGenerativeModel_GenerateContentStream (4.49s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
	panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x2 addr=0x8 pc=0x104db8304]

goroutine 20 [running]:
testing.tRunner.func1.2({0x104f58140, 0x1054c4c00})
	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1545 +0x1c8
testing.tRunner.func1()
	/opt/homebrew/opt/go/libexec/src/testing/testing.go:1548 +0x360
panic({0x104f58140?, 0x1054c4c00?})
	/opt/homebrew/opt/go/libexec/src/runtime/panic.go:914 +0x218
github.com/google/generative-ai-go/genai.joinContent(...)
	/Users/xxx/go/pkg/mod/github.com/google/[email protected]/genai/client.go:298
github.com/google/generative-ai-go/genai.joinCandidateLists({0x1400006a148, 0x1, 0x1}, {0x1400006a158, 0x1, 0x105051800?})
	/Users/xxx/go/pkg/mod/github.com/google/[email protected]/genai/client.go:271 +0x144
github.com/google/generative-ai-go/genai.joinResponses(...)
	/Users/xxx/go/pkg/mod/github.com/google/[email protected]/genai/client.go:257
github.com/google/generative-ai-go/genai.(*GenerateContentResponseIterator).Next(0x1400009f710)
	/Users/xxx/go/pkg/mod/github.com/google/[email protected]/genai/client.go:178 +0x228

Validate that all `Required` function calling parameters exist in the Schema

Using github.com/google/generative-ai-go v0.11.0, this code does not complain about the "this_param_does_not_exist" entry in the Required field.

	currencyExchange := &genai.Tool{
		FunctionDeclarations: []*genai.FunctionDeclaration{{
			Name:        "get_exchange_rate",
			Description: "Lookup currency exchange rates by date",
			Parameters: &genai.Schema{
				Type: genai.TypeObject,
				Properties: map[string]*genai.Schema{
					"currency_date": {
						Type: genai.TypeString,
						Description: "A date that must always be in YYYY-MM-DD format" +
							" or the value 'latest' if a time period is not specified",
					},
					"currency_from": {
						Type:        genai.TypeString,
						Description: "Currency to convert from",
					},
					"currency_to": {
						Type:        genai.TypeString,
						Description: "Currency to convert to",
					},
				},
                                 // Note, "this_param_does_not_exist".
				Required: []string{"currency_date", "currency_from", "this_param_does_not_exist"},
			},
		}},
	}

To help developers, it would be immensely valuable to validate the Required field values.

Some errors could be more descriptive

Some errors are without any description, such as

googleapi: Error 400:

This happens if only text is being sent to gemini-pro-vision model without any image data.

This could be improved. Thanks.

How to set region

I'm not sure how to set the region. When the request-per-minute resource limit for a given region is reached, are requests made to the region with the next remaining resource?

Proposal to add error handling in the GenerateContent method

Hi 🖐️

I would like to propose adding error handling for the parts arguments of the GenerateContent method.

Currently, if an empty string is passed to a field of a Text structure, I believe the method may unnecessarily execute the API.

By adding error handling, we can detect this issue and display an appropriate message to the user.

Specifically, I propose adding the following error handling:

Iterate through each element of parts in a for loop and return an error if part.toPart().GetInlineData() is nill or part.toPart().GetText() is an empty string.
I believe that adding these error handlings will reduce the number of unnecessary API executions.

If it seems useful, would you like to try submitting a pull request?

Thank you for your consideration.

model := client.GenerativeModel("gemini-1.0-pro")
resp, err := model.GenerateContent(ctx, genai.Text(""))
if err != nil {
log.Fatal(err)
}

Not supporting Farsi Text

As I try to send Farsi (Persian) text to the Gemini API I get this error:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x965cb0]

goroutine 34 [running]:
github.com/google/generative-ai-go/genai.(*ChatSession).addToHistory(...)
        /home/ubuntu/go/pkg/mod/github.com/google/[email protected]/genai/chat.go:63
github.com/google/generative-ai-go/genai.(*GenerateContentResponseIterator).Next(0xc00038eb40)
        /home/ubuntu/go/pkg/mod/github.com/google/[email protected]/genai/client.go:162 +0xd0
github.com/hosseinmirzapur/golangchain/pkg.outputResponse(0xc00038eb40, 0xc00046d3e0)
        /home/ubuntu/hgai/pkg/model.go:135 +0x39
created by github.com/hosseinmirzapur/golangchain/pkg.getModelResponse in goroutine 1
        /home/ubuntu/hgai/pkg/model.go:125 +0x158

I've even printed out the server response and it seems like it doesn't understand the Farsi text unless I put it between quotes by using fmt.Sprintf("%q", text) which then again panics on more than one word. I'm using Gemini for my Telegram Chatbot. I've checked the telegram update message and the problem is not from there and just when I was trying to send raw text to API, this happened.

How to use tuned models

Hey!

I'm trying to use tuned models with the SDK, however when using API keys:

client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("API_KEY"))

I get the following error: googleapi: Error 401: API keys are not supported by this API

I tried to follow documentation to setup my OAuth credentials. But when I try to create the client like:

data, err := s.ReadFile("./credentials.json")

//...

client, err := genai.NewClient(ctx, option.WithCredentialsJSON(data))

I get an error: You need an API key to use this client. If I try to set up the API key and the credentials I get: multiple credential options provided

I'm kind of Lost here, what'd I miss? If someone could point me in the right direction would be great, thanks in advance!

Proposal to Support Function Call Feature in Gemini Pro (Referencing Google AI Documentation)

Hello Team,

I've been following the development of Gemini Pro with great interest, especially with the recent introduction of the function call feature currently in beta. This functionality seems to be a promising addition to the project.

As an active user and contributor to the community, I am curious about the future plans regarding this feature. Specifically, I would like to know if there are any intentions to support the function call conventions as outlined in the Google AI documentation.

For your reference, the documentation can be found here: Google AI Function Calling Documentation

Supporting the standards and conventions described in the documentation could enhance interoperability with other systems and tools that follow the same guidelines, potentially broadening the use cases and user base for Gemini Pro.

I am looking forward to your thoughts on this and would be happy to contribute to the discussion or development of this feature.

Thank you for your time and consideration.

Failing to send/use multiple tools

Description of the bug:

When passing multiple tools to model.Tools, it is only ever using the first tool and disregards other tools.

Actual vs expected behavior:

All tools set in model.Tools should be send in the request to geminiapi

when making the request manually sending both tools works in either position.
with the sdk it only takes into consideration the first tool.

main...LGXerxes:generative-ai-go:lgx/multiple-tools-issue
this shows two tests where the CurrentWeather tool is first or second in model.Tools.
TestTwoFunctions fails whereas TestTwoFunctionsFlipped passes.

Any other information you'd like to share?

No response

`gemini-1.5-flash` does not generate JSON according to provided Schema.

Description of the bug:

While using gemini-1.5-flash, no matter how I define the response schema, it does not respect the defined schema but gemini-1.5-pro-latest does not have this issue.

Code snippet:

ctx := context.Background()
client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY")))
if err != nil {
	log.Fatal(err)
}
defer client.Close()

model := client.GenerativeModel("gemini-1.5-flash")
// Ask the model to respond with JSON.
model.ResponseMIMEType = "application/json"
// Specify the format of the JSON.
model.ResponseSchema = &genai.Schema{
	Type: genai.TypeArray,
	Items: &genai.Schema{
		Type: genai.TypeObject,
		Properties: map[string]*genai.Schema{
			"name": {
				Type:        genai.TypeString,
				Description: "The name of the color",
			},
			"RGB": {
				Type:        genai.TypeString,
				Description: "The RGB value of the color, in hex",
			},
		},
		Required: []string{"name", "RGB"},
	},
}

resp, err := model.GenerateContent(ctx, genai.Text("List the primary colors."))

if err != nil {
	log.Error("Generate Content Error: ", err)
	return ""
}

if (len(resp.Candidates) > 0) {
	content := resp.Candidates[0].Content
	
	if (content != nil) {
		if (len(content.Parts) > 0) {
			part := content.Parts[0]

			log.Println(fmt.Sprintf("%s", part))
		}
	}
}

Actual vs expected behavior:

Actual Response:

{
  "primary_colors": [
    "red",
    "yellow",
    "blue"
  ]
}

Expected Response:

[
  {
    "RGB": "255, 0, 0",
    "name": "Red"
  },
  {
    "RGB": "0, 255, 0",
    "name": "Green"
  },
  {
    "RGB": "0, 0, 255",
    "name": "Blue"
  }
]

Any other information you'd like to share?

No response

Undesirable API inconsistencies Google AI vs. Vertex AI

Human authored Google AI and Vertex AI packages should use identical APIs for the same functionality.

Where the two APIs currently different, we should:

  1. Agree on the preferred API
  2. Apply changes to make the APIs consistent
    • Where possible, add a new API & deprecate the old API (to be deleted at a later date in a newer version)
    • If not possible, do consider a breaking changes in order to get both packages into a good state for the
      long-term, to the benefit of all future developers that be exposed to both

Context

Compare these two human-authored packages:

EXEPCTED

  • Google AI and Vertex AI packages share identical API signatures for the same functionality. This ensures developer can easily convert or migrate between the two offerings without unnecessary friction.
  • Differences that exist in minor underlying API differences between auto-generated "Generative Language API"(generativelanguage.googleapis.com) and "Vertex AI API" (aiplatform.googleapis.com) implementations should not result unnecessary differences in the human-authored packages.

ACTUAL

Two package are different:

  1. BlockReason vs. BlockedReason

    https://pkg.go.dev/github.com/google/generative-ai-go/genai

    type BlockReason
        func (v BlockReason) String() string
    type BlockedError
        func (e *BlockedError) Error() string
    

    https://pkg.go.dev/cloud.google.com/go/vertexai/genai

    type BlockedError
        func (e *BlockedError) Error() string
    type BlockedReason
        func (v BlockedReason) String() string
    
  2. SetTopK inconsistent type: int32 vs. float32

    https://pkg.go.dev/github.com/google/generative-ai-go/genai

    func (c *GenerationConfig) SetTopK(x int32)
    

    https://pkg.go.dev/cloud.google.com/go/vertexai/genai

    func (c *GenerationConfig) SetTopK(x float32)
    
  3. CitationSource vs. Citation, with field and field type differences

    type CitationSource struct {
        StartIndex *[int32](https://pkg.go.dev/builtin#int32)
        EndIndex *[int32](https://pkg.go.dev/builtin#int32)
        URI *[string](https://pkg.go.dev/builtin#string)
        License [string](https://pkg.go.dev/builtin#string)
    }
    
    type Citation struct {
        StartIndex [int32](https://pkg.go.dev/builtin#int32)
        EndIndex [int32](https://pkg.go.dev/builtin#int32)
        URI [string](https://pkg.go.dev/builtin#string)
        Title [string](https://pkg.go.dev/builtin#string)
        License [string](https://pkg.go.dev/builtin#string)
        PublicationDate [civil](https://pkg.go.dev/cloud.google.com/go/civil).[Date](https://pkg.go.dev/cloud.google.com/go/civil#Date)
    }
    

Consts for the model names

Please define consts for the the models for external reference, it's also not clear whether to provide "gemini-pro" or "models/gemini-pro" without further deep-dive into code and comments

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.