| document.addEventListener('DOMContentLoaded', function () { | |
| const form = document.getElementById('prediction-form'); | |
| const predictBtn = document.getElementById('predict-btn'); | |
| const spinner = predictBtn.querySelector('.spinner-border'); | |
| const resultsArea = document.getElementById('results-area'); | |
| const errorAlert = document.getElementById('error-alert'); | |
| const consentCheckbox = document.getElementById('consent-checkbox'); | |
| const dataFileInput = document.getElementById('data-file'); | |
| const downloadTemplateLink = document.getElementById('download-template'); | |
| downloadTemplateLink.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| const csvContent = "protein_sequence,substrate_smiles\n" + | |
| "MTEITAAMVKELRESTGAGMMDCKNALSETNGDFDKAVQLLREKGLGKAAKKADRLAAEG,CC(=O)O\n" + | |
| "MKAVQLLREKGLGKAAKKADRLAAEGTKAVQLLREKGLGKAAKKADRLAAEGGKAAKKADR,C(C(=O)O)N"; | |
| const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); | |
| const link = document.createElement("a"); | |
| const url = URL.createObjectURL(blob); | |
| link.setAttribute("href", url); | |
| link.setAttribute("download", "template.csv"); | |
| link.style.visibility = 'hidden'; | |
| document.body.appendChild(link); | |
| link.click(); | |
| document.body.removeChild(link); | |
| }); | |
| form.addEventListener('submit', async function (event) { | |
| event.preventDefault(); | |
| predictBtn.disabled = true; | |
| spinner.classList.remove('d-none'); | |
| resultsArea.classList.add('d-none'); | |
| errorAlert.classList.add('d-none'); | |
| const file = dataFileInput.files[0]; | |
| if (!file) { | |
| showError("错误:请先选择一个文件。"); | |
| return; | |
| } | |
| const formData = new FormData(); | |
| formData.append('data_file', file); | |
| formData.append('consent_given', consentCheckbox.checked); | |
| try { | |
| const response = await fetch('/predict', { | |
| method: 'POST', | |
| body: formData, | |
| }); | |
| if (!response.ok) { | |
| const errorData = await response.json(); | |
| throw new Error(errorData.error || '服务器返回了一个未知错误。'); | |
| } | |
| const blob = await response.blob(); | |
| const contentDisposition = response.headers.get('Content-Disposition'); | |
| let filename = 'predictions.csv'; | |
| if (contentDisposition) { | |
| const filenameMatch = contentDisposition.match(/filename="(.+)"/); | |
| if (filenameMatch && filenameMatch.length > 1) { | |
| filename = filenameMatch[1]; | |
| } | |
| } | |
| const url = window.URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.style.display = 'none'; | |
| a.href = url; | |
| a.download = filename; | |
| document.body.appendChild(a); | |
| a.click(); | |
| window.URL.revokeObjectURL(url); | |
| document.body.removeChild(a); | |
| resultsArea.classList.remove('d-none'); | |
| } catch (error) { | |
| showError('错误: ' + error.message); | |
| } finally { | |
| predictBtn.disabled = false; | |
| spinner.classList.add('d-none'); | |
| } | |
| }); | |
| function showError(message) { | |
| errorAlert.textContent = message; | |
| errorAlert.classList.remove('d-none'); | |
| predictBtn.disabled = false; | |
| spinner.classList.add('d-none'); | |
| } | |
| }); |