MountainDash / nonebot-bison

A nonebot2 plugin to repost social media posts to QQ group
https://nonebot-bison.netlify.app
MIT License
160 stars 33 forks source link

[Feature Request] 关键词拦截 #551

Open RH-Xie opened 3 months ago

RH-Xie commented 3 months ago

概况

动机和需求

需求:支持关键词屏蔽 动机:以关注@明日方舟(微博) 为例,抽奖结果的转发推文比较刷屏,如下: image

那我可以关闭转发么?是可以的,但是考虑到转发的推文不一定是抽奖结果,可能是别的重要信息(比如联动转发)

据此最好的办法应该是设置关键词屏蔽(Issue #50 曾提及过该功能),如方舟的微博抽奖带有“微博官方唯一抽奖工具”,配置读入后正则过滤。

但是直接做成“包含关键词就不转发”有点不灵活,用户可以选择不转发或者使用替代文本(比如抽奖信息就是太长了,可以转换成一段包含关键信息的文本即可)

在此之上,替换文本里可以包含变量如$source$携带原消息的重要部分(全量替换,原来构建的Post没要了,因为我不太会重新构建一个Post

过滤后示意图:

image

添加的配置(bison_block_keyword项,值为json): image

需求粗分析(打勾为已实现)

关键代码示意:send.py

def is_contain_keyword(msg_str: str):
    try:
        for keyword in block_keywords:
            if keyword in msg_str:
                # 包含屏蔽词
                logger.info(f"检测到屏蔽词 {keyword}")
                if not block_set[keyword]:
                    return True, ''
                return True, f"{block_set[keyword]}"
        return False, '' # 不过滤
    except Exception as e:
        logger.error(f"过滤失败 {str(e)}")
        logger.error(f"过滤失败消息: {msg_str}")
        return False, '' # 不过滤

async def _do_send(send_target: PlatformTarget, msg: Sendable):
    # 关键词屏蔽
    msg_str = str(msg)
    addon_info = "来源" + msg_str.split("来源")[-1]
    logger.info(f"addon_info: {addon_info}")
    is_blocked, block_info = is_contain_keyword(msg_str)
    logger.info(f"检测到屏蔽词\nis_blocked: {is_blocked}\n替代消息:{block_info}")
    if is_blocked and not block_info:
        return; # 直接结束
    to_send_msg = msg
    if is_blocked:
        to_send_msg = MessageFactory(block_info.replace("$source$", addon_info))
    try:
        await to_send_msg.send_to(send_target)
    except ActionFailed:  # TODO: catch exception of other adapters
        await refresh_bots()
        logger.warning("send msg failed, refresh bots")

问题

一是目前是全平台、全群组拦截的,不能具体到群组或者某个订阅,另一方面就算是实现了,考虑到配置里些多层嵌套,对用户来说,可能会没那么好配置,望指点

二是而且这种直接str(msg)的写法貌似不太符合规范

目前是能用了,可以极大避免抽奖转发消息的刷屏

AzideCupric commented 3 months ago

应该类似于订阅Tag的部分,不过这样待屏蔽文本想替换成其他内容可能有点麻烦 转发里的#转发抽奖#tag好像不能参与过滤 坏

RH-Xie commented 2 months ago

确实是的,还会把原消息屏蔽掉(比如4.29逻各斯的实装预览消息,附带了#转发抽奖#tag) 至于“给每个群聊or订阅配置单独的屏蔽规则”,后来想了下,应该跟随插件的使用习惯,在群组/超管私聊命令or后台去配置屏蔽关键词,维护一个json文件,而不是像我上面那样在.env中写(当时没考虑太多XD