Prathamesh1420 commited on
Commit
b1da0c5
·
verified ·
1 Parent(s): 9503367

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +138 -332
index.html CHANGED
@@ -1,340 +1,146 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
-
4
  <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Object Detection</title>
8
- <style>
9
- body {
10
- font-family: system-ui, -apple-system, sans-serif;
11
- background: linear-gradient(135deg, #2d2b52 0%, #191731 100%);
12
- color: white;
13
- margin: 0;
14
- padding: 20px;
15
- height: 100vh;
16
- box-sizing: border-box;
17
- display: flex;
18
- flex-direction: column;
19
- align-items: center;
20
- justify-content: center;
21
- }
22
-
23
- .container {
24
- width: 100%;
25
- max-width: 800px;
26
- text-align: center;
27
- display: flex;
28
- flex-direction: column;
29
- align-items: center;
30
- }
31
-
32
- .video-container {
33
- width: 100%;
34
- max-width: 500px;
35
- aspect-ratio: 1/1;
36
- background: rgba(255, 255, 255, 0.1);
37
- border-radius: 12px;
38
- overflow: hidden;
39
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
40
- margin: 10px 0;
41
- }
42
-
43
- #video-output {
44
- width: 100%;
45
- height: 100%;
46
- object-fit: cover;
47
- }
48
-
49
- button {
50
- background: white;
51
- color: #2d2b52;
52
- border: none;
53
- padding: 12px 32px;
54
- border-radius: 24px;
55
- font-size: 16px;
56
- font-weight: 600;
57
- cursor: pointer;
58
- transition: all 0.3s ease;
59
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
60
- }
61
-
62
- button:hover {
63
- transform: translateY(-2px);
64
- box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
65
- }
66
-
67
- h1 {
68
- font-size: 2.5em;
69
- margin-bottom: 0.3em;
70
- }
71
-
72
- p {
73
- color: rgba(255, 255, 255, 0.8);
74
- margin-bottom: 1em;
75
- }
76
-
77
- .controls {
78
- display: flex;
79
- flex-direction: column;
80
- gap: 12px;
81
- align-items: center;
82
- margin-top: 10px;
83
- }
84
-
85
- .slider-container {
86
- width: 100%;
87
- max-width: 300px;
88
- display: flex;
89
- flex-direction: column;
90
- gap: 8px;
91
- }
92
-
93
- .slider-container label {
94
- color: rgba(255, 255, 255, 0.8);
95
- font-size: 14px;
96
- }
97
-
98
- input[type="range"] {
99
- width: 100%;
100
- height: 6px;
101
- -webkit-appearance: none;
102
- background: rgba(255, 255, 255, 0.1);
103
- border-radius: 3px;
104
- outline: none;
105
- }
106
-
107
- input[type="range"]::-webkit-slider-thumb {
108
- -webkit-appearance: none;
109
- width: 18px;
110
- height: 18px;
111
- background: white;
112
- border-radius: 50%;
113
- cursor: pointer;
114
- }
115
-
116
- /* Add styles for toast notifications */
117
- .toast {
118
- position: fixed;
119
- top: 20px;
120
- left: 50%;
121
- transform: translateX(-50%);
122
- padding: 16px 24px;
123
- border-radius: 4px;
124
- font-size: 14px;
125
- z-index: 1000;
126
- display: none;
127
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
128
- }
129
-
130
- .toast.error {
131
- background-color: #f44336;
132
- color: white;
133
- }
134
-
135
- .toast.warning {
136
- background-color: #ffd700;
137
- color: black;
138
- }
139
- </style>
140
  </head>
141
-
142
  <body>
143
- <!-- Add toast element after body opening tag -->
144
- <div id="error-toast" class="toast"></div>
145
- <div class="container">
146
- <h1>Real-time Object Detection</h1>
147
- <p>Using YOLOv10 to detect objects in your webcam feed</p>
148
- <div class="video-container">
149
- <video id="video-output" autoplay playsinline></video>
150
- </div>
151
- <div class="controls">
152
- <div class="slider-container">
153
- <label>Confidence Threshold: <span id="conf-value">0.3</span></label>
154
- <input type="range" id="conf-threshold" min="0" max="1" step="0.01" value="0.3">
155
- </div>
156
- <button id="start-button">Start</button>
157
- </div>
158
  </div>
