Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions genai/controlled_generation/controlled_generation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// 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 controlled_generation

import (
"bytes"
"testing"

"github.com/GoogleCloudPlatform/golang-samples/internal/testutil"
)

func TestTextGeneration(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 with enum schema", func(t *testing.T) {
buf.Reset()
err := generateWithEnumSchema(buf)
if err != nil {
t.Fatalf("generateWithEnumSchema failed: %v", err)
}

output := buf.String()
if output == "" {
t.Error("expected non-empty output, got empty")
}
})

t.Run("generate with response schema", func(t *testing.T) {
buf.Reset()
err := generateWithRespSchema(buf)
if err != nil {
t.Fatalf("generateWithRespSchema failed: %v", err)
}

output := buf.String()
if output == "" {
t.Error("expected non-empty output, got empty")
}
})

t.Run("generate with response schema with nullable values", func(t *testing.T) {
buf.Reset()
err := generateWithNullables(buf)
if err != nil {
t.Fatalf("generateWithNullables failed: %v", err)
}

output := buf.String()
if output == "" {
t.Error("expected non-empty output, got empty")
}
})
}
69 changes: 69 additions & 0 deletions genai/controlled_generation/ctrlgen_with_enum_schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// 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 controlled_generation shows how to use the GenAI SDK to generate text that adheres to a specific schema.
package controlled_generation

// [START googlegenaisdk_ctrlgen_with_enum_schema]
import (
"context"
"fmt"
"io"

genai "google.golang.org/genai"
)

// generateWithEnumSchema shows how to use enum schema to generate output.
func generateWithEnumSchema(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.0-flash-001"
contents := []*genai.Content{
{Parts: []*genai.Part{
{Text: "What type of instrument is an oboe?"},
}},
}
config := &genai.GenerateContentConfig{
ResponseMIMEType: "text/x.enum",
ResponseSchema: &genai.Schema{
Type: "STRING",
Enum: []string{"Percussion", "String", "Woodwind", "Brass", "Keyboard"},
},
}

resp, err := client.Models.GenerateContent(ctx, modelName, contents, config)
if err != nil {
return fmt.Errorf("failed to generate content: %w", err)
}

respText, err := resp.Text()
if err != nil {
return fmt.Errorf("failed to convert model response to text: %w", err)
}
fmt.Fprintln(w, respText)

// Example response:
// Woodwind

return nil
}

// [END googlegenaisdk_ctrlgen_with_enum_schema]
106 changes: 106 additions & 0 deletions genai/controlled_generation/ctrlgen_with_nullable_schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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 controlled_generation shows how to use the GenAI SDK to generate text that adheres to a specific schema.
package controlled_generation

// [START googlegenaisdk_ctrlgen_with_nullable_schema]
import (
"context"
"fmt"
"io"

genai "google.golang.org/genai"
)

