Clone voices using OpenAPI
The CosyVoice voice cloning service lets you quickly generate a natural-sounding custom voice that closely resembles the original. You only need to provide a short audio sample. To clone a voice with CosyVoice using OpenAPI, you must write your own code to handle identity verification and request logic. You can use OpenAPI to clone and query voices if a software development kit (SDK) is not available for your programming language or to control dependent components. This topic describes the API protocol.
Request message
The client can send requests over HTTPS using the POST method. The server provides an API that is based on the Alibaba Cloud POP protocol. Therefore, the client must implement the Alibaba Cloud POP signature mechanism.
URL
Protocol
URL
Method
HTTPS
https://nls-slp.cn-shanghai.aliyuncs.com
POST
Request parameters
Name
Type
Required
Description
AccessKeyId
String
Yes
The AccessKey ID of your Alibaba Cloud account.
Action
String
Yes
POP API name:
Voice cloning:
CosyVoiceCloneQuery voices:
ListCosyVoice
Version
String
Yes
POP API Version: 2019-08-19
Format
String
Yes
The format of the response:
JSONRegionId
String
Yes
The ID of the region where the service is located:
cn-shanghaiTimestamp
String
Yes
The timestamp of the request. The timestamp must follow the ISO 8601 standard and be in UTC. The time zone is +0. Format: YYYY-MM-DDThh:mm:ssZ. For example, 2019-04-03T06:15:03Z represents 06:15:03 on April 3, 2019 (UTC).
SignatureMethod
String
Yes
The signature algorithm:
HMAC-SHA1SignatureVersion
String
Yes
The version of the signature algorithm: 1.0
SignatureNonce
String
Yes
A universally unique identifier (UUID) that prevents replay attacks. Each request must have a unique UUID that cannot be reused. The format is A-B-C-D-E, where the number of characters for A, B, C, D, and E is 8, 4, 4, 4, and 12, respectively. Example:
8d1e6a7a-f44e-40d5-aedb-fe4a1c80f434.Signature
String
Yes
The signature string calculated from all request parameters. For information about how to generate the signature, see the "Signature mechanism" section.
VoicePrefix
String
Yes
The prefix for the cloned voice. It can contain only lowercase letters and digits, and must be no more than 10 characters in length.
Url
String
Required only for CosyVoiceClone.
The URL of the audio file for voice cloning.
PageIndex
Integer
Used only for ListCosyVoice. This parameter is optional. The default value is 1.
The page number of the voice list to query.
PageSize
Integer
Used only for ListCosyVoice. This parameter is optional. The default value is 10.
The number of voices on each page.
HTTPS request headers
An HTTPS request header consists of key-value pairs. Each pair is on a separate line. The key and value in each pair are separated by a colon (:). The header includes the following content:
Name
Type
Required
Description
Host
String
No
The server domain name for HTTPS requests is
nls-meta.cn-shanghai.aliyuncs.com. This domain name is typically parsed automatically from the request URL.Accept
String
No
Specifies the content types that the client can accept:
application/json. If not set, the default is */*.Content-type
String
Required for the POST method
Specifies the data format of the request body for the POST method:
application/x-www-form-urlencoded.
Message examples
HTTPS POST request message
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-prefixListCosyVoice
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
Response
After you send an HTTPS request, the server returns a response. The result is returned in the response as a JSON string.
Successful response
The HTTPS status code is 200. The response fields are described in the following table.
Parameter
Type
Description
RequestId
String
requestId
Message
String
SUCCESS
VoiceName
String
The name of the successfully cloned 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": [ ] }
Failed response
The HTTPS status code is not 200. The response fields are described in the following table.
Parameter
Type
Description
RequestId
String
The ID of the request.
Message
String
The error message returned for the failed request.
Recommend
String
Troubleshooting suggestions.
HostId
String
The ID of the host.
Code
String
The error type of the failed response. For more information, see Service status codes.
{ "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" }
Signature mechanism
The server-side OpenAPI authenticates the sender of each API request. You must include signature information in your requests. The signature mechanism allows the server to identify the user who sends the API request and verify that the request has not been tampered with during transmission.
Security authentication flow
To calculate a signature, you need the AccessKey ID and AccessKey secret of your Alibaba Cloud account. The HMAC-SHA1 algorithm is used for symmetric encryption. The workflow is as follows:
The client generates a string to sign based on the API request content, which includes the HTTPS request parameters and the request body.
The client uses the AccessKey ID and AccessKey secret of the Alibaba Cloud account to sign the string that is generated in the previous step. This creates a digital signature for the API request.
The client sends the API request content and the digital signature to the server.
After receiving the request, the server repeats steps 1 and 2 to calculate the expected digital signature. The server retrieves the user's key.
The server compares the expected digital signature with the digital signature sent by the client. If they match, the request is authenticated. Otherwise, the request is rejected.
Generate the string to sign for a request
Construct the canonicalized query string.
Construct a canonicalized query string from the HTTPS request parameters, excluding the Signature parameter. The steps are as follows:
Sort the parameters. Sort the request parameters by parameter name in case-sensitive lexicographical order.
Encode the parameters. Encode the sorted request parameters.
URL-encode the request parameter names and values using the
UTF-8character set. The URL encoding rules are as follows:Do not encode uppercase letters (A-Z), lowercase letters (a-z), digits (0-9), hyphens (
-), underscores (_), periods (.), or tildes (~).Encode other characters into the "%XY" format, where XY is the hexadecimal representation of the character's ASCII code. For example, a double quotation mark (") is encoded as %22.
Encode extended
UTF-8characters into the "%XY%ZA..." format.An English space must be encoded as %20, not as a plus sign (
+).
NoteMost URL encoding libraries, such as `java.net.URLEncoder` in Java, encode according to the rules of the "application/x-www-form-urlencoded" Multipurpose Internet Mail Extensions (MIME) type. You can use this method for encoding. Then, in the encoded string, replace plus signs (
+) with%20, asterisks (*) with%2A, and%7Ewith tildes (~) to obtain the encoded string that is described in the preceding rules.Use an equal sign (
=) to connect the URL-encoded parameter name and value:percentEncode(ParameterKey) + "=" + percentEncode(ParameterValue).Use an ampersand (
&) to connect the URL-encoded request parameter pairs from the previous step. For example:Action=CreateToken&Format=JSON.NoteDo not add an ampersand (
&) before the first parameter name in the string.Return the canonicalized query string.
The following provides an example:
String percentEncode(String value) throws UnsupportedEncodingException { return value != null ? URLEncoder.encode(value, URL_ENCODING) .replace("+", "%20") .replace("*", "%2A") .replace("%7E", "~") : null; } // Sort the parameter keys String[] sortedKeys = queryParamsMap.keySet().toArray(new String[] {}); Arrays.sort(sortedKeys); // Encode and concatenate the sorted parameters for (String key : sortedKeys) { canonicalizedQueryString.append("&") .append(percentEncode(key)).append("=") .append(percentEncode(queryParamsMap.get(key))); } queryString = canonicalizedQueryString.toString().substring(1);NoteFor the complete code implementation, see the
canonicalizedQueryfunction in the full example.Construct the canonicalized query string:
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-19Construct the string to sign.
Concatenate the HTTPS request method (GET), the URL-encoded URL path (/), and the canonicalized query string from step 1 with the
&character to create the string to be signed:HTTPSMethod + "&" + percentEncode("/") + "&" + percentEncode(queryString).The following code provides an example of how to construct the string to sign:
StringBuilder strBuilderSign = new StringBuilder(); strBuilderSign.append(HTTPMethod); strBuilderSign.append("&"); strBuilderSign.append(percentEncode(urlPath)); strBuilderSign.append("&"); strBuilderSign.append(percentEncode(queryString)); stringToSign = strBuilderSign.toString();NoteFor the complete code implementation, see the
createStringToSignfunction in the full example.The constructed string to sign:
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-19Calculate the signature.
The signature is calculated using the HMAC-SHA1 algorithm and then Base64-encoded. The character encoding is
UTF-8.Use your AccessKey secret to calculate the HMAC-SHA1 digital signature for the string to sign that you constructed in Step 2. When calculating the signature, you must append an ampersand (
&) to your AccessKey secret.The signature must also be URL-encoded.
The following code provides an example of how to calculate the signature:
signature = Base64( HMAC-SHA1(stringToSign, accessKeySecret + "&") ); // URL-encode the signature signature = percentEncode(signature)NoteFor the complete code implementation, see the
signfunction in the full example.The calculated signature:
# Signature string AKIktdPUMCV12fTh667BLXeuCtg= # URL-encoded result AKIktdPUMCV12fTh667BLXeuCtg%3DAfter you calculate the signature, join its key and value with an
=character and append the result to the query string from step 1 with an&character. You can then send the complete string to the server-side in an HTTPS GET request to obtain the token.String queryStringWithSign = "Signature=" + signature + "&" + queryString;
Quick test
You can use the following parameters to calculate a signature and compare the result with your own.
The AccessKey ID and AccessKey secret are not real. The timestamp has expired. A signature calculated with these parameters will fail when you try to obtain a token. This test is provided only for you to compare your signature calculation results.
AccessKeyId:
my_access_key_idAccessKeySecret:
my_access_key_secretTimestamp:
2019-04-18T08:32:31ZSignatureNonce:
b924c8c3-6d03-4c5d-ad36-d984d3116788
The request parameters are as follows:
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-72ec8d600bedConstruct the canonicalized query string.
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_prefixConstruct the string to sign.
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_prefixCalculate the signature.
xDyEd10/tcCLyq5mfV3QEipF9vs= # URL-encoded result xDyEd10%2FtcCLyq5mfV3QEipF9vs%3DObtain the request string with the signature.
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_prefixAssemble the HTTPS request URL.
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_prefixUse the HTTPS request URL from Step 5 to clone a CosyVoice voice using a browser or cURL.
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
Complete examples
This topic provides example code in Java and Python. You can implement client programs in other languages based on the protocol and the provided examples.
Before you call the API, configure environment variables to read your access credentials. The environment variable names for the Intelligent Speech Interaction AccessKey ID and AccessKey secret are ALIYUN_AK_ID and ALIYUN_AK_SECRET.
Java example
Dependencies:
<!-- 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>Example code:
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";
/**
* Get the timestamp.
* Must conform to the ISO 8601 standard and use UTC with time zone +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);
}
/**
* Get the UUID.
*/
public static String getUniqueNonce() {
UUID uuid = UUID.randomUUID();
return uuid.toString();
}
/**
* URL encoding.
* Use the UTF-8 character set to encode request parameters and their values according to RFC 3986.
*/
public static String percentEncode(String value) throws UnsupportedEncodingException {
return value != null ? URLEncoder.encode(value, URL_ENCODING).replace("+", "%20")
.replace("*", "%2A").replace("%7E", "~") : null;
}
/***
* Sorts the parameters, normalizes them, and combines them into a request string.
* @param queryParamsMap All request parameters.
* @return The canonicalized query string.
*/
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("Canonicalized query string: " + queryString);
} catch (UnsupportedEncodingException e) {
System.out.println("UTF-8 encoding is not supported.");
e.printStackTrace();
}
return queryString;
}
/***
* Constructs the string to sign.
* @param method The HTTP request method.
* @param urlPath The URI of the HTTP request.
* @param queryString The canonicalized query string.
* @return The string to sign.
*/
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("Constructed string to sign: " + stringToSign);
} catch (UnsupportedEncodingException e) {
System.out.println("UTF-8 encoding is not supported.");
e.printStackTrace();
}
return stringToSign;
}
/***
* Calculates the signature.
* @param stringToSign The string to sign.
* @param accessKeySecret The Alibaba Cloud AccessKey secret with an ampersand (&) appended.
* @return The calculated signature.
*/
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("Calculated signature: " + signBase64);
String signUrlEncode = percentEncode(signBase64);
System.out.println("URL-encoded signature: " + 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());
}
}
/***
* Sends an HTTP POST request.
* @param queryString The request parameters.
*/
public static void processPostRequest(String queryString) {
/**
* Configure the HTTP POST request.
* 1. Use the HTTPS protocol.
* 2. Service domain name: nls-slp.cn-shanghai.aliyuncs.com
* 3. Request path: /
* 4. Set the request parameters.
*/
String url = "https://nls-slp.cn-shanghai.aliyuncs.com";
url = url + "/";
url = url + "?" + queryString;
System.out.println("HTTP request URL: " + 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("Request failed: " + result);
}
response.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Calls the CosyVoiceClone operation to clone a voice.
* @param accessKeyId The Alibaba Cloud AccessKey ID.
* @param accessKeySecret The Alibaba Cloud AccessKey secret.
* @param voicePrefix The voice prefix.
* @param audioFileUrl The URL of the audio file.
*/
public static void cosyCLone(String accessKeyId, String accessKeySecret, String voicePrefix, String audioFileUrl) {
// All request parameters
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. Construct the canonicalized query string.
*/
String queryString = canonicalizedQuery(queryParamsMap);
if (null == queryString) {
System.out.println("Failed to construct the canonicalized query string!");
return;
}
/**
* 2. Construct the string to sign.
*/
String method = "POST"; // The HTTP method for the request, POST.
String urlPath = "/"; // The request path.
String stringToSign = createStringToSign(method, urlPath, queryString);
if (null == stringToSign) {
System.out.println("Failed to construct the string to sign");
return;
}
/**
* 3. Calculate the signature.
*/
String signature = sign(stringToSign, accessKeySecret + "&");
if (null == signature) {
System.out.println("Failed to calculate the signature!");
return;
}
/**
* 4. Add the signature to the request string from step 1.
*/
String queryStringWithSign = "Signature=" + signature + "&" + queryString;
System.out.println("Request string with signature: " + queryStringWithSign);
/**
* 5. Send an HTTP POST request. You can call the ListCosyVoice operation to query the status of all voices with a specific prefix.
*/
processPostRequest(queryStringWithSign);
}
/**
* Calls the ListCosyVoice operation to query the status of all voices with a specific prefix.
* @param accessKeyId The Alibaba Cloud AccessKey ID.
* @param accessKeySecret The Alibaba Cloud AccessKey secret.
* @param voicePrefix The voice prefix.
* @param pageIndex The page number.
* @param pageSize The page size.
*/
public static void cosyList(String accessKeyId, String accessKeySecret, String voicePrefix, int pageIndex, int pageSize) {
// All request parameters
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. Construct the canonicalized query string.
*/
String queryString = canonicalizedQuery(queryParamsMap);
if (null == queryString) {
System.out.println("Failed to construct the canonicalized query string!");
return;
}
/**
* 2. Construct the string to sign.
*/
String method = "POST"; // The HTTP method for the request, POST.
String urlPath = "/"; // The request path.
String stringToSign = createStringToSign(method, urlPath, queryString);
if (null == stringToSign) {
System.out.println("Failed to construct the string to sign");
return;
}
/**
* 3. Calculate the signature.
*/
String signature = sign(stringToSign, accessKeySecret + "&");
if (null == signature) {
System.out.println("Failed to calculate the signature!");
return;
}
/**
* 4. Add the signature to the request string from step 1.
*/
String queryStringWithSign = "Signature=" + signature + "&" + queryString;
System.out.println("Request string with signature: " + queryStringWithSign);
/**
* 5. Send an HTTP POST request. You can call the ListCosyVoice operation to query the status of all voices with a specific prefix.
*/
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 = "your-audio-file-url";
System.out.println(getISO8601Time(null));
cosyCLone(accessKeyId, accessKeySecret, voicePrefix, audioUrl);
cosyList(accessKeyId, accessKeySecret, voicePrefix, 1, 10);
}
}Python Example
Python version requirement: Python 3.4 or later.
Install the Requests HTTP library for Python:
pip install requests#!/usr/bin/env python3
# -*- 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,
}
# Construct the canonicalized query string
query_string = CosyClone._encode_dict(parameters)
print('Canonicalized query string: %s' % query_string)
# Construct the string to sign
string_to_sign = 'POST' + '&' + CosyClone._encode_text('/') + '&' + CosyClone._encode_text(query_string)
print('String to sign: %s' % string_to_sign)
# Calculate the signature
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('Signature: %s' % signature)
# URL-encode the signature
signature = CosyClone._encode_text(signature)
print('URL-encoded signature: %s' % signature)
# Call the service
full_url = 'https://nls-slp.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
print('url: %s' % full_url)
# Submit the HTTP POST request
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,
}
# Construct the canonicalized query string
query_string = CosyClone._encode_dict(parameters)
print('Canonicalized query string: %s' % query_string)
# Construct the string to sign
string_to_sign = 'POST' + '&' + CosyClone._encode_text('/') + '&' + CosyClone._encode_text(query_string)
print('String to sign: %s' % string_to_sign)
# Calculate the signature
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('Signature: %s' % signature)
# URL-encode the signature
signature = CosyClone._encode_text(signature)
print('URL-encoded signature: %s' % signature)
# Call the service
full_url = 'https://nls-slp.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (signature, query_string)
print('url: %s' % full_url)
# Submit the HTTP POST request
response = requests.post(full_url)
print(response.text)
if __name__ == "__main__":
# User information
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)
Service status codes
Status code | Status message | Cause and solution |
40001000 | QUOTA_ERROR | Check whether the service is activated. |
40001001 | VOICE_LIMIT_ERROR | The number of cloned voices exceeds the limit. The default limit is 1,000. |
40001002 | VOICE_PREFIX_ERROR | The voice name prefix does not meet the following rules:
|
40002000 | AUDIO_URL_ERROR | The audio URL is invalid. |
40002001 | AUDIO_DOWNLOAD_FAIL | Failed to download the audio. |
40002002 | FILE_SIZE_EXCEED | The audio file exceeds 10 MB. |
40002003 | AUDIO_SAMPLE_RATE_ERROR | The audio sample rate is less than 16 kHz. |
40002004 | AUDIO_FORMAT_ERROR | The audio format is incorrect and decoding failed. The supported formats are |
40003000 | SILENT_AUDIO_ERROR | There is not enough valid speech in the audio. |
40003001 | AUDIO_SNR_ERROR | The signal-to-noise ratio (SNR) of the audio is too low. |
50000000 | SERVER_ERROR | A service error occurred. Retrying the operation usually resolves the issue. When you use the CosyVoice voice cloning feature, this error usually occurs because the recording quality is poor. Follow the instructions in the Recording guide to re-record the audio and perform voice cloning. Make sure that the recorded audio has no noise, avoid frequent and unnecessary pauses, and ensure that there are at least 5 seconds of continuous sound. |
- | ACCESS_DENIED : Permission denied! | Permission denied. During voice cloning, this error occurs if you use a RAM user that has not been granted the AliyunNLSFullAccess permission. For more information, see Manage RAM user permissions. |