@@ -32,13 +32,13 @@ class DingTalkMessage(ChatMessage): | |||||
# 钉钉支持直接识别语音,所以此处将直接提取文字,当文字处理 | # 钉钉支持直接识别语音,所以此处将直接提取文字,当文字处理 | ||||
self.content = event.extensions['content']['recognition'].strip() | self.content = event.extensions['content']['recognition'].strip() | ||||
self.ctype = ContextType.TEXT | self.ctype = ContextType.TEXT | ||||
self.from_user_id = event.sender_id | |||||
if self.is_group: | |||||
self.from_user_id = event.conversation_id | |||||
self.actual_user_id = event.sender_id | |||||
else: | |||||
self.from_user_id = event.sender_id | |||||
self.to_user_id = event.chatbot_user_id | self.to_user_id = event.chatbot_user_id | ||||
self.other_user_nickname = event.conversation_title | self.other_user_nickname = event.conversation_title | ||||
user_id = event.sender_id | user_id = event.sender_id | ||||
nickname =event.sender_nick | nickname =event.sender_nick | ||||
@@ -2,12 +2,13 @@ from bridge.context import Context, ContextType | |||||
from bridge.reply import Reply, ReplyType | from bridge.reply import Reply, ReplyType | ||||
from common.log import logger | from common.log import logger | ||||
from linkai import LinkAIClient, PushMsg | from linkai import LinkAIClient, PushMsg | ||||
from config import conf, pconf, plugin_config | |||||
from config import conf, pconf, plugin_config, load_config | |||||
from plugins import PluginManager | from plugins import PluginManager | ||||
chat_client: LinkAIClient | chat_client: LinkAIClient | ||||
class ChatClient(LinkAIClient): | class ChatClient(LinkAIClient): | ||||
def __init__(self, api_key, host, channel): | def __init__(self, api_key, host, channel): | ||||
super().__init__(api_key, host) | super().__init__(api_key, host) | ||||
@@ -27,29 +28,65 @@ class ChatClient(LinkAIClient): | |||||
def on_config(self, config: dict): | def on_config(self, config: dict): | ||||
if not self.client_id: | if not self.client_id: | ||||
return | return | ||||
logger.info(f"从控制台加载配置: {config}") | |||||
logger.info(f"[LinkAI] 从客户端管理加载远程配置: {config}") | |||||
if config.get("enabled") != "Y": | |||||
return | |||||
local_config = conf() | local_config = conf() | ||||
for key in local_config.keys(): | for key in local_config.keys(): | ||||
if config.get(key) is not None: | if config.get(key) is not None: | ||||
local_config[key] = config.get(key) | local_config[key] = config.get(key) | ||||
if config.get("reply_voice_mode"): | |||||
if config.get("reply_voice_mode") == "voice_reply_voice": | |||||
# 语音配置 | |||||
reply_voice_mode = config.get("reply_voice_mode") | |||||
if reply_voice_mode: | |||||
if reply_voice_mode == "voice_reply_voice": | |||||
local_config["voice_reply_voice"] = True | local_config["voice_reply_voice"] = True | ||||
elif config.get("reply_voice_mode") == "always_reply_voice": | |||||
elif reply_voice_mode == "always_reply_voice": | |||||
local_config["always_reply_voice"] = True | local_config["always_reply_voice"] = True | ||||
# if config.get("admin_password") and plugin_config["Godcmd"]: | |||||
# plugin_config["Godcmd"]["password"] = config.get("admin_password") | |||||
# PluginManager().instances["Godcmd"].reload() | |||||
# if config.get("group_app_map") and pconf("linkai"): | |||||
# local_group_map = {} | |||||
# for mapping in config.get("group_app_map"): | |||||
# local_group_map[mapping.get("group_name")] = mapping.get("app_code") | |||||
# pconf("linkai")["group_app_map"] = local_group_map | |||||
# PluginManager().instances["linkai"].reload() | |||||
if config.get("admin_password") and plugin_config["Godcmd"]: | |||||
plugin_config["Godcmd"]["password"] = config.get("admin_password") | |||||
PluginManager().instances["GODCMD"].reload() | |||||
if config.get("group_app_map") and pconf("linkai"): | |||||
local_group_map = {} | |||||
for mapping in config.get("group_app_map"): | |||||
local_group_map[mapping.get("group_name")] = mapping.get("app_code") | |||||
pconf("linkai")["group_app_map"] = local_group_map | |||||
PluginManager().instances["LINKAI"].reload() | |||||
def start(channel): | def start(channel): | ||||
global chat_client | global chat_client | ||||
chat_client = ChatClient(api_key=conf().get("linkai_api_key"), | chat_client = ChatClient(api_key=conf().get("linkai_api_key"), | ||||
host="link-ai.chat", channel=channel) | host="link-ai.chat", channel=channel) | ||||
chat_client.config = _build_config() | |||||
chat_client.start() | chat_client.start() | ||||
def _build_config(): | |||||
local_conf = conf() | |||||
config = { | |||||
"linkai_app_code": local_conf.get("linkai_app_code"), | |||||
"single_chat_prefix": local_conf.get("single_chat_prefix"), | |||||
"single_chat_reply_prefix": local_conf.get("single_chat_reply_prefix"), | |||||
"single_chat_reply_suffix": local_conf.get("single_chat_reply_suffix"), | |||||
"group_chat_prefix": local_conf.get("group_chat_prefix"), | |||||
"group_chat_reply_prefix": local_conf.get("group_chat_reply_prefix"), | |||||
"group_chat_reply_suffix": local_conf.get("group_chat_reply_suffix"), | |||||
"group_name_white_list": local_conf.get("group_name_white_list"), | |||||
"nick_name_black_list": local_conf.get("nick_name_black_list"), | |||||
"speech_recognition": "Y" if local_conf.get("speech_recognition") else "N", | |||||
"text_to_image": local_conf.get("text_to_image"), | |||||
"image_create_prefix": local_conf.get("image_create_prefix") | |||||
} | |||||
if local_conf.get("always_reply_voice"): | |||||
config["reply_voice_mode"] = "always_reply_voice" | |||||
elif local_conf.get("voice_reply_voice"): | |||||
config["reply_voice_mode"] = "voice_reply_voice" | |||||
if pconf("linkai"): | |||||
config["group_app_map"] = pconf("linkai").get("group_app_map") | |||||
if plugin_config.get("Godcmd"): | |||||
config["admin_password"] = plugin_config.get("Godcmd").get("password") | |||||
return config |
@@ -258,6 +258,8 @@ def load_config(): | |||||
config.load_user_datas() | config.load_user_datas() | ||||
def get_root(): | def get_root(): | ||||
return os.path.dirname(os.path.abspath(__file__)) | return os.path.dirname(os.path.abspath(__file__)) | ||||
@@ -10,6 +10,7 @@ from common import const | |||||
import os | import os | ||||
from .utils import Util | from .utils import Util | ||||
@plugins.register( | @plugins.register( | ||||
name="linkai", | name="linkai", | ||||
desc="A plugin that supports knowledge base and midjourney drawing.", | desc="A plugin that supports knowledge base and midjourney drawing.", | ||||
@@ -32,7 +33,6 @@ class LinkAI(Plugin): | |||||
self.sum_config = self.config.get("summary") | self.sum_config = self.config.get("summary") | ||||
logger.info(f"[LinkAI] inited, config={self.config}") | logger.info(f"[LinkAI] inited, config={self.config}") | ||||
def on_handle_context(self, e_context: EventContext): | def on_handle_context(self, e_context: EventContext): | ||||
""" | """ | ||||
消息处理逻辑 | 消息处理逻辑 | ||||
@@ -42,7 +42,8 @@ class LinkAI(Plugin): | |||||
return | return | ||||
context = e_context['context'] | context = e_context['context'] | ||||
if context.type not in [ContextType.TEXT, ContextType.IMAGE, ContextType.IMAGE_CREATE, ContextType.FILE, ContextType.SHARING]: | |||||
if context.type not in [ContextType.TEXT, ContextType.IMAGE, ContextType.IMAGE_CREATE, ContextType.FILE, | |||||
ContextType.SHARING]: | |||||
# filter content no need solve | # filter content no need solve | ||||
return | return | ||||
@@ -76,7 +77,8 @@ class LinkAI(Plugin): | |||||
if not res: | if not res: | ||||
_set_reply_text("因为神秘力量无法获取文章内容,请稍后再试吧~", e_context, level=ReplyType.TEXT) | _set_reply_text("因为神秘力量无法获取文章内容,请稍后再试吧~", e_context, level=ReplyType.TEXT) | ||||
return | return | ||||
_set_reply_text(res.get("summary") + "\n\n💬 发送 \"开启对话\" 可以开启与文章内容的对话", e_context, level=ReplyType.TEXT) | |||||
_set_reply_text(res.get("summary") + "\n\n💬 发送 \"开启对话\" 可以开启与文章内容的对话", e_context, | |||||
level=ReplyType.TEXT) | |||||
USER_FILE_MAP[_find_user_id(context) + "-sum_id"] = res.get("summary_id") | USER_FILE_MAP[_find_user_id(context) + "-sum_id"] = res.get("summary_id") | ||||
return | return | ||||
@@ -99,7 +101,8 @@ class LinkAI(Plugin): | |||||
_set_reply_text("开启对话失败,请稍后再试吧", e_context) | _set_reply_text("开启对话失败,请稍后再试吧", e_context) | ||||
return | return | ||||
USER_FILE_MAP[_find_user_id(context) + "-file_id"] = res.get("file_id") | USER_FILE_MAP[_find_user_id(context) + "-file_id"] = res.get("file_id") | ||||
_set_reply_text("💡你可以问我关于这篇文章的任何问题,例如:\n\n" + res.get("questions") + "\n\n发送 \"退出对话\" 可以关闭与文章的对话", e_context, level=ReplyType.TEXT) | |||||
_set_reply_text("💡你可以问我关于这篇文章的任何问题,例如:\n\n" + res.get( | |||||
"questions") + "\n\n发送 \"退出对话\" 可以关闭与文章的对话", e_context, level=ReplyType.TEXT) | |||||
return | return | ||||
if context.type == ContextType.TEXT and context.content == "退出对话" and _find_file_id(context): | if context.type == ContextType.TEXT and context.content == "退出对话" and _find_file_id(context): | ||||
@@ -117,12 +120,10 @@ class LinkAI(Plugin): | |||||
e_context.action = EventAction.BREAK_PASS | e_context.action = EventAction.BREAK_PASS | ||||
return | return | ||||
if self._is_chat_task(e_context): | if self._is_chat_task(e_context): | ||||
# 文本对话任务处理 | # 文本对话任务处理 | ||||
self._process_chat_task(e_context) | self._process_chat_task(e_context) | ||||
# 插件管理功能 | # 插件管理功能 | ||||
def _process_admin_cmd(self, e_context: EventContext): | def _process_admin_cmd(self, e_context: EventContext): | ||||
context = e_context['context'] | context = e_context['context'] | ||||
@@ -177,7 +178,9 @@ class LinkAI(Plugin): | |||||
tips_text = "关闭" | tips_text = "关闭" | ||||
is_open = False | is_open = False | ||||
if not self.sum_config: | if not self.sum_config: | ||||
_set_reply_text(f"插件未启用summary功能,请参考以下链添加插件配置\n\nhttps://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/linkai/README.md", e_context, level=ReplyType.INFO) | |||||
_set_reply_text( | |||||
f"插件未启用summary功能,请参考以下链添加插件配置\n\nhttps://github.com/zhayujie/chatgpt-on-wechat/blob/master/plugins/linkai/README.md", | |||||
e_context, level=ReplyType.INFO) | |||||
else: | else: | ||||
self.sum_config["enabled"] = is_open | self.sum_config["enabled"] = is_open | ||||
_set_reply_text(f"文章总结功能{tips_text}", e_context, level=ReplyType.INFO) | _set_reply_text(f"文章总结功能{tips_text}", e_context, level=ReplyType.INFO) | ||||
@@ -254,6 +257,9 @@ class LinkAI(Plugin): | |||||
except Exception as e: | except Exception as e: | ||||
logger.exception(e) | logger.exception(e) | ||||
def reload(self): | |||||
self.config = super().load_config() | |||||
def _send_info(e_context: EventContext, content: str): | def _send_info(e_context: EventContext, content: str): | ||||
reply = Reply(ReplyType.TEXT, content) | reply = Reply(ReplyType.TEXT, content) | ||||
@@ -273,15 +279,19 @@ def _set_reply_text(content: str, e_context: EventContext, level: ReplyType = Re | |||||
e_context["reply"] = reply | e_context["reply"] = reply | ||||
e_context.action = EventAction.BREAK_PASS | e_context.action = EventAction.BREAK_PASS | ||||
def _get_trigger_prefix(): | def _get_trigger_prefix(): | ||||
return conf().get("plugin_trigger_prefix", "$") | return conf().get("plugin_trigger_prefix", "$") | ||||
def _find_sum_id(context): | def _find_sum_id(context): | ||||
return USER_FILE_MAP.get(_find_user_id(context) + "-sum_id") | return USER_FILE_MAP.get(_find_user_id(context) + "-sum_id") | ||||
def _find_file_id(context): | def _find_file_id(context): | ||||
user_id = _find_user_id(context) | user_id = _find_user_id(context) | ||||
if user_id: | if user_id: | ||||
return USER_FILE_MAP.get(user_id + "-file_id") | return USER_FILE_MAP.get(user_id + "-file_id") | ||||
USER_FILE_MAP = ExpiredDict(conf().get("expires_in_seconds") or 60 * 30) | USER_FILE_MAP = ExpiredDict(conf().get("expires_in_seconds") or 60 * 30) |