Spaces:
Sleeping
Sleeping
import streamlit as st | |
import gradio as gr | |
import subprocess | |
import tempfile | |
import os | |
import time | |
import signal | |
import requests | |
import re | |
import json | |
import sys | |
from pathlib import Path | |
import atexit | |
# Print version info | |
st.set_page_config( | |
page_title="Gradio App Generator", | |
page_icon="🤖", | |
layout="wide" | |
) | |
# Directory to store temporary apps | |
TEMP_DIR = Path(tempfile.gettempdir()) / "gradio_apps" | |
os.makedirs(TEMP_DIR, exist_ok=True) | |
# Track running processes | |
if 'process' not in st.session_state: | |
st.session_state.process = None | |
st.session_state.app_port = None | |
st.session_state.app_path = None | |
# Clean up on exit | |
def cleanup(): | |
if st.session_state.process and st.session_state.process.poll() is None: | |
st.session_state.process.terminate() | |
try: | |
st.session_state.process.wait(timeout=5) | |
except subprocess.TimeoutExpired: | |
st.session_state.process.kill() | |
# Clean up temp files | |
if st.session_state.app_path and os.path.exists(st.session_state.app_path): | |
try: | |
os.unlink(st.session_state.app_path) | |
except: | |
pass | |
atexit.register(cleanup) | |
def stop_running_app(): | |
"""Stop the currently running Gradio app""" | |
if st.session_state.process and st.session_state.process.poll() is None: | |
st.session_state.process.terminate() | |
try: | |
st.session_state.process.wait(timeout=5) | |
except subprocess.TimeoutExpired: | |
st.session_state.process.kill() | |
st.session_state.process = None | |
st.session_state.app_port = None | |
if st.session_state.app_path and os.path.exists(st.session_state.app_path): | |
try: | |
os.unlink(st.session_state.app_path) | |
except: | |
pass | |
st.session_state.app_path = None | |
return True | |
return False | |
def get_openai_code(api_key, description): | |
"""Get code from OpenAI API""" | |
prompt = f"""Create a simple Gradio app that {description}. | |
IMPORTANT: The app should: | |
1. Use gr.Interface (not Blocks) | |
2. Have flagging_callback=None to avoid permission issues | |
3. Include demo.launch(server_name="0.0.0.0", server_port=PORT) at the end | |
4. Be self-contained with only standard libraries | |
Provide ONLY Python code with no explanation.""" | |
try: | |
response = requests.post( | |
"https://api.openai.com/v1/chat/completions", | |
headers={ | |
"Content-Type": "application/json", | |
"Authorization": f"Bearer {api_key}" | |
}, | |
json={ | |
"model": "gpt-4o", | |
"messages": [ | |
{"role": "system", "content": "You are a Gradio expert. Provide only Python code without explanations."}, | |
{"role": "user", "content": prompt} | |
], | |
"temperature": 0.2 | |
}, | |
timeout=30 | |
) | |
if response.status_code != 200: | |
return None, f"API Error: {response.status_code}" | |
content = response.json()["choices"][0]["message"]["content"] | |
# Extract code blocks if present | |
code_pattern = r'```python\s*([\s\S]*?)```' | |
code_matches = re.findall(code_pattern, content) | |
if code_matches: | |
return code_matches[0], None | |
# If no code blocks found, use the whole content | |
return content, None | |
except Exception as e: | |
return None, f"Error: {str(e)}" | |
def run_gradio_app(code, port=8050): | |
"""Run a Gradio app with the given code""" | |
# Stop any existing app | |
stop_running_app() | |
# Replace PORT in the code with the actual port | |
code = code.replace("PORT", str(port)) | |
# Make sure flagging is disabled | |
if "gr.Interface" in code and "flagging_callback=None" not in code: | |
code = code.replace("gr.Interface(", "gr.Interface(flagging_callback=None, ") | |
# Create a temporary file | |
fd, path = tempfile.mkstemp(suffix='.py', dir=TEMP_DIR) | |
with os.fdopen(fd, 'w') as f: | |
f.write(code) | |
st.session_state.app_path = path | |
# Run the app as a subprocess | |
try: | |
process = subprocess.Popen([sys.executable, path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
st.session_state.process = process | |
st.session_state.app_port = port | |
# Wait a bit for the app to start | |
time.sleep(3) | |
# Check if process is still running | |
if process.poll() is not None: | |
stdout, stderr = process.communicate() | |
return False, f"Failed to start app: {stderr.decode('utf-8')}" | |
return True, None | |
except Exception as e: | |
return False, f"Error starting app: {str(e)}" | |
# Predefined Gradio app templates | |
TEMPLATES = { | |
"hello_world": """ | |
import gradio as gr | |
def greet(name): | |
return f"Hello, {name}!" | |
demo = gr.Interface( | |
fn=greet, | |
inputs=gr.Textbox(label="Name"), | |
outputs=gr.Textbox(label="Greeting"), | |
title="Hello World App", | |
flagging_callback=None | |
) | |
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="Simple Calculator", | |
flagging_callback=None | |
) | |
demo.launch(server_name="0.0.0.0", server_port=PORT) | |
""", | |
"image_filter": """ | |
import gradio as gr | |
import numpy as np | |
def apply_filter(image, filter_type): | |
if image is None: | |
return None | |
if filter_type == "Grayscale": | |
return np.mean(image, axis=2).astype(np.uint8) | |
elif filter_type == "Invert": | |
return 255 - image | |
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 = image.dot(sepia.T) | |
sepia_img[sepia_img > 255] = 255 | |
return sepia_img.astype(np.uint8) | |
return image | |
demo = gr.Interface( | |
fn=apply_filter, | |
inputs=[ | |
gr.Image(type="numpy"), | |
gr.Radio(["Grayscale", "Invert", "Sepia"], label="Filter") | |
], | |
outputs=gr.Image(type="numpy"), | |
title="Image Filter App", | |
flagging_callback=None | |
) | |
demo.launch(server_name="0.0.0.0", server_port=PORT) | |
""", | |
"text_analysis": """ | |
import gradio as gr | |
def analyze_text(text): | |
if not text: | |
return "Please enter some text" | |
char_count = len(text) | |
word_count = len(text.split()) | |
line_count = len(text.splitlines()) | |
return f"Characters: {char_count}\\nWords: {word_count}\\nLines: {line_count}" | |
demo = gr.Interface( | |
fn=analyze_text, | |
inputs=gr.Textbox(label="Enter Text", lines=5), | |
outputs=gr.Textbox(label="Analysis"), | |
title="Text Analysis Tool", | |
flagging_callback=None | |
) | |
demo.launch(server_name="0.0.0.0", server_port=PORT) | |
""" | |
} | |
# Streamlit UI | |
st.title("🤖 Gradio App Generator") | |
tab1, tab2 = st.tabs(["Built-in Templates", "Custom Generator"]) | |
# Built-in templates tab | |
with tab1: | |
st.header("Generate from Templates") | |
template_choice = st.selectbox( | |
"Select a template", | |
["hello_world", "calculator", "image_filter", "text_analysis"], | |
format_func=lambda x: { | |
"hello_world": "Hello World", | |
"calculator": "Simple Calculator", | |
"image_filter": "Image Filter", | |
"text_analysis": "Text Analysis" | |
}[x] | |
) | |
if st.button("Generate from Template"): | |
code = TEMPLATES[template_choice] | |
success, error = run_gradio_app(code) | |
if success: | |
st.success("App started successfully!") | |
else: | |
st.error(f"Failed to start app: {error}") | |
st.code(code, language="python") | |
# Custom generator tab | |
with tab2: | |
st.header("Generate Custom App") | |
api_key = st.text_input("OpenAI API Key", type="password", help="Your OpenAI API key") | |
app_description = st.text_area("Describe the app you want", height=100) | |
if st.button("Generate Custom App"): | |
if not api_key or len(api_key) < 20: | |
st.error("Please enter a valid OpenAI API key") | |
elif not app_description: | |
st.error("Please enter a description for your app") | |
else: | |
with st.spinner("Generating app..."): | |
code, error = get_openai_code(api_key, app_description) | |
if error: | |
st.error(f"Error generating code: {error}") | |
else: | |
success, run_error = run_gradio_app(code) | |
if success: | |
st.success("App started successfully!") | |
else: | |
st.error(f"Failed to start app: {run_error}") | |
st.code(code, language="python") | |
# Display the currently running app | |
st.header("Running App") | |
if st.session_state.app_port: | |
# Create an iframe to display the app | |
st.components.v1.iframe( | |
src=f"http://localhost:{st.session_state.app_port}", | |
height=600, | |
scrolling=True | |
) | |
if st.button("Stop App"): | |
if stop_running_app(): | |
st.success("App stopped successfully") | |
st.experimental_rerun() | |
else: | |
st.info("No app is currently running. Generate an app first.") |