import os import importlib.util import sys import tempfile import traceback from pathlib import Path import gradio as gr import openai from flask import Flask, request, jsonify from dotenv import load_dotenv from utils import sanitize_code, extract_code_blocks, validate_gradio_code # Load environment variables load_dotenv() # Configure OpenAI API openai.api_key = os.getenv("OPENAI_API_KEY") # For development purposes, use a placeholder key if not provided # This will still fail when making actual API calls, but prevents immediate startup failure if not openai.api_key: print("WARNING: OPENAI_API_KEY environment variable is not set. Using placeholder for startup.") print("You will need to add your API key in the Hugging Face Space settings as a secret.") openai.api_key = "placeholder_key_replace_in_hf_settings" app = Flask(__name__) generated_app = None current_code = "" def generate_gradio_app(prompt): """Generate Gradio app code using OpenAI API""" try: response = openai.chat.completions.create( model="gpt-4o", # Using gpt-4o for best code generation messages=[ {"role": "system", "content": """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. The code must: 1. Import all necessary libraries 2. Define a complete, functional Gradio interface 3. Launch the interface with share=False and show_api=False 4. Use gr.Blocks() for complex interfaces 5. Handle errors gracefully 6. Use relative paths for any file operations 7. NOT use external APIs or services unless specifically requested 8. Be completely self-contained in a single script 9. End with a simple if __name__ == "__main__": block that launches the app """ }, {"role": "user", "content": prompt} ], temperature=0.2, max_tokens=4000 ) generated_code = response.choices[0].message.content code_blocks = extract_code_blocks(generated_code) if code_blocks: return code_blocks[0], None else: return generated_code, None except Exception as e: return None, str(e) def load_and_run_gradio_app(code): """Load and run the generated Gradio app code""" global generated_app, current_code # Check if code is safe to execute is_valid, error_msg = validate_gradio_code(code) if not is_valid: return None, error_msg # Clean up previous app if it exists if generated_app: try: generated_app.close() except: pass # Save code to a temporary file with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f: f.write(code.encode('utf-8')) temp_file = f.name try: # Import the 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) # Find the Gradio interface for attr_name in dir(module): attr = getattr(module, attr_name) if isinstance(attr, gr.Blocks) or isinstance(attr, gr.Interface): # Save a reference to the app generated_app = attr current_code = code # Return the app return attr, None return None, "No Gradio interface found in the generated code" except Exception as e: error_details = traceback.format_exc() return None, f"Error executing the generated code: {str(e)}\n{error_details}" finally: # Clean up the temporary file try: os.unlink(temp_file) except: pass def create_ui(): """Create the main Gradio interface""" with gr.Blocks(title="Dynamic Gradio App Generator") as interface: gr.Markdown("# 🤖 Dynamic Gradio App Generator") gr.Markdown("Describe the Gradio app you want to create, and the AI will generate and run it for you.") with gr.Row(): with gr.Column(scale=2): prompt = gr.Textbox( label="App Description", placeholder="Describe the Gradio app you want to create...", lines=5 ) with gr.Row(): submit_btn = gr.Button("Generate & Run App", variant="primary") clear_btn = gr.Button("Clear", variant="secondary") with gr.Accordion("Generated Code", open=False): code_output = gr.Code(language="python", label="Generated Code") with gr.Column(scale=3): output = gr.Markdown("Your generated app will appear here.") error_output = gr.Markdown(visible=False) def on_submit(prompt_text): # Generate the Gradio app code code, error = generate_gradio_app(prompt_text) if error: return None, f"⚠️ **Error generating code**: {error}", gr.update(visible=True), None # Load and run the generated app app, run_error = load_and_run_gradio_app(code) if run_error: return code, f"⚠️ **Error running the generated app**: {run_error}", gr.update(visible=True), None # Create an iframe to display the app iframe_html = f'' return code, "", gr.update(visible=False), iframe_html def on_clear(): return "", "", gr.update(visible=False), "Your generated app will appear here." submit_btn.click( on_submit, inputs=[prompt], outputs=[code_output, error_output, error_output, output] ) clear_btn.click( on_clear, inputs=[], outputs=[prompt, code_output, error_output, output] ) return interface # Flask routes to handle the generated app @app.route('/generated_app') def serve_generated_app(): """Serve the generated Gradio app""" if not generated_app: return "No app has been generated yet. Please create one first." # Create a tempfile with the current code with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f: f.write(current_code.encode('utf-8')) temp_file = f.name # Execute the code in a subprocess # This is a simplified version - in a real app, you'd need a more robust solution import subprocess result = subprocess.run([sys.executable, temp_file], capture_output=True, text=True) # Clean up os.unlink(temp_file) if result.returncode != 0: return f"Error running the app: {result.stderr}" return result.stdout if __name__ == "__main__": # Create the Gradio interface demo = create_ui() # Launch the Gradio app demo.launch(server_name="0.0.0.0", server_port=7860)