broadfield-dev commited on
Commit
d74e8cc
·
verified ·
1 Parent(s): c4ee6de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -32
app.py CHANGED
@@ -1,18 +1,17 @@
1
  import os
2
  os.system("playwright install")
3
- # app.py (Final, Working Async Version)
4
 
5
  import gradio as gr
6
  from playwright.async_api import async_playwright, Error as PlaywrightError
7
  from bs4 import BeautifulSoup
8
  import urllib.parse
9
- import atexit
10
- import re
11
  import os
12
  from itertools import cycle
13
  import uuid
14
 
15
- # --- 1. ASYNC GLOBAL RESOURCES & STATE ---
 
16
  P = None
17
  BROWSER = None
18
  REVOLVER = None
@@ -43,7 +42,7 @@ class CredentialRevolver:
43
  def get_next(self): return next(self.proxy_cycler) if self.proxy_cycler else None
44
  def count(self): return len(self.proxies)
45
 
46
- # --- 3. ASYNC LOGIC ---
47
  async def _fetch_and_update_tab_state(tab_state: TabState, url: str):
48
  log = f"▶️ Navigating to {url}..."; live_page = LIVE_CONTEXTS[tab_state.id]["page"]
49
  try:
@@ -91,22 +90,10 @@ async def handle_action(browser_state: BrowserState, action: str, value=None):
91
  browser_state.active_tab_id = value; log = f"Switched to tab."
92
  return browser_state, log
93
 
94
- def update_ui_components(browser_state: BrowserState): # This function is not async
95
- active_tab = browser_state.get_active_tab()
96
- if not active_tab: return {page_content: gr.Markdown("No active tabs."), url_textbox: "", links_display: "", tab_selector: gr.Radio(choices=[])}
97
- tab_choices = [(f"Tab {i}: {t.title[:25]}... (via {t.proxy_used})", t.id) for i, t in enumerate(browser_state.tabs)]
98
- links_md = "### 🔗 Links on Page\n" + ('\n'.join(f"{i}. [{link['text'][:80]}]({link['url']})" for i, link in enumerate(active_tab.links[:25])) if active_tab.links else "_No links found._")
99
- return {
100
- page_content: gr.Markdown(f"# {active_tab.title}\n**URL:** {active_tab.url}\n\n---\n\n{active_tab.parsed_text[:2000]}..."),
101
- url_textbox: gr.Textbox(value=active_tab.url), links_display: gr.Markdown(links_md),
102
- tab_selector: gr.Radio(choices=tab_choices, value=active_tab.id, label="Active Tabs"),
103
- }
104
-
105
- # --- 4. GRADIO UI AND EVENT HANDLING ---
106
  with gr.Blocks(theme=gr.themes.Soft(), title="Real Browser Demo") as demo:
107
  browser_state = gr.State(BrowserState())
108
  gr.Markdown("# 🛰️ Real Browser Demo (Final Working Version)")
109
- gr.Markdown(f"This demo runs a real headless browser. All threading issues are resolved.")
110
  # UI Layout is the same...
111
  with gr.Row():
112
  with gr.Column(scale=3):
@@ -120,8 +107,9 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Real Browser Demo") as demo:
120
  links_display = gr.Markdown("...");
121
  with gr.Row(): click_num_box = gr.Number(label="Link #", scale=1, minimum=0, step=1); click_btn = gr.Button("Click Link", scale=2)
122
 
 
123
  all_outputs = [page_content, url_textbox, links_display, tab_selector, log_display]
124
-
125
  async def master_handler(current_state, action, value=None):
126
  global APP_STARTED, P, BROWSER, REVOLVER
127
  if not APP_STARTED:
@@ -131,18 +119,47 @@ with gr.Blocks(theme=gr.themes.Soft(), title="Real Browser Demo") as demo:
131
  print(f"✅ Playwright started. {REVOLVER.count()} proxies loaded."); APP_STARTED = True
132
 
133
  new_state, log = await handle_action(current_state, action, value)
134
- ui_updates = update_ui_components(new_state); ui_updates[log_display] = log
135
- return new_state, ui_updates
136
-
137
- # All event listeners MUST be lambdas that await the async master_handler
138
- go_btn.click(lambda s, v: master_handler(s, "go", v), [browser_state, url_textbox], [browser_state, *all_outputs], show_progress="full")
139
- url_textbox.submit(lambda s, v: master_handler(s, "go", v), [browser_state, url_textbox], [browser_state, *all_outputs], show_progress="full")
140
- click_btn.click(lambda s, v: master_handler(s, "click", v), [browser_state, click_num_box], [browser_state, *all_outputs], show_progress="full")
141
- new_tab_btn.click(lambda s: master_handler(s, "new_tab", None), [browser_state], [browser_state, *all_outputs], show_progress="full")
142
- close_tab_btn.click(lambda s: master_handler(s, "close_tab", None), [browser_state], [browser_state, *all_outputs])
143
- tab_selector.input(lambda s, v: master_handler(s, "switch_tab", v), [browser_state, tab_selector], [browser_state, *all_outputs])
144
-
145
- # The load event triggers the very first startup
146
- demo.load(lambda s: master_handler(s, "new_tab", None), inputs=[browser_state], outputs=[browser_state, *all_outputs])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
  demo.launch()
 
