語音評測 API 簡介
概念解釋
語音評測:通過語音評測技術(shù)自動對發(fā)音水平進(jìn)行不同維度下的評價,給出用戶發(fā)音信息和得分詳情。
說明
Hi,您好,歡迎使用有道智云智能語音評測服務(wù)。
如果您想快速體驗服務(wù),建議您前往 語音評測體驗中心 或者在體驗中心右下側(cè)找到小程序二維碼,掃描進(jìn)行體驗。
本文檔主要針對需要集成短語音識別服務(wù)HTTP API的開發(fā)工程師
,詳細(xì)描述有道智云語音評測能力及如何集成的技術(shù)內(nèi)容。
如果您有與我們商務(wù)合作的需求,可以通過以下方式聯(lián)系我們:
商務(wù)郵箱: AIcloud_Business@corp.youdao.com
如果您對文檔內(nèi)容有任何疑問,可以通過以下幾種方式聯(lián)系我們:
客服QQ:1906538062
智云語音技術(shù)交流QQ群:861723255
聯(lián)系郵箱: zhiyun@corp.youdao.com
溫馨提示:
- 本文檔主要針對開發(fā)人員,接入測試前需要在后臺創(chuàng)建API應(yīng)用,獲取
應(yīng)用ID
和應(yīng)用密鑰
;如果您還沒有,請按照 新手指南 獲取。 - 平臺向每個賬戶贈送50元的體驗金,供用戶集成前測試所用,具體資費規(guī)則詳見 語音評測服務(wù)報價 。
接口說明
有道語音評測服務(wù)對用戶發(fā)音的完整度、流利度、準(zhǔn)確度進(jìn)行全方位評測,并能對發(fā)音錯誤、缺陷進(jìn)行定位。支持的音頻格式為16K采樣率,16bits 精度的 wav 音頻,目前支持的語種為中英文。
接口地址:
https接口: https://openapi.youdao.com/iseapi
語音支持:
格式支持:wav(不壓縮、pcm編碼)
采樣率:推薦16k。
編碼:16bit位深的單聲道
接口調(diào)用參數(shù)
調(diào)用API需要向接口發(fā)送以下字段來訪問服務(wù)。
字段名 | 類型 | 含義 | 必填 | 備注 |
---|
q | text | 要評測的音頻文件的Base64編碼字符串 | True | 必須是Base64編碼,編碼后不超過20M |
text | text | 要評測的音頻文件對應(yīng)的文本 | True | have a good day |
langType | text | 源語言 | True | 支持語言 |
appKey | text | 應(yīng)用ID | True | 可在 應(yīng)用管理 查看 |
salt | text | UUID | True | uuid,唯一通用識別碼 |
curtime | text | 時間戳(秒) | True | TimeStamp |
sign | text | 簽名,通過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 | 語音文件的格式,wav | true | wav |
rate | text | 采樣率,推薦 16000 采用率 | true | 16000 |
channel | text | 聲道數(shù), 僅支持單聲道,請?zhí)顚懝潭ㄖ? | true | 1 |
type | text | 上傳類型, 僅支持base64上傳,請?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的計算方式為:input
=q前10個字符
+ q長度
+ q后10個字符
(當(dāng)q長度大于20)或 input
=q字符串
(當(dāng)q長度小于等于20)。
具體示例如下:
a.比如:q="Welcome to youdao AICloud.",字符串長度為26,大于20,其input="Welcome to"(前10個字符) + 26(字符串長度) + "o AICloud."(q字符串后10個字符)。
b.比如:q = "sdT4bWrjS",字符串長度為9,小于20,input = "sdT4bWrjS".
輸出結(jié)果
輸出字段介紹
響應(yīng)結(jié)果是以json形式輸出,包含字段如下表所示:
字段 | 含義 |
---|
errorCode | 識別結(jié)果錯誤碼,一定存在。 詳細(xì)信息可見 錯誤代碼列表 |
refText | 請求的文本 |
start | 音頻中句子開始時間,單位是秒 |
end | 音頻中句子結(jié)束時間,單位是秒 |
integrity | 句子完整度得分 |
fluency | 句子流利度得分 |
pronunciation | 句子準(zhǔn)確度得分 |
speed | 語速,單詞/分鐘 |
overall | 句子綜合評分 |
words | 單詞評分?jǐn)?shù)組 |
-word | 單詞 |
-start | 單詞開始時間,單位是秒 |
-end | 單詞結(jié)束時間,單位是秒 |
-pronunciation | 單詞準(zhǔn)確度得分 |
-phonemes | 音標(biāo)數(shù)組 |
--phoneme | 音標(biāo) |
--start | 音標(biāo)開始時間,單位是秒 |
--end | 音標(biāo)結(jié)束時間,單位是秒 |
--judge | 判斷音素是否錯誤,true為發(fā)音正確,false為發(fā)音錯誤,同時calibration給出提示 |
--calibration | 如果發(fā)音錯誤,提示用戶該發(fā)音像什么 |
--prominence | 重音程度,分?jǐn)?shù)越高,當(dāng)前音標(biāo)越可能是重音,分?jǐn)?shù)在[0 100] |
--stress_ref | 元音重音參考/標(biāo)準(zhǔn)答案,如果為true,說明參考答案認(rèn)為該元音應(yīng)該發(fā)重音,輔音時無意義 |
--stress_detect | 在一個單詞中,用戶該音標(biāo)發(fā)音為重音 |
輸出結(jié)果示例
{
"intonation": "", // 預(yù)留字段,目前未使用
"refText": "have a good day", //待評測語音對應(yīng)的文本
"pronunciation": 100, //句子發(fā)音準(zhǔn)確度
"start": 0.180000, //音頻開始時間,秒
"words": [ //單詞信息列表
{
"phonics": [],
"pronunciation": 70.216576, //單詞準(zhǔn)確度分?jǐn)?shù)
"start": 0.180000, //單詞開始時間,秒
"end": 0.450000, //單詞結(jié)束時間,秒
"IPA": "h?v", //單詞音標(biāo)
"word": "have", //單詞文本
"phonemes": [ //音標(biāo)信息列表
{
"stress_ref": false, //元音重音參考(即標(biāo)準(zhǔn)重音),如果為true,說明參考答案認(rèn)為該元音應(yīng)該發(fā)重音,輔音時無意義
"pronunciation": 44.661324, //音標(biāo)準(zhǔn)確度評分
"stress_detect": false, //在一個單詞中,用戶該音標(biāo)發(fā)音不為重音
"phoneme": "h", //音標(biāo)名稱
"start": 0.180000, //音標(biāo)開始時間,秒
"end": 0.330000, //音標(biāo)結(jié)束時間,秒
"judge": true, //判斷音標(biāo)是否錯誤,true為發(fā)音正確,false為發(fā)音錯誤,同時calibration給出提示
"calibration": "h", //判斷音標(biāo)是否錯誤,true為發(fā)音正確,false為發(fā)音錯誤,同時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", //識別結(jié)果錯誤碼,一定存在
"version": "capt-onetime-en:online-V2.0.8", // 服務(wù)版本號
"speed": 242.424210, // 句子語速(單詞/分鐘)
"integrity": 100, //句子完整度
"emotion": 0, // 預(yù)留字段,目前未使用
"service": "capt", // 服務(wù)標(biāo)識
"requestId": "4e9e84ef-dc06-4899-9f24-8c5043dd672d", // 請求ID
"overall": 100, //句子綜合評分
"end": 1.170000 //句子結(jié)束時間,秒
}
支持語言
目前支持中英文的語音評測。
服務(wù)配置
支持格式 | 音頻大小上限 | 單次最大請求時長(s) | 每小時最大查詢次數(shù) | 支持語言 |
---|
wav | 20M(編碼后) | 120 | 3000 | 英 |
錯誤代碼列表
錯誤碼 | 含義 |
---|
101 | 缺少必填的參數(shù),首先確保必填參數(shù)齊全,然后,確認(rèn)參數(shù)書寫是否正確。 |
102 | 不支持的語言類型 |
103 | 翻譯文本過長 |
104 | 不支持的API類型 |
105 | 不支持的簽名類型 |
106 | 不支持的響應(yīng)類型 |
107 | 不支持的傳輸加密類型 |
108 | 應(yīng)用ID無效,注冊賬號,登錄后臺創(chuàng)建應(yīng)用并完成綁定,可獲得應(yīng)用ID和應(yīng)用密鑰等信息 |
109 | batchLog格式不正確 |
110 | 無相關(guān)服務(wù)的有效實例,應(yīng)用沒有綁定服務(wù)實例,可以新建服,綁定服務(wù)。注:某些服務(wù)的結(jié)果發(fā)音需要tts服務(wù),需要在控制臺創(chuàng)建語音合成服務(wù)綁定應(yīng)用后方能使用。 |
111 | 開發(fā)者賬號無效 |
112 | 請求服務(wù)無效 |
113 | q不能為空 |
114 | 不支持的圖片傳輸方式 |
201 | 解密失敗,可能為DES,BASE64,URLDecode的錯誤 |
202 | 簽名檢驗失敗,如果確認(rèn)應(yīng)用ID和應(yīng)用密鑰的正確性,仍返回202,一般是編碼問題。請確保翻譯文本 q 為UTF-8編碼. |
203 | 訪問IP地址不在可訪問IP列表 |
205 | 請求的接口與應(yīng)用的平臺類型不一致,確保接入方式(Android SDK、IOS SDK、API)與創(chuàng)建的應(yīng)用平臺類型一致。如有疑問請參考入門指南 |
206 | 因為時間戳無效導(dǎo)致簽名校驗失敗 |
207 | 重放請求 |
301 | 辭典查詢失敗 |
302 | 翻譯查詢失敗 |
303 | 服務(wù)端的其它異常 |
304 | 會話閑置太久超時 |
401 | 賬戶已經(jīng)欠費停 |
402 | offlinesdk不可用 |
411 | 訪問頻率受限,請稍后訪問 |
412 | 長請求過于頻繁,請稍后訪問 |
1001 | 無效的OCR類型 |
1002 | 不支持的OCR image類型 |
1003 | 不支持的OCR Language類型 |
1004 | 識別圖片過大 |
1201 | 圖片base64解密失敗 |
1301 | OCR段落識別失敗 |
1411 | 訪問頻率受限 |
1412 | 超過最大識別字節(jié)數(shù) |
2003 | 不支持的語言識別Language類型 |
2004 | 合成字符過長 |
2005 | 不支持的音頻文件類型 |
2006 | 不支持的發(fā)音類型 |
2201 | 解密失敗 |
2301 | 服務(wù)的異常 |
2411 | 訪問頻率受限,請稍后訪問 |
2412 | 超過最大請求字符數(shù) |
3001 | 不支持的語音格式 |
3002 | 不支持的語音采樣率 |
3003 | 不支持的語音聲道 |
3004 | 不支持的語音上傳類型 |
3005 | 不支持的語言類型 |
3006 | 不支持的識別類型 |
3007 | 識別音頻文件過大 |
3008 | 識別音頻時長過長 |
3009 | 不支持的音頻文件類型 |
3010 | 不支持的發(fā)音類型 |
3201 | 解密失敗 |
3301 | 語音識別失敗 |
3302 | 語音翻譯失敗 |
3303 | 服務(wù)的異常 |
3411 | 訪問頻率受限,請稍后訪問 |
3412 | 超過最大請求字符數(shù) |
4001 | 不支持的語音識別格式 |
4002 | 不支持的語音識別采樣率 |
4003 | 不支持的語音識別聲道 |
4004 | 不支持的語音上傳類型 |
4005 | 不支持的語言類型 |
4006 | 識別音頻文件過大 |
4007 | 識別音頻時長過長 |
4201 | 解密失敗 |
4301 | 語音識別失敗 |
4303 | 服務(wù)的異常 |
4411 | 訪問頻率受限,請稍后訪問 |
4412 | 超過最大請求時長 |
5001 | 無效的OCR類型 |
5002 | 不支持的OCR image類型 |
5003 | 不支持的語言類型 |
5004 | 識別圖片過大 |
5005 | 不支持的圖片類型 |
5006 | 文件為空 |
5201 | 解密錯誤,圖片base64解密失敗 |
5301 | OCR段落識別失敗 |
5411 | 訪問頻率受限 |
5412 | 超過最大識別流量 |
9001 | 不支持的語音格式 |
9002 | 不支持的語音采樣率 |
9003 | 不支持的語音聲道 |
9004 | 不支持的語音上傳類型 |
9005 | 不支持的語音識別 Language類型 |
9301 | ASR識別失敗 |
9303 | 服務(wù)器內(nèi)部錯誤 |
9411 | 訪問頻率受限(超過最大調(diào)用次數(shù)) |
9412 | 超過最大處理語音長度 |
10001 | 無效的OCR類型 |
10002 | 不支持的OCR image類型 |
10004 | 識別圖片過大 |
10201 | 圖片base64解密失敗 |
10301 | OCR段落識別失敗 |
10411 | 訪問頻率受限 |
10412 | 超過最大識別流量 |
11001 | 不支持的語音識別格式 |
11002 | 不支持的語音識別采樣率 |
11003 | 不支持的語音識別聲道 |
11004 | 不支持的語音上傳類型 |
11005 | 不支持的語言類型 |
11006 | 識別音頻文件過大 |
11007 | 識別音頻時長過長,最大支持120s |
11008 | 識別文件為空 |
11009 | 不支持的識別文件類型 |
11010 | 識別音頻時長過短 |
11011 | 識別的音頻內(nèi)容無效,不做評分 |
11012 | 識別的文本內(nèi)容過短,不做評分 |
11013 | 非法的單詞評測請求,不是單詞 |
11201 | 解密失敗 |
11301 | 口語評測請求失敗 |
11302 | 口語評測請求超時 |
11303 | 口語評測限流,請稍后再試 |
11304 | 服務(wù)異常,請聯(lián)系技術(shù)人員 |
11411 | 訪問頻率受限,請稍后訪問 |
11412 | 超過最大請求時長 |
12001 | 圖片尺寸過大 |
12002 | 圖片base64解密失敗 |
12003 | 引擎服務(wù)器返回錯誤 |
12004 | 圖片為空 |
12005 | 不支持的識別圖片類型 |
12006 | 圖片無匹配結(jié)果 |
13001 | 不支持的角度類型 |
13002 | 不支持的文件類型 |
13003 | 表格識別圖片過大 |
13004 | 文件為空 |
13301 | 表格識別失敗 |
15001 | 需要圖片 |
15002 | 圖片過大(1M) |
15003 | 服務(wù)調(diào)用失敗 |
17001 | 需要圖片 |
17002 | 圖片過大(1M) |
17003 | 識別類型未找到 |
17004 | 不支持的識別類型 |
17005 | 服務(wù)調(diào)用失敗 |
版本更新記錄
上線日期 | 版本號 | 更新內(nèi)容 |
---|
2018.12.20 | v1.0.0 | 上線英語口語評測服務(wù),從發(fā)音準(zhǔn)確度、完整度、流利度、重音以及實際發(fā)音對應(yīng)音標(biāo)的多維度進(jìn)行全方位語音評測。 |
2019.04.19 | v1.1.0 | 優(yōu)化打分邏輯,全面提升評分相關(guān)性。 |
常用語言 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 = "合成文本的語言類型";
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", "音頻對應(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 = '合成文本的語言類型'
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'] = '音頻對應(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 = '合成文本的語言類型'
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'] = '音頻對應(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 = "合成文本的語言類型";
string format = "wav";
string rate = "16000";
string channel = "1";
string type = "1";
string salt = Guid.NewGuid().ToString();
dic.Add("text", "音頻對應(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'] = '音頻對應(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ò)請求
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 = "合成文本的語言類型";
$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");
?>