nakas commited on
Commit
1368c37
·
verified ·
1 Parent(s): 8be8236

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +382 -208
app.py CHANGED
@@ -1,113 +1,104 @@
1
  import gradio as gr
2
  import requests
3
  import re
4
- import tempfile
5
- import importlib.util
6
- import sys
7
  import os
8
- import traceback
9
-
10
- # Print Gradio version for debugging
11
- GRADIO_VERSION = gr.__version__
12
- print(f"Using Gradio version: {GRADIO_VERSION}")
13
-
14
- # Minimal hardcoded apps that should work with any Gradio version
15
- HELLO_WORLD_APP = """
16
- import gradio as gr
17
-
18
- def hello_world():
19
- return "Hello, World!"
20
-
21
- demo = gr.Interface(
22
- fn=hello_world,
23
- inputs=None,
24
- outputs="text"
25
- )
26
- """
27
 
28
- CALCULATOR_APP = """
29
- import gradio as gr
 
30
 
31
- def calculate(a, b, operation):
32
- if operation == "add":
33
- return a + b
34
- elif operation == "subtract":
35
- return a - b
36
- elif operation == "multiply":
37
- return a * b
38
- elif operation == "divide":
39
- return a / b if b != 0 else "Error: Division by zero"
40
- else:
41
- return "Invalid operation"
42
 
43
- demo = gr.Interface(
44
- fn=calculate,
45
- inputs=[
46
- gr.Number(label="First Number"),
47
- gr.Number(label="Second Number"),
48
- gr.Radio(["add", "subtract", "multiply", "divide"], label="Operation")
49
- ],
50
- outputs="text"
51
- )
52
- """
53
 
54
- TEXT_ANALYZER_APP = """
55
- import gradio as gr
56
 
57
- def analyze_text(text):
58
- if not text:
59
- return "Please enter some text"
60
-
61
- num_chars = len(text)
62
- num_words = len(text.split())
63
-
64
- return f"Characters: {num_chars}, Words: {num_words}"
 
 
65
 
66
- demo = gr.Interface(
67
- fn=analyze_text,
68
- inputs="text",
69
- outputs="text"
70
- )
71
- """
72
 
73
  def call_openai_api(api_key, prompt):
74
- """Direct API call to OpenAI with minimal output requirements"""
75
  headers = {
76
  "Content-Type": "application/json",
77
  "Authorization": f"Bearer {api_key}"
78
  }
79
 
80
- system_prompt = """You are an expert Gradio developer.
81
- Create a standalone Gradio application based on the user's prompt.
82
- Your response should ONLY include Python code without any explanation.
 
 
 
 
 
 
 
83
 
84
- IMPORTANT: Use the MOST BASIC Gradio features ONLY.
85
- - Use gr.Interface() instead of gr.Blocks()
86
- - Use string literals "text" for text inputs/outputs
87
- - Do not use any component methods like .click() or event handlers
88
- - Do not use component properties or attributes
89
- - Keep it extremely simple
 
 
 
 
 
 
90
 
91
- Example of a valid app:
92
 
93
  ```python
94
  import gradio as gr
 
95
 
96
- def my_function(text_input):
97
- return f"You entered: {text_input}"
 
 
98
 
 
99
  demo = gr.Interface(
100
- fn=my_function,
101
- inputs="text",
102
- outputs="text"
 
103
  )
104
- ```
105
 
106
- The code must:
107
- 1. Import only gradio and basic Python libraries
108
- 2. Define simple functions
109
- 3. Create a minimal gr.Interface named 'demo'
110
- 4. NOT include a launch command or if __name__ == "__main__" block
111
  """
112
 
