在使用AI智能体时,我们遇到很多已经运行结束,就是还不知道的情况下,我们可以设置一段脚本,让运行完声音一直提醒我们,让第一时间我们知道,才写的这段脚本,很完美,你们尝试一下。
这段代码实现了一个基于音频相似度检测的自动复读系统。
简单来说,它的作用是:监听环境声音,当检测到特定的"触发音"时,自动播放一段指定的 MP3 音频(复读)。
以下是代码的详细功能模块总结:
🎯 核心用途
这是一个声音触发器。它通常用于自动化场景,例如:
游戏辅助:听到游戏内的特定提示音(如"检查员来了"),自动播放语音提醒或执行操作。
语音交互:听到特定的唤醒词或指令后,自动播放回复语音。
自动化监控:监控特定频率或类型的声音事件。
⚙️ 功能模块详解
- 模板录制与学习
功能:程序启动后,首先会进入"录制模式"。
实现:利用 sounddevice 录制一段用户发出的声音作为"模板"。
目的:确立"我要找的声音"是什么样子的,作为后续比对的基准。 - 实时监听与特征比对
功能:在后台循环监听麦克风输入。
核心算法:
滑动窗口:在录音流中截取片段。
相关系数:使用 np.corrcoef 计算录音片段与模板声音的皮尔逊相关系数。
阈值判定:如果相似度超过设定的 THRESHOLD (代码中设为 0.45),则判定为匹配成功。 - 自动复读
功能:一旦检测到匹配的声音,触发播放线程。
实现:使用 pygame.mixer 播放指定的本地 MP3 文件(代码路径指向 D:\trae\检查员提示音_Freesound.mp3)。
逻辑:播放 REPEAT_COUNT (10次),且在播放期间暂停新的检测,防止重复触发。
🔑 关键技术点
音频处理库:使用 sounddevice 进行低延迟的音频流录制,numpy 进行信号处理和数学计算。
多线程:
主线程保持程序运行。
监听线程负责后台检测。
播放线程负责播放音频,避免阻塞监听。
抗噪与优化:
设置了音量阈值 (volume < 0.05) 忽略静音片段,节省计算资源。
滑动步长设为 1000,加快比对速度。
📝 总结
这就好比一个"声音回声筒":你先教它认一个声音,然后它一直竖着耳朵听,一旦在环境里听到这个声音,它就会大声把另一个预设好的 MP3 文件播放出来。
python
# -*- coding: utf-8 -*-
import warnings
warnings.filterwarnings("ignore")
import os
import time
import threading
import pygame
import numpy as np
import sounddevice as sd
# ================= 配置区域 =================
TEMPLATE_RECORD_SECONDS = 1
REPEAT_COUNT = 10
# 阈值设为 0.45 (刚才测到了 0.53,所以 0.45 很安全)
THRESHOLD = 0.45
# ===========================================
is_repeating = False
target_template = None
def record_template():
global target_template
print("\n" + "="*50)
print("🎤 准备录制模板")
print("请按 Enter 键,然后播放提示音...")
input()
SAMPLE_RATE = 44100
print("🔴 正在录制... (发出你要识别的声音)")
audio = sd.rec(int(TEMPLATE_RECORD_SECONDS * SAMPLE_RATE),
samplerate=SAMPLE_RATE, channels=1, dtype='float32')
sd.wait()
target_template = audio[:, 0]
print(f"✅ 模板录制成功!长度: {len(target_template)} 个采样点")
print("="*50 + "\n")
time.sleep(1)
def play_task():
global is_repeating
try:
print(f"\n🔊 开始复读任务...")
pygame.mixer.init(frequency=44100, size=-16, channels=1)
pygame.mixer.music.load(r"D:\trae\检查员提示音_Freesound.mp3")
for i in range(REPEAT_COUNT):
print(f" 播放第 {i+1}/{REPEAT_COUNT} 次...")
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
time.sleep(3)
print(" ✅ 复读完成")
except Exception as e:
print(f" ❌ 播放错误: {e}")
finally:
pygame.mixer.quit()
is_repeating = False
def listen_loop():
global is_repeating
record_template()
template_len = len(target_template)
print(f"👂 正在监听... (阈值: {THRESHOLD})")
while True:
if is_repeating:
time.sleep(0.5)
continue
try:
RECORD_SECONDS = 2
SAMPLE_RATE = 44100
audio = sd.rec(int(RECORD_SECONDS * SAMPLE_RATE),
samplerate=SAMPLE_RATE, channels=1, dtype='float32')
sd.wait()
recording = audio[:, 0]
# 音量检测
volume = np.max(np.abs(recording))
if volume < 0.05:
continue
# --- 核心修改:滑动窗口比对 ---
max_similarity = 0.0
# 如果录音比模板长,我们就滑动查找
if len(recording) > template_len:
# 滑动步长设为 1000,加快计算速度
step = 1000
for i in range(0, len(recording) - template_len, step):
# 截取一段
rec_part = recording[i : i + template_len]
# 计算相关系数
corr = np.corrcoef(rec_part, target_template)
sim = abs(corr[0, 1])
# 记录最高相似度
if sim > max_similarity:
max_similarity = sim
else:
# 如果录音太短,直接比对(补零或截断)
min_len = min(len(recording), template_len)
corr = np.corrcoef(recording[:min_len], target_template[:min_len])
max_similarity = abs(corr[0, 1])
print(f"🔊 音量: {volume:.2f} | 最高相似度: {max_similarity:.3f}")
if max_similarity > THRESHOLD:
print(f"\n⚡ 发现匹配声音!(相似度 {max_similarity:.3f}) 触发复读!")
is_repeating = True
t = threading.Thread(target=play_task)
t.daemon = True
t.start()
except Exception as e:
print(f" 🎤 错误: {e}")
time.sleep(1)
if __name__ == "__main__":
print("🚀 程序启动...")
if not os.path.exists(r"D:\trae\检查员提示音_Freesound.mp3"):
print("❌ MP3文件不存在")
exit()
listener_thread = threading.Thread(target=listen_loop, daemon=True)
listener_thread.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\n👋 退出。")

