def handle_messages(): payload = request.get_data() token = app.config['PAT'] webhook_type = get_type_from_payload(payload) # Handle messages if webhook_type == 'message': for sender_id, message in messaging_events(payload): # Only process message in here if not message: return "ok" # Start processing valid requests try: FB.show_typing(token, sender_id) response = processIncoming(sender_id, message) FB.show_typing(token, sender_id, 'typing_off') if response is not None and response != 'pseudo': # 'pseudo' is an "ok" signal for functions that sends response on their own # without returning anything back this function print response FB.send_message(token, sender_id, response) elif response != 'pseudo': FB.send_message(token, sender_id, "Sorry I don't understand that") except Exception, e: print e traceback.print_exc() FB.send_message(app.config['PAT'], sender_id, NLP.oneOf(NLP.error))
def handle_first_time_user(users, user): user_id = user['user_id'] token = app.config['PAT'] hi = "%s %s, nice to meet you :)"%(NLP.sayHiTimeZone(user), user['first_name']) FB.send_message(token, user_id, hi) FB.send_picture(app.config['PAT'], user_id, 'https://monosnap.com/file/I6WEAs2xvpZ5qTNmVauNguEzcaRrnI.png') handle_help(user_id) FB.send_message(app.config['PAT'], user_id, "Next time just tell me \"help\" to view this again :D")
def processIncoming(user_id, message): global noun_phrases_remember if message['type'] == 'text': message_text = message['data'] if message_text[-1] != ".": # help separate sentence for parsetree dotted_message = message_text + "." s = parsetree(dotted_message, relations=True, lemmata=True) sentence = s[0] if NLP.isGreetings(message_text): return "Hey whassup? How can I help you?" elif NLP.isAskingBotInformation(message_text): return NLP.handleBotInfo(message_text) elif NLP.isAskingRestaurant(sentence, message_text): rest_data, noun_phrases_remember = NLP.handle_find_rest(sentence) if rest_data is None: return "Can you send me your location? :D" elif len(rest_data) == 0: return "No result found, sorry :(" else: send_yelp_results(PAT, user_id, rest_data['businesses']) return 'send alr' elif NLP.isGoodbye(message_text): noun_phrases_remember = "" return "Goodbye!!!" return "I don't understand this ._." elif message['type'] == 'location': rest_data = NLP.handle_location(noun_phrases_remember, message['data']) if len(rest_data) == 0: return "No result found, sorry :(" else: send_yelp_results(PAT, user_id, rest_data['businesses']) noun_phrases_remember = "" return 'send alr' return "Hmm..." # Unrecognizable incoming, remove context and reset all data to start afresh else: noun_phrases_remember = "" return "*scratch my head*"
def handle_find_food(user_id, context, sentence, nounPhrase, message, incomingMessage, stage, location_from_memory=0): if stage == 'receive_request': # "Stage 1" contextNow = {'context':'find-food', 'location': None, 'coordinates': None, 'terms': nounPhrase, 'location_from_memory': location_from_memory } Mongo.add_context(users, g.user, contextNow) FB.send_message(app.config['PAT'], user_id, "Can you send me your location? :D") if len(g.user['yelp_location_history']) > 0: FB.send_quick_replies_yelp_suggest_location(app.config['PAT'], user_id, get_recent_locations_yelp()) return 'pseudo' elif stage == 'receive_location_gps': # "Stage 2-GPS" if location_from_memory == 1: Mongo.update_context(users, g.user, 'find-food', 'location_from_memory', 1) location = message['data'] Mongo.update_context(users, g.user, 'find-food', 'coordinates', location) FB.send_message(app.config['PAT'], user_id, NLP.oneOf(NLP.looking_replies)) FB.show_typing(app.config['PAT'], user_id) result = yelp_search(context['terms'], None, location) FB.show_typing(app.config['PAT'], user_id, 'typing_off') if result['status'] == 1: FB.send_message(app.config['PAT'], user_id, "Okay, I've found %s places:"%(len(result['businesses']))) FB.send_yelp_results(app.config['PAT'], user_id, result['businesses']) FB.send_quick_replies_yelp_search(app.config['PAT'], user_id) return 'pseudo' else: return "Sorry I couldn't find anything :(" elif stage == 'receive_location_text': # "Stage 2 - Text" if context['location'] == None and context['coordinates'] == None: context['location'] = nounPhrase try: geolocator = Nominatim() location_lookup = geolocator.geocode(nounPhrase) coords = [location_lookup.latitude, location_lookup.longitude] Mongo.update_context(users, g.user, 'find-food', 'coordinates', coords) Mongo.update_context(users, g.user, 'find-food', 'location', nounPhrase) FB.show_typing(app.config['PAT'], user_id) FB.send_message(app.config['PAT'], user_id, NLP.oneOf(NLP.looking_replies)) result = yelp_search(context['terms'], None, coords) except Exception, e: print e Mongo.update_context(users, g.user, 'find-food', 'location', nounPhrase) FB.send_message(app.config['PAT'], user_id, NLP.oneOf(NLP.looking_replies)) result = yelp_search(context['terms'], nounPhrase) FB.show_typing(app.config['PAT'], user_id, 'typing_off') if result['status'] == 1: # Successful search FB.send_message(app.config['PAT'], user_id, "Okay, I've found %s places:"%(len(result['businesses']))) FB.send_yelp_results(app.config['PAT'], user_id, result['businesses']) FB.send_quick_replies_yelp_search(app.config['PAT'], user_id) return 'pseudo' else: Mongo.pop_context(users, g.user) return "Sorry I can't find any results for that :(" # Follow up? else: Mongo.pop_context(users, g.user) return
def processIncoming(user_id, message, just_text=False): # First time user if not Mongo.user_exists(users, user_id): g.user = Mongo.get_user_mongo(users, user_id) return handle_first_time_user(users, g.user) else: g.user = Mongo.get_user_mongo(users, user_id) last_seen = datetime.strptime(g.user['last_seen'],"%Y-%m-%d %H:%M:%S") recent5min = datetime.now() - timedelta(minutes=5) if last_seen < recent5min: Mongo.update_last_seen(users, g.user) contextData = g.user['contexts'] # Text message type ========================================================= if just_text or message['type'] == 'text': # just_text is transcribe audio message_text = message if just_text else message['data'] if dev_area(message_text): # go through development codes return 'pseudo' if message_text.lower() == "help": handle_help(user_id) return 'pseudo' if message_text[-1] != ".": # help separate sentence for parsetree dotted_message = message_text + "." s = parsetree(dotted_message, relations=True, lemmata=True) sentence = s[0] nounPhrase = NLP.findNounPhrase(sentence) if NLP.isAskingBotInformation(sentence): return NLP.handleBotInfo(sentence) if contextData is not None and len(contextData) > 0: context = contextData[-1] if NLP.isDismissPreviousRequest(message_text): Mongo.pop_context(users, g.user) return "Sure, no problem" # Find food functionality if context['context'] == 'find-food': return handle_find_food(user_id, context, sentence, nounPhrase, message, message_text, 'receive_location_text') elif context['context'] == 'yelp-rename': handle_yelp_rename(user_id, g.user, context, message_text) Mongo.pop_context(users, g.user) # pop yelp-rename return "Ta da! %s is now in my cloudy memory :D"%(message_text) elif context['context'] == 'create-memo': return handle_memo(user_id, message_text) else: if NLP.isGreetings(message_text): greeting = "%s %s :D"%(NLP.sayHiTimeZone(g.user), g.user['first_name']) FB.send_message(app.config['PAT'], user_id, greeting) return "How can I help you?" elif NLP.isGoodbye(message_text): return NLP.sayByeTimeZone(g.user) elif NLP.isYelp(sentence): print nounPhrase return handle_find_food(user_id, None, sentence, nounPhrase, message, message_text, 'receive_request') elif NLP.isMemoCommandOnly(message_text): data = { 'context': 'create-memo' } Mongo.add_context(users, g.user, data) return "I'm listening, go ahead :D" elif NLP.isMemo(message_text): content = NLP.get_memo_content(message_text) return handle_memo(user_id, content) elif NLP.isGetNews(sentence): keyword = NLP.getNewsQuery(sentence) FB.send_message(app.config['PAT'], user_id, "Scanning %s documents on the Internet B-)"%(random.randint(9999,999999)*random.randint(9999,999999)+random.randint(1,9)) ) FB.show_typing(app.config['PAT'], user_id) posts = News.get_trending_news(keyword) FB.show_typing(app.config['PAT'], user_id, 'typing_off') # Log if there's no result to analyze if len(posts) == 0: FB.send_message(app.config['PAT'], user_id, "Sorry, I can't find any news for that :(") Mongo.log_message(log, user_id, 'no_news', keyword) else: FB.send_trending_news(app.config['PAT'], user_id, posts) return 'pseudo' else: # Log this message for categorization later Mongo.log_message(uncategorized_messages, user_id, "text", message_text) try: response = simSimi.getConversation(message_text)['response'] bad_times = 0 while NLP.badWords(response): bad_times += 1 print response response = simSimi.getConversation(message_text)['response'] if bad_times == 5: return "Hmm... I can't think of anything witty enough to respond to that :P" if 'simsimi' in response.lower(): response = response.lower().replace("simsimi", "Optimist Prime") return response except simsimi.SimSimiException as e: print e return # return None will trigger a bot confusion response # ==/ END Text message type ===================================================== # Location message type ========================================================= elif message['type'] == 'location': FB.send_message(app.config['PAT'], user_id, "I've received location (%s,%s) (y)"%(message['data'][0],message['data'][1])) if contextData is not None and len(contextData) > 0: context = contextData[-1] if 'context' in context and context['context'] == 'find-food': return handle_find_food(user_id, context, None, None, message, None, 'receive_location_gps') else: return 'pseudo' # ==/ END Location message type ================================================== # Audio message type ========================================================= elif message['type'] == 'audio': audio_url = message['data'] # Get text from audio try: message_text = STT.transcribe(audio_url) if message_text == "" or message_text == None: return # if 'DISPLAY_STT_RESULT' in os.environ and os.environ['DISPLAY_STT_RESULT'] != 0: print message_text except Exception, e: message_text = "Sorry I can't process that now :(" FB.send_message(app.config['PAT'], user_id, message_text) print e return # Begin processing audio command message_text = message_text.decode('utf-8') return processIncoming(user_id, message_text, True)
def handle_messages(): # print "Handling Messages" payload = request.get_data() if app.config['PRINT_INCOMING_PAYLOAD']: print payload token = app.config['PAT'] webhook_type = get_type_from_payload(payload) # Handle Postback # Developer-defined postbacks # Currently in use: Help button (in Persistent Menu), and Getting Started button (first-time users will see this) if webhook_type == 'postback': for sender_id, postback_payload in postback_events(payload): if postback_payload == 'OPTIMIST_HELP': handle_help(sender_id) elif postback_payload == 'OPTIMIST_GET_STARTED': if not Mongo.user_exists(users, sender_id): g.user = Mongo.get_user_mongo(users, sender_id) return handle_first_time_user(users, g.user) # Handle messages elif webhook_type == 'message': for sender_id, message in messaging_events(payload): # Only process message in here if not message: return "ok" # Handle Facebook's bug when receiving long audio # The bug: The app keeps receiving the same POST request # This acts as a rescue exit signal global temp_message_id mid = message['message_id'] if mid == temp_message_id: return 'ok' temp_message_id = mid # Start processing valid requests if app.config['PRINT_INCOMING_MESSAGE']: print "User ID: %s\nMessage:%s" % (sender_id, message) try: FB.show_typing(token, sender_id) response = processIncoming(sender_id, message) FB.show_typing(token, sender_id, 'typing_off') if response is not None and response != 'pseudo': # 'pseudo' is an "ok" signal for functions that sends response on their own # without returning anything back this function print response FB.send_message(token, sender_id, response) elif response != 'pseudo': if NLP.randOneIn(7): FB.send_message(token, sender_id, NLP.oneOf(NLP.no_response)) FB.send_picture(token, sender_id, 'https://monosnap.com/file/I6WEAs2xvpZ5qTNmVauNguEzcaRrnI.png') except Exception, e: print e traceback.print_exc() FB.send_message(app.config['PAT'], sender_id, NLP.oneOf(NLP.error)) Mongo.pop_context(users, g.user) if NLP.randOneIn(7): FB.send_picture(app.config['PAT'], sender_id, 'https://monosnap.com/file/3DnnKT60TkUhF93dwjGbNQCaCUK9WH.png')
def handle_find_food(user_id, context, sentence, nounPhrase, message, incomingMessage, stage, location_from_memory=0): if stage == 'receive_request': # "Stage 1" contextNow = { 'context': 'find-food', 'location': None, 'coordinates': None, 'terms': nounPhrase, 'location_from_memory': location_from_memory } Mongo.add_context(users, g.user, contextNow) FB.send_message(app.config['PAT'], user_id, "Can you send me your location? :D") if len(g.user['yelp_location_history']) > 0: FB.send_quick_replies_yelp_suggest_location( app.config['PAT'], user_id, get_recent_locations_yelp()) return 'pseudo' elif stage == 'receive_location_gps': # "Stage 2-GPS" if location_from_memory == 1: Mongo.update_context(users, g.user, 'find-food', 'location_from_memory', 1) location = message['data'] Mongo.update_context(users, g.user, 'find-food', 'coordinates', location) FB.send_message(app.config['PAT'], user_id, NLP.oneOf(NLP.looking_replies)) FB.show_typing(app.config['PAT'], user_id) result = yelp_search(context['terms'], None, location) FB.show_typing(app.config['PAT'], user_id, 'typing_off') if result['status'] == 1: FB.send_message( app.config['PAT'], user_id, "Okay, I've found %s places:" % (len(result['businesses']))) FB.send_yelp_results(app.config['PAT'], user_id, result['businesses']) FB.send_quick_replies_yelp_search(app.config['PAT'], user_id) return 'pseudo' else: return "Sorry I couldn't find anything :(" elif stage == 'receive_location_text': # "Stage 2 - Text" if context['location'] == None and context['coordinates'] == None: context['location'] = nounPhrase try: geolocator = Nominatim() location_lookup = geolocator.geocode(nounPhrase) coords = [location_lookup.latitude, location_lookup.longitude] Mongo.update_context(users, g.user, 'find-food', 'coordinates', coords) Mongo.update_context(users, g.user, 'find-food', 'location', nounPhrase) FB.show_typing(app.config['PAT'], user_id) FB.send_message(app.config['PAT'], user_id, NLP.oneOf(NLP.looking_replies)) result = yelp_search(context['terms'], None, coords) except Exception, e: print e Mongo.update_context(users, g.user, 'find-food', 'location', nounPhrase) FB.send_message(app.config['PAT'], user_id, NLP.oneOf(NLP.looking_replies)) result = yelp_search(context['terms'], nounPhrase) FB.show_typing(app.config['PAT'], user_id, 'typing_off') if result['status'] == 1: # Successful search FB.send_message( app.config['PAT'], user_id, "Okay, I've found %s places:" % (len(result['businesses']))) FB.send_yelp_results(app.config['PAT'], user_id, result['businesses']) FB.send_quick_replies_yelp_search(app.config['PAT'], user_id) return 'pseudo' else: Mongo.pop_context(users, g.user) return "Sorry I can't find any results for that :(" # Follow up? else: Mongo.pop_context(users, g.user) return
def processIncoming(user_id, message, just_text=False): # First time user if not Mongo.user_exists(users, user_id): g.user = Mongo.get_user_mongo(users, user_id) return handle_first_time_user(users, g.user) else: g.user = Mongo.get_user_mongo(users, user_id) last_seen = datetime.strptime(g.user['last_seen'], "%Y-%m-%d %H:%M:%S") recent5min = datetime.now() - timedelta(minutes=5) if last_seen < recent5min: Mongo.update_last_seen(users, g.user) contextData = g.user['contexts'] # Text message type ========================================================= if just_text or message['type'] == 'text': # just_text is transcribe audio message_text = message if just_text else message['data'] if dev_area(message_text): # go through development codes return 'pseudo' if message_text.lower() == "help": handle_help(user_id) return 'pseudo' if message_text[-1] != ".": # help separate sentence for parsetree dotted_message = message_text + "." s = parsetree(dotted_message, relations=True, lemmata=True) sentence = s[0] nounPhrase = NLP.findNounPhrase(sentence) if NLP.isAskingBotInformation(sentence): return NLP.handleBotInfo(sentence) if contextData is not None and len(contextData) > 0: context = contextData[-1] if NLP.isDismissPreviousRequest(message_text): Mongo.pop_context(users, g.user) return "Sure, no problem" # Find food functionality if context['context'] == 'find-food': return handle_find_food(user_id, context, sentence, nounPhrase, message, message_text, 'receive_location_text') elif context['context'] == 'yelp-rename': handle_yelp_rename(user_id, g.user, context, message_text) Mongo.pop_context(users, g.user) # pop yelp-rename return "Ta da! %s is now in my cloudy memory :D" % ( message_text) elif context['context'] == 'create-memo': return handle_memo(user_id, message_text) else: if NLP.isGreetings(message_text): greeting = "%s %s :D" % (NLP.sayHiTimeZone( g.user), g.user['first_name']) FB.send_message(app.config['PAT'], user_id, greeting) return "How can I help you?" elif NLP.isGoodbye(message_text): return NLP.sayByeTimeZone(g.user) elif NLP.isYelp(sentence): print nounPhrase return handle_find_food(user_id, None, sentence, nounPhrase, message, message_text, 'receive_request') elif NLP.isMemoCommandOnly(message_text): data = {'context': 'create-memo'} Mongo.add_context(users, g.user, data) return "I'm listening, go ahead :D" elif NLP.isMemo(message_text): content = NLP.get_memo_content(message_text) return handle_memo(user_id, content) elif NLP.isGetNews(sentence): keyword = NLP.getNewsQuery(sentence) FB.send_message( app.config['PAT'], user_id, "Scanning %s documents on the Internet B-)" % (random.randint(9999, 999999) * random.randint(9999, 999999) + random.randint(1, 9))) FB.show_typing(app.config['PAT'], user_id) posts = News.get_trending_news(keyword) FB.show_typing(app.config['PAT'], user_id, 'typing_off') # Log if there's no result to analyze if len(posts) == 0: FB.send_message( app.config['PAT'], user_id, "Sorry, I can't find any news for that :(") Mongo.log_message(log, user_id, 'no_news', keyword) else: FB.send_trending_news(app.config['PAT'], user_id, posts) return 'pseudo' else: # Log this message for categorization later Mongo.log_message(uncategorized_messages, user_id, "text", message_text) try: response = simSimi.getConversation( message_text)['response'] bad_times = 0 while NLP.badWords(response): bad_times += 1 print response response = simSimi.getConversation( message_text)['response'] if bad_times == 5: return "Hmm... I can't think of anything witty enough to respond to that :P" if 'simsimi' in response.lower(): response = response.lower().replace( "simsimi", "Optimist Prime") return response except simsimi.SimSimiException as e: print e return # return None will trigger a bot confusion response # ==/ END Text message type ===================================================== # Location message type ========================================================= elif message['type'] == 'location': FB.send_message( app.config['PAT'], user_id, "I've received location (%s,%s) (y)" % (message['data'][0], message['data'][1])) if contextData is not None and len(contextData) > 0: context = contextData[-1] if 'context' in context and context['context'] == 'find-food': return handle_find_food(user_id, context, None, None, message, None, 'receive_location_gps') else: return 'pseudo' # ==/ END Location message type ================================================== # Audio message type ========================================================= elif message['type'] == 'audio': audio_url = message['data'] # Get text from audio try: message_text = STT.transcribe(audio_url) if message_text == "" or message_text == None: return # if 'DISPLAY_STT_RESULT' in os.environ and os.environ['DISPLAY_STT_RESULT'] != 0: print message_text except Exception, e: message_text = "Sorry I can't process that now :(" FB.send_message(app.config['PAT'], user_id, message_text) print e return # Begin processing audio command message_text = message_text.decode('utf-8') return processIncoming(user_id, message_text, True)
def handle_messages(): # print "Handling Messages" payload = request.get_data() if app.config['PRINT_INCOMING_PAYLOAD']: print payload token = app.config['PAT'] webhook_type = get_type_from_payload(payload) # Handle Postback # Developer-defined postbacks # Currently in use: Help button (in Persistent Menu), and Getting Started button (first-time users will see this) if webhook_type == 'postback': for sender_id, postback_payload in postback_events(payload): if postback_payload == 'OPTIMIST_HELP': handle_help(sender_id) elif postback_payload == 'OPTIMIST_GET_STARTED': if not Mongo.user_exists(users, sender_id): g.user = Mongo.get_user_mongo(users, sender_id) return handle_first_time_user(users, g.user) # Handle messages elif webhook_type == 'message': for sender_id, message in messaging_events(payload): # Only process message in here if not message: return "ok" # Handle Facebook's bug when receiving long audio # The bug: The app keeps receiving the same POST request # This acts as a rescue exit signal global temp_message_id mid = message['message_id'] if mid == temp_message_id: return 'ok' temp_message_id = mid # Start processing valid requests if app.config['PRINT_INCOMING_MESSAGE']: print "User ID: %s\nMessage:%s" % (sender_id, message) try: FB.show_typing(token, sender_id) response = processIncoming(sender_id, message) FB.show_typing(token, sender_id, 'typing_off') if response is not None and response != 'pseudo': # 'pseudo' is an "ok" signal for functions that sends response on their own # without returning anything back this function print response FB.send_message(token, sender_id, response) elif response != 'pseudo': if NLP.randOneIn(7): FB.send_message(token, sender_id, NLP.oneOf(NLP.no_response)) FB.send_picture( token, sender_id, 'https://monosnap.com/file/I6WEAs2xvpZ5qTNmVauNguEzcaRrnI.png' ) except Exception, e: print e traceback.print_exc() FB.send_message(app.config['PAT'], sender_id, NLP.oneOf(NLP.error)) Mongo.pop_context(users, g.user) if NLP.randOneIn(7): FB.send_picture( app.config['PAT'], sender_id, 'https://monosnap.com/file/3DnnKT60TkUhF93dwjGbNQCaCUK9WH.png' )