RESTful API

长文本语音合成RESTful API支持HTTPS POST方式请求,将待合成的文本通过HTTPS POST上传到服务端,服务端返回文本的语音合成结果。

功能介绍

支持如下设置:

  • 合成音频的格式:PCM、WAV、MP3。

  • 合成音频的采样率:8000 Hz、16000 Hz。

  • 多种发音人。

  • 可设置语速、语调、音量。

  • 数据获取方式:轮询方式、回调方式。

注意

  • 随着TTS合成效果不断提升,算法的复杂度也越来越高,对您而言,可能会遇到合成耗时变长的情况。因此我们建议您使用流式合成机制。本文及SDK示例中有相关流式处理示例代码可供参考。

  • 下载nls-restful-java-demo.zip

    新增RESTful语音合成Java示例代码。

前提条件

服务地址

访问类型

说明

URL

Host

外网访问

所有服务器均可使用外网访问URL。

https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async

nls-gateway.cn-shanghai.aliyuncs.com

内网访问

使用阿里云上海ECS(即ECS地域为华东2(上海)),可使用内网访问URL。

http://nls-gateway.cn-shanghai-internal.aliyuncs.com/rest/v1/tts/async

nls-gateway.cn-shanghai-internal.aliyuncs.com

注意

以下将以使用外网访问URL的方式进行介绍。如果您使用阿里云上海ECS,并需要通过内网访问URL,则使用HTTP协议,并替换外网访问的URL和Host。以下示例中除了Python,均支持HTTP和HTTPS协议,在使用Python示例时请阅读其注意事项。

POST方法上传文本

一个完整的语音合成RESTful API POST请求包含以下要素:

  • URL

    协议

    URL

    方法

    HTTPS

    https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async

    POST

  • HTTPS POST请求体

    请求体是请求参数组成的JSON格式字符串,因此在POST请求头部中的Content-Type必须设置为”application/json”,示例如下。

    {
        "payload":{
            "tts_request":{
                "voice":"xiaoyun",
                "sample_rate":16000,
                "format":"wav",
                "text":"今天天气好晴朗",
                "enable_subtitle": true
            },
            "enable_notify":false
        },
        "context":{
            "device_id":"my_device_id"
        },
        "header":{
            "appkey":"yourAppkey",
            "token":"yourToken"
        }
    }

响应结果

发送请求后,不论是调用成功还是失败,服务端的响应消息都会通过HTTP的消息体返回给客户端。使用HTTPS GET方法和使用HTTPS POST方法请求的响应是相同的,响应的结果都包含在HTTPS的Body中。响应结果的成功或失败通过HTTPS Header的Content-Type字段来区分:

  • 成功响应

    • HTTPS Headers的Content-Type字段内容为audio/mpeg,表示合成成功,合成的语音数据在Body中。

    • HTTPS Header的X-NLS-RequestId字段内容为请求任务的task_id

    • Body内容为合成音频的二进制数据。

  • 失败响应

    • HTTPS Headers没有Content-Type字段,或者Content-Type字段内容为application/json,表示合成失败,错误信息在Body中。

    • HTTPS Header的X-NLS-RequestId字段内容为请求任务的task_id

    • Body内容为错误信息,以JSON格式的字符串表示。

      错误信息字段如下表所示。

      名称

      类型

      描述

      task_id

      String

      32位请求任务ID,请记录该值,用于排查错误。

      error_code

      Integer

      服务状态码。

      error_message

      String

      服务状态描述。

  • 发起请求后的成功响应

    {
      "status":200,
      "error_code":20000000,
      "error_message":"SUCCESS",
      "request_id":"f0a9e2c49e9049e78730a3bf0b32****",
      "data":{
          "task_id":"35d9f813e00b11e9a2ce9ba0d6a2****"
      }
    }
  • 发起请求后的失败响应

    {
      "error_message":"Meta:ACCESS_DENIED:The token 'fdf' is invalid!",
      "error_code":40000001,
      "request_id":"0d8c0eea55824aada9a374aec650****",
      "url":"/rest/v1/tts/async",
      "status":400
    }
  • 轮询服务端合成状态的成功响应

    /// 轮询时服务端返回的中间状态。
    {
        "status":200,
        "error_code":20000000,
        "error_message":"RUNNING",
        "request_id":"a3370c49a29148e78b39978f98ba****",
        "data":{
            "task_id":"35d9f813e00b11e9a2ce9ba0d6a2****",
            "audio_address":null,
            "notify_custom":null
        }
    }
    /// 获取到最终合成结果。
    {
        "status":200,
        "error_code":20000000,
        "error_message":"SUCCESS",
        "request_id":"c541eae489af48d69dae2d2e203a****",
        "data":{
            "sentences":[
                {
                    "text":"长文本语音合成接口",
                    "begin_time":"0",
                    "end_time":"2239"
                },
                {
                    "text":"一次返回所有文本对应的音频.现在需要增加句级别的时间戳信息",
                    "begin_time":"2239",
                    "end_time":"8499"
                },
                {
                    "text":"客户可利用该信息,实现播放控制功能",
                    "begin_time":"8499",
                    "end_time":"12058"
                }
            ],
            "task_id":"f4e9bf53cb1611eab327b15f61b4****",
            "audio_address":"此处为生成的url地址",
            "notify_custom":""
        }
    }

    说明

    audio_address字段对应的HTTP下载地址有期限最多只有3天。

