Skip to content

Commit 16feb56

Browse files
controlled generation(genai): Add new code samples (#13109)
* controlled generation(genai): Add new code samples * controlled generation(genai): Add test case * controlled generation(genai): Update test file * controlled generation(genai): Update region tag prefix * controlled generation(genai): fix lint issues and add requirements-test.txt * controlled generation(genai): reviewer suggestions
1 parent cdfa595 commit 16feb56

7 files changed

+322
-0
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
def generate_content() -> str:
17+
# [START googlegenaisdk_ctrlgen_with_class_schema]
18+
from google import genai
19+
from pydantic import BaseModel, TypeAdapter
20+
21+
class Recipe(BaseModel):
22+
recipe_name: str
23+
ingredients: list[str]
24+
25+
client = genai.Client()
26+
response = client.models.generate_content(
27+
model="gemini-2.0-flash-001",
28+
contents="List a few popular cookie recipes.",
29+
config={
30+
"response_mime_type": "application/json",
31+
"response_schema": list[Recipe],
32+
},
33+
)
34+
# Use the response as a JSON string.
35+
print(response.text)
36+
37+
# Example output:
38+
# [Recipe(recipe_name='Chocolate Chip Cookies', ingredients=['2 1/4 cups all-purpose flour'
39+
# {
40+
# "ingredients": [
41+
# "2 1/4 cups all-purpose flour",
42+
# "1 teaspoon baking soda",
43+
# "1 teaspoon salt",
44+
# "1 cup (2 sticks) unsalted butter, softened",
45+
# "3/4 cup granulated sugar",
46+
# "3/4 cup packed brown sugar",
47+
# "1 teaspoon vanilla extract",
48+
# "2 large eggs",
49+
# "2 cups chocolate chips"
50+
# ],
51+
# "recipe_name": "Classic Chocolate Chip Cookies"
52+
# }, ... ]
53+
54+
# [END googlegenaisdk_ctrlgen_with_class_schema]
55+
return response.text
56+
57+
58+
if __name__ == "__main__":
59+
generate_content()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
def generate_content() -> str:
17+
# [START googlegenaisdk_ctrlgen_with_enum_schema]
18+
from google import genai
19+
20+
client = genai.Client()
21+
response = client.models.generate_content(
22+
model="gemini-2.0-flash-001",
23+
contents="What type of instrument is an oboe?",
24+
config={
25+
"response_mime_type": "text/x.enum",
26+
"response_schema": {
27+
"type": "STRING",
28+
"enum": ["Percussion", "String", "Woodwind", "Brass", "Keyboard"],
29+
},
30+
},
31+
)
32+
33+
print(response.text)
34+
# Example output:
35+
# Woodwind
36+
37+
# [END googlegenaisdk_ctrlgen_with_enum_schema]
38+
return response.text
39+
40+
41+
if __name__ == "__main__":
42+
generate_content()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
def generate_content() -> str:
17+
# [START googlegenaisdk_ctrlgen_with_nested_class_schema]
18+
from google import genai
19+
20+
import enum
21+
from pydantic import BaseModel
22+
23+
class Grade(enum.Enum):
24+
A_PLUS = "a+"
25+
A = "a"
26+
B = "b"
27+
C = "c"
28+
D = "d"
29+
F = "f"
30+
31+
class Recipe(BaseModel):
32+
recipe_name: str
33+
rating: Grade
34+
35+
client = genai.Client()
36+
response = client.models.generate_content(
37+
model="gemini-2.0-flash-001",
38+
contents="List about 10 home-baked cookies and give them grades based on tastiness.",
39+
config={
40+
"response_mime_type": "application/json",
41+
"response_schema": list[Recipe],
42+
},
43+
)
44+
45+
print(response.text)
46+
# Example output:
47+
# [{"rating": "a+", "recipe_name": "Classic Chocolate Chip Cookies"}, ...]
48+
49+
# [END googlegenaisdk_ctrlgen_with_nested_class_schema]
50+
return response.text
51+
52+
53+
if __name__ == "__main__":
54+
generate_content()
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
16+
def generate_content() -> str:
17+
# [START googlegenaisdk_ctrlgen_with_nullable_schema]
18+
from google import genai
19+
20+
response_schema = {
21+
"type": "OBJECT",
22+
"properties": {
23+
"forecast": {
24+
"type": "ARRAY",
25+
"items": {
26+
"type": "OBJECT",
27+
"properties": {
28+
"Day": {"type": "STRING", "nullable": True},
29+
"Forecast": {"type": "STRING", "nullable": True},
30+
"Temperature": {"type": "INTEGER", "nullable": True},
31+
"Humidity": {"type": "STRING", "nullable": True},
32+
"Wind Speed": {"type": "INTEGER", "nullable": True},
33+
},
34+
"required": ["Day", "Temperature", "Forecast", "Wind Speed"],
35+
},
36+
}
37+
},
38+
}
39+
40+
prompt = """
41+
The week ahead brings a mix of weather conditions.
42+
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.
43+
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.
44+
Tuesday brings rain showers, with temperatures dropping to 64°F and humidity rising to 70%.
45+
Wednesday may see thunderstorms, with a temperature of 68°F.
46+
Thursday will be cloudy with a temperature of 66°F and moderate humidity at 60%.
47+
Friday returns to partly cloudy conditions, with a temperature of 73°F and the Winds will be light at 12 km/h.
48+
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.
49+
"""
50+
51+
client = genai.Client()
52+
response = client.models.generate_content(
53+
model="gemini-2.0-flash-001",
54+
contents=prompt,
55+
config={
56+
"response_mime_type": "application/json",
57+
"response_schema": response_schema,
58+
},
59+
)
60+
61+
print(response.text)
62+
# Example output:
63+
# {"forecast": [{"Day": "Sunday", "Forecast": "sunny", "Temperature": 77, "Wind Speed": 10, "Humidity": "50%"},
64+
# {"Day": "Monday", "Forecast": "partly cloudy", "Temperature": 72, "Wind Speed": 15},
65+
# {"Day": "Tuesday", "Forecast": "rain showers", "Temperature": 64, "Wind Speed": null, "Humidity": "70%"},
66+
# {"Day": "Wednesday", "Forecast": "thunderstorms", "Temperature": 68, "Wind Speed": null},
67+
# {"Day": "Thursday", "Forecast": "cloudy", "Temperature": 66, "Wind Speed": null, "Humidity": "60%"},
68+
# {"Day": "Friday", "Forecast": "partly cloudy", "Temperature": 73, "Wind Speed": 12},
69+
# {"Day": "Saturday", "Forecast": "sunny", "Temperature": 80, "Wind Speed": 8, "Humidity": "40%"}]}
70+
71+
# [END googlegenaisdk_ctrlgen_with_nullable_schema]
72+
return response.text
73+
74+
75+
if __name__ == "__main__":
76+
generate_content()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2021 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Default TEST_CONFIG_OVERRIDE for python repos.
16+
17+
# You can copy this file into your directory, then it will be imported from
18+
# the noxfile.py.
19+
20+
# The source of truth:
21+
# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py
22+
23+
TEST_CONFIG_OVERRIDE = {
24+
# You can opt out from the test for specific Python versions.
25+
"ignored_versions": ["2.7", "3.7", "3.8", "3.10", "3.11", "3.12"],
26+
# Old samples are opted out of enforcing Python type hints
27+
# All new samples should feature them
28+
"enforce_type_hints": True,
29+
# An envvar key for determining the project id to use. Change it
30+
# to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
31+
# build specific Cloud project. You can also use your own string
32+
# to use your own Cloud project.
33+
"gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
34+
# 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
35+
# If you need to use a specific version of pip,
36+
# change pip_version_override to the string representation
37+
# of the version number, for example, "20.2.4"
38+
"pip_version_override": None,
39+
# A dictionary you want to inject into your test. Don't put any
40+
# secrets here. These values will override predefined values.
41+
"envs": {},
42+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
backoff==2.2.1
2+
google-api-core==2.19.0
3+
pytest==8.2.0
4+
pytest-asyncio==0.23.6
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
#
16+
# Using Google Cloud Vertex AI to test the code samples.
17+
#
18+
19+
import os
20+
21+
import ctrlgen_with_class_schema
22+
import ctrlgen_with_enum_schema
23+
import ctrlgen_with_nested_class_schema
24+
import ctrlgen_with_nullable_schema
25+
26+
os.environ["GOOGLE_GENAI_USE_VERTEXAI"] = "True"
27+
os.environ["GOOGLE_CLOUD_LOCATION"] = "us-central1"
28+
# The project name is included in the CICD pipeline
29+
# os.environ['GOOGLE_CLOUD_PROJECT'] = "add-your-project-name"
30+
31+
32+
def test_ctrlgen_with_class_schema() -> None:
33+
assert ctrlgen_with_class_schema.generate_content()
34+
35+
36+
def test_ctrlgen_with_enum_schema() -> None:
37+
assert ctrlgen_with_enum_schema.generate_content()
38+
39+
40+
def test_ctrlgen_with_nested_class_schema() -> None:
41+
assert ctrlgen_with_nested_class_schema.generate_content()
42+
43+
44+
def test_ctrlgen_with_nullable_schema() -> None:
45+
assert ctrlgen_with_nullable_schema.generate_content()

0 commit comments

Comments
 (0)