diff --git a/modules/features/teamsbot/service.py b/modules/features/teamsbot/service.py index e481bf86..e1ac6eda 100644 --- a/modules/features/teamsbot/service.py +++ b/modules/features/teamsbot/service.py @@ -450,7 +450,7 @@ class TeamsbotService: if captureDiagnostics and captureDiagnostics.get("rms") is not None: try: rmsVal = float(captureDiagnostics.get("rms")) - if rmsVal < 0.0015: + if rmsVal < 0.0003: logger.debug(f"[AudioChunk] Skipping silent audio ({len(audioBytes)} bytes, rms={rmsVal:.6f})") return except Exception: @@ -763,32 +763,42 @@ class TeamsbotService: now = time.time() timeSinceLastCall = now - self._lastAiCallTime - # Bot name mentioned -> immediate trigger (OVERRIDES cooldown) + # Bot name detection — overrides the periodic cooldown but still + # respects a minimum re-trigger interval to prevent caption-event + # spam (multiple caption snapshots of the same utterance). + minNameRetriggerSeconds = 10 botNameLower = self.config.botName.lower() transcriptLower = transcriptText.lower() - if botNameLower in transcriptLower: - logger.info(f"Trigger: Bot name '{self.config.botName}' detected in transcript (overrides cooldown): '{transcriptText[:60]}...'") - return True - # Also check first name and phonetically similar words (speech recognition artifacts) - botFirstName = botNameLower.split()[0] if " " in botNameLower else botNameLower - if len(botFirstName) >= 3: - for word in transcriptLower.split(): - # Strip punctuation from word - cleanWord = word.strip(".,!?:;\"'()[]") - if not cleanWord or len(cleanWord) < 3: - continue - # Exact first name match - if cleanWord == botFirstName: - logger.info(f"Trigger: Bot first name '{botFirstName}' detected: '{transcriptText[:60]}...'") - return True - # Simple phonetic similarity: same first letter, similar length, high character overlap - if cleanWord[0] == botFirstName[0] and abs(len(cleanWord) - len(botFirstName)) <= 2: - common = sum(1 for c in set(botFirstName) if c in cleanWord) - similarity = common / max(len(set(botFirstName)), len(set(cleanWord))) - if similarity >= 0.6: - logger.info(f"Trigger: Phonetically similar to '{botFirstName}' -> '{cleanWord}' (sim={similarity:.2f}): '{transcriptText[:60]}...'") - return True + nameDetected = False + if botNameLower in transcriptLower: + nameDetected = True + else: + botFirstName = botNameLower.split()[0] if " " in botNameLower else botNameLower + if len(botFirstName) >= 3: + for word in transcriptLower.split(): + cleanWord = word.strip(".,!?:;\"'()[]") + if not cleanWord or len(cleanWord) < 3: + continue + if cleanWord == botFirstName: + nameDetected = True + break + if cleanWord[0] == botFirstName[0] and abs(len(cleanWord) - len(botFirstName)) <= 2: + common = sum(1 for c in set(botFirstName) if c in cleanWord) + similarity = common / max(len(set(botFirstName)), len(set(cleanWord))) + if similarity >= 0.6: + nameDetected = True + break + + if nameDetected: + if timeSinceLastCall < minNameRetriggerSeconds: + logger.debug( + f"Trigger: Bot name detected but within re-trigger cooldown " + f"({timeSinceLastCall:.1f}s < {minNameRetriggerSeconds}s)" + ) + return False + logger.info(f"Trigger: Bot name detected in transcript: '{transcriptText[:60]}...'") + return True # Cooldown check (only for non-name triggers) if timeSinceLastCall < self.config.triggerCooldownSeconds: