def format_response_text_with_links(text_reponse, links): if (len(links) == 0): return [{"text": text_reponse, "link": ""}] new_text_response = [] matches = re.findall('((.*?)(link[0-9]+))', text_reponse) found_text = "" for match in matches: found_text = found_text + match[0] linkid = match[2] text_before_link = match[1] item_detail = {} item_detail["text"] = text_before_link if linkid in links.keys(): logger("webUI").info("Link " + linkid + " after: " + text_before_link) item_detail["link"] = links[linkid] del links[linkid] new_text_response.append(item_detail) remain_text = text_reponse.replace(found_text, "").strip() if (remain_text != ""): new_text_response.append({"text": remain_text, "link": ""}) logger("webUI").info(new_text_response) return new_text_response
def format_response(text_response): text_response_wo_link = text_response retlinks = {} # @description: This part is to detect and extract all links in the response (It could be returned from dialogflow or web-hook # @input: Text response # @output: dictionary of link with {link<1|2|...|n>: http address} logger("chat").info("4.1. Extract links from the response") if ("http" in text_response): links = re.findall(WEB_URL_REGEX, text_response) i = 1 for url in links: if not (url.startswith('http')): continue text_response_wo_link = text_response_wo_link.replace( url, 'link' + str(i)) retlinks['link' + str(i)] = url i = i + 1 logger("chat").debug(" -> Detecting link " + url) (intro_response, detail_response) = separate_retro_with_detail(text_response_wo_link) logger("chat").info("4.2. Extract retro/introduction from response: " + intro_response) # Split detail into list and remove the empty elements. # To ignore the case where empty or element with 'spaces', need to check detail_response start with '-' or not first. # Ignore the new line in the text, to prevent to mismatch of regular expression later in the code. responses = [] formated_responses = [] if not (detail_response == ""): detail_response = detail_response.replace("\n", " ") detail_response = detail_response.replace("<section>", "<li><section>") responses = filter(None, detail_response.split("<li>")) for response in responses: if response.strip() == '': continue else: formated_responses.append(response.strip()) # Return: retro text, list of detail response, dictionary of links logger("chat").info("4.3. Format the details/list from response: ") logger("chat").info(" -> ".join(formated_responses)) return (intro_response, formated_responses, retlinks)
def receive_wav_files(): form = request.form if (request.method == 'POST'): # UPLOAD_FOLDER #print (request.form) split_ind = request.form['data'].find(",") data = request.form['data'][(split_ind + 1):] decodedData = base64.decodestring(data) filename = (request.form['fname']).replace("%3A", ":") #print ("The output filename is " + filename) #print (decodedData) with open(WAVS_FOLDER + "/" + filename, 'wb') as wavfile: wavfile.write(decodedData) logger("voice_input").info("The output file is " + UPLOAD_FOLDER + "/" + filename) return render_template('nsfnb_chat.html', form=form)
def main_render(): form = ChatForm(request.form) # ---------To clear the log each time the page is refreshed, even the same session id ----------# form.ssid = uuid.uuid4().hex if (form.ssid in form.chats.keys()): del form.chats[form.ssid][:] logger("webUI").info("You are requesting a new session by refresh: " + form.ssid) # ---------To keep log each time the page is refreshed but the time in bot response is lost ----------# logger("webUI").info("======================CHAT HISTORY======================") logger("webUI").info(form.chats) if len(form.chats.keys()) == 1: form.ssid = form.chats.keys()[0] logger("webUI").info("======================SESSION ID======================") logger("webUI").info(form.ssid) if (__DEBUG__): print ("Session id: " + str(form.ssid)) retro_msg = [{"text": "Welcome! I am North-Spine Food Ordering bot."}] retro_details = [[{'text': 'Ordering food in canteen A (NorthSpine)', 'link': 'http://www.ntu.edu.sg/has/FnB/Pages/NorthSpine.aspx'}], [{'text': 'Getting to know the location of Canteen A', 'link': 'http://maps.ntu.edu.sg/m?q=Canteen%20A&fs=m'}] ] link = [] singaporetz = timezone('Asia/Singapore') form.chats[form.ssid] = [] form.chats[form.ssid].insert(0, { #'user': ("User: Get started"), 'bot': (retro_details), 'retro': (retro_msg), 'link': (link), 'time': datetime.now(singaporetz), 'id': len(form.chats[form.ssid]) + 1, 'feedback': '' }) return render_template('nsfnb_chat.html', form=form)
def format_response_list_with_links(detail_list, links): logger("webUI").info(links.keys()) new_details = [] for detail in detail_list: m = re.match('(.*?)(link[0-9]+)', detail) item_detail = {} if bool(m): key = m.group(2) logger("webUI").info("Link index " + key + " and detail: " + detail) item_detail["text"] = detail.replace(key, "") if key in links.keys(): item_detail["link"] = links[key] del links[key] else: item_detail["text"] = detail item_detail["link"] = "" new_details.append(item_detail) logger("webUI").info(new_details) return new_details
def receive_query(): form = ChatForm(request.form) # Select to use session id info (1. generated from client, or 2. returned from dialogflow|api.ai) if (request.form['session_id'] == ''): form.ssid = uuid.uuid4().hex else: form.ssid =request.form['session_id'] # If the ssid is new, should clear the chat log - history. if (form.ssid not in form.chats.keys()): form.chats[form.ssid] = [] last_ind = len(form.chats[form.ssid]) if (last_ind > 0): logger("webUI").info("Last query, response and feedback: ") logger("webUI").info(form.chats[form.ssid][0]) singaporetz = timezone('Asia/Singapore') user_query = "" timestamp_userquery = datetime.now(singaporetz) """ #CHECK IF THE INPUT IS AUDIO -> CONVERT TO TEXT THEN ASSIGN TO USER_QUERY logger("webUI").info("UPLOAD FILE debugging - start") if (request.method == 'POST'): # check if the post request has the file part if 'au_file' not in request.files: flash('Warning: No file part') return redirect(request.url) file = request.files['au_file'] # if user does not select file, browser also # submit a empty part without filename if file.filename == '': flash('Warning: No selected file') return redirect(request.url) if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) logger("webUI").info("UPLOAD FILE debugging - end") return redirect(url_for('receive_query', _external="true", _scheme="https")) """ # Get information returned form dialogflow (FAQs agent) user_query = request.form['user_query'] if (__DEBUG__): print ("1. Your query is ") pprint.pprint(user_query) if (user_query.strip() != ""): #(bot_response, detail_list, links, sessionid, timestamp_insgtz, intentname, params) = ask_question(user_query) (bot_response, detail_list, links, sessionid, timestamp_insgtz, intentname, params) = ask_question_v2(user_query) if (__DEBUG__): print ("---------------------------") pprint.pprint(params) print ("---------------------------") # Delete the chat history if the ssid is different. logger("webUI").info("Return session from api.ai: " + sessionid) if not (sessionid in form.recent_sessionids): form.recent_sessionids.append(sessionid) del form.chats[form.ssid][:] # update the form's parameters from result. form.intent_name = intentname form.intent_params = params form.timestamp = timestamp_insgtz formated_details = format_response_list_with_links(detail_list, links) formated_retro_response = format_response_text_with_links(bot_response, links) if (__DEBUG__): print ("2. Inserting data to forms.chats") #form.chats[form.ssid].insert(0, { # 'user': ["User (" + str(timestamp_userquery) + ")", user_query], # 'bot': (formated_details), # 'retro': (formated_retro_response), # 'link': (links.values()), # 'time': form.timestamp, # 'id': len(form.chats[form.ssid]) + 1, # 'feedback': '' # }) form.chats[form.ssid].append({ 'user': ["User (" + str(timestamp_userquery) + ")", user_query], 'bot': (formated_details), 'retro': (formated_retro_response), 'link': (links.values()), 'time': form.timestamp, 'id': len(form.chats[form.ssid]) + 1, 'feedback': '', 'meta': params, }) if (__DEBUG__): print ("3. Number of elements: " + str(len(form.chats))) form.similar_queries = suggest_commplete(user_query) return render_template('nsfnb_chat.html', form=form)
def unauthorized(): logger().error(ConstStr.unauthorized_access) return make_response(jsonify({"error": ConstStr.unauthorized_access}), 403)
def post(self): args = self.reqparse.parse_args() # 1. Check if the session id is new or old - meaning the different person or timeout if (__DEBUG__): print("Receiving request from facebook-dialogflow") pprint.pprint(args) print("Finished receiving from facebook-dialogflow") ######################################## # Process the information from api.ai ######################################## # 1. Check if the session id is new or old - meaning the different person or timeout sessionId = args["responseId"] logger("webhookInterface").info("Current session id is " + sessionId) if (__DEBUG__): print("Current session id is " + sessionId) result = dict(args["queryResult"]) # 2. Output context, should save in backend for future processing intent_name_confident_score = (result["intentDetectionConfidence"]) function_name_from_intent = "" context_user_id = sessionId parameters = {} if ("intent" in result.keys()): function_name_from_intent = str(result["intent"]["displayName"]) parameters = dict(result["parameters"]) if ('outputContexts' in result.keys()): context_user_id = get_user_id(result["outputContexts"]) if (__DEBUG__): pprint.pprint(result['outputContexts']) print("Finished processing user id ") pprint.pprint(context_user_id) logger("webhookInterface").debug(type(parameters)) if (len(parameters.values()) > 0): logger("webhookInterface").debug(parameters.values()[0]) logger("webhookInterface").info("--------------------------") logger("webhookInterface").info(parameters.values()) logger("webhookInterface").info("--------------------------") # 3. Original query, provide more information, maybe contain the info that api.ai doesn't recognize reslt_query = str(result["queryText"]) logger("webhookInterface").info("Resolved query is " + reslt_query) # 4. Action associated with the query (checking map, database, etc.) #reslt_action = str(result["action"]) # 5. Get the intent name, call the function named as intent to get the result logger("webhookInterface").info("Call the function " + function_name_from_intent + "(" + str(parameters.values()) + ")") if (__DEBUG__): print("Call the function " + function_name_from_intent + "(" + str(parameters.values()) + ")") webhookResponses = {"text": ConstStr.unknown_input_str1} if function_name_from_intent in methods: func_params = parameters.values() func_params.append(context_user_id) if (__DEBUG__): print("Parameters pass to the function: ") pprint.pprint(func_params) webhookResponses = methods[function_name_from_intent]( func_params) # + argument list of course else: if ("smalltalk" in function_name_from_intent): logger("webhookInterface").info("No need webhook") else: raise Exception("Method %s not implemented" % function_name_from_intent) # 6. Return the result: Form the result conform with the request. if webhookResponses == None: logger("webhookInterface").info( "There is no response from webhook") return { "fulfillmentText": webhookResponses, "fulfillmentMessages": [{ "text": { "text": [webhookResponses] } }], "source": "webhookInterface", "payload": {}, "outputContexts": [], "followupEventInput": {} } else: logger("webhookInterface").info("Response from webhook is: ") if (__DEBUG__): pprint.pprint(webhookResponses) print("Return format") fullReps = format_dialogflow_text(webhookResponses['text']) if ('quickReplies' in webhookResponses.keys()): fullReps = fullReps + format_dialogflow_qR( webhookResponses['quickReplies']) if ('cards' in webhookResponses.keys()): fullReps = fullReps + format_dialogflow_cards( webhookResponses['cards']) if (__DEBUG__): pprint.pprint(fullReps) if (type(webhookResponses) == type({})): return { "fulfillmentText": webhookResponses['text'][0], "fulfillmentMessages": fullReps, "source": "webhookInterface", "payload": {}, "outputContexts": [], "followupEventInput": {} } else: return { "fulfillmentText": webhookResponses, "fulfillmentMessages": [{ "text": { "text": [webhookResponses] } }], "source": "webhookInterface", "payload": {}, "outputContexts": [], "followupEventInput": {} }
def ask_question_v2(input_query): global session_id # Initiate the Dialogflow agent logger("chat").info("Receiving input query" + input_query) ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN) request = ai.text_request() request.lang = 'en' # optional, default value equal 'en' request.session_id = session_id request.query = input_query.replace("\"", "'") request.resetContexts = is_reset_context_request(input_query) logger("chat").info("Request sent to YakunFood Agent") logger("chat").info(request) # Get the response from dialogflow agent response = request.getresponse() responsestr = response.read().decode('utf-8') response_obj = json.loads(responsestr) logger("chat").info("Receiving response from api.ai agent" + responsestr) text_response = response_obj["result"]["fulfillment"]["speech"] logger("chat").info("Response to display in webpage: " + text_response) return_session_id = response_obj["sessionId"] rich_messages = {"text": [], "quickreplies": [], "cards": []} detail_msgs = response_obj["result"]["fulfillment"]["messages"] for resp_message in detail_msgs: msg_type = (resp_message['type']) if (msg_type == 0): rich_messages["text"] = rich_messages[ "text"] + format_text_on_website(resp_message) if (__DEBUG__): print("Format of text on website:") pprint.pprint(rich_messages["text"]) elif (msg_type == 1): # Processing the button/card rich_messages["cards"] = rich_messages[ "cards"] + format_cards_on_website(resp_message) if (__DEBUG__): print("Format of cards on website:") pprint.pprint(rich_messages["cards"]) elif (msg_type == 2): # Processing the quickReplies rich_messages["quickreplies"] = rich_messages[ "quickreplies"] + format_quickreplies_on_website(resp_message) if (__DEBUG__): print("Format of quickreplies on website:") pprint.pprint(rich_messages["quickreplies"]) else: # Processing the carousell? pass # PROCESS THE RESPONSE - FORMAT (intro_response, detail_responses, links) = format_response(text_response) intent_name = "" if ("intentName" in (response_obj["result"]["metadata"]).keys()): # In case there is no intent name: using smalltalk or other pre-built agents from dialogflow| api.ai| google intent_name = response_obj["result"]["metadata"]["intentName"] if (intent_name == "Default Fallback Intent"): # If the agent cannot recognize the intent, we will suggest user topics of their queries. intro_response = "You can ask me something related to ordering food and beverage in Canteen A (North Spine, NTU, Singapore)." detail_responses = [] # If no intent name (small talk or prebuilt agents), using the action name instead. actionname = response_obj["result"]["action"] if (intent_name == ""): intent_name = actionname # Return the parameters, this is for debugging. parameters = dict(response_obj["result"]["parameters"]) response_timestamp = response_obj["timestamp"] # Convert time zone singaporetz = timezone('Asia/Singapore') timestamp_insgtz = convert_my_iso_8601(response_timestamp, singaporetz) return (intro_response, detail_responses, links, return_session_id, timestamp_insgtz, intent_name, rich_messages)