sharanyaswarup commited on
Commit
651eb52
Β·
1 Parent(s): 5e4d279

Update UI aesthetics and add smart JSON scanning

Browse files
Files changed (1) hide show
  1. app.py +45 -10
app.py CHANGED
@@ -43,6 +43,19 @@ def get_output_file(state: str) -> str:
43
  def get_excel_file(state: str) -> str:
44
  return os.path.join(EXCEL_DIR, f"{_state_prefix(state)}_Schools.xlsx")
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  # ── HTML builders ─────────────────────────────────────────────────────────────
48
 
@@ -264,6 +277,20 @@ def _stream(pytest_args: list, state: str, max_retries: int, mode: str):
264
  yield (_stopped_html(), _phase_html("Stopped by user."), result_rendered,
265
  "\n".join(log_lines[-80:]), out_file if os.path.exists(out_file) else None, gr.update(), gr.update(value="⏹ Stopped", variant="secondary"))
266
  else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  yield _emit()
268
 
269
 
@@ -287,6 +314,12 @@ def ui_retry(state, max_retries):
287
  if not os.path.exists(out):
288
  yield _idle_html(), _phase_html(f"⚠️ No output file for {state}. Run Main Scrape first."), "", "", None, gr.update(), gr.update()
289
  return
 
 
 
 
 
 
