import gradio as gr import os import tempfile import time import subprocess import threading import signal import json import random import string # Set fixed MPLCONFIGDIR to avoid permission issues os.environ['MPLCONFIGDIR'] = '/tmp' # Create tmp directory if it doesn't exist TEMP_DIR = os.path.join(tempfile.gettempdir(), "gradio_apps") os.makedirs(TEMP_DIR, exist_ok=True) # Track running processes processes = {} # Sample code for different Gradio apps EXAMPLE_CODES = { "hello_world": """ import gradio as gr def greet(name): return f"Hello, {name}!" demo = gr.Interface( fn=greet, inputs=gr.Textbox(label="Your Name"), outputs=gr.Textbox(label="Greeting"), title="Hello World", description="A simple greeting app" ) demo.launch(server_name="0.0.0.0", server_port=PORT) """, "calculator": """ import gradio as gr 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 demo = gr.Interface( fn=calculate, inputs=[ gr.Number(label="First Number"), gr.Number(label="Second Number"), gr.Radio(["Add", "Subtract", "Multiply", "Divide"], label="Operation") ], outputs=gr.Textbox(label="Result"), title="Calculator", description="Perform basic arithmetic operations" ) demo.launch(server_name="0.0.0.0", server_port=PORT) """, "image_filter": """ import gradio as gr import numpy as np from PIL import Image def apply_filter(image, filter_type): if image is None: return None img_array = np.array(image) if filter_type == "Grayscale": result = np.mean(img_array, axis=2).astype(np.uint8) return Image.fromarray(result) elif filter_type == "Invert": result = 255 - img_array return Image.fromarray(result) elif filter_type == "Sepia": sepia = np.array([[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]) sepia_img = img_array.dot(sepia.T) sepia_img[sepia_img > 255] = 255 return Image.fromarray(sepia_img.astype(np.uint8)) return image demo = gr.Interface( fn=apply_filter, inputs=[ gr.Image(type="pil"), gr.Radio(["Grayscale", "Invert", "Sepia"], label="Filter") ], outputs=gr.Image(type="pil"), title="Image Filter", description="Apply various filters to images", allow_flagging=False ) demo.launch(server_name="0.0.0.0", server_port=PORT) """ } # Function to simulate LLM API call def simulate_llm_response(prompt): """Simulate an LLM response based on the prompt""" prompt_lower = prompt.lower() if "hello" in prompt_lower or "greet" in prompt_lower: return EXAMPLE_CODES["hello_world"], None elif "calculat" in prompt_lower or "math" in prompt_lower or "arithmetic" in prompt_lower: return EXAMPLE_CODES["calculator"], None elif "image" in prompt_lower or "filter" in prompt_lower or "photo" in prompt_lower: return EXAMPLE_CODES["image_filter"], None else: # Default to hello world return EXAMPLE_CODES["hello_world"], None # Find an available port def find_available_port(start_port=7870): """Find an available port starting from start_port""" import socket from contextlib import closing def is_port_available(port): with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: return sock.connect_ex(('localhost', port)) != 0 port = start_port while not is_port_available(port): port += 1 return port # Generate a random string def random_string(length=8): """Generate a random string of fixed length""" letters = string.ascii_lowercase return ''.join(random.choice(letters) for i in range(length)) # Function to run a Gradio app as a subprocess def run_gradio_app(code, app_id=None): """Run a Gradio app as a subprocess and return the port""" global processes # Clean up any previous process with the same ID if app_id in processes and processes[app_id]["process"].poll() is None: processes[app_id]["process"].terminate() try: processes[app_id]["process"].wait(timeout=5) except: processes[app_id]["process"].kill() # Remove the file try: os.unlink(processes[app_id]["file"]) except: pass # Generate a unique ID if not provided if app_id is None: app_id = random_string() # Find an available port port = find_available_port() # Replace PORT in the code with the actual port code = code.replace("PORT", str(port)) # Create a temporary file with tempfile.NamedTemporaryFile(suffix='.py', dir=TEMP_DIR, delete=False) as f: f.write(code.encode('utf-8')) file_path = f.name # Run the app as a subprocess try: process = subprocess.Popen( [sys.executable, file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) # Wait a moment for the app to start time.sleep(3) # Check if the process is still running if process.poll() is not None: stdout, stderr = process.communicate() return None, f"App failed to start (exit code: {process.returncode})\nStdout: {stdout.decode('utf-8')}\nStderr: {stderr.decode('utf-8')}" # Store the process and file path processes[app_id] = { "process": process, "file": file_path, "port": port } return port, None except Exception as e: import traceback return None, f"Error starting app: {str(e)}\n{traceback.format_exc()}" # Function to stop a running app def stop_gradio_app(app_id): """Stop a running Gradio app""" global processes if app_id in processes: process = processes[app_id]["process"] file_path = processes[app_id]["file"] if process.poll() is None: process.terminate() try: process.wait(timeout=5) except: process.kill() # Remove the file try: os.unlink(file_path) except: pass del processes[app_id] return True return False # Clean up on exit def cleanup(): """Clean up all running processes and temporary files""" for app_id in list(processes.keys()): stop_gradio_app(app_id) import atexit atexit.register(cleanup) # Import sys after we've defined all the functions import sys # Main Gradio interface with gr.Blocks(title="LLM Gradio App Generator") as demo: # Header gr.Markdown("# 🤖 LLM Gradio App Generator") gr.Markdown("Generate and run Gradio apps dynamically!") # App ID for tracking the current app app_id = gr.State("") with gr.Row(): # Left column (input) with gr.Column(scale=1): # App description input prompt = gr.Textbox( label="Describe the app you want", placeholder="e.g., A calculator app that can perform basic arithmetic", lines=3 ) # Example buttons gr.Markdown("### Try These Examples:") with gr.Row(): hello_btn = gr.Button("Hello World") calc_btn = gr.Button("Calculator") image_btn = gr.Button("Image Filter") # Generate button with gr.Row(): generate_btn = gr.Button("Generate & Run App", variant="primary") stop_btn = gr.Button("Stop App", variant="stop") # Display the generated code with gr.Accordion("Generated Code", open=False): code_output = gr.Code(language="python", label="Python Code") # Status message status_output = gr.Markdown("Enter a description and click 'Generate & Run App'") # Right column (output) with gr.Column(scale=2): # Frame to display the running app app_frame = gr.HTML( """

