Spaces:
Sleeping
Sleeping
import gradio as gr | |
import os | |
import json | |
import importlib | |
import sys | |
from contextlib import redirect_stdout, redirect_stderr | |
import io | |
# Set environment variable to avoid matplotlib permission issues | |
os.environ['MPLCONFIGDIR'] = '/tmp' | |
# Example app implementations | |
APP_REGISTRY = { | |
"hello_world": { | |
"title": "Hello World", | |
"description": "A simple greeting app", | |
"function": None # will be populated | |
}, | |
"calculator": { | |
"title": "Calculator", | |
"description": "A basic arithmetic calculator", | |
"function": None # will be populated | |
}, | |
"image_filter": { | |
"title": "Image Filter", | |
"description": "Apply visual effects to images", | |
"function": None # will be populated | |
} | |
} | |
# Hello World implementation | |
def create_hello_world(): | |
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", | |
examples=[["World"], ["Friend"], ["Gradio"]] | |
) | |
return demo | |
# Calculator implementation | |
def create_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 | |
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", | |
examples=[ | |
[5, 3, "Add"], | |
[10, 4, "Subtract"], | |
[6, 7, "Multiply"], | |
[20, 4, "Divide"] | |
] | |
) | |
return demo | |
# Image Filter implementation | |
def create_image_filter(): | |
def apply_filter(image, filter_type): | |
if image is None: | |
return None | |
import numpy as np | |
from PIL import Image | |
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", | |
examples=[ | |
["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "Grayscale"], | |
["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "Invert"], | |
["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "Sepia"] | |
] | |
) | |
return demo | |
# Register demo creation functions | |
APP_REGISTRY["hello_world"]["function"] = create_hello_world | |
APP_REGISTRY["calculator"]["function"] = create_calculator | |
APP_REGISTRY["image_filter"]["function"] = create_image_filter | |
# Example of code for each app as a string (for display purposes) | |
APP_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 App", | |
description="A simple greeting app", | |
examples=[["World"], ["Friend"], ["Gradio"]] | |
) | |
""", | |
"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", | |
examples=[ | |
[5, 3, "Add"], | |
[10, 4, "Subtract"], | |
[6, 7, "Multiply"], | |
[20, 4, "Divide"] | |
] | |
) | |
""", | |
"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", | |
examples=[ | |
["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "Grayscale"], | |
["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "Invert"], | |
["https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=500", "Sepia"] | |
] | |
) | |
""" | |
} | |
# Create an endpoint to get the app configuration | |
def get_app_config(app_name): | |
if app_name not in APP_REGISTRY: | |
return {"error": f"App '{app_name}' not found"} | |
return { | |
"title": APP_REGISTRY[app_name]["title"], | |
"description": APP_REGISTRY[app_name]["description"], | |
"code": APP_CODES[app_name] | |
} | |
# Create an endpoint to load an app | |
def load_app_interface(app_name): | |
if app_name not in APP_REGISTRY: | |
return None | |
try: | |
# Capture stdout/stderr to prevent it from polluting the response | |
stdout_buffer = io.StringIO() | |
stderr_buffer = io.StringIO() | |
with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer): | |
app = APP_REGISTRY[app_name]["function"]() | |
return app | |
except Exception as e: | |
return None | |
# Main app with dynamic loading capabilities | |
def create_main_app(): | |
with gr.Blocks(title="Dynamic Gradio App Generator", css="#app-container { min-height: 400px; }") as demo: | |
gr.Markdown("# 🔄 Dynamic Gradio App Generator") | |
gr.Markdown("Select an app type to load it without refreshing the page") | |
# Create a state variable to track the current app | |
current_app = gr.State("none") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
# App selection area | |
gr.Markdown("### Choose an App Template") | |
app_selection = gr.Radio( | |
choices=list(APP_REGISTRY.keys()), | |
value="hello_world", | |
label="Available Templates", | |
info="Select a template to view and run it", | |
interactive=True | |
) | |
# Description display | |
app_description = gr.Markdown(f"**{APP_REGISTRY['hello_world']['title']}**: {APP_REGISTRY['hello_world']['description']}") | |
# Load button | |
load_btn = gr.Button("Load Selected App", variant="primary") | |
# Code display | |
with gr.Accordion("View Code", open=False): | |
code_display = gr.Code( | |
language="python", | |
value=APP_CODES["hello_world"], | |
label="App Code" | |
) | |
# Status message | |
status_msg = gr.Markdown("Select an app and click 'Load Selected App'") | |
with gr.Column(scale=2): | |
# App container (where the dynamic app will be loaded) | |
app_container = gr.HTML( | |
value="<div id='app-container'><p>No app loaded yet. Select an app template and click 'Load Selected App'.</p></div>", | |
label="App Preview" | |
) | |
# Update description and code when selection changes | |
def update_description_and_code(selection): | |
config = get_app_config(selection) | |
return ( | |
f"**{config['title']}**: {config['description']}", | |
config['code'] | |
) | |
app_selection.change( | |
update_description_and_code, | |
inputs=app_selection, | |
outputs=[app_description, code_display] | |
) | |
# Function to dynamically load the selected app | |
def load_selected_app(app_name): | |
try: | |
# Clear the previous app | |
gr.update(value="<div id='app-container'><p>Loading app...</p></div>") | |
# Create a new app instance | |
selected_app = load_app_interface(app_name) | |
if selected_app is None: | |
return ( | |
gr.update(value="<div id='app-container'><p>Error loading app. Please try again.</p></div>"), | |
f"Error: Could not load {APP_REGISTRY[app_name]['title']}", | |
app_name | |
) | |
# Generate a unique ID for this app instance | |
app_id = f"app-{app_name}-{id(selected_app)}" | |
# Create a custom JavaScript function that will inject the app | |
js_code = f""" | |
<div id="{app_id}-container"> | |
<p>Loading {APP_REGISTRY[app_name]['title']}...</p> | |
</div> | |
<script> | |
(function() {{ | |
const appContainer = document.getElementById('{app_id}-container'); | |
// Create a timer to check when Gradio is fully loaded | |
const checkInterval = setInterval(() => {{ | |
if (window.gradio_config && window.gradioApp) {{ | |
clearInterval(checkInterval); | |
// Create a temporary element to mount the app | |
const tempElement = document.createElement('div'); | |
document.body.appendChild(tempElement); | |
// Move the app to our container | |
setTimeout(() => {{ | |
try {{ | |
// Find the app elements with the right ID | |
const appElements = Array.from( | |
document.querySelectorAll( | |
`.gradio-container[id^='{app_id}']` | |
) | |
); | |
if (appElements.length > 0) {{ | |
// Move the app to our container | |
appContainer.innerHTML = ''; | |
appElements.forEach(el => {{ | |
appContainer.appendChild(el); | |
}}); | |
}} else {{ | |
appContainer.innerHTML = '<p>App loaded but could not be displayed. Please refresh the page.</p>'; | |
}} | |
}} catch (e) {{ | |
console.error('Error moving app:', e); | |
appContainer.innerHTML = '<p>Error loading app: ' + e.message + '</p>'; | |
}} | |
}}, 1000); | |
}} | |
}}, 100); | |
}})(); | |
</script> | |
""" | |
return ( | |
gr.update(value=js_code), | |
f"Successfully loaded {APP_REGISTRY[app_name]['title']}", | |
app_name | |
) | |
except Exception as e: | |
error_msg = str(e) | |
return ( | |
gr.update(value=f"<div id='app-container'><p>Error: {error_msg}</p></div>"), | |
f"Error: {error_msg}", | |
app_name | |
) | |
# Handle the load button click | |
load_btn.click( | |
load_selected_app, | |
inputs=app_selection, | |
outputs=[app_container, status_msg, current_app] | |
) | |
return demo | |
# Create and launch the main app | |
demo = create_main_app() | |
# Add endpoints for direct API access to apps | |
for app_name, app_info in APP_REGISTRY.items(): | |
app_func = app_info["function"] | |
if app_func: | |
app = app_func() | |
demo = gr.mount_gradio_app(demo, app, f"/{app_name}") | |
# Launch the app | |
if __name__ == "__main__": | |
demo.launch(server_name="0.0.0.0", server_port=7860) |