diff --git a/src/browser/custom_context.py b/src/browser/custom_context.py
index 70cabe5..2fe7e7c 100644
--- a/src/browser/custom_context.py
+++ b/src/browser/custom_context.py
@@ -14,16 +14,15 @@ from browser_use.browser.browser import Browser
from browser_use.browser.context import BrowserContext, BrowserContextConfig
logger = logging.getLogger(__name__)
-
class CustomBrowserContext(BrowserContext):
def __init__(
self,
- browser: "Browser",
+ browser: "CustomBrowser", # Forward declaration for CustomBrowser
config: BrowserContextConfig = BrowserContextConfig(),
- context: BrowserContext = None,
+ context: PlaywrightContext = None
):
super(CustomBrowserContext, self).__init__(browser=browser, config=config)
- self.context = context
+ self.context = context # Rename to avoid confusion
self._page = None
@property
@@ -31,7 +30,7 @@ class CustomBrowserContext(BrowserContext):
"""Returns the underlying Playwright context implementation"""
return self.context
- async def _create_context(self, browser: PlaywrightBrowser):
+ async def _create_context(self, browser: PlaywrightBrowser = None):
"""Creates a new browser context with anti-detection measures and loads cookies if available."""
if self.context:
return self.context
diff --git a/webui.py b/webui.py
index afd05a3..87fde48 100644
--- a/webui.py
+++ b/webui.py
@@ -627,18 +627,68 @@ def create_ui(theme_name="Ocean"):
)
add_infos = gr.Textbox(lines=3, label="Additional Information")
- # Results
- with gr.Tab("📊 Results"):
- browser_view = gr.HTML(
- value="
Waiting for browser session...
",
- label="Live Browser View",
+ with gr.TabItem("📊 Results", id=5):
+ with gr.Group():
+ gr.Markdown("### Results")
+ with gr.Row():
+ browser_view = gr.HTML(
+ value="Waiting for browser session...
",
+ label="Live Browser View",
+ )
+ with gr.Row():
+ with gr.Column():
+ final_result_output = gr.Textbox(
+ label="Final Result", lines=3, show_label=True
+ )
+ with gr.Column():
+ errors_output = gr.Textbox(
+ label="Errors", lines=3, show_label=True
+ )
+ with gr.Row():
+ with gr.Column():
+ model_actions_output = gr.Textbox(
+ label="Model Actions", lines=3, show_label=True
+ )
+ with gr.Column():
+ model_thoughts_output = gr.Textbox(
+ label="Model Thoughts", lines=3, show_label=True
+ )
+
+ recording_file = gr.Video(label="Latest Recording")
+ trace_file = gr.File(label="Trace File")
+ with gr.TabItem("🎥 Recordings", id=6):
+ def list_recordings(save_recording_path):
+ if not os.path.exists(save_recording_path):
+ return []
+
+ # Get all video files
+ recordings = glob.glob(os.path.join(save_recording_path, "*.[mM][pP]4")) + glob.glob(os.path.join(save_recording_path, "*.[wW][eE][bB][mM]"))
+
+ # Sort recordings by creation time (oldest first)
+ recordings.sort(key=os.path.getctime)
+
+ # Add numbering to the recordings
+ numbered_recordings = []
+ for idx, recording in enumerate(recordings, start=1):
+ filename = os.path.basename(recording)
+ numbered_recordings.append((recording, f"{idx}. {filename}"))
+
+ return numbered_recordings
+
+ recordings_gallery = gr.Gallery(
+ label="Recordings",
+ value=list_recordings("./tmp/record_videos"),
+ columns=3,
+ height="auto",
+ object_fit="contain"
+ )
+
+ refresh_button = gr.Button("🔄 Refresh Recordings", variant="secondary")
+ refresh_button.click(
+ fn=list_recordings,
+ inputs=save_recording_path,
+ outputs=recordings_gallery
)
- final_result_output = gr.Textbox(label="Final Result", lines=3)
- errors_output = gr.Textbox(label="Errors", lines=3)
- model_actions_output = gr.Textbox(label="Model Actions", lines=3)
- model_thoughts_output = gr.Textbox(label="Model Thoughts", lines=3)
- recording_file = gr.Video(label="Latest Recording")
- trace_file = gr.File(label="Trace File")
with gr.Row():
run_button = gr.Button("▶️ Run Agent", variant="primary")