記一次講故事機器人的開發-我有故事,讓機器人來讀

Al發表於2020-10-17

記一次講故事機器人的開發-我有故事,讓機器人來讀

最近工作較忙,回家閒下來只想閉目休息,一分鐘螢幕都不想再看,然而我又想追更之前看的小說,於是,需求來了——我需要一個給我講故事的機器人!

瀏覽器或者閱讀器App裡其實也有朗讀功能,但是比較僵硬,總是將引人入勝的情節念成流水賬,分分鐘讓人棄坑,所以我考慮自己使用爬蟲定時下載更新的章節,而後將文字合成儲存到音訊檔案,這樣不僅可以選擇一個靠譜的語音合成工具來處理文字,而且儲存下來的音訊還能反覆收聽,一舉兩得。

文字整合容易,但是如何將其快速轉換成音訊呢?難道要自己訓練模型“煉丹”解決?no no ,費力不討好,畢竟自己手頭這點演算法知識非常淺顯,而且硬體條件也不允許,本著“能用就行”的原則,我決定先使用市面上開放平臺的產品來解決。經過對比,發現有道智雲的語音合成還不錯(此處可體驗),決定使用有道智雲的語音合成API進行開發。

效果先睹為快:

我拿來朱自清先生的《荷塘月色》的其中兩段作為實驗素材,開發了簡單的demo,走通了從載入文字到生成音訊檔案的邏輯,下面我來詳細介紹開發過程。

需要語音合成的文字:

待翻譯的文字

合成結果(第一段):


對應音訊連結為:

http://music.xf1433.com/up/view.php/14f5c51944701491ebeb73317fb29e16.mp3

合成結果(第二段):


對應音訊連結為:

http://music.xf1433.com/up/view.php/3f10780ede6ca4abcc376b6e316ab55c.mp3

呼叫API介面的準備工作

首先,是需要在有道智雲的個人頁面上建立例項、建立應用、繫結應用和例項,獲取到應用的id和金鑰。具體個人註冊的過程和應用建立過程詳見文章分享一次批量檔案翻譯的開發過程

建立例項

開發過程詳細介紹

下面介紹具體的程式碼開發過程。

首先根據文件分析有道智雲的API輸入輸出規範。語音合成API呼叫十分簡單,該API採用https方式通訊,所需引數如下表:

欄位名 型別 含義 必填 備註
q text 待合成音訊檔案的文字字串 True 比如:您好
langType text 合成文字的語言型別 True 支援語言
appKey text 應用 ID True 可在 應用管理 檢視
salt text UUID True UUID
sign text True MD5(應用ID+q+salt+應用金鑰)
voice text 翻譯結果發音選擇,0為女聲,1為男聲,預設為女聲 false 0
format text 目標音訊格式,支援mp3 false mp3
speed text 合成音訊的語速 false 比如:"1"為正常速度
volume text 合成音訊的音量 false 正常為"1.00",最大為"5.00",最小為"0.50"

簡單概括,組織好自己的語言(utf-8編碼文字),輔以簽名等必要引數,並告訴API所需要的音訊特徵,即可得到一份令人滿意的合成音訊。

介面輸出中,如果合成成功,正常返回為二進位制語音檔案,具體header資訊 Content-type: audio/mp3,如果合成出現錯誤,則會返回json結果,具體header資訊為:Content-type: application/json,可據此判斷執行情況。

Demo開發:

這個demo使用python3開發,包括maindow.py,synthesis.py,synthesistool.py三個檔案,分別為demo的介面、介面邏輯處理和語音合成介面呼叫工具封裝。

  1. 介面部分:

    介面部分程式碼如下,比較簡單。

    root=tk.Tk()
    root.title("youdao speech synthesis test")
    frm = tk.Frame(root)
    frm.grid(padx='50', pady='50')
    # 檔案選取按鈕
    btn_get_file = tk.Button(frm, text='選擇待合成檔案', command=get_files)
    btn_get_file.grid(row=0, column=0, ipadx='3', ipady='3', padx='10', pady='20')
    # 所選檔案列表展示框
    text1 = tk.Text(frm, width='40', height='10')
    text1.grid(row=0, column=1)
    # 啟動按鈕
    btn_sure=tk.Button(frm,text="合成",command=synthesis_files)
    btn_sure.grid(row=1,column=1)
    

    其中啟動按鈕btn_sure的繫結事件synthesis_files()來收集帶所有的文字檔案,啟動合成,並列印執行結果:

    def synthesis_files():
        if syn_m.file_paths:
            message=syn_m.get_synthesis_result()
            tk.messagebox.showinfo("提示", message)
            os.system('start' + '.\\result')
        else :
            tk.messagebox.showinfo("提示","無檔案")
    
  2. synthesis.py

    這裡主要是配合介面實現一些文字讀取和請求介面處理返回值的邏輯。首先定義一個Synthesis_model

    class Synthesis_model():
        def __init__(self,file_paths,result_root_path,syn_type):
            self.file_paths=file_paths				# 待合成檔案路徑
            self.result_root_path=result_root_path  # 結果路徑
            self.syn_type=syn_type                  # 合成型別
    

    get_synthesis_result()方法實現了批量讀取檔案並呼叫合成方法、處理返回資訊的邏輯:

        def get_synthesis_result(self):
            syn_result=""
            for file_path in self.file_paths:
                # 讀取檔案
                file_name=os.path.basename(file_path).split('.')[0]
                file_content=open(file_path,encoding='utf-8').read()
                # 呼叫合成方法
                result=self.synthesis_use_netease(file_name,file_content)
                # 處理返回訊息
                if result=="1":
                    syn_result=syn_result+file_path+" ok !\n"
                else:
                    syn_result=syn_result+file_path+result
            return syn_result
    

    單獨定義了方法synthesis_use_netease()具體實現呼叫API的方法,這樣增加了demo的擴充套件性,實現了一種合成模組可插拔的鬆耦合形式:

    def synthesis_use_netease(self,file_name,text):
        result=connect(text,'zh-CHS')
        print(result)
        if result.headers['Content-Type']=="audio/mp3":
            millis = int(round(time.time() * 1000))
            filePath = "./result/" + file_name+"-"+str(millis) + ".mp3"
            fo = open(filePath, 'wb')
            fo.write(result.content)
            fo.close()
            return "1"
        else:
            return "error:"+result.content
    
  3. synthesistool.py
    1. synthesistool.py中是和請求有道智雲API直接相關的一些方法,最核心的是connect()方法,整合了API所要求的各個引數,並呼叫執行請求的方法do_request(),並返回API處理結果。

      def connect(text,lang_type):
          q = text
      
          data = {}
          data['langType'] = lang_type
          salt = str(uuid.uuid1())
          signStr = APP_KEY + q + salt + APP_SECRET
          sign = encrypt(signStr)
          data['appKey'] = APP_KEY
          data['q'] = q
          data['salt'] = salt
          data['sign'] = sign
      
          response = do_request(data)
          return response
      

    需要體驗一下的小夥伴,請下載我的程式碼自行嘗試或去官網體驗 : P。專案地址:https://github.com/LemonQH/SpeechSynthesis

    特別提示:
    1、執行demo時,需要替換synthesistool.py模組中的 APP_KEY 、 APP_SECRET為你自己生成的 APP_KEY、APP_SECRET哦
    2、該工程預設存放結果存在./result 資料夾下,你需要手動在專案路徑下建立該目錄。或者修改為任意你想存放的位置

總結

以上就是我的開發過程,有道智雲的語音合成API文件清晰,呼叫過程全程無坑,開發體驗和合成效果都令人感到舒適。

我有故事,我把它交給機器人來講,閉目養神不枯燥,真是一件美事!

相關文章