人工智能之百度AI的使用


百度AI開放平台官網:http://ai.baidu.com/?track=cp:aipinzhuan|pf:pc|pp:AIpingtai|pu:title|ci:|kw:10005792

pip3 install baidu-aip

百度AI的使用:

1、首先創建應用:

2、使用方法可以查看文檔:

3、各功能的使用

3.1 語言合成:

from aip import AipSpeech

""" 你的 APPID AK SK """
APP_ID = '15420336'
API_KEY = 'VwSGcqqwsCl282LGKnFwHDIA'
SECRET_KEY = 'h4oL6Y9yRuvmD0oSdQGQZchNcix4TF5P'

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)


result = client.synthesis('先帝創業未半而中道崩殂', 'zh', 1, {
    'vol': 5,
    "spd": 3,
    "pit": 7,
    "per": 4
})
print(result)

# 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
if not isinstance(result, dict):
    with open('audio.mp3', 'wb') as f:
        f.write(result)
語言合成 簡單示例

Python使用 語言合成 文檔:

3.1.1 簡介

Hi,您好,歡迎使用百度語音合成服務。

本文檔主要針對Python開發者,描述百度語音合成接口服務的相關技術內容。如果您對文檔內容有任何疑問,可以通過以下幾種方式聯系我們:

  • 在百度雲控制台內提交工單,咨詢問題類型請選擇人工智能服務;
  • 加入開發者QQ群:910926227

接口能力

接口名稱 接口能力簡要描述
語音合成 將計算機自己產生的、或外部輸入的文字信息轉變為可以聽得懂的、流利的口語輸出的技術。

注意事項

目前本SDK的功能同REST API,需要聯網調用http接口 。REST API 僅支持最多512字(1024 字節)的音頻合成,合成的文件格式為mp3。沒有其他額外功能。 如果需要使用離線合成等其它功能,請使用Android或者iOS 合成 SDK

請嚴格按照文檔里描述的參數進行開發。請注意以下幾個問題:

  1. 合成文本長度必須小於1024字節,如果本文長度較長,可以采用多次請求的方式。切忌文本長度超過限制。

2.新創建語音合成應用不限制每日調用量,但有QPS限額。詳細限額數據可在控制台中查看。完成個人實名認證及企業認證可提高QPS限額。若需更大QPS可進一步商務合作咨詢

  1. 必填字段中,嚴格按照文檔描述中內容填寫。

版本更新記錄

上線日期 版本號 更新內容
2017.5.11 1.0.0 語音合成服務上線

3.1.2 快速入門

安裝語音合成 Python SDK

語音合成 Python SDK目錄結構

├── README.md
├── aip                   //SDK目錄
│   ├── __init__.py       //導出類
│   ├── base.py           //aip基類
│   ├── http.py           //http請求
│   └── speech.py //語音合成
└── setup.py              //setuptools安裝

支持Python版本:2.7.+ ,3.+

安裝使用Python SDK有如下方式:

  • 如果已安裝pip,執行pip install baidu-aip即可。
  • 如果已安裝setuptools,執行python setup.py install即可。

新建AipSpeech

AipSpeech是語音合成的Python SDK客戶端,為使用語音合成的開發人員提供了一系列的交互方法。

參考如下代碼新建一個AipSpeech:

from aip import AipSpeech

""" 你的 APPID AK SK """
APP_ID = '你的 App ID'
API_KEY = '你的 Api Key'
SECRET_KEY = '你的 Secret Key'

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

在上面代碼中,常量APP_ID在百度雲控制台中創建,常量API_KEYSECRET_KEY是在創建完畢應用后,系統分配給用戶的,均為字符串,用於標識用戶,為訪問做簽名驗證,可在AI服務控制台中的應用列表中查看。

配置AipSpeech

如果用戶需要配置AipSpeech的網絡請求參數(一般不需要配置),可以在構造AipSpeech之后調用接口設置參數,目前只支持以下參數:

