nonebot-plugin-aigf 0.1.5__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/PKG-INFO +1 -1
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/__init__.py +1 -4
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/memory.py +12 -6
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/session.py +39 -35
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/PKG-INFO +1 -1
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/setup.py +1 -1
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/README.md +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/client.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/config.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/image_manager.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/mem.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/meme_manager.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/presets.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/vlm.py +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/SOURCES.txt +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/dependency_links.txt +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/requires.txt +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/top_level.txt +0 -0
- {nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/setup.cfg +0 -0
|
@@ -18,7 +18,6 @@ import asyncio
|
|
|
18
18
|
import base64
|
|
19
19
|
from dataclasses import dataclass, field
|
|
20
20
|
from datetime import datetime
|
|
21
|
-
import json
|
|
22
21
|
import re
|
|
23
22
|
import ssl
|
|
24
23
|
import traceback
|
|
@@ -30,7 +29,6 @@ from nonebot.adapters import Message
|
|
|
30
29
|
from nonebot.adapters.onebot.v11 import (
|
|
31
30
|
Bot, Event, GroupMessageEvent, MessageSegment, Message as OneBotMessage, PrivateMessageEvent,
|
|
32
31
|
)
|
|
33
|
-
from nonebot.matcher import Matcher
|
|
34
32
|
from nonebot.params import CommandArg
|
|
35
33
|
from nonebot.permission import SUPERUSER
|
|
36
34
|
from nonebot.plugin import PluginMetadata
|
|
@@ -43,14 +41,13 @@ from .config import Config, plugin_config
|
|
|
43
41
|
from .image_manager import IMAGE_CACHE_DIR, image_manager
|
|
44
42
|
from .meme_manager import AtMessage, MemeMessage, TextMessage, meme_manager
|
|
45
43
|
from .mem import Message as MMessage
|
|
46
|
-
from .presets import PRESETS, load_presets
|
|
44
|
+
from .presets import PRESETS, load_presets
|
|
47
45
|
from .session import Session
|
|
48
46
|
|
|
49
47
|
__plugin_meta__ = PluginMetadata(
|
|
50
48
|
name="AI-group-friend", description="群聊特化LLM聊天机器人,具有记忆和表情包功能",
|
|
51
49
|
usage="群聊特化LLM聊天机器人", type="application",
|
|
52
50
|
config=Config, supported_adapters={"~onebot.v11"},
|
|
53
|
-
homepage="https://github.com/Funny1Potato/nonebot-plugin-aigf",
|
|
54
51
|
extra={"author": "Funny1Potato"},
|
|
55
52
|
)
|
|
56
53
|
|
|
@@ -20,10 +20,13 @@ import nonebot_plugin_localstore as store
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class MemoryManager:
|
|
23
|
-
def __init__(self):
|
|
24
|
-
self.
|
|
25
|
-
|
|
23
|
+
def __init__(self, group_id: str = "default"):
|
|
24
|
+
self.group_id = group_id
|
|
25
|
+
# 短期/长期记忆按群隔离
|
|
26
|
+
self.data_dir = store.get_plugin_data_dir() / "memory" / group_id
|
|
26
27
|
self.data_dir.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
# 群友信息全局共享
|
|
29
|
+
self.friends_dir = store.get_plugin_data_dir() / "memory" / "friends"
|
|
27
30
|
self.friends_dir.mkdir(parents=True, exist_ok=True)
|
|
28
31
|
|
|
29
32
|
async def load_short_term(self) -> list[str]:
|
|
@@ -75,11 +78,11 @@ class MemoryManager:
|
|
|
75
78
|
await f.write(json.dumps(data, ensure_ascii=False, indent=2))
|
|
76
79
|
|
|
77
80
|
async def load_friends_batch(self, users: list[dict[str, str]]) -> dict[str, dict]:
|
|
78
|
-
"""
|
|
81
|
+
"""批量加载当前群的群友信息"""
|
|
79
82
|
result = {}
|
|
80
83
|
for user in users:
|
|
81
84
|
data = await self.load_friend(user["id"])
|
|
82
|
-
if data:
|
|
85
|
+
if data and self.group_id in data.get("groups", []):
|
|
83
86
|
result[user["id"]] = data
|
|
84
87
|
return result
|
|
85
88
|
|
|
@@ -133,7 +136,10 @@ class MemoryManager:
|
|
|
133
136
|
for key, ops in friends_ops.items():
|
|
134
137
|
# 如果 key 不是纯数字(QQ号),尝试从反查表中找到对应的 QQ 号
|
|
135
138
|
user_id = key if key.isdigit() else nickname_to_id.get(key, key)
|
|
136
|
-
friend = await self.load_friend(user_id) or {"id": user_id, "name": key if not key.isdigit() else key, "info": []}
|
|
139
|
+
friend = await self.load_friend(user_id) or {"id": user_id, "name": key if not key.isdigit() else key, "info": [], "groups": []}
|
|
140
|
+
# 确保当前群在 groups 列表中
|
|
141
|
+
if self.group_id not in friend.get("groups", []):
|
|
142
|
+
friend.setdefault("groups", []).append(self.group_id)
|
|
137
143
|
info = friend.get("info", [])
|
|
138
144
|
for idx in sorted([int(i) for i in ops.get("delete", [])], reverse=True):
|
|
139
145
|
if 0 <= idx < len(info):
|
|
@@ -17,9 +17,6 @@
|
|
|
17
17
|
import base64
|
|
18
18
|
import json
|
|
19
19
|
import re
|
|
20
|
-
from dataclasses import asdict
|
|
21
|
-
from datetime import datetime
|
|
22
|
-
from pathlib import Path
|
|
23
20
|
|
|
24
21
|
import anyio
|
|
25
22
|
from nonebot import logger
|
|
@@ -29,7 +26,7 @@ from .config import plugin_config
|
|
|
29
26
|
from .meme_manager import AtMessage, MemeMessage, TextMessage, meme_manager
|
|
30
27
|
from .memory import MemoryManager
|
|
31
28
|
from .mem import Message
|
|
32
|
-
from .presets import PRESETS
|
|
29
|
+
from .presets import PRESETS
|
|
33
30
|
|
|
34
31
|
|
|
35
32
|
class Session:
|
|
@@ -37,7 +34,7 @@ class Session:
|
|
|
37
34
|
self.id = id
|
|
38
35
|
self.name = name
|
|
39
36
|
self.role = role
|
|
40
|
-
self.memory = MemoryManager()
|
|
37
|
+
self.memory = MemoryManager(group_id=id)
|
|
41
38
|
self.recent_messages: list[Message] = []
|
|
42
39
|
|
|
43
40
|
async def load_preset(self, preset_name: str) -> bool:
|
|
@@ -65,9 +62,6 @@ class Session:
|
|
|
65
62
|
active_users = MemoryManager.get_active_users(messages_chunk)
|
|
66
63
|
friends = await self.memory.load_friends_batch(active_users)
|
|
67
64
|
|
|
68
|
-
# 构建 id→昵称映射
|
|
69
|
-
id_name_map = {u["id"]: u["name"] for u in active_users}
|
|
70
|
-
|
|
71
65
|
# LLM 模式:读取缓存图片的 base64
|
|
72
66
|
sticker_images: list[str] = []
|
|
73
67
|
if plugin_config.aigf_image_mode == "llm" and cached_stickers:
|
|
@@ -167,11 +161,18 @@ class Session:
|
|
|
167
161
|
|
|
168
162
|
# 群友信息(按 QQ 号存储,显示时带昵称)
|
|
169
163
|
friends_str = ""
|
|
164
|
+
# 已有记忆的群友
|
|
170
165
|
for uid, data in friends.items():
|
|
171
166
|
display_name = data.get("name", uid)
|
|
172
167
|
info_list = data.get("info", [])
|
|
173
168
|
info_str = "、".join(info_list) if info_list else "暂无信息"
|
|
174
169
|
friends_str += f"- {display_name}(QQ:{uid}):{info_str}\n"
|
|
170
|
+
# 当前聊天中但还没有记忆的群友
|
|
171
|
+
active_users = MemoryManager.get_active_users(messages_chunk)
|
|
172
|
+
existing_ids = set(friends.keys())
|
|
173
|
+
new_users = [u for u in active_users if u["id"] not in existing_ids]
|
|
174
|
+
for u in new_users:
|
|
175
|
+
friends_str += f"- {u['name']}(QQ:{u['id']}):暂无信息\n"
|
|
175
176
|
friends_str = friends_str or "无"
|
|
176
177
|
|
|
177
178
|
# 最近 10 条消息
|
|
@@ -188,10 +189,8 @@ class Session:
|
|
|
188
189
|
if meme_list:
|
|
189
190
|
meme_section = f"""
|
|
190
191
|
|
|
191
|
-
##
|
|
192
|
+
## 可用的表情包(用于发送)
|
|
192
193
|
{meme_list}
|
|
193
|
-
|
|
194
|
-
如果想发表情包,在 reply 中加入 {{"type": "meme", "id": "表情包id"}}。
|
|
195
194
|
"""
|
|
196
195
|
|
|
197
196
|
# 缓存中的表情包(可供收藏)
|
|
@@ -232,27 +231,26 @@ class Session:
|
|
|
232
231
|
### 短期记忆
|
|
233
232
|
{short_term_str}
|
|
234
233
|
这是你对近期对话的记忆。你应该积极管理:
|
|
235
|
-
-
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
- 内容可以详细,不必精简
|
|
234
|
+
- 添加:新的对话内容、临时上下文、有趣的梗
|
|
235
|
+
- 修改:对话有新进展时,更新已有条目(用 index 指定要改哪条)
|
|
236
|
+
- 删除:已结束的话题、已解决的问题、不再 relevant 的内容(用 index 指定要删哪条)
|
|
239
237
|
|
|
240
238
|
### 长期记忆
|
|
241
239
|
{long_term_str}
|
|
242
240
|
这是你记住的重要信息。你应该积极管理:
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
|
|
247
|
-
不要记:临时性的对话内容、无关紧要的闲聊、可以通过常识推断的信息。
|
|
241
|
+
- 添加:新的事件、知识、规则
|
|
242
|
+
- 修改:发现旧信息不准确或需要更新时(用 index 指定要改哪条)
|
|
243
|
+
- 删除:被证伪、过时、不再适用的信息(用 index 指定要删哪条)
|
|
244
|
+
不要记:临时性的对话内容、无关紧要的闲聊。
|
|
248
245
|
|
|
249
246
|
### 相关群友信息
|
|
250
247
|
{friends_str}
|
|
251
248
|
这是你对群友的了解。你应该积极管理:
|
|
252
|
-
-
|
|
253
|
-
-
|
|
254
|
-
-
|
|
255
|
-
-
|
|
249
|
+
- 添加:群友透露的新信息(职业、爱好、性格等)
|
|
250
|
+
- 修改:发现之前记错了,或信息有变化时(用 index 指定要改哪条)
|
|
251
|
+
- 删除:不再准确的信息(用 index 指定要删哪条)
|
|
252
|
+
- update_name:群友改名时更新昵称
|
|
253
|
+
注意:index 从 0 开始计数,对应上面列表中的第几条。修改和删除时必须指定正确的 index。
|
|
256
254
|
|
|
257
255
|
## 最近的聊天记录
|
|
258
256
|
{recent_str}
|
|
@@ -278,32 +276,38 @@ class Session:
|
|
|
278
276
|
],
|
|
279
277
|
"memory": {{
|
|
280
278
|
"short_term": {{
|
|
281
|
-
"add": ["
|
|
282
|
-
"modify": [{{"index": 0, "content": "
|
|
279
|
+
"add": ["小明说他周末要去爬山"],
|
|
280
|
+
"modify": [{{"index": 0, "content": "小明说周末要去爬山,小红也想去"}}],
|
|
283
281
|
"delete": [2]
|
|
284
282
|
}},
|
|
285
283
|
"long_term": {{
|
|
286
|
-
"add": ["
|
|
287
|
-
"modify": [{{"index": 0, "content": "
|
|
288
|
-
"delete": [
|
|
284
|
+
"add": ["群里组织过一次聚餐"],
|
|
285
|
+
"modify": [{{"index": 0, "content": "群规更新:不允许发广告和链接"}}],
|
|
286
|
+
"delete": [1]
|
|
289
287
|
}},
|
|
290
288
|
"friends": {{
|
|
291
|
-
"
|
|
292
|
-
"add": ["
|
|
293
|
-
"modify": [{{"index": 0, "content": "
|
|
289
|
+
"123456": {{
|
|
290
|
+
"add": ["职业:程序员", "爱好:打游戏"],
|
|
291
|
+
"modify": [{{"index": 0, "content": "职业:前端工程师"}}],
|
|
294
292
|
"delete": [1],
|
|
295
|
-
"update_name": "
|
|
293
|
+
"update_name": "新昵称"
|
|
296
294
|
}}
|
|
297
|
-
}}
|
|
298
|
-
"save_meme": [{{"id": "表情包id", "description": "你写的简短描述", "keywords": ["关键词1", "关键词2"]}}](仅当上面列出了可收藏的表情包时才需要,可收藏多个)
|
|
295
|
+
}}
|
|
299
296
|
}}
|
|
300
297
|
}}
|
|
301
298
|
```
|
|
302
299
|
|
|
300
|
+
示例说明:
|
|
301
|
+
- "modify" 中的 "index" 是要修改的条目在列表中的位置(从 0 开始)
|
|
302
|
+
- "delete" 中的数字是要删除的条目的 index
|
|
303
|
+
- 修改和删除前,请先确认列表中对应 index 的内容是否正确
|
|
304
|
+
- 如果不需要修改或删除,可以省略对应字段
|
|
305
|
+
|
|
303
306
|
注意:
|
|
304
307
|
- reply 中的元素也可以是纯字符串,等同于 {{"type": "text", "content": "..."}}
|
|
305
308
|
- memory 中的所有字段都是可选的,不需要的操作可以省略
|
|
306
309
|
- at 的 name 必须是上面列出的群友昵称
|
|
310
|
+
- 当群友的话题与你无关、你不感兴趣、或没有值得补充的内容时,不需要回复
|
|
307
311
|
- 如果不想回复,reply 设为空数组 []
|
|
308
312
|
- 不要编造表情包 id,只能使用上面列出的
|
|
309
313
|
- friends 的 key 必须是 QQ 号(数字),绝对不要用昵称做 key
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setuptools.setup(
|
|
7
7
|
name="nonebot-plugin-aigf", # 用自己的名替换其中的YOUR_USERNAME_
|
|
8
|
-
version="0.
|
|
8
|
+
version="0.2.0", #包版本号,便于维护版本
|
|
9
9
|
author="Funny1Potato", #作者,可以写自己的姓名
|
|
10
10
|
author_email="funny_potato@126.com", #作者联系方式,可写自己的邮箱地址
|
|
11
11
|
description="基于nonebot-plugin-nyaturingtest重构的群聊特化 LLM 聊天机器人,具有 LLM 驱动的记忆系统和表情包功能。",#包的简述
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf/image_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/requires.txt
RENAMED
|
File without changes
|
{nonebot-plugin-aigf-0.1.5 → nonebot-plugin-aigf-0.2.0}/nonebot_plugin_aigf.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|