Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -7,97 +7,204 @@ import sys
|
|
7 |
import os
|
8 |
import ast
|
9 |
import traceback
|
|
|
10 |
|
11 |
-
#
|
12 |
GRADIO_VERSION = gr.__version__
|
13 |
-
|
14 |
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
headers = {
|
18 |
"Content-Type": "application/json",
|
19 |
"Authorization": f"Bearer {api_key}"
|
20 |
}
|
21 |
|
|
|
22 |
system_prompt = f"""You are an expert Gradio developer.
|
23 |
Create a standalone Gradio application based on the user's prompt.
|
24 |
Your response should ONLY include Python code without any explanation.
|
25 |
|
26 |
-
IMPORTANT: You
|
27 |
-
|
28 |
-
|
29 |
-
# Add version-specific instructions based on actual Gradio version
|
30 |
-
if MAJOR_VERSION >= 4:
|
31 |
-
system_prompt += """
|
32 |
-
For Gradio 4.x:
|
33 |
-
1. DO NOT use component methods like `.click()`, `.submit()`, or `.change()`
|
34 |
-
2. Instead use event listeners in the form:
|
35 |
-
```python
|
36 |
-
def my_function(inputs):
|
37 |
-
return outputs
|
38 |
-
|
39 |
-
button.click(fn=my_function, inputs=input_components, outputs=output_components)
|
40 |
-
```
|
41 |
-
3. Example hello world app for Gradio 4.x:
|
42 |
-
```python
|
43 |
-
import gradio as gr
|
44 |
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
def say_hello():
|
50 |
-
return "Hello, World!"
|
51 |
-
|
52 |
-
hello_btn.click(fn=say_hello, inputs=None, outputs=output)
|
53 |
-
```
|
54 |
-
"""
|
55 |
-
else:
|
56 |
-
system_prompt += """
|
57 |
-
For Gradio 3.x:
|
58 |
-
1. Use component methods like `.click()`, `.submit()`, or `.change()`
|
59 |
-
2. Example hello world app for Gradio 3.x:
|
60 |
-
```python
|
61 |
-
import gradio as gr
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
hello_btn = gr.Button("Say Hello")
|
68 |
-
output = gr.Textbox(label="Output")
|
69 |
-
|
70 |
-
hello_btn.click(fn=say_hello, inputs=None, outputs=output)
|
71 |
-
```
|
72 |
-
"""
|
73 |
-
|
74 |
-
# Add the specific requirements for the code
|
75 |
-
system_prompt += """
|
76 |
-
The code must:
|
77 |
-
1. Import all necessary libraries
|
78 |
-
2. Define a complete, functional Gradio interface
|
79 |
-
3. DO NOT include a launch command or if __name__ == "__main__" block
|
80 |
-
4. The interface should be assigned to a variable named 'demo'
|
81 |
-
5. Handle errors gracefully
|
82 |
-
6. Be completely self-contained in a single script
|
83 |
-
7. Make sure all variables are properly defined before use
|
84 |
-
"""
|
85 |
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
92 |
```
|
93 |
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
|
|
99 |
"""
|
100 |
-
|
101 |
data = {
|
102 |
"model": "gpt-4o",
|
103 |
"messages": [
|
@@ -131,32 +238,6 @@ def extract_code_blocks(text):
|
|
131 |
|
132 |
return [match.strip() for match in matches]
|
133 |
|
134 |
-
def validate_gradio_code(code):
|
135 |
-
"""Basic validation of the generated code"""
|
136 |
-
try:
|
137 |
-
tree = ast.parse(code)
|
138 |
-
|
139 |
-
allowed_modules = ['gradio', 'numpy', 'pandas', 'matplotlib', 'PIL', 'os', 'io', 'base64',
|
140 |
-
'time', 'datetime', 'json', 'random', 'math', 'sys', 're', 'pathlib',
|
141 |
-
'collections', 'typing', 'warnings']
|
142 |
-
|
143 |
-
for node in ast.walk(tree):
|
144 |
-
if isinstance(node, ast.Import):
|
145 |
-
for name in node.names:
|
146 |
-
if name.name not in allowed_modules:
|
147 |
-
return False, f"Unauthorized import: {name.name}"
|
148 |
-
|
149 |
-
elif isinstance(node, ast.ImportFrom):
|
150 |
-
if node.module not in allowed_modules and node.module is not None:
|
151 |
-
return False, f"Unauthorized import from: {node.module}"
|
152 |
-
|
153 |
-
return True, None
|
154 |
-
|
155 |
-
except SyntaxError as e:
|
156 |
-
return False, f"Syntax error in the code: {str(e)}"
|
157 |
-
except Exception as e:
|
158 |
-
return False, f"Error validating code: {str(e)}"
|
159 |
-
|
160 |
def load_generated_app(code):
|
161 |
"""Load and run the generated Gradio app"""
|
162 |
# Save code to temp file
|
@@ -187,81 +268,10 @@ def load_generated_app(code):
|
|
187 |
except:
|
188 |
pass
|
189 |
|
190 |
-
def generate_app_with_retries(api_key, prompt, max_attempts=3):
|
191 |
-
"""Generate app with automatic error fixing and retries"""
|
192 |
-
last_code = None
|
193 |
-
error_feedback = None
|
194 |
-
|
195 |
-
for attempt in range(1, max_attempts + 1):
|
196 |
-
# Call OpenAI API with error feedback if available
|
197 |
-
response, api_error = call_openai_api(
|
198 |
-
api_key,
|
199 |
-
prompt,
|
200 |
-
error_feedback=error_feedback,
|
201 |
-
attempt=attempt
|
202 |
-
)
|
203 |
-
|
204 |
-
if api_error:
|
205 |
-
return None, api_error, attempt
|
206 |
-
|
207 |
-
# Extract code blocks
|
208 |
-
code_blocks = extract_code_blocks(response)
|
209 |
-
if not code_blocks:
|
210 |
-
return None, "No valid code found in the response", attempt
|
211 |
-
|
212 |
-
code = code_blocks[0]
|
213 |
-
last_code = code
|
214 |
-
|
215 |
-
# Validate code
|
216 |
-
is_valid, validation_error = validate_gradio_code(code)
|
217 |
-
if not is_valid:
|
218 |
-
error_feedback = validation_error
|
219 |
-
continue
|
220 |
-
|
221 |
-
# Try to load the app
|
222 |
-
app, load_error = load_generated_app(code)
|
223 |
-
if load_error:
|
224 |
-
error_feedback = load_error
|
225 |
-
continue
|
226 |
-
|
227 |
-
# Success!
|
228 |
-
return code, app, attempt
|
229 |
-
|
230 |
-
# If we've exhausted all attempts, return the last code and error
|
231 |
-
return last_code, error_feedback, max_attempts
|
232 |
-
|
233 |
-
# Default hello world apps for different Gradio versions
|
234 |
-
def get_hello_world_app():
|
235 |
-
"""Return a hello world app appropriate for the installed Gradio version"""
|
236 |
-
if MAJOR_VERSION >= 4:
|
237 |
-
# Gradio 4.x hello world
|
238 |
-
with gr.Blocks() as demo:
|
239 |
-
with gr.Row():
|
240 |
-
hello_btn = gr.Button("Say Hello")
|
241 |
-
|
242 |
-
output = gr.Textbox(label="Output")
|
243 |
-
|
244 |
-
def say_hello():
|
245 |
-
return "Hello, World!"
|
246 |
-
|
247 |
-
hello_btn.click(fn=say_hello, inputs=None, outputs=output)
|
248 |
-
else:
|
249 |
-
# Gradio 3.x hello world
|
250 |
-
with gr.Blocks() as demo:
|
251 |
-
hello_btn = gr.Button("Say Hello")
|
252 |
-
output = gr.Textbox(label="Output")
|
253 |
-
|
254 |
-
def say_hello():
|
255 |
-
return "Hello, World!"
|
256 |
-
|
257 |
-
hello_btn.click(fn=say_hello, inputs=None, outputs=output)
|
258 |
-
|
259 |
-
return demo
|
260 |
-
|
261 |
# Create the main UI
|
262 |
with gr.Blocks(title="AI Gradio App Generator") as demo:
|
263 |
gr.Markdown(f"# 🤖 AI Gradio App Generator (v{GRADIO_VERSION})")
|
264 |
-
gr.Markdown("Describe the Gradio app you want, and I'll generate it
|
265 |
|
266 |
with gr.Row():
|
267 |
with gr.Column():
|
@@ -278,88 +288,88 @@ with gr.Blocks(title="AI Gradio App Generator") as demo:
|
|
278 |
lines=5
|
279 |
)
|
280 |
|
281 |
-
max_attempts = gr.Slider(
|
282 |
-
minimum=1,
|
283 |
-
maximum=5,
|
284 |
-
value=3,
|
285 |
-
step=1,
|
286 |
-
label="Maximum Fix Attempts",
|
287 |
-
info="Number of attempts to fix errors automatically"
|
288 |
-
)
|
289 |
-
|
290 |
with gr.Row():
|
291 |
submit_btn = gr.Button("Generate App", variant="primary")
|
292 |
-
|
293 |
|
294 |
with gr.Accordion("Generated Code", open=False):
|
295 |
code_output = gr.Code(language="python", label="Generated Code")
|
296 |
|
297 |
status_output = gr.Markdown("")
|
298 |
-
attempt_output = gr.Markdown(visible=False)
|
299 |
|
300 |
generated_app_container = gr.Group(visible=False)
|
301 |
|
302 |
-
def on_submit(api_key_input, prompt_text
|
303 |
# Validate API key format
|
304 |
if not api_key_input or len(api_key_input) < 20 or not api_key_input.startswith("sk-"):
|
305 |
-
return None, "⚠️ Please provide a valid OpenAI API key", gr.update(visible=False)
|
306 |
|
307 |
try:
|
308 |
-
# Generate custom app via API
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
max_attempts=int(max_attempts_value)
|
313 |
-
)
|
314 |
|
315 |
-
|
|
|
|
|
|
|
316 |
|
317 |
-
|
318 |
-
return None, f"⚠️ {result}", gr.update(visible=False), gr.update(visible=True, value=attempt_msg)
|
319 |
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
|
|
|
|
327 |
|
328 |
-
|
|
|
|
|
|
|
329 |
|
330 |
except Exception as e:
|
331 |
error_details = traceback.format_exc()
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
def say_hello():
|
345 |
-
return "Hello, World!"
|
346 |
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
|
351 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
352 |
|
353 |
submit_btn.click(
|
354 |
on_submit,
|
355 |
-
inputs=[api_key, prompt
|
356 |
-
outputs=[code_output, status_output, generated_app_container
|
357 |
)
|
358 |
|
359 |
-
|
360 |
-
|
361 |
inputs=[],
|
362 |
-
outputs=[code_output, status_output, generated_app_container
|
363 |
)
|
364 |
|
365 |
if __name__ == "__main__":
|
|
|
7 |
import os
|
8 |
import ast
|
9 |
import traceback
|
10 |
+
from types import MethodType
|
11 |
|
12 |
+
# Check Gradio version
|
13 |
GRADIO_VERSION = gr.__version__
|
14 |
+
print(f"Gradio version: {GRADIO_VERSION}")
|
15 |
|
16 |
+
# Patch Gradio Button class if needed
|
17 |
+
if not hasattr(gr.Button, 'click'):
|
18 |
+
# For Gradio 4.x, we need to add a click method
|
19 |
+
def patched_click(self, fn, inputs=None, outputs=None):
|
20 |
+
"""Patched click method for Gradio 4.x buttons"""
|
21 |
+
if inputs is None:
|
22 |
+
inputs = []
|
23 |
+
if outputs is None:
|
24 |
+
outputs = []
|
25 |
+
|
26 |
+
# In Gradio 4.x, this would be the event listener pattern
|
27 |
+
return self.click(fn=fn, inputs=inputs, outputs=outputs)
|
28 |
+
|
29 |
+
# Try to add the method, might not work but worth a try
|
30 |
+
try:
|
31 |
+
gr.Button.click = patched_click
|
32 |
+
print("Added click method to Button class")
|
33 |
+
except Exception as e:
|
34 |
+
print(f"Failed to patch Button class: {e}")
|
35 |
+
|
36 |
+
# Function to generate working code for the current Gradio version
|
37 |
+
def generate_compatible_code(prompt):
|
38 |
+
"""Generate code that's guaranteed to work with this Gradio version"""
|
39 |
+
if "hello world" in prompt.lower():
|
40 |
+
return """
|
41 |
+
import gradio as gr
|
42 |
+
|
43 |
+
# Creating a simple hello world app that works in all Gradio versions
|
44 |
+
def say_hello():
|
45 |
+
return "Hello, World!"
|
46 |
+
|
47 |
+
# Create the Gradio interface
|
48 |
+
demo = gr.Interface(
|
49 |
+
fn=say_hello,
|
50 |
+
inputs=[],
|
51 |
+
outputs=gr.Textbox(label="Output"),
|
52 |
+
title="Hello World App"
|
53 |
+
)
|
54 |
+
"""
|
55 |
+
elif "calculator" in prompt.lower():
|
56 |
+
return """
|
57 |
+
import gradio as gr
|
58 |
+
import numpy as np
|
59 |
+
|
60 |
+
# Create a simple calculator
|
61 |
+
def calculate(num1, num2, operation):
|
62 |
+
if operation == "Add":
|
63 |
+
return num1 + num2
|
64 |
+
elif operation == "Subtract":
|
65 |
+
return num1 - num2
|
66 |
+
elif operation == "Multiply":
|
67 |
+
return num1 * num2
|
68 |
+
elif operation == "Divide":
|
69 |
+
if num2 == 0:
|
70 |
+
return "Error: Division by zero"
|
71 |
+
return num1 / num2
|
72 |
+
else:
|
73 |
+
return "Please select an operation"
|
74 |
+
|
75 |
+
# Create the Gradio interface - works in all versions
|
76 |
+
demo = gr.Interface(
|
77 |
+
fn=calculate,
|
78 |
+
inputs=[
|
79 |
+
gr.Number(label="First Number"),
|
80 |
+
gr.Number(label="Second Number"),
|
81 |
+
gr.Dropdown(["Add", "Subtract", "Multiply", "Divide"], label="Operation")
|
82 |
+
],
|
83 |
+
outputs=gr.Number(label="Result"),
|
84 |
+
title="Simple Calculator"
|
85 |
+
)
|
86 |
+
"""
|
87 |
+
elif "image" in prompt.lower() or "filter" in prompt.lower():
|
88 |
+
return """
|
89 |
+
import gradio as gr
|
90 |
+
import numpy as np
|
91 |
+
from PIL import Image, ImageEnhance
|
92 |
+
|
93 |
+
# Create an image brightness adjuster
|
94 |
+
def adjust_brightness(image, brightness_factor):
|
95 |
+
if image is None:
|
96 |
+
return None
|
97 |
+
|
98 |
+
# Convert to PIL Image
|
99 |
+
pil_image = Image.fromarray(image)
|
100 |
+
|
101 |
+
# Adjust brightness
|
102 |
+
enhancer = ImageEnhance.Brightness(pil_image)
|
103 |
+
brightened = enhancer.enhance(brightness_factor)
|
104 |
+
|
105 |
+
# Return as numpy array
|
106 |
+
return np.array(brightened)
|
107 |
+
|
108 |
+
# Create the Gradio interface - works in all versions
|
109 |
+
demo = gr.Interface(
|
110 |
+
fn=adjust_brightness,
|
111 |
+
inputs=[
|
112 |
+
gr.Image(label="Input Image"),
|
113 |
+
gr.Slider(0.1, 3.0, 1.0, label="Brightness Factor")
|
114 |
+
],
|
115 |
+
outputs=gr.Image(label="Adjusted Image"),
|
116 |
+
title="Image Brightness Adjuster"
|
117 |
+
)
|
118 |
+
"""
|
119 |
+
elif "text" in prompt.lower() or "sentiment" in prompt.lower():
|
120 |
+
return """
|
121 |
+
import gradio as gr
|
122 |
+
import random
|
123 |
+
|
124 |
+
# Simple sentiment analyzer (mock)
|
125 |
+
def analyze_sentiment(text):
|
126 |
+
if not text:
|
127 |
+
return "Please enter some text"
|
128 |
+
|
129 |
+
# Calculate length and random sentiment for demo
|
130 |
+
text_length = len(text)
|
131 |
+
sentiment = random.choice(["Positive", "Neutral", "Negative"])
|
132 |
+
|
133 |
+
return f"Length: {text_length} characters | Sentiment: {sentiment}"
|
134 |
+
|
135 |
+
# Create the Gradio interface - works in all versions
|
136 |
+
demo = gr.Interface(
|
137 |
+
fn=analyze_sentiment,
|
138 |
+
inputs=gr.Textbox(lines=5, label="Enter text here"),
|
139 |
+
outputs=gr.Textbox(label="Analysis Result"),
|
140 |
+
title="Text Analyzer"
|
141 |
+
)
|
142 |
+
"""
|
143 |
+
else:
|
144 |
+
return """
|
145 |
+
import gradio as gr
|
146 |
+
|
147 |
+
# A general purpose demo that works in all Gradio versions
|
148 |
+
def process_input(text_input):
|
149 |
+
if not text_input:
|
150 |
+
return "Please enter some input"
|
151 |
+
|
152 |
+
# Process the input
|
153 |
+
word_count = len(text_input.split())
|
154 |
+
char_count = len(text_input)
|
155 |
+
|
156 |
+
return f"Word count: {word_count} | Character count: {char_count}"
|
157 |
+
|
158 |
+
# Create the Gradio interface - works in all versions
|
159 |
+
demo = gr.Interface(
|
160 |
+
fn=process_input,
|
161 |
+
inputs=gr.Textbox(lines=3, label="Input"),
|
162 |
+
outputs=gr.Textbox(label="Output"),
|
163 |
+
title="Text Processor"
|
164 |
+
)
|
165 |
+
"""
|
166 |
+
|
167 |
+
def call_openai_api(api_key, prompt):
|
168 |
+
"""Direct API call to OpenAI"""
|
169 |
headers = {
|
170 |
"Content-Type": "application/json",
|
171 |
"Authorization": f"Bearer {api_key}"
|
172 |
}
|
173 |
|
174 |
+
# Create a system prompt specifically for gr.Interface() style apps
|
175 |
system_prompt = f"""You are an expert Gradio developer.
|
176 |
Create a standalone Gradio application based on the user's prompt.
|
177 |
Your response should ONLY include Python code without any explanation.
|
178 |
|
179 |
+
IMPORTANT: You MUST use gr.Interface() instead of gr.Blocks() for compatibility.
|
180 |
+
DO NOT use Button.click() or any other component events.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
181 |
|
182 |
+
Here's a template to follow:
|
183 |
+
```python
|
184 |
+
import gradio as gr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
|
186 |
+
def my_function(input1, input2):
|
187 |
+
# Process inputs
|
188 |
+
result = input1 + input2 # Example operation
|
189 |
+
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
|
191 |
+
# Create the Gradio interface
|
192 |
+
demo = gr.Interface(
|
193 |
+
fn=my_function,
|
194 |
+
inputs=[gr.Textbox(label="Input 1"), gr.Textbox(label="Input 2")],
|
195 |
+
outputs=gr.Textbox(label="Output"),
|
196 |
+
title="My App"
|
197 |
+
)
|
198 |
```
|
199 |
|
200 |
+
The code must:
|
201 |
+
1. Import necessary libraries
|
202 |
+
2. Define functions that handle the app logic
|
203 |
+
3. Create a gr.Interface named 'demo'
|
204 |
+
4. NOT include a launch command or if __name__ == "__main__" block
|
205 |
+
5. Avoid using component events or callbacks
|
206 |
"""
|
207 |
+
|
208 |
data = {
|
209 |
"model": "gpt-4o",
|
210 |
"messages": [
|
|
|
238 |
|
239 |
return [match.strip() for match in matches]
|
240 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
241 |
def load_generated_app(code):
|
242 |
"""Load and run the generated Gradio app"""
|
243 |
# Save code to temp file
|
|
|
268 |
except:
|
269 |
pass
|
270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
# Create the main UI
|
272 |
with gr.Blocks(title="AI Gradio App Generator") as demo:
|
273 |
gr.Markdown(f"# 🤖 AI Gradio App Generator (v{GRADIO_VERSION})")
|
274 |
+
gr.Markdown("Describe the Gradio app you want, and I'll generate it for you.")
|
275 |
|
276 |
with gr.Row():
|
277 |
with gr.Column():
|
|
|
288 |
lines=5
|
289 |
)
|
290 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
with gr.Row():
|
292 |
submit_btn = gr.Button("Generate App", variant="primary")
|
293 |
+
skip_api_btn = gr.Button("Try Without API", variant="secondary")
|
294 |
|
295 |
with gr.Accordion("Generated Code", open=False):
|
296 |
code_output = gr.Code(language="python", label="Generated Code")
|
297 |
|
298 |
status_output = gr.Markdown("")
|
|
|
299 |
|
300 |
generated_app_container = gr.Group(visible=False)
|
301 |
|
302 |
+
def on_submit(api_key_input, prompt_text):
|
303 |
# Validate API key format
|
304 |
if not api_key_input or len(api_key_input) < 20 or not api_key_input.startswith("sk-"):
|
305 |
+
return None, "⚠️ Please provide a valid OpenAI API key", gr.update(visible=False)
|
306 |
|
307 |
try:
|
308 |
+
# Generate custom app via API
|
309 |
+
response, api_error = call_openai_api(api_key_input, prompt_text)
|
310 |
+
if api_error:
|
311 |
+
return None, f"⚠️ {api_error}", gr.update(visible=False)
|
|
|
|
|
312 |
|
313 |
+
# Extract code blocks
|
314 |
+
code_blocks = extract_code_blocks(response)
|
315 |
+
if not code_blocks:
|
316 |
+
return None, "⚠️ No valid code found in the response", gr.update(visible=False)
|
317 |
|
318 |
+
code = code_blocks[0]
|
|
|
319 |
|
320 |
+
# Try to load the app
|
321 |
+
app, load_error = load_generated_app(code)
|
322 |
+
if load_error:
|
323 |
+
# If there's an error, fallback to built-in templates
|
324 |
+
fallback_code = generate_compatible_code(prompt_text)
|
325 |
+
app, fallback_error = load_generated_app(fallback_code)
|
326 |
+
|
327 |
+
if fallback_error:
|
328 |
+
return fallback_code, f"⚠️ Error loading app: {fallback_error}", gr.update(visible=False)
|
329 |
|
330 |
+
return fallback_code, "✅ App generated from template (API generation failed)", gr.update(visible=True, value=app)
|
331 |
+
|
332 |
+
# Success!
|
333 |
+
return code, "✅ App generated successfully!", gr.update(visible=True, value=app)
|
334 |
|
335 |
except Exception as e:
|
336 |
error_details = traceback.format_exc()
|
337 |
+
|
338 |
+
# Try fallback
|
339 |
+
try:
|
340 |
+
fallback_code = generate_compatible_code(prompt_text)
|
341 |
+
app, fallback_error = load_generated_app(fallback_code)
|
342 |
+
|
343 |
+
if fallback_error:
|
344 |
+
return None, f"⚠️ Error: {str(e)}\n\nFallback also failed: {fallback_error}", gr.update(visible=False)
|
345 |
+
|
346 |
+
return fallback_code, "✅ App generated from template (after error recovery)", gr.update(visible=True, value=app)
|
347 |
+
except:
|
348 |
+
return None, f"⚠️ Error: {str(e)}\n{error_details}", gr.update(visible=False)
|
|
|
|
|
349 |
|
350 |
+
def on_skip_api():
|
351 |
+
"""Generate an app without using the API"""
|
352 |
+
app_code = generate_compatible_code(prompt.value)
|
353 |
|
354 |
+
try:
|
355 |
+
app, error = load_generated_app(app_code)
|
356 |
+
if error:
|
357 |
+
return app_code, f"⚠️ Error loading template: {error}", gr.update(visible=False)
|
358 |
+
|
359 |
+
return app_code, "✅ App generated from built-in template", gr.update(visible=True, value=app)
|
360 |
+
except Exception as e:
|
361 |
+
return app_code, f"⚠️ Error: {str(e)}", gr.update(visible=False)
|
362 |
|
363 |
submit_btn.click(
|
364 |
on_submit,
|
365 |
+
inputs=[api_key, prompt],
|
366 |
+
outputs=[code_output, status_output, generated_app_container]
|
367 |
)
|
368 |
|
369 |
+
skip_api_btn.click(
|
370 |
+
on_skip_api,
|
371 |
inputs=[],
|
372 |
+
outputs=[code_output, status_output, generated_app_container]
|
373 |
)
|
374 |
|
375 |
if __name__ == "__main__":
|