Skip to content

Commit 76ddd87

Browse files
committed
stablize it
1 parent 48c4171 commit 76ddd87

2 files changed

Lines changed: 118 additions & 51 deletions

File tree

app.js

Lines changed: 101 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,36 @@ const POINT_CLOUDS = {
77
5: generatePyramid(1000)
88
};
99

10-
// Function to generate point cloud based on instruction
11-
async function processInstruction() {
12-
const instruction = document.getElementById('instruction').value;
13-
14-
if (!instruction) {
15-
alert('Please enter an instruction');
16-
return;
17-
}
18-
19-
// Show loading spinner
20-
document.getElementById('loading').style.display = 'block';
10+
let isProcessing = false; // Track if we're currently processing a request
2111

22-
try {
23-
// Call the server endpoint
24-
// const response = await fetch('http://localhost:8080/generate', {
25-
const response = await fetch('https://yixuanwang.me/generate', {
26-
method: 'POST',
27-
headers: {
28-
'Content-Type': 'application/json',
29-
'Accept': 'application/json'
30-
},
31-
body: JSON.stringify({ instruction })
32-
});
12+
// Function to check if Plotly is loaded
13+
function isPlotlyReady() {
14+
return typeof Plotly !== 'undefined';
15+
}
3316

34-
const data = await response.json();
35-
if (!response.ok) {
36-
throw new Error(data.error || 'Request failed');
17+
// Function to wait for Plotly to load
18+
function waitForPlotly(callback, maxAttempts = 10) {
19+
let attempts = 0;
20+
const checkInterval = setInterval(() => {
21+
attempts++;
22+
if (isPlotlyReady()) {
23+
clearInterval(checkInterval);
24+
callback();
25+
} else if (attempts >= maxAttempts) {
26+
clearInterval(checkInterval);
27+
console.error('Plotly failed to load');
28+
alert('Visualization library failed to load. Please refresh the page.');
3729
}
38-
39-
// Visualize the point cloud
40-
visualizePointCloud(data.points);
41-
} catch (error) {
42-
console.error('Error:', error);
43-
alert('Error: ' + error.message);
44-
} finally {
45-
// Hide loading spinner
46-
document.getElementById('loading').style.display = 'none';
47-
}
30+
}, 500);
4831
}
4932

5033
// Function to visualize point cloud using Plotly
5134
function visualizePointCloud(points) {
35+
if (!isPlotlyReady()) {
36+
waitForPlotly(() => visualizePointCloud(points));
37+
return;
38+
}
39+
5240
const x = points.map(p => p[0]);
5341
const y = points.map(p => p[1]);
5442
const z = points.map(p => p[2]);
@@ -82,7 +70,76 @@ function visualizePointCloud(points) {
8270
}
8371
};
8472

85-
Plotly.newPlot('visualization', [trace], layout);
73+
try {
74+
Plotly.newPlot('visualization', [trace], layout);
75+
} catch (error) {
76+
console.error('Error plotting:', error);
77+
alert('Error creating visualization. Please try again.');
78+
}
79+
}
80+
81+
// Function to generate point cloud based on instruction
82+
async function processInstruction() {
83+
if (isProcessing) return; // Prevent multiple simultaneous submissions
84+
85+
const instructionInput = document.getElementById('instruction');
86+
const submitButton = document.querySelector('.button.is-primary');
87+
const loadingSpinner = document.getElementById('loading');
88+
89+
if (!instructionInput.value) {
90+
alert('Please enter an instruction');
91+
return;
92+
}
93+
94+
// Disable UI elements and show loading state
95+
isProcessing = true;
96+
instructionInput.disabled = true;
97+
submitButton.disabled = true;
98+
loadingSpinner.style.display = 'block';
99+
100+
// Setup request timeout
101+
const controller = new AbortController();
102+
const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
103+
104+
try {
105+
// Call the server endpoint
106+
const response = await fetch('https://yixuanwang.me/generate', {
107+
method: 'POST',
108+
headers: {
109+
'Content-Type': 'application/json',
110+
'Accept': 'application/json'
111+
},
112+
body: JSON.stringify({ instruction: instructionInput.value }),
113+
signal: controller.signal
114+
});
115+
116+
clearTimeout(timeoutId);
117+
118+
if (!response.ok) {
119+
const data = await response.json();
120+
throw new Error(data.error || 'Request failed');
121+
}
122+
123+
const data = await response.json();
124+
// Visualize the point cloud
125+
visualizePointCloud(data.points);
126+
} catch (error) {
127+
console.error('Error:', error);
128+
if (error.name === 'AbortError') {
129+
alert('Request timed out. Please try again.');
130+
} else {
131+
alert('Error: ' + error.message);
132+
}
133+
// Show a precomputed point cloud as fallback
134+
visualizePointCloud(POINT_CLOUDS[1]);
135+
} finally {
136+
// Re-enable UI elements and hide loading state
137+
isProcessing = false;
138+
instructionInput.disabled = false;
139+
submitButton.disabled = false;
140+
loadingSpinner.style.display = 'none';
141+
clearTimeout(timeoutId);
142+
}
86143
}
87144

88145
// Point cloud generation functions
@@ -165,14 +222,17 @@ function generatePyramid(numPoints) {
165222
return points;
166223
}
167224

225+
// Initialize visualization when the page loads
226+
document.addEventListener('DOMContentLoaded', function() {
227+
// Wait for Plotly to load before showing initial visualization
228+
waitForPlotly(() => {
229+
visualizePointCloud(POINT_CLOUDS[1]); // Show initial sphere
230+
});
231+
});
232+
168233
// Add event listener for Enter key
169234
document.getElementById('instruction').addEventListener('keypress', function(e) {
170235
if (e.key === 'Enter') {
171236
processInstruction();
172237
}
173-
});
174-
175-
// On page load, show a precomputed point cloud (e.g., a sphere)
176-
window.addEventListener('DOMContentLoaded', function() {
177-
visualizePointCloud(POINT_CLOUDS[1]); // or any other precomputed shape
178238
});

index.html

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<!-- External Libraries -->
1919
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
2020
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
21-
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
21+
<script src="https://cdn.plot.ly/plotly-2.27.1.min.js"></script>
2222
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
2323

2424
<!-- Fonts -->
@@ -266,24 +266,31 @@ <h2 class="title is-3">Method</h2>
266266
<div class="columns" style="margin-bottom: -10rem;">
267267
<div class="column is-6 is-offset-5" style="max-width: 100%;">
268268
<div style="width: 60%; min-width: 300px; max-width: 500px;">
269-
<div class="field has-addons">
269+
<div class="field has-addons" style="position: relative;">
270270
<div class="control has-icons-left is-expanded">
271-
<input type="text" id="instruction" class="input is-small" style="font-size: 0.875rem;" placeholder="Hang the blue mug on the left branch.">
271+
<input type="text"
272+
id="instruction"
273+
class="input is-small"
274+
style="font-size: 0.875rem;"
275+
placeholder="Hang the blue mug on the left branch."
276+
autocomplete="off"
277+
spellcheck="false">
272278
<span class="icon is-left is-small">
273279
<i class="fas fa-terminal"></i>
274280
</span>
275281
</div>
276282
<div class="control">
277-
<button class="button is-primary is-small" onclick="processInstruction()" style="font-size: 0.875rem;">
283+
<button class="button is-primary is-small"
284+
onclick="processInstruction()"
285+
style="font-size: 0.875rem; min-width: 70px;">
278286
<span>Enter</span>
279287
</button>
280288
</div>
281-
</div>
282-
<div id="loading" class="has-text-left" style="display: none; margin-top: 0.5rem;">
283-
<span class="icon">
284-
<i class="fas fa-circle-notch fa-spin"></i>
285-
</span>
286-
<span>Loading...</span>
289+
<div class="control" id="loading" style="display: none; position: absolute; right: -30px; top: 50%; transform: translateY(-50%);">
290+
<span class="icon is-small">
291+
<i class="fas fa-circle-notch fa-spin"></i>
292+
</span>
293+
</div>
287294
</div>
288295
</div>
289296
</div>

0 commit comments

Comments
 (0)