記一次智慧語音軟體的開發-終於為孩子找到了個靠譜的口語老師

Al發表於2020-11-27

記一次智慧語音軟體的開發-終於為孩子找到了個靠譜的口語老師

“再窮不能窮教育,再苦不能苦孩子”,作為娃的爸媽,不僅僅要努力工作保證物質支援,更要關注娃的學習狀況,而且時刻都怕娃“輸在了起跑線上”,可是,現在孩子們的起跑線也太多了點,英語、各種藝術特長,甚至跳繩,忙的不亦樂乎。然而家長也不是全才啊,這不,我的姐姐最近就開始發愁女兒的英語口語問題了,自己發音不準確,報班又不知道哪家靠譜,眼看著孩子就要落後於小夥伴了,瞭解到這個情況後,我拿出英語課本,想到自己每次都是60飄過的英語成績,又放了回去,拿起了我的武器——程式碼。

近些年自然語言處理已經成熟地應用在很多領域,智慧語音測評的使用成本早已是大眾所能承受。根據給娃糾正讀音的需求,我最終選擇呼叫靠譜的大廠,有道智雲的API來開發個簡易語音評測程式,或者稱之為——智慧口語老師!

呼叫API介面的準備工作

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

應用例項

開發過程詳細介紹

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

首先研究官方文件給出的API輸入輸出規範。該API採用https方式通訊,簡單來說,就是將預先錄製好的聲音檔案編碼處理,簽名後提交給API,解析API返回的json即可得到評分結果。

介面地址:

https介面: https://openapi.youdao.com/iseap

API輸入所需引數如下表:

欄位名 型別 含義 必填 備註
q text 要評測的音訊檔案的Base64編碼字串 True 必須是Base64編碼
text text 要評測的音訊檔案對應的文字 True have a good day
langType text 源語言 True 支援語言
appKey text 應用ID True 可在 應用管理 檢視
salt text UUID True UUID
curtime text 時間戳(秒) True TimeStamp
sign text 簽名,通過sha256(應用ID+input+salt+curtime+應用金鑰)生成;input的生成規則見表下的備註 True sha256(應用ID+input+salt+curtime+應用金鑰)
signType text 簽名型別 True v2
format text 語音檔案的格式,wav true wav
rate text 取樣率,推薦 16000 採用率 true 16000
channel text 聲道數, 僅支援單聲道,請填寫固定值1 true 1
type text 上傳型別, 僅支援base64上傳,請填寫固定值1 true 1

其中籤名sign生成方法如下:
signType=v2; sign=sha256(應用ID+input+salt+curtime+應用金鑰)。
這裡需要注意的是input的計算方式為:input=q前10個字元 + q長度 + q後10個字元(當q長度大於20)或 input=q字串(當q長度小於等於20)。

介面的輸出引數如下:

欄位 含義
errorCode 識別結果錯誤碼,一定存在。 詳細資訊可見 錯誤程式碼列表
refText 請求的文字
start 音訊中句子開始時間,單位是秒
end 音訊中句子結束時間,單位是秒
integrity 句子完整度得分
fluency 句子流利度得分
pronunciation 句子準確度得分
speed 語速,單詞/分鐘
overall 句子綜合評分
words 單詞評分陣列
-word 單詞
-start 單詞開始時間,單位是秒
-end 單詞結束時間,單位是秒
-pronunciation 單詞準確度得分
-phonemes 音標陣列
--phoneme 音標
--start 音標開始時間,單位是秒
--end 音標結束時間,單位是秒
--judge 判斷音素是否錯誤,true為發音正確,false為發音錯誤,同時calibration給出提示
--calibration 如果發音錯誤,提示使用者該發音像什麼
--prominence 重音程度,分數越高,當前音標越可能是重音,分數在[0 100]
--stress_ref 母音重音參考/標準答案,如果為true,說明參考答案認為該母音應該發重音,子音時無意義
--stress_detect 在一個單詞中,使用者該音標發音為重音

Demo開發:

