async def custom_config(ctx): """ Verifica as configurações customizaveis para este server. """ server = make_hash('id', ctx.message.guild.id).decode('utf-8') payload = Query.get_custom_config(server) gql_client = get_gql_client(BACKEND_URL) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') return await ctx.send('D-desculpa, não consegui...') data = response.get('custom_config') embed = discord.Embed(color=0x1E1E1E, type='rich') embed.add_field(name='Server', value=data.get('server_name'), inline=True) embed.add_field(name='Sys Channel', value=data.get('main_channel'), inline=True) embed.add_field(name='Allow auto send message', value=data.get('allow_auto_send_messages'), inline=False) embed.add_field(name='Allow chat learning', value=data.get('allow_learning_from_chat'), inline=False) embed.add_field(name='Filter offensive messages', value=data.get('filter_offensive_messages'), inline=False) return await ctx.send('Configurações do servidor:', embed=embed)
async def quote(ctx, *args): """ Ensina um novo quote à Luci """ message = ' '.join(word for word in args) author = ctx.author.name if not message: return await ctx.send( 'Por favor insira uma mensagem.\nExemplo:\n'\ '``` !quote my name is bond, vagabond ```' ) if '@' in message: return await ctx.send( 'Eu não posso aprender esse tipo de coisa. Vou contar pro meu pai.' ) server = make_hash('id', ctx.guild.id) payload = Mutation.create_quote(message, server.decode('utf-8'), author) client = get_gql_client(BACKEND_URL) try: response = client.execute(payload) except Exception as err: print(f'Erro: {str(err)}\n\n') return await ctx.send('Buguei') quote = response['create_quote'].get('quote') embed = discord.Embed(color=0x1E1E1E, type="rich") embed.add_field(name='Entendi:', value=quote.get('quote'), inline=True) return await ctx.send('Ok:', embed=embed)
async def source(ctx, *args): """ Pergunta quem foi que ensinou a mensagem. """ text = ' '.join(char for char in args) if not text.strip(): return await ctx.send('Ué você não disse nada ...') query = Query.get_message_authors(text) gql_client = get_gql_client(BACKEND_URL) try: response = gql_client.execute(query) except Exception as err: log.error(f'Erro: {str(err)}\n\n') return authors = set() messages = response.get('messages', []) if not messages: return await ctx.send('Não conhecia essa ainda, até agora...') for message in messages: authors.add(message.get('author')) if len(authors) > 9: return await ctx.send( f'Ja vi tipo umas {len(authors)} pessoas dizerem isso :rolling_eyes:' ) authors = ';'.join(author for author in list(authors)) return await ctx.send(f'Aprendi isso com {authors}')
async def user_status(ctx): """ Verifica o relatório de afeição que Luci possui de um determinado membro. Uso: !user @Username """ mentions = ctx.message.mentions if not mentions: return await tx.send( 'Não sei de quem vc está falando. Marca ele tipo @Fulano.') # consulta os membros no backend server = make_hash('id', ctx.message.guild.id).decode('utf-8') user_id = make_hash(server, mentions[0].id).decode('utf-8') payload = Query.get_user(user_id) gql_client = get_gql_client(BACKEND_URL) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') return data = response.get('users', []) if not data: return await ctx.send('Acho que não c-conheço... Desculpa.') # monta a resposta embed = discord.Embed(color=0x1E1E1E, type='rich') name = data[0].get('name') friendshipness = data[0].get('friendshipness', 0) emotions = data[0].get('emotion_resume', {}) user_id = extract_user_id(data[0]['reference']) pleasantness_status = EmotionHourglass.get_pleasantness( emotions["pleasantness"]) pleasantness = f':heart_decoration: {emotions["pleasantness"]:.2f} '\ f'| status: {pleasantness_status}' attention_status = EmotionHourglass.get_attention(emotions["attention"]) attention = f':yin_yang: {emotions["attention"]:.2f} | status: {attention_status}' sensitivity_status = EmotionHourglass.get_sensitivity( emotions["sensitivity"]) sensitivity = f':place_of_worship: {emotions["sensitivity"]:.2f} | ' \ f'status: {sensitivity_status}' aptitude_status = EmotionHourglass.get_aptitude(emotions["aptitude"]) aptitude = f':atom: {emotions["aptitude"]:.2f} | status: {aptitude_status}' embed.add_field(name='Username', value=name, inline=True) embed.add_field(name='Affection', value=friendshipness, inline=True) embed.add_field(name='Pleasantness', value=pleasantness, inline=False) embed.add_field(name='Attention', value=attention, inline=False) embed.add_field(name='Sensitivity', value=sensitivity, inline=False) embed.add_field(name='Aptitude', value=aptitude, inline=False) return await ctx.send('', embed=embed)
async def track(self): """ Tracking task """ log.info('tracking...') gql_client = get_gql_client(BACKEND_URL) for guild in self.guilds: log.info(guild.name) server = make_hash('id', guild.id).decode('utf-8') # recupera a configuração do server query = Query.get_custom_config(server) try: response = gql_client.execute(query) except: log.error(f'Cant get server {guild.name} config. Skipping!') continue server_config = response.get('custom_config') main_channel = server_config.get('main_channel') if not main_channel: continue channel = client.get_channel(int(main_channel)) # data da última mensagem enviada no server try: last_message_dt = parser.parse(self.short_memory.get(guild.id)) except: last_message_dt = None if last_message_dt: now = datetime.now().astimezone(tz=timezone.utc) elapsed_time = now.replace( tzinfo=None) - last_message_dt.replace(tzinfo=None) log.info('elapsed time: ') log.info(elapsed_time) log.info('total: ') log.info(elapsed_time.total_seconds() / 60 / 60) if (elapsed_time.total_seconds() / 60 / 60) > self.window: if server_config.get('allow_auto_send_messages'): # envia mensagem no canal principal se autorizado log.info('Notifying channel %s', channel) await channel.send(choice(bored_messages)) # Renova a data de última mensagem para a data atual self.short_memory.set(guild.id, str(now.astimezone(tz=timezone.utc))) log.info('Renewed datetime to %s', str(now)) payload = Mutation.update_emotion(server=server, aptitude=-0.1) try: response = gql_client.execute(payload) log.info('Updated aptitude') except Exception as err: log.error(f'Erro: {str(err)}\n\n')
async def friendship(ctx, opt=None): """ Lista os membros com maior afinidade com a Luci. O parâmetro `-` solicita que sejam listados os membros com menor afinidade. Exemplos: - `!fs` - `!friendship -` """ embed = discord.Embed(color=0x1E1E1E, type="rich") # consulta os membros no backend server = make_hash('id', ctx.message.guild.id).decode('utf-8') payload = Query.get_users(server) gql_client = get_gql_client(BACKEND_URL) try: response = gql_client.execute(payload) except Exception as err: print(f'Erro: {str(err)}\n\n') return members = response.get('users') if not members: return await ctx.send('Acho que ainda não gosto muito de ninguém') if opt and opt == '-': members = [m for m in members if m['friendshipness'] < 0] if not members: return await ctx.send('Acho que não tenho muitos amigos aqui ainda' ) members = sorted(members, key=lambda k: k['friendshipness'])[:10] for member in members: body = f'{member["name"]} | :heartpulse: : {member["friendshipness"]}' embed.add_field(name='Membro', value=body, inline=False) return await ctx.send('Membros que eu menos curto :rolling_eyes:', embed=embed) members = [m for m in members if m['friendshipness'] >= 0] if not members: return await ctx.send('Acho que gosto de todo mundo por aqui') members = sorted(members, key=lambda k: k['friendshipness'], reverse=True)[:10] for member in members: body = f'{member["name"]} | :heartpulse: : {member["friendshipness"]}' embed.add_field(name='Membro', value=body, inline=False) return await ctx.send('Membros que eu mais curto :blush:', embed=embed)
async def random_quote(bot): """ Retorna um quote aleatório. """ server = make_hash('id', bot.guild.id) payload = Query.get_quotes(server.decode('utf-8')) client = get_gql_client(BACKEND_URL) try: response = client.execute(payload) except Exception as err: print(f'Erro: {str(err)}\n\n') return await bot.send('Buguei') quotes = response.get('quotes') if not quotes: return await bot.send('Ainda não aprendi quotes neste servidor') # sorteia um quote vindo da memória de longo rpazo chosen_quote = choice([quote['quote'] for quote in quotes]) # recupera os últimos quotes ditos nesse server da memória de curto prazo server_memory = get_short_memory_value(server) # se o quote sorteado não for um quote repetido if chosen_quote not in server_memory.get('last_quotes', []): # atualiza memória de curto prazo e retorna o quote sorteado server_memory['last_quotes'].append(chosen_quote) if len(server_memory['last_quotes']) > 10: server_memory['last_quotes'].pop(0) set_short_memory_value(server, server_memory) return await bot.send(chosen_quote) # se ela souber menos que 10 quotes nesse server pode retornar o quote repetido mesmo if len(quotes) < 10: return await bot.send(chosen_quote) # Se não tem que ir sorteando quotes até não ser repetido while chosen_quote in server_memory['last_quotes']: chosen_quote = choice([quote['quote'] for quote in quotes]) # Atualiza a memória de curto rpazo ao selecionar o quote server_memory['last_quotes'].append(chosen_quote) if len(server_memory['last_quotes']) > 10: server_memory['last_quotes'].pop(0) set_short_memory_value(server, server_memory) return await bot.send(chosen_quote)
async def track(self): """ Tracking task """ log.info('tracking...') for guild in self.guilds: log.info(guild.name) # data da última mensagem enviada no server try: last_message_dt = parser.parse(self.short_memory.get(guild.id)) except: last_message_dt = None if last_message_dt: now = datetime.now().astimezone(tz=timezone.utc) elapsed_time = now.replace(tzinfo=None) - last_message_dt.replace(tzinfo=None) log.info('elapsed time: ') log.info(elapsed_time) log.info('total: ') log.info(elapsed_time.total_seconds() / 60 / 60) if (elapsed_time.total_seconds() / 60 / 60) > self.window: # envia mensagem no canal principal log.info('Notifying channel %s', guild.system_channel.name) await guild.system_channel.send(choice(bored_messages)) # Renova a data de última mensagem para a data atual self.short_memory.set( guild.id, str(now.astimezone(tz=timezone.utc)) ) log.info('Renewed datetime to %s', str(now)) # O humor poderia ser localmente em um mongo # Atualiza o humor da Luci no backend server = make_hash('id', guild.id).decode('utf-8') gql_client = get_gql_client(BACKEND_URL) payload = Mutation.update_emotion( server=server, aptitude=-0.1 ) try: response = gql_client.execute(payload) log.info('Updated aptitude') except Exception as err: log.error(f'Erro: {str(err)}\n\n')
async def status(bot): """ Verifica o estado emocional da Luci. """ server = make_hash('id', bot.guild.id) payload = Query.get_emotions(server.decode('utf-8')) client = get_gql_client(BACKEND_URL) try: response = client.execute(payload) except Exception as err: print(f'Erro: {str(err)}\n\n') return await bot.send('Buguei') humor = response.get('emotions') if humor: luci_humor = humor[0] embed = discord.Embed(color=0x1E1E1E, type='rich') pleasantness_status = EmotionHourglass.get_pleasantness( luci_humor["pleasantness"] ) pleasantness = f':heart_decoration: {luci_humor["pleasantness"]:.2f} '\ f'| status: {pleasantness_status}' attention_status = EmotionHourglass.get_attention( luci_humor["attention"] ) attention = f':yin_yang: {luci_humor["attention"]:.2f} | status: {attention_status}' sensitivity_status = EmotionHourglass.get_sensitivity( luci_humor["sensitivity"] ) sensitivity = f':place_of_worship: {luci_humor["sensitivity"]:.2f} | ' \ f'status: {sensitivity_status}' aptitude_status = EmotionHourglass.get_aptitude(luci_humor["aptitude"]) aptitude = f':atom: {luci_humor["aptitude"]:.2f} | status: {aptitude_status}' embed.add_field(name='Pleasantness', value=pleasantness, inline=False) embed.add_field(name='Attention', value=attention, inline=False) embed.add_field(name='Sensitivity', value=sensitivity, inline=False) embed.add_field(name='Aptitude', value=aptitude, inline=False) return await bot.send('', embed=embed)
async def random_quote(bot): """ Retorna um quote aleatório. """ server = make_hash('id', bot.guild.id) payload = Query.get_quotes(server.decode('utf-8')) client = get_gql_client(BACKEND_URL) try: response = client.execute(payload) except Exception as err: print(f'Erro: {str(err)}\n\n') return await bot.send('Buguei') quotes = response.get('quotes') if not quotes: return await bot.send('Ainda não aprendi quotes neste servidor') chosen_quote = choice([quote['quote'] for quote in quotes]) return await bot.send(chosen_quote)
async def on_message(message): """ Handler para mensagens do chat. """ channel = message.channel if message.author.bot: return await client.process_commands(message) server = make_hash('id', message.guild.id).decode('utf-8') # guarda a data da mensagem como valor para o id da guilda short_memory = redis.Redis(REDIS_HOST, REDIS_PORT) short_memory.set(message.guild.id, str(message.created_at)) text = message.content global_intention, specific_intention = get_intentions(text) is_offensive = validate_text_offense(text) text_pol = extract_sentiment(text) user_name = message.author.name new_humor = change_humor_values(text_pol, is_offensive) friendshipness = -0.5 + text_pol if is_offensive else text_pol msg = { 'global_intention': global_intention, 'specific_intention': specific_intention, 'text': text } user_id = make_hash(server, message.author.id).decode('utf-8') gql_client = get_gql_client(BACKEND_URL) # Atualiza o humor da Luci payload = Mutation.update_emotion(server=server, **new_humor) try: gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') # Atualiza o humor status do usuario payload = Mutation.update_user(user_id, user_name, friendshipness, new_humor, msg) try: gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') # get server configuration query = Query.get_custom_config(server) try: response = gql_client.execute(query) except Exception as error: log.error(str(error)) response = {} server_config = response.get('custom_config') # Atualiza reconhecimento de respostas, se for resposta à outra mensagem if message.reference: payload = Mutation.assign_response( text=message.reference.resolved.content, possible_response=msg) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') # process @Luci mentions if str(channel.guild.me.id) in text: # busca possíveis respostas na memória de longo prazo payload = Query.get_possible_responses(text=remove_id(text)) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') response = {'messages': []} if response.get('messages'): possible_responses = [] for msg in response['messages']: for possible_response in msg.get('possible_responses'): possible_responses.append(possible_response.get('text')) if possible_responses: return await channel.send(choice(possible_responses)) # Caso não conheça nenhuma resposta, use o classificador inocente return await channel.send( naive_response(remove_id(text), reference=server)) # 10% chance to not answer if is offensive and lucis not mentioned is_allowed = server_config.get('allow_auto_send_messages') if not is_allowed: return if is_offensive and choice([1, 0]) and choice([1, 0]): return await channel.send( f'{message.author.mention} {choice(offended)}')
async def on_message(message): """ Handler para mensagens do chat. """ channel = message.channel if message.author.bot: return await client.process_commands(message) # guarda a data da mensagem como valor para o id da guilda short_memory = redis.Redis(REDIS_HOST, REDIS_PORT) short_memory.set(message.guild.id, str(message.created_at)) text = message.content global_intention, specific_intention = get_intentions(text) is_offensive = validate_text_offense(text) text_pol = extract_sentiment(text) user_name = message.author.name new_humor = change_humor_values(text_pol, is_offensive) friendshipness = -0.5 + text_pol if is_offensive else text_pol msg = { 'global_intention': global_intention, 'specific_intention': specific_intention, 'text': text } server = make_hash('id', message.guild.id).decode('utf-8') user_id = make_hash(server, message.author.id).decode('utf-8') gql_client = get_gql_client(BACKEND_URL) # Atualiza o humor da Luci payload = Mutation.update_emotion(server=server, **new_humor) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') # Atualiza o humor status do usuario payload = Mutation.update_user( user_id, user_name, friendshipness, new_humor, msg ) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') # Atualiza reconhecimento de respostas, se for resposta à outra mensagem if message.reference: payload = Mutation.assign_response( text=message.reference.resolved.content, possible_response=msg ) try: response = gql_client.execute(payload) except Exception as err: log.error(f'Erro: {str(err)}\n\n') # process @Luci mentions if str(channel.guild.me.id) in text: return await channel.send(naive_response(remove_id(text))) # 10% chance to not answer if is offensive and lucis not mentioned if is_offensive and choice([1, 0]) and choice([1, 0]): return await channel.send(f'{message.author.mention} {choice(offended)}')