ai-code-maintainability-engine / AI_Code_Maintainability_Engine_Revision.html
usman-ai-dev's picture
Deploy AI Code Maintainability Scoring Engine to Hugging Face Spaces
38bc0dc verified
Raw
History Blame Contribute Delete
14.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AI Code Maintainability Scoring & Refactoring Engine β€” Revision Notes</title>
<style>
:root {
--bg: #0d1117;
--card: #161b22;
--border: #30363d;
--text: #e6edf3;
--muted: #8b949e;
--accent: #58a6ff;
--green: #3fb950;
--orange: #d29922;
--red: #f85149;
--purple: #bc8cff;
}
* { box-sizing: border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
}
.wrap { max-width: 880px; margin: 0 auto; padding: 32px 20px 80px; }
h1 {
font-size: 1.7em;
border-bottom: 2px solid var(--accent);
padding-bottom: 12px;
margin-bottom: 4px;
}
.subtitle { color: var(--muted); margin-bottom: 28px; font-size: 0.95em; }
h2 {
color: var(--accent);
font-size: 1.25em;
margin-top: 42px;
border-left: 4px solid var(--accent);
padding-left: 12px;
}
h3 {
color: var(--purple);
font-size: 1.05em;
margin-top: 26px;
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 8px;
padding: 16px 20px;
margin: 14px 0;
}
.pill {
display: inline-block;
background: rgba(88,166,255,0.15);
color: var(--accent);
border-radius: 5px;
padding: 2px 8px;
font-size: 0.85em;
margin-right: 6px;
}
table { width: 100%; border-collapse: collapse; margin: 14px 0; }
th, td {
border: 1px solid var(--border);
padding: 8px 12px;
text-align: left;
font-size: 0.95em;
}
th { background: #1c2229; color: var(--accent); }
tr:nth-child(even) { background: rgba(255,255,255,0.02); }
code, pre {
background: #010409;
color: #79c0ff;
border-radius: 6px;
font-family: "SF Mono", Consolas, monospace;
}
code { padding: 2px 6px; font-size: 0.9em; }
pre {
padding: 14px 16px;
overflow-x: auto;
border: 1px solid var(--border);
line-height: 1.5;
font-size: 0.88em;
}
.flow {
background: var(--card);
border: 1px solid var(--border);
border-radius: 8px;
padding: 18px 22px;
font-family: Consolas, monospace;
color: var(--green);
white-space: pre;
font-size: 0.9em;
}
.q {
color: var(--orange);
font-weight: 600;
margin-top: 18px;
}
.summary-box {
background: linear-gradient(135deg, rgba(88,166,255,0.1), rgba(188,140,255,0.1));
border: 1px solid var(--accent);
border-radius: 8px;
padding: 18px 22px;
font-style: italic;
margin: 16px 0;
}
.warn {
background: rgba(248,81,73,0.1);
border: 1px solid var(--red);
border-radius: 8px;
padding: 12px 18px;
color: #ffb3ac;
font-size: 0.92em;
margin: 14px 0;
}
.num-table td:first-child { color: var(--muted); }
.num-table td:last-child { color: var(--green); font-weight: 600; }
ul { padding-left: 22px; }
li { margin: 4px 0; }
</style>
</head>
<body>
<div class="wrap">
<h1>AI Code Maintainability Scoring & Refactoring Engine</h1>
<div class="subtitle">Revision Notes β€” Light-touch interview prep (2–3 sentences + one technical detail per topic)</div>
<div class="warn">
<strong>Scope reminder:</strong> this project was deliberately scoped as light-touch, not a deep-dive like Urdu Sentiment or Medical Image. Use the "One-Line Summary" and "Quick Answers" sections as your primary prep. The deeper sections exist so you're not caught flat-footed on a follow-up, not so you memorize all of it.
</div>
<h2>What Is This Project? (Elevator Pitch)</h2>
<div class="card">
"I built a two-phase AI system that scores the structural quality of Python code and then autonomously refactors risky code to improve it. Phase 1 uses AST parsing + a Random Forest classifier to predict a maintainability risk score. Phase 2 uses a CodeT5 deep learning model to generate and iteratively select better versions of risky code."
</div>
<h2>The Problem It Solves</h2>
<div class="card">
Traditional linters (PyLint, Flake8) use rigid, hand-written rules. This engine instead <strong>learns</strong> what "risky" structure looks like from data β€” deep nesting, high complexity, large functions β€” and then goes a step further than any linter by actually generating improved code, not just flagging problems.
</div>
<h2>Full Pipeline Flow</h2>
<div class="flow">Input Code
β”‚
β–Ό
PHASE 1 β€” Evaluator
AST Parsing β†’ Feature Extraction β†’ ML Scoring β†’ Explanation
β”‚
β–Ό
Risk Score (0–100) + Top 3 Reasons
β”‚
β–Ό
PHASE 2 β€” Refactorer (only if risky)
Generate Candidates (CodeT5) β†’ Validate β†’ Re-score via Phase 1 β†’ Select Best
β”‚ (loop until target score or max iterations)
β–Ό
Improved Code</div>
<h2>Phase 1 β€” The Evaluator</h2>
<h3>1. AST Analyzer β€” 11 Structural Features</h3>
<div class="card">
Parses code into an Abstract Syntax Tree (not line-by-line text reading β€” actual structural traversal via <code>ast.walk()</code>) and extracts 11 signals:
<table>
<tr><th>Feature</th><th>What it measures</th></tr>
<tr><td>max_nesting_depth</td><td><strong>Strongest predictor</strong> β€” deepest if/for/while/try nesting</td></tr>
<tr><td>cyclomatic_complexity</td><td>1 + every decision point (if/for/while/except/with/assert/bool-op)</td></tr>
<tr><td>avg_function_length</td><td>Mean lines per function</td></tr>
<tr><td>num_functions, num_loops, num_if, num_try_except, num_return</td><td>Raw structural counts</td></tr>
<tr><td>line_count</td><td>Total file size</td></tr>
<tr><td>recursion_flag</td><td>1 if any function calls itself, else 0</td></tr>
<tr><td>global_variable_count</td><td>Count of <code>global</code> declarations β€” hidden state / tight coupling</td></tr>
</table>
<strong>One technical detail worth knowing cold:</strong> nesting depth is computed via a recursive traversal that increments depth only when it enters a defined set of "nesting nodes" (<code>If, For, While, With, Try, FunctionDef, AsyncFunctionDef, ClassDef</code>) β€” everything else keeps the current depth.
</div>
<h3>2. Dataset Generation</h3>
<div class="card">
Synthetic dataset generated from code templates, not scraped real-world code. <strong>220 total samples, perfectly balanced: 110 labeled Clean (0), 110 labeled Risky (1).</strong> Reproducible via <code>random.seed(42)</code> β€” same dataset every run.
</div>
<h3>3. Feature Pipeline</h3>
<div class="card">
Converts the feature dictionary into a fixed-order numeric vector (<code>FEATURE_SCHEMA</code> defines the order β€” this order must stay identical between training and inference or predictions break silently). Scales with <code>StandardScaler</code> (mean=0, std=1) so no single feature like <code>line_count</code> dominates just because its raw numbers are bigger. Scaler is pickled and reused at inference time β€” never re-fit on new data.
</div>
<h3>4. Model Training</h3>
<div class="card">
Two models trained side by side on an 80/20 stratified split (176 train / 44 test):
<table>
<tr><th>Model</th><th>Key hyperparameters</th></tr>
<tr><td>Random Forest <span class="pill">primary / production</span></td><td>200 trees, max_depth=10, min_samples_split=4, class_weight="balanced"</td></tr>
<tr><td>XGBoost <span class="pill">comparison only</span></td><td>200 estimators, max_depth=6, learning_rate=0.1, subsample=0.8</td></tr>
</table>
<strong>Random Forest is the one actually used in the live Scoring API</strong> β€” XGBoost is trained and evaluated for comparison but not deployed.
</div>
<div class="warn">
No saved accuracy/F1 number exists in the repo β€” the evaluation function prints it live but doesn't persist it to a file. Run <code>python model_trainer.py</code> before your interview and note the actual number rather than guessing one.
</div>
<h3>5. Explanation Engine</h3>
<div class="card">
Answers "why is this risky" without recomputing anything new. Logic: for each of the 11 features, check if the code's actual value exceeds a fixed threshold (e.g. <code>max_nesting_depth > 3</code>, <code>cyclomatic_complexity > 5</code>, <code>global_variable_count > 1</code>). Of the features that exceed threshold, rank by the model's feature importance and return the <strong>top 3</strong> as plain-English sentences (e.g. "Deep nesting detected (depth: 7)").
</div>
<h3>6. Scoring API β€” Final Output</h3>
<div class="card">
Single entry point: <code>evaluate(code)</code>. Runs the model's predicted probability of the "risky" class Γ— 100 as the risk score.
<table>
<tr><th>Risk Score</th><th>Level</th></tr>
<tr><td>0–30</td><td style="color:var(--green)">Low</td></tr>
<tr><td>31–60</td><td style="color:var(--orange)">Medium</td></tr>
<tr><td>61–100</td><td style="color:var(--red)">High</td></tr>
</table>
<pre>{
"risk_score": 82,
"risk_level": "High",
"confidence": 0.82,
"top_risk_factors": ["Deep nesting detected (depth: 7)", ...]
}</pre>
Properties worth naming if asked: deterministic, stateless, fast (no training happens at inference time).
</div>
<h2>Phase 2 β€” The Refactorer</h2>
<div class="card">
Only runs on code Phase 1 flagged as risky. Uses <strong>CodeT5</strong> (a deep learning code-generation model) to produce multiple refactored candidates, then uses Phase 1's own <code>evaluate()</code> as a reward/ranking function to pick the best one.
</div>
<h3>1. Candidate Generation β€” 3 Strategies</h3>
<div class="card">
Generates one candidate per strategy, each with a different prompt and temperature:
<table>
<tr><th>Strategy</th><th>Temperature</th></tr>
<tr><td>Improve readability and clarity</td><td>0.5 (conservative)</td></tr>
<tr><td>Reduce nesting and simplify logic</td><td>0.7</td></tr>
<tr><td>Refactor for strict maintainability best practices</td><td>0.85 (more creative)</td></tr>
</table>
<strong>One technical detail:</strong> temperature controls how much the model deviates from the "safe" rewrite β€” low temperature stays close to minimal edits, high temperature takes bigger structural risks.
</div>
<h3>2. Validation β†’ Selection β†’ Iteration</h3>
<div class="card">
Each candidate is checked to <strong>actually compile</strong> (no syntax errors) before it's even considered. Valid candidates are re-scored by feeding them back through the Phase 1 <code>evaluate()</code> API, and the lowest risk score wins that round.
<br><br>
<strong>Iterative loop defaults:</strong> <code>target_score=20</code>, <code>max_iterations=3</code>. Stops early if the target is hit, or after 3 rounds regardless. Starts by initializing the best-known score to <code>float('inf')</code> β€” a simple trick meaning "anything found is automatically an improvement over nothing."
</div>
<h2>Tech Stack</h2>
<div class="card">
<table>
<tr><th>Component</th><th>Technology</th></tr>
<tr><td>Structural Analysis</td><td>Python <code>ast</code> module</td></tr>
<tr><td>Risk Prediction</td><td>Random Forest (primary), XGBoost (comparison) β€” scikit-learn</td></tr>
<tr><td>Refactoring</td><td>CodeT5 (Transformers / PyTorch)</td></tr>
<tr><td>API</td><td>Unified <code>main.py</code> entry point + <code>api_server.py</code></td></tr>
<tr><td>Deployment</td><td>Live at ai-code-maintainability.hmuhammadusman.com</td></tr>
</table>
</div>
<h2>Numbers to Remember</h2>
<div class="card">
<table class="num-table">
<tr><td>Structural features extracted</td><td>11</td></tr>
<tr><td>Total dataset samples</td><td>220 (110 Clean / 110 Risky β€” balanced)</td></tr>
<tr><td>Train / test split</td><td>176 / 44 (80/20, stratified)</td></tr>
<tr><td>Random Forest trees</td><td>200 (max_depth=10)</td></tr>
<tr><td>Risk score range</td><td>0–100</td></tr>
<tr><td>Top risk factors surfaced</td><td>3</td></tr>
<tr><td>Refactor candidate strategies</td><td>3 (temps 0.5 / 0.7 / 0.85)</td></tr>
<tr><td>Default optimizer target / max iterations</td><td>20 / 3</td></tr>
<tr><td>Reproducibility seed</td><td>42</td></tr>
</table>
</div>
<h2>Quick Answers β€” Likely Questions</h2>
<div class="q">"Why Random Forest over a simpler rule-based linter?"</div>
<div class="card">Rule-based linters need every threshold hand-tuned per rule. A trained model learns which combinations of features actually correlate with risk from data, and can weigh 11 signals together instead of checking them independently.</div>
<div class="q">"Why two models (RF + XGBoost) if only one is deployed?"</div>
<div class="card">Comparison during development β€” training both and comparing accuracy tells you whether the extra complexity of boosting is worth it on this dataset size before committing to one in production.</div>
<div class="q">"Isn't 220 samples very small for ML?"</div>
<div class="card">Yes β€” be upfront about this if asked. It's a synthetic, template-generated dataset, not real-world code, which is both the honest limitation and a natural "what I'd improve next" answer (train on real open-source repos labeled by actual maintainability metrics).</div>
<div class="q">"How does Phase 2 know a candidate is actually better, not just different?"</div>
<div class="card">It doesn't trust the language model's own judgment β€” every candidate gets re-scored through the exact same Phase 1 <code>evaluate()</code> pipeline used on the original code, so "better" is measured by the same objective risk score, not by how the refactor looks.</div>
<div class="q">"What would you improve?"</div>
<div class="card">Real-world training data instead of synthetic templates; persisting evaluation metrics instead of only printing them; and multi-file / cross-function analysis, since right now every file is scored in isolation.</div>
<h2>One-Line Summary to Open With</h2>
<div class="summary-box">
"I built a two-phase AI system β€” Phase 1 uses AST parsing and a Random Forest model to score Python code's maintainability risk out of 100 and explain why, and Phase 2 uses a CodeT5 deep learning model to iteratively generate and select better refactored versions of risky code, using the Phase 1 score itself as the judge of improvement."
</div>
</div>
</body>
</html>