【語音智能管家】之語音喚醒(附演示視頻)


目錄

一.語音喚醒引擎(snowboy)

1.獲取源代碼並編譯

2.自定義自己的喚醒詞(喚醒詞:小貝)

3.測試

二、自定義響應

三、實現了智能語音音響--聽音樂

后續延伸


加群獲取學習資料QQ群:901381280

 

我設計的語音智能管家是部署在樹莓派上的,所以現在先列一下大概的硬件:

  • 樹莓派4b+ x1
  • 麥克風
  • usb聲卡
  • u任意一個支持樹莓派的音頻輸出設備(3.5mm孔的 或者一些藍牙設備)

 

usb聲卡

樹莓派4b+

 

備注:樹莓派上面那個是攝像頭(后面視頻監控和人臉識別會用到,所以就安上了)

 

ok,進入正題,開始干貨

 

一.語音喚醒引擎(snowboy)

這里我選擇使用開源的snowboy開源引擎(好處:免費,還可以自定義喚醒詞:比如我自定義的喚醒詞是:小貝)

snowboy 是一個開源的、輕量級語音喚醒引擎,可以通過它很輕松地創建屬於自己的類似“hey, Siri” 的喚醒詞。它的主要特性如下:

  • 高度可定制性。可自由創建和訓練屬於自己的喚醒詞
  • 始終傾聽。可離線使用,無需聯網,保護隱私。精確度高,低延遲
  • 輕量可嵌入。耗費資源非常低(單核 700MHz 樹莓派只占用 10% CPU)
  • 開源跨平台。開放源代碼,支持多種操作系統和硬件平台,可綁定多種編程語言

接下來開始如何使用snowboy以及怎么部署到樹莓派。

 

1.獲取源代碼並編譯

安裝依賴

樹莓派原生的音頻設備是不支持語音輸入的(無法錄音),需要在網上購買一支免驅動的USB音頻驅動(便攜式的和 U 盤差不多),一般插上即可直接使用。
建議安裝下 pulseaudio 軟件,減少音頻配置的步驟:

$ sudo apt-get install pulseaudio

安裝 sox 軟件測試錄音與播放功能:

$ sudo apt-get install sox

安裝完成后運行 sox -d -d 命令,對着麥克風說話,確認可以聽到自己的聲音。

安裝其他軟件依賴

安裝 PyAudio:$ sudo apt-get install python3-pyaudio
安裝 SWIG(>3.0.10):$ sudo apt-get install swig
安裝 ATLAS:$ sudo apt-get install libatlas-base-dev

編譯源代碼

獲取源代碼:

$ git clone https://github.com/Kitt-AI/snowboy.git

PS官方源代碼使用 Python3 測試有報錯,經測試需修改

snowboy/examples/Python3

目錄下的 snowboydecoder.py 文件。
將第 5 行代碼 from * import snowboydetect 改為 import snowboydetect 即可直接運行。


備注:網上很多教程是make之后再修改,這種情況是不成功的,因為make后會生成配置文件,你這時候改了不起效果,因此先修改,在執行下一步的make。


編譯 Python3 綁定:

$ cd snowboy/swig/Python3 && make

測試
進入官方示例目錄 snowboy/examples/Python3 並運行以下命令:

$ python3 demo.py resources/models/snowboy.umdl


