Rodrigo1421 commited on
Commit
58acd77
·
verified ·
1 Parent(s): 9dede68

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +71 -117
app.js CHANGED
@@ -1,5 +1,5 @@
1
  // CV Curve Fitting Pro - Pure Python JAX + SciPy Engine Client
2
- // Connected to Python FastAPI Streaming & WebSocket Backend (Free ZeroGPU & CPU Ready)
3
 
4
  // Global State
5
  let activeSocket = null;
@@ -33,36 +33,23 @@ function resolveEndpoints(rawUrl) {
33
  }
34
 
35
  let httpHealth = "";
36
- let wsSolve = "";
37
  let httpSolve = "";
38
 
39
  if (url.startsWith("https://")) {
40
  httpHealth = url + "/health";
41
  httpSolve = url + "/api/solve";
42
- wsSolve = url.replace("https://", "wss://") + "/ws/solve";
43
  } else if (url.startsWith("http://")) {
44
  httpHealth = url + "/health";
45
  httpSolve = url + "/api/solve";
46
- wsSolve = url.replace("http://", "ws://") + "/ws/solve";
47
- } else if (url.startsWith("wss://")) {
48
- wsSolve = url.includes("/ws/solve") ? url : url + "/ws/solve";
49
- httpHealth = url.replace("wss://", "https://").replace(/\/ws\/solve\/?$/, "") + "/health";
50
- httpSolve = url.replace("wss://", "https://").replace(/\/ws\/solve\/?$/, "") + "/api/solve";
51
- } else if (url.startsWith("ws://")) {
52
- wsSolve = url.includes("/ws/solve") ? url : url + "/ws/solve";
53
- httpHealth = url.replace("ws://", "http://").replace(/\/ws\/solve\/?$/, "") + "/health";
54
- httpSolve = url.replace("ws://", "http://").replace(/\/ws\/solve\/?$/, "") + "/api/solve";
55
  } else {
56
  httpHealth = "https://" + url + "/health";
57
  httpSolve = "https://" + url + "/api/solve";
58
- wsSolve = "wss://" + url + "/ws/solve";
59
  }
60
 
61
  return {
62
  rawUrl: url,
63
  httpHealth: httpHealth,
64
- httpSolve: httpSolve,
65
- wsSolve: wsSolve
66
  };
67
  }
68
 
@@ -110,9 +97,9 @@ async function probePythonBackend() {
110
  isBackendAvailable = true;
111
  activeBackendType = "cloud";
112
  if (dot) dot.className = 'status-dot online';
113
- if (label) label.innerText = 'ZeroGPU JAX Engine Ready';
114
  if (msg) {
115
- msg.innerHTML = `<span style="color: #10b981; font-weight: 500;">✓ ZeroGPU JAX Server Active</span>`;
116
  }
117
  return false;
118
  }
@@ -444,123 +431,84 @@ window.handleFormSubmit = async function(e) {
444
  return false;
445
  };
446
 
447
- // Execution via HTTP Streaming (NDJSON) with Real-Time Plotly Updates & WebSocket Fallback
448
  async function executePythonSolver(fileContent, config) {
449
  const stageEl = document.getElementById('status-stage');
450
  const detailsEl = document.getElementById('status-details');
451
- if (stageEl) stageEl.innerText = '⚡ ZeroGPU JAX Engine Running...';
452
- if (detailsEl) detailsEl.innerText = 'Initializing JAX multi-stage L-BFGS-B optimization...';
453
 
454
- const solveCandidates = [
 
455
  window.location.origin + "/api/solve",
456
  window.location.origin + "/solve",
457
  DEFAULT_HF_SPACE_URL + "/api/solve",
458
- DEFAULT_LOCAL_URL + "/api/solve",
459
- currentEndpoints.httpSolve
460
  ];
461
 
462
- let streamSucceeded = false;
463
-
464
- for (const endpoint of solveCandidates) {
465
  try {
466
- const response = await fetch(endpoint, {
 
 
467
  method: "POST",
468
  headers: { "Content-Type": "application/json" },
469
  body: JSON.stringify({
470
- action: "solve",
471
- config: config,
472
- file_content: fileContent
473
- })
474
  });
 
475
 
476
- if (!response.ok) continue;
477
-
478
- const reader = response.body.getReader();
479
- const decoder = new TextDecoder();
480
- let buffer = "";
481
- streamSucceeded = true;
482
-
483
- while (true) {
484
- const { done, value } = await reader.read();
485
- if (done) break;
486
-
487
- buffer += decoder.decode(value, { stream: true });
488
- const lines = buffer.split("\n");
489
- buffer = lines.pop();
490
-
491
- for (const line of lines) {
492
- if (!line.trim()) continue;
493
- try {
494
- const data = JSON.parse(line);
495
- handleSolverMessage(data);
496
- } catch (err) {
497
- console.error("JSON parse error in chunk:", err);
498
- }
499
- }
500
- }
501
-
502
- if (buffer.trim()) {
503
- try {
504
- const data = JSON.parse(buffer);
505
- handleSolverMessage(data);
506
- } catch (err) {}
507
  }
508
-
509
- break;
510
  } catch (err) {
511
- console.warn(`Streaming attempt to ${endpoint} failed, trying next fallback:`, err);
512
  }
513
  }
514
 
515
- if (!streamSucceeded) {
516
- executeWebSocketFallback(fileContent, config);
517
- }
518
- }
 
