mic3333 commited on
Commit
735010b
Β·
verified Β·
1 Parent(s): a791ab7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +339 -121
app.py CHANGED
@@ -1,18 +1,17 @@
1
  #!/usr/bin/env python3
2
  """
3
- LibreChat Pyodide Code Interpreter - Fixed JavaScript Syntax
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
- """Create a Gradio interface that uses Pyodide for client-side Python execution"""
10
 
11
- # Fixed HTML/JS with proper string escaping
12
  pyodide_html = """
13
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
14
  <div id="pyodide-status" style="font-weight: bold; padding: 10px; background: #f0f0f0; border-radius: 3px;">
15
- πŸ”„ Loading Pyodide... This may take 10-30 seconds on first load.
16
  </div>
17
  <div id="debug-info" style="display:none; margin-top: 10px; padding: 10px; background: #fff3cd; border-radius: 3px; font-size: 12px;">
18
  <strong>Debug Info:</strong>
@@ -25,6 +24,9 @@ def create_pyodide_interface():
25
  </div>
26
  </div>
27
 
 
 
 
28
  <script>
29
  // Global variables
30
  let pyodide = null;
@@ -61,48 +63,63 @@ def create_pyodide_interface():
61
  initializationStarted = true;
62
 
63
  try {
64
- // Check if loadPyodide is available
65
  if (typeof loadPyodide === 'undefined') {
66
- throw new Error('loadPyodide function not available');
 
 
 
67
  }
68
 
69
  updateStatus('πŸ”„ Loading Pyodide core...', 'blue');
70
- debugLog('Starting Pyodide initialization...');
71
 
72
  pyodide = await loadPyodide({
73
  indexURL: "https://cdn.jsdelivr.net/pyodide/v0.25.0/full/"
74
  });
75
 
76
  debugLog('Pyodide core loaded');
77
- updateStatus('πŸ“¦ Loading packages...', 'blue');
78
 
79
- // Load packages with error handling
80
- try {
81
- await pyodide.loadPackage(['numpy', 'matplotlib', 'pandas']);
82
- debugLog('All packages loaded successfully');
83
- } catch (pkgError) {
84
- debugLog('Package loading error: ' + pkgError.message);
85
- // Try minimal packages
86
  try {
87
- await pyodide.loadPackage(['numpy']);
88
- debugLog('Loaded numpy only');
89
- } catch (minError) {
90
- debugLog('Even numpy failed: ' + minError.message);
 
91
  }
92
  }
93
 
94
- updateStatus('πŸ”§ Setting up environment...', 'blue');
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- // Setup Python environment with proper escaping
97
  pyodide.runPython(`
98
  import sys
99
  print("Python " + sys.version)
100
 
101
- # Global plot data storage
102
- _current_plot_data = None
 
103
 
104
  def capture_matplotlib():
105
- global _current_plot_data
106
  try:
107
  import matplotlib.pyplot as plt
108
  import io
@@ -114,56 +131,102 @@ def capture_matplotlib():
114
  buffer.seek(0)
115
  plot_data = buffer.getvalue()
116
  buffer.close()
117
- _current_plot_data = base64.b64encode(plot_data).decode()
118
  plt.close('all')
119
- return _current_plot_data
 
 
 
120
  return None
 
 
 
 
 
 
 
 
121
  except Exception as e:
122
- print("Plot capture error: " + str(e))
123
  return None
124
 
125
- def get_plot_data():
126
- return _current_plot_data
 
 
 
127
 
128
  def clear_plot_data():
129
- global _current_plot_data
130
- _current_plot_data = None
 
131
 
132
- # Try to set up matplotlib
133
  try:
134
  import matplotlib
135
  matplotlib.use('Agg')
136
  import matplotlib.pyplot as plt
137
 
138
- # Override show function
139
  original_show = plt.show
140
  def custom_show(*args, **kwargs):
141
  return capture_matplotlib()
142
  plt.show = custom_show
143
 
144
- print("Matplotlib configured successfully")
145
  except ImportError:
146
- print("Matplotlib not available")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
 
148
- print("Python environment ready!")
 
 
 
 
 
 
149
  `);
150
 
151
  pyodideReady = true;
152
- updateStatus('βœ… Pyodide ready!', 'green');
153
- debugLog('Initialization complete');
154
 
155
  // Show output area
156
  const outputDiv = document.getElementById('pyodide-output');
157
- if (outputDiv) {
158
- outputDiv.style.display = 'block';
159
- }
160
  const outputText = document.getElementById('output-text');
161
  if (outputText) {
162
- outputText.textContent = 'Pyodide ready! You can now execute Python code.';
163
  }
164
 
165
  } catch (error) {
166
- console.error('Pyodide initialization error:', error);
167
  debugLog('Init error: ' + error.message);
168
  updateStatus('❌ Failed: ' + error.message, 'red');
169
  pyodideReady = false;
@@ -174,21 +237,16 @@ print("Python environment ready!")
174
  debugLog('Execute function called');
175
 
176
  if (!pyodideReady) {
177
- updateStatus('⏳ Not ready yet...', 'orange');
178
  return 'Pyodide is not ready. Please wait for green status.';
179
  }
180
 
181
- if (!pyodide) {
182
- return 'Error: Pyodide not available.';
183
- }
184
-
185
  if (!code || code.trim() === '') {
186
  return 'Error: No code provided.';
187
  }
188
 
189
  try {
190
- updateStatus('▢️ Executing...', 'blue');
191
- debugLog('Executing code: ' + code.substring(0, 50) + '...');
192
 
193
  // Clear previous plots
194
  pyodide.runPython('clear_plot_data()');
@@ -211,7 +269,8 @@ captured_output.getvalue()
211
  `);
212
 
213
  // Get plot data
214
- let plotData = pyodide.runPython('get_plot_data()');
 
215
 
216
  debugLog('Execution completed');
217
 
@@ -219,22 +278,48 @@ captured_output.getvalue()
219
  const outputText = document.getElementById('output-text');
220
  const plotContainer = document.getElementById('plot-container');
221
 
 
222
  if (outputText) {
223
  let textOutput = stdout || '';
224
  if (result !== undefined && result !== null && result !== '') {
225
  if (textOutput) textOutput += '\\n';
226
  textOutput += 'Return: ' + result;
227
  }
228
- outputText.textContent = textOutput || 'Code executed (no output)';
229
  }
230
 
231
  // Handle plots
232
- if (plotContainer && plotData && plotData.length > 100) {
233
- plotContainer.innerHTML = '<div style="margin: 10px 0;"><h5>πŸ“Š Plot:</h5><img src="data:image/png;base64,' + plotData + '" style="max-width: 100%; height: auto; border: 1px solid #ddd;" alt="Plot"></div>';
234
- updateStatus('βœ… Executed with plot!', 'green');
235
- debugLog('Plot generated and displayed');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  } else {
237
- if (plotContainer) plotContainer.innerHTML = '';
238
  updateStatus('βœ… Executed successfully!', 'green');
239
  }
240
 
@@ -242,7 +327,7 @@ captured_output.getvalue()
242
 
243
  } catch (error) {
244
  console.error('Execution error:', error);
245
- debugLog('Execution error: ' + error.message);
246
 
247
  const outputText = document.getElementById('output-text');
248
  if (outputText) {
@@ -253,38 +338,66 @@ captured_output.getvalue()
253
  }
254
  }
255
 
256
- // Initialize when ready
257
- function safeInit() {
258
- setTimeout(function() {
259
- if (typeof loadPyodide !== 'undefined') {
260
- debugLog('loadPyodide available, starting init');
261
- initPyodide();
262
- } else {
263
- debugLog('loadPyodide not available yet, retrying...');
264
- updateStatus('⏳ Waiting for CDN...', 'orange');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  safeInit();
 
 
266
  }
267
  }, 1000);
 
 
 
 
 
 
 
 
268
  }
269
 
270
- // Start initialization
271
  if (document.readyState === 'loading') {
272
- document.addEventListener('DOMContentLoaded', safeInit);
273
  } else {
274
- safeInit();
275
  }
276
 
277
  // Global functions
278
  window.executePyodideCode = executePyodideCode;
279
- window.checkPyodideStatus = function() {
280
- return pyodideReady;
281
- };
282
  window.toggleDebugMode = function() {
283
  debugMode = !debugMode;
284
  const debugDiv = document.getElementById('debug-info');
285
- if (debugDiv) {
286
- debugDiv.style.display = debugMode ? 'block' : 'none';
287
- }
288
  return debugMode;
289
  };
290
 
@@ -295,69 +408,179 @@ captured_output.getvalue()
295
  return pyodide_html
296
 
297
  # Create the Gradio interface
298
- with gr.Blocks(title="LibreChat Pyodide Code Interpreter") as demo:
299
- gr.Markdown("# 🐍 LibreChat Pyodide Code Interpreter")
300
- gr.Markdown("**Client-side Python execution** - Python runs in your browser!")
301
 
302
  # Pyodide interface
303
  pyodide_interface = gr.HTML(create_pyodide_interface())
304
 
305
  with gr.Row():
306
- with gr.Column():
307
  code_input = gr.Textbox(
308
- value="""# Start with this simple test:
309
- print("Hello from Python!")
310
- print("2 + 2 =", 2 + 2)
311
 
312
- # Check what's available:
313
- import sys
314
- print("Python version:", sys.version_info[:2])
 
315
 
316
- try:
317
- import numpy as np
318
- print("βœ… NumPy available")
319
- print("Random number:", np.random.rand())
320
- except ImportError:
321
- print("❌ NumPy not available")
322
 
323
- try:
324
- import matplotlib.pyplot as plt
325
- print("βœ… Matplotlib available")
326
- except ImportError:
327
- print("❌ Matplotlib not available")""",
328
- lines=15,
329
- label="Python Code"
 
 
 
 
330
  )
331
 
332
- execute_btn = gr.Button("πŸš€ Execute", variant="primary")
 
 
 
 
 
333
 
334
- with gr.Column():
335
  status_display = gr.Textbox(
336
  label="Status",
337
  interactive=False,
338
- lines=3
339
  )
340
 
341
- check_btn = gr.Button("πŸ“Š Check Status")
342
- debug_btn = gr.Button("πŸ› Toggle Debug")
 
343
 
344
- # Fixed JavaScript handlers with proper escaping
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  execute_btn.click(
346
  fn=None,
347
  inputs=[code_input],
348
  outputs=[status_display],
349
  js="""
350
  function(code) {
351
- console.log('Execute button clicked');
352
  try {
353
  if (window.executePyodideCode) {
354
  return window.executePyodideCode(code);
355
  } else {
356
- return 'executePyodideCode function not available';
357
  }
358
  } catch (error) {
359
- console.error('JS execution error:', error);
360
- return 'JavaScript error: ' + error.message;
361
  }
362
  }
363
  """
@@ -370,14 +593,10 @@ except ImportError:
370
  js="""
371
  function() {
372
  try {
373
- if (window.checkPyodideStatus) {
374
- const ready = window.checkPyodideStatus();
375
- return ready ? 'βœ… Pyodide is ready!' : '⏳ Pyodide still loading...';
376
- } else {
377
- return '❌ Status function not available';
378
- }
379
  } catch (error) {
380
- return 'Status check error: ' + error.message;
381
  }
382
  }
383
  """
@@ -391,19 +610,18 @@ except ImportError:
391
  function() {
392
  try {
393
  if (window.toggleDebugMode) {
394
- const debugOn = window.toggleDebugMode();
395
- return debugOn ? 'πŸ› Debug ON' : 'πŸ› Debug OFF';
396
- } else {
397
- return '❌ Debug toggle not available';
398
  }
 
399
  } catch (error) {
400
- return 'Debug toggle error: ' + error.message;
401
  }
402
  }
403
  """
404
  )
405
 
406
  if __name__ == "__main__":
 
407
  demo.launch(
408
  server_name="0.0.0.0",
409
  server_port=7860,
 
1
  #!/usr/bin/env python3
2
  """
3
+ LibreChat Pyodide Code Interpreter - With Plotly Support
4
  """
5
 
6
  import gradio as gr
7
 
8
  def create_pyodide_interface():
9
+ """Create a Gradio interface with Pyodide + Plotly support"""
10
 
 
11
  pyodide_html = """
12
  <div id="pyodide-container" style="border: 1px solid #ddd; padding: 15px; border-radius: 5px; margin: 10px 0;">
13
  <div id="pyodide-status" style="font-weight: bold; padding: 10px; background: #f0f0f0; border-radius: 3px;">
14
+ πŸ”„ Loading Pyodide with Plotly... This may take 15-30 seconds.
15
  </div>
16
  <div id="debug-info" style="display:none; margin-top: 10px; padding: 10px; background: #fff3cd; border-radius: 3px; font-size: 12px;">
17
  <strong>Debug Info:</strong>
 
24
  </div>
25
  </div>
26
 
27
+ <!-- Load Plotly.js first -->
28
+ <script src="https://cdn.plot.ly/plotly-2.27.0.min.js"></script>
29
+
30
  <script>
31
  // Global variables
32
  let pyodide = null;
 
63
  initializationStarted = true;
64
 
65
  try {
66
+ // Check prerequisites
67
  if (typeof loadPyodide === 'undefined') {
68
+ throw new Error('Pyodide CDN not loaded');
69
+ }
70
+ if (typeof Plotly === 'undefined') {
71
+ throw new Error('Plotly CDN not loaded');
72
  }
73
 
74
  updateStatus('πŸ”„ Loading Pyodide core...', 'blue');
75
+ debugLog('Starting Pyodide with Plotly support...');
76
 
77
  pyodide = await loadPyodide({
78
  indexURL: "https://cdn.jsdelivr.net/pyodide/v0.25.0/full/"
79
  });
80
 
81
  debugLog('Pyodide core loaded');
82
+ updateStatus('πŸ“¦ Installing Python packages...', 'blue');
83
 
84
+ // Install plotly and other packages
85
+ const packages = ['numpy', 'pandas', 'matplotlib'];
86
+
87
+ for (const pkg of packages) {
 
 
 
88
  try {
89
+ debugLog(`Installing ${pkg}...`);
90
+ await pyodide.loadPackage(pkg);
91
+ debugLog(`βœ“ ${pkg} installed`);
92
+ } catch (error) {
93
+ debugLog(`⚠ ${pkg} failed: ${error.message}`);
94
  }
95
  }
96
 
97
+ // Install plotly via pip in Pyodide
98
+ updateStatus('πŸ“¦ Installing Plotly via pip...', 'blue');
99
+ try {
100
+ await pyodide.loadPackage(['micropip']);
101
+ await pyodide.runPythonAsync(`
102
+ import micropip
103
+ await micropip.install('plotly')
104
+ `);
105
+ debugLog('βœ“ Plotly installed via micropip');
106
+ } catch (error) {
107
+ debugLog('⚠ Plotly installation failed: ' + error.message);
108
+ }
109
+
110
+ updateStatus('πŸ”§ Setting up plotting environment...', 'blue');
111
 
112
+ // Setup Python environment with Plotly support
113
  pyodide.runPython(`
114
  import sys
115
  print("Python " + sys.version)
116
 
117
+ # Global storage for plots
118
+ _matplotlib_data = None
119
+ _plotly_data = None
120
 
121
  def capture_matplotlib():
122
+ global _matplotlib_data
123
  try:
124
  import matplotlib.pyplot as plt
125
  import io
 
131
  buffer.seek(0)
132
  plot_data = buffer.getvalue()
133
  buffer.close()
134
+ _matplotlib_data = base64.b64encode(plot_data).decode()
135
  plt.close('all')
136
+ return _matplotlib_data
137
+ return None
138
+ except Exception as e:
139
+ print("Matplotlib capture error: " + str(e))
140
  return None
141
+
142
+ def capture_plotly(fig):
143
+ global _plotly_data
144
+ try:
145
+ # Convert plotly figure to HTML
146
+ import plotly.offline as pyo
147
+ _plotly_data = pyo.plot(fig, output_type='div', include_plotlyjs=False)
148
+ return _plotly_data
149
  except Exception as e:
150
+ print("Plotly capture error: " + str(e))
151
  return None
152
 
153
+ def get_matplotlib_data():
154
+ return _matplotlib_data
155
+
156
+ def get_plotly_data():
157
+ return _plotly_data
158
 
159
  def clear_plot_data():
160
+ global _matplotlib_data, _plotly_data
161
+ _matplotlib_data = None
162
+ _plotly_data = None
163
 
164
+ # Setup matplotlib if available
165
  try:
166
  import matplotlib
167
  matplotlib.use('Agg')
168
  import matplotlib.pyplot as plt
169
 
 
170
  original_show = plt.show
171
  def custom_show(*args, **kwargs):
172
  return capture_matplotlib()
173
  plt.show = custom_show
174
 
175
+ print("βœ… Matplotlib configured")
176
  except ImportError:
177
+ print("❌ Matplotlib not available")
178
+
179
+ # Setup plotly if available
180
+ try:
181
+ import plotly.graph_objects as go
182
+ import plotly.express as px
183
+
184
+ # Custom show function for Plotly
185
+ def show_plotly(fig):
186
+ return capture_plotly(fig)
187
+
188
+ # Monkey patch plotly's show
189
+ original_plotly_show = go.Figure.show
190
+ def custom_plotly_show(self, *args, **kwargs):
191
+ return capture_plotly(self)
192
+ go.Figure.show = custom_plotly_show
193
+
194
+ print("βœ… Plotly configured")
195
+ print("Available: plotly.graph_objects as 'go', plotly.express as 'px'")
196
+ except ImportError as e:
197
+ print("❌ Plotly not available: " + str(e))
198
+
199
+ # Test basic functionality
200
+ try:
201
+ import numpy as np
202
+ print("βœ… NumPy available")
203
+ except ImportError:
204
+ print("❌ NumPy not available")
205
 
206
+ try:
207
+ import pandas as pd
208
+ print("βœ… Pandas available")
209
+ except ImportError:
210
+ print("❌ Pandas not available")
211
+
212
+ print("Environment setup complete!")
213
  `);
214
 
215
  pyodideReady = true;
216
+ updateStatus('βœ… Pyodide + Plotly ready!', 'green');
217
+ debugLog('Full initialization complete');
218
 
219
  // Show output area
220
  const outputDiv = document.getElementById('pyodide-output');
221
+ if (outputDiv) outputDiv.style.display = 'block';
222
+
 
223
  const outputText = document.getElementById('output-text');
224
  if (outputText) {
225
+ outputText.textContent = 'Pyodide ready with Plotly support!\\n\\nTry the examples below or write your own code.';
226
  }
227
 
228
  } catch (error) {
229
+ console.error('Initialization error:', error);
230
  debugLog('Init error: ' + error.message);
231
  updateStatus('❌ Failed: ' + error.message, 'red');
232
  pyodideReady = false;
 
237
  debugLog('Execute function called');
238
 
239
  if (!pyodideReady) {
 
240
  return 'Pyodide is not ready. Please wait for green status.';
241
  }
242
 
 
 
 
 
243
  if (!code || code.trim() === '') {
244
  return 'Error: No code provided.';
245
  }
246
 
247
  try {
248
+ updateStatus('▢️ Executing Python...', 'blue');
249
+ debugLog('Executing: ' + code.substring(0, 50) + '...');
250
 
251
  // Clear previous plots
252
  pyodide.runPython('clear_plot_data()');
 
269
  `);
270
 
271
  // Get plot data
272
+ let matplotlibData = pyodide.runPython('get_matplotlib_data()');
273
+ let plotlyData = pyodide.runPython('get_plotly_data()');
274
 
275
  debugLog('Execution completed');
276
 
 
278
  const outputText = document.getElementById('output-text');
279
  const plotContainer = document.getElementById('plot-container');
280
 
281
+ // Handle text output
282
  if (outputText) {
283
  let textOutput = stdout || '';
284
  if (result !== undefined && result !== null && result !== '') {
285
  if (textOutput) textOutput += '\\n';
286
  textOutput += 'Return: ' + result;
287
  }
288
+ outputText.textContent = textOutput || 'Code executed successfully (no text output)';
289
  }
290
 
291
  // Handle plots
292
+ let plotHTML = '';
293
+
294
+ if (matplotlibData && matplotlibData.length > 100) {
295
+ plotHTML += `
296
+ <div style="margin: 10px 0;">
297
+ <h5>πŸ“Š Matplotlib Plot:</h5>
298
+ <img src="data:image/png;base64,${matplotlibData}"
299
+ style="max-width: 100%; height: auto; border: 1px solid #ddd;"
300
+ alt="Matplotlib Plot">
301
+ </div>
302
+ `;
303
+ }
304
+
305
+ if (plotlyData && plotlyData.length > 100) {
306
+ plotHTML += `
307
+ <div style="margin: 10px 0;">
308
+ <h5>πŸ“ˆ Interactive Plotly Chart:</h5>
309
+ <div style="border: 1px solid #ddd; border-radius: 5px; padding: 10px;">
310
+ ${plotlyData}
311
+ </div>
312
+ </div>
313
+ `;
314
+ }
315
+
316
+ if (plotContainer) {
317
+ plotContainer.innerHTML = plotHTML;
318
+ }
319
+
320
+ if (plotHTML) {
321
+ updateStatus('βœ… Executed with plot(s)!', 'green');
322
  } else {
 
323
  updateStatus('βœ… Executed successfully!', 'green');
324
  }
325
 
 
327
 
328
  } catch (error) {
329
  console.error('Execution error:', error);
330
+ debugLog('Error: ' + error.message);
331
 
332
  const outputText = document.getElementById('output-text');
333
  if (outputText) {
 
338
  }
339
  }
