@@ -381,16 +381,37 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
381381 return null ;
382382 }
383383
384+ // Step 1b: Detect hard hats in the frame
385+ let hardHatDetections = [ ] ;
386+ try {
387+ updateStatus ( 'Detecting hard hats...' ) ;
388+ window . reasoningConsole . logApiCall ( '/detect (hard hat)' , 0 ) ;
389+ const hatStart = Date . now ( ) ;
390+ const hatResult = await client . detect ( imageDataUrl , 'hard hat' ) ;
391+ hardHatDetections = ( hatResult . objects || [ ] ) . map ( h => ( {
392+ x_min : h . x_min || 0 ,
393+ y_min : h . y_min || 0 ,
394+ x_max : h . x_max || 0 ,
395+ y_max : h . y_max || 0
396+ } ) ) ;
397+ const hatLatency = Date . now ( ) - hatStart ;
398+ window . reasoningConsole . logApiCall ( '/detect (hard hat)' , hatLatency ) ;
399+ window . reasoningConsole . logInfo ( `Detected ${ hardHatDetections . length } hard hat(s) [${ hatLatency } ms]` ) ;
400+ } catch ( e ) {
401+ window . reasoningConsole . logError ( 'Hard hat detection failed: ' + e . message ) ;
402+ }
403+
384404 if ( detections . length === 0 ) {
385405 // No people — scene is safe
386- drawPersonOverlays ( [ ] , imageDataUrl ) ;
406+ drawPersonOverlays ( [ ] , imageDataUrl , hardHatDetections ) ;
387407 return {
388408 safetyRating : 5 ,
389409 status : 'all_clear' ,
390410 primaryConcern : 'No personnel detected' ,
391411 recommendedAction : 'Continue monitoring' ,
392412 detectedHazards : [ ] ,
393- people : [ ]
413+ people : [ ] ,
414+ hardHats : hardHatDetections
394415 } ;
395416 }
396417
@@ -443,7 +464,7 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
443464 }
444465
445466 // Step 3: Draw visual overlays + update summary
446- drawPersonOverlays ( people , imageDataUrl ) ;
467+ drawPersonOverlays ( people , imageDataUrl , hardHatDetections ) ;
447468 drawCanvasSummaryBadge ( people ) ;
448469 updatePPESummary ( people ) ;
449470
@@ -490,7 +511,8 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
490511 primaryConcern : concern ,
491512 recommendedAction : action ,
492513 detectedHazards : hazards ,
493- people : people
514+ people : people ,
515+ hardHats : hardHatDetections
494516 } ;
495517 }
496518
@@ -536,10 +558,11 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
536558 }
537559 }
538560
539- function drawPersonOverlays ( people , imageDataUrl ) {
561+ function drawPersonOverlays ( people , imageDataUrl , hardHats ) {
540562 overlayCtx . clearRect ( 0 , 0 , overlayCanvas . width , overlayCanvas . height ) ;
563+ hardHats = hardHats || [ ] ;
541564
542- if ( people . length === 0 ) return ;
565+ if ( people . length === 0 && hardHats . length === 0 ) return ;
543566
544567 // Get image dimensions for coordinate scaling
545568 const img = new Image ( ) ;
@@ -619,6 +642,31 @@ If you see a hard hat AND a safety vest, safe=true. Otherwise safe=false.`;
619642 } ) ;
620643 } ) ;
621644
645+ // Draw hard hat detection boxes
646+ hardHats . forEach ( function ( hat ) {
647+ const hx = hat . x_min * iw * scaleX ;
648+ const hy = hat . y_min * ih * scaleY ;
649+ const hw = ( hat . x_max - hat . x_min ) * iw * scaleX ;
650+ const hh = ( hat . y_max - hat . y_min ) * ih * scaleY ;
651+
652+ // Bright cyan box for hard hats
653+ overlayCtx . strokeStyle = '#00E5FF' ;
654+ overlayCtx . lineWidth = 2 ;
655+ overlayCtx . setLineDash ( [ ] ) ;
656+ overlayCtx . strokeRect ( hx , hy , hw , hh ) ;
657+
658+ // Label
659+ const hatLabel = '⛑ Hard Hat' ;
660+ overlayCtx . font = 'bold 11px sans-serif' ;
661+ const hatLabelW = overlayCtx . measureText ( hatLabel ) . width + 8 ;
662+ overlayCtx . fillStyle = '#00E5FF' ;
663+ overlayCtx . beginPath ( ) ;
664+ overlayCtx . roundRect ( hx , hy - 16 , hatLabelW , 16 , 3 ) ;
665+ overlayCtx . fill ( ) ;
666+ overlayCtx . fillStyle = '#000' ;
667+ overlayCtx . fillText ( hatLabel , hx + 4 , hy - 3 ) ;
668+ } ) ;
669+
622670 // Overall border based on safety
623671 const unsafeCount = people . filter ( p => ! p . safe ) . length ;
624672 if ( unsafeCount > 0 ) {
0 commit comments