Spaces:
Sleeping
Sleeping
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( | |
"""<div style="display:flex; justify-content:center; align-items:center; height:600px; border:1px dashed #ccc; border-radius:8px;"> | |
<div style="text-align:center;"> | |
<h3>App Preview</h3> | |
<p>Generate an app to see it here</p> | |
</div> | |
</div>""" | |
) | |
# 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""" | |
<div style="height:600px; border:1px solid #ddd; border-radius:8px; overflow:hidden;"> | |
<iframe src="http://localhost:{port}" width="100%" height="100%" frameborder="0"></iframe> | |
</div> | |
""" | |
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 = """ | |
<div style="display:flex; justify-content:center; align-items:center; height:600px; border:1px dashed #ccc; border-radius:8px;"> | |
<div style="text-align:center;"> | |
<h3>App Stopped</h3> | |
<p>Generate a new app to see it here</p> | |
</div> | |
</div> | |
""" | |
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) |