519
 
520
- function executeWebSocketFallback(fileContent, config) {
521
- const stageEl = document.getElementById('status-stage');
522
- const detailsEl = document.getElementById('status-details');
523
- if (stageEl) stageEl.innerText = 'Connecting via WebSocket...';
524
- if (detailsEl) detailsEl.innerText = `Opening WebSocket on ${currentEndpoints.wsSolve}...`;
525
-
526
- if (activeSocket) {
527
- activeSocket.close();
528
- }
529
-
530
- try {
531
- activeSocket = new WebSocket(currentEndpoints.wsSolve);
532
- } catch (err) {
533
- handleBackendOffline();
534
- return;
535
- }
536
-
537
- activeSocket.onopen = () => {
538
- if (stageEl) stageEl.innerText = '⚡ JAX Optimization Running';
539
- if (detailsEl) detailsEl.innerText = 'Hardware-accelerated JAX XLA optimization in progress...';
540
-
541
- activeSocket.send(JSON.stringify({
542
- action: 'solve',
543
- config: config,
544
- file_content: fileContent
545
- }));
546
- };
547
-
548
- activeSocket.onmessage = (event) => {
549
  try {
550
- const data = JSON.parse(event.data);
551
- handleSolverMessage(data);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
552
  } catch (e) {
553
- console.error("Error parsing message:", e);
554
  }
555
- };
556
-
557
- activeSocket.onerror = () => {
558
- handleBackendOffline();
559
- };
560
 
561
- activeSocket.onclose = () => {
562
- stopOptimizationUI();
563
- };
564
  }
565
 
566
  function handleSolverMessage(data) {
@@ -571,7 +519,7 @@ function handleSolverMessage(data) {
571
  const stageName = data.stage_name || `Stage ${data.stage}`;
572
  const iterText = data.iteration ? ` (Iter ${data.iteration})` : '';
573
  if (stageEl) stageEl.innerText = `⚡ ${stageName}${iterText}`;
574
- if (detailsEl) detailsEl.innerText = `Objective Loss: ${data.loss.toExponential(4)} | Diffusivity D0: ${(data.d0 || 0).toExponential(3)} cm²/s`;
575
 
576
  if (data.current_fit && window.Plotly) {
577
  updateLivePlotProgress(data.current_fit);
@@ -583,20 +531,26 @@ function handleSolverMessage(data) {
583
  stopOptimizationUI();
584
  latestResults = data;
585
  displayExtractedResults(data);
 
 
 
 
 
 
 
 
586
  } else if (data.type === 'error') {
587
- if (stageEl) stageEl.innerText = ' Optimization Error';
588
- if (detailsEl) detailsEl.innerText = data.message || 'An error occurred during calculation.';
589
- stopOptimizationUI();
590
- alert(`Solver Message: ${data.message}`);
591
  }
592
  }
593
 
594
- function handleBackendOffline() {
595
  const stageEl = document.getElementById('status-stage');
596
  const detailsEl = document.getElementById('status-details');
597
- if (stageEl) stageEl.innerText = 'Engine Reconnecting...';
598
- if (detailsEl) detailsEl.innerText = 'ZeroGPU container is initializing. Please click Execute again in 10s.';
599
  stopOptimizationUI();
 
600
  }
601
 
602
  function startOptimizationUI() {
 
1
  // CV Curve Fitting Pro - Pure Python JAX + SciPy Engine Client
2
+ // Connected to Python ZeroGPU Engine (Free ZeroGPU & CPU Ready)
3
 
4
  // Global State
5
  let activeSocket = null;
 
33
  }
34
 
35
  let httpHealth = "";
 
36
  let httpSolve = "";
37
 
38
  if (url.startsWith("https://")) {
39
  httpHealth = url + "/health";
40
  httpSolve = url + "/api/solve";
 
41
  } else if (url.startsWith("http://")) {
42
  httpHealth = url + "/health";
43
  httpSolve = url + "/api/solve";
 
 
 
 
 
 
 
 
 
44
  } else {
45
  httpHealth = "https://" + url + "/health";
46
  httpSolve = "https://" + url + "/api/solve";
 
47
  }
48
 
49
  return {
50
  rawUrl: url,
51
  httpHealth: httpHealth,
52
+ httpSolve: httpSolve
 
53
  };
54
  }
55
 
 
97
  isBackendAvailable = true;
98
  activeBackendType = "cloud";
99
  if (dot) dot.className = 'status-dot online';
100
+ if (label) label.innerText = 'ZeroGPU A100 Engine Ready';
101
  if (msg) {
102
+ msg.innerHTML = `<span style="color: #10b981; font-weight: 500;">✓ ZeroGPU JAX Server Active (100% Free)</span>`;
103
  }
104
  return false;
105
  }
 
431
  return false;