340
 
341
+ // Safe initialization with retry
342
+ async function safeInit() {
343
+ let retries = 0;
344
+ const maxRetries = 3;
345
+
346
+ while (retries < maxRetries) {
347
+ try {
348
+ if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
349
+ await initPyodide();
350
+ return;
351
+ }
352
+ } catch (error) {
353
+ debugLog(`Init attempt ${retries + 1} failed: ${error.message}`);
354
+ }
355
+
356
+ retries++;
357
+ if (retries < maxRetries) {
358
+ debugLog(`Retrying in ${retries * 2} seconds...`);
359
+ await new Promise(resolve => setTimeout(resolve, retries * 2000));
360
+ }
361
+ }
362
+
363
+ updateStatus('❌ Initialization failed after ' + maxRetries + ' attempts', 'red');
364
+ }
365
+
366
+ // Wait for both CDNs to load
367
+ function waitForCDNs() {
368
+ const checkInterval = setInterval(() => {
369
+ if (typeof loadPyodide !== 'undefined' && typeof Plotly !== 'undefined') {
370
+ clearInterval(checkInterval);
371
+ debugLog('Both CDNs loaded, starting init');
372
  safeInit();
373
+ } else {
374
+ debugLog('Waiting for CDNs... Pyodide: ' + (typeof loadPyodide !== 'undefined') + ', Plotly: ' + (typeof Plotly !== 'undefined'));
375
  }
376
  }, 1000);
377
+
378
+ // Timeout after 30 seconds
379
+ setTimeout(() => {
380
+ clearInterval(checkInterval);
381
+ if (!pyodideReady) {
382
+ updateStatus('❌ CDN loading timeout', 'red');
383
+ }
384
+ }, 30000);
385
  }
