日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

通過OpenAPI復刻

CosyVoice聲音復刻服務,僅需提供較短的樣本音頻,即可迅速生成高度相似且聽感自然的定制聲音。通過OpenAPI進行CosyVoice聲音復刻,要求開發者自行編寫代碼完成身份驗證和請求邏輯,如果缺少對應編程語言的SDK,或者需要控制依賴組件,可以通過OpenAPI進行音色復刻和查詢。本文為您介紹相關接口協議說明。

請求報文

客戶端發送的請求支持使用HTTPS協議,請求方法支持POST方法。服務端提供了基于阿里云POP協議的接口,因此客戶端需要實現阿里云POP的簽名機制。

  • URL

    協議

    URL

    方法

    HTTPS

    https://nls-slp.cn-shanghai.aliyuncs.com

    POST

  • 請求參數

    名稱

    類型

    是否必選

    說明

    AccessKeyId

    String

    阿里云賬號AccessKey ID

    Action

    String

    POP API名稱:

    • 音色復刻:CosyVoiceClone

    • 查詢音色:ListCosyVoice

    Version

    String

    POP API版本:2019-08-19

    Format

    String

    響應返回的類型:JSON

    RegionId

    String

    服務所在的地域ID:cn-shanghai

    Timestamp

    String

    請求的時間戳。日期格式按照ISO 8601標準表示,且使用UTC時間,時區:+0。格式:YYYY-MM-DDThh:mm:ssZ。如2019-04-03T06:15:03Z為UTC時間2019年4月3日6點15分03秒

    SignatureMethod

    String

    簽名算法:HMAC-SHA1

    SignatureVersion

    String

    簽名算法版本:1.0

    SignatureNonce

    String

    唯一隨機數uuid,用于請求的防重放攻擊,每次請求唯一,不能重復使用。格式為A-B-C-D-E(A、B、C、D、E的字符位數分別為8、4、4、4、12)。例如,8d1e6a7a-f44e-40d5-aedb-fe4a1c80f434

    Signature

    String

    由所有請求參數計算出的簽名結果,生成方法參見下文簽名機制。

    VoicePrefix

    String

    復刻音色的前綴,僅包含小寫英文字母及數字,且長度不超過10個字符。

    Url

    String

    僅在CosyVoiceClone中使用,必選。

    用于音色復刻的音頻文件URL。

    PageIndex

    Integer

    僅在ListCosyVoice中使用,非必選,默認為1。

    查詢音色列表頁碼。

    PageSize

    Integer

    僅在ListCosyVoice中使用,非必選,默認為10。

    一頁音色數量。

  • HTTPS請求頭部

    HTTPS請求頭部由“關鍵字-值”對組成,每行一對,關鍵字和值用英文冒號“:”分隔,內容如下:

    名稱

    類型

    是否必選

    描述

    Host

    String

    HTTPS請求的服務器域名:nls-meta.cn-shanghai.aliyuncs.com,一般根據請求鏈接自動解析。

    Accept

    String

    指定客戶端能夠接收的內容類型:application/json,不設置默認為 */* 。

    Content-type

    String

    POST方法必須設置

    指定POST方法請求體數據格式:application/x-www-form-urlencoded

報文示例

  • HTTPS POST請求報文

    • CosyVoiceClone

      POST&%2F&AccessKeyId%3DALIYUN_AK_ID%26Action%3DCosyVoiceClone%26Format%3DJSON%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D80bf00d8-3f4d-11ef-941b-72ec8d600bed%26SignatureVersion%3D1.0%26Timestamp%3D2024-07-11T06%253A19%253A17Z%26Url%3Dyour-audio-file-url%26Version%3D2019-08-19%26VoicePrefix%3Dyour-voice-prefix
    • ListCosyVoice

      POST&%2F&AccessKeyId%3DALIYUN_AK_ID%26Action%3DListCosyVoice%26Format%3DJSON%26PageIndex%3D1%26PageSize%3D10%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D823730ac-3f4d-11ef-941b-72ec8d600bed%26SignatureVersion%3D1.0%26Timestamp%3D2024-07-11T06%253A19%253A20Z%26Version%3D2019-08-19%26VoicePrefix%3Dyour-voice-prefix

響應結果

發送HTTPS請求后,會受到服務端響應,結果以JSON字符串的形式保存在響應中。

  • 成功響應

    HTTPS狀態碼為200,響應字段如下表所示。

    參數

    類型

    說明

    RequestId

    String

    requestId

    Message

    String

    SUCCESS

    VoiceName

    String

    復刻成功聲音的voice名字

    • CosyVoiceClone

      {
          "RequestId": "0D6FF6C9-7D90-57C0-9931-xxxxxxx",
          "Message": "SUCCESS",
          "Code": 20000000,
          "VoiceName": "cosyvoice-xxxxx"
      }
    • ListCosyVoice

      {
          "TotalCount": 0,
          "RequestId": "C4E8622C-B365-55B3-899A-xxxxxxxxxxx",
          "Message": "SUCCESS",
          "PageSize": 10,
          "PageIndex": 1,
          "Code": 20000000,
          "Voices": [
      
          ]
      }
  • 失敗響應

    HTTPS狀態碼為非200,響應字段說明如下表。

    參數

    類型

    說明

    RequestId

    String

    請求ID

    Message

    String

    失敗響應的錯誤信息

    Recommend

    String

    排查建議

    HostId

    String

    Host ID

    Code

    String

    失敗響應的錯誤類型,詳情請參見服務狀態碼

    {
        "RequestId": "00CDBC76-BC8D-5734-BEA4-xxxxxxxx",
        "Message": "Specified access key is not found.",
        "Recommend": "https://api.aliyun.com/troubleshoot?q=InvalidAccessKeyId.NotFound&product=nls-slp&requestId=00CDBC76-BC8D-5734-BEA4-D4752DF81D14",
        "HostId": "nls-slp.cn-shanghai.aliyuncs.com",
        "Code": "InvalidAccessKeyId.NotFound"
    }

簽名機制

服務端POP API對每個接口訪問請求的發送者都要進行身份驗證,需要在請求中包含簽名信息。通過簽名機制,服務端可以確認哪位用戶在做API請求,并能確認請求在網絡傳輸過程中是否被篡改。

安全驗證流程

計算簽名時,需要阿里云賬號的AccessKey IdAccessKey Secret,使用HMAC-SHA1算法進行對稱加密。其工作流程如下。

  1. 請求端根據API請求內容(包括HTTPS請求參數和請求體)生成簽名字符串。

  2. 請求端使用阿里云賬號的AccessKey IdAccessKey Secret對第一步生成的簽名字符串進行簽名,獲得該API請求的數字簽名。

  3. 請求端把API請求內容和數字簽名一同發送給服務端。

  4. 服務端在接收到請求后會重復12步驟(服務端會在后臺獲取該請求使用的用戶密鑰)并計算出該請求期望的數字簽名。

  5. 服務端用期望的數字簽名和請求端發送過來的數字簽名做對比,若完全一致則認為該請求通過驗證。否則拒絕該請求。

生成請求的簽名字符串

  1. 構造規范化的請求字符串。

    將HTTPS請求參數(不包括Signature)構造成規范化的請求字符串。規范化步驟:

    1. 參數排序。按參數名的字典順序,對請求參數進行大小寫敏感排序。

    2. 參數編碼。對排序后的請求參數進行規范化設置。

      請求參數名和值都要使用UTF-8字符集進行URL編碼,URL編碼規則如下:

      • 對于字符 A-Z、a-z、0-9以及字符-_.~不編碼。

      • 對于其他字符編碼成“%XY”的格式,其中XY是字符對應ASCII碼的16進制表示。比如英文的雙引號(”)對應的編碼就是%22。

      • 對于擴展的UTF-8字符,編碼成“%XY%ZA…”的格式。

      • 需要說明的是英文空格要被編碼為%20,而不是加號+

      說明

      一般支持URL編碼的庫(比如Java中的java.net.URLEncoder)都是按照“application/x-www-form-urlencoded”的MIME類型的規則進行編碼的。實現時可以直接使用此類方式進行編碼,然后把編碼后的字符串中:加號+替換為%20,星號*替換為%2A%7E替換為波浪號~,即可得到上述規則描述的編碼字符串。

    3. 使用等號=連接URL編碼后的參數名和參數值:percentEncode(參數Key) + “=” + percentEncode(參數值)

    4. 使用與(&)號連接第c步URL編碼后的請求參數對,如Action=CreateToken&Format=JSON

      說明

      字符串中第一個參數名前面不需要&符號。

    5. 返回規范化的請求字符串。

    示例如下:

    String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, URL_ENCODING)
                .replace("+", "%20")
                .replace("*", "%2A")
                .replace("%7E", "~") : null;
    }
    
    // 對參數Key排序
    String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {});
    Arrays.sort(sortedKeys);
    
    // 對排序的參數進行編碼、拼接
    for (String key : sortedKeys) {
        canonicalizedQueryString.append("&")
                .append(percentEncode(key)).append("=")
                .append(percentEncode(queryParamsMap.get(key)));
    }
    queryString = canonicalizedQueryString.toString().substring(1);
    說明

    完整代碼實現請參見完整示例的canonicalizedQuery函數。

    構造規范化的請求字符串:

    AccessKeyId=LTA******3s2&Action=CosyVoiceClone&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=f20b1beb-e5dc-4245-9e96-aa582e905c1a&SignatureVersion=1.0&Timestamp=2019-04-03T03%3A40%3A13Z&Version=2019-08-19
  2. 構造待簽名字符串。

    將HTTPS請求的方法(GET)、URL編碼的URL路徑(/)、第1步獲取的規范化請求字符串使用與(&)符號連接成待簽名字符串:HTTPSMethod + "&" + percentEncode("/") + "&" + percentEncode(queryString)

    構造簽名字符串代碼示例:

    StringBuilder strBuilderSign = new StringBuilder();
    strBuilderSign.append(HTTPMethod);
    strBuilderSign.append("&");
    strBuilderSign.append(percentEncode(urlPath));
    strBuilderSign.append("&");
    strBuilderSign.append(percentEncode(queryString));
    
    stringToSign = strBuilderSign.toString();
    說明

    完整代碼實現請參見完整示例的createStringToSign函數。

    構造的簽名字符串:

    GET&%2F&AccessKeyId%3DLTA******F3s%26Action%3DCosyVoiceClone%26Format%3DJSON%26RegionID%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3Da237e025-07ea-4d87-bb04-d9b2712d871d%26SignatureVersion%3D1.0%26Timestamp%3D2019-04-19T03%253A31%253A40Z%26Version%3D2019-08-19
  3. 計算簽名。

    • 簽名采用HMAC-SHA1算法 + Base64,編碼采用UTF-8

    • 根據AccessKey Secret,將第2步構造的待簽名字符串使用HMAC-SHA1算法計算出對應的數字簽名。其中,計算簽名時使用的AccessKey Secret必須在其后面增加一個與字符&

    • 簽名也要做URL編碼。

    計算簽名的代碼示例:

    signature = Base64( HMAC-SHA1(stringToSign, accessKeySecret + "&") );
    // 進行URL編碼
    signature = percentEncode(signature)
    說明

    完整代碼實現請閱讀完整示例的sign函數。

    計算得到的簽名:

    # 簽名串
    AKIktdPUMCV12fTh667BLXeuCtg=
    # URL編碼后的結果
    AKIktdPUMCV12fTh667BLXeuCtg%3D

    計算簽名后,將簽名的鍵值對用符號=連接,并使用符號&添加到第1步獲取的請求字符串中,作為HTTPS GET請求參數,發送到服務端,獲取Token。

    String queryStringWithSign = "Signature=" + signature + "&" + queryString;

快速測試

您可以使用以下參數計算簽名,比較計算結果是否一致。

說明

AccessKey Id和AccessKey Secret沒有提供真實數據,Timestamp是過期的時間,使用這些參數計算的簽名,獲取Token時會失敗,僅用于計算簽名測試對比。

  • AccessKeyId: 

    my_access_key_id

  • AccessKeySecret: 

    my_access_key_secret

  • Timestamp: 

    2019-04-18T08:32:31Z

  • SignatureNonce: 

    b924c8c3-6d03-4c5d-ad36-d984d3116788

請求參數如下:

AccessKeyId:my_access_key_id
Action:CosyVoiceClone
Version:2019-08-19
Timestamp:2019-04-18T08:32:31Z
Format:JSON
RegionId:cn-shanghai
SignatureMethod:HMAC-SHA1
SignatureVersion:1.0
VoicePrefix:my_voice_prefix
Url:my_url
SignatureNonce:3D472c6930-3f4f-11ef-a0b8-72ec8d600bed
  1. 規范化請求字符串。

    AccessKeyId=my_access_key_id&Action=CosyVoiceClone&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=3D472c6930-3f4f-11ef-a0b8-72ec8d600bed&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Url=my_url&Version=2019-08-19&VoicePrefix=my_voice_prefix
  2. 構造待簽名字符串。

    POST&%2F&AccessKeyId%3Dmy_access_key_id%26Action%3DCosyVoiceClone%26Format%3DJSON%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D3D472c6930-3f4f-11ef-a0b8-72ec8d600bed%26SignatureVersion%3D1.0%26Timestamp%3D2019-04-18T08%253A32%253A31Z%26Url%3Dmy_url%26Version%3D2019-08-19%26VoicePrefix%3Dmy_voice_prefix
  3. 計算得到簽名。

    xDyEd10/tcCLyq5mfV3QEipF9vs=
    # URL編碼后的結果
    xDyEd10%2FtcCLyq5mfV3QEipF9vs%3D
  4. 得到攜帶簽名的請求字符串。

    Signature=xDyEd10%2FtcCLyq5mfV3QEipF9vs%3D&AccessKeyId=my_access_key_id&Action=CosyVoiceClone&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=3D472c6930-3f4f-11ef-a0b8-72ec8d600bed&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Url=my_url&Version=2019-08-19&VoicePrefix=my_voice_prefix
  5. 組合成HTTPS請求鏈接。

    https://nls-slp.cn-shanghai.aliyuncs.com/?Signature=xDyEd10%2FtcCLyq5mfV3QEipF9vs%3D&AccessKeyId=my_access_key_id&Action=CosyVoiceClone&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=3D472c6930-3f4f-11ef-a0b8-72ec8d600bed&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Url=my_url&Version=2019-08-19&VoicePrefix=my_voice_prefix
  6. 替換第5步獲取的HTTPS請求鏈接,使用瀏覽器或者curl,進行CosyVoice聲音復刻。

    curl -X POST https://nls-slp.cn-shanghai.aliyuncs.com/?Signature=xDyEd10%2FtcCLyq5mfV3QEipF9vs%3D&AccessKeyId=my_access_key_id&Action=CosyVoiceClone&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=3D472c6930-3f4f-11ef-a0b8-72ec8d600bed&SignatureVersion=1.0&Timestamp=2019-04-18T08%3A32%3A31Z&Url=my_url&Version=2019-08-19&VoicePrefix=my_voice_prefix

完整示例

說明
  • 本文提供Java、Python語言示例代碼,您可根據協議和示例實現其他語言的客戶端程序。

  • 調用接口前,需配置環境變量,通過環境變量讀取訪問憑證。智能語音交互的AccessKey ID和AccessKey Secret的環境變量名為:ALIYUN_AK_IDALIYUN_AK_SECRET

Java示例

依賴文件:

<!-- http://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.9.1</version>
</dependency>

示例代碼:

package org.example;

import okhttp3.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

public class OpenApiClone {
    private final static String TIME_ZONE = "GMT";
    private final static String FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    private final static String URL_ENCODING = "UTF-8";
    private static final String ALGORITHM_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";
    /**
     * 獲取時間戳
     * 必須符合ISO8601規范,并需要使用UTC時間,時區為+0。
     */
    public static String getISO8601Time(Date date) {
        Date nowDate = date;
        if (null == date) {
            nowDate = new Date();
        }
        SimpleDateFormat df = new SimpleDateFormat(FORMAT_ISO8601);
        df.setTimeZone(new SimpleTimeZone(0, TIME_ZONE));
        return df.format(nowDate);
    }
    /**
     * 獲取UUID
     */
    public static String getUniqueNonce() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString();
    }
    /**
     * URL編碼
     * 使用UTF-8字符集按照RFC3986規則編碼請求參數和參數取值。
     */
    public static String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, URL_ENCODING).replace("+", "%20")
                .replace("*", "%2A").replace("%7E", "~") : null;
    }
    /***
     * 將參數排序后,進行規范化設置,組合成請求字符串。
     * @param queryParamsMap   所有請求參數
     * @return 規范化的請求字符串
     */
    public static String canonicalizedQuery( Map<String, String> queryParamsMap) {
        String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {});
        Arrays.sort(sortedKeys);
        String queryString = null;
        try {
            StringBuilder canonicalizedQueryString = new StringBuilder();
            for (String key : sortedKeys) {
                canonicalizedQueryString.append("&")
                        .append(percentEncode(key)).append("=")
                        .append(percentEncode(queryParamsMap.get(key)));
            }
            queryString = canonicalizedQueryString.toString().substring(1);
            System.out.println("規范化后的請求參數串:" + queryString);
        } catch (UnsupportedEncodingException e) {
            System.out.println("UTF-8 encoding is not supported.");
            e.printStackTrace();
        }
        return queryString;
    }
    /***
     * 構造簽名字符串
     * @param method       HTTP請求的方法
     * @param urlPath      HTTP請求的資源路徑
     * @param queryString  規范化的請求字符串
     * @return 簽名字符串
     */
    public static String createStringToSign(String method, String urlPath, String queryString) {
        String stringToSign = null;
        try {
            StringBuilder strBuilderSign = new StringBuilder();
            strBuilderSign.append(method);
            strBuilderSign.append("&");
            strBuilderSign.append(percentEncode(urlPath));
            strBuilderSign.append("&");
            strBuilderSign.append(percentEncode(queryString));
            stringToSign = strBuilderSign.toString();
            System.out.println("構造的簽名字符串:" + stringToSign);
        } catch (UnsupportedEncodingException e) {
            System.out.println("UTF-8 encoding is not supported.");
            e.printStackTrace();
        }
        return stringToSign;
    }
    /***
     * 計算簽名
     * @param stringToSign      簽名字符串
     * @param accessKeySecret   阿里云AccessKey Secret加上與號&
     * @return 計算得到的簽名
     */
    public static String sign(String stringToSign, String accessKeySecret) {
        try {
            Mac mac = Mac.getInstance(ALGORITHM_NAME);
            mac.init(new SecretKeySpec(
                    accessKeySecret.getBytes(ENCODING),
                    ALGORITHM_NAME
            ));
            byte[] signData = mac.doFinal(stringToSign.getBytes(ENCODING));
            String signBase64 = DatatypeConverter.printBase64Binary(signData);
            System.out.println("計算的得到的簽名:" + signBase64);
            String signUrlEncode = percentEncode(signBase64);
            System.out.println("UrlEncode編碼后的簽名:" + signUrlEncode);
            return signUrlEncode;
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException(e.toString());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException(e.toString());
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException(e.toString());
        }
    }
    /***
     * 發送HTTP POST請求
     * @param queryString 請求參數
     */
    public static void processPostRequest(String queryString) {
        /**
         * 設置HTTP GET請求
         * 1. 使用HTTP協議
         * 2. 服務域名:nls-slp.cn-shanghai.aliyuncs.com
         * 3. 請求路徑:/
         * 4. 設置請求參數
         */
        String url = "https://nls-slp.cn-shanghai.aliyuncs.com";
        url = url + "/";
        url = url + "?" + queryString;
        System.out.println("HTTP請求鏈接:" + url);
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), "");
        Request request = new Request.Builder()
                .url(url)
                .header("Accept", "application/json")
                .post(body)
                .build();
        try {
            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            String result = response.body().string();
            if (response.isSuccessful()) {

                System.out.println(result);
            }
            else {
                System.err.println("請求失敗: " + result);
            }
            response.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 調用CosyVoiceClone接口復刻聲音
     * @param accessKeyId 阿里云AccessKey ID
     * @param accessKeySecret 阿里云AccessKey Secret
     * @param voicePrefix 聲音前綴
     * @param audioFileUrl 音頻文件URL
     */
    public static void cosyCLone(String accessKeyId, String accessKeySecret, String voicePrefix, String audioFileUrl) {
        // 所有請求參數
        Map<String, String> queryParamsMap = new HashMap<String, String>();
        queryParamsMap.put("AccessKeyId", accessKeyId);
        queryParamsMap.put("Action", "CosyVoiceClone");
        queryParamsMap.put("Version", "2019-08-19");
        queryParamsMap.put("Timestamp", getISO8601Time(null));
        queryParamsMap.put("Format", "JSON");
        queryParamsMap.put("RegionId", "cn-shanghai");
        queryParamsMap.put("SignatureMethod", "HMAC-SHA1");
        queryParamsMap.put("SignatureVersion", "1.0");
        queryParamsMap.put("SignatureNonce", getUniqueNonce());
        queryParamsMap.put("VoicePrefix", voicePrefix);
        queryParamsMap.put("Url", audioFileUrl);
        /**
         * 1.構造規范化的請求字符串
         */
        String queryString = canonicalizedQuery(queryParamsMap);
        if (null == queryString) {
            System.out.println("構造規范化的請求字符串失敗!");
            return;
        }
        /**
         * 2.構造簽名字符串
         */
        String method = "POST";  // 發送請求的 HTTP 方法,POST
        String urlPath = "/";   // 請求路徑
        String stringToSign = createStringToSign(method, urlPath, queryString);
        if (null == stringToSign) {
            System.out.println("構造簽名字符串失敗");
            return;
        }
        /**
         * 3.計算簽名
         */
        String signature = sign(stringToSign, accessKeySecret + "&");
        if (null == signature) {
            System.out.println("計算簽名失敗!");
            return;
        }
        /**
         * 4.將簽名加入到第1步獲取的請求字符串
         */
        String queryStringWithSign = "Signature=" + signature + "&" + queryString;
        System.out.println("帶有簽名的請求字符串:" + queryStringWithSign);
        /**
         * 5.發送HTTP POST請求,調用ListCosyVoice接口可以查詢您某個前綴所有聲音的狀態。
         */
        processPostRequest(queryStringWithSign);
    }

    /**
     * 調用ListCosyVoice接口可以查詢您某個前綴所有聲音的狀態。
     * @param accessKeyId 阿里云AccessKey ID
     * @param accessKeySecret 阿里云AccessKey Secret
     * @param voicePrefix 聲音前綴
     * @param pageIndex 頁碼
     * @param pageSize 頁大小
     */
    public static void cosyList(String accessKeyId, String accessKeySecret, String voicePrefix, int pageIndex, int pageSize) {
        // 所有請求參數
        Map<String, String> queryParamsMap = new HashMap<String, String>();
        queryParamsMap.put("AccessKeyId", accessKeyId);
        queryParamsMap.put("Action", "ListCosyVoice");
        queryParamsMap.put("Version", "2019-08-19");
        queryParamsMap.put("Timestamp", getISO8601Time(null));
        queryParamsMap.put("Format", "JSON");
        queryParamsMap.put("RegionId", "cn-shanghai");
        queryParamsMap.put("SignatureMethod", "HMAC-SHA1");
        queryParamsMap.put("SignatureVersion", "1.0");
        queryParamsMap.put("SignatureNonce", getUniqueNonce());
        queryParamsMap.put("VoicePrefix", voicePrefix);
        queryParamsMap.put("PageIndex", String.valueOf(pageIndex));
        queryParamsMap.put("PageSize", String.valueOf(pageSize));
        /**
         * 1.構造規范化的請求字符串
         */
        String queryString = canonicalizedQuery(queryParamsMap);
        if (null == queryString) {
            System.out.println("構造規范化的請求字符串失敗!");
            return;
        }
        /**
         * 2.構造簽名字符串
         */
        String method = "POST";  // 發送請求的 HTTP 方法,POST
        String urlPath = "/";   // 請求路徑
        String stringToSign = createStringToSign(method, urlPath, queryString);
        if (null == stringToSign) {
            System.out.println("構造簽名字符串失敗");
            return;
        }
        /**
         * 3.計算簽名
         */
        String signature = sign(stringToSign, accessKeySecret + "&");
        if (null == signature) {
            System.out.println("計算簽名失敗!");
            return;
        }
        /**
         * 4.將簽名加入到第1步獲取的請求字符串
         */
        String queryStringWithSign = "Signature=" + signature + "&" + queryString;
        System.out.println("帶有簽名的請求字符串:" + queryStringWithSign);
        /**
         * 5.發送HTTP POST請求,調用ListCosyVoice接口可以查詢您某個前綴所有聲音的狀態。
         */
        processPostRequest(queryStringWithSign);
    }

    public static void main(String args[]) {
        if (args.length < 2) {
            System.err.println("Need params: <AccessKey Id> <AccessKey Secret>");
            System.exit(-1);
        }
        String accessKeyId = System.getenv().get("ALIYUN_AK_ID");
        String accessKeySecret = System.getenv().get("ALIYUN_AK_SECRET");
        String voicePrefix = "your-voice-prefix";
        String audioUrl = "audio-file-url";
        System.out.println(getISO8601Time(null));

        cosyCLone(accessKeyId, accessKeySecret, voicePrefix, audioUrl);
        cosyList(accessKeyId, accessKeySecret, voicePrefix, 1, 10);
    }
}

Python示例

說明
  • Python版本要求:Python3.4及以上。

  • 安裝Python HTTP庫Requests

  •  pip install requests
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import base64
import hashlib
import hmac
import requests
import time
import uuid
from urllib import parse
class CosyClone:
    @staticmethod
    def _encode_text(text):
        encoded_text = parse.quote_plus(text)
        return encoded_text.replace('+', '%20').replace('*', '%2A').replace('%7E', '~')
    @staticmethod
    def _encode_dict(dic):
        keys = dic.keys()
        dic_sorted = [(key, dic[key]) for key in sorted(keys)]
        encoded_text = parse.urlencode(dic_sorted)
        return encoded_text.replace('+', '%20').replace('*', '%2A').replace('%7E', '~')
    @staticmethod
    def cosy_clone(access_key_id, access_key_secret, voicePrefix, audio_url):
        parameters = {'AccessKeyId': access_key_id,
                      'Action': 'CosyVoiceClone',
                      'Format': 'JSON',
                      'RegionId': 'cn-shanghai',
                      'SignatureMethod': 'HMAC-SHA1',
                      'SignatureNonce': str(uuid.uuid1()),
                      'SignatureVersion': '1.0',
                      'Timestamp': time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
                      'Version': '2019-08-19',
                      'VoicePrefix': voicePrefix,
                      'Url': audio_url,
                      }
        # 構造規范化的請求字符串
        query_string = CosyClone._encode_dict(parameters)
        print('規范化的請求字符串: %s' % query_string)
        # 構造待簽名字符串
        string_to_sign = 'POST' + '&' + CosyClone._encode_text('/') + '&' + CosyClone._encode_text(query_string)
        print('待簽名的字符串: %s' % string_to_sign)
        # 計算簽名
        secreted_string = hmac.new(bytes(access_key_secret + '&', encoding='utf-8'),
                                   bytes(string_to_sign, encoding='utf-8'),
                                   hashlib.sha1).digest()
        signature = base64.b64encode(secreted_string)
        print('簽名: %s' % signature)
        # 進行URL編碼
        signature = CosyClone._encode_text(signature)
        print('URL編碼后的簽名: %s' % signature)
        # 調用服務
        full_url = 'https://nls-slp.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
        print('url: %s' % full_url)
        # 提交HTTP POST請求
        response = requests.post(full_url)
        print(response.text)
    
    @staticmethod
    def cosy_list(access_key_id, access_key_secret, voice_prefix, page_index=1, page_size=10):
        parameters = {'AccessKeyId': access_key_id,
                      'Action': 'ListCosyVoice',
                      'Format': 'JSON',
                      'RegionId': 'cn-shanghai',
                      'SignatureMethod': 'HMAC-SHA1',
                      'SignatureNonce': str(uuid.uuid1()),
                      'SignatureVersion': '1.0',
                      'Timestamp': time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
                      'Version': '2019-08-19',
                      'VoicePrefix': voice_prefix,
                      'PageIndex': page_index,
                      'PageSize': page_size,
                      }
        # 構造規范化的請求字符串
        query_string = CosyClone._encode_dict(parameters)
        print('規范化的請求字符串: %s' % query_string)
        # 構造待簽名字符串
        string_to_sign = 'POST' + '&' + CosyClone._encode_text('/') + '&' + CosyClone._encode_text(query_string)
        print('待簽名的字符串: %s' % string_to_sign)
        # 計算簽名
        secreted_string = hmac.new(bytes(access_key_secret + '&', encoding='utf-8'),
                                   bytes(string_to_sign, encoding='utf-8'),
                                   hashlib.sha1).digest()
        signature = base64.b64encode(secreted_string)
        print('簽名: %s' % signature)
        # 進行URL編碼
        signature = CosyClone._encode_text(signature)
        print('URL編碼后的簽名: %s' % signature)
        # 調用服務
        full_url = 'https://nls-slp.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
        print('url: %s' % full_url)
        # 提交HTTP POST請求
        response = requests.post(full_url)
        print(response.text)


