Web UI — Visual Pipeline Editor
The webui/ directory contains a browser-based node editor for building and running foreblocks forecasting pipelines without writing code. Nodes represent pipeline stages; edges connect outputs to inputs. Execution happens on a local FastAPI backend that streams progress back to the browser via WebSocket.
Starting the server
cd webui
npm install # first time only
npm run build # compile the React frontend into dist/
python server.py # starts on http://localhost:8000Open http://localhost:8000 in a browser. The static frontend is served from dist/.
Dependencies:
pip install fastapi uvicorn torch matplotlibArchitecture
Browser (React + ReactFlow)
↓ POST /execute (generated Python code + workflow graph)
FastAPI server → ThreadPoolExecutor worker
↓ WebSocket /ws/{task_id} (live events)
Browser receives: logs, progress, node results, artifactsThe frontend generates Python code from the node graph and sends it to the backend. The backend executes the code in a thread-pool worker and pushes structured events back to all connected WebSocket clients for that task.
REST API
POST /execute
Submit a pipeline for execution.
{
"code": "# generated Python code\ntrainer = ...",
"workflow": {"nodes": [...], "connections": [...]},
"sync": false,
"timeout_sec": 1.5
}sync=false(default): returns immediately with atask_id; poll or subscribe via WebSocket for resultssync=true: waits up totimeout_secand returns inline results if finished in time
Response:
{"success": true, "task_id": "uuid4", "results": null}GET /status/{task_id}
Poll task state.
{
"task_id": "...",
"state": "running",
"progress": 0.55,
"message": "Generating plot",
"results": null
}States: queued → running → success | error
GET /logs/{task_id}
Retrieve timestamped execution logs.
{"task_id": "...", "logs": ["[10:42:01] ⏳ Starting execution", ...]}GET /artifact/{task_id}/{name}
Download a saved artifact file (e.g., a PNG plot saved by user code).
WebSocket events
Connect to ws://localhost:8000/ws/{task_id} to receive live updates.
On connect, the server sends a snapshot event with current state and the last 50 log lines. Subsequent events:
| Event type | Fields | Meaning |
|---|---|---|
log | line | New log line from worker |
state | state, progress, message | Progress update |
node_result | node_id, result | A node has produced output |
artifact | name | A file artifact was saved |
done | success, results | Execution finished |
error | message | Task not found or server error |
Result types
The result field in node_result events has a type discriminator:
| Type | Data format |
|---|---|
plot | Base64-encoded PNG |
image | Base64-encoded binary image |
metrics | {key: float} dict |
table | {columns: [...], rows: [[...]]} |
json | Any JSON-serializable value |
array | Flat or nested list |
text | Plain string fallback |
report object in user code
The worker injects a report object into the execution namespace. Use it to push structured results back to the UI from within your pipeline code:
# These are available without import inside the executed code:
# report, torch, numpy (as np)
report.log("Loading dataset...")
report.progress(0.2, "Data loaded")
metrics = {"mae": 0.042, "rmse": 0.071}
report.set_result("output_1", "metrics", metrics)
fig = trainer.plot_prediction(X_val, Y_val, show=False)
report.set_result("plot_node", "plot", fig) # matplotlib figure → base64 PNG
report.artifact("forecast.png", fig) # also saves file to artifacts/set_result(node_id, result_type, data) — node_id should match the node's ID in the workflow graph. result_type is one of the type strings from the table above.
Auto-detection fallback
If user code does not call report.set_result(), the backend attempts automatic result extraction by looking for these variables in the execution namespace:
| Variable | Action |
|---|---|
trainer, X_val, Y_val | Calls trainer.metrics(X_val, Y_val) and trainer.plot_prediction(...) |
metrics | Attaches as metrics result on the output node |
time_series, train_size | Passed to plot_prediction as full_series / offset |
Environment injected into user code
| Name | Value |
|---|---|
torch | import torch |
report | ReportBridge instance for the current task |
__name__ | "__main__" |
numpy, matplotlib.pyplot, and matplotlib (Agg backend) are imported inside the worker before exec() but are not injected into the namespace by default — import them explicitly in your code if needed.