nakas commited on
Commit
b5fe8ca
·
verified ·
1 Parent(s): cb42996

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +224 -99
app.py CHANGED
@@ -1,11 +1,24 @@
1
  import gradio as gr
2
  import os
3
- import io
4
- from contextlib import redirect_stdout, redirect_stderr
 
 
 
 
 
 
5
 
6
  # Set fixed MPLCONFIGDIR to avoid permission issues
7
  os.environ['MPLCONFIGDIR'] = '/tmp'
8
 
 
 
 
 
 
 
 
9
  # Sample code for different Gradio apps
10
  EXAMPLE_CODES = {
11
  "hello_world": """
@@ -21,6 +34,8 @@ demo = gr.Interface(
21
  title="Hello World",
22
  description="A simple greeting app"
23
  )
 
 
24
  """,
25
 
26
  "calculator": """
@@ -49,6 +64,8 @@ demo = gr.Interface(
49
  title="Calculator",
50
  description="Perform basic arithmetic operations"
51
  )
 
 
52
  """,
53
 
54
  "image_filter": """
@@ -85,8 +102,11 @@ demo = gr.Interface(
85
  ],
86
  outputs=gr.Image(type="pil"),
87
  title="Image Filter",
88
- description="Apply various filters to images"
 
89
  )
 
 
90
  """
91
  }
92
 
@@ -105,40 +125,140 @@ def simulate_llm_response(prompt):
105
  # Default to hello world
106
  return EXAMPLE_CODES["hello_world"], None
107
 
108
- # Function to execute code and extract the demo object
109
- def execute_code(code):
110
- """Execute the code and return the demo object"""
111
- # Create a clean namespace
112
- namespace = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
- # Capture stdout and stderr
115
- stdout_buffer = io.StringIO()
116
- stderr_buffer = io.StringIO()
117
 
 
 
 
 
 
 
 
 
 
118
  try:
119
- with redirect_stdout(stdout_buffer), redirect_stderr(stderr_buffer):
120
- # Execute the code in the namespace
121
- exec(code, namespace)
 
 
122
 
123
- # Check if 'demo' exists in the namespace
124
- if 'demo' not in namespace:
125
- return None, "No 'demo' object found in the code", stdout_buffer.getvalue(), stderr_buffer.getvalue()
126
 
127
- # Return the demo object
128
- return namespace['demo'], None, stdout_buffer.getvalue(), stderr_buffer.getvalue()
129
-
 
 
 
 
 
 
 
 
 
 
130
  except Exception as e:
131
  import traceback
132
- return None, f"Error executing code: {str(e)}\n{traceback.format_exc()}", stdout_buffer.getvalue(), stderr_buffer.getvalue()
133
 
134
- # Main app
135
- with gr.Blocks(title="LLM Gradio App Generator") as app:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  # Header
137
  gr.Markdown("# 🤖 LLM Gradio App Generator")
138
  gr.Markdown("Generate and run Gradio apps dynamically!")
139
 
 
 
 
140
  with gr.Row():
141
- # Input column
142
  with gr.Column(scale=1):
143
  # App description input
144
  prompt = gr.Textbox(
@@ -148,120 +268,125 @@ with gr.Blocks(title="LLM Gradio App Generator") as app:
148
  )
149
 
150
  # Example buttons
151
- gr.Markdown("### Example Prompts")
152
- hello_btn = gr.Button("Hello World App")
153
- calc_btn = gr.Button("Calculator App")
154
- img_btn = gr.Button("Image Filter App")
 
155
 
156
  # Generate button
157
- generate_btn = gr.Button("Generate & Run App", variant="primary")
 
 
158
 
159
- # Code display
160
- gr.Markdown("### Generated Code")
161
- code_display = gr.Code(language="python")
162
 
163
- # Log output
164
- with gr.Accordion("Execution Log", open=False):
165
- log_output = gr.Textbox(label="Output Log", lines=5)
166
 
167
- # Output column
168
  with gr.Column(scale=2):
169
- # Status message
170
- status_msg = gr.Markdown("### Generated App Will Appear Here")
171
-
172
- # Container for the dynamically generated app
173
- app_container = gr.HTML(
174
- """<div style="display:flex; justify-content:center; align-items:center; height:400px; border:1px dashed #ccc; border-radius:8px;">
175
  <div style="text-align:center;">
176
- <h3>No App Generated Yet</h3>
177
- <p>Enter a description and click "Generate & Run App"</p>
178
  </div>
179
  </div>"""
180
  )
181
 
182
  # Example button functions
183
- def set_prompt(text):
184
- return text
185
 
186
  hello_btn.click(
187
- lambda: set_prompt("A simple hello world app that greets the user by name"),
188
  inputs=None,
189
  outputs=prompt
190
  )
191
 
192
  calc_btn.click(
193
- lambda: set_prompt("A calculator app that can add, subtract, multiply and divide two numbers"),
194
  inputs=None,
195
  outputs=prompt
196
  )
197
 
198
- img_btn.click(
199
- lambda: set_prompt("An image filter app that can apply grayscale, invert, and sepia filters to images"),
200
  inputs=None,
201
  outputs=prompt
202
  )
203
 
204
- # Main function to generate and run the app
205
- def generate_and_run_app(prompt_text):
206
  if not prompt_text:
207
- return (
208
- "Please enter a description of the app you want to generate.",
209
- "",
210
- """<div style="text-align:center; padding:20px;">
211
- <h3>No App Generated</h3>
212
- <p>Please enter a description first.</p>
213
- </div>"""
214
- )
215
 
216
  # Get code from LLM (simulated)
217
  code, error = simulate_llm_response(prompt_text)
218
  if error:
219
- return (
220
- code,
221
- f"Error generating code: {error}",
222
- """<div style="text-align:center; color:red; padding:20px;">
223
- <h3>Error</h3>
224
- <p>{0}</p>
225
- </div>""".format(error)
226
- )
227
 
228
- # Execute the code
229
- demo_obj, exec_error, stdout, stderr = execute_code(code)
230
- log_output = f"STDOUT:\n{stdout}\n\nSTDERR:\n{stderr}"
 
231
 
232
- if exec_error:
233
- return (
234
- code,
235
- f"Error: {exec_error}",
236
- """<div style="text-align:center; color:red; padding:20px;">
237
- <h3>Execution Error</h3>
238
- <p>{0}</p>
239
- </div>""".format(exec_error)
240
- )
241
 
242
- try:
243
- # Render the demo to HTML
244
- rendered_html = demo_obj.render().replace('window.gradio_mode = "app";', '')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
- return code, f"✅ App generated and running!", rendered_html
247
- except Exception as e:
248
- import traceback
249
- return (
250
- code,
251
- f"Error rendering app: {str(e)}",
252
- """<div style="text-align:center; color:red; padding:20px;">
253
- <h3>Rendering Error</h3>
254
- <p>{0}</p>
255
- </div>""".format(traceback.format_exc())
256
- )
257
 
258
  # Connect the generate button
259
  generate_btn.click(
260
- generate_and_run_app,
261
- inputs=prompt,
262
- outputs=[code_display, log_output, app_container]
 
 
 
 
 
 
 
263
  )
264
 
265
- # Launch the app
266
  if __name__ == "__main__":
267
- app.launch(server_name="0.0.0.0", server_port=7860)
 
1
  import gradio as gr
2
  import os
3
+ import tempfile
4
+ import time
5
+ import subprocess
6
+ import threading
7
+ import signal
8
+ import json
9
+ import random
10
+ import string
11
 
12
  # Set fixed MPLCONFIGDIR to avoid permission issues
13
  os.environ['MPLCONFIGDIR'] = '/tmp'
14
 
15
+ # Create tmp directory if it doesn't exist
16
+ TEMP_DIR = os.path.join(tempfile.gettempdir(), "gradio_apps")
17
+ os.makedirs(TEMP_DIR, exist_ok=True)
18
+
19
+ # Track running processes
20
+ processes = {}
21
+
22
  # Sample code for different Gradio apps
23
  EXAMPLE_CODES = {
24
  "hello_world": """
 
34
  title="Hello World",
35
  description="A simple greeting app"
36
  )
37
+
38
+ demo.launch(server_name="0.0.0.0", server_port=PORT)
39
  """,
40
 
41
  "calculator": """
 
64
  title="Calculator",
65
  description="Perform basic arithmetic operations"
66
  )
67
+
68
+ demo.launch(server_name="0.0.0.0", server_port=PORT)
69
  """,
70
 
71
  "image_filter": """
 
102
  ],
103
  outputs=gr.Image(type="pil"),
104
  title="Image Filter",
105
+ description="Apply various filters to images",
106
+ allow_flagging=False
107
  )
108
+
109
+ demo.launch(server_name="0.0.0.0", server_port=PORT)
110
  """
111
  }
112
 
 
125
  # Default to hello world
126
  return EXAMPLE_CODES["hello_world"], None
127
 
