CoBeDigger commited on
Commit
50b5a43
Β·
1 Parent(s): 6339bd9

feat(ui): streaming real-time action log for baseline runner

Browse files
Files changed (1) hide show
  1. gradio_app.py +127 -18
gradio_app.py CHANGED
@@ -555,35 +555,144 @@ with gr.Blocks(title="PipelineOps Arena β€” OpenEnv") as demo:
555
 
556
  # ── BASELINE TAB ──────────────────────────────────────────────────────
557
  with gr.Tab("πŸš€ Run Baseline"):
558
- gr.Markdown("### Run the hardcoded expert baseline against the live environment")
559
 
560
  run_btn = gr.Button("β–Ά Run Full Baseline (All 4 Stages)", elem_classes="btn-primary")
561
 
562
  live_output = gr.Textbox(
563
- label="Baseline Output",
564
- lines=22,
565
  interactive=False,
566
- placeholder="Click Run to execute the baseline agent…",
567
  elem_classes="code-box"
568
  )
569
 
570
- def run_baseline_ui():
571
- import subprocess, os, sys
572
- env = os.environ.copy()
573
- env["DATAENGENV_URL"] = BASE_URL
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
574
  try:
575
- result = subprocess.run(
576
- [sys.executable, "baseline/run_baseline.py"],
577
- capture_output=True, text=True, timeout=300, env=env
578
- )
579
- out = result.stdout + result.stderr
580
- return out if out.strip() else "βœ… Baseline completed with no output."
581
- except subprocess.TimeoutExpired:
582
- return "⏱ Baseline timed out after 5 minutes."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
  except Exception as e:
584
- return f"❌ Error running baseline: {e}"
585
 
586
- run_btn.click(run_baseline_ui, inputs=[], outputs=[live_output])
587
 
588
  # ── DOCS TAB ─────────────────────────────────────────────────────────
589
  with gr.Tab("πŸ“– API Docs"):
 
555
 
556
  # ── BASELINE TAB ──────────────────────────────────────────────────────
557
  with gr.Tab("πŸš€ Run Baseline"):
558
+ gr.Markdown("### Run the hardcoded expert baseline β€” watch every action live as it executes")
559
 
560
  run_btn = gr.Button("β–Ά Run Full Baseline (All 4 Stages)", elem_classes="btn-primary")
561
 
562
  live_output = gr.Textbox(
563
+ label="⚑ Live Action Log",
564
+ lines=28,
565
  interactive=False,
566
+ placeholder="Click Run to start the baseline agent…\n\nYou will see each action appear here in real-time as the agent\nworks through all 4 stages of the pipeline.",
567
  elem_classes="code-box"
568
  )
569
 
570
+ ACTION_ICONS = {
571
+ "inspect_data": "πŸ”",
572
+ "check_schema": "πŸ“‹",
573
+ "run_script": "▢️ ",
574
+ "edit_script": "✏️ ",
575
+ "query_actor": "πŸ€–",
576
+ "submit": "πŸ“€",
577
+ }
578
+ STAGE_LABELS = {
579
+ 1: "Data Repair",
580
+ 2: "Training Monitor",
581
+ 3: "Eval Validation",
582
+ 4: "Deploy Gate",
583
+ }
584
+
585
+ def run_baseline_streaming():
586
+ import time as _time
587
+ log = []
588
+
589
+ def emit(line):
590
+ log.append(line)
591
+ return "\n".join(log)
592
+
593
+ yield emit("╔══════════════════════════════════════════════════════╗")
594
+ yield emit("β•‘ PipelineOps Arena β€” Baseline Run β•‘")
595
+ yield emit("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n")
596
+
597
  try:
