def searchImage(): """!img <... query ...>""" # use imgur's API to return the link to the first non-album result. from json import loads import random import requests msg = Message._create_message(flask.request.form) searchText = msg.textBody url = "https://api.imgur.com/3/gallery/search/{{sort}}/{{window}}/{{page}}" querystring = {"q": searchText} headers = {'authorization': 'Client-ID 01aa1688f43ca6c'} response = requests.request("GET", url, headers=headers, params=querystring) a = loads(response.text)['data'] # a = filter(lambda x: 'imgur.com/a/' not in x['link'], a) if len(a) > 0: # imageUrl = a[0]['link'] # return random.choice(a)['link'] try: return random.choice(a)['link'] except: # there was an error finding a link key in the item's dict. return "Sorry, I couldn't find a photo of that..." else: return "Sorry, I couldn't find a photo of that..."
def define(): """!define <word> <... meaning ...> Create a quick alias that makes Sue say something. You: !define ping pong You: !ping Sue: pong""" msg = Message(flask.request.form) textBody = msg.textBody if len(textBody) == 0: return 'Please supply a word to define.' try: textBody = textBody.split(' ', 1) if len(textBody) == 2: defnName, meaning = textBody[0], textBody[1] else: return 'Please supply a meaning for the word.' except: # There was an error. return 'Error adding definition. No unicode pls :(' defnName = clean(defnName) q = db.findDefn(defnName) if q: db.updateDefn(defnName, meaning) return ('%s updated.' % defnName) else: db.addDefn(defnName, meaning) return ('%s added.' % defnName) return 0
def urbanDictionary(): """!ud <... term ...>""" import sys import json import requests msg = Message._create_message(flask.request.form) term = msg.textBody responses = [] if term: if sys.version < '3': from urllib import quote as urlquote else: from urllib.parse import quote as urlquote url = 'http://api.urbandictionary.com/v0/define?term=' + urlquote(term) else: # no term provided. Send a random one. url = 'http://api.urbandictionary.com/v0/random' r = requests.get(url) data = json.loads(r.content) if not data['list']: return ["Sorry, couldn't find that..."] clean = lambda x: x.replace('\r\n', '\n').strip() for entry in data['list'][:1]: responses.append(str(data['list'][0]['word'])) output = 'def: ' + clean(entry['definition']) + '\n' output += 'ex: ' + clean(entry['example']) responses.append(str(output)) return responses
def sue_random(): """!random <upper> <lower>""" msg = Message._create_message(flask.request.form) if not msg: return 'Error with message.' textBody = msg.textBody.lower() print(textBody) randRange = sorted(textBody.split(' ')) if len(randRange) != 2: # can't have a range between 3 elements return sue_random.__doc__ numberBased = set(map(lambda x: x.isdigit(), randRange)) try: if numberBased == {True}: # 1 - 123 randRange = [int(x) for x in randRange] randRange.sort() return str(random.randint(randRange[0], randRange[1])) elif numberBased == {False}: # a - z randRange = [ord(x) for x in randRange] randRange.sort() return str(chr(random.randint(randRange[0], randRange[1]))) else: return str(random.random()) except: return str(random.random())
def lewd(): """!lewd <image> Queries clarif.ai to detect if an image is 'lewd'. Usage: !lewd <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('nsfw-v1.0') if not model: return 'Model no longer exists.' image = ClImage(file_obj=open(fileName, 'rb')) responses = [] imageData = model.predict([image]) result = imageData['outputs'][0]['data']['concepts'][0] if result['name'] == u'nsfw': responses.append('LEEEWWWDDD!!!!!') responses.append('accuracy: %f' % result['value']) return responses else: return 'not lewd'
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 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 lewd(): """!lewd <image>""" # detect whether an image is lewd or not 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('nsfw-v1.0') image = ClImage(file_obj=open(fileName, 'rb')) responses = [] imageData = model.predict([image]) result = imageData['outputs'][0]['data']['concepts'][0] if result['name'] == u'nsfw': responses.append('LEEEWWWDDD!!!!!') responses.append('accuracy: %f' % result['value']) return responses else: return 'not lewd'
def poll(): """!poll <topic>\\n<opt1>\\n<opt2> ... Create a poll for people to !vote on. Usage: !poll which movie? grand budapest tron bee movie""" msg = Message(flask.request.form) options = tokenize(msg.textBody) if len(options) < 2: return 'Please specify a topic with options delimited by newlines.' if '?' in options[0]: # Injected user data may have messed up tokenization... # !poll Where should we have lunch? #lunchplaces (no comma) # instead of: !poll Where should we have lunch?, #lunchplaces (comma) firstQuestionIdx = options[0].find('?') if options[0][-1] != '?': # The question ended earlier in the string. Find it. pollQuestion, firstOption = options[0].split('?', 1) options = [pollQuestion.strip() + '?', firstOption.strip()] + options[1:] return create_poll(options, msg)
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 searchImage(): """!img <... query ...> Query imgur.com to return a url to a related image (selects randomly from results). Usage: !img flower""" # use imgur's API to return the link to the first non-album result. from json import loads import random import requests msg = Message._create_message(flask.request.form) searchText = msg.textBody url = "https://api.imgur.com/3/gallery/search/{{sort}}/{{window}}/{{page}}" querystring = {"q": searchText} headers = {'authorization': app.config['IMGUR_CLIENT_ID']} response = requests.request("GET", url, headers=headers, params=querystring) a = loads(response.text)['data'] # a = filter(lambda x: 'imgur.com/a/' not in x['link'], a) if len(a) > 0: try: return random.choice(a).get( 'link', 'Error selecting link from response...') except: # there was an error finding a link key in the item's dict. return "Sorry, I couldn't find a photo of that..." else: return "Sorry, I couldn't find a photo of that..."
def echo(): """!echo <... text ...> Used to debug member-defined data structures. You: !echo !choose #lunchplaces Sue: !choose fuego, antonios, potbelly, taco bell""" msg = Message(flask.request.form) return msg.textBody
def movie(): # Used to get information about movies that are currently being stored/ # downloaded. # TODO: Implement. # return 'Needs to be implemented.' print('doing something') msg = Message._create_message(flask.request.form) return query_couch_potato(msg.textBody)
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 shuffle(): """!shuffle <1> <2> ... <n>""" from functools import reduce msg = Message(flask.request.form) items = msg.textBody.split(' ') random.shuffle(items) return reduce(lambda x, y: str(x) + ' ' + str(y), items)
def callDefn(): msg = Message._create_message(flask.request.form) defnName = msg.command q = db.findDefn(defnName) if q: return str(q[u'meaning']) else: return 'Not found. Add it with !define'
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 callDefn(): # the route used to call !define'd objects. msg = Message(flask.request.form) defnName = msg.command q = db.findDefn(defnName) if q: return str(q[u'meaning']) else: return 'Not found. Add it with !define'
def shuffle(): """!shuffle <1> <2> ... <n> Shuffles and then returns your input.""" from functools import reduce msg = Message._create_message(flask.request.form) items = tokenize(msg.textBody) random.shuffle(items) return reduce(lambda x,y: str(x)+' '+str(y), items)
def name(): """!name <newname>""" msg = Message._create_message(flask.request.form) sender = msg.sender textBody = msg.textBody # make changes to our names collection. if len(textBody) == 0: return 'Please specify a name.' else: db.updateName(sender, textBody) return '{0} shall now be known as {1}'.format(sender, textBody)
def whoami(): """!whoami""" msg = Message._create_message(flask.request.form) sender = msg.sender # load names from pickle file nameFound = db.findName(sender) if nameFound: print('You are {0}.'.format(nameFound)) return 'You are {0}.'.format(nameFound) else: return 'I do not know you. Set your name with !name'
def lunchPlaces(): """!lunchPlaces <place1>, <place2>, ...""" msg = Message._create_message(flask.request.form) # split by commas and trim whitespace lunchPlaces = [each.strip() for each in msg.textBody.split(',')] # add lunchPlaces to the mongo polls collection db.mUpdate('polls', {'group' : msg.chatId}, {'group' : msg.chatId, 'lunchPlaces' : lunchPlaces })
def wiki(): """!wiki <... topic ...>""" import wikipedia as wikip msg = Message._create_message(flask.request.form) searchTerm = msg.textBody try: data = wikip.summary(searchTerm, sentences=1) if len(data) < 50: data = wikip.summary(searchTerm, sentences=2) return str(data) except: return "Hmm, couldn't find that..."
def name(): """!name <newname> Create a new name for Sue to call you by. This currently isn't used for anything. You: !name Robert Sue: +1234567890 shall now be known as Robert""" msg = Message(flask.request.form) sender = msg.sender textBody = msg.textBody # make changes to our names collection. if len(textBody) == 0: return 'Please specify a name.' else: db.updateName(sender, textBody) return '{0} shall now be known as {1}'.format(sender, textBody)
def choose(): """!choose <1> <2> ... <n> Returns a random object in your space-delimited argument. Usage: !choose up down left right""" msg = Message._create_message(flask.request.form) options = tokenize(msg.textBody) meguminOption = ('megumin' in map(lambda x: x.lower(), options)) if meguminOption and msg.sender == '+12107485865': return 'megumin' elif meguminOption and msg.sender == '+12108342408': return 'Roses are Red, Violets are Blue. Megumin best girl and glorious waifu.' else: return random.choice(options)
def image(): """!i <param> <image> Available parameters are: smile, smile2, hot, old, young, hollywood, glasses, hitman, mustache, pan, heisenberg, female, female2, male """ global VALID_IMAGE_PARAMS msg = Message(flask.request.form) _param = msg.textBody.lower() paramAliases = { 'mustache': 'mustache_free', 'glasses': 'fun_glasses', 'smile2': 'smile_2', 'female2': 'female_2' } if _param not in VALID_IMAGE_PARAMS: _param = paramAliases.get(_param) if not _param: return 'Not a valid parameter. See !help i' if msg.fileName == 'noFile': return 'Please supply a file.' elif msg.fileName == 'fileError': return 'There was an error selecting the last file transfer.' import faces import uuid try: img = faces.FaceAppImage(file=open(msg.fileName, 'rb')) outimg = img.apply_filter(_param, cropped=False) except faces.ImageHasNoFaces: return 'No faces on this image.' except faces.BadInfo as ex: return str(ex) # Create the directory for us to store these files if it doesn't exist. if not os.path.exists('resources/iout/'): os.mkdir('resources/iout') outPath = os.path.abspath('resources/iout/{}.jpg'.format(uuid.uuid4())) with open(outPath, 'wb') as f: f.write(outimg) return DataResponse(outPath)
def choose(): """!choose <1> <2> ... <n>""" msg = Message._create_message(flask.request.form) print(msg.__dict__) textBody = msg.textBody sender = msg.buddyId options = textBody.split(' ') meguminOption = 'megumin' in map(lambda x: x.lower(), options) if meguminOption and sender == '12107485865': return 'megumin' elif meguminOption and sender == '12108342408': return 'http://megumin.club Roses are Red, Violets are Blue. Megumin best girl and glorious waifu.' else: return random.choice(options)
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 whoami(): """!whoami Fetches the name you set for yourself using !name You: !whoami Sue: You are Robert.""" msg = Message(flask.request.form) sender = msg.sender # load names from pickle file nameFound = db.findName(sender) if nameFound: print('You are {0}.'.format(nameFound)) return 'You are {0}.'.format(nameFound) else: return 'I do not know you. Set your name with !name'