接口 說明
setConnectionTimeoutInMillis 建立連接的超時時間(單位:毫秒
setSocketTimeoutInMillis 通過打開的連接傳輸數據的超時時間(單位:毫秒)

3.1.3 接口說明

語音合成

接口描述

基於該接口,開發者可以輕松的獲取語音合成能力

請求說明

  • 合成文本長度必須小於1024字節,如果本文長度較長,可以采用多次請求的方式。文本長度不可超過限制

舉例,要把一段文字合成為語音文件:

result  = client.synthesis('你好百度', 'zh', 1, {
    'vol': 5,
})

# 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
if not isinstance(result, dict):
    with open('auido.mp3', 'wb') as f:
        f.write(result)
參數 類型 描述 是否必須
tex String 合成的文本,使用UTF-8編碼,
請注意文本長度必須小於1024字節
cuid String 用戶唯一標識,用來區分用戶,
填寫機器 MAC 地址或 IMEI 碼,長度為60以內
spd String 語速,取值0-9,默認為5中語速
pit String 音調,取值0-9,默認為5中語調
vol String 音量,取值0-15,默認為5中音量
per String 發音人選擇, 0為女聲,1為男聲,
3為情感合成-度逍遙,4為情感合成-度丫丫,默認為普通女

返回樣例:

// 成功返回二進制文件流
// 失敗返回
{
    "err_no":500,
    "err_msg":"notsupport.",
    "sn":"abcdefgh",
    "idx":1
}

3.1.4 錯誤信息

錯誤返回格式

若請求錯誤,服務器將返回的JSON文本包含以下參數:

  • error_code:錯誤碼。
  • error_msg:錯誤描述信息,幫助理解和解決發生的錯誤。

錯誤碼

錯誤碼 含義
500 不支持的輸入
501 輸入參數不正確
502 token驗證失敗
503 合成后端錯誤

3.2 語言識別

from aip import AipSpeech
import os


""" 你的 APPID AK SK """
APP_ID = '15420336'
API_KEY = 'VwSGcqqwsCl282LGKnFwHDIA'
SECRET_KEY = 'h4oL6Y9yRuvmD0oSdQGQZchNcix4TF5P'

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)


