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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +151 -211
app.py CHANGED
@@ -1,26 +1,47 @@
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": """
25
  import gradio as gr
26
 
@@ -31,13 +52,14 @@ demo = gr.Interface(
31
  fn=greet,
32
  inputs=gr.Textbox(label="Your Name"),
33
  outputs=gr.Textbox(label="Greeting"),
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": """
42
  import gradio as gr
43
 
@@ -61,13 +83,14 @@ demo = gr.Interface(
61
  gr.Radio(["Add", "Subtract", "Multiply", "Divide"], label="Operation")
62
  ],
63
  outputs=gr.Textbox(label="Result"),
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": """
72
  import gradio as gr
73
  import numpy as np
@@ -101,290 +124,207 @@ demo = gr.Interface(
101
  gr.Radio(["Grayscale", "Invert", "Sepia"], label="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
 
113
- # Function to simulate LLM API call
114
- def simulate_llm_response(prompt):
115
- """Simulate an LLM response based on the prompt"""
116
- prompt_lower = prompt.lower()
117
-
118
- if "hello" in prompt_lower or "greet" in prompt_lower:
119
- return EXAMPLE_CODES["hello_world"], None
120
- elif "calculat" in prompt_lower or "math" in prompt_lower or "arithmetic" in prompt_lower:
121
- return EXAMPLE_CODES["calculator"], None
122
- elif "image" in prompt_lower or "filter" in prompt_lower or "photo" in prompt_lower:
123
- return EXAMPLE_CODES["image_filter"], None
124
- else:
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(
265
- label="Describe the app you want",
266
- placeholder="e.g., A calculator app that can perform basic arithmetic",
267
- lines=3
 
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
 
1
  import gradio as gr
 
2
  import tempfile
3
+ import os
4
+ import sys
5
  import subprocess
6
+ import time
 
 
7
  import random
8
  import string
9
+ import signal
10
+ import atexit
11
 
12
+ # Set environment variable to avoid matplotlib issues
13
  os.environ['MPLCONFIGDIR'] = '/tmp'
14
 
15
+ # Create a temp directory for our app files
16
  TEMP_DIR = os.path.join(tempfile.gettempdir(), "gradio_apps")
17
  os.makedirs(TEMP_DIR, exist_ok=True)
18
 
19
  # Track running processes
20
+ running_process = None
21
+ current_port = None
22
+ current_file = None
23
 
24
+ # Cleanup function to ensure we don't leave processes running
25
+ def cleanup():
26
+ global running_process, current_file
27
+ if running_process and running_process.poll() is None:
28
+ try:
29
+ running_process.terminate()
30
+ running_process.wait(timeout=5)
31
+ except:
32
+ running_process.kill()
33
+
34
+ if current_file and os.path.exists(current_file):
35
+ try:
36
+ os.unlink(current_file)
37
+ except:
38
+ pass
39
+
40
+ # Register cleanup
41
+ atexit.register(cleanup)
42
+
43
+ # Example Gradio app codes to choose from
44
+ EXAMPLE_APPS = {
45
  "hello_world": """
46
  import gradio as gr
47
 
 
52
  fn=greet,
53
  inputs=gr.Textbox(label="Your Name"),
54
  outputs=gr.Textbox(label="Greeting"),
55
+ title="Hello World App",
56
  description="A simple greeting app"
57
  )
58
 
59
+ # Launch on specified port
60
  demo.launch(server_name="0.0.0.0", server_port=PORT)
61
  """,
62
+
63
  "calculator": """
64
  import gradio as gr
65
 
 
83
  gr.Radio(["Add", "Subtract", "Multiply", "Divide"], label="Operation")
84
  ],
85
  outputs=gr.Textbox(label="Result"),
86
+ title="Calculator App",
87
  description="Perform basic arithmetic operations"
88
  )
89
 
90
+ # Launch on specified port
91
  demo.launch(server_name="0.0.0.0", server_port=PORT)
92
  """,
93
+
94
  "image_filter": """
95
  import gradio as gr
96
  import numpy as np
 
124
  gr.Radio(["Grayscale", "Invert", "Sepia"], label="Filter")
125
  ],
126
  outputs=gr.Image(type="pil"),
127
+ title="Image Filter App",
128
+ description="Apply different filters to your images"
 
129
  )
130
 
131
+ # Launch on specified port
132
  demo.launch(server_name="0.0.0.0", server_port=PORT)
133
  """
134
  }
135
 
136
+ # Function to find an available port
137
+ def find_available_port(start=7870):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  import socket
139
+ port = start
140
+ while True:
141
+ try:
142
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
143
+ s.bind(('localhost', port))
144
+ return port
145
+ except OSError:
146
+ port += 1
 
 
 
 
 
 
 
 
 
147
 
148
  # Function to run a Gradio app as a subprocess
149
+ def run_app(app_code, port):
150
+ global running_process, current_file
 
151
 
152
+ # Stop any existing app
153
+ stop_app()
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ # Replace PORT in the code
156
+ app_code = app_code.replace("PORT", str(port))
 
157
 
158
+ # Create a temporary file
159
+ fd, filepath = tempfile.mkstemp(suffix='.py', dir=TEMP_DIR)
160
+ os.close(fd)
161
 
162
+ with open(filepath, 'w') as f:
163
+ f.write(app_code)
164
 
165
+ # Store the current file path
166
+ current_file = filepath
 
 
167
 
168
+ # Run the app
169
  try:
170
  process = subprocess.Popen(
171
+ [sys.executable, filepath],
172
  stdout=subprocess.PIPE,
173
  stderr=subprocess.PIPE
174
  )
175
 
176
+ # Store the process
177
+ running_process = process
178
+
179
  # Wait a moment for the app to start
180
+ time.sleep(2)
181
 
182
  # Check if the process is still running
183
  if process.poll() is not None:
184
+ # Process failed to start
185
  stdout, stderr = process.communicate()
186
+ error_msg = f"App failed to start: {stderr.decode('utf-8')}"
187
+ return None, error_msg
 
 
 
 
 
 
188
 
189
  return port, None
190
  except Exception as e:
191
+ return None, f"Error starting app: {str(e)}"
 
192
 
193
+ # Function to stop the running app
194
+ def stop_app():
195
+ global running_process, current_file
 
196
 
197
+ if running_process and running_process.poll() is None:
198
+ running_process.terminate()
199
+ try:
200
+ running_process.wait(timeout=5)
201
+ except:
202
+ running_process.kill()
203
+
204
+ if current_file and os.path.exists(current_file):
 
 
 
 
205
  try:
206
+ os.unlink(current_file)
207
  except:
208
  pass
 
 
 
209
 
210
+ running_process = None
211
+ current_file = None
 
 
 
 
 
212
 
213
+ # Function to select an app based on description
214
+ def select_app(description):
215
+ description = description.lower()
216
+
217
+ if "hello" in description or "greet" in description:
218
+ return EXAMPLE_APPS["hello_world"]
219
+ elif "calculat" in description or "math" in description or "arithmetic" in description:
220
+ return EXAMPLE_APPS["calculator"]
221
+ elif "image" in description or "filter" in description or "photo" in description:
222
+ return EXAMPLE_APPS["image_filter"]
223
+ else:
224
+ # Default to hello world
225
+ return EXAMPLE_APPS["hello_world"]
226
 
227
  # Main Gradio interface
228
+ with gr.Blocks(title="Gradio App Generator") as demo:
229
+ gr.Markdown("# 🔄 Dynamic Gradio App Generator")
230
+ gr.Markdown("Select an app type to generate and run it dynamically")
 
 
 
 
231
 
232
  with gr.Row():
 
233
  with gr.Column(scale=1):
234
+ # Input area
235
+ app_description = gr.Textbox(
236
+ label="App Description",
237
+ placeholder="Describe the app you want to generate...",
238
+ lines=3,
239
+ value="A calculator app that performs basic arithmetic"
240
  )
241
 
242
  # Example buttons
 
243
  with gr.Row():
244
  hello_btn = gr.Button("Hello World")
245
  calc_btn = gr.Button("Calculator")
246
  image_btn = gr.Button("Image Filter")
247
 
248
+ # Generate and stop buttons
249
  with gr.Row():
250
  generate_btn = gr.Button("Generate & Run App", variant="primary")
251
  stop_btn = gr.Button("Stop App", variant="stop")
252
 
253
+ # Code display
254
  with gr.Accordion("Generated Code", open=False):
255
+ code_display = gr.Code(language="python")
256
 
257
  # Status message
258
+ status_msg = gr.Markdown("")
259
 
 
260
  with gr.Column(scale=2):
261
+ # Preview area
262
+ app_frame = gr.HTML("<div style='border:1px dashed #ccc; height:500px; display:flex; justify-content:center; align-items:center;'><p>App will appear here</p></div>")
 
 
 
 
 
 
 
263
 
264
+ # Example button handlers
265
+ def set_description(desc):
266
+ return desc
267
 
268
  hello_btn.click(
269
+ lambda: set_description("A hello world app that greets the user by name"),
270
  inputs=None,
271
+ outputs=app_description
272
  )
273
 
274
  calc_btn.click(
275
+ lambda: set_description("A calculator app that performs basic arithmetic"),
276
  inputs=None,
277
+ outputs=app_description
278
  )
279
 
280
  image_btn.click(
281
+ lambda: set_description("An image filter app that can apply effects to photos"),
282
  inputs=None,
283
+ outputs=app_description
284
  )
285
 
286
+ # Generate button handler
287
+ def on_generate(description):
288
+ if not description:
289
+ return None, "Please enter a description", "<div style='border:1px dashed #ccc; height:500px; display:flex; justify-content:center; align-items:center;'><p>Enter a description first</p></div>"
290
 
291
+ # Select app based on description
292
+ app_code = select_app(description)
 
293
 
294
+ # Find an available port
295
+ port = find_available_port()
 
 
 
 
 
296
 
297
  # Run the app
298
+ result_port, error = run_app(app_code, port)
299
+
300
+ if error:
301
+ return app_code, f"Error: {error}", "<div style='border:1px solid #f44336; height:500px; display:flex; justify-content:center; align-items:center;'><p>Failed to start app:<br>{error}</p></div>"
302
 
303
+ # Create iframe to show the app
304
  iframe_html = f"""
305
+ <div style="border:1px solid #ddd; height:500px; overflow:hidden;">
306
+ <iframe src="http://localhost:{result_port}" width="100%" height="100%" frameborder="0"></iframe>
307
  </div>
308
  """
309
 
310
+ return app_code, f"✅ App running on port {result_port}", iframe_html
311
 
312
+ # Stop button handler
313
+ def on_stop():
314
+ stop_app()
315
+ return "✅ App stopped", "<div style='border:1px dashed #ccc; height:500px; display:flex; justify-content:center; align-items:center;'><p>App stopped</p></div>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
316
 
317
+ # Connect buttons to handlers
318
  generate_btn.click(
319
+ on_generate,
320
+ inputs=app_description,
321
+ outputs=[code_display, status_msg, app_frame]
322
  )
323
 
 
324
  stop_btn.click(
325
+ on_stop,
326
+ inputs=None,
327
+ outputs=[status_msg, app_frame]
328
  )
329
 
330
  # Launch the main app