598
+ # Reset
599
+ r = httpx.post(f"{BASE_URL}/reset", timeout=15)
600
+ obs = r.json()
601
+ if "observation" in obs:
602
+ obs = obs["observation"]
603
+ yield emit(f"βœ… Environment reset β†’ Stage 1: {STAGE_LABELS[1]}\n")
604
+ _time.sleep(0.3)
605
+
606
+ steps = [
607
+ # Stage 1
608
+ {"action_type": "inspect_data", "payload": {}},
609
+ {"action_type": "edit_script", "payload": {
610
+ "old": "X = df[['age_years', 'salary', 'credit_score', 'loan_amount', 'employment_years']].copy()",
611
+ "new": "df.dropna(inplace=True)\nX = df[['age', 'salary', 'credit_score', 'loan_amount', 'employment_years']].copy()"
612
+ }},
613
+ {"action_type": "run_script", "payload": {}},
614
+ {"action_type": "submit", "payload": {}},
615
+ # Stage 2
616
+ {"action_type": "inspect_data", "payload": {}},
617
+ {"action_type": "edit_script", "payload": {
618
+ "old": "clf = MLPClassifier(hidden_layer_sizes=(64, 32), max_iter=200, random_state=42)",
619
+ "new": "from sklearn.preprocessing import StandardScaler\nscaler = StandardScaler()\nX_train = scaler.fit_transform(X_train)\nX_test = scaler.transform(X_test)\nclf = MLPClassifier(hidden_layer_sizes=(64, 32), max_iter=200, random_state=42)"
620
+ }},
621
+ {"action_type": "run_script", "payload": {}},
622
+ {"action_type": "submit", "payload": {}},
623
+ # Stage 3
624
+ {"action_type": "run_script", "payload": {}},
625
+ {"action_type": "edit_script", "payload": {
626
+ "old": "scaler = StandardScaler()\nX_scaled = scaler.fit_transform(X)\nX_train, X_test, y_train, y_test = train_test_split(\n X_scaled, y, test_size=0.2, random_state=42, stratify=y\n)",
627
+ "new": "X_train, X_test, y_train, y_test = train_test_split(\n X, y, test_size=0.2, random_state=42, stratify=y\n)\nscaler = StandardScaler()\nX_train = scaler.fit_transform(X_train)\nX_test = scaler.transform(X_test)"
628
+ }},
629
+ {"action_type": "run_script", "payload": {}},
630
+ {"action_type": "submit", "payload": {}},
631
+ # Stage 4
632
+ {"action_type": "inspect_data", "payload": {}},
633
+ {"action_type": "query_actor", "payload": {}},
634
+ {"action_type": "edit_script", "payload": {
635
+ "old": "clf = LogisticRegression(max_iter=1000, random_state=42)",
636
+ "new": "clf = LogisticRegression(max_iter=1000, random_state=42, class_weight='balanced')"
637
+ }},
638
+ {"action_type": "run_script", "payload": {}},
639
+ {"action_type": "submit", "payload": {}},
640
+ ]
641
+
642
+ current_stage = 1
643
+ step_num = 0
644
+
645
+ for action in steps:
646
+ step_num += 1
647
+ atype = action["action_type"]
648
+ icon = ACTION_ICONS.get(atype, "β–Έ")
649
+
650
+ yield emit(f" Step {step_num:02d} β”‚ {icon} {atype.upper():<18} β”‚ running…")
651
+ _time.sleep(0.2)
652
+
653
+ resp = httpx.post(f"{BASE_URL}/step", json=action, timeout=30)
654
+ data = resp.json()
655
+ obs = data.get("observation", data)
656
+ rwd = data.get("reward", {})
657
+ score = float(rwd.get("score", 0.0))
658
+ msg = rwd.get("message", "")[:55]
659
+ new_stage = obs.get("current_stage", current_stage)
660
+ done = obs.get("done", False)
661
+
662
+ # Overwrite the last line with result
663
+ log[-1] = f" Step {step_num:02d} β”‚ {icon} {atype.upper():<18} β”‚ score={score:.2f} {msg}"
664
+ yield "\n".join(log)
665
+
666
+ # Stage transition banner
667
+ if new_stage != current_stage:
668
+ current_stage = new_stage
669
+ label = STAGE_LABELS.get(current_stage, f"Stage {current_stage}")
670
+ yield emit(f"\n{'─'*54}")
671
+ yield emit(f" ➜ Advancing to Stage {current_stage}: {label}")
672
+ yield emit(f"{'─'*54}\n")
673
+
674
+ if done:
675
+ break
676
+
677
+ _time.sleep(0.4)
678
+
679
+ # Final summary
680
+ status = httpx.get(f"{BASE_URL}/pipeline_status", timeout=10).json()
681
+ completed = status.get("stages_completed", [])
682
+ final_score = status.get("episode_score", 0.0)
683
+ total_steps = status.get("total_steps", step_num)
684
+
685
+ yield emit(f"\n╔══════════════════════════════════════════════════════╗")
686
+ yield emit(f"β•‘ βœ… EPISODE COMPLETE! β•‘")
687
+ yield emit(f"β•‘ Stages completed : {str(completed):<34}β•‘")
688
+ yield emit(f"β•‘ Total steps : {str(total_steps):<34}β•‘")
689
+ yield emit(f"β•‘ Final score : {final_score:.2f}{'':<33}β•‘")
690
+ yield emit(f"β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•")
691
+
692
  except Exception as e:
693
+ yield emit(f"\n❌ Error during baseline run: {e}")
694
 
695
+ run_btn.click(run_baseline_streaming, inputs=[], outputs=[live_output])
696
 
697
  # ── DOCS TAB ─────────────────────────────────────────────────────────
698
  with gr.Tab("πŸ“– API Docs"):