Example #1
0
def sue_help():
    help_docs = []
    msg = Message._create_message(flask.request.form)

    # iterate through our routes, getting the doc-strings we defined as
    # miniature man-pages for these commands.
    for r in app.url_map.iter_rules():
        current_doc = app.view_functions[r.endpoint].__doc__
        if current_doc and ('static' not in r.rule):
            docString = current_doc.strip()
            firstLine = docString.split('\n', 1)[0]

            # if someone wants help about a specific command, get them
            # the extra info we placed after the first line-break.
            if msg.textBody:
                if firstLine.split(' ',
                                   1)[0].replace('!',
                                                 '') == msg.textBody.lower():
                    specificDocumentation = docString.split('\n', 1)
                    if len(specificDocumentation) == 2:
                        return reduce_output(specificDocumentation[1].strip(),
                                             delimiter='\n')
                    else:
                        return 'No documentation for {0} yet. Add it to the\
                        repo! https://github.com/inculi/Sue'.format(
                            msg.textBody)
                # else:
                #     print(firstLine.split(' ',1)[0].replace('!',''))
                #     print(msg.textBody.lower())

            help_docs.append(firstLine)

    return reduce_output(sorted(help_docs), delimiter='\n')
Example #2
0
File: poll.py Project: bellyfat/Sue
def create_poll(options, msg):
    """Allows !poll, !lunch, and eventually other commands to construct polls in
    a more abstracted way.
    """
    response = []

    # set this to the current poll for our group.
    poll_data = {
        "letter_options": [],
        "options": options[1:],
        "question": options[0],
        "votes": {}
    }

    response.append(poll_data['question'])

    for i, cur_option in enumerate(poll_data["options"]):
        _option_letter = chr(ord('a') + i)
        poll_data["letter_options"].append(_option_letter)
        response.append("{0}. {1}".format(_option_letter, cur_option))

    db.mUpdate('polls', {'group': msg.chatId}, {
        'group': msg.chatId,
        'data': poll_data
    })

    return reduce_output(response, delimiter='\n')
Example #3
0
def identify():
    """!identify <image>
    
    Queries clarif.ai to identify the top 10 concepts within an image.
    Usage: !identify <image>"""

    msg = Message(flask.request.form)
    fileName = msg.fileName

    if fileName == 'noFile':
        return 'Please supply a file.'
    elif fileName == 'fileError':
        return 'There was an error selecting the last file transfer.'
    else:
        init_clarifai()
        model = clarifai.models.get('general-v1.3')
        image = ClImage(file_obj=open(fileName, 'rb'))

        imageData = model.predict([image])
        try:
            imageData = imageData['outputs'][0]['data']['concepts'][:10]
            imageData = [x['name'] for x in imageData]

            return reduce_output(imageData, delimiter=', ')
        except:
            return 'Error'
Example #4
0
def identify():
    """!identify <image>"""

    msg = Message._create_message(flask.request.form)
    fileName = msg.fileName

    if fileName == 'noFile':
        return 'Please supply a file.'
    elif fileName == 'fileError':
        return 'There was an error selecting the last file transfer.'
    else:
        from clarifai.rest import ClarifaiApp
        from clarifai.rest import Image as ClImage

        app = ClarifaiApp(api_key='ab4ea7efce5a4398bcbed8329a3d81c7')
        model = app.models.get('general-v1.3')
        image = ClImage(file_obj=open(fileName, 'rb'))

        imageData = model.predict([image])
        try:
            imageData = imageData['outputs'][0]['data']['concepts'][:10]
            imageData = [x['name'] for x in imageData]

            return reduce_output(imageData, delimiter=', ')
        except:
            return 'Error'
Example #5
0
def poll():
    """!poll <topic>\\n<opt1>\\n<opt2> ..."""

    msg = Message._create_message(flask.request.form)
    options = msg.textBody.split('\n')

    response = []

    if len(options) < 2:
        return 'Please specify a topic with options delimited by newlines.'
    
    # set this to the current poll for our group.
    poll_data = {
        "letter_options" : set(),
        "options" : options[1:],
        "question" : options[0],
        "votes" : {}
    }

    response.append(poll_data['question'])

    for i, cur_option in enumerate(poll_data["options"]):
        _option_letter = chr(ord('a') + i)
        poll_data["letter_options"].add(_option_letter)
        response.append("{0}. {1}".format(_option_letter, cur_option))
    
    # mongo doesn't like sets so I have to convert to list.
    poll_data["letter_options"] = list(poll_data["letter_options"])
    db.mUpdate('polls',
               {'group' : msg.chatId},
               {'group' : msg.chatId, 'data' : poll_data })

    return reduce_output(response, delimiter='\n')
