Test_1 / index.html
smithmegan's picture
Update index.html
961ef37 verified
Raw History Blame Contribute Delete
7.37 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>AI Recommendation Engine</title>
<!-- Fast CSV Parser & Markdown Renderer CDNs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.4.1/papaparse.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
:root {
--primary: #4f46e5;
--bg: #f9fafb;
--card: #ffffff;
--text: #1f2937;
--border: #e5e7eb;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background-color: var(--bg);
color: var(--text);
max-width: 1200px;
margin: 30px auto;
padding: 0 20px;
}
/* Responsive Two-Column Layout */
.container {
display: grid;
grid-template-columns: 1.6fr 1fr; /* Quiz takes ~60%, Sidebar ~40% */
gap: 24px;
}
/* Stack on mobile screens */
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
}
}
.card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05);
}
/* Form Styles */
.form-group {
margin-bottom: 16px;
}
label {
display: block;
font-weight: 600;
margin-bottom: 6px;
text-transform: none;
}
select, input[type="number"] {
width: 100%;
padding: 10px;
border: 1px solid var(--border);
border-radius: 6px;
box-sizing: border-box;
font-size: 14px;
}
button {
width: 100%;
background-color: var(--primary);
color: white;
border: none;
padding: 12px;
border-radius: 6px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
button:hover {
background-color: #4338ca;
}
/* Result Box */
.result-box {
margin-top: 20px;
padding: 16px;
background: #eef2ff;
border-left: 4px solid var(--primary);
border-radius: 4px;
display: none;
}
/* Sidebar Markdown Styles */
.sidebar h1, .sidebar h2, .sidebar h3 {
color: var(--primary);
margin-top: 0;
}
.sidebar img {
max-width: 100%;
height: auto;
margin-top: 15px;
}
.disclaimer {
font-size: 13px;
color: #6b7280;
margin-top: 16px;
}
</style>
</head>
<body>
<div class="container">
<!-- MAIN COLUMN: Quiz Interface -->
<main class="card">
<h2>😌 AI Recommendation Engine</h2>
<p>Take the quiz below to get a personalized recommendation based on our dataset.</p>
<div id="loading">Loading dataset...</div>
<form id="quiz-form" style="display: none;"></form>
<div id="result-box" class="result-box">
<h3 style="margin: 0 0 8px 0;">Your Recommendation:</h3>
<p id="recommendation-text" style="font-size: 18px; font-weight: bold; margin: 0;"></p>
</div>
<div class="disclaimer">
⭐ <strong>Note:</strong> Recommendations are derived using nearest-neighbor similarity matching against <code>data.csv</code> directly in your browser.
</div>
</main>
<!-- SIDEBAR COLUMN: Project Info (renders info.md) -->
<aside class="card sidebar" id="sidebar-content">
<p>Loading project details...</p>
</aside>
</div>
<script>
let csvData = [];
let featureCols = [];
let targetCol = "";
// 1. Fetch & Render info.md into the sidebar automatically
fetch("info.md")
.then(res => res.text())
.then(text => {
document.getElementById("sidebar-content").innerHTML = marked.parse(text);
})
.catch(() => {
document.getElementById("sidebar-content").innerHTML = "<p>Could not load info.md</p>";
});
// 2. Fetch & Parse data.csv
Papa.parse("data.csv", {
download: true,
header: true,
skipEmptyLines: true,
complete: function(results) {
csvData = results.data;
if (csvData.length === 0) return;
const allCols = Object.keys(csvData[0]);
const hasTimestamp = allCols[0].toLowerCase().includes("time");
const cleanCols = hasTimestamp ? allCols.slice(1) : allCols;
targetCol = cleanCols[cleanCols.length - 1];
featureCols = cleanCols.slice(0, cleanCols.length - 1);
buildForm();
}
});
// 3. Dynamic Form Generator
function buildForm() {
const form = document.getElementById("quiz-form");
featureCols.forEach(col => {
const group = document.createElement("div");
group.className = "form-group";
const label = document.createElement("label");
label.innerText = col;
group.appendChild(label);
const sampleValue = csvData[0][col];
const isNumeric = !isNaN(parseFloat(sampleValue)) && isFinite(sampleValue);
if (isNumeric) {
const input = document.createElement("input");
input.type = "number";
input.name = col;
input.step = "any";
input.required = true;
input.placeholder = `Enter ${col}`;
group.appendChild(input);
} else {
const select = document.createElement("select");
select.name = col;
select.required = true;
const uniqueVals = [...new Set(csvData.map(row => row[col]))].filter(Boolean);
uniqueVals.forEach(val => {
const opt = document.createElement("option");
opt.value = val;
opt.innerText = val;
select.appendChild(opt);
});
group.appendChild(select);
}
form.appendChild(group);
});
const btn = document.createElement("button");
btn.type = "submit";
btn.innerText = "Click to see your personalized result!";
form.appendChild(btn);
document.getElementById("loading").style.display = "none";
form.style.display = "block";
form.addEventListener("submit", getRecommendation);
}
// 4. Recommendation Logic
function getRecommendation(e) {
e.preventDefault();
const formData = new FormData(e.target);
const userInputs = {};
featureCols.forEach(col => userInputs[col] = formData.get(col));
let minDistance = Infinity;
let bestMatchRow = null;
csvData.forEach(row => {
let distance = 0;
featureCols.forEach(col => {
const userVal = userInputs[col];
const rowVal = row[col];
if (!isNaN(userVal) && !isNaN(rowVal)) {
distance += Math.pow(parseFloat(userVal) - parseFloat(rowVal), 2);
} else {
distance += (userVal === rowVal ? 0 : 1);
}
});
if (distance < minDistance) {
minDistance = distance;
bestMatchRow = row;
}
});
const resultBox = document.getElementById("result-box");
const resultText = document.getElementById("recommendation-text");
resultText.innerText = bestMatchRow[targetCol];
resultBox.style.display = "block";
}
</script>
</body>
</html>