128
+ # Find an available port
129
+ def find_available_port(start_port=7870):
130
+ """Find an available port starting from start_port"""
131
+ import socket
132
+ from contextlib import closing
133
+
134
+ def is_port_available(port):
135
+ with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
136
+ return sock.connect_ex(('localhost', port)) != 0
137
+
138
+ port = start_port
139
+ while not is_port_available(port):
140
+ port += 1
141
+
142
+ return port
143
+
144
+ # Generate a random string
145
+ def random_string(length=8):
146
+ """Generate a random string of fixed length"""
147
+ letters = string.ascii_lowercase
148
+ return ''.join(random.choice(letters) for i in range(length))
149
+
150
+ # Function to run a Gradio app as a subprocess
151
+ def run_gradio_app(code, app_id=None):
152
+ """Run a Gradio app as a subprocess and return the port"""
153
+ global processes
154
+
155
+ # Clean up any previous process with the same ID
156
+ if app_id in processes and processes[app_id]["process"].poll() is None:
157
+ processes[app_id]["process"].terminate()
158
+ try:
159
+ processes[app_id]["process"].wait(timeout=5)
160
+ except:
161
+ processes[app_id]["process"].kill()
162
+
163
+ # Remove the file
164
+ try:
165
+ os.unlink(processes[app_id]["file"])
166
+ except:
167
+ pass
168
+
169
+ # Generate a unique ID if not provided
170
+ if app_id is None:
171
+ app_id = random_string()
172
 
173
+ # Find an available port
174
+ port = find_available_port()
 
175
 
176
+ # Replace PORT in the code with the actual port
177
+ code = code.replace("PORT", str(port))
178
+
179
+ # Create a temporary file
180
+ with tempfile.NamedTemporaryFile(suffix='.py', dir=TEMP_DIR, delete=False) as f:
181
+ f.write(code.encode('utf-8'))
182
+ file_path = f.name
183
+
184
+ # Run the app as a subprocess
185
  try:
186
+ process = subprocess.Popen(
187
+ [sys.executable, file_path],
188
+ stdout=subprocess.PIPE,
189
+ stderr=subprocess.PIPE
190
+ )
191
 
192
+ # Wait a moment for the app to start
193
+ time.sleep(3)
 
194
 
195
+ # Check if the process is still running
196
+ if process.poll() is not None:
197
+ stdout, stderr = process.communicate()
198
+ return None, f"App failed to start (exit code: {process.returncode})\nStdout: {stdout.decode('utf-8')}\nStderr: {stderr.decode('utf-8')}"
199
+
200
+ # Store the process and file path
201
+ processes[app_id] = {
202
+ "process": process,
203
+ "file": file_path,
204
+ "port": port
205
+ }
206
+
207
+ return port, None
208
  except Exception as e:
209
  import traceback
210
+ return None, f"Error starting app: {str(e)}\n{traceback.format_exc()}"
211
 
212
+ # Function to stop a running app
213
+ def stop_gradio_app(app_id):
214
+ """Stop a running Gradio app"""
215
+ global processes
216
+
217
+ if app_id in processes:
218
+ process = processes[app_id]["process"]
219
+ file_path = processes[app_id]["file"]
220
+
221
+ if process.poll() is None:
222
+ process.terminate()
223
+ try:
224
+ process.wait(timeout=5)
225
+ except:
226
+ process.kill()
227
+
228
+ # Remove the file
229
+ try:
230
+ os.unlink(file_path)
231
+ except:
232
+ pass
233
+
234
+ del processes[app_id]
235
+ return True
236
+
237
+ return False
238
+
239
+ # Clean up on exit
240
+ def cleanup():
241
+ """Clean up all running processes and temporary files"""
242
+ for app_id in list(processes.keys()):
243
+ stop_gradio_app(app_id)
244
+
245
+ import atexit
246
+ atexit.register(cleanup)
247
+
248
+ # Import sys after we've defined all the functions
249
+ import sys
250
+
251
+ # Main Gradio interface
252
+ with gr.Blocks(title="LLM Gradio App Generator") as demo:
253
  # Header
254
  gr.Markdown("# 🤖 LLM Gradio App Generator")
255
  gr.Markdown("Generate and run Gradio apps dynamically!")
256
 
257
+ # App ID for tracking the current app
258
+ app_id = gr.State("")
259
+
260
  with gr.Row():
261
+ # Left column (input)
262
  with gr.Column(scale=1):
263
  # App description input
264
  prompt = gr.Textbox(
 
268
  )
269
 
270
  # Example buttons
271
+ gr.Markdown("### Try These Examples:")
272
+ with gr.Row():
273
+ hello_btn = gr.Button("Hello World")
274
+ calc_btn = gr.Button("Calculator")
275
+ image_btn = gr.Button("Image Filter")
276
 
