コード例 #1
0
ファイル: __init__.py プロジェクト: desolution025/Sanae-Bot
async def batch_get_prob(bot: Bot, event: MessageEvent, state: T_State):
    if str(event.message) in CANCEL_EXPRESSION:
        await learn.finish('已退出当前对话')
    if not event.raw_message.isdigit():
        state['wrong_times'] += 1
        if state['wrong_times'] < 3:
            await batch_learn.reject(
                prompt='请输入数字参数作为相对出现率,范围[0-100],请重新输入,发送[取消]结束当前学习对话')
        else:
            await batch_learn.finish('看来你是不想好好说了,就这样吧,挂了')

    prob = int(event.raw_message)
    if prob < 0 or prob > 100:
        state['wrong_times'] += 1
        if state['wrong_times'] < 3:
            await batch_learn.reject(
                prompt='输入范围应该是[0-100],请重新输入,发送[取消]结束当前学习对话')
        else:
            await batch_learn.send('不要闹了,我先帮你设置成50了,要该的话之后用[设置出现率]来改吧')
            asyncio.sleep(1)  # 停一秒防止设置成功的消息和此条消息顺序出错

    public = 0 if state["force_priv"] else state["public"]
    source = event.group_id if event.message_type == "group" and 'selflearn' not in state else 0
    creator = event.user_id if 'selflearn' not in state else event.self_id
    result = insertmany(state["question"].split('|'),
                        state["answer"].split('|'), prob, creator, source,
                        public)
    if isinstance(result, int):
        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) + result - 1
            fund = cgauss(fund_mu, 1, 1) + result - 1
            user = UserLevel(event.user_id)
            await user.expup(exp, bot, event)
            user.turnover(fund)
            msg = f'已记录{result}条对话,赠送您{exp}exp 和 {fund}金币作为谢礼~'
            dlmt.increase()
        else:
            dlmt.conn.close()
            msg = f'已记录{result}条对话'
        if state["force_priv"]:
            msg += "\n(消息中含at信息,将强制设置公开性为群内限定)"
    else:
        repeat_ls = [
            f"问句:{emojize(q)} 回答:{a} 被{creator}在{creation_time}创建"
            for q, a, creator, creation_time in result
        ]
        msg = f'以下对话已存在:\n' + '\n'.join(repeat_ls) + '\n请去除重复对话后重新学习'
    await batch_learn.finish(msg)
コード例 #2
0
ファイル: __init__.py プロジェクト: desolution025/Sanae-Bot
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, '这条词语好像记不住耶,要不联系主人试试?'))
コード例 #3
0
ファイル: sign_in.py プロジェクト: desolution025/Sanae-Bot
async def sign_(bot: Bot, event: MessageEvent):
    uid = event.user_id
    user = UserLevel(uid)

    # 是否可以签到
    today = date.today()
    last_sign_day = user.last_sign.date()

    if today > last_sign_day:
        with QbotDB() as botdb:
            botdb.update(
                'update userinfo set `last_sign`=NOW(), total_sign=total_sign+1 where qq_number=%s;',
                (uid, ))

        gndexp = cgauss(8, 2, 0)
        gndfund = cgauss(25, 3, 0)

        await user.expup(gndexp, bot, event)
        user.turnover(gndfund)
        await sign.send(reply_header(event,
                                     f'感谢签到,经验值+{gndexp},资金+{gndfund}!'))

    else:
        await sign.finish(reply_header(event, '今天你已经签到过了哦~'))