( 命令中的 snowboy.umdl 文件即語音識別模型

然后對着麥克風清晰地講出snowboy,如果可以聽到“滴”的聲音,則安裝配置成功。命令行輸出如下:

2.自定義自己的喚醒詞(喚醒詞:小貝)

可將包含自定義喚醒詞的音頻文件上傳至 snowboy 官網https://snowboy.kitt.ai/dashboard(需要登錄),以訓練生成自己喜歡的語音模型
需要上傳的音頻文件數量為 3 個,wav 格式。我試過直接在線錄制,貌似有 Bug ,這里建議大家錄制好wav音頻上傳錄喚醒詞

 

訓練完成並測試通過后,即可下載 PMDL 后綴的模型文件了。

 

3.測試

將以下文件復制到自己的項目目錄下(snowboy/examples/Python3 目錄下的 demo.pysnowboydecoder.pysnowboydetect.py 文件以及 resources 目錄):

  • 在項目目錄下執行 
  • $ python3 demo.py  小貝.pmdl 

     

  • 並使用自己的喚醒詞進行測試

 

二、自定義響應

官方提供的示例 demo.py 文件的源代碼如下:

import snowboydecoder
import sys
import signal

interrupted = False

def signal_handler(signal, frame):
    global interrupted
    interrupted = True

def interrupt_callback():
    global interrupted
    return interrupted

if len(sys.argv) == 1:
    print("Error: need to specify model name")
    print("Usage: python demo.py your.model")
    sys.exit(-1)

model = sys.argv[1]

# capture SIGINT signal, e.g., Ctrl+C
signal.signal(signal.SIGINT, signal_handler)

detector = snowboydecoder.HotwordDetector(model, sensitivity=0.5)
print('Listening... Press Ctrl+C to exit')

# main loop
detector.start(detected_callback=snowboydecoder.play_audio_file,
               interrupt_check=interrupt_callback,
               sleep_time=0.03)

detector.terminate()

通過喚醒詞可以聽到ding的一聲,但是我想通過喚醒詞喚醒后,能夠進行回應。因此我自定義了回應操作,比如回應:哎,我在或者我來啦

在回調函數這里,我自定義了回調函數callbacks

# 修改回調函數可實現我們想要的功能
    detector.start(detected_callback=callbacks,  # 自定義回調函數
                   interrupt_check=interrupt_callback,
                   sleep_time=0.03)

callbacks:

# 回調函數,語音識別在這里實現,修改也是在這里
def callbacks():
    global detector
    time.sleep(0.2)
    your_text=['哎,我在','我來啦']
    a=random.randint(0,1)
    ############################
    #文字轉語音,並保存result.wav
    towav(your_text[a])
    print(your_text[a])
    #歡迎詞
    play("result.wav")

為了是通過語音來回復,所以這里我接入了百度AI的語音合成,通過文字轉語音的功能,將歡迎詞:哎,我在或者我來啦轉為音頻再播放出來。

下面是語音合成的代碼:

# coding=utf-8
import sys
import json

IS_PY3 = sys.version_info.major == 3
if IS_PY3:
    from urllib.request import urlopen
    from urllib.request import Request
    from urllib.error import URLError
    from urllib.parse import urlencode
    from urllib.parse import quote_plus
else:
    import urllib2
    from urllib import quote_plus
    from urllib2 import urlopen
    from urllib2 import Request
    from urllib2 import URLError
    from urllib import urlencode

API_KEY = '自己的API_KEY'
SECRET_KEY = '自己的SECRET_KEY '

TEXT = "你好,我在"

# 發音人選擇, 基礎音庫:0為度小美,1為度小宇,3為度逍遙,4為度丫丫,
# 精品音庫:5為度小嬌,103為度米朵,106為度博文,110為度小童,111為度小萌,默認為度小美
PER = 4
# 語速,取值0-15,默認為5中語速
SPD = 5
# 音調,取值0-15,默認為5中語調
PIT = 5
# 音量,取值0-9,默認為5中音量
VOL = 5
# 下載的文件格式, 3:mp3(default) 4: pcm-16k 5: pcm-8k 6. wav
AUE = 3

FORMATS = {3: "mp3", 4: "pcm", 5: "pcm", 6: "wav"}
FORMAT = FORMATS[AUE]

CUID = "123456PYTHON"

TTS_URL = 'http://tsn.baidu.com/text2audio'


class DemoError(Exception):
    pass


"""  TOKEN start """

TOKEN_URL = 'http://openapi.baidu.com/oauth/2.0/token'
SCOPE = 'audio_tts_post'  # 有此scope表示有tts能力,沒有請在網頁里勾選


def fetch_token():
    print("fetch token begin")
    params = {'grant_type': 'client_credentials',
              'client_id': API_KEY,
              'client_secret': SECRET_KEY}
    post_data = urlencode(params)
    if (IS_PY3):
        post_data = post_data.encode('utf-8')
    req = Request(TOKEN_URL, post_data)
    try:
        f = urlopen(req, timeout=5)
        result_str = f.read()
    except URLError as err:
        print('token http response http code : ' + str(err.code))
        result_str = err.read()
    if (IS_PY3):
        result_str = result_str.decode()

    print(result_str)
    result = json.loads(result_str)
    print(result)
    if ('access_token' in result.keys() and 'scope' in result.keys()):
        if not SCOPE in result['scope'].split(' '):
            raise DemoError('scope is not correct')
        print('SUCCESS WITH TOKEN: %s ; EXPIRES IN SECONDS: %s' % (result['access_token'], result['expires_in']))
        return result['access_token']
    else:
        raise DemoError('MAYBE API_KEY or SECRET_KEY not correct: access_token or scope not found in token response')


"""  TOKEN end """

if __name__ == '__main__':
    token = fetch_token()
    tex = quote_plus(TEXT)  # 此處TEXT需要兩次urlencode
    print(tex)
    params = {'tok': token, 'tex': tex, 'per': PER, 'spd': SPD, 'pit': PIT, 'vol': VOL, 'aue': AUE, 'cuid': CUID,
              'lan': 'zh', 'ctp': 1}  # lan ctp 固定參數

    data = urlencode(params)
    print('test on Web Browser' + TTS_URL + '?' + data)

    req = Request(TTS_URL, data.encode('utf-8'))
    has_error = False
    try:
        f = urlopen(req)
        result_str = f.read()

        headers = dict((name.lower(), value) for name, value in f.headers.items())

        has_error = ('content-type' not in headers.keys() or headers['content-type'].find('audio/') < 0)
    except  URLError as err:
        print('asr http response http code : ' + str(err.code))
        result_str = err.read()
        has_error = True

    save_file = "error.txt" if has_error else 'result.' + FORMAT
    with open(save_file, 'wb') as of:
        of.write(result_str)

    if has_error:
        if (IS_PY3):
            result_str = str(result_str, 'utf-8')
        print("tts api  error:" + result_str)

    print("result saved as :" + save_file)

 

API_KEY = '自己的API_KEY'
SECRET_KEY = '自己的SECRET_KEY '

大家可以去百度AI平台免費申請,這里是百度AI的官方案例,可以直接使用。

如果大家不懂怎么申請的可以在下面評論)因為比較簡單,所以就不詳細介紹了。

 

