MeetGeniusAI / templates /live.html
LovnishVerma's picture
Upload 12 files
944bf22 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeetGenius AI – Live Meeting</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { darkMode: 'class' }
</script>
<style>
/* πŸ”΄ Blinking recording dot */
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.3; }
100% { opacity: 1; }
}
.record-dot {
animation: pulse 1s infinite;
}
/* πŸ”Š Zigzag waveform animation */
.wave {
display: flex;
gap: 4px;
}
.wave span {
width: 4px;
height: 12px;
background: #22c55e;
animation: waveMove 1s infinite ease-in-out;
}
.wave span:nth-child(2) { animation-delay: 0.1s; }
.wave span:nth-child(3) { animation-delay: 0.2s; }
.wave span:nth-child(4) { animation-delay: 0.3s; }
.wave span:nth-child(5) { animation-delay: 0.4s; }
@keyframes waveMove {
0%, 100% { height: 8px; }
50% { height: 24px; }
}
</style>
</head>
<body class="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-indigo-950
flex items-center justify-center px-6">
<div class="max-w-4xl w-full bg-white dark:bg-slate-900/90
border border-slate-700 rounded-2xl shadow-2xl p-10">
<h1 class="text-3xl font-bold text-center text-gray-900 dark:text-white mb-4">
πŸŽ™οΈ Live Meeting Intelligence
</h1>
<p class="text-center text-gray-600 dark:text-slate-400 mb-6">
Works with Google Meet, Zoom, Webex (mic-based recording)
</p>
<!-- πŸ”΄ RECORDING STATUS + TIMER -->
<div class="flex items-center justify-center gap-4 mb-4">
<div id="recordingIndicator" class="hidden flex items-center gap-2 text-red-500 font-semibold">
<span class="w-3 h-3 bg-red-500 rounded-full record-dot"></span>
Recording
</div>
<div id="timer" class="text-slate-400 font-mono text-lg">
00:00:00
</div>
</div>
<!-- πŸ”Š ZIGZAG WAVEFORM -->
<div id="waveform" class="hidden flex justify-center mb-6">
<div class="wave">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
<!-- BUTTONS -->
<div class="flex justify-center gap-4 mb-6">
<button id="startBtn"
class="px-6 py-3 bg-green-600 text-white rounded-xl">
β–Ά Start Recording
</button>
<button id="stopBtn" disabled
class="px-6 py-3 bg-red-600 text-white rounded-xl">
⏹ Stop & Analyze
</button>
<button id="timestampBtn"
class="px-6 py-3 bg-indigo-600 text-white rounded-xl">
⏱ Timestamp: OFF
</button>
<button id="clearBtn"
class="px-6 py-3 bg-slate-600 text-white rounded-xl">
🧹 Clear
</button>
</div>
<div id="status" class="text-center text-slate-400 mb-6"></div>
<!-- OUTPUT -->
<div id="output" class="hidden space-y-6">
<div class="p-5 bg-slate-100 dark:bg-slate-800 rounded-xl border-l-4 border-indigo-500">
<h3 class="font-semibold mb-2">🧠 Summary</h3>
<pre id="summary" class="whitespace-pre-wrap"></pre>
</div>
<div class="p-5 bg-slate-100 dark:bg-slate-800 rounded-xl border-l-4 border-green-500">
<h3 class="font-semibold mb-2">πŸ“˜ Notes</h3>
<pre id="notes" class="whitespace-pre-wrap"></pre>
</div>
<div class="p-5 bg-slate-100 dark:bg-slate-800 rounded-xl border-l-4 border-yellow-500">
<h3 class="font-semibold mb-2">βœ… Conclusion</h3>
<pre id="conclusion" class="whitespace-pre-wrap"></pre>
</div>
</div>
</div>
<script>
let mediaRecorder;
let audioChunks = [];
let timerInterval;
let seconds = 0;
let timestampsEnabled = false;
const startBtn = document.getElementById("startBtn");
const stopBtn = document.getElementById("stopBtn");
const timestampBtn = document.getElementById("timestampBtn");
const clearBtn = document.getElementById("clearBtn");
const status = document.getElementById("status");
const timer = document.getElementById("timer");
const indicator = document.getElementById("recordingIndicator");
const waveform = document.getElementById("waveform");
/* ⏱ Timer */
function startTimer() {
seconds = 0;
timer.textContent = "00:00:00";
timerInterval = setInterval(() => {
seconds++;
const h = String(Math.floor(seconds / 3600)).padStart(2, "0");
const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, "0");
const s = String(seconds % 60).padStart(2, "0");
timer.textContent = `${h}:${m}:${s}`;
}, 1000);
}
function stopTimer() {
clearInterval(timerInterval);
}
/* β–Ά Start Recording */
startBtn.onclick = async () => {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = e => audioChunks.push(e.data);
mediaRecorder.start();
indicator.classList.remove("hidden");
waveform.classList.remove("hidden");
startTimer();
status.textContent = "πŸŽ™οΈ Recording live meeting...";
startBtn.disabled = true;
stopBtn.disabled = false;
};
/* ⏹ Stop Recording */
stopBtn.onclick = async () => {
mediaRecorder.stop();
stopTimer();
indicator.classList.add("hidden");
waveform.classList.add("hidden");
status.textContent = "⏳ Analyzing meeting...";
mediaRecorder.onstop = async () => {
const blob = new Blob(audioChunks, { type: "audio/wav" });
const formData = new FormData();
formData.append("audio", blob, "live.wav");
formData.append("timestamps", timestampsEnabled);
const res = await fetch("/live/process", {
method: "POST",
body: formData
});
const data = await res.json();
document.getElementById("output").classList.remove("hidden");
document.getElementById("summary").textContent = data.summary;
document.getElementById("notes").textContent = data.notes;
document.getElementById("conclusion").textContent = data.conclusion;
status.textContent = "βœ… Meeting analyzed successfully";
startBtn.disabled = false;
stopBtn.disabled = true;
};
};
/* ⏱ Timestamp Toggle */
timestampBtn.onclick = () => {
timestampsEnabled = !timestampsEnabled;
timestampBtn.textContent = timestampsEnabled
? "⏱ Timestamp: ON"
: "⏱ Timestamp: OFF";
};
/* 🧹 Clear Output */
clearBtn.onclick = () => {
document.getElementById("output").classList.add("hidden");
document.getElementById("summary").textContent = "";
document.getElementById("notes").textContent = "";
document.getElementById("conclusion").textContent = "";
status.textContent = "";
stopTimer();
timer.textContent = "00:00:00";
};
</script>
</body>
</html>