nakas's picture
Update app.py
ef388e2 verified
raw
history blame
14.7 kB
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)