diff --git a/genai/batch_prediction/batchpredict_embeddings_with_gcs.go b/genai/batch_prediction/batchpredict_embeddings_with_gcs.go new file mode 100644 index 0000000000..38c5a19eb2 --- /dev/null +++ b/genai/batch_prediction/batchpredict_embeddings_with_gcs.go @@ -0,0 +1,99 @@ +// 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 batch_prediction shows how to use the GenAI SDK to batch prediction. + +package batch_prediction + +// [START googlegenaisdk_batchpredict_embeddings_with_gcs] +import ( + "context" + "fmt" + "io" + "time" + + "google.golang.org/genai" +) + +// generateBatchEmbeddings shows how to run a batch embeddings prediction job. +func generateBatchEmbeddings(w io.Writer, outputURI string) error { + // outputURI = "gs://your-bucket/your-prefix" + 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 := "text-embedding-005" + // See the documentation: https://googleapis.github.io/python-genai/genai.html#genai.batches.Batches.create + job, err := client.Batches.Create(ctx, + modelName, + &genai.BatchJobSource{ + Format: "jsonl", + // Source link: https://storage.cloud.google.com/cloud-samples-data/generative-ai/embeddings/embeddings_input.jsonl + GCSURI: []string{"gs://cloud-samples-data/generative-ai/embeddings/embeddings_input.jsonl"}, + }, + &genai.CreateBatchJobConfig{ + Dest: &genai.BatchJobDestination{ + Format: "jsonl", + GCSURI: outputURI, + }, + }, + ) + if err != nil { + return fmt.Errorf("failed to create batch job: %w", err) + } + + fmt.Fprintf(w, "Job name: %s\n", job.Name) + fmt.Fprintf(w, "Job state: %s\n", job.State) + // Example response: + // Job name: projects/{PROJECT_ID}/locations/us-central1/batchPredictionJobs/9876453210000000000 + // Job state: JOB_STATE_PENDING + + // See the documentation: https://googleapis.github.io/python-genai/genai.html#genai.types.BatchJob + completedStates := map[genai.JobState]bool{ + genai.JobStateSucceeded: true, + genai.JobStateFailed: true, + genai.JobStateCancelled: true, + genai.JobStatePaused: true, + } + + // Poll until job finishes + for !completedStates[job.State] { + time.Sleep(30 * time.Second) + job, err = client.Batches.Get(ctx, job.Name, nil) + if err != nil { + return fmt.Errorf("failed to get batch job: %w", err) + } + fmt.Fprintf(w, "Job state: %s\n", job.State) + + if job.State == genai.JobStateFailed { + fmt.Fprintf(w, "Error: %+v\n", job.Error) + break + } + } + + // Example response: + // Job state: JOB_STATE_PENDING + // Job state: JOB_STATE_RUNNING + // Job state: JOB_STATE_RUNNING + // ... + // Job state: JOB_STATE_SUCCEEDED + + return nil +} + +// [END googlegenaisdk_batchpredict_embeddings_with_gcs] diff --git a/genai/batch_prediction/batchpredict_with_bq.go b/genai/batch_prediction/batchpredict_with_bq.go new file mode 100644 index 0000000000..085e383f00 --- /dev/null +++ b/genai/batch_prediction/batchpredict_with_bq.go @@ -0,0 +1,96 @@ +// 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 batch_prediction shows how to use the GenAI SDK to batch prediction. + +package batch_prediction + +// [START googlegenaisdk_batchpredict_with_bq] +import ( + "context" + "fmt" + "io" + "time" + + "google.golang.org/genai" +) + +// generateBatchPredictWithBQ shows how to run a batch prediction job with BigQuery input/output. +func generateBatchPredictWithBQ(w io.Writer, outputURI string) error { + // outputURI = "bq://your-project.your_dataset.your_table" + 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) + } + + // BigQuery input + src := &genai.BatchJobSource{ + Format: "bigquery", + BigqueryURI: "bq://storage-samples.generative_ai.batch_requests_for_multimodal_input", + } + + // BigQuery output + config := &genai.CreateBatchJobConfig{ + Dest: &genai.BatchJobDestination{ + Format: "bigquery", + BigqueryURI: outputURI, + }, + } + + // To use a tuned model, set the model param to your tuned model using the following format: + // modelName:= "projects/{PROJECT_ID}/locations/{LOCATION}/models/{MODEL_ID} + modelName := "gemini-2.5-flash" + job, err := client.Batches.Create(ctx, modelName, src, config) + if err != nil { + return fmt.Errorf("failed to create batch job: %w", err) + } + + fmt.Fprintf(w, "Job name: %s\n", job.Name) + fmt.Fprintf(w, "Job state: %s\n", job.State) + // Example response: + // Job name: projects/{PROJECT_ID}/locations/us-central1/batchPredictionJobs/9876453210000000000 + // Job state: JOB_STATE_PENDING + + // See the documentation: https://googleapis.github.io/python-genai/genai.html#genai.types.BatchJob + completedStates := map[genai.JobState]bool{ + genai.JobStateSucceeded: true, + genai.JobStateFailed: true, + genai.JobStateCancelled: true, + genai.JobStatePaused: true, + } + + for !completedStates[job.State] { + time.Sleep(30 * time.Second) + job, err = client.Batches.Get(ctx, job.Name, nil) + if err != nil { + return fmt.Errorf("failed to get batch job: %w", err) + } + fmt.Fprintf(w, "Job state: %s\n", job.State) + } + + // Example response: + // Job state: JOB_STATE_PENDING + // Job state: JOB_STATE_RUNNING + // Job state: JOB_STATE_RUNNING + // ... + // Job state: JOB_STATE_SUCCEEDED + + return nil +} + +// [END googlegenaisdk_batchpredict_with_bq] diff --git a/genai/batch_prediction/batchpredict_with_gcs.go b/genai/batch_prediction/batchpredict_with_gcs.go new file mode 100644 index 0000000000..433da01a2b --- /dev/null +++ b/genai/batch_prediction/batchpredict_with_gcs.go @@ -0,0 +1,99 @@ +// 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 batch_prediction shows how to use the GenAI SDK to batch prediction. + +package batch_prediction + +// [START googlegenaisdk_batchpredict_with_gcs] +import ( + "context" + "fmt" + "io" + "time" + + "google.golang.org/genai" +) + +// generateBatchPredict runs a batch prediction job using GCS input/output. +func generateBatchPredict(w io.Writer, outputURI string) error { + // outputURI = "gs://your-bucket/your-prefix" + 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) + } + + // Source file with prompts for prediction + src := &genai.BatchJobSource{ + Format: "jsonl", + // Source link: https://storage.cloud.google.com/cloud-samples-data/batch/prompt_for_batch_gemini_predict.jsonl + GCSURI: []string{"gs://cloud-samples-data/batch/prompt_for_batch_gemini_predict.jsonl"}, + } + + // Batch job config with output GCS location + config := &genai.CreateBatchJobConfig{ + Dest: &genai.BatchJobDestination{ + Format: "jsonl", + GCSURI: outputURI, + }, + } + // To use a tuned model, set the model param to your tuned model using the following format: + // modelName:= "projects/{PROJECT_ID}/locations/{LOCATION}/models/{MODEL_ID} + modelName := "gemini-2.5-flash" + // See the documentation: https://googleapis.github.io/python-genai/genai.html#genai.batches.Batches.create + job, err := client.Batches.Create(ctx, modelName, src, config) + if err != nil { + return fmt.Errorf("failed to create batch job: %w", err) + } + + fmt.Fprintf(w, "Job name: %s\n", job.Name) + fmt.Fprintf(w, "Job state: %s\n", job.State) + // Example response: + // Job name: projects/{PROJECT_ID}/locations/us-central1/batchPredictionJobs/9876453210000000000 + // Job state: JOB_STATE_PENDING + + // See the documentation: https://googleapis.github.io/python-genai/genai.html#genai.types.BatchJob + completedStates := map[genai.JobState]bool{ + genai.JobStateSucceeded: true, + genai.JobStateFailed: true, + genai.JobStateCancelled: true, + genai.JobStatePaused: true, + } + + for !completedStates[job.State] { + time.Sleep(30 * time.Second) + + job, err = client.Batches.Get(ctx, job.Name, nil) + if err != nil { + return fmt.Errorf("failed to get batch job: %w", err) + } + + fmt.Fprintf(w, "Job state: %s\n", job.State) + } + + // Example response: + // Job state: JOB_STATE_PENDING + // Job state: JOB_STATE_RUNNING + // Job state: JOB_STATE_RUNNING + // ... + // Job state: JOB_STATE_SUCCEEDED + + return nil +} + +// [END googlegenaisdk_batchpredict_with_gcs] diff --git a/genai/batch_prediction/batchprediction_examples_test.go b/genai/batch_prediction/batchprediction_examples_test.go new file mode 100644 index 0000000000..d076dac5eb --- /dev/null +++ b/genai/batch_prediction/batchprediction_examples_test.go @@ -0,0 +1,80 @@ +// 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 batch_prediction + +import ( + "bytes" + "fmt" + "testing" + "time" + + "github.com/GoogleCloudPlatform/golang-samples/internal/testutil" +) + +const gcsOutputBucket = "golang-docs-samples-tests" + +func TestBatchPrediction(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) + + prefix := fmt.Sprintf("embeddings_output/%d", time.Now().UnixNano()) + outputURI := fmt.Sprintf("gs://%s/%s", gcsOutputBucket, prefix) + buf := new(bytes.Buffer) + + t.Run("generate batch embeddings with GCS", func(t *testing.T) { + buf.Reset() + err := generateBatchEmbeddings(buf, outputURI) + if err != nil { + t.Fatalf("generateBatchEmbeddings failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + + t.Run("generate batch predict with gcs input/output", func(t *testing.T) { + buf.Reset() + err := generateBatchPredict(buf, outputURI) + if err != nil { + t.Fatalf("generateBatchPredict failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + + }) + + t.Run("generate batch predict with BigQuery", func(t *testing.T) { + buf.Reset() + outputURIBQ := "bq://your-project.your_dataset.your_table" + + err := generateBatchPredictWithBQ(buf, outputURIBQ) + if err != nil { + t.Fatalf("generateBatchPredictWithBQ failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) +} 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..00df420c64 --- /dev/null +++ b/genai/image_generation/image_generation_examples_test.go @@ -0,0 +1,104 @@ +// 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" +) + +func TestImageGeneration(t *testing.T) { + buf := new(bytes.Buffer) + + t.Run("style customization with style reference", func(t *testing.T) { + buf.Reset() + // TODO(developer): update with your bucket + outputGCSURI := "gs://your-bucket/your-prefix" + + err := generateStyleRefWithText(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateStyleRefWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected printed output, got empty") + } + }) + + t.Run("canny edge customization with text+image", func(t *testing.T) { + buf.Reset() + // TODO(developer): update with your bucket + outputGCSURI := "gs://your-bucket/your-prefix" + + err := generateCannyCtrlTypeWithText(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateCannyCtrlTypeWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + + t.Run("generate image with scribble control type", func(t *testing.T) { + buf.Reset() + // TODO(developer): update with your bucket + outputGCSURI := "gs://your-bucket/your-prefix" + + err := generateScribbleCtrlTypeWithText(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateScribbleCtrlTypeWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + + t.Run("subject customization with control reference", func(t *testing.T) { + buf.Reset() + // TODO(developer): update with your bucket + outputGCSURI := "gs://your-bucket/your-prefix" + + err := generateSubjRefCtrlReferWithText(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateSubjRefCtrlReferWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + + t.Run("generate style transfer customization with raw reference", func(t *testing.T) { + buf.Reset() + // TODO(developer): update with your bucket + outputGCSURI := "gs://your-bucket/your-prefix" + + err := generateRawReferWithText(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateRawReferWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) +} diff --git a/genai/image_generation/imggen_canny_ctrl_type_with_txt_img.go b/genai/image_generation/imggen_canny_ctrl_type_with_txt_img.go new file mode 100644 index 0000000000..d5584b75ed --- /dev/null +++ b/genai/image_generation/imggen_canny_ctrl_type_with_txt_img.go @@ -0,0 +1,81 @@ +// 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 from prompt. + +package image_generation + +// [START googlegenaisdk_imggen_canny_ctrl_type_with_txt_img] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateCannyCtrlTypeWithText demonstrates how to generate an image using a canny ctrl type. +func generateCannyCtrlTypeWithText(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + ctx := context.Background() + + client, err := genai.NewClient(ctx, nil) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + controlReference := &genai.ControlReferenceConfig{ + ControlType: genai.ControlReferenceTypeCanny, + } + + referenceImage := &genai.ControlReferenceImage{ + ReferenceID: 1, + ReferenceImage: &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/car_canny.png", + }, + Config: controlReference, + } + + modelName := "imagen-3.0-capability-001" + prompt := "a watercolor painting of a red car[1] driving on a road" + + resp, err := client.Models.EditImage(ctx, + modelName, + prompt, + []genai.ReferenceImage{referenceImage}, + &genai.EditImageConfig{ + EditMode: genai.EditModeControlledEditing, + NumberOfImages: 1, + SafetyFilterLevel: genai.SafetyFilterLevelBlockMediumAndAbove, + PersonGeneration: genai.PersonGenerationAllowAdult, + OutputGCSURI: outputGCSURI, + }, + ) + if err != nil { + return fmt.Errorf("failed to edit image: %w", err) + } + + if len(resp.GeneratedImages) == 0 || resp.GeneratedImages[0].Image == nil { + return fmt.Errorf("no image generated") + } + + uri := resp.GeneratedImages[0].Image.GCSURI + fmt.Fprintln(w, uri) + + // Example response: + // gs://your-bucket/your-prefix + return nil +} + +// [END googlegenaisdk_imggen_canny_ctrl_type_with_txt_img] diff --git a/genai/image_generation/imggen_raw_refer_with_txt_img.go b/genai/image_generation/imggen_raw_refer_with_txt_img.go new file mode 100644 index 0000000000..b437a8c5dd --- /dev/null +++ b/genai/image_generation/imggen_raw_refer_with_txt_img.go @@ -0,0 +1,80 @@ +// 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 from prompt. + +package image_generation + +// [START googlegenaisdk_imggen_raw_reference_with_txt_img] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateRawReferWithText demonstrates subject & control reference customization. +func generateRawReferWithText(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + ctx := context.Background() + + client, err := genai.NewClient(ctx, nil) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + // Create a raw reference image of teacup stored in Google Cloud Storage + // using https://storage.googleapis.com/cloud-samples-data/generative-ai/image/teacup-1.png + rawRefImage := &genai.RawReferenceImage{ + ReferenceID: 1, + ReferenceImage: &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/teacup-1.png", + }, + } + + prompt := "transform the subject in the image so that the teacup[1] is made entirely out of chocolate" + modelName := "imagen-3.0-capability-001" + + resp, err := client.Models.EditImage(ctx, + modelName, + prompt, + []genai.ReferenceImage{ + rawRefImage, + }, + &genai.EditImageConfig{ + EditMode: genai.EditModeDefault, + NumberOfImages: 1, + SafetyFilterLevel: genai.SafetyFilterLevelBlockMediumAndAbove, + PersonGeneration: genai.PersonGenerationAllowAdult, + OutputGCSURI: outputGCSURI, + }, + ) + if err != nil { + return fmt.Errorf("failed to edit image: %w", err) + } + + if len(resp.GeneratedImages) == 0 || resp.GeneratedImages[0].Image == nil { + return fmt.Errorf("no generated images returned") + } + + uri := resp.GeneratedImages[0].Image.GCSURI + fmt.Fprintln(w, uri) + + // Example response: + // gs://your-bucket/your-prefix + return nil +} + +// [END googlegenaisdk_imggen_raw_reference_with_txt_img] diff --git a/genai/image_generation/imggen_scribble_ctrl_type_with_txt_img.go b/genai/image_generation/imggen_scribble_ctrl_type_with_txt_img.go new file mode 100644 index 0000000000..48d5ae7e73 --- /dev/null +++ b/genai/image_generation/imggen_scribble_ctrl_type_with_txt_img.go @@ -0,0 +1,81 @@ +// 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 from prompt. + +package image_generation + +// [START googlegenaisdk_imggen_scribble_ctrl_type_with_txt_img] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateScribbleCtrlTypeWithText demonstrates how to generate an image using a scribble ctrl type. +func generateScribbleCtrlTypeWithText(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + ctx := context.Background() + + client, err := genai.NewClient(ctx, nil) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + controlReference := &genai.ControlReferenceConfig{ + ControlType: genai.ControlReferenceTypeScribble, + } + + referenceImage := &genai.ControlReferenceImage{ + ReferenceID: 1, + ReferenceImage: &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/car_scribble.png", + }, + Config: controlReference, + } + + modelName := "imagen-3.0-capability-001" + prompt := "an oil painting showing the side of a red car[1]" + + resp, err := client.Models.EditImage(ctx, + modelName, + prompt, + []genai.ReferenceImage{referenceImage}, + &genai.EditImageConfig{ + EditMode: genai.EditModeControlledEditing, + NumberOfImages: 1, + SafetyFilterLevel: genai.SafetyFilterLevelBlockMediumAndAbove, + PersonGeneration: genai.PersonGenerationAllowAdult, + OutputGCSURI: outputGCSURI, + }, + ) + if err != nil { + return fmt.Errorf("failed to edit image: %w", err) + } + + if len(resp.GeneratedImages) == 0 || resp.GeneratedImages[0].Image == nil { + return fmt.Errorf("no image generated") + } + + uri := resp.GeneratedImages[0].Image.GCSURI + fmt.Fprintln(w, uri) + + // Example response: + // gs://your-bucket/your-prefix + return nil +} + +// [END googlegenaisdk_imggen_scribble_ctrl_type_with_txt_img] diff --git a/genai/image_generation/imggen_styleref_with_txt_img.go b/genai/image_generation/imggen_styleref_with_txt_img.go new file mode 100644 index 0000000000..391e7e27e2 --- /dev/null +++ b/genai/image_generation/imggen_styleref_with_txt_img.go @@ -0,0 +1,86 @@ +// 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 from prompt. + +package image_generation + +// [START googlegenaisdk_imggen_style_reference_with_txt_img] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateStyleRefWithText demonstrates how to generate an image using a style reference. +func generateStyleRefWithText(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + ctx := context.Background() + + client, err := genai.NewClient(ctx, nil) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + // Create a style reference image of a neon sign stored in Google Cloud Storage + // using https://storage.googleapis.com/cloud-samples-data/generative-ai/image/neon.png + styleRefImg := &genai.StyleReferenceImage{ + ReferenceID: 1, + ReferenceImage: &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/neon.png", + }, + Config: &genai.StyleReferenceConfig{ + StyleDescription: "neon sign", + }, + } + + // prompt that references the style image with [1] + prompt := "generate an image of a neon sign [1] with the words: have a great day" + modelName := "imagen-3.0-capability-001" + + // EditImage takes: ctx, model, prompt, referenceImages []ReferenceImage, config *EditImageConfig + resp, err := client.Models.EditImage(ctx, + modelName, + prompt, + []genai.ReferenceImage{ + styleRefImg, + }, + &genai.EditImageConfig{ + EditMode: genai.EditModeDefault, + NumberOfImages: 1, + SafetyFilterLevel: genai.SafetyFilterLevelBlockMediumAndAbove, + PersonGeneration: genai.PersonGenerationAllowAdult, + OutputGCSURI: outputGCSURI, + }, + ) + if err != nil { + return fmt.Errorf("failed to edit image: %w", err) + } + + if len(resp.GeneratedImages) == 0 || resp.GeneratedImages[0].Image == nil { + return fmt.Errorf("no generated images returned") + } + + // Grab the first generated image URI and print it + uri := resp.GeneratedImages[0].Image.GCSURI + fmt.Fprintln(w, uri) + + // Example response: + // gs://your-bucket/your-prefix + return nil +} + +// [END googlegenaisdk_imggen_style_reference_with_txt_img] diff --git a/genai/image_generation/imggen_subj_refer_ctrl_refer_with_txt_imgs.go b/genai/image_generation/imggen_subj_refer_ctrl_refer_with_txt_imgs.go new file mode 100644 index 0000000000..43f48c754e --- /dev/null +++ b/genai/image_generation/imggen_subj_refer_ctrl_refer_with_txt_imgs.go @@ -0,0 +1,96 @@ +// 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 from prompt. + +package image_generation + +// [START googlegenaisdk_imggen_subj_refer_ctrl_refer_with_txt_imgs] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateSubjRefCtrlReferWithText demonstrates subject & control reference customization. +func generateSubjRefCtrlReferWithText(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + ctx := context.Background() + + client, err := genai.NewClient(ctx, nil) + if err != nil { + return fmt.Errorf("failed to create genai client: %w", err) + } + + // Create subject and control reference images of a photograph stored in Google Cloud Storage + // using https://storage.googleapis.com/cloud-samples-data/generative-ai/image/person.png + subjectReferenceImage := &genai.SubjectReferenceImage{ + ReferenceID: 1, + ReferenceImage: &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/person.png", + }, + Config: &genai.SubjectReferenceConfig{ + SubjectType: genai.SubjectReferenceTypeSubjectTypePerson, + SubjectDescription: "a headshot of a woman", + }, + } + + controlReferenceImage := &genai.ControlReferenceImage{ + ReferenceID: 2, + ReferenceImage: &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/person.png", + }, + Config: &genai.ControlReferenceConfig{ + ControlType: genai.ControlReferenceTypeFaceMesh, + }, + } + + // prompt that references the style image with [1] + prompt := "a portrait of a woman[1] in the pose of the control image[2] in a watercolor style by a professional artist, light and low-contrast strokes, bright pastel colors, a warm atmosphere, clean background, grainy paper, bold visible brushstrokes, patchy details" + modelName := "imagen-3.0-capability-001" + + resp, err := client.Models.EditImage(ctx, + modelName, + prompt, + []genai.ReferenceImage{ + subjectReferenceImage, + controlReferenceImage, + }, + &genai.EditImageConfig{ + EditMode: genai.EditModeDefault, + NumberOfImages: 1, + SafetyFilterLevel: genai.SafetyFilterLevelBlockMediumAndAbove, + PersonGeneration: genai.PersonGenerationAllowAdult, + OutputGCSURI: outputGCSURI, + }, + ) + if err != nil { + return fmt.Errorf("failed to edit image: %w", err) + } + + if len(resp.GeneratedImages) == 0 || resp.GeneratedImages[0].Image == nil { + return fmt.Errorf("no generated images returned") + } + + uri := resp.GeneratedImages[0].Image.GCSURI + fmt.Fprintln(w, uri) + + // Example response: + // gs://your-bucket/your-prefix + return nil +} + +// [END googlegenaisdk_imggen_subj_refer_ctrl_refer_with_txt_imgs] diff --git a/genai/tools/tools_examples_test.go b/genai/tools/tools_examples_test.go index 867e868ae1..eff5262c5c 100644 --- a/genai/tools/tools_examples_test.go +++ b/genai/tools/tools_examples_test.go @@ -16,6 +16,7 @@ package tools import ( "bytes" + "fmt" "testing" "github.com/GoogleCloudPlatform/golang-samples/internal/testutil" @@ -68,4 +69,18 @@ func TestTextGeneration(t *testing.T) { t.Error("expected non-empty output, got empty") } }) + + t.Run("generate with VAIS Search", func(t *testing.T) { + buf.Reset() + dataStore := fmt.Sprintf("projects/%s/locations/global/collections/default_collection/dataStores/grounding-test-datastore", tc.ProjectID) + err := generateWithGoogleVAIS(buf, dataStore) + if err != nil { + t.Fatalf("generateWithGoogleVAIS failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) } diff --git a/genai/tools/tools_vais_search_with_txt.go b/genai/tools/tools_vais_search_with_txt.go new file mode 100644 index 0000000000..250df01ffd --- /dev/null +++ b/genai/tools/tools_vais_search_with_txt.go @@ -0,0 +1,68 @@ +// 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 tools shows examples of various tools that Gemini model can use to generate text. +package tools + +// [START googlegenaisdk_tools_vais_with_txt] +import ( + "context" + "fmt" + "io" + + "google.golang.org/genai" +) + +// generateWithGoogleVAIS shows how to generate text using VAIS Search. +func generateWithGoogleVAIS(w io.Writer, datastore string) error { + //datastore = "gs://your-datastore/your-prefix" + 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-flash" + contents := genai.Text("How do I make an appointment to renew my driver's license?") + config := &genai.GenerateContentConfig{ + Tools: []*genai.Tool{ + { + Retrieval: &genai.Retrieval{ + VertexAISearch: &genai.VertexAISearch{ + Datastore: datastore, + }, + }, + }, + }, + } + + resp, err := client.Models.GenerateContent(ctx, modelName, contents, config) + if err != nil { + return fmt.Errorf("failed to generate content: %w", err) + } + + respText := resp.Text() + + fmt.Fprintln(w, respText) + + // Example response: + // 'The process for making an appointment to renew your driver's license varies depending on your location. To provide you with the most accurate instructions...' + + return nil +} + +// [END googlegenaisdk_tools_vais_with_txt] diff --git a/genai/video_generation/video_gen_with_img.go b/genai/video_generation/video_gen_with_img.go new file mode 100644 index 0000000000..c52b97189e --- /dev/null +++ b/genai/video_generation/video_gen_with_img.go @@ -0,0 +1,78 @@ +// 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 video_generation shows how to use the GenAI SDK to generate video. +package video_generation + +// [START googlegenaisdk_videogen_with_img] +import ( + "context" + "fmt" + "io" + "time" + + "google.golang.org/genai" +) + +// generateVideoFromImage shows how to gen video from img. +func generateVideoFromImage(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + 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 := &genai.Image{ + GCSURI: "gs://cloud-samples-data/generative-ai/image/flowers.png", + MIMEType: "image/png", + } + + config := &genai.GenerateVideosConfig{ + AspectRatio: "16:9", + OutputGCSURI: outputGCSURI, + } + + modelName := "veo-3.0-generate-preview" + prompt := "Extreme close-up of a cluster of vibrant wildflowers swaying gently in a sun-drenched meadow." + operation, err := client.Models.GenerateVideos(ctx, modelName, prompt, image, config) + if err != nil { + return fmt.Errorf("failed to start video generation: %w", err) + } + + // Polling until the operation is done + for !operation.Done { + time.Sleep(15 * time.Second) + operation, err = client.Operations.GetVideosOperation(ctx, operation, nil) + if err != nil { + return fmt.Errorf("failed to get operation status: %w", err) + } + } + + if operation.Response != nil && len(operation.Response.GeneratedVideos) > 0 { + videoURI := operation.Response.GeneratedVideos[0].Video.URI + fmt.Fprintln(w, videoURI) + return nil + } + + // Example response: + // gs://your-bucket/your-prefix/videoURI + + return fmt.Errorf("video generation failed or returned no results") +} + +// [END googlegenaisdk_videogen_with_img] diff --git a/genai/video_generation/video_gen_with_txt.go b/genai/video_generation/video_gen_with_txt.go new file mode 100644 index 0000000000..922e153111 --- /dev/null +++ b/genai/video_generation/video_gen_with_txt.go @@ -0,0 +1,73 @@ +// 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 video_generation shows how to use the GenAI SDK to generate video. +package video_generation + +// [START googlegenaisdk_videogen_with_txt] +import ( + "context" + "fmt" + "io" + "time" + + "google.golang.org/genai" +) + +// generateVideoWithText shows how to gen video from text. +func generateVideoWithText(w io.Writer, outputGCSURI string) error { + //outputGCSURI = "gs://your-bucket/your-prefix" + 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) + } + + config := &genai.GenerateVideosConfig{ + AspectRatio: "16:9", + OutputGCSURI: outputGCSURI, + } + + modelName := "veo-3.0-generate-preview" + prompt := "a cat reading a book" + operation, err := client.Models.GenerateVideos(ctx, modelName, prompt, nil, config) + if err != nil { + return fmt.Errorf("failed to start video generation: %w", err) + } + + // Polling until the operation is done + for !operation.Done { + time.Sleep(15 * time.Second) + operation, err = client.Operations.GetVideosOperation(ctx, operation, nil) + if err != nil { + return fmt.Errorf("failed to get operation status: %w", err) + } + } + + if operation.Response != nil && len(operation.Response.GeneratedVideos) > 0 { + videoURI := operation.Response.GeneratedVideos[0].Video.URI + fmt.Fprintln(w, videoURI) + return nil + } + + // Example response: + // gs://your-bucket/your-prefix/videoURI + + return fmt.Errorf("video generation failed or returned no results") +} + +// [END googlegenaisdk_videogen_with_txt] diff --git a/genai/video_generation/video_generation_examples_test.go b/genai/video_generation/video_generation_examples_test.go new file mode 100644 index 0000000000..591cfc8313 --- /dev/null +++ b/genai/video_generation/video_generation_examples_test.go @@ -0,0 +1,64 @@ +// 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 video_generation + +import ( + "bytes" + "testing" + "time" + + "github.com/GoogleCloudPlatform/golang-samples/internal/testutil" +) + +func TestVideoGeneration(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) + + gcsOutputBucket := "HERE-go-bucket-samples-tests" + prefix := "go_videogen_test/" + time.Now().Format("20060102-150405") + outputGCSURI := "gs://" + gcsOutputBucket + "/" + prefix + + t.Run("generate video content with img", func(t *testing.T) { + buf.Reset() + err := generateVideoFromImage(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateVideoFromImage failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + + t.Run("generate video content with text", func(t *testing.T) { + buf.Reset() + err := generateVideoWithText(buf, outputGCSURI) + if err != nil { + t.Fatalf("generateVideoWithText failed: %v", err) + } + + output := buf.String() + if output == "" { + t.Error("expected non-empty output, got empty") + } + }) + +}