移動(dòng)端應(yīng)用如何安全訪問(wèn)智能語(yǔ)音交互服務(wù)
為了避免在移動(dòng)端App或者桌面端工具中保存固定AccessKey ID和AccessKey Secret可能引起的泄露風(fēng)險(xiǎn),您可以通過(guò)在App服務(wù)端創(chuàng)建Token并下發(fā)到移動(dòng)端使用,或使用STS臨時(shí)訪問(wèn)憑證調(diào)用語(yǔ)音服務(wù)兩種方式,更加安全地訪問(wèn)智能語(yǔ)音交互服務(wù)。
背景信息
方案 | 適用接口 |
| |
離線語(yǔ)音合成 |
方案一:通過(guò)App服務(wù)端創(chuàng)建Token并下發(fā)到移動(dòng)端使用
前提條件
已開(kāi)通智能語(yǔ)音交互服務(wù),并根據(jù)產(chǎn)品文檔調(diào)試成功,具體操作,請(qǐng)參見(jiàn)開(kāi)通服務(wù)。
適用場(chǎng)景
如果您作為移動(dòng)App開(kāi)發(fā)者或者桌面端開(kāi)發(fā)者,希望您的用戶調(diào)用阿里云智能語(yǔ)音交互產(chǎn)品的語(yǔ)音合成、一句話識(shí)別、實(shí)時(shí)識(shí)別等服務(wù)時(shí),為避免在移動(dòng)端App或者桌面端工具中保存固定AccessKey ID和AccessKey Secret可能引起的泄露風(fēng)險(xiǎn),您可以使用App服務(wù)端下發(fā)語(yǔ)音Token調(diào)用服務(wù)。
交互流程
App端向用戶應(yīng)用服務(wù)器請(qǐng)求一個(gè)調(diào)用智能語(yǔ)音交互接口所依賴的語(yǔ)音Token,此處使用您自有的通信協(xié)議即可,比如用戶登錄時(shí)自動(dòng)請(qǐng)求或服務(wù)端自動(dòng)下發(fā),或定時(shí)向應(yīng)用服務(wù)器發(fā)起請(qǐng)求。
用戶應(yīng)用服務(wù)器向阿里云智能語(yǔ)音服務(wù)發(fā)起創(chuàng)建語(yǔ)音Token的真正請(qǐng)求,此處請(qǐng)您使用阿里云SDK或智能語(yǔ)音交互SDK來(lái)創(chuàng)建Token,創(chuàng)建Token所需的AccessKey ID和AccessKey Secret保存在您的應(yīng)用服務(wù)器上。由于語(yǔ)音Token具有時(shí)效性,您可以在有效期范圍內(nèi)直接返回給App端,無(wú)需每次都向智能語(yǔ)音交互服務(wù)請(qǐng)求新的Token。
智能語(yǔ)音交互服務(wù)返回給應(yīng)用服務(wù)器一個(gè)語(yǔ)音Token信息,包括Token字符串及有效期時(shí)間,在有效期內(nèi),您可以多次復(fù)用該Token而無(wú)需重新創(chuàng)建,Token的使用不受不同用戶、不同設(shè)備的限制。
用戶應(yīng)用服務(wù)器將Token返回給App端,此時(shí)App端可以緩存并使用該Token,直到Token失效。當(dāng)Token失效時(shí),App端需要向應(yīng)用服務(wù)器申請(qǐng)新的Token。假設(shè)Token憑證有效期為24小時(shí),App端可以在Token過(guò)期前1到2小時(shí)主動(dòng)向應(yīng)用服務(wù)器請(qǐng)求更新Token。
App端使用獲取到的Token構(gòu)建請(qǐng)求,向阿里云智能語(yǔ)音交互公共云發(fā)起調(diào)用,比如調(diào)用實(shí)時(shí)語(yǔ)音識(shí)別、一句話識(shí)別、語(yǔ)音合成等接口(不包括錄音文件識(shí)別、錄音文件識(shí)別閑時(shí)版等離線類(lèi)接口),更多信息,請(qǐng)參見(jiàn)阿里云智能語(yǔ)音交互相關(guān)文檔。
此方案無(wú)需過(guò)多額外設(shè)置或開(kāi)發(fā),將AccessKey ID和AccessKey Secret保存到移動(dòng)端改為保存到用戶自己的服務(wù)端,并通過(guò)服務(wù)端創(chuàng)建語(yǔ)音Token再下發(fā)給移動(dòng)端使用,兼容了使用安全性及開(kāi)發(fā)便捷性。
方案二:使用STS臨時(shí)訪問(wèn)憑證調(diào)用語(yǔ)音服務(wù)
阿里云STS(Security Token Service)是阿里云提供的一種臨時(shí)訪問(wèn)權(quán)限管理服務(wù)。您可以通過(guò)STS服務(wù)給其他用戶頒發(fā)臨時(shí)訪問(wèn)憑證,該用戶可使用臨時(shí)訪問(wèn)憑證,在規(guī)定時(shí)間內(nèi)調(diào)用智能語(yǔ)音交互的錄音文件識(shí)別服務(wù)(含閑時(shí)版)。臨時(shí)訪問(wèn)憑證無(wú)需透露您的長(zhǎng)期密鑰,保障您的賬戶更加安全。
前提條件
已確保當(dāng)前賬號(hào)為阿里云賬號(hào)或者被授予AliyunRAMFullAccess權(quán)限的RAM用戶。關(guān)于為RAM用戶授權(quán)的具體步驟,請(qǐng)參見(jiàn)為RAM用戶授權(quán)。
適用場(chǎng)景
如果您作為移動(dòng)App開(kāi)發(fā)者或者桌面端開(kāi)發(fā)者,希望您的用戶調(diào)用阿里云智能語(yǔ)音交互產(chǎn)品的錄音文件識(shí)別等服務(wù)時(shí),避免在移動(dòng)端App或者桌面端工具中保存固定AccessKey ID和AccessKey Secret可能引起的泄露風(fēng)險(xiǎn),您可以使用STS授權(quán)用戶調(diào)用服務(wù)。
交互流程
App端向用戶應(yīng)用服務(wù)器請(qǐng)求STS臨時(shí)訪問(wèn)憑證,此處使用用戶自有的通信協(xié)議即可,比如用戶登錄時(shí)自動(dòng)請(qǐng)求或服務(wù)端自動(dòng)下發(fā),或定時(shí)向應(yīng)用服務(wù)器發(fā)起請(qǐng)求。
用戶應(yīng)用服務(wù)器向阿里云STS服務(wù)發(fā)起STS請(qǐng)求,此處請(qǐng)使用阿里云SDK,根據(jù)應(yīng)用服務(wù)器自身保存的固定AK向STS請(qǐng)求生成一個(gè)臨時(shí)憑證。
STS返回給應(yīng)用服務(wù)器一個(gè)臨時(shí)訪問(wèn)憑證,包括臨時(shí)訪問(wèn)密鑰(AccessKey ID和AccessKey Secret)、安全令牌(SecurityToken)、該憑證的過(guò)期時(shí)間等信息。
用戶應(yīng)用服務(wù)器將臨時(shí)憑證返回給App端,此時(shí)App端可以緩存并使用該憑證,直到憑證失效。當(dāng)憑證失效時(shí),App端需要向應(yīng)用服務(wù)器申請(qǐng)新的臨時(shí)訪問(wèn)憑證。假設(shè)臨時(shí)訪問(wèn)憑證有效期為1小時(shí),App端可以每30分鐘或者每50分鐘的頻率向應(yīng)用服務(wù)器請(qǐng)求更新臨時(shí)訪問(wèn)憑證。
App端使用獲取到的臨時(shí)憑證構(gòu)建請(qǐng)求,向阿里云智能語(yǔ)音交互公共云發(fā)起調(diào)用,更多信息,請(qǐng)參見(jiàn)阿里云智能語(yǔ)音交互相關(guān)開(kāi)發(fā)文檔。
本文以錄音文件識(shí)別為例,為您介紹相關(guān)示例代碼。
操作步驟
步驟一:創(chuàng)建RAM用戶
登錄RAM控制臺(tái)。
在左側(cè)導(dǎo)航欄,選擇身份管理 > 用戶。
單擊創(chuàng)建用戶。
輸入登錄名稱和顯示名稱。
在訪問(wèn)方式區(qū)域下,選擇Open API 調(diào)用訪問(wèn),然后單擊確定。
單擊復(fù)制,保存訪問(wèn)密鑰(AccessKey ID 和 AccessKey Secret)。
步驟二:為RAM用戶授予請(qǐng)求AssumeRole的權(quán)限
在已創(chuàng)建的RAM用戶右側(cè),單擊對(duì)應(yīng)的添加權(quán)限。
在添加權(quán)限頁(yè)面,選擇AliyunSTSAssumeRoleAccess系統(tǒng)策略。
單擊確定。
步驟三:創(chuàng)建用于獲取臨時(shí)訪問(wèn)憑證的角色
在左側(cè)導(dǎo)航欄,選擇身份管理 > 角色。
單擊創(chuàng)建角色,可信實(shí)體類(lèi)型選擇阿里云賬號(hào),單擊下一步。
填寫(xiě)角色名稱(此處以stsrole為例),選擇當(dāng)前云賬號(hào)。
單擊完成。完成角色創(chuàng)建后,單擊關(guān)閉。
在RAM角色管理頁(yè)面,搜索框輸入角色名稱stsrole。
單擊復(fù)制,保存角色的ARN。
步驟四:為角色授予調(diào)用錄音文件識(shí)別接口的權(quán)限
創(chuàng)建上傳文件的自定義權(quán)限策略。
在左側(cè)導(dǎo)航欄,選擇權(quán)限管理 > 權(quán)限策略。
單擊創(chuàng)建權(quán)限策略。
在創(chuàng)建權(quán)限策略頁(yè)面,單擊腳本編輯。
如果您需要角色具備調(diào)用錄音文件識(shí)別、錄音文件識(shí)別閑時(shí)版服務(wù),請(qǐng)參考以下配置示例。
重要以下示例僅供參考。您需要根據(jù)實(shí)際需求配置更細(xì)粒度的授權(quán)策略,防止出現(xiàn)權(quán)限過(guò)大的風(fēng)險(xiǎn)。關(guān)于更細(xì)粒度的授權(quán)策略配置詳情,請(qǐng)參見(jiàn)通過(guò)RAM或STS服務(wù)向其他用戶授權(quán)。
{ "Version": "1", "Statement": [ { "Action": "nls:SubmitTask", "Resource": "*", "Effect": "Allow" }, { "Action": "nls:GetTaskResult", "Resource": "*", "Effect": "Allow" } ] }
策略配置完成后,單擊繼續(xù)編輯基本信息。
在基本信息區(qū)域,填寫(xiě)策略名稱(此處以nls-stsuser-policy為例),然后單擊確定。
為上面創(chuàng)建的RAM角色stsrole授予自定義權(quán)限策略。
在左側(cè)導(dǎo)航欄,選擇身份管理 > 角色。
在角色頁(yè)面,找到目標(biāo)RAM角色stsrole。
單擊RAM角色stsrole右側(cè)的添加權(quán)限。
在添加權(quán)限頁(yè)面下的自定義策略頁(yè)簽,選擇已創(chuàng)建的自定義權(quán)限策略nls-stsuser-policy。
單擊確定。
步驟五:服務(wù)端獲取STS臨時(shí)訪問(wèn)憑證
需要注意,此步驟并不是在客戶端側(cè)(移動(dòng)端App或桌面端)調(diào)用的,您可以在自己的應(yīng)用服務(wù)器側(cè),通過(guò)您持有的固定AccessKey ID和AccessKey Secret(即步驟一創(chuàng)建RAM用戶時(shí)保存的賬戶信息)創(chuàng)建STS臨時(shí)訪問(wèn)憑證,然后將該憑證通過(guò)您已有的交互鏈路返回給客戶端側(cè)。客戶端側(cè)獲取到臨時(shí)訪問(wèn)憑證后,再調(diào)用步驟六中的錄音文件識(shí)別服務(wù)。
方式一:使用阿里云SDK(推薦)
您可以使用多語(yǔ)言STS SDK獲取臨時(shí)訪問(wèn)憑證。
以下Java代碼用于獲取臨時(shí)訪問(wèn)憑證。
引入POM依賴:
<dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.6</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-sts</artifactId> <version>3.0.0</version> </dependency>
完整示例代碼如下:
import com.aliyuncs.CommonRequest; import com.aliyuncs.CommonResponse; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.auth.sts.AssumeRoleRequest; import com.aliyuncs.auth.sts.AssumeRoleResponse; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.http.MethodType; import com.aliyuncs.http.ProtocolType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; public class CreateStsCredentialsDemo { public static void main(String args[]) throws ClientException { //同region STS的OpenAPI地址 String endpoint = "sts.aliyuncs.com"; // 填寫(xiě)步驟一生成的訪問(wèn)密鑰AccessKey ID和AccessKey Secret。 String accessKeyId = "******"; String accessKeySecret = "******"; // 填寫(xiě)步驟三獲取的角色ARN, 一般是: acs:ram::********:role/*** String roleArn = "******"; // 自定義角色會(huì)話名稱,用來(lái)區(qū)分不同的令牌,例如可填寫(xiě)為nls-role-session-99。 String roleSession = "nls-role-session-99"; // 添加endpoint(直接使用STS endpoint,前兩個(gè)參數(shù)留空,無(wú)需添加region ID) DefaultProfile.addEndpoint("", "Sts", endpoint); // 構(gòu)造default profile(參數(shù)留空,無(wú)需添加region ID) IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret); // 用profile構(gòu)造client DefaultAcsClient client = new DefaultAcsClient(profile); final AssumeRoleRequest request = new AssumeRoleRequest(); request.setRoleArn(roleArn); request.setRoleSessionName(roleSession); final AssumeRoleResponse response = client.getAcsResponse(request); String stsAccessKeyId = response.getCredentials().getAccessKeyId(); String stsAccessKeySecret = response.getCredentials().getAccessKeySecret(); String stsToken = response.getCredentials().getSecurityToken(); System.out.println("Expiration: " + response.getCredentials().getExpiration()); System.out.println("Access Key Id: " + stsAccessKeyId); System.out.println("Access Key Secret: " + stsAccessKeySecret); System.out.println("Security Token: " + stsToken); System.out.println("RequestId: " + response.getRequestId()); } }
方式二:使用REST API
您可以通過(guò)調(diào)用STS服務(wù)接口AssumeRole獲取臨時(shí)訪問(wèn)憑證。
步驟六:客戶端使用臨時(shí)訪問(wèn)憑證調(diào)用錄音文件識(shí)別服務(wù)(或錄音文件識(shí)別閑時(shí)版)
如果您使用的是錄音文件識(shí)別閑時(shí)版服務(wù),本文流程及以下示例代碼都可復(fù)用。
為了調(diào)用錄音文件識(shí)別閑時(shí)版服務(wù),下方的示例代碼的產(chǎn)品信息需要從:
PRODUCT = "nls-filetrans"
DOMAIN = "filetrans.cn-shanghai.aliyuncs.com"
API_VERSION = "2018-08-17"
改為:
PRODUCT = "SpeechFileTranscriberLite"
DOMAIN = "speechfiletranscriberlite.cn-shanghai.aliyuncs.com"
API_VERSION = "2021-12-21"
Java代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件識(shí)別服務(wù)
引入POM依賴:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.6</version>
</dependency>
以下是Java代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件轉(zhuǎn)寫(xiě)服務(wù)的完整示例:
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
public class FileTransByStsJavaDemo {
// 地域ID,常量,固定值。
public static final String REGIONID = "cn-shanghai";
public static final String ENDPOINTNAME = "cn-shanghai";
public static final String PRODUCT = "nls-filetrans";
public static final String DOMAIN = "filetrans.cn-shanghai.aliyuncs.com";
public static final String API_VERSION = "2018-08-17";
public static final String POST_REQUEST_ACTION = "SubmitTask";
public static final String GET_REQUEST_ACTION = "GetTaskResult";
// 請(qǐng)求參數(shù)
public static final String KEY_APP_KEY = "appkey";
public static final String KEY_FILE_LINK = "file_link";
public static final String KEY_VERSION = "version";
public static final String KEY_ENABLE_WORDS = "enable_words";
// 響應(yīng)參數(shù)
public static final String KEY_TASK = "Task";
public static final String KEY_TASK_ID = "TaskId";
public static final String KEY_STATUS_TEXT = "StatusText";
public static final String KEY_RESULT = "Result";
// 狀態(tài)值
public static final String STATUS_SUCCESS = "SUCCESS";
private static final String STATUS_RUNNING = "RUNNING";
private static final String STATUS_QUEUEING = "QUEUEING";
// 阿里云鑒權(quán)client
IAcsClient client;
public FileTransByStsJavaDemo(String stsAccessKeyId, String stsAccessKeySecret, String stsToken) {
// 設(shè)置endpoint
try {
DefaultProfile.addEndpoint(ENDPOINTNAME, REGIONID, PRODUCT, DOMAIN);
} catch (ClientException e) {
e.printStackTrace();
}
// 創(chuàng)建DefaultAcsClient實(shí)例并初始化
DefaultProfile profile = DefaultProfile.getProfile(REGIONID, stsAccessKeyId, stsAccessKeySecret, stsToken);
this.client = new DefaultAcsClient(profile);
}
public String submitFileTransRequest(String appKey, String fileLink) {
/**
* 1. 創(chuàng)建CommonRequest,設(shè)置請(qǐng)求參數(shù)。
*/
CommonRequest postRequest = new CommonRequest();
// 設(shè)置域名
postRequest.setDomain(DOMAIN);
// 設(shè)置API的版本號(hào),格式為YYYY-MM-DD。
postRequest.setVersion(API_VERSION);
// 設(shè)置action
postRequest.setAction(POST_REQUEST_ACTION);
// 設(shè)置產(chǎn)品名稱
postRequest.setProduct(PRODUCT);
/**
* 2. 設(shè)置錄音文件識(shí)別請(qǐng)求參數(shù),以JSON字符串的格式設(shè)置到請(qǐng)求Body中。
*/
JSONObject taskObject = new JSONObject();
// 設(shè)置appkey
taskObject.put(KEY_APP_KEY, appKey);
// 設(shè)置音頻文件訪問(wèn)鏈接
taskObject.put(KEY_FILE_LINK, fileLink);
// 新接入請(qǐng)使用4.0版本,已接入(默認(rèn)2.0)如需維持現(xiàn)狀,請(qǐng)注釋掉該參數(shù)設(shè)置。
taskObject.put(KEY_VERSION, "4.0");
// 設(shè)置是否輸出詞信息,默認(rèn)為false,開(kāi)啟時(shí)需要設(shè)置version為4.0及以上。
taskObject.put(KEY_ENABLE_WORDS, true);
String task = taskObject.toJSONString();
System.out.println(task);
// 設(shè)置以上JSON字符串為Body參數(shù)。
postRequest.putBodyParameter(KEY_TASK, task);
// 設(shè)置為POST方式的請(qǐng)求。
postRequest.setMethod(MethodType.POST);
/**
* 3. 提交錄音文件識(shí)別請(qǐng)求,獲取錄音文件識(shí)別請(qǐng)求任務(wù)的ID,以供識(shí)別結(jié)果查詢使用。
*/
String taskId = null;
try {
CommonResponse postResponse = client.getCommonResponse(postRequest);
System.err.println("提交錄音文件識(shí)別請(qǐng)求的響應(yīng):" + postResponse.getData());
if (postResponse.getHttpStatus() == 200) {
JSONObject result = JSONObject.parseObject(postResponse.getData());
String statusText = result.getString(KEY_STATUS_TEXT);
if (STATUS_SUCCESS.equals(statusText)) {
taskId = result.getString(KEY_TASK_ID);
}
}
} catch (ClientException e) {
e.printStackTrace();
}
return taskId;
}
public String getFileTransResult(String taskId) {
/**
* 1. 創(chuàng)建CommonRequest,設(shè)置任務(wù)ID。
*/
CommonRequest getRequest = new CommonRequest();
// 設(shè)置域名
getRequest.setDomain(DOMAIN);
// 設(shè)置API版本
getRequest.setVersion(API_VERSION);
// 設(shè)置action
getRequest.setAction(GET_REQUEST_ACTION);
// 設(shè)置產(chǎn)品名稱
getRequest.setProduct(PRODUCT);
// 設(shè)置任務(wù)ID為查詢參數(shù)
getRequest.putQueryParameter(KEY_TASK_ID, taskId);
// 設(shè)置為GET方式的請(qǐng)求
getRequest.setMethod(MethodType.GET);
/**
* 2. 提交錄音文件識(shí)別結(jié)果查詢請(qǐng)求
* 以輪詢的方式進(jìn)行識(shí)別結(jié)果的查詢,直到服務(wù)端返回的狀態(tài)描述為“SUCCESS”或錯(cuò)誤描述,則結(jié)束輪詢。
*/
String result = null;
while (true) {
try {
CommonResponse getResponse = client.getCommonResponse(getRequest);
System.err.println("識(shí)別查詢結(jié)果:" + getResponse.getData());
if (getResponse.getHttpStatus() != 200) {
break;
}
JSONObject rootObj = JSONObject.parseObject(getResponse.getData());
String statusText = rootObj.getString(KEY_STATUS_TEXT);
if (STATUS_RUNNING.equals(statusText) || STATUS_QUEUEING.equals(statusText)) {
// 繼續(xù)輪詢,注意設(shè)置輪詢時(shí)間間隔。
Thread.sleep(10000);
}
else {
// 狀態(tài)信息為成功,返回識(shí)別結(jié)果;狀態(tài)信息為異常,返回空。
if (STATUS_SUCCESS.equals(statusText)) {
result = rootObj.getString(KEY_RESULT);
// 狀態(tài)信息為成功,但沒(méi)有識(shí)別結(jié)果,則可能是由于文件里全是靜音、噪音等導(dǎo)致識(shí)別為空。
if(result == null) {
result = "";
}
}
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
public static void main(String args[]) throws Exception {
// 相比非STS模式,此時(shí)此處填寫(xiě)之前生成的STS臨時(shí)訪問(wèn)憑證。
// 特別需要注意的是:臨時(shí)訪問(wèn)憑證存在有效期,在有效期內(nèi)您可以一直使用,但是請(qǐng)?jiān)谶^(guò)期前及時(shí)再次獲取
final String stsAccessKeyId = "STS.******";
final String stsAccessKeySecret = "******";
final String stsToken = "******";
final String appKey = "******";
String fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav";
FileTransByStsJavaDemo demo = new FileTransByStsJavaDemo(stsAccessKeyId, stsAccessKeySecret, stsToken);
// 第一步:提交錄音文件識(shí)別請(qǐng)求,獲取任務(wù)ID用于后續(xù)的識(shí)別結(jié)果輪詢。
String taskId = demo.submitFileTransRequest(appKey, fileLink);
if (taskId != null) {
System.out.println("錄音文件識(shí)別請(qǐng)求成功,task_id: " + taskId);
}
else {
System.out.println("錄音文件識(shí)別請(qǐng)求失?。?);
return;
}
// 第二步:根據(jù)任務(wù)ID輪詢識(shí)別結(jié)果。
String result = demo.getFileTransResult(taskId);
if (result != null) {
System.out.println("錄音文件識(shí)別結(jié)果查詢成功:" + result);
}
else {
System.out.println("錄音文件識(shí)別結(jié)果查詢失??!");
}
}
}
Python代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件識(shí)別服務(wù)
# -*- coding: utf-8 -*-
import json
import time
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.auth.credentials import StsTokenCredential
from aliyunsdkcore.request import CommonRequest
REGION_ID = "cn-shanghai"
DOMAIN = "filetrans.cn-shanghai.aliyuncs.com"
PRODUCT = "nls-filetrans"
API_VERSION = "2018-08-17"
POST_REQUEST_ACTION = "SubmitTask"
GET_REQUEST_ACTION = "GetTaskResult"
KEY_APP_KEY = "appkey"
KEY_FILE_LINK = "file_link"
KEY_VERSION = "version"
KEY_TASK = "Task"
KEY_TASK_ID = "TaskId"
KEY_STATUS_TEXT = "StatusText"
def submitTask(stsAkId, stsAkSecret, stsToken, appKey, fileLink):
# 創(chuàng)建AcsClient實(shí)例
stsTokenCredential = StsTokenCredential(stsAkId, stsAkSecret, stsToken)
client = AcsClient(region_id=REGION_ID, credential=stsTokenCredential)
# 創(chuàng)建提交錄音文件識(shí)別請(qǐng)求,并設(shè)置請(qǐng)求參數(shù)。
postRequest = CommonRequest()
postRequest.set_domain(DOMAIN)
postRequest.set_version(API_VERSION)
postRequest.set_product(PRODUCT)
postRequest.set_action_name(POST_REQUEST_ACTION)
postRequest.set_method('POST')
task = {KEY_APP_KEY : appKey, KEY_FILE_LINK : fileLink, KEY_VERSION : "4.0", "enable_words" : False}
task = json.dumps(task)
print(task)
postRequest.add_body_params(KEY_TASK, task)
taskId = ""
try :
# 提交錄音文件識(shí)別請(qǐng)求,處理服務(wù)端返回的響應(yīng)。
postResponse = client.do_action_with_exception(postRequest)
postResponse = json.loads(postResponse)
print(postResponse)
# 獲取錄音文件識(shí)別請(qǐng)求任務(wù)的ID,以供識(shí)別結(jié)果查詢使用。
statusText = postResponse[KEY_STATUS_TEXT]
if statusText == "SUCCESS" :
print("錄音文件識(shí)別請(qǐng)求成功響應(yīng)!")
taskId = postResponse[KEY_TASK_ID]
print("taskId = " + taskId)
else :
print("錄音文件識(shí)別請(qǐng)求失?。?)
except ServerException as e:
print(e)
except ClientException as e:
print(e)
print(taskId)
return taskId
def queryResult(stsAkId, stsAkSecret, stsToken, taskId):
# 創(chuàng)建CommonRequest,設(shè)置任務(wù)ID。
stsTokenCredential = StsTokenCredential(stsAkId, stsAkSecret, stsToken)
client = AcsClient(region_id=REGION_ID, credential=stsTokenCredential)
getRequest = CommonRequest()
getRequest.set_domain(DOMAIN)
getRequest.set_version(API_VERSION)
getRequest.set_product(PRODUCT)
getRequest.set_action_name(GET_REQUEST_ACTION)
getRequest.set_method('GET')
getRequest.add_query_param(KEY_TASK_ID, taskId)
# 提交錄音文件識(shí)別結(jié)果查詢請(qǐng)求
# 以輪詢的方式進(jìn)行識(shí)別結(jié)果的查詢,直到服務(wù)端返回的狀態(tài)描述符為"SUCCESS"、"SUCCESS_WITH_NO_VALID_FRAGMENT",或者為錯(cuò)誤描述,則結(jié)束輪詢。
statusText = ""
while True :
try :
getResponse = client.do_action_with_exception(getRequest)
getResponse = json.loads(getResponse)
print (json.dumps(getResponse).decode('unicode-escape'))
statusText = getResponse[KEY_STATUS_TEXT]
if statusText == "RUNNING" or statusText == "QUEUEING" :
# 繼續(xù)輪詢
time.sleep(5)
else :
# 退出輪詢
break
except ServerException as e:
print (e)
except ClientException as e:
print (e)
if statusText == "SUCCESS" :
print ("錄音文件識(shí)別成功!")
else :
print ("錄音文件識(shí)別失敗!")
# 智能語(yǔ)音交互Appkey,獲取Appkey請(qǐng)前往控制臺(tái):https://nls-portal.console.aliyun.com/applist
appKey = '******'
# 測(cè)試錄音的url
fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav"
# 相比非STS模式,此時(shí)此處填寫(xiě)之前生成的STS臨時(shí)訪問(wèn)憑證(含STS賬號(hào)信息及SecurityToken)
# 特別需要注意的是:臨時(shí)訪問(wèn)憑證存在有效期,在有效期內(nèi)您可以一直使用,但是請(qǐng)?jiān)谶^(guò)期前及時(shí)再次獲取
stsAkId = 'STS.******'
stsAkSecret = '******'
stsToken = '************'
print("--- submit one file ---")
taskId = submitTask(stsAkId, stsAkSecret, stsToken, appKey, fileLink)
print("--- query result ---")
queryResult(stsAkId, stsAkSecret, stsToken, taskId)
Go代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件轉(zhuǎn)寫(xiě)服務(wù)
關(guān)于阿里云SDK Go語(yǔ)言版本的安裝操作,請(qǐng)參見(jiàn)Go SDK 依賴及STS SDK。
以下是Go代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件轉(zhuǎn)寫(xiě)服務(wù)的完整示例:
package main
import (
"encoding/json"
"fmt"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
)
func main() {
// 地域ID,固定值。
const REGION_ID string = "cn-shanghai"
const ENDPOINT_NAME string = "cn-shanghai"
const PRODUCT string = "nls-filetrans"
const DOMAIN string = "filetrans.cn-shanghai.aliyuncs.com"
const API_VERSION string = "2018-08-17"
const POST_REQUEST_ACTION string = "SubmitTask"
const GET_REQUEST_ACTION string = "GetTaskResult"
// 請(qǐng)求參數(shù)
const KEY_APP_KEY string = "appkey"
const KEY_FILE_LINK string = "file_link"
const KEY_VERSION string = "version"
const KEY_ENABLE_WORDS string = "enable_words"
// 響應(yīng)參數(shù)
const KEY_TASK string = "Task"
const KEY_TASK_ID string = "TaskId"
const KEY_STATUS_TEXT string = "StatusText"
const KEY_RESULT string = "Result"
// 狀態(tài)值
const STATUS_SUCCESS string = "SUCCESS"
const STATUS_RUNNING string = "RUNNING"
const STATUS_QUEUEING string = "QUEUEING"
// 相比非STS模式,此時(shí)此處填寫(xiě)之前生成的STS臨時(shí)訪問(wèn)憑證(含STS賬號(hào)信息及SecurityToken)
// 特別需要注意的是:臨時(shí)訪問(wèn)憑證存在有效期,在有效期內(nèi)您可以一直使用,但是請(qǐng)?jiān)谶^(guò)期前及時(shí)再次獲取
var accessKeyId string = "STS.******"
var accessKeySecret string = "******"
var stsToken string = ""******""
var appKey string = "請(qǐng)?zhí)顚?xiě)您的appkey"
var fileLink string = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav"
client, err := sdk.NewClientWithStsToken(REGION_ID, accessKeyId, accessKeySecret, stsToken)
if err != nil {
panic(err)
}
postRequest := requests.NewCommonRequest()
postRequest.Domain = DOMAIN
postRequest.Version = API_VERSION
postRequest.Product = PRODUCT
postRequest.ApiName = POST_REQUEST_ACTION
postRequest.Method = "POST"
mapTask := make(map[string]string)
mapTask[KEY_APP_KEY] = appKey
mapTask[KEY_FILE_LINK] = fileLink
// 新接入請(qǐng)使用4.0版本,已接入(默認(rèn)2.0)如需維持現(xiàn)狀,請(qǐng)注釋掉該參數(shù)設(shè)置。
mapTask[KEY_VERSION] = "4.0"
// 設(shè)置是否輸出詞信息,默認(rèn)為false。開(kāi)啟時(shí)需要設(shè)置version為4.0。
mapTask[KEY_ENABLE_WORDS] = "false"
task, err := json.Marshal(mapTask)
if err != nil {
panic(err)
}
postRequest.FormParams[KEY_TASK] = string(task)
postResponse, err := client.ProcessCommonRequest(postRequest)
if err != nil {
panic(err)
}
postResponseContent := postResponse.GetHttpContentString()
fmt.Println(postResponseContent)
if postResponse.GetHttpStatus() != 200 {
fmt.Println("錄音文件識(shí)別請(qǐng)求失敗,Http錯(cuò)誤碼: ", postResponse.GetHttpStatus())
return
}
var postMapResult map[string]interface{}
err = json.Unmarshal([]byte(postResponseContent), &postMapResult)
if err != nil {
panic(err)
}
var taskId string = ""
var statusText string = ""
statusText = postMapResult[KEY_STATUS_TEXT].(string)
if statusText == STATUS_SUCCESS {
fmt.Println("錄音文件識(shí)別請(qǐng)求成功響應(yīng)!")
taskId = postMapResult[KEY_TASK_ID].(string)
} else {
fmt.Println("錄音文件識(shí)別請(qǐng)求失敗!")
return
}
getRequest := requests.NewCommonRequest()
getRequest.Domain = DOMAIN
getRequest.Version = API_VERSION
getRequest.Product = PRODUCT
getRequest.ApiName = GET_REQUEST_ACTION
getRequest.Method = "GET"
getRequest.QueryParams[KEY_TASK_ID] = taskId
statusText = ""
for true {
getResponse, err := client.ProcessCommonRequest(getRequest)
if err != nil {
panic(err)
}
getResponseContent := getResponse.GetHttpContentString()
fmt.Println("識(shí)別查詢結(jié)果:", getResponseContent)
if getResponse.GetHttpStatus() != 200 {
fmt.Println("識(shí)別結(jié)果查詢請(qǐng)求失敗,Http錯(cuò)誤碼:", getResponse.GetHttpStatus())
break
}
var getMapResult map[string]interface{}
err = json.Unmarshal([]byte(getResponseContent), &getMapResult)
if err != nil {
panic(err)
}
statusText = getMapResult[KEY_STATUS_TEXT].(string)
if statusText == STATUS_RUNNING || statusText == STATUS_QUEUEING {
time.Sleep(10 * time.Second)
} else {
break
}
}
if statusText == STATUS_SUCCESS {
fmt.Println("錄音文件識(shí)別成功!")
} else {
fmt.Println("錄音文件識(shí)別失??!")
}
}
Node.js代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件識(shí)別服務(wù)
請(qǐng)您提前安裝阿里云Core SDK、STS SDK及錄音文件轉(zhuǎn)寫(xiě)識(shí)別SDK,前兩個(gè)SDK的安裝,請(qǐng)參見(jiàn)Node.js SDK安裝及示例。簡(jiǎn)單步驟如下:
npm install @alicloud/pop-core --save
npm install @alicloud/sts-sdk --save
npm install @alicloud/nls-filetrans-2018-08-17 --save
以下是Node.js代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件轉(zhuǎn)寫(xiě)服務(wù)的完整示例:
'use strict';
const Client = require('@alicloud/nls-filetrans-2018-08-17');
function fileTrans(akID, akSecret, stsToken, appKey, fileLink) {
//地域ID,固定值。
var ENDPOINT = 'http://filetrans.cn-hangzhou.aliyuncs.com';
var API_VERSION = '2018-08-17';
/**
* 創(chuàng)建阿里云鑒權(quán)client
*/
var client = new Client({
accessKeyId: akID,
secretAccessKey: akSecret,
securityToken: stsToken,
endpoint: ENDPOINT,
apiVersion: API_VERSION
});
/**
* 提交錄音文件識(shí)別請(qǐng)求,請(qǐng)求參數(shù)組合成JSON格式的字符串作為task的值。
* 請(qǐng)求參數(shù)appkey:項(xiàng)目appkey,獲取Appkey請(qǐng)前往控制臺(tái):https://nls-portal.console.aliyun.com/applist
* 請(qǐng)求參數(shù)file_link:需要識(shí)別的錄音文件。
*/
var task = {
appkey : appKey,
file_link : fileLink,
version : "4.0", // 新接入請(qǐng)使用4.0版本,已接入(默認(rèn)2.0)如需維持現(xiàn)狀,請(qǐng)注釋掉該參數(shù)設(shè)置。
enable_words : false // 設(shè)置是否輸出詞信息,默認(rèn)值為false,開(kāi)啟時(shí)需要設(shè)置version為4.0。
};
task = JSON.stringify(task);
var taskParams = {
Task : task
};
var options = {
method: 'POST'
};
// 提交錄音文件識(shí)別請(qǐng)求,處理服務(wù)端返回的響應(yīng)。
client.submitTask(taskParams, options).then((response) => {
console.log(response);
// 服務(wù)端響應(yīng)信息的狀態(tài)描述StatusText。
var statusText = response.StatusText;
if (statusText != 'SUCCESS') {
console.log('錄音文件識(shí)別請(qǐng)求響應(yīng)失敗!')
return;
}
console.log('錄音文件識(shí)別請(qǐng)求響應(yīng)成功!');
// 獲取錄音文件識(shí)別請(qǐng)求任務(wù)的TaskId,以供識(shí)別結(jié)果查詢使用。
var taskId = response.TaskId;
/**
* 以TaskId為查詢參數(shù),提交識(shí)別結(jié)果查詢請(qǐng)求。
* 以輪詢的方式進(jìn)行識(shí)別結(jié)果的查詢,直到服務(wù)端返回的狀態(tài)描述為"SUCCESS"、SUCCESS_WITH_NO_VALID_FRAGMENT,
* 或者為錯(cuò)誤描述,則結(jié)束輪詢。
*/
var taskIdParams = {
TaskId : taskId
};
var timer = setInterval(() => {
client.getTaskResult(taskIdParams).then((response) => {
console.log('識(shí)別結(jié)果查詢響應(yīng):');
console.log(response);
var statusText = response.StatusText;
if (statusText == 'RUNNING' || statusText == 'QUEUEING') {
// 繼續(xù)輪詢,注意間隔周期。
}
else {
if (statusText == 'SUCCESS' || statusText == 'SUCCESS_WITH_NO_VALID_FRAGMENT') {
console.log('錄音文件識(shí)別成功:');
var sentences = response.Result;
console.log(sentences);
}
else {
console.log('錄音文件識(shí)別失敗!');
}
// 退出輪詢
clearInterval(timer);
}
}).catch((error) => {
console.error(error);
// 異常情況,退出輪詢。
clearInterval(timer);
});
}, 10000);
}).catch((error) => {
console.error(error);
});
}
// 相比非STS模式,此時(shí)此處填寫(xiě)之前生成的STS臨時(shí)訪問(wèn)憑證(含STS賬號(hào)信息及SecurityToken)
// 特別需要注意的是:臨時(shí)訪問(wèn)憑證存在有效期,在有效期內(nèi)您可以一直使用,但是請(qǐng)?jiān)谶^(guò)期前及時(shí)再次獲取
var akId = 'STS.******';
var akSecret = '******';
var stsToken = '******';
var appKey = '請(qǐng)?zhí)顚?xiě)您的appkey';
var fileLink = 'https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav';
fileTrans(akId, akSecret, stsToken, appKey, fileLink);
PHP代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件識(shí)別服務(wù)
請(qǐng)您提前安裝阿里云Core SDK、STS SDK的PHP語(yǔ)言版本,詳細(xì)安裝請(qǐng)參見(jiàn)Node.js SDK安裝及示例。簡(jiǎn)單步驟如下:
composer require alibabacloud/sdk
composer require alibabacloud/sts
以下是PHP代碼演示通過(guò)STS臨時(shí)訪問(wèn)憑證調(diào)用錄音文件識(shí)別服務(wù)的完整示例:
<?php
require __DIR__ . '/vendor/autoload.php';
use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;
class NLSFileTrans {
// 請(qǐng)求參數(shù)
private const KEY_APP_KEY = "appkey";
private const KEY_FILE_LINK = "file_link";
private const KEY_VERSION = "version";
private const KEY_ENABLE_WORDS = "enable_words";
// 響應(yīng)參數(shù)
private const KEY_TASK_ID = "TaskId";
private const KEY_STATUS_TEXT = "StatusText";
private const KEY_RESULT = "Result";
// 狀態(tài)值
private const STATUS_SUCCESS = "SUCCESS";
private const STATUS_RUNNING = "RUNNING";
private const STATUS_QUEUEING = "QUEUEING";
function submitFileTransRequest($appKey, $fileLink) {
// 獲取task JSON字符串,包含appkey和file_link參數(shù)等。
$taskArr = array(self::KEY_APP_KEY => $appKey, self::KEY_FILE_LINK => $fileLink, self::KEY_VERSION => "4.0", self::KEY_ENABLE_WORDS => FALSE);
$task = json_encode($taskArr);
print $task . "\n";
try {
// 提交請(qǐng)求,返回服務(wù)端的響應(yīng)。
$submitTaskResponse = AlibabaCloud::nlsFiletrans()
->v20180817()
->submitTask()
->host("filetrans.cn-shanghai.aliyuncs.com")
->withTask($task)
->request();
print $submitTaskResponse . "\n";
// 獲取錄音文件識(shí)別請(qǐng)求任務(wù)的ID,以供識(shí)別結(jié)果查詢使用。
$taskId = NULL;
$statusText = $submitTaskResponse[self::KEY_STATUS_TEXT];
if (strcmp(self::STATUS_SUCCESS, $statusText) == 0) {
$taskId = $submitTaskResponse[self::KEY_TASK_ID];
}
return $taskId;
} catch (ClientException $exception) {
// 獲取錯(cuò)誤消息
print_r($exception->getErrorMessage());
} catch (ServerException $exception) {
// 獲取錯(cuò)誤消息
print_r($exception->getErrorMessage());
}
}
function getFileTransResult($taskId) {
$result = NULL;
while (TRUE) {
try {
$getResultResponse = AlibabaCloud::nlsFiletrans()
->v20180817()
->getTaskResult()
->host("filetrans.cn-shanghai.aliyuncs.com")
->withTaskId($taskId)
->request();
print "識(shí)別查詢結(jié)果: " . $getResultResponse . "\n";
$statusText = $getResultResponse[self::KEY_STATUS_TEXT];
if (strcmp(self::STATUS_RUNNING, $statusText) == 0 || strcmp(self::STATUS_QUEUEING, $statusText) == 0) {
// 繼續(xù)輪詢
sleep(10);
}
else {
if (strcmp(self::STATUS_SUCCESS, $statusText) == 0) {
$result = $getResultResponse;
}
// 退出輪詢
break;
}
} catch (ClientException $exception) {
// 獲取錯(cuò)誤消息
print_r($exception->getErrorMessage());
} catch (ServerException $exception) {
// 獲取錯(cuò)誤消息
print_r($exception->getErrorMessage());
}
}
return $result;
}
}
$accessKeyId = "STS.******";
$accessKeySecret = "******";
$stsToken = "******";
$appKey = "請(qǐng)?zhí)顚?xiě)您的appkey";
$fileLink = "https://gw.alipayobjects.com/os/bmw-prod/0574ee2e-f494-45a5-820f-63aee583045a.wav";
/**
* 第一步:設(shè)置一個(gè)全局客戶端。
* 使用阿里云RAM賬號(hào)的AccessKey ID和AccessKey Secret進(jìn)行鑒權(quán)。
*/
Alibabacloud::stsClient($accessKeyId, $accessKeySecret, $stsToken)
->regionId("cn-shanghai")
->asGlobalClient();
$fileTrans = new NLSFileTrans();
/**
* 第二步:提交錄音文件識(shí)別請(qǐng)求,獲取任務(wù)ID,用于后續(xù)的識(shí)別結(jié)果輪詢。
*/
$taskId = $fileTrans->submitFileTransRequest($appKey, $fileLink);
if ($taskId != NULL) {
print "錄音文件識(shí)別請(qǐng)求成功,task_id: " . $taskId . "\n";
}
else {
print "錄音文件識(shí)別請(qǐng)求失敗!";
return ;
}
/**
* 第三步:根據(jù)任務(wù)ID輪詢識(shí)別結(jié)果。
*/
$result = $fileTrans->getFileTransResult($taskId);
if ($result != NULL) {
print "錄音文件識(shí)別結(jié)果查詢成功: " . $result . "\n";
}
else {
print "錄音文件識(shí)別結(jié)果查詢失敗!";
}