def nag_users(self, msg_writer, event, wit_entities, credentials):
        """
        Generates a nagging conversation, and begins nagging the individual specified in the event.
        Closed by nag_response
        :return: The Nagging conversation
        """
        user_name_to_nag = get_highest_confidence_entity(wit_entities, 'name')['value']
        if not user_name_to_nag:
            msg_writer.send_message(event['channel'], "I don't know who you want me to nag")
            return
        nag_subject = get_highest_confidence_entity(wit_entities, 'randomize_option')['value']
        nagger = event['user_name'].get('real_name')
        dm = None

        for member in self.users:
            # This equality might prove buggy. Perhaps some fuzzy matching here to allow for tolerances?
            if member.get('profile').get('real_name') == user_name_to_nag:
                dm = self.get_dm_id_from_user_id(member.get('id'))
                message = "You need to {}. {} said so".format(nag_subject, nagger)

        if not dm:
            msg_writer.send_message(event['channel'], "I couldn't find anyone named {} to nag".format(user_name_to_nag))
            return

        thread = StoppableThread(msg_writer.send_message, dm, message, delay=7200)  # 2 hour repeat delay
        msg_writer.send_message(event['channel'], "Nagging {}".format(user_name_to_nag))
        thread.start()

        conversation = NaggingConversation({'user': event['user'], 'channel': event['channel']},
                                           dm,
                                           user_name_to_nag,
                                           nag_subject,
                                           thread)

        return conversation
 def test_get_highest_confidence_entity(self):
     sample_entities_dict_1 = {
         u'randomize_option': [{
             u'suggested': True,
             u'confidence': 0.5173704573627974,
             u'type': u'value',
             u'value': u'quote'
         }],
         u'intent': [{
             u'confidence': 0.7794858005199589,
             u'value': u'movie-quote'
         }]
     }
     sample_entity_1_1 = u'intent'
     sample_entity_1_2 = u'randomize_option'
     sample_entity_1_3 = u'other'
     # Check wholly valid entity
     self.assertEqual(
         utils.get_highest_confidence_entity(sample_entities_dict_1,
                                             sample_entity_1_1),
         {
             u'confidence': 0.7794858005199589,
             u'value': u'movie-quote'
         })
     # Check extant, but low confidence entity
     self.assertEqual(
         utils.get_highest_confidence_entity(sample_entities_dict_1,
                                             sample_entity_1_2), None)
     # Check non-extant entity
     self.assertEqual(
         utils.get_highest_confidence_entity(sample_entities_dict_1,
                                             sample_entity_1_3), None)
示例#3
0
def onboarding_start(msg_writer, event, wit_entities):
    if event['user'] not in onboarding_authed_user_ids:
        msg_writer.send_message(event['channel'], "You are not allowed to start onboarding")
        return

    new_employee = get_highest_confidence_entity(wit_entities, 'name')
    start_date = get_highest_confidence_entity(wit_entities, 'date')

    # abstract from here on
    msg_writer.send_message('IT', "Please begin setting up accounts for {}, who starts on {}".format(new_employee, start_date))
    msg_writer.send_message('Kim', "Please begin setting up the desk for {}, who starts on {}".format(new_employee, start_date))
    msg_writer.send_message('Phones', "Please begin setting up phones for {}, who starts on {}".format(new_employee, start_date))
    msg_writer.send_message('Email', "Please begin setting up email for {}, who starts on {}".format(new_employee, start_date))
    msg_writer.send_message('Sheri', "Please sign {} up for slack, who starts on {}".format(new_employee, start_date))

    conversation = {
        'id': uuid4(),
        'waiting_for': ['accounts-setup', 'desk-setup', 'phones-setup', 'email-setup', 'slack-setup'],
        'context': {
            'return': {'user': event['user'], 'channel': event['channel']},
            'new_employee_name': new_employee,
            'start_date': start_date
        },
        'done': False
    }

    return conversation
 def test_get_highest_confidence_entity(self):
     sample_entities_dict_1 = {u'randomize_option': [{u'suggested': True, u'confidence': 0.5173704573627974, u'type': u'value', u'value': u'quote'}], u'intent': [{u'confidence': 0.7794858005199589, u'value': u'movie-quote'}]}
     sample_entity_1_1 = u'intent'
     sample_entity_1_2 = u'randomize_option'
     sample_entity_1_3 = u'other'
     # Check wholly valid entity
     self.assertEqual(utils.get_highest_confidence_entity(sample_entities_dict_1, sample_entity_1_1), {u'confidence': 0.7794858005199589, u'value': u'movie-quote'})
     # Check extant, but low confidence entity
     self.assertEqual(utils.get_highest_confidence_entity(sample_entities_dict_1, sample_entity_1_2), None)
     # Check non-extant entity
     self.assertEqual(utils.get_highest_confidence_entity(sample_entities_dict_1, sample_entity_1_3), None)
