diff --git a/genai/image_generation/image_generation_examples_test.go b/genai/image_generation/image_generation_examples_test.go new file mode 100644 index 0000000000..b2d1216fd9 --- /dev/null +++ b/genai/image_generation/image_generation_examples_test.go @@ -0,0 +1,58 @@ +// 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 +// +// http://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 + +import ( + "bytes" + "testing" + + "github.com/GoogleCloudPlatform/golang-samples/internal/testutil" +) + +func TestImageGeneration(t *testing.T) { + tc := testutil.SystemTest(t) + + t.Setenv("GOOGLE_GENAI_USE_VERTEXAI", "1") + t.Setenv("GOOGLE_CLOUD_LOCATION", "global") + t.Setenv("GOOGLE_CLOUD_PROJECT", tc.ProjectID) + + buf := new(bytes.Buffer) + + 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..a0f85375f6 --- /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 := "testdata/bw-example-image.png" + inputFile := "testdata/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_with_txt.go b/genai/image_generation/imggen_with_txt.go new file mode 100644 index 0000000000..a374e4a909 --- /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 := "testdata/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/testdata/bw-example-image.png b/genai/image_generation/testdata/bw-example-image.png new file mode 100644 index 0000000000..89dc4566e5 Binary files /dev/null and b/genai/image_generation/testdata/bw-example-image.png differ diff --git a/genai/image_generation/testdata/dog_newspaper.png b/genai/image_generation/testdata/dog_newspaper.png new file mode 100644 index 0000000000..70234ae8a3 Binary files /dev/null and b/genai/image_generation/testdata/dog_newspaper.png differ diff --git a/genai/image_generation/testdata/example-image-eiffel-tower.png b/genai/image_generation/testdata/example-image-eiffel-tower.png new file mode 100644 index 0000000000..3628ddfa67 Binary files /dev/null and b/genai/image_generation/testdata/example-image-eiffel-tower.png differ 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 new file mode 100644 index 0000000000..c685c63ea0 --- /dev/null +++ b/genai/thinking/thinking_examples_test.go @@ -0,0 +1,45 @@ +// 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 +// +// http://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 + +import ( + "bytes" + "testing" + + "github.com/GoogleCloudPlatform/golang-samples/internal/testutil" +) + +func TestThinkingGeneration(t *testing.T) { + tc := testutil.SystemTest(t) + + t.Setenv("GOOGLE_GENAI_USE_VERTEXAI", "1") + t.Setenv("GOOGLE_CLOUD_LOCATION", "us-central1") + t.Setenv("GOOGLE_CLOUD_PROJECT", tc.ProjectID) + + 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") + } + }) +} diff --git a/genai/tuning/tuning_examples_test.go b/genai/tuning/tuning_examples_test.go new file mode 100644 index 0000000000..165f978d04 --- /dev/null +++ b/genai/tuning/tuning_examples_test.go @@ -0,0 +1,45 @@ +// 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 +// +// http://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 + +import ( + "bytes" + "testing" + + "github.com/GoogleCloudPlatform/golang-samples/internal/testutil" +) + +func TestTuningGeneration(t *testing.T) { + tc := testutil.SystemTest(t) + + t.Setenv("GOOGLE_GENAI_USE_VERTEXAI", "1") + t.Setenv("GOOGLE_CLOUD_LOCATION", "us-central1") + t.Setenv("GOOGLE_CLOUD_PROJECT", tc.ProjectID) + + buf := new(bytes.Buffer) + + 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]