Example #6
0
def sue_help():
    help_docs = []
    for r in app.url_map.iter_rules():
        current_doc = app.view_functions[r.endpoint].__doc__
        if current_doc and ('static' not in r.rule):
            help_docs.append(current_doc.strip())

    return reduce_output(sorted(help_docs), delimiter='\n')
Example #7
0
def process_reply():
    """Main route for processing requests.
    
    Based on information we detect in the flask.request.form (logic provided
      in models.py), we can figure out if we are sending the response back to
      Signal, iMessage, and from there-- a group, or an individual. Cool, huh?
    """

    if not check_command(flask.request.form):
        return ''  # User isn't talking to Sue. Ignore.
    flask.request.form = prepare_message(flask.request.form)
    msg = Message(flask.request.form)

    init_sue_funcs()
    f = sue_funcs.get('/' + msg.command)
    if f:
        # Command exists. Execute it and get the response.
        sue_response = f()
    else:
        # It's not a command we made. Check to see if it is user defined.
        sue_response = sue_funcs['/callDefn']()

    # cast her response to a string. (ex: lists are reduced).
    attachment = None
    if isinstance(sue_response, list):
        sue_response = reduce_output(sue_response, delimiter='\n')
    elif isinstance(sue_response, DataResponse):
        # set the attachment to our image path
        attachment = sue_response.data

        # set the sue_response to a blank string (we won't send it anyway)
        sue_response = ''
    elif not isinstance(sue_response, str):
        try:
            sue_response = str(sue_response)
        except:
            sue_response = "Couldn't convert from {0} to str".format(
                type(sue_response))

    # TODO: Create consts for these, so we have less `magic string` usage.
    if msg.platform is 'imessage':
        # forward to applescript handler
        IMessageResponse(msg, sue_response, attachment=attachment)
        return 'success'
    elif msg.platform is 'signal':
        # return to GET request from run_signal.py
        return json.dumps({
            'messageBody': sue_response,
            'attachmentFilenames': [attachment]
        })
    elif msg.platform is 'telegram':
        return sue_response
    elif msg.platform is 'debug':
        return sue_response
    else:
        print('Unfamiliar message platform: {0}'.format(msg.platform))
        # TODO: Throw exception?
        return 'failure'
Example #8
0
def phrases():
    import random

    data = db.listDefns()
    random.shuffle(data)

    output = reduce_output(data[0:30], delimiter=', ')

    return output
Example #9
0
def sue_help():
    """Returns a sorted list of commands available for the user to use. If you
      give it a command name as an argument, it will read you the extended
      "manpage" for that command.

    Usage
    -----
    !help
    !help <command>

    Examples
    --------
    """

    help_docs = []
    msg = Message(flask.request.form)

    # Iterate through our routes, getting the doc-strings we defined as
    #   miniature man-pages for these commands.
    hiddenEndpoints = set(['/', '/help'])
    for r in app.url_map.iter_rules():
        current_doc = app.view_functions[r.endpoint].__doc__
        if current_doc:
            if 'static' in r.rule:
                continue
            if r.rule in hiddenEndpoints:
                continue

            docString = current_doc.strip()
            firstLine = docString.split('\n', 1)[0]

            # If someone wants help about a specific command, get them
            # the extra info we placed after the first line-break.
            if msg.textBody:
                if firstLine.split(' ', 1)[0].replace('!', '') != msg.command:
                    continue

                cmdDocs = docString.split('\n', 1)
                if len(cmdDocs) != 2:
                    return 'No documentation for {0} yet. Add it to the\
                    repo! https://github.com/inculi/Sue'.format(msg.command)

                response = ''
                for line in cmdDocs[1].split('\n'):
                    if not line:
                        continue
                    if line[0] == ' ':
                        response += ' ' + line.strip()
                    else:
                        response += '\n' + line.strip()

                return response

            help_docs.append(firstLine)

    return reduce_output(sorted(help_docs), delimiter='\n')
Example #10
0
def phrases():
    # See a random sample of 30 phrases !define'd in Sue's memory.

    import random

    data = db.listDefns()
    random.shuffle(data)
    output = reduce_output(data[0:30], delimiter=', ')

    return output
Example #11
0
def process_reply():
    if app.config['DEBUG']:
        print(flask.request.form)

    command = check_command(flask.request.form)
    if not command:
        return ''

    # get a list of our available functions
    sue_funcs = {}
    for r in app.url_map.iter_rules():
        sue_funcs[r.rule] = app.view_functions[r.endpoint]

    f = sue_funcs.get('/' + command)
    if f:
        # get the response back from Sue.
        sue_response = f()

        # cast her response to a string. (ex: lists are reduced).
        if isinstance(sue_response, list):
            sue_response = reduce_output(sue_response, delimiter='\n')
        elif not isinstance(sue_response, str):
            try:
                sue_response = str(sue_response)
            except:
                sue_response = "Couldn't convert from {0} to str".format(
                    type(sue_response))

        # message metadata will be used to direct response output.
        msg = Message._create_message(flask.request.form)

        if msg.platform is 'imessage':
            # forward to applescript handler
            Response(msg, sue_response)
            return 'success'
        elif msg.platform is 'signal':
            # return to GET request from run_signal.py
            return sue_response
        else:
            print('Unfamiliar message platform: {0}'.format(msg.platform))
            return 'failure'
    else:
        # see if it is user defined
        sue_response = sue_funcs['/callDefn']()
        Response(flask.request.form, sue_response)
        return 'success'
Example #12
0
File: poll.py Project: bellyfat/Sue
def vote():
    """!vote <letter>
    
    Used to vote on a poll that is currently ongoing.
    Usage: !vote a"""

    msg = Message(flask.request.form)
    options = msg.textBody.split(' ')
    poll_data = db.mFind('polls', 'group', msg.chatId).get('data', {})

    if not poll_data:
        return 'Could not find a poll for your group. Make one with !poll'

    response = []

    # if there is actually a correct input
    if len(options) == 1:
        the_letter = options[0].lower()
        if the_letter in poll_data.get('letter_options', []):
            poll_data['votes'][msg.sender] = the_letter
        else:
            return 'That is not a option in this poll.'

    response.append(poll_data["question"])

    # display the new status
    total_letters = poll_data.get('letter_options')
    voted_letters = list(poll_data.get('votes', {}).values())
    vote_counts = [voted_letters.count(x) for x in total_letters]

    for cnt, ltr, option in zip(vote_counts, total_letters,
                                poll_data['options']):
        # (0 votes) A. Dog
        vote_plurality = 'vote' if (cnt == 1) else 'votes'  # thanks, Rick :/
        response.append('({0} {1}) {2}. {3}'.format(cnt, vote_plurality, ltr,
                                                    option))

    # mongo doesn't like sets so I have to convert to list.
    db.mUpdate('polls', {'group': msg.chatId}, {
        'group': msg.chatId,
        'data': poll_data
    })

    return reduce_output(response, delimiter='\n')
Example #13
0
def lunch():
    """!lunch"""

    # retrieve the group-specific lunchPlaces
    options = db.mFind('polls', 'group', msg.chatId).get('lunchPlaces', None)
    # if lunchPlaces isn't in the database
    if options == None:
        return "There are no lunchPlaces set,\nset with !lunchPlaces <place1>, <place2>, ..."
    options =  ["Where should we get lunch?"] + options
    msg = Message._create_message(flask.request.form)

    #
    # the rest of this code is copy-paste from !poll
    #
    response = []

    if len(options) < 2:
        return 'Please specify a topic with options delimited by newlines.'
    
    # set this to the current poll for our group.
    poll_data = {
        "letter_options" : set(),
        "options" : options[1:],
        "question" : options[0],
        "votes" : {}
    }

    response.append(poll_data['question'])

    for i, cur_option in enumerate(poll_data["options"]):
        _option_letter = chr(ord('a') + i)
        poll_data["letter_options"].add(_option_letter)
        response.append("{0}. {1}".format(_option_letter, cur_option))
    
    # mongo doesn't like sets so I have to convert to list.
    poll_data["letter_options"] = list(poll_data["letter_options"])
    db.mUpdate('polls',
               {'group' : msg.chatId},
               {'group' : msg.chatId, 'data' : poll_data })

    return reduce_output(response, delimiter='\n')
