From 1a66262a5e42126d3a5fe98fb0347c2275bf8d13 Mon Sep 17 00:00:00 2001 From: Mengqin Shen Date: Thu, 22 Jan 2026 16:37:27 -0800 Subject: [PATCH 1/2] fix(py): fixed broken flows in menu sample --- py/samples/menu/pyproject.toml | 12 ++++++- py/samples/menu/src/case_02/flows.py | 2 +- py/samples/menu/src/case_03/flows.py | 2 +- py/samples/menu/src/case_04/flows.py | 48 ++++++++++++++++++++++++++-- py/samples/menu/src/case_05/flows.py | 15 +++++---- py/samples/menu/src/main.py | 1 + py/samples/menu/src/menu_ai.py | 5 ++- py/samples/menu/src/menu_schemas.py | 23 +++++++++++-- 8 files changed, 93 insertions(+), 15 deletions(-) diff --git a/py/samples/menu/pyproject.toml b/py/samples/menu/pyproject.toml index 7ba7975d49..d2e4006dd9 100644 --- a/py/samples/menu/pyproject.toml +++ b/py/samples/menu/pyproject.toml @@ -54,4 +54,14 @@ build-backend = "hatchling.build" requires = ["hatchling"] [tool.hatch.build.targets.wheel] -packages = ["src/menu"] +packages = ["src"] + +[tool.uv.sources] +genkit = { workspace = true } +genkit-plugin-dev-local-vectorstore = { workspace = true } +genkit-plugin-firebase = { workspace = true } +genkit-plugin-google-genai = { workspace = true } +genkit-plugin-google-cloud = { workspace = true } +genkit-plugin-ollama = { workspace = true } +genkit-plugin-vertex-ai = { workspace = true } + diff --git a/py/samples/menu/src/case_02/flows.py b/py/samples/menu/src/case_02/flows.py index b0ef54f9d0..8be39a07cb 100644 --- a/py/samples/menu/src/case_02/flows.py +++ b/py/samples/menu/src/case_02/flows.py @@ -21,7 +21,7 @@ from .prompts import s02_dataMenuPrompt -@ai.flow(name='s02_menuQuestion') +@ai.flow(name='s02_menu_question') async def s02_menuQuestionFlow( my_input: MenuQuestionInputSchema, ) -> AnswerOutputSchema: diff --git a/py/samples/menu/src/case_03/flows.py b/py/samples/menu/src/case_03/flows.py index 7b6668104c..f90cce191f 100644 --- a/py/samples/menu/src/case_03/flows.py +++ b/py/samples/menu/src/case_03/flows.py @@ -61,7 +61,7 @@ ) -@ai.flow(name='s03_multiTurnChat') +@ai.flow(name='s03_multi_turn_chat') async def s03_multiTurnChatFlow( my_input: ChatSessionInputSchema, ) -> ChatSessionOutputSchema: diff --git a/py/samples/menu/src/case_04/flows.py b/py/samples/menu/src/case_04/flows.py index 2377e743fd..fa6baf730f 100644 --- a/py/samples/menu/src/case_04/flows.py +++ b/py/samples/menu/src/case_04/flows.py @@ -27,10 +27,54 @@ class IndexMenuItemsOutputSchema(BaseModel): rows: int = Field(...) -@ai.flow(name='s04_indexMenuItems') +@ai.flow(name='s04_index_menu_items') async def s04_indexMenuItemsFlow( menu_items: list[MenuItemSchema], ) -> IndexMenuItemsOutputSchema: + # If empty list provided (e.g., from Dev UI default), use the default menu items + if not menu_items: + menu_items = [ + MenuItemSchema( + title='White Meat Crispy Chicken Wings', + description="All-white meat chicken wings tossed in your choice of wing sauce. Choose from classic buffalo, honey bbq, garlic parmesan, or sweet & sour", + price=12.0, + ), + MenuItemSchema(title='Cheese Fries', description='Fresh fries covered with melted cheddar cheese and bacon', price=8.0), + MenuItemSchema( + title='Reuben', + description='Classic Reuben sandwich with corned beef, sauerkraut, Swiss cheese, and Thousand Island dressing on grilled rye bread.', + price=12.0, + ), + MenuItemSchema( + title='Grilled Chicken Club Wrap', + description='Grilled chicken, bacon, lettuce, tomato, pickles, and cheddar cheese wrapped in a spinach tortilla, served with your choice of dressing', + price=12.0, + ), + MenuItemSchema( + title='Buffalo Chicken Sandwich', + description='Fried chicken breast coated in your choice of wing sauce, topped with lettuce, tomato, onion, and pickles on a toasted brioche roll.', + price=12.0, + ), + MenuItemSchema( + title='Half Cuban Sandwich', + description='Slow roasted pork butt, ham, Swiss, and yellow mustard on a toasted baguette', + price=12.0, + ), + MenuItemSchema( + title='The Albie Burger', + description='Classic burger topped with bacon, provolone, banana peppers, and chipotle mayo', + price=13.0, + ), + MenuItemSchema(title='57 Chevy Burger', description='Heaven burger with your choice of cheese', price=14.0), + MenuItemSchema( + title='Chicken Caesar Wrap', + description='Tender grilled chicken, romaine lettuce, croutons, and Parmesan cheese tossed in a creamy Caesar dressing and wrapped in a spinach tortilla', + price=10.0, + ), + MenuItemSchema(title='Kids Hot Dog', description='Kids under 12', price=5.0), + MenuItemSchema(title='Chicken Fingers', description='Tender chicken strips, grilled or fried', price=8.0), + ] + documents = [ Document.from_text(f'{item.title} {item.price} \n {item.description}', metadata=item.model_dump()) for item in menu_items @@ -43,7 +87,7 @@ async def s04_indexMenuItemsFlow( return IndexMenuItemsOutputSchema(rows=len(menu_items)) -@ai.flow(name='s04_ragMenuQuestion') +@ai.flow(name='s04_rag_menu_question') async def s04_ragMenuQuestionFlow( my_input: MenuQuestionInputSchema, ) -> AnswerOutputSchema: diff --git a/py/samples/menu/src/case_05/flows.py b/py/samples/menu/src/case_05/flows.py index e6fe2dbcee..b16e06a7e2 100644 --- a/py/samples/menu/src/case_05/flows.py +++ b/py/samples/menu/src/case_05/flows.py @@ -27,32 +27,35 @@ ) -@ai.flow(name='s05_readMenu') +@ai.flow(name='s05_read_menu') async def s05_readMenuFlow(_: None = None) -> str: image_data_url = inline_data_url('menu.jpeg', 'image/jpeg') response = await s05_readMenuPrompt({'imageUrl': image_data_url}) return response.text -@ai.flow(name='s05_textMenuQuestion') +@ai.flow(name='s05_text_menu_question') async def s05_textMenuQuestionFlow( my_input: TextMenuQuestionInputSchema, ) -> AnswerOutputSchema: - response = await s05_textMenuPrompt({'menuText': my_input.menuText, 'question': my_input.question}) + response = await s05_textMenuPrompt({'menuText': my_input.menu_text, 'question': my_input.question}) return AnswerOutputSchema( answer=response.text, ) -@ai.flow(name='s05_visionMenuQuestion') +@ai.flow(name='s05_vision_menu_question') async def s05_visionMenuQuestionFlow( my_input: MenuQuestionInputSchema, ) -> AnswerOutputSchema: + # If empty question provided (e.g., from Dev UI default), use the default question + question = my_input.question if my_input.question else 'What kind of burger buns do you have?' + menu_text = await s05_readMenuFlow() return await s05_textMenuQuestionFlow( TextMenuQuestionInputSchema( - question=my_input.question, - menuText=menu_text, + question=question, + menu_text=menu_text, ) ) diff --git a/py/samples/menu/src/main.py b/py/samples/menu/src/main.py index e17e94d117..ceb9896662 100755 --- a/py/samples/menu/src/main.py +++ b/py/samples/menu/src/main.py @@ -39,3 +39,4 @@ async def main(): if __name__ == '__main__': ai.run_main(main()) + diff --git a/py/samples/menu/src/menu_ai.py b/py/samples/menu/src/menu_ai.py index 5d711a2a70..e6c2c0f917 100644 --- a/py/samples/menu/src/menu_ai.py +++ b/py/samples/menu/src/menu_ai.py @@ -22,7 +22,10 @@ from genkit.plugins.google_genai import GoogleAI if 'GEMINI_API_KEY' not in os.environ: - os.environ['GEMINI_API_KEY'] = input('Please enter your GEMINI_API_KEY: ') + print('GEMINI_API_KEY not set. Some features may not work.') + print('To run full examples, set GEMINI_API_KEY environment variable.') + os.environ['GEMINI_API_KEY'] = 'placeholder_key_for_dev_ui' + ai = Genkit(plugins=[GoogleAI()]) diff --git a/py/samples/menu/src/menu_schemas.py b/py/samples/menu/src/menu_schemas.py index 2bc35cf4fb..11d66dfbc3 100644 --- a/py/samples/menu/src/menu_schemas.py +++ b/py/samples/menu/src/menu_schemas.py @@ -29,7 +29,7 @@ class MenuItemSchema(BaseModel): class MenuQuestionInputSchema(BaseModel): """Input schema for the menu question prompt.""" - question: str = Field(..., description='A question about the menu') + question: str = Field(default='What kind of burger buns do you have?', description='A question about the menu') class AnswerOutputSchema(BaseModel): @@ -48,8 +48,25 @@ class DataMenuQuestionInputSchema(BaseModel): class TextMenuQuestionInputSchema(BaseModel): """Input schema for the text menu question prompt.""" - menu_text: str = Field(...) - question: str = Field(..., description='A question about the menu') + menu_text: str = Field( + default="""APPETIZERS +- Mozzarella Sticks $8 - Crispy fried mozzarella sticks served with marinara sauce +- Chicken Wings $10 - Crispy fried chicken wings tossed in your choice of sauce +- Nachos $12 - Crispy tortilla chips topped with melted cheese, chili, sour cream, and salsa + +BURGERS & SANDWICHES +- Classic Cheeseburger $12 - A juicy beef patty topped with melted American cheese, lettuce, tomato, and onion on a toasted bun +- Bacon Cheeseburger $14 - A classic cheeseburger with the addition of crispy bacon +- Mushroom Swiss Burger $15 - A beef patty topped with sautéed mushrooms, melted Swiss cheese, and a creamy horseradish sauce +- Chicken Sandwich $13 - A crispy chicken breast on a toasted bun with lettuce, tomato, and your choice of sauce + +SALADS +- House Salad $8 - Mixed greens with your choice of dressing +- Caesar Salad $9 - Romaine lettuce with croutons, Parmesan cheese, and Caesar dressing""", + description='The menu text content', + alias='menuText', + ) + question: str = Field(default='What kind of burger buns do you have?', description='A question about the menu') class MenuToolOutputSchema(BaseModel): From 5036075f83aa872160d08b1e398baed144e0dc7f Mon Sep 17 00:00:00 2001 From: Mengqin Shen Date: Thu, 22 Jan 2026 17:04:34 -0800 Subject: [PATCH 2/2] fix(py): revised with gemini comments --- py/samples/menu/src/case_04/flows.py | 50 +++++----------------------- py/samples/menu/src/case_05/flows.py | 5 +-- py/samples/menu/src/constants.py | 36 ++++++++++++++++++++ py/samples/menu/src/main.py | 1 - py/samples/menu/src/menu_ai.py | 9 +++-- py/samples/menu/src/menu_schemas.py | 20 +++-------- 6 files changed, 57 insertions(+), 64 deletions(-) create mode 100644 py/samples/menu/src/constants.py diff --git a/py/samples/menu/src/case_04/flows.py b/py/samples/menu/src/case_04/flows.py index fa6baf730f..3541986616 100644 --- a/py/samples/menu/src/case_04/flows.py +++ b/py/samples/menu/src/case_04/flows.py @@ -14,6 +14,9 @@ # # SPDX-License-Identifier: Apache-2.0 +import json +import os + from menu_ai import ai from menu_schemas import AnswerOutputSchema, MenuItemSchema, MenuQuestionInputSchema from pydantic import BaseModel, Field @@ -31,49 +34,12 @@ class IndexMenuItemsOutputSchema(BaseModel): async def s04_indexMenuItemsFlow( menu_items: list[MenuItemSchema], ) -> IndexMenuItemsOutputSchema: - # If empty list provided (e.g., from Dev UI default), use the default menu items + # If empty list provided (e.g., from Dev UI default), load from example file if not menu_items: - menu_items = [ - MenuItemSchema( - title='White Meat Crispy Chicken Wings', - description="All-white meat chicken wings tossed in your choice of wing sauce. Choose from classic buffalo, honey bbq, garlic parmesan, or sweet & sour", - price=12.0, - ), - MenuItemSchema(title='Cheese Fries', description='Fresh fries covered with melted cheddar cheese and bacon', price=8.0), - MenuItemSchema( - title='Reuben', - description='Classic Reuben sandwich with corned beef, sauerkraut, Swiss cheese, and Thousand Island dressing on grilled rye bread.', - price=12.0, - ), - MenuItemSchema( - title='Grilled Chicken Club Wrap', - description='Grilled chicken, bacon, lettuce, tomato, pickles, and cheddar cheese wrapped in a spinach tortilla, served with your choice of dressing', - price=12.0, - ), - MenuItemSchema( - title='Buffalo Chicken Sandwich', - description='Fried chicken breast coated in your choice of wing sauce, topped with lettuce, tomato, onion, and pickles on a toasted brioche roll.', - price=12.0, - ), - MenuItemSchema( - title='Half Cuban Sandwich', - description='Slow roasted pork butt, ham, Swiss, and yellow mustard on a toasted baguette', - price=12.0, - ), - MenuItemSchema( - title='The Albie Burger', - description='Classic burger topped with bacon, provolone, banana peppers, and chipotle mayo', - price=13.0, - ), - MenuItemSchema(title='57 Chevy Burger', description='Heaven burger with your choice of cheese', price=14.0), - MenuItemSchema( - title='Chicken Caesar Wrap', - description='Tender grilled chicken, romaine lettuce, croutons, and Parmesan cheese tossed in a creamy Caesar dressing and wrapped in a spinach tortilla', - price=10.0, - ), - MenuItemSchema(title='Kids Hot Dog', description='Kids under 12', price=5.0), - MenuItemSchema(title='Chicken Fingers', description='Tender chicken strips, grilled or fried', price=8.0), - ] + example_file = os.path.join(os.path.dirname(__file__), 'example.indexMenuItems.json') + with open(example_file, 'r') as f: + menu_data = json.load(f) + menu_items = [MenuItemSchema(**item) for item in menu_data] documents = [ Document.from_text(f'{item.title} {item.price} \n {item.description}', metadata=item.model_dump()) diff --git a/py/samples/menu/src/case_05/flows.py b/py/samples/menu/src/case_05/flows.py index b16e06a7e2..d254bf7ff4 100644 --- a/py/samples/menu/src/case_05/flows.py +++ b/py/samples/menu/src/case_05/flows.py @@ -19,6 +19,7 @@ import os from case_05.prompts import s05_readMenuPrompt, s05_textMenuPrompt +from constants import DEFAULT_MENU_QUESTION from menu_ai import ai from menu_schemas import ( AnswerOutputSchema, @@ -49,8 +50,8 @@ async def s05_visionMenuQuestionFlow( my_input: MenuQuestionInputSchema, ) -> AnswerOutputSchema: # If empty question provided (e.g., from Dev UI default), use the default question - question = my_input.question if my_input.question else 'What kind of burger buns do you have?' - + question = my_input.question if my_input.question else DEFAULT_MENU_QUESTION + menu_text = await s05_readMenuFlow() return await s05_textMenuQuestionFlow( TextMenuQuestionInputSchema( diff --git a/py/samples/menu/src/constants.py b/py/samples/menu/src/constants.py new file mode 100644 index 0000000000..91c245adf7 --- /dev/null +++ b/py/samples/menu/src/constants.py @@ -0,0 +1,36 @@ +# Copyright 2026 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. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Constants used across the menu sample.""" + +# Default question for menu-related flows +DEFAULT_MENU_QUESTION = 'What kind of burger buns do you have?' + +# Default menu text for text-based menu flows +DEFAULT_MENU_TEXT = """APPETIZERS +- Mozzarella Sticks $8 - Crispy fried mozzarella sticks served with marinara sauce +- Chicken Wings $10 - Crispy fried chicken wings tossed in your choice of sauce +- Nachos $12 - Crispy tortilla chips topped with melted cheese, chili, sour cream, and salsa + +BURGERS & SANDWICHES +- Classic Cheeseburger $12 - A juicy beef patty topped with melted American cheese, lettuce, tomato, and onion on a toasted bun +- Bacon Cheeseburger $14 - A classic cheeseburger with the addition of crispy bacon +- Mushroom Swiss Burger $15 - A beef patty topped with sautéed mushrooms, melted Swiss cheese, and a creamy horseradish sauce +- Chicken Sandwich $13 - A crispy chicken breast on a toasted bun with lettuce, tomato, and your choice of sauce + +SALADS +- House Salad $8 - Mixed greens with your choice of dressing +- Caesar Salad $9 - Romaine lettuce with croutons, Parmesan cheese, and Caesar dressing""" diff --git a/py/samples/menu/src/main.py b/py/samples/menu/src/main.py index ceb9896662..e17e94d117 100755 --- a/py/samples/menu/src/main.py +++ b/py/samples/menu/src/main.py @@ -39,4 +39,3 @@ async def main(): if __name__ == '__main__': ai.run_main(main()) - diff --git a/py/samples/menu/src/menu_ai.py b/py/samples/menu/src/menu_ai.py index e6c2c0f917..dfa8c2157d 100644 --- a/py/samples/menu/src/menu_ai.py +++ b/py/samples/menu/src/menu_ai.py @@ -22,9 +22,12 @@ from genkit.plugins.google_genai import GoogleAI if 'GEMINI_API_KEY' not in os.environ: - print('GEMINI_API_KEY not set. Some features may not work.') - print('To run full examples, set GEMINI_API_KEY environment variable.') - os.environ['GEMINI_API_KEY'] = 'placeholder_key_for_dev_ui' + raise ValueError( + 'GEMINI_API_KEY environment variable is required to run this sample.\n' + 'Please set it before starting the application:\n' + ' export GEMINI_API_KEY=your_api_key_here\n' + 'You can get an API key from https://aistudio.google.com/' + ) ai = Genkit(plugins=[GoogleAI()]) diff --git a/py/samples/menu/src/menu_schemas.py b/py/samples/menu/src/menu_schemas.py index 11d66dfbc3..1b2a414df4 100644 --- a/py/samples/menu/src/menu_schemas.py +++ b/py/samples/menu/src/menu_schemas.py @@ -15,6 +15,7 @@ # SPDX-License-Identifier: Apache-2.0 +from constants import DEFAULT_MENU_QUESTION, DEFAULT_MENU_TEXT from pydantic import BaseModel, Field @@ -29,7 +30,7 @@ class MenuItemSchema(BaseModel): class MenuQuestionInputSchema(BaseModel): """Input schema for the menu question prompt.""" - question: str = Field(default='What kind of burger buns do you have?', description='A question about the menu') + question: str = Field(default=DEFAULT_MENU_QUESTION, description='A question about the menu') class AnswerOutputSchema(BaseModel): @@ -49,24 +50,11 @@ class TextMenuQuestionInputSchema(BaseModel): """Input schema for the text menu question prompt.""" menu_text: str = Field( - default="""APPETIZERS -- Mozzarella Sticks $8 - Crispy fried mozzarella sticks served with marinara sauce -- Chicken Wings $10 - Crispy fried chicken wings tossed in your choice of sauce -- Nachos $12 - Crispy tortilla chips topped with melted cheese, chili, sour cream, and salsa - -BURGERS & SANDWICHES -- Classic Cheeseburger $12 - A juicy beef patty topped with melted American cheese, lettuce, tomato, and onion on a toasted bun -- Bacon Cheeseburger $14 - A classic cheeseburger with the addition of crispy bacon -- Mushroom Swiss Burger $15 - A beef patty topped with sautéed mushrooms, melted Swiss cheese, and a creamy horseradish sauce -- Chicken Sandwich $13 - A crispy chicken breast on a toasted bun with lettuce, tomato, and your choice of sauce - -SALADS -- House Salad $8 - Mixed greens with your choice of dressing -- Caesar Salad $9 - Romaine lettuce with croutons, Parmesan cheese, and Caesar dressing""", + default=DEFAULT_MENU_TEXT, description='The menu text content', alias='menuText', ) - question: str = Field(default='What kind of burger buns do you have?', description='A question about the menu') + question: str = Field(default=DEFAULT_MENU_QUESTION, description='A question about the menu') class MenuToolOutputSchema(BaseModel):