智能云上手指南:语音合成 API 快速接入

6月21日,腾讯云在2017「云+未来」峰会上推出了战略新品——智能云,宣布将腾讯积累近20年的AI能力向政府、企业和开发者开放,其中首批开放计算机视觉、智能语音识别、自然语言处理的三大核心能力。腾讯云技术社区将陆续推出系列文章,介绍普通开发者如何快速接入并使用这三大 AI 能力。

本文将为大家讲解如何上手智能云提供的智能语音识别服务

功能简介

语音合成服务提供文本转语音服务,支持多种音色选择、语速选择。

目前提供Restful API方式,用户可以通过API上传需要合成的中文文本,系统会立即进行合成,云端合成成功后,返回合成结果语音。

语音合成实现了机器向人的语音交互,适用场景包括:广播播报,有声小说,智能车载等等,让应用开口说话,便捷人机交互。

Restful API

语音合成的 RESTful API 请求结构如下:

参数名称

必选

类型

描述

Version

String

HTTPS 协议版本

URL

String

HTTPS 请求地址

Https Headers

数据集合

HTTPS 请求头部

Https Method

String

HTTPS 请求方法,请求方法为 POST

Https Body

String

HTTPS 请求正文

其中,URL 的结构为 :

https://aai.qcloud.com/tts/v1/<appid>?
projectid=xxx&
sub_service_type=xxx&
speech_format=xxx&
volume=xxx&
person=xxx&
speed=xxx&
secretid=<secretid>&
timestamp=xxx&
expired=xxx&
nonce=xxx

URL 中各字段含义如下(各字段的值需要进行 URL 编码):

字段

必选

类型

描述

appid

uint

腾讯云应用 ID 值

projectid

uint

腾讯云项目 ID,不填为默认项目,即0,总长度不超过1024字节

sub_service_type

uint

子服务类型。0:短文本实时合成。目前只支持短文本实时合成

speech_format

String

合成语音格式,目前支持MP3格式

volume

uint

音量,默认为5,取值范围为0-10

person

uint

发音人,目前仅支持0,女声

speed

uint

语速,默认值为0,取值范围为-40到40,1表示加速到原来的1.1倍,-1为相对于正常语速放慢1.1倍

secretid

String

官网云API密钥中获得的SecretId

timestamp

uint

当前时间戳,是一个符合 UNIX Epoch 时间戳规范的数值,单位为秒

expired

uint

timestamp 且 expired - timestamp 小于90天

nonce

uint

随机正整数。用户需自行生成,最长10位

HTTPS Headers 的结构如下:

参数名称

必选

类型

描述

Host

String

语音识别服务域名,固定为 aai.qcloud.com

Authorization

String

用户的有效签名,用于鉴权。对应签名鉴权中得到的签名字符串

Content-Type

String

multipart/form-data

Content-Length

Int

请求长度,此处为https body总的字节数。文本数据,utf-8编码,长度限制为1024字节以内

请求示例

下列示例中,<箭头括号>表示必须替换为有效值的变量。请求 Host 与路径:

https://aai.qcloud.com/tts/v1/<appid>?

请求参数:

{
"projectid":"0",
"sub_service_type":"0",
"speech_format":"mp3",
"volume":"3",
"person":"0",
"speed":"0",
"secretid":"AKIDlfdHxN0ntSVt4KPH0xXWnGl21UUFNoO5",
"timestamp":"1484109983",
"expired":"1484113583",
"nonce":"1675199141"
}

这里以< appid > = 20170111, < SecretKey >=oaYWFO70LGDmcpfwo8uF1IInayysGtgZ 为例拼接签名原文,则拼接的签名原文为:

POSTaai.qcloud.com/tts/v1/20170111?expired=1484113583&nonce=1675199141&person=0&projectid=0&secretid=AKIDlfdHxN0ntSVt4KPH0xXWnGl21UUFNoO5&speech_format=mp3&speed=0&sub_service_type=0&timestamp=1484109983&volume=3

对原文进行加密处理:

Base64Encode(HmacSha1(签名原文, SecretKey))

最终得到签名串为:

HRCKlbwPhWtVvfGn914qE5O1rwc= 请求 headers 为:

