import json import gradio as gr from backend import ( task_queue, result_queue, BROWSER_STATE, BROWSER_LOCK, start_worker_thread, stop_worker_thread, StorageState ) # ───────────────────────────── # Frontend callbacks (Gradio) # ───────────────────────────── def start_browser(storage_state_file:bytes): with BROWSER_LOCK: running = BROWSER_STATE.running if running: with BROWSER_LOCK: tabs = list(BROWSER_STATE.pages.keys()) active = BROWSER_STATE.active_page return "Browser is already running.", None, gr.update(choices=tabs, value=active) start_worker_thread(StorageState(json.loads(storage_state_file)) if storage_state_file else None) return "Browser Started!", None, gr.update(choices=["Tab-1"], value="Tab-1") def stop_browser(): with BROWSER_LOCK: running = BROWSER_STATE.running if not running: return "Browser is not running.", None, gr.update(choices=[], value=None) stop_worker_thread() with BROWSER_LOCK: BROWSER_STATE.pages.clear() BROWSER_STATE.active_page = None return "Browser Closed!", None, gr.update(choices=[], value=None) def execute_code(code): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "eval", "code": code}) return result_queue.get() def navigate(url): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "goto", "url": url}) return result_queue.get() def click(selector): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "click", "selector": selector}) return result_queue.get() def type_text(selector, text): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "type", "selector": selector, "text": text}) return result_queue.get() def new_tab(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "new_tab"}) r, screenshot = result_queue.get() with BROWSER_LOCK: tabs = list(BROWSER_STATE.pages.keys()) active = BROWSER_STATE.active_page return r, screenshot, gr.update(choices=tabs, value=active) def close_tab(tab): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "close_tab", "tab": tab}) r, screenshot = result_queue.get() with BROWSER_LOCK: tabs = list(BROWSER_STATE.pages.keys()) active = BROWSER_STATE.active_page return r, screenshot, gr.update(choices=tabs, value=active) def switch_tab(tab): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "switch_tab", "tab": tab}) r, screenshot = result_queue.get() with BROWSER_LOCK: tabs = list(BROWSER_STATE.pages.keys()) active = BROWSER_STATE.active_page return r, screenshot, gr.update(choices=tabs, value=active) def inspect_element(selector): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "inspect", "selector": selector}) return result_queue.get() def show_network_logs(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "get_network_logs"}) return result_queue.get() def show_console_logs(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "get_console_logs"}) return result_queue.get() def clear_logs(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "clear_logs"}) return result_queue.get() def start_recording(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "start_record"}) return result_queue.get() def stop_recording(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "stop_record"}) return result_queue.get() def play_macro(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "play_macro"}) return result_queue.get() def capture_screenshot(): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "take_screenshot"}) return result_queue.get() def find_template(template_img): with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({"cmd": "find_template", "template": template_img}) return result_queue.get() def handle_click(event: gr.SelectData, click_type, last_image): x, y = event.index if last_image is None: return "No screenshot available. Take screenshot first.", None img_w, img_h = last_image.size with BROWSER_LOCK: if not BROWSER_STATE.running: return "Start browser first.", None task_queue.put({ "cmd": "click_xy", "x": x, "y": y, "img_w": img_w, "img_h": img_h, "click_type": click_type }) return result_queue.get() # ───────────────────────────── # Gradio UI # ───────────────────────────── with gr.Blocks() as app: gr.Markdown("## 🔥 Advanced Playwright Control Panel (DOM + Logs + Macro + Vision RPA)") state_file = gr.File(label="PlayWright State File",file_types=['.json'],type="binary") with gr.Row(): start_btn = gr.Button("Open Browser") stop_btn = gr.Button("Close Browser") tabs_dropdown = gr.Dropdown(label="Tabs", choices=[], value=None) with gr.Tab("Browse"): with gr.Row(): url_box = gr.Textbox(label="URL", scale=4) nav_btn = gr.Button("Go", scale=1) with gr.Row(): sel_box = gr.Textbox(label="Selector (CSS)", scale=3) click_btn = gr.Button("Click", scale=1) type_box = gr.Textbox(label="Type Text", scale=3) type_btn = gr.Button("Type", scale=1) with gr.Tab("Inspect / Code"): with gr.Row(): inspect_sel = gr.Textbox(label="Inspect Selector (CSS)") inspect_btn = gr.Button("Inspect + Generate XPath") code_input = gr.TextArea(label="Python Code (eval in Playwright worker - restricted)") run_btn = gr.Button("Run Code") with gr.Tab("Logs"): with gr.Row(): net_btn = gr.Button("Show Network Logs") cons_btn = gr.Button("Show Console Logs") clear_logs_btn = gr.Button("Clear Logs") with gr.Tab("Tabs & Macros"): with gr.Row(): new_tab_btn = gr.Button("New Tab") close_tab_btn = gr.Button("Close Selected Tab") switch_tab_btn = gr.Button("Switch Tab") with gr.Row(): start_rec_btn = gr.Button("Start Macro Recording") stop_rec_btn = gr.Button("Stop Recording") play_macro_btn = gr.Button("Play Recorded Macro") with gr.Tab("Vision Tools"): capture_btn = gr.Button("📸 Capture Screenshot") click_type = gr.Radio( ["left", "double", "right", "hover"], value="left", label="Click Type" ) template_img = gr.Image( label="Template Image (for OpenCV match)", type="pil" ) find_template_btn = gr.Button("🔍 Find Template on Page") output_text = gr.TextArea(label="Output") output_image = gr.Image(label="Screenshot", type="pil") # screenshot click handler output_image.select( handle_click, inputs=[click_type, output_image], outputs=[output_text, output_image] ) # Bindings start_btn.click(start_browser, inputs=[state_file], outputs=[output_text, output_image, tabs_dropdown]) stop_btn.click(stop_browser, outputs=[output_text, output_image, tabs_dropdown]) new_tab_btn.click(new_tab, outputs=[output_text, output_image, tabs_dropdown]) close_tab_btn.click(close_tab, inputs=tabs_dropdown, outputs=[output_text, output_image, tabs_dropdown]) switch_tab_btn.click(switch_tab, inputs=tabs_dropdown, outputs=[output_text, output_image, tabs_dropdown]) nav_btn.click(navigate, inputs=url_box, outputs=[output_text, output_image]) click_btn.click(click, inputs=sel_box, outputs=[output_text, output_image]) type_btn.click(type_text, inputs=[sel_box, type_box], outputs=[output_text, output_image]) run_btn.click(execute_code, inputs=code_input, outputs=[output_text, output_image]) inspect_btn.click(inspect_element, inputs=inspect_sel, outputs=[output_text, output_image]) net_btn.click(show_network_logs, outputs=[output_text, output_image]) cons_btn.click(show_console_logs, outputs=[output_text, output_image]) clear_logs_btn.click(clear_logs, outputs=[output_text, output_image]) start_rec_btn.click(start_recording, outputs=[output_text, output_image]) stop_rec_btn.click(stop_recording, outputs=[output_text, output_image]) play_macro_btn.click(play_macro, outputs=[output_text, output_image]) capture_btn.click(capture_screenshot, outputs=[output_text, output_image]) find_template_btn.click(find_template, inputs=[template_img], outputs=[output_text, output_image]) if __name__ == "__main__": app.launch()