您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # coding=utf-8
  2. """
  3. Author: chazzjimel
  4. Email: chazzjimel@gmail.com
  5. wechat:cheung-z-x
  6. Description:
  7. """
  8. import http.client
  9. import json
  10. import time
  11. import requests
  12. import datetime
  13. import hashlib
  14. import hmac
  15. import base64
  16. import urllib.parse
  17. import uuid
  18. from common.log import logger
  19. from common.tmp_dir import TmpDir
  20. def text_to_speech_aliyun(url, text, appkey, token):
  21. """
  22. 使用阿里云的文本转语音服务将文本转换为语音。
  23. 参数:
  24. - url (str): 阿里云文本转语音服务的端点URL。
  25. - text (str): 要转换为语音的文本。
  26. - appkey (str): 您的阿里云appkey。
  27. - token (str): 阿里云API的认证令牌。
  28. 返回值:
  29. - str: 成功时输出音频文件的路径,否则为None。
  30. """
  31. headers = {
  32. "Content-Type": "application/json",
  33. }
  34. data = {
  35. "text": text,
  36. "appkey": appkey,
  37. "token": token,
  38. "format": "wav"
  39. }
  40. response = requests.post(url, headers=headers, data=json.dumps(data))
  41. if response.status_code == 200 and response.headers['Content-Type'] == 'audio/mpeg':
  42. output_file = TmpDir().path() + "reply-" + str(int(time.time())) + "-" + str(hash(text) & 0x7FFFFFFF) + ".wav"
  43. with open(output_file, 'wb') as file:
  44. file.write(response.content)
  45. logger.debug(f"音频文件保存成功,文件名:{output_file}")
  46. else:
  47. logger.debug("响应状态码: {}".format(response.status_code))
  48. logger.debug("响应内容: {}".format(response.text))
  49. output_file = None
  50. return output_file
  51. def speech_to_text_aliyun(url, audioContent, appkey, token):
  52. """
  53. 使用阿里云的语音识别服务识别音频文件中的语音。
  54. 参数:
  55. - url (str): 阿里云语音识别服务的端点URL。
  56. - audioContent (byte): pcm音频数据。
  57. - appkey (str): 您的阿里云appkey。
  58. - token (str): 阿里云API的认证令牌。
  59. 返回值:
  60. - str: 成功时输出识别到的文本,否则为None。
  61. """
  62. format = 'pcm'
  63. sample_rate = 16000
  64. enablePunctuationPrediction = True
  65. enableInverseTextNormalization = True
  66. enableVoiceDetection = False
  67. # 设置RESTful请求参数
  68. request = url + '?appkey=' + appkey
  69. request = request + '&format=' + format
  70. request = request + '&sample_rate=' + str(sample_rate)
  71. if enablePunctuationPrediction :
  72. request = request + '&enable_punctuation_prediction=' + 'true'
  73. if enableInverseTextNormalization :
  74. request = request + '&enable_inverse_text_normalization=' + 'true'
  75. if enableVoiceDetection :
  76. request = request + '&enable_voice_detection=' + 'true'
  77. host = 'nls-gateway-cn-shanghai.aliyuncs.com'
  78. # 设置HTTPS请求头部
  79. httpHeaders = {
  80. 'X-NLS-Token': token,
  81. 'Content-type': 'application/octet-stream',
  82. 'Content-Length': len(audioContent)
  83. }
  84. conn = http.client.HTTPSConnection(host)
  85. conn.request(method='POST', url=request, body=audioContent, headers=httpHeaders)
  86. response = conn.getresponse()
  87. body = response.read()
  88. try:
  89. body = json.loads(body)
  90. status = body['status']
  91. if status == 20000000 :
  92. result = body['result']
  93. if result :
  94. logger.info(f"阿里云语音识别到了:{result}")
  95. conn.close()
  96. return result
  97. else :
  98. logger.error(f"语音识别失败,状态码: {status}")
  99. except ValueError:
  100. logger.error(f"语音识别失败,收到非JSON格式的数据: {body}")
  101. conn.close()
  102. return None
  103. class AliyunTokenGenerator:
  104. """
  105. 用于生成阿里云服务认证令牌的类。
  106. 属性:
  107. - access_key_id (str): 您的阿里云访问密钥ID。
  108. - access_key_secret (str): 您的阿里云访问密钥秘密。
  109. """
  110. def __init__(self, access_key_id, access_key_secret):
  111. self.access_key_id = access_key_id
  112. self.access_key_secret = access_key_secret
  113. def sign_request(self, parameters):
  114. """
  115. 为阿里云服务签名请求。
  116. 参数:
  117. - parameters (dict): 请求的参数字典。
  118. 返回值:
  119. - str: 请求的签名签章。
  120. """
  121. # 将参数按照字典顺序排序
  122. sorted_params = sorted(parameters.items())
  123. # 构造待签名的查询字符串
  124. canonicalized_query_string = ''
  125. for (k, v) in sorted_params:
  126. canonicalized_query_string += '&' + self.percent_encode(k) + '=' + self.percent_encode(v)
  127. # 构造用于签名的字符串
  128. string_to_sign = 'GET&%2F&' + self.percent_encode(canonicalized_query_string[1:]) # 使用GET方法
  129. # 使用HMAC算法计算签名
  130. h = hmac.new((self.access_key_secret + "&").encode('utf-8'), string_to_sign.encode('utf-8'), hashlib.sha1)
  131. signature = base64.encodebytes(h.digest()).strip()
  132. return signature
  133. def percent_encode(self, encode_str):
  134. """
  135. 对字符串进行百分比编码。
  136. 参数:
  137. - encode_str (str): 要编码的字符串。
  138. 返回值:
  139. - str: 编码后的字符串。
  140. """
  141. encode_str = str(encode_str)
  142. res = urllib.parse.quote(encode_str, '')
  143. res = res.replace('+', '%20')
  144. res = res.replace('*', '%2A')
  145. res = res.replace('%7E', '~')
  146. return res
  147. def get_token(self):
  148. """
  149. 获取阿里云服务的令牌。
  150. 返回值:
  151. - str: 获取到的令牌。
  152. """
  153. # 设置请求参数
  154. params = {
  155. 'Format': 'JSON',
  156. 'Version': '2019-02-28',
  157. 'AccessKeyId': self.access_key_id,
  158. 'SignatureMethod': 'HMAC-SHA1',
  159. 'Timestamp': datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ"),
  160. 'SignatureVersion': '1.0',
  161. 'SignatureNonce': str(uuid.uuid4()), # 使用uuid生成唯一的随机数
  162. 'Action': 'CreateToken',
  163. 'RegionId': 'cn-shanghai'
  164. }
  165. # 计算签名
  166. signature = self.sign_request(params)
  167. params['Signature'] = signature
  168. # 构造请求URL
  169. url = 'http://nls-meta.cn-shanghai.aliyuncs.com/?' + urllib.parse.urlencode(params)
  170. # 发送请求
  171. response = requests.get(url)
  172. return response.text