Example #14
0
def vote():
    """!vote <letter>"""

    msg = Message._create_message(flask.request.form)
    options = msg.textBody.split(' ')
    poll_data = db.mFind('polls', 'group', msg.chatId).get('data', {})
    print(poll_data)
    if not poll_data:
        return 'Could not find a poll for your group. Make one with !poll'
    response = []

    # if there is actually a correct input
    if len(options) == 1:
        the_letter = options[0].lower()
        if the_letter in poll_data.get('letter_options', set()):
            poll_data['votes'][msg.sender] = the_letter
        else:
            return 'That is not a option in this poll.'
    
    response.append(poll_data["question"])

    # display the new status
    votes = poll_data.get('votes', {}).values()
    vote_counts = [list(votes).count(x) for x in poll_data.get('letter_options')]
    entries = list(zip(vote_counts, poll_data['letter_options'], poll_data.get('options', ['?'])))
    entries.sort(key=lambda x: x[1])

    for num_votes, letter, option in entries:
        # (0 votes) A. Dog
        response.append(
            '({0} votes) {1}. {2}'.format(num_votes, letter, option)
        )
    
    # mongo doesn't like sets so I have to convert to list.
    db.mUpdate('polls',
               {'group' : msg.chatId},
               {'group' : msg.chatId, 'data' : poll_data })
    
    return reduce_output(response, delimiter='\n')
Example #15
0
def process_reply():
    # Main route for processing requests. Based on information we detect in the
    #   flask.request.form (logic provided in models.py), we can figure out if
    #   we are sending the response back to Signal, iMessage, and from there--
    #   a group, or an individual. Cool, huh?

    if app.config['DEBUG']:
        print('Old form:')
        pprint(flask.request.form)
        # flask.request.form'textBody'] = flask.request.form['textBody'].upper()

    command = check_command(flask.request.form)
    if not command:
        # User isn't talking to Sue. Ignore.
        return ''

    # message metadata will be used to direct response output.
    msg = Message._create_message(flask.request.form)

    # parse message textBody to see if we need to inject any user-defined
    # variables into it.
    if msg.textBody:
        newFormItems = []
        for key, val in flask.request.form.to_dict().items():
            if key == 'textBody':
                # inject our variables into it.
                if '#' in val:
                    newTextBody = inject_user_structures(val)
                    newFormItems.append((key, newTextBody))
                    continue

            newFormItems.append((key, val))
        flask.request.form = ImmutableMultiDict(newFormItems)

    print(flask.request.form)
    # get a list of our available functions
    sue_funcs = {}
    for r in app.url_map.iter_rules():
        sue_funcs[r.rule] = app.view_functions[r.endpoint]

    f = sue_funcs.get('/' + command)
    if f:
        # Command exists. Execute it and get the response.
        sue_response = f()
    else:
        # It's not a command we made. Check to see if it is user defined.
        sue_response = sue_funcs['/callDefn']()

    # cast her response to a string. (ex: lists are reduced).
    attachment = None
    if isinstance(sue_response, list):
        sue_response = reduce_output(sue_response, delimiter='\n')
    elif isinstance(sue_response, DataResponse):
        # set the attachment to our image path
        attachment = sue_response.data

        # set the sue_response to a blank string (we won't send it anyway)
        sue_response = ''
    elif not isinstance(sue_response, str):
        try:
            sue_response = str(sue_response)
        except:
            sue_response = "Couldn't convert from {0} to str".format(
                type(sue_response))

    # TODO: Create consts for these, so we have less `magic string` usage.
    if msg.platform is 'imessage':
        # forward to applescript handler
        Response(msg, sue_response, attachment=attachment)
        return 'success'
    elif msg.platform is 'signal':
        # return to GET request from run_signal.py
        return sue_response
    elif msg.platform is 'debug':
        return 'SUE :\n{0}'.format(sue_response)
    else:
        print('Unfamiliar message platform: {0}'.format(msg.platform))
        return 'failure'