合成之后生成一個result.wav文件,通過play函數進行播放。

play("result.wav")

play

###播放歡迎詞
def play(fname):
    ding_wav = wave.open(fname, 'rb')
    ding_data = ding_wav.readframes(ding_wav.getnframes())
    #with no_alsa_error():
    audio = PyAudio()
    stream_out = audio.open(
        format=audio.get_format_from_width(ding_wav.getsampwidth()),
        channels=ding_wav.getnchannels(),
        rate=ding_wav.getframerate(), input=False, output=True)
    stream_out.start_stream()
    stream_out.write(ding_data)
    time.sleep(0.2)
    stream_out.stop_stream()
    stream_out.close()
    audio.terminate()

 

這里的play函數大家可以留意一下,網上很多都無法使用,尤其是在樹莓派上了,這個代碼是本人親測可用,可以在樹莓派上直接播放聲音。

 

這樣我通過喚醒詞喚醒后,系統回復聲音(哎,我在或者我來啦

 

三、實現了智能語音音響--聽音樂
 

這里我已經實現了第一個功能【休閑】-聽音樂,智能音響

先給出演示視頻

演示視頻

語音智能系統-語音音響播放音樂

 

 

下次更新實現了智能語音音響--聽音樂的具體實現代碼和操作。本期就更新語音喚醒。

 

 

后續延伸

修改回調函數可以完成更多工作

 

這里是語音智能管家的規划功能,后面會繼續進行開發,更新記錄這個過程。

 

歡迎在下方評論。

 

在平時的科研和任務不多的時候,利用空閑的時間去編寫這個系統(因為空閑時間的樂趣就是做自己喜歡的事情,嘻嘻嘻,正好可以用來編寫這個系統)。

每次完成一個小進度的時候都會在公眾號和博客進行更新,記錄一下這個過程(畢竟自己動手完成一件事,還是很有成就感的)

希望大家也能在這個過程中可以學習到一些知識(大牛就忽略了吧,哈哈哈)

 

同時在這個過程中,大家有更好的建議也可以進行評論交流,讓這個系統更加完善。

 

                               【加群獲取學習資料QQ群:901381280

                                         【各種爬蟲源碼獲取方式

                                      識別文末二維碼,回復:爬蟲源碼

                        歡迎關注公眾號:Python爬蟲數據分析挖掘,方便及時閱讀最新文章

                             回復【開源源碼】免費獲取更多開源項目源碼;

                 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM