語(yǔ)音評(píng)測(cè) API 簡(jiǎn)介
概念解釋
語(yǔ)音評(píng)測(cè):通過(guò)語(yǔ)音評(píng)測(cè)技術(shù)自動(dòng)對(duì)發(fā)音水平進(jìn)行不同維度下的評(píng)價(jià),給出用戶發(fā)音信息和得分詳情。
說(shuō)明
Hi,您好,歡迎使用有道智云智能語(yǔ)音評(píng)測(cè)服務(wù)。
如果您想快速體驗(yàn)服務(wù),建議您前往 語(yǔ)音評(píng)測(cè)體驗(yàn)中心 或者在體驗(yàn)中心右下側(cè)找到小程序二維碼,掃描進(jìn)行體驗(yàn)。
本文檔主要針對(duì)需要集成短語(yǔ)音識(shí)別服務(wù)HTTP API的開發(fā)工程師,詳細(xì)描述有道智云語(yǔ)音評(píng)測(cè)能力及如何集成的技術(shù)內(nèi)容。
如果您有與我們商務(wù)合作的需求,可以通過(guò)以下方式聯(lián)系我們:
商務(wù)郵箱: AIcloud_Business@corp.youdao.com
如果您對(duì)文檔內(nèi)容有任何疑問(wèn),可以通過(guò)以下幾種方式聯(lián)系我們:
客服QQ:1906538062
智云語(yǔ)音技術(shù)交流QQ群:861723255
聯(lián)系郵箱: zhiyun@corp.youdao.com
溫馨提示:
- 本文檔主要針對(duì)開發(fā)人員,接入測(cè)試前需要在后臺(tái)創(chuàng)建API應(yīng)用,獲取應(yīng)用ID和應(yīng)用密鑰;如果您還沒(méi)有,請(qǐng)按照 新手指南 獲取。
- 平臺(tái)向每個(gè)賬戶贈(zèng)送50元的體驗(yàn)金,供用戶集成前測(cè)試所用,具體資費(fèi)規(guī)則詳見 語(yǔ)音評(píng)測(cè)服務(wù)報(bào)價(jià) 。
接口說(shuō)明
有道語(yǔ)音評(píng)測(cè)服務(wù)對(duì)用戶發(fā)音的完整度、流利度、準(zhǔn)確度進(jìn)行全方位評(píng)測(cè),并能對(duì)發(fā)音錯(cuò)誤、缺陷進(jìn)行定位。支持的音頻格式為16K采樣率,16bits 精度的 wav 音頻,目前支持的語(yǔ)種為中英文。
接口地址:
https接口: https://openapi.youdao.com/iseapi
語(yǔ)音支持:
格式支持:wav(不壓縮、pcm編碼)
采樣率:推薦16k。
編碼:16bit位深的單聲道
接口調(diào)用參數(shù)
調(diào)用API需要向接口發(fā)送以下字段來(lái)訪問(wèn)服務(wù)。
| 字段名 | 類型 | 含義 | 必填 | 備注 | 
| q | text | 要評(píng)測(cè)的音頻文件的Base64編碼字符串 | True | 必須是Base64編碼,編碼后不超過(guò)20M | 
| text | text | 要評(píng)測(cè)的音頻文件對(duì)應(yīng)的文本 | True | have a good day | 
| langType | text | 源語(yǔ)言 | True | 支持語(yǔ)言 | 
| appKey | text | 應(yīng)用ID | True | 可在 應(yīng)用管理 查看 | 
| salt | text | UUID | True | uuid,唯一通用識(shí)別碼 | 
| curtime | text | 時(shí)間戳(秒) | True | TimeStamp | 
| sign | text | 簽名,通過(guò)sha256(應(yīng)用ID+input+salt+curtime+應(yīng)用密鑰)生成;input的生成規(guī)則見表下的備注 | True | sha256(應(yīng)用ID+input+salt+curtime+應(yīng)用密鑰) | 
| signType | text | 簽名類型 | True | v2 | 
| format | text | 語(yǔ)音文件的格式,wav | true | wav | 
| rate | text | 采樣率,推薦 16000 采用率 | true | 16000 | 
| channel | text | 聲道數(shù), 僅支持單聲道,請(qǐng)?zhí)顚懝潭ㄖ? | true | 1 | 
| type | text | 上傳類型, 僅支持base64上傳,請(qǐng)?zhí)顚懝潭ㄖ? | true | 1 | 
| phoneSeq | text | 音素序列(ip88) | false | 嚴(yán)格遵守音素,例如:boy的phoneSeq為:b?? | 
簽名sign生成方法如下:
signType=v2;
sign=sha256(應(yīng)用ID+input+salt+curtime+應(yīng)用密鑰)。
其中,input的計(jì)算方式為:input=q前10個(gè)字符 + q長(zhǎng)度 + q后10個(gè)字符(當(dāng)q長(zhǎng)度大于20)或 input=q字符串(當(dāng)q長(zhǎng)度小于等于20)。
具體示例如下:
a.比如:q="Welcome to youdao  AICloud.",字符串長(zhǎng)度為26,大于20,其input="Welcome to"(前10個(gè)字符) + 26(字符串長(zhǎng)度) +  "o AICloud."(q字符串后10個(gè)字符)。
b.比如:q = "sdT4bWrjS",字符串長(zhǎng)度為9,小于20,input = "sdT4bWrjS".
輸出結(jié)果
輸出字段介紹
響應(yīng)結(jié)果是以json形式輸出,包含字段如下表所示:
| 字段 | 含義 | 
| errorCode | 識(shí)別結(jié)果錯(cuò)誤碼,一定存在。 詳細(xì)信息可見 錯(cuò)誤代碼列表
 | 