コード例 #4
0
ファイル: __init__.py プロジェクト: desolution025/Sanae-Bot
async def check_fortune(bot: Bot, event: MessageEvent):
    name = event.sender.card if event.message_type == 'group' else event.sender.nickname
    dlmt = DailyNumberLimiter(event.user_id, func_name='运势', max_num=1)
    stick = query_fortune(event.user_id)
    rp = 0  # 如果抽中了特殊的签要发生一些事件 TODO:加入一些今天功能冷却减少之类的什么奖励吧
    if dlmt.check(close_conn=False) or not stick:
        stick = choice(sticks)
        if dlmt.count == 0:
            if stick.name == '28.jpg':  # 恋爱运,惩罚
                rp = 1
            elif stick.name == '27.jpg':  # 凶,奖励
                rp = 2
            elif stick.name in ('8.jpg', '16.jpg', '19.jpg'):  # 金运,给钱
                rp = 3
            elif stick.name in ('15.jpg', '23.jpg'):  # 全体运,群内统统滴奖励,私聊无效
                rp = 4
            elif stick.name == '17.jpg':  # 关系运, 私聊的时候给予奖励吧
                rp = 5

        draw_fortune(event.user_id, stick.name)
        dlmt.increase()
    else:
        dlmt.conn.close()
        stick = assets_folder / stick
    logger.debug(f'{event.user_id} got stick {stick.name}')
    await fortune.send(f'{name}今日的运势是' + imgseg(stick), at_sender=True)

    if rp:
        await asleep(1.5)
        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()

        if rp == 1 and is_user(event.user_id):
            exp = randint(9, 15)
            fund = randint(20, 30)
            user = UserLevel(event.user_id)
            await user.expup(-exp, bot, event)
            user.turnover(-fund, check_overdraft=False)
            await fortune.finish(
                f'虽然你抽中了恋爱运也不一定会遇到恋爱事件,不过对和恋爱沾边的家伙给予惩罚才是正义的\n{name}的exp -{exp}, 资金 -{fund}',
                at_sender=True)

        elif rp == 2 and is_user(event.user_id):
            exp = randint(15, 25)
            fund = randint(30, 50)
            user = UserLevel(event.user_id)
            await user.expup(exp, bot, event)
            user.turnover(fund)
            await fortune.finish(
                'Emmmm,因为占卜的师傅如果不是有别的什么目的的话,为了讨好前来占卜的人都会尽量说是吉签嘛\n    抽到这个凶签这种小概率事件,某种意义上这才是奇迹真正应该有的样子'
                f'\n{name}获得了{exp}exp和{fund}资金',
                at_sender=True)

        elif rp == 3 and is_user(event.user_id):
            fund = randint(20, 30)
            user = UserLevel(event.user_id)
            user.turnover(fund)
            await fortune.finish(
                f'因为{BOTNAME}给不了你软妹币所以也只好送些这个给你了~不过说不定哪天它会像比特币一样突然价值激增哦~\n{name}获得了{fund}资金',
                at_sender=True)

        elif rp == 4:
            if event.message_type == 'group':

                await fortune.send('大家会感谢你的,无私的散财者~骗你的( •̀ ω •́ )✧',
                                   at_sender=True)
                memberlist = await bot.get_group_member_list(
                    group_id=event.group_id)
                uids = filter_users(*[m['user_id'] for m in memberlist])
                if len(uids) > 5:
                    uids = get_active_user(*uids)
                logger.debug(f'获得奖励的群员{uids}')
                if uids:
                    for uid in uids:
                        exp = randint(5, 8)
                        fund = randint(5, 8)
                        user = UserLevel(uid)
                        await user.expup(exp,
                                         bot,
                                         event=None,
                                         gid=event.group_id)

                        try:
                            member = await bot.get_group_member_info(
                                group_id=event.group_id, user_id=uid)
                        except ActionFailed as e:
                            logger.warning(
                                f'可能是已经退群的群员: group: {event.group_id} qq: {uid}, error: {e}'
                            )
                            await fortune.send(
                                group_id=event.group_id,
                                message=
                                f'本应该在群内的成员({uid})貌似获取不到了,是不是退群了呢?没有的话请联系维护组查看一下出问题的原因哦~'
                            )
                            continue

                        name = member['card'] or member['nickname'] or str(uid)
                        await fortune.send(message=MessageSegment.text(
                            f'{name}获得了{exp}exp和{fund}资金') +
                                           MessageSegment.at(qq=uid))
                        await asleep(1.5)

                else:
                    await fortune.finish('啊嘞,这个群里好像还没有能获得奖励的伙伴呢~')
            else:
                await fortune.finish('可惜这里是私聊所以全体运的效果生效不了了呢~')

        elif rp == 5 and is_user(event.user_id):
            if event.message_type == 'group':
                await fortune.finish('啊~获得了可以增加亲密度的签,但是这个签只有私聊抽中的时候才有效哦~残念',
                                     at_sender=True)
            else:
                exp = randint(25, 40)
                fund = randint(40, 50)
                user = UserLevel(event.user_id)
                await user.expup(exp, bot, event)
                user.turnover(fund)
                await fortune.finish(
                    f'真的为了什么才和{BOTNAME}进行私密对话的吗?送你{exp}exp和{fund}资金吧,除了这些{BOTNAME}也没有其它的了'
                )