# 讀取文件
def get_file_content(filePath):
    os.system(f"ffmpeg -y  -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
    with open(f"{filePath}.pcm", 'rb') as fp:
        return fp.read()

# 識別本地文件
res = client.asr(get_file_content('wyn.wma'), 'pcm', 16000, {
    'dev_pid': 1536,
})

print(res.get("result")[0])
語言識別 簡單示例

 

Python使用 語言識別 文檔:

音頻處理工具

3.2.1 簡介

目前本SDK的功能同REST API,需要聯網調用http接口, 具體功能見REST API 文檔, REST API 僅支持整段語音識別的模式,即需要上傳完整語音文件進行識別,時長不超過60s,支持、自定義詞庫設置, 沒有其他額外功能。

接口能力

接口名稱 接口能力簡要描述
語音識別 將人類的語音中的詞匯內容轉換為計算機可讀的輸入,例如按鍵、二進制編碼或者字符序列

支持的語音格式

原始 PCM 的錄音參數必須符合 16k 采樣率、16bit 位深、單聲道,支持的格式有:pcm(不壓縮)、wav(不壓縮,pcm編碼)、amr(壓縮格式)。

注意事項

如果需要使用實時識別、長語音、喚醒詞、語義解析等其它語音功能,請使用Android或者iOS SDK 或 Linux C++ SDK 等。

  1. 請嚴格按照文檔里描述的參數進行開發,特別請關注原始錄音參數以及語音壓縮格式的建議,否則會影響識別率,進而影響到產品的用戶體驗。
  2. 目前系統支持的語音時長上限為60s,請不要超過這個長度,否則會返回錯誤。

反饋

  • 在百度雲控制台內提交工單,咨詢問題類型請選擇人工智能服務;
  • QQ群快速溝通: AI開放平台官網首頁底部“QQ支持群”中,查找“百度語音”。

版本更新記錄

上線日期 版本號 更新內容
2017.5.11 1.0.0 語音識別服務上線

3.2.2 快速入門

安裝語音識別 Python SDK

語音識別 Python SDK目錄結構

├── README.md
├── aip                   //SDK目錄
│   ├── __init__.py       //導出類
│   ├── base.py           //aip基類
│   ├── http.py           //http請求
│   └── speech.py //語音識別
└── setup.py              //setuptools安裝

支持Python版本:2.7.+ ,3.+

安裝使用Python SDK有如下方式:

  • 如果已安裝pip,執行pip install baidu-aip即可。
  • 如果已安裝setuptools,執行python setup.py install即可。

新建AipSpeech

AipSpeech是語音識別的Python SDK客戶端,為使用語音識別的開發人員提供了一系列的交互方法。

參考如下代碼新建一個AipSpeech:

from aip import AipSpeech

""" 你的 APPID AK SK """
APP_ID = '你的 App ID'
API_KEY = '你的 Api Key'
SECRET_KEY = '你的 Secret Key'

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

在上面代碼中,常量APP_ID在百度雲控制台中創建,常量API_KEYSECRET_KEY是在創建完畢應用后,系統分配給用戶的,均為字符串,用於標識用戶,為訪問做簽名驗證,可在AI服務控制台中的應用列表中查看。

配置AipSpeech

如果用戶需要配置AipSpeech的網絡請求參數(一般不需要配置),可以在構造AipSpeech之后調用接口設置參數,目前只支持以下參數:

接口 說明
setConnectionTimeoutInMillis 建立連接的超時時間(單位:毫秒
setSocketTimeoutInMillis 通過打開的連接傳輸數據的超時時間(單位:毫秒)

3.2.3 接口說明

語音識別

接口描述

向遠程服務上傳整段語音進行識別

請求說明

舉例,要對段保存有一段語音的語音文件進行識別:

# 讀取文件
def get_file_content(filePath):
    with open(filePath, 'rb') as fp:
        return fp.read()

# 識別本地文件
client.asr(get_file_content('audio.pcm'), 'pcm', 16000, {
    'dev_pid': 1536,
})
參數 類型 描述 是否必須
speech Buffer 建立包含語音內容的Buffer對象, 語音文件的格式,pcm 或者 wav 或者 amr。不區分大小寫
format String 語音文件的格式,pcm 或者 wav 或者 amr。不區分大小寫。推薦pcm文件
rate int 采樣率,16000,固定值
cuid String 用戶唯一標識,用來區分用戶,填寫機器 MAC 地址或 IMEI 碼,長度為60以內
dev_pid Int 不填寫lan參數生效,都不填寫,默認1537(普通話 輸入法模型),dev_pid參數見本節開頭的表格
lan(已廢棄) String 歷史兼容參數,請使用dev_pid。如果dev_pid填寫,該參數會被覆蓋。語種選擇,輸入法模型,默認中文(zh)。 中文=zh、粵語=ct、英文=en,不區分大小寫。

dev_pid 參數列表

dev_pid 語言 模型 是否有標點 備注
1536 普通話(支持簡單的英文識別) 搜索模型 無標點 支持自定義詞庫
1537 普通話(純中文識別) 輸入法模型 有標點 支持自定義詞庫
1737 英語   無標點 不支持自定義詞庫
1637 粵語   有標點 不支持自定義詞庫
1837 四川話   有標點 不支持自定義詞庫
1936 普通話遠場 遠場模型 有標點 不支持

語音識別 返回數據參數詳情

參數 類型 是否一定輸出 描述
err_no int 錯誤碼
err_msg int 錯誤碼描述
sn int 語音數據唯一標識,系統內部產生,用於 debug
result int 識別結果數組,提供1-5 個候選結果,string 類型為識別的字符串, utf-8 編碼

返回樣例:

// 成功返回
{
    "err_no": 0,
    "err_msg": "success.",
    "corpus_no": "15984125203285346378",
    "sn": "481D633F-73BA-726F-49EF-8659ACCC2F3D",
    "result": ["北京天氣"]
}

// 失敗返回
{
    "err_no": 2000,
    "err_msg": "data empty.",
    "sn": null
}

3.2.4 錯誤信息

錯誤返回格式

若請求錯誤,服務器將返回的JSON文本包含以下參數:

  • error_code:錯誤碼。
  • error_msg:錯誤描述信息,幫助理解和解決發生的錯誤。

錯誤碼

錯誤碼 用戶輸入/服務端 含義 一般解決方法
3300 用戶輸入錯誤 輸入參數不正確 請仔細核對文檔及參照demo,核對輸入參數
3301 用戶輸入錯誤 音頻質量過差 請上傳清晰的音頻
3302 用戶輸入錯誤 鑒權失敗 token字段校驗失敗。請使用正確的API_KEY 和 SECRET_KEY生成。或QPS、調用量超出限額。或音頻采樣率不正確(可嘗試更換為16k采樣率)。
3303 服務端問題 語音服務器后端問題 請將api返回結果反饋至論壇或者QQ群
3304 用戶請求超限 用戶的請求QPS超限 請降低識別api請求頻率 (qps以appId計算,移動端如果共用則累計)
3305 用戶請求超限 用戶的日pv(日請求量)超限 請“申請提高配額”,如果暫未通過,請降低日請求量
3307 服務端問題 語音服務器后端識別出錯問題 目前請確保16000的采樣率音頻時長低於30s。如果仍有問題,請將api返回結果反饋至論壇或者QQ群
3308 用戶輸入錯誤 音頻過長 音頻時長不超過60s,請將音頻時長截取為60s以下
3309 用戶輸入錯誤 音頻數據問題 服務端無法將音頻轉為pcm格式,可能是長度問題,音頻格式問題等。 請將輸入的音頻時長截取為60s以下,並核對下音頻的編碼,是否是16K, 16bits,單聲道。
3310 用戶輸入錯誤 輸入的音頻文件過大 語音文件共有3種輸入方式: json 里的speech 參數(base64后); 直接post 二進制數據,及callback參數里url。 分別對應三種情況:json超過10M;直接post的語音文件超過10M;callback里回調url的音頻文件超過10M
3311 用戶輸入錯誤 采樣率rate參數不在選項里 目前rate參數僅提供16000,填寫4000即會有此錯誤
3312 用戶輸入錯誤 音頻格式format參數不在選項里 目前格式僅僅支持pcm,wav或amr,如填寫mp3即會有此錯誤

錯誤碼常見問題及具體分析

3300 錯誤

語音識別api使用的是HTTP POST方法, BODY里直接放置json, Content-Type頭部為 application/json。 並非常見的瀏覽器表單請求(application/x-www-form-urlencoded或者multipart/x-www-form-urlencoded)。

必填字段:format rate channel cuid token cuid token cuid token cuid token,請勿漏填。此外 (speech, len) 及 (url, callback) 這兩組參數必須二選一,如果都填,默認處理第一組。 channel cuid token,請勿漏填。此外 (speech, len) 及 (url, callback) 這兩組參數必須二選一,如果都填,默認處理第一種。 channel cuid token,請勿漏填。此外 (speech, len) 及 (url, callback) 這兩組參數必須二選一,如果都填,默認處理第一種。

必填字段如format rate channel cuid token,請勿漏填。此外 (speech, len) 及 (url, callback) 這兩組參數必須二選一,如果都填,默認處理第一種,並確認 音頻時長截取為60s以下。

3309錯誤

wav和amr的音頻,服務端會自動轉為pcm,這個過程中導致轉碼出錯。請確認下format及rate參數與音頻一致,並確認音頻時長截取為60s以下。

3301 錯誤

識別結果實際為空。可能是音頻質量過差,不清晰,或者是空白音頻。 有時也可能是pcm填錯采樣率。如16K采樣率的pcm文件,填寫的rate參數為8000。

行業與場景限制 根據工信部《綜合整治騷擾電話專項行動方案》、《關於推進綜合整治騷擾電話專項行動的工作方案》,相關能力不得用於商業營銷類、惡意騷擾類和違法犯罪類騷擾電話類場景,也不支持在貸款、理財、信用卡、股票、基金、債券、保險、售房租房、醫療機構、保健食品、人力資源服務、旅游等場景的騷擾電話營銷行為。

 

基於 語言合成 和 語言識別 可以做一個 機器學我們說話 功能:

from aip import AipSpeech
import time,os

""" 你的 APPID AK SK """
APP_ID = '15420336'
API_KEY = 'VwSGcqqwsCl282LGKnFwHDIA'
SECRET_KEY = 'h4oL6Y9yRuvmD0oSdQGQZchNcix4TF5P'

client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

# 讀取文件
def get_file_content(filePath):
    os.system(f"ffmpeg -y  -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
    with open(f"{filePath}.pcm", 'rb') as fp:
        return fp.read()

def audio2text(filepath):
    # 識別本地文件
    res = client.asr(get_file_content(filepath), 'pcm', 16000, {
        'dev_pid': 1536,
    })

    print(res.get("result")[0])

    return res.get("result")[0]

def text2audio(text):
    filename = f"{time.time()}.mp3"
    result = client.synthesis(text, 'zh', 1, {
        'vol': 5,
        "spd": 3,
        "pit": 7,
        "per": 4
    })

    # 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
    if not isinstance(result, dict):
        with open(filename, 'wb') as f:
            f.write(result)

    return filename


text = audio2text("wyn.wma")
filename = text2audio(text)

os.system(filename)
學說話

 

3.3 自然語言處理技術

短文本相似度NLP

from aip import AipSpeech,AipNlp
import time,os

""" 你的 APPID AK SK """
APP_ID = '15420336'
API_KEY = 'VwSGcqqwsCl282LGKnFwHDIA'
SECRET_KEY = 'h4oL6Y9yRuvmD0oSdQGQZchNcix4TF5P'

nlp =  AipNlp(APP_ID, API_KEY, SECRET_KEY)  #短文本相似度
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

# 讀取文件
def get_file_content(filePath):
    os.system(f"ffmpeg -y  -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
    with open(f"{filePath}.pcm", 'rb') as fp:
        return fp.read()

def audio2text(filepath):
    # 識別本地文件
    res = client.asr(get_file_content(filepath), 'pcm', 16000, {
        'dev_pid': 1536,
    })

    print(res.get("result")[0])

    return res.get("result")[0]

def text2audio(text):
    filename = f"{time.time()}.mp3"
    result = client.synthesis(text, 'zh', 1, {
        'vol': 5,
        "spd": 3,
        "pit": 7,
        "per": 4
    })

    # 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
    if not isinstance(result, dict):
        with open(filename, 'wb') as f:
            f.write(result)

    return filename

def to_tuling(text):
    import requests

    args = {
        "reqType": 0,
        "perception": {
            "inputText": {
                "text": text
            }
        },
        "userInfo": {
            "apiKey": "9a9a026e2eb64ed6b006ad99d27f6b9e",
            "userId": "1111"
        }
    }

    url = "http://openapi.tuling123.com/openapi/api/v2"

    res = requests.post(url, json=args)

    text = res.json().get("results")[0].get("values").get("text")
    return text

# res = nlp.simnet("你叫什么名字","你的名字是什么")
# print(res)


text = audio2text("bjtq.wma")
# 短文本相似度
if nlp.simnet("你叫什么名字",text).get("score") >= 0.68 :
    text = "我的名字叫銀角大王8"
else:
    text = to_tuling(text)

filename = text2audio(text)

os.system(filename)
短文本相似度NLP的簡單使用示例

 

圖靈機器人官網:http://www.tuling123.com/

基於 語言合成 和 語言識別 以及 自然語言的短文本相似度 還有 圖靈機器人 做一個 機器智能回答問題 的功能:

簡易版:

from aip import AipSpeech,AipNlp
import time,os

""" 你的 APPID AK SK """
APP_ID = '15420336'
API_KEY = 'VwSGcqqwsCl282LGKnFwHDIA'
SECRET_KEY = 'h4oL6Y9yRuvmD0oSdQGQZchNcix4TF5P'

nlp =  AipNlp(APP_ID, API_KEY, SECRET_KEY)
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

# 讀取文件
def get_file_content(filePath):
    os.system(f"ffmpeg -y  -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
    with open(f"{filePath}.pcm", 'rb') as fp:
        return fp.read()

def audio2text(filepath):
    # 識別本地文件
    res = client.asr(get_file_content(filepath), 'pcm', 16000, {
        'dev_pid': 1536,
    })

    print(res.get("result")[0])

    return res.get("result")[0]

def text2audio(text):
    filename = f"{time.time()}.mp3"
    result = client.synthesis(text, 'zh', 1, {
        'vol': 5,
        "spd": 3,
        "pit": 7,
        "per": 4
    })

    # 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
    if not isinstance(result, dict):
        with open(filename, 'wb') as f:
            f.write(result)

    return filename

def to_tuling(text):
    import requests

    args = {
        "reqType": 0,
        "perception": {
            "inputText": {
                "text": text
            }
        },
        "userInfo": {
            "apiKey": "9a9a026e2eb64ed6b006ad99d27f6b9e",
            "userId": "1111"
        }
    }

    url = "http://openapi.tuling123.com/openapi/api/v2"

    res = requests.post(url, json=args)

    text = res.json().get("results")[0].get("values").get("text")
    return text

# res = nlp.simnet("你叫什么名字","你的名字是什么")
# print(res)


text = audio2text("bjtq.wma")

if nlp.simnet("你叫什么名字",text).get("score") >= 0.68 :
    text = "我的名字叫銀角大王8"
else:
    text = to_tuling(text)

filename = text2audio(text)

os.system(filename)
View Code

完善版:

from flask import Flask,render_template,request,jsonify,send_file
from uuid import uuid4
import baidu_ai

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/ai",methods=["POST"])
def ai():
    # 1.保存錄音文件
    audio = request.files.get("record")
    filename = f"{uuid4()}.wav"
    audio.save(filename)
    #2.將錄音文件轉換為PCM發送給百度進行語音識別
    q_text = baidu_ai.audio2text(filename)

    #3.將識別的問題交給圖靈或自主處理獲取答案
    a_text = baidu_ai.to_tuling(q_text)

    #4.將答案發送給百度語音合成,合成音頻文件
    a_file = baidu_ai.text2audio(a_text)

    #5.將音頻文件發送給前端播放

    return jsonify({"filename":a_file})


@app.route("/get_audio/<filename>")
def get_audio(filename):
    return send_file(filename)



if __name__ == '__main__':
    app.run("0.0.0.0",9527,debug=True)
app.py
from aip import AipSpeech,AipNlp
import time,os

""" 你的 APPID AK SK """
APP_ID = '15420336'
API_KEY = 'VwSGcqqwsCl282LGKnFwHDIA'
SECRET_KEY = 'h4oL6Y9yRuvmD0oSdQGQZchNcix4TF5P'

nlp =  AipNlp(APP_ID, API_KEY, SECRET_KEY)
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)

# 讀取文件
def get_file_content(filePath):
    os.system(f"ffmpeg -y  -i {filePath} -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {filePath}.pcm")
    with open(f"{filePath}.pcm", 'rb') as fp:
        return fp.read()

def audio2text(filepath):
    # 識別本地文件
    res = client.asr(get_file_content(filepath), 'pcm', 16000, {
        'dev_pid': 1536,
    })

    print(res.get("result")[0])

    return res.get("result")[0]

def text2audio(text):
    filename = f"{time.time()}.mp3"
    result = client.synthesis(text, 'zh', 1, {
        'vol': 5,
        "spd": 3,
        "pit": 7,
        "per": 4
    })

    # 識別正確返回語音二進制 錯誤則返回dict 參照下面錯誤碼
    if not isinstance(result, dict):
        with open(filename, 'wb') as f:
            f.write(result)

    return filename

def to_tuling(text):
    import requests

    args = {
        "reqType": 0,
        "perception": {
            "inputText": {
                "text": text
            }
        },
        "userInfo": {
            "apiKey": "9a9a026e2eb64ed6b006ad99d27f6b9e",
            "userId": "1111"
        }
    }

    url = "http://openapi.tuling123.com/openapi/api/v2"

    res = requests.post(url, json=args)

    text = res.json().get("results")[0].get("values").get("text")

    print("圖靈答案",text)
    return text
baidu_ai.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<audio controls autoplay id="player"></audio>
<p>
    <button onclick="start_reco()" style="background-color: yellow">錄制語音指令</button>
</p>
<p>
    <button onclick="stop_reco_audio()" style="background-color: blue">發送語音指令</button>
</p>
</body>
<!--<script type="application/javascript" src="/static/Recorder.js"></script>-->
<script type="application/javascript" src="https://cdn.bootcss.com/recorderjs/0.1.0/recorder.js"></script>
<script type="text/javascript" src="/static/jQuery3.1.1.js"></script>

<script type="text/javascript">
    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_audio() {
        reco.stop();
        send_audio();
        reco.clear();
    }


    function send_audio() {
        reco.exportWAV(function (wav_file) {
            var formdata = new FormData();
            formdata.append("record", wav_file);
            console.log(formdata);
            $.ajax({
                url: "http://192.168.13.42:9527/ai",
                type: 'post',
                processData: false,
                contentType: false,
                data: formdata,
                dataType: 'json',
                success: function (data) {
                    document.getElementById("player").src ="http://192.168.13.42:9527/get_audio/" + data.filename
                }
            });

        })
    }



</script>
</html>
templates/index.html
bootsdn download
static/jQuery3.1.1.js
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Recorder = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";

module.exports = require("./Recorder").Recorder;

},{"./recorder":2}],2:[function(require,module,exports){
'use strict';

var _createClass = (function () {
    function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
            var descriptor = props[i];descriptor.enumerable = descriptor.enumerable || false;descriptor.configurable = true;if ("value" in descriptor) descriptor.writable = true;Object.defineProperty(target, descriptor.key, descriptor);
        }
    }return function (Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps);if (staticProps) defineProperties(Constructor, staticProps);return Constructor;
    };
})();

Object.defineProperty(exports, "__esModule", {
    value: true
});
exports.Recorder = undefined;

var _inlineWorker = require('inline-worker');

var _inlineWorker2 = _interopRequireDefault(_inlineWorker);

function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : { default: obj };
}

