Conversation
Summary of ChangesHello @chrisraygill, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request delivers a substantial update and expansion to the Go documentation for the Google AI plugin within Genkit. The changes aim to provide a more comprehensive and user-friendly guide for developers, covering a wider array of Google's generative AI models and their advanced features. The updated documentation includes detailed setup instructions, authentication methods, and extensive examples for various model types, multimodal inputs/outputs, and advanced configurations like structured output, reasoning, context caching, and grounding capabilities. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request significantly expands the Go documentation for the Google Generative AI plugin, introducing comprehensive sections on various model types (Language, Embedding, Image, Video, Speech) and multimodal capabilities. The updated documentation includes detailed usage examples for features such as structured output, thinking and reasoning, context caching, safety settings, and grounding with Google Search, Google Maps, and code execution. However, the review comments point out several issues, including incomplete code snippets that are missing necessary import statements or undefined variables, incorrect methods for extracting image URLs and processing structured/audio output, and inconsistencies in heading styles that need to be addressed for clarity and correctness.
| // Option 1: Extract only the image (if it's the expected first part) | ||
| if len(resp.Message.Content) > 0 && resp.Message.Content[0].IsImage() { | ||
| imageUrl := resp.Message.Content[0].Text | ||
| fmt.Printf("Image URL: %s\n", imageUrl) | ||
| } | ||
|
|
||
| // Option 2: Extract both text and images | ||
| for _, part := range resp.Message.Content { | ||
| if part.IsText() { | ||
| fmt.Printf("Text: %s\n", part.Text) | ||
| } else if part.IsImage() { | ||
| fmt.Printf("Image URL: %s\n", part.Text) | ||
| } | ||
| } |
There was a problem hiding this comment.
This code for extracting image and text from a multimodal response is incorrect. For an image part, the URL is in part.Media.URL, not part.Text. Using part.Text for an image part will not work. Also, the fmt package is used but not imported.
import "fmt"
// Option 1: Extract only the image (if it's the expected first part)
if len(resp.Message.Content) > 0 && resp.Message.Content[0].IsImage() {
imageUrl := resp.Message.Content[0].Media.URL
fmt.Printf("Image URL: %s\n", imageUrl)
}
// Option 2: Extract both text and images
for _, part := range resp.Message.Content {
if part.IsText() {
fmt.Printf("Text: %s\n", part.Text)
} else if part.IsImage() {
fmt.Printf("Image URL: %s\n", part.Media.URL)
}
}
| **Gemini 3 Series** - Latest experimental models with state-of-the-art reasoning: | ||
| - `gemini-3-pro-preview` - Preview of the most capable model for complex tasks | ||
| - `gemini-3-flash-preview` - Fast and intelligent model for high-volume tasks | ||
| - `gemini-3-pro-image-preview` - Supports image generation outputs | ||
|
|
||
| **Gemini 2.5 Series** - Latest stable models with advanced reasoning and multimodal capabilities: | ||
| - `gemini-2.5-pro` - Most capable stable model for complex tasks | ||
| - `gemini-2.5-flash` - Fast and efficient for most use cases | ||
| - `gemini-2.5-flash-lite` - Lightweight version for simple tasks | ||
| - `gemini-2.5-flash-image` - Supports image generation outputs | ||
|
|
||
| **Gemma 3 Series** - Open models for various use cases: |
There was a problem hiding this comment.
The document uses a mix of ### headings and bolded text for section titles (e.g., ### Available Models vs. **Gemini 3 Series**). For better document structure and consistency, consider using ### for all similar-level headings. This also applies to **Gemini 2.5 Series**, **Gemma 3 Series**, **Imagen 4 Series**, **Veo 3.1 Series**, etc.
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModel(model), | ||
| ai.WithPrompt("Generate a profile for a fictional character"), | ||
| ai.WithOutputSchema(profile), | ||
| ) |
There was a problem hiding this comment.
The model variable is used here but not defined. This makes the code snippet incomplete and confusing. Please define it before use, for example by using ai.WithModelName("googleai/gemini-2.5-flash").
resp, err := genkit.Generate(ctx, g,
ai.WithModelName("googleai/gemini-2.5-flash"),
ai.WithPrompt("Generate a profile for a fictional character"),
ai.WithOutputSchema(profile),
)
| // The model output will be in resp.Text which is a JSON string | ||
| json.Unmarshal([]byte(resp.Text()), &profile) |
There was a problem hiding this comment.
Using json.Unmarshal on resp.Text() is not the idiomatic way to get structured output in Genkit for Go. It's better to use the resp.Output() helper function, which is safer and simpler.
// The model output can be unmarshalled using the Output helper.
if err = resp.Output(&profile); err != nil {
// handle error
}
There was a problem hiding this comment.
Bot is right, you know.
| ```go | ||
| resp, err := genkit.Generate(ctx, g, ai.WithModel(modelRef), ai.WithPrompt("Tell me a joke.")) | ||
| if err != nil { | ||
| return err | ||
| // Structure prompts with consistent content at the beginning | ||
| baseContext := strings.Repeat("You are a helpful cook... (large context) ...", 50) | ||
|
|
||
| // First request - content will be cached | ||
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModel(model), | ||
| ai.WithPrompt(baseContext + "\n\nTask 1..."), | ||
| ) | ||
|
|
||
| // Second request with same prefix - eligible for cache hit | ||
| resp, err = genkit.Generate(ctx, g, | ||
| ai.WithModel(model), | ||
| ai.WithPrompt(baseContext + "\n\nTask 2..."), | ||
| ) | ||
| ``` |
There was a problem hiding this comment.
This code snippet for context caching has a couple of issues:
- It uses
strings.Repeat, but thestringspackage is not imported. - The
modelvariable is used but not defined.
Please update the snippet to be a complete, runnable example.
import "strings"
// Structure prompts with consistent content at the beginning
baseContext := strings.Repeat("You are a helpful cook... (large context) ...", 50)
model := googlegenai.GoogleAIModelRef("gemini-2.5-pro", nil)
// First request - content will be cached
resp, err := genkit.Generate(ctx, g,
ai.WithModel(model),
ai.WithPrompt(baseContext + "\n\nTask 1..."),
)
// Second request with same prefix - eligible for cache hit
resp, err = genkit.Generate(ctx, g,
ai.WithModel(model),
ai.WithPrompt(baseContext + "\n\nTask 2..."),
)
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModel(model), | ||
| ai.WithPrompt( | ||
| ai.NewTextPart("What happens in this video?"), | ||
| ai.NewMediaPart("video/mp4", "https://example.com/video.mp4"), | ||
| ), | ||
| ) | ||
| ``` |
There was a problem hiding this comment.
The model variable is used in this snippet but is not defined. This makes the example incomplete. Please define it, for instance: model := googlegenai.GoogleAIModelRef("gemini-2.5-flash", nil). This issue is also present in the other multimodal examples for Image, Audio, and PDF understanding.
model := googlegenai.GoogleAIModelRef("gemini-2.5-flash", nil)
resp, err := genkit.Generate(ctx, g,
ai.WithModel(model),
ai.WithPrompt(
ai.NewTextPart("What happens in this video?"),
ai.NewMediaPart("video/mp4", "https://example.com/video.mp4"),
),
)
| ```go | ||
| // Start video generation | ||
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModelName("googleai/veo-3.0-fast-generate-001"), | ||
| ai.WithPrompt("A majestic dragon soaring over a mystical forest at dawn."), | ||
| ) | ||
|
|
||
| // Check progress using the operation ID | ||
| op := resp.Operation() | ||
| for !op.Done { | ||
| time.Sleep(5 * time.Second) | ||
| op = genkit.CheckOperation(ctx, g, op) | ||
| } | ||
|
|
||
| if op.Error != nil { | ||
| log.Fatal(op.Error) | ||
| } | ||
|
|
||
| // Access generated video URI from the operation result | ||
| videoURI := op.Output.Message.Content[0].Media.URL | ||
| ``` |
There was a problem hiding this comment.
This video generation example uses functions from the time and log packages, but they are not imported. Please add the necessary imports to make the snippet runnable.
import (
"log"
"time"
)
// Start video generation
resp, err := genkit.Generate(ctx, g,
ai.WithModelName("googleai/veo-3.0-fast-generate-001"),
ai.WithPrompt("A majestic dragon soaring over a mystical forest at dawn."),
)
// Check progress using the operation ID
op := resp.Operation()
for !op.Done {
time.Sleep(5 * time.Second)
op = genkit.CheckOperation(ctx, g, op)
}
if op.Error != nil {
log.Fatal(op.Error)
}
// Access generated video URI from the operation result
videoURI := op.Output.Message.Content[0].Media.URL
| ```go | ||
| import "google.golang.org/genai" | ||
|
|
||
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModelName("googleai/gemini-2.5-flash-preview-tts"), | ||
| ai.WithConfig(&genai.GenerateContentConfig{ | ||
| ResponseModalities: []string{"AUDIO"}, | ||
| SpeechConfig: &genai.SpeechConfig{ | ||
| VoiceConfig: &genai.VoiceConfig{ | ||
| PrebuiltVoiceConfig: &genai.PrebuiltVoiceConfig{ | ||
| VoiceName: "Algenib", | ||
| }, | ||
| }, | ||
| }, | ||
| }), | ||
| ai.WithPrompt("Say: Genkit is the best Gen AI library!"), | ||
| ) | ||
|
|
||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| // The model output will be a base64 encoded string in resp.Text() | ||
| // You can decode this and save it as a PCM file or convert to WAV. | ||
| ``` |
There was a problem hiding this comment.
This speech model example has a couple of issues:
- The
logpackage is used but not imported. - The comment
// The model output will be a base64 encoded string in resp.Text()is likely incorrect. For audio responses, the output is typically a media part, with the data encoded in a data URL inresp.Message.Content[0].Media.URL, not inresp.Text(). The current comment is misleading and doesn't show how to actually process the audio.
| Temperature: genai.Ptr[float32](0.5), | ||
| } | ||
|
|
||
| // Option 1: Use a model reference with "baked-in" config |
There was a problem hiding this comment.
Mention that this has strong typing so it ensures that you are using the correct config type for the plugin.
| // Option 2: Pass configuration per-request | ||
| resp, err = genkit.Generate(ctx, g, | ||
| ai.WithModelName("googleai/gemini-2.5-flash"), | ||
| ai.WithConfig(config), // Pass config explicitly |
There was a problem hiding this comment.
Whereas this has no strong typing and will work the same but doesn't have any guiderails, although it will error at runtime.
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModel(model), | ||
| ai.WithPrompt("Generate a profile for a fictional character"), | ||
| ai.WithOutputSchema(profile), |
There was a problem hiding this comment.
This is not valid. Either WithOutputType(CharacterProfile{}) or char, resp, err := genkit.GenerateData[CharacterProfile](...).
|
|
||
| The following configuration options are available for code execution: | ||
|
|
||
| - **codeExecution** _object_ |
There was a problem hiding this comment.
What is this notation? Why bold/italic?
| if len(resp.Message.Content) > 0 && resp.Message.Content[0].IsImage() { | ||
| imageUrl := resp.Message.Content[0].Text | ||
| fmt.Printf("Image URL: %s\n", imageUrl) | ||
| } | ||
|
|
||
| // Option 2: Extract both text and images | ||
| for _, part := range resp.Message.Content { | ||
| if part.IsText() { | ||
| fmt.Printf("Text: %s\n", part.Text) | ||
| } else if part.IsImage() { | ||
| fmt.Printf("Image URL: %s\n", part.Text) | ||
| } | ||
| } |
There was a problem hiding this comment.
Can just do resp.Text() or resp.Media() instead of all this.
| resp, err := genkit.Generate(ctx, g, | ||
| ai.WithModelName("googleai/veo-3.0-fast-generate-001"), | ||
| ai.WithPrompt("A majestic dragon soaring over a mystical forest at dawn."), | ||
| ) | ||
|
|
||
| // Check progress using the operation ID | ||
| op := resp.Operation() |
There was a problem hiding this comment.
| resp, err := genkit.Generate(ctx, g, | |
| ai.WithModelName("googleai/veo-3.0-fast-generate-001"), | |
| ai.WithPrompt("A majestic dragon soaring over a mystical forest at dawn."), | |
| ) | |
| // Check progress using the operation ID | |
| op := resp.Operation() | |
| op, err := genkit.GenerateOperation(ctx, g, | |
| ai.WithModelName("googleai/veo-3.0-fast-generate-001"), | |
| ai.WithPrompt("A majestic dragon soaring over a mystical forest at dawn."), | |
| ) | |
| } | ||
|
|
||
| // Access generated video URI from the operation result | ||
| videoURI := op.Output.Message.Content[0].Media.URL |
There was a problem hiding this comment.
op.Output.Media() is the preferred way. Should work I think.
No description provided.