這個demo使用python3開發,包括maindow.py,audioandprocess.py,isebynetease.py 三個檔案,分別為demo的介面、錄音以及其他邏輯處理和智慧語音評測介面呼叫方法的封裝。

  1. 介面部分:

    UI 部分大體分為三部分,文章處理區域、錄音區域和評分展示區域。

    介面

    其佈局程式碼如下:

    root=tk.Tk()
    root.title("youdao ise test")
    frm = tk.Frame(root)
    frm.grid(padx='50', pady='50')
    
    # 選取文章
    btn_get_file_path=tk.Button(frm,text='選擇課文 :',command=get_file)
    btn_get_file_path.grid(row=0,column=0)
    
    text1=tk.Text(frm,width='70', height='2')
    text1.grid(row=0,column=1)
    
    # 文章內容展示
    text2=tk.Text(frm,width='70', height='5')
    text2.grid(row=1,column=1)
    
    # 開始和停止錄音
    btn_start_rec=tk.Button(frm,text='錄音',command=start_rec,width=10)
    btn_start_rec.grid(row=2,column=0)
    
    lb_Status = tk.Label(frm, text='Ready', anchor='w', fg='green')
    lb_Status.grid(row=2,column=1)
    
    btn_stop_rec=tk.Button(frm,text="結束錄音",command=stop_rec)
    btn_stop_rec.grid(row=2,column=2)
    
    # 打分按鈕和結果展示
    btn_score=tk.Button(frm,text="評分",command=start_score,width=10)
    btn_score.grid(row=3,column=0)
    
    text3=tk.Text(frm,width='70', height='10')
    text3.grid(row=3,column=1)
    
    root.mainloop()
    

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

    def start_score():
        result=au_model.get_score(file_dict)
        for r in result:
            text3.insert(tk.END,r)
    
  2. audioandprocess.py

    這裡主要實現了檔案處理、錄音和處理介面返回的功能。首先定義一個Audio_model

    class Audio_model():
        def __init__(self, audio_path,is_recording):
            self.current_file=''				# 當前錄音對應的原文路徑
            self.is_recording=is_recording		# 錄音狀態標識
            self.audio_chunk_size=1600			# 以下均為錄音必要引數
            self.audio_channels=1
            self.audio_format=pyaudio.paInt16
            self.audio_rate=16000
    

    record_and_save()方法進行錄音並儲存到專案的record路徑中,錄音檔名與原文的檔名相同,便於對應。

        def record_and_save(self):
            self.is_recording = True
            file_name=self.get_file_name(self.current_file)
            self.audio_file_name='./record/'+file_name+'.wav'
            threading.Thread(target=self.record,args=(self.audio_file_name,)).start()
    

    get_score()方法實現了呼叫isebynetease.py中封裝的工具並解析返回值的功能:

        def get_score(self,dict):
            result=[]
            #self.is_recording=False
            for path in dict:
                file_content=self.get_content(path)
                file_name=self.get_file_name(path)
                audio_path='./record/'+file_name+'.wav'
                print(file_content,audio_path)
                score_result=connect(audio_path,file_content)
                #處理結果,新增進結果集
                result.append( score_result)
            return result
    
  3. isebynetease.py

    isebynetease.py中是和請求有道智雲API直接相關的一些方法,最核心的是connect()方法,整合了API所要求的各個引數,並呼叫執行請求的方法do_request(),而後根據UI的展示需求,處理API的返回結果並拼接字串。

    def connect(audio_file_path,audio_text):
        recordname=audio_file_path.split("/")[-1]
        audio_file_path = audio_file_path
        lang_type = 'en' # 當前僅支援英文
        extension = audio_file_path[audio_file_path.rindex('.')+1:]
        if extension != 'wav':
            print('不支援的音訊型別')
            sys.exit(1)
        wav_info = wave.open(audio_file_path, 'rb')
        sample_rate = wav_info.getframerate()
        nchannels = wav_info.getnchannels()
        wav_info.close()
        with open(audio_file_path, 'rb') as file_wav:
            q = base64.b64encode(file_wav.read()).decode('utf-8')
    
        data = {}
        data['text'] = audio_text
        curtime = str(int(time.time()))
        data['curtime'] = curtime
        salt = str(uuid.uuid1())
        signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET
        sign = encrypt(signStr)
        data['appKey'] = APP_KEY
        data['q'] = q
        data['salt'] = salt
        data['sign'] = sign
        data['signType'] = "v2"
        data['langType'] = lang_type
        data['rate'] = sample_rate
        data['format'] = 'wav'
        data['channel'] = nchannels
        data['type'] = 1
    
        # 處理返回值
        response = do_request(data)
        j = json.loads(str(response.content, encoding="utf-8"))
        print(j)
        # 句子完整度
        contextIntegrity="句子完整度:"+str( round(j["integrity"], 2))+"  "
        pronunciation="發音準確度:"+str(round(j["pronunciation"],2))+"  "
        fluency="流利度:"+str(round(j["fluency"],2))+"  "
        speed="語速:" +str(round(j["speed"],2))+" "
        recordAndResult=recordname+" "+contextIntegrity+pronunciation+fluency+speed+"\n"
       
        return recordAndResult
    