113
  data = {
@@ -131,154 +122,337 @@ The code must:
131
  return None, f"API Error: {response.status_code} - {response.text}"
132
 
133
  result = response.json()
134
- return result["choices"][0]["message"]["content"], None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  except Exception as e:
136
- return None, f"API Error: {str(e)}"
137
 
138
- def extract_code_blocks(text):
139
- """Extract code blocks from markdown"""
140
- pattern = r'```(?:python)?\s*([\s\S]*?)```'
141
- matches = re.findall(pattern, text)
142
-
143
- if not matches and text.strip():
144
- if re.search(r'import\s+\w+|def\s+\w+\(|class\s+\w+:', text):
145
- return [text.strip()]
146
-
147
- return [match.strip() for match in matches]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
- def load_generated_app(code):
150
- """Load and run the generated Gradio app"""
151
- # Save code to temp file
152
- with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f:
153
- f.write(code.encode('utf-8'))
154
- temp_file = f.name
155
-
156
  try:
157
- # Import module
158
- module_name = os.path.basename(temp_file).replace('.py', '')
159
- spec = importlib.util.spec_from_file_location(module_name, temp_file)
160
- module = importlib.util.module_from_spec(spec)
161
- sys.modules[module_name] = module
162
- spec.loader.exec_module(module)
163
 
164
- # Get the Gradio interface
165
- if hasattr(module, 'demo'):
166
- return module.demo, None
167
- else:
168
- return None, "No 'demo' variable found in the generated code"
169
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  except Exception as e:
171
- error_details = traceback.format_exc()
172
- return None, f"{str(e)}\n{error_details}"
173
- finally:
174
- try:
175
- os.unlink(temp_file)
176
- except:
177
- pass
178
 
179
- def get_template_app(prompt_text):
180
- """Get appropriate template app based on prompt keywords"""
181
- prompt_lower = prompt_text.lower()
182
-
183
- if "hello" in prompt_lower or "world" in prompt_lower:
184
- return HELLO_WORLD_APP
185
- elif "calculator" in prompt_lower or "math" in prompt_lower or "calculate" in prompt_lower:
186
- return CALCULATOR_APP
187
- else:
188
- return TEXT_ANALYZER_APP
 
 
 
 
189
 
190
- # Create the main UI - using the most basic approach
191
- with gr.Blocks() as demo:
192
- gr.Markdown(f"# AI Gradio App Generator (v{GRADIO_VERSION})")
193
- gr.Markdown("Describe the Gradio app you want, and I'll generate it for you.")
194
-
195
- api_key = gr.Textbox(
196
- label="OpenAI API Key",
197
- placeholder="sk-...",
198
- type="password"
199
- )
200
 
201
- prompt = gr.Textbox(
202
- label="App Description",
203
- placeholder="Describe the Gradio app you want to create...",
204
- lines=3
205
- )
206
-
207
- submit_btn = gr.Button("Generate App")
208
- template_btn = gr.Button("Use Template App")
209
-
210
- code_output = gr.Code(language="python", label="Generated Code")
211
- status_output = gr.Textbox(label="Status")
212
 
213
- app_container = gr.HTML(label="Generated App")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
- def on_submit(api_key_input, prompt_text):
 
 
 
 
 
 
 
 
 
 
 
216
  # Validate API key
217
- if not api_key_input or len(api_key_input) < 20:
218
- return None, "Please provide a valid OpenAI API key", "<p>Enter a valid API key</p>"
 
 
 
 
219
 
220
  try:
221
- # Try to generate code via API
222
- response, error = call_openai_api(api_key_input, prompt_text)
223
- if error:
224
- # Fall back to template if API fails
225
- template_code = get_template_app(prompt_text)
226
- app, app_error = load_generated_app(template_code)
227
-
228
- if app_error:
229
- return template_code, f"Template fallback also failed: {app_error}", "<p>Failed to generate app</p>"
230
-
231
- return template_code, "Using template app (API failed)", f"<iframe src='/template' width='100%' height='500px'></iframe>"
232
 
233
- # Extract code from response
234
- code_blocks = extract_code_blocks(response)
235
- if not code_blocks:
236
- template_code = get_template_app(prompt_text)
237
- return template_code, "No code found in API response, using template", f"<iframe src='/template' width='100%' height='500px'></iframe>"
238
 
239
- code = code_blocks[0]
 
 
 
 
 
240
 
241
- # Try to load the generated app
242
- app, app_error = load_generated_app(code)
243
- if app_error:
244
- # Fall back to template
245
- template_code = get_template_app(prompt_text)
246
- return template_code, f"Generated code error: {app_error}\nUsing template instead", f"<iframe src='/template' width='100%' height='500px'></iframe>"
 
 
247
 
248
- return code, "App generated successfully!", f"<iframe src='/generated' width='100%' height='500px'></iframe>"
249
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
  except Exception as e:
251
- # Final fallback
252
- template_code = get_template_app(prompt_text)
253
- return template_code, f"Error: {str(e)}\nUsing template instead", f"<iframe src='/template' width='100%' height='500px'></iframe>"
 
 
 
 
254
 
255
- def on_template(prompt_text):
256
- template_code = get_template_app(prompt_text)
257
- return template_code, "Using built-in template app", f"<iframe src='/template' width='100%' height='500px'></iframe>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
- submit_btn.click(
260
- on_submit,
261
- inputs=[api_key, prompt],
262
- outputs=[code_output, status_output, app_container]
 
 
 
263
  )
264
 
265
- template_btn.click(
266
- on_template,
267
- inputs=[prompt],
268
- outputs=[code_output, status_output, app_container]
269
  )
270
 
271
- # Hello world demo that should work with any Gradio version
272
- def hello_world():
273
- return "Hello, World!"
274
-
275
- basic_demo = gr.Interface(
276
- fn=hello_world,
277
- inputs=None,
278
- outputs="text",
279
- title="Hello World App"
280
- )
281
-
282
  if __name__ == "__main__":
283
- # Use the simplest launch method
284
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
1
  import gradio as gr
2
  import requests
3
  import re
 
 
 
4
  import os
5
+ import subprocess
6
+ import uuid
7
+ import time
8
+ import json
9
+ import sys
10
+ import importlib.util
11
+ import tempfile
12
+ import signal
13
+ import atexit
14
+ from pathlib import Path
 
 
 
 
 
 
 
 
 
15
 
16
+ # Print Python version info for debugging
17
+ print(f"Python version: {sys.version}")
18
+ print(f"Python executable: {sys.executable}")
19
 
20
+ # Application directories
21
+ APP_DIR = Path(os.getcwd())
22
+ VENV_DIR = APP_DIR / "venvs"
23
+ os.makedirs(VENV_DIR, exist_ok=True)
 
 
 
 
 
 
 
24
 
25
+ # Make sure we have virtualenv installed
26
+ try:
27
+ import venv
28
+ print("venv module available")
29
+ except ImportError:
30
+ subprocess.run([sys.executable, "-m", "pip", "install", "virtualenv"], check=True)
31
+ print("Installed virtualenv")
 
 
 
32
 
33
+ # Track running processes
34
+ running_processes = []
35
 
36
+ # Clean up any running processes on exit
37
+ def cleanup_processes():
38
+ for process in running_processes:
39
+ try:
40
+ if process.poll() is None: # If process is still running
41
+ process.terminate()
42
+ process.wait(timeout=5)
43
+ print(f"Terminated process {process.pid}")
44
+ except Exception as e:
45
+ print(f"Error terminating process: {e}")
46
 
47
+ atexit.register(cleanup_processes)
 
 
 
 
 
48
 
49
  def call_openai_api(api_key, prompt):
50
+ """Call OpenAI API to generate Gradio app code and requirements"""
51
  headers = {
52
  "Content-Type": "application/json",
53
  "Authorization": f"Bearer {api_key}"
54
  }
55
 
56
+ system_prompt = """You are an expert at creating Python applications with Gradio.
57
+ Your task is to create a complete, standalone Gradio application based on the user's prompt.
58
+
59
+ Provide your response in the following JSON format:
60
+ {
61
+ "app_code": "# Your Python code here...",
62
+ "requirements": ["gradio==3.50.2", "numpy", "pandas", ...],
63
+ "app_name": "descriptive-name-of-app",
64
+ "description": "Brief description of what the app does"
65
+ }
66
 
67
+ Important guidelines:
68
+ 1. The app_code should be a complete Gradio application.
69
+ 2. Include gradio.launch(server_name="0.0.0.0", server_port=8000) at the end of the app.
70
+ 3. Don't use any resource that requires internet access (no API calls).
71
+ 4. Only use libraries that can be installed via pip.
72
+ 5. First requirement should be gradio==3.50.2.
73
+ 6. Make sure your code only uses the import statements for packages in the requirements list.
74
+ 7. Make the app functionality self-contained and robust.
75
+ 8. Don't use any buttons' .click() methods or event handlers - use gr.Interface() instead.
76
+ 9. Don't create directories or write to any file paths.
77
+ 10. Don't use flagging callbacks or features.
78
+ 11. Don't use __name__ == "__main__" checks, just have the launch call at the end.
79
 
80
+ Here's a simple template to follow:
81
 
82
  ```python
83
  import gradio as gr
84
+ import numpy as np
85
 
86
+ # Define your functions here
87
+ def process_data(input_data):
88
+ result = input_data * 2 # Simple example
89
+ return f"Processed: {result}"
90
 
91
+ # Create the Gradio interface
92
  demo = gr.Interface(
93
+ fn=process_data,
94
+ inputs=gr.Number(label="Input Data"),
95
+ outputs=gr.Textbox(label="Result"),
96
+ title="Data Processor"
97
  )
 
98
 
99
+ # Launch the app
100
+ demo.launch(server_name="0.0.0.0", server_port=8000)
101
+ ```
 
 
102
  """
103
 
104
  data = {
 
122
  return None, f"API Error: {response.status_code} - {response.text}"
123
 
124
  result = response.json()
125
+ content = result["choices"][0]["message"]["content"]
126
+
127
+ # Try to parse the JSON response
128
+ try:
129
+ # Extract JSON from response
130
+ json_pattern = r'```json\s*([\s\S]*?)```|({[\s\S]*})'
131
+ json_matches = re.findall(json_pattern, content)
132
+
133
+ json_str = ""
134
+ for match in json_matches:
135
+ if match[0]: # From code block
136
+ json_str = match[0]
137
+ break
138
+ elif match[1]: # Direct JSON
139
+ json_str = match[1]
140
+ break
141
+
142
+ if not json_str:
143
+ json_str = content # Try the whole content
144
+
145
+ app_info = json.loads(json_str)
146
+
147
+ # Extract Python code if it's wrapped in code blocks
148
+ if "```python" in app_info["app_code"]:
149
+ code_pattern = r'```python\s*([\s\S]*?)```'
150
+ code_match = re.search(code_pattern, app_info["app_code"])
151
+ if code_match:
152
+ app_info["app_code"] = code_match.group(1)
153
+
154
+ return app_info, None
155
+ except json.JSONDecodeError:
156
+ # Fallback pattern matching if JSON parsing fails
157
+ app_code_pattern = r'```python\s*([\s\S]*?)```'
158
+ app_code_matches = re.findall(app_code_pattern, content)
159
+
160
+ app_code = app_code_matches[0] if app_code_matches else ""
161
+
162
+ if not app_code:
163
+ return None, "Could not extract app code from response"
164
+
165
+ # Try to extract requirements
166
+ req_pattern = r'```(?:python)?\s*.*?import\s+([a-zA-Z0-9_]+)'
167
+ req_matches = re.findall(req_pattern, content)
168
+
169
+ requirements = ["gradio==3.50.2"]
170
+ if req_matches:
171
+ for module in req_matches:
172
+ if module != "gradio" and module not in requirements:
173
+ requirements.append(module)
174
+
175
+ # Construct a partial app_info
176
+ app_info = {
177
+ "app_code": app_code,
178
+ "requirements": requirements,
179
+ "app_name": f"gradio-app-{int(time.time())}",
180
+ "description": "Generated Gradio application"
181
+ }
182
+
183
+ return app_info, None
184
  except Exception as e:
185
+ return None, f"Error: {str(e)}"
186
 
187
+ def create_virtual_env(app_info):
188
+ """Create a virtual environment with the required packages"""
189
+ try:
190
+ # Create a unique ID for this app
191
+ app_id = str(uuid.uuid4())[:8]
192
+ app_name = f"{app_info['app_name']}-{app_id}"
193
+ venv_path = VENV_DIR / app_name
194
+
195
+ # Create a virtual environment
196
+ print(f"Creating virtual environment at {venv_path}")
197
+ subprocess.run([sys.executable, "-m", "venv", str(venv_path)], check=True)
198
+
199
+ # Determine the pip executable path
200
+ if os.name == 'nt': # Windows
201
+ pip_path = venv_path / "Scripts" / "pip"
202
+ else: # Unix/Linux
203
+ pip_path = venv_path / "bin" / "pip"
204
+
205
+ # Install required packages
206
+ print(f"Installing packages: {', '.join(app_info['requirements'])}")
207
+ subprocess.run([str(pip_path), "install", "--upgrade", "pip"], check=True)
208
+ for req in app_info["requirements"]:
209
+ subprocess.run([str(pip_path), "install", req], check=True)
210
+
211
+ return {
212
+ "app_id": app_id,
213
+ "app_name": app_name,
214
+ "venv_path": str(venv_path),
215
+ "pip_path": str(pip_path),
216
+ "description": app_info["description"],
217
+ "code": app_info["app_code"],
218
+ "requirements": app_info["requirements"]
219
+ }
220
+ except Exception as e:
221
+ return None, f"Error creating virtual environment: {str(e)}"
222
 
223
+ def run_app_in_venv(app_details, app_code):
224
+ """Run the Gradio app in a virtual environment"""
 
 
 
 
 
225
  try:
226
+ # Determine the Python executable path
227
+ if os.name == 'nt': # Windows
228
+ python_path = Path(app_details["venv_path"]) / "Scripts" / "python"
229
+ else: # Unix/Linux
230
+ python_path = Path(app_details["venv_path"]) / "bin" / "python"
 
231
 
232
+ # Create a temporary file for the app code
233
+ with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as f:
234
+ app_file = f.name
235
+ f.write(app_code.encode('utf-8'))
236
+
237
+ # Change the port to 8000 if not already set
238
+ if "server_port" not in app_code:
239
+ with open(app_file, 'a') as f:
240
+ f.write("\n\n# Ensure the app is running on port 8000\nif 'demo' in locals():\n demo.launch(server_name='0.0.0.0', server_port=8000)\n")
241
+
242
+ # Run the app
243
+ print(f"Running app with Python: {python_path}")
244
+ process = subprocess.Popen(
245
+ [str(python_path), app_file],
246
+ stdout=subprocess.PIPE,
247
+ stderr=subprocess.PIPE,
248
+ text=True
249
+ )
250
+
251
+ running_processes.append(process)
252
+
253
+ # Wait a bit for the app to start
254
+ time.sleep(5)
255
+
256
+ # Check if the process is still running
257
+ if process.poll() is not None:
258
+ stdout, stderr = process.communicate()
259
+ return None, f"App failed to start: {stderr}"
260
+
261
+ return {
262
+ "process": process,
263
+ "app_file": app_file,
264
+ "url": "http://localhost:8000",
265
+ "process_id": process.pid
266
+ }, None
267
  except Exception as e:
268
+ return None, f"Error running app: {str(e)}"
 
 
 
 
 
 
269
 
270
+ def stop_running_app(app_process):
271
+ """Stop a running Gradio app process"""
272
+ if app_process and app_process.poll() is None:
273
+ app_process.terminate()
274
+ try:
275
+ app_process.wait(timeout=5)
276
+ except subprocess.TimeoutExpired:
277
+ app_process.kill()
278
+
279
+ if app_process in running_processes:
280
+ running_processes.remove(app_process)
281
+
282
+ return True
283
+ return False
284
 
285
+ # Create the Gradio interface
286
+ with gr.Blocks(title="Gradio App Generator") as demo:
287
+ gr.Markdown("# 🤖 Gradio App Generator")
288
+ gr.Markdown("""
289
+ This app generates a Gradio application based on your description and runs it in a virtual environment
290
+ with the required dependencies. The generated app will be displayed below.
291
+ """)
 
 
 
292
 
293
+ # State variables to track the running app
294
+ running_app_process = gr.State(None)
295
+ running_app_file = gr.State(None)
 
 
 
 
 
 
 
 
296
 
297
+ with gr.Row():
298
+ with gr.Column(scale=1):
299
+ api_key = gr.Textbox(
300
+ label="OpenAI API Key",
301
+ placeholder="sk-...",
302
+ type="password",
303
+ info="Your key is used only for this session"
304
+ )
305
+
306
+ prompt = gr.Textbox(
307
+ label="App Description",
308
+ placeholder="Describe the Gradio app you want to create...",
309
+ lines=5
310
+ )
311
+
312
+ install_bar = gr.HTML(
313
+ "<div id='install-status'></div>",
314
+ visible=False,
315
+ label="Installation Status"
316
+ )
317
+
318
+ with gr.Row():
319
+ generate_btn = gr.Button("Generate & Run App", variant="primary")
320
+ stop_btn = gr.Button("Stop Running App", variant="stop", visible=False)
321
+
322
+ with gr.Accordion("Generated Code", open=False):
323
+ code_output = gr.Code(language="python", label="App Code")
324
+
325
+ with gr.Accordion("Requirements", open=False):
326
+ req_output = gr.Textbox(label="Required Packages")
327
+
328
+ status_output = gr.Markdown("")
329
+
330
+ with gr.Column(scale=2):
331
+ # Frame to display the running app
332
+ app_frame = gr.HTML("<div style='text-align:center; padding:50px;'><h3>Your generated app will appear here</h3></div>")
333
 
334
+ def on_generate(api_key_val, prompt_val, running_process, app_file):
335
+ # Stop any previously running app
336
+ if running_process:
337
+ stop_running_app(running_process)
338
+
339
+ # Clean up previous app file
340
+ if app_file and os.path.exists(app_file):
341
+ try:
342
+ os.unlink(app_file)
343
+ except:
344
+ pass
345
+
346
  # Validate API key
347
+ if not api_key_val or len(api_key_val) < 20 or not api_key_val.startswith("sk-"):
348
+ return (
349
+ None, None, None, "⚠️ Please provide a valid OpenAI API key",
350
+ "<div style='text-align:center; padding:50px;'><h3>Invalid API key</h3></div>",
351
+ gr.update(visible=False), gr.update(visible=False), running_process, app_file
352
+ )
353
 
354
  try:
355
+ # Generate code via API
356
+ app_info, api_error = call_openai_api(api_key_val, prompt_val)
357
+ if api_error or not app_info:
358
+ return (
359
+ None, None, None, f"⚠️ {api_error or 'Failed to generate app'}",
360
+ "<div style='text-align:center; padding:50px;'><h3>Error generating app</h3></div>",
361
+ gr.update(visible=False), gr.update(visible=False), running_process, app_file
362
+ )
 
 
 
363
 
364
+ # Create virtual environment with required packages
365
+ install_status = f"<div style='padding:10px; background-color:#f0f0f0; border-radius:5px;'>"
366
+ install_status += f"<p>Creating virtual environment for '{app_info['app_name']}'...</p>"
367
+ install_status += f"<p>Installing packages: {', '.join(app_info['requirements'])}</p>"
368
+ install_status += "</div>"
369
 
370
+ yield (
371
+ app_info["app_code"], "\n".join(app_info["requirements"]), None,
372
+ "⏳ Setting up virtual environment and installing packages...",
373
+ "<div style='text-align:center; padding:50px;'><h3>Preparing your app...</h3></div>",
374
+ gr.update(visible=True, value=install_status), gr.update(visible=False), running_process, app_file
375
+ )
376
 
377
+ venv_details, venv_error = create_virtual_env(app_info)
378
+ if venv_error or not venv_details:
379
+ return (
380
+ app_info["app_code"], "\n".join(app_info["requirements"]), None,
381
+ f"⚠️ {venv_error or 'Failed to create virtual environment'}",
382
+ "<div style='text-align:center; padding:50px;'><h3>Error setting up environment</h3></div>",
383
+ gr.update(visible=False), gr.update(visible=False), running_process, app_file
384
+ )
385
 
386
+ # Run the app
387
+ app_result, app_error = run_app_in_venv(venv_details, app_info["app_code"])
388
+ if app_error or not app_result:
389
+ return (
390
+ app_info["app_code"], "\n".join(app_info["requirements"]), None,
391
+ f"⚠️ {app_error or 'Failed to run app'}",
392
+ "<div style='text-align:center; padding:50px;'><h3>Error running app</h3></div>",
393
+ gr.update(visible=False), gr.update(visible=False), running_process, app_file
394
+ )
395
+
396
+ # Display the running app in an iframe
397
+ iframe_html = f"""
398
+ <div style="height:600px; border:1px solid #ddd; border-radius:5px; overflow:hidden;">
399
+ <iframe src="http://localhost:8000" width="100%" height="100%" frameborder="0"></iframe>
400
+ </div>
401
+ """
402
+
403
+ return (
404
+ app_info["app_code"], "\n".join(app_info["requirements"]), None,
405
+ f"✅ App '{venv_details['app_name']}' is running! View it below.",
406
+ iframe_html,
407
+ gr.update(visible=False), gr.update(visible=True), app_result["process"], app_result["app_file"]
408
+ )
409
  except Exception as e:
410
+ import traceback
411
+ error_details = traceback.format_exc()
412
+ return (
413
+ None, None, None, f"⚠️ Error: {str(e)}\n\n{error_details}",
414
+ "<div style='text-align:center; padding:50px;'><h3>An error occurred</h3></div>",
415
+ gr.update(visible=False), gr.update(visible=False), running_process, app_file
416
+ )
417
 
418
+ def on_stop(running_process, app_file):
419
+ if running_process:
420
+ stopped = stop_running_app(running_process)
421
+
422
+ # Clean up app file
423
+ if app_file and os.path.exists(app_file):
424
+ try:
425
+ os.unlink(app_file)
426
+ except:
427
+ pass
428
+
429
+ if stopped:
430
+ return (
431
+ "✅ App stopped successfully",
432
+ "<div style='text-align:center; padding:50px;'><h3>App stopped</h3></div>",
433
+ gr.update(visible=False), None, None
434
+ )
435
+
436
+ return (
437
+ "⚠️ No app was running",
438
+ "<div style='text-align:center; padding:50px;'><h3>No app was running</h3></div>",
439
+ gr.update(visible=False), None, None
440
+ )
441
 
442
+ generate_btn.click(
443
+ on_generate,
444
+ inputs=[api_key, prompt, running_app_process, running_app_file],
445
+ outputs=[
446
+ code_output, req_output, install_bar, status_output, app_frame,
447
+ install_bar, stop_btn, running_app_process, running_app_file
448
+ ]
449
  )
450
 
451
+ stop_btn.click(
452
+ on_stop,
453
+ inputs=[running_app_process, running_app_file],
454
+ outputs=[status_output, app_frame, stop_btn, running_app_process, running_app_file]
455
  )
456
 
 
 
 
 
 
 
 
 
 
 
 
457
  if __name__ == "__main__":
458
+ demo.queue().launch(server_name="0.0.0.0", server_port=7860)