159
-
160
- <script>
161
- let peerConnection;
162
- let webrtc_id;
163
- const startButton = document.getElementById('start-button');
164
- const videoOutput = document.getElementById('video-output');
165
- const confThreshold = document.getElementById('conf-threshold');
166
- const confValue = document.getElementById('conf-value');
167
-
168
- // Update confidence value display
169
- confThreshold.addEventListener('input', (e) => {
170
- confValue.textContent = e.target.value;
171
- if (peerConnection) {
172
- updateConfThreshold(e.target.value);
173
- }
174
- });
175
-
176
- function updateConfThreshold(value) {
177
- fetch('/input_hook', {
178
- method: 'POST',
179
- headers: {
180
- 'Content-Type': 'application/json',
181
- },
182
- body: JSON.stringify({
183
- webrtc_id: webrtc_id,
184
- conf_threshold: parseFloat(value)
185
- })
186
- });
187
- }
188
-
189
- function showError(message) {
190
- const toast = document.getElementById('error-toast');
191
- toast.textContent = message;
192
- toast.className = 'toast error';
193
- toast.style.display = 'block';
194
-
195
- // Hide toast after 5 seconds
196
- setTimeout(() => {
197
- toast.style.display = 'none';
198
- }, 5000);
199
- }
200
-
201
- async function setupWebRTC() {
202
- const config = __RTC_CONFIGURATION__;
203
- peerConnection = new RTCPeerConnection(config);
204
-
205
- const timeoutId = setTimeout(() => {
206
- const toast = document.getElementById('error-toast');
207
- toast.textContent = "Connection is taking longer than usual. Are you on a VPN?";
208
- toast.className = 'toast warning';
209
- toast.style.display = 'block';
210
-
211
- // Hide warning after 5 seconds
212
- setTimeout(() => {
213
- toast.style.display = 'none';
214
- }, 5000);
215
- }, 5000);
216
-
217
- try {
218
- const stream = await navigator.mediaDevices.getUserMedia({
219
- video: true
220
- });
221
-
222
- stream.getTracks().forEach(track => {
223
- peerConnection.addTrack(track, stream);
224
- });
225
-
226
- peerConnection.addEventListener('track', (evt) => {
227
- if (videoOutput && videoOutput.srcObject !== evt.streams[0]) {
228
- videoOutput.srcObject = evt.streams[0];
229
- }
230
- });
231
-
232
- const dataChannel = peerConnection.createDataChannel('text');
233
- dataChannel.onmessage = (event) => {
234
- const eventJson = JSON.parse(event.data);
235
- if (eventJson.type === "error") {
236
- showError(eventJson.message);
237
- } else if (eventJson.type === "send_input") {
238
- updateConfThreshold(confThreshold.value);
239
- }
240
- };
241
-
242
- const offer = await peerConnection.createOffer();
243
- await peerConnection.setLocalDescription(offer);
244
-
245
- await new Promise((resolve) => {
246
- if (peerConnection.iceGatheringState === "complete") {
247
- resolve();
248
- } else {
249
- const checkState = () => {
250
- if (peerConnection.iceGatheringState === "complete") {
251
- peerConnection.removeEventListener("icegatheringstatechange", checkState);
252
- resolve();
253
- }
254
- };
255
- peerConnection.addEventListener("icegatheringstatechange", checkState);
256
- }
257
- });
258
-
259
- webrtc_id = Math.random().toString(36).substring(7);
260
-
261
- const response = await fetch('/webrtc/offer', {
262
- method: 'POST',
263
- headers: { 'Content-Type': 'application/json' },
264
- body: JSON.stringify({
265
- sdp: peerConnection.localDescription.sdp,
266
- type: peerConnection.localDescription.type,
267
- webrtc_id: webrtc_id
268
- })
269
- });
270
-
271
- const serverResponse = await response.json();
272
-
273
- if (serverResponse.status === 'failed') {
274
- showError(serverResponse.meta.error === 'concurrency_limit_reached'
275
- ? `Too many connections. Maximum limit is ${serverResponse.meta.limit}`
276
- : serverResponse.meta.error);
277
- stop();
278
- startButton.textContent = 'Start';
279
- return;
280
- }
281
-
282
- await peerConnection.setRemoteDescription(serverResponse);
283
-
284
- // Send initial confidence threshold
285
- updateConfThreshold(confThreshold.value);
286
-
287
- peerConnection.addEventListener('connectionstatechange', () => {
288
- if (peerConnection.connectionState === 'connected') {
289
- clearTimeout(timeoutId);
290
- const toast = document.getElementById('error-toast');
291
- toast.style.display = 'none';
292
- }
293
- });
294
-
295
- } catch (err) {
296
- clearTimeout(timeoutId);
297
- console.error('Error setting up WebRTC:', err);
298
- showError('Failed to establish connection. Please try again.');
299
- stop();
300
- startButton.textContent = 'Start';
301
- }
302
- }
303
-
304
- function stop() {
305
- if (peerConnection) {
306
- if (peerConnection.getTransceivers) {
307
- peerConnection.getTransceivers().forEach(transceiver => {
308
- if (transceiver.stop) {
309
- transceiver.stop();
310
- }
311
- });
312
- }
313
-
314
- if (peerConnection.getSenders) {
315
- peerConnection.getSenders().forEach(sender => {
316
- if (sender.track && sender.track.stop) sender.track.stop();
317
- });
318
- }
319
-
320
- setTimeout(() => {
321
- peerConnection.close();
322
- }, 500);
323
- }
324
-
325
- videoOutput.srcObject = null;
326
- }
327
-
328
- startButton.addEventListener('click', () => {
329
- if (startButton.textContent === 'Start') {
330
- setupWebRTC();
331
- startButton.textContent = 'Stop';
332
- } else {
333
- stop();
334
- startButton.textContent = 'Start';
335
- }
336
  });
