import streamlit as st import requests import json import os from datetime import datetime # ── Page config ─────────────────────────────────────────────────────────────── st.set_page_config( page_title="AI Code Reviewer", page_icon="🔍", layout="wide", ) # ── Styles ──────────────────────────────────────────────────────────────────── st.markdown(""" """, unsafe_allow_html=True) # ── Config ──────────────────────────────────────────────────────────────────── N8N_WEBHOOK_URL = os.environ.get( "N8N_WEBHOOK_URL", "https://YOUR-N8N-INSTANCE/webhook/code-review" # ← replace or set env var ) LANGUAGES = [ "Python", "JavaScript", "TypeScript", "Java", "C", "C++", "C#", "Go", "Rust", "Ruby", "PHP", "Swift", "Kotlin", "SQL", "Other" ] # ── Helpers ─────────────────────────────────────────────────────────────────── def score_class(score: int) -> str: if score >= 8: return "score-high" if score >= 5: return "score-mid" return "score-low" def call_n8n(code: str, language: str) -> dict: """POST to n8n webhook and return parsed review dict.""" payload = { "code": code, "language": language, "timestamp": datetime.utcnow().isoformat(), } try: resp = requests.post(N8N_WEBHOOK_URL, json=payload, timeout=60) resp.raise_for_status() return resp.json() except requests.exceptions.Timeout: return {"error": "Request timed out — n8n or DeepSeek took too long."} except requests.exceptions.ConnectionError: return {"error": "Could not reach n8n. Is the webhook URL correct and the workflow active?"} except requests.exceptions.HTTPError as e: return {"error": f"n8n returned HTTP {e.response.status_code}: {e.response.text[:300]}"} except json.JSONDecodeError: return {"error": "n8n returned a non-JSON response. Check the Respond to Webhook node."} def render_review(review: dict): """Render the structured review returned by DeepSeek.""" # ── Score ────────────────────────────────────────────────────────────── score = review.get("score", 0) cls = score_class(score) st.markdown( f'{score}/10', unsafe_allow_html=True ) # ── Summary ──────────────────────────────────────────────────────────── summary = review.get("summary", "") if summary: st.markdown(f"**Summary:** {summary}") st.markdown("---") col_bugs, col_sugg = st.columns([1, 1], gap="large") # ── Bugs ─────────────────────────────────────────────────────────────── with col_bugs: bugs = review.get("bugs", []) st.markdown(f"#### 🐛 Issues found `{len(bugs)}`") if not bugs: st.success("No bugs detected.") for bug in bugs: line = bug.get("line", "?") issue = bug.get("issue", "") fix = bug.get("fix", "") st.markdown( f"""