nakas commited on
Commit
da5bcdc
·
verified ·
1 Parent(s): 44abb7c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +234 -224
app.py CHANGED
@@ -7,97 +7,204 @@ import sys
7
  import os
8
  import ast
9
  import traceback
 
10
 
11
- # Determine Gradio version
12
  GRADIO_VERSION = gr.__version__
13
- MAJOR_VERSION = int(GRADIO_VERSION.split('.')[0])
14
 
15
- def call_openai_api(api_key, prompt, error_feedback=None, attempt=1):
16
- """Direct API call to OpenAI with auto-fixing based on errors"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 must use Gradio version {GRADIO_VERSION} (Gradio {MAJOR_VERSION}.x) syntax correctly.
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
- with gr.Blocks() as demo:
46
- hello_btn = gr.Button("Say Hello")
47
- output = gr.Textbox(label="Output")
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
- def say_hello():
64
- return "Hello, World!"
65
-
66
- with gr.Blocks() as demo:
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
- # Add error feedback for auto-fixing
87
- if error_feedback and attempt > 1:
88
- system_prompt += f"""
89
- IMPORTANT: Previous code generated an error. Fix the code to avoid this error:
90
- ```
91
- {error_feedback}
 
92
  ```
93
 
94
- Fix these common issues:
95
- - If error mentions 'object has no attribute click/change/submit', make sure you're using the correct event syntax for Gradio {MAJOR_VERSION}.x
96
- - For NameError, ensure all variables are defined before use
97
- - For ImportError, check that you only use standard libraries
98
- - For AttributeError, verify component properties and methods
 
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 using OpenAI's API with automatic error fixing.")
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
- hello_world_btn = gr.Button("Hello World Example")
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, max_attempts_value):
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), gr.update(visible=False)
306
 
307
  try:
308
- # Generate custom app via API with auto-fixing
309
- code, result, attempt = generate_app_with_retries(
310
- api_key_input,
311
- prompt_text,
312
- max_attempts=int(max_attempts_value)
313
- )
314
 
315
- attempt_msg = f"Generation attempt {attempt}/{max_attempts_value}"
 
 
 
316
 
317
- if code is None:
318
- return None, f"⚠️ {result}", gr.update(visible=False), gr.update(visible=True, value=attempt_msg)
319
 
320
- if isinstance(result, str): # Error message
321
- return code, f"⚠️ {result}", gr.update(visible=False), gr.update(visible=True, value=attempt_msg)
322
-
323
- # Success - result is the app
324
- success_msg = "✅ App generated successfully!"
325
- if attempt > 1:
326
- success_msg += f" (fixed after {attempt} attempts)"
 
 
327
 
328
- return code, success_msg, gr.update(visible=True, value=result), gr.update(visible=True, value=attempt_msg)
 
 
 
329
 
330
  except Exception as e:
331
  error_details = traceback.format_exc()
332
- return None, f"⚠️ Error: {str(e)}\n{error_details}", gr.update(visible=False), gr.update(visible=False)
333
-
334
- def on_hello_world():
335
- """Show a basic hello world example that works with the installed Gradio version"""
336
- hello_app = get_hello_world_app()
337
- hello_code = """
338
- import gradio as gr
339
-
340
- with gr.Blocks() as demo:
341
- hello_btn = gr.Button("Say Hello")
342
- output = gr.Textbox(label="Output")
343
-
344
- def say_hello():
345
- return "Hello, World!"
346
 
347
- # This syntax works for Gradio {0}.x
348
- hello_btn.click(fn=say_hello, inputs=None, outputs=output)
349
- """.format(MAJOR_VERSION)
350
 
351
- return hello_code, "✅ Hello World example shown below!", gr.update(visible=True, value=hello_app), gr.update(visible=False)
 
 
 
 
 
 
 
352
 
353
  submit_btn.click(
354
  on_submit,
355
- inputs=[api_key, prompt, max_attempts],
356
- outputs=[code_output, status_output, generated_app_container, attempt_output]
357
  )
358
 
359
- hello_world_btn.click(
360
- on_hello_world,
361
  inputs=[],
362
- outputs=[code_output, status_output, generated_app_container, attempt_output]
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__":