效果展示

展示一下本人純正的”chinenglish“ 錄音後程式的執行情況(得分多少不重要,重要的是它客觀的評價方式 :P )

首先介紹一下操作方法:

1)點選“選擇文章”,選擇需要評測的文章;

2)點選“錄音”,“結束錄音”按鈕,進行語音錄製;

3)如需對多篇文章進行評測,重複1)、2)步驟即可

4)點選“評分“,進行智慧語音評測,並展示評分結果,同時將詳細評分結果,儲存在本程式碼路徑的result目錄下。

效果展示

介面部分:展示了 句子完整度、發音準確度的、流利度的得分,以及語速:

文件部分:分別對每個語音進行了測評,並將返回的詳細結果以json的形式存在了result資料夾下。

輸出結果展示:

{
    ’integrity‘: 100,//句子完整度
    'refText’: "Are you ok? ",//待評測語音對應的文字
    'pronunciation': 67.108101,//句子發音準確度
    'start': 0.030000,//音訊開始時間,秒
    	'words': [{ //單詞資訊列表
		'pronunciation': 50.640327, //單詞準確度分數
		'start': 0.73, //單詞開始時間,秒
		'end': 0.76,//單詞結束時間,秒
		'word': 'Are', //單詞文字
		'phonemes': [{ //音標資訊列表
			'stress_ref': False, //母音重音參考(即標準重音),如果為true,說明參考答案認為該母音應該發重音,子音時無意義
			'pronunciation': 50.640331, //音標準確度評分
			'stress_detect': False,//在一個單詞中,使用者該音標發音不為重音
			'phoneme': 'ɝ', //音標名稱
			'start': 0.73,  //音標開始時間,秒
			'end': 0.76,    //音標結束時間,秒
			'judge': True,  //判斷音標是否錯誤,true為發音正確,false為發音錯誤,同時calibration給出提示
			'calibration': 'ɝ', //判斷音標是否錯誤,true為發音正確,false為發音錯誤,同時calibration給出提示
			'prominence': 1 //重音程度,當前音標越可能是重音,分數區間[0 100]
		}]
	}, {
		'pronunciation': 76.810608,
		'start': 0.77,
		'end': 1.08,
		'word': 'you',
		'phonemes': [{
			'stress_ref': False,
			'pronunciation': 79.084282,
			'stress_detect': False,
			'phoneme': 'j',
			'start': 0.77,
			'end': 0.86,
			'judge': True,
			'calibration': 'j',
			'prominence': 0.944885
		}, {
			'stress_ref': True,
			'pronunciation': 74.536934,
			'stress_detect': True,
			'phoneme': 'u',
			'start': 0.87,
			'end': 1.08,
			'judge': True,
			'calibration': 'u',
			'prominence': 1
		}]
	}, {
		'pronunciation': 66.129013,
		'start': 1.14,
		'end': 1.8,
		'word': 'ok',
		'phonemes': [{
			'stress_ref': True,
			'pronunciation': 69.046341,
			'stress_detect': True,
			'phoneme': 'o',
			'start': 1.14,
			'end': 1.27,
			'judge': True,
			'calibration': 'o',
			'prominence': 1
		}, {
			'stress_ref': False,
			'pronunciation': 65.357841,
			'stress_detect': False,
			'phoneme': 'k',
			'start': 1.28,
			'end': 1.42,
			'judge': True,
			'calibration': 'k',
			'prominence': 0.838557
		}, {
			'stress_ref': True,
			'pronunciation': 63.982838,
			'stress_detect': True,
			'phoneme': 'e',
			'start': 1.43,
			'end': 1.8,
			'judge': True,
			'calibration': 'e',
			'prominence': 0.956448
		}]
	}],
	'fluency': 83.554047, //句子流利度
	'overall': 83.885124,//句子綜合評分
	'errorCode': '0', //識別結果錯誤碼,一定存在
	'end': 1.8,//句子結束時間,秒
	'speed': 55.555557 // 句子語速(單詞/分鐘)
}

總結

有道智雲的智慧語音評測API文件清晰,呼叫過程全程無坑,開發體驗非常友好,評分結果客觀公正,很具有參考價值,以至於我都想和小侄女一起學習進步去了!

專案地址:https://github.com/LemonQH/BatchISEDemo

相關文章