|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>AI Coach for Site Supervisors</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/heroicons/2.1.1/outline/index.min.css" rel="stylesheet"> |
|
<style> |
|
body { |
|
font-family: 'Inter', sans-serif; |
|
} |
|
.checklist-item { |
|
transition: background-color 0.3s ease, transform 0.2s ease; |
|
} |
|
.checklist-item.completed { |
|
background-color: #ecfdf5; |
|
transform: scale(1.02); |
|
} |
|
.checklist-item:hover { |
|
transform: scale(1.02); |
|
} |
|
.tip-card { |
|
transition: transform 0.3s ease, box-shadow 0.3s ease; |
|
} |
|
.tip-card:hover { |
|
transform: translateY(-5px); |
|
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); |
|
} |
|
.fade-in { |
|
animation: fadeIn 0.5s ease-in-out; |
|
} |
|
@keyframes fadeIn { |
|
from { opacity: 0; transform: translateY(10px); } |
|
to { opacity: 1; transform: translateY(0); } |
|
} |
|
.gradient-header { |
|
background: linear-gradient(135deg, #3b82f6, #1d4ed8); |
|
} |
|
.spinner { |
|
border: 4px solid #f3f3f3; |
|
border-top: 4px solid #3b82f6; |
|
border-radius: 50%; |
|
width: 24px; |
|
height: 24px; |
|
animation: spin 1s linear infinite; |
|
display: none; |
|
} |
|
@keyframes spin { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-50 min-h-screen flex flex-col"> |
|
|
|
<header class="gradient-header text-white p-6 shadow-lg"> |
|
<h1 class="text-3xl font-bold tracking-tight flex items-center"> |
|
<svg class="w-8 h-8 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path> |
|
</svg> |
|
AI Coach for Supervisors |
|
</h1> |
|
<p class="mt-1 text-sm opacity-80">Your daily guide to success</p> |
|
</header> |
|
|
|
|
|
<main class="flex-1 p-6 space-y-8 max-w-3xl mx-auto"> |
|
|
|
<section class="bg-white rounded-xl shadow-md p-6 fade-in"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path> |
|
</svg> |
|
Supervisor Details |
|
</h2> |
|
<div class="space-y-4"> |
|
<div> |
|
<label class="block text-gray-700 font-medium mb-1">Role</label> |
|
<input id="role" type="text" value="Site Supervisor" class="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-400 focus:border-transparent" placeholder="e.g., Site Supervisor"> |
|
</div> |
|
<div> |
|
<label class="block text-gray-700 font-medium mb-1">Location</label> |
|
<input id="location" type="text" value="Construction Site A" class="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-400 focus:border-transparent" placeholder="e.g., Construction Site A"> |
|
</div> |
|
<div> |
|
<label class="block text-gray-700 font-medium mb-1">Project Schedule (JSON)</label> |
|
<textarea id="schedule" class="w-full p-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-400 focus:border-transparent" rows="3" placeholder='e.g., [{"task": "Foundation Inspection", "due_date": "2025-05-07", "status": "Pending"}]'>[{"task": "Foundation Inspection", "due_date": "2025-05-07", "status": "Pending"}, {"task": "Material Delivery", "due_date": "2025-05-06", "status": "Delayed"}]</textarea> |
|
</div> |
|
<button id="loadData" class="w-full bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors duration-200 flex items-center justify-center"> |
|
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9H20m-7 7v5h-.582m-7.356-2A8.001 8.001 0 0119.418 15H4"></path> |
|
</svg> |
|
Load Coaching Data |
|
<div id="spinner" class="spinner ml-2"></div> |
|
</button> |
|
</div> |
|
</section> |
|
|
|
|
|
<section id="alerts" class="bg-red-50 rounded-xl shadow-md p-6 fade-in hidden"> |
|
<h2 class="text-2xl font-semibold text-red-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path> |
|
</svg> |
|
Alerts |
|
</h2> |
|
<p class="text-red-700">No alerts at this time. (Placeholder for missed milestones or unsafe patterns)</p> |
|
</section> |
|
|
|
|
|
<section id="checklistSection" class="bg-white rounded-xl shadow-md p-6 fade-in hidden"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path> |
|
</svg> |
|
Daily Checklist |
|
</h2> |
|
<ul id="checklist" class="space-y-3"></ul> |
|
</section> |
|
|
|
|
|
<section id="tipsSection" class="bg-white rounded-xl shadow-md p-6 fade-in hidden"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path> |
|
</svg> |
|
Today's Top 3 Focus Areas |
|
</h2> |
|
<ul id="tips" class="space-y-3"></ul> |
|
</section> |
|
|
|
|
|
<section id="quoteSection" class="bg-white rounded-xl shadow-md p-6 fade-in hidden"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"></path> |
|
</svg> |
|
Motivational Quote |
|
</h2> |
|
<p id="quote" class="italic text-gray-600 text-lg"></p> |
|
</section> |
|
|
|
|
|
<section class="bg-white rounded-xl shadow-md p-6 fade-in"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path> |
|
</svg> |
|
Reflection Journal |
|
</h2> |
|
<textarea id="reflection" class="w-full p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-400 focus:border-transparent" rows="4" placeholder="Log your thoughts or observations..."></textarea> |
|
<button id="saveReflection" class="mt-3 w-full bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition-colors duration-200">Save Reflection</button> |
|
</section> |
|
|
|
|
|
<section class="bg-white rounded-xl shadow-md p-6 fade-in"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 012-2h2a2 2 0 012 2v12a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path> |
|
</svg> |
|
Engagement Score |
|
</h2> |
|
<p class="text-gray-600 mb-3">Weekly trend (Placeholder)</p> |
|
<div class="h-40 bg-gray-100 rounded-lg flex items-center justify-center"> |
|
<svg width="100%" height="100" class="max-w-full"> |
|
<polyline points="10,90 30,70 50,80 70,50 90,60 110,40 130,60" fill="none" stroke="#3b82f6" stroke-width="2"/> |
|
<text x="10" y="20" fill="#4b5563" font-size="12">Engagement: 85%</text> |
|
<line x1="10" y1="90" x2="130" y2="90" stroke="#d1d5db" stroke-width="1"/> |
|
<line x1="10" y1="90" x2="10" y2="30" stroke="#d1d5db" stroke-width="1"/> |
|
</svg> |
|
</div> |
|
</section> |
|
|
|
|
|
<section class="bg-white rounded-xl shadow-md p-6 fade-in"> |
|
<h2 class="text-2xl font-semibold text-gray-800 mb-4 flex items-center"> |
|
<svg class="w-6 h-6 mr-2 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> |
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path> |
|
</svg> |
|
Summary Report |
|
</h2> |
|
<button id="downloadPdf" class="w-full bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700 transition-colors duration-200">Download PDF Summary</button> |
|
</section> |
|
</main> |
|
|
|
<script> |
|
|
|
let supervisorData = { |
|
supervisor_id: "SUP123", |
|
role: "Site Supervisor", |
|
project_id: "PRJ456", |
|
milestones: [ |
|
{ task: "Foundation Inspection", due_date: "2025-05-07", status: "Pending" }, |
|
{ task: "Material Delivery", due_date: "2025-05-06", status: "Delayed" } |
|
], |
|
reflection_log: "Noticed delays due to rain; team morale is low.", |
|
weather: "Rainy, 20°C" |
|
}; |
|
|
|
async function fetchCoachingOutput() { |
|
const spinner = document.getElementById('spinner'); |
|
spinner.style.display = 'block'; |
|
try { |
|
const response = await fetch('/generate', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify(supervisorData) |
|
}); |
|
const result = await response.json(); |
|
if (result.status === 'success') { |
|
updateUI(result.output); |
|
} else { |
|
alert('Error: ' + result.message); |
|
} |
|
} catch (error) { |
|
alert('Failed to fetch coaching output: ' + error.message); |
|
} finally { |
|
spinner.style.display = 'none'; |
|
} |
|
} |
|
|
|
function updateUI(output) { |
|
|
|
document.getElementById('checklistSection').classList.remove('hidden'); |
|
document.getElementById('tipsSection').classList.remove('hidden'); |
|
document.getElementById('quoteSection').classList.remove('hidden'); |
|
|
|
|
|
const checklist = document.getElementById('checklist'); |
|
checklist.innerHTML = output.checklist.map(item => ` |
|
<li class="checklist-item flex items-center p-3 bg-gray-50 rounded-lg"> |
|
<input type="checkbox" class="w-5 h-5 text-green-500 rounded focus:ring-green-400 mr-3" onchange="toggleCompletion(this)"> |
|
<span class="text-gray-700">${item}</span> |
|
</li> |
|
`).join(''); |
|
|
|
|
|
const tips = document.getElementById('tips'); |
|
tips.innerHTML = output.tips.map(tip => ` |
|
<li class="tip-card p-4 bg-blue-50 rounded-lg text-gray-700">${tip}</li> |
|
`).join(''); |
|
|
|
|
|
document.getElementById('quote').textContent = output.quote; |
|
} |
|
|
|
function toggleCompletion(checkbox) { |
|
const li = checkbox.parentElement; |
|
li.classList.toggle('completed', checkbox.checked); |
|
} |
|
|
|
document.getElementById('saveReflection').addEventListener('click', () => { |
|
const reflection = document.getElementById('reflection').value; |
|
if (reflection) { |
|
alert('Reflection saved: ' + reflection); |
|
} else { |
|
alert('Please enter a reflection'); |
|
} |
|
}); |
|
|
|
document.getElementById('downloadPdf').addEventListener('click', () => { |
|
alert('PDF download feature coming soon...'); |
|
}); |
|
|
|
document.getElementById('loadData').addEventListener('click', () => { |
|
const role = document.getElementById('role').value; |
|
const location = document.getElementById('location').value; |
|
const schedule = JSON.parse(document.getElementById('schedule').value || '[]'); |
|
supervisorData.role = role; |
|
supervisorData.location = location; |
|
supervisorData.milestones = schedule; |
|
fetchCoachingOutput(); |
|
}); |
|
|
|
|
|
fetchCoachingOutput(); |
|
</script> |
|
</body> |
|
</html> |