nakas's picture
Update app.py
6e19f63 verified
raw
history blame
10.8 kB
import gradio as gr
import requests
import re
import tempfile
import importlib.util
import sys
import os
import ast
def call_openai_api(api_key, prompt):
"""Direct API call to OpenAI"""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
# Determine Gradio version to ensure compatibility
gradio_version = gr.__version__
major_version = int(gradio_version.split('.')[0])
system_prompt = f"""You are an expert Gradio developer.
Create a standalone Gradio application based on the user's prompt.
Your response should ONLY include Python code without any explanation.
IMPORTANT: You must use Gradio version {gradio_version} (Gradio {major_version}.x) syntax.
For Gradio 3.x: Use the `.click()` method on buttons and elements to connect them to functions.
For Gradio 4.x: Use the event subscription pattern instead of .click().
The code must:
1. Import all necessary libraries
2. Define a complete, functional Gradio interface
3. DO NOT include a launch command or if __name__ == "__main__" block
4. The interface should be assigned to a variable named 'demo'
5. Handle errors gracefully
6. Be completely self-contained in a single script
Example for Gradio 3.x:
```python
import gradio as gr
def greet(name):
return f"Hello, {name}!"
with gr.Blocks() as demo:
name_input = gr.Textbox(label="Your Name")
greet_btn = gr.Button("Greet")
output = gr.Textbox(label="Output")
greet_btn.click(fn=greet, inputs=name_input, outputs=output)
```
"""
data = {
"model": "gpt-4o",
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": prompt}
],
"temperature": 0.2,
"max_tokens": 4000
}
response = requests.post(
"https://api.openai.com/v1/chat/completions",
headers=headers,
json=data
)
if response.status_code != 200:
return None, f"API Error: {response.status_code} - {response.text}"
result = response.json()
return result["choices"][0]["message"]["content"], None
def extract_code_blocks(text):
"""Extract code blocks from markdown"""
pattern = r'```(?:python)?\s*([\s\S]*?)```'
matches = re.findall(pattern, text)
if not matches and text.strip():
if re.search(r'import\s+\w+|def\s+\w+\(|class\s+\w+:|if\s+__name__\s*==\s*[\'"]__main__[\'"]:', text):
return [text.strip()]
return [match.strip() for match in matches]
def validate_gradio_code(code):
"""Basic validation of the generated code"""
try:
tree = ast.parse(code)
allowed_modules = ['gradio', 'numpy', 'pandas', 'matplotlib', 'PIL', 'os', 'io', 'base64',
'time', 'datetime', 'json', 'random', 'math', 'sys', 're', 'pathlib',
'collections', 'typing', 'warnings']
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for name in node.names:
if name.name not in allowed_modules:
return False, f"Unauthorized import: {name.name}"
elif isinstance(node, ast.ImportFrom):
if node.module not in allowed_modules and node.module is not None:
return False, f"Unauthorized import from: {node.module}"
return True, None
except SyntaxError as e:
return False, f"Syntax error in the code: {str(e)}"
except Exception as e:
return False, f"Error validating code: {str(e)}"
def load_generated_app(code):
"""Load and run the generated Gradio app"""
# Save code to temp file
with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f:
f.write(code.encode('utf-8'))
temp_file = f.name
try:
# Import module
module_name = os.path.basename(temp_file).replace('.py', '')
spec = importlib.util.spec_from_file_location(module_name, temp_file)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
# Get the Gradio interface
if hasattr(module, 'demo'):
return module.demo, None
else:
return None, "No 'demo' variable found in the generated code"
except Exception as e:
return None, f"Error: {str(e)}"
finally:
try:
os.unlink(temp_file)
except:
pass
def generate_app(api_key, prompt):
"""Main function to generate and load a Gradio app"""
# Validate API key format
if not api_key or len(api_key) < 20 or not api_key.startswith("sk-"):
return None, "Please provide a valid OpenAI API key"
# Call OpenAI API
response, error = call_openai_api(api_key, prompt)
if error:
return None, error
# Extract code blocks
code_blocks = extract_code_blocks(response)
if not code_blocks:
return None, "No valid code found in the response"
code = code_blocks[0]
# Validate code
is_valid, error_msg = validate_gradio_code(code)
if not is_valid:
return code, error_msg
# Load the app
app, app_error = load_generated_app(code)
if app_error:
return code, app_error
return code, app
# Example Gradio apps for common requests
EXAMPLE_APPS = {
"calculator": """
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":
if num2 == 0:
return "Error: Division by zero"
return num1 / num2
else:
return "Please select an operation"
with gr.Blocks() as demo:
gr.Markdown("# Simple Calculator")
with gr.Row():
num1_input = gr.Number(label="First Number")
num2_input = gr.Number(label="Second Number")
op_dropdown = gr.Dropdown(
["Add", "Subtract", "Multiply", "Divide"],
label="Operation"
)
calculate_btn = gr.Button("Calculate")
result = gr.Number(label="Result")
calculate_btn.click(
fn=calculate,
inputs=[num1_input, num2_input, op_dropdown],
outputs=result
)
""",
"image_filter": """
import gradio as gr
import numpy as np
from PIL import Image, ImageEnhance, ImageFilter
def apply_filter(image, filter_type, intensity):
if image is None:
return None
img = Image.fromarray(image)
if filter_type == "Blur":
filtered = img.filter(ImageFilter.GaussianBlur(radius=intensity))
elif filter_type == "Sharpen":
enhancer = ImageEnhance.Sharpness(img)
filtered = enhancer.enhance(1 + intensity)
elif filter_type == "Brightness":
enhancer = ImageEnhance.Brightness(img)
filtered = enhancer.enhance(1 + intensity)
elif filter_type == "Contrast":
enhancer = ImageEnhance.Contrast(img)
filtered = enhancer.enhance(1 + intensity)
else:
filtered = img
return np.array(filtered)
with gr.Blocks() as demo:
gr.Markdown("# Image Filter App")
with gr.Row():
with gr.Column():
input_image = gr.Image(label="Original Image")
filter_type = gr.Dropdown(
["Blur", "Sharpen", "Brightness", "Contrast"],
label="Filter Type",
value="Blur"
)
intensity = gr.Slider(0, 2, 0.5, label="Intensity")
apply_btn = gr.Button("Apply Filter")
with gr.Column():
output_image = gr.Image(label="Filtered Image")
apply_btn.click(
fn=apply_filter,
inputs=[input_image, filter_type, intensity],
outputs=output_image
)
"""
}
# Create the main UI
with gr.Blocks(title="AI Gradio App Generator") as demo:
gr.Markdown("# 🤖 AI Gradio App Generator")
gr.Markdown("Describe the Gradio app you want, and I'll generate it using OpenAI's API.")
with gr.Row():
with gr.Column():
api_key = gr.Textbox(
label="OpenAI API Key",
placeholder="sk-...",
type="password",
info="Your key is used only for this session"
)
prompt = gr.Textbox(
label="App Description",
placeholder="Describe the Gradio app you want to create...",
lines=5
)
submit_btn = gr.Button("Generate App", variant="primary")
with gr.Accordion("Generated Code", open=False):
code_output = gr.Code(language="python", label="Generated Code")
status_output = gr.Markdown("")
generated_app_container = gr.Group(visible=False)
def on_submit(api_key_input, prompt_text):
try:
# If it's a simple request for a common app, use our built-in example
lower_prompt = prompt_text.lower()
for key, example_code in EXAMPLE_APPS.items():
if key in lower_prompt:
try:
app, app_error = load_generated_app(example_code)
if app_error:
return example_code, f"⚠️ {app_error}", gr.update(visible=False)
return example_code, "✅ App generated successfully (from template)!", gr.update(visible=True, value=app)
except Exception as e:
pass # Fall back to API generation if template fails
# Generate custom app via API
code, result = generate_app(api_key_input, prompt_text)
if code is None:
return None, f"⚠️ {result}", gr.update(visible=False)
if isinstance(result, str): # Error message
return code, f"⚠️ {result}", gr.update(visible=False)
# Success - result is the app
return code, "✅ App generated successfully!", gr.update(visible=True, value=result)
except Exception as e:
return None, f"⚠️ Error: {str(e)}", gr.update(visible=False)
submit_btn.click(
on_submit,
inputs=[api_key, prompt],
outputs=[code_output, status_output, generated_app_container]
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)