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')
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')
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'
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'
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')
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')
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'
def phrases(): import random data = db.listDefns() random.shuffle(data) output = reduce_output(data[0:30], delimiter=', ') return output
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')
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
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'
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')
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')
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')
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'