277
  # Generate button
278
+ with gr.Row():
279
+ generate_btn = gr.Button("Generate & Run App", variant="primary")
280
+ stop_btn = gr.Button("Stop App", variant="stop")
281
 
282
+ # Display the generated code
283
+ with gr.Accordion("Generated Code", open=False):
284
+ code_output = gr.Code(language="python", label="Python Code")
285
 
286
+ # Status message
287
+ status_output = gr.Markdown("Enter a description and click 'Generate & Run App'")
 
288
 
289
+ # Right column (output)
290
  with gr.Column(scale=2):
291
+ # Frame to display the running app
292
+ app_frame = gr.HTML(
293
+ """<div style="display:flex; justify-content:center; align-items:center; height:600px; border:1px dashed #ccc; border-radius:8px;">
 
 
 
294
  <div style="text-align:center;">
295
+ <h3>App Preview</h3>
296
+ <p>Generate an app to see it here</p>
297
  </div>
298
  </div>"""
299
  )
300
 
301
  # Example button functions
302
+ def use_example(example_text):
303
+ return example_text
304
 
305
  hello_btn.click(
306
+ lambda: use_example("A simple hello world app that greets the user by name"),
307
  inputs=None,
308
  outputs=prompt
309
  )
310
 
311
  calc_btn.click(
312
+ lambda: use_example("A calculator app that can add, subtract, multiply and divide two numbers"),
313
  inputs=None,
314
  outputs=prompt
315
  )
316
 
317
+ image_btn.click(
318
+ lambda: use_example("An image filter app that can apply grayscale, invert, and sepia filters to images"),
319
  inputs=None,
320
  outputs=prompt
321
  )
322
 
323
+ # Generate and run the app
324
+ def on_generate_click(prompt_text, current_app_id):
325
  if not prompt_text:
326
+ return current_app_id, "", "Please enter a description of the app you want to generate.", app_frame.value
327
+
328
+ # Stop the current app if running
329
+ if current_app_id:
330
+ stop_gradio_app(current_app_id)
331
+
332
+ # Generate a new app ID
333
+ new_app_id = random_string()
334
 
335
  # Get code from LLM (simulated)
336
  code, error = simulate_llm_response(prompt_text)
337
  if error:
338
+ return current_app_id, "", f"Error generating code: {error}", app_frame.value
 
 
 
 
 
 
 
339
 
340
+ # Run the app
341
+ port, run_error = run_gradio_app(code, new_app_id)
342
+ if run_error:
343
+ return current_app_id, code, f"Error running app: {run_error}", app_frame.value
344
 
345
+ # Create an iframe to display the app
346
+ iframe_html = f"""
347
+ <div style="height:600px; border:1px solid #ddd; border-radius:8px; overflow:hidden;">
348
+ <iframe src="http://localhost:{port}" width="100%" height="100%" frameborder="0"></iframe>
349
+ </div>
350
+ """
 
 
 
351
 
352
+ return new_app_id, code, f"✅ App running on port {port}", iframe_html
353
+
354
+ # Stop the app
355
+ def on_stop_click(current_app_id):
356
+ if not current_app_id:
357
+ return "", "No app is currently running"
358
+
359
+ stopped = stop_gradio_app(current_app_id)
360
+
361
+ if stopped:
362
+ # Reset the frame
363
+ iframe_html = """
364
+ <div style="display:flex; justify-content:center; align-items:center; height:600px; border:1px dashed #ccc; border-radius:8px;">
365
+ <div style="text-align:center;">
366
+ <h3>App Stopped</h3>
367
+ <p>Generate a new app to see it here</p>
368
+ </div>
369
+ </div>
370
+ """
371
 
372
+ return "", f"✅ App stopped successfully", iframe_html
373
+ else:
374
+ return current_app_id, "Failed to stop the app", app_frame.value
 
 
 
 
 
 
 
 
375
 
376
  # Connect the generate button
377
  generate_btn.click(
378
+ on_generate_click,
379
+ inputs=[prompt, app_id],
380
+ outputs=[app_id, code_output, status_output, app_frame]
381
+ )
382
+
383
+ # Connect the stop button
384
+ stop_btn.click(
385
+ on_stop_click,
386
+ inputs=[app_id],
387
+ outputs=[app_id, status_output, app_frame]
388
  )
389
 
390
+ # Launch the main app
391
  if __name__ == "__main__":
392
+ demo.launch(server_name="0.0.0.0", server_port=7860)