Spaces:
Sleeping
Sleeping
Download app.py from rgera/compiler_project: direct link, hf CLI and curl.
- Browser
- Download file 12.8 kB
-
https://huggingface.co/spaces/rgera/compiler_project/resolve/main/app.py
- Command line
-
hf download hf://spaces/rgera/compiler_project/app.py
-
curl -L -o app.py https://huggingface.co/spaces/rgera/compiler_project/resolve/main/app.py
12.8 kB
| import ast | |
| import gradio as gr | |
| from PIL import Image | |
| import io | |
| import networkx as nx | |
| import matplotlib.pyplot as plt | |
| import copy | |
| import google.generativeai as genai | |
| import os | |
| from dotenv import load_dotenv | |
| import speech_recognition as sr | |
| import numpy as np | |
| import wave | |
| import tempfile | |
| load_dotenv() | |
| # Configure Gemini API | |
| genai.configure(api_key=os.getenv('GEMINI_API_KEY')) | |
| model = genai.GenerativeModel('gemini-1.5-flash') | |
| def generate_code(prompt: str): | |
| try: | |
| response = model.generate_content( | |
| f"Write Python code for this requirement: {prompt}. " | |
| "Only return the code without any explanation." | |
| ) | |
| generated_code = response.text.strip() | |
| # Try parsing the generated code to verify it's valid Python | |
| generated_code = generated_code[9:-3] | |
| ast.parse(generated_code) #temporarily | |
| return "Code generated successfully!", generated_code | |
| except Exception as e: | |
| return f"Error: {str(e)}", "" | |
| def transcribe_audio(audio): | |
| if audio is None: | |
| return "Error: No audio provided", "" | |
| recognizer = sr.Recognizer() | |
| try: | |
| # Handle different audio input formats | |
| if isinstance(audio, str): | |
| # Direct file path | |
| with sr.AudioFile(audio) as source: | |
| audio_data = recognizer.record(source) | |
| else: | |
| # Convert numpy array to WAV file | |
| sample_rate, y = audio | |
| with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_audio: | |
| with wave.open(temp_audio.name, 'wb') as wf: | |
| wf.setnchannels(1) | |
| wf.setsampwidth(2) | |
| wf.setframerate(sample_rate) | |
| wf.writeframes((y * 32767).astype(np.int16).tobytes()) | |
| with sr.AudioFile(temp_audio.name) as source: | |
| audio_data = recognizer.record(source) | |
| text = recognizer.recognize_google(audio_data) | |
| return "Transcription successful!", text | |
| except Exception as e: | |
| return f"Error in transcription: {str(e)}", "" | |
| def process_voice_to_code(audio_path): | |
| status, transcribed_text = transcribe_audio(audio_path) | |
| if "Error" in status: | |
| return status, "" | |
| return generate_code(transcribed_text) | |
| # Step 1: Convert AST to NetworkX | |
| def visualize_ast(code: str): | |
| try: | |
| tree = ast.parse(code) | |
| except SyntaxError as e: | |
| return f"Syntax Error: {e}", None | |
| G = nx.DiGraph() | |
| def get_node_label(node): | |
| if isinstance(node, ast.Name): | |
| return f"{type(node).__name__}\nid: {node.id}" | |
| elif isinstance(node, ast.Constant): | |
| return f"{type(node).__name__}\nvalue: {node.value}" | |
| elif isinstance(node, ast.FunctionDef): | |
| return f"{type(node).__name__}\nname: {node.name}" | |
| elif isinstance(node, ast.ClassDef): | |
| return f"{type(node).__name__}\nname: {node.name}" | |
| elif isinstance(node, ast.Call): | |
| return f"{type(node).__name__}" | |
| else: | |
| return type(node).__name__ | |
| def add_nodes_edges(node, parent_id=None, edge_label=""): | |
| node_id = id(node) | |
| G.add_node(node_id, label=get_node_label(node)) | |
| if parent_id is not None: | |
| G.add_edge(parent_id, node_id, label=edge_label) | |
| for field, value in ast.iter_fields(node): | |
| if isinstance(value, ast.AST): | |
| add_nodes_edges(value, node_id, field) | |
| elif isinstance(value, list): | |
| for item in value: | |
| if isinstance(item, ast.AST): | |
| add_nodes_edges(item, node_id, field) | |
| add_nodes_edges(tree) | |
| plt.figure(figsize=(15, 10)) | |
| pos = nx.kamada_kawai_layout(G) # Better layout for hierarchical structures | |
| # Draw edges with labels | |
| nx.draw_networkx_edges(G, pos, edge_color='gray', arrows=True, arrowsize=20) | |
| edge_labels = nx.get_edge_attributes(G, 'label') | |
| nx.draw_networkx_edge_labels(G, pos, edge_labels, font_size=8) | |
| # Draw nodes with custom style | |
| nx.draw_networkx_nodes(G, pos, node_color='lightblue', | |
| node_size=2500, alpha=0.9) | |
| # Add node labels with better formatting | |
| labels = nx.get_node_attributes(G, 'label') | |
| nx.draw_networkx_labels(G, pos, labels, font_size=8) | |
| plt.title("Abstract Syntax Tree Visualization") | |
| # Save to buffer with higher DPI for better quality | |
| buf = io.BytesIO() | |
| plt.savefig(buf, format='png', bbox_inches='tight', dpi=200) | |
| plt.close() | |
| buf.seek(0) | |
| image = Image.open(buf) | |
| return "AST Generated Successfully", image | |
| # Step 2: Data Flow Analysis | |
| def analyze_dataflow(code: str): | |
| try: | |
| tree = ast.parse(code) | |
| except SyntaxError as e: | |
| return f"Syntax Error: {e}", None | |
| DFG = nx.DiGraph() | |
| variables = {} # Track variable definitions and uses | |
| class DataFlowVisitor(ast.NodeVisitor): | |
| def visit_Assign(self, node): | |
| for target in node.targets: | |
| if isinstance(target, ast.Name): | |
| var_name = target.id | |
| def_id = f"def_{var_name}_{id(node)}" | |
| DFG.add_node(def_id, label=f"Define\n{var_name}", type="def") | |
| variables[var_name] = variables.get(var_name, []) + [def_id] | |
| self.generic_visit(node) | |
| def visit_Name(self, node): | |
| if isinstance(node.ctx, ast.Load): | |
| var_name = node.id | |
| use_id = f"use_{var_name}_{id(node)}" | |
| DFG.add_node(use_id, label=f"Use\n{var_name}", type="use") | |
| # Add edges from all previous definitions | |
| if var_name in variables: | |
| for def_id in variables[var_name]: | |
| DFG.add_edge(def_id, use_id) | |
| DataFlowVisitor().visit(tree) | |
| if not DFG.nodes(): | |
| return "No data flow to analyze", None | |
| plt.figure(figsize=(15, 10)) | |
| pos = nx.spring_layout(DFG, k=2) # More spread out layout | |
| # Draw nodes with different colors for def/use | |
| def_nodes = [n for n, d in DFG.nodes(data=True) if d.get('type') == 'def'] | |
| use_nodes = [n for n, d in DFG.nodes(data=True) if d.get('type') == 'use'] | |
| nx.draw_networkx_nodes(DFG, pos, nodelist=def_nodes, node_color='lightgreen', | |
| node_size=3000, alpha=0.9) | |
| nx.draw_networkx_nodes(DFG, pos, nodelist=use_nodes, node_color='lightblue', | |
| node_size=3000, alpha=0.9) | |
| # Draw edges and labels | |
| nx.draw_networkx_edges(DFG, pos, edge_color='gray', arrows=True, arrowsize=20) | |
| labels = nx.get_node_attributes(DFG, 'label') | |
| nx.draw_networkx_labels(DFG, pos, labels, font_size=10) | |
| plt.title("Data Flow Graph") | |
| buf = io.BytesIO() | |
| plt.savefig(buf, format='png', bbox_inches='tight', dpi=200) | |
| plt.close() | |
| buf.seek(0) | |
| image = Image.open(buf) | |
| return "Data Flow Analysis Complete", image | |
| # Step 3: Optimization Analysis | |
| def analyze_optimizations(code: str): | |
| try: | |
| tree = ast.parse(code) | |
| except SyntaxError as e: | |
| return f"Syntax Error: {e}", None | |
| CFG = nx.DiGraph() | |
| constants = {} | |
| dead_code = set() | |
| class OptimizationVisitor(ast.NodeVisitor): | |
| def __init__(self): | |
| self.current_block = 0 | |
| self.last_block = 0 | |
| def new_block(self): | |
| self.last_block = self.current_block | |
| self.current_block += 1 | |
| return self.current_block | |
| def visit_Assign(self, node): | |
| if isinstance(node.value, ast.Constant): | |
| constants[id(node)] = node.value.value | |
| block_id = f"B{self.current_block}" | |
| label = ast.unparse(node) | |
| CFG.add_node(block_id, label=label, type='assign') | |
| if self.last_block >= 0: | |
| CFG.add_edge(f"B{self.last_block}", block_id) | |
| # Mark as dead code if value is never used | |
| if isinstance(node.targets[0], ast.Name): | |
| var_name = node.targets[0].id | |
| if not any(isinstance(n, ast.Name) and n.id == var_name | |
| for n in ast.walk(tree) if isinstance(n, ast.Name) | |
| and isinstance(n.ctx, ast.Load)): | |
| dead_code.add(block_id) | |
| self.generic_visit(node) | |
| OptimizationVisitor().visit(tree) | |
| plt.figure(figsize=(15, 10)) | |
| pos = nx.spring_layout(CFG, k=2) | |
| # Draw nodes with different colors based on optimization opportunities | |
| regular_nodes = [n for n in CFG.nodes() if n not in dead_code] | |
| dead_nodes = list(dead_code) | |
| # Draw regular nodes | |
| nx.draw_networkx_nodes(CFG, pos, nodelist=regular_nodes, | |
| node_color='lightblue', node_size=3000) | |
| # Draw dead code nodes | |
| nx.draw_networkx_nodes(CFG, pos, nodelist=dead_nodes, | |
| node_color='salmon', node_size=3000) | |
| # Draw edges and labels | |
| nx.draw_networkx_edges(CFG, pos, edge_color='gray', arrows=True, arrowsize=20) | |
| labels = nx.get_node_attributes(CFG, 'label') | |
| nx.draw_networkx_labels(CFG, pos, labels, font_size=10) | |
| # Add legend | |
| plt.plot([], [], 'o', color='salmon', label='Dead Code') | |
| plt.plot([], [], 'o', color='lightblue', label='Active Code') | |
| plt.legend() | |
| plt.title("Control Flow Graph with Optimization Opportunities") | |
| buf = io.BytesIO() | |
| plt.savefig(buf, format='png', bbox_inches='tight', dpi=200) | |
| plt.close() | |
| buf.seek(0) | |
| image = Image.open(buf) | |
| # Prepare optimization summary | |
| summary = [] | |
| if dead_code: | |
| summary.append(f"Found {len(dead_code)} dead code block(s)") | |
| if constants: | |
| summary.append(f"Found {len(constants)} constant propagation opportunities") | |
| return "\n".join(summary) if summary else "No optimization opportunities found", image | |
| # Step 4: Gradio Interface | |
| with gr.Blocks() as demo: | |
| gr.Markdown("## 🧠 Python Code Analysis Visualizer") | |
| with gr.Tabs(): | |
| with gr.TabItem("AST Visualization"): | |
| with gr.Row(): | |
| ast_code_input = gr.Code(label="Enter Python Code", language="python") | |
| ast_output = gr.Image(label="AST Visualization") | |
| ast_status = gr.Textbox(label="Status") | |
| ast_btn = gr.Button("Visualize AST") | |
| with gr.TabItem("Data Flow Analysis"): | |
| with gr.Row(): | |
| dfg_code_input = gr.Code(label="Enter Python Code", language="python") | |
| dfg_output = gr.Image(label="Data Flow Graph") | |
| dfg_status = gr.Textbox(label="Status") | |
| dfg_btn = gr.Button("Analyze Data Flow") | |
| with gr.TabItem("Optimization Analysis"): | |
| with gr.Row(): | |
| opt_code_input = gr.Code(label="Enter Python Code", language="python") | |
| opt_output = gr.Image(label="Optimization Visualization") | |
| opt_status = gr.Textbox(label="Optimization Opportunities") | |
| opt_btn = gr.Button("Analyze Optimizations") | |
| with gr.TabItem("Natural Language to Code"): | |
| with gr.Row(): | |
| with gr.Column(): | |
| prompt_input = gr.Textbox( | |
| label="Enter your requirement in natural language", | |
| placeholder="e.g., write a function to calculate fibonacci series" | |
| ) | |
| audio_input = gr.Audio( | |
| sources=["microphone"], | |
| type="numpy", | |
| label="Or speak your requirement" | |
| ) | |
| with gr.Column(): | |
| code_output = gr.Code( | |
| label="Generated Code", | |
| language="python" | |
| ) | |
| gen_status = gr.Textbox(label="Status") | |
| with gr.Row(): | |
| generate_btn = gr.Button("Generate from Text") | |
| voice_btn = gr.Button("Generate from Voice") | |
| ast_btn.click(visualize_ast, inputs=ast_code_input, outputs=[ast_status, ast_output]) | |
| dfg_btn.click(analyze_dataflow, inputs=dfg_code_input, outputs=[dfg_status, dfg_output]) | |
| opt_btn.click(analyze_optimizations, inputs=opt_code_input, outputs=[opt_status, opt_output]) | |
| generate_btn.click( | |
| generate_code, | |
| inputs=prompt_input, | |
| outputs=[gen_status, code_output] | |
| ) | |
| voice_btn.click( | |
| process_voice_to_code, | |
| inputs=audio_input, | |
| outputs=[gen_status, code_output] | |
| ) | |
| demo.launch() | |