Download app.py from SyedTahir/STHASI-Code-Review-Assistant: direct link, hf CLI and curl.
- Browser
- Download file 13.9 kB
-
https://huggingface.co/spaces/SyedTahir/STHASI-Code-Review-Assistant/resolve/main/app.py
- Command line
-
hf download hf://spaces/SyedTahir/STHASI-Code-Review-Assistant/app.py
-
curl -L -o app.py https://huggingface.co/spaces/SyedTahir/STHASI-Code-Review-Assistant/resolve/main/app.py
13.9 kB
| import gradio as gr | |
| import os | |
| from transformers import pipeline | |
| import torch | |
| import re | |
| import ast | |
| import traceback | |
| # Initialize a more suitable model for code analysis | |
| code_analyzer = None | |
| def load_analyzer(): | |
| global code_analyzer | |
| if code_analyzer is None: | |
| try: | |
| # Using a text generation model that's better for code analysis | |
| code_analyzer = pipeline( | |
| "text-generation", | |
| model="Salesforce/codegen-350M-mono", | |
| device=0 if torch.cuda.is_available() else -1 | |
| ) | |
| except: | |
| code_analyzer = "fallback" | |
| return code_analyzer | |
| def check_python_syntax(code): | |
| """Check Python syntax errors""" | |
| errors = [] | |
| try: | |
| ast.parse(code) | |
| except SyntaxError as e: | |
| errors.append({ | |
| 'type': 'Syntax Error', | |
| 'line': e.lineno, | |
| 'message': e.msg, | |
| 'text': e.text.strip() if e.text else '' | |
| }) | |
| except Exception as e: | |
| errors.append({ | |
| 'type': 'Parse Error', | |
| 'line': None, | |
| 'message': str(e), | |
| 'text': '' | |
| }) | |
| return errors | |
| def check_common_errors(code, language): | |
| """Detect common coding errors""" | |
| errors = [] | |
| lines = code.split('\n') | |
| if language.lower() == 'python': | |
| # Check for missing colons | |
| for i, line in enumerate(lines, 1): | |
| stripped = line.strip() | |
| if stripped and not stripped.startswith('#'): | |
| if any(stripped.startswith(kw) for kw in ['def ', 'class ', 'if ', 'elif ', 'else', 'for ', 'while ', 'try', 'except', 'finally', 'with ']): | |
| if not stripped.endswith(':') and not stripped.endswith('\\'): | |
| errors.append({ | |
| 'type': 'Missing Colon', | |
| 'line': i, | |
| 'message': 'Missing colon at end of statement', | |
| 'text': stripped | |
| }) | |
| # Check for missing parentheses | |
| for i, line in enumerate(lines, 1): | |
| if 'def ' in line or 'for ' in line or 'while ' in line: | |
| if '(' not in line or ')' not in line: | |
| errors.append({ | |
| 'type': 'Missing Parentheses', | |
| 'line': i, | |
| 'message': 'Missing parentheses in statement', | |
| 'text': line.strip() | |
| }) | |
| # Check for undefined variables (simple check) | |
| defined_vars = set() | |
| for i, line in enumerate(lines, 1): | |
| # Track variable assignments | |
| if '=' in line and not line.strip().startswith('#'): | |
| parts = line.split('=')[0].strip() | |
| if ' ' not in parts or parts.split()[0] in ['for']: | |
| var_name = parts.split()[-1].strip('()') | |
| defined_vars.add(var_name) | |
| # Check for undefined variable usage | |
| words = re.findall(r'\b[a-zA-Z_][a-zA-Z0-9_]*\b', line) | |
| for word in words: | |
| if word not in ['def', 'class', 'if', 'else', 'elif', 'for', 'while', 'in', 'return', 'print', 'len', 'range', 'str', 'int', 'float', 'list', 'dict', 'set', 'tuple']: | |
| # Check if it looks like it's being used but not defined | |
| if word not in defined_vars and f'{word}(' not in line and f'{word} =' not in line: | |
| if re.search(rf'\b{word}\b(?!\s*=)(?!\s*\()', line): | |
| errors.append({ | |
| 'type': 'Potential Undefined Variable', | |
| 'line': i, | |
| 'message': f"Variable '{word}' may not be defined", | |
| 'text': line.strip() | |
| }) | |
| return errors | |
| def analyze_code_structure(code, language): | |
| """Analyze code structure and provide metrics""" | |
| lines = code.split('\n') | |
| total_lines = len(lines) | |
| code_lines = len([l for l in lines if l.strip() and not l.strip().startswith('#') and not l.strip().startswith('//')]) | |
| comment_lines = len([l for l in lines if l.strip().startswith('#') or l.strip().startswith('//')]) | |
| blank_lines = total_lines - code_lines - comment_lines | |
| # Calculate complexity | |
| complexity_keywords = ['if', 'else', 'elif', 'for', 'while', 'switch', 'case', 'catch', 'try'] | |
| complexity = sum(code.lower().count(keyword) for keyword in complexity_keywords) | |
| # Check for functions | |
| func_count = len(re.findall(r'\bdef\s+\w+\s*\(', code)) if language.lower() == 'python' else len(re.findall(r'\bfunction\s+\w+\s*\(', code)) | |
| return { | |
| 'total_lines': total_lines, | |
| 'code_lines': code_lines, | |
| 'comment_lines': comment_lines, | |
| 'blank_lines': blank_lines, | |
| 'complexity': complexity, | |
| 'functions': func_count | |
| } | |
| def detect_vulnerabilities(code, language): | |
| """Detect common security vulnerabilities""" | |
| vulnerabilities = [] | |
| patterns = { | |
| 'SQL Injection': [r'execute\s*\(.*\+.*\)', r'query\s*\(.*\+.*\)', r'SELECT.*\+.*FROM'], | |
| 'Hardcoded Secrets': [r'password\s*=\s*["\'][^"\']+["\']', r'api_key\s*=\s*["\'][^"\']+["\']', r'secret\s*=\s*["\'][^"\']+["\']'], | |
| 'Command Injection': [r'os\.system\s*\(', r'subprocess\.call\s*\(', r'eval\s*\(', r'exec\s*\('], | |
| 'Path Traversal': [r'\.\./', r'open\s*\(.*\+.*\)'], | |
| 'XSS Vulnerability': [r'innerHTML\s*=', r'document\.write\s*\('], | |
| } | |
| for vuln_type, pattern_list in patterns.items(): | |
| for pattern in pattern_list: | |
| if re.search(pattern, code, re.IGNORECASE): | |
| vulnerabilities.append(vuln_type) | |
| break | |
| return list(set(vulnerabilities)) | |
| def generate_smart_suggestions(code, language, errors): | |
| """Generate intelligent code suggestions based on detected issues""" | |
| suggestions = [] | |
| # Suggestions based on errors | |
| if errors: | |
| suggestions.append("**Critical Issues Found:**") | |
| for error in errors[:5]: # Limit to first 5 errors | |
| suggestions.append(f"- Line {error['line']}: {error['type']} - {error['message']}") | |
| if error['text']: | |
| suggestions.append(f" ```{language.lower()}\n {error['text']}\n ```") | |
| # Code quality suggestions | |
| metrics = analyze_code_structure(code, language) | |
| if metrics['comment_lines'] == 0 and metrics['code_lines'] > 5: | |
| suggestions.append("\n**Documentation:**") | |
| suggestions.append("- Add comments to explain complex logic") | |
| suggestions.append("- Consider adding docstrings to functions") | |
| if metrics['complexity'] > 10: | |
| suggestions.append("\n**Complexity:**") | |
| suggestions.append("- High cyclomatic complexity detected. Consider breaking down complex functions") | |
| # Language-specific suggestions | |
| if language.lower() == 'python': | |
| if 'print(' in code and '+' in code: | |
| suggestions.append("\n**String Formatting:**") | |
| suggestions.append("- Use f-strings instead of string concatenation: `f'The average is {average}'`") | |
| if not re.search(r'if\s+__name__\s*==\s*["\']__main__["\']', code) and metrics['code_lines'] > 10: | |
| suggestions.append("\n**Best Practices:**") | |
| suggestions.append("- Add `if __name__ == '__main__':` guard for script execution") | |
| return "\n".join(suggestions) if suggestions else "Code looks good! Consider adding more comments for better maintainability." | |
| def review_code(code, language): | |
| """Main code review function""" | |
| if not code.strip(): | |
| return "β οΈ Please enter some code to review.", "", "" | |
| # Check for syntax and common errors | |
| all_errors = [] | |
| if language.lower() == 'python': | |
| syntax_errors = check_python_syntax(code) | |
| all_errors.extend(syntax_errors) | |
| common_errors = check_common_errors(code, language) | |
| all_errors.extend(common_errors) | |
| # Analyze code structure | |
| metrics = analyze_code_structure(code, language) | |
| # Detect vulnerabilities | |
| vulnerabilities = detect_vulnerabilities(code, language) | |
| # Generate smart suggestions | |
| suggestions = generate_smart_suggestions(code, language, all_errors) | |
| # Format metrics output | |
| quality_score = 100 | |
| if metrics['comment_lines'] == 0: | |
| quality_score -= 20 | |
| if all_errors: | |
| quality_score -= len(all_errors) * 10 | |
| if metrics['complexity'] > 10: | |
| quality_score -= 15 | |
| quality_score = max(0, quality_score) | |
| metrics_output = f"""## π Code Metrics | |
| - **Total Lines:** {metrics['total_lines']} | |
| - **Code Lines:** {metrics['code_lines']} | |
| - **Comment Lines:** {metrics['comment_lines']} | |
| - **Blank Lines:** {metrics['blank_lines']} | |
| - **Functions:** {metrics['functions']} | |
| - **Cyclomatic Complexity:** {metrics['complexity']} | |
| - **Comment Ratio:** {(metrics['comment_lines'] / max(metrics['code_lines'], 1) * 100):.1f}% | |
| - **Quality Score:** {quality_score}/100 {'π’' if quality_score >= 70 else 'π‘' if quality_score >= 40 else 'π΄'} | |
| """ | |
| # Format errors and vulnerabilities | |
| issues_output = "" | |
| if all_errors: | |
| issues_output += "## β Errors Detected\n\n" | |
| for i, error in enumerate(all_errors[:10], 1): # Show first 10 errors | |
| issues_output += f"{i}. **{error['type']}** (Line {error['line']})\n" | |
| issues_output += f" - {error['message']}\n" | |
| if error['text']: | |
| issues_output += f" - Code: `{error['text']}`\n" | |
| issues_output += "\n" | |
| if vulnerabilities: | |
| issues_output += "## π Security Vulnerabilities\n\n" | |
| for vuln in vulnerabilities: | |
| issues_output += f"- β οΈ **{vuln}**\n" | |
| issues_output += "\n**Recommendation:** Review and fix these security issues before deployment.\n" | |
| if not all_errors and not vulnerabilities: | |
| issues_output = "## β No Critical Issues Detected\n\nNo syntax errors or obvious security issues found." | |
| # Format suggestions | |
| suggestions_output = f"""## π‘ Suggestions for Improvement | |
| {suggestions} | |
| ### General Best Practices: | |
| - Write unit tests for your functions | |
| - Use meaningful variable and function names | |
| - Keep functions small and focused (Single Responsibility Principle) | |
| - Handle exceptions appropriately | |
| - Follow {language} PEP 8 style guide (for Python) or equivalent standards | |
| """ | |
| return metrics_output, issues_output, suggestions_output | |
| # Custom CSS | |
| custom_css = """ | |
| #header { | |
| text-align: center; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 30px; | |
| border-radius: 10px; | |
| margin-bottom: 20px; | |
| color: white; | |
| } | |
| #header h1 { | |
| margin: 0; | |
| font-size: 2.5em; | |
| font-weight: bold; | |
| } | |
| #header p { | |
| margin: 10px 0 0 0; | |
| font-size: 1.1em; | |
| opacity: 0.9; | |
| } | |
| .footer { | |
| text-align: center; | |
| margin-top: 30px; | |
| padding: 20px; | |
| background: #f8f9fa; | |
| border-radius: 10px; | |
| } | |
| .footer a { | |
| color: #667eea; | |
| text-decoration: none; | |
| font-weight: bold; | |
| margin: 0 10px; | |
| } | |
| .footer a:hover { | |
| text-decoration: underline; | |
| } | |
| """ | |
| # Create Gradio interface | |
| with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo: | |
| gr.HTML(""" | |
| <div id="header"> | |
| <h1>π STHASI Code Review Assistant</h1> | |
| <p>AI-Powered Code Analysis, Quality Metrics & Security Vulnerability Detection</p> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π Input Code") | |
| language = gr.Dropdown( | |
| choices=["Python", "JavaScript", "Java", "C++", "C#", "Go", "Ruby", "PHP", "TypeScript", "Swift"], | |
| value="Python", | |
| label="Programming Language" | |
| ) | |
| code_input = gr.Code( | |
| label="Paste your code here", | |
| language="python", | |
| lines=15 | |
| ) | |
| review_btn = gr.Button("π Review Code", variant="primary", size="lg") | |
| gr.Markdown(""" | |
| ### π Features: | |
| - **Syntax error detection** | |
| - **Code quality metrics** | |
| - **Security vulnerability scan** | |
| - **Smart improvement suggestions** | |
| - **Multi-language support** | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| metrics_output = gr.Markdown(label="Code Metrics") | |
| with gr.Row(): | |
| with gr.Column(): | |
| issues_output = gr.Markdown(label="Issues & Security") | |
| with gr.Row(): | |
| with gr.Column(): | |
| suggestions_output = gr.Markdown(label="Suggestions") | |
| gr.HTML(""" | |
| <div class="footer"> | |
| <a href="https://www.linkedin.com/in/syedtahirhussan/" target="_blank">π LinkedIn</a> | |
| <a href="https://github.com/SyedTahirHussan" target="_blank">π» GitHub</a> | |
| <p style="font-size: 0.9em; margin-top: 10px; color: black;">Built with β€οΈ by <a href="https://www.linkedin.com/in/syedtahirhussan/" target="_blank" style="color: black; text-decoration: underline;">Syed Tahir Hussan</a></p> | |
| <p style="margin-top: 15px; color: #666;">Powered by Advanced Static Analysis | Gradio 5.49.1</p> | |
| </div> | |
| """) | |
| review_btn.click( | |
| fn=review_code, | |
| inputs=[code_input, language], | |
| outputs=[metrics_output, issues_output, suggestions_output] | |
| ) | |
| language.change( | |
| fn=lambda x: gr.Code(language=x.lower()), | |
| inputs=[language], | |
| outputs=[code_input] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |