style: introduce ruff as linter and formatter (#1356)

* style: remove necessary imports

* style: fix F841

* style: fix F401

* style: fix F811

* style: fix E402

* style: fix E721

* style: fix E722

* style: fix E722

* style: fix F541

* style: ruff format

* style: all passed

* style: add ruff in deps

* style: more ignores in ruff.toml

* style: add pre-commit
This commit is contained in:
Junyan Qin (Chin)
2025-04-29 17:24:07 +08:00
committed by GitHub
parent 09e70d70e9
commit 209f16af76
240 changed files with 5307 additions and 4689 deletions

View File

@@ -2,18 +2,19 @@ from __future__ import annotations
import os
import traceback
from PIL import Image, ImageDraw, ImageFont
from ...core import app
from . import strategy
from .strategies import image, forward
from .. import stage, entities
from ...core import entities as core_entities
from ...config import manager as cfg_mgr
from ...platform.types import message as platform_message
from ...utils import importutil
from . import strategies
importutil.import_modules_in_pkg(strategies)
@stage.stage_class("LongTextProcessStage")
@stage.stage_class('LongTextProcessStage')
class LongTextProcessStage(stage.PipelineStage):
"""长消息处理阶段
@@ -31,34 +32,48 @@ class LongTextProcessStage(stage.PipelineStage):
# 检查是否存在
if not os.path.exists(use_font):
# 若是windows系统使用微软雅黑
if os.name == "nt":
use_font = "C:/Windows/Fonts/msyh.ttc"
if os.name == 'nt':
use_font = 'C:/Windows/Fonts/msyh.ttc'
if not os.path.exists(use_font):
self.ap.logger.warn("未找到字体文件且无法使用Windows自带字体更换为转发消息组件以发送长消息您可以在配置文件中调整相关设置。")
config['blob_message_strategy'] = "forward"
self.ap.logger.warn(
'未找到字体文件且无法使用Windows自带字体更换为转发消息组件以发送长消息您可以在配置文件中调整相关设置。'
)
config['blob_message_strategy'] = 'forward'
else:
self.ap.logger.info("使用Windows自带字体" + use_font)
self.ap.logger.info('使用Windows自带字体' + use_font)
config['font-path'] = use_font
else:
self.ap.logger.warn("未找到字体文件,且无法使用系统自带字体,更换为转发消息组件以发送长消息,您可以在配置文件中调整相关设置。")
self.ap.logger.warn(
'未找到字体文件,且无法使用系统自带字体,更换为转发消息组件以发送长消息,您可以在配置文件中调整相关设置。'
)
pipeline_config['output']['long-text-processing']['strategy'] = "forward"
except:
pipeline_config['output']['long-text-processing'][
'strategy'
] = 'forward'
except Exception:
traceback.print_exc()
self.ap.logger.error("加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在配置文件中调整相关设置。".format(use_font))
self.ap.logger.error(
'加载字体文件失败({}),更换为转发消息组件以发送长消息,您可以在配置文件中调整相关设置。'.format(
use_font
)
)
pipeline_config['output']['long-text-processing']['strategy'] = "forward"
pipeline_config['output']['long-text-processing']['strategy'] = (
'forward'
)
for strategy_cls in strategy.preregistered_strategies:
if strategy_cls.name == config['strategy']:
self.strategy_impl = strategy_cls(self.ap)
break
else:
raise ValueError(f"未找到名为 {config['strategy']} 的长消息处理策略")
raise ValueError(f'未找到名为 {config["strategy"]} 的长消息处理策略')
await self.strategy_impl.initialize()
async def process(self, query: core_entities.Query, stage_inst_name: str) -> entities.StageProcessResult:
async def process(
self, query: core_entities.Query, stage_inst_name: str
) -> entities.StageProcessResult:
# 检查是否包含非 Plain 组件
contains_non_plain = False
@@ -66,13 +81,19 @@ class LongTextProcessStage(stage.PipelineStage):
if not isinstance(msg, platform_message.Plain):
contains_non_plain = True
break
if contains_non_plain:
self.ap.logger.debug("消息中包含非 Plain 组件,跳过长消息处理。")
elif len(str(query.resp_message_chain[-1])) > query.pipeline_config['output']['long-text-processing']['threshold']:
query.resp_message_chain[-1] = platform_message.MessageChain(await self.strategy_impl.process(str(query.resp_message_chain[-1]), query))
self.ap.logger.debug('消息中包含非 Plain 组件,跳过长消息处理。')
elif (
len(str(query.resp_message_chain[-1]))
> query.pipeline_config['output']['long-text-processing']['threshold']
):
query.resp_message_chain[-1] = platform_message.MessageChain(
await self.strategy_impl.process(
str(query.resp_message_chain[-1]), query
)
)
return entities.StageProcessResult(
result_type=entities.ResultType.CONTINUE,
new_query=query
result_type=entities.ResultType.CONTINUE, new_query=query
)

View File

@@ -1,8 +1,6 @@
# 转发消息组件
from __future__ import annotations
import typing
import pydantic.v1 as pydantic
from .. import strategy as strategy_model
from ....core import entities as core_entities
@@ -13,29 +11,27 @@ ForwardMessageDiaplay = platform_message.ForwardMessageDiaplay
Forward = platform_message.Forward
@strategy_model.strategy_class("forward")
@strategy_model.strategy_class('forward')
class ForwardComponentStrategy(strategy_model.LongTextStrategy):
async def process(self, message: str, query: core_entities.Query) -> list[platform_message.MessageComponent]:
async def process(
self, message: str, query: core_entities.Query
) -> list[platform_message.MessageComponent]:
display = ForwardMessageDiaplay(
title="群聊的聊天记录",
brief="[聊天记录]",
source="聊天记录",
preview=["QQ用户: "+message],
summary="查看1条转发消息"
title='群聊的聊天记录',
brief='[聊天记录]',
source='聊天记录',
preview=['QQ用户: ' + message],
summary='查看1条转发消息',
)
node_list = [
platform_message.ForwardMessageNode(
sender_id=query.adapter.bot_account_id,
sender_name='QQ用户',
message_chain=platform_message.MessageChain([message])
message_chain=platform_message.MessageChain([message]),
)
]
forward = Forward(
display=display,
node_list=node_list
)
forward = Forward(display=display, node_list=node_list)
return [forward]

View File

@@ -1,6 +1,5 @@
from __future__ import annotations
import typing
import os
import base64
import time
@@ -15,26 +14,30 @@ from .. import strategy as strategy_model
from ....core import entities as core_entities
@strategy_model.strategy_class("image")
@strategy_model.strategy_class('image')
class Text2ImageStrategy(strategy_model.LongTextStrategy):
async def initialize(self):
pass
@functools.lru_cache(maxsize=16)
def get_font(self, query: core_entities.Query):
return ImageFont.truetype(query.pipeline_config['output']['long-text-processing']['font-path'], 32, encoding="utf-8")
async def process(self, message: str, query: core_entities.Query) -> list[platform_message.MessageComponent]:
return ImageFont.truetype(
query.pipeline_config['output']['long-text-processing']['font-path'],
32,
encoding='utf-8',
)
async def process(
self, message: str, query: core_entities.Query
) -> list[platform_message.MessageComponent]:
img_path = self.text_to_image(
text_str=message,
save_as='temp/{}.png'.format(int(time.time())),
query=query
query=query,
)
compressed_path, size = self.compress_image(
img_path,
outfile="temp/{}_compressed.png".format(int(time.time()))
img_path, outfile='temp/{}_compressed.png'.format(int(time.time()))
)
with open(compressed_path, 'rb') as f:
@@ -93,13 +96,11 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
resultIndex.append(v)
return resultIndex
def get_size(self, file):
# 获取文件大小:KB
size = os.path.getsize(file)
return size / 1024
def get_outfile(self, infile, outfile):
if outfile:
return outfile
@@ -107,7 +108,6 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
outfile = '{}-out{}'.format(dir, suffix)
return outfile
def compress_image(self, infile, outfile='', kb=100, step=20, quality=90):
"""不改变图片尺寸压缩到指定大小
:param infile: 压缩源文件
@@ -130,24 +130,28 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
o_size = self.get_size(outfile)
return outfile, self.get_size(outfile)
def text_to_image(
self,
text_str: str,
save_as='temp.png',
width=800,
query: core_entities.Query = None,
):
text_str = text_str.replace('\t', ' ')
def text_to_image(self, text_str: str, save_as="temp.png", width=800, query: core_entities.Query = None):
text_str = text_str.replace("\t", " ")
# 分行
lines = text_str.split('\n')
# 计算并分割
final_lines = []
text_width = width-80
text_width = width - 80
self.ap.logger.debug("lines: {}, text_width: {}".format(lines, text_width))
self.ap.logger.debug('lines: {}, text_width: {}'.format(lines, text_width))
for line in lines:
# 如果长了就分割
line_width = self.get_font(query).getlength(line)
self.ap.logger.debug("line_width: {}".format(line_width))
self.ap.logger.debug('line_width: {}'.format(line_width))
if line_width < text_width:
final_lines.append(line)
continue
@@ -161,7 +165,10 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
numbers = self.indexNumber(rest_text)
for number in numbers:
if number[1] < point < number[1] + len(number[0]) and number[1] != 0:
if (
number[1] < point < number[1] + len(number[0])
and number[1] != 0
):
point = number[1]
break
@@ -174,16 +181,23 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
else:
continue
# 准备画布
img = Image.new('RGBA', (width, max(280, len(final_lines) * 35 + 65)), (255, 255, 255, 255))
img = Image.new(
'RGBA', (width, max(280, len(final_lines) * 35 + 65)), (255, 255, 255, 255)
)
draw = ImageDraw.Draw(img, mode='RGBA')
self.ap.logger.debug("正在绘制图片...")
self.ap.logger.debug('正在绘制图片...')
# 绘制正文
line_number = 0
offset_x = 20
offset_y = 30
for final_line in final_lines:
draw.text((offset_x, offset_y + 35 * line_number), final_line, fill=(0, 0, 0), font=self.text_render_font)
draw.text(
(offset_x, offset_y + 35 * line_number),
final_line,
fill=(0, 0, 0),
font=self.text_render_font,
)
# 遍历此行,检查是否有emoji
idx_in_line = 0
for ch in final_line:
@@ -196,7 +210,7 @@ class Text2ImageStrategy(strategy_model.LongTextStrategy):
line_number += 1
self.ap.logger.debug("正在保存图片...")
self.ap.logger.debug('正在保存图片...')
img.save(save_as)
return save_as

View File

@@ -12,7 +12,7 @@ preregistered_strategies: list[typing.Type[LongTextStrategy]] = []
def strategy_class(
name: str
name: str,
) -> typing.Callable[[typing.Type[LongTextStrategy]], typing.Type[LongTextStrategy]]:
"""长文本处理策略类装饰器
@@ -36,8 +36,7 @@ def strategy_class(
class LongTextStrategy(metaclass=abc.ABCMeta):
"""长文本处理策略抽象类
"""
"""长文本处理策略抽象类"""
name: str
@@ -45,12 +44,14 @@ class LongTextStrategy(metaclass=abc.ABCMeta):
def __init__(self, ap: app.Application):
self.ap = ap
async def initialize(self):
pass
@abc.abstractmethod
async def process(self, message: str, query: core_entities.Query) -> list[platform_message.MessageComponent]:
async def process(
self, message: str, query: core_entities.Query
) -> list[platform_message.MessageComponent]:
"""处理长文本
在 platform.json 中配置 long-text-process 字段,只要 文本长度超过了 threshold 就会调用此方法