This guide provides a reference for converting NodeTool workflows into Gradio applications. It covers the architectural differences, graph structure, and strategies for mapping NodeTool concepts to Gradio components.
Overview
NodeTool workflows are Directed Acyclic Graphs (DAGs) where each node runs as an independent actor. Gradio applications, by contrast, are typically defined by sequential functions. Converting a workflow requires flattening the graph and mapping distributed logic into a cohesive function or set of functions.
Graph Structure (JSON)
To convert a workflow, you often need to parse its JSON representation.
{
"nodes": [
{
"id": "input-1",
"type": "nodetool.input.StringInput",
"data": { "name": "user_name", "value": "" }
},
{
"id": "process-1",
"type": "nodetool.text.Concat",
"data": { "a": "Hello, ", "b": "" }
}
],
"edges": [
{
"source": "input-1",
"sourceHandle": "output",
"target": "process-1",
"targetHandle": "b"
}
]
}
Key Components:
- Nodes: Contain
id,type(class path), anddata(parameters). - Edges: Define data flow via
source/sourceHandleandtarget/targetHandle.
Architectural Differences
| Aspect | NodeTool | Gradio |
|---|---|---|
| Model | Graph-based DAG | Sequential function-based |
| Execution | Async Actor Model (Distributed) | Synchronous/Threaded Function |
| State | Flows through edges | Function parameters/returns |
| Streaming | Async Generators (First-class) | Generator functions (Limited) |
Conversion Strategy
1. Graph Analysis
- Flatten the graph if it contains nested groups.
- Sort nodes topologically to determine execution order.
- Identify InputNodes (parameters) and OutputNodes (returns).
2. Function Extraction
Convert the linear sequence of nodes into a single Python function.
NodeTool Workflow:
StringInput → Concat → StringOutput
Gradio Equivalent:
def concatenate_text(prefix: str, suffix: str) -> str:
return prefix + suffix
gr.Interface(
fn=concatenate_text,
inputs=["text", "text"],
outputs="text"
)
3. Handling Multiple Outputs
Map multiple OutputNodes to a tuple return type.
def process_text(text: str) -> tuple[str, float]:
# ... processing logic ...
return processed_text, score
gr.Interface(
fn=process_text,
inputs="text",
outputs=["text", "number"]
)
4. Streaming Conversion
Map NodeTool’s async def gen_process to Python generators.
# NodeTool
async def gen_process(self, context):
for item in items:
yield {"output": item}
# Gradio
def process_items(items):
for item in items:
yield item
5. Asset Handling
NodeTool uses AssetRef (ImageRef, AudioRef). Gradio typically uses raw types (PIL.Image, numpy arrays) or file paths.
# NodeTool
async def process(self, context) -> ImageRef:
pil_img = await context.image_to_pil(self.image)
return await context.image_from_pil(result)
# Gradio
def process_image(image: PIL.Image) -> PIL.Image:
# process directly with PIL
return result_image
Type Mapping Reference
| NodeTool Node | Gradio Component | Python Type |
|---|---|---|
StringInput |
Textbox |
str |
IntegerInput |
Number (precision=0) |
int |
FloatInput |
Slider / Number |
float |
BooleanInput |
Checkbox |
bool |
ImageInput |
Image |
PIL.Image / str (path) |
AudioInput |
Audio |
tuple / str (path) |
VideoInput |
Video |
str (path) |
DataframeOutput |
Dataframe |
pd.DataFrame |
ColorInput |
ColorPicker |
str (hex) |
Best Practices
- Statelessness: Keep functions pure. Avoid global state.
- Environment Variables: Use
os.environfor API keys (OpenAI, etc.) instead of passing them as graph inputs if possible. - Error Handling: Gradio functions fail entirely on error. Add try/catch blocks to handle graceful failures if needed.