Spaces:
Sleeping
Sleeping
import gradio as gr | |
import tempfile | |
import os | |
import sys | |
import subprocess | |
import time | |
import random | |
import string | |
import signal | |
import atexit | |
# Set environment variable to avoid matplotlib issues | |
os.environ['MPLCONFIGDIR'] = '/tmp' | |
# Create a temp directory for our app files | |
TEMP_DIR = os.path.join(tempfile.gettempdir(), "gradio_apps") | |
os.makedirs(TEMP_DIR, exist_ok=True) | |
# Track running processes | |
running_process = None | |
current_port = None | |
current_file = None | |
# Cleanup function to ensure we don't leave processes running | |
def cleanup(): | |
global running_process, current_file | |
if running_process and running_process.poll() is None: | |
try: | |
running_process.terminate() | |
running_process.wait(timeout=5) | |
except: | |
running_process.kill() | |
if current_file and os.path.exists(current_file): | |
try: | |
os.unlink(current_file) | |
except: | |
pass | |
# Register cleanup | |
atexit.register(cleanup) | |
# Example Gradio app codes to choose from | |
EXAMPLE_APPS = { | |
"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 App", | |
description="A simple greeting app" | |
) | |
# Launch on specified port | |
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 App", | |
description="Perform basic arithmetic operations" | |
) | |
# Launch on specified port | |
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 App", | |
description="Apply different filters to your images" | |
) | |
# Launch on specified port | |
demo.launch(server_name="0.0.0.0", server_port=PORT) | |
""" | |
} | |
# Function to find an available port | |
def find_available_port(start=7870): | |
import socket | |
port = start | |
while True: | |
try: | |
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: | |
s.bind(('localhost', port)) | |
return port | |
except OSError: | |
port += 1 | |
# Function to run a Gradio app as a subprocess | |
def run_app(app_code, port): | |
global running_process, current_file | |
# Stop any existing app | |
stop_app() | |
# Replace PORT in the code | |
app_code = app_code.replace("PORT", str(port)) | |
# Create a temporary file | |
fd, filepath = tempfile.mkstemp(suffix='.py', dir=TEMP_DIR) | |
os.close(fd) | |
with open(filepath, 'w') as f: | |
f.write(app_code) | |
# Store the current file path | |
current_file = filepath | |
# Run the app | |
try: | |
process = subprocess.Popen( | |
[sys.executable, filepath], | |
stdout=subprocess.PIPE, | |
stderr=subprocess.PIPE | |
) | |
# Store the process | |
running_process = process | |
# Wait a moment for the app to start | |
time.sleep(2) | |
# Check if the process is still running | |
if process.poll() is not None: | |
# Process failed to start | |
stdout, stderr = process.communicate() | |
error_msg = f"App failed to start: {stderr.decode('utf-8')}" | |
return None, error_msg | |
return port, None | |
except Exception as e: | |
return None, f"Error starting app: {str(e)}" | |
# Function to stop the running app | |
def stop_app(): | |
global running_process, current_file | |
if running_process and running_process.poll() is None: | |
running_process.terminate() | |
try: | |
running_process.wait(timeout=5) | |
except: | |
running_process.kill() | |
if current_file and os.path.exists(current_file): | |
try: | |
os.unlink(current_file) | |
except: | |
pass | |
running_process = None | |
current_file = None | |
# Function to select an app based on description | |
def select_app(description): | |
description = description.lower() | |
if "hello" in description or "greet" in description: | |
return EXAMPLE_APPS["hello_world"] | |
elif "calculat" in description or "math" in description or "arithmetic" in description: | |
return EXAMPLE_APPS["calculator"] | |
elif "image" in description or "filter" in description or "photo" in description: | |
return EXAMPLE_APPS["image_filter"] | |
else: | |
# Default to hello world | |
return EXAMPLE_APPS["hello_world"] | |
# Main Gradio interface | |
with gr.Blocks(title="Gradio App Generator") as demo: | |
gr.Markdown("# π Dynamic Gradio App Generator") | |
gr.Markdown("Select an app type to generate and run it dynamically") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
# Input area | |
app_description = gr.Textbox( | |
label="App Description", | |
placeholder="Describe the app you want to generate...", | |
lines=3, | |
value="A calculator app that performs basic arithmetic" | |
) | |
# Example buttons | |
with gr.Row(): | |
hello_btn = gr.Button("Hello World") | |
calc_btn = gr.Button("Calculator") | |
image_btn = gr.Button("Image Filter") | |
# Generate and stop buttons | |
with gr.Row(): | |
generate_btn = gr.Button("Generate & Run App", variant="primary") | |
stop_btn = gr.Button("Stop App", variant="stop") | |
# Code display | |
with gr.Accordion("Generated Code", open=False): | |
code_display = gr.Code(language="python") | |
# Status message | |
status_msg = gr.Markdown("") | |
with gr.Column(scale=2): | |
# Preview area | |
app_frame = gr.HTML("<div style='border:1px dashed #ccc; height:500px; display:flex; justify-content:center; align-items:center;'><p>App will appear here</p></div>") | |
# Example button handlers | |
def set_description(desc): | |
return desc | |
hello_btn.click( | |
lambda: set_description("A hello world app that greets the user by name"), | |
inputs=None, | |
outputs=app_description | |
) | |
calc_btn.click( | |
lambda: set_description("A calculator app that performs basic arithmetic"), | |
inputs=None, | |
outputs=app_description | |
) | |
image_btn.click( | |
lambda: set_description("An image filter app that can apply effects to photos"), | |
inputs=None, | |
outputs=app_description | |
) | |
# Generate button handler | |
def on_generate(description): | |
if not description: | |
return None, "Please enter a description", "<div style='border:1px dashed #ccc; height:500px; display:flex; justify-content:center; align-items:center;'><p>Enter a description first</p></div>" | |
# Select app based on description | |
app_code = select_app(description) | |
# Find an available port | |
port = find_available_port() | |
# Run the app | |
result_port, error = run_app(app_code, port) | |
if error: | |
return app_code, f"Error: {error}", "<div style='border:1px solid #f44336; height:500px; display:flex; justify-content:center; align-items:center;'><p>Failed to start app:<br>{error}</p></div>" | |
# Create iframe to show the app | |
iframe_html = f""" | |
<div style="border:1px solid #ddd; height:500px; overflow:hidden;"> | |
<iframe src="http://localhost:{result_port}" width="100%" height="100%" frameborder="0"></iframe> | |
</div> | |
""" | |
return app_code, f"β App running on port {result_port}", iframe_html | |
# Stop button handler | |
def on_stop(): | |
stop_app() | |
return "β App stopped", "<div style='border:1px dashed #ccc; height:500px; display:flex; justify-content:center; align-items:center;'><p>App stopped</p></div>" | |
# Connect buttons to handlers | |
generate_btn.click( | |
on_generate, | |
inputs=app_description, | |
outputs=[code_display, status_msg, app_frame] | |
) | |
stop_btn.click( | |
on_stop, | |
inputs=None, | |
outputs=[status_msg, app_frame] | |
) | |
# Launch the main app | |
if __name__ == "__main__": | |
demo.launch(server_name="0.0.0.0", server_port=7860) |