| refText | 請(qǐng)求的文本 | 
| start | 音頻中句子開始時(shí)間,單位是秒 | 
| end | 音頻中句子結(jié)束時(shí)間,單位是秒 | 
| integrity | 句子完整度得分 | 
| fluency | 句子流利度得分 | 
| pronunciation | 句子準(zhǔn)確度得分 | 
| speed | 語(yǔ)速,單詞/分鐘 | 
| overall | 句子綜合評(píng)分 | 
| words | 單詞評(píng)分?jǐn)?shù)組 | 
| -word | 單詞 | 
| -start | 單詞開始時(shí)間,單位是秒 | 
| -end | 單詞結(jié)束時(shí)間,單位是秒 | 
| -pronunciation | 單詞準(zhǔn)確度得分 | 
| -phonemes | 音標(biāo)數(shù)組 | 
| --phoneme | 音標(biāo) | 
| --start | 音標(biāo)開始時(shí)間,單位是秒 | 
| --end | 音標(biāo)結(jié)束時(shí)間,單位是秒 | 
| --judge | 判斷音素是否錯(cuò)誤,true為發(fā)音正確,false為發(fā)音錯(cuò)誤,同時(shí)calibration給出提示 | 
| --calibration | 如果發(fā)音錯(cuò)誤,提示用戶該發(fā)音像什么 | 
| --prominence | 重音程度,分?jǐn)?shù)越高,當(dāng)前音標(biāo)越可能是重音,分?jǐn)?shù)在[0 100] | 
| --stress_ref | 元音重音參考/標(biāo)準(zhǔn)答案,如果為true,說(shuō)明參考答案認(rèn)為該元音應(yīng)該發(fā)重音,輔音時(shí)無(wú)意義 | 
| --stress_detect | 在一個(gè)單詞中,用戶該音標(biāo)發(fā)音為重音 | 
輸出結(jié)果示例
{
    "intonation": "",  // 預(yù)留字段,目前未使用
    "refText": "have a good day",  //待評(píng)測(cè)語(yǔ)音對(duì)應(yīng)的文本
    "pronunciation": 100,  //句子發(fā)音準(zhǔn)確度
    "start": 0.180000, //音頻開始時(shí)間,秒
    "words": [  //單詞信息列表
        {
            "phonics": [],
            "pronunciation": 70.216576,  //單詞準(zhǔn)確度分?jǐn)?shù)
            "start": 0.180000,  //單詞開始時(shí)間,秒
            "end": 0.450000,  //單詞結(jié)束時(shí)間,秒
            "IPA": "h?v",  //單詞音標(biāo)
            "word": "have",  //單詞文本
            "phonemes": [  //音標(biāo)信息列表
                {
                    "stress_ref": false,  //元音重音參考(即標(biāo)準(zhǔn)重音),如果為true,說(shuō)明參考答案認(rèn)為該元音應(yīng)該發(fā)重音,輔音時(shí)無(wú)意義
                    "pronunciation": 44.661324,  //音標(biāo)準(zhǔn)確度評(píng)分
                    "stress_detect": false,  //在一個(gè)單詞中,用戶該音標(biāo)發(fā)音不為重音
                    "phoneme": "h",  //音標(biāo)名稱
                    "start": 0.180000,  //音標(biāo)開始時(shí)間,秒
                    "end": 0.330000,  //音標(biāo)結(jié)束時(shí)間,秒
                    "judge": true,  //判斷音標(biāo)是否錯(cuò)誤,true為發(fā)音正確,false為發(fā)音錯(cuò)誤,同時(shí)calibration給出提示
                    "calibration": "h",  //判斷音標(biāo)是否錯(cuò)誤,true為發(fā)音正確,false為發(fā)音錯(cuò)誤,同時(shí)calibration給出提示
                    "calibration-diphone": "",  // 預(yù)留字段,目前未使用
                    "prominence": 0  //重音程度,當(dāng)前音標(biāo)越可能是重音,分?jǐn)?shù)區(qū)間[0 100]
                },
                {
                    "stress_ref": false,
                    "pronunciation": 67.160324,
                    "stress_detect": false,
                    "phoneme": "?",
                    "start": 0.330000,
                    "end": 0.390000,
                    "judge": true,
                    "calibration": "?",
                    "calibration-diphone": "",
                    "prominence": 0
                },
                {
                    "stress_ref": false,
                    "pronunciation": 98.828072,
                    "stress_detect": false,
                    "phoneme": "v",
                    "start": 0.390000,
                    "end": 0.450000,
                    "judge": true,
                    "calibration": "v",
                    "calibration-diphone": "",
                    "prominence": 0
                }
            ]
        },
        {
            "phonics": [],
            "pronunciation": 100,
            "start": 0.450000,
            "end": 0.510000,
            "IPA": "?",
            "word": "a",
            "phonemes": [
                {
                    "stress_ref": false,
                    "pronunciation": 100,
                    "stress_detect": false,
                    "phoneme": "?",
                    "start": 0.450000,
                    "end": 0.510000,
                    "judge": true,
                    "calibration": "?",
                    "calibration-diphone": "",
                    "prominence": 0
                }
            ]
        },
        {
            "phonics": [],
            "pronunciation": 100,
            "start": 0.510000,
            "end": 0.720000,
            "IPA": "ɡ?d",
            "word": "good",
            "phonemes": [
                {
                    "stress_ref": false,
                    "pronunciation": 100,
                    "stress_detect": false,
                    "phoneme": "ɡ",
                    "start": 0.510000,
                    "end": 0.600000,
                    "judge": true,
                    "calibration": "ɡ",
                    "calibration-diphone": "",
                    "prominence": 0.284910
                },
                {
                    "stress_ref": false,
                    "pronunciation": 100,
                    "stress_detect": false,
                    "phoneme": "?",
                    "start": 0.600000,
                    "end": 0.690000,
                    "judge": true,
                    "calibration": "?",
                    "calibration-diphone": "",
                    "prominence": 0.999990
                },
                {
                    "stress_ref": false,
                    "pronunciation": 100,
                    "stress_detect": false,
                    "phoneme": "d",
                    "start": 0.690000,
                    "end": 0.720000,
                    "judge": true,
                    "calibration": "d",
                    "calibration-diphone": "",
                    "prominence": 1.000000
                }
            ]
        },
        {
            "phonics": [],
            "pronunciation": 100,
            "start": 0.720000,
            "end": 1.170000,
            "IPA": "de?",
            "word": "day",
            "phonemes": [
                {
                    "stress_ref": false,
                    "pronunciation": 100,
                    "stress_detect": false,
                    "phoneme": "d",
                    "start": 0.720000,
                    "end": 0.840000,
                    "judge": true,
                    "calibration": "d",
                    "calibration-diphone": "",
                    "prominence": 0.967651
                },
                {
                    "stress_ref": false,
                    "pronunciation": 95.965294,
                    "stress_detect": false,
                    "phoneme": "e?",
                    "start": 0.840000,
                    "end": 1.170000,
                    "judge": true,
                    "calibration": "e?",
                    "calibration-diphone": "",
                    "prominence": 1.000000
                }
            ]
        }
    ],
    "fluency": 100,  //句子流利度
    "errorCode": "0",  //識(shí)別結(jié)果錯(cuò)誤碼,一定存在
    "version": "capt-onetime-en:online-V2.0.8",  // 服務(wù)版本號(hào)
    "speed": 242.424210,  // 句子語(yǔ)速(單詞/分鐘)
    "integrity": 100,  //句子完整度
    "emotion": 0,  // 預(yù)留字段,目前未使用
    "service": "capt",  // 服務(wù)標(biāo)識(shí)
    "requestId": "4e9e84ef-dc06-4899-9f24-8c5043dd672d",  // 請(qǐng)求ID
    "overall": 100,  //句子綜合評(píng)分
    "end": 1.170000  //句子結(jié)束時(shí)間,秒
}
支持語(yǔ)言
目前支持中英文的語(yǔ)音評(píng)測(cè)。
| 語(yǔ)言 | 代碼 | 
| 英文 | en | 
| 中文 | zh-CHS | 
服務(wù)配置
| 支持格式 | 音頻大小上限 | 單次最大請(qǐng)求時(shí)長(zhǎng)(s) | 每小時(shí)最大查詢次數(shù) | 支持語(yǔ)言 | 
| wav | 20M(編碼后) | 120 | 3000 | 英 | 
錯(cuò)誤代碼列表
| 錯(cuò)誤碼 | 含義 | 
| 101 | 缺少必填的參數(shù),首先確保必填參數(shù)齊全,然后,確認(rèn)參數(shù)書寫是否正確。 | 
| 102 | 不支持的語(yǔ)言類型 | 
| 103 | 翻譯文本過(guò)長(zhǎng) | 
| 104 | 不支持的API類型 | 
| 105 | 不支持的簽名類型 | 
| 106 | 不支持的響應(yīng)類型 | 
| 107 | 不支持的傳輸加密類型 | 
| 108 | 應(yīng)用ID無(wú)效,注冊(cè)賬號(hào),登錄后臺(tái)創(chuàng)建應(yīng)用并完成綁定,可獲得應(yīng)用ID和應(yīng)用密鑰等信息 | 
| 109 | batchLog格式不正確 | 
| 110 | 無(wú)相關(guān)服務(wù)的有效實(shí)例,應(yīng)用沒(méi)有綁定服務(wù)實(shí)例,可以新建服,綁定服務(wù)。注:某些服務(wù)的結(jié)果發(fā)音需要tts服務(wù),需要在控制臺(tái)創(chuàng)建語(yǔ)音合成服務(wù)綁定應(yīng)用后方能使用。 | 
| 111 | 開發(fā)者賬號(hào)無(wú)效 | 
| 112 | 請(qǐng)求服務(wù)無(wú)效 | 
| 113 | q不能為空 | 
| 114 | 不支持的圖片傳輸方式 | 
| 201 | 解密失敗,可能為DES,BASE64,URLDecode的錯(cuò)誤 | 
| 202 | 簽名檢驗(yàn)失敗,如果確認(rèn)應(yīng)用ID和應(yīng)用密鑰的正確性,仍返回202,一般是編碼問(wèn)題。請(qǐng)確保翻譯文本 q為UTF-8編碼. | 
| 203 | 訪問(wèn)IP地址不在可訪問(wèn)IP列表 | 
| 205 | 請(qǐng)求的接口與應(yīng)用的平臺(tái)類型不一致,確保接入方式(Android SDK、IOS SDK、API)與創(chuàng)建的應(yīng)用平臺(tái)類型一致。如有疑問(wèn)請(qǐng)參考入門指南 | 
| 206 | 因?yàn)闀r(shí)間戳無(wú)效導(dǎo)致簽名校驗(yàn)失敗 | 
| 207 | 重放請(qǐng)求 | 
| 301 | 辭典查詢失敗 | 
| 302 | 翻譯查詢失敗 | 
| 303 | 服務(wù)端的其它異常 | 
| 304 | 會(huì)話閑置太久超時(shí) | 
| 401 | 賬戶已經(jīng)欠費(fèi)停 | 
| 402 | offlinesdk不可用 | 
| 411 | 訪問(wèn)頻率受限,請(qǐng)稍后訪問(wèn) | 
| 412 | 長(zhǎng)請(qǐng)求過(guò)于頻繁,請(qǐng)稍后訪問(wèn) | 
| 1001 | 無(wú)效的OCR類型 | 
| 1002 | 不支持的OCR image類型 | 
| 1003 | 不支持的OCR Language類型 | 
| 1004 | 識(shí)別圖片過(guò)大 | 
| 1201 | 圖片base64解密失敗 | 
| 1301 | OCR段落識(shí)別失敗 | 
| 1411 | 訪問(wèn)頻率受限 | 
| 1412 | 超過(guò)最大識(shí)別字節(jié)數(shù) | 
| 2003 | 不支持的語(yǔ)言識(shí)別Language類型 | 
| 2004 | 合成字符過(guò)長(zhǎng) | 
| 2005 | 不支持的音頻文件類型 | 
| 2006 | 不支持的發(fā)音類型 | 
| 2201 | 解密失敗 | 
| 2301 | 服務(wù)的異常 | 
| 2411 | 訪問(wèn)頻率受限,請(qǐng)稍后訪問(wèn) | 
| 2412 | 超過(guò)最大請(qǐng)求字符數(shù) | 
| 3001 | 不支持的語(yǔ)音格式 | 
| 3002 | 不支持的語(yǔ)音采樣率 | 
| 3003 | 不支持的語(yǔ)音聲道 | 
| 3004 | 不支持的語(yǔ)音上傳類型 | 
| 3005 | 不支持的語(yǔ)言類型 | 
| 3006 | 不支持的識(shí)別類型 | 
| 3007 | 識(shí)別音頻文件過(guò)大 | 
| 3008 | 識(shí)別音頻時(shí)長(zhǎng)過(guò)長(zhǎng) | 
| 3009 | 不支持的音頻文件類型 | 
| 3010 | 不支持的發(fā)音類型 | 
| 3201 | 解密失敗 | 
| 3301 | 語(yǔ)音識(shí)別失敗 | 
| 3302 | 語(yǔ)音翻譯失敗 | 
| 3303 | 服務(wù)的異常 | 
| 3411 | 訪問(wèn)頻率受限,請(qǐng)稍后訪問(wèn) | 
| 3412 | 超過(guò)最大請(qǐng)求字符數(shù) | 
| 4001 | 不支持的語(yǔ)音識(shí)別格式 | 
| 4002 | 不支持的語(yǔ)音識(shí)別采樣率 | 
| 4003 | 不支持的語(yǔ)音識(shí)別聲道 | 
| 4004 | 不支持的語(yǔ)音上傳類型 | 
| 4005 | 不支持的語(yǔ)言類型 | 
| 4006 | 識(shí)別音頻文件過(guò)大 | 
| 4007 | 識(shí)別音頻時(shí)長(zhǎng)過(guò)長(zhǎng) | 
| 4201 | 解密失敗 | 
| 4301 | 語(yǔ)音識(shí)別失敗 | 
| 4303 | 服務(wù)的異常 | 
| 4411 | 訪問(wèn)頻率受限,請(qǐng)稍后訪問(wèn) | 
| 4412 | 超過(guò)最大請(qǐng)求時(shí)長(zhǎng) | 
| 5001 | 無(wú)效的OCR類型 | 
| 5002 | 不支持的OCR image類型 | 
| 5003 | 不支持的語(yǔ)言類型 | 
| 5004 | 識(shí)別圖片過(guò)大 | 
| 5005 | 不支持的圖片類型 | 
| 5006 | 文件為空 | 
| 5201 | 解密錯(cuò)誤,圖片base64解密失敗 | 
| 5301 | OCR段落識(shí)別失敗 | 
| 5411 | 訪問(wèn)頻率受限 | 
| 5412 | 超過(guò)最大識(shí)別流量 | 
| 9001 | 不支持的語(yǔ)音格式 | 
| 9002 | 不支持的語(yǔ)音采樣率 | 
| 9003 | 不支持的語(yǔ)音聲道 | 
| 9004 | 不支持的語(yǔ)音上傳類型 | 
| 9005 | 不支持的語(yǔ)音識(shí)別 Language類型 | 
| 9301 | ASR識(shí)別失敗 | 
| 9303 | 服務(wù)器內(nèi)部錯(cuò)誤 | 
| 9411 | 訪問(wèn)頻率受限(超過(guò)最大調(diào)用次數(shù)) | 
| 9412 | 超過(guò)最大處理語(yǔ)音長(zhǎng)度 | 
| 10001 | 無(wú)效的OCR類型 | 
| 10002 | 不支持的OCR image類型 | 
| 10004 | 識(shí)別圖片過(guò)大 | 
| 10201 | 圖片base64解密失敗 | 
| 10301 | OCR段落識(shí)別失敗 | 
| 10411 | 訪問(wèn)頻率受限 | 
| 10412 | 超過(guò)最大識(shí)別流量 | 
| 11001 | 不支持的語(yǔ)音識(shí)別格式 | 
| 11002 | 不支持的語(yǔ)音識(shí)別采樣率 | 
| 11003 | 不支持的語(yǔ)音識(shí)別聲道 | 
| 11004 | 不支持的語(yǔ)音上傳類型 | 
| 11005 | 不支持的語(yǔ)言類型 | 
| 11006 | 識(shí)別音頻文件過(guò)大 | 
| 11007 | 識(shí)別音頻時(shí)長(zhǎng)過(guò)長(zhǎng),最大支持120s | 
| 11008 | 識(shí)別文件為空 | 
| 11009 | 不支持的識(shí)別文件類型 | 
| 11010 | 識(shí)別音頻時(shí)長(zhǎng)過(guò)短 | 
| 11011 | 識(shí)別的音頻內(nèi)容無(wú)效,不做評(píng)分 | 
| 11012 | 識(shí)別的文本內(nèi)容過(guò)短,不做評(píng)分 | 
| 11013 | 非法的單詞評(píng)測(cè)請(qǐng)求,不是單詞 | 
| 11201 | 解密失敗 | 
| 11301 | 口語(yǔ)評(píng)測(cè)請(qǐng)求失敗 | 
| 11302 | 口語(yǔ)評(píng)測(cè)請(qǐng)求超時(shí) | 
| 11303 | 口語(yǔ)評(píng)測(cè)限流,請(qǐng)稍后再試 | 
| 11304 | 服務(wù)異常,請(qǐng)聯(lián)系技術(shù)人員 | 
| 11411 | 訪問(wèn)頻率受限,請(qǐng)稍后訪問(wèn) | 
| 11412 | 超過(guò)最大請(qǐng)求時(shí)長(zhǎng) | 
| 12001 | 圖片尺寸過(guò)大 | 
| 12002 | 圖片base64解密失敗 | 
| 12003 | 引擎服務(wù)器返回錯(cuò)誤 | 
| 12004 | 圖片為空 | 
| 12005 | 不支持的識(shí)別圖片類型 | 
| 12006 | 圖片無(wú)匹配結(jié)果 | 
| 13001 | 不支持的角度類型 | 
| 13002 | 不支持的文件類型 | 
| 13003 | 表格識(shí)別圖片過(guò)大 | 
| 13004 | 文件為空 | 
| 13301 | 表格識(shí)別失敗 | 
| 15001 | 需要圖片 | 
| 15002 | 圖片過(guò)大(1M) | 
| 15003 | 服務(wù)調(diào)用失敗 | 
| 17001 | 需要圖片 | 
| 17002 | 圖片過(guò)大(1M) | 
| 17003 | 識(shí)別類型未找到 | 
| 17004 | 不支持的識(shí)別類型 | 
| 17005 | 服務(wù)調(diào)用失敗 | 
版本更新記錄
| 上線日期 | 版本號(hào) | 更新內(nèi)容 | 
| 2018.12.20 | v1.0.0 | 上線英語(yǔ)口語(yǔ)評(píng)測(cè)服務(wù),從發(fā)音準(zhǔn)確度、完整度、流利度、重音以及實(shí)際發(fā)音對(duì)應(yīng)音標(biāo)的多維度進(jìn)行全方位語(yǔ)音評(píng)測(cè)。 | 
| 2019.04.19 | v1.1.0 | 優(yōu)化打分邏輯,全面提升評(píng)分相關(guān)性。 | 
常用語(yǔ)言 Demo
Java示例
package com.youdao.ai;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.Base64;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class IseV2Demo {
    private static final String YOUDAO_URL = "https://openapi.youdao.com/iseapi";
    private static final String APP_KEY = "您的應(yīng)用ID";
    private static final String APP_SECRET = "您的應(yīng)用密鑰";
    public static String truncate(String q) {
        if (q == null) {
            return null;
        }
        int len = q.length();
        String result;
        return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
    }
    public static String loadAsBase64(String filename) {
        InputStream in = null;
        byte[] data = null;
        try {
            in = new FileInputStream(filename);
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.getEncoder().encodeToString(data);
    }
    public static String doRequest(String url, Map<String,String> requestParams) throws Exception{
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        for (String key : requestParams.keySet()) {
            params.add(new BasicNameValuePair(key, requestParams.get(key)));
        }
        httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
        try {
            HttpEntity httpEntity = httpResponse.getEntity();
            result = EntityUtils.toString(httpEntity, "utf-8");
            EntityUtils.consume(httpEntity);
        } finally {
            try {
                if (httpResponse != null) {
                    httpResponse.close();
                }
            } catch(IOException e) {
                System.out.println("## release resouce error ##" + e);
            }
        }
        return result;
    }
    public static String getDigest(String string) {
        if (string == null) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
        try {
            MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
    public static void main(String[] args) throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        String filename = "音頻的路徑";
        String langType = "合成文本的語(yǔ)言類型";
        params.put("appKey", APP_KEY);
        String q = loadAsBase64(filename);
        params.put("q", q);
        params.put("format", "wav");
        params.put("rate", "16000");
        params.put("channel", "1");
        params.put("docType", "json");
        params.put("type", "1");
        String salt = UUID.randomUUID().toString();
        params.put("salt", salt);
        params.put("langType", langType);
        params.put("text", "音頻對(duì)應(yīng)的文字");
        String curtime = String.valueOf(System.currentTimeMillis() / 1000);
        params.put("curtime", curtime);
        String signStr = APP_KEY + truncate(q) + salt + curtime + APP_SECRET;
        String sign = getDigest(signStr);
        params.put("sign", sign);
        params.put("signType", "v2");
        String result = doRequest(YOUDAO_URL, params);
        System.out.println(result);
    }
}
Python2 示例
# -*- coding: utf-8 -*-
import sys
import uuid
import requests
import wave
import base64
import hashlib
import time
reload(sys)
sys.setdefaultencoding('utf-8')
YOUDAO_URL = 'https://openapi.youdao.com/iseapi'
APP_KEY = '您的應(yīng)用ID'
APP_SECRET = '您的應(yīng)用密鑰'
def truncate(q):
    if q is None:
        return None
    q_utf8 = q.decode("utf-8")
    size = len(q_utf8)
    return q_utf8 if size <= 20 else q_utf8[0:10] + str(size) + q_utf8[size - 10:size]
def encrypt(signStr):
    hash_algorithm = hashlib.sha256()
    hash_algorithm.update(signStr.encode('utf-8'))
    return hash_algorithm.hexdigest()
def do_request(data):
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    return requests.post(YOUDAO_URL, data=data, headers=headers)
def connect():
    audio_file_path = '音頻的路徑'
    lang_type = '合成文本的語(yǔ)言類型'
    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())
    data = {}
    data['text'] = '音頻對(duì)應(yīng)的文字'
    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)
    print response.content
