CoolFace
Apppublic

ishaAtif/python-code-reviewer

sourceHugging Faceupdated 6mo agoView on Hugging Face
0likes
app.py548 linesDownload Raw Back to root
1import json2import time3import streamlit as st4from code_editor import code_editor5from reviewer import review_code6 7# ── Page config ───────────────────────────────────────────────────────────────8st.set_page_config(page_title="Python Code Reviewer", page_icon="🐍", layout="wide")9 10# ── Usage protection ──────────────────────────────────────────────────────────11MAX_REQUESTS_PER_SESSION = 512COOLDOWN_SECONDS = 1513MAX_CODE_LENGTH = 600014 15if "request_count" not in st.session_state:16    st.session_state.request_count = 017 18if "last_request_time" not in st.session_state:19    st.session_state.last_request_time = 020 21# ── Custom CSS ────────────────────────────────────────────────────────────────22st.markdown(23    """24<style>25    .stApp {26        background: linear-gradient(135deg, #0b1020 0%, #161b33 45%, #1f2550 100%);27        color: #f8fafc;28    }29 30    .block-container {31        max-width: 1100px;32        padding-top: 2rem;33        padding-bottom: 3rem;34    }35 36    .hero {37        text-align: center;38        padding: 1.2rem 0 2rem 0;39    }40 41    .main-title {42        font-size: 3.2rem;43        font-weight: 800;44        margin-bottom: 0.4rem;45        background: linear-gradient(90deg, #ff4ecd, #7c5cff);46        -webkit-background-clip: text;47        -webkit-text-fill-color: transparent;48    }49 50    .subtitle {51        color: #cbd5e1;52        font-size: 1.08rem;53        line-height: 1.7;54        max-width: 760px;55        margin: 0 auto;56    }57 58    .section-heading {59        font-size: 2rem;60        font-weight: 800;61        color: #ffffff;62        margin-top: 1rem;63        margin-bottom: 0.8rem;64    }65 66    .card {67        background: rgba(255, 255, 255, 0.06);68        border: 1px solid rgba(255, 255, 255, 0.10);69        border-radius: 18px;70        padding: 1.25rem;71        margin-top: 1rem;72        margin-bottom: 1rem;73        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);74    }75 76    .section-title {77        font-size: 1.15rem;78        font-weight: 700;79        margin-bottom: 1rem;80        letter-spacing: 0.2px;81    }82 83    .bug-title { color: #ff7b7b; }84    .complex-title { color: #ffd54a; }85    .oop-title { color: #68e0a1; }86    .rewrite-title { color: #69a8ff; }87 88    .helper-text {89        color: #dbe4f0;90        font-size: 0.97rem;91        line-height: 1.8;92    }93 94    /* Text area */95    .stTextArea textarea {96        background: #07122b !important;97        color: #f8fafc !important;98        border: 1px solid rgba(255,255,255,0.18) !important;99        border-radius: 14px !important;100        font-family: Consolas, "Courier New", monospace !important;101        font-size: 0.95rem !important;102        line-height: 1.6 !important;103        padding: 1rem !important;104    }105    .stTextArea textarea::placeholder {106    color: #94a3b8 !important;107    opacity: 1 !important;108    }109 110    .stTextArea label {111        color: #e2e8f0 !important;112        font-weight: 700 !important;113    }114 115    /* Button */116    .stButton > button {117        background: linear-gradient(90deg, #ff4ecd, #7c5cff);118        color: white;119        border: none;120        border-radius: 12px;121        padding: 0.85rem 1.2rem;122        font-size: 1rem;123        font-weight: 700;124        width: 100%;125        box-shadow: 0 8px 20px rgba(124, 92, 255, 0.35);126        transition: 0.2s ease;127    }128 129    .stButton > button:hover {130        transform: translateY(-1px);131        opacity: 0.97;132    }133 134    /* Metrics */135    div[data-testid="stMetric"] {136        background: rgba(255, 255, 255, 0.05);137        border: 1px solid rgba(255,255,255,0.10);138        padding: 1rem;139        border-radius: 14px;140    }141 142    div[data-testid="stMetricLabel"] {143        color: #cbd5e1;144        font-weight: 600;145    }146 147    div[data-testid="stMetricValue"] {148        color: #ffffff;149        font-weight: 800;150    }151 152    /* Tabs */153    div[data-testid="stTabs"] {154        margin-top: 0.4rem;155    }156 157    button[data-baseweb="tab"] {158        color: #94a3b8 !important;159        font-weight: 600 !important;160        background: transparent !important;161        border: none !important;162    }163 164    button[data-baseweb="tab"]:hover {165        color: #ffffff !important;166        background: transparent !important;167    }168 169    button[data-baseweb="tab"][aria-selected="true"] {170        color: #ffffff !important;171        border-bottom: 2px solid #7c5cff !important;172    }173 174    /* Expander */175    div[data-testid="stExpander"] {176        background: rgba(255,255,255,0.04) !important;177        border: 1px solid rgba(255,255,255,0.08) !important;178        border-radius: 12px !important;179        overflow: hidden !important;180    }181 182    div[data-testid="stExpander"] summary {183        color: #e2e8f0 !important;184        font-weight: 600 !important;185    }186 187    div[data-testid="stExpander"] div[role="region"] {188        color: #dbe4f0 !important;189    }190 191    /* Inline code */192    code {193        background: rgba(255,255,255,0.08) !important;194        color: #f8fafc !important;195        padding: 2px 6px !important;196        border-radius: 6px !important;197    }198 199    /* Code block */200    pre {201        background: #020617 !important;202        color: #f8fafc !important;203        border-radius: 12px !important;204    }205 206    .stCodeBlock {207        border-radius: 14px;208        overflow: hidden;209    }210 211    hr {212        border: none;213        height: 1px;214        background: rgba(255,255,255,0.08);215        margin: 1.2rem 0 1.8rem 0;216    }217    /* REMOVE TOP WHITE BAR */218    header[data-testid="stHeader"] {219        background: transparent !important;220    }221 222    header {223        visibility: hidden;224        height: 0px;225    }226 227    div[data-testid="stDecoration"] {228        display: none !important;229    }230    231    232    .editor-label {233    color: #e2e8f0;234    font-weight: 700;235    font-size: 1.05rem;236    margin-bottom: 0.6rem;237    letter-spacing: 0.3px;238    }239    div[data-testid="stElementContainer"]:has(.streamlit_code-editor) {240        border: none;241        border-radius: 14px;242        overflow: hidden;243        background: transparent;244        padding: 0px;245        width: 100% !important;246        box-sizing: border-box !important;247    }248 249    div[data-testid="stElementContainer"]:has(.streamlit_code-editor) iframe {250        border: none !important;251        display: block;252    }     253    .metric-box {254    background: rgba(255,255,255,0.05);255    border: 1px solid rgba(255,255,255,0.08);256    border-radius: 14px;257    padding: 1rem;258    }259 260    .metric-label {261        color: #94a3b8;262        font-size: 0.85rem;263        font-weight: 600;264        margin-bottom: 0.4rem;265    }266 267    .metric-value {268        color: #ffffff;269        font-size: 1.6rem;270        font-weight: 800;271    }272</style>273""",274    unsafe_allow_html=True,275)276 277# ── Header ────────────────────────────────────────────────────────────────────278st.markdown(279    """280<div class="hero">281    <div class="main-title">🐍 Python Code Reviewer</div>282    <div class="subtitle">283        Paste your Python code and get a clean AI-powered review with bug detection,284        complexity analysis, design suggestions, and improved code.285    </div>286</div>287""",288    unsafe_allow_html=True,289)290 291# ── Input section ─────────────────────────────────────────────────────────────292st.markdown(293    '<div class="editor-label">Paste your Python code</div>', unsafe_allow_html=True294)295 296editor_result = code_editor(297    code="def my_function():\n    # paste your Python code here\n    pass",298    lang="python",299    theme="monokai",300    height=[14, 16],301    options={302        "wrap": True,303        "showLineNumbers": True,304    },305    response_mode=["debounce"],306    props={"style": {"borderRadius": "14px", "fontSize": "15px"}},307    component_props={308        "style": {309            "width": "100%",310            "maxWidth": "100%",311            "borderRadius": "14px",312            "overflow": "hidden",313            "background": "#07122b",314            "boxSizing": "border-box",315            "border": "1.5px solid rgba(255,255,255,1)",316            "boxShadow": "0 4px 24px rgba(0,0,0,0.3)",317        },318        "css": """319            font-weight: 500;320            border-radius: 14px;321            overflow: hidden;322 323            &.streamlit_code-editor {324                border-radius: 12px !important;325                overflow: hidden !important;326            }327 328            &.streamlit_code-editor .drag-handle,329            &.streamlit_code-editor [class*="drag"],330            &.streamlit_code-editor [class*="resize"],331            &.streamlit_code-editor [class*="handle"] {332                display: none !important;333            }334 335            &.streamlit_code-editor .ace-streamlit-dark.ace_editor {336                    background-color: #07122b !important;337                    color: #f8fafc !important;338                    border-radius: 14px !important;339                    overflow: hidden !important;340            }341 342            &.streamlit_code-editor .ace_gutter {343                background: #0b1633 !important;344                color: #94a3b8 !important;345                border-top-left-radius: 14px !important;346                border-bottom-left-radius: 14px !important;347            }348 349            &.streamlit_code-editor .ace_scroller {350                background-color: #07122b !important;351            }352 353            &.streamlit_code-editor .ace_content {354                background-color: #07122b !important;355            }356 357            &.streamlit_code-editor .ace_layer.ace_gutter-layer {358                background: #0b1633 !important;359            }360 361            &.streamlit_code-editor .ace_active-line {362                background: rgba(255,255,255,0.04) !important;363            }364 365            &.streamlit_code-editor .ace_cursor {366                color: #ffffff !important;367            }368 369            &.streamlit_code-editor .ace_identifier {370                color: #f8f8f2 !important;371            }372 373            &.streamlit_code-editor .ace_variable {374                color: #f8f8f2 !important;375            }376 377            &.streamlit_code-editor .ace_text-layer {378                color: #f8f8f2 !important;379            }380 381            &.streamlit_code-editor,382            &.streamlit_code-editor * {383                box-sizing: border-box !important;384            }385 386            &.streamlit_code-editor {387                border-radius: 12px !important;388                overflow: hidden !important;389            }390        """,391        "globalCSS": """392            :root {393                --streamlit-dark-background-color: #07122b;394            }395        """,396    },397    key="code_editor_main",398)399 400code_input = ""401if editor_result and isinstance(editor_result, dict):402    code_input = editor_result.get("text", "")403 404col1, col2 = st.columns([5.2, 1.3])405with col2:406    analyse_btn = st.button("🔍 Analyse My Code", key="analyse_main")407 408st.caption(409    f"Usage this session: {st.session_state.request_count}/{MAX_REQUESTS_PER_SESSION} • Cooldown: {COOLDOWN_SECONDS}s"410)411 412# ── Results ───────────────────────────────────────────────────────────────────413if analyse_btn:414    current_time = time.time()415 416    if not code_input.strip():417        st.warning("⚠️ Please paste some Python code first.")418 419    elif len(code_input) > MAX_CODE_LENGTH:420        st.warning(f"⚠️ Code is too long. Please keep it under {MAX_CODE_LENGTH} characters.")421 422    elif st.session_state.request_count >= MAX_REQUESTS_PER_SESSION:423        st.error(424            f"❌ Session limit reached. You can only analyse {MAX_REQUESTS_PER_SESSION} times per session."425        )426 427    elif current_time - st.session_state.last_request_time < COOLDOWN_SECONDS:428        remaining = int(COOLDOWN_SECONDS - (current_time - st.session_state.last_request_time))429        st.warning(f"⏳ Please wait {remaining} more seconds before trying again.")430 431    else:432        st.session_state.request_count += 1433        st.session_state.last_request_time = current_time434 435        with st.spinner("Reviewing your code..."):436            try:437                result = review_code(code_input)438 439                st.markdown("---")440                st.markdown(441                    '<div class="section-heading">Review Summary</div>',442                    unsafe_allow_html=True,443                )444 445                bugs_tab, complexity_tab, design_tab, rewritten_tab = st.tabs(446                    ["Bugs", "Complexity", "Design Suggestions", "Rewritten Code"]447                )448 449                with bugs_tab:450                    st.markdown('<div class="card">', unsafe_allow_html=True)451                    st.markdown(452                        '<div class="section-title bug-title">🐛 Bug Detection</div>',453                        unsafe_allow_html=True,454                    )455 456                    bugs = result.get("bugs", [])457                    if not bugs:458                        st.success("✅ No bugs detected.")459                    else:460                        for bug in bugs:461                            line = bug.get("line", "?")462                            issue = bug.get("issue", "Issue found")463                            fix = bug.get("fix", "No fix provided")464 465                            with st.expander(f"Line {line} — {issue}"):466                                st.markdown(f"**Fix:** {fix}")467 468                    st.markdown("</div>", unsafe_allow_html=True)469 470                with complexity_tab:471                    st.markdown('<div class="card">', unsafe_allow_html=True)472                    st.markdown(473                        '<div class="section-title complex-title">⏱️ Complexity Analysis</div>',474                        unsafe_allow_html=True,475                    )476 477                    complexity = result.get("complexity", {})478 479                    col_t, col_s = st.columns(2)480 481                    with col_t:482                        st.markdown(483                            f"""484                        <div class="metric-box">485                            <div class="metric-label">Time Complexity</div>486                            <div class="metric-value">{complexity.get("time", "N/A")}</div>487                        </div>488                        """,489                            unsafe_allow_html=True,490                        )491 492                    with col_s:493                        st.markdown(494                            f"""495                        <div class="metric-box">496                            <div class="metric-label">Space Complexity</div>497                            <div class="metric-value">{complexity.get("space", "N/A")}</div>498                        </div>499                        """,500                            unsafe_allow_html=True,501                        )502 503                    st.markdown(504                        f'<div class="helper-text">{complexity.get("explanation", "No explanation provided.")}</div>',505                        unsafe_allow_html=True,506                    )507 508                    st.markdown("</div>", unsafe_allow_html=True)509 510                with design_tab:511                    st.markdown('<div class="card">', unsafe_allow_html=True)512                    st.markdown(513                        '<div class="section-title oop-title">🏗️ Design Suggestions</div>',514                        unsafe_allow_html=True,515                    )516 517                    oop_suggestions = result.get("oop_suggestions", [])518                    if not oop_suggestions:519                        st.success("✅ No design improvements needed.")520                    else:521                        for i, suggestion in enumerate(oop_suggestions, 1):522                            st.markdown(523                                f'<div class="helper-text"><b>{i}.</b> {suggestion}</div>',524                                unsafe_allow_html=True,525                            )526 527                    st.markdown("</div>", unsafe_allow_html=True)528 529                with rewritten_tab:530                    st.markdown('<div class="card">', unsafe_allow_html=True)531                    st.markdown(532                        '<div class="section-title rewrite-title">✨ Rewritten Code</div>',533                        unsafe_allow_html=True,534                    )535 536                    rewritten = result.get("rewritten_code", "")537                    if rewritten:538                        st.code(rewritten, language="python")539                    else:540                        st.warning("No rewritten code provided.")541 542                    st.markdown("</div>", unsafe_allow_html=True)543 544            except json.JSONDecodeError:545                st.error("❌ Could not parse the AI response. Please try again.")546            except Exception as e:547                st.error(f"❌ Something went wrong: {e}")548