import streamlit as st import os import json import pandas as pd from dotenv import load_dotenv load_dotenv() from data.bug_dataset import TRAINING_SCENARIOS from orchestrator import Debugger st.set_page_config(page_title="CodeDebugger RL", layout="wide") st.markdown(""" """, unsafe_allow_html=True) # Sync API Key from state to env if "groq_api_key" not in st.session_state: st.session_state.groq_api_key = os.environ.get("GROQ_API_KEY", "") # Load datasets problems_dict = {f"{p['id']}: {p.get('title', 'Unknown')} [{p['difficulty']}]": p for p in TRAINING_SCENARIOS} st.title("CodeDebugger RL Environment") tab1, tab2, tab3 = st.tabs(["Debug Results", "Before vs After Training", "Training Results"]) # ========================================== # TAB 1: Debug Results # ========================================== with tab1: with st.sidebar: st.header("Debugger Settings") # Select Problem custom_toggle = st.checkbox("Paste custom buggy code") if custom_toggle: custom_code = st.text_area("Buggy Code") custom_error = st.text_input("Error Type (e.g. IndexError)") problem = { "id": "custom", "difficulty": "custom", "title": "Custom Code", "description": "Custom bug", "buggy_code": custom_code, "error_type": custom_error, "test_cases": [{"input": "N/A", "expected": "N/A"}] # dummy } else: selected_prob_name = st.selectbox("Select Problem", list(problems_dict.keys())) problem = problems_dict[selected_prob_name] iterations = st.slider("Max Iterations", 1, 5, 3) api_key = st.text_input("Groq API Key (Optional)", value=st.session_state.groq_api_key, type="password") if api_key: os.environ["GROQ_API_KEY"] = api_key st.session_state.groq_api_key = api_key run_btn = st.button("Run Debugger", type="primary") if run_btn: with st.spinner("Running Debugger..."): debugger = Debugger(max_iterations=iterations) result = debugger.run(problem, verbose=False) st.session_state.last_result = result if "last_result" in st.session_state: res = st.session_state.last_result st.header(f"Best Fix: Iter {res['best_iter']} | Reward: {res['best_reward']:.2f}") # Action Buttons col1, col2 = st.columns(2) with col1: if st.button("View Iteration History", use_container_width=True): st.session_state.show_history = True with col2: if st.button("View Reward Details", use_container_width=True): st.session_state.show_reward = True # Main Area Code st.markdown("### Best Fixed Code") st.code(res.get("best_code", "No code returned"), language="python") # Test Results & Anti-Hack passed = res['tests_passed_final'] total = res['tests_total'] st.markdown(f"**Test Results:** {passed}/{total} Passed") last_iter_info = res["iterations"][-1] safety = last_iter_info["info"].get("safety_violations", []) anti_hack_failed = last_iter_info["info"].get("anti_hack_failed", False) if not safety and not anti_hack_failed: st.success("✅ No cheating detected") else: violations = safety.copy() if safety else [] if anti_hack_failed: violations.append("Anti-hack checks failed") st.error(f"🚨 Cheating caught: {', '.join(violations)}") else: st.markdown("""

Ready to Debug

Select a buggy Python problem from the sidebar or paste your own custom code. Click Run Debugger to unleash the RL agent to fix your code, score it, and ensure no anti-hacking rules are broken.

