Exemple #1
0
def event_set(bot_id, group_id, user_id, message, key, value, **argv):
    MessageLogs.add(group_id, user_id, nAIset=1)  #紀錄次數
    if group_id is None:
        return '目前沒有個人設定喵'
    else:
        if key == '全群組關鍵字':
            UserSettings.update(group_id, all_group_keyword=str2bool(value))
            return '設定完成'
        elif key == '髒話過濾':
            UserSettings.update(group_id, filter_fuck=str2bool(value))
        else:
            return ('目前可使用:\n'
                    '設定=髒話過濾=開/關\n'
                    '設定=全群組關鍵字=開/閉\n(可以使用別的群組的關鍵字)\n')
Exemple #2
0
def event_add(bot_id, group_id, user_id, message, key, value, **argv):
    MessageLogs.add(group_id, user_id, nAIset=1)  #紀錄次數
    filter_fuck = (group_id is None
                   or UserSettings.get(group_id, 'filter_fuck', True))
    if filter_fuck and isValueHaveKeys(message, cfg['詞組']['髒話']):
        return '愛醬覺得說髒話是不對的!!'

    if key is None:
        return cfg['學習說明']

    key = key.lower()
    if value is None or value == '':
        reply_message = ['<%s>' % key]

        if group_id is not None:
            data = UserKeyword.get(group_id, key)
            if data is not None:
                reply_message.append('群組=%s' % data.reply)

        if user_id is not None:
            data = UserKeyword.get(user_id, key)
            if data is not None:
                reply_message.append('個人=%s' % data.reply)

        return '\n'.join(reply_message) if len(
            reply_message) > 1 else '喵喵喵? 愛醬不記得<%s>' % (key)

    while '***' in key:
        key = key.replace('***', '**')
    while '|||' in key:
        key = key.replace('|||', '||')
    while '___' in key:
        key = key.replace('___', '__')

    for i in value.replace('__', '||').split('||'):
        i = i.strip()
        if i[:4] == 'http' and not is_image_and_ready(i):
            return '<%s>\n愛醬發現圖片網址是錯誤的\n請使用格式(jpg, png)\n短網址或網頁嵌圖片可能無效\n必須使用https' % i
        break  #如果全部都檢查時間會太久 只幫第一個檢查格式 通常使用者圖床也會使用同一個 應該不會有問題

    reply_message = ['<%s>記住了喔 ' % key]

    if group_id is not None and UserKeyword.add_and_update(
            group_id, user_id, key, value):
        reply_message.append('(群組)')

    if user_id is not None and UserKeyword.add_and_update(
            user_id, user_id, key, value):
        reply_message.append('(個人)')
    else:
        reply_message.append('(不儲存個人)\nhttps://goo.gl/zTwaL2')

    return ''.join(reply_message)
Exemple #3
0
def event_text_main(bot_id, group_id, user_id, message, reply_token, **argv):
    #紀錄最後使用時間 用來移除過久無人使用的資料
    if group_id is not None: UserSettings.refresh_last_time(group_id)
    if user_id is not None: UserSettings.refresh_last_time(user_id)

    message = message.replace('"', '"').replace("'", '’').replace(
        ';', ';')  #替換一些字元成全型 防SQL注入攻擊
    order, *value = message.split('=')
    for key, func in event_funcs.items():
        if key == order or key == '':
            reply_message = func(
                bot_id=bot_id,
                group_id=group_id,
                user_id=user_id,
                message=message,
                key=(value[0] if len(value) > 0 else None),
                value=('='.join(value[1:]) if len(value) > 1 else None),
                **argv)

            #公告
            if reply_message is None:
                reply_message = []
            if type(reply_message) == str:
                reply_message = [reply_message]

            if group_id is not None and UserSettings.check_news(group_id):
                reply_message.append(''.join(
                    [cfg['公告']['ver'], ' ', cfg['公告']['內容']]))

            for mid in [user_id, group_id]:
                if mid is not None and UserSettings_temp.has_option(
                        mid, '臨時公告'):
                    reply_message.append(UserSettings_temp.get(mid, '臨時公告'))
                    UserSettings_temp.remove_option(mid, '臨時公告')
                    UserSettings_temp.save()

            bots[bot_id].reply_message(reply_token, reply_message)
            db.session.commit()
            return reply_message
