abdulsalam2121 commited on
Commit
99c2f3b
·
1 Parent(s): 534993f

Add live browser screenshot panel for dashboard

Browse files
app/browser_session.py CHANGED
@@ -85,6 +85,11 @@ class BrowserSession:
85
  except Exception:
86
  pass
87
  return False
 
 
 
 
 
88
  return True
89
  except Exception as e:
90
  logger.error(f"Navigation failed [{url}]: {e}")
@@ -98,6 +103,16 @@ class BrowserSession:
98
  try:
99
  path = f"logs/{name}.png"
100
  self.page.screenshot(path=path, full_page=True)
 
 
 
 
 
 
 
 
 
 
101
  logger.debug(f"Screenshot: {path}")
102
  except Exception:
103
  pass
 
85
  except Exception:
86
  pass
87
  return False
88
+ try:
89
+ # Update the latest screenshot after successful navigation for debugging/UI
90
+ self.screenshot("latest")
91
+ except Exception:
92
+ pass
93
  return True
94
  except Exception as e:
95
  logger.error(f"Navigation failed [{url}]: {e}")
 
103
  try:
104
  path = f"logs/{name}.png"
105
  self.page.screenshot(path=path, full_page=True)
106
+ # Also write a consistent latest screenshot for the UI
107
+ try:
108
+ latest = Path("logs") / "screenshot_latest.png"
109
+ Path(path).resolve()
110
+ # overwrite latest
111
+ from shutil import copyfile
112
+
113
+ copyfile(path, str(latest))
114
+ except Exception:
115
+ pass
116
  logger.debug(f"Screenshot: {path}")
117
  except Exception:
118
  pass
app/static/app.js CHANGED
@@ -24,6 +24,7 @@ const elements = {
24
  let logCursor = 0;
25
  let pollTimer = null;
26
  let running = false;
 
27
 
28
  function setBanner(element, message) {
29
  if (!message) {
@@ -204,6 +205,17 @@ function boot() {
204
  setRunningState(false);
205
  fetchStatus();
206
  pollTimer = window.setInterval(fetchStatus, 2000);
 
 
 
 
 
 
 
 
 
 
 
207
  }
208
 
209
  document.addEventListener('DOMContentLoaded', boot);
 
24
  let logCursor = 0;
25
  let pollTimer = null;
26
  let running = false;
27
+ let screenshotTimer = null;
28
 
29
  function setBanner(element, message) {
30
  if (!message) {
 
205
  setRunningState(false);
206
  fetchStatus();
207
  pollTimer = window.setInterval(fetchStatus, 2000);
208
+ // Start screenshot refresher
209
+ const img = document.getElementById('screenshotImg');
210
+ if (img) {
211
+ const refresh = () => {
212
+ img.src = '/screenshot?ts=' + Date.now();
213
+ };
214
+ // refresh every 3 seconds
215
+ screenshotTimer = window.setInterval(refresh, 3000);
216
+ // try an initial load
217
+ refresh();
218
+ }
219
  }
220
 
221
  document.addEventListener('DOMContentLoaded', boot);
app/templates/index.html CHANGED
@@ -102,6 +102,12 @@
102
  </div>
103
  <pre id="logOutput" class="log-output">Waiting for the next run...</pre>
104
  </div>
 
 
 
 
 
 
105
  </section>
106
  </main>
107
  </div>
 
102
  </div>
103
  <pre id="logOutput" class="log-output">Waiting for the next run...</pre>
104
  </div>
105
+ <div class="screenshot-panel">
106
+ <h3>Live Browser View</h3>
107
+ <div class="screenshot-wrap">
108
+ <img id="screenshotImg" src="/screenshot" alt="Latest screenshot" style="width:100%;border-radius:6px;display:block;" />
109
+ </div>
110
+ </div>
111
  </section>
112
  </main>
113
  </div>
app/web_app.py CHANGED
@@ -93,6 +93,19 @@ def status():
93
  return jsonify(controller.snapshot())
94
 
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  @app.get("/download")
97
  def download():
98
  snapshot = controller.snapshot()
 
93
  return jsonify(controller.snapshot())
94
 
95
 
96
+ @app.get("/screenshot")
97
+ def screenshot_route():
98
+ latest = APP_DIR / ".." / "logs" / "screenshot_latest.png"
99
+ # normalize
100
+ latest = latest.resolve()
101
+ if not latest.exists():
102
+ return ("", 204)
103
+ try:
104
+ return send_file(str(latest), mimetype="image/png")
105
+ except Exception:
106
+ return ("", 500)
107
+
108
+
109
  @app.get("/download")
110
  def download():
111
  snapshot = controller.snapshot()