""", unsafe_allow_html=True) # Modals for Tab 1 @st.dialog("Iteration History", width="large") def show_history_modal(): res = st.session_state.last_result for i, it in enumerate(res["iterations"]): r_total = it["reward"]["total"] if r_total >= 80: icon = "✅" elif r_total >= 50: icon = "⚠️" else: icon = "❌" with st.expander(f"Iteration {it['iteration']} | Reward: {r_total:.2f} {icon}"): method = it["fix_result"].get("method", "unknown") st.caption(f"Method: {method}") st.markdown("#### Component Scores") html = "" for k, v in it["reward"].items(): if k != "total": color = "green" if v >= 0 else "red" # Simple heuristic scaling for visual bar perc = min(100, max(0, abs(v) * 2)) html += f"""
{k} ({v:.1f})
""" st.markdown(html, unsafe_allow_html=True) st.markdown("#### Code Submitted") st.code(it["fix_result"].get("fixed_code", ""), language="python") @st.dialog("Reward Details", width="large") def show_reward_modal(): res = st.session_state.last_result st.markdown("### Reward Trajectory") iters = [it["iteration"] for it in res["iterations"]] rewards = [it["reward"]["total"] for it in res["iterations"]] df = pd.DataFrame({"Iteration": iters, "Reward": rewards}).set_index("Iteration") st.line_chart(df) st.markdown("### Component Breakdown (Final Iteration)") final_reward_dict = res["iterations"][-1]["reward"] components = {k: v for k, v in final_reward_dict.items() if k != "total"} # Horizontal bar chart comp_df = pd.DataFrame(list(components.items()), columns=["Component", "Score"]).set_index("Component") st.bar_chart(comp_df, horizontal=True) # Trigger dialogs based on session state if st.session_state.get("show_history", False): show_history_modal() st.session_state.show_history = False if st.session_state.get("show_reward", False): show_reward_modal() st.session_state.show_reward = False # ========================================== # TAB 2: Before vs After Training # ========================================== with tab2: b_path = "outputs/baseline_scores.json" t_path = "outputs/trained_scores.json" if not os.path.exists(b_path) or not os.path.exists(t_path): st.info("Run run_baseline.py and train_grpo.py first to generate outputs/baseline_scores.json and trained_scores.json") else: try: with open(b_path, "r") as f: b_data = json.load(f) with open(t_path, "r") as f: t_data = json.load(f) baseline = b_data.get("results", b_data) if isinstance(b_data, dict) else b_data trained = t_data.get("results", t_data) if isinstance(t_data, dict) else t_data base_solved = sum(1 for p in baseline if p.get("solved")) train_solved = sum(1 for p in trained if p.get("solved")) total = len(baseline) st.header(f"Solved: {base_solved}/{total} → {train_solved}/{total} after training") prob_ids = [p["problem_id"] for p in baseline] df_chart = pd.DataFrame({ "Baseline": [p["best_reward"] for p in baseline], "Trained": [p["best_reward"] for p in trained] }, index=prob_ids) st.bar_chart(df_chart) # Difficulty Table st.markdown("### Difficulty Breakdown") diff_metrics = [] for diff in ["easy", "medium", "hard"]: b_diff = [p for p in baseline if p.get("difficulty") == diff] t_diff = [p for p in trained if p.get("difficulty") == diff] if not b_diff: continue b_avg = sum(p["best_reward"] for p in b_diff) / len(b_diff) t_avg = sum(p["best_reward"] for p in t_diff) / len(t_diff) diff_metrics.append({ "Difficulty": diff.capitalize(), "Before (Avg)": round(b_avg, 2), "After (Avg)": round(t_avg, 2), "Delta": round(t_avg - b_avg, 2) }) st.dataframe(pd.DataFrame(diff_metrics)) except Exception as e: st.error(f"Error parsing JSON files: {e}") # ========================================== # TAB 3: Training Results # ========================================== with tab3: st.header("Training Results") log_path = "outputs/training_log.jsonl" if not os.path.exists(log_path): st.info("Run train_grpo.py first to generate outputs/training_log.jsonl") else: try: steps, rewards, diffs = [], [], [] with open(log_path, "r") as f: for line in f: if line.strip(): data = json.loads(line) steps.append(data.get("step", len(steps))) rewards.append(data.get("reward", 0.0)) diffs.append(data.get("difficulty", "unknown")) df_train = pd.DataFrame({"Reward": rewards, "Difficulty": diffs}, index=steps) st.line_chart(df_train, y="Reward", color="Difficulty") except Exception as e: st.error(f"Error parsing training logs: {e}")