| | document.addEventListener('DOMContentLoaded', () => { |
| | console.log('Landing page loaded.'); |
| | |
| | |
| | const animatedElements = document.querySelectorAll('.animate-on-scroll'); |
| | const observer = new IntersectionObserver(entries => { |
| | entries.forEach(entry => { |
| | if (entry.isIntersecting) { |
| | entry.target.classList.add('animate-fadeIn'); |
| | observer.unobserve(entry.target); |
| | } |
| | }); |
| | }, { threshold: 0.2 }); |
| | |
| | animatedElements.forEach(el => observer.observe(el)); |
| |
|
| | |
| | const initialPlotDiv = document.getElementById('initialPlot'); |
| | if (initialPlotDiv) { |
| | const plotData = JSON.parse(initialPlotDiv.dataset.plot); |
| | Plotly.newPlot('plotDiv', plotData.data, plotData.layout); |
| | } |
| |
|
| | |
| | if (!document.getElementById('toast-container')) { |
| | const toastContainer = document.createElement('div'); |
| | toastContainer.id = 'toast-container'; |
| | toastContainer.className = 'fixed top-4 right-4 z-50'; |
| | document.body.appendChild(toastContainer); |
| | } |
| | }); |
| |
|
| | function showToast(message, type = 'success') { |
| | const toast = document.createElement('div'); |
| | toast.className = `p-4 mb-4 rounded shadow-lg ${type === 'success' ? 'bg-green-500' : 'bg-red-500'} text-white`; |
| | toast.textContent = message; |
| | |
| | const container = document.getElementById('toast-container'); |
| | container.appendChild(toast); |
| | |
| | setTimeout(() => { |
| | toast.remove(); |
| | }, 3000); |
| | } |
| |
|
| | window.createPlot = function() { |
| | const column = document.getElementById('plotColumn').value; |
| | const plotType = document.getElementById('plotType').value; |
| | |
| | fetch('/forecast/sales/plot', { |
| | method: 'POST', |
| | headers: { |
| | 'Content-Type': 'application/x-www-form-urlencoded', |
| | }, |
| | body: `column=${column}&plot_type=${plotType}` |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | const plotData = JSON.parse(data.plot); |
| | Plotly.newPlot('plotDiv', plotData.data, plotData.layout); |
| | showToast(`Generated ${plotType} for ${column}`); |
| | } else { |
| | showToast(data.error, 'error'); |
| | } |
| | }) |
| | .catch(error => { |
| | console.error('Error:', error); |
| | showToast(error.message, 'error'); |
| | }); |
| | } |
| |
|
| | window.fixNulls = function(column) { |
| | const method = document.getElementById('method-' + column).value; |
| | fetch('/forecast/sales/fix_nulls', { |
| | method: 'POST', |
| | headers: {'Content-Type': 'application/x-www-form-urlencoded'}, |
| | body: `column=${column}&method=${method}` |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | const msgDiv = document.getElementById('null-fix-message'); |
| | if (data.success) { |
| | msgDiv.textContent = data.message; |
| | msgDiv.classList.remove('text-red-700'); |
| | msgDiv.classList.add('text-green-700'); |
| | showToast(data.message); |
| |
|
| | |
| | updateSummaryStats(data.summary_stats); |
| |
|
| | |
| | updatePreviewTable(data.columns, data.preview_data); |
| |
|
| | |
| | updateNullsUI(data.summary_stats.missing_values); |
| |
|
| | } else { |
| | msgDiv.textContent = data.error; |
| | msgDiv.classList.remove('text-green-700'); |
| | msgDiv.classList.add('text-red-700'); |
| | showToast(data.error, 'error'); |
| | } |
| | }); |
| | } |
| |
|
| | |
| | function updateSummaryStats(stats) { |
| | document.querySelectorAll('.summary-total-rows').forEach(el => el.textContent = stats.total_rows); |
| | document.querySelectorAll('.summary-total-cols').forEach(el => el.textContent = stats.total_columns); |
| | document.querySelectorAll('.summary-numeric-cols').forEach(el => el.textContent = stats.numeric_columns.join(', ')); |
| | document.querySelectorAll('.summary-categorical-cols').forEach(el => el.textContent = stats.categorical_columns.join(', ')); |
| | } |
| |
|
| | |
| | function updatePreviewTable(columns, previewData) { |
| | const table = document.getElementById('preview-table'); |
| | if (!table) return; |
| | |
| | let thead = table.querySelector('thead'); |
| | let tbody = table.querySelector('tbody'); |
| | thead.innerHTML = '<tr>' + columns.map(col => `<th class="px-4 py-2 bg-gray-100">${col}</th>`).join('') + '</tr>'; |
| | |
| | tbody.innerHTML = previewData.map(row => |
| | '<tr>' + columns.map(col => `<td class="border px-4 py-2">${row[col]}</td>`).join('') + '</tr>' |
| | ).join(''); |
| | } |
| |
|
| | |
| | function updateNullsUI(missingValues) { |
| | const nullList = document.getElementById('null-list'); |
| | if (!nullList) return; |
| | let html = ''; |
| | let hasNulls = false; |
| | for (const [col, count] of Object.entries(missingValues)) { |
| | if (count > 0) { |
| | hasNulls = true; |
| | html += ` |
| | <li> |
| | <span>${col}: ${count} missing values</span> |
| | <select id="method-${col}" class="border rounded p-1 mx-2"> |
| | <option value="drop">Drop Rows</option> |
| | <option value="mean">Fill Mean</option> |
| | <option value="median">Fill Median</option> |
| | <option value="mode">Fill Mode</option> |
| | </select> |
| | <button class="btn-learn-more" onclick="fixNulls('${col}')">Fix</button> |
| | </li> |
| | `; |
| | } |
| | } |
| | nullList.innerHTML = html; |
| | |
| | if (!hasNulls) { |
| | nullList.innerHTML = '<li class="text-green-700 font-semibold">No missing values remaining!</li>'; |
| | } |
| | } |
| | window.runForecast = function() { |
| | const dateCol = document.getElementById('forecastDateCol').value; |
| | const targetCol = document.getElementById('forecastTargetCol').value; |
| | const model = document.getElementById('forecastModel').value; |
| | const horizon = document.getElementById('forecastHorizon').value; |
| | const metricsDiv = document.getElementById('forecast-metrics'); |
| | const plotDiv = document.getElementById('forecast-plot'); |
| | const errorDiv = document.getElementById('forecast-error'); |
| | metricsDiv.innerHTML = ''; |
| | plotDiv.innerHTML = ''; |
| | errorDiv.textContent = ''; |
| |
|
| | fetch('/forecast/sales/run_forecast', { |
| | method: 'POST', |
| | headers: {'Content-Type': 'application/x-www-form-urlencoded'}, |
| | body: `date_col=${dateCol}&target_col=${targetCol}&model=${model}&horizon=${horizon}` |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | |
| | metricsDiv.innerHTML = ` |
| | <div class="mb-2"> |
| | <strong>Model:</strong> ${data.model} |
| | </div> |
| | <div class="mb-2"> |
| | <strong>MAPE:</strong> ${data.metrics.MAPE.toFixed(2)}% |
| | <strong class="ml-4">RMSE:</strong> ${data.metrics.RMSE.toFixed(2)} |
| | <strong class="ml-4">R²:</strong> ${data.metrics.R2.toFixed(3)} |
| | </div> |
| | `; |
| | |
| | const trace = { |
| | x: data.dates, |
| | y: data.forecast, |
| | mode: 'lines+markers', |
| | name: 'Forecast' |
| | }; |
| | const lower = data.conf_int.map(ci => ci[0]); |
| | const upper = data.conf_int.map(ci => ci[1]); |
| | const ciTrace = { |
| | x: [...data.dates, ...data.dates.slice().reverse()], |
| | y: [...upper, ...lower.reverse()], |
| | fill: 'toself', |
| | fillcolor: 'rgba(0,100,80,0.2)', |
| | line: {color: 'transparent'}, |
| | name: 'Confidence Interval', |
| | showlegend: true, |
| | type: 'scatter' |
| | }; |
| | const layout = { |
| | title: 'Forecasted Sales', |
| | xaxis: {title: 'Date'}, |
| | yaxis: {title: 'Forecast'}, |
| | showlegend: true |
| | }; |
| | Plotly.newPlot(plotDiv, [trace, ciTrace], layout); |
| | showToast('Forecast generated!'); |
| | } else { |
| | errorDiv.textContent = data.error; |
| | showToast(data.error, 'error'); |
| | } |
| | }) |
| | .catch(error => { |
| | errorDiv.textContent = error.message; |
| | showToast(error.message, 'error'); |
| | }); |
| | } |
| |
|
| | |
| |
|
| | function runPrediction() { |
| | |
| | const metricsDiv = document.getElementById('predict-metrics'); |
| | const errorDiv = document.getElementById('predict-error'); |
| | const singlePredictionSection = document.getElementById('single-prediction-section'); |
| | |
| | metricsDiv.innerHTML = '<p>Running prediction...</p>'; |
| | errorDiv.textContent = ''; |
| | singlePredictionSection.classList.add('hidden'); |
| | |
| | |
| | const targetCol = document.getElementById('predictTargetCol').value; |
| | const model = document.getElementById('predictModel').value; |
| | |
| | |
| | const formData = new FormData(); |
| | formData.append('target_col', targetCol); |
| | formData.append('model', model); |
| |
|
| | |
| | fetch('/predict/machine_failure/run_prediction', { |
| | method: 'POST', |
| | body: formData |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | |
| | let metricsHtml = |
| | '<div class="grid grid-cols-2 md:grid-cols-4 gap-4">'; |
| | for (const [key, value] of Object.entries(data.metrics)) { |
| | metricsHtml += ` |
| | <div class="p-4 bg-blue-50 rounded"> |
| | <p class="font-semibold">${key}</p> |
| | <p class="text-xl">${value.toFixed(4)}</p> |
| | </div> |
| | `; |
| | } |
| | metricsHtml += "</div>"; |
| | metricsDiv.innerHTML = metricsHtml; |
| |
|
| | |
| | if (data.top_features && Array.isArray(data.top_features)) { |
| | const fiDiv = document.getElementById("feature-importance"); |
| | const fiList = document.getElementById("feature-importance-list"); |
| | fiDiv.classList.remove("hidden"); |
| | fiList.innerHTML = ` |
| | <table class="min-w-full table-auto"> |
| | <thead> |
| | <tr> |
| | <th class="px-4 py-2 bg-gray-100">Feature</th> |
| | <th class="px-4 py-2 bg-gray-100">Importance</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | ${data.top_features |
| | .map( |
| | (f) => |
| | `<tr> |
| | <td class="border px-4 py-2">${ |
| | f.feature |
| | }</td> |
| | <td class="border px-4 py-2">${f.importance.toFixed( |
| | 4 |
| | )}</td> |
| | </tr>` |
| | ) |
| | .join("")} |
| | </tbody> |
| | </table> |
| | `; |
| | } |
| |
|
| | showToast("Model trained successfully"); |
| |
|
| | |
| | fetchSinglePredictionForm(); |
| | } else { |
| | errorDiv.textContent = data.error || 'An error occurred'; |
| | showToast(data.error || 'An error occurred', 'error'); |
| | } |
| | }) |
| | .catch(error => { |
| | errorDiv.textContent = 'Error: ' + error.message; |
| | showToast('Error: ' + error.message, 'error'); |
| | }); |
| | } |
| |
|
| | window.runPrediction = runPrediction; |
| |
|
| | |
| | function fetchSinglePredictionForm() { |
| | fetch('/predict/machine_failure/get_form_data') |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | generatePredictionForm(data.form_fields); |
| | document.getElementById('single-prediction-section').classList.remove('hidden'); |
| | } else { |
| | showToast(data.error, 'error'); |
| | document.getElementById('single-prediction-error').textContent = data.error; |
| | } |
| | }) |
| | .catch(error => { |
| | console.error('Error fetching form data:', error); |
| | showToast('Error fetching form data: ' + error.message, 'error'); |
| | document.getElementById('single-prediction-error').textContent = 'Error fetching form data: ' + error.message; |
| | }); |
| | } |
| |
|
| | |
| | function generatePredictionForm(formFields) { |
| | const formContainer = document.getElementById('single-prediction-form'); |
| | formContainer.innerHTML = ''; |
| |
|
| | formFields.forEach(field => { |
| | const div = document.createElement('div'); |
| | div.className = 'mb-4'; |
| |
|
| | const label = document.createElement('label'); |
| | label.className = 'block text-gray-700 text-sm font-bold mb-2'; |
| | label.textContent = field.name.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); |
| |
|
| | div.appendChild(label); |
| |
|
| | if (field.type === 'select') { |
| | const select = document.createElement('select'); |
| | select.id = `input-${field.name}`; |
| | select.name = field.name; |
| | select.className = 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'; |
| | |
| | field.options.forEach(option => { |
| | const optionElement = document.createElement('option'); |
| | optionElement.value = option; |
| | optionElement.textContent = option; |
| | |
| | if (field.default_value !== undefined && String(field.default_value) === String(option)) { |
| | optionElement.selected = true; |
| | } |
| | select.appendChild(optionElement); |
| | }); |
| | div.appendChild(select); |
| | } else if (field.type === 'number') { |
| | const input = document.createElement('input'); |
| | input.id = `input-${field.name}`; |
| | input.name = field.name; |
| | input.type = 'number'; |
| | input.className = 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'; |
| | input.placeholder = `Enter ${field.name.replace(/_/g, ' ')}`; |
| | if (field.default_value !== undefined) { |
| | input.value = field.default_value; |
| | } |
| | div.appendChild(input); |
| | } else { |
| | const input = document.createElement('input'); |
| | input.id = `input-${field.name}`; |
| | input.name = field.name; |
| | input.type = 'text'; |
| | input.className = 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'; |
| | input.placeholder = field.placeholder || `Enter ${field.name.replace(/_/g, ' ')}`; |
| | if (field.default_value !== undefined) { |
| | input.value = field.default_value; |
| | } |
| | div.appendChild(input); |
| | } |
| | formContainer.appendChild(div); |
| | }); |
| | } |
| |
|
| | |
| | window.predictSingleInstance = function() { |
| | const form = document.getElementById('single-prediction-form'); |
| | const formData = {}; |
| | const inputs = form.querySelectorAll('input, select'); |
| |
|
| | inputs.forEach(input => { |
| | formData[input.name] = input.value; |
| | }); |
| |
|
| | const resultDiv = document.getElementById('single-prediction-result'); |
| | const predictionOutput = document.getElementById('prediction-output'); |
| | const probabilityOutput = document.getElementById('probability-output'); |
| | const errorDiv = document.getElementById('single-prediction-error'); |
| |
|
| | resultDiv.classList.add('hidden'); |
| | errorDiv.textContent = ''; |
| | predictionOutput.textContent = 'Predicting...'; |
| | probabilityOutput.innerHTML = ''; |
| |
|
| | fetch('/predict/machine_failure/predict_single', { |
| | method: 'POST', |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | }, |
| | body: JSON.stringify(formData) |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | let displayPrediction = 'Unknown'; |
| | if (data.prediction === 0 || data.prediction === '0') { |
| | displayPrediction = 'No Failure'; |
| | } else if (data.prediction === 1 || data.prediction === '1') { |
| | displayPrediction = 'Failure'; |
| | } else { |
| | displayPrediction = data.prediction; |
| | } |
| | predictionOutput.textContent = displayPrediction; |
| |
|
| | if (data.probability && Array.isArray(data.probability)) { |
| | if (data.probability.length === 2) { |
| | const probNoFailure = data.probability[0]; |
| | const probFailure = data.probability[1]; |
| | probabilityOutput.innerHTML = `Probability of No Failure: ${(probNoFailure * 100).toFixed(2)}%<br> |
| | Probability of Failure: ${(probFailure * 100).toFixed(2)}%`; |
| | } else { |
| | probabilityOutput.innerHTML = 'Probabilities: ' + data.probability.map((p, i) => `Class ${i}: ${(p * 100).toFixed(2)}%`).join(', '); |
| | } |
| | } else { |
| | probabilityOutput.innerHTML = 'Probability: N/A (not a classification model)'; |
| | } |
| | resultDiv.classList.remove('hidden'); |
| | showToast('Single prediction successful!'); |
| | } else { |
| | errorDiv.textContent = data.error || 'An error occurred during single prediction.'; |
| | showToast(data.error || 'An error occurred', 'error'); |
| | } |
| | }) |
| | .catch(error => { |
| | console.error('Error during single prediction:', error); |
| | errorDiv.textContent = 'Error: ' + error.message; |
| | showToast('Error: ' + error.message, 'error'); |
| | }); |
| | }; |
| |
|
| |
|
| | |
| |
|
| | window.runSupplyPrediction = function() { |
| | const metricsDiv = document.getElementById('predict-metrics-supply'); |
| | const errorDiv = document.getElementById('predict-error-supply'); |
| | const singlePredictionSection = document.getElementById('single-prediction-section-supply'); |
| | |
| | metricsDiv.innerHTML = '<p>Running prediction...</p>'; |
| | errorDiv.textContent = ''; |
| | singlePredictionSection.classList.add('hidden'); |
| | |
| | |
| | const targetCol = 'failure_flag'; |
| | const model = document.getElementById('predictModelSupply').value; |
| | |
| | const formData = new FormData(); |
| | formData.append('target_col', targetCol); |
| | formData.append('model', model); |
| |
|
| | fetch('/predict/supply_failure/run_prediction', { |
| | method: 'POST', |
| | body: formData |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | let metricsHtml = |
| | '<div class="grid grid-cols-2 md:grid-cols-4 gap-4">'; |
| | for (const [key, value] of Object.entries(data.metrics)) { |
| | metricsHtml += ` |
| | <div class="p-4 bg-blue-50 rounded"> |
| | <p class="font-semibold">${key}</p> |
| | <p class="text-xl">${value.toFixed(4)}</p> |
| | </div> |
| | `; |
| | } |
| | metricsHtml += "</div>"; |
| | metricsDiv.innerHTML = metricsHtml; |
| |
|
| | |
| | if (data.top_features && Array.isArray(data.top_features)) { |
| | const fiDiv = document.getElementById("feature-importance"); |
| | const fiList = document.getElementById("feature-importance-list"); |
| | fiDiv.classList.remove("hidden"); |
| | fiList.innerHTML = ` |
| | <table class="min-w-full table-auto"> |
| | <thead> |
| | <tr> |
| | <th class="px-4 py-2 bg-gray-100">Feature</th> |
| | <th class="px-4 py-2 bg-gray-100">Importance</th> |
| | </tr> |
| | </thead> |
| | <tbody> |
| | ${data.top_features |
| | .map( |
| | (f) => |
| | `<tr> |
| | <td class="border px-4 py-2">${ |
| | f.feature |
| | }</td> |
| | <td class="border px-4 py-2">${f.importance.toFixed( |
| | 4 |
| | )}</td> |
| | </tr>` |
| | ) |
| | .join("")} |
| | </tbody> |
| | </table> |
| | `; |
| | } |
| |
|
| | showToast("Supply Model trained successfully"); |
| | fetchSupplySinglePredictionForm(); |
| | } else { |
| | errorDiv.textContent = data.error || 'An error occurred'; |
| | showToast(data.error || 'An error occurred', 'error'); |
| | } |
| | }) |
| | .catch(error => { |
| | errorDiv.textContent = 'Error: ' + error.message; |
| | showToast('Error: ' + error.message, 'error'); |
| | }); |
| | } |
| |
|
| | function fetchSupplySinglePredictionForm() { |
| | fetch('/predict/supply_failure/get_form_data') |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | generateSupplyPredictionForm(data.form_fields); |
| | document.getElementById('single-prediction-section-supply').classList.remove('hidden'); |
| | } else { |
| | showToast(data.error, 'error'); |
| | document.getElementById('single-prediction-error-supply').textContent = data.error; |
| | } |
| | }) |
| | .catch(error => { |
| | console.error('Error fetching supply form data:', error); |
| | showToast('Error fetching supply form data: ' + error.message, 'error'); |
| | document.getElementById('single-prediction-error-supply').textContent = 'Error fetching supply form data: ' + error.message; |
| | }); |
| | } |
| |
|
| | function generateSupplyPredictionForm(formFields) { |
| | const formContainer = document.getElementById('single-prediction-form-supply'); |
| | formContainer.innerHTML = ''; |
| |
|
| | formFields.forEach(field => { |
| | const div = document.createElement('div'); |
| | div.className = 'mb-4'; |
| |
|
| | const label = document.createElement('label'); |
| | label.className = 'block text-gray-700 text-sm font-bold mb-2'; |
| | label.textContent = field.name.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); |
| |
|
| | div.appendChild(label); |
| |
|
| | if (field.type === 'select') { |
| | const select = document.createElement('select'); |
| | select.id = `input-supply-${field.name}`; |
| | select.name = field.name; |
| | select.className = 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'; |
| | |
| | field.options.forEach(option => { |
| | const optionElement = document.createElement('option'); |
| | optionElement.value = option; |
| | optionElement.textContent = option; |
| | if (field.default_value !== undefined && String(field.default_value) === String(option)) { |
| | optionElement.selected = true; |
| | } |
| | select.appendChild(optionElement); |
| | }); |
| | div.appendChild(select); |
| | } else if (field.type === 'number') { |
| | const input = document.createElement('input'); |
| | input.id = `input-supply-${field.name}`; |
| | input.name = field.name; |
| | input.type = 'number'; |
| | input.className = 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'; |
| | input.placeholder = `Enter ${field.name.replace(/_/g, ' ')}`; |
| | if (field.default_value !== undefined) { |
| | input.value = field.default_value; |
| | } |
| | div.appendChild(input); |
| | } else { |
| | const input = document.createElement('input'); |
| | input.id = `input-supply-${field.name}`; |
| | input.name = field.name; |
| | input.type = 'text'; |
| | input.className = 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline'; |
| | input.placeholder = field.placeholder || `Enter ${field.name.replace(/_/g, ' ')}`; |
| | if (field.default_value !== undefined) { |
| | input.value = field.default_value; |
| | } |
| | div.appendChild(input); |
| | } |
| | formContainer.appendChild(div); |
| | }); |
| | } |
| |
|
| | window.predictSupplySingleInstance = function() { |
| | const form = document.getElementById('single-prediction-form-supply'); |
| | const formData = {}; |
| | const inputs = form.querySelectorAll('input, select'); |
| |
|
| | inputs.forEach(input => { |
| | formData[input.name] = input.value; |
| | }); |
| |
|
| | const resultDiv = document.getElementById('single-prediction-result-supply'); |
| | const predictionOutput = document.getElementById('prediction-output-supply'); |
| | const probabilityOutput = document.getElementById('probability-output-supply'); |
| | const errorDiv = document.getElementById('single-prediction-error-supply'); |
| |
|
| | resultDiv.classList.add('hidden'); |
| | errorDiv.textContent = ''; |
| | predictionOutput.textContent = 'Predicting...'; |
| | probabilityOutput.innerHTML = ''; |
| |
|
| | fetch('/predict/supply_failure/predict_single', { |
| | method: 'POST', |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | }, |
| | body: JSON.stringify(formData) |
| | }) |
| | .then(response => response.json()) |
| | .then(data => { |
| | if (data.success) { |
| | |
| | let displayPrediction = 'Unknown'; |
| | if (data.prediction === "Delivery Successful") { |
| | displayPrediction = 'Delivery Successful'; |
| | } else if (data.prediction === "Delivery Failed") { |
| | displayPrediction = 'Delivery Failed'; |
| | } else { |
| | displayPrediction = data.prediction; |
| | } |
| | predictionOutput.textContent = displayPrediction; |
| |
|
| | if (data.probability && Array.isArray(data.probability)) { |
| | if (data.probability.length === 2) { |
| | |
| | const probSuccessful = data.probability[0]; |
| | const probFailed = data.probability[1]; |
| | probabilityOutput.innerHTML = `Probability of Delivery Successful: ${(probSuccessful * 100).toFixed(2)}%<br> |
| | Probability of Delivery Failed: ${(probFailed * 100).toFixed(2)}%`; |
| | } else { |
| | probabilityOutput.innerHTML = 'Probabilities: ' + data.probability.map((p, i) => `Class ${i}: ${(p * 100).toFixed(2)}%`).join(', '); |
| | } |
| | } else { |
| | probabilityOutput.innerHTML = 'Probability: N/A (not a classification model)'; |
| | } |
| | resultDiv.classList.remove('hidden'); |
| | showToast('Single prediction successful!'); |
| | } else { |
| | errorDiv.textContent = data.error || 'An error occurred during single prediction.'; |
| | showToast(data.error || 'An error occurred', 'error'); |
| | } |
| | }) |
| | .catch(error => { |
| | console.error('Error during single prediction:', error); |
| | errorDiv.textContent = 'Error: ' + error.message; |
| | showToast('Error: ' + error.message, 'error'); |
| | }); |
| | }; |