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"""
Line {line}
{issue}
💡 {fix}
""", unsafe_allow_html=True ) # ── Suggestions ──────────────────────────────────────────────────────── with col_sugg: suggestions = review.get("suggestions", []) st.markdown(f"#### ✨ Suggestions   `{len(suggestions)}`") if not suggestions: st.info("No further suggestions.") for s in suggestions: st.markdown( f'{s}', unsafe_allow_html=True ) # ── Raw JSON expander ────────────────────────────────────────────────── with st.expander("Raw JSON response"): st.json(review) # ── Layout ──────────────────────────────────────────────────────────────────── st.title("🔍 AI Code Reviewer") st.caption("Paste your code → get structured feedback powered by DeepSeek via n8n") left, right = st.columns([1, 1], gap="large") with left: language = st.selectbox("Language", LANGUAGES) code = st.text_area( "Paste your code here", height=380, placeholder="def fibonacci(n):\n if n <= 0:\n return []\n ...", ) submit = st.button("Review my code →", type="primary", use_container_width=True) with right: st.markdown("#### Review") if submit: if not code.strip(): st.warning("Please paste some code first.") else: with st.spinner("Sending to n8n → DeepSeek…"): result = call_n8n(code.strip(), language) if "error" in result: st.error(result["error"]) else: render_review(result) else: st.markdown( """
Your review will appear here.

🤖
""", unsafe_allow_html=True ) # ── Footer ──────────────────────────────────────────────────────────────────── st.markdown("---") st.caption("Built with Streamlit · n8n · DeepSeek — logs saved to Google Sheets")