mirror of
https://github.com/zhayujie/chatgpt-on-wechat.git
synced 2026-06-02 00:57:41 +08:00
Merge branch 'zhayujie:master' into master
This commit is contained in:
@@ -75,6 +75,7 @@ class ChatChannel(Channel):
|
|||||||
):
|
):
|
||||||
session_id = group_id
|
session_id = group_id
|
||||||
else:
|
else:
|
||||||
|
logger.debug(f"No need reply, groupName not in whitelist, group_name={group_name}")
|
||||||
return None
|
return None
|
||||||
context["session_id"] = session_id
|
context["session_id"] = session_id
|
||||||
context["receiver"] = group_id
|
context["receiver"] = group_id
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ def qrCallback(uuid, status, qrcode):
|
|||||||
print(qr_api4)
|
print(qr_api4)
|
||||||
print(qr_api2)
|
print(qr_api2)
|
||||||
print(qr_api1)
|
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 = qrcode.QRCode(border=1)
|
||||||
qr.add_data(url)
|
qr.add_data(url)
|
||||||
qr.make(fit=True)
|
qr.make(fit=True)
|
||||||
|
|||||||
@@ -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, available_setting
|
||||||
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,64 @@ 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 config.keys():
|
||||||
if config.get(key) is not None:
|
if key in available_setting and 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")
|
if config.get("admin_password") and plugin_config["Godcmd"]:
|
||||||
# PluginManager().instances["Godcmd"].reload()
|
plugin_config["Godcmd"]["password"] = config.get("admin_password")
|
||||||
# if config.get("group_app_map") and pconf("linkai"):
|
PluginManager().instances["GODCMD"].reload()
|
||||||
# local_group_map = {}
|
|
||||||
# for mapping in config.get("group_app_map"):
|
if config.get("group_app_map") and pconf("linkai"):
|
||||||
# local_group_map[mapping.get("group_name")] = mapping.get("app_code")
|
local_group_map = {}
|
||||||
# pconf("linkai")["group_app_map"] = local_group_map
|
for mapping in config.get("group_app_map"):
|
||||||
# PluginManager().instances["linkai"].reload()
|
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
|
||||||
|
|||||||
@@ -265,6 +265,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)
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ broadscope_bailian
|
|||||||
# google
|
# google
|
||||||
google-generativeai
|
google-generativeai
|
||||||
|
|
||||||
# linkai
|
|
||||||
linkai>=0.0.3.5
|
|
||||||
|
|
||||||
# dingtalk
|
# dingtalk
|
||||||
dingtalk_stream
|
dingtalk_stream
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ requests>=2.28.2
|
|||||||
chardet>=5.1.0
|
chardet>=5.1.0
|
||||||
Pillow
|
Pillow
|
||||||
pre-commit
|
pre-commit
|
||||||
web.py
|
web.py
|
||||||
|
linkai>=0.0.3.7
|
||||||
|
|||||||
Reference in New Issue
Block a user