function _classCallCheck(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}

var Recorder = exports.Recorder = (function () {
    function Recorder(source, cfg) {
        var _this = this;

        _classCallCheck(this, Recorder);

        this.config = {
            bufferLen: 4096,
            numChannels: 2,
            mimeType: 'audio_pcm/wav'
        };
        this.recording = false;
        this.callbacks = {
            getBuffer: [],
            exportWAV: []
        };

        Object.assign(this.config, cfg);
        this.context = source.context;
        this.node = (this.context.createScriptProcessor || this.context.createJavaScriptNode).call(this.context, this.config.bufferLen, this.config.numChannels, this.config.numChannels);

        this.node.onaudioprocess = function (e) {
            if (!_this.recording) return;

            var buffer = [];
            for (var channel = 0; channel < _this.config.numChannels; channel++) {
                buffer.push(e.inputBuffer.getChannelData(channel));
            }
            _this.worker.postMessage({
                command: 'record',
                buffer: buffer
            });
        };

        source.connect(this.node);
        this.node.connect(this.context.destination); //this should not be necessary

        var self = {};
        this.worker = new _inlineWorker2.default(function () {
            var recLength = 0,
                recBuffers = [],
                sampleRate = undefined,
                numChannels = undefined;

            self.onmessage = function (e) {
                switch (e.data.command) {
                    case 'init':
                        init(e.data.config);
                        break;
                    case 'record':
                        record(e.data.buffer);
                        break;
                    case 'exportWAV':
                        exportWAV(e.data.type);
                        break;
                    case 'getBuffer':
                        getBuffer();
                        break;
                    case 'clear':
                        clear();
                        break;
                }
            };

            function init(config) {
                sampleRate = config.sampleRate;
                numChannels = config.numChannels;
                initBuffers();
            }

            function record(inputBuffer) {
                for (var channel = 0; channel < numChannels; channel++) {
                    recBuffers[channel].push(inputBuffer[channel]);
                }
                recLength += inputBuffer[0].length;
            }

            function exportWAV(type) {
                var buffers = [];
                for (var channel = 0; channel < numChannels; channel++) {
                    buffers.push(mergeBuffers(recBuffers[channel], recLength));
                }
                var interleaved = undefined;
                if (numChannels === 2) {
                    interleaved = interleave(buffers[0], buffers[1]);
                } else {
                    interleaved = buffers[0];
                }
                var dataview = encodeWAV(interleaved);
                var audioBlob = new Blob([dataview], { type: type });

                self.postMessage({ command: 'exportWAV', data: audioBlob });
            }

            function getBuffer() {
                var buffers = [];
                for (var channel = 0; channel < numChannels; channel++) {
                    buffers.push(mergeBuffers(recBuffers[channel], recLength));
                }
                self.postMessage({ command: 'getBuffer', data: buffers });
            }

            function clear() {
                recLength = 0;
                recBuffers = [];
                initBuffers();
            }

            function initBuffers() {
                for (var channel = 0; channel < numChannels; channel++) {
                    recBuffers[channel] = [];
                }
            }

            function mergeBuffers(recBuffers, recLength) {
                var result = new Float32Array(recLength);
                var offset = 0;
                for (var i = 0; i < recBuffers.length; i++) {
                    result.set(recBuffers[i], offset);
                    offset += recBuffers[i].length;
                }
                return result;
            }

            function interleave(inputL, inputR) {
                var length = inputL.length + inputR.length;
                var result = new Float32Array(length);

                var index = 0,
                    inputIndex = 0;

                while (index < length) {
                    result[index++] = inputL[inputIndex];
                    result[index++] = inputR[inputIndex];
                    inputIndex++;
                }
                return result;
            }

            function floatTo16BitPCM(output, offset, input) {
                for (var i = 0; i < input.length; i++, offset += 2) {
                    var s = Math.max(-1, Math.min(1, input[i]));
                    output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
                }
            }

            function writeString(view, offset, string) {
                for (var i = 0; i < string.length; i++) {
                    view.setUint8(offset + i, string.charCodeAt(i));
                }
            }

            function encodeWAV(samples) {
                var buffer = new ArrayBuffer(44 + samples.length * 2);
                var view = new DataView(buffer);

                /* RIFF identifier */
                writeString(view, 0, 'RIFF');
                /* RIFF chunk length */
                view.setUint32(4, 36 + samples.length * 2, true);
                /* RIFF type */
                writeString(view, 8, 'WAVE');
                /* format chunk identifier */
                writeString(view, 12, 'fmt ');
                /* format chunk length */
                view.setUint32(16, 16, true);
                /* sample format (raw) */
                view.setUint16(20, 1, true);
                /* channel count */
                view.setUint16(22, numChannels, true);
                /* sample rate */
                view.setUint32(24, sampleRate, true);
                /* byte rate (sample rate * block align) */
                view.setUint32(28, sampleRate * 4, true);
                /* block align (channel count * bytes per sample) */
                view.setUint16(32, numChannels * 2, true);
                /* bits per sample */
                view.setUint16(34, 16, true);
                /* data chunk identifier */
                writeString(view, 36, 'data');
                /* data chunk length */
                view.setUint32(40, samples.length * 2, true);

                floatTo16BitPCM(view, 44, samples);

                return view;
            }
        }, self);

        this.worker.postMessage({
            command: 'init',
            config: {
                sampleRate: this.context.sampleRate,
                numChannels: this.config.numChannels
            }
        });

        this.worker.onmessage = function (e) {
            var cb = _this.callbacks[e.data.command].pop();
            if (typeof cb == 'function') {
                cb(e.data.data);
            }
        };
    }

    _createClass(Recorder, [{
        key: 'record',
        value: function record() {
            this.recording = true;
        }
    }, {
        key: 'stop',
        value: function stop() {
            this.recording = false;
        }
    }, {
        key: 'clear',
        value: function clear() {
            this.worker.postMessage({ command: 'clear' });
        }
    }, {
        key: 'getBuffer',
        value: function getBuffer(cb) {
            cb = cb || this.config.callback;
            if (!cb) throw new Error('Callback not set');

            this.callbacks.getBuffer.push(cb);

            this.worker.postMessage({ command: 'getBuffer' });
        }
    }, {
        key: 'exportWAV',
        value: function exportWAV(cb, mimeType) {
            mimeType = mimeType || this.config.mimeType;
            cb = cb || this.config.callback;
            if (!cb) throw new Error('Callback not set');

            this.callbacks.exportWAV.push(cb);

            this.worker.postMessage({
                command: 'exportWAV',
                type: mimeType
            });
        }
    }], [{
        key: 'forceDownload',
        value: function forceDownload(blob, filename) {
            var url = (window.URL || window.webkitURL).createObjectURL(blob);
            var link = window.document.createElement('a');
            link.href = url;
            link.download = filename || 'output.wav';
            var click = document.createEvent("Event");
            click.initEvent("click", true, true);
            link.dispatchEvent(click);
        }
    }]);

    return Recorder;
})();