示例#5
0
def create_drive_file(msg_writer, event, wit_entities, credentials):
    """
    :param msg_writer: writer used to write to the slack channel
    :param event: slack event object
    :param wit_entities: entity object returned by wit API call
    :param credentials GoogleCredentials object used to authorize requests
    :return: None, affirmitive message indicating creation of file with name specified by wit_entities is sent
    to slack channel
    """
    state_id = uuid4()
    current_creds = credentials.get_credential(event, state_id, user=event['user'])
    if current_creds is None:
        state = WaitState(build_uuid=state_id, intent_value='create-drive-file', event=event,
                          wit_entities=wit_entities, credentials=credentials)
        return state
    http = current_creds.authorize(httplib2.Http())
    service = discovery.build('drive', 'v3', http=http)

    desired_file_name = get_highest_confidence_entity(wit_entities, 'randomize_option')['value']

    blank_id = service.files().create(body={"name": desired_file_name}).execute()

    if blank_id:
        msg_writer.send_message(event['channel'], "Created file '{}'".format(desired_file_name))
    else:
        msg_writer.write_error(event['channel'], "Failure in file creation")
示例#6
0
def view_drive_file(msg_writer, event, wit_entities, credentials):
    """
    :param msg_writer: writer used to write to the slack channel
    :param event: slack event object
    :param wit_entities: entity object returned by wit API call
    :param credentials GoogleCredentials object used to authorize requests
    :return: None, list of drive files with the name specified by wit_entities is written to slack channel
    """
    state_id = uuid4()
    current_creds = credentials.get_credential(event, state_id, user=event['user'])
    if current_creds is None:
        state = WaitState(build_uuid=state_id, intent_value='view-drive-file', event=event,
                          wit_entities=wit_entities, credentials=credentials)
        return state
    http = current_creds.authorize(httplib2.Http())
    service = discovery.build('drive', 'v3', http=http)

    files = service.files().list().execute()['files']

    file_names = [x['name'] for x in files]

    try:
        desired_file_name = get_highest_confidence_entity(wit_entities, 'randomize_option')['value']
    except TypeError:
        msg_writer.send_message(event['channel'], "I don't know what file you're talking about")
        return

    likely_file = process.extractOne(desired_file_name, file_names)

    if likely_file and likely_file[1] >= 75:  # Arbitrary probability cutoff
        likely_file_id = get_id_from_name(files, likely_file[0])
        msg_writer.send_message(event['channel'], "```File ID: {}```".format(likely_file_id))

    else:
        msg_writer.send_message(event['channel'], "No file found with that name, sorry")
def send_email(msg_writer, event, wit_entities, credentials):
    """
    :param msg_writer: A message writer used to write output to slack
    :param event: The triggering event
    :param wit_entities: The entities of the wit response
    :param credentials: A Google Credentials object used to validate with google Oauth
    send_email generates an email from the message text and sends it to the indicated email address
    :return: A WaitState if the user is not authenticated, nothing if they are
    """
    state_id = uuid4()
    current_creds = credentials.get_credential(event, state_id, user=event['user'])
    if current_creds is None:
        state = WaitState(build_uuid=state_id, intent_value='send-email', event=event,
                          wit_entities=wit_entities, credentials=credentials)
        return state
    http = current_creds.authorize(httplib2.Http())
    service = discovery.build('gmail', 'v1', http=http)

    msg_text = event['cleaned_text']
    email_string = "<mailto:.*@.*\..*\|.*@.*\..*>"  # matches <mailto:[email protected]|[email protected]>
    string_cleaner = re.compile(email_string)
    cleaned_msg_text = string_cleaner.sub("", msg_text)
    msg_to = get_highest_confidence_entity(wit_entities, 'email')['value']
    if not msg_to:
        msg_writer.send_message(event['channel'], "I can't understand where you want me to send the message, sorry")
        return

    message = MIMEText(cleaned_msg_text)
    message['to'] = msg_to
    message['from'] = "{}@galatea-associates.com".format(event['user_name']['profile']['last_name'])
    message['subject'] = "Message via Hal from {}".format(event['user_name']['profile']['real_name'])

    message_encoded = {'raw': base64.urlsafe_b64encode(message.as_string().encode('utf-8')).decode('utf-8')}

    service.users().messages().send(userId="me", body=message_encoded).execute()
    def _handle_message(self, event):

        if not self._proof_message(event):
            return

        msg_txt = event['text']
        channel_id = event['channel']

        # Remove mention of the bot so that the rest of the code doesn't need to
        msg_txt = self.clients.remove_mention(msg_txt).strip()

        # Ask wit to interpret the text and send back a list of entities
        logger.info("Asking wit to interpret| {}".format(msg_txt))
        wit_resp = self.wit_client.interpret(msg_txt)

        # Add username and channel name, user dm, and cleaned text to the event object
        user_name = self.clients.get_user_name_from_id(event['user'])
        if is_direct_message(channel_id):
            channel_name = "Direct Message"
        else:
            channel_name = self.clients.get_channel_name_from_id(channel_id)
        event.update({
            "user_name": user_name,
            "channel_name": channel_name,
            "user_dm": self.clients.get_dm_id_from_user_id(event['user']),
            "cleaned_text": msg_txt
        })

        # Find the intent with the highest confidence that met our default threshold
        intent_entity = get_highest_confidence_entity(wit_resp['entities'], 'intent')

        # If we couldn't find an intent entity, let the user know
        if intent_entity is None:
            self.msg_writer.write_prompt(channel_id, self.intents)
            return

        intent_value = intent_entity['value']
        if intent_value in conversation_intent_types:
            match = self._conversation_match(intent_value, wit_resp, event)
            if match:
                event.update({"conversation": match})

        if intent_value in self.intents:
            t = {
                'intent': self.intents[intent_value][0],
                'msg_writer': self.msg_writer,
                'event': event,
                'wit_entities': wit_resp['entities'],
                'credentials': self.credentials,
                'state_q': self.state_updating_q
            }
            self.event_processing_q.put(t)

        else:
            raise ReferenceError("No function found to handle intent {}".format(intent_value))
示例#9
0
def phones_setup(msg_writer, event, wit_entities):
    info = get_highest_confidence_entity(wit_entities, 'phone_number')
    conversation = event.get('conversation')
    context = conversation.get('context')
    msg_writer.send_message(context.get('return').get('channel'),
                            "Phones for {} setup, with {} number".format(context.get('new_employee_name'), info))
    conversation.get('waiting_for').remove('phones_setup')
    if conversation.get('waiting_for') is None:
        email_new_hire(msg_writer, conversation)
        return None
    return conversation
示例#10
0
def email_setup(msg_writer, event, wit_entities):
    conversation = event.get('conversation')
    email = get_highest_confidence_entity(wit_entities, 'email')
    context = conversation.get('context')
    msg_writer.send_message(context.get('return').get('channel'),
                            "Email for {} setup".format(context.get('new_employee_name')))
    conversation.get('waiting_for').remove('email_setup')
    conversation.get('context').add({'email': email})
    if conversation.get('waiting_for') is None:
        email_new_hire(msg_writer, conversation)
        return None
    return conversation
示例#11
0
    def _handle_message(self, event):

        # Event won't have a user if slackbot is unfurling messages for you
        if 'user' not in event:
            return

        # Filter out messages from the bot itself
        if self.clients.is_message_from_me(event['user']):
            return

        msg_txt = event['text']
        channel_id = event['channel']

        # Filter out message unless this bot is mentioned or it is a direct message
        if not (is_direct_message(channel_id) or self.clients.is_bot_mention(msg_txt)):
            return

        # Remove mention of the bot so that the rest of the code doesn't need to
        msg_txt = self.clients.remove_mention(msg_txt).strip()

        # Ensure that we don't go to wit with messages posted by an ignored user
        if event['user'] in user_ignore_list:
            return

        # bot_uid = self.clients.bot_user_id()

        # Ask wit to interpret the text and send back a list of entities
        logger.info("Asking wit to interpret| {}".format(msg_txt))
        wit_resp = self.wit_client.interpret(msg_txt)

        # Find the intent with the highest confidence that met our default threshold
        intent_entity = get_highest_confidence_entity(wit_resp['entities'], 'intent')

        # If we couldn't find an intent entity, let the user know
        if intent_entity is None:
            self.msg_writer.write_prompt(channel_id, intents)
            return

        intent_value = intent_entity['value']
        if intent_value in intents:
            intents[intent_value][0](self.msg_writer, event, wit_resp['entities'])
        else:
            raise ReferenceError("No function found to handle intent {}".format(intent_value))