App Preview

Generate an app to see it here

""" ) # Example button functions def use_example(example_text): return example_text hello_btn.click( lambda: use_example("A simple hello world app that greets the user by name"), inputs=None, outputs=prompt ) calc_btn.click( lambda: use_example("A calculator app that can add, subtract, multiply and divide two numbers"), inputs=None, outputs=prompt ) image_btn.click( lambda: use_example("An image filter app that can apply grayscale, invert, and sepia filters to images"), inputs=None, outputs=prompt ) # Generate and run the app def on_generate_click(prompt_text, current_app_id): if not prompt_text: return current_app_id, "", "Please enter a description of the app you want to generate.", app_frame.value # Stop the current app if running if current_app_id: stop_gradio_app(current_app_id) # Generate a new app ID new_app_id = random_string() # Get code from LLM (simulated) code, error = simulate_llm_response(prompt_text) if error: return current_app_id, "", f"Error generating code: {error}", app_frame.value # Run the app port, run_error = run_gradio_app(code, new_app_id) if run_error: return current_app_id, code, f"Error running app: {run_error}", app_frame.value # Create an iframe to display the app iframe_html = f"""
""" return new_app_id, code, f"✅ App running on port {port}", iframe_html # Stop the app def on_stop_click(current_app_id): if not current_app_id: return "", "No app is currently running" stopped = stop_gradio_app(current_app_id) if stopped: # Reset the frame iframe_html = """

App Stopped

Generate a new app to see it here

""" return "", f"✅ App stopped successfully", iframe_html else: return current_app_id, "Failed to stop the app", app_frame.value # Connect the generate button generate_btn.click( on_generate_click, inputs=[prompt, app_id], outputs=[app_id, code_output, status_output, app_frame] ) # Connect the stop button stop_btn.click( on_stop_click, inputs=[app_id], outputs=[app_id, status_output, app_frame] ) # Launch the main app if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860)