服务状态码

服务状态码

服务状态描述

解决办法

20000000

请求成功

无。

40000000

默认的客户端错误码

检查对应的错误消息。

40000001

身份认证失败

检查使用的令牌是否正确,是否过期。

40000002

无效的消息

检查发送的消息是否符合要求。

40000003

无效的参数

检查参数值设置是否合理。

40000004

空闲超时

确认是否长时间没有发送数据到服务端。

40000005

请求数量过多

检查是否超过了并发连接数或者每秒钟请求数。

40000010

新用户免费试用3个月已到期

继续使用需要付费商用,请前往控制台,在服务管理与开通页面,单击目标服务右侧的升级为商用版,进行付费使用。

50000000

默认的服务端错误

内部服务错误,需要客户端进行重试。

50000001

内部GRPC调用错误

内部服务错误,需要客户端进行重试。

Java示例

依赖文件内容如下:

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

示例代码如下:

package com.alibaba.nls.client;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 此示例演示了长文本语音合成的使用方式。
 */
public class SpeechLongSynthesizerRestfulDemo {
    private static Logger logger = LoggerFactory.getLogger(SpeechLongSynthesizerRestfulDemo.class);
    private String accessToken;
    private String appkey;
    public SpeechLongSynthesizerRestfulDemo(String appkey, String token) {
        this.appkey = appkey;
        this.accessToken = token;
    }
    public void processPOSTRequest(String text, String format, int sampleRate, String voice) {
        String url = "https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async";
        // 拼接HTTP Post请求的消息体内容。
        JSONObject context = new JSONObject();
        // device_id设置,可以设置为自定义字符串或者设备信息id。
        context.put("device_id", "my_device_id");
        JSONObject header = new JSONObject();
        // 设置你的appkey。获取Appkey请前往控制台:https://nls-portal.console.aliyun.com/applist
        header.put("appkey", appkey);
        // 设置你的Token。获取Token具体操作,请参见:https://help.aliyun.com/document_detail/450514.html
        header.put("token", accessToken);
        // voice 发音人,可选,默认是xiaoyun。
        // volume 音量,范围是0~100,可选,默认50。
        // speech_rate 语速,范围是-500~500,可选,默认是0。
        // pitch_rate 语调,范围是-500~500,可选,默认是0。
        JSONObject tts = new JSONObject();
        tts.put("text", text);
        // 设置发音人。
        tts.put("voice", voice);
        // 设置编码格式。
        tts.put("format", format);
        // 设置采样率。
        tts.put("sample_rate", sampleRate);
        // 设置声音大小,可选。
        //tts.put("volume", 100);
        // 设置语速,可选。
        //tts.put("speech_rate", 200);
        // 长文本tts restful接口支持句级时间戳,默认为false。
        tts.put("enable_subtitle", true);
        JSONObject payload = new JSONObject();
        // 可选,是否设置回调。如果设置,则服务端在完成长文本语音合成之后回调用户此处设置的回调接口,将请求状态推送给用户侧。
        payload.put("enable_notify", false);
        payload.put("notify_url", "http://123.com");
        payload.put("tts_request", tts);
        JSONObject json = new JSONObject();
        json.put("context", context);
        json.put("header", header);
        json.put("payload", payload);
        String bodyContent = json.toJSONString();
        logger.info("POST Body Content: " + bodyContent);
        // 发起请求
        RequestBody reqBody = RequestBody.create(MediaType.parse("application/json"), bodyContent);
        Request request = new Request.Builder()
            .url(url)
            .header("Content-Type", "application/json")
            .post(reqBody)
            .build();
        try {
            OkHttpClient client = new OkHttpClient();
            Response response = client.newCall(request).execute();
            String contentType = response.header("Content-Type");
            System.out.println("contentType = " + contentType);
            // 获取结果,并根据返回进一步进行处理。
            String result = response.body().string();
            response.close();
            System.out.println("result = " + result);
            JSONObject resultJson = JSON.parseObject(result);
            if(resultJson.containsKey("error_code") && resultJson.getIntValue("error_code") == 20000000) {
                logger.info("Request Success! task_id = " + resultJson.getJSONObject("data").getString("task_id"));
                String task_id = resultJson.getJSONObject("data").getString("task_id");
                String request_id = resultJson.getString("request_id");
                /// 可选:轮询检查服务端的合成状态,该轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
                waitLoop4Complete(url, appkey, accessToken, task_id, request_id);
            }else {
                logger.error("Request Error: status=" + resultJson.getIntValue("status")
                    + ", error_code=" + resultJson.getIntValue("error_code")
                    + ", error_message=" + resultJson.getString("error_message"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /// 根据特定信息轮询检查某个请求在服务端的合成状态,轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
    private void waitLoop4Complete(String url, String appkey, String token, String task_id, String request_id) {
        String fullUrl = url + "?appkey=" + appkey + "&task_id=" + task_id + "&token=" + token + "&request_id=" + request_id;
        System.out.println("query url = " + fullUrl);
        while(true) {
            Request request = new Request.Builder().url(fullUrl).get().build();
            try {
                OkHttpClient client = new OkHttpClient();
                Response response = client.newCall(request).execute();
                String result = response.body().string();
                response.close();
                System.out.println("waitLoop4Complete = " + result);
                JSONObject resultJson = JSON.parseObject(result);
                if(resultJson.containsKey("error_code")
                    && resultJson.getIntValue("error_code") == 20000000
                    && resultJson.containsKey("data")
                    && resultJson.getJSONObject("data").getString("audio_address") != null) {
                    logger.info("Tts Finished! task_id = " + resultJson.getJSONObject("data").getString("task_id"));
                    logger.info("Tts Finished! audio_address = " + resultJson.getJSONObject("data").getString("audio_address"));
                    break;
                }else {
                    logger.info("Tts Queuing...");
                }
                // 每隔10秒钟轮询一次状态。
                Thread.sleep(10000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        if (args.length < 2) {
            System.err.println("SpeechLongSynthesizerRestfulDemo need params: <token> <app-key>");
            System.exit(-1);
        }
        String token = args[0];
        String appkey = args[1];
        SpeechLongSynthesizerRestfulDemo demo = new SpeechLongSynthesizerRestfulDemo(appkey, token);
        String text = "我家的后面有一个很大的园,相传叫作百草园。现在是早已并屋子一起卖给朱文公的子孙了,连那最末次的相见也已经隔了七八年,其中似乎确凿只有一些野草;但那时却是我的乐园。";
        String format = "wav";
        int sampleRate = 16000;
        String voice = "siyue";
        demo.processPOSTRequest(text, format, sampleRate, voice);
    }
}

Python示例

说明

  • Python 2.x请使用httplib模块;Python 3.x请使用http.client模块。

  • 如果使用阿里云上海ECS内网访问URL,请使用HTTP协议,需要替换如下函数,即将HTTPSConnection修改为HTTPConnection

Python 3.x

import http.client
import urllib.request
import json
import time


class TtsHeader:
    def __init__(self, appkey, token):
        self.appkey = appKey
        self.token = token

    def tojson(self, e):
        return {'appkey': e.appkey, 'token': e.token}


class TtsContext:
    def __init__(self, device_id):
        self.device_id = device_id
    # 将序列化函数定义到类中。

    def tojson(self, e):
        return {'device_id': e.device_id}


class TtsRequest:
    def __init__(self, voice, sample_rate, format, enable_subtitle, text):
        self.voice = voice
        self.sample_rate = sample_rate
        self.format = format
        self.enable_subtitle = enable_subtitle
        self.text = text

    def tojson(self, e):
        return {'voice': e.voice, 'sample_rate': e.sample_rate, 'format': e.format, 'enable_subtitle': e.enable_subtitle, 'text': e.text}


class TtsPayload:
    def __init__(self, enable_notify, notify_url, tts_request):
        self.enable_notify = enable_notify
        self.notify_url = notify_url
        self.tts_request = tts_request

    def tojson(self, e):
        return {'enable_notify': e.enable_notify, 'notify_url': e.notify_url, 'tts_request': e.tts_request.tojson(e.tts_request)}


class TtsBody:
    def __init__(self, tts_header, tts_context, tts_payload):
        self.tts_header = tts_header
        self.tts_context = tts_context
        self.tts_payload = tts_payload

    def tojson(self, e):
        return {'header': e.tts_header.tojson(e.tts_header), 'context': e.tts_context.tojson(e.tts_context), 'payload': e.tts_payload.tojson(e.tts_payload)}
# 根据特定信息轮询检查某个请求在服务端的合成状态,每隔10秒钟轮询一次状态.轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。


def waitLoop4Complete(url, appkey, token, task_id, request_id):
    # fullUrl = url + "?appkey=" + appkey + "&task_id=" + task_id + "&token=" + token + "&request_id=" + request_id

    fullUrl = url + "?appkey=" + appkey + "&task_id=" + \
        task_id + "&token=" + token + "&request_id=" + request_id

    print("fullUrl=", fullUrl)
    host = {"Host": "nls-gateway.cn-shanghai.aliyuncs.com", "Accept": "*/*",
            "Connection": "keep-alive", 'Content-Type': 'application/json'}
    while True:
        result = urllib.request.urlopen(fullUrl).read()
        print("query result = ", result)
        jsonData = json.loads(result)

        # jsonData["data"]["audio_address"] is None表示还在未合成完成的状态...每隔10秒钟轮询一次状态
        if (jsonData["data"]["audio_address"] is None):
            print(" Tts Queuing...please wait...")
            time.sleep(10)
        elif "error_code" in jsonData and jsonData["error_code"] == 20000000 and "data" in jsonData and (jsonData["data"]["audio_address"] != ""):
            print("Tts Finished! task_id = " + jsonData["data"]["task_id"])
            print("Tts Finished! audio_address = " +
                  jsonData["data"]["audio_address"])
            break

        else:
            print("Tts Running...")
            time.sleep(10)
# 长文本语音合成restful接口,支持post调用,不支持get请求。发出请求后,可以轮询状态或者等待服务端合成后自动回调(如果设置了回调参数)。


def requestLongTts4Post(tts_body, appkey, token):
    host = 'nls-gateway.cn-shanghai.aliyuncs.com'
    url = 'https://' + host + '/rest/v1/tts/async'
    # 设置HTTP Headers
    http_headers = {'Content-Type': 'application/json'}
    print('The POST request body content: ' + tts_body)
    conn = http.client.HTTPSConnection(host)
    #conn = httplib.HTTPConnection(host)
    conn.request(method='POST', url=url, body=tts_body, headers=http_headers)
    response = conn.getresponse()
    print('Response status and response reason:')
    print(response.status, response.reason)
    contentType = response.getheader('Content-Type')
    print(contentType)
    body = response.read()
    if response.status == 200:
        jsonData = json.loads(body)
        print('The request succeed : ', jsonData)
        print('error_code = ', jsonData['error_code'])
        task_id = jsonData['data']['task_id']
        request_id = jsonData['request_id']
        print('task_id = ', task_id)
        print('request_id = ', request_id)
        # 说明:轮询检查服务端的合成状态,轮询操作非必须。如果设置了回调url,则服务端会在合成完成后主动回调。
        waitLoop4Complete(url, appkey, token, task_id, request_id)
    else:
        print('The request failed: ' + str(body))


appKey = 'yourAppkey'
token = 'yourToken'

text = '今天是周一,天气挺好的。'

# 拼接HTTP Post请求的消息体内容。
th = TtsHeader(appKey, token)
tc = TtsContext("mydevice")
# TtsRequest对象内容为:发音人、采样率、语音格式、待合成文本内容。
tr = TtsRequest("xiaoyun", 16000, "wav", False, text)
# 是否设置回调url,回调url地址,TtsRequest对象。
tp = TtsPayload(True, "http://134.com", tr)
tb = TtsBody(th, tc, tp)
body = json.dumps(tb, default=tb.tojson)
requestLongTts4Post(str(body), appKey, token)

Python 2.x

# -*- coding: UTF-8 -*-
# Python 2.x
import httplib
import urllib
import urllib2
import json
import time

class TtsHeader:
    def __init__(self, appkey, token):
        self.appkey = appKey
        self.token = token
    def tojson(self, e):
        return {'appkey': e.appkey, 'token': e.token}
class TtsContext:
    def __init__(self, device_id):
        self.device_id = device_id
    #将序列化函数定义到类中。
    def tojson(self, e):
        return {'device_id': e.device_id}
class TtsRequest:
    def __init__(self, voice, sample_rate, format, enable_subtitle, text):
        self.voice = voice
        self.sample_rate = sample_rate
        self.format = format
        self.enable_subtitle = enable_subtitle
        self.text = text
    def tojson(self, e):
        return {'voice': e.voice, 'sample_rate': e.sample_rate, 'format': e.format, 'enable_subtitle': e.enable_subtitle, 'text': e.text}
class TtsPayload:
    def __init__(self, enable_notify, notify_url, tts_request):
        self.enable_notify = enable_notify
        self.notify_url = notify_url
        self.tts_request = tts_request
    def tojson(self, e):
        return {'enable_notify': e.enable_notify, 'notify_url': e.notify_url, 'tts_request': e.tts_request.tojson(e.tts_request)}
class TtsBody:
    def __init__(self, tts_header, tts_context, tts_payload):
        self.tts_header = tts_header
        self.tts_context = tts_context
        self.tts_payload = tts_payload
    def tojson(self, e):
        return {'header': e.tts_header.tojson(e.tts_header), 'context': e.tts_context.tojson(e.tts_context), 'payload': e.tts_payload.tojson(e.tts_payload)}
# 根据特定信息轮询检查某个请求在服务端的合成状态,每隔10秒钟轮询一次状态.轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
def waitLoop4Complete(url, appkey, token, task_id, request_id):
    # fullUrl = url + "?appkey=" + appkey + "&task_id=" + task_id + "&token=" + token + "&request_id=" + request_id

    fullUrl = url + "?appkey=" + appkey + "&task_id=" + task_id + "&token=" + token + "&request_id=" + request_id

    print("fullUrl=", fullUrl)
    host = {"Host":"nls-gateway.cn-shanghai.aliyuncs.com", "Accept":"*/*", "Connection":"keep-alive",'Content-Type': 'application/json'}
    while True:
        req = urllib2.Request(url=fullUrl)
        result = urllib2.urlopen(req).read()
        print("query result = ", result)
        jsonData = json.loads(result)

        # jsonData["data"]["audio_address"] is None表示还在未合成完成的状态...每隔10秒钟轮询一次状态
        if (jsonData["data"]["audio_address"] is None):
            print(" Tts Queuing...please wait...")
            time.sleep(10)
        elif jsonData.has_key("error_code") and jsonData["error_code"] == 20000000 and jsonData.has_key("data") and (jsonData["data"]["audio_address"] != ""):
            print("Tts Finished! task_id = " + jsonData["data"]["task_id"])
            print("Tts Finished! audio_address = " + jsonData["data"]["audio_address"])
            break

        else:
            print("Tts Running...")
            time.sleep(10)
# 长文本语音合成restful接口,支持post调用,不支持get请求。发出请求后,可以轮询状态或者等待服务端合成后自动回调(如果设置了回调参数)。
def requestLongTts4Post(tts_body, appkey, token):
    host = 'nls-gateway.cn-shanghai.aliyuncs.com'
    url = 'https://' + host + '/rest/v1/tts/async'
    # 设置HTTP Headers
    http_headers = {'Content-Type': 'application/json'}
    print('The POST request body content: ' + tts_body)
    conn = httplib.HTTPSConnection(host)
    #conn = httplib.HTTPConnection(host)
    conn.request(method='POST', url=url, body=tts_body, headers=http_headers)
    response = conn.getresponse()
    print('Response status and response reason:')
    print(response.status ,response.reason)
    contentType = response.getheader('Content-Type')
    print(contentType)
    body = response.read()
    if response.status == 200:
        jsonData = json.loads(body)
        print('The request succeed : ', jsonData)
        print('error_code = ', jsonData['error_code'])
        task_id = jsonData['data']['task_id']
        request_id = jsonData['request_id']
        print('task_id = ', task_id)
        print('request_id = ', request_id)
        # 说明:轮询检查服务端的合成状态,轮询操作非必须。如果设置了回调url,则服务端会在合成完成后主动回调。
        waitLoop4Complete(url, appkey, token, task_id, request_id)
    else:
        print('The request failed: ' + str(body))

appKey = 'yourAppkey'
token = 'yourToken'

text = '今天是周一,天气挺好的。'

# 拼接HTTP Post请求的消息体内容。
th = TtsHeader(appKey, token)
tc = TtsContext("mydevice")
# TtsRequest对象内容为:发音人、采样率、语音格式、待合成文本内容。
tr = TtsRequest("xiaoyun", 16000, "wav", False, text)
# 是否设置回调url,回调url地址,TtsRequest对象。
tp = TtsPayload(True, "http://134.com", tr)
tb = TtsBody(th, tc, tp)
body = json.dumps(tb, default=tb.tojson)
requestLongTts4Post(str(body), appKey, token)

PHP示例

说明

PHP示例中使用了cURL函数,要求PHP的版本为4.0.2以上,并且确保已安装cURL扩展。

<?php
// 根据特定信息轮询检查某个请求在服务端的合成状态,每隔10秒钟轮询一次状态.轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
function waitLoop4Complete($url, $appkey, $token, $task_id, $request_id) {
    $fullUrl = $url . "?appkey=" . $appkey . "&task_id=" . $task_id . "&token=" . $token . "&request_id=" . $request_id;
    print "query url = " . $fullUrl . "\n";
    while(true) {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($curl, CURLOPT_URL, $fullUrl);
        curl_setopt($curl, CURLOPT_HEADER, TRUE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        $response = curl_exec($curl);
        if ($response == FALSE) {
            print "curl_exec failed!\n";
            curl_close($curl);
            return ;
        }
        // 处理服务端返回的响应。
        $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
        $headers = substr($response, 0, $headerSize);
        $bodyContent = substr($response, $headerSize);
        print $bodyContent."\n";
        $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        if($http_code != 200) {     // 如果请求失败,需要检查调用是否正确。
            print "tts request failure, error code = " . $http_code . "\n";
            curl_close($curl);
            return ;
        }
        curl_close($curl);
        $data = json_decode($bodyContent, true);

        //$data["data"]["audio_address"]== null时表示还在合成未完成的状态,需要等待。。。
        if(isset($data["error_code"]) && $data["error_code"] == 20000000
            && isset($data["data"]) && $data["data"]["audio_address"]== null){

            print "Tts Queuing...please wait..." . "\n";
            
        }
        else if(isset($data["error_code"]) && $data["error_code"] == 20000000
            && isset($data["data"]) && $data["data"]["audio_address"] != "")  {
            print "Tts Finished! task_id = " . $data["data"]["task_id"] . "\n";
            print "Tts Finished! audio_address = " . $data["data"]["audio_address"] . "\n";
            break;
        }

        // 每隔10秒钟轮询一次状态。
        sleep(10);
    }
}
// 长文本语音合成restful接口,支持post调用,不支持get请求。发出请求后,可以轮询状态或者等待服务端合成后自动回调(如果设置了回调参数)。
function requestLongTts4Post($appkey, $token, $text, $voice, $format, $sampleRate) {

    $url = "https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async";

    // 拼接HTTP Post请求的消息体内容。
    $header = array("appkey" => $appkey, "token" => $token);
    $context = array("device_id" => "my_device_id");
    $tts_request = array("text" => $text, "format" => $format, "voice" => $voice, "sample_rate" => $sampleRate, "enable_subtitle" => false);
    $payload = array("enable_notify" => true, "notify_url" => "http://123.com", "tts_request" => $tts_request);
    $tts_body = array("context" => $context, "header" => $header, "payload" => $payload);
    $body = json_encode($tts_body);
    print "The POST request body content: " . $body . "\n";
    $httpHeaders = array("Content-Type: application/json");
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, TRUE);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $httpHeaders);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
    curl_setopt($curl, CURLOPT_HEADER, TRUE);
    $response = curl_exec($curl);
    if ($response == FALSE) {
        print "curl_exec failed!\n";
        curl_close($curl);
        return ;
    }
    $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
    $headers = substr($response, 0, $headerSize);
    $bodyContent = substr($response, $headerSize);
    $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if($http_code != 200) {
        print "tts request failure, error code = " . $http_code . "\n";
        print "tts request failure, response = " . $bodyContent . "\n";
        return ;
    }
    curl_close($curl);
    print $bodyContent . "\n";
    $data = json_decode($bodyContent, true);
    if( isset($data["error_code"]) && $data["error_code"] == 20000000) {
        $task_id = $data["data"]["task_id"];
        $request_id = $data["request_id"];
        print "Request Success! task_id = " . $task_id . "\n";
        print "Request Success! request_id = " . $request_id . "\n";
        ///说明:轮询检查服务端的合成状态,轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
        waitLoop4Complete($url, $appkey, $token, $task_id, $request_id);
    } else {
        print "Request Error: status=" . $data["status"] . "; error_code=" . $data["error_code"] . "; error_message=" . $data["error_message"] . "\n";
    }
}

$appkey = "yourAppkey";
$token = "yourToken";

$text = "今天是周一,天气挺好的。";
$format = "wav";
$voice = "xiaogang";
$sampleRate = 16000;
requestLongTts4Post($appkey, $token, $text, $voice, $format, $sampleRate);

?>

Node.js示例

首先安装request依赖,请在您的示例文件所在目录执行如下命令:

npm install request --save

示例代码如下:

const request = require('request');
const fs = require('fs');
    // 长文本语音合成restful接口,支持post调用,不支持get请求。发出请求后,可以轮询状态或者等待服务端合成后自动回调(如果设置了回调参数)。
    function requestLongTts4Post(textValue, appkeyValue, tokenValue, voiceValue, formatValue, sampleRateValue) {
        
        var url = "https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async"
        console.log(url);
        // 请求参数,以JSON格式字符串填入HTTPS POST请求的Body中。
        var context = {
            device_id : "device_id",
        };
        var header = {
            appkey : appkeyValue,
            token : tokenValue,
        };
        var tts_request = {
            text : textValue,
            voice : voiceValue,
            format : formatValue,
            "sample_rate" : sampleRateValue,
            "enable_subtitle" : false
        };
        var payload = {
            "enable_notify" : false,
            "notify_url": "http://123.com",
            "tts_request" : tts_request,
        };
        var tts_body = {
            "context" : context,
            "header" : header,
            "payload" : payload
        };
        var bodyContent = JSON.stringify(tts_body);
        console.log('The POST request body content: ' + bodyContent);
        // 设置HTTPS POST请求头部。
        var httpHeaders = {'Content-type' : 'application/json'};
        // 设置HTTPS POST请求。
        // encoding必须设置为null,HTTPS响应的Body为二进制Buffer类型。
        var options = {
            url: url,
            method: 'POST',
            headers: httpHeaders,
            body: bodyContent,
            encoding: null
        };
        request(options, function (error, response, body) {
            // 处理服务端的响应。
            if (error != null) {
                console.log(error);
            } else {
                if(response.statusCode != 200) {
                    console.log("Http Request Fail: " + response.statusCode + "; " + body.toString());
                    return;
                }
                console.log("response result: " + body.toString());
                var code = 0;
                var task_id = "";
                var request_id = "";
                var json = JSON.parse(body.toString());
                console.info(json);
                for(var key in json){  
                    if(key=='error_code'){
                        code = json[key]
                    } else if(key=='request_id'){
                        request_id = json[key]
                    } else if(key == "data") {
                        task_id = json[key]["task_id"];
                    }
                }
                if(code == 20000000) {
                    console.info("Request Success! task_id = " + task_id);
                    console.info("Request Success! request_id = " + request_id);
                    /// 说明:轮询检查服务端的合成状态,轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
                    waitLoop4Complete(url, appkey, token, task_id, request_id);
                } else {
                    console.info("Request Error: status=" + $data["status"] + "; error_code=" + $data["error_code"] + "; error_message=" + $data["error_message"]);
                }
            }
        });
        
    }
    // 根据特定信息轮询检查某个请求在服务端的合成状态,每隔10秒钟轮询一次状态.轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
    function waitLoop4Complete(urlValue, appkeyValue, tokenValue, task_id_value, request_id_value) {
        var fullUrl = urlValue + "?appkey=" + appkeyValue + "&task_id=" + task_id_value + "&token=" + tokenValue + "&request_id=" + request_id_value;
        console.info("query url = " + fullUrl);
        //while(true) {
        var timer = setInterval(() => {
            var options = {
                url: fullUrl,
                method: 'GET'
            };
            console.info("query url = " + fullUrl);
            request(options, function (error, response, body) {
                // 处理服务端的响应。
                if (error != null) {
                    console.log(error);
                } else if(response.statusCode != 200) {
                    console.log("Http Request Fail: " + response.statusCode + "; " + body.toString());
                    return;
                } else {
                    console.log("query result: " + body.toString());
                    var code = 0;
                    var task_id = "";
                    var output_url = "";
                    var json = JSON.parse(body.toString());
                    console.info(json);
                    for(var key in json){  
                        if(key=='error_code'){
                            code = json[key]
                        } else if(key=='request_id'){
                            request_id = json[key]
                        } else if(key == "data" && json["data"] != null) {
                            task_id = json[key]["task_id"];
                            audio_address = json[key]["audio_address"];
                        }
                    }
                    if(code == 20000000 && audio_address == null) {

                        console.info("Tts Queuing...please wait...");
                    }
                    else if(code == 20000000 && audio_address != "") {
                        console.info("Tts Finished! task_id = " + task_id);
                        console.info("Tts Finished! audio_address = " + audio_address);
                        // 退出轮询。
                        clearInterval(timer);
                    } 
                }
            }
            );
        }
    , 10000);
    }

var appkey = 'yourAppkey';
var token = 'yourToken';

var text = '今天是周一,天气挺好的。';
var voice = "xiaogang";
var format = 'wav';
var sampleRate = 16000;
requestLongTts4Post(text, appkey, token, voice, format, sampleRate);

GO示例

package main

import (
 "bytes"
 "encoding/json"
 "fmt"
 "io/ioutil"
 "net/http"
 "strconv"
 "time"
)

// 长文本语音合成restful接口,支持post调用,不支持get请求。发出请求后,可以轮询状态或者等待服务端合成后自动回调(如果设置了回调参数)。
func requestLongTts4Post(text string, appkey string, token string) {

 var url string = "https://nls-gateway.cn-shanghai.aliyuncs.com/rest/v1/tts/async"

 // 拼接HTTP Post请求的消息体内容。
 context := make(map[string]interface{})
 context["device_id"] = "test-device"
 header := make(map[string]interface{})
 header["appkey"] = appkey
 header["token"] = token
 tts_request := make(map[string]interface{})
 tts_request["text"] = text
 tts_request["format"] = "wav"
 tts_request["voice"] = "xiaogang"
 tts_request["sample_rate"] = 16000
 tts_request["enable_subtitle"] = false
 payload := make(map[string]interface{})
 payload["enable_notify"] = false
 payload["notify_url"] = "http://123.com"
 payload["tts_request"] = tts_request
 ttsBody := make(map[string]interface{})
 ttsBody["context"] = context
 ttsBody["header"] = header
 ttsBody["payload"] = payload
 ttsBodyJson, err := json.Marshal(ttsBody)
 if err != nil {
  panic(nil)
 }
 fmt.Println(string(ttsBodyJson))
 // 发送HTTPS POST请求,处理服务端的响应。
 response, err := http.Post(url, "application/json;charset=utf-8", bytes.NewBuffer([]byte(ttsBodyJson)))
 if err != nil {
  panic(err)
 }
 defer response.Body.Close()
 contentType := response.Header.Get("Content-Type")
 body, _ := ioutil.ReadAll(response.Body)
 fmt.Println(string(contentType))
 fmt.Println(string(body))
 statusCode := response.StatusCode
 if statusCode == 200 {
  fmt.Println("The POST request succeed!")
  var f interface{}
  err := json.Unmarshal(body, &f)
  if err != nil {
   fmt.Println(err)
  }
  // 从消息体中解析出来task_id(重要)和request_id。
  var taskId string = ""
  var requestId string = ""
  m := f.(map[string]interface{})
  for k, v := range m {
   if k == "error_code" {
    fmt.Println("error_code = ", v)
   } else if k == "request_id" {
    fmt.Println("request_id = ", v)
    requestId = v.(string)

   } else if k == "data" {
    fmt.Println("data = ", v)
    data := v.(map[string]interface{})
    fmt.Println(data)
    taskId = data["task_id"].(string)

   }
  }

  // 说明:轮询检查服务端的合成状态,轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
  waitLoop4Complete(url, appkey, token, taskId, requestId)

 } else {
  fmt.Println("The POST request failed: " + string(body))
  fmt.Println("The HTTP statusCode: " + strconv.Itoa(statusCode))
 }

}

// 根据特定信息轮询检查某个请求在服务端的合成状态,每隔10秒钟轮询一次状态.轮询操作非必须,如果设置了回调url,则服务端会在合成完成后主动回调。
func waitLoop4Complete(url string, appkey string, token string, task_id string, request_id string) {
 var fullUrl string = url + "?appkey=" + appkey + "&task_id=" + task_id + "&token=" + token + "&request_id=" + request_id
 fmt.Println("fullUrl=" + fullUrl)
 for {
  response, err := http.Get(fullUrl)
  if err != nil {
   fmt.Println("The GET request failed!")
   panic(err)
  }
  defer response.Body.Close()
  body, _ := ioutil.ReadAll(response.Body)
  fmt.Println("waitLoop4Complete = ", string(body))
  var f interface{}
  json.Unmarshal(body, &f)
  if err != nil {
   fmt.Println(err)
  }
  // 从消息体中解析出来task_id(重要)和request_id。
  var code float64 = 0
  var taskId string = ""
  var audioAddress string = ""
  m := f.(map[string]interface{})
  for k, v := range m {
   if k == "error_code" {
    code = v.(float64)
   } else if k == "request_id" {
   } else if k == "data" {
    if v != nil {
     data := v.(map[string]interface{})
     taskId = data["task_id"].(string)
     if data["audio_address"] == nil {
      fmt.Println("Tts Queuing...,please wait...")

     } else {
      audioAddress = data["audio_address"].(string)
     }
    }
   }
  }
  if code == 20000000 && audioAddress != "" {
   fmt.Println("Tts Finished! task_id = " + taskId)
   fmt.Println("Tts Finished! audio_address = " + audioAddress)
   break
  } else {
   // 每隔10秒钟轮询一次状态
   time.Sleep(time.Duration(10) * time.Second)
  }
 }
}
func main() {
 var appkey string = "yourAppkey"
 var token string = "yourToken"
 var text string = "今天是周一,天气挺好的。"
 requestLongTts4Post(text, appkey, token)

}
阿里云首页 智能语音交互 相关技术圈