nakas's picture
Update app.py
07aeb52 verified
raw
history blame
9.94 kB
import gradio as gr
import os
import tempfile
import requests
import subprocess
import re
import time
import sys
# Global variables to track resources
app_process = None
temp_file_path = None
def cleanup():
"""Clean up resources when the app exits"""
global app_process, temp_file_path
if app_process and app_process.poll() is None:
print("Stopping running process...")
app_process.terminate()
time.sleep(1)
if app_process.poll() is None:
app_process.kill()
if temp_file_path and os.path.exists(temp_file_path):
print(f"Removing temp file: {temp_file_path}")
try:
os.unlink(temp_file_path)
except Exception as e:
print(f"Error removing temp file: {e}")
# Register cleanup function to run at exit
import atexit
atexit.register(cleanup)
def get_app_code(api_key, description):
"""Get app code from the OpenAI API"""
prompt = f"""Create a simple Gradio app that {description}.
VERY IMPORTANT: You MUST include this to disable flagging which creates permission errors:
gr.Interface(..., flagging_callback=None)
The app should:
1. Use gr.Interface with flagging_callback=None
2. Be self-contained and not use any external dependencies
3. Use only Python standard library and NumPy/Pandas if needed
4. Include demo.launch(server_name="0.0.0.0", server_port=7861) at the end
5. Do NOT create any directories or write any files
Provide ONLY Python code with no explanation or markdown."""
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
}
)
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 ensure_flagging_disabled(code):
"""Ensure flagging is disabled in the code"""
# Check if flagging_callback=None is present in Interface creation
if 'Interface(' in code and 'flagging_callback=None' not in code:
# Insert flagging_callback=None in the Interface parameters
code = code.replace('Interface(', 'Interface(flagging_callback=None, ')
return code
def run_gradio_app(code):
"""Save the code to a temp file and run it as a subprocess"""
global app_process, temp_file_path
# Stop any existing process
if app_process and app_process.poll() is None:
app_process.terminate()
time.sleep(1)
if app_process.poll() is None:
app_process.kill()
# Remove any existing temp file
if temp_file_path and os.path.exists(temp_file_path):
try:
os.unlink(temp_file_path)
except:
pass
# Create a new temp file
fd, temp_file_path = tempfile.mkstemp(suffix='.py')
os.close(fd)
# Ensure flagging is disabled
modified_code = ensure_flagging_disabled(code)
# Write code to file
with open(temp_file_path, 'w') as f:
f.write(modified_code)
# Run the app as a subprocess
try:
app_process = subprocess.Popen(
[sys.executable, temp_file_path],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
# Wait a moment for the app to start
time.sleep(3)
# Check if process is still running
if app_process.poll() is not None:
# Get error output
_, stderr = app_process.communicate()
error_msg = stderr.decode('utf-8')
return False, f"App failed to start:\n{error_msg}"
return True, None
except Exception as e:
return False, f"Error launching app: {str(e)}"
# Create demo app for direct usage
def make_demo_app(app_type):
"""Create a simple demo app based on type"""
if app_type == "calculator":
return """
import gradio as gr
import numpy as np
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":
return num1 / num2 if num2 != 0 else "Error: Division by zero"
else:
return "Invalid operation"
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=7861)
"""
elif app_type == "image":
return """
import gradio as gr
import numpy as np
from PIL import Image
def grayscale(img):
gray_img = np.mean(img, axis=2).astype(np.uint8)
return gray_img
demo = gr.Interface(
fn=grayscale,
inputs=gr.Image(type="numpy"),
outputs=gr.Image(type="numpy"),
title="Image Grayscale Converter",
flagging_callback=None
)
demo.launch(server_name="0.0.0.0", server_port=7861)
"""
else: # Default hello world
return """
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",
flagging_callback=None
)
demo.launch(server_name="0.0.0.0", server_port=7861)
"""
# Create a very simple Gradio interface
with gr.Blocks() as demo:
gr.Markdown("# 🤖 Simple Gradio App Generator")
with gr.Tab("Generate Custom App"):
api_key = gr.Textbox(label="OpenAI API Key", placeholder="sk-...", type="password")
description = gr.Textbox(label="Describe the app you want", lines=3)
generate_btn = gr.Button("Generate & Run App")
with gr.Tab("Quick Demo Apps"):
demo_type = gr.Radio(
["hello", "calculator", "image"],
label="Select Demo App",
value="hello"
)
demo_btn = gr.Button("Run Demo App")
with gr.Row():
stop_btn = gr.Button("Stop Running App", visible=False)
code_display = gr.Code(label="Generated Code", language="python")
status = gr.Markdown("")
# Frame to display the running app
app_display = gr.HTML("<div style='text-align:center; margin-top:20px;'>App will appear here</div>")
def generate_and_run(key, desc):
if not key or len(key) < 20:
return None, "Please enter a valid API key", gr.update(visible=False), gr.update(visible=False)
# Get code from API
code, error = get_app_code(key, desc)
if error:
return None, f"Error: {error}", gr.update(visible=False), gr.update(visible=False)
# Run the app
success, run_error = run_gradio_app(code)
if not success:
return code, f"Error running app: {run_error}", gr.update(visible=False), gr.update(visible=False)
# Create iframe to show the app
iframe = f"""
<div style="border:1px solid #ddd; border-radius:5px; height:500px; margin-top:10px;">
<iframe src="http://localhost:7861" width="100%" height="100%" frameborder="0"></iframe>
</div>
"""
return code, "✅ App is running! View it below:", iframe, gr.update(visible=True)
def run_demo(app_type):
code = make_demo_app(app_type)
success, run_error = run_gradio_app(code)
if not success:
return code, f"Error running demo: {run_error}", gr.update(visible=False), gr.update(visible=False)
# Create iframe to show the app
iframe = f"""
<div style="border:1px solid #ddd; border-radius:5px; height:500px; margin-top:10px;">
<iframe src="http://localhost:7861" width="100%" height="100%" frameborder="0"></iframe>
</div>
"""
return code, "✅ Demo app is running! View it below:", iframe, gr.update(visible=True)
def stop_app():
global app_process
if app_process and app_process.poll() is None:
app_process.terminate()
time.sleep(1)
if app_process.poll() is None:
app_process.kill()
return "App stopped", "<div style='text-align:center; margin-top:20px;'>App stopped</div>", gr.update(visible=False)
generate_btn.click(
generate_and_run,
inputs=[api_key, description],
outputs=[code_display, status, app_display, stop_btn]
)
demo_btn.click(
run_demo,
inputs=[demo_type],
outputs=[code_display, status, app_display, stop_btn]
)
stop_btn.click(
stop_app,
inputs=[],
outputs=[status, app_display, stop_btn]
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)