"""Gradio demo for the AI Code Reviewer, published as a HuggingFace Space. Reuses the same prompt templates and Qwen endpoint as the MCP server. """ from __future__ import annotations import os from collections.abc import Iterator import gradio as gr from reviewer import ( ANALYSIS_LABELS, GitHubRepo, build_context, check_llm_health, parse_target, render_result, run_analysis, ) GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN") CHOICES = [(label, key) for key, label in ANALYSIS_LABELS.items()] DEFAULT = ["review", "bugs"] def review(target: str, analyses: list[str]) -> Iterator[str]: yield "_Starting review..._" target = (target or "").strip() if not target: yield "Please enter a GitHub repository (e.g. `owner/repo` or a repo URL)." return if not analyses: yield "Please select at least one analysis." return try: yield "_Checking Qwen endpoint..._" check_llm_health() ref = parse_target(target) repo = GitHubRepo(ref, token=GITHUB_TOKEN) yield f"Fetching `{repo.describe()}`..." context, included = build_context(repo) except Exception as exc: # noqa: BLE001 - surface any fetch error to the UI yield f"Failed to load repository: {exc}" return report = [f"# AI Code Review Report\n\n_Target: {repo.describe()}_"] for analysis_type in analyses: label = ANALYSIS_LABELS.get(analysis_type, analysis_type) yield "\n\n---\n\n".join(report) + f"\n\n---\n\n_Running {label} analysis..._" try: result = run_analysis(repo, analysis_type, context) report.append(render_result(analysis_type, repo.describe(), result, len(included))) except Exception as exc: # noqa: BLE001 report.append(f"## {label}\n\n_Analysis failed: {exc}_") yield "\n\n---\n\n".join(report) def _setup_banner() -> str: base_url = os.environ.get("QWEN_BASE_URL", "").strip() api_key = os.environ.get("QWEN_API_KEY", "").strip() if base_url and api_key: return ( "**Endpoint configured.** Enter a public GitHub repo below. " "Each analysis takes ~30–90 s on your GPU server." ) missing = [] if not base_url: missing.append("`QWEN_BASE_URL`") if not api_key: missing.append("`QWEN_API_KEY`") return ( "> **Setup required** — this Space calls a **self-hosted** Qwen endpoint. " f"Add Space secrets: {', '.join(missing)}. " "See the [README](https://huggingface.co/spaces/ImTamsi/ai-code-reviewer) " "and [deployment config](https://huggingface.co/ImTamsi/qwen3.6-27b-code-reviewer)." ) with gr.Blocks(title="AI Code Reviewer", theme=gr.themes.Soft()) as demo: gr.Markdown( """ # AI Code Reviewer Analyze any public GitHub repository with **Qwen3.6-27B** (self-hosted): code review, potential bugs, technical debt, security, performance and missing tests. """ ) gr.Markdown(_setup_banner()) with gr.Row(): target = gr.Textbox( label="GitHub repository", placeholder="owner/repo or https://github.com/owner/repo", scale=3, ) run_btn = gr.Button("Review", variant="primary", scale=1) analyses = gr.CheckboxGroup( choices=CHOICES, value=DEFAULT, label="Analyses to run" ) output = gr.Markdown(label="Report") gr.Examples( examples=[["psf/requests", DEFAULT], ["tiangolo/fastapi", ["security", "bugs"]]], inputs=[target, analyses], ) run_btn.click( fn=review, inputs=[target, analyses], outputs=output, show_progress="full", ) target.submit( fn=review, inputs=[target, analyses], outputs=output, show_progress="full", ) # Required for generator/streaming handlers on HuggingFace Spaces and locally. demo.queue(max_size=8) if __name__ == "__main__": demo.launch()