Exemple #4
0
    def check(self, userkeyword_list, all_reply=False):
        '''
            關鍵字觸發的邏輯檢查
        '''
        exclude_url = all_reply and not (not self.group or UserSettings.get(
            self.group.id, None, '全圖片', default=False))

        keys = []
        result = []

        for row in userkeyword_list:
            row_reply = row.reply

            if row_reply[:1] == '@':  #全回應模式過濾開頭@
                if all_reply:
                    continue
                else:
                    row_reply = row.reply[1:]

            if exclude_url and 'https:' in row_reply:  #全回應模式過濾網址只排除可能是圖片類型的
                continue

            if row.keyword == self.message:
                if all_reply:
                    result.append(row_reply)
                else:
                    return self.later(row_reply)
            elif row.keyword.replace('**', '') == self.message:
                result.append(row_reply)
            elif not all_reply or len(row_reply) > 1:  #超過一個字才加入全回應
                keys.append((row.keyword, row_reply))

        if len(result) > 0:
            return self.later(choice(result))  #結果集隨機抽取一個

        results = {}
        result_level = -99
        for k, v in keys:
            try:
                kn = -1
                k_arr = k.split('**')
                for k2 in k_arr:
                    if k2 != '':
                        n = self.message.find(k2)
                        if n > kn:
                            kn = n
                        else:
                            break
                    #最後檢查前後如果為任意字元的情況 那相對的最前最後一個字元必須相等 雖然使用字串會比較精準 暫時先用一個字元 如果**混在中間有可能誤判 但是問題不大
                    if k_arr[0] != '' and self.message[0] != k[0]: break
                    if k_arr[-1] != '' and self.message[-1] != k[-1]: break
                else:
                    #result.append(v)
                    level = len(k) - k.count('**') - (2 if k[:2] == '**' else
                                                      0) - (2 if k[-2:] == '**'
                                                            else 0)
                    if not level in results:
                        results[level] = []
                    if level > result_level:
                        result_level = level
                    results[level].append(v)
            except Exception as e:
                bots['admin'].send_message(
                    cfg['admin_line'],
                    '錯誤:%s\ngid:%s\nuid:%s\nmsg:%s\nkey:<%s>\n<%s>' %
                    (str(e), self.group_id, self.user_id, self.message, k, v))
                raise e

        if len(results) > 0:
            return self.later(choice(results[result_level]))

        return None
