Bio-gpt / templates /index.html
Priyansu19's picture
Add all BioGPT app files with LFS tracking
b347ca3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BioGPT HoC Inference</title>
<!-- Load Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Include Inter font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
}
.hallmark-badge {
display: inline-block;
padding: 0.3rem 0.6rem;
margin: 0.2rem;
border-radius: 0.5rem; /* Rounded corners */
font-size: 0.8rem;
line-height: 1rem;
font-weight: 500;
cursor: default;
transition: background-color 0.2s ease-in-out;
border: 1px solid transparent;
}
/* Color definitions (same as before) */
.hallmark-color-0 { background-color: #EFF6FF; color: #1E40AF; border-color: #BEE3F8; } /* Blue */
.hallmark-color-1 { background-color: #ECFDF5; color: #065F46; border-color: #A7F3D0; } /* Green */
.hallmark-color-2 { background-color: #FFFBEB; color: #92400E; border-color: #FDE68A; } /* Yellow */
.hallmark-color-3 { background-color: #FEF2F2; color: #991B1B; border-color: #FECACA; } /* Red */
.hallmark-color-4 { background-color: #F5F3FF; color: #5B21B6; border-color: #DDD6FE; } /* Purple */
.hallmark-color-5 { background-color: #FDF2F8; color: #9D174D; border-color: #FBCFE8; } /* Pink */
.hallmark-color-6 { background-color: #EEF2FF; color: #3730A3; border-color: #C7D2FE; } /* Indigo */
.hallmark-color-7 { background-color: #F0FDFA; color: #134E4A; border-color: #99F6E4; } /* Teal */
.hallmark-color-8 { background-color: #FFF7ED; color: #9A3412; border-color: #FED7AA; } /* Orange */
.hallmark-color-9 { background-color: #F9FAFB; color: #374151; border-color: #E5E7EB; } /* Gray */
/* Loading Spinner */
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
width: 36px;
height: 36px;
border-radius: 50%;
border-left-color: #4f46e5; /* Indigo */
animation: spin 1s ease infinite;
margin: 20px auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center justify-center p-4 sm:p-6">
<div class="bg-white p-6 sm:p-8 rounded-lg shadow-xl w-full max-w-2xl space-y-6">
<!-- Header -->
<div class="text-center border-b pb-4">
<h1 class="text-2xl sm:text-3xl font-bold text-gray-800 mb-1">BioGPT HoC Inference</h1>
<h2 class="text-md sm:text-lg font-semibold text-blue-700 mb-2">~27M Parameter Finetuned SLM</h2>
<p class="text-sm text-gray-600 max-w-2xl mx-auto">
Enter a biomedical abstract below to predict Hallmarks of Cancer labels using the finetuned model.
</p>
</div>
<!-- Input Area -->
<div>
<label for="abstract-input" class="block text-sm font-medium text-gray-700 mb-1">Enter Abstract Text:</label>
<textarea id="abstract-input" rows="8" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition duration-150 ease-in-out shadow-sm" placeholder="Paste or type abstract here..."></textarea>
</div>
<!-- Predict Button -->
<div class="text-center">
<button id="predict-button" class="bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2.5 px-8 rounded-lg transition duration-150 ease-in-out shadow-md hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed">
Predict Hallmarks
</button>
</div>
<!-- Results Area -->
<div id="results-area" class="space-y-3 hidden">
<div class="border border-green-200 p-4 rounded-lg bg-green-50 shadow-sm min-h-[80px]">
<h3 class="text-md font-semibold text-green-800 mb-2">Predicted Hallmarks:</h3>
<div id="loading-indicator" class="hidden text-center">
<div class="spinner"></div>
<p class="text-sm text-gray-600">Predicting...</p>
</div>
<div id="error-message" class="hidden text-center text-red-600 font-medium">
An error occurred. Please try again.
</div>
<div id="prediction-output">
<!-- Badges will be inserted here -->
</div>
</div>
</div>
</div>
<script>
// --- Hallmark Colors (for consistent styling) ---
const hallmarkList = [ // Ensure this matches the list in app.py
"activating invasion and metastasis", "avoiding immune destruction",
"cellular energetics", "enabling replicative immortality",
"evading growth suppressors", "genomic instability and mutation",
"inducing angiogenesis", "resisting cell death",
"sustaining proliferative signaling", "tumor promoting inflammation",
];
const hallmarkColors = {};
hallmarkList.forEach((hallmark, index) => {
hallmarkColors[hallmark] = `hallmark-color-${index % 10}`;
});
// --- DOM Elements ---
const abstractInput = document.getElementById('abstract-input');
const predictButton = document.getElementById('predict-button');
const resultsArea = document.getElementById('results-area');
const loadingIndicator = document.getElementById('loading-indicator');
const errorMessage = document.getElementById('error-message');
const predictionOutput = document.getElementById('prediction-output');
// --- Event Listener ---
predictButton.addEventListener('click', handlePrediction);
// --- Prediction Logic ---
async function handlePrediction() {
const abstractText = abstractInput.value.trim();
if (!abstractText) {
alert("Please enter some abstract text.");
return;
}
// --- UI Updates: Start loading ---
predictButton.disabled = true;
resultsArea.classList.remove('hidden');
predictionOutput.innerHTML = ''; // Clear previous results
errorMessage.classList.add('hidden');
loadingIndicator.classList.remove('hidden');
try {
// --- Call the backend API ---
const response = await fetch('/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ abstract: abstractText }),
});
// --- Handle Response ---
loadingIndicator.classList.add('hidden'); // Hide loading indicator
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
}
const data = await response.json();
displayPredictions(data.predictions);
} catch (error) {
console.error('Prediction failed:', error);
loadingIndicator.classList.add('hidden');
errorMessage.textContent = `Prediction failed: ${error.message}`;
errorMessage.classList.remove('hidden');
} finally {
predictButton.disabled = false; // Re-enable button
}
}
// --- Display Logic ---
function displayPredictions(predictions) {
predictionOutput.innerHTML = ''; // Clear previous just in case
errorMessage.classList.add('hidden');
if (predictions && predictions.length > 0) {
predictions.forEach(label => {
const badge = document.createElement('span');
badge.textContent = label;
const colorClass = hallmarkColors[label] || 'hallmark-color-9'; // Default color
badge.className = `hallmark-badge ${colorClass}`;
predictionOutput.appendChild(badge);
});
} else {
predictionOutput.innerHTML = '<span class="text-gray-500 italic text-sm">No specific hallmarks predicted for this abstract.</span>';
}
}
</script>
</body>
</html>