exports.default = Recorder;

},{"inline-worker":3}],3:[function(require,module,exports){
"use strict";

module.exports = require("./inline-worker");
},{"./inline-worker":4}],4:[function(require,module,exports){
(function (global){
"use strict";

var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };

var WORKER_ENABLED = !!(global === global.window && global.URL && global.Blob && global.Worker);

var InlineWorker = (function () {
  function InlineWorker(func, self) {
    var _this = this;

    _classCallCheck(this, InlineWorker);

    if (WORKER_ENABLED) {
      var functionBody = func.toString().trim().match(/^function\s*\w*\s*\([\w\s,]*\)\s*{([\w\W]*?)}$/)[1];
      var url = global.URL.createObjectURL(new global.Blob([functionBody], { type: "text/javascript" }));

      return new global.Worker(url);
    }

    this.self = self;
    this.self.postMessage = function (data) {
      setTimeout(function () {
        _this.onmessage({ data: data });
      }, 0);
    };

    setTimeout(function () {
      func.call(self);
    }, 0);
  }

  _createClass(InlineWorker, {
    postMessage: {
      value: function postMessage(data) {
        var _this = this;

        setTimeout(function () {
          _this.self.onmessage({ data: data });
        }, 0);
      }
    }
  });

  return InlineWorker;
})();

module.exports = InlineWorker;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[1])(1)
});
static/Recorder.js

 


免責聲明!

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



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