432
  };
433
 
434
+ // Execution via Native ZeroGPU Pipeline & Direct HTTP API
435
  async function executePythonSolver(fileContent, config) {
436
  const stageEl = document.getElementById('status-stage');
437
  const detailsEl = document.getElementById('status-details');
438
+ if (stageEl) stageEl.innerText = '⚡ ZeroGPU A100 Optimizing...';
439
+ if (detailsEl) detailsEl.innerText = 'JAX Auto-Diff multi-stage L-BFGS-B optimization in progress...';
440
 
441
+ // 1. Direct HTTP API Call to the Space backend
442
+ const endpoints = [
443
  window.location.origin + "/api/solve",
444
  window.location.origin + "/solve",
445
  DEFAULT_HF_SPACE_URL + "/api/solve",
446
+ DEFAULT_LOCAL_URL + "/api/solve"
 
447
  ];
448
 
449
+ for (const endpoint of endpoints) {
 
 
450
  try {
451
+ const controller = new AbortController();
452
+ const timeoutId = setTimeout(() => controller.abort(), 180000);
453
+ const res = await fetch(endpoint, {
454
  method: "POST",
455
  headers: { "Content-Type": "application/json" },
456
  body: JSON.stringify({
457
+ file_content: fileContent,
458
+ config: config
459
+ }),
460
+ signal: controller.signal
461
  });
462
+ clearTimeout(timeoutId);
463
 
464
+ if (res.ok) {
465
+ const data = await res.json();
466
+ handleSolverMessage(data);
467
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
468
  }
 
 
469
  } catch (err) {
470
+ console.warn(`HTTP solve attempt on ${endpoint} failed:`, err);
471
  }
472
  }
473
 
474
+ // 2. Native Gradio Event Trigger fallback
475
+ const grInputFile = document.querySelector('#gr_input_file textarea, #gr_input_file input');
476
+ const grInputConfig = document.querySelector('#gr_input_config textarea, #gr_input_config input');
477
+ const grBtn = document.querySelector('#gr_trigger_btn');
478
+ const grOutput = document.querySelector('#gr_output_json textarea, #gr_output_json input');
479
 
480
+ if (grInputFile && grInputConfig && grBtn) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  try {
482
+ grInputFile.value = fileContent;
483
+ grInputFile.dispatchEvent(new Event('input', { bubbles: true }));
484
+ grInputConfig.value = JSON.stringify(config);
485
+ grInputConfig.dispatchEvent(new Event('input', { bubbles: true }));
486
+
487
+ let checkCount = 0;
488
+ const checkInterval = setInterval(() => {
489
+ checkCount++;
490
+ if (grOutput && grOutput.value && grOutput.value.trim().length > 0) {
491
+ clearInterval(checkInterval);
492
+ try {
493
+ const data = JSON.parse(grOutput.value);
494
+ handleSolverMessage(data);
495
+ } catch (e) {
496
+ console.error(e);
497
+ }
498
+ } else if (checkCount > 120) {
499
+ clearInterval(checkInterval);
500
+ handleSolverError("Optimization timed out.");
501
+ }
502
+ }, 1000);
503
+
504
+ grBtn.click();
505
+ return;
506
  } catch (e) {
507
+ console.warn("Gradio trigger error:", e);
508
  }
509
+ }
 
 
 
 
510
 
511
+ handleSolverError("Could not reach ZeroGPU backend server. Please check your Space status.");
 
 
512
  }
513
 
514
  function handleSolverMessage(data) {
 
519
  const stageName = data.stage_name || `Stage ${data.stage}`;
520
  const iterText = data.iteration ? ` (Iter ${data.iteration})` : '';
521
  if (stageEl) stageEl.innerText = `⚡ ${stageName}${iterText}`;
522
+ if (detailsEl) detailsEl.innerText = `Objective Loss: ${data.loss ? data.loss.toExponential(4) : ''} | Diffusivity D0: ${(data.d0 || 0).toExponential(3)} cm²/s`;
523
 
524
  if (data.current_fit && window.Plotly) {
525
  updateLivePlotProgress(data.current_fit);
 
531
  stopOptimizationUI();
532
  latestResults = data;
533
  displayExtractedResults(data);
534
+
535
+ // Update main plot with final simulation overlay
536
+ if (data.plots && data.plots.sim_current && window.Plotly) {
537
+ updateLivePlotProgress({
538
+ potential: data.plots.exp_potential,
539
+ current: data.plots.sim_current
540
+ });
541
+ }
542
  } else if (data.type === 'error') {
543
+ handleSolverError(data.message || 'An error occurred during calculation.');
 
 
 
544
  }
545
  }
546
 
547
+ function handleSolverError(msg) {
548
  const stageEl = document.getElementById('status-stage');
549
  const detailsEl = document.getElementById('status-details');
550
+ if (stageEl) stageEl.innerText = ' Optimization Notice';
551
+ if (detailsEl) detailsEl.innerText = msg;
552
  stopOptimizationUI();
553
+ alert(`Solver: ${msg}`);
554
  }
555
 
556
  function startOptimizationUI() {