{
"Content-Type":"multipart/form-data",
"Authorization":"HRCKlbwPhWtVvfGn914qE5O1rwc="
}

返回结构

RESTful API 返回结果

语音全文转写识别的 RESTful API 请求返回结果如下表所示:

参数名称

类型

说明

code

int

服务器错误码,0为成功

message

String

服务器返回的信息

speech

String

经过Base64编码的合成语音数据

返回示例

返回消息示例如下:

 {
 "code":0, 
 "message":"success",
 "speech": "xxxxxxx"
 }

返回码 0 表示成功。

Python代码示例

#!/usr/bin/python
# coding: UTF-8

import requests
import time
import random
import hmac, hashlib, base64
import json

appid = 0
secret_id = 'your_secret_id'
secret_key = 'your_secret_key'

args = {
        'secretid': secret_id,
        'projectid': 0,
        'sub_service_type': 0,
        'speech_format': 'mp3',
        'volume': 2,
        'person': 0,
        'speed': 0,
        'timestamp': int(time.time()),
        'expired': int(time.time()) + 60 * 60,
        'nonce': random.randint(1048576, 104857600),
}

query_str = "&".join(["%s=%s"%(k,args[k]) for k in sorted(args.keys())])
calc_str = "POSTaai.qcloud.com/tts/v1/%(appid)s?%(query_str)s"%vars()
hashed = hmac.new(secret_key, calc_str, hashlib.sha1)
headers = {"Authorization": base64.b64encode(hashed.digest())}

url = "http://aai.qcloud.com/tts/v1/%(appid)s?%(query_str)s"%vars()
upload_file = "hello.txt"
files = {"file": open(upload_file, "rb")}
resp = requests.post(url=url, files=files, headers=headers)
resp = json.loads(resp.text)
data = base64.b64decode(resp["speech"])

f = open("hello.mp3", "w")
f.write(data)
f.close()

PHP代码示例

<?php
ini_set("display_errors", "1");
error_reporting(E_ALL);
$serverIp = "aai.qcloud.com";
$serverPort = 80;

$appid = YOUR_APPID;
// 获取secretId 和 secretKey -> https://console.qcloud.com/capi
$secret_id = 'YOUR_SECRET_ID';
$secret_key = 'YOUR_SECRET_KEY';

$query_arr = array(
    'secretid' => $secret_id,
    'projectid' => 0,
    'sub_service_type' => 0,
    'speech_format' => 'mp3',
    'volume' => 2,
    'person' => 0,
    'speed' => 0,
    'timestamp' => time(),
    'expired' => time() + 60 * 60,
    'nonce' => rand(),
);

ksort($query_arr);
$query_str = "";
foreach($query_arr as $key => $val) {
    $query_str .= "$key=$val&";
}
$query_str = trim($query_str, "&");

// 计算签名
$sign_str = "POSTaai.qcloud.com/tts/v1/$appid?$query_str";
$signature = base64_encode(hash_hmac('SHA1', $sign_str, $secret_key, TRUE));

// 请求消息体,multipart/form-data格式
$form_boundary = "----WebKitFormBoundarybS1Fvrpes3yfBSvu";
$body_str = "--$form_boundary\r\n";
$body_str .= "Content-Disposition: form-data; name=".'"'."test1".'"'."; filename=".'"'."test_upload.txt".'"'."\r\n";
$body_str .= "Content-Type: application/octet-stream\r\n";
$body_str .= "\r\n";
$body_str .= "你好啊吃饭了没\r\n";
$body_str .= "--$form_boundary\r\n";
$body_str .= "Content-Disposition: form-data; name=".'"'."test2".'"'."; filename=".'"'."debug.log".'"'."\r\n";
$body_str .= "Content-Type: application/octet-stream\r\n";
$body_str .= "\r\n";
$body_str .= "最近雾霾很严重最好留在室内\r\n";
$body_str .= "--$form_boundary\r\n";
$body_str .= 'Content-Disposition: form-data; name="submit"'."\r\n";
$body_str .= "\r\n";
$body_str .= "Submit\r\n";
$body_str .= "--$form_boundary--\r\n";

$req = "POST /tts/v1/$appid?$query_str HTTP/1.1 \r\n";
$req .= "Host: aai.qcloud.com\r\n";
$req .= "Authorization: $signature\r\n";
$req .= "Content-Type: multipart/form-data; boundary=$form_boundary\r\n";
$req .= "Content-Length: ";
$req .= strlen($body_str);
$req .= "\r\n\r\n";
$req .= $body_str;
echo "=================== req start ===================\n";
echo "$req\n";
echo "=================== req end ===================\n";
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if($socket < 0){
    echo "socket_create failed : ".socket_strerror($socket)."\n";
    return ;
}
$res = socket_connect($socket, $serverIp,$serverPort);
if($res < 0){
    echo "socket_connect failed : ".socket_strerror($res)."\n";
    return ;
}
$res = socket_write($socket,$req,strlen($req));
if(!$res){
    echo "socket_write failed : ".socket_strerror($socket)."\n";
    return ;
}
$rsp = "";
while($tmprsp = socket_read($socket,8192)){
    $rsp .= $tmprsp;
}
echo "=================== resp ===================\n";
echo "rsp :\n".$rsp."\n";
socket_close($socket);

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏安恒信息

邮箱安全服务专题第5期 | 邮箱APT检测分析关键技术

上一期我们介绍了钓鱼邮件的常规检测方法,其实,无论采用怎么样的方式,人的安全意识永远都是第一位,纵使钓鱼邮件写得多么诱人深入人心,只要我们守住底线,点击之前先思...

2856
来自专栏FreeBuf

科普哈希长度扩展攻击(Hash Length Extension Attacks)

貌似大多数渗透师都很少测试密码学方面的漏洞。我一直都对密码学颇有兴趣,于是决定研究web应用开发者误用加密算法的情况,以及如何利用这些漏洞。 一月份的时候,我研...

2196
来自专栏菜鸟程序员

WikiLeaks公开资料解读系列之CIA Hive项目

1103
来自专栏SAP最佳业务实践

SAP最佳业务实践:SD–退货和投诉(111)-2业务处理

一、VA01创建退货订单 在此活动中,创建退货订单。 必须有根据 销售订单处理:自库存销售 (109) 的参考发票编号和开票凭证。 角色销售助理 后勤 ® 销...

3304
来自专栏怀英的自我修炼

怀英漫谈6-shiro-02

你好,这次我想接着上上次的Shiro的话题,聊聊Shiro怎么用。 上次我们说过Shiro有一个外部视角,也有一个内部视角。而外部视角就是通过应用(Applic...

3948
来自专栏吉浦迅科技

CUDA菜鸟必看:论坛里那些总是被问到的问题.....

高 校校园,太平洋吹来暖湿的季风,学霸和学妹正在疯长,又到了大学生们最忙碌的季节——写论文。在导师眼中,GPU能为学生发毕业论文带来好运,值得为它冒险。现代社会...

2867
来自专栏尹磊的专栏

巧用 Nginx 的 geo 模块来记录地理信息

Nginx 提供了 GeoIP 来记录来源 IP 的地理位置信息,但 GeoIP 所依赖的 IP 库是收费项目,免费的模块只能区分国家信息,不大适合在线上使用。

4640
来自专栏FreeBuf

快速读懂无线安全

* 本文原创作者:icecolor不疯不魔不成活,本文属FreeBuf原创奖励计划,未经许可禁止转载 About channel: ? 1.每个协议都有不同的工...

20910
来自专栏SAP最佳业务实践

SAP最佳业务实践:FI–应收帐款(157)-3 F-37预付款

4.3 F-37过帐预付款请求 预付款请求是一些不会影响余额表的备注项。在帐户分析、催款程序和付款程序中可将它们考虑在内。 使用备用统驭帐户19990501的特...

3594
来自专栏北京马哥教育

怎么制定一套合适的服务器命名方案

在MNX上,我们一直致力于为我们的云托管服务建立一个全新的数据中心。起初我们是一家提供管理Linux服务的咨询公司,这也就意味着我们将置身于大量的不同用户环境,...

3174

扫码关注云+社区