Exemple #5
0
    def main(self):
        '''
            關鍵字觸發
        '''
        if 'http:' in self.message or 'https:' in self.message:  #如果內容含有網址 做網址檢查
            if self.group:
                self._count({'網頁': 1})  #紀錄次數
                return google_safe_browsing(self.message)
            else:
                return google_shorten_url(self.message)  #短網址

        self.message = self.message.lower().strip(' \n')  #調整內容 以增加觸發命中率
        self._count({
            '對話': 1,
            '髒話': self.message.count('幹') + self.message.count('f**k'),
            '字數': len(self.message),
        })

        if self.message == '':
            return None

        #暫存訊息 用於對話模型訓練
        #if self.group:
        #    with open('E:\\bot_log\\%s.log' % self.group_id, 'a+', encoding='utf-8') as f:
        #        f.write(self.message + '\n')

        #愛醬開頭可以強制呼叫
        if self.group:
            if self.message != text['名稱'] and self.message[:2] == text['名稱']:
                message_old = self.message
                self.message = self.message[2:].strip(' \n ')
                reply_message = self.check(UserKeyword.get(self.group_id))
                if reply_message:
                    return reply_message

                reply_message = self.check(UserKeyword.get(self.user_id))
                if reply_message:
                    return reply_message
                self.message = message_old

        #睡覺模式
        if UserSettings_temp.has_option(self.group_id, '暫停'):
            if time() > UserSettings_temp.getfloat(self.group_id, '暫停'):
                UserSettings_temp.remove_option(self.group_id, '暫停')
                UserSettings_temp.save()
                return text['睡醒']
        #一般模式
        else:
            if not self.group or (self.user and UserSettings.get(
                    self.group.id, self.user.id, '個人詞庫', False)):  #檢查是否使用個人詞庫
                reply_message = self.check(UserKeyword.get(self.user.id))
                if reply_message:
                    return reply_message

            if self.group and self.user:
                if not UserSettings.get(self.group.id, self.user.id, '別理我',
                                        False):  #檢查不理我模式
                    reply_message = self.check(UserKeyword.get(self.group.id))
                    if reply_message:
                        return reply_message

        #全回應模式
        if self.message[:2] == text['名稱'] or self.group_id is None:
            if self.group is None or UserSettings.get(
                    self.group_id, None, '全回應', default=False):
                if self.message != text['名稱'] and self.message[:2] == text[
                        '名稱']:  #做兩層是為了方便1對1不見得也要愛醬開頭
                    self.message = self.message[2:].strip(' \n ')

                reply_message = self.check(UserKeyword.get(), all_reply=True)
                if reply_message:
                    return reply_message
                if self.group:
                    return choice(text['未知'])
            else:
                return choice(text['未知']) + '\n(全回應模式關閉)\n使用「設定」開啟'

        if self.group_id is None:
            return text['預設回覆']
        else:
            return None
