smart-mcq-solver / index.html
KrishivPatel11111's picture
Update index.html
a583fe1 verified
Raw
History Blame Contribute Delete
7.85 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Smart MCQ Solver</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 30px 15px;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #eef2ff, #f8fafc);
color: #172033;
}
.container {
width: 100%;
max-width: 850px;
margin: auto;
padding: 30px;
background: white;
border-radius: 18px;
box-shadow: 0 12px 35px rgba(0, 0, 0, 0.1);
}
h1 {
margin-top: 0;
text-align: center;
color: #4338ca;
}
.description {
text-align: center;
color: #64748b;
margin-bottom: 28px;
}
label {
display: block;
margin-top: 15px;
margin-bottom: 6px;
font-weight: bold;
}
textarea,
input {
width: 100%;
padding: 12px;
border: 1px solid #cbd5e1;
border-radius: 9px;
font-size: 15px;
}
textarea {
min-height: 100px;
resize: vertical;
}
.options {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
button {
width: 100%;
margin-top: 24px;
padding: 14px;
border: none;
border-radius: 9px;
background: #4f46e5;
color: white;
font-size: 17px;
font-weight: bold;
cursor: pointer;
}
button:hover {
background: #3730a3;
}
button:disabled {
background: #94a3b8;
cursor: wait;
}
#status {
margin-top: 18px;
padding: 12px;
text-align: center;
background: #f1f5f9;
border-radius: 9px;
color: #475569;
}
#result {
display: none;
margin-top: 20px;
padding: 20px;
border: 2px solid #c7d2fe;
border-radius: 12px;
background: #eef2ff;
}
.prediction {
text-align: center;
font-size: 25px;
font-weight: bold;
color: #4338ca;
margin-bottom: 18px;
}
.rank {
margin-top: 9px;
padding: 11px;
background: white;
border-radius: 8px;
}
.note {
margin-top: 25px;
font-size: 13px;
color: #64748b;
text-align: center;
}
@media (max-width: 600px) {
.options {
grid-template-columns: 1fr;
}
.container {
padding: 20px;
}
}
</style>
</head>
<body>
<main class="container">
<h1>🧠 Smart MCQ Solver</h1>
<p class="description">
Rank five answer options using MiniLM sentence embeddings
and semantic similarity.
</p>
<label for="question">Question</label>
<textarea
id="question"
placeholder="Enter your multiple-choice question"
></textarea>
<div class="options">
<div>
<label for="optionA">Option A</label>
<input id="optionA" placeholder="Enter option A" />
</div>
<div>
<label for="optionB">Option B</label>
<input id="optionB" placeholder="Enter option B" />
</div>
<div>
<label for="optionC">Option C</label>
<input id="optionC" placeholder="Enter option C" />
</div>
<div>
<label for="optionD">Option D</label>
<input id="optionD" placeholder="Enter option D" />
</div>
<div>
<label for="optionE">Option E</label>
<input id="optionE" placeholder="Enter option E" />
</div>
</div>
<button id="solveButton">Rank Answers</button>
<div id="status">
The AI model will download when you make the first prediction.
</div>
<section id="result">
<div id="prediction" class="prediction"></div>
<div id="rankings"></div>
</section>
<p class="note">
This demonstration uses the MiniLM component from the Smart MCQ
Solver Kaggle project.
</p>
</main>
<script type="module">
import { pipeline } from
"https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.8.1";
const MODEL_ID =
"onnx-community/all-MiniLM-L6-v2-ONNX";
const labels = ["A", "B", "C", "D", "E"];
const button = document.getElementById("solveButton");
const status = document.getElementById("status");
const result = document.getElementById("result");
const prediction = document.getElementById("prediction");
const rankings = document.getElementById("rankings");
let extractor = null;
function getValue(id) {
return document.getElementById(id).value.trim();
}
function escapeHTML(value) {
const element = document.createElement("div");
element.textContent = value;
return element.innerHTML;
}
function dotProduct(first, second) {
return first.reduce(
(total, value, index) =>
total + value * second[index],
0
);
}
button.addEventListener("click", async () => {
const question = getValue("question");
const options = [
getValue("optionA"),
getValue("optionB"),
getValue("optionC"),
getValue("optionD"),
getValue("optionE")
];
if (!question) {
status.textContent = "Please enter a question.";
return;
}
if (options.some(option => !option)) {
status.textContent = "Please enter all five options.";
return;
}
button.disabled = true;
result.style.display = "none";
try {
if (!extractor) {
status.textContent =
"Downloading the MiniLM model. Please wait...";
extractor = await pipeline(
"feature-extraction",
MODEL_ID,
{
dtype: "q4",
progress_callback: event => {
if (
event.status === "progress" &&
event.progress !== undefined
) {
status.textContent =
`Downloading model: ${Math.round(
event.progress
)}%`;
}
}
}
);
}
status.textContent = "Analysing the answer options...";
const output = await extractor(
[question, ...options],
{
pooling: "mean",
normalize: true
}
);
const vectors = output.tolist();
const questionVector = vectors[0];
const scores = options.map(
(_, index) =>
dotProduct(
questionVector,
vectors[index + 1]
)
);
const rankedIndices = [0, 1, 2, 3, 4].sort(
(first, second) =>
scores[second] - scores[first]
);
const topThree = rankedIndices
.slice(0, 3)
.map(index => labels[index])
.join(" ");
prediction.textContent =
`Top-3 Prediction: ${topThree}`;
rankings.innerHTML = rankedIndices
.map(
(index, position) => `
<div class="rank">
<strong>
${position + 1}. Option ${labels[index]}
</strong>
${escapeHTML(options[index])}
<br>
Similarity score: ${scores[index].toFixed(4)}
</div>
`
)
.join("");
result.style.display = "block";
status.textContent =
"Prediction completed successfully.";
} catch (error) {
console.error(error);
status.textContent =
"The model could not load. Refresh the page and try again.";
} finally {
button.disabled = false;
}
});
</script>
</body>
</html>