Paradise151 commited on
Commit
454767c
·
verified ·
1 Parent(s): ba7cf5d

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +41 -531
index.html CHANGED
@@ -2,565 +2,75 @@
2
  <html>
3
  <head>
4
  <meta charset="utf-8">
5
- <title>GrechnikNet — YOLOv8n Detection</title>
6
  <style>
7
- body { background:#111; color:#eee; font-family: sans-serif; margin:0; }
8
- header { padding:16px; text-align:center; }
9
- main { display:flex; flex-direction:column; align-items:center; gap:16px; padding:16px; }
10
- video, img { width: min(100vw, 720px); height: auto; border:1px solid #333; border-radius:8px; }
11
- .controls { display:flex; gap:16px; flex-wrap:wrap; align-items:center; justify-content:center; }
12
- .control { background:#1b1b1b; padding:10px 12px; border-radius:8px; }
13
- label { display:block; font-size:14px; margin-bottom:6px; }
14
- input[type="range"] { width:200px; }
15
- button { padding:10px 14px; border:none; border-radius:8px; background:#3a6df0; color:#fff; cursor:pointer; }
16
  button:disabled { background:#555; cursor:not-allowed; }
17
- .row { display:flex; flex-direction:row; gap:16px; flex-wrap:wrap; justify-content:center; }
18
  </style>
19
  </head>
20
  <body>
21
  <header>
22
- <h2>GrechnikNet — Impurity Detection (Phone Camera)</h2>
23
- <p>Наведи камеру телефона на гречку, получи боксы. Без зеркала, корректный цвет.</p>
24
  </header>
25
 
26
- <main>
27
- <div class="controls">
28
- <div class="control">
29
- <label>Камера:</label>
30
- <select id="cameraSelect"></select>
31
- </div>
32
- <div class="control">
33
- <label>Confidence: <span id="confVal">0.25</span></label>
34
- <input type="range" id="confSlider" min="0" max="1" step="0.05" value="0.25">
35
- </div>
36
- <div class="control">
37
- <label>IoU: <span id="iouVal">0.45</span></label>
38
- <input type="range" id="iouSlider" min="0" max="1" step="0.05" value="0.45">
39
- </div>
40
- <div class="control">
41
- <label>Режим ответа:</label>
42
- <select id="modeSelect">
43
- <option value="image">Аннотированное изображение</option>
44
- <option value="json">Только боксы (JSON)</option>
45
- </select>
46
- </div>
47
- <div class="control">
48
- <button id="startBtn">Старт</button>
49
- <button id="stopBtn" disabled>Стоп</button>
50
- </div>
51
- </div>
52
 
53
- <div class="row">
54
- <video id="video" playsinline autoplay muted></video>
55
- <img id="resultImg" alt="Detections" />
56
- <pre id="jsonOut" style="display:none; width: min(100vw, 720px); background:#0e0e0e; padding:12px; border-radius:8px;"></pre>
57
- </div>
58
- </main>
59
 
60
- <!-- 1 вариант но его колбасит из-за задержек -->
61
- <!-- <script>
 
 
62
  const video = document.getElementById('video');
 
63
  const resultImg = document.getElementById('resultImg');
64
- const jsonOut = document.getElementById('jsonOut');
65
- const startBtn = document.getElementById('startBtn');
66
- const stopBtn = document.getElementById('stopBtn');
67
- const cameraSelect = document.getElementById('cameraSelect');
68
- const confSlider = document.getElementById('confSlider');
69
- const iouSlider = document.getElementById('iouSlider');
70
- const confVal = document.getElementById('confVal');
71
- const iouVal = document.getElementById('iouVal');
72
- const modeSelect = document.getElementById('modeSelect');
73
-
74
- let stream = null;
75
- let captureInterval = null;
76
- let currentDeviceId = null;
77
-
78
- confSlider.oninput = () => confVal.textContent = confSlider.value;
79
- iouSlider.oninput = () => iouVal.textContent = iouSlider.value;
80
-
81
- async function enumerateCameras() {
82
- const devices = await navigator.mediaDevices.enumerateDevices();
83
- cameraSelect.innerHTML = '';
84
- const cams = devices.filter(d => d.kind === 'videoinput');
85
- cams.forEach((cam, i) => {
86
- const opt = document.createElement('option');
87
- opt.value = cam.deviceId || i;
88
- opt.textContent = cam.label || `Камера ${i+1}`;
89
- cameraSelect.appendChild(opt);
90
- });
91
- if (cams.length > 0) currentDeviceId = cams[0].deviceId;
92
- }
93
-
94
- async function startCamera(deviceId) {
95
- if (stream) stopCamera();
96
- const constraints = {
97
- video: {
98
- deviceId: deviceId ? { exact: deviceId } : undefined,
99
- facingMode: 'environment', // на телефоне — основная камера
100
- width: { ideal: 720 },
101
- height: { ideal: 720 }
102
- },
103
- audio: false
104
- };
105
- stream = await navigator.mediaDevices.getUserMedia(constraints);
106
- video.srcObject = stream;
107
- await video.play();
108
- }
109
-
110
- function stopCamera() {
111
- if (stream) {
112
- stream.getTracks().forEach(t => t.stop());
113
- stream = null;
114
- }
115
- }
116
-
117
- cameraSelect.onchange = async () => {
118
- currentDeviceId = cameraSelect.value;
119
- await startCamera(currentDeviceId);
120
- };
121
 
122
- async function captureAndSendFrame() {
123
- if (!stream) return;
 
 
 
 
 
124
 
 
125
  // Снимаем кадр в canvas
126
  const canvas = document.createElement('canvas');
127
- const w = Math.min(720, video.videoWidth || 640);
128
- const h = Math.floor(w * (video.videoHeight / video.videoWidth));
129
- canvas.width = w;
130
- canvas.height = h;
131
  const ctx = canvas.getContext('2d');
 
132
 
133
- // Без зеркала: просто рисуем кадр как есть
134
- ctx.drawImage(video, 0, 0, w, h);
135
-
136
- // Конвертим в Blob (JPEG)
137
- const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.85));
138
- const formData = new FormData();
139
- formData.append('file', blob, 'frame.jpg');
140
- formData.append('conf', confSlider.value);
141
- formData.append('iou', iouSlider.value);
142
-
143
- const returnImage = (modeSelect.value === 'image') ? 1 : 0;
144
- formData.append('return_image', returnImage.toString());
145
-
146
- const resp = await fetch('/predict', { method: 'POST', body: formData });
147
-
148
- if (returnImage === 1) {
149
- const arrBuf = await resp.arrayBuffer();
150
- const blobRes = new Blob([arrBuf], { type: 'image/jpeg' });
151
- const url = URL.createObjectURL(blobRes);
152
- resultImg.src = url;
153
- resultImg.style.display = 'block';
154
- jsonOut.style.display = 'none';
155
- } else {
156
- const data = await resp.json();
157
- jsonOut.textContent = JSON.stringify(data, null, 2);
158
- jsonOut.style.display = 'block';
159
- resultImg.style.display = 'none';
160
- }
161
- }
162
-
163
- startBtn.onclick = async () => {
164
- await enumerateCameras();
165
- await startCamera(currentDeviceId);
166
- startBtn.disabled = true;
167
- stopBtn.disabled = false;
168
- // Частота отправки кадров: 5–10 FPS (баланс скорости/качества)
169
- captureInterval = setInterval(captureAndSendFrame, 120);
170
- };
171
-
172
- stopBtn.onclick = () => {
173
- startBtn.disabled = false;
174
- stopBtn.disabled = true;
175
- clearInterval(captureInterval);
176
- captureInterval = null;
177
- stopCamera();
178
- };
179
-
180
- // Предзагрузка списка камер (нужно permission для labels; поэтому делаем после старта)
181
- </script> -->
182
 
183
- <!-- 2 вариант с обработкой каждого второго кадра -->
184
- <!-- <script>
185
- const video = document.getElementById('video');
186
- const resultImg = document.getElementById('resultImg');
187
- const jsonOut = document.getElementById('jsonOut');
188
- const startBtn = document.getElementById('startBtn');
189
- const stopBtn = document.getElementById('stopBtn');
190
- const cameraSelect = document.getElementById('cameraSelect');
191
- const confSlider = document.getElementById('confSlider');
192
- const iouSlider = document.getElementById('iouSlider');
193
- const confVal = document.getElementById('confVal');
194
- const iouVal = document.getElementById('iouVal');
195
- const modeSelect = document.getElementById('modeSelect');
196
-
197
- let stream = null;
198
- let captureInterval = null;
199
- let currentDeviceId = null;
200
- let frameCounter = 0; // счётчик кадров
201
-
202
- confSlider.oninput = () => confVal.textContent = confSlider.value;
203
- iouSlider.oninput = () => iouVal.textContent = iouSlider.value;
204
-
205
- async function enumerateCameras() {
206
- const devices = await navigator.mediaDevices.enumerateDevices();
207
- cameraSelect.innerHTML = '';
208
- const cams = devices.filter(d => d.kind === 'videoinput');
209
- cams.forEach((cam, i) => {
210
- const opt = document.createElement('option');
211
- opt.value = cam.deviceId || i;
212
- opt.textContent = cam.label || `Камера ${i+1}`;
213
- cameraSelect.appendChild(opt);
214
- });
215
- if (cams.length > 0) currentDeviceId = cams[0].deviceId;
216
- }
217
-
218
- async function startCamera(deviceId) {
219
- if (stream) stopCamera();
220
- const constraints = {
221
- video: {
222
- deviceId: deviceId ? { exact: deviceId } : undefined,
223
- facingMode: 'environment',
224
- width: { ideal: 720 },
225
- height: { ideal: 720 }
226
- },
227
- audio: false
228
- };
229
- stream = await navigator.mediaDevices.getUserMedia(constraints);
230
- video.srcObject = stream;
231
- await video.play();
232
- }
233
-
234
- function stopCamera() {
235
- if (stream) {
236
- stream.getTracks().forEach(t => t.stop());
237
- stream = null;
238
- }
239
- }
240
-
241
- cameraSelect.onchange = async () => {
242
- currentDeviceId = cameraSelect.value;
243
- await startCamera(currentDeviceId);
244
- };
245
-
246
- async function captureAndSendFrame() {
247
- if (!stream) return;
248
-
249
- frameCounter++;
250
- if (frameCounter % 2 !== 0) {
251
- // пропускаем каждый второй кадр
252
- return;
253
- }
254
-
255
- const canvas = document.createElement('canvas');
256
- const w = Math.min(720, video.videoWidth || 640);
257
- const h = Math.floor(w * (video.videoHeight / video.videoWidth));
258
- canvas.width = w;
259
- canvas.height = h;
260
- const ctx = canvas.getContext('2d');
261
- ctx.drawImage(video, 0, 0, w, h);
262
-
263
- const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.85));
264
  const formData = new FormData();
265
  formData.append('file', blob, 'frame.jpg');
266
- formData.append('conf', confSlider.value);
267
- formData.append('iou', iouSlider.value);
268
- const returnImage = (modeSelect.value === 'image') ? 1 : 0;
269
- formData.append('return_image', returnImage.toString());
270
-
271
- const resp = await fetch('/predict', { method: 'POST', body: formData });
272
- if (returnImage === 1) {
273
- const arrBuf = await resp.arrayBuffer();
274
- const blobRes = new Blob([arrBuf], { type: 'image/jpeg' });
275
- const url = URL.createObjectURL(blobRes);
276
- resultImg.src = url;
277
- resultImg.style.display = 'block';
278
- jsonOut.style.display = 'none';
279
- } else {
280
- const data = await resp.json();
281
- jsonOut.textContent = JSON.stringify(data, null, 2);
282
- jsonOut.style.display = 'block';
283
- resultImg.style.display = 'none';
284
- }
285
- }
286
-
287
- startBtn.onclick = async () => {
288
- await enumerateCameras();
289
- await startCamera(currentDeviceId);
290
- startBtn.disabled = true;
291
- stopBtn.disabled = false;
292
- captureInterval = setInterval(captureAndSendFrame, 120); // ~8 FPS, но реально уйдёт ~4 FPS
293
- };
294
-
295
- stopBtn.onclick = () => {
296
- startBtn.disabled = false;
297
- stopBtn.disabled = true;
298
- clearInterval(captureInterval);
299
- captureInterval = null;
300
- stopCamera();
301
- };
302
- </script> -->
303
 
304
- <!-- <!-- 3-ий вариант - следующий кадр только после ответа -->
305
- <script>
306
- const video = document.getElementById('video');
307
- const resultImg = document.getElementById('resultImg');
308
- const jsonOut = document.getElementById('jsonOut');
309
- const startBtn = document.getElementById('startBtn');
310
- const stopBtn = document.getElementById('stopBtn');
311
- const cameraSelect = document.getElementById('cameraSelect');
312
- const confSlider = document.getElementById('confSlider');
313
- const iouSlider = document.getElementById('iouSlider');
314
- const confVal = document.getElementById('confVal');
315
- const iouVal = document.getElementById('iouVal');
316
- const modeSelect = document.getElementById('modeSelect');
317
-
318
- let stream = null;
319
- let active = false;
320
- let currentDeviceId = null;
321
-
322
- confSlider.oninput = () => confVal.textContent = confSlider.value;
323
- iouSlider.oninput = () => iouVal.textContent = iouSlider.value;
324
-
325
- async function enumerateCameras() {
326
- const devices = await navigator.mediaDevices.enumerateDevices();
327
- cameraSelect.innerHTML = '';
328
- const cams = devices.filter(d => d.kind === 'videoinput');
329
- cams.forEach((cam, i) => {
330
- const opt = document.createElement('option');
331
- opt.value = cam.deviceId || i;
332
- opt.textContent = cam.label || `Камера ${i+1}`;
333
- cameraSelect.appendChild(opt);
334
- });
335
- if (cams.length > 0) currentDeviceId = cams[0].deviceId;
336
- }
337
-
338
- async function startCamera(deviceId) {
339
- if (stream) stopCamera();
340
- const constraints = {
341
- video: {
342
- deviceId: deviceId ? { exact: deviceId } : undefined,
343
- facingMode: 'environment',
344
- width: { ideal: 720 },
345
- height: { ideal: 720 }
346
- },
347
- audio: false
348
- };
349
- stream = await navigator.mediaDevices.getUserMedia(constraints);
350
- video.srcObject = stream;
351
- await video.play();
352
- }
353
-
354
- function stopCamera() {
355
- if (stream) {
356
- stream.getTracks().forEach(t => t.stop());
357
- stream = null;
358
- }
359
- }
360
-
361
- cameraSelect.onchange = async () => {
362
- currentDeviceId = cameraSelect.value;
363
- await startCamera(currentDeviceId);
364
- };
365
-
366
- async function captureAndSendFrame() {
367
- if (!stream || !active) return;
368
-
369
- const canvas = document.createElement('canvas');
370
- const w = Math.min(720, video.videoWidth || 640);
371
- const h = Math.floor(w * (video.videoHeight / video.videoWidth));
372
- canvas.width = w;
373
- canvas.height = h;
374
- const ctx = canvas.getContext('2d');
375
- ctx.drawImage(video, 0, 0, w, h);
376
-
377
- const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.9));
378
- const formData = new FormData();
379
- formData.append('file', blob, 'frame.jpg');
380
- formData.append('conf', confSlider.value);
381
- formData.append('iou', iouSlider.value);
382
- const returnImage = (modeSelect.value === 'image') ? 1 : 0;
383
- formData.append('return_image', returnImage.toString());
384
-
385
  try {
386
  const resp = await fetch('/predict', { method: 'POST', body: formData });
387
- if (returnImage === 1) {
388
- const arrBuf = await resp.arrayBuffer();
389
- const blobRes = new Blob([arrBuf], { type: 'image/jpeg' });
390
- const url = URL.createObjectURL(blobRes);
391
- resultImg.src = url;
392
- resultImg.style.display = 'block';
393
- jsonOut.style.display = 'none';
394
- } else {
395
- const data = await resp.json();
396
- jsonOut.textContent = JSON.stringify(data, null, 2);
397
- jsonOut.style.display = 'block';
398
- resultImg.style.display = 'none';
399
  }
400
- } catch (e) {
401
- console.error("Ошибка запроса:", e);
402
- }
403
-
404
- // запускаем следующий кадр только после ответа
405
- if (active) requestAnimationFrame(captureAndSendFrame);
406
- }
407
-
408
- startBtn.onclick = async () => {
409
- await enumerateCameras();
410
- await startCamera(currentDeviceId);
411
- active = true;
412
- startBtn.disabled = true;
413
- stopBtn.disabled = false;
414
- captureAndSendFrame(); // запускаем цикл
415
- };
416
-
417
- stopBtn.onclick = () => {
418
- active = false;
419
- startBtn.disabled = false;
420
- stopBtn.disabled = true;
421
- stopCamera();
422
- };
423
- </script> -->
424
-
425
-
426
- <!-- 4 вариант - всегда свежий, последний кадр -->
427
- <script>
428
- const video = document.getElementById('video');
429
- const resultImg = document.getElementById('resultImg');
430
- const jsonOut = document.getElementById('jsonOut');
431
- const startBtn = document.getElementById('startBtn');
432
- const stopBtn = document.getElementById('stopBtn');
433
- const cameraSelect = document.getElementById('cameraSelect');
434
- const confSlider = document.getElementById('confSlider');
435
- const iouSlider = document.getElementById('iouSlider');
436
- const confVal = document.getElementById('confVal');
437
- const iouVal = document.getElementById('iouVal');
438
- const modeSelect = document.getElementById('modeSelect');
439
-
440
- let stream = null;
441
- let active = false;
442
- let currentDeviceId = null;
443
- let busy = false; // сервер занят
444
- let pendingFrame = null; // последний кадр в буфере
445
-
446
- confSlider.oninput = () => confVal.textContent = confSlider.value;
447
- iouSlider.oninput = () => iouVal.textContent = iouSlider.value;
448
-
449
- async function enumerateCameras() {
450
- const devices = await navigator.mediaDevices.enumerateDevices();
451
- cameraSelect.innerHTML = '';
452
- const cams = devices.filter(d => d.kind === 'videoinput');
453
- cams.forEach((cam, i) => {
454
- const opt = document.createElement('option');
455
- opt.value = cam.deviceId || i;
456
- opt.textContent = cam.label || `Камера ${i+1}`;
457
- cameraSelect.appendChild(opt);
458
- });
459
- if (cams.length > 0) currentDeviceId = cams[0].deviceId;
460
- }
461
-
462
- async function startCamera(deviceId) {
463
- if (stream) stopCamera();
464
- const constraints = {
465
- video: {
466
- deviceId: deviceId ? { exact: deviceId } : undefined,
467
- facingMode: 'environment',
468
- width: { ideal: 720 },
469
- height: { ideal: 720 }
470
- },
471
- audio: false
472
- };
473
- stream = await navigator.mediaDevices.getUserMedia(constraints);
474
- video.srcObject = stream;
475
- await video.play();
476
- requestAnimationFrame(captureLoop);
477
- }
478
-
479
- function stopCamera() {
480
- if (stream) {
481
- stream.getTracks().forEach(t => t.stop());
482
- stream = null;
483
- }
484
- }
485
-
486
- cameraSelect.onchange = async () => {
487
- currentDeviceId = cameraSelect.value;
488
- await startCamera(currentDeviceId);
489
- };
490
-
491
- function captureLoop() {
492
- if (!active || !stream) return;
493
-
494
- const canvas = document.createElement('canvas');
495
- const w = Math.min(720, video.videoWidth || 640);
496
- const h = Math.floor(w * (video.videoHeight / video.videoWidth));
497
- canvas.width = w;
498
- canvas.height = h;
499
- const ctx = canvas.getContext('2d');
500
- ctx.drawImage(video, 0, 0, w, h);
501
-
502
- canvas.toBlob(blob => {
503
- pendingFrame = blob; // сохраняем последний кадр
504
- if (!busy) sendFrame(); // если сервер свободен — отправляем
505
- }, 'image/jpeg', 0.9);
506
-
507
- requestAnimationFrame(captureLoop);
508
- }
509
-
510
- async function sendFrame() {
511
- if (!pendingFrame) return;
512
- busy = true;
513
-
514
- const formData = new FormData();
515
- formData.append('file', pendingFrame, 'frame.jpg');
516
- formData.append('conf', confSlider.value);
517
- formData.append('iou', iouSlider.value);
518
- const returnImage = (modeSelect.value === 'image') ? 1 : 0;
519
- formData.append('return_image', returnImage.toString());
520
-
521
- pendingFrame = null; // очищаем буфер
522
-
523
- try {
524
- const resp = await fetch('/predict', { method: 'POST', body: formData });
525
- if (returnImage === 1) {
526
  const arrBuf = await resp.arrayBuffer();
527
  const blobRes = new Blob([arrBuf], { type: 'image/jpeg' });
528
  resultImg.src = URL.createObjectURL(blobRes);
529
- resultImg.style.display = 'block';
530
- jsonOut.style.display = 'none';
531
- } else {
532
- const data = await resp.json();
533
- jsonOut.textContent = JSON.stringify(data, null, 2);
534
- jsonOut.style.display = 'block';
535
- resultImg.style.display = 'none';
536
  }
537
- } catch (e) {
538
- console.error("Ошибка запроса:", e);
539
- }
540
-
541
- busy = false;
542
- if (pendingFrame) sendFrame(); // если уже есть новый кадр — сразу отправляем
543
- }
544
-
545
- startBtn.onclick = async () => {
546
- await enumerateCameras();
547
- await startCamera(currentDeviceId);
548
- active = true;
549
- startBtn.disabled = true;
550
- stopBtn.disabled = false;
551
- };
552
-
553
- stopBtn.onclick = () => {
554
- active = false;
555
- startBtn.disabled = false;
556
- stopBtn.disabled = true;
557
- stopCamera();
558
- };
559
- </script>
560
-
561
- </script>
562
  </body>
