閒來無事,想起吃灰的樹莓派拿來做點什麼,貌似去年還專門買了個麥克風還沒怎麼用過。正好拿來做個類似小愛智慧語音助手的小林同學,現在智慧助手不接入大模型都不好意思說出來,當然小林同學沒有小愛同學的米家生態功能,後續如果加入多模態圖片識別貌似會更有點意思。
智慧助手涉及到的技術主要由:語音離線喚醒、錄音、語音識別(Speech-to-Text)、TTS、大模型,在現在這個時候整合這些技術做出個Demo的玩具並沒有多少難度。做了些技術調研還有驗證馬上就動手。下面簡單介紹硬體配置、主要程式碼實現;
樹莓派配置
alsamixer 配置 聲音大小等
aplay -l 檢視裝置情況
修改/etc/asound.conf或.asoundrc
vim .asoundrc
配置預設裝置
defaults.pcm.card 1 預設播放裝置
defaults.ctl.card 0 預設控制裝置
sudo /etc/init.d/alsa-utils restart
錄音 arecord -D hw:2,0 -t wav -c 1 -r 44100 -f S16_LE test.wav
-D hw:2,0 第二個音效卡的第一個裝置 -f S16_LE 指定了取樣格式為 16 位小端 -r 44100 設定了取樣率為 44100Hz -c 1 表示使用單聲道錄音
播放 aplay test.wav
語音喚醒—》錄音—》語音識別—》大模型—》TTS—》語音播報
語音喚醒
選了開源的Snowboy作為語音喚醒的實現,Snowboy非常適合在樹莓派上使用,非常輕量反應很靈敏。它的喚醒為離線實現並不依賴網路,還可以定製個人喚醒詞,如小林同學、Alexa、小愛同學等你想要的任何喚醒詞,使用也非常簡單。
錄製喚醒詞:https://snowboy.hahack.com
from snowboy import snowboydecoder
def hello_callback():
communicate = edge_tts.Communicate("你好啊",voice)
asyncio.run(communicate.save("./hello.wav"))
playsound("hello.wav")
detector.start(detected_callback=hello_callback,
interrupt_check=interrupt_callback,
sleep_time=0.03)
detector.terminate()
啟動程式 python main.py snowboy/linx.pmdl
語音錄製
最初選了Sounddevice作為錄製語音的框架,在錄製固定長度音訊是並沒有問題生成音訊檔案沒什麼雜音,但在加了閾值聽到聲音才開始錄製沒有聲音停止錄製的邏輯之後生成音訊有嘟嘟嘟嘟的雜音,搞了一兩個小時沒有解決換了技術方案。
其實AI助手也不需要聽到聲音開始錄製,只需要在喚醒時錄製即可。最終選擇了SpeechRecognition作為技術方案,錄製效果也不錯。
import speech_recognition as sr
import baidu
import json
def rec(rate=16000):
try:
r = sr.Recognizer()
file = "recording.wav"
with sr.Microphone(sample_rate=rate) as source:
audio = r.listen(source,timeout=12,phrase_time_limit=6)
with open(file, "wb") as f:
f.write(audio.get_wav_data())
text = json.loads(baidu.tts(file))
if(text is not None):
return text.get("result")[0]
else:
return None
except sr.WaitTimeoutError:
print("錄音超時,沒有檢測到聲音。")
except Exception as e:
print(f"發生錯誤: {e}")
語音識別
想著搞離線語音識別最近有一個OpenAi開源的神器Whisper Live不僅可以對影片進行轉為文字還可以進行實時影片轉錄,如生成影片字幕。在筆記本上試了下效果的確不錯,但由於算力硬體原因,在樹莓派上效果並不理想一個幾秒語音轉錄就要幾十秒。沒辦法最終換成了百度的線上語音識別。
TTS(Text To Speech)
文字轉語音選擇了微軟開源的Edge-TTS效果還不錯,在樹莓派上體驗效能還算能接受。
import edge_tts
def generater_wav(msg:str):
communicate = edge_tts.Communicate(msg,voice)
asyncio.run(communicate.save("./temp.wav"))
playsound("temp.wav")