Skip to content

Instantly share code, notes, and snippets.

@hzbd
Last active November 3, 2021 01:20
Show Gist options
  • Save hzbd/72f0a77402f1fa57ef6cf970a7ceb946 to your computer and use it in GitHub Desktop.
Save hzbd/72f0a77402f1fa57ef6cf970a7ceb946 to your computer and use it in GitHub Desktop.
aliyun speech synthesis service demo. 阿里云语音合成服务演示
# -*- coding:utf-8 -*-
#
# Copyright (c) 2021 623 MIT
#
from urllib import parse
import logging
import os
import time
import uuid
import requests
import base64
import hashlib
import hmac
import requests
import time
import uuid
logger = logging.getLogger(__name__)
ACCESS_KEY_ID =""
ACCESS_SECRET =""
class AliyunSig(object):
"""
REF doc:
https://help.aliyun.com/document_detail/94737.html
https://help.aliyun.com/document_detail/113251.html#h2-u7B7Eu540Du673Au52362
Tips:
* synthesizing within 300 characters at a time for free.
"""
def __init__(self,
access_key=os.environ.get('ACCESS_KEY_ID', ACCESS_KEY_ID),
access_secret=os.environ.get('ACCESS_SECRET', ACCESS_SECRET)):
self.requests = requests.Session()
self.access_key = access_key
self.access_secret = access_secret
@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', '~')
def gen_token(self):
parameters = {
'AccessKeyId': self.access_key,
'Action': 'CreateToken',
'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-02-28'
}
query_string = AliyunSig._encode_dict(parameters)
string_to_sign = 'GET' + '&' + \
AliyunSig._encode_text('/') + '&' + AliyunSig._encode_text(query_string)
secreted_string = hmac.new(bytes(self.access_secret + '&', encoding='utf-8'),
bytes(string_to_sign, encoding='utf-8'), hashlib.sha1).digest()
signature = base64.b64encode(secreted_string)
signature = AliyunSig._encode_text(signature)
full_url = 'https://nls-meta.cn-shanghai.aliyuncs.com/?Signature=%s&%s' % (
signature, query_string)
response = self.requests.get(full_url)
if response.ok:
root_obj = response.json()
key = 'Token'
if key in root_obj:
token = root_obj[key]['Id']
expire_time = root_obj[key]['ExpireTime']
return token, expire_time
logger.info(response.text)
return None, None
def gen_speech(self, appkey, text_words, sample_rate=16000,
voice="xiaoyun", volume=86, speech_rate=-357, format="wav"):
"""
Parameter list:
name type optional description
appkey String y 项目appkey。
text String y 待合成的文本,需要为UTF-8编码。使用GET方法,需要再采用RFC 3986规范进行urlencode编码;使用POST方法不需要urlencode编码。
token String n 若不设置token参数,需要在HTTP Headers中设置X-NLS-Token字段来指定Token。
format String n 音频编码格式,支持pcm/wav/mp3格式。默认值:pcm。
sample_rate Integer n 音频采样率,支持16000Hz/8000Hz,默认值:16000Hz。
voice String n 发音人,默认值:xiaoyun。更多发音人请参见接口说明。
volume Integer n 音量,取值范围:0~100,默认值:50。
speech_rate Integer n 语速,取值范围:-500~500,默认值:0。
pitch_rate Integer n 语调,取值范围:-500~500,默认值:0。
"""
token, _ = self.gen_token()
headers = {'Content-type': 'application/json'}
payload = {
"appkey": appkey,
"text": text_words,
"sample_rate": sample_rate,
"voice": voice,
"volume": volume,
"speech_rate": speech_rate,
"token": token,
"format": format
}
# print(payload)
url = "https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/tts"
response = self.requests.post(url, json=payload, headers=headers)
return response
if __name__ == '__main__':
# token, expire_time = AliyunSig().gen_token()
# logger.info('token: %s, expire time(s): %s' % (token, expire_time))
app_key = "<APPKEY-HERE>"
text_words = "你好啊,世界"
resp = AliyunSig().gen_speech(app_key, text_words)
audio_file = "/tmp/demo.wav"
if "audio/mpeg" == resp.headers['Content-Type']:
with open(audio_file, 'wb') as f:
f.write(resp.content)
else:
print(resp.content)
logger.warn("error message: {}".format(resp.content))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment