You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 line
4.2KB

  1. # coding=utf-8
  2. """
  3. Author: chazzjimel
  4. Email: chazzjimel@gmail.com
  5. wechat:cheung-z-x
  6. Description:
  7. """
  8. import json
  9. import time
  10. import requests
  11. import datetime
  12. import hashlib
  13. import hmac
  14. import base64
  15. import urllib.parse
  16. import uuid
  17. from common.log import logger
  18. from common.tmp_dir import TmpDir
  19. def text_to_speech_aliyun(url, text, appkey, token):
  20. """
  21. 使用阿里云的文本转语音服务将文本转换为语音。
  22. 参数:
  23. - url (str): 阿里云文本转语音服务的端点URL。
  24. - text (str): 要转换为语音的文本。
  25. - appkey (str): 您的阿里云appkey。
  26. - token (str): 阿里云API的认证令牌。
  27. 返回值:
  28. - str: 成功时输出音频文件的路径,否则为None。
  29. """
  30. headers = {
  31. "Content-Type": "application/json",
  32. }
  33. data = {
  34. "text": text,
  35. "appkey": appkey,
  36. "token": token,
  37. "format": "wav"
  38. }
  39. response = requests.post(url, headers=headers, data=json.dumps(data))
  40. if response.status_code == 200 and response.headers['Content-Type'] == 'audio/mpeg':
  41. output_file = TmpDir().path() + "reply-" + str(int(time.time())) + "-" + str(hash(text) & 0x7FFFFFFF) + ".wav"
  42. with open(output_file, 'wb') as file:
  43. file.write(response.content)
  44. logger.debug(f"音频文件保存成功,文件名:{output_file}")
  45. else:
  46. logger.debug("响应状态码: {}".format(response.status_code))
  47. logger.debug("响应内容: {}".format(response.text))
  48. output_file = None
  49. return output_file
  50. class AliyunTokenGenerator:
  51. """
  52. 用于生成阿里云服务认证令牌的类。
  53. 属性:
  54. - access_key_id (str): 您的阿里云访问密钥ID。
  55. - access_key_secret (str): 您的阿里云访问密钥秘密。
  56. """
  57. def __init__(self, access_key_id, access_key_secret):
  58. self.access_key_id = access_key_id
  59. self.access_key_secret = access_key_secret
  60. def sign_request(self, parameters):
  61. """
  62. 为阿里云服务签名请求。
  63. 参数:
  64. - parameters (dict): 请求的参数字典。
  65. 返回值:
  66. - str: 请求的签名签章。
  67. """
  68. # 将参数按照字典顺序排序
  69. sorted_params = sorted(parameters.items())
  70. # 构造待签名的查询字符串
  71. canonicalized_query_string = ''
  72. for (k, v) in sorted_params:
  73. canonicalized_query_string += '&' + self.percent_encode(k) + '=' + self.percent_encode(v)
  74. # 构造用于签名的字符串
  75. string_to_sign = 'GET&%2F&' + self.percent_encode(canonicalized_query_string[1:]) # 使用GET方法
  76. # 使用HMAC算法计算签名
  77. h = hmac.new((self.access_key_secret + "&").encode('utf-8'), string_to_sign.encode('utf-8'), hashlib.sha1)
  78. signature = base64.encodebytes(h.digest()).strip()
  79. return signature
  80. def percent_encode(self, encode_str):
  81. """
  82. 对字符串进行百分比编码。
  83. 参数:
  84. - encode_str (str): 要编码的字符串。
  85. 返回值:
  86. - str: 编码后的字符串。
  87. """
  88. encode_str = str(encode_str)
  89. res = urllib.parse.quote(encode_str, '')
  90. res = res.replace('+', '%20')
  91. res = res.replace('*', '%2A')
  92. res = res.replace('%7E', '~')
  93. return res
  94. def get_token(self):
  95. """
  96. 获取阿里云服务的令牌。
  97. 返回值:
  98. - str: 获取到的令牌。
  99. """
  100. # 设置请求参数
  101. params = {
  102. 'Format': 'JSON',
  103. 'Version': '2019-02-28',
  104. 'AccessKeyId': self.access_key_id,
  105. 'SignatureMethod': 'HMAC-SHA1',
  106. 'Timestamp': datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
  107. 'SignatureVersion': '1.0',
  108. 'SignatureNonce': str(uuid.uuid4()), # 使用uuid生成唯一的随机数
  109. 'Action': 'CreateToken',
  110. 'RegionId': 'cn-shanghai'
  111. }
  112. # 计算签名
  113. signature = self.sign_request(params)
  114. params['Signature'] = signature
  115. # 构造请求URL
  116. url = 'http://nls-meta.cn-shanghai.aliyuncs.com/?' + urllib.parse.urlencode(params)
  117. # 发送请求
  118. response = requests.get(url)
  119. return response.text