prospect-ai-saas / training.html
EdgarDataScientist's picture
Design me a modern SaaS web app for Prospect AI that integrates with the following FastAPI backend endpoints:
980f6a1 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Training - Prospect AI</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
primary: '#00f2fe',
secondary: '#4facfe',
dark: '#0f172a',
darker: '#0a0f1f'
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
background-color: #0f172a;
color: #f1f5f9;
}
.gradient-bg {
background: linear-gradient(135deg, #0f172a 0%, #0a0f1f 100%);
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body class="gradient-bg">
<div class="container mx-auto px-4 py-8 max-w-4xl">
<!-- Header -->
<header class="flex justify-between items-center mb-10 py-6">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 rounded-full bg-gradient-to-r from-primary to-secondary flex items-center justify-center">
<i data-feather="cpu" class="text-dark"></i>
</div>
<h1 class="text-2xl font-bold">Prospect AI</h1>
</div>
<nav class="flex space-x-6">
<a href="landing.html" class="text-gray-400 hover:text-primary transition">Home</a>
<a href="training.html" class="text-primary font-medium">Training</a>
<a href="ml-prospecting.html" class="text-gray-400 hover:text-primary transition">ML Prospecting</a>
<a href="crewai-enrichment.html" class="text-gray-400 hover:text-primary transition">CrewAI Enrichment</a>
<a href="hybrid-prospecting.html" class="text-gray-400 hover:text-primary transition">Hybrid Prospecting</a>
</nav>
</header>
<!-- Training Section -->
<section class="bg-darker rounded-2xl shadow-xl p-8 fade-in">
<div class="text-center mb-8">
<h2 class="text-3xl font-bold mb-2">Train Your Model</h2>
<p class="text-gray-400">Upload your lead data to train the Prospect AI model</p>
</div>
<div class="border-2 border-dashed border-gray-700 rounded-xl p-10 text-center">
<div class="flex flex-col items-center justify-center">
<i data-feather="upload" class="w-12 h-12 text-gray-500 mb-4"></i>
<h3 class="text-lg font-semibold text-gray-300 mb-2">Upload Training Data</h3>
<p class="text-gray-500 mb-6">Upload a CSV file with your historical lead data</p>
<div class="flex flex-col sm:flex-row gap-4 w-full max-w-md">
<input
type="file"
id="trainingFile"
accept=".csv"
class="hidden"
>
<button
id="uploadButton"
class="bg-gradient-to-r from-primary to-secondary hover:opacity-90 text-dark px-6 py-3 rounded-lg font-medium transition duration-200 flex items-center justify-center w-full"
>
<i data-feather="file-text" class="w-5 h-5 mr-2"></i>
Select CSV File
</button>
</div>
<div id="fileName" class="mt-4 text-gray-400 text-sm hidden">
<span id="fileText"></span>
</div>
<button
id="trainButton"
class="mt-6 bg-primary hover:opacity-90 text-dark px-8 py-3 rounded-lg font-bold transition duration-200 hidden"
>
Train Model
</button>
</div>
</div>
<div id="resultMessage" class="mt-8 text-center hidden">
<div class="inline-flex items-center px-4 py-2 rounded-full bg-green-900/30 text-green-400">
<i data-feather="check-circle" class="w-5 h-5 mr-2"></i>
<span id="resultText">Model trained successfully!</span>
</div>
</div>
</section>
<!-- Footer -->
<footer class="mt-12 text-center text-gray-500 text-sm">
<p>© 2025 Prospect AI • Smarter Lead Generation</p>
</footer>
</div>
<script>
feather.replace();
document.addEventListener('DOMContentLoaded', function() {
const uploadButton = document.getElementById('uploadButton');
const trainingFile = document.getElementById('trainingFile');
const fileName = document.getElementById('fileName');
const fileText = document.getElementById('fileText');
const trainButton = document.getElementById('trainButton');
const resultMessage = document.getElementById('resultMessage');
const resultText = document.getElementById('resultText');
uploadButton.addEventListener('click', () => {
trainingFile.click();
});
trainingFile.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
fileText.textContent = e.target.files[0].name;
fileName.classList.remove('hidden');
trainButton.classList.remove('hidden');
}
});
trainButton.addEventListener('click', async () => {
if (!trainingFile.files[0]) return;
const formData = new FormData();
formData.append('file', trainingFile.files[0]);
trainButton.innerHTML = '<i data-feather="loader" class="w-5 h-5 mr-2 animate-spin"></i>Training...';
feather.replace();
trainButton.disabled = true;
try {
const response = await fetch('http://localhost:8000/train', {
method: 'POST',
body: formData
});
if (response.ok) {
resultText.textContent = 'Model trained successfully!';
resultMessage.classList.remove('hidden');
} else {
resultText.textContent = 'Training failed. Please try again.';
resultMessage.classList.remove('hidden');
resultMessage.querySelector('div').className = 'inline-flex items-center px-4 py-2 rounded-full bg-red-900/30 text-red-400';
}
} catch (error) {
resultText.textContent = 'Error connecting to server.';
resultMessage.classList.remove('hidden');
resultMessage.querySelector('div').className = 'inline-flex items-center px-4 py-2 rounded-full bg-red-900/30 text-red-400';
} finally {
trainButton.innerHTML = 'Train Model';
feather.replace();
trainButton.disabled = false;
}
});
});
</script>
</body>
</html>