Skip to content

Commit

Permalink
Merge branch 'master' into upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
ZoruaFox committed Dec 30, 2024
2 parents 5b3717e + 791c34a commit 6d84db1
Show file tree
Hide file tree
Showing 48 changed files with 1,529 additions and 149 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ assets/bots_list.json
assets/discord_slash_list.json
assets/modules_list.json
assets/schedulers_list.json
modules/yunhei/admins.json

12 changes: 1 addition & 11 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,4 @@ repos:
- repo: https://github.com/pre-commit/mirrors-autopep8
rev: "v2.0.4"
hooks:
- id: autopep8

- repo: local
hooks:
- id: auto-generate-config
name: Auto-generate config
entry: poetry run python ./core/scripts/config_generate.py
language: python
pass_filenames: false


- id: autopep8
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 说明
本项目为Teahouse/akari-bot的分支项目,对比原始项目存在对TOS、模块i18n等部分的自定义,并包括了一个研究中的原神模块。

原项目说明见下

<div align="center">
<img width="512" src="./assets/character_marked.png" alt="logo">

Expand Down
Binary file added assets/Hack-Regular.ttf
Binary file not shown.
Binary file added assets/LXGWWenKai-Bold.ttf
Binary file not shown.
Binary file added assets/LXGWWenKai-Light.ttf
Binary file not shown.
Binary file added assets/LXGWWenKai-Regular.ttf
Binary file not shown.
Binary file added assets/LXGWWenKaiMono-Bold.ttf
Binary file not shown.
Binary file added assets/LXGWWenKaiMono-Light.ttf
Binary file not shown.
Binary file added assets/LXGWWenKaiMono-Regular.ttf
Binary file not shown.
2 changes: 1 addition & 1 deletion bots/aiogram/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ async def send_message(

async def check_native_permission(self):
if not self.session.message:
chat = await bot.get_chat(self.session.target)
chat = await dp.bot.get_chat(self.session.target)
else:
chat = self.session.message.chat
if chat.type == "private":
Expand Down
1 change: 0 additions & 1 deletion bots/discord/slash_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ async def send_message(

return FinishedSession(self, msg_ids, send)


async def check_native_permission(self):
if self.session.message.channel.permissions_for(
self.session.message.author
Expand Down
193 changes: 111 additions & 82 deletions bots/matrix/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ async def send_message(
if not message_chain.is_safe and not disable_secret_check:
return await self.send_message((I18NContext("error.message.chain.unsafe", locale=self.locale.locale)))
self.sent.append(message_chain)
sentMessages: list[nio.RoomSendResponse] = []
send: list[nio.RoomSendResponse] = []
for x in message_chain.as_sendable(self, embed=False):

async def sendMsg(content):
Expand Down Expand Up @@ -140,13 +140,13 @@ async def sendMsg(content):
split = await image_split(x)
for xs in split:
path = await xs.get()
with open(path, "rb") as image:
with open(path, 'rb') as image:
filename = os.path.basename(path)
filesize = os.path.getsize(path)
(content_type, content_encoding) = mimetypes.guess_type(path)
if not content_type or not content_encoding:
content_type = "image"
content_encoding = "png"
content_type = 'image'
content_encoding = 'png'
mimetype = f"{content_type}/{content_encoding}"

encrypted = self.session.target in bot.encrypted_rooms
Expand All @@ -155,32 +155,31 @@ async def sendMsg(content):
content_type=mimetype,
filename=filename,
encrypt=encrypted,
filesize=filesize,
)
filesize=filesize)
Logger.info(
f"Uploaded image {filename} to media repo, uri: {
upload.content_uri}, mime: {mimetype}, encrypted: {encrypted}")
# todo: provide more image info
if not encrypted:
content = {
"msgtype": "m.image",
"url": upload.content_uri,
"body": filename,
"info": {
"size": filesize,
"mimetype": mimetype,
},
'msgtype': 'm.image',
'url': upload.content_uri,
'body': filename,
'info': {
'size': filesize,
'mimetype': mimetype,
}
}
else:
upload_encryption["url"] = upload.content_uri
upload_encryption['url'] = upload.content_uri
content = {
"msgtype": "m.image",
"body": filename,
"file": upload_encryption,
"info": {
"size": filesize,
"mimetype": mimetype,
},
'msgtype': 'm.image',
'body': filename,
'file': upload_encryption,
'info': {
'size': filesize,
'mimetype': mimetype,
}
}
Logger.info(
f"[Bot] -> [{self.target.target_id}]: Image: {str(xs.__dict__)}"
Expand All @@ -192,12 +191,12 @@ async def sendMsg(content):
filesize = os.path.getsize(path)
(content_type, content_encoding) = mimetypes.guess_type(path)
if not content_type or not content_encoding:
content_type = "audio"
content_encoding = "ogg"
content_type = 'audio'
content_encoding = 'ogg'
mimetype = f"{content_type}/{content_encoding}"

encrypted = self.session.target in bot.encrypted_rooms
with open(path, "rb") as audio:
with open(path, 'rb') as audio:
(upload, upload_encryption) = await bot.upload(
audio,
content_type=mimetype,
Expand All @@ -210,82 +209,116 @@ async def sendMsg(content):
# todo: provide audio duration info
if not encrypted:
content = {
"msgtype": "m.audio",
"url": upload.content_uri,
"body": filename,
"info": {
"size": filesize,
"mimetype": mimetype,
},
'msgtype': 'm.audio',
'url': upload.content_uri,
'body': filename,
'info': {
'size': filesize,
'mimetype': mimetype,
}
}
else:
upload_encryption["url"] = upload.content_uri
upload_encryption['url'] = upload.content_uri
content = {
"msgtype": "m.audio",
"body": filename,
"file": upload_encryption,
"info": {
"size": filesize,
"mimetype": mimetype,
},
'msgtype': 'm.audio',
'body': filename,
'file': upload_encryption,
'info': {
'size': filesize,
'mimetype': mimetype,
}
}

Logger.info(
f"[Bot] -> [{self.target.target_id}]: Voice: {str(x.__dict__)}"
)
await sendMsg(content)
Logger.info(f'[Bot] -> [{self.target.target_id}]: Voice: {str(x.__dict__)}')

if reply_to:
# rich reply
content['m.relates_to'] = {
'm.in_reply_to': {
'event_id': reply_to
}
}
# mention target user
content['m.mentions'] = {
'user_ids': [reply_to_user]
}

if self.session.message and 'm.relates_to' in self.session.message['content']:
relates_to = self.session.message['content']['m.relates_to']
if 'rel_type' in relates_to and relates_to['rel_type'] == 'm.thread':
# replying in thread
thread_root = relates_to['event_id']
if reply_to:
# reply to msg replying in thread
content['m.relates_to'] = {
'rel_type': 'm.thread',
'event_id': thread_root,
'is_falling_back': False,
'm.in_reply_to': {
'event_id': reply_to
}
}
pass
else:
# reply in thread
content['m.relates_to'] = {
'rel_type': 'm.thread',
'event_id': thread_root,
'is_falling_back': True,
'm.in_reply_to': {
'event_id': self.target.message_id
}
}

resp = await bot.room_send(self.session.target, 'm.room.message', content, ignore_unverified_devices=True)
if 'status_code' in resp.__dict__:
Logger.error(f"Error in sending message: {str(resp)}")
else:
send.append(resp)
if callback:
for x in sentMessages:
for x in send:
MessageTaskManager.add_callback(x.event_id, callback)
return FinishedSession(
self, [resp.event_id for resp in sentMessages], self.session.target
)
return FinishedSession(self, [resp.event_id for resp in send], self.session.target)

async def check_native_permission(self):
if self.session.target.startswith("@") or self.session.sender.startswith("!"):
if self.session.target.startswith('@') or self.session.sender.startswith('!'):
return True
# https://spec.matrix.org/v1.9/client-server-api/#permissions
power_levels = (
await bot.room_get_state_event(self.session.target, "m.room.power_levels")
).content
level = (
power_levels["users"][self.session.sender]
if self.session.sender in power_levels["users"]
else power_levels["users_default"]
)
power_levels = (await bot.room_get_state_event(self.session.target, 'm.room.power_levels')).content
level = power_levels['users'][self.session.sender] if self.session.sender in power_levels['users'] else power_levels['users_default']
if level and int(level) >= 50:
return True
return False

def as_display(self, text_only=False):
if not self.session.message:
return ""
if not text_only or self.session.message["content"]["msgtype"] == "m.text":
return str(self.session.message["content"]["body"])
if not text_only and "format" in self.session.message["content"]:
return str(self.session.message["content"]["formatted_body"])
return ""
return ''
if not text_only or self.session.message['content']['msgtype'] == 'm.text':
return str(self.session.message['content']['body'])
if not text_only and 'format' in self.session.message['content']:
return str(self.session.message['content']['formatted_body'])
return ''

async def to_message_chain(self):
if not self.session.message:
return MessageChain([])
content = self.session.message["content"]
msgtype = content["msgtype"]
if msgtype == "m.emote":
msgtype = "m.text"
if msgtype == "m.text": # compatible with py38
text = str(content["body"])
content = self.session.message['content']
msgtype = content['msgtype']
if msgtype == 'm.emote':
msgtype = 'm.text'
if msgtype == 'm.text': # compatible with py38
text = str(content['body'])
if self.target.reply_id:
# redact the fallback line for rich reply
# https://spec.matrix.org/v1.9/client-server-api/#fallbacks-for-rich-replies
while text.startswith("> "):
text = "".join(text.splitlines(keepends=True)[1:])
while text.startswith('> '):
text = ''.join(text.splitlines(keepends=True)[1:])
return MessageChain(Plain(text.strip()))
if msgtype == "m.image":
url = None
if "url" in content:
url = str(content["url"])
elif "file" in content:
if 'url' in content:
url = str(content['url'])
elif 'file' in content:
# todo: decrypt image
# url = str(content['file']['url'])
return MessageChain([])
Expand Down Expand Up @@ -327,20 +360,16 @@ class FetchedSession(Bot.FetchedSession):

async def _resolve_matrix_room_(self):
target_id: str = self.session.target
if target_id.startswith("@"):
if target_id.startswith('@'):
# find private messaging room
for room in bot.rooms:
room = bot.rooms[room]
if room.join_rule == "invite" and (
(room.member_count == 2 and target_id in room.users)
or (room.member_count == 1 and target_id in room.invited_users)
):
resp = await bot.room_get_state_event(
room.room_id, "m.room.member", target_id
)
if room.join_rule == 'invite' and ((room.member_count == 2 and target_id in room.users)
or (room.member_count == 1 and target_id in room.invited_users)):
resp = await bot.room_get_state_event(room.room_id, 'm.room.member', target_id)
if resp is nio.ErrorResponse:
pass
elif resp.content["membership"] in ["join", "leave", "invite"]:
elif resp.content['membership'] in ['join', 'leave', 'invite']:
self.session.target = room.room_id
return
Logger.info(
Expand Down
4 changes: 2 additions & 2 deletions core/locales/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@
"tos.message.report": "User ${sender} triggered an abuse warning in session ${target}.",
"tos.message.tempbanned": "Note:\nWe have temporarily banned you because your action triggered a warning.\n${ban_time} second(s) remaining until unban.",
"tos.message.tempbanned.warning": "Note:\nAlthough the temporary ban was triggered, using commands still may cause you to be warned again.\n${ban_time} second(s) remaining until unban.",
"tos.message.warning": "Warning:\nYou have violated our Code of Conduct according to our Terms of Service.",
"tos.message.warning.count": "You have received ${current_warns} warnings.",
"tos.message.warning": "Warning:\nCommand abuse is strictly forbidden, you have reached that redline.",
"tos.message.warning.count": "You have received ${current_warns} warnings. Your account will be blocked if you receive more than ${warn_counts} warnings.",
"tos.message.warning.last": "This is the last warning.",
"tos.message.warning.prompt": "Your account will be blocked if you receive more than ${warn_counts} warnings."
}
2 changes: 1 addition & 1 deletion core/locales/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
"tos.message.report": "用户 ${sender} 在会话 ${target} 触发了滥用警告。",
"tos.message.tempbanned": "提示:\n由于你的行为触发了警告,我们已对你进行临时封禁。\n距离解封时间还有 ${ban_time} 秒。",
"tos.message.tempbanned.warning": "提示:\n即使已被临时封禁,尝试继续滥用命令可能会导致你被再次警告。\n距离解封时间还有 ${ban_time} 秒。",
"tos.message.warning": "警告:\n根据服务条款,你已违反我们的行为准则",
"tos.message.warning": "警告:\n本bot禁止短时间大量使用,您已触碰到此阈值",
"tos.message.warning.count": "这是第 ${current_warns} 次警告。",
"tos.message.warning.last": "这是最后一次警告。",
"tos.message.warning.prompt": "如超过 ${warn_counts} 次警告,我们将会封禁你的账户。"
Expand Down
2 changes: 1 addition & 1 deletion core/locales/zh_tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
"tos.message.report": "使用者 ${sender} 在會話 ${target} 觸發了濫用警告。",
"tos.message.tempbanned": "提示:\n由於你的行為觸發了警告,我們已對你暫時封鎖。\n距解除時間還有 ${ban_time} 秒。",
"tos.message.tempbanned.warning": "提示:\n即使已被暫時封鎖,嘗試繼續濫用指令可能會導致你被再次警告。\n距解除時間還有 ${ban_time} 秒。",
"tos.message.warning": "警告:\n依據使用條款,你已違反我們的行為準則",
"tos.message.warning": "警告:\n本bot嚴禁濫用,您已觸發濫用閾值",
"tos.message.warning.count": "這是第 ${current_warns} 次警告。",
"tos.message.warning.last": "這是最後一次警告。",
"tos.message.warning.prompt": "如超過 ${warn_counts} 次警告,我們將會封鎖你的帳戶。"
Expand Down
4 changes: 2 additions & 2 deletions core/parser/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ async def tos_msg_counter(msg: Bot.MessageSession, command: str):
'ts': datetime.now().timestamp()}
else:
same['count'] += 1
if same['count'] > 10:
if same['count'] > 5:
raise AbuseWarning("{tos.message.reason.cooldown}")
all_ = counter_all.get(msg.target.sender_id)
if not all_ or datetime.now().timestamp() - all_['ts'] > 300: # 检查是否滥用(5分钟内使用20条命令)
counter_all[msg.target.sender_id] = {'count': 1,
'ts': datetime.now().timestamp()}
else:
all_['count'] += 1
if all_['count'] > 20:
if all_['count'] > 10:
raise AbuseWarning("{tos.message.reason.abuse}")


Expand Down
6 changes: 4 additions & 2 deletions modules/ask/tools/self_knowledge/src/ask.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
You are the chat mode of AkariBot (Chinese: 小可), a chat bot.

AkariBot is a product of Teahouse Studios (Chinese: 茶馆工作室).

You are a fork program of Akaribot,your maintainer is Haiyuyouyan (Chineses:海屿有燕).

AkariBot is powered by GPT-3.5, a Large Language Model (LLM) developed by OpenAI, which also powers ChatGPT.

AkariBot have access to the a number of tools powered by LangChain.
Expand All @@ -24,6 +28,4 @@ AkariBot have many contributors. The one who contributed the most is OasisAkari.

AkariBot use puppeteer to render webpages and wiki infoboxes.

AkariBot is a product of Teahouse Studios (Chinese: 茶馆工作室).

Teahouse Studios also created a Minecraft resource pack called Memified Chinese (Chinese: 梗体中文) and it's very popular.
Loading

0 comments on commit 6d84db1

Please sign in to comment.