diff --git a/badfiles_test.go b/badfiles_test.go index e9700fea3c..b7f7b4b37f 100644 --- a/badfiles_test.go +++ b/badfiles_test.go @@ -86,6 +86,7 @@ var allowList = []string{ "genai/**/*.mp4", "genai/**/*.jpg", "genai/**/*.png", + "genai/**/*.md", // Endpoints samples. "endpoints/**/*.proto", diff --git a/genai/image_generation/bw-example-image.png b/genai/image_generation/bw-example-image.png new file mode 100644 index 0000000000..ede2e49373 Binary files /dev/null and b/genai/image_generation/bw-example-image.png differ diff --git a/genai/image_generation/dog_newspaper.png b/genai/image_generation/dog_newspaper.png new file mode 100644 index 0000000000..49416ca153 Binary files /dev/null and b/genai/image_generation/dog_newspaper.png differ diff --git a/genai/image_generation/example-image-2.png b/genai/image_generation/example-image-2.png new file mode 100644 index 0000000000..443ddf0a60 Binary files /dev/null and b/genai/image_generation/example-image-2.png differ diff --git a/genai/image_generation/example-image-4.png b/genai/image_generation/example-image-4.png new file mode 100644 index 0000000000..6ec8e700e6 Binary files /dev/null and b/genai/image_generation/example-image-4.png differ diff --git a/genai/image_generation/example-image-6.png b/genai/image_generation/example-image-6.png new file mode 100644 index 0000000000..b38c42b35b Binary files /dev/null and b/genai/image_generation/example-image-6.png differ diff --git a/genai/image_generation/example-image-eiffel-tower.png b/genai/image_generation/example-image-eiffel-tower.png new file mode 100644 index 0000000000..ff123fdbed Binary files /dev/null and b/genai/image_generation/example-image-eiffel-tower.png differ diff --git a/genai/image_generation/image_generation_examples_test.go b/genai/image_generation/image_generation_examples_test.go index 31c9c61dfa..ad9a240325 100644 --- a/genai/image_generation/image_generation_examples_test.go +++ b/genai/image_generation/image_generation_examples_test.go @@ -55,4 +55,30 @@ func TestImageGeneration(t *testing.T) { t.Error("expected non-empty output, got empty") } }) + + t.Run("generate image content with text", func(t *testing.T) { + buf.Reset() + err := generateImageWithText(buf) + if err != nil { + t.Fatalf("generateImageWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + + t.Run("generate mmflash image content with text and image", func(t *testing.T) { + buf.Reset() + err := generateImageMMFlashEditWithTextImg(buf) + if err != nil { + t.Fatalf("generateImageMMFlashEditWithTextImg failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) } diff --git a/genai/image_generation/imggen_mmflash_edit_img_with_txt_img.go b/genai/image_generation/imggen_mmflash_edit_img_with_txt_img.go new file mode 100644 index 0000000000..59d818b518 --- /dev/null +++ b/genai/image_generation/imggen_mmflash_edit_img_with_txt_img.go @@ -0,0 +1,101 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package image_generation shows how to use the GenAI SDK to generate images and text. +package image_generation + +// [START googlegenaisdk_imggen_mmflash_edit_img_with_txt_img] +import ( + "context" + "fmt" + "io" + "os" + + "google.golang.org/genai" +) + +// generateImageMMFlashEditWithTextImg demonstrates editing an image with text and image inputs. +func generateImageMMFlashEditWithTextImg(w io.Writer) error { + // TODO(developer): Update below lines + outputFile := "bw-example-image.png" + inputFile := "example-image-eiffel-tower.png" + ctx := context.Background() + + client, err := genai.NewClient(ctx, &genai.ClientConfig{ + HTTPOptions: genai.HTTPOptions{APIVersion: "v1"}, + }) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + image, err := os.ReadFile(inputFile) + if err != nil { + return fmt.Errorf("failed to read image: %w", err) + } + + modelName := "gemini-2.5-flash-image" + prompt := "Edit this image to make it look like a cartoon." + contents := []*genai.Content{ + { + Role: "user", + Parts: []*genai.Part{ + {Text: prompt}, + {InlineData: &genai.Blob{ + MIMEType: "image/png", + Data: image, + }}, + }, + }, + } + resp, err := client.Models.GenerateContent(ctx, + modelName, + contents, + &genai.GenerateContentConfig{ + ResponseModalities: []string{ + string(genai.ModalityText), + string(genai.ModalityImage), + }, + }, + ) + if err != nil { + return fmt.Errorf("failed to generate content: %w", err) + } + + if len(resp.Candidates) == 0 || resp.Candidates[0].Content == nil { + return fmt.Errorf("no content was generated") + } + + for _, part := range resp.Candidates[0].Content.Parts { + if part.Text != "" { + fmt.Fprintln(w, part.Text) + } else if part.InlineData != nil { + if len(part.InlineData.Data) > 0 { + if err := os.WriteFile(outputFile, part.InlineData.Data, 0644); err != nil { + return fmt.Errorf("failed to save image: %w", err) + } + fmt.Fprintln(w, outputFile) + } + } + } + + // Example response: + // Here's the image of the Eiffel Tower and fireworks, cartoonized for you! + // Cartoon-style edit: + // - Simplified the Eiffel Tower with bolder lines and slightly exaggerated proportions. + // - Brightened and saturated the colors of the sky, fireworks, and foliage for a more vibrant, cartoonish look. + // .... + return nil +} + +// [END googlegenaisdk_imggen_mmflash_edit_img_with_txt_img] diff --git a/genai/image_generation/imggen_mmflash_txt_img_with_txt.go b/genai/image_generation/imggen_mmflash_txt_img_with_txt.go index 4a0d3ec8f2..ab03913182 100644 --- a/genai/image_generation/imggen_mmflash_txt_img_with_txt.go +++ b/genai/image_generation/imggen_mmflash_txt_img_with_txt.go @@ -68,7 +68,7 @@ func generateMMFlashTxtImgWithText(w io.Writer) error { return fmt.Errorf("no candidates returned") } - outputFolder := "testdata" + outputFolder := "" // Create the markdown file mdFile := filepath.Join(outputFolder, "paella-recipe.md") diff --git a/genai/image_generation/imggen_mmflash_with_txt.go b/genai/image_generation/imggen_mmflash_with_txt.go index 5013b77f14..d1723a6151 100644 --- a/genai/image_generation/imggen_mmflash_with_txt.go +++ b/genai/image_generation/imggen_mmflash_with_txt.go @@ -74,7 +74,7 @@ func generateMMFlashWithText(w io.Writer) error { if part.Text != "" { fmt.Fprintln(w, part.Text) } else if part.InlineData != nil { - fileName = "testdata/example-image-eiffel-tower.png" + fileName = "example-image-eiffel-tower.png" if err := os.WriteFile(fileName, part.InlineData.Data, 0o644); err != nil { return fmt.Errorf("failed to save image: %w", err) } diff --git a/genai/image_generation/imggen_with_txt.go b/genai/image_generation/imggen_with_txt.go new file mode 100644 index 0000000000..2a71ae49e1 --- /dev/null +++ b/genai/image_generation/imggen_with_txt.go @@ -0,0 +1,70 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package image_generation shows how to use the GenAI SDK to generate images and text. +package image_generation + +// [START googlegenaisdk_imggen_with_txt] +import ( + "context" + "fmt" + "io" + "os" + + "google.golang.org/genai" +) + +// generateImageWithText demonstrates how to generate an image from a text prompt. +func generateImageWithText(w io.Writer) error { + // TODO(developer): Update below line + outputFile := "dog_newspaper.png" + ctx := context.Background() + + client, err := genai.NewClient(ctx, &genai.ClientConfig{ + HTTPOptions: genai.HTTPOptions{APIVersion: "v1"}, + }) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + modelName := "imagen-4.0-generate-001" + prompt := "A dog reading a newspaper" + resp, err := client.Models.GenerateImages(ctx, + modelName, + prompt, + &genai.GenerateImagesConfig{ + ImageSize: "2K", + }, + ) + if err != nil { + return fmt.Errorf("failed to generate content: %w", err) + } + + if len(resp.GeneratedImages) == 0 || resp.GeneratedImages[0].Image == nil { + return fmt.Errorf("no image generated") + } + + img := resp.GeneratedImages[0].Image + if err := os.WriteFile(outputFile, img.ImageBytes, 0644); err != nil { + return fmt.Errorf("failed to save image: %w", err) + } + + fmt.Fprintln(w, len(img.ImageBytes)) + + // Example response: + // Created output image using 6098201 bytes + return nil +} + +// [END googlegenaisdk_imggen_with_txt] diff --git a/genai/image_generation/paella-recipe.md b/genai/image_generation/paella-recipe.md new file mode 100644 index 0000000000..920ae1fd3b --- /dev/null +++ b/genai/image_generation/paella-recipe.md @@ -0,0 +1,52 @@ +Let's get cooking! Here's an illustrated recipe for a delicious paella: + +## Authentic Spanish Paella + +Paella is a classic Spanish dish, famous for its vibrant flavors and communal spirit. While there are many variations, this recipe focuses on a traditional seafood and chicken paella. + +### Ingredients: + +* **For the Sofrito:** + * 1 large onion, finely chopped + * 2 cloves garlic, minced + * 1 red bell pepper, finely chopped + * 1 green bell pepper, finely chopped + * 2 ripe tomatoes, grated or finely diced + * 1/2 cup olive oil + * Salt and freshly ground black pepper to taste + +* **For the Paella:** + * 1 lb boneless, skinless chicken thighs, cut into 1-inch pieces + * 1/2 lb Spanish chorizo, sliced (optional) + * 1 lb large shrimp, peeled and deveined + * 1 lb mussels, scrubbed and de-bearded + * 1 lb calamari, cut into rings (optional) + * 4 cups short-grain Spanish rice (Bomba or Calasparra preferred) + * 8 cups hot chicken or seafood broth + * 1 teaspoon saffron threads, steeped in 1/4 cup hot water + * 1 teaspoon smoked paprika + * 1/2 cup fresh or frozen peas + * 1 lemon, cut into wedges, for serving + * Fresh parsley, chopped, for garnish + +### Equipment: + +* A 16-inch paella pan (or a wide, shallow pan) + +### Instructions: + +--- + +**Step 1: Prepare Your Ingredients** + +Chop all your vegetables and chicken. Have your seafood ready. This preparation is key for smooth cooking. ![image](example-image-2.png) + +--- + +**Step 2: Start the Sofrito** + +Heat the olive oil in your paella pan over medium heat. Add the chopped onion and bell peppers. Cook until softened, about 8-10 minutes. ![image](example-image-4.png)--- + +**Step 3: Add Garlic and Tomatoes** + +Stir in the minced garlic and cook for another minute until fragrant. Then, add the grated or diced tomatoes, smoked paprika, salt, and pepper. Cook for about 10-15 minutes, stirring occasionally, until the sauce thickens and deepens in color. This is your sofrito base. ![image](example-image-6.png) \ No newline at end of file diff --git a/genai/image_generation/testdata/example-image-2.png b/genai/image_generation/testdata/example-image-2.png deleted file mode 100644 index 2fa98867ed..0000000000 Binary files a/genai/image_generation/testdata/example-image-2.png and /dev/null differ diff --git a/genai/image_generation/testdata/example-image-4.png b/genai/image_generation/testdata/example-image-4.png deleted file mode 100644 index 97bb7c95cd..0000000000 Binary files a/genai/image_generation/testdata/example-image-4.png and /dev/null differ diff --git a/genai/image_generation/testdata/example-image-6.png b/genai/image_generation/testdata/example-image-6.png deleted file mode 100644 index 981b550739..0000000000 Binary files a/genai/image_generation/testdata/example-image-6.png and /dev/null differ diff --git a/genai/image_generation/testdata/example-image-eiffel-tower.png b/genai/image_generation/testdata/example-image-eiffel-tower.png deleted file mode 100644 index 3628ddfa67..0000000000 Binary files a/genai/image_generation/testdata/example-image-eiffel-tower.png and /dev/null differ diff --git a/genai/image_generation/testdata/paella-recipe.md b/genai/image_generation/testdata/paella-recipe.md deleted file mode 100644 index 5d5101a966..0000000000 --- a/genai/image_generation/testdata/paella-recipe.md +++ /dev/null @@ -1,44 +0,0 @@ -Let's get cooking! Here's an illustrated recipe for a delicious paella: - -## Traditional Spanish Paella - -Paella is a classic Spanish dish, known for its vibrant colors and rich flavors. While there are many variations, this recipe will guide you through making a traditional chicken and seafood paella. - -### Ingredients: - -* 2 tablespoons olive oil -* 1 lb boneless, skinless chicken thighs, cut into 1-inch pieces -* 1 lb shrimp, peeled and deveined -* 1 cup chopped chorizo (optional) -* 1 large onion, chopped -* 2 cloves garlic, minced -* 1 red bell pepper, chopped -* 1 (14.5 ounce) can diced tomatoes, undrained -* 1 teaspoon smoked paprika -* 1/2 teaspoon saffron threads, crushed and steeped in 1/4 cup warm water -* 2 cups Bomba rice (or other short-grain rice) -* 4 cups chicken broth, warmed -* 1/2 cup frozen peas -* 1/4 cup chopped fresh parsley -* Lemon wedges, for serving -* Salt and freshly ground black pepper to taste - -### Equipment: - -* Large paella pan (or a large, shallow, oven-safe pan) -* Wooden spoon - -### Instructions: - -**Step 1: Prepare Your Ingredients** - -Before you start cooking, it's helpful to have all your ingredients prepped and ready to go. Chop your chicken, onion, bell pepper, and mince your garlic. Don't forget to steep your saffron threads! -![image](example-image-2.png)**Step 2: Sauté the Chicken and Chorizo** - -Heat the olive oil in your paella pan over medium-high heat. Add the chicken pieces and cook until browned on all sides. If using, add the chorizo and cook until lightly crisped. Remove the chicken and chorizo from the pan and set aside, leaving any drippings in the pan. - -![image](example-image-4.png)**Step 3: Cook the Aromatics** - -Add the chopped onion and bell pepper to the pan and cook until softened, about 5-7 minutes. Stir in the minced garlic and cook for another minute until fragrant. - -![image](example-image-6.png) \ No newline at end of file diff --git a/genai/thinking/thinkgen_include_thoughts_with_txt.go b/genai/thinking/thinkgen_include_thoughts_with_txt.go new file mode 100644 index 0000000000..4f1c334064 --- /dev/null +++ b/genai/thinking/thinkgen_include_thoughts_with_txt.go @@ -0,0 +1,133 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package thinking shows how to use the GenAI SDK to include thoughts with txt. +package thinking + +// [START googlegenaisdk_thinking_includethoughts_with_txt] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateContentWithThoughts demonstrates how to generate text including the model's thought process. +func generateContentWithThoughts(w io.Writer) error { + ctx := context.Background() + + client, err := genai.NewClient(ctx, &genai.ClientConfig{ + HTTPOptions: genai.HTTPOptions{APIVersion: "v1"}, + }) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + modelName := "gemini-2.5-pro" + contents := []*genai.Content{ + { + Parts: []*genai.Part{ + {Text: "solve x^2 + 4x + 4 = 0"}, + }, + Role: "user", + }, + } + + resp, err := client.Models.GenerateContent(ctx, + modelName, + contents, + &genai.GenerateContentConfig{ + ThinkingConfig: &genai.ThinkingConfig{ + IncludeThoughts: true, + }, + }, + ) + if err != nil { + return fmt.Errorf("failed to generate content: %w", err) + } + + if len(resp.Candidates) == 0 || resp.Candidates[0].Content == nil { + return fmt.Errorf("no content was generated") + } + + // The response may contain both the final answer and the model's thoughts. + // Iterate through the parts to print them separately. + fmt.Fprintln(w, "Answer:") + for _, part := range resp.Candidates[0].Content.Parts { + if part.Text != "" && !part.Thought { + fmt.Fprintln(w, part.Text) + } + } + fmt.Fprintln(w, "\nThoughts:") + for _, part := range resp.Candidates[0].Content.Parts { + if part.Thought { + fmt.Fprintln(w, part.Text) + } + } + + // Example response: + // Answer: + // Of course! We can solve this quadratic equation in a couple of ways. + // + //### Method 1: Factoring (the easiest method for this problem) + // + //1. **Recognize the pattern.** The expression `x² + 4x + 4` is a perfect square trinomial. It fits the pattern `a² + 2ab + b² = (a + b)²`. In this case, `a = x` and `b = 2`. + // + //2. **Factor the equation.** + // `x² + 4x + 4 = (x + 2)(x + 2) = (x + 2)²` + // + //3. **Solve for x.** Now set the factored expression to zero: + // `(x + 2)² = 0` + // + // Take the square root of both sides: + // `x + 2 = 0` + // + // Subtract 2 from both sides: + // `x = -2` + // + //This type of solution is called a "repeated root" or a "double root" because the factor `(x+2)` appears twice. + // + //--- + // + //### Method 2: Using the Quadratic Formula + // + //You can use the quadratic formula for any equation in the form `ax² + bx + c = 0`. + // + //The formula is: `x = [-b ± sqrt(b² - 4ac)] / 2a` + // + //1. **Identify a, b, and c.** + // * a = 1 + // * b = 4 + // * c = 4 + // + //2. **Plug the values into the formula.** + // `x = [-4 ± sqrt(4² - 4 * 1 * 4)] / (2 * 1)` + // + //3. **Simplify.** + // `x = [-4 ± sqrt(16 - 16)] / 2` + // `x = [-4 ± sqrt(0)] / 2` + // `x = -4 / 2` + // + //4. **Solve for x.** + // `x = -2` + //Alright, the user wants to solve the quadratic equation `x² + 4x + 4 = 0`. My first instinct is to see if I can factor it; that's often the fastest approach if it works. Looking at the coefficients, I see `a = 1`, `b = 4`, and `c = 4`. Factoring is clearly the most direct path here. I need to find two numbers that multiply to 4 (c) and add up to 4 (b). Hmm, let's see… 1 and 4? Nope, that adds to 5. 2 and 2? Perfect! 2 times 2 is 4, and 2 plus 2 is also 4. + // + //So, `x² + 4x + 4` factors nicely into `(x + 2)(x + 2)`. Ah, a perfect square trinomial! That's useful to note. Now, I can write the equation as `(x + 2)² = 0`. Taking the square root of both sides gives me `x + 2 = 0`. And finally, subtracting 2 from both sides, I get `x = -2`. That's the solution. + // + //Just to be thorough, and maybe to offer an alternative explanation, let's verify this using the quadratic formula. It's `x = [-b ± √(b² - 4ac)] / 2a`. Plugging in my values: `x = [-4 ± √(4² - 4 * 1 * 4)] / (2 * 1)`. That simplifies to `x = [-4 ± √(16 - 16)] / 2`, or `x = [-4 ± 0] / 2`. Therefore, `x = -2`. The discriminant being zero tells me I have exactly one real, repeated root. Great. So, whether I factor or use the quadratic formula, the answer is the same. + return nil +} + +// [END googlegenaisdk_thinking_includethoughts_with_txt] diff --git a/genai/thinking/thinking_examples_test.go b/genai/thinking/thinking_examples_test.go index 57478c0b8c..1e43bb37ef 100644 --- a/genai/thinking/thinking_examples_test.go +++ b/genai/thinking/thinking_examples_test.go @@ -30,6 +30,19 @@ func TestThinkingGeneration(t *testing.T) { buf := new(bytes.Buffer) + t.Run("generate content including thoughts", func(t *testing.T) { + buf.Reset() + err := generateContentWithThoughts(buf) + if err != nil { + t.Fatalf("generateContentWithThoughts failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + t.Run("generate content including with text", func(t *testing.T) { buf.Reset() err := generateContentWithTxt(buf) diff --git a/genai/tuning/tuning_examples_test.go b/genai/tuning/tuning_examples_test.go index 56b744527f..15b6b3bec6 100644 --- a/genai/tuning/tuning_examples_test.go +++ b/genai/tuning/tuning_examples_test.go @@ -152,4 +152,17 @@ func TestTuningGeneration(t *testing.T) { t.Error("expected non-empty output, got empty") } }) + + t.Run("list tuning jobs in project", func(t *testing.T) { + buf.Reset() + err := listTuningJobs(buf) + if err != nil { + t.Fatalf("listTuningJobs failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) } diff --git a/genai/tuning/tuning_list_jobs.go b/genai/tuning/tuning_list_jobs.go new file mode 100644 index 0000000000..348b230c07 --- /dev/null +++ b/genai/tuning/tuning_list_jobs.go @@ -0,0 +1,52 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package tuning shows how to use the GenAI SDK to list tuning jobs. +package tuning + +// [START googlegenaisdk_tuning_job_list] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// listTuningJobs demonstrates how to list tuning jobs. +func listTuningJobs(w io.Writer) error { + ctx := context.Background() + + client, err := genai.NewClient(ctx, &genai.ClientConfig{ + HTTPOptions: genai.HTTPOptions{APIVersion: "v1"}, + }) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + page, errList := client.Tunings.List(ctx, nil) + if errList != nil { + return fmt.Errorf("failed to list tuning jobs: %w", errList) + } + for _, job := range page.Items { + fmt.Fprintln(w, job.Name) + } + + // Example response: + // projects/123456789012/locations/us-central1/tuningJobs/123456789012345 + // ... + return nil +} + +// [END googlegenaisdk_tuning_job_list]