Skip to content

Dev custom widgets #385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ea48c93
fix project root calc
Cherwayway Feb 19, 2025
bfa9015
fix: settings save
shanexi Feb 19, 2025
be28f53
[Feat] add api widget, for test only
Cherwayway Feb 23, 2025
1d55581
chore: Upgrade some Git workflow actions to v4 (#299)
tiancheng-myshell Feb 14, 2025
1567021
[Fix] get local file failed
Cherwayway Feb 23, 2025
b8d7b83
Merge branch 'dev_custom_widgets' of github.com:myshell-ai/ShellAgent…
shanexi Feb 24, 2025
c9d6c6a
[Feat] custom widgets implemente/import/export
Cherwayway Feb 24, 2025
1dfa703
Merge branch 'dev_custom_widgets' of https://github.com/myshell-ai/Sh…
Cherwayway Feb 24, 2025
5bcc380
fix: Compatible with new data struct
shanexi Feb 24, 2025
eddd0dc
Merge branch 'dev_custom_widgets' of github.com:myshell-ai/ShellAgent…
shanexi Feb 24, 2025
8dc2a86
update export custom widgets format
Cherwayway Feb 25, 2025
6b58c12
Merge branch 'dev_custom_widgets' of https://github.com/myshell-ai/Sh…
Cherwayway Feb 25, 2025
c1f2e9b
wip
myshell-joe Feb 25, 2025
7d692e9
Merge branch 'alpha' of github.com:myshell-ai/ShellAgent into dev_cus…
myshell-joe Feb 25, 2025
f27eeb8
Merge branch 'dev_custom_widgets' of github.com:myshell-ai/ShellAgent…
myshell-joe Feb 25, 2025
6b29f20
update expresssion map use, and node length
Cherwayway Feb 25, 2025
f94cf42
update expression
Cherwayway Feb 25, 2025
ee3a843
Merge branch 'alpha' into dev_custom_widgets
Cherwayway Feb 26, 2025
04a6b5f
Revert "wip"
myshell-joe Feb 26, 2025
c849146
update engine interface for custom widgets
Cherwayway Mar 4, 2025
5736ecc
Merge branch 'dev_custom_widgets' of https://github.com/myshell-ai/Sh…
Cherwayway Mar 4, 2025
8f32d9e
Merge branch 'alpha' into dev_custom_widgets
Cherwayway Mar 4, 2025
5e547f6
update test/stable environ for custom widgets
Cherwayway Mar 4, 2025
6f2d98d
update
shanexi Feb 24, 2025
690ff90
Merge branch 'alpha' of https://github.com/myshell-ai/ShellAgent into…
Cherwayway Mar 6, 2025
4beede2
update import
Cherwayway Mar 6, 2025
3a0e4c3
fix: export data structure
shanexi Mar 10, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/package-and-upload-new-linux.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/package-and-upload-new-mac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/package-and-upload-new-windows.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down Expand Up @@ -125,7 +125,7 @@ jobs:
overwrite: true

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./web-build
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/package-and-upload.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./web-build
Expand Down Expand Up @@ -94,7 +94,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down Expand Up @@ -172,7 +172,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down Expand Up @@ -222,7 +222,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/package-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down Expand Up @@ -127,7 +127,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down Expand Up @@ -169,7 +169,7 @@ jobs:
python-version: 3.10.10

- name: Download web-build artifact
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: web-build
path: ./servers/web-build
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ hf_repo
launch.sh
.idea/
.DS_Store
custom_widgets/*/
61 changes: 61 additions & 0 deletions assets/myshell_widget_list.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,65 @@
{
"1892877244783509504": {
"id": "1892877244783509504",
"name": "API Widget",
"description": "API Widget",
"usage": "Tools",
"inputs": {
"properties": {
"url": {
"type": "string",
"description": "API endpoint URL",
"default": ""
},
"method": {
"type": "string",
"description": "HTTP method",
"enum": [
"GET",
"POST",
"PUT",
"DELETE"
],
"default": "GET"
},
"headers": {
"type": "string",
"description": "Request headers (JSON format)",
"default": "{}"
},
"params": {
"type": "string",
"description": "URL parameters (JSON format)",
"default": "{}"
},
"data": {
"type": "string",
"description": "Request body (JSON format)",
"default": "{}"
}
},
"required": [
"url"
]
},
"outputs": {
"properties": {
"status_code": {
"type": "integer",
"description": "HTTP status code"
},
"headers": {
"type": "object",
"description": "Response headers"
},
"body": {
"type": "string",
"description": "Response body"
}
}
},
"widget_id": "1892877244783509504"
},
"1781991963803181056": {
"id": "1781991963803181056",
"name": "Crawler",
Expand Down
8 changes: 4 additions & 4 deletions custom_widget_info.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"proconfig-diffuser-imagen": {
"git": "https://github.com/wl-zhao/proconfig-diffuser-imagen.git",
"commit": "latest",
"custom_widget_demo": {
"git": "https://github.com/Cherwayway/custom_widget_demo.git",
"commit": "651f1c69cad4921d09e705802733aadae1aa9058",
"branch": "main",
"description": "Simple image generation widget implemented by diffusers"
"description": "A demo widget for custom widgets"
}
}
1 change: 0 additions & 1 deletion custom_widgets/widgets_status.json

This file was deleted.

11 changes: 11 additions & 0 deletions proconfig/runners/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from proconfig.utils.pytree import tree_map
import proconfig.utils.pytree as pytree
from proconfig.widgets.base import WIDGETS
from proconfig.utils.expressions import calc_expression
from proconfig.utils.misc import hash_dict
from proconfig.core import Automata, Workflow, State
Expand Down Expand Up @@ -253,6 +254,14 @@ def process_myshell_extra_inputs(self, task):
"inputs": copy.deepcopy(task.inputs)
}
task.inputs["myshell_actual_inputs"] = myshell_actual_inputs

def process_custom_widget_extra_inputs(self, task):
custom_widget_actual_inputs = {
"widget_name": task.widget_class_name,
"inputs": copy.deepcopy(task.inputs)
}
task.widget_class_name = "CustomAnyWidgetCallerWidget"
task.inputs["custom_widget_actual_inputs"] = custom_widget_actual_inputs

def run_task(self, container, task, environ, local_vars):

Expand All @@ -262,6 +271,8 @@ def run_task(self, container, task, environ, local_vars):
self.process_comfy_extra_inputs(task)
elif task.widget_class_name == "MyShellAnyWidgetCallerWidget":
self.process_myshell_extra_inputs(task)
elif not WIDGETS.get(task.widget_class_name):
self.process_custom_widget_extra_inputs(task)

if task.mode in ["widget", "comfy_workflow"]:
return self.run_widget_task(container, task, environ, local_vars)
Expand Down
46 changes: 37 additions & 9 deletions proconfig/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,51 @@
os.environ[CURRENT_PACKAGE_NAME_KEY] = "myshell"
from proconfig.widgets.utils import load_module
from proconfig.widgets.base import build_widgets
from proconfig.utils.widget_manager import install_widget

import proconfig.widgets.imagen_widgets
import proconfig.widgets.language_models
import proconfig.widgets.tools
import proconfig.widgets.myshell_widgets
import proconfig.widgets.custom_widgets
# load custom widgets

import os

def load_custom_widgets():
widget_status = json.load(open("custom_widgets/widgets_status.json"))
for custom_widget in os.listdir("custom_widgets"):
if not os.path.isdir(os.path.join("custom_widgets", custom_widget)):
continue
if custom_widget in widget_status:
current_commit = widget_status[custom_widget]["current_commit"]
os.environ[CURRENT_PACKAGE_NAME_KEY] = custom_widget
load_module(os.path.join(custom_widget, current_commit), "custom_widgets", module_name=custom_widget)

try:
with open("custom_widget_info.json", "r") as f:
widget_info = json.load(f)
# Remove custom_widget_demo if it exists
if "custom_widget_demo" in widget_info:
del widget_info["custom_widget_demo"]
except FileNotFoundError:
widget_info = {}

# Get list of existing widget directories
existing_widgets = set(d for d in os.listdir("custom_widgets")
if os.path.isdir(os.path.join("custom_widgets", d)))

# Install widgets from widget_info that don't exist
for widget_name, widget_data in widget_info.items():
if widget_name not in existing_widgets:
# Extract git URL from widget_data if it's a dictionary
install_widget(
widget_data["git"],
os.path.join("custom_widgets", widget_name),
widget_data.get("commit", None),
widget_data.get("branch", "main")
)

# Update existing widget list, filter out non-directory files
existing_widgets = set(d for d in os.listdir("custom_widgets")
if os.path.isdir(os.path.join("custom_widgets", d))
and not d.startswith('.')
and not d.startswith('__'))

# Load all widgets from custom_widgets directory
for custom_widget in existing_widgets:
os.environ[CURRENT_PACKAGE_NAME_KEY] = custom_widget
load_module(custom_widget, "custom_widgets", module_name=custom_widget)

load_custom_widgets()
1 change: 1 addition & 0 deletions proconfig/widgets/custom_widgets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from proconfig.widgets.custom_widgets.custom_widget_caller import CustomAnyWidgetCallerWidget
75 changes: 75 additions & 0 deletions proconfig/widgets/custom_widgets/custom_widget_caller.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from typing import Any, Literal, Optional, List
from pydantic import Field, BaseModel

from proconfig.widgets.base import BaseWidget, WIDGETS
from proconfig.core.exception import ShellException

# import instructor
import os
from pydantic import BaseModel, Field
import requests
import json

@WIDGETS.register_module()
class CustomAnyWidgetCallerWidget(BaseWidget):
NAME = "CustomAnyWidgetCallerWidget"
dynamic_schema = True

class InputsSchema(BaseWidget.InputsSchema):
widget_name: str = Field(..., description="the widget name to call")
inputs: dict = {}

class OutputsSchema(BaseWidget.OutputsSchema): # useless
data: str | list

def execute(self, environ, config_ori):
# API endpoint URL
url = "https://openapi.myshell.ai/public/v1/custom_widget/run"
if "MYSHELL_DEPLOY" in os.environ and os.environ["MYSHELL_DEPLOY"] == "TEST":
url = "https://openapi-test.myshell.fun/public/v1/custom_widget/run"
config = config_ori["custom_widget_actual_inputs"]
widget_name = config["widget_name"]

# Headers for the API request
headers = {
"x-myshell-openapi-key": os.environ["MYSHELL_API_KEY"],
"Content-Type": "application/json",
**environ.get("MYSHELL_HEADERS", {})
}

# Request payload
data = {
"widget_name": widget_name,
"input": json.dumps(config["inputs"])
}

del config_ori["custom_widget_actual_inputs"]

# print("widget inputs:", config["inputs"])

# Send POST request to the API
response = requests.post(url, headers=headers, json=data)

# Parse the JSON response
json_response = response.json()

# Extract the 'result' field and return it as a string
if json_response.get('success') and 'result' in json_response:
result = json.loads(json_response['result'])
# handle the _url
if "_url" in result:
response = requests.get(result["_url"])
if response.status_code == 200:
return response.json()
else:
return {"error_message": "error when retrieve the result"}
return result
else:
error = {
'error_code': 'SHELL-1102',
'error_head': 'Widget Execution Error',
'msg': f'widget {widget_name} failed to execute',
'traceback': json.dumps(json_response),
}
exception = ShellException(**error)
raise exception
Loading