386
 
387
+ // Start when DOM is ready
388
  if (document.readyState === 'loading') {
389
+ document.addEventListener('DOMContentLoaded', waitForCDNs);
390
  } else {
391
+ waitForCDNs();
392
  }
393
 
394
  // Global functions
395
  window.executePyodideCode = executePyodideCode;
396
+ window.checkPyodideStatus = () => pyodideReady;
 
 
397
  window.toggleDebugMode = function() {
398
  debugMode = !debugMode;
399
  const debugDiv = document.getElementById('debug-info');
400
+ if (debugDiv) debugDiv.style.display = debugMode ? 'block' : 'none';
 
 
401
  return debugMode;
402
  };
403
 
 
408
  return pyodide_html
409
 
410
  # Create the Gradio interface
411
+ with gr.Blocks(title="Pyodide + Plotly Code Interpreter") as demo:
412
+ gr.Markdown("# πŸπŸ“ˆ Pyodide + Plotly Code Interpreter")
413
+ gr.Markdown("**Interactive Python with Plotly charts** - runs entirely in your browser!")
414
 
415
  # Pyodide interface
416
  pyodide_interface = gr.HTML(create_pyodide_interface())
417
 
418
  with gr.Row():
419
+ with gr.Column(scale=2):
420
  code_input = gr.Textbox(
421
+ value="""# Plotly Example 1: Simple Line Chart
422
+ import plotly.graph_objects as go
423
+ import numpy as np
424
 
425
+ # Generate data
426
+ x = np.linspace(0, 10, 100)
427
+ y1 = np.sin(x)
428
+ y2 = np.cos(x)
429
 
430
+ # Create figure
431
+ fig = go.Figure()
432
+ fig.add_trace(go.Scatter(x=x, y=y1, name='sin(x)', line=dict(color='blue')))
433
+ fig.add_trace(go.Scatter(x=x, y=y2, name='cos(x)', line=dict(color='red')))
 
 
434
 
435
+ fig.update_layout(
436
+ title='Interactive Sine and Cosine Waves',
437
+ xaxis_title='X values',
438
+ yaxis_title='Y values',
439
+ hovermode='x unified'
440
+ )
441
+
442
+ fig.show()
443
+ print("Interactive Plotly chart created! πŸŽ‰")""",
444
+ lines=18,
445
+ label="Python Code with Plotly"
446
  )
