diff --git a/bot/bot.py b/bot/bot.py index 850ba3b..fd56e50 100644 --- a/bot/bot.py +++ b/bot/bot.py @@ -3,8 +3,12 @@ Auto-replay chat robot abstract class """ +from bridge.context import Context +from bridge.reply import Reply + + class Bot(object): - def reply(self, query, context=None): + def reply(self, query, context : Context =None) -> Reply: """ bot auto-reply content :param req: received message diff --git a/bot/chatgpt/chat_gpt_bot.py b/bot/chatgpt/chat_gpt_bot.py index 2c8567d..b2e062d 100644 --- a/bot/chatgpt/chat_gpt_bot.py +++ b/bot/chatgpt/chat_gpt_bot.py @@ -1,6 +1,8 @@ # encoding:utf-8 from bot.bot import Bot +from bridge.context import ContextType +from bridge.reply import Reply, ReplyType from config import conf, load_config from common.log import logger from common.expired_dict import ExpiredDict @@ -19,22 +21,19 @@ class ChatGPTBot(Bot): def reply(self, query, context=None): # acquire reply content - if context['type'] == 'TEXT': + if context.type == ContextType.TEXT: logger.info("[OPEN_AI] query={}".format(query)) session_id = context['session_id'] reply = None if query == '#清除记忆': self.sessions.clear_session(session_id) - reply = {'type': 'INFO', 'content': '记忆已清除'} + reply = Reply(ReplyType.INFO, '记忆已清除') elif query == '#清除所有': self.sessions.clear_all_session() - reply = {'type': 'INFO', 'content': '所有人记忆已清除'} + reply = Reply(ReplyType.INFO, '所有人记忆已清除') elif query == '#更新配置': load_config() - reply = {'type': 'INFO', 'content': '配置已更新'} - elif query == '#DEBUG': - logger.setLevel('DEBUG') - reply = {'type': 'INFO', 'content': 'DEBUG模式已开启'} + reply = Reply(ReplyType.INFO, '配置已更新') if reply: return reply session = self.sessions.build_session_query(query, session_id) @@ -47,25 +46,25 @@ class ChatGPTBot(Bot): reply_content = self.reply_text(session, session_id, 0) logger.debug("[OPEN_AI] new_query={}, session_id={}, reply_cont={}".format(session, session_id, reply_content["content"])) if reply_content['completion_tokens'] == 0 and len(reply_content['content']) > 0: - reply = {'type': 'ERROR', 'content': reply_content['content']} + reply = Reply(ReplyType.ERROR, reply_content['content']) elif reply_content["completion_tokens"] > 0: self.sessions.save_session(reply_content["content"], session_id, reply_content["total_tokens"]) - reply={'type':'TEXT', 'content':reply_content["content"]} + reply = Reply(ReplyType.TEXT, reply_content["content"]) else: - reply = {'type': 'ERROR', 'content': reply_content['content']} + reply = Reply(ReplyType.ERROR, reply_content['content']) logger.debug("[OPEN_AI] reply {} used 0 tokens.".format(reply_content)) return reply - elif context['type'] == 'IMAGE_CREATE': + elif context.type == ContextType.IMAGE_CREATE: ok, retstring = self.create_img(query, 0) reply = None if ok: - reply = {'type': 'IMAGE_URL', 'content': retstring} + reply = Reply(ReplyType.IMAGE_URL, retstring) else: - reply = {'type': 'ERROR', 'content': retstring} + reply = Reply(ReplyType.ERROR, retstring) return reply else: - reply= {'type':'ERROR', 'content':'Bot不支持处理{}类型的消息'.format(context['type'])} + reply = Reply(ReplyType.ERROR, 'Bot不支持处理{}类型的消息'.format(context.type)) return reply def reply_text(self, session, session_id, retry_count=0) -> dict: diff --git a/bridge/bridge.py b/bridge/bridge.py index 304046e..2b67a8a 100644 --- a/bridge/bridge.py +++ b/bridge/bridge.py @@ -1,3 +1,5 @@ +from bridge.context import Context +from bridge.reply import Reply from common.log import logger from bot import bot_factory from common.singleton import singleton @@ -28,16 +30,13 @@ class Bridge(object): def get_bot_type(self,typename): return self.btype[typename] - # 以下所有函数需要得到一个reply字典,格式如下: - # reply["type"] = "ERROR" / "TEXT" / "VOICE" / ... - # reply["content"] = reply的内容 - def fetch_reply_content(self, query, context): + def fetch_reply_content(self, query, context : Context) -> Reply: return self.get_bot("chat").reply(query, context) - def fetch_voice_to_text(self, voiceFile): + def fetch_voice_to_text(self, voiceFile) -> Reply: return self.get_bot("voice_to_text").voiceToText(voiceFile) - def fetch_text_to_voice(self, text): + def fetch_text_to_voice(self, text) -> Reply: return self.get_bot("text_to_voice").textToVoice(text) diff --git a/bridge/context.py b/bridge/context.py new file mode 100644 index 0000000..1fbe4d4 --- /dev/null +++ b/bridge/context.py @@ -0,0 +1,42 @@ +# encoding:utf-8 + +from enum import Enum + +class ContextType (Enum): + TEXT = 1 # 文本消息 + VOICE = 2 # 音频消息 + IMAGE_CREATE = 3 # 创建图片命令 + + def __str__(self): + return self.name +class Context: + def __init__(self, type : ContextType = None , content = None, kwargs = dict()): + self.type = type + self.content = content + self.kwargs = kwargs + def __getitem__(self, key): + if key == 'type': + return self.type + elif key == 'content': + return self.content + else: + return self.kwargs[key] + + def __setitem__(self, key, value): + if key == 'type': + self.type = value + elif key == 'content': + self.content = value + else: + self.kwargs[key] = value + + def __delitem__(self, key): + if key == 'type': + self.type = None + elif key == 'content': + self.content = None + else: + del self.kwargs[key] + + def __str__(self): + return "Context(type={}, content={}, kwargs={})".format(self.type, self.content, self.kwargs) \ No newline at end of file diff --git a/bridge/reply.py b/bridge/reply.py new file mode 100644 index 0000000..c6bcd54 --- /dev/null +++ b/bridge/reply.py @@ -0,0 +1,22 @@ + +# encoding:utf-8 + +from enum import Enum + +class ReplyType(Enum): + TEXT = 1 # 文本 + VOICE = 2 # 音频文件 + IMAGE = 3 # 图片文件 + IMAGE_URL = 4 # 图片URL + + INFO = 9 + ERROR = 10 + def __str__(self): + return self.name + +class Reply: + def __init__(self, type : ReplyType = None , content = None): + self.type = type + self.content = content + def __str__(self): + return "Reply(type={}, content={})".format(self.type, self.content) \ No newline at end of file diff --git a/channel/channel.py b/channel/channel.py index a1395c4..62e1ad3 100644 --- a/channel/channel.py +++ b/channel/channel.py @@ -3,6 +3,8 @@ Message sending channel abstract class """ from bridge.bridge import Bridge +from bridge.context import Context +from bridge.reply import Reply class Channel(object): def startup(self): @@ -27,11 +29,11 @@ class Channel(object): """ raise NotImplementedError - def build_reply_content(self, query, context=None): + def build_reply_content(self, query, context : Context=None) -> Reply: return Bridge().fetch_reply_content(query, context) - def build_voice_to_text(self, voice_file): + def build_voice_to_text(self, voice_file) -> Reply: return Bridge().fetch_voice_to_text(voice_file) - def build_text_to_voice(self, text): + def build_text_to_voice(self, text) -> Reply: return Bridge().fetch_text_to_voice(text) diff --git a/channel/wechat/wechat_channel.py b/channel/wechat/wechat_channel.py index 0ba923f..eff788d 100644 --- a/channel/wechat/wechat_channel.py +++ b/channel/wechat/wechat_channel.py @@ -7,6 +7,8 @@ wechat channel import itchat import json from itchat.content import * +from bridge.reply import * +from bridge.context import * from channel.channel import Channel from concurrent.futures import ThreadPoolExecutor from common.log import logger @@ -69,10 +71,8 @@ class WechatChannel(Channel): from_user_id = msg['FromUserName'] other_user_id = msg['User']['UserName'] if from_user_id == other_user_id: - context = {'isgroup': False, 'msg': msg, 'receiver': other_user_id} - context['type'] = 'VOICE' - context['content'] = msg['FileName'] - context['session_id'] = other_user_id + context = Context(ContextType.VOICE,msg['FileName']) + context.kwargs = {'isgroup': False, 'msg': msg, 'receiver': other_user_id, 'session_id': other_user_id} thread_pool.submit(self.handle, context).add_done_callback(thread_pool_callback) def handle_text(self, msg): @@ -89,17 +89,17 @@ class WechatChannel(Channel): content = content.replace(match_prefix, '', 1).strip() else: return - context = {'isgroup': False, 'msg': msg, 'receiver': other_user_id} - context['session_id'] = other_user_id + context = Context() + context.kwargs = {'isgroup': False, 'msg': msg, 'receiver': other_user_id, 'session_id': other_user_id} img_match_prefix = check_prefix(content, conf().get('image_create_prefix')) if img_match_prefix: content = content.replace(img_match_prefix, '', 1).strip() - context['type'] = 'IMAGE_CREATE' + context.type = ContextType.IMAGE_CREATE else: - context['type'] = 'TEXT' + context.type = ContextType.TEXT - context['content'] = content + context.content = content thread_pool.submit(self.handle, context).add_done_callback(thread_pool_callback) def handle_group(self, msg): @@ -123,15 +123,16 @@ class WechatChannel(Channel): match_prefix = (msg['IsAt'] and not config.get("group_at_off", False)) or check_prefix(origin_content, config.get('group_chat_prefix')) \ or check_contain(origin_content, config.get('group_chat_keyword')) if ('ALL_GROUP' in config.get('group_name_white_list') or group_name in config.get('group_name_white_list') or check_contain(group_name, config.get('group_name_keyword_white_list'))) and match_prefix: - context = { 'isgroup': True, 'msg': msg, 'receiver': group_id} + context = Context() + context.kwargs = { 'isgroup': True, 'msg': msg, 'receiver': group_id} img_match_prefix = check_prefix(content, conf().get('image_create_prefix')) if img_match_prefix: content = content.replace(img_match_prefix, '', 1).strip() - context['type'] = 'IMAGE_CREATE' + context.type = ContextType.IMAGE_CREATE else: - context['type'] = 'TEXT' - context['content'] = content + context.type = ContextType.TEXT + context.content = content group_chat_in_one_session = conf().get('group_chat_in_one_session', []) if ('ALL_GROUP' in group_chat_in_one_session or @@ -144,18 +145,18 @@ class WechatChannel(Channel): thread_pool.submit(self.handle, context).add_done_callback(thread_pool_callback) # 统一的发送函数,每个Channel自行实现,根据reply的type字段发送不同类型的消息 - def send(self, reply, receiver): - if reply['type'] == 'TEXT': - itchat.send(reply['content'], toUserName=receiver) + def send(self, reply : Reply, receiver): + if reply.type == ReplyType.TEXT: + itchat.send(reply.content, toUserName=receiver) logger.info('[WX] sendMsg={}, receiver={}'.format(reply, receiver)) - elif reply['type'] == 'ERROR' or reply['type'] == 'INFO': - itchat.send(reply['content'], toUserName=receiver) + elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO: + itchat.send(reply.content, toUserName=receiver) logger.info('[WX] sendMsg={}, receiver={}'.format(reply, receiver)) - elif reply['type'] == 'VOICE': - itchat.send_file(reply['content'], toUserName=receiver) - logger.info('[WX] sendFile={}, receiver={}'.format(reply['content'], receiver)) - elif reply['type']=='IMAGE_URL': # 从网络下载图片 - img_url = reply['content'] + elif reply.type == ReplyType.VOICE: + itchat.send_file(reply.content, toUserName=receiver) + logger.info('[WX] sendFile={}, receiver={}'.format(reply.content, receiver)) + elif reply.type == ReplyType.IMAGE_URL: # 从网络下载图片 + img_url = reply.content pic_res = requests.get(img_url, stream=True) image_storage = io.BytesIO() for block in pic_res.iter_content(1024): @@ -163,69 +164,69 @@ class WechatChannel(Channel): image_storage.seek(0) itchat.send_image(image_storage, toUserName=receiver) logger.info('[WX] sendImage url=, receiver={}'.format(img_url,receiver)) - elif reply['type']=='IMAGE': # 从文件读取图片 - image_storage = reply['content'] + elif reply.type == ReplyType.IMAGE: # 从文件读取图片 + image_storage = reply.content image_storage.seek(0) itchat.send_image(image_storage, toUserName=receiver) logger.info('[WX] sendImage, receiver={}'.format(receiver)) # 处理消息 TODO: 如果wechaty解耦,此处逻辑可以放置到父类 def handle(self, context): - reply = {} + reply = Reply() logger.debug('[WX] ready to handle context: {}'.format(context)) # reply的构建步骤 e_context = PluginManager().emit_event(EventContext(Event.ON_HANDLE_CONTEXT, {'channel' : self, 'context': context, 'reply': reply})) - reply=e_context['reply'] + reply = e_context['reply'] if not e_context.is_pass(): - logger.debug('[WX] ready to handle context: type={}, content={}'.format(context['type'], context['content'])) - if context['type'] == 'TEXT' or context['type'] == 'IMAGE_CREATE': - reply = super().build_reply_content(context['content'], context) - elif context['type'] == 'VOICE': + logger.debug('[WX] ready to handle context: type={}, content={}'.format(context.type, context.content)) + if context.type == ContextType.TEXT or context.type == ContextType.IMAGE_CREATE: + reply = super().build_reply_content(context.content, context) + elif context.type == ContextType.VOICE: msg = context['msg'] - file_name = TmpDir().path() + context['content'] + file_name = TmpDir().path() + context.content msg.download(file_name) reply = super().build_voice_to_text(file_name) - if reply['type'] != 'ERROR' and reply['type'] != 'INFO': - context['content'] = reply['content'] # 语音转文字后,将文字内容作为新的context - context['type'] = reply['type'] - reply = super().build_reply_content(context['content'], context) - if reply['type'] == 'TEXT': + if reply.type != ReplyType.ERROR and reply.type != ReplyType.INFO: + context.content = reply.content # 语音转文字后,将文字内容作为新的context + context.type = ContextType.TEXT + reply = super().build_reply_content(context.content, context) + if reply.type == ReplyType.TEXT: if conf().get('voice_reply_voice'): - reply = super().build_text_to_voice(reply['content']) + reply = super().build_text_to_voice(reply.content) else: - logger.error('[WX] unknown context type: {}'.format(context['type'])) + logger.error('[WX] unknown context type: {}'.format(context.type)) return logger.debug('[WX] ready to decorate reply: {}'.format(reply)) # reply的包装步骤 - if reply and reply['type']: + if reply and reply.type: e_context = PluginManager().emit_event(EventContext(Event.ON_DECORATE_REPLY, {'channel' : self, 'context': context, 'reply': reply})) reply=e_context['reply'] - if not e_context.is_pass() and reply and reply['type']: - if reply['type'] == 'TEXT': - reply_text = reply['content'] + if not e_context.is_pass() and reply and reply.type: + if reply.type == ReplyType.TEXT: + reply_text = reply.content if context['isgroup']: reply_text = '@' + context['msg']['ActualNickName'] + ' ' + reply_text.strip() reply_text = conf().get("group_chat_reply_prefix", "")+reply_text else: reply_text = conf().get("single_chat_reply_prefix", "")+reply_text - reply['content'] = reply_text - elif reply['type'] == 'ERROR' or reply['type'] == 'INFO': - reply['content'] = reply['type']+":\n" + reply['content'] - elif reply['type'] == 'IMAGE_URL' or reply['type'] == 'VOICE' or reply['type'] == 'IMAGE': + reply.content = reply_text + elif reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO: + reply.content = str(reply.type)+":\n" + reply.content + elif reply.type == ReplyType.IMAGE_URL or reply.type == ReplyType.VOICE or reply.type == ReplyType.IMAGE: pass else: - logger.error('[WX] unknown reply type: {}'.format(reply['type'])) + logger.error('[WX] unknown reply type: {}'.format(reply.type)) return # reply的发送步骤 - if reply and reply['type']: + if reply and reply.type: e_context = PluginManager().emit_event(EventContext(Event.ON_SEND_REPLY, {'channel' : self, 'context': context, 'reply': reply})) reply=e_context['reply'] - if not e_context.is_pass() and reply and reply['type']: + if not e_context.is_pass() and reply and reply.type: logger.debug('[WX] ready to send reply: {} to {}'.format(reply, context['receiver'])) self.send(reply, context['receiver']) diff --git a/channel/wechat/wechaty_channel.py b/channel/wechat/wechaty_channel.py index 7ae4683..3a7fe2c 100644 --- a/channel/wechat/wechaty_channel.py +++ b/channel/wechat/wechaty_channel.py @@ -11,6 +11,7 @@ import time import asyncio import requests from typing import Optional, Union +from bridge.context import Context, ContextType from wechaty_puppet import MessageType, FileBox, ScanStatus # type: ignore from wechaty import Wechaty, Contact from wechaty.user import Message, Room, MiniProgram, UrlLink @@ -127,11 +128,9 @@ class WechatyChannel(Channel): try: if not query: return - context = dict() + context = Context(ContextType.TEXT, query) context['session_id'] = reply_user_id - context['type'] = 'TEXT' - context['content'] = query - reply_text = super().build_reply_content(query, context)['content'] + reply_text = super().build_reply_content(query, context).content if reply_text: await self.send(conf().get("single_chat_reply_prefix") + reply_text, reply_user_id) except Exception as e: @@ -141,10 +140,8 @@ class WechatyChannel(Channel): try: if not query: return - context = dict() - context['type'] = 'IMAGE_CREATE' - context['content'] = query - img_url = super().build_reply_content(query, context)['content'] + context = Context(ContextType.IMAGE_CREATE, query) + img_url = super().build_reply_content(query, context).content if not img_url: return # 图片下载 @@ -165,7 +162,7 @@ class WechatyChannel(Channel): async def _do_send_group(self, query, group_id, group_name, group_user_id, group_user_name): if not query: return - context = dict() + context = Context(ContextType.TEXT, query) group_chat_in_one_session = conf().get('group_chat_in_one_session', []) if ('ALL_GROUP' in group_chat_in_one_session or \ group_name in group_chat_in_one_session or \ @@ -173,9 +170,7 @@ class WechatyChannel(Channel): context['session_id'] = str(group_id) else: context['session_id'] = str(group_id) + '-' + str(group_user_id) - context['type'] = 'TEXT' - context['content'] = query - reply_text = super().build_reply_content(query, context)['content'] + reply_text = super().build_reply_content(query, context).content if reply_text: reply_text = '@' + group_user_name + ' ' + reply_text.strip() await self.send_group(conf().get("group_chat_reply_prefix", "") + reply_text, group_id) @@ -184,10 +179,8 @@ class WechatyChannel(Channel): try: if not query: return - context = dict() - context['type'] = 'IMAGE_CREATE' - context['content'] = query - img_url = super().build_reply_content(query, context)['content'] + context = Context(ContextType.IMAGE_CREATE, query) + img_url = super().build_reply_content(query, context).content if not img_url: return # 图片发送 diff --git a/plugins/godcmd/godcmd.py b/plugins/godcmd/godcmd.py index 3bd24dd..e988452 100644 --- a/plugins/godcmd/godcmd.py +++ b/plugins/godcmd/godcmd.py @@ -5,6 +5,8 @@ import os import traceback from typing import Tuple from bridge.bridge import Bridge +from bridge.context import ContextType +from bridge.reply import Reply, ReplyType from config import load_config import plugins from plugins import * @@ -123,13 +125,13 @@ class Godcmd(Plugin): def on_handle_context(self, e_context: EventContext): - context_type = e_context['context']['type'] - if context_type != "TEXT": + context_type = e_context['context'].type + if context_type != ContextType.TEXT: if not self.isrunning: e_context.action = EventAction.BREAK_PASS return - content = e_context['context']['content'] + content = e_context['context'].content logger.debug("[Godcmd] on_handle_context. content: %s" % content) if content.startswith("#"): # msg = e_context['context']['msg'] @@ -239,12 +241,12 @@ class Godcmd(Plugin): else: ok, result = False, f"未知指令:{cmd}\n查看指令列表请输入#help \n" - reply = {} + reply = Reply() if ok: - reply["type"] = "INFO" + reply.type = ReplyType.INFO else: - reply["type"] = "ERROR" - reply["content"] = result + reply.type = ReplyType.ERROR + reply.content = result e_context['reply'] = reply e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑 diff --git a/plugins/hello/hello.py b/plugins/hello/hello.py index 1eb409e..53d87e6 100644 --- a/plugins/hello/hello.py +++ b/plugins/hello/hello.py @@ -1,5 +1,7 @@ # encoding:utf-8 +from bridge.context import ContextType +from bridge.reply import Reply, ReplyType import plugins from plugins import * from common.log import logger @@ -14,31 +16,31 @@ class Hello(Plugin): def on_handle_context(self, e_context: EventContext): - if e_context['context']['type'] != "TEXT": + if e_context['context'].type != ContextType.TEXT: return - content = e_context['context']['content'] + content = e_context['context'].content logger.debug("[Hello] on_handle_context. content: %s" % content) if content == "Hello": - reply = {} - reply['type'] = "TEXT" + reply = Reply() + reply.type = ReplyType.TEXT msg = e_context['context']['msg'] if e_context['context']['isgroup']: - reply['content'] = "Hello, " + msg['ActualNickName'] + " from " + msg['User'].get('NickName', "Group") + reply.content = "Hello, " + msg['ActualNickName'] + " from " + msg['User'].get('NickName', "Group") else: - reply['content'] = "Hello, " + msg['User'].get('NickName', "My friend") + reply.content = "Hello, " + msg['User'].get('NickName', "My friend") e_context['reply'] = reply e_context.action = EventAction.BREAK_PASS # 事件结束,并跳过处理context的默认逻辑 if content == "Hi": - reply={} - reply['type'] = "TEXT" - reply['content'] = "Hi" + reply = Reply() + reply.type = ReplyType.TEXT + reply.content = "Hi" e_context['reply'] = reply e_context.action = EventAction.BREAK # 事件结束,进入默认处理逻辑,一般会覆写reply if content == "End": # 如果是文本消息"End",将请求转换成"IMAGE_CREATE",并将content设置为"The World" - e_context['context']['type'] = "IMAGE_CREATE" + e_context['context'].type = "IMAGE_CREATE" content = "The World" e_context.action = EventAction.CONTINUE # 事件继续,交付给下个插件或默认逻辑 diff --git a/voice/baidu/baidu_voice.py b/voice/baidu/baidu_voice.py index adab169..531d8ce 100644 --- a/voice/baidu/baidu_voice.py +++ b/voice/baidu/baidu_voice.py @@ -4,6 +4,7 @@ baidu voice service """ import time from aip import AipSpeech +from bridge.reply import Reply, ReplyType from common.log import logger from common.tmp_dir import TmpDir from voice.voice import Voice @@ -30,8 +31,8 @@ class BaiduVoice(Voice): with open(fileName, 'wb') as f: f.write(result) logger.info('[Baidu] textToVoice text={} voice file name={}'.format(text, fileName)) - reply = {"type": "VOICE", "content": fileName} + reply = Reply(ReplyType.VOICE, fileName) else: logger.error('[Baidu] textToVoice error={}'.format(result)) - reply = {"type": "ERROR", "content": "抱歉,语音合成失败"} + reply = Reply(ReplyType.ERROR, "抱歉,语音合成失败") return reply diff --git a/voice/google/google_voice.py b/voice/google/google_voice.py index 6c00892..74431db 100644 --- a/voice/google/google_voice.py +++ b/voice/google/google_voice.py @@ -6,6 +6,7 @@ google voice service import pathlib import subprocess import time +from bridge.reply import Reply, ReplyType import speech_recognition import pyttsx3 from common.log import logger @@ -32,16 +33,15 @@ class GoogleVoice(Voice): ' -acodec pcm_s16le -ac 1 -ar 16000 ' + new_file, shell=True) with speech_recognition.AudioFile(new_file) as source: audio = self.recognizer.record(source) - reply = {} try: text = self.recognizer.recognize_google(audio, language='zh-CN') logger.info( '[Google] voiceToText text={} voice file name={}'.format(text, voice_file)) - reply = {"type": "TEXT", "content": text} + reply = Reply(ReplyType.TEXT, text) except speech_recognition.UnknownValueError: - reply = {"type": "ERROR", "content": "抱歉,我听不懂"} + reply = Reply(ReplyType.ERROR, "抱歉,我听不懂") except speech_recognition.RequestError as e: - reply = {"type": "ERROR", "content": "抱歉,无法连接到 Google 语音识别服务;{0}".format(e)} + reply = Reply(ReplyType.ERROR, "抱歉,无法连接到 Google 语音识别服务;{0}".format(e)) finally: return reply def textToVoice(self, text): @@ -51,8 +51,8 @@ class GoogleVoice(Voice): self.engine.runAndWait() logger.info( '[Google] textToVoice text={} voice file name={}'.format(text, textFile)) - reply = {"type": "VOICE", "content": textFile} + reply = Reply(ReplyType.VOICE, textFile) except Exception as e: - reply = {"type": "ERROR", "content": str(e)} + reply = Reply(ReplyType.ERROR, str(e)) finally: return reply diff --git a/voice/openai/openai_voice.py b/voice/openai/openai_voice.py index 3b77c52..2e85e10 100644 --- a/voice/openai/openai_voice.py +++ b/voice/openai/openai_voice.py @@ -4,6 +4,7 @@ google voice service """ import json import openai +from bridge.reply import Reply, ReplyType from config import conf from common.log import logger from voice.voice import Voice @@ -16,16 +17,15 @@ class OpenaiVoice(Voice): def voiceToText(self, voice_file): logger.debug( '[Openai] voice file name={}'.format(voice_file)) - reply={} try: file = open(voice_file, "rb") result = openai.Audio.transcribe("whisper-1", file) text = result["text"] - reply = {"type": "TEXT", "content": text} + reply = Reply(ReplyType.TEXT, text) logger.info( '[Openai] voiceToText text={} voice file name={}'.format(text, voice_file)) except Exception as e: - reply = {"type": "ERROR", "content": str(e)} + reply = Reply(ReplyType.ERROR, str(e)) finally: return reply