Spaces:
Running
Running
Update index.html
Browse files- index.html +33 -14
index.html
CHANGED
|
@@ -76,20 +76,38 @@
|
|
| 76 |
</button>
|
| 77 |
</div>
|
| 78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
</div>
|
| 80 |
|
| 81 |
<script>
|
| 82 |
const BASE_URL = 'https://32d5c4f4e919.ngrok-free.app';
|
| 83 |
const prevBtn = document.getElementById('prev-btn');
|
| 84 |
const nextBtn = document.getElementById('next-btn');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
|
| 86 |
/**
|
| 87 |
* Handles the API call with exponential backoff for resilience.
|
| 88 |
-
* Now includes explicit check for Content-Type to avoid JSON parsing errors
|
| 89 |
-
* when the server returns HTML (e.g., an error page).
|
| 90 |
-
* @param {string} fullUrl - The full URL to fetch.
|
| 91 |
-
* @param {number} retries - Maximum number of retry attempts.
|
| 92 |
-
* @param {number} delay - Initial delay in milliseconds.
|
| 93 |
*/
|
| 94 |
async function safeFetch(fullUrl, retries = 3, delay = 1000) {
|
| 95 |
for (let i = 0; i < retries; i++) {
|
|
@@ -98,28 +116,23 @@
|
|
| 98 |
const contentType = response.headers.get("content-type");
|
| 99 |
|
| 100 |
if (!response.ok) {
|
| 101 |
-
// Handle non-200 HTTP status codes
|
| 102 |
const responseText = await response.text();
|
| 103 |
throw new Error(`HTTP error ${response.status}: ${responseText.substring(0, 100)}...`);
|
| 104 |
}
|
| 105 |
|
| 106 |
if (!contentType || !contentType.includes("application/json")) {
|
| 107 |
-
// Handle correct HTTP status but unexpected body type (e.g., HTML error page)
|
| 108 |
const responseText = await response.text();
|
| 109 |
throw new Error(`Content-Type error! Expected 'application/json' but received: ${contentType || 'None'}. Server body starts with: ${responseText.substring(0, 50)}...`);
|
| 110 |
}
|
| 111 |
|
| 112 |
-
// Parse JSON only if checks pass
|
| 113 |
return await response.json();
|
| 114 |
|
| 115 |
} catch (error) {
|
| 116 |
-
// Log the specific error during retry
|
| 117 |
console.error(`Attempt ${i + 1} failed for ${fullUrl}:`, error.message);
|
| 118 |
if (i < retries - 1) {
|
| 119 |
await new Promise(resolve => setTimeout(resolve, delay));
|
| 120 |
-
delay *= 2;
|
| 121 |
} else {
|
| 122 |
-
// On final attempt, re-throw the error
|
| 123 |
throw new Error(`Failed to complete request to ${fullUrl} after ${retries} attempts. Reason: ${error.message}`);
|
| 124 |
}
|
| 125 |
}
|
|
@@ -128,21 +141,24 @@
|
|
| 128 |
|
| 129 |
/**
|
| 130 |
* Main function to handle button click and send request.
|
| 131 |
-
* @param {string} endpoint - The path to append to the base URL (e.g., '/next').
|
| 132 |
*/
|
| 133 |
async function sendRequest(endpoint) {
|
| 134 |
const fullUrl = `${BASE_URL}${endpoint}`;
|
| 135 |
|
| 136 |
-
// Disable buttons
|
| 137 |
prevBtn.disabled = true;
|
| 138 |
nextBtn.disabled = true;
|
|
|
|
| 139 |
console.log(`Sending request to: ${fullUrl}`);
|
| 140 |
|
| 141 |
try {
|
| 142 |
const result = await safeFetch(fullUrl);
|
|
|
|
|
|
|
| 143 |
console.log(`SUCCESS: Response from ${endpoint}`, result);
|
| 144 |
} catch (error) {
|
| 145 |
-
//
|
|
|
|
| 146 |
console.error(`ERROR: Failed request to ${endpoint}`, error.message);
|
| 147 |
} finally {
|
| 148 |
// Enable buttons regardless of success or failure
|
|
@@ -154,6 +170,9 @@
|
|
| 154 |
// Event listeners for the buttons
|
| 155 |
prevBtn.addEventListener('click', () => sendRequest(prevBtn.dataset.endpoint));
|
| 156 |
nextBtn.addEventListener('click', () => sendRequest(nextBtn.dataset.endpoint));
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
</script>
|
| 159 |
</body>
|
|
|
|
| 76 |
</button>
|
| 77 |
</div>
|
| 78 |
|
| 79 |
+
<!-- Response Display Area -->
|
| 80 |
+
<div id="response-display" class="pt-8 text-center min-h-[4rem] text-lg font-medium text-gray-400">
|
| 81 |
+
<!-- Messages will appear here -->
|
| 82 |
+
</div>
|
| 83 |
+
|
| 84 |
</div>
|
| 85 |
|
| 86 |
<script>
|
| 87 |
const BASE_URL = 'https://32d5c4f4e919.ngrok-free.app';
|
| 88 |
const prevBtn = document.getElementById('prev-btn');
|
| 89 |
const nextBtn = document.getElementById('next-btn');
|
| 90 |
+
const responseDisplay = document.getElementById('response-display');
|
| 91 |
+
|
| 92 |
+
/**
|
| 93 |
+
* Updates the UI display with the given message and style.
|
| 94 |
+
* @param {string} message - The text to display.
|
| 95 |
+
* @param {string} type - 'success' or 'error'.
|
| 96 |
+
*/
|
| 97 |
+
function updateDisplay(message, type) {
|
| 98 |
+
responseDisplay.textContent = message;
|
| 99 |
+
responseDisplay.classList.remove('text-green-400', 'text-red-400', 'text-gray-400');
|
| 100 |
+
if (type === 'success') {
|
| 101 |
+
responseDisplay.classList.add('text-green-400');
|
| 102 |
+
} else if (type === 'error') {
|
| 103 |
+
responseDisplay.classList.add('text-red-400');
|
| 104 |
+
} else {
|
| 105 |
+
responseDisplay.classList.add('text-gray-400');
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
|
| 109 |
/**
|
| 110 |
* Handles the API call with exponential backoff for resilience.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
*/
|
| 112 |
async function safeFetch(fullUrl, retries = 3, delay = 1000) {
|
| 113 |
for (let i = 0; i < retries; i++) {
|
|
|
|
| 116 |
const contentType = response.headers.get("content-type");
|
| 117 |
|
| 118 |
if (!response.ok) {
|
|
|
|
| 119 |
const responseText = await response.text();
|
| 120 |
throw new Error(`HTTP error ${response.status}: ${responseText.substring(0, 100)}...`);
|
| 121 |
}
|
| 122 |
|
| 123 |
if (!contentType || !contentType.includes("application/json")) {
|
|
|
|
| 124 |
const responseText = await response.text();
|
| 125 |
throw new Error(`Content-Type error! Expected 'application/json' but received: ${contentType || 'None'}. Server body starts with: ${responseText.substring(0, 50)}...`);
|
| 126 |
}
|
| 127 |
|
|
|
|
| 128 |
return await response.json();
|
| 129 |
|
| 130 |
} catch (error) {
|
|
|
|
| 131 |
console.error(`Attempt ${i + 1} failed for ${fullUrl}:`, error.message);
|
| 132 |
if (i < retries - 1) {
|
| 133 |
await new Promise(resolve => setTimeout(resolve, delay));
|
| 134 |
+
delay *= 2;
|
| 135 |
} else {
|
|
|
|
| 136 |
throw new Error(`Failed to complete request to ${fullUrl} after ${retries} attempts. Reason: ${error.message}`);
|
| 137 |
}
|
| 138 |
}
|
|
|
|
| 141 |
|
| 142 |
/**
|
| 143 |
* Main function to handle button click and send request.
|
|
|
|
| 144 |
*/
|
| 145 |
async function sendRequest(endpoint) {
|
| 146 |
const fullUrl = `${BASE_URL}${endpoint}`;
|
| 147 |
|
| 148 |
+
// Disable buttons and show loading state
|
| 149 |
prevBtn.disabled = true;
|
| 150 |
nextBtn.disabled = true;
|
| 151 |
+
updateDisplay("Connecting to backend...", 'loading');
|
| 152 |
console.log(`Sending request to: ${fullUrl}`);
|
| 153 |
|
| 154 |
try {
|
| 155 |
const result = await safeFetch(fullUrl);
|
| 156 |
+
// Extract and display the "Statement" from your JSON response
|
| 157 |
+
updateDisplay(result.Statement || "Success! JSON received.", 'success');
|
| 158 |
console.log(`SUCCESS: Response from ${endpoint}`, result);
|
| 159 |
} catch (error) {
|
| 160 |
+
// Display the detailed error on the screen
|
| 161 |
+
updateDisplay(`Connection Error: ${error.message}`, 'error');
|
| 162 |
console.error(`ERROR: Failed request to ${endpoint}`, error.message);
|
| 163 |
} finally {
|
| 164 |
// Enable buttons regardless of success or failure
|
|
|
|
| 170 |
// Event listeners for the buttons
|
| 171 |
prevBtn.addEventListener('click', () => sendRequest(prevBtn.dataset.endpoint));
|
| 172 |
nextBtn.addEventListener('click', () => sendRequest(nextBtn.dataset.endpoint));
|
| 173 |
+
|
| 174 |
+
// Set initial message
|
| 175 |
+
updateDisplay("Ready. Please ensure your FastAPI server is running.", 'loading');
|
| 176 |
|
| 177 |
</script>
|
| 178 |
</body>
|