junaid17's picture
Update index.html
2bbf568 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Customer Segmentation API</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--dark-gray: #1a1a1a;
--darker-gray: #0d0d0d;
--light-gray: #2d2d2d;
--accent: #4a90e2;
--accent-hover: #357abd;
--text: #e0e0e0;
--text-secondary: #a0a0a0;
--success: #4caf50;
--error: #f44336;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, var(--darker-gray), var(--dark-gray));
color: var(--text);
min-height: 100vh;
padding: 20px;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
.header {
text-align: center;
margin-bottom: 40px;
animation: fadeInDown 1s ease-out;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
background: linear-gradient(45deg, var(--accent), #66b3ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header p {
color: var(--text-secondary);
font-size: 1.1rem;
}
.main-content {
display: grid;
grid-template-columns: 1fr;
gap: 30px;
}
@media (min-width: 768px) {
.main-content {
grid-template-columns: 1fr 1fr;
}
}
.form-section, .result-section {
background: var(--light-gray);
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
animation: slideInUp 0.8s ease-out;
}
.form-section h2, .result-section h2 {
margin-bottom: 25px;
color: var(--accent);
font-size: 1.8rem;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
color: var(--text);
font-weight: 500;
}
.form-group input {
width: 100%;
padding: 12px 15px;
border: 2px solid #404040;
border-radius: 8px;
background: var(--darker-gray);
color: var(--text);
font-size: 1rem;
transition: all 0.3s ease;
}
.form-group input:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.2);
}
.form-group input:hover {
border-color: #5a9fe4;
}
.submit-btn {
width: 100%;
padding: 15px;
background: linear-gradient(45deg, var(--accent), #66b3ff);
color: white;
border: none;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
margin-top: 10px;
}
.submit-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(74, 144, 226, 0.4);
}
.submit-btn:active {
transform: translateY(0);
}
.submit-btn:disabled {
background: #555;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.result-card {
background: var(--darker-gray);
padding: 25px;
border-radius: 10px;
border-left: 4px solid var(--accent);
margin-bottom: 20px;
animation: fadeIn 0.6s ease-out;
}
.result-card h3 {
color: var(--accent);
margin-bottom: 10px;
font-size: 1.3rem;
}
.result-card p {
color: var(--text-secondary);
margin-bottom: 5px;
}
.loading {
text-align: center;
padding: 20px;
display: none;
}
.spinner {
border: 4px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top: 4px solid var(--accent);
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 15px;
}
.error {
background: rgba(244, 67, 54, 0.1);
border: 1px solid var(--error);
color: var(--error);
padding: 15px;
border-radius: 8px;
margin: 15px 0;
display: none;
}
.success {
background: rgba(76, 175, 80, 0.1);
border: 1px solid var(--success);
color: var(--success);
padding: 15px;
border-radius: 8px;
margin: 15px 0;
display: none;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInUp {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.pulse {
animation: pulse 2s infinite;
}
.mobile-only {
display: block;
}
@media (min-width: 768px) {
.mobile-only {
display: none;
}
}
.desktop-only {
display: none;
}
@media (min-width: 768px) {
.desktop-only {
display: block;
}
}
.form-grid {
display: grid;
grid-template-columns: 1fr;
gap: 15px;
}
@media (min-width: 768px) {
.form-grid {
grid-template-columns: 1fr 1fr;
}
}
.input-pair {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
@media (max-width: 767px) {
.input-pair {
grid-template-columns: 1fr;
}
}
.result-highlight {
background: rgba(74, 144, 226, 0.1);
padding: 15px;
border-radius: 8px;
margin: 10px 0;
border: 1px solid var(--accent);
}
.result-title {
font-size: 1.2rem;
color: var(--accent);
margin-bottom: 5px;
}
.result-content {
color: var(--text);
}
.no-result {
text-align: center;
color: var(--text-secondary);
padding: 40px 20px;
font-style: italic;
}
.animate-in {
animation: fadeIn 0.5s ease-out forwards;
}
.animate-out {
animation: fadeOut 0.3s ease-out forwards;
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.slide-up {
animation: slideUp 0.5s ease-out;
}
@keyframes slideUp {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Customer Segmentation API</h1>
<p>Enter customer data to predict their segment and get personalized recommendations</p>
</div>
<div class="main-content">
<div class="form-section">
<h2>Customer Data</h2>
<form id="predictionForm">
<div class="form-grid">
<div class="form-group">
<label for="age">Age</label>
<input type="number" id="age" name="age" min="18" max="100" required placeholder="18-100">
</div>
<div class="form-group">
<label for="income">Income</label>
<input type="number" id="income" name="income" min="0" max="200000" required placeholder="0-200000">
</div>
</div>
<div class="form-group">
<label for="totalSpendings">Total Spendings</label>
<input type="number" id="totalSpendings" name="totalSpendings" min="0" max="5000" required placeholder="0-5000">
</div>
<div class="input-pair">
<div class="form-group">
<label for="webPurchases">Web Purchases</label>
<input type="number" id="webPurchases" name="webPurchases" min="0" max="100" required placeholder="0-100">
</div>
<div class="form-group">
<label for="storePurchases">Store Purchases</label>
<input type="number" id="storePurchases" name="storePurchases" min="0" max="100" required placeholder="0-100">
</div>
</div>
<div class="input-pair">
<div class="form-group">
<label for="webVisits">Web Visits/Month</label>
<input type="number" id="webVisits" name="webVisits" min="0" max="50" required placeholder="0-50">
</div>
<div class="form-group">
<label for="recency">Recency (days)</label>
<input type="number" id="recency" name="recency" min="0" max="365" required placeholder="0-365">
</div>
</div>
<button type="submit" class="submit-btn pulse" id="predictBtn">
Predict Customer Segment
</button>
</form>
<div class="loading" id="loading">
<div class="spinner"></div>
<p>Analyzing customer data...</p>
</div>
<div class="error" id="error"></div>
<div class="success" id="success"></div>
</div>
<div class="result-section">
<h2>Prediction Result</h2>
<div id="resultContent">
<div class="no-result">
<p>Enter customer data and click "Predict Customer Segment" to see results</p>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('predictionForm');
const predictBtn = document.getElementById('predictBtn');
const loading = document.getElementById('loading');
const error = document.getElementById('error');
const success = document.getElementById('success');
const resultContent = document.getElementById('resultContent');
// Sample result template
const resultTemplate = {
"cluster_id": 3,
"cluster_name": "Active Online-Focused Shoppers",
"description": "High income, high spending, shops frequently both online and in-store—with strongest activity on web.",
"recommendation": "Offer premium bundles, omnichannel loyalty rewards (e.g., buy online, pick up in-store + bonus points), and personalized cross-channel recommendations."
};
form.addEventListener('submit', async function(e) {
e.preventDefault();
// Show loading
loading.style.display = 'block';
error.style.display = 'none';
success.style.display = 'none';
// Disable button during prediction
predictBtn.disabled = true;
predictBtn.textContent = 'Analyzing...';
try {
// Get form data
const formData = new FormData(form);
const inputData = {
Age: parseInt(formData.get('age')),
Income: parseInt(formData.get('income')),
Total_Spendings: parseInt(formData.get('totalSpendings')),
NumWebPurchases: parseInt(formData.get('webPurchases')),
NumStorePurchases: parseInt(formData.get('storePurchases')),
NumWebVisitsMonth: parseInt(formData.get('webVisits')),
Recency: parseInt(formData.get('recency'))
};
// Make API call
const response = await fetch('https://junaid17-customer-segmentation-api.hf.space/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(inputData)
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const result = await response.json();
// Display result
displayResult(result);
success.style.display = 'block';
success.textContent = 'Prediction successful!';
} catch (err) {
console.error('Prediction error:', err);
error.style.display = 'block';
error.textContent = `Error: ${err.message || 'Failed to get prediction'}`;
// Also show in result area
resultContent.innerHTML = `
<div class="error" style="display: block;">
<p>Failed to get prediction: ${err.message || 'Unknown error'}</p>
</div>
`;
} finally {
// Hide loading and re-enable button
loading.style.display = 'none';
predictBtn.disabled = false;
predictBtn.textContent = 'Predict Customer Segment';
}
});
function displayResult(result) {
resultContent.innerHTML = `
<div class="result-card slide-up">
<div class="result-highlight">
<div class="result-title">Cluster ID: ${result.cluster_id}</div>
<div class="result-content"><strong>Name:</strong> ${result.cluster_name}</div>
</div>
<div class="result-highlight">
<div class="result-title">Description</div>
<div class="result-content">${result.description}</div>
</div>
<div class="result-highlight">
<div class="result-title">Recommendation</div>
<div class="result-content">${result.recommendation}</div>
</div>
</div>
`;
}
// Add input validation
const inputs = form.querySelectorAll('input');
inputs.forEach(input => {
input.addEventListener('input', function() {
const min = parseInt(this.min);
const max = parseInt(this.max);
const value = parseInt(this.value);
if (value < min || value > max) {
this.style.borderColor = 'var(--error)';
} else {
this.style.borderColor = '#404040';
}
});
});
// Add animation to form elements on focus
inputs.forEach(input => {
input.addEventListener('focus', function() {
this.parentElement.style.transform = 'translateY(-2px)';
});
input.addEventListener('blur', function() {
this.parentElement.style.transform = 'translateY(0)';
});
});
// Add smooth scrolling for mobile
if (window.innerWidth <= 768) {
form.addEventListener('submit', function() {
document.querySelector('.result-section').scrollIntoView({
behavior: 'smooth'
});
});
}
});
</script>
</body>
</html>