447
 
448
+ with gr.Row():
449
+ execute_btn = gr.Button("πŸš€ Execute", variant="primary", size="lg")
450
+ examples_btn = gr.Button("πŸ“‹ Load Examples", variant="secondary")
451
+
452
+ with gr.Column(scale=1):
453
+ gr.Markdown("### πŸŽ›οΈ Controls")
454
 
 
455
  status_display = gr.Textbox(
456
  label="Status",
457
  interactive=False,
458
+ lines=4
459
  )
460
 
461
+ with gr.Row():
462
+ check_btn = gr.Button("πŸ“Š Status", size="sm")
463
+ debug_btn = gr.Button("πŸ› Debug", size="sm")
464
 
465
+ # Example code snippets
466
+ examples = {
467
+ "Plotly Bar Chart": """import plotly.express as px
468
+ import pandas as pd
469
+
470
+ # Sample data
471
+ data = {
472
+ 'Category': ['A', 'B', 'C', 'D', 'E'],
473
+ 'Values': [23, 45, 56, 78, 32],
474
+ 'Colors': ['red', 'blue', 'green', 'orange', 'purple']
475
+ }
476
+ df = pd.DataFrame(data)
477
+
478
+ # Create bar chart
479
+ fig = px.bar(df, x='Category', y='Values', color='Colors',
480
+ title='Interactive Bar Chart',
481
+ labels={'Values': 'Count'})
482
+
483
+ fig.show()
484
+ print("Bar chart created!")""",
485
+
486
+ "Plotly 3D Scatter": """import plotly.graph_objects as go
487
+ import numpy as np
488
+
489
+ # Generate 3D data
490
+ n = 100
491
+ x = np.random.randn(n)
492
+ y = np.random.randn(n)
493
+ z = np.random.randn(n)
494
+ colors = np.random.randn(n)
495
+
496
+ # Create 3D scatter plot
497
+ fig = go.Figure(data=go.Scatter3d(
498
+ x=x, y=y, z=z,
499
+ mode='markers',
500
+ marker=dict(
501
+ size=8,
502
+ color=colors,
503
+ colorscale='Viridis',
504
+ showscale=True
505
+ )
506
+ ))
507
+
508
+ fig.update_layout(
509
+ title='Interactive 3D Scatter Plot',
510
+ scene=dict(
511
+ xaxis_title='X Axis',
512
+ yaxis_title='Y Axis',
513
+ zaxis_title='Z Axis'
514
+ )
515
+ )
516
+
517
+ fig.show()
518
+ print("3D scatter plot created!")""",
519
+
520
+ "Plotly Dashboard": """import plotly.graph_objects as go
521
+ from plotly.subplots import make_subplots
522
+ import numpy as np
523
+
524
+ # Generate sample data
525
+ x = np.linspace(0, 10, 50)
526
+ y1 = np.sin(x)
527
+ y2 = np.cos(x)
528
+ y3 = np.random.normal(0, 0.1, len(x))
529
+
530
+ # Create subplots
531
+ fig = make_subplots(
532
+ rows=2, cols=2,
533
+ subplot_titles=('Line Plot', 'Histogram', 'Box Plot', 'Heatmap'),
534
+ specs=[[{"secondary_y": True}, {}],
535
+ [{}, {}]]
536
+ )
537
+
538
+ # Add line plot
539
+ fig.add_trace(go.Scatter(x=x, y=y1, name='sin(x)'), row=1, col=1)
540
+ fig.add_trace(go.Scatter(x=x, y=y2, name='cos(x)', yaxis='y2'), row=1, col=1, secondary_y=True)
541
+
542
+ # Add histogram
543
+ fig.add_trace(go.Histogram(x=np.random.normal(0, 1, 1000), name='Normal Dist'), row=1, col=2)
544
+
545
+ # Add box plot
546
+ categories = ['A', 'B', 'C']
547
+ values = [np.random.normal(i, 0.5, 100) for i in range(len(categories))]
548
+ for i, (cat, vals) in enumerate(zip(categories, values)):
549
+ fig.add_trace(go.Box(y=vals, name=cat), row=2, col=1)
550
+
551
+ # Add heatmap
552
+ z = np.random.randn(10, 10)
553
+ fig.add_trace(go.Heatmap(z=z, colorscale='RdBu'), row=2, col=2)
554
+
555
+ fig.update_layout(height=600, title_text="Multi-Plot Dashboard")
556
+ fig.show()
557
+ print("Dashboard created with multiple charts!")"""
558
+ }
559
+
560
+ def load_example():
561
+ return examples["Plotly Bar Chart"]
562
+
563
+ examples_btn.click(
564
+ fn=load_example,
565
+ inputs=[],
566
+ outputs=[code_input]
567
+ )
568
+
569
+ # Event handlers
570
  execute_btn.click(
571
  fn=None,
572
  inputs=[code_input],
573
  outputs=[status_display],
574
  js="""
575
  function(code) {
 
576
  try {
577
  if (window.executePyodideCode) {
578
  return window.executePyodideCode(code);
579
  } else {
580
+ return 'Execution function not available';
581
  }
582
  } catch (error) {
583
+ return 'Error: ' + error.message;
 
584
  }
585
  }
586
  """
 
593
  js="""
594
  function() {
595
  try {
596
+ const ready = window.checkPyodideStatus ? window.checkPyodideStatus() : false;
597
+ return ready ? 'βœ… Ready for Plotly!' : '⏳ Still loading...';
 
 
 
 
598
  } catch (error) {
599
+ return 'Status error: ' + error.message;
600
  }
601
  }
602
  """
 
610
  function() {
611
  try {
612
  if (window.toggleDebugMode) {
613
+ return window.toggleDebugMode() ? 'πŸ› Debug ON' : 'πŸ› Debug OFF';
 
 
 
614
  }
615
+ return 'Debug toggle unavailable';
616
  } catch (error) {
617
+ return 'Debug error: ' + error.message;
618
  }
619
  }
620
  """
621
  )
622
 
623
  if __name__ == "__main__":
624
+ print("πŸš€ Starting Pyodide + Plotly Interpreter...")
625
  demo.launch(
626
  server_name="0.0.0.0",
627
  server_port=7860,