@@ -14,6 +14,7 @@ def exp_result_to_html(
1414 axtree_open : bool = False ,
1515 html_open : bool = False ,
1616 prompt_open : bool = False ,
17+ embed_images : bool = True , # New parameter
1718) -> str :
1819 """
1920 Convert an ExpResult to HTML with collapsible sections.
@@ -25,6 +26,7 @@ def exp_result_to_html(
2526 axtree_open: Whether AXTree sections start expanded (default: False)
2627 html_open: Whether HTML sections start expanded (default: False)
2728 prompt_open: Whether Prompt sections start expanded (default: False)
29+ embed_images: Whether to embed images as base64 or use file paths (default: True)
2830
2931 Returns:
3032 str: HTML string with collapsible episode visualization
@@ -36,7 +38,7 @@ def exp_result_to_html(
3638 # Build HTML structure
3739 html_parts = []
3840
39- # Add CSS for styling
41+ # Add CSS for styling (unchanged)
4042 html_parts .append (
4143 """
4244 <style>
@@ -169,16 +171,14 @@ def exp_result_to_html(
169171 if step_info .action is None and i == 0 :
170172 continue # Skip initial reset step if no action
171173
172- # html_parts.append('<div class="step-separator"></div>')
173-
174174 # Step container with collapsible wrapper
175175 step_open_attr = "open" if steps_open else ""
176176 html_parts .append (f"<details { step_open_attr } >" )
177177 html_parts .append (f"<summary>Step { i } </summary>" )
178178 html_parts .append ('<div class="step-content">' )
179179
180180 # Screenshot (flat in step)
181- screenshot_html = _get_screenshot_html (exp_result , i )
181+ screenshot_html = _get_screenshot_html (exp_result , i , embed_images )
182182 html_parts .append (screenshot_html )
183183
184184 # Action (flat in step)
@@ -195,7 +195,7 @@ def exp_result_to_html(
195195 )
196196
197197 # SOM Screenshot (nested collapsible)
198- som_screenshot_html = _get_som_screenshot_html (exp_result , i , som_open )
198+ som_screenshot_html = _get_som_screenshot_html (exp_result , i , som_open , embed_images )
199199 if som_screenshot_html :
200200 html_parts .append (som_screenshot_html )
201201
@@ -255,30 +255,48 @@ def exp_result_to_html(
255255 return "" .join (html_parts )
256256
257257
258- def _get_screenshot_html (exp_result , step : int ) -> str :
258+ def _get_screenshot_html (exp_result , step : int , embed_images : bool ) -> str :
259259 """Get HTML for main screenshot at given step."""
260260 try :
261- screenshot = exp_result .get_screenshot (step , som = False )
262- return _image_to_html (screenshot , f"Screenshot { step } " )
261+ if embed_images :
262+ screenshot = exp_result .get_screenshot (step , som = False )
263+ return _image_to_html (screenshot , f"Screenshot { step } " )
264+ else :
265+ screenshot_path = exp_result .get_screenshot_path (step , som = False )
266+ return _path_to_html (screenshot_path , f"Screenshot { step } " )
263267 except (FileNotFoundError , IndexError ):
264268 return "<p>Screenshot not available</p>"
265269
266270
267- def _get_som_screenshot_html (exp_result , step : int , som_open : bool ) -> str :
271+ def _get_som_screenshot_html (exp_result , step : int , som_open : bool , embed_images : bool ) -> str :
268272 """Get HTML for SOM screenshot if available."""
269273 try :
270- screenshot_som = exp_result .get_screenshot (step , som = True )
271- if screenshot_som :
272- som_open_attr = "open" if som_open else ""
273- som_html = _image_to_html (screenshot_som , f"SOM Screenshot { step } " )
274- return f"""
275- <details class="nested-details" { som_open_attr } >
276- <summary>Screenshot_som[{ step } ]</summary>
277- <div class="content">
278- { som_html }
279- </div>
280- </details>
281- """
274+ if embed_images :
275+ screenshot_som = exp_result .get_screenshot (step , som = True )
276+ if screenshot_som :
277+ som_open_attr = "open" if som_open else ""
278+ som_html = _image_to_html (screenshot_som , f"SOM Screenshot { step } " )
279+ return f"""
280+ <details class="nested-details" { som_open_attr } >
281+ <summary>Screenshot_som[{ step } ]</summary>
282+ <div class="content">
283+ { som_html }
284+ </div>
285+ </details>
286+ """
287+ else :
288+ screenshot_path = exp_result .get_screenshot_path (step , som = True )
289+ if screenshot_path and screenshot_path .exists ():
290+ som_open_attr = "open" if som_open else ""
291+ som_html = _path_to_html (screenshot_path , f"SOM Screenshot { step } " )
292+ return f"""
293+ <details class="nested-details" { som_open_attr } >
294+ <summary>Screenshot_som[{ step } ]</summary>
295+ <div class="content">
296+ { som_html }
297+ </div>
298+ </details>
299+ """
282300 except (FileNotFoundError , IndexError ):
283301 pass
284302 return ""
@@ -297,6 +315,17 @@ def _image_to_html(image, alt_text: str) -> str:
297315 return f'<img src="data:image/png;base64,{ img_str } " alt="{ alt_text } " class="screenshot">'
298316
299317
318+ def _path_to_html (image_path , alt_text : str ) -> str :
319+ """Convert image path to HTML img tag."""
320+ if image_path is None or not image_path .exists ():
321+ return f"<p>{ alt_text } not available</p>"
322+
323+ # Convert to absolute path and use file:// protocol
324+ abs_path = image_path .resolve ()
325+ return f'<img src="file://{ abs_path } " alt="{ alt_text } " class="screenshot">'
326+
327+
328+ # Rest of the helper functions remain unchanged...
300329def _format_goal (goal ) -> str :
301330 """Format goal object like xray does - using code blocks."""
302331 if goal is None :
@@ -391,7 +420,6 @@ def _escape_html(text: str) -> str:
391420
392421
393422if __name__ == "__main__" :
394- from pathlib import Path
395423
396424 from agentlab .experiments .exp_utils import RESULTS_DIR
397425
@@ -403,7 +431,7 @@ def _escape_html(text: str) -> str:
403431 print (f"Using first exp_dir in most recent study:\n { exp_dir } " )
404432 exp_result = ExpResult (exp_dir = exp_dir )
405433
406- page = exp_result_to_html (exp_result )
434+ page = exp_result_to_html (exp_result , embed_images = False )
407435
408436 output_file = exp_dir / "episode.html"
409437 print (f"Writing HTML to\n { output_file } " )
0 commit comments