Spaces:
Runtime error
Runtime error
File size: 7,186 Bytes
2a414bf e893bee 2a414bf aa1b688 2a414bf aa1b688 2a414bf aa1b688 2a414bf 808f948 2a414bf aa1b688 2a414bf aa1b688 2a414bf aa1b688 2a414bf e893bee aa1b688 e893bee aa1b688 e893bee 2a414bf aa1b688 e893bee aa1b688 2a414bf aa1b688 e893bee aa1b688 e893bee aa1b688 e893bee 2a414bf e893bee 2a414bf aa1b688 2a414bf e893bee 2a414bf e893bee 2a414bf aa1b688 2a414bf aa1b688 2a414bf e893bee 2a414bf e893bee 2a414bf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | import os
import zipfile
import tempfile
import gradio as gr
from docx import Document
from huggingface_hub import InferenceClient
# -----------------------------
# 1οΈβ£ Hugging Face client
# -----------------------------
HF_TOKEN = os.getenv("HUGGINGFACE_API_KEY")
client = InferenceClient(api_key=HF_TOKEN)
# -----------------------------
# 2οΈβ£ Review prompt
# -----------------------------
promt = """
You are a senior software engineer with 10+ years of experience reviewing code in multiple languages.
Provide feedback like a human: friendly, clear, and actionable.
Give short, clear feedback in bullet points.
**Rules:**
Review the code and provide actionable points under these 4 areas:
1. **Code Standards** β Naming, formatting, magic numbers, comments
2. **Security** β SQL injection, input validation, hardcoded secrets, authentication issues
3. **Reusability** β Duplicate code, missing helper functions, not using libraries
4. **Refactoring** β Simplify complex code, performance improvements, better error handling
**Format:**
- Each suggestion must be a single concise line:
`Line X: Problem β Fix`
- Always **show both the incorrect and corrected examples** when suggesting naming or syntax improvements.
- Use **real corrected form** (e.g., `_AuthService` β `_authService`).
- Keep tone friendly, direct, and professional.
- Do not repeat identical feedback for multiple lines; combine where possible.
"""
ignore_folders = ['.venv', 'wwwroot', 'node_modules', '__pycache__', 'bin', 'obj', 'properties']
ALLOWED_EXTS = [".py", ".js", ".java", ".cs", ".cpp", ".ts", ".cshtml", ".razor"]
# -----------------------------
# 3οΈβ£ Helper functions
# -----------------------------
def analyze_code_with_ai(code_text: str, filename: str) -> str:
try:
completion = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[
{"role": "system", "content": promt},
{"role": "user", "content": f"Review the following code from {filename}:\n\n{code_text}"}
]
)
return completion.choices[0].message["content"]
except Exception as e:
return f"β οΈ Error: {str(e)}"
def extract_zip_to_temp(zip_file_path):
temp_dir = tempfile.mkdtemp()
with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir)
return temp_dir
def list_subfolders(folder_path):
folders = [os.path.basename(folder_path)]
for root, dirs, _ in os.walk(folder_path):
for d in dirs:
if any(ignored in root for ignored in ignore_folders):
continue
rel_path = os.path.relpath(os.path.join(root, d), folder_path)
folders.append(rel_path)
return folders
def process_selected_folders(base_path, selected_folders):
reviews = {}
for subfolder in selected_folders:
full_path = base_path if subfolder == os.path.basename(base_path) else os.path.join(base_path, subfolder)
for root, _, files in os.walk(full_path):
if any(ignored in root for ignored in ignore_folders):
continue
for file in files:
if any(file.endswith(ext) for ext in ALLOWED_EXTS):
filepath = os.path.join(root, file)
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
code = f.read()
reviews[file] = analyze_code_with_ai(code, file)
return reviews
def process_file(file_path):
filename = os.path.basename(file_path)
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
code = f.read()
return {filename: analyze_code_with_ai(code, filename)}
def generate_report(reviews, output_path="review_report.docx"):
doc = Document()
doc.add_heading("Code Review Report", 0)
for fname, review in reviews.items():
doc.add_heading(fname, level=1)
doc.add_paragraph(review)
doc.save(output_path)
return output_path
# -----------------------------
# 4οΈβ£ Gradio functions
# -----------------------------
# List subfolders after ZIP upload
def load_subfolders_from_zip(zip_file):
if not zip_file:
return gr.update(choices=[], value=[]), "β οΈ No ZIP uploaded."
folder_path = extract_zip_to_temp(zip_file.name)
folders = list_subfolders(folder_path)
return gr.update(choices=folders, value=folders), folder_path, f"β
Found {len(folders)} folders."
# Review selected subfolders
def review_zip_selected(folder_path, selected_folders):
if not folder_path or not os.path.isdir(folder_path):
return "β οΈ Invalid folder path.", None
if not selected_folders:
return "β οΈ No folders selected.", None
reviews = process_selected_folders(folder_path, selected_folders)
if not reviews:
return "β οΈ No code files found.", None
report_path = generate_report(reviews)
output_text = "\n\n".join([f"π {f}:\n{r}" for f, r in reviews.items()])
return output_text, report_path
# Review single file
def review_single_file(file_obj):
if not file_obj:
return "β οΈ No file uploaded.", None
reviews = process_file(file_obj.name)
if not reviews:
return "β οΈ Could not analyze file.", None
report_path = generate_report(reviews)
output_text = "\n\n".join([f"π {f}:\n{r}" for f, r in reviews.items()])
return output_text, report_path
# -----------------------------
# 5οΈβ£ Gradio UI
# -----------------------------
with gr.Blocks() as demo:
gr.Markdown("# π€ AI Code Reviewer\nUpload a ZIP or a single file and get a code review report.")
with gr.Tab("π¦ Review ZIP with Folder Selection"):
zip_input = gr.File(label="Upload ZIP File", file_types=[".zip"])
load_btn = gr.Button("π Load Subfolders")
folder_status = gr.Markdown("")
folder_select = gr.CheckboxGroup(label="Select Folders to Review")
run_zip_btn = gr.Button("π Run Review")
zip_output_text = gr.Textbox(label="AI Review Output", lines=15)
zip_report_file = gr.File(label="Download DOCX Report", type="filepath")
# Store the temp folder path in gr.State
temp_folder_state = gr.State()
# When loading subfolders, also store folder path in state
load_btn.click(
fn=load_subfolders_from_zip,
inputs=zip_input,
outputs=[folder_select, temp_folder_state, folder_status]
)
# Use stored folder path from gr.State for review
run_zip_btn.click(
fn=review_zip_selected,
inputs=[temp_folder_state, folder_select],
outputs=[zip_output_text, zip_report_file]
)
with gr.Tab("π Review Single File"):
file_input = gr.File(label="Upload Single File", file_types=ALLOWED_EXTS)
run_file_btn = gr.Button("π Run Review")
file_output_text = gr.Textbox(label="AI Review Output", lines=15)
file_report_file = gr.File(label="Download DOCX Report", type="filepath")
run_file_btn.click(fn=review_single_file, inputs=file_input, outputs=[file_output_text, file_report_file])
demo.launch()
|