补充
python
# -*- coding: utf-8 -*-
import warnings
warnings.filterwarnings("ignore")
import os
import time
import threading
import pygame
import numpy as np
import sounddevice as sd
# ================= 配置区域 =================
TEMPLATE_RECORD_SECONDS = 1
REPEAT_COUNT = 10
# 阈值设为 0.45 (刚才测到了 0.53,所以 0.45 很安全)
THRESHOLD = 0.45
# ===========================================
is_repeating = False
target_template = None
def record_template():
global target_template
print("\n" + "="*50)
print("🎤 准备录制模板")
print("请按 Enter 键,然后播放提示音...")
input()
SAMPLE_RATE = 44100
print("🔴 正在录制... (发出你要识别的声音)")
audio = sd.rec(int(TEMPLATE_RECORD_SECONDS * SAMPLE_RATE),
samplerate=SAMPLE_RATE, channels=1, dtype='float32')
sd.wait()
target_template = audio[:, 0]
print(f"✅ 模板录制成功!长度: {len(target_template)} 个采样点")
print("="*50 + "\n")
time.sleep(1)
def play_task():
global is_repeating
try:
print(f"\n🔊 开始复读任务...")
pygame.mixer.init(frequency=44100, size=-16, channels=1)
pygame.mixer.music.load(r"D:\trae\检查员提示音_Freesound.mp3")
for i in range(REPEAT_COUNT):
print(f" 播放第 {i+1}/{REPEAT_COUNT} 次...")
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
time.sleep(3)
print(" ✅ 复读完成")
except Exception as e:
print(f" ❌ 播放错误: {e}")
finally:
pygame.mixer.quit()
is_repeating = False
def listen_loop():
global is_repeating
record_template()
template_len = len(target_template)
print(f"👂 正在监听... (阈值: {THRESHOLD})")
while True:
if is_repeating:
time.sleep(0.1)
continue
try:
RECORD_SECONDS = 2
SAMPLE_RATE = 44100
audio = sd.rec(int(RECORD_SECONDS * SAMPLE_RATE),
samplerate=SAMPLE_RATE, channels=1, dtype='float32')
sd.wait()
recording = audio[:, 0]
# 音量检测
volume = np.max(np.abs(recording))
if volume < 0.05:
continue
# --- 核心修改:滑动窗口比对 ---
max_similarity = 0.0
# 如果录音比模板长,我们就滑动查找
if len(recording) > template_len:
# 滑动步长设为 1000,加快计算速度
step = 100
for i in range(0, len(recording) - template_len, step):
# 截取一段
rec_part = recording[i : i + template_len]
# 计算相关系数
corr = np.corrcoef(rec_part, target_template)
sim = abs(corr[0, 1])
# 记录最高相似度
if sim > max_similarity:
max_similarity = sim
else:
# 如果录音太短,直接比对(补零或截断)
min_len = min(len(recording), template_len)
corr = np.corrcoef(recording[:min_len], target_template[:min_len])
max_similarity = abs(corr[0, 1])
print(f"🔊 音量: {volume:.2f} | 最高相似度: {max_similarity:.3f}")
if max_similarity > THRESHOLD:
print(f"\n⚡ 发现匹配声音!(相似度 {max_similarity:.3f}) 触发复读!")
is_repeating = True
t = threading.Thread(target=play_task)
t.daemon = True
t.start()
except Exception as e:
print(f" 🎤 错误: {e}")
time.sleep(1)
if __name__ == "__main__":
print("🚀 程序启动...")
if not os.path.exists(r"D:\trae\检查员提示音_Freesound.mp3"):
print("❌ MP3文件不存在")
exit()
listener_thread = threading.Thread(target=listen_loop, daemon=True)
listener_thread.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\n👋 退出。")