rgera's picture
Update app.py
d2a009a verified
Raw History Blame Contribute Delete
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()