Spaces:
Runtime error
Runtime error
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>LiveKit Object Detection</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<style> | |
body { | |
font-family: system-ui, -apple-system, sans-serif; | |
background: linear-gradient(135deg, #2d2b52 0%, #191731 100%); | |
color: white; | |
margin: 0; | |
padding: 20px; | |
height: 100vh; | |
box-sizing: border-box; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
} | |
.container { | |
max-width: 800px; | |
text-align: center; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
} | |
.video-container { | |
max-width: 500px; | |
aspect-ratio: 1/1; | |
background: rgba(255, 255, 255, 0.1); | |
border-radius: 12px; | |
overflow: hidden; | |
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); | |
margin: 10px 0; | |
} | |
video { | |
width: 100%; | |
height: 100%; | |
object-fit: cover; | |
} | |
button { | |
background: white; | |
color: #2d2b52; | |
border: none; | |
padding: 12px 32px; | |
border-radius: 24px; | |
font-size: 16px; | |
font-weight: 600; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); | |
} | |
button:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2); | |
} | |
.slider-container { | |
max-width: 300px; | |
margin-top: 16px; | |
} | |
input[type="range"] { | |
width: 100%; | |
} | |
label { | |
font-size: 14px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>LiveKit Object Detection</h1> | |
<p>Stream webcam feed and detect objects using YOLOv10</p> | |
<div class="video-container"> | |
<video id="video" autoplay muted playsinline></video> | |
</div> | |
<div class="slider-container"> | |
<label>Confidence Threshold: <span id="conf-value">0.3</span></label> | |
<input type="range" id="conf-threshold" min="0" max="1" step="0.01" value="0.3"> | |
</div> | |
<button id="start-button">Start Streaming</button> | |
</div> | |
<script type="module"> | |
import { connect } from "https://cdn.jsdelivr.net/npm/livekit-client/dist/livekit-client.esm.js"; | |
const startBtn = document.getElementById("start-button"); | |
const video = document.getElementById("video"); | |
const confSlider = document.getElementById("conf-threshold"); | |
const confVal = document.getElementById("conf-value"); | |
let room; | |
let intervalId; | |
confSlider.addEventListener("input", () => { | |
confVal.textContent = confSlider.value; | |
}); | |
async function startStream() { | |
const livekitURL = "wss://myvoiceassistant-h4f2cbzj.livekit.cloud"; // Replace this | |
const token = "APIVcbcyNpkNcsL"; // Replace this | |
room = await connect(livekitURL, token, { | |
video: true, | |
audio: false, | |
}); | |
const pubTrack = room.localParticipant.getTrackPublications().find((pub) => pub.kind === "video"); | |
const stream = new MediaStream([pubTrack.track.mediaStreamTrack]); | |
video.srcObject = stream; | |
// Send image frames to backend every 1 second | |
intervalId = setInterval(() => { | |
const canvas = document.createElement("canvas"); | |
canvas.width = video.videoWidth; | |
canvas.height = video.videoHeight; | |
const ctx = canvas.getContext("2d"); | |
ctx.drawImage(video, 0, 0); | |
const imageData = canvas.toDataURL("image/jpeg"); | |
fetch("http://localhost:8000/detect", { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ | |
image: imageData, | |
conf_threshold: parseFloat(confSlider.value) | |
}) | |
}); | |
}, 1000); | |
} | |
startBtn.addEventListener("click", async () => { | |
if (startBtn.textContent === "Start Streaming") { | |
await startStream(); | |
startBtn.textContent = "Stop Streaming"; | |
} else { | |
if (room) room.disconnect(); | |
if (intervalId) clearInterval(intervalId); | |
video.srcObject = null; | |
startBtn.textContent = "Start Streaming"; | |
} | |
}); | |
</script> | |
</body> | |
</html> | |