Esempio n. 1
0
async def batch_get_q(bot: Bot, event: MessageEvent, state: T_State):
    state["question"] = await msg2str(Message(event.raw_message))
    logger.debug(f'Current question is [{state["question"]}]')
    qs = event.raw_message.split("|")
    qs_i = [f'{i + 1}.{q}' for i, q in enumerate(qs)]
    msg = Message('当前要记录的问句为:\n' + '\n'.join(qs_i) +
                  '\n请确认以上问句无误,输入回答内容,使用“|”分隔,否则请发送[取消]结束对话重新输入')
    await batch_learn.send(msg)
Esempio n. 2
0
async def show_remind(bot: Bot, event: GroupMessageEvent, state: T_State):
    gid = str(event.group_id)
    if gid not in exitremind_settings:
        en_setting = DEFAULT_REMIND
    else:
        en_setting = exitremind_settings[gid]
    lv_reminds = '\n'.join([f'{i+1}.{speech}' for i, speech in enumerate(en_setting['leave'])])
    kk_reminds = '\n'.join([f'{i+1+len(en_setting["leave"])}.{speech}' for i, speech in enumerate(en_setting['kick'])])
    status = '已锁定' if en_setting['locked'] else '未锁定'
    msg = '当前群内主动退群提醒语句为:\n' + lv_reminds + '\n────────────\n被管理踢出群聊提醒语句为:\n' + kk_reminds + '\n────────────\n可修改状态:' + status
    if en_setting['locked'] and event.sender.role == 'member':
        await remind_editor.finish(Message(msg))
    else:
        msg += '\n────────────\n使用以下命令修改通知语句(不带中括号):\n[添加主动退群] 添加一个主动退群提醒语句(使用{name}字段可自动替换退群者的昵称,参考默认邀请语句)\n[添加管理踢人] 添加一个管理踢人提醒语句(除{name}之外可使用{admin}字段可自动替换执行的管理的昵称,参考默认踢人提醒语句)\n[删除+序号] 删除指定的语句\n[切换锁定] 更改锁定状态,锁定状态下群员不可修改退群提醒语句'
        await remind_editor.send(Message(msg))
Esempio n. 3
0
async def reply_checker(bot: Bot, event: MessageEvent, state: T_State) -> bool:
    """问答对话触发规则"""
    q = await msg2str(Message(event.raw_message)
                      )  # 仅仅使用message会去掉呼唤bot昵称的原文本,造成问句中有bot昵称时逻辑混乱
    logger.debug(f'Search question <{q}> in corpus...')
    gid = event.group_id if event.message_type == 'group' else 0
    result = query(q, gid)
    logger.debug(f'当前获得了可触发的对话:{result}')
    if not result:
        return False

    alter = [(s, a) for s, a, p in result
             if randint(0, 100) < p]  # 过滤出通过随机概率的对话
    logger.debug(f'当前被过滤出的对话:{alter}')
    if not alter:
        return False

    sid, answer = choice(alter)  # 从可触发的对话中随机选择一个
    if event.message_type == 'group':
        name = event.sender.card or event.sender.nickname or event.get_user_id(
        )
    else:
        name = event.sender.nickname or event.get_user_id()
    state['answer'] = msglize(answer, name)
    state['sid'] = sid
    return True
Esempio n. 4
0
async def show_speech(bot: Bot, event: GroupMessageEvent, state: T_State):
    gid = str(event.group_id)
    if gid not in welcome_settings:
        wl_setting = DEFAULT_SPEECH
    else:
        wl_setting = welcome_settings[gid]
    ap_speeches = '\n'.join([f'{i+1}.{speech}' for i, speech in enumerate(wl_setting['approve'])])
    # in_speeches = '\n'.join([f'{i+1+len(wl_setting["approve"])}.{speech}' for i, speech in enumerate(wl_setting['invite'])])
    status = '已锁定' if wl_setting['locked'] else '未锁定'
    msg = '当前新人入群欢迎语句为:\n' + ap_speeches + '\n────────────\n可修改状态:' + status
    if wl_setting['locked'] and event.sender.role == 'member':
        await speech_editor.finish(Message(msg))
    else:
        # msg += '\n────────────\n使用以下命令修改通知语句(不带中括号):\n[添加] 添加一个迎新语句(使用{name}字段可自动替换新人的昵称,参考默认欢迎语句)\n[添加邀请入群] 添加一个被邀请入群欢迎语句(除{name}之外可使用{admin}字段可自动替换邀请人的昵称,参考默认邀请语句)\n[删除+序号] 删除指定的语句\n[切换锁定] 更改锁定状态,锁定状态下群员不可修改欢迎语句'
        msg += '\n────────────\n使用以下命令修改通知语句(不带中括号):\n[添加] 添加一个迎新语句(使用{name}字段可自动替换新人的昵称,参考默认欢迎语句)\n[删除+序号] 删除指定的语句\n[切换锁定] 更改锁定状态,锁定状态下群员不可修改欢迎语句'
        await speech_editor.send(Message(msg))
Esempio n. 5
0
async def show_record(bot: Bot, event: GroupMessageEvent):
    arg = str(event.message).split('号记录')[0]
    if not arg.isdigit():
        await recorder.finish(reply_header(event, '哪有这种代号的记录啊?!'))
    fake_id = int(arg)
    if fake_id not in recalled[event.group_id]:
        await recorder.finish(reply_header(event, '这条记录不存在或者因为太久所以被消除了~'))
    msg_id, passive, timestamp = recalled[event.group_id][fake_id]
    try:
        msginfo = await bot.get_msg(message_id=msg_id)
        logger.debug(
            f"Got recalled message({type(msginfo['message'])}): {str(msginfo['message'])}"
        )
    except ActionFailed:
        await recorder.finish(reply_header(event, '这条记录不存在或者因为太久所以被消除了~'))
    for seg in msginfo["message"]:
        logger.debug(f'Check type of segment: {seg}\n{seg["type"]}')
        if seg['type'] not in ('text', 'face', 'image', 'at',
                               'reply'):  # 可以夹在普通消息框里的片段
            can_append = False
            break
    else:
        can_append = True

    time = datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
    try:
        litigant_info = await bot.get_group_member_info(
            group_id=event.group_id, user_id=msginfo["sender"]["user_id"])
        name = litigant_info["card"] or litigant_info["nickname"] or str(
            litigant_info["user_id"])
    except ActionFailed:
        name = msginfo["sender"]["user_id"]  # 没获取到的话可能群员退群了
    if passive:
        header = f"{name}在{time}被撤回了:\n"
    else:
        header = f"{name}在{time}撤回了:\n"

    if can_append:
        await recorder.finish(Message(header) + (Message(msginfo["message"])))
    else:
        await recorder.send(Message(header))
        await asleep(1)
        # await recorder.finish(msginfo["message"])

        await recorder.finish(Message(msginfo["raw_message"]))
Esempio n. 6
0
async def batch_get_a(bot: Bot, event: MessageEvent, state: T_State):
    answer = Message(event.raw_message)
    # 不可以at自己
    for seg in answer:
        if seg.type == 'at' and seg.data["qq"] == str(event.self_id):
            await learn.finish('我为什么要at我自己?不要这样啦,会有bug的::>_<::')
    answer = await msg2str(answer, localize_=True, bot=bot)
    if answer:
        state["answer"] = answer
    else:
        await batch_learn.finish(reply_header(event, '含有学习失败的信息,要不联系主人试试?'))
    logger.debug(f'Current answer is [{answer}]')
    ans = event.raw_message.split("|")
    as_i = [f'{i + 1}.{a}' for i, a in enumerate(ans)]
    msg = Message('当前要记录的回答为:\n' + '\n'.join(as_i) +
                  '\n请确认以上回答无误,输入相对出现率[0-100],否则请发送[取消]结束对话重新输入')
    await batch_learn.send(msg)
    state['wrong_times'] = 0  # 输入错误次数,用于获取出现率时计算
Esempio n. 7
0
async def welcome_newcomers(bot: Bot, event: GroupIncreaseNoticeEvent):
    gid = str(event.group_id)
    if gid not in welcome_settings:
        welcome_settings[gid] = DEFAULT_SPEECH
    settings = welcome_settings[gid]
    userinfo = await bot.get_group_member_info(group_id=event.group_id, user_id=event.user_id)
    name = userinfo['card'] or userinfo['nickname'] or str(event.user_id)
    # admininfo = await bot.get_group_member_info(group_id=event.group_id, user_id=event.operator_id)
    # admin = admininfo['card'] or admininfo['nickname'] or str(event.user_id)
    # msg = Message(choice(settings[event.sub_type]).format(name=name, admin=admin))
    msg = Message(choice(settings['approve']).format(name=name))
    await entry_welcome.finish(msg, at_sender=True)
Esempio n. 8
0
async def get_a(bot: Bot, event: MessageEvent, state: T_State):
    question = state["question"]
    if "answer" in state:
        answer = state["answer"]
    else:
        answer = Message(event.raw_message)
        # 不可以at自己
        for seg in answer:
            if seg.type == 'at' and seg.data["qq"] == str(event.self_id):
                await learn.finish('我为什么要at我自己?不要这样啦,会有bug的::>_<::')
        answer = await msg2str(answer, localize_=True, bot=bot)

    if len(question) > 3000 or len(answer) > 3000:
        await learn.finish(f'内容太长的对话{BOTNAME}记不住的说>﹏<')
    if answer:
        logger.debug(f'Current answer is [{answer}]')
        source = event.group_id if event.message_type == "group" and 'selflearn' not in state else 0
        public = 0 if state["force_priv"] else state["public"]
        creator = event.user_id if 'selflearn' not in state else event.self_id
        result = insertone(question, answer, 70, creator, source, public)
        if isinstance(result, tuple):
            await learn.finish(f'记录已被用户{result[0]}在{result[1]}时创建')
        else:
            logger.info(
                f'Insert record to corpus :\nquestion:[{question}]\nanswer:[{answer}]\npublic:{public}\ncreator:{creator}\nsource:{source}'
            )

            dlmt = DailyNumberLimiter(uid=event.user_id,
                                      func_name='学习',
                                      max_num=6)
            if dlmt.check(close_conn=False):
                if dlmt.count <= 3:
                    exp_mu, fund_mu = 5, 10
                else:
                    exp_mu, fund_mu = 2, 3
                exp = cgauss(exp_mu, 1, 1)
                fund = cgauss(fund_mu, 1, 1)
                user = UserLevel(event.user_id)
                await user.expup(exp, bot, event)
                user.turnover(fund)
                msg = f'对话已记录, 赠送您{exp}exp 和 {fund}金币作为谢礼~'
                dlmt.increase()
            else:
                dlmt.conn.close()
                msg = '对话已记录'
            if state["force_priv"]:
                msg += "\n(消息中含at信息,将强制设置公开性为群内限定)"
            msg += "\n﹟ 当前对话相对出现率默认设置为70,如需设置出现率可直接输入0-100范围内数字,否则可忽视本条说明"
            preprob[event.user_id] = result
            await learn.finish(msg)
    else:
        await learn.finish(reply_header(event, '这条词语好像记不住耶,要不联系主人试试?'))
Esempio n. 9
0
async def first_receive(bot: Bot, event: MessageEvent, state: T_State):

    # 过滤妖精的早苗
    if event.user_id in SANAE_BOTS:
        await learn.finish('两只AI成功握手,但被主人阻止掉了(;∀;)')

    command = state["_prefix"]["raw_command"]
    if command == '群内学习':
        if isinstance(event, GroupMessageEvent):
            state["public"] = 0
        else:
            await learn.finish(
                '[群内学习]只适用于在群中对话哦,公开性对话学习请使用[学习对话],私聊内保密对话学习命令为[私聊学习]')
    elif command in ('私聊学习', '偷偷学习'):
        if isinstance(event, PrivateMessageEvent):
            state["public"] = 0
        else:
            await learn.finish(
                f'[{command}]只适用于在私聊中对话哦,公开性对话学习请使用[学习对话],群内保密对话学习命令为[群内学习]')
    else:
        if command == '自学':
            state["selflearn"] = True
        state["public"] = 1
    state[
        "force_priv"] = False  # 强制不公开,输入q或a中有at信息且没有用私有学习命令时改为true并在最后将public强制设置为1
    arg = str(event.get_message())
    if arg:
        if ' 回答' not in arg:
            state['question'] = arg
        else:  # 快速学习,但插入记录仍放到对话最后处理
            question, answer = arg.split(' 回答', maxsplit=1)
            state["question"] = await msg2str(Message(question))

            answer = await msg2str(Message(answer), localize_=True, bot=bot)
            if not answer:
                await learn.finish(reply_header(event, '这条词语好像记不住耶,要不联系主人试试?'))
            else:
                state["answer"] = answer.lstrip(
                )  # 删除行左的空格,因为不确定用户是否会输入多个空格做回答分隔符,如果有需求可能要改逻辑
Esempio n. 10
0
async def member_exit_remind(bot: Bot, event: GroupDecreaseNoticeEvent):
    gid = str(event.group_id)
    if gid not in exitremind_settings:
        exitremind_settings[gid] = DEFAULT_REMIND
    settings = exitremind_settings[gid]
    userinfo = await bot.get_stranger_info(user_id=event.user_id)
    name = userinfo['nickname'] or str(event.user_id)
    if event.user_id != event.operator_id:
        admininfo = await bot.get_group_member_info(group_id=event.group_id, user_id=event.operator_id)
        admin = admininfo['card'] or admininfo['nickname'] or str(event.user_id)
    else:
        admin = name
    msg = Message(choice(settings[event.sub_type]).format(name=name, admin=admin))
    await entry_exitremind.finish(msg)
Esempio n. 11
0
async def get_setu(bot: Bot, event: MessageEvent, state: T_State):
    msg: Message = Message(state["setu"])
    try:
        for seg in msg:
            if seg.type == "image":
                url = seg.data["url"]  # 图片链接
                break
        else:
            await setu.finish(reply_header(event, "这也不是图啊!"))

        await bot.send(event=event, message="让我搜一搜...")
        result = MessageSegment.text('————>SauceNao<————')
        async for msg in get_des(url, 'sau'):
            if not msg:
                await setu.send('未从saucenao检索到高相似度图片,将运行ascii2d检索')
                break
            result += msg + '────────────\n'
        else:
            result = Message(str(result).rstrip('────────────\n'))
            await setu.finish(result)

        result = MessageSegment.text('————>ascii2d<————')
        async for msg in get_des(url, 'ascii2d'):
            if not msg:
                await setu.finish('未从ascii2d检索到高相似度图片,请等待加入更多检索方式')
                break
            result += msg + '────────────\n'
        else:
            result = Message(str(result).rstrip('────────────\n'))
            await setu.finish(result)

    except (IndexError, ClientError):
        logger.exception(traceback.format_exc())
        await setu.finish("遇到未知打击,中断了搜索")
    except ActionFailed as e:
        logger.error(f'Send result failed: {e}')
        await setu.finish('虽然搜到了,但是发送结果途中遭遇拦截,可稍后再试一试')
Esempio n. 12
0
async def parse_qa(bot: Bot, event: MessageEvent, state: T_State):
    # 退出指令
    if str(event.message) in CANCEL_EXPRESSION:
        await learn.finish('已退出当前对话')
    # if f'[CQ:at,qq={event.self_id}]' in event.raw_message:
    #     await learn.finish('我为什么要at我自己?不要这样啦,会有bug的::>_<::')
    for seg in Message(event.raw_message):
        if seg.type == "at" and seg.data["qq"] != str(event.self_id):
            # 强制非公开
            if state["public"]:
                state["force_priv"] = True
                logger.info('Got at info, force set public to 0')
        # 不能存入消息的格式
        if seg.type not in ALLOW_SEGMENT:
            if seg.type == 'reply':
                await learn.finish('请不要学习带有回复上文消息的内容,会引发定位错误')
            else:
                await learn.finish('接收的消息不在可学习范围内')
Esempio n. 13
0
async def parse_batch_qa(bot: Bot, event: MessageEvent, state: T_State):
    # 退出指令
    if str(event.message) in CANCEL_EXPRESSION:
        await learn.finish('已退出当前对话')
    for seg in Message(event.raw_message):
        if seg.type == "at":
            # 不可以at自己
            if seg.data["qq"] == str(event.self_id):
                await learn.finish('我为什么要at我自己?不要这样啦,会有bug的::>_<::')
                logger.debug(f'type{type(seg.data["qq"])}')  # 检测一下type
            # 强制非公开
            if state["public"]:
                state["force_priv"] == True
        # 不能存入消息的格式
        if seg.type not in ALLOW_SEGMENT:
            if seg.type == 'reply':
                await learn.finish('请不要学习带有回复上文消息的内容,会引发定位错误')
            else:
                await learn.finish('接收的消息不在可学习范围内')
Esempio n. 14
0
def msglize(msg: str,
            name: str = "{name}",
            prestr: bool = False) -> Union[Message, str]:
    """解析数据库answer时调用,把返回消息中的{res_path}替换为真实资源路径, 把{name}换成昵称并去转义emoji

    Args:
        msg (str): 数据库中的answer
        name (str, optional): 要替换{name}字段的字符,通常为event.sender.card|nickname. Defaults to "{name}".
        prestr (bool): 是否要保持字符串,使用此选项不会把消息转为Message而是会保持为字符串返回. Defaults to False.

    Returns:
        Union[Message, str]: 解析后自动转换Message或保持str
    """
    if '[CQ:image,' in msg or "{name}" in msg:
        msg = msg.format(res_path=str(CORPUS_IMAGES_PATH), name=name)
    if prestr:
        return emojize(msg)
    else:
        return Message(
            emojize(msg))  # 由于nb2使用array上报数据所以要实例化为Message可直接转化旧版字符串数据
Esempio n. 15
0
async def look_over(bot: Bot, event: MessageEvent, state: T_State):
    op = str(event.message.extract_plain_text())
    if not op:
        await query_record.reject()
    if op in CANCEL_EXPRESSION:
        await query_record.finish('已退出查询页面')
    if op.strip().startswith('修改出现率'):
        await handle_event(bot, event)
        # 如果不能一次输入参数的话两个对话会同时进行产生冲突,参数数量不符合时会直接结束查询对话
        if len(op.strip('-')) == 3:
            await query_record.reject()
        else:
            await query_record.finish()
    bar: Pagination = state["record_bar"]
    addend = '\n发送[上一页][下一页]翻页查看列表,发送<页面序号>跳转到指定页\n使用 [修改出现率] <对话id> <出现率> 来修改指定对话的相对出现率\n发送[退出]退出当前查询'
    if op == "上一页":
        if bar.crupg == 1:
            msg = '当前已经是首页了哦~'
            state['left_wrong_times'] -= 1
        else:
            msg = bar.pgup() + addend
    elif op == '下一页':
        if bar.crupg == len(bar.rcd_ls):
            msg = '已经是最后页了~'
            state['left_wrong_times'] -= 1
        else:
            msg = bar.pgdn() + addend
    elif op.isdigit():
        pgnum = int(op)
        if pgnum > 0 and pgnum <= len(bar.rcd_ls):
            msg = bar.turnpage(pgnum) + addend
        else:
            msg = '超出当前已有的页面范围了~'
            state['left_wrong_times'] -= 1
    elif state['left_wrong_times'] > 0:
        msg = f"未期望的输入,{state['left_wrong_times']}次输入错误将退出查询对话,发送[退出]退出当前查询"
        state['left_wrong_times'] -= 1
    else:
        await query_record.finish('未期望的输入,已退出当前查询对话')

    await query_record.reject(Message(msg))
