@@ -75,6 +75,7 @@ class ChatChannel(Channel): | |||
): | |||
session_id = group_id | |||
else: | |||
logger.debug(f"No need reply, groupName not in whitelist, group_name={group_name}") | |||
return None | |||
context["session_id"] = session_id | |||
context["receiver"] = group_id | |||
@@ -32,13 +32,13 @@ class DingTalkMessage(ChatMessage): | |||
# 钉钉支持直接识别语音,所以此处将直接提取文字,当文字处理 | |||
self.content = event.extensions['content']['recognition'].strip() | |||
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.other_user_nickname = event.conversation_title | |||
user_id = event.sender_id | |||
nickname =event.sender_nick | |||
@@ -96,7 +96,7 @@ def qrCallback(uuid, status, qrcode): | |||
print(qr_api4) | |||
print(qr_api2) | |||
print(qr_api1) | |||
_send_qr_code([qr_api1, qr_api2, qr_api3, qr_api4]) | |||
_send_qr_code([qr_api3, qr_api4, qr_api2, qr_api1]) | |||
qr = qrcode.QRCode(border=1) | |||
qr.add_data(url) | |||
qr.make(fit=True) | |||
@@ -2,12 +2,13 @@ from bridge.context import Context, ContextType | |||
from bridge.reply import Reply, ReplyType | |||
from common.log import logger | |||
from linkai import LinkAIClient, PushMsg | |||
from config import conf, pconf, plugin_config | |||
from config import conf, pconf, plugin_config, available_setting | |||
from plugins import PluginManager | |||
chat_client: LinkAIClient | |||
class ChatClient(LinkAIClient): | |||
def __init__(self, api_key, host, channel): | |||
super().__init__(api_key, host) | |||
@@ -27,29 +28,64 @@ class ChatClient(LinkAIClient): | |||
def on_config(self, config: dict): | |||
if not self.client_id: | |||
return | |||
logger.info(f"从控制台加载配置: {config}") | |||
logger.info(f"[LinkAI] 从客户端管理加载远程配置: {config}") | |||
if config.get("enabled") != "Y": | |||
return | |||
local_config = conf() | |||
for key in local_config.keys(): | |||
if config.get(key) is not None: | |||
for key in config.keys(): | |||
if key in available_setting and config.get(key) is not None: | |||
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 | |||
elif config.get("reply_voice_mode") == "always_reply_voice": | |||
elif reply_voice_mode == "always_reply_voice": | |||
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): | |||
global chat_client | |||
chat_client = ChatClient(api_key=conf().get("linkai_api_key"), | |||
host="link-ai.chat", channel=channel) | |||
chat_client.config = _build_config() | |||
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 |
@@ -265,6 +265,8 @@ def load_config(): | |||
config.load_user_datas() | |||
def get_root(): | |||
return os.path.dirname(os.path.abspath(__file__)) | |||
@@ -10,6 +10,7 @@ from common import const | |||
import os | |||
from .utils import Util | |||
@plugins.register( | |||
name="linkai", | |||
desc="A plugin that supports knowledge base and midjourney drawing.", | |||
@@ -32,7 +33,6 @@ class LinkAI(Plugin): | |||
self.sum_config = self.config.get("summary") | |||
logger.info(f"[LinkAI] inited, config={self.config}") | |||
def on_handle_context(self, e_context: EventContext): | |||
""" | |||
消息处理逻辑 | |||
@@ -42,7 +42,8 @@ class LinkAI(Plugin): | |||
return | |||
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 | |||
return | |||
@@ -76,7 +77,8 @@ class LinkAI(Plugin): | |||
if not res: | |||
_set_reply_text("因为神秘力量无法获取文章内容,请稍后再试吧~", e_context, level=ReplyType.TEXT) | |||
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") | |||
return | |||
@@ -99,7 +101,8 @@ class LinkAI(Plugin): | |||
_set_reply_text("开启对话失败,请稍后再试吧", e_context) | |||
return | |||
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 | |||
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 | |||
return | |||
if self._is_chat_task(e_context): | |||
# 文本对话任务处理 | |||
self._process_chat_task(e_context) | |||
# 插件管理功能 | |||
def _process_admin_cmd(self, e_context: EventContext): | |||
context = e_context['context'] | |||
@@ -177,7 +178,9 @@ class LinkAI(Plugin): | |||
tips_text = "关闭" | |||
is_open = False | |||
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: | |||
self.sum_config["enabled"] = is_open | |||
_set_reply_text(f"文章总结功能{tips_text}", e_context, level=ReplyType.INFO) | |||
@@ -254,6 +257,9 @@ class LinkAI(Plugin): | |||
except Exception as e: | |||
logger.exception(e) | |||
def reload(self): | |||
self.config = super().load_config() | |||
def _send_info(e_context: EventContext, content: str): | |||
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.action = EventAction.BREAK_PASS | |||
def _get_trigger_prefix(): | |||
return conf().get("plugin_trigger_prefix", "$") | |||
def _find_sum_id(context): | |||
return USER_FILE_MAP.get(_find_user_id(context) + "-sum_id") | |||
def _find_file_id(context): | |||
user_id = _find_user_id(context) | |||
if user_id: | |||
return USER_FILE_MAP.get(user_id + "-file_id") | |||
USER_FILE_MAP = ExpiredDict(conf().get("expires_in_seconds") or 60 * 30) |
@@ -35,9 +35,6 @@ broadscope_bailian | |||
google-generativeai | |||
# linkai | |||
linkai>=0.0.3.5 | |||
# dingtalk | |||
dingtalk_stream | |||
@@ -6,4 +6,5 @@ requests>=2.28.2 | |||
chardet>=5.1.0 | |||
Pillow | |||
pre-commit | |||
web.py | |||
web.py | |||
linkai>=0.0.3.7 |