Skip to content

Commit d33f899

Browse files
committed
feat: added orchestrator-workflow-rendered some caching
1 parent 8145574 commit d33f899

File tree

1 file changed

+68
-60
lines changed

1 file changed

+68
-60
lines changed

tools/orchestrator_workflow_renderer.py

Lines changed: 68 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,44 @@ def __init__(self):
1818
Path(__file__).parent.parent / "assets" / "workflow-renderer" / "index.html"
1919
)
2020
self.workflows_dir = Path(__file__).parent.parent / "assets" / "workflows"
21+
self._browser = None
22+
self._page = None
23+
self._playwright = None
24+
25+
async def __init_browser(self):
26+
"""
27+
Initialize browser and load the workflow renderer page just once
28+
29+
Context: editor.js is 20MB, (yes, you read correct) and
30+
we need to cached if not the timeouts happens)
31+
"""
32+
33+
if self._browser is None:
34+
logger.info("Initializing browser...")
35+
self._playwright = await async_playwright().start()
36+
self._browser = await self._playwright.chromium.launch()
37+
self._page = await self._browser.new_page()
38+
39+
self._page.on(
40+
"console",
41+
lambda msg: logger.info(f"Browser console [{msg.type}]: {msg.text}"),
42+
)
43+
self._page.on(
44+
"pageerror", lambda err: logger.error(f"Browser error: {err}")
45+
)
46+
47+
logger.info(f"Loading HTML file: file://{self.html_path.absolute()}")
48+
await self._page.goto(f"file://{self.html_path.absolute()}")
49+
50+
# Wait for editor to initialize
51+
logger.info("Waiting for editor to initialize...")
52+
await self._page.wait_for_function("typeof render_workflow === 'function'")
53+
await self._page.wait_for_function("ready(); EditorIsReady === true")
54+
logger.info("Browser initialized and page loaded")
55+
56+
@property
57+
def browser(self):
58+
return self._browser
2159

2260
async def render_workflow_to_png_file(self, workflow_data: str) -> str:
2361
"""
@@ -56,70 +94,40 @@ async def render_workflow_to_svg(self, workflow_data: str) -> str:
5694
str: SVG content
5795
"""
5896
logger.info("Starting workflow rendering process...")
59-
logger.info(f"HTML path: {self.html_path.absolute()}")
6097

61-
async with async_playwright() as p:
62-
logger.info("Launching headless browser...")
63-
browser = await p.chromium.launch()
64-
page = await browser.new_page()
98+
await self.__init_browser()
6599

66-
page.on(
67-
"console",
68-
lambda msg: logger.info(f"Browser console [{msg.type}]: {msg.text}"),
100+
try:
101+
await self._page.evaluate(f"""
102+
let workflow_data = {workflow_data};
103+
render_workflow(
104+
document.getElementById("renderWorkflow"),
105+
JSON.stringify(workflow_data)
106+
);
107+
""")
108+
109+
# Get the SVG content
110+
await self._page.wait_for_function(
111+
"document.getElementById('renderWorkflow')."
112+
"querySelector('svg') !== null"
69113
)
70-
page.on("pageerror", lambda err: logger.error(f"Browser error: {err}"))
71-
72-
# Load the HTML file
73-
logger.info(f"Loading HTML file: file://{self.html_path.absolute()}")
74-
await page.goto(f"file://{self.html_path.absolute()}")
75-
76-
# Wait for editor to initialize
77-
logger.info("Waiting for editor to initialize...")
78-
await page.wait_for_function("typeof render_workflow === 'function'")
79-
await page.wait_for_function("ready(); EditorIsReady === true")
80-
81-
# Execute the workflow rendering on page load
82-
try:
83-
# Example rendering
84-
# await page.evaluate("""
85-
# render_workflow(
86-
# document.getElementById("renderWorkflow"),
87-
# JSON.stringify(sample_data)
88-
# );
89-
# """)
90-
91-
await page.evaluate(f"""
92-
let workflow_data = {workflow_data};
93-
render_workflow(
94-
document.getElementById("renderWorkflow"),
95-
JSON.stringify(workflow_data)
96-
);
97-
""")
98-
99-
# Get the SVG content
100-
await page.wait_for_function(
101-
"document.getElementById('renderWorkflow')."
102-
"querySelector('svg') !== null"
103-
)
104-
svg_content = await page.evaluate(
105-
"document.getElementById('renderWorkflow').innerHTML"
106-
)
107-
except Exception as e:
108-
logger.error(f"Error calling render_workflow: {e}")
109-
# Try to get any error messages from the page
110-
errors = await page.evaluate(
111-
"document.querySelector('#renderWorkflow').innerHTML"
112-
)
113-
logger.info(f"Container content: {errors}")
114-
raise
115-
116-
logger.info(
117-
f"SVG generated, length: "
118-
f"{len(svg_content) if svg_content else 0} characters"
114+
svg_content = await self._page.evaluate(
115+
"document.getElementById('renderWorkflow').innerHTML"
116+
)
117+
except Exception as e:
118+
logger.error(f"Error calling render_workflow: {e}")
119+
# Try to get any error messages from the page
120+
errors = await self._page.evaluate(
121+
"document.querySelector('#renderWorkflow').innerHTML"
119122
)
120-
await browser.close()
121-
logger.info("Browser closed")
122-
return svg_content
123+
logger.info(f"Container content: {errors}")
124+
raise
125+
126+
logger.info(
127+
f"SVG generated, length: "
128+
f"{len(svg_content) if svg_content else 0} characters"
129+
)
130+
return svg_content
123131

124132

125133
@orchestrator_mcp.tool()

0 commit comments

Comments
 (0)