1
  import os
2
  os.system("playwright install")
3
+ # app.py (Final, Working Async Version with Bugfixes)
4
 
5
  import gradio as gr
6
  from playwright.async_api import async_playwright, Error as PlaywrightError
7
  from bs4 import BeautifulSoup
8
  import urllib.parse
 
 
9
  import os
10
  from itertools import cycle
11
  import uuid
12
 
13
+ # --- 1. GLOBAL RESOURCES & STATE ---
14
+ # These are initialized on the first request to be compatible with Spaces.
15
  P = None
16
  BROWSER = None
17
  REVOLVER = None
 
42
  def get_next(self): return next(self.proxy_cycler) if self.proxy_cycler else None
43
  def count(self): return len(self.proxies)
44
 
45
+ # --- 3. ASYNC LOGIC (Unchanged) ---
46
  async def _fetch_and_update_tab_state(tab_state: TabState, url: str):
47
  log = f"▶️ Navigating to {url}..."; live_page = LIVE_CONTEXTS[tab_state.id]["page"]
48
  try:
 
90
  browser_state.active_tab_id = value; log = f"Switched to tab."
91
  return browser_state, log
92
 
93
+ # --- 4. GRADIO UI AND EVENT HANDLING (WITH FIXES) ---
 
 
 
 
 
 
 
 
 
 
 
94
  with gr.Blocks(theme=gr.themes.Soft(), title="Real Browser Demo") as demo:
95
  browser_state = gr.State(BrowserState())
96
  gr.Markdown("# 🛰️ Real Browser Demo (Final Working Version)")
 
97
  # UI Layout is the same...
98
  with gr.Row():
99
  with gr.Column(scale=3):
 
107
  links_display = gr.Markdown("...");
108
  with gr.Row(): click_num_box = gr.Number(label="Link #", scale=1, minimum=0, step=1); click_btn = gr.Button("Click Link", scale=2)
109
 
110
+ # This order must be consistent
111
  all_outputs = [page_content, url_textbox, links_display, tab_selector, log_display]
112
+
113
  async def master_handler(current_state, action, value=None):
114
  global APP_STARTED, P, BROWSER, REVOLVER
115
  if not APP_STARTED:
 
119
  print(f"✅ Playwright started. {REVOLVER.count()} proxies loaded."); APP_STARTED = True
120
 
121
  new_state, log = await handle_action(current_state, action, value)
122
+ ui_updates = update_ui_components(new_state)
123
+
124
+ # **THE CRITICAL FIX IS HERE:**
125
+ # We must return a tuple with a value for EACH output component, in the correct order.
126
+ return (
127
+ new_state, # 1. For the browser_state output
128
+ ui_updates[page_content], # 2.
129
+ ui_updates[url_textbox], # 3.
130
+ ui_updates[links_display], # 4.
131
+ ui_updates[tab_selector], # 5.
132
+ ui_updates[log_display] # 6.
133
+ )
134
+
135
+ # **THE SECOND CRITICAL FIX IS HERE:**
136
+ # Each event listener is a simple, separate async function that Gradio can correctly await.
137
+
138
+ async def on_load(state):
139
+ return await master_handler(state, "new_tab", None)
140
+
141
+ async def on_go_click(state, value):
142
+ return await master_handler(state, "go", value)
143
+
144
+ async def on_click_link(state, value):
145
+ return await master_handler(state, "click", value)
146
+
147
+ async def on_new_tab(state):
148
+ return await master_handler(state, "new_tab", None)
149
+
150
+ async def on_close_tab(state):
151
+ return await master_handler(state, "close_tab", None)
152
+
153
+ async def on_switch_tab(state, value):
154
+ return await master_handler(state, "switch_tab", value)
155
+
156
+ # Wire up the new, clean event handlers
157
+ demo.load(on_load, inputs=[browser_state], outputs=[browser_state, *all_outputs])
158
+ go_btn.click(on_go_click, [browser_state, url_textbox], [browser_state, *all_outputs], show_progress="full")
159
+ url_textbox.submit(on_go_click, [browser_state, url_textbox], [browser_state, *all_outputs], show_progress="full")
160
+ click_btn.click(on_click_link, [browser_state, click_num_box], [browser_state, *all_outputs], show_progress="full")
161
+ new_tab_btn.click(on_new_tab, [browser_state], [browser_state, *all_outputs], show_progress="full")
162
+ close_tab_btn.click(on_close_tab, [browser_state], [browser_state, *all_outputs])
163
+ tab_selector.input(on_switch_tab, [browser_state, tab_selector], [browser_state, *all_outputs])
164
 
165
  demo.launch()