563
  </html>
564
-
565
-
566
-
 
2
  <html>
3
  <head>
4
  <meta charset="utf-8">
5
+ <title>GrechnikNet — Snapshot Detection</title>
6
  <style>
7
+ body { background:#111; color:#eee; font-family:sans-serif; text-align:center; margin:0; }
8
+ header { padding:16px; }
9
+ video, img { width: min(100vw, 720px); height:auto; border:1px solid #333; border-radius:8px; margin:10px 0; }
10
+ button { padding:10px 16px; border:none; border-radius:6px; background:#3a6df0; color:#fff; cursor:pointer; }
 
 
 
 
 
11
  button:disabled { background:#555; cursor:not-allowed; }
 
12
  </style>
13
  </head>
14
  <body>
15
  <header>
16
+ <h2>GrechnikNet — Snapshot Detection</h2>
17
+ <p>Сверху — поток с камеры, снизу результат последнего снимка</p>
18
  </header>
19
 
20
+ <!-- верхнее окно: живое видео -->
21
+ <video id="video" autoplay playsinline muted></video><br>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ <!-- кнопка -->
24
+ <button id="snapBtn">Сделать фото</button><br>
 
 
 
 
25
 
26
+ <!-- нижнее окно: результат -->
27
+ <img id="resultImg" alt="Результат появится здесь">
28
+
29
+ <script>
30
  const video = document.getElementById('video');
31
+ const snapBtn = document.getElementById('snapBtn');
32
  const resultImg = document.getElementById('resultImg');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
+ // Запрашиваем доступ к камере
35
+ navigator.mediaDevices.getUserMedia({
36
+ video: { facingMode: 'environment', width: 720 },
37
+ audio: false
38
+ })
39
+ .then(stream => { video.srcObject = stream; })
40
+ .catch(err => { alert("Ошибка доступа к камере: " + err); });
41
 
42
+ snapBtn.onclick = async () => {
43
  // Снимаем кадр в canvas
44
  const canvas = document.createElement('canvas');
45
+ canvas.width = video.videoWidth;
46
+ canvas.height = video.videoHeight;
 
 
47
  const ctx = canvas.getContext('2d');
48
+ ctx.drawImage(video, 0, 0);
49
 
50
+ // Конвертим в Blob
51
+ const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.9));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ // Отправляем на сервер
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  const formData = new FormData();
55
  formData.append('file', blob, 'frame.jpg');
56
+ formData.append('conf', '0.25');
57
+ formData.append('iou', '0.45');
58
+ formData.append('return_image', '1');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  try {
61
  const resp = await fetch('/predict', { method: 'POST', body: formData });
62
+ if (!resp.ok) {
63
+ const text = await resp.text();
64
+ alert("Ошибка сервера: " + text);
65
+ return;
 
 
 
 
 
 
 
 
66
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  const arrBuf = await resp.arrayBuffer();
68
  const blobRes = new Blob([arrBuf], { type: 'image/jpeg' });
69
  resultImg.src = URL.createObjectURL(blobRes);
70
+ } catch (e) {
71
+ alert("Ошибка запроса: " + e);
 
 
 
 
 
72
  }
73
+ };
74
+ </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  </body>
76
  </html>