1. 程式人生 > >【Python + Flask + Web錄音 + baidu-aip + 圖靈機器人 = 人機對話】

【Python + Flask + Web錄音 + baidu-aip + 圖靈機器人 = 人機對話】

安裝baidu-aip:pip install baidu-aip

百度雲網址:https://login.bce.baidu.com
百度語音合成文件:https://ai.baidu.com/docs#/TTS-Online-Python-SDK/top
百度語音識別文件:https://ai.baidu.com/docs#/ASR-Online-Python-SDK/top
百度自然語言處理基礎技術文件:https://ai.baidu.com/docs#/NLP-Python-SDK/6dfe1b04
Mac系統安裝ffmpeg文件:https://blog.csdn.net/stonenotes/article/details/68958332


圖靈機器人官網:http://www.tuling123.com/
圖靈機器人介面說明:https://www.kancloud.cn/turing/www-tuling123-com/718227

後端程式碼

# ⚠️這是在macOS系統上(版本10.14)寫的

# pip install baidu-aip

# 百度雲:https://login.bce.baidu.com
# 百度語音合成文件:https://ai.baidu.com/docs#/TTS-Online-Python-SDK/top
# 百度語音識別文件:https://ai.baidu.com/docs#/ASR-Online-Python-SDK/top
# 百度自然語言處理基礎技術文件:https://ai.baidu.com/docs#/NLP-Python-SDK/6dfe1b04 # Mac系統安裝ffmpeg文件:https://blog.csdn.net/stonenotes/article/details/68958332 # 圖靈機器人官網:http://www.tuling123.com/ # 圖靈機器人介面說明:https://www.kancloud.cn/turing/www-tuling123-com/718227 import os import time import uuid import requests import subprocess from
aip import AipSpeech, AipNlp # baidu-aip from flask import Flask, request, render_template, send_file, jsonify # =======================下面是百度語音合成/識別======================= class VoiceTextConversion(object): # 這3個私有屬性是本人的百度應用的appID等資訊 __APP_ID = '15225447' __API_KEY = 's5m43BMMEGGPaFGxeX3SsY7m' __SECRET_KEY = 'Lca9FEGpWNZW6yd8WWAHAyCyLovmi6rb' text_to_voice_error_info = {500: '不支援的輸入', 501: '輸入的引數不正確', 502: 'token驗證失敗', 503: '合成後端錯誤'} def __init__(self, app_id=None, api_key=None, secret_key=None, connect_timeout=None, socket_timeout=None, is_external_called=False): """ :param APP_ID: 請使用你自己的百度應用 :param API_KEY: 請使用你自己的百度應用 :param SECRET_KEY: 請使用你自己的百度應用 :param connectTimeout: 建立連線的超時時間(單位:毫秒,1000毫秒=1秒)預設60秒 :param socketTimeout: 通過開啟的連線傳輸資料的超時時間(單位:毫秒)預設60秒 :param is_external_called: 當前物件是否為其它應用呼叫 """ self.__is_external_called = is_external_called if requests.get('http://www.baidu.com').status_code is not 200: exit(self.__custom_print("沒網你玩個錘子啊!")) # 如果你有自己的百度語音應用,請使用你自己的百度語音應用,如果你沒有,請去註冊(免費): self.client = AipSpeech(app_id, api_key, secret_key) if app_id \ else AipSpeech(self.__APP_ID, self.__API_KEY, self.__SECRET_KEY) # 可設定連結/傳輸的超時時間: connect_timeout and self.client.setConnectionTimeoutInMillis(connect_timeout) socket_timeout and self.client.setSocketTimeoutInMillis(socket_timeout) def text_to_voice(self, text, filepath='語音檔案', lang='zh', ctp=1, per=3, pid=5, spd=5, vol=5): """ 文字 -> 語音 :param text: 要轉換的文字 :param filename: 儲存路徑,自動新增 .mp3 字尾 :param lang: 語言,預設中文 :param ctp: ? :param per: 發音人,0為女聲;1為男聲;3為情感合成-度逍遙;4為情感合成-度牙牙 :param pid: 音調,取值0-9,預設為5 中語速 :param spd: 語速,取值0-9,預設為5 中語速 :param vol: 音量,取值0-15,預設為5 中音量 """ voice_format = {'per': per, 'pid': pid, 'spd': spd, 'vol': vol} # 開始轉換: # 轉換成功時返回bytes語音資料;轉換失敗時返回錯誤資訊字典; result = self.client.synthesis(text, lang, ctp, voice_format) # 如果轉換成功,將儲存至磁碟: if isinstance(result, bytes): with open(f'{filepath}.mp3', 'wb') as f: f.write(result) self.__custom_print(f'合成語音成功:{filepath}', color=32, is_error=False) # 如果出現錯誤: else: err_code = result.get('err_no') err_info = self.text_to_voice_error_info[err_code] self.__custom_print(err_info) def voice_to_text(self, filepath=None, format='pcm', dev_pid=1536): """ 語音 -> 文字 使用前請安裝ffmpeg,用於將其它格式的語音檔案轉換為 .pcm 格式的語音檔案 :param filepath: 語音檔案路徑 :param format: 語音檔案格式(字尾),.pcm 或 .wav 或 .amr 不區分大小寫。推薦使用 .pcm 檔案 :param dev_pid: 語言,1536普通話(支援簡單的英文識別),1537普通話,1737英語,1637粵語,1837四川話,1936普通話遠場(距離識別) :return: """ # 如果輸入的檔案路徑有誤 if not os.path.isfile(filepath): return self.__custom_print('語音檔案路徑錯誤') # 將語音檔案轉換為 format 格式,這一步驟將呼叫系統命令ffmpeg並會生成新檔案,需要安裝該命令(詳見頂部:Mac系統安裝ffmpeg文件連結) cmd = f'ffmpeg -y -i {filepath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filepath}.{format}' # ffmpeg命令執行過程中輸出的資訊被儲存在stderr中 r = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE) # 命令執行成功,將會生成 format 格式的語音檔案 # 語音檔案生成的很慢,這個很奇怪的問題,先這麼解決吧: for i in range(999): time.sleep(0.1) if os.path.isfile(f'{filepath}.{format}'): break # 讀取轉換後的語言檔案: with open(f'{filepath}.{format}', 'rb') as fp: voice_content = fp.read() # 讀取後,刪除生成的 format 格式的檔案 os.remove(f'{filepath}.{format}') # 開始轉換: result = self.client.asr(voice_content, format, 16000, {'dev_pid': dev_pid}) # 如果轉換成功,直接輸出文字: if not result.get('err_no'): content = result.get('result')[0] if self.__is_external_called: return content self.__custom_print(content, 34, 1, is_error=False) # 如果轉換錯誤 else: err_code = result.get('err_no') self.__custom_print(f'錯誤程式碼:{err_code},詳見頂部:百度語音識別文件') def short_text_compare(self, text1, text2): """ 短文字相似度,詳見頂部:百度自然語言處理基礎技術文件 超過72% 極度相似 超過60% 比較相似 超過60% 可能相似 低於50% 不相似 越低越不相似 :param text1: 第一個短文字 :param text2: 第二個短文字 :return: 相似百分比 """ nlp_client = AipNlp(self.__APP_ID, self.__API_KEY, self.__SECRET_KEY) # 傳送短文字 result = nlp_client.simnet(text1, text2) # 獲取相似度 score = result.get('score') # 轉換百分比 score = f'{round(score * 100)}%' self.__custom_print(f'相似度:{score}', 35, 1, is_error=False) def __custom_print(self, data=None, color=31, font=0, is_error=True): """ 自定義列印資訊的字型及顏色 :param color: 列印顏色,預設紅色,32綠色,34藍色,35紫紅色,更多列印顏色請百度 :param font: 列印字型,預設正常字型,1為黑體(加粗) :param is_error: 是否列印錯誤資訊 """ if self.__is_external_called: return is_error and self.__custom_print('錯誤!!!', font=1, is_error=False) print_info = f'\033[{font};{color};0m{data}\033[0m' print(print_info) # ---------開始使用--------- # if __name__ == '__main__': # # 我們先例項化一個物件 # obj = VoiceTextConversion() # # # 文字 -> 語音 # text = '人活著就要有夢想,不然跟鹹魚又有什麼區別呢?' # obj.text_to_voice(text, filepath='語音檔案') # # # 語音 -> 文字 # obj.voice_to_text('語音檔案.mp3') # # # 短文字相似度 # text1, text2 = '你叫什麼名字', '你的名字叫什麼' # obj.short_text_compare(text1, text2) # =======================下面是圖靈機器人======================= class TuringRobot(object): # 玩轉圖靈機器人,詳見頂部:圖靈機器人介面說明 # 機器人標示,若果你有自己的機器人,請使用你自己的機器人 __API_KEY = '8c512c52ac324a3eb4c40639d43bd507' # 免費版 100次/天 # 圖靈機器人接入地址 URL = 'http://openapi.tuling123.com/openapi/api/v2' # 請求引數 POST_DATA = { "reqType": 0, # 輸入型別:0-文字(預設) 1-圖片 2-音訊 "perception": { # 輸入資訊 "inputText": { # 文字資訊 "text": "" # 直接輸入文字,1-128個字元 }, }, "userInfo": { # 使用者引數 "apiKey": "", # 機器人標示 "userId": "", # 使用者唯一標示,用於請求上下文判斷是否為同一個使用者,不可重複 } } @classmethod def run(cls, text='你的名字叫什麼', user_id='user01', api_key=None, *args, **kwargs): """ 開始玩轉圖靈機器人 :param text: 你對機器人說的話 :param api_key: 圖靈機器人標示,如果你有自己的機器人,請使用你自己的機器人 :param user_id: 使用者唯一ID,用於請求上下文判斷是否為同一個使用者,多個使用者使用時不可重複 :return: 直接返回機器人回的話 """ cls.POST_DATA.get('userInfo')['apiKey'] = api_key or cls.__API_KEY cls.POST_DATA.get('userInfo')['userId'] = user_id cls.POST_DATA.get('perception')['inputText']['text'] = text result = requests.post(cls.URL, json=cls.POST_DATA).json() return result.get('results')[0]['values']['text'] # =======================Flase App======================= app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def index(): return render_template('web.html') @app.route('/toy_uploader', methods=['GET', 'POST']) def toy_uploader(): uuid4 = uuid.uuid4() vct = VoiceTextConversion(is_external_called=True) # 確保檔案唯一,錄音檔案為 .wav 格式 filename = f'{uuid4}.wav' # 儲存語音檔案 request.files['record'].save(filename) # 開始語音轉文字 content = vct.voice_to_text(filename) os.remove(filename) # 與圖靈機器人對話 result = TuringRobot.run(text=content, user_id='user01') # 開始文字轉語音 vct.text_to_voice(text=result, filepath=uuid4) # 返回給前端語音檔名 return jsonify({'filename': f'{uuid4}.mp3'}) @app.route('/get_audio/<filename>') def get_audio(filename): # 前端ajax通過檔名來獲取語音檔案 ret = send_file(filename) os.remove(filename) return ret if __name__ == '__main__': app.run('0.0.0.0', 5000, debug=True)

