nivakaran's picture
Upload index.html
cde478d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Food Delivery Time Prediction</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1000px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border-radius: 24px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
padding: 40px;
text-align: center;
color: white;
position: relative;
overflow: hidden;
}
.header::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
animation: pulse 4s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { transform: scale(1); opacity: 0.5; }
50% { transform: scale(1.1); opacity: 0.3; }
}
.header h1 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 10px;
position: relative;
z-index: 1;
}
.header p {
font-size: 1.1rem;
opacity: 0.9;
position: relative;
z-index: 1;
}
.form-container {
padding: 40px;
}
.train-btn {
width: 100%;
padding: 16px;
background: linear-gradient(135deg, #f093fb, #f5576c);
color: white;
border: none;
border-radius: 12px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 32px;
position: relative;
overflow: hidden;
}
.train-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(240, 147, 251, 0.3);
}
.train-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.train-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
.train-btn:hover::before {
left: 100%;
}
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
margin-bottom: 32px;
}
.form-group {
position: relative;
}
.form-group label {
display: block;
font-weight: 600;
color: #2d3748;
margin-bottom: 8px;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 16px 20px;
border: 2px solid #e2e8f0;
border-radius: 12px;
font-size: 1rem;
transition: all 0.3s ease;
background: white;
color: #2d3748;
}
.form-group input:focus,
.form-group select:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1);
transform: translateY(-2px);
}
.form-group input:hover,
.form-group select:hover {
border-color: #cbd5e0;
transform: translateY(-1px);
}
.form-group select {
cursor: pointer;
appearance: none;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3e%3c/svg%3e");
background-position: right 12px center;
background-repeat: no-repeat;
background-size: 16px;
}
.submit-btn {
width: 100%;
padding: 18px;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 12px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 1px;
position: relative;
overflow: hidden;
}
.submit-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
}
.submit-btn:active {
transform: translateY(0);
}
.submit-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
.submit-btn:hover::before {
left: 100%;
}
.result {
margin-top: 32px;
padding: 24px;
background: linear-gradient(135deg, #48bb78, #38a169);
border-radius: 16px;
color: white;
text-align: center;
opacity: 0;
transform: translateY(20px);
transition: all 0.5s ease;
}
.result.show {
opacity: 1;
transform: translateY(0);
}
.error-result {
margin-top: 32px;
padding: 24px;
background: linear-gradient(135deg, #e53e3e, #c53030);
border-radius: 16px;
color: white;
text-align: center;
opacity: 0;
transform: translateY(20px);
transition: all 0.5s ease;
}
.error-result.show {
opacity: 1;
transform: translateY(0);
}
.result-icon {
font-size: 3rem;
margin-bottom: 16px;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% { transform: translateY(0); }
40% { transform: translateY(-10px); }
60% { transform: translateY(-5px); }
}
.result-text {
font-size: 1.2rem;
font-weight: 600;
}
.loading {
display: none;
justify-content: center;
align-items: center;
margin-top: 20px;
padding: 20px;
background: linear-gradient(135deg, #667eea, #764ba2);
border-radius: 16px;
color: white;
}
.loading.show {
display: flex;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(255, 255, 255, 0.3);
border-top: 4px solid white;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 12px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.feature-icons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 20px;
margin-top: 32px;
padding-top: 32px;
border-top: 2px solid #e2e8f0;
}
.feature-icon {
text-align: center;
padding: 20px;
border-radius: 12px;
background: linear-gradient(135deg, #f7fafc, #edf2f7);
transition: transform 0.3s ease;
}
.feature-icon:hover {
transform: translateY(-5px);
}
.feature-icon i {
font-size: 2rem;
color: #667eea;
margin-bottom: 8px;
}
.feature-icon span {
display: block;
font-size: 0.8rem;
color: #4a5568;
font-weight: 500;
}
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
gap: 20px;
}
.header h1 {
font-size: 2rem;
}
.form-container {
padding: 24px;
}
.header {
padding: 32px 24px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1><i class="fas fa-motorcycle"></i> Food Delivery Time Prediction</h1>
<p>Advanced AI-powered delivery time estimation system</p>
</div>
<div class="form-container">
<!-- Training Section -->
<button type="button" class="train-btn" id="train-btn">
<i class="fas fa-graduation-cap"></i> Train Model
</button>
<form id="prediction-form">
<div class="form-grid">
<div class="form-group">
<label for="multiple_deliveries"><i class="fas fa-boxes"></i> Multiple Deliveries</label>
<input type="number" id="multiple_deliveries" name="multiple_deliveries" step="1" min="0" placeholder="e.g., 1" required>
</div>
<div class="form-group">
<label for="Road_traffic_density"><i class="fas fa-road"></i> Road Traffic Density</label>
<select id="Road_traffic_density" name="Road_traffic_density" required>
<option value="" disabled selected>Select traffic level</option>
<option value="Low">Low</option>
<option value="Medium">Medium</option>
<option value="High">High</option>
<option value="Jam">Jam</option>
</select>
</div>
<div class="form-group">
<label for="Vehicle_condition"><i class="fas fa-car"></i> Vehicle Condition</label>
<select id="Vehicle_condition" name="Vehicle_condition" required>
<option value="" disabled selected>Select condition</option>
<option value="Poor">Poor</option>
<option value="Good">Good</option>
<option value="Excellent">Excellent</option>
</select>
</div>
<div class="form-group">
<label for="Delivery_person_Ratings"><i class="fas fa-star"></i> Delivery Person Ratings (1-5)</label>
<input type="number" id="Delivery_person_Ratings" name="Delivery_person_Ratings" step="0.1" min="1" max="5" placeholder="e.g., 4.5" required>
</div>
<div class="form-group">
<label for="distance_deliveries"><i class="fas fa-calculator"></i> Distance × Deliveries</label>
<input type="number" id="distance_deliveries" name="distance_deliveries" step="0.1" placeholder="e.g., 10.5" required>
</div>
<div class="form-group">
<label for="Weather_conditions"><i class="fas fa-cloud-sun"></i> Weather Conditions</label>
<select id="Weather_conditions" name="Weather_conditions" required>
<option value="" disabled selected>Select weather</option>
<option value="Sunny">Sunny</option>
<option value="Cloudy">Cloudy</option>
<option value="Fog">Fog</option>
<option value="Sandstorms">Sandstorms</option>
<option value="Stormy">Stormy</option>
<option value="Windy">Windy</option>
</select>
</div>
<div class="form-group">
<label for="Festival"><i class="fas fa-calendar-alt"></i> Festival</label>
<select id="Festival" name="Festival" required>
<option value="" disabled selected>Festival period?</option>
<option value="No">No</option>
<option value="Yes">Yes</option>
</select>
</div>
<div class="form-group">
<label for="distance_traffic"><i class="fas fa-chart-line"></i> Distance × Traffic</label>
<input type="number" id="distance_traffic" name="distance_traffic" step="0.1" placeholder="e.g., 15.2" required>
</div>
<div class="form-group">
<label for="distance"><i class="fas fa-route"></i> Distance (km)</label>
<input type="number" id="distance" name="distance" step="0.1" min="0" placeholder="e.g., 5.0" required>
</div>
<div class="form-group">
<label for="Delivery_person_Age"><i class="fas fa-user"></i> Delivery Person Age</label>
<input type="number" id="Delivery_person_Age" name="Delivery_person_Age" step="1" min="18" max="60" placeholder="e.g., 30" required>
</div>
<div class="form-group">
<label for="prep_traffic"><i class="fas fa-clock"></i> Prep Time × Traffic</label>
<input type="number" id="prep_traffic" name="prep_traffic" step="0.1" placeholder="e.g., 12.0" required>
</div>
<div class="form-group">
<label for="City"><i class="fas fa-city"></i> City</label>
<select id="City" name="City" required>
<option value="" disabled selected>Select city type</option>
<option value="Urban">Urban</option>
<option value="Semi-Urban">Semi-Urban</option>
<option value="Metropolitan">Metropolitan</option>
</select>
</div>
</div>
<button type="submit" class="submit-btn" id="predict-btn">
<i class="fas fa-magic"></i> Predict Delivery Time
</button>
</form>
<div class="loading" id="loading">
<div class="spinner"></div>
<span id="loading-text">Processing...</span>
</div>
<div id="result" class="result">
<div class="result-icon">🚀</div>
<div class="result-text"></div>
</div>
<div id="error-result" class="error-result">
<div class="result-icon"></div>
<div class="result-text"></div>
</div>
<div class="feature-icons">
<div class="feature-icon">
<i class="fas fa-brain"></i>
<span>AI Powered</span>
</div>
<div class="feature-icon">
<i class="fas fa-tachometer-alt"></i>
<span>Real-time</span>
</div>
<div class="feature-icon">
<i class="fas fa-chart-bar"></i>
<span>Accurate</span>
</div>
<div class="feature-icon">
<i class="fas fa-mobile-alt"></i>
<span>Responsive</span>
</div>
</div>
</div>
</div>
<script>
// Helper function to show loading
function showLoading(message = "Processing...") {
document.getElementById('loading-text').textContent = message;
document.getElementById('loading').classList.add('show');
document.getElementById('result').classList.remove('show');
document.getElementById('error-result').classList.remove('show');
}
// Helper function to hide loading
function hideLoading() {
document.getElementById('loading').classList.remove('show');
}
// Helper function to show success result
function showSuccess(message) {
document.getElementById('result').classList.add('show');
document.querySelector('#result .result-text').innerHTML = message;
document.getElementById('result').scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
// Helper function to show error result
function showError(message) {
document.getElementById('error-result').classList.add('show');
document.querySelector('#error-result .result-text').innerHTML = message;
document.getElementById('error-result').scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
// Training functionality - ONLY when train button is clicked
document.getElementById('train-btn').addEventListener('click', async function() {
const trainBtn = this;
// Show loading and disable button
showLoading("Training model with latest data...");
trainBtn.disabled = true;
trainBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Training in Progress...';
try {
const response = await fetch('/train', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
}
});
hideLoading();
if (response.ok) {
const text = await response.text();
showSuccess(
`<strong>✅ Model Training Completed Successfully!</strong><br>
<small>The AI model has been retrained with the latest data and is ready for predictions</small>`
);
} else {
const errorText = await response.text();
throw new Error(`Training failed: ${response.status} - ${errorText}`);
}
} catch (error) {
console.error('Training error:', error);
hideLoading();
showError(
`<strong>Training Failed!</strong><br>
<small>Error: ${error.message}<br>
Please check your server connection and try again.</small>`
);
} finally {
// Re-enable button
trainBtn.disabled = false;
trainBtn.innerHTML = '<i class="fas fa-graduation-cap"></i> Train Model';
}
});
// Prediction functionality - when form is submitted
document.getElementById('prediction-form').addEventListener('submit', async function(e) {
e.preventDefault();
const predictBtn = document.getElementById('predict-btn');
// Show loading and disable predict button
showLoading("Calculating delivery time...");
predictBtn.disabled = true;
predictBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Predicting...';
// Collect form data
const formData = new FormData(this);
try {
const response = await fetch('/predict', {
method: 'POST',
body: formData
});
const data = await response.json();
hideLoading();
if (response.ok && data.prediction !== undefined) {
// Show successful prediction result
showSuccess(
`<strong>Estimated Delivery Time: ${data.prediction} minutes</strong><br>
<small>Based on current conditions and AI analysis</small>`
);
} else {
// Show error from backend
throw new Error(data.error || 'Prediction failed');
}
} catch (error) {
console.error('Prediction error:', error);
hideLoading();
showError(
`<strong>Prediction Failed!</strong><br>
<small>Error: ${error.message}<br>
Please check your input values and try again.</small>`
);
} finally {
// Re-enable predict button
predictBtn.disabled = false;
predictBtn.innerHTML = '<i class="fas fa-magic"></i> Predict Delivery Time';
}
});
// Add input animations
document.querySelectorAll('input, select').forEach(element => {
element.addEventListener('focus', function() {
this.parentElement.style.transform = 'scale(1.02)';
});
element.addEventListener('blur', function() {
this.parentElement.style.transform = 'scale(1)';
});
});
// Add form validation feedback
document.querySelectorAll('input[required], select[required]').forEach(element => {
element.addEventListener('invalid', function() {
this.style.borderColor = '#e53e3e';
this.style.boxShadow = '0 0 0 4px rgba(229, 62, 62, 0.1)';
});
element.addEventListener('input', function() {
if (this.validity.valid) {
this.style.borderColor = '#48bb78';
this.style.boxShadow = '0 0 0 4px rgba(72, 187, 120, 0.1)';
} else {
this.style.borderColor = '#e2e8f0';
this.style.boxShadow = 'none';
}
});
});
// Clear results when form is modified
document.querySelectorAll('input, select').forEach(element => {
element.addEventListener('input', function() {
document.getElementById('result').classList.remove('show');
document.getElementById('error-result').classList.remove('show');
});
});
</script>
</body>
</html>