"""Gradio UI for TorchReview Copilot.""" from __future__ import annotations from html import escape import gradio as gr try: from ..triage import get_default_engine except ImportError: from triage import get_default_engine CSS = """ :root { --paper: #f6f1e8; --ink: #162521; --accent: #d95d39; --panel: #fffdf8; --border: #d6c4b8; --muted: #5f6f67; --good: #2d7d62; --warn: #b76516; --high: #b23a48; } body, .gradio-container { background: radial-gradient(circle at top left, rgba(247, 197, 159, 0.35), transparent 35%), linear-gradient(135deg, #f9f6ef 0%, #efe5d3 100%); color: var(--ink); font-family: Georgia, "Times New Roman", serif; } .gradio-container { max-width: 1260px !important; } .hero-card, .metric-card, .subtle-card { background: rgba(255, 253, 248, 0.95); border: 1px solid var(--border); border-radius: 20px; box-shadow: 0 16px 40px rgba(22, 37, 33, 0.08); } .hero-card { padding: 28px 30px; margin-bottom: 12px; } .metric-card, .subtle-card { padding: 20px 22px; } .eyebrow { text-transform: uppercase; letter-spacing: 0.12em; font-size: 12px; color: var(--accent); margin-bottom: 10px; } .hero-title { font-size: 44px; line-height: 1.05; margin: 0 0 10px; } .hero-copy { margin: 0; font-size: 18px; line-height: 1.55; color: var(--muted); } .summary-title { display: flex; justify-content: space-between; gap: 12px; align-items: center; margin-bottom: 14px; } .pill { display: inline-block; padding: 6px 12px; border-radius: 999px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; background: #efe5d3; } .pill.low { color: var(--good); } .pill.medium { color: var(--warn); } .pill.high { color: var(--high); } .summary-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 16px; } .summary-stat { background: #fff7ef; border-radius: 14px; padding: 12px 14px; border: 1px solid rgba(214, 196, 184, 0.8); } .summary-stat strong { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 6px; } .radar-wrap { display: grid; gap: 12px; } .bar { display: grid; gap: 6px; } .bar-head { display: flex; justify-content: space-between; font-size: 13px; color: var(--muted); } .bar-track { width: 100%; height: 12px; background: #f2e5d6; border-radius: 999px; overflow: hidden; } .bar-fill { height: 100%; border-radius: 999px; } .matched-box { background: #fff7ef; border: 1px solid rgba(214, 196, 184, 0.8); border-radius: 16px; padding: 14px; } .how-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; } .how-step { background: rgba(255, 253, 248, 0.9); border: 1px solid var(--border); border-radius: 18px; padding: 16px; } @media (max-width: 900px) { .hero-title { font-size: 34px; } .summary-grid, .how-grid { grid-template-columns: 1fr; } } """ def _default_outputs() -> tuple[str, str, str, str, str]: return ( "
Awaiting Analysis

Paste Python code, add an optional traceback, or load one of the built-in examples.

", "
Live Triage Radar

Confidence bars will appear after the first analysis run.

", "### Improvement Plan\nAnalyze a sample to generate syntax, edge-case, and scalability recommendations.", "### Known Pattern Match\nThe nearest OpenEnv task will be highlighted here after inference runs.", "### Model Notes\nBackend and extracted signal details will appear here.", ) def _summary_html(result) -> str: issue = escape(result.issue_label.title()) summary = escape(result.summary) next_action = escape(result.suggested_next_action) return f"""
TorchReview Verdict

{issue} Issue

{escape(result.repair_risk)} repair risk

{summary}

Reward Score {result.reward_score:.0%}
ML Quality {result.ml_quality_score:.0%}
Matched Pattern {escape(result.matched_pattern.title)}
Inference Backend {escape(result.model_backend)}
Lint Score {result.lint_score:.0%}
Complexity Penalty {result.complexity_penalty:.0%}
Next Action {next_action}
""" def _radar_html(result) -> str: colors = { "syntax": "#d95d39", "logic": "#4f772d", "performance": "#355070", } bars = [] for label, score in result.confidence_scores.items(): bars.append( f"""
{escape(label.title())}{score:.0%}
""" ) return f"""
Live Triage Radar
{''.join(bars)}
Nearest Known Pattern: {escape(result.matched_pattern.title)}
{escape(result.matched_pattern.summary)}
""" def _plan_markdown(result) -> str: plan_lines = "\n".join(f"{index + 1}. {step}" for index, step in enumerate(result.repair_plan)) return ( "### Improvement Plan\n" f"**Primary issue:** `{result.issue_label}`\n\n" f"{plan_lines}\n\n" f"**Suggested next action:** {result.suggested_next_action}" ) def _match_markdown(result) -> str: return ( "### Known Pattern Match\n" f"**Task:** `{result.matched_pattern.task_id}` \n" f"**Title:** {result.matched_pattern.title} \n" f"**Why it matched:** {result.matched_pattern.rationale} \n" f"**Similarity:** {result.matched_pattern.similarity:.0%}" ) def _model_markdown(result) -> str: signal_lines = "\n".join( f"- `{signal.name}` -> {signal.value} ({signal.impact}, weight {signal.weight:.2f}): {signal.evidence}" for signal in result.extracted_signals ) or "- No strong static signals were extracted." notes = "\n".join(f"- {item}" for item in result.inference_notes) or "- No additional backend notes." return ( "### Model Notes\n" f"- **Model backend:** `{result.model_backend}`\n" f"- **Model id:** `{result.model_id}`\n" f"- **Analysis time:** `{result.analysis_time_ms:.2f} ms`\n\n" "### Reward Formula\n" f"- `reward = (0.5 x {result.ml_quality_score:.2f}) + (0.3 x {result.lint_score:.2f}) - (0.2 x {result.complexity_penalty:.2f})`\n" f"- **Final reward:** `{result.reward_score:.2f}`\n\n" "### Extracted Signals\n" f"{signal_lines}\n\n" "### Backend Notes\n" f"{notes}" ) def analyze_inputs(code: str, traceback_text: str, context_window: str) -> tuple[str, str, str, str, str]: """Run the triage engine and format outputs for the Gradio UI.""" result = get_default_engine().triage(code or "", traceback_text or "", context_window or "") return ( _summary_html(result), _radar_html(result), _plan_markdown(result), _match_markdown(result), _model_markdown(result), ) def load_example(example_key: str) -> tuple[str, str, str, str, str, str, str, str, str]: """Populate the UI from a built-in example and immediately analyze it.""" example = get_default_engine().example_map()[example_key] outputs = analyze_inputs(example.code, example.traceback_text, example.context_window) header = ( f"### Example Scenario\n" f"**{example.title}** \n" f"{example.summary} \n" f"Label target: `{example.label}`" ) return (example.code, example.traceback_text, example.context_window, header, *outputs) def build_demo() -> gr.Blocks: """Create the TorchReview Copilot Gradio application.""" examples = get_default_engine().example_map() first_example = next(iter(examples.values())) with gr.Blocks(theme=gr.themes.Soft(primary_hue="orange", secondary_hue="amber"), css=CSS, title="TorchReview Copilot") as demo: gr.HTML( """
Meta PyTorch OpenEnv Hackathon Demo

TorchReview Copilot

AI-powered code review and improvement system using PyTorch to score code quality, surface bugs, and generate a three-step improvement plan. OpenEnv stays underneath as the deterministic validation engine.

""" ) with gr.Row(): with gr.Column(scale=6): example_choice = gr.Radio( choices=[(item.title, item.key) for item in examples.values()], value=first_example.key, label="Try a built-in failure scenario", info="Switching examples updates the Live Triage Radar immediately.", ) example_header = gr.Markdown() code_input = gr.Code( value=first_example.code, language="python", lines=18, label="Python code under review", ) traceback_input = gr.Textbox( value=first_example.traceback_text, lines=7, label="Optional traceback / failing test output", placeholder="Paste stack traces, assertion failures, or benchmark notes here.", ) context_input = gr.Textbox( value=first_example.context_window, lines=4, label="Context window", placeholder="Describe expected behavior, constraints, or repository context.", ) with gr.Row(): analyze_button = gr.Button("Analyze & Score Code", variant="primary") clear_button = gr.Button("Clear Inputs", variant="secondary") with gr.Column(scale=5): summary_html = gr.HTML() radar_html = gr.HTML() plan_markdown = gr.Markdown() match_markdown = gr.Markdown() model_markdown = gr.Markdown() gr.HTML( """
How It Works
Input
Code plus optional traceback or benchmark signal.
Processing
Static checks extract parser, lint, complexity, and runtime clues.
Model
CodeBERTa embeddings run through PyTorch and score code quality against known OpenEnv patterns.
Output
Confidence radar, reward score, and a three-step improvement plan.
""" ) example_choice.change( fn=load_example, inputs=example_choice, outputs=[code_input, traceback_input, context_input, example_header, summary_html, radar_html, plan_markdown, match_markdown, model_markdown], show_progress="hidden", ) analyze_button.click( fn=analyze_inputs, inputs=[code_input, traceback_input, context_input], outputs=[summary_html, radar_html, plan_markdown, match_markdown, model_markdown], show_progress="minimal", ) clear_button.click( fn=lambda: ("", "", "", "### Example Scenario\nChoose a built-in example or paste custom code.", *_default_outputs()), inputs=None, outputs=[code_input, traceback_input, context_input, example_header, summary_html, radar_html, plan_markdown, match_markdown, model_markdown], show_progress="hidden", ) demo.load( fn=load_example, inputs=example_choice, outputs=[code_input, traceback_input, context_input, example_header, summary_html, radar_html, plan_markdown, match_markdown, model_markdown], show_progress="hidden", ) return demo