Fix camera/mic interference: detection runs during TTS, 12s exit threshold, require no recent commands

- Remove isSpeaking outer guard — detection loop now runs always so lastFaceSeen stays current
- While isSpeaking + no face detected: refresh lastFaceSeen to prevent exit timer ticking during TTS
- Raise no-face exit threshold from 3s to 12s — sporadic missed frames no longer kill the session
- Add noCommandMs guard: camera never exits voice mode within 12s of last spoken command
- Voice auto-trigger still respects isSpeaking (wont reactivate mid-response)
This commit is contained in:
2026-06-02 00:15:47 +00:00
parent c91e5b8be7
commit c34d497e9d
+16 -10
View File
@@ -1539,7 +1539,8 @@ async function startCamera() {
addMessage('system', 'Face detection active — reactor tracking engaged.');
faceLoopId = setInterval(async () => {
if (!cameraActive || isSpeaking) return;
if (!cameraActive) return;
// Run detection even while speaking — needed for tracking + prevents lastFaceSeen staling out
try {
const detection = await faceapi.detectSingleFace(
document.getElementById('faceVideo'),
@@ -1548,25 +1549,30 @@ async function startCamera() {
const now = Date.now();
if (detection) {
lastFaceSeen = now;
const {x, y, width, height} = detection.box;
const ratio = (width * height) / (320 * 240);
const ratio = (detection.box.width * detection.box.height) / (320 * 240);
// Drive the reactor to follow the face
// Always drive the reactor
updateFaceTarget(detection.box, 320, 240);
// Trigger voice if face fills >3% of frame
if (ratio > 0.03 && !voiceMode && now > autoMicCooldown) {
// Only auto-trigger voice when not already speaking/active, cooldown passed
if (ratio > 0.03 && !voiceMode && !isSpeaking && now > autoMicCooldown) {
autoMicCooldown = now + 9000;
document.getElementById('cameraBtn').classList.add('cam-sensing');
enterVoiceMode();
}
} else {
clearFaceTarget();
// No face — exit voice mode if face gone >3s
if (voiceMode && now - lastFaceSeen > 3000) {
// While JARVIS is speaking, keep lastFaceSeen fresh so the exit timer doesn't tick down
if (isSpeaking) { lastFaceSeen = now; }
else { clearFaceTarget(); }
document.getElementById('cameraBtn').classList.remove('cam-sensing');
// Exit voice mode only if: face gone >12s AND no command in that same window AND not speaking
const noFaceMs = now - lastFaceSeen;
const noCommandMs = now - (voiceLastCmd || 0);
if (voiceMode && !isSpeaking && noFaceMs > 12000 && noCommandMs > 12000) {
exitVoiceMode();
}
document.getElementById('cameraBtn').classList.remove('cam-sensing');
}
} catch(_) {}
}, 600);