if __name__ == "__main__":
    # 用戶信息
    access_key_id = os.getenv('ALIYUN_AK_ID')
    access_key_secret = os.getenv('ALIYUN_AK_SECRET')
    voice_prefix = 'your-voice-prefix'
    audio_url = 'your-audio-file-url'

    CosyClone.cosy_clone(access_key_id, access_key_secret, voice_prefix, audio_url)
    CosyClone.cosy_list(access_key_id, access_key_secret, voice_prefix)
   

服務狀態碼

狀態碼

狀態消息

原因和處理方法

40001000

QUOTA_ERROR

檢查是否開通服務。

40001001

VOICE_LIMIT_ERROR

音色克隆數量超限,目前默認1000個。

40001002

VOICE_PREFIX_ERROR

音色名前綴不滿足規則:

  • 不為空

  • 不超過10個字符

  • 僅包含數字和字母

40002000

AUDIO_URL_ERROR

音頻URL地址無效。

40002001

AUDIO_DOWNLOAD_FAIL

下載音頻失敗。

40002002

FILE_SIZE_EXCEED

音頻文件超過10 MB。

40002003

AUDIO_SAMPLE_RATE_ERROR

音頻采樣率小于16 kHz。

40002004

AUDIO_FORMAT_ERROR

音頻格式錯誤,解碼失敗,目前支持wavmp3m4aaac

40003000

SILENT_AUDIO_ERROR

音頻內無足夠的有效語音。

40003001

AUDIO_SNR_ERROR

音頻信噪比太低。

50000000

SERVER_ERROR

服務錯誤,一般可通過重試解決。