// generateWithNullables shows how to use the response schema with nullable values.
func generateWithNullables(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.0-flash-001"
prompt := `
The week ahead brings a mix of weather conditions.
Sunday is expected to be sunny with a temperature of 77°F and a humidity level of 50%. Winds will be light at around 10 km/h.
Monday will see partly cloudy skies with a slightly cooler temperature of 72°F and the winds will pick up slightly to around 15 km/h.
Tuesday brings rain showers, with temperatures dropping to 64°F and humidity rising to 70%.
Wednesday may see thunderstorms, with a temperature of 68°F.
Thursday will be cloudy with a temperature of 66°F and moderate humidity at 60%.
Friday returns to partly cloudy conditions, with a temperature of 73°F and the Winds will be light at 12 km/h.
Finally, Saturday rounds off the week with sunny skies, a temperature of 80°F, and a humidity level of 40%. Winds will be gentle at 8 km/h.
`
contents := []*genai.Content{
{Parts: []*genai.Part{
{Text: prompt},
}},
}
config := &genai.GenerateContentConfig{
ResponseMIMEType: "application/json",
// See the OpenAPI specification for more details and examples:
// https://spec.openapis.org/oas/v3.0.3.html#schema-object
ResponseSchema: &genai.Schema{
Type: "object",
Properties: map[string]*genai.Schema{
"forecast": {
Type: "array",
Items: &genai.Schema{
Type: "object",
Properties: map[string]*genai.Schema{
"Day": {Type: "string", Nullable: true},
"Forecast": {Type: "string", Nullable: true},
"Temperature": {Type: "integer", Nullable: true},
"Humidity": {Type: "string", Nullable: true},
"Wind Speed": {Type: "integer", Nullable: true},
},
Required: []string{"Day", "Temperature", "Forecast", "Wind Speed"},
},
},
},
},
}

resp, err := client.Models.GenerateContent(ctx, modelName, contents, config)
if err != nil {
return fmt.Errorf("failed to generate content: %w", err)
}

respText, err := resp.Text()
if err != nil {
return fmt.Errorf("failed to convert model response to text: %w", err)
}
fmt.Fprintln(w, respText)

// Example response:
// {
// "forecast": [
// {"Day": "Sunday", "Forecast": "Sunny", "Temperature": 77, "Wind Speed": 10, "Humidity": "50%"},
// {"Day": "Monday", "Forecast": "Partly Cloudy", "Temperature": 72, "Wind Speed": 15},
// {"Day": "Tuesday", "Forecast": "Rain Showers", "Temperature": 64, "Wind Speed": null, "Humidity": "70%"},
// {"Day": "Wednesday", "Forecast": "Thunderstorms", "Temperature": 68, "Wind Speed": null},
// {"Day": "Thursday", "Forecast": "Cloudy", "Temperature": 66, "Wind Speed": null, "Humidity": "60%"},
// {"Day": "Friday", "Forecast": "Partly Cloudy", "Temperature": 73, "Wind Speed": 12},
// {"Day": "Saturday", "Forecast": "Sunny", "Temperature": 80, "Wind Speed": 8, "Humidity": "40%"}
// ]
// }

return nil
}

// [END googlegenaisdk_ctrlgen_with_nullable_schema]
94 changes: 94 additions & 0 deletions genai/controlled_generation/ctrlgen_with_resp_schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 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 controlled_generation shows how to use the GenAI SDK to generate text that adheres to a specific schema.
package controlled_generation

// [START googlegenaisdk_ctrlgen_with_resp_schema]
import (
"context"
"fmt"
"io"

genai "google.golang.org/genai"
)

// generateWithRespSchema shows how to use a response schema to generate output in a specific format.
func generateWithRespSchema(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)
}

config := &genai.GenerateContentConfig{
ResponseMIMEType: "application/json",
// See the OpenAPI specification for more details and examples:
// https://spec.openapis.org/oas/v3.0.3.html#schema-object
ResponseSchema: &genai.Schema{
Type: "array",
Items: &genai.Schema{
Type: "object",
Properties: map[string]*genai.Schema{
"recipe_name": {Type: "string"},
"ingredients": {
Type: "array",
Items: &genai.Schema{Type: "string"},
},
},
Required: []string{"recipe_name", "ingredients"},
},
},
}
contents := []*genai.Content{
{Parts: []*genai.Part{
{Text: "List a few popular cookie recipes."},
}},
}
modelName := "gemini-2.0-flash-001"

resp, err := client.Models.GenerateContent(ctx, modelName, contents, config)
if err != nil {
return fmt.Errorf("failed to generate content: %w", err)
}

respText, err := resp.Text()
if err != nil {
return fmt.Errorf("failed to convert model response to text: %w", err)
}
fmt.Fprintln(w, respText)

// Example response:
// [
// {
// "ingredients": [
// "2 1/4 cups all-purpose flour",
// "1 teaspoon baking soda",
// ...
// ],
// "recipe_name": "Chocolate Chip Cookies"
// },
// {
// ...
// },
// ...
// ]

return nil
}

// [END googlegenaisdk_ctrlgen_with_resp_schema]
Loading
Loading