Skip to content

Commit 04ef090

Browse files
committed
Summary and MJ support can be configured through LinkAI platform app plugins.
1 parent 6f665cf commit 04ef090

File tree

5 files changed

+100
-21
lines changed

5 files changed

+100
-21
lines changed

plugins/linkai/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898

9999
如果不想创建 `plugins/linkai/config.json` 配置,可以直接通过 `$linkai sum open` 指令开启该功能。
100100

101+
也可以通过私聊(全局 `config.json` 中的 `linkai_app_code`)或者群聊绑定(通过`group_app_map`参数配置)的应用来开启该功能:在LinkAI平台 [应用配置](https://link-ai.tech/console/factory) 里添加并开启**内容总结**插件。
102+
101103
#### 使用
102104

103105
功能开启后,向机器人发送 **文件****分享链接卡片****图片** 即可生成摘要,进一步可以与文件或链接的内容进行多轮对话。如果需要关闭某种类型的内容总结,设置 `summary`配置中的type字段即可。

plugins/linkai/linkai.py

+48-13
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from common import const
1010
import os
1111
from .utils import Util
12-
from config import plugin_config
12+
from config import plugin_config, conf
1313

1414

1515
@plugins.register(
@@ -28,7 +28,7 @@ def __init__(self):
2828
# 未加载到配置,使用模板中的配置
2929
self.config = self._load_config_template()
3030
if self.config:
31-
self.mj_bot = MJBot(self.config.get("midjourney"))
31+
self.mj_bot = MJBot(self.config.get("midjourney"), self._fetch_group_app_code)
3232
self.sum_config = {}
3333
if self.config:
3434
self.sum_config = self.config.get("summary")
@@ -56,7 +56,8 @@ def on_handle_context(self, e_context: EventContext):
5656
return
5757
if context.type != ContextType.IMAGE:
5858
_send_info(e_context, "正在为你加速生成摘要,请稍后")
59-
res = LinkSummary().summary_file(file_path)
59+
app_code = self._fetch_app_code(context)
60+
res = LinkSummary().summary_file(file_path, app_code)
6061
if not res:
6162
if context.type != ContextType.IMAGE:
6263
_set_reply_text("因为神秘力量无法获取内容,请稍后再试吧", e_context, level=ReplyType.TEXT)
@@ -74,7 +75,8 @@ def on_handle_context(self, e_context: EventContext):
7475
if not LinkSummary().check_url(context.content):
7576
return
7677
_send_info(e_context, "正在为你加速生成摘要,请稍后")
77-
res = LinkSummary().summary_url(context.content)
78+
app_code = self._fetch_app_code(context)
79+
res = LinkSummary().summary_url(context.content, app_code)
7880
if not res:
7981
_set_reply_text("因为神秘力量无法获取文章内容,请稍后再试吧~", e_context, level=ReplyType.TEXT)
8082
return
@@ -169,7 +171,7 @@ def _process_admin_cmd(self, e_context: EventContext):
169171
return
170172

171173
if len(cmd) == 3 and cmd[1] == "sum" and (cmd[2] == "open" or cmd[2] == "close"):
172-
# 知识库开关指令
174+
# 总结对话开关指令
173175
if not Util.is_admin(e_context):
174176
_set_reply_text("需要管理员权限执行", e_context, level=ReplyType.ERROR)
175177
return
@@ -192,14 +194,34 @@ def _process_admin_cmd(self, e_context: EventContext):
192194
return
193195

194196
def _is_summary_open(self, context) -> bool:
195-
if not self.sum_config or not self.sum_config.get("enabled"):
196-
return False
197-
if context.kwargs.get("isgroup") and not self.sum_config.get("group_enabled"):
198-
return False
199-
support_type = self.sum_config.get("type") or ["FILE", "SHARING"]
200-
if context.type.name not in support_type and context.type.name != "TEXT":
201-
return False
202-
return True
197+
# 获取远程应用插件状态
198+
remote_enabled = False
199+
if context.kwargs.get("isgroup"):
200+
# 群聊场景只查询群对应的app_code
201+
group_name = context.get("msg").from_user_nickname
202+
app_code = self._fetch_group_app_code(group_name)
203+
if app_code:
204+
remote_enabled = Util.fetch_app_plugin(app_code, "内容总结")
205+
else:
206+
# 非群聊场景使用全局app_code
207+
app_code = conf().get("linkai_app_code")
208+
if app_code:
209+
remote_enabled = Util.fetch_app_plugin(app_code, "内容总结")
210+
211+
# 基础条件:总开关开启且消息类型符合要求
212+
base_enabled = (
213+
self.sum_config
214+
and self.sum_config.get("enabled")
215+
and (context.type.name in (
216+
self.sum_config.get("type") or ["FILE", "SHARING"]) or context.type.name == "TEXT")
217+
)
218+
219+
# 群聊:需要满足(总开关和群开关)或远程插件开启
220+
if context.kwargs.get("isgroup"):
221+
return (base_enabled and self.sum_config.get("group_enabled")) or remote_enabled
222+
223+
# 非群聊:只需要满足总开关或远程插件开启
224+
return base_enabled or remote_enabled
203225

204226
# LinkAI 对话任务处理
205227
def _is_chat_task(self, e_context: EventContext):
@@ -230,6 +252,19 @@ def _fetch_group_app_code(self, group_name: str) -> str:
230252
app_code = group_mapping.get(group_name) or group_mapping.get("ALL_GROUP")
231253
return app_code
232254

255+
def _fetch_app_code(self, context) -> str:
256+
"""
257+
根据主配置或者群聊名称获取对应的应用code,优先获取群聊配置的应用code
258+
:param context: 上下文
259+
:return: 应用code
260+
"""
261+
app_code = conf().get("linkai_app_code")
262+
if context.kwargs.get("isgroup"):
263+
# 群聊场景只查询群对应的app_code
264+
group_name = context.get("msg").from_user_nickname
265+
app_code = self._fetch_group_app_code(group_name)
266+
return app_code
267+
233268
def get_help_text(self, verbose=False, **kwargs):
234269
trigger_prefix = _get_trigger_prefix()
235270
help_text = "用于集成 LinkAI 提供的知识库、Midjourney绘画、文档总结、联网搜索等能力。\n\n"

plugins/linkai/midjourney.py

+25-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from plugins import EventContext, EventAction
1111
from .utils import Util
1212

13+
1314
INVALID_REQUEST = 410
1415
NOT_FOUND_ORIGIN_IMAGE = 461
1516
NOT_FOUND_TASK = 462
@@ -67,10 +68,11 @@ def __str__(self):
6768

6869
# midjourney bot
6970
class MJBot:
70-
def __init__(self, config):
71+
def __init__(self, config, fetch_group_app_code):
7172
self.base_url = conf().get("linkai_api_base", "https://api.link-ai.tech") + "/v1/img/midjourney"
7273
self.headers = {"Authorization": "Bearer " + conf().get("linkai_api_key")}
7374
self.config = config
75+
self.fetch_group_app_code = fetch_group_app_code
7476
self.tasks = {}
7577
self.temp_dict = {}
7678
self.tasks_lock = threading.Lock()
@@ -98,7 +100,7 @@ def judge_mj_task_type(self, e_context: EventContext):
98100
return TaskType.VARIATION
99101
elif cmd_list[0].lower() == f"{trigger_prefix}mjr":
100102
return TaskType.RESET
101-
elif context.type == ContextType.IMAGE_CREATE and self.config.get("use_image_create_prefix") and self.config.get("enabled"):
103+
elif context.type == ContextType.IMAGE_CREATE and self.config.get("use_image_create_prefix") and self._is_mj_open(context):
102104
return TaskType.GENERATE
103105

104106
def process_mj_task(self, mj_type: TaskType, e_context: EventContext):
@@ -129,8 +131,8 @@ def process_mj_task(self, mj_type: TaskType, e_context: EventContext):
129131
self._set_reply_text(f"Midjourney绘画已{tips_text}", e_context, level=ReplyType.INFO)
130132
return
131133

132-
if not self.config.get("enabled"):
133-
logger.warn("Midjourney绘画未开启,请查看 plugins/linkai/config.json 中的配置")
134+
if not self._is_mj_open(context):
135+
logger.warn("Midjourney绘画未开启,请查看 plugins/linkai/config.json 中的配置,或者在LinkAI平台 应用中添加/打开”MJ“插件")
134136
self._set_reply_text(f"Midjourney绘画未开启", e_context, level=ReplyType.INFO)
135137
return
136138

@@ -409,6 +411,25 @@ def find_tasks_by_user_id(self, user_id) -> list:
409411
result.append(task)
410412
return result
411413

414+
def _is_mj_open(self, context) -> bool:
415+
# 获取远程应用插件状态
416+
remote_enabled = False
417+
if context.kwargs.get("isgroup"):
418+
# 群聊场景只查询群对应的app_code
419+
group_name = context.get("msg").from_user_nickname
420+
app_code = self.fetch_group_app_code(group_name)
421+
if app_code:
422+
remote_enabled = Util.fetch_app_plugin(app_code, "Midjourney")
423+
else:
424+
# 非群聊场景使用全局app_code
425+
app_code = conf().get("linkai_app_code")
426+
if app_code:
427+
remote_enabled = Util.fetch_app_plugin(app_code, "Midjourney")
428+
429+
# 本地配置
430+
base_enabled = self.config.get("enabled")
431+
432+
return base_enabled or remote_enabled
412433

413434
def _send(channel, reply: Reply, context, retry_cnt=0):
414435
try:

plugins/linkai/summary.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ class LinkSummary:
99
def __init__(self):
1010
pass
1111

12-
def summary_file(self, file_path: str):
12+
def summary_file(self, file_path: str, app_code: str):
1313
file_body = {
1414
"file": open(file_path, "rb"),
1515
"name": file_path.split("/")[-1],
16+
"app_code": app_code
1617
}
1718
url = self.base_url() + "/v1/summary/file"
1819
res = requests.post(url, headers=self.headers(), files=file_body, timeout=(5, 300))
1920
return self._parse_summary_res(res)
2021

21-
def summary_url(self, url: str):
22+
def summary_url(self, url: str, app_code: str):
2223
url = html.unescape(url)
2324
body = {
24-
"url": url
25+
"url": url,
26+
"app_code": app_code
2527
}
2628
res = requests.post(url=self.base_url() + "/v1/summary/url", headers=self.headers(), json=body, timeout=(5, 180))
2729
return self._parse_summary_res(res)

plugins/linkai/utils.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import requests
2+
from common.log import logger
13
from config import global_config
24
from bridge.reply import Reply, ReplyType
35
from plugins.event import EventContext, EventAction
4-
6+
from config import conf
57

68
class Util:
79
@staticmethod
@@ -26,3 +28,20 @@ def set_reply_text(content: str, e_context: EventContext, level: ReplyType = Rep
2628
reply = Reply(level, content)
2729
e_context["reply"] = reply
2830
e_context.action = EventAction.BREAK_PASS
31+
32+
@staticmethod
33+
def fetch_app_plugin(app_code: str, plugin_name: str) -> bool:
34+
headers = {"Authorization": "Bearer " + conf().get("linkai_api_key")}
35+
# do http request
36+
base_url = conf().get("linkai_api_base", "https://api.link-ai.tech")
37+
params = {"app_code": app_code}
38+
res = requests.get(url=base_url + "/v1/app/info", params=params, headers=headers, timeout=(5, 10))
39+
if res.status_code == 200:
40+
plugins = res.json().get("data").get("plugins")
41+
for plugin in plugins:
42+
if plugin.get("name") and plugin.get("name") == plugin_name:
43+
return True
44+
return False
45+
else:
46+
logger.warning(f"[LinkAI] find app info exception, res={res}")
47+
return False

0 commit comments

Comments
 (0)