290
  yield from _stream(
291
  ["pytest", "tests/test_retry_districts_by_category.py", "-v", "-s", "--state", state],
292
  state, max_retries, "retry",
@@ -354,9 +387,9 @@ custom_theme = gr.themes.Soft(
354
 
355
  with gr.Blocks(title="KYS Category Scraper", css=css, theme=custom_theme) as app:
356
 
357
- gr.Markdown("# 🏫 KYS School Scraper β€” District Γ— Category", elem_id="title")
358
  gr.Markdown(
359
- "Categories **3 Β· 5 Β· 6 Β· 7 Β· 10 Β· 11** applied at API call time. District-level.",
360
  elem_id="subtitle",
361
  )
362
 
@@ -370,10 +403,7 @@ with gr.Blocks(title="KYS Category Scraper", css=css, theme=custom_theme) as app
370
  download_btn = gr.File(label="⬇️ Download JSON", interactive=False)
371
  excel_dl_btn = gr.File(label="⬇️ Download Excel", interactive=False)
372
 
373
- # ── Retries slider ────────────────────────────────────────────────────────
374
- retries_slider = gr.Slider(minimum=1, maximum=10, value=5, step=1,
375
- label="πŸ” Max captcha retry rounds per combo (each round = 2 API calls)")
376
-
377
  gr.Markdown("---")
378
 
379
  # ── Buttons ───────────────────────────────────────────────────────────────
@@ -385,13 +415,13 @@ with gr.Blocks(title="KYS Category Scraper", css=css, theme=custom_theme) as app
385
 
386
  with gr.Row():
387
  with gr.Column(scale=2):
388
- gr.Markdown("_Starts fresh β€” deletes previous output for this state._")
389
  with gr.Column(scale=2):
390
- gr.Markdown("_Merges into existing file. Only re-scrapes captcha-failed combos._")
391
  with gr.Column(scale=2):
392
- gr.Markdown("_Converts JSON to Schools.xlsx format._")
393
  with gr.Column(scale=1):
394
- gr.Markdown("_Kills the running test immediately._")
395
 
396
  gr.Markdown("---")
397
 
@@ -408,6 +438,11 @@ with gr.Blocks(title="KYS Category Scraper", css=css, theme=custom_theme) as app
408
  show_label=False, elem_classes=["log-box"],
409
  placeholder="Logs appear here during the run...")
410
 
 
 
 
 
 
411
  # ── Wiring ────────────────────────────────────────────────────────────────
412
  shared_outputs = [progress_html, phase_html, result_html, log_box, download_btn, retry_btn, status_indicator]
413
 
 
43
  def get_excel_file(state: str) -> str:
44
  return os.path.join(EXCEL_DIR, f"{_state_prefix(state)}_Schools.xlsx")
45
 
46
+ def check_missed_schools(json_path: str):
47
+ if not os.path.exists(json_path):
48
+ return None
49
+ try:
50
+ import json
51
+ with open(json_path, 'r', encoding='utf-8') as f:
52
+ data = json.load(f)
53
+ if not isinstance(data, list):
54
+ return None
55
+ return sum(1 for item in data if item.get("status") != "success")
56
+ except Exception:
57
+ return None
58
+
59
 
60
  # ── HTML builders ─────────────────────────────────────────────────────────────
61
 
 
277
  yield (_stopped_html(), _phase_html("Stopped by user."), result_rendered,
278
  "\n".join(log_lines[-80:]), out_file if os.path.exists(out_file) else None, gr.update(), gr.update(value="⏹ Stopped", variant="secondary"))
279
  else:
280
+ # Post-run scan of JSON file to guarantee state
281
+ failed_count = check_missed_schools(out_file)
282
+ if failed_count is not None:
283
+ if failed_count == 0:
284
+ is_done = True
285
+ has_failures = False
286
+ phase_text = "βœ… All data retrieved successfully!"
287
+ result_rendered += "<br/><div style='color:green; font-weight:bold;'>File scanned: All schools retrieved.</div>"
288
+ else:
289
+ is_done = True
290
+ has_failures = True
291
+ phase_text = f"⚠️ {failed_count} combos missed. Click 'Run Retry'."
292
+ result_rendered += f"<br/><div style='color:orange; font-weight:bold;'>File scanned: {failed_count} combos still missing.</div>"
293
+
294
  yield _emit()
295
 
296
 
 
314
  if not os.path.exists(out):
315
  yield _idle_html(), _phase_html(f"⚠️ No output file for {state}. Run Main Scrape first."), "", "", None, gr.update(), gr.update()
316
  return
317
+
318
+ failed_count = check_missed_schools(out)
319
+ if failed_count == 0:
320
+ yield _idle_html(), _phase_html("βœ… All data is already retrieved successfully! No need to retry."), "", "", out, gr.update(), gr.update(value="βœ… ALL DATA RETRIEVED! You can download/export now.", variant="primary")
321
+ return
322
+
323
  yield from _stream(
324
  ["pytest", "tests/test_retry_districts_by_category.py", "-v", "-s", "--state", state],
325
  state, max_retries, "retry",
 
387
 
388
  with gr.Blocks(title="KYS Category Scraper", css=css, theme=custom_theme) as app:
389
 
390
+ gr.Markdown("# 🏫 KYS School Scraper", elem_id="title")
391
  gr.Markdown(
392
+ "<div style='text-align: center; color: var(--body-text-color-subdued);'>Categories 3 Β· 5 Β· 6 Β· 7 Β· 10 Β· 11</div>",
393
  elem_id="subtitle",
394
  )
395
 
 
403
  download_btn = gr.File(label="⬇️ Download JSON", interactive=False)
404
  excel_dl_btn = gr.File(label="⬇️ Download Excel", interactive=False)
405
 
406
+ # (Settings moved to bottom)
 
 
 
407
  gr.Markdown("---")
408
 
409
  # ── Buttons ───────────────────────────────────────────────────────────────
 
415
 
416
  with gr.Row():
417
  with gr.Column(scale=2):
418
+ gr.Markdown("<div style='text-align:center;'>_Starts fresh run_</div>")
419
  with gr.Column(scale=2):
420
+ gr.Markdown("<div style='text-align:center;'>_Retries failed captchas_</div>")
421
  with gr.Column(scale=2):
422
+ gr.Markdown("<div style='text-align:center;'>_Converts to Excel_</div>")
423
  with gr.Column(scale=1):
424
+ gr.Markdown("<div style='text-align:center;'>_Stop process_</div>")
425
 
426
  gr.Markdown("---")
427
 
 
438
  show_label=False, elem_classes=["log-box"],
439
  placeholder="Logs appear here during the run...")
440
 
441
+ # ── Settings ──────────────────────────────────────────────────────────────
442
+ with gr.Accordion("βš™οΈ Settings", open=False):
443
+ retries_slider = gr.Slider(minimum=1, maximum=10, value=5, step=1,
444
+ label="πŸ” Max captcha retry rounds per combo")
445
+
446
  # ── Wiring ────────────────────────────────────────────────────────────────
447
  shared_outputs = [progress_html, phase_html, result_html, log_box, download_btn, retry_btn, status_indicator]
448