前端程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>人機對話</title>
</head>
<body>
<audio src="" controls autoplay id="player"></audio>
<div>
    <button onclick="start_reco()" style="background-color: red">錄製語音</button>
</div>
<div>
    <button onclick="stop_reco()" style="background-color: green">傳送語音</button>
</div>
</body>
<script type="text/javascript" src=https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js></script>
<script type="text/javascript" src="/static/Recorder.js"></script>
<script type="text/javascript">
    var serv = "http://127.0.0.1:5000";
    // var get_music = "http://192.168.1.102:9527/get_music/";
    // var get_chat = "http://192.168.1.102:9527/get_chat/";
    var reco = null;

    var audio_context = new AudioContext();
    navigator.getUserMedia = (navigator.getUserMedia ||
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.msGetUserMedia);

    navigator.getUserMedia({audio: true}, create_stream, function (err) {
        console.log(err)
    });

    function create_stream(user_media) {
        var stream_input = audio_context.createMediaStreamSource(user_media);
        reco = new Recorder(stream_input);
    }

    function start_reco() {
        reco.record();
    }

    function stop_reco() {
        reco.stop();
        get_audio();
        reco.clear();
    }

    function get_audio() {
        reco.exportWAV(function (wav_file) {
            // wav_file = Blob物件 file物件
            // ws.send(wav_file);
            var formdata = new FormData();
            formdata.append("record", wav_file);
            // formdata.append("sender", toy_id);
            // formdata.append("to_user", document.getElementById("from_user").innerText);
            $.ajax({
                url: serv + "/toy_uploader",  // ⚠️
                type: 'post',
                processData: false,
                contentType: false,
                data: formdata,
                dataType: 'json',
                success: function (data) {
                    console.log(data.A);
                    // console.log(data);
                    document.getElementById("player").src =
                        "http://127.0.0.1:5000/get_audio/" + data.filename;  // ⚠️
                }
            })
        })
    }
</script>
</html>

前端依賴外掛:
Recorder.js:https://download.csdn.net/download/qq_41964425/10867911
uuid.js:https://download.csdn.net/download/qq_41964425/10867907

使用火狐瀏覽器錄音.