Exemple #6
0
    def settings(self):
        '''
            設定
        '''
        if self.key is None:
            return [
                '設定=別理我=開/關\n'
                '設定=個人詞庫=開/關\n'
                '設定=全回應=開/關\n'
                '設定=全圖片=開/關(需要全回應)\n'
                '設定=幫忙愛醬=開/關\n'
                '\n'
                '(不輸入值可查看說明)',
                UserSettings.show(self.group_id, self.user_id)
            ]

        try:
            if self.key in ['過濾髒話', '髒話過濾']:
                return '這設定已經移除了'

            #全群組
            if self.key == '全回應':
                if self.value is None:
                    return '開啟後愛醬開頭的對話將從全部的詞庫中產生反應\n「預設:關」'
                UserSettings.update(self.group_id, None,
                                    {'全回應': text2bool(self.value)})
                return '設定完成'

            if self.key == '全圖片':
                if self.value is None:
                    return '開啟後全回應的結果包含圖片\n(需要開啟全圖片)\n(注意:圖片沒有任何審核 有可能出現不適圖片 如可接受再開啟)\n「預設:關」'
                UserSettings.update(self.group_id, None,
                                    {'全圖片': text2bool(self.value)})
                return '設定完成'

            if self.key == '幫忙愛醬':
                if self.value is None:
                    return '開啟後會快取群組的對話紀錄\n只用於機器學習\n作者會稍微過目後進行分類丟入程式\n用完後刪除「預設:關」\n使用「設定=幫忙愛醬=開」開啟'
                UserSettings.update(self.group_id, None,
                                    {'幫忙愛醬': text2bool(self.value)})
                return '設定完成'

            #群組中個人
            if self.key == '別理我':
                if self.value is None:
                    return '開啟後愛醬不會在此群組對你產生回應\n(愛醬開頭還是可以強制呼叫)\n「預設:關」'
                if self.user_id is None:
                    return text['權限不足']
                UserSettings.update(self.group_id, self.user_id,
                                    {'別理我': text2bool(self.value)})
                return '設定完成'

            if self.key == '個人詞庫':
                if self.value is None:
                    return '開啟後會對你的個人詞庫產生回應\n「預設:關」'
                if self.user_id is None:
                    return text['權限不足']
                UserSettings.update(self.group_id, self.user_id,
                                    {'個人詞庫': text2bool(self.value)})
                return '設定完成'

            return '沒有此設定喔'
        except Exception as e:
            return '設定錯誤 <%s>' % str(e)
    def later(self, reply_message):
        '''
            關鍵字觸發的後處理
        '''
        self._count({'觸發':1})

        #取參數
        opt = {}
        if '##' in reply_message:
            reply_message_new = []
            for i in reply_message.split('##'):
                if '=' in i:
                    a, *b = i.split('=')
                    opt[a] = '='.join(b)
                else:
                    reply_message_new.append(i)
            #reply_message = ''.join(reply_message_new)
            reply_message = reply_message[:reply_message.find('##')] #參數之後會由add儲存至database 這邊之後會廢棄

        filter_fuck = self.group_id is not None and UserSettings.get(self.group_id, None, '髒話過濾', True)
        if filter_fuck and isValueHaveKeys(self.message, cfg['詞組']['髒話']):
            return '愛醬是好孩子不說髒話!!\n(可用「設定」關閉)'

        #隨機 (算法:比重)
        if '__' in reply_message:
            weight_total = 0
            result_pool = {}
            minimum_pool = []
            for msg in reply_message.split('__'):
                if msg == '':
                    continue

                index = msg.rfind('%')
                if index > -1 and isFloat(msg[index+1:].strip()):
                #if index > -1 and msg[index+1:].strip().isdigit():
                    weight = float(msg[index+1:].strip())
                    msg = msg[:index]
                else:
                    weight = 1
                weight_total += weight

                is_minimum = msg[:1] == '*'
                if is_minimum:
                    is_minimum_pool = msg[:2] == '**'
                    msg = msg[2:] if is_minimum_pool else msg[1:]

                result_pool[msg] = {
                    'weight':weight,
                    'is_minimum':is_minimum,
                }
                if is_minimum and is_minimum_pool:
                    minimum_pool.append(msg)

            if opt.get('百分比', '0').isdigit(): #百分比隨機模式
                number = int(opt.get('百分比', '0'))
                if number > 0:
                    reply_message = []
                    total = 100.0

                    if number > len(result_pool):
                        number = len(result_pool)
                    result_pool = sample([msg for msg, msg_opt in result_pool.items()], number)

                    n = 0
                    for msg in result_pool:
                        n += 1
                        if n >= number or n >= len(result_pool):
                            ratio = total
                            total = 0
                        else:
                            ratio = uniform(0, total)
                            total -= ratio
                        reply_message.append('%s(%3.2f%)' % (msg, ratio))
                        if total <= 0:
                            break

                    return '\n'.join(reply_message)

            count = int(self.message[self.message.rfind('*')+1:]) if '*' in self.message and self.message[self.message.rfind('*')+1:].isdigit() else 1
            if count > 10000: count = 10000
            if count <  1: count = 1
            if count == 1 and '種子' in opt and opt['種子'].isdigit() and int(opt['種子']) > 0:
                seed_time = int((datetime.now()-datetime(2017,1,1)).days * 24 / int(opt['種子']))
                seed = int(md5((str(self.user_id) + str(seed_time)).encode()).hexdigest().encode(), 16) % weight_total
            else:
                try:
                    #random.org的隨機據說為真隨機
                    if count > 1:
                        r = requests.get('https://www.random.org/integers/?num=%s&min=0&max=%s&col=1&base=10&format=plain&rnd=new' % (count, int(weight_total)), timeout=3)
                        if 'Error' in r.text:
                            raise
                        seed = r.text.split('\n')[:-1]
                    else:
                        raise
                except:
                    seed = [uniform(0, int(weight_total)) for i in range(count)]

            minimum_count = 0
            minimum_index = int(opt.get('保底', 10))
            reply_message_new = {}
            reply_message_image = []
            for i in range(count):
                #r = uniform(0, weight_total) if seed == -1 else seed
                r = float(seed[i]) if type(seed) == list else seed
                for msg, msg_opt in result_pool.items():
                    if r > msg_opt['weight']:
                        r -= msg_opt['weight']
                    else:
                        minimum_count = 0 if msg_opt['is_minimum'] else minimum_count + 1
                        if minimum_count >= minimum_index and len(minimum_pool) > 0:
                            minimum_count = 0
                            msg = choice(minimum_pool)
                        if msg[:6] == 'https:':
                            reply_message_image.append(msg)
                            if len(reply_message_image) > 5:
                                break
                        else:
                            reply_message_new[msg] = (reply_message_new[msg] + 1) if msg in reply_message_new else 1
                        break
                    
            if len(reply_message_new) > 0:
                if count == 1:
                    reply_message = list(reply_message_new.keys())
                else:
                    reply_message = []
                    for msg, num in reply_message_new.items():
                        reply_message.append('%s x %s' % (msg, num))
                    reply_message = ['\n'.join(reply_message)]
            else:
                reply_message = []
            reply_message.extend(reply_message_image[:5])
                
        #這邊有待優化
        if type(reply_message) == str:
            reply_message = [reply_message]
        reply_message_new = []
        for msg in reply_message:
            for msg_split in msg.split('||'):
                reply_message_new.append(msg_split)
        return reply_message_new
