feat: simplify using visualization (#165)

This commit is contained in:
Marcus Schiesser
2025-09-04 15:48:58 +08:00
committed by GitHub
parent bdea898243
commit e3f47176f9
10 changed files with 77 additions and 119 deletions
+7
View File
@@ -0,0 +1,7 @@
---
"demo-viz": patch
"@llamaindex/workflow-otel": patch
"@llamaindex/workflow-viz": patch
---
Simplify visualization by exporting .draw function
+3 -6
View File
@@ -9,13 +9,10 @@
"preview": "vite preview"
},
"dependencies": {
"@llamaindex/workflow-core": "latest",
"@llamaindex/workflow-viz": "latest",
"graphology": "^0.26.0",
"graphology-layout-force": "^0.2.4",
"@llamaindex/workflow-core": "^1.3.1",
"@llamaindex/workflow-viz": "^1.0.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"sigma": "^3.0.1"
"react-dom": "^19.1.0"
},
"devDependencies": {
"@types/react": "^19.1.2",
+3 -22
View File
@@ -1,28 +1,9 @@
import "./style.css";
import Sigma from "sigma";
import { workflow } from "./workflow";
import { toSigma } from "@llamaindex/workflow-viz";
import ForceSupervisor from "graphology-layout-force/worker";
const container = document.getElementById("app") as HTMLElement;
// const graph = new Graph();
// graph.addNode("John", { x: 0, y: 10, size: 5, label: "John", color: "blue" });
// graph.addNode("Mary", { x: 10, y: 0, size: 3, label: "Mary", color: "red" });
// graph.addEdge("John", "Mary");
const graph = toSigma(workflow.getGraph());
graph.nodes().forEach((node, i) => {
const angle = (i * 2 * Math.PI) / graph.order;
graph.setNodeAttribute(node, "x", 100 * Math.cos(angle));
graph.setNodeAttribute(node, "y", 100 * Math.sin(angle));
});
const layout = new ForceSupervisor(graph);
layout.start();
const settings = {
workflow.draw(container, {
defaultEdgeColor: "#999",
};
new Sigma(graph, container, settings);
layout: "force",
});
+2 -2
View File
@@ -1,5 +1,5 @@
import { createWorkflow, workflowEvent } from "@llamaindex/workflow-core";
import { withGraph } from "@llamaindex/workflow-viz";
import { withDrawing } from "@llamaindex/workflow-viz";
//#region define workflow events
const startEvent = workflowEvent<string>({
@@ -26,7 +26,7 @@ const stopEvent = workflowEvent<string>({
//#endregion
//#region defines workflow
const workflow = withGraph(createWorkflow());
const workflow = withDrawing(createWorkflow());
workflow.handle([startEvent], async (ctx) => {
const { sendEvent, stream } = ctx;
+1 -1
View File
@@ -46,7 +46,7 @@
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/run-llama/llama-flow.git",
"url": "https://github.com/run-llama/workflow-ts.git",
"directory": "packages/otel"
},
"publishConfig": {
-72
View File
@@ -1,72 +0,0 @@
import { createWorkflow, workflowEvent } from "@llamaindex/workflow-core";
import { withGraph } from "@llamaindex/workflow-viz";
//#region define workflow events
const startEvent = workflowEvent<string>({
debugLabel: "start",
});
const branchAEvent = workflowEvent<string>({
debugLabel: "branchA",
});
const branchBEvent = workflowEvent<string>({
debugLabel: "branchB",
});
const branchCEvent = workflowEvent<string>({
debugLabel: "branchC",
});
const branchCompleteEvent = workflowEvent<string>({
debugLabel: "branchComplete",
});
const allCompleteEvent = workflowEvent<string>({
debugLabel: "allComplete",
});
const stopEvent = workflowEvent<string>({
debugLabel: "stop",
});
//#endregion
//#region defines workflow
const workflow = withGraph(createWorkflow());
workflow.handle([startEvent], async (context) => {
const { sendEvent, stream } = context;
// emit 3 different events, handled separately
sendEvent(branchAEvent.with("Branch A"));
sendEvent(branchBEvent.with("Branch B"));
sendEvent(branchCEvent.with("Branch C"));
const results = await stream.filter(branchCompleteEvent).take(3).toArray();
return allCompleteEvent.with(results.map((e) => e.data).join(", "));
});
workflow.handle([branchAEvent], (_context1, branchA) => {
return branchCompleteEvent.with(branchA.data);
});
workflow.handle([branchBEvent], (_context2, branchB) => {
return branchCompleteEvent.with(branchB.data);
});
workflow.handle([branchCEvent], (_context3, branchC) => {
return branchCompleteEvent.with(branchC.data);
});
workflow.handle([allCompleteEvent], (_context4, allComplete) => {
return stopEvent.with(allComplete.data);
});
//#endregion
const graph = workflow.getGraph();
console.log("--- Graph Nodes ---");
graph.forEachNode((node, attributes) => {
console.log(`Node: ${node}, Attributes: ${JSON.stringify(attributes)}`);
});
console.log("\n--- Graph Edges ---");
graph.forEachEdge((edge, attributes, source, target) => {
console.log(
`Edge from ${source} to ${target} (ID: ${edge}), Attributes: ${JSON.stringify(attributes)}`,
);
});
console.log("--- End of Graph Details ---");
+5 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@llamaindex/workflow-viz",
"version": "1.0.2",
"description": "Visualization components for LlamaFlow",
"description": "Visualization components for drawing LlamaIndex Workflows in the browser",
"type": "module",
"main": "dist/index.cjs",
"types": "dist/index.d.ts",
@@ -46,7 +46,7 @@
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/run-llama/llama-flow.git",
"url": "https://github.com/run-llama/workflow-ts.git",
"directory": "packages/viz"
},
"publishConfig": {
@@ -54,6 +54,8 @@
},
"dependencies": {
"@babel/parser": "^7.27.2",
"graphology": "^0.26.0"
"graphology": "^0.26.0",
"graphology-layout-force": "^0.2.4",
"sigma": "^3.0.1"
}
}
+47
View File
@@ -0,0 +1,47 @@
import type { Workflow } from "@llamaindex/workflow-core";
import Sigma from "sigma";
import type { Settings } from "sigma/settings";
import { withGraph } from "./graph";
import { toSigma } from "./sigma";
import ForceSupervisor from "graphology-layout-force/worker";
export type DrawingOptions = {
layout?: "force" | "none";
} & Partial<Settings>;
export type WithDrawingWorkflow = {
draw(container: HTMLElement, options?: DrawingOptions): void;
};
export function withDrawing<WorkflowLike extends Workflow>(
workflow: WorkflowLike,
): WorkflowLike & WithDrawingWorkflow {
const workflowWithGraph = withGraph(workflow);
return {
...workflowWithGraph,
draw: (container: HTMLElement, options?: DrawingOptions) => {
const graph = toSigma(workflowWithGraph.getGraph());
// simple radial positions so nodes don't overlap before layout
const nodes = graph.nodes();
const order = graph.order || nodes.length || 1;
nodes.forEach((node, i) => {
const angle = (i * 2 * Math.PI) / order;
graph.setNodeAttribute(node, "x", 100 * Math.cos(angle));
graph.setNodeAttribute(node, "y", 100 * Math.sin(angle));
});
// default to force layout unless explicitly disabled
if ((options?.layout ?? "force") === "force") {
const layout = new ForceSupervisor(graph);
layout.start();
}
// create sigma renderer
const { layout: _layout, ...sigmaSettings } = options ?? {};
void _layout;
new Sigma(graph, container, sigmaSettings);
},
};
}
+1 -2
View File
@@ -1,2 +1 @@
export * from "./graph";
export * from "./sigma";
export { withDrawing } from "./drawing";
+8 -11
View File
@@ -203,26 +203,17 @@ importers:
demo/visualization:
dependencies:
'@llamaindex/workflow-core':
specifier: latest
specifier: ^1.3.1
version: link:../../packages/core
'@llamaindex/workflow-viz':
specifier: latest
specifier: ^1.0.1
version: link:../../packages/viz
graphology:
specifier: ^0.26.0
version: 0.26.0(graphology-types@0.24.8)
graphology-layout-force:
specifier: ^0.2.4
version: 0.2.4(graphology-types@0.24.8)
react:
specifier: ^19.1.0
version: 19.1.0
react-dom:
specifier: ^19.1.0
version: 19.1.0(react@19.1.0)
sigma:
specifier: ^3.0.1
version: 3.0.2(graphology-types@0.24.8)
devDependencies:
'@types/react':
specifier: ^19.1.2
@@ -384,6 +375,12 @@ importers:
graphology:
specifier: ^0.26.0
version: 0.26.0(graphology-types@0.24.8)
graphology-layout-force:
specifier: ^0.2.4
version: 0.2.4(graphology-types@0.24.8)
sigma:
specifier: ^3.0.1
version: 3.0.2(graphology-types@0.24.8)
devDependencies:
'@babel/types':
specifier: ^7.27.1