nakas commited on
Commit
e9c6962
·
verified ·
1 Parent(s): 83a7163

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +227 -102
app.py CHANGED
@@ -7,18 +7,22 @@ import tempfile
7
  import sys
8
  import json
9
  import time
 
 
10
  import atexit
11
 
12
  # Print Python version and gradio version for debugging
13
  print(f"Python version: {sys.version}")
14
  print(f"Gradio version: {gr.__version__}")
15
 
16
- # Track running processes for cleanup
17
  running_process = None
 
18
 
19
- # Clean up running process on exit
20
- def cleanup_process():
21
- global running_process
 
22
  if running_process and running_process.poll() is None:
23
  try:
24
  running_process.terminate()
@@ -26,8 +30,34 @@ def cleanup_process():
26
  print(f"Terminated process {running_process.pid}")
27
  except Exception as e:
28
  print(f"Error terminating process: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- atexit.register(cleanup_process)
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  def call_openai_api(api_key, prompt):
33
  """Call OpenAI API to generate Gradio app code and requirements"""
@@ -54,6 +84,7 @@ Important guidelines:
54
  5. Keep the app simple and focused on the user's request
55
  6. DO NOT use any flagging callbacks
56
  7. DO NOT create or use any directories or file paths
 
57
 
58
  Example:
59
  ```python
@@ -144,83 +175,107 @@ demo.launch(server_name="0.0.0.0", server_port=7861)
144
  except Exception as e:
145
  return None, f"API call failed: {str(e)}"
146
 
147
- def install_and_run_app(code, requirements):
148
- """Install requirements and run the app in a subprocess"""
149
- global running_process
 
 
150
 
151
- try:
152
- # Clean up any previous process
153
- if running_process and running_process.poll() is None:
154
- running_process.terminate()
155
- running_process.wait(timeout=5)
156
-
157
- # Create a temporary file for the app
158
- fd, app_file = tempfile.mkstemp(suffix='.py')
159
- os.close(fd)
160
-
161
- with open(app_file, 'w') as f:
162
- f.write(code)
163
-
164
- # Install requirements
165
- install_output = ""
166
- for req in requirements:
167
- try:
168
- cmd = [sys.executable, "-m", "pip", "install", "--upgrade", "--no-cache-dir", req]
169
- result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=120)
170
- install_output += f"Installing {req}: {'SUCCESS' if result.returncode == 0 else 'FAILED'}\n"
171
- if result.returncode != 0:
172
- install_output += f"Error: {result.stderr}\n"
173
- except Exception as e:
174
- install_output += f"Error installing {req}: {str(e)}\n"
175
-
176
- # Run the app
177
- running_process = subprocess.Popen(
178
- [sys.executable, app_file],
179
- stdout=subprocess.PIPE,
180
- stderr=subprocess.PIPE,
181
- text=True
182
- )
183
-
184
- # Wait a bit for the app to start
185
- time.sleep(5)
186
-
187
- # Check if the process is still running
188
- if running_process.poll() is not None:
189
- stdout, stderr = running_process.communicate()
190
- os.unlink(app_file)
191
- return None, f"App failed to start:\n{stderr}\n\nInstallation log:\n{install_output}"
192
-
193
- return {
194
- "app_file": app_file,
195
- "install_output": install_output
196
- }, None
197
- except Exception as e:
198
- if 'app_file' in locals() and os.path.exists(app_file):
199
- os.unlink(app_file)
200
- return None, f"Error setting up and running app: {str(e)}"
201
 
202
- def stop_running_app():
203
- """Stop the running app"""
204
- global running_process
205
 
 
206
  if running_process and running_process.poll() is None:
 
207
  try:
208
- running_process.terminate()
209
  running_process.wait(timeout=5)
210
- running_process = None
211
- return True
212
- except Exception as e:
213
- print(f"Error stopping app: {str(e)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
- running_process = None
216
- return False
 
 
 
 
 
 
 
 
 
 
 
217
 
218
  # Create the Gradio interface
219
  with gr.Blocks(title="Gradio App Generator") as demo:
220
  gr.Markdown("# 🤖 Gradio App Generator")
221
  gr.Markdown("""
222
  This app generates a Gradio application based on your description, installs required packages,
223
- and runs it directly. The generated app will be displayed below.
224
  """)
225
 
226
  with gr.Row():
@@ -245,8 +300,13 @@ with gr.Blocks(title="Gradio App Generator") as demo:
245
  with gr.Accordion("Generated Code", open=False):
246
  code_output = gr.Code(language="python", label="App Code")
247
 
248
- with gr.Accordion("Installation Log", open=False):
249
- install_output = gr.Textbox(label="Package Installation Log", lines=5)
 
 
 
 
 
250
 
251
  status_output = gr.Markdown("")
252
 
@@ -254,15 +314,20 @@ with gr.Blocks(title="Gradio App Generator") as demo:
254
  # Frame to display the running app
255
  app_frame = gr.HTML("<div style='text-align:center; padding:50px;'><h3>Your generated app will appear here</h3></div>")
256
 
257
- # App file path storage
258
  app_file_state = gr.State(None)
259
 
260
  def on_generate(api_key_val, prompt_val):
 
 
 
 
261
  # Validate API key
262
  if not api_key_val or len(api_key_val) < 20 or not api_key_val.startswith("sk-"):
263
  return (
264
- None, None, "⚠️ Please provide a valid OpenAI API key",
265
  "<div style='text-align:center; padding:50px;'><h3>Invalid API key</h3></div>",
 
266
  gr.update(visible=False), None
267
  )
268
 
@@ -270,16 +335,18 @@ with gr.Blocks(title="Gradio App Generator") as demo:
270
  # Generate app code and requirements
271
  status_message = "⏳ Generating app code..."
272
  yield (
273
- None, None, status_message,
274
  "<div style='text-align:center; padding:50px;'><h3>Generating code...</h3></div>",
 
275
  gr.update(visible=False), None
276
  )
277
 
278
  app_info, error = call_openai_api(api_key_val, prompt_val)
279
  if error or not app_info:
280
  return (
281
- None, None, f"⚠️ {error or 'Failed to generate app'}",
282
  "<div style='text-align:center; padding:50px;'><h3>Error generating app</h3></div>",
 
283
  gr.update(visible=False), None
284
  )
285
 
@@ -293,19 +360,66 @@ with gr.Blocks(title="Gradio App Generator") as demo:
293
  else:
294
  code += "\n\ndemo.launch(server_name=\"0.0.0.0\", server_port=7861)"
295
 
296
- status_message = "⏳ Installing packages and starting app..."
297
  yield (
298
- code, None, status_message,
299
  "<div style='text-align:center; padding:50px;'><h3>Installing packages...</h3></div>",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  gr.update(visible=False), None
301
  )
302
 
303
- # Install packages and run the app
304
- run_result, run_error = install_and_run_app(code, requirements)
305
- if run_error or not run_result:
 
 
 
 
 
 
306
  return (
307
- code, None, f"⚠️ {run_error}",
308
- "<div style='text-align:center; padding:50px;'><h3>Error running app</h3></div>",
 
309
  gr.update(visible=False), None
310
  )
311
 
@@ -317,56 +431,67 @@ with gr.Blocks(title="Gradio App Generator") as demo:
317
  """
318
 
319
  return (
320
- code, run_result["install_output"], f"✅ App is running! View it below.",
321
- iframe_html, gr.update(visible=True), run_result["app_file"]
 
 
322
  )
323
  except Exception as e:
324
  import traceback
325
  error_details = traceback.format_exc()
326
  return (
327
- None, None, f"⚠️ Error: {str(e)}\n\n{error_details}",
328
  "<div style='text-align:center; padding:50px;'><h3>An error occurred</h3></div>",
 
329
  gr.update(visible=False), None
330
  )
331
 
332
  def on_stop(app_file):
333
- stopped = stop_running_app()
 
 
 
 
 
 
 
 
 
334
 
335
  # Clean up the app file
336
  if app_file and os.path.exists(app_file):
337
  try:
338
  os.unlink(app_file)
 
 
339
  except:
340
  pass
341
 
342
- if stopped:
343
- return (
344
- " App stopped successfully",
345
- "<div style='text-align:center; padding:50px;'><h3>App stopped</h3></div>",
346
- gr.update(visible=False), None
347
- )
348
- else:
349
- return (
350
- "⚠️ No app was running",
351
- "<div style='text-align:center; padding:50px;'><h3>No app was running</h3></div>",
352
- gr.update(visible=False), None
353
- )
354
 
355
  generate_btn.click(
356
  on_generate,
357
  inputs=[api_key, prompt],
358
  outputs=[
359
- code_output, install_output, status_output, app_frame,
360
- stop_btn, app_file_state
361
  ]
362
  )
363
 
364
  stop_btn.click(
365
  on_stop,
366
  inputs=[app_file_state],
367
- outputs=[status_output, app_frame, stop_btn, app_file_state]
 
 
 
368
  )
369
 
370
  if __name__ == "__main__":
371
  # Make sure we're not trying to use flagging
372
- demo.launch(server_name="0.0.0.0", server_port=7860, flagging_callback=None)
 
7
  import sys
8
  import json
9
  import time
10
+ import threading
11
+ import queue
12
  import atexit
13
 
14
  # Print Python version and gradio version for debugging
15
  print(f"Python version: {sys.version}")
16
  print(f"Gradio version: {gr.__version__}")
17
 
18
+ # Track running processes and resources for cleanup
19
  running_process = None
20
+ temp_files = []
21
 
22
+ # Clean up resources on exit
23
+ def cleanup_resources():
24
+ global running_process, temp_files
25
+ # Stop any running process
26
  if running_process and running_process.poll() is None:
27
  try:
28
  running_process.terminate()
 
30
  print(f"Terminated process {running_process.pid}")
31
  except Exception as e:
32
  print(f"Error terminating process: {e}")
33
+
34
+ # Remove temporary files
35
+ for file_path in temp_files:
36
+ if os.path.exists(file_path):
37
+ try:
38
+ os.unlink(file_path)
39
+ print(f"Removed temporary file: {file_path}")
40
+ except Exception as e:
41
+ print(f"Error removing file {file_path}: {e}")
42
+
43
+ atexit.register(cleanup_resources)
44
+
45
+ # Queue for capturing subprocess output
46
+ output_queue = queue.Queue()
47
 
48
+ def read_output(process, output_queue):
49
+ """Read output from a process and put it in a queue"""
50
+ for line in iter(process.stdout.readline, ''):
51
+ if line:
52
+ output_queue.put(line)
53
+ process.stdout.close()
54
+
55
+ def read_error(process, output_queue):
56
+ """Read error output from a process and put it in a queue"""
57
+ for line in iter(process.stderr.readline, ''):
58
+ if line:
59
+ output_queue.put(f"ERROR: {line}")
60
+ process.stderr.close()
61
 
62
  def call_openai_api(api_key, prompt):
63
  """Call OpenAI API to generate Gradio app code and requirements"""
 
84
  5. Keep the app simple and focused on the user's request
85
  6. DO NOT use any flagging callbacks
86
  7. DO NOT create or use any directories or file paths
87
+ 8. Do not use features from newer Gradio versions
88
 
89
  Example:
90
  ```python
 
175
  except Exception as e:
176
  return None, f"API call failed: {str(e)}"
177
 
178
+ def install_package(package, output_queue):
179
+ """Install a package and send output to the queue"""
180
+ cmd = [sys.executable, "-m", "pip", "install", "--upgrade", package]
181
+ print(f"Installing: {package}")
182
+ output_queue.put(f"Installing: {package}\n")
183
 
184
+ process = subprocess.Popen(
185
+ cmd,
186
+ stdout=subprocess.PIPE,
187
+ stderr=subprocess.PIPE,
188
+ text=True,
189
+ bufsize=1
190
+ )
191
+
192
+ # Start threads to read output
193
+ stdout_thread = threading.Thread(target=read_output, args=(process, output_queue))
194
+ stderr_thread = threading.Thread(target=read_error, args=(process, output_queue))
195
+
196
+ stdout_thread.daemon = True
197
+ stderr_thread.daemon = True
198
+
199
+ stdout_thread.start()
200
+ stderr_thread.start()
201
+
202
+ # Wait for the process to complete
203
+ process.wait()
204
+
205
+ # Wait for threads to finish
206
+ stdout_thread.join()
207
+ stderr_thread.join()
208
+
209
+ if process.returncode == 0:
210
+ output_queue.put(f"Successfully installed {package}\n")
211
+ return True
212
+ else:
213
+ output_queue.put(f"Failed to install {package} (error code: {process.returncode})\n")
214
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
+ def run_app(app_code, output_queue):
217
+ """Run the app in a separate process"""
218
+ global running_process, temp_files
219
 
220
+ # Stop any existing process
221
  if running_process and running_process.poll() is None:
222
+ running_process.terminate()
223
  try:
 
224
  running_process.wait(timeout=5)
225
+ except subprocess.TimeoutExpired:
226
+ running_process.kill()
227
+
228
+ # Create a temporary file for the app
229
+ fd, app_file = tempfile.mkstemp(suffix='.py')
230
+ os.close(fd)
231
+
232
+ with open(app_file, 'w') as f:
233
+ f.write(app_code)
234
+
235
+ temp_files.append(app_file)
236
+
237
+ # Make sure the code has the correct launch parameters
238
+ if "demo.launch" not in app_code:
239
+ with open(app_file, 'a') as f:
240
+ f.write("\n\ndemo.launch(server_name='0.0.0.0', server_port=7861)\n")
241
+
242
+ # Run the app
243
+ output_queue.put(f"Starting the app...\n")
244
+ running_process = subprocess.Popen(
245
+ [sys.executable, app_file],
246
+ stdout=subprocess.PIPE,
247
+ stderr=subprocess.PIPE,
248
+ text=True,
249
+ bufsize=1
250
+ )
251
+
252
+ # Start threads to read output
253
+ stdout_thread = threading.Thread(target=read_output, args=(running_process, output_queue))
254
+ stderr_thread = threading.Thread(target=read_error, args=(running_process, output_queue))
255
+
256
+ stdout_thread.daemon = True
257
+ stderr_thread.daemon = True
258
 
259
+ stdout_thread.start()
260
+ stderr_thread.start()
261
+
262
+ # Wait a bit for the app to start
263
+ time.sleep(5)
264
+
265
+ # Check if the process is still running
266
+ if running_process.poll() is not None:
267
+ output_queue.put(f"App failed to start (error code: {running_process.returncode})\n")
268
+ return False, app_file
269
+
270
+ output_queue.put(f"App is running on port 7861\n")
271
+ return True, app_file
272
 
273
  # Create the Gradio interface
274
  with gr.Blocks(title="Gradio App Generator") as demo:
275
  gr.Markdown("# 🤖 Gradio App Generator")
276
  gr.Markdown("""
277
  This app generates a Gradio application based on your description, installs required packages,
278
+ and runs it directly within this container. The generated app will be displayed below.
279
  """)
280
 
281
  with gr.Row():
 
300
  with gr.Accordion("Generated Code", open=False):
301
  code_output = gr.Code(language="python", label="App Code")
302
 
303
+ progress_output = gr.Textbox(
304
+ label="Progress Log",
305
+ lines=10,
306
+ max_lines=20,
307
+ autoscroll=True,
308
+ interactive=False
309
+ )
310
 
311
  status_output = gr.Markdown("")
312
 
 
314
  # Frame to display the running app
315
  app_frame = gr.HTML("<div style='text-align:center; padding:50px;'><h3>Your generated app will appear here</h3></div>")
316
 
317
+ # App file storage
318
  app_file_state = gr.State(None)
319
 
320
  def on_generate(api_key_val, prompt_val):
321
+ # Initialize output queue
322
+ global output_queue
323
+ output_queue = queue.Queue()
324
+
325
  # Validate API key
326
  if not api_key_val or len(api_key_val) < 20 or not api_key_val.startswith("sk-"):
327
  return (
328
+ None, "⚠️ Please provide a valid OpenAI API key",
329
  "<div style='text-align:center; padding:50px;'><h3>Invalid API key</h3></div>",
330
+ "Please enter a valid OpenAI API key",
331
  gr.update(visible=False), None
332
  )
333
 
 
335
  # Generate app code and requirements
336
  status_message = "⏳ Generating app code..."
337
  yield (
338
+ None, status_message,
339
  "<div style='text-align:center; padding:50px;'><h3>Generating code...</h3></div>",
340
+ "Generating app code...",
341
  gr.update(visible=False), None
342
  )
343
 
344
  app_info, error = call_openai_api(api_key_val, prompt_val)
345
  if error or not app_info:
346
  return (
347
+ None, f"⚠️ {error or 'Failed to generate app'}",
348
  "<div style='text-align:center; padding:50px;'><h3>Error generating app</h3></div>",
349
+ f"Error: {error or 'Failed to generate app'}",
350
  gr.update(visible=False), None
351
  )
352
 
 
360
  else:
361
  code += "\n\ndemo.launch(server_name=\"0.0.0.0\", server_port=7861)"
362
 
363
+ status_message = "⏳ Installing packages..."
364
  yield (
365
+ code, status_message,
366
  "<div style='text-align:center; padding:50px;'><h3>Installing packages...</h3></div>",
367
+ "Starting package installation...",
368
+ gr.update(visible=False), None
369
+ )
370
+
371
+ # Install packages one by one with real-time updates
372
+ install_results = []
373
+ for i, package in enumerate(requirements):
374
+ success = install_package(package, output_queue)
375
+ install_results.append(success)
376
+
377
+ # Update the progress output
378
+ progress_text = ""
379
+ while not output_queue.empty():
380
+ progress_text += output_queue.get_nowait()
381
+
382
+ yield (
383
+ code, f"⏳ Installing packages ({i+1}/{len(requirements)})...",
384
+ "<div style='text-align:center; padding:50px;'><h3>Installing packages...</h3></div>",
385
+ progress_text,
386
+ gr.update(visible=False), None
387
+ )
388
+
389
+ # Check if all packages were installed successfully
390
+ if not all(install_results):
391
+ progress_text = ""
392
+ while not output_queue.empty():
393
+ progress_text += output_queue.get_nowait()
394
+
395
+ return (
396
+ code, "⚠️ Some packages failed to install",
397
+ "<div style='text-align:center; padding:50px;'><h3>Error installing packages</h3></div>",
398
+ progress_text,
399
+ gr.update(visible=False), None
400
+ )
401
+
402
+ status_message = "⏳ Starting the app..."
403
+ yield (
404
+ code, status_message,
405
+ "<div style='text-align:center; padding:50px;'><h3>Starting app...</h3></div>",
406
+ progress_text,
407
  gr.update(visible=False), None
408
  )
409
 
410
+ # Run the app
411
+ success, app_file = run_app(code, output_queue)
412
+
413
+ # Update the progress output again
414
+ progress_text = ""
415
+ while not output_queue.empty():
416
+ progress_text += output_queue.get_nowait()
417
+
418
+ if not success:
419
  return (
420
+ code, "⚠️ Failed to start the app",
421
+ "<div style='text-align:center; padding:50px;'><h3>Error starting app</h3></div>",
422
+ progress_text,
423
  gr.update(visible=False), None
424
  )
425
 
 
431
  """
432
 
433
  return (
434
+ code, f"✅ App is running! View it below.",
435
+ iframe_html,
436
+ progress_text,
437
+ gr.update(visible=True), app_file
438
  )
439
  except Exception as e:
440
  import traceback
441
  error_details = traceback.format_exc()
442
  return (
443
+ None, f"⚠️ Error: {str(e)}",
444
  "<div style='text-align:center; padding:50px;'><h3>An error occurred</h3></div>",
445
+ f"Error: {str(e)}\n\n{error_details}",
446
  gr.update(visible=False), None
447
  )
448
 
449
  def on_stop(app_file):
450
+ global running_process
451
+
452
+ if running_process and running_process.poll() is None:
453
+ running_process.terminate()
454
+ try:
455
+ running_process.wait(timeout=5)
456
+ except subprocess.TimeoutExpired:
457
+ running_process.kill()
458
+
459
+ running_process = None
460
 
461
  # Clean up the app file
462
  if app_file and os.path.exists(app_file):
463
  try:
464
  os.unlink(app_file)
465
+ if app_file in temp_files:
466
+ temp_files.remove(app_file)
467
  except:
468
  pass
469
 
470
+ return (
471
+ "✅ App stopped",
472
+ "<div style='text-align:center; padding:50px;'><h3>App stopped</h3></div>",
473
+ "App has been stopped",
474
+ gr.update(visible=False), None
475
+ )
 
 
 
 
 
 
476
 
477
  generate_btn.click(
478
  on_generate,
479
  inputs=[api_key, prompt],
480
  outputs=[
481
+ code_output, status_output, app_frame,
482
+ progress_output, stop_btn, app_file_state
483
  ]
484
  )
485
 
486
  stop_btn.click(
487
  on_stop,
488
  inputs=[app_file_state],
489
+ outputs=[
490
+ status_output, app_frame, progress_output,
491
+ stop_btn, app_file_state
492
+ ]
493
  )
494
 
495
  if __name__ == "__main__":
496
  # Make sure we're not trying to use flagging
497
+ demo.queue().launch(server_name="0.0.0.0", server_port=7860, flagging_callback=None)