Exemple #8
0
def event_main(bot_id, group_id, user_id, message, key, value, **argv):
    #後處理
    def later(reply_message):
        MessageLogs.add(group_id, user_id, nAItrigger=1)  #紀錄次數

        #取參數
        opt = {}
        if '##' in reply_message:
            reply_message_new = []
            for i in reply_message.split('##'):
                if '=' in i:
                    a, *b = i.split('=')
                    opt[a] = '='.join(b)
                else:
                    reply_message_new.append(i)
            reply_message = ''.join(reply_message_new)

        #隨機 (算法:比重)
        if '__' in reply_message:
            weight_total = 0
            result_pool = {}
            minimum_pool = []
            for msg in reply_message.split('__'):
                if msg == '':
                    continue

                index = msg.rfind('%')
                if index > -1 and isFloat(msg[index + 1:].strip()):
                    #if index > -1 and msg[index+1:].strip().isdigit():
                    weight = float(msg[index + 1:].strip())
                    msg = msg[:index]
                else:
                    weight = 1
                weight_total += weight

                is_minimum = msg[:1] == '*'
                if is_minimum:
                    is_minimum_pool = msg[:2] == '**'
                    msg = msg[2:] if is_minimum_pool else msg[1:]

                result_pool[msg] = {
                    'weight': weight,
                    'is_minimum': is_minimum,
                }
                if is_minimum and is_minimum_pool:
                    minimum_pool.append(msg)

            count = int(
                message[message.rfind('*') +
                        1:]) if '*' in message and message[message.rfind('*') +
                                                           1:].isdigit() else 1
            if count > 10000: count = 10000
            if count < 1: count = 1
            if count == 1 and '種子' in opt and opt['種子'].isdigit() and int(
                    opt['種子']) > 0:
                seed_time = int((datetime.now() - datetime(2017, 1, 1)).days *
                                24 / int(opt['種子']))
                seed = int(
                    md5((str(user_id) + str(seed_time)
                         ).encode()).hexdigest().encode(), 16) % weight_total
            else:
                try:
                    #random.org的隨機據說為真隨機
                    if count > 1:
                        r = requests.get(
                            'https://www.random.org/integers/?num=%s&min=0&max=%s&col=1&base=10&format=plain&rnd=new'
                            % (count, int(weight_total)),
                            timeout=3)
                        if 'Error' in r.text:
                            raise
                        seed = r.text.split('\n')[:-1]
                    else:
                        raise
                except:
                    seed = [
                        uniform(0, int(weight_total)) for i in range(count)
                    ]

            minimum_count = 0
            minimum_index = int(opt.get('保底', 10))
            reply_message_new = {}
            reply_message_image = []
            for i in range(count):
                #r = uniform(0, weight_total) if seed == -1 else seed
                r = float(seed[i]) if type(seed) == list else seed
                for msg, msg_opt in result_pool.items():
                    if r > msg_opt['weight']:
                        r -= msg_opt['weight']
                    else:
                        minimum_count = 0 if msg_opt[
                            'is_minimum'] else minimum_count + 1
                        if minimum_count >= minimum_index and len(
                                minimum_pool) > 0:
                            minimum_count = 0
                            msg = choice(minimum_pool)
                        if msg[:6] == 'https:':
                            reply_message_image.append(msg)
                            if len(reply_message_image) > 5:
                                break
                        else:
                            reply_message_new[msg] = (
                                reply_message_new[msg] +
                                1) if msg in reply_message_new else 1
                        break

            if len(reply_message_new) > 0:
                if count == 1:
                    reply_message = list(reply_message_new.keys())
                else:
                    reply_message = []
                    for msg, num in reply_message_new.items():
                        reply_message.append('%s x %s' % (msg, num))
                    reply_message = ['\n'.join(reply_message)]
            else:
                reply_message = []
            reply_message.extend(reply_message_image[:5])

        #這邊有待優化
        if type(reply_message) == str:
            reply_message = [reply_message]
        reply_message_new = []
        for msg in reply_message:
            for msg_split in msg.split('||'):
                reply_message_new.append(msg_split)
        return reply_message_new

    message = message.lower()
    if 'http:' in message or 'https:' in message:  #如果內容含有網址 不觸發 順便紀錄
        MessageLogs.add(group_id, user_id, nUrl=1)  #紀錄次數
        return None
    else:
        MessageLogs.add(group_id,
                        user_id,
                        nText=1,
                        nFuck=(message.count('幹') + message.count('f**k')),
                        nLenght=len(message))  #紀錄次數

    if UserSettings_temp.has_option(group_id, '暫停'):
        if time() > UserSettings_temp.getfloat(group_id, '暫停'):
            UserSettings_temp.remove_option(group_id, '暫停')
            UserSettings_temp.save()
            return '愛醬大復活!'
        else:
            return None

    if group_id is not None:
        reply_message = UserKeyword.get(group_id, message)
        if reply_message is not None:
            return later(reply_message.reply)

    if user_id is not None:
        reply_message = UserKeyword.get(user_id, message)
        if reply_message is not None:
            return later(reply_message.reply)

    keys = []
    if group_id is not None:
        for i in UserKeyword.get(group_id):
            keys.append((i.keyword, i.reply))
    if user_id is not None:
        for i in UserKeyword.get(user_id):
            keys.append((i.keyword, i.reply))

    for k, v in keys:
        kn = -1
        k_arr = k.split('**')
        for k2 in k_arr:
            if k2 != '':
                n = message.find(k2)
                if n > kn:
                    kn = n
                else:
                    break
            #最後檢查前後如果為任意字元的情況 那相對的最前最後一個字元必須相等 雖然使用字串會比較精準 暫時先用一個字元 如果**混在中間有可能誤判 但是問題不大
            if k_arr[0] != '' and message[0] != k[0]: break
            if k_arr[-1] != '' and message[-1] != k[-1]: break
        else:
            return later(v)

    #使用全群組的關鍵字 限無**
    if group_id is not None and UserSettings.get(group_id, 'all_group_keyword',
                                                 False):
        for k in UserKeyword.query.filter_by(
                super=0, keyword=message).order_by(UserKeyword._id.desc()):
            return later(k.reply)

    if group_id is None:
        message = message.strip()
        if message[:4] == 'http':
            return '愛醬幫你申請短網址了喵\n%s' % google_shorten_url(message)
        else:
            return '群組指令說明輸入【指令】\n個人服務:\n直接傳給愛醬網址即可產生短網址\n直接傳圖給愛醬即可上傳到圖床\n其他功能如果有建議請使用回報'
    else:
        return None