コード例 #5
0
async def send_lolicon(bot: Bot, event: MessageEvent, state: T_State):

    gid = event.group_id if event.message_type=='group' else 0
    if gid:
        if str(gid) not in sl_settings:
            await setu.finish('''先设置本群sl再使用此功能吧
[设置sl 最小sl-最大sl]
例如:设置sl 0-4
────────────
sl说明:
大概可以解释成本群能接收的工口程度,sl越高的图被人看见越会触发社死事件
※ r18权限已改为sl, 当最大sl为5时即为开启r18权限,sl0-4级别仅适用于美图,色图会自动忽略
最低sl0:不含任何ero要素,纯陶冶情操,也有一部分风景图
最高sl5: 就是R18了
中间的等级依次过渡''')

        max_sl = sl_settings[str(gid)]['max_sl']
        min_sl = sl_settings[str(gid)]['min_sl']
        restricted = True if max_sl < 5 else False  # r18是否在本群受限
    else:
        restricted = False

    # 限制条件优先度:r18,5张最大数,等级限制数量,频率,资金,由于要检测参数只好先把个别参数解析混入条款中了
    uid = event.user_id

    # r18限制条款,顺便解析了r18
    r18_call = state["_matched_dict"]['r18_call'] or state["_matched_dict"]['r18_call2']
    if r18_call and restricted:
        await setu.finish(reply_header(event, f'当前群内最大sl为{max_sl},已禁止R18内容'))

    # 5张最大数量限制条款,顺便解析了num
    if state["_matched_dict"]['num']:
        num = cn2an(state["_matched_dict"]['num'].replace('两', '二'), 'smart')
    elif state["_matched_dict"]['num2']:
        num = cn2an(state["_matched_dict"]['num2'].replace('两', '二'), 'smart')
    else:
        num = 1

    if num > 5:
        await setu.finish(reply_header(event, '一次最多只能要5张'))
    elif num == 0:
        await setu.finish(reply_header(event, '你好奇怪的要求'))
    elif num < 0:
        await setu.finish(reply_header(event, f'好的,你现在欠大家{-num}张涩图,快发吧'))  # TODO: 想想办法把负数给提取出来

    # 等级限制数量条款,注册了用户信息
    userinfo = UserLevel(uid)
    if userinfo.level < num:
        if userinfo.level > 0:
            await setu.finish(f'您当前等级为{userinfo.level},最多一次要{userinfo.level}张')
        elif num > 1:
            await setu.finish(reply_header(event, '啊这..0级用户一次只能叫一张哦,使用[签到]或者学习对话可以提升等级~'))

    # 频率限制条款,注册了频率限制器
    flmt = FreqLimiter(uid, 'setu')
    if not flmt.check():
        refuse = f'你冲得太快了,请{ceil(flmt.left_time())}秒后再冲'  # 不用round主要是防止出现'还有0秒'的不科学情况
        if userinfo.level == 0:
            refuse += ',提升等级可以加快装填哦~'
        await setu.finish(reply_header(event, refuse))
    cd = cd_step(userinfo.level, 480)  # 冷却时间
    flmt.start_cd(cd)  # 先进行冷却,防止连续呼叫击穿频率装甲,要是没返回图的话解掉

    # 资金限制条款,注册了每日次数限制器
    cost = num * 3
    dlmt = DailyNumberLimiter(uid, '色图', 3)
    in_free = True if event.message_type == 'private' and event.sub_type == 'friend'\
            else dlmt.check(close_conn=False)  # 来自好友的对话不消耗金币

    if userinfo.fund < cost and not in_free:
        if userinfo.fund > 0:
            refuse = choice((f'你还剩{userinfo.fund}块钱啦,要饭也不至于这么穷吧!', f'你只剩{userinfo.fund}块钱了,要不考虑援交一下赚点钱?'))
        elif userinfo.level == 0 and userinfo.fund == 0:
            refuse = '每天有三次免费次数哦,使用[签到]领取资金来获得更多使用次数吧~'
        else:
            refuse = '你已经穷得裤子都穿不起了,到底是做了什么呀?!'
        dlmt.conn.close()  # 确认直接结束不会增加调用次数了,直接返还链接
        flmt.start_cd(0)
        await setu.finish(reply_header(event, refuse))

    kwd = state["_matched_dict"]['kwd'] or ''

    if r18_call:
        r18 = 1 if r18_call in ('r18', 'R18') else 0      
    else:
        if event.message_type == 'group':
            if max_sl < 5:
                r18 = 0
            elif min_sl == 5:
                r18 = 1
            elif min_sl < 5:
                r18 = 2
        else:
            r18 = 2
    
    msg = MessageSegment.reply(id_=event.message_id) if event.message_type == 'group' else MessageSegment.text('') # 由于当前私聊回复有bug所以只在群里设置信息开始为回复消息

    # 有搜索条件,从本地库中提
    if kwd:
        kwds = tuple(kwdrex.split(kwd))
        success, result = get_setu(gid, kwds, num, r18)
        if not success:
            flmt.start_cd(0)
            dlmt.conn.close()
            await setu.finish(reply_header(event, result))

        count = result['count']  # 返回数量,每次处理过后自减1
        miss_count = 0  # 丢失数量
        for data in result['data']:
            if data is None:
                miss_count += 1
                continue
            img : Path = data['file']
            logger.debug(f'当前处理本地图片{img.name}')
            info = f"{data['title']}\n画师:{data['author']}\nPID:{data['source']}\n"
            try:
                im_b64 = Image_Handler(img).save2b64()
            except OSError as err:
                miss_count += 1
                logger.error(f'File {img} may be damaged: {err}')
                continue
            except UnidentifiedImageError as imgerr:
                miss_count += 1
                logger.error(f'failed to open local file: {img}: {imgerr}')
                continue
            msg += MessageSegment.text(info) + MessageSegment.image(im_b64)
            if count > 1:
                msg += MessageSegment.text('\n=====================\n')
                count -= 1
            elif result['count'] < num:
                msg += MessageSegment.text(f'\n=====================\n没搜到{num}张,只搜到这些了')

    # 无搜索条件,链接API,5次错误退出并反馈错误
    else:
        logger.debug('Start getting lolicon API')
        failed_time = 0
        while failed_time < 5:
            try:
                result = await get_lolicon(kwd, r18, num)
                break
            except BaseException as e:
                failed_time += 1
                logger.exception(f"connect api faild {failed_time} time(s)\n{e}")
        else:
            logger.error(f'多次链接API失败,当前参数: kwd: [{kwd}], num: {num}, r18: {r18}')
            dlmt.conn.close()
            flmt.start_cd(0)
            await setu.finish('链接API失败, 若多次失败请反馈给维护组', at_sender=True)
        logger.debug('Receive lolicon API data!')

        # 处理数据
        if result['code'] == 0:
            count = result['count']  # 返回数量,每次处理过后自减1
            untreated_ls = []  # 未处理数据列表,遇到本地库中没有的数据要加入这个列表做并发下载
            miss_count = 0  # 丢失数量
            for data in result['data']:
                pid = data['pid']
                p = data['p']
                name = f'{pid}_p{p}'
                # 按 色图备份路径->美图原文件路径 顺序查找本地图,遇到没有本地路径的等待并发下载处理
                imgbkup = [f for f in Path(SETUPATH).glob(f'{name}.[jp][pn]*g')]
                if imgbkup:
                    img = imgbkup[0]
                else:
                    imgorg = [f for f in (Path(MEITUPATH)/'origin_info').rglob(f'{name}.[jp][pn]*g')]
                    if imgorg:
                        img = imgorg[0]
                    else:
                        untreated_ls.append(data)
                        continue
                logger.debug(f'当前处理本地图片{name}')
                info = f"{data['title']}\n画师:{data['author']}\nPID:{name}\n"
                try:
                    im_b64 = Image_Handler(img).save2b64()
                except UnidentifiedImageError as imgerr:
                    miss_count += 1
                    logger.error(f'failed to open local file: {img}: {imgerr}')
                    continue
                msg += MessageSegment.text(info) + MessageSegment.image(im_b64)
                if count > 1:
                    msg += MessageSegment.text('\n=====================\n')
                    count -= 1
                elif result['count'] < num:
                    msg += MessageSegment.text(f'\n=====================\n没搜到{num}张,只搜到这些了')
                
            # 对未处理过的数据进行并发下载,只下载1200做临时使用
            async with httpx.AsyncClient() as client:
                task_ls = []
                for imgurl in [d['url'] for d in untreated_ls]:
                    task_ls.append(client.get(get_1200(imgurl), timeout=120))
                imgs = await gather(*task_ls, return_exceptions=True)
                
            for i, data in enumerate(untreated_ls):
                if isinstance(imgs[i], BaseException):
                    miss_count += 1
                    logger.exception(data)
                    continue
                if imgs[i].status_code != httpx.codes.OK:
                    miss_count += 1
                    logger.error(f'Got unsuccessful status_code [{imgs[i].status_code}] when visit url: {imgs[i].url}')
                    continue
                pid = data['pid']
                p = data['p']
                name = f'{pid}_p{p}'
                info = f"{data['title']}\n画师:{data['author']}\nPID:{name}\n"
                logger.debug(f'当前处理网络图片{name}')
                try:
                    im_b64 = Image_Handler(imgs[i].content).save2b64()
                except BaseException as err:
                    logger.error(f"Error with handle {name}, url: [{data['url']}]\n{err}")
                    miss_count += 1
                    continue

                msg += MessageSegment.text(info) + MessageSegment.image(im_b64)
                if count > 1:
                    msg += MessageSegment.text('\n=====================\n')
                    count -= 1
                elif result['count'] < num:
                    msg += MessageSegment.text(f'\n=====================\n没搜到{num}张,只搜到这些了')
            if miss_count > 0 and num > 1:
                msg += MessageSegment.text(f'\n有{miss_count}张图丢掉了,{BOTNAME}也不知道丢到哪里去了T_T')
            elif miss_count == 1:
                msg += MessageSegment.text(f'{BOTNAME}拿来了图片但是弄丢了呜呜T_T')
        else:
            flmt.start_cd(0)
            dlmt.conn.close()
            await setu.finish(msg + MessageSegment.text('获取涩图失败,请稍后再试'))

    try:
        await setu.send(msg)
    except NetworkError as err:
        logger.error(f'Maybe callout error happend: {err}')
    except AdapterException as err:
        logger.error(f"Some Unkown error: {err}")

    if miss_count < result['count']:
        if not in_free:
            cost = (result['count'] - miss_count) * 3  # 返回数量可能少于调用量,并且要减去miss的数量
            userinfo.turnover(-cost)  # 如果超过每天三次的免费次数则扣除相应资金
        dlmt.increase()  # 调用量加一
    else:
        flmt.start_cd(0)  # 一张没得到也刷新CD
        dlmt.conn.close()

    # 下载原始图片做本地备份
    if not kwd:
        async with httpx.AsyncClient() as bakeuper:
            backup_ls = []
            json_ls = []
            for info in untreated_ls:
                url = info['url']
                json_data = {
                    'pid': info['pid'],
                    'p': info['p'],
                    'uid': info['uid'],
                    'title': info['title'],
                    'author': info['author'],
                    'url': url,
                    'r18': info['r18'],
                    'tags': info['tags']
                }
                backup_ls.append(bakeuper.get(url, timeout=500))
                json_ls.append(json_data)
            origims = await gather(*backup_ls, return_exceptions=True)
            for i, im in enumerate(origims):
                if isinstance(im, BaseException):
                    logger.exception(im)
                    continue
                if im.status_code != httpx.codes.OK:
                    logger.error(f'Got unsuccessful status_code [{im.status_code}] when visit url: {im.url}')
                    continue
                imgfp = Path(SETUPATH)/(str(json_ls[i]['pid']) + '_p' + str(json_ls[i]['p']) + '.' + json_ls[i]['url'].split('.')[-1])
                jsonfp = Path(SETUPATH)/(str(json_ls[i]['pid']) + '_p' + str(json_ls[i]['p']) + '.json')
                try:
                    with imgfp.open('wb') as f:
                        f.write(im.content)
                    logger.info(f'Downloaded image {imgfp.absolute()}')
                except BaseException as e:
                    logger.exception(e)
                with jsonfp.open('w', encoding='utf-8') as j:
                    json.dump(json_ls[i], j, ensure_ascii=False, escape_forward_slashes=False, indent=4)
                    logger.info(f'Generated json {jsonfp.absolute()}')
                increase_setu(**json_ls[i])