if __name__ == '__main__':
    connect()
Python3 示例
# -*- coding: utf-8 -*-
import sys
import uuid
import requests
import wave
import base64
import hashlib
from imp import reload
import time
reload(sys)
YOUDAO_URL = 'https://openapi.youdao.com/iseapi'
APP_KEY = '您的應(yīng)用ID'
APP_SECRET = '您的應(yīng)用密鑰'
def truncate(q):
    if q is None:
        return None
    size = len(q)
    return q if size <= 20 else q[0:10] + str(size) + q[size-10:size]
def encrypt(signStr):
    hash_algorithm = hashlib.sha256()
    hash_algorithm.update(signStr.encode('utf-8'))
    return hash_algorithm.hexdigest()
def do_request(data):
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    return requests.post(YOUDAO_URL, data=data, headers=headers)
def connect():
    audio_file_path = '音頻的路徑'
    lang_type = '合成文本的語(yǔ)言類型'
    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'] = '音頻對(duì)應(yīng)的文字'
    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)
    print(response.content)
if __name__ == '__main__':
    connect()
C# 示例
using System;
using System.IO;
using System.Web;
using System.Net;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Cryptography;
namespace zhiyun_csharp_demo
{
    class IseV2Demo
    {
        public static void Main()
        {
            String url = "https://openapi.youdao.com/iseapi";
            Dictionary<String, String> dic = new Dictionary<String, String>();
            string q = LoadAsBase64("音頻的路徑");
            string appKey = "您的應(yīng)用ID";
            string appSecret = "您的應(yīng)用密鑰";
            string langType = "合成文本的語(yǔ)言類型";
            string format = "wav";
            string rate = "16000";
            string channel = "1";
            string type = "1";
            string salt = Guid.NewGuid().ToString();
            dic.Add("text", "音頻對(duì)應(yīng)的文字");
            TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            long millis = (long) ts.TotalMilliseconds;
            string curtime = Convert.ToString(millis / 1000);
            dic.Add("curtime", curtime);
            string signStr = appKey + Truncate(q) + salt + curtime + appSecret;;
            string sign = ComputeHash(signStr, new SHA256CryptoServiceProvider());
            dic.Add("q", System.Web.HttpUtility.UrlEncode(q));
            dic.Add("appKey", appKey);
            dic.Add("langType", langType);
            dic.Add("format", format);
            dic.Add("rate", rate);
            dic.Add("channel", channel);
            dic.Add("type", type);
            dic.Add("salt", salt);
            dic.Add("sign", sign);
            dic.Add("signType", "v2");
            string result = Post(url, dic);
            Console.WriteLine(result);
        }
        protected static string ComputeHash(string input, HashAlgorithm algorithm)
        {
          Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
          Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
          return BitConverter.ToString(hashedBytes).Replace("-", "");
        }
        protected static string Truncate(string q)
        {
            if (q == null)
            {
               return null;
            }
            int len = q.Length;
            return len <= 20 ? q : (q.Substring(0, 10) + len + q.Substring(len - 10, 10));
        }
        protected static string LoadAsBase64(string filename)
        {
            try
            {
                FileStream filestream = new FileStream(filename, FileMode.Open);
                byte[] arr = new byte[filestream.Length];
                filestream.Position = 0;
                filestream.Read(arr, 0, (int)filestream.Length);
                filestream.Close();
                return Convert.ToBase64String(arr);
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        protected static string Post(string url, Dictionary<String, String> dic)
        {
            string result = "";
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            StringBuilder builder = new StringBuilder();
            int i = 0;
            foreach (var item in dic)
            {
                if (i > 0)
                    builder.Append("&");
                builder.AppendFormat("{0}={1}", item.Key, item.Value);
                i++;
            }
            byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
            req.ContentLength = data.Length;
            using (Stream reqStream = req.GetRequestStream())
            {
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();
            }
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            Stream stream = resp.GetResponseStream();
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
            {
                result = reader.ReadToEnd();
            }
            return result;
        }
    }
}
php 示例
<?php
define("CURL_TIMEOUT",   2000);
define("URL",            "https://openapi.youdao.com/iseapi");
define("APP_KEY",        "您的應(yīng)用ID"); // 替換為您的應(yīng)用ID
define("SEC_KEY",        "您的應(yīng)用密鑰"); // 替換為您的密鑰
function do_request($q, $langType, $channel, $rate, $format)
{
    $salt = create_guid();
    $args = array(
        'q' => $q,
        'appKey' => APP_KEY,
        'salt' => $salt,
        'langType' => $langType,
        'channel' => $channel,
        'rate' => $rate,
        'format' => $format,
        'type' => "1",
        'signType' => "v2",
    );
    $args['text'] = '音頻對(duì)應(yīng)的文字';
    $curtime = strtotime("now");
    $args['curtime'] = $curtime;
    $signStr = APP_KEY . truncate($q) . $salt . $curtime . SEC_KEY;
    $args['sign'] = hash("sha256", $signStr);
    $ret = call(URL, $args);
    print_r($ret);
    $ret = json_decode($ret, true);
    return $ret;
}
// 發(fā)起網(wǎng)絡(luò)請(qǐng)求
function call($url, $args=null, $method="post", $testflag = 0, $timeout = CURL_TIMEOUT, $headers=array())
{
    $ret = false;
    $i = 0;
    while($ret === false)
    {
        if($i > 1)
            break;
        if($i > 0)
        {
            sleep(1);
        }
        $ret = callOnce($url, $args, $method, false, $timeout, $headers);
        $i++;
    }
    return $ret;
}
function callOnce($url, $args=null, $method="post", $withCookie = false, $timeout = CURL_TIMEOUT, $headers=array())
{
    $ch = curl_init();
    if($method == "post")
    {
        $data = convert($args);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_POST, 1);
    }
    else
    {
        $data = convert($args);
        if($data)
        {
            if(stripos($url, "?") > 0)
            {
                $url .= "&$data";
            }
            else
            {
                $url .= "?$data";
            }
        }
    }
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if(!empty($headers))
    {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }
    if($withCookie)
    {
        curl_setopt($ch, CURLOPT_COOKIEJAR, $_COOKIE);
    }
    $r = curl_exec($ch);
    curl_close($ch);
    return $r;
}
function convert(&$args)
{
    $data = '';
    if (is_array($args))
    {
        foreach ($args as $key=>$val)
        {
            if (is_array($val))
            {
                foreach ($val as $k=>$v)
                {
                    $data .= $key.'['.$k.']='.rawurlencode($v).'&';
                }
            }
            else
            {
                $data .="$key=".rawurlencode($val)."&";
            }
        }
        return trim($data, "&");
    }
    return $args;
}
// uuid generator
function create_guid(){
    $microTime = microtime();
    list($a_dec, $a_sec) = explode(" ", $microTime);
    $dec_hex = dechex($a_dec* 1000000);
    $sec_hex = dechex($a_sec);
    ensure_length($dec_hex, 5);
    ensure_length($sec_hex, 6);
    $guid = "";
    $guid .= $dec_hex;
    $guid .= create_guid_section(3);
    $guid .= '-';
    $guid .= create_guid_section(4);
    $guid .= '-';
    $guid .= create_guid_section(4);
    $guid .= '-';
    $guid .= create_guid_section(4);
    $guid .= '-';
    $guid .= $sec_hex;
    $guid .= create_guid_section(6);
    return $guid;
}
function truncate($q) {
    $len = abslength($q);
    return $len <= 20 ? $q : (mb_substr($q, 0, 10) . $len . mb_substr($q, $len - 10, $len));
}
function abslength($str)
{
    if(empty($str)){
        return 0;
    }
    if(function_exists('mb_strlen')){
        return mb_strlen($str,'utf-8');
    }
    else {
        preg_match_all("/./u", $str, $ar);
        return count($ar[0]);
    }
}
function ensure_length(&$string, $length){
    $strlen = strlen($string);
    if($strlen < $length)
    {
        $string = str_pad($string, $length, "0");
    }
    else if($strlen > $length)
    {
        $string = substr($string, 0, $length);
    }
}
function create_guid_section($characters){
    $return = "";
    for($i = 0; $i < $characters; $i++)
    {
        $return .= dechex(mt_rand(0,15));
    }
    return $return;
}
$file = "音頻的路徑";
$langType = "合成文本的語(yǔ)言類型";
$fp = fopen($file, "r") or die("Can't open file");
// base64編碼
$q = chunk_split(base64_encode(fread($fp, filesize($file))));
fclose($fp);
do_request($q, $langType, "1", 16000, "wav");
?>