import gradio as gr import requests import re import tempfile import importlib.util import sys import os import ast import traceback from types import MethodType # Check Gradio version GRADIO_VERSION = gr.__version__ print(f"Gradio version: {GRADIO_VERSION}") # Patch Gradio Button class if needed if not hasattr(gr.Button, 'click'): # For Gradio 4.x, we need to add a click method def patched_click(self, fn, inputs=None, outputs=None): """Patched click method for Gradio 4.x buttons""" if inputs is None: inputs = [] if outputs is None: outputs = [] # In Gradio 4.x, this would be the event listener pattern return self.click(fn=fn, inputs=inputs, outputs=outputs) # Try to add the method, might not work but worth a try try: gr.Button.click = patched_click print("Added click method to Button class") except Exception as e: print(f"Failed to patch Button class: {e}") # Function to generate working code for the current Gradio version def generate_compatible_code(prompt): """Generate code that's guaranteed to work with this Gradio version""" if "hello world" in prompt.lower(): return """ import gradio as gr # Creating a simple hello world app that works in all Gradio versions def say_hello(): return "Hello, World!" # Create the Gradio interface demo = gr.Interface( fn=say_hello, inputs=[], outputs=gr.Textbox(label="Output"), title="Hello World App" ) """ elif "calculator" in prompt.lower(): return """ import gradio as gr import numpy as np # Create a simple calculator def calculate(num1, num2, operation): if operation == "Add": return num1 + num2 elif operation == "Subtract": return num1 - num2 elif operation == "Multiply": return num1 * num2 elif operation == "Divide": if num2 == 0: return "Error: Division by zero" return num1 / num2 else: return "Please select an operation" # Create the Gradio interface - works in all versions demo = gr.Interface( fn=calculate, inputs=[ gr.Number(label="First Number"), gr.Number(label="Second Number"), gr.Dropdown(["Add", "Subtract", "Multiply", "Divide"], label="Operation") ], outputs=gr.Number(label="Result"), title="Simple Calculator" ) """ elif "image" in prompt.lower() or "filter" in prompt.lower(): return """ import gradio as gr import numpy as np from PIL import Image, ImageEnhance # Create an image brightness adjuster def adjust_brightness(image, brightness_factor): if image is None: return None # Convert to PIL Image pil_image = Image.fromarray(image) # Adjust brightness enhancer = ImageEnhance.Brightness(pil_image) brightened = enhancer.enhance(brightness_factor) # Return as numpy array return np.array(brightened) # Create the Gradio interface - works in all versions demo = gr.Interface( fn=adjust_brightness, inputs=[ gr.Image(label="Input Image"), gr.Slider(0.1, 3.0, 1.0, label="Brightness Factor") ], outputs=gr.Image(label="Adjusted Image"), title="Image Brightness Adjuster" ) """ elif "text" in prompt.lower() or "sentiment" in prompt.lower(): return """ import gradio as gr import random # Simple sentiment analyzer (mock) def analyze_sentiment(text): if not text: return "Please enter some text" # Calculate length and random sentiment for demo text_length = len(text) sentiment = random.choice(["Positive", "Neutral", "Negative"]) return f"Length: {text_length} characters | Sentiment: {sentiment}" # Create the Gradio interface - works in all versions demo = gr.Interface( fn=analyze_sentiment, inputs=gr.Textbox(lines=5, label="Enter text here"), outputs=gr.Textbox(label="Analysis Result"), title="Text Analyzer" ) """ else: return """ import gradio as gr # A general purpose demo that works in all Gradio versions def process_input(text_input): if not text_input: return "Please enter some input" # Process the input word_count = len(text_input.split()) char_count = len(text_input) return f"Word count: {word_count} | Character count: {char_count}" # Create the Gradio interface - works in all versions demo = gr.Interface( fn=process_input, inputs=gr.Textbox(lines=3, label="Input"), outputs=gr.Textbox(label="Output"), title="Text Processor" ) """ def call_openai_api(api_key, prompt): """Direct API call to OpenAI""" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {api_key}" } # Create a system prompt specifically for gr.Interface() style apps system_prompt = f"""You are an expert Gradio developer. Create a standalone Gradio application based on the user's prompt. Your response should ONLY include Python code without any explanation. IMPORTANT: You MUST use gr.Interface() instead of gr.Blocks() for compatibility. DO NOT use Button.click() or any other component events. Here's a template to follow: ```python import gradio as gr def my_function(input1, input2): # Process inputs result = input1 + input2 # Example operation return result # Create the Gradio interface demo = gr.Interface( fn=my_function, inputs=[gr.Textbox(label="Input 1"), gr.Textbox(label="Input 2")], outputs=gr.Textbox(label="Output"), title="My App" ) ``` The code must: 1. Import necessary libraries 2. Define functions that handle the app logic 3. Create a gr.Interface named 'demo' 4. NOT include a launch command or if __name__ == "__main__" block 5. Avoid using component events or callbacks """ data = { "model": "gpt-4o", "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt} ], "temperature": 0.2, "max_tokens": 4000 } response = requests.post( "https://api.openai.com/v1/chat/completions", headers=headers, json=data ) if response.status_code != 200: return None, f"API Error: {response.status_code} - {response.text}" result = response.json() return result["choices"][0]["message"]["content"], None def extract_code_blocks(text): """Extract code blocks from markdown""" pattern = r'```(?:python)?\s*([\s\S]*?)```' matches = re.findall(pattern, text) if not matches and text.strip(): if re.search(r'import\s+\w+|def\s+\w+\(|class\s+\w+:|if\s+__name__\s*==\s*[\'"]__main__[\'"]:', text): return [text.strip()] return [match.strip() for match in matches] def load_generated_app(code): """Load and run the generated Gradio app""" # Save code to temp file with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f: f.write(code.encode('utf-8')) temp_file = f.name try: # Import module module_name = os.path.basename(temp_file).replace('.py', '') spec = importlib.util.spec_from_file_location(module_name, temp_file) module = importlib.util.module_from_spec(spec) sys.modules[module_name] = module spec.loader.exec_module(module) # Get the Gradio interface if hasattr(module, 'demo'): return module.demo, None else: return None, "No 'demo' variable found in the generated code" except Exception as e: error_details = traceback.format_exc() return None, f"{str(e)}\n{error_details}" finally: try: os.unlink(temp_file) except: pass # Create the main UI with gr.Blocks(title="AI Gradio App Generator") as demo: gr.Markdown(f"# 🤖 AI Gradio App Generator (v{GRADIO_VERSION})") gr.Markdown("Describe the Gradio app you want, and I'll generate it for you.") with gr.Row(): with gr.Column(): api_key = gr.Textbox( label="OpenAI API Key", placeholder="sk-...", type="password", info="Your key is used only for this session" ) prompt = gr.Textbox( label="App Description", placeholder="Describe the Gradio app you want to create...", lines=5 ) with gr.Row(): submit_btn = gr.Button("Generate App", variant="primary") skip_api_btn = gr.Button("Try Without API", variant="secondary") with gr.Accordion("Generated Code", open=False): code_output = gr.Code(language="python", label="Generated Code") status_output = gr.Markdown("") generated_app_container = gr.Group(visible=False) def on_submit(api_key_input, prompt_text): # Validate API key format if not api_key_input or len(api_key_input) < 20 or not api_key_input.startswith("sk-"): return None, "⚠️ Please provide a valid OpenAI API key", gr.update(visible=False) try: # Generate custom app via API response, api_error = call_openai_api(api_key_input, prompt_text) if api_error: return None, f"⚠️ {api_error}", gr.update(visible=False) # Extract code blocks code_blocks = extract_code_blocks(response) if not code_blocks: return None, "⚠️ No valid code found in the response", gr.update(visible=False) code = code_blocks[0] # Try to load the app app, load_error = load_generated_app(code) if load_error: # If there's an error, fallback to built-in templates fallback_code = generate_compatible_code(prompt_text) app, fallback_error = load_generated_app(fallback_code) if fallback_error: return fallback_code, f"⚠️ Error loading app: {fallback_error}", gr.update(visible=False) return fallback_code, "✅ App generated from template (API generation failed)", gr.update(visible=True, value=app) # Success! return code, "✅ App generated successfully!", gr.update(visible=True, value=app) except Exception as e: error_details = traceback.format_exc() # Try fallback try: fallback_code = generate_compatible_code(prompt_text) app, fallback_error = load_generated_app(fallback_code) if fallback_error: return None, f"⚠️ Error: {str(e)}\n\nFallback also failed: {fallback_error}", gr.update(visible=False) return fallback_code, "✅ App generated from template (after error recovery)", gr.update(visible=True, value=app) except: return None, f"⚠️ Error: {str(e)}\n{error_details}", gr.update(visible=False) def on_skip_api(): """Generate an app without using the API""" app_code = generate_compatible_code(prompt.value) try: app, error = load_generated_app(app_code) if error: return app_code, f"⚠️ Error loading template: {error}", gr.update(visible=False) return app_code, "✅ App generated from built-in template", gr.update(visible=True, value=app) except Exception as e: return app_code, f"⚠️ Error: {str(e)}", gr.update(visible=False) submit_btn.click( on_submit, inputs=[api_key, prompt], outputs=[code_output, status_output, generated_app_container] ) skip_api_btn.click( on_skip_api, inputs=[], outputs=[code_output, status_output, generated_app_container] ) if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)