Esempio n. 16
0
async def fake_del_handle(bot: Bot, event: MessageEvent, state: T_State):
    # 退出指令
    if str(event.message) in CANCEL_EXPRESSION:
        await delete_record.finish('已退出当前对话')
    sid = state["sid"] if "sid" in state else event.message.extract_plain_text(
    ).strip()
    if event.user_id in SUPERUSERS:  # 真实的删除
        try:
            sid = int(sid)
        except ValueError:
            await delete_record.finish(reply_header(event, '非数字参数'))
        exsit = query_exists(sid)
        if not exsit:
            await delete_record.finish(reply_header(event, '不存在的对话'))
        del_record(sid)
        await delete_record.finish(reply_header(event, f'已删除对话{sid}'))
    else:  # 虚假的删除
        event.message = Message(f'修改出现率 -{sid} -0')
        await handle_event(bot, event)


# TODO: 查询自己设置过的,举报,修改随机算法,先预计算所有会出现的对话再choice
Esempio n. 17
0
async def standby(bot: Bot, event: GroupMessageEvent, state: T_State):
    await repeater.finish(Message(state['raw_msg']))
Esempio n. 18
0
async def handle_query(bot: Bot, event: MessageEvent, state: T_State):
    question = state["question"] if 'question' in state else await msg2str(
        Message(event.raw_message))
    logger.debug(f'Query question in corpus: [{question}]')
    gid = event.group_id if event.message_type == 'group' else 0
    result = query(question, gid, q=True)

    if not result:
        await query_record.finish(
            Message(f'没找到关于 ') + Message(question) + (Message(' 的对话')))

    Record = namedtuple('Record', [
        'sid', 'answer', 'probability', 'creator', 'source', 'creation_time',
        'public'
    ])
    result = map(lambda x: Record(*x), result)

    # 群里不把私聊中非公开对话列出,私聊中不把非自己创建的私聊非公开对话列出,用作最终显示数据
    result = [
        r for r in result if not (r.public == 0 and r.source == 0 and (
            event.message_type == 'group'
            or event.message_type != 'group' and event.user_id != r.creator))
    ]

    def sort_rule(r: Record) -> int:
        """按照本群限定>本群创建但公开>其它群创建但公开>其它群限定的顺序排列"""

        if r.source == gid:
            priority = 1 if not r.public else 2
        else:
            priority = 3 if r.public else 4
        return priority

    result.sort(key=sort_rule)

    # 可能在当前对话窗口出现的内容,把出现率是0、不在此群或私聊创建的非公开选项排除,用作计算绝对出现率
    # possible = [r for r in result if not (r.probability == 0 or (not r.public and r.source != gid))]
    # possible_count = len(possible)

    result_ls = [
        f'''ID:{sid}
回答:{msglize(answer, prestr=True)}
相对出现率:{probability}%
来自:{creator} 在 {('群' + str(source)) if source else '私聊'} 中创建的{'公开' if public else '群内限定'}对话
创建时间:
{creation_time}
────────────
''' for sid, answer, probability, creator, source, creation_time, public in
        result
    ]
    # TODO: 把回复里的音频和视频分离出来变成'[音频][视频]'
    # TODO:绝对出现率算出来

    record_bar = Pagination(*result_ls)
    if len(record_bar.rcd_ls) == 1:
        msg = ''.join(result_ls)
        await query_record.finish(
            reply_header(
                event,
                Message(
                    msg +
                    '使用"[修改出现率] <对话id> <出现率>"来修改指定对话的相对出现率\n例:修改出现率 -2234 -10')
            ))
    else:
        state["record_bar"] = record_bar
        state['left_wrong_times'] = 3
        await query_record.send(
            reply_header(
                event,
                Message(
                    str(record_bar) +
                    '\n发送[上一页][下一页]翻页查看列表,发送<序号>跳转到指定页,发送[退出]退出当前查询')))
Esempio n. 19
0
async def recieve_query(bot: Bot, event: MessageEvent, state: T_State):
    arg = await msg2str(Message(event.message))
    if arg:
        state["question"] = arg
Esempio n. 20
0
async def get_q(bot: Bot, event: MessageEvent, state: T_State):
    if "question" not in state:
        state["question"] = await msg2str(Message(event.raw_message))
    logger.debug(f'Current question is [{state["question"]}]')