lib_tts_dipai.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @Author: 程尧
  4. @Desc: 语音合成(朗读)功能
  5. # 合成小语种需要传输小语种文本、使用小语种发音人vcn、tte=unicode以及修改文本编码方式
  6. # 错误码链接:https://www.xfyun.cn/document/error-code (code返回错误码时必看)
  7. """
  8. import time
  9. import websocket
  10. import datetime
  11. import hashlib
  12. import base64
  13. import hmac
  14. import json
  15. import ssl
  16. import _thread as thread
  17. import os
  18. from threading import Thread
  19. import sys
  20. import random
  21. from urllib.parse import quote
  22. import config
  23. URL = 'ws://112.30.115.188:28080/dpwsTts/v2/tts'
  24. APPID = 'shuchuan'
  25. APIKey = '988472d12573b52e0a9f07ff5368eeac'
  26. APISecret = '1b802ee73ba0cb67e7a2331d59cb4fc8'
  27. # URL = config.config["DiPai_TTS_URL"]
  28. # APPID = config.config["DiPai_TTS_APPID"]
  29. # APIKey = config.config["DiPai_TTS_APIKey"]
  30. # APISecret = config.config["DiPai_TTS_APISecret"]
  31. def get_proxy():
  32. _proxy = ""
  33. proxy_type = ""
  34. host = ""
  35. port = ""
  36. user = ""
  37. pswd = ""
  38. try:
  39. _proxy = os.environ["http_proxy"]
  40. except:
  41. pass
  42. else:
  43. try:
  44. addr = _proxy.split("//")[1]
  45. proxy_type_str = _proxy.split("//")[0]
  46. proxy_type = proxy_type_str[:-1]
  47. port = addr.split(":")[-1]
  48. if "@" in addr: # 有用户密码
  49. host_str = addr.split("@")[-1]
  50. host = host_str.split(f":{port}")[0]
  51. auth_str = addr.split(host_str)[0]
  52. user = auth_str.split(":")[0]
  53. pswd_str = auth_str.split(":")[-1]
  54. pswd = pswd_str[:-1]
  55. else:
  56. host = addr.split(":")[0]
  57. except:
  58. pass
  59. return _proxy, proxy_type, host, port, user, pswd
  60. def get_home_env():
  61. if sys.platform == "win32":
  62. return 'APPDATA'
  63. return 'HOME'
  64. def gen_tmp_mp3_file():
  65. _dir = os.path.join(os.environ[get_home_env()], "iFLYAssistant")
  66. if not os.path.exists(_dir):
  67. os.makedirs(_dir)
  68. _tmp_dir = os.path.join(_dir, "tmp")
  69. if not os.path.exists(_tmp_dir):
  70. os.makedirs(_tmp_dir)
  71. _path = os.path.join(_tmp_dir, f"{int(time.time())}.mp3")
  72. return _path
  73. def get_nonce():
  74. random_number = random.randint(1, 100)
  75. return random_number
  76. # TTS工作线程
  77. class TTSManagerNew(Thread):
  78. def __init__(self, text, vcn, speed_mode, queue):
  79. super(TTSManagerNew, self).__init__()
  80. self.daemon = True
  81. self.queue = queue
  82. self._ws = None
  83. self.code = None
  84. self.sid = None
  85. self._speed = self.get_speed_value(speed_mode)
  86. # 公共参数(common)
  87. self.CommonArgs = {"app_id": APPID}
  88. # 业务参数(business),更多个性化参数可在官网查看
  89. self.BusinessArgs = {"aue": "raw", "auf": "audio/L16;rate=16000", "vcn": vcn, "tte": "UTF8"}
  90. self.Data = {"status": 2, "text": str(base64.b64encode(text.encode('utf-8')), "UTF8")}
  91. self.d = {"common": self.CommonArgs,
  92. "business": self.BusinessArgs,
  93. "data": self.Data,
  94. }
  95. # 生成url
  96. def create_url(self):
  97. # 构造握手参数
  98. curTime = int(time.time())
  99. nonce = get_nonce()
  100. srcStr = "APIKey=" + APIKey + "&Nonce=" + str(nonce) + "&Region=bj&Task=TTS&Timestamp=" + str(curTime)
  101. signature_sha = hmac.new(APISecret.encode('utf-8'),
  102. srcStr.encode('utf-8'),
  103. digestmod=hashlib.sha256).digest()
  104. signature_sha = base64.b64encode(signature_sha).decode(encoding='utf-8')
  105. print(signature_sha)
  106. signature_encoded = quote(signature_sha, safe='')
  107. print(signature_encoded)
  108. connParam = "?" + srcStr + "&Signature=" + signature_encoded
  109. # 拼接鉴权参数,生成url
  110. url = URL + connParam
  111. # print("date: ",date)
  112. # print("v: ",v)
  113. # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致
  114. # print('websocket url :', url)
  115. return url
  116. def run(self):
  117. ws_url = self.create_url()
  118. self._ws = websocket.WebSocketApp(ws_url, on_open=self.on_open, on_message=self.on_message,
  119. on_error=self.on_error,
  120. on_close=self.on_close)
  121. _proxy, proxy_type, host, port, user, pswd = get_proxy()
  122. try:
  123. if all([_proxy, proxy_type, host, port, user, pswd]):
  124. self._ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE},
  125. http_proxy_host=host,
  126. http_proxy_port=port,
  127. proxy_type=proxy_type,
  128. http_proxy_auth=(user, pswd)
  129. )
  130. elif all([_proxy, proxy_type, host, port]):
  131. self._ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE},
  132. http_proxy_host=host,
  133. http_proxy_port=port,
  134. proxy_type=proxy_type
  135. )
  136. else:
  137. self._ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
  138. except:
  139. return
  140. # 收到websocket连接建立的处理
  141. def on_open(self, ws):
  142. def run(*args):
  143. ws.send(json.dumps(self.d))
  144. thread.start_new_thread(run, ())
  145. def on_message(self, ws, message):
  146. try:
  147. message = json.loads(message)
  148. self.code = message["code"]
  149. # self.sid = message["sid"]
  150. status = message["status"]
  151. if status == 2:
  152. audio = message["audio"]
  153. audio = base64.b64decode(audio)
  154. self.queue.put(audio)
  155. pass
  156. self.queue.put("--end--")
  157. if self.code != 0:
  158. err_msg = message["message"]
  159. if "NoneType" not in str(err_msg):
  160. self.queue.put(f"error:{err_msg},{self.code}")
  161. else:
  162. audio = message["audio"]
  163. audio = base64.b64decode(audio)
  164. self.queue.put(audio)
  165. except Exception as e:
  166. if "NoneType" not in str(e):
  167. self.queue.put(f"error:{self.sid},{str(e)},{self.code}")
  168. # 收到websocket关闭的处理
  169. @staticmethod
  170. def on_close(ws, *args):
  171. pass
  172. # 收到websocket错误的处理
  173. def on_error(self, ws, error):
  174. if "NoneType" not in str(error):
  175. self.queue.put(f"error:{self.sid},{str(error)},{self.code}")
  176. @staticmethod
  177. def get_speed_value(speed_mode):
  178. if speed_mode == 1:
  179. speed = 80
  180. elif speed_mode == 2:
  181. speed = 30
  182. else:
  183. speed = 50
  184. return speed
  185. def stop(self):
  186. self._ws.close()