From a243dcaa271c75181877a619a7636685c318e934 Mon Sep 17 00:00:00 2001 From: jiazeng Date: Mon, 16 Oct 2023 15:47:22 +0800 Subject: [PATCH] add icon in tool meta, not package template resolve --- .../develop-a-tool/add-a-tool-icon.md | 10 ++++---- scripts/tool/generate_package_tool_meta.py | 24 +++++++++++++++++-- .../tool/generate_tool_package_template.py | 17 ++++--------- scripts/tool/templates/tool.yaml.j2 | 1 - scripts/tool/templates/tool2.yaml.j2 | 1 - .../tool/utils/generate_tool_meta_utils.py | 18 +++++++++----- 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/docs/how-to-guides/develop-a-tool/add-a-tool-icon.md b/docs/how-to-guides/develop-a-tool/add-a-tool-icon.md index cd20c6e61cfa..537157629dc3 100644 --- a/docs/how-to-guides/develop-a-tool/add-a-tool-icon.md +++ b/docs/how-to-guides/develop-a-tool/add-a-tool-icon.md @@ -20,19 +20,21 @@ Adding a custom tool icon is optional. If you do not provide one, the system use ``` ## Add tool icon with _icon_ parameter -Use the `icon` parameter when generating your tool package to add a custom tool icon: +Run below command under your tool project to auto generate your tool YAML, use _-i_ or _--icon_ parameter to add a custom tool icon: ``` -python \tool\generate_tool_package_template.py --destination --package-name --tool-name --function-name --icon +python \tool\generate_package_tool_meta.py -m -o -n -d -i ``` For example: ``` -python D:\proj\github\promptflow\scripts\tool\generate_tool_package_template.py --destination hello-world-proj --package-name hello-world --tool-name hello_world_tool --function-name get_greeting_message --icon D:\proj\github\promptflow\examples\tools\tool-package-quickstart\my_tool_package\icons\custom-tool-icon.png +python D:\proj\github\promptflow\scripts\tool\generate_package_tool_meta.py -m hello_world.tools.hello_world_tool -o hello_world\yamls\hello_world_tool.yaml -n "Hello World Tool" -d "This is my hello world tool." -i D:\proj\github\promptflow\examples\tools\tool-package-quickstart\my_tool_package\icons\custom-tool-icon.png ``` In the auto-generated tool YAML file, the custom tool icon data URI is added in the `icon` field: ```yaml hello_world.tools.hello_world_tool.get_greeting_message + description: This is hello world tool function: get_greeting_message + icon: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACq0lEQVR4nKWTPWxTVxiGn3N/bF/fGyd2YxsQ5LdSmoqGgKJMEQNZYGBFkVhY2JGYmFG3ioWZpWukqqpaqaVKq6pFIAECAkSxMA6RHZP4Jnbs+O/6xvdjcCLKT6ee7ZwjvfrOc55XiYjwP5bx740IZDf3+PVZicdrVeK2yfzJJBem02iaQv1XQCCCCNz+Lce91R1mRvtYd5uEDIfl9SqpWIjZLxOIgPooRQtE0JQiU6xx91mJfNkjZoX47vIkM2Nx6l6Xmz9kWHywgVIQBB++WImI1Nv7fP/XOqah0fKFdH8YQwXcf1Vh6WWZTrfLaDLK4rVZrJD+wSQGwJrbQtc0rs4PAXDr5xy/PHW5NJsmGQuhNI0/XrisFmtMjwxwOLVCYXTaTdq+kHagXq0iAo4phE2dn564XD8/zLlTRwn8gK1dQaHQtfcgDDMcwQo1Wc43mEp16YpibdsjEKHdEX5/8YZEpIhjCckBi9a+ibfvETEsIobdY1Bp+Pz4cAvP67C522IsbeN1A0zd5r77LWF7hebe1xxJrzKRmON56W/OHDnHwskbaCIQt03OTsbJljxeuz4rxSYXp2JcmYszedQhrNscj/ehJIKuQpiaBegHEFVPoOHBKOPpKMXdNtlSmzt/bpC0XTb9LxgcmGDq2CT5mpC0hhiO1UhGe8ANBYgCQ1dcnR9iJGnxT6ZMrtLmbV1H78/QrD0nagQ82ljCP+HzqLBEsB8wP7bQ+8ZDpoauuHA6xfnpFA3Px4mY3M2cJbeTZjTxFQYm44lv0MRkPDH1aRcOtdaUwon0rgrbBdbd10S1AXJbWRxzkLXNLDEz1VP54wDtQLHuQUl36xUKpTzl6jYFN89OdYeCm6eyV3mv8mdKxuFxueHS8PawTJuW3yAacmh26jiRfhL2IO8AhSUo7nmFnjUAAAAASUVORK5CYII= inputs: connection: type: @@ -42,9 +44,7 @@ hello_world.tools.hello_world_tool.get_greeting_message - string module: hello_world.tools.hello_world_tool name: Hello World Tool - description: This is hello world tool type: python - icon: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACq0lEQVR4nKWTPWxTVxiGn3N/bF/fGyd2YxsQ5LdSmoqGgKJMEQNZYGBFkVhY2JGYmFG3ioWZpWukqqpaqaVKq6pFIAECAkSxMA6RHZP4Jnbs+O/6xvdjcCLKT6ee7ZwjvfrOc55XiYjwP5bx740IZDf3+PVZicdrVeK2yfzJJBem02iaQv1XQCCCCNz+Lce91R1mRvtYd5uEDIfl9SqpWIjZLxOIgPooRQtE0JQiU6xx91mJfNkjZoX47vIkM2Nx6l6Xmz9kWHywgVIQBB++WImI1Nv7fP/XOqah0fKFdH8YQwXcf1Vh6WWZTrfLaDLK4rVZrJD+wSQGwJrbQtc0rs4PAXDr5xy/PHW5NJsmGQuhNI0/XrisFmtMjwxwOLVCYXTaTdq+kHagXq0iAo4phE2dn564XD8/zLlTRwn8gK1dQaHQtfcgDDMcwQo1Wc43mEp16YpibdsjEKHdEX5/8YZEpIhjCckBi9a+ibfvETEsIobdY1Bp+Pz4cAvP67C522IsbeN1A0zd5r77LWF7hebe1xxJrzKRmON56W/OHDnHwskbaCIQt03OTsbJljxeuz4rxSYXp2JcmYszedQhrNscj/ehJIKuQpiaBegHEFVPoOHBKOPpKMXdNtlSmzt/bpC0XTb9LxgcmGDq2CT5mpC0hhiO1UhGe8ANBYgCQ1dcnR9iJGnxT6ZMrtLmbV1H78/QrD0nagQ82ljCP+HzqLBEsB8wP7bQ+8ZDpoauuHA6xfnpFA3Px4mY3M2cJbeTZjTxFQYm44lv0MRkPDH1aRcOtdaUwon0rgrbBdbd10S1AXJbWRxzkLXNLDEz1VP54wDtQLHuQUl36xUKpTzl6jYFN89OdYeCm6eyV3mv8mdKxuFxueHS8PawTJuW3yAacmh26jiRfhL2IO8AhSUo7nmFnjUAAAAASUVORK5CYII= ``` ## Verify the tool icon in VS Code extension diff --git a/scripts/tool/generate_package_tool_meta.py b/scripts/tool/generate_package_tool_meta.py index 9a8b46fe1801..e877a56467b8 100644 --- a/scripts/tool/generate_package_tool_meta.py +++ b/scripts/tool/generate_package_tool_meta.py @@ -9,6 +9,7 @@ sys.path.append("src/promptflow-tools") sys.path.append(os.getcwd()) +from convert_image_to_data_url import check_image_type_and_generate_data_url # noqa: E402 from utils.generate_tool_meta_utils import generate_custom_llm_tools_in_module_as_dict, generate_python_tools_in_module_as_dict # noqa: E402, E501 @@ -31,12 +32,31 @@ type=str, ) parser.add_argument("--description", "-d", help="Provide a brief description of the tool.", type=str) + parser.add_argument( + "--icon", + "-i", + type=str, + help="your tool's icon image path, if not provided, the system will use the default icon", + required=False) args = parser.parse_args() m = importlib.import_module(args.module) + + icon = "" + if args.icon: + icon = check_image_type_and_generate_data_url(args.icon) + if args.tool_type == "custom_llm": - tools_dict = generate_custom_llm_tools_in_module_as_dict(m, name=args.name, description=args.description) + tools_dict = generate_custom_llm_tools_in_module_as_dict( + m, + name=args.name, + description=args.description, + icon=icon) else: - tools_dict = generate_python_tools_in_module_as_dict(m, name=args.name, description=args.description) + tools_dict = generate_python_tools_in_module_as_dict( + m, + name=args.name, + description=args.description, + icon=icon) # The generated dict cannot be dumped as yaml directly since yaml cannot handle string enum. tools_dict = json.loads(json.dumps(tools_dict)) with open(args.output, "w") as f: diff --git a/scripts/tool/generate_tool_package_template.py b/scripts/tool/generate_tool_package_template.py index 22a5584201f7..741988357f85 100644 --- a/scripts/tool/generate_tool_package_template.py +++ b/scripts/tool/generate_tool_package_template.py @@ -3,7 +3,6 @@ import re from jinja2 import Environment, FileSystemLoader from pathlib import Path -from convert_image_to_data_url import check_image_type_and_generate_data_url def make_pythonic_variable_name(input_string): @@ -29,7 +28,7 @@ def create_folder(path): def create_tool_project_structure(destination: str, package_name: str, tool_name: str, - function_name: str, icon_data_url: str, is_class_way=False): + function_name: str, is_class_way=False): if is_class_way: class_name = convert_tool_name_to_class_name(tool_name) @@ -92,11 +91,10 @@ def create_tool_project_structure(destination: str, package_name: str, tool_name if is_class_way: template = env.get_template('tool2.yaml.j2') output = template.render(package_name=package_name, tool_name=tool_name, class_name=class_name, - icon_data_url=icon_data_url, function_name=function_name) + function_name=function_name) else: template = env.get_template('tool.yaml.j2') - output = template.render(package_name=package_name, tool_name=tool_name, icon_data_url=icon_data_url, - function_name=function_name) + output = template.render(package_name=package_name, tool_name=tool_name, function_name=function_name) with open(os.path.join(yamls_dir, f'{tool_name}.yaml'), 'w') as f: f.write(output) @@ -129,9 +127,6 @@ def create_tool_project_structure(destination: str, package_name: str, tool_name help="your tool's name, by default is hello_world_tool", required=False) parser.add_argument("--function-name", "-f", type=str, help="your tool's function name, by default is your tool's name", required=False) - parser.add_argument("--icon", "-i", type=str, - help="your tool's icon image path, if not provided, the system will use the default icon", - required=False) parser.add_argument("--use-class", action='store_true', help="Specify whether to use a class implementation way.") args = parser.parse_args() @@ -153,8 +148,4 @@ def create_tool_project_structure(destination: str, package_name: str, tool_name function_name = tool_name function_name = function_name.lower() - icon_data_url = "" - if args.icon: - icon_data_url = check_image_type_and_generate_data_url(args.icon) - - create_tool_project_structure(destination, package_name, tool_name, function_name, icon_data_url, args.use_class) + create_tool_project_structure(destination, package_name, tool_name, function_name, args.use_class) diff --git a/scripts/tool/templates/tool.yaml.j2 b/scripts/tool/templates/tool.yaml.j2 index cee9be496f3c..87d9ed7febd1 100644 --- a/scripts/tool/templates/tool.yaml.j2 +++ b/scripts/tool/templates/tool.yaml.j2 @@ -11,4 +11,3 @@ name: Hello World Tool description: This is hello world tool type: python - icon: {{ icon_data_url }} diff --git a/scripts/tool/templates/tool2.yaml.j2 b/scripts/tool/templates/tool2.yaml.j2 index 6c7c5ebf92a0..78e75c32e6b2 100644 --- a/scripts/tool/templates/tool2.yaml.j2 +++ b/scripts/tool/templates/tool2.yaml.j2 @@ -12,4 +12,3 @@ name: Hello World Tool description: This is hello world tool type: python - icon: {{ icon_data_url }} diff --git a/scripts/tool/utils/generate_tool_meta_utils.py b/scripts/tool/utils/generate_tool_meta_utils.py index b18f69c4c69d..102dec5a0a00 100644 --- a/scripts/tool/utils/generate_tool_meta_utils.py +++ b/scripts/tool/utils/generate_tool_meta_utils.py @@ -18,6 +18,12 @@ def asdict_without_none(obj): return asdict(obj, dict_factory=lambda x: {k: v for (k, v) in x if v}) +def asdict_with_advanced_features_without_none(obj, **advanced_features): + dict_without_none = asdict_without_none(obj) + dict_without_none.update({k: v for k, v in advanced_features.items() if v}) + return dict_without_none + + def is_tool(f): if not isinstance(f, types.FunctionType): return False @@ -82,9 +88,9 @@ def generate_python_tools_in_module(module, name, description): ] -def generate_python_tools_in_module_as_dict(module, name=None, description=None): +def generate_python_tools_in_module_as_dict(module, name=None, description=None, **advanced_features): tools = generate_python_tools_in_module(module, name, description) - return _construct_tool_dict(tools) + return _construct_tool_dict(tools, **advanced_features) def generate_custom_llm_tools_in_module(module, name, description): @@ -101,16 +107,16 @@ def generate_custom_llm_tools_in_module(module, name, description): ] -def generate_custom_llm_tools_in_module_as_dict(module, name=None, description=None): +def generate_custom_llm_tools_in_module_as_dict(module, name=None, description=None, **advanced_features): tools = generate_custom_llm_tools_in_module(module, name, description) - return _construct_tool_dict(tools) + return _construct_tool_dict(tools, **advanced_features) -def _construct_tool_dict(tools): +def _construct_tool_dict(tools, **advanced_features): return { f"{t.module}.{t.class_name}.{t.function}" if t.class_name is not None - else f"{t.module}.{t.function}": asdict_without_none(t) + else f"{t.module}.{t.function}": asdict_with_advanced_features_without_none(t, **advanced_features) for t in tools }