Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

82 lines
3.0KB

  1. # -*- coding: utf-8 -*-
  2. """
  3. Author: chazzjimel
  4. Email: chazzjimel@gmail.com
  5. wechat:cheung-z-x
  6. Description:
  7. ali voice service
  8. """
  9. import json
  10. import os
  11. import re
  12. import time
  13. from bridge.reply import Reply, ReplyType
  14. from common.log import logger
  15. from voice.voice import Voice
  16. from voice.ali.ali_api import AliyunTokenGenerator
  17. from voice.ali.ali_api import text_to_speech_aliyun
  18. from config import conf
  19. class AliVoice(Voice):
  20. def __init__(self):
  21. """
  22. 初始化AliVoice类,从配置文件加载必要的配置。
  23. """
  24. try:
  25. curdir = os.path.dirname(__file__)
  26. config_path = os.path.join(curdir, "config.json")
  27. with open(config_path, "r") as fr:
  28. config = json.load(fr)
  29. self.token = None
  30. self.token_expire_time = 0
  31. # 默认复用阿里云千问的 access_key 和 access_secret
  32. self.api_url = config.get("api_url")
  33. self.app_key = config.get("app_key")
  34. self.access_key_id = conf().get("qwen_access_key_id") or config.get("access_key_id")
  35. self.access_key_secret = conf().get("qwen_access_key_secret") or config.get("access_key_secret")
  36. except Exception as e:
  37. logger.warn("AliVoice init failed: %s, ignore " % e)
  38. def textToVoice(self, text):
  39. """
  40. 将文本转换为语音文件。
  41. :param text: 要转换的文本。
  42. :return: 返回一个Reply对象,其中包含转换得到的语音文件或错误信息。
  43. """
  44. # 清除文本中的非中文、非英文和非基本字符
  45. text = re.sub(r'[^\u4e00-\u9fa5\u3040-\u30FF\uAC00-\uD7AFa-zA-Z0-9'
  46. r'äöüÄÖÜáéíóúÁÉÍÓÚàèìòùÀÈÌÒÙâêîôûÂÊÎÔÛçÇñÑ,。!?,.]', '', text)
  47. # 提取有效的token
  48. token_id = self.get_valid_token()
  49. fileName = text_to_speech_aliyun(self.api_url, text, self.app_key, token_id)
  50. if fileName:
  51. logger.info("[Ali] textToVoice text={} voice file name={}".format(text, fileName))
  52. reply = Reply(ReplyType.VOICE, fileName)
  53. else:
  54. reply = Reply(ReplyType.ERROR, "抱歉,语音合成失败")
  55. return reply
  56. def get_valid_token(self):
  57. """
  58. 获取有效的阿里云token。
  59. :return: 返回有效的token字符串。
  60. """
  61. current_time = time.time()
  62. if self.token is None or current_time >= self.token_expire_time:
  63. get_token = AliyunTokenGenerator(self.access_key_id, self.access_key_secret)
  64. token_str = get_token.get_token()
  65. token_data = json.loads(token_str)
  66. self.token = token_data["Token"]["Id"]
  67. # 将过期时间减少一小段时间(例如5分钟),以避免在边界条件下的过期
  68. self.token_expire_time = token_data["Token"]["ExpireTime"] - 300
  69. logger.debug(f"新获取的阿里云token:{self.token}")
  70. else:
  71. logger.debug("使用缓存的token")
  72. return self.token