import os import uuid import gradio as gr from openai import OpenAI # Get API key from environment api_key = os.environ.get("NEBIUS_API_KEY") if not api_key: print("Warning: NEBIUS_API_KEY environment variable not set. LLM features will be disabled.") client = None else: client = OpenAI( base_url="https://api.studio.nebius.com/v1/", api_key=api_key, ) # Import visualization tools and helper from tools.visualizer_linked_list import generate_linked_list_gif from tools.visualizer_sort import generate_bubble_sort_gif from tools.utility_helpers import ensure_output_dir from tools.code_analyzer import CodeAnalyzer ensure_output_dir() # make sure ./output/ exists code_analyzer = CodeAnalyzer() PLACEHOLDER_IMG = os.path.join("output", "no_visualization.gif") def create_placeholder_gif(): # Create a simple placeholder GIF if it doesn't exist if not os.path.exists(PLACEHOLDER_IMG): from PIL import Image, ImageDraw img = Image.new('RGB', (400, 100), color='white') d = ImageDraw.Draw(img) d.text((10, 40), "No visualization available", fill=(0, 0, 0)) img.save(PLACEHOLDER_IMG, format='GIF') create_placeholder_gif() def explain_algorithm_with_llm(code_snippet: str, code_info: dict = None): """ Send a prompt to Nebius-hosted LLM (Meta-Llama-3.1-70B-Instruct). Returns the model's explanation text. """ if not client: return "LLM features are disabled. Please set the NEBIUS_API_KEY environment variable to enable AI explanations." if code_info: prompt = code_analyzer.get_explanation_prompt(code_info) prompt += f"\n\nCode:\n{code_snippet}" else: prompt = f"Please explain this code step by step:\n\n{code_snippet}" response = client.chat.completions.create( model="meta-llama/Meta-Llama-3.1-70B-Instruct", messages=[{"role": "user", "content": prompt}], temperature=0.6 ) return response.choices[0].message.content def extract_array_from_code(code: str): import re # Try to find Python list or comma-separated numbers array_match = re.search(r'\[([\d\s,]+)\]', code) if array_match: try: return [int(x.strip()) for x in array_match.group(1).split(',') if x.strip()] except Exception: pass # Try to find comma-separated numbers in the code csv_match = re.search(r'(\d+(?:\s*,\s*\d+)+)', code) if csv_match: try: return [int(x.strip()) for x in csv_match.group(1).split(',') if x.strip()] except Exception: pass return None def extract_linked_list_ops_from_code(code: str): import re operations = [] for line in code.split('\n'): if 'insert' in line.lower(): num_match = re.search(r'insert\s+(\d+)', line.lower()) if num_match: operations.append(f"insert {num_match.group(1)}") elif 'delete' in line.lower(): operations.append("delete") return operations if operations else None def generate_visualization(code_info: dict, code: str) -> str: """ Generate appropriate visualization based on code analysis. Returns the path to the generated GIF. """ gif_name = f"{uuid.uuid4()}.gif" output_path = os.path.join("output", gif_name) # Extract values for visualization from the code try: # For sorting algorithms, try to find array/list in the code if any('sort' in algo for algo in code_info['patterns']['algorithms']): values = extract_array_from_code(code) if values: generate_bubble_sort_gif(values, output_path) return output_path # For linked list operations if any('linked_list' in ds for ds in code_info['patterns']['data_structures']): operations = extract_linked_list_ops_from_code(code) if operations: generate_linked_list_gif(operations, output_path) return output_path except Exception as e: print(f"Error generating visualization: {e}") return PLACEHOLDER_IMG def process_code(code_snippet: str): """ Process the input code: 1. Analyze the code 2. Generate visualization 3. Get LLM explanation """ # Analyze the code code_info = code_analyzer.analyze_code(code_snippet) debug_log = [] if code_info.get('type') == 'error': return f"❌ Code analysis failed: {code_info.get('error')}", PLACEHOLDER_IMG # Generate visualization visualization_path = generate_visualization(code_info, code_snippet) no_visual = (visualization_path == PLACEHOLDER_IMG) # Get LLM explanation explanation = explain_algorithm_with_llm(code_snippet, code_info) # Create a beautiful markdown output markdown_output = f""" # 📊 Code Analysis Report ## 🎯 Code Type & Name - **Type:** {code_info['type'].title()} {f"- **Name:** `{code_info['name']}`" if code_info['name'] else ""} - **Complexity:** `{code_info['complexity']}` ## 🔍 Detected Patterns """ if code_info['patterns']['algorithms']: markdown_output += "\n### 🧮 Algorithms\n" for algo in code_info['patterns']['algorithms']: markdown_output += f"- {algo.replace(':', ': ').title()}\n" if code_info['patterns']['data_structures']: markdown_output += "\n### 📚 Data Structures\n" for ds in code_info['patterns']['data_structures']: markdown_output += f"- {ds.replace(':', ': ').title()}\n" markdown_output += "\n## 📝 Code Structure\n" structure = code_info['structure'] markdown_output += f"- {'✅' if structure['has_recursion'] else '❌'} Recursion\n" markdown_output += f"- {'✅' if structure['has_classes'] else '❌'} Classes\n" markdown_output += f"- {'✅' if structure['has_functions'] else '❌'} Functions\n" markdown_output += f"- {'✅' if structure['has_loops'] else '❌'} Loops\n" if no_visual: markdown_output += """ ## ⚠️ Visualization Note No visualization could be generated for this code. **Supported Visualizations:** - Bubble Sort (with array) - Linked List (with 'insert N'/'delete' lines) """ markdown_output += "\n## 📖 Explanation\n" markdown_output += explanation return markdown_output, visualization_path # Custom CSS css = """ .code-input { font-family: 'Consolas', 'Monaco', monospace !important; font-size: 14px !important; } .explanation-output { font-size: 14px !important; line-height: 1.6 !important; } .visualization-output { border-radius: 8px !important; box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important; } """ # Gradio UI with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo: gr.Markdown(""" # 🧠 CodeViz: Visual Learning of Algorithms Enter your code below to get: 1. A detailed explanation of how it works 2. A visualization of the algorithm/data structure 3. Analysis of its complexity and patterns Examples: ```python # Bubble Sort def bubble_sort(arr): n = len(arr) for i in range(n): for j in range(0, n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr # Test with array arr = [64, 34, 25, 12, 22, 11, 90] ``` ```python # Linked List Insert class Node: def __init__(self, data): self.data = data self.next = None def insert_at_end(head, data): new_node = Node(data) if head is None: return new_node current = head while current.next: current = current.next current.next = new_node return head ``` """) with gr.Row(): with gr.Column(scale=1): code_input = gr.Textbox( label="Enter your code", lines=10, placeholder="Paste your code here...", elem_classes=["code-input"], type="text" ) run_btn = gr.Button("Visualize & Explain", variant="primary") with gr.Column(scale=1): explanation_output = gr.Markdown( label="Explanation & Analysis", elem_classes=["explanation-output"] ) visualization_output = gr.Image( label="Visualization", type="filepath", elem_classes=["visualization-output"] ) run_btn.click( fn=process_code, inputs=[code_input], outputs=[explanation_output, visualization_output], api_name="process_code" ) if __name__ == "__main__": demo.queue().launch( server_name="0.0.0.0", server_port=7860, share=True, # Enable sharing for easier access show_error=True # Show detailed error messages )