Skip to content

Commit

Permalink
add icon in tool meta, not package template
Browse files Browse the repository at this point in the history
resolve
  • Loading branch information
jiazengcindy committed Oct 16, 2023
1 parent 48a4c19 commit a243dca
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 28 deletions.
10 changes: 5 additions & 5 deletions docs/how-to-guides/develop-a-tool/add-a-tool-icon.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <path-to-scripts>\tool\generate_tool_package_template.py --destination <your-tool-project> --package-name <your-package-name> --tool-name <your-tool-name> --function-name <your-tool-function-name> --icon <your-tool-icon-path>
python <path-to-scripts>\tool\generate_package_tool_meta.py -m <tool_module> -o <tool_yaml_path> -n <tool_name> -d <tool_description> -i <tool-icon-path>
```
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:
Expand All @@ -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
Expand Down
24 changes: 22 additions & 2 deletions scripts/tool/generate_package_tool_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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:
Expand Down
17 changes: 4 additions & 13 deletions scripts/tool/generate_tool_package_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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()
Expand All @@ -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)
1 change: 0 additions & 1 deletion scripts/tool/templates/tool.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@
name: Hello World Tool
description: This is hello world tool
type: python
icon: {{ icon_data_url }}
1 change: 0 additions & 1 deletion scripts/tool/templates/tool2.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@
name: Hello World Tool
description: This is hello world tool
type: python
icon: {{ icon_data_url }}
18 changes: 12 additions & 6 deletions scripts/tool/utils/generate_tool_meta_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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
}

Expand Down

0 comments on commit a243dca

Please sign in to comment.