From cae12eb187b4bd561702ec0ad352f06bba10dc76 Mon Sep 17 00:00:00 2001 From: lanvent Date: Sun, 23 Apr 2023 03:51:09 +0800 Subject: [PATCH] feat: add baidu translate api --- bot/{bot_factory.py => factory.py} | 0 bridge/bridge.py | 14 +++++--- config.py | 5 +++ translate/baidu/baidu_translate.py | 49 ++++++++++++++++++++++++++ translate/factory.py | 6 ++++ translate/translator.py | 12 +++++++ voice/{voice_factory.py => factory.py} | 0 7 files changed, 81 insertions(+), 5 deletions(-) rename bot/{bot_factory.py => factory.py} (100%) create mode 100644 translate/baidu/baidu_translate.py create mode 100644 translate/factory.py create mode 100644 translate/translator.py rename voice/{voice_factory.py => factory.py} (100%) diff --git a/bot/bot_factory.py b/bot/factory.py similarity index 100% rename from bot/bot_factory.py rename to bot/factory.py diff --git a/bridge/bridge.py b/bridge/bridge.py index dcf6e7e..18acdad 100644 --- a/bridge/bridge.py +++ b/bridge/bridge.py @@ -1,11 +1,12 @@ -from bot import bot_factory +from bot.factory import create_bot from bridge.context import Context from bridge.reply import Reply from common import const from common.log import logger from common.singleton import singleton from config import conf -from voice import voice_factory +from translate.factory import create_translator +from voice.factory import create_voice @singleton @@ -15,6 +16,7 @@ class Bridge(object): "chat": const.CHATGPT, "voice_to_text": conf().get("voice_to_text", "openai"), "text_to_voice": conf().get("text_to_voice", "google"), + "translate": conf().get("translate", "baidu"), } model_type = conf().get("model") if model_type in ["text-davinci-003"]: @@ -27,11 +29,13 @@ class Bridge(object): if self.bots.get(typename) is None: logger.info("create bot {} for {}".format(self.btype[typename], typename)) if typename == "text_to_voice": - self.bots[typename] = voice_factory.create_voice(self.btype[typename]) + self.bots[typename] = create_voice(self.btype[typename]) elif typename == "voice_to_text": - self.bots[typename] = voice_factory.create_voice(self.btype[typename]) + self.bots[typename] = create_voice(self.btype[typename]) elif typename == "chat": - self.bots[typename] = bot_factory.create_bot(self.btype[typename]) + self.bots[typename] = create_bot(self.btype[typename]) + elif typename == "translate": + self.bots[typename] = create_translator(self.btype[typename]) return self.bots[typename] def get_bot_type(self, typename): diff --git a/config.py b/config.py index b7de15e..b385519 100644 --- a/config.py +++ b/config.py @@ -66,6 +66,11 @@ available_setting = { "chat_time_module": False, # 是否开启服务时间限制 "chat_start_time": "00:00", # 服务开始时间 "chat_stop_time": "24:00", # 服务结束时间 + # 翻译api + "translate": "baidu", # 翻译api,支持baidu + # baidu翻译api的配置 + "baidu_translate_app_id": "", # 百度翻译api的appid + "baidu_translate_app_key": "", # 百度翻译api的秘钥 # itchat的配置 "hot_reload": False, # 是否开启热重载 # wechaty的配置 diff --git a/translate/baidu/baidu_translate.py b/translate/baidu/baidu_translate.py new file mode 100644 index 0000000..d9bdf5c --- /dev/null +++ b/translate/baidu/baidu_translate.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +import random +from hashlib import md5 + +import requests + +from config import conf +from translate.translator import Translator + +# from langid import classify + + +class BaiduTranslator(Translator): + def __init__(self) -> None: + super().__init__() + endpoint = "http://api.fanyi.baidu.com" + path = "/api/trans/vip/translate" + self.url = endpoint + path + self.appid = conf().get("baidu_translate_app_id") + self.appkey = conf().get("baidu_translate_app_key") + + # For list of language codes, please refer to `https://api.fanyi.baidu.com/doc/21`, need to convert to ISO 639-1 codes + def translate(self, query: str, from_lang: str = "", to_lang: str = "en") -> str: + if not from_lang: + from_lang = "auto" # baidu suppport auto detect + # from_lang = classify(query)[0] + salt = random.randint(32768, 65536) + sign = self.make_md5(self.appid + query + str(salt) + self.appkey) + headers = {"Content-Type": "application/x-www-form-urlencoded"} + payload = {"appid": self.appid, "q": query, "from": from_lang, "to": to_lang, "salt": salt, "sign": sign} + + retry_cnt = 3 + while retry_cnt: + r = requests.post(self.url, params=payload, headers=headers) + result = r.json() + if errcode := result.get("error_code", "52000") != "52000": + if errcode == "52001" or errcode == "52002": + retry_cnt -= 1 + continue + else: + raise Exception(result["error_msg"]) + else: + break + text = "\n".join([item["dst"] for item in result["trans_result"]]) + return text + + def make_md5(self, s, encoding="utf-8"): + return md5(s.encode(encoding)).hexdigest() diff --git a/translate/factory.py b/translate/factory.py new file mode 100644 index 0000000..ba80aa5 --- /dev/null +++ b/translate/factory.py @@ -0,0 +1,6 @@ +def create_translator(voice_type): + if voice_type == "baidu": + from translate.baidu.baidu_translate import BaiduTranslator + + return BaiduTranslator() + raise RuntimeError diff --git a/translate/translator.py b/translate/translator.py new file mode 100644 index 0000000..b394f4e --- /dev/null +++ b/translate/translator.py @@ -0,0 +1,12 @@ +""" +Voice service abstract class +""" + + +class Translator(object): + # please use https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes to specify language + def translate(self, query: str, from_lang: str = "", to_lang: str = "en") -> str: + """ + Translate text from one language to another + """ + raise NotImplementedError diff --git a/voice/voice_factory.py b/voice/factory.py similarity index 100% rename from voice/voice_factory.py rename to voice/factory.py