337
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  </body>
339
-
340
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
 
3
  <head>
4
+ <meta charset="UTF-8" />
5
+ <title>LiveKit Object Detection</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <style>
8
+ body {
9
+ font-family: system-ui, -apple-system, sans-serif;
10
+ background: linear-gradient(135deg, #2d2b52 0%, #191731 100%);
11
+ color: white;
12
+ margin: 0;
13
+ padding: 20px;
14
+ height: 100vh;
15
+ box-sizing: border-box;
16
+ display: flex;
17
+ flex-direction: column;
18
+ align-items: center;
19
+ justify-content: center;
20
+ }
21
+ .container {
22
+ max-width: 800px;
23
+ text-align: center;
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ }
28
+ .video-container {
29
+ max-width: 500px;
30
+ aspect-ratio: 1/1;
31
+ background: rgba(255, 255, 255, 0.1);
32
+ border-radius: 12px;
33
+ overflow: hidden;
34
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
35
+ margin: 10px 0;
36
+ }
37
+ video {
38
+ width: 100%;
39
+ height: 100%;
40
+ object-fit: cover;
41
+ }
42
+ button {
43
+ background: white;
44
+ color: #2d2b52;
45
+ border: none;
46
+ padding: 12px 32px;
47
+ border-radius: 24px;
48
+ font-size: 16px;
49
+ font-weight: 600;
50
+ cursor: pointer;
51
+ transition: all 0.3s ease;
52
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
53
+ }
54
+ button:hover {
55
+ transform: translateY(-2px);
56
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
57
+ }
58
+ .slider-container {
59
+ max-width: 300px;
60
+ margin-top: 16px;
61
+ }
62
+ input[type="range"] {
63
+ width: 100%;
64
+ }
65
+ label {
66
+ font-size: 14px;
67
+ }
68
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  </head>
 
70
  <body>
71
+ <div class="container">
72
+ <h1>LiveKit Object Detection</h1>
73
+ <p>Stream webcam feed and detect objects using YOLOv10</p>
74
+ <div class="video-container">
75
+ <video id="video" autoplay muted playsinline></video>
 
 
 
 
 
 
 
 
 
 
76
  </div>
77
+ <div class="slider-container">
78
+ <label>Confidence Threshold: <span id="conf-value">0.3</span></label>
79
+ <input type="range" id="conf-threshold" min="0" max="1" step="0.01" value="0.3">
80
+ </div>
81
+ <button id="start-button">Start Streaming</button>
82
+ </div>
83
+
84
+ <script type="module">
85
+ import { connect } from "https://cdn.jsdelivr.net/npm/livekit-client/dist/livekit-client.esm.js";
86
+
87
+ const startBtn = document.getElementById("start-button");
88
+ const video = document.getElementById("video");
89
+ const confSlider = document.getElementById("conf-threshold");
90
+ const confVal = document.getElementById("conf-value");
91
+
92
+ let room;
93
+ let intervalId;
94
+
95
+ confSlider.addEventListener("input", () => {
96
+ confVal.textContent = confSlider.value;
97
+ });
98
+
99
+ async function startStream() {
100
+ const livekitURL = "wss://myvoiceassistant-h4f2cbzj.livekit.cloud"; // Replace this
101
+ const token = "APIVcbcyNpkNcsL"; // Replace this
102
+
103
+ room = await connect(livekitURL, token, {
104
+ video: true,
105
+ audio: false,
106
+ });
107
+
108
+ const pubTrack = room.localParticipant.getTrackPublications().find((pub) => pub.kind === "video");
109
+ const stream = new MediaStream([pubTrack.track.mediaStreamTrack]);
110
+
111
+ video.srcObject = stream;
112
+
113
+ // Send image frames to backend every 1 second
114
+ intervalId = setInterval(() => {
115
+ const canvas = document.createElement("canvas");
116
+ canvas.width = video.videoWidth;
117
+ canvas.height = video.videoHeight;
118
+ const ctx = canvas.getContext("2d");
119
+ ctx.drawImage(video, 0, 0);
120
+ const imageData = canvas.toDataURL("image/jpeg");
121
+
122
+ fetch("http://localhost:8000/detect", {
123
+ method: "POST",
124
+ headers: { "Content-Type": "application/json" },
125
+ body: JSON.stringify({
126
+ image: imageData,
127
+ conf_threshold: parseFloat(confSlider.value)
128
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  });
130
+ }, 1000);
131
+ }
132
+
133
+ startBtn.addEventListener("click", async () => {
134
+ if (startBtn.textContent === "Start Streaming") {
135
+ await startStream();
136
+ startBtn.textContent = "Stop Streaming";
137
+ } else {
138
+ if (room) room.disconnect();
139
+ if (intervalId) clearInterval(intervalId);
140
+ video.srcObject = null;
141
+ startBtn.textContent = "Start Streaming";
142
+ }
143
+ });
144
+ </script>
145
  </body>
146
+ </html>