def search(): if not g.search_form.validate(): return redirect(url_for('main.explore')) page = request.args.get('page', 1, type=int) companies, total = Company.search(g.search_form.q.data, page, current_app.config['COMPANIES_PER_PAGE']) next_url = url_for('main.search', q=g.search_form.q.data, page=page + 1) \ if total > page * current_app.config['COMPANIES_PER_PAGE'] else None prev_url = url_for('main.search', q=g.search_form.q.data, page=page - 1) \ if page > 1 else None return render_template('search.html', title=_('Search'), companies=companies, next_url=next_url, prev_url=prev_url)
def check_intent(chat, text, callback_query=False): """ This will help determine types of intents by users 1. getSubscribedCompany: This will return list of companies that the user has subscribed to (must be existing user) 2. getAnnouncement <Company>: This will return list of announcements published by the <Company> that the user has queried to (must have company) 3. subscribeCompany <Company>: This will add the <Company> into the user list company of subscription (must have company) 4. unsubscribeCompany <Company>: This will remove the <Company> from the user list company of subscription (must be existing user and have company) 5. generic intents to handle fallback and default intent """ chat_id = chat.id user = TelegramSubscriber.query.filter( TelegramSubscriber.chat_id == chat_id, TelegramSubscriber.status != 0).first() message = None markup = None response_text = None per_page = 4 if callback_query: # Do if it is callback query intention = text.split('@') intent = intention[0] page = 1 if len(intention) <= 2 else int(intention[2]) companies = [None if len(intention) <= 1 else intention[1]] price = None else: # Do if it is not callback query (generic text query) response = detect_intent_text(os.environ.get('PROJECT_ID'), chat_id, text, 'en') intent = response.query_result.intent.display_name companies = response.query_result.parameters.fields.get( 'company' ).list_value.values if response.query_result.parameters.fields.get( 'company') else None price = response.query_result.parameters.fields.get( 'price' ).number_value if response.query_result.parameters.fields.get( 'price') else None if companies: strings = [] for company in companies: string = company.string_value strings.append(string) companies = strings fulfillment_text = response.query_result.fulfillment_text page = 1 if user: if user.status == 2: intent = 'optOutFeedback' company_ind = 0 while True: company = companies[company_ind] if companies else None comp = Company.query.filter_by(stock_code=company).first() # Checking the combination between comp, company(user input), user(user from database) and intent to guess what is the user trying to do. if intent == "defaultFallbackIntent": response_text = "I'm sorry, can you repeat that again or try one of the below options?" markup = [[ telegram.InlineKeyboardButton( text="▶️ Start", callback_data="defaultWelcomeIntent"), telegram.InlineKeyboardButton( text="ℹ️ Help", callback_data="getAgentInformation") ]] elif intent == "defaultWelcomeIntent": response_text = "Hi {}, I will be your handler to fetch stock announcements from Bursa Malaysia. Feel free to explore my capabilities with /help.".format( chat.first_name) elif intent == "getAgentInformation": response_text = render_template('telebot/agent_info_template.html', user_name=chat.first_name) markup = [ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany"), telegram.InlineKeyboardButton(text="Query", callback_data="queryCompany") ] if user: user.update_name(chat) markup = [markup] markup.append([ telegram.InlineKeyboardButton( text="Check Subscription", callback_data="getSubscribedCompany"), telegram.InlineKeyboardButton( text="Set Price Alert", callback_data="setPriceAlert") ]) markup.append([ telegram.InlineKeyboardButton( text="Unsubscribe", callback_data="unsubscribeCompany"), telegram.InlineKeyboardButton(text="⏹️ Opt Out", callback_data="optOut") ]) else: markup = [markup] elif intent == "queryCompany": if not company: # no company is typed detect_intent_text(os.environ.get('PROJECT_ID'), chat_id, intent, 'en') response_text = 'Please input the stock name that you are interested in.' elif not comp and current_app.elasticsearch: # no specific company is found in db response_text = 'This is the list of stocks that are nearest to your input.' query, total = Company.search(company, page, per_page) target_companies = query.all() buttons = [] for target_company in target_companies: button = telegram.InlineKeyboardButton( text="{stock_name}: {company_name} ({stock_code})". format(stock_name=target_company.stock_name, company_name=target_company.company_name, stock_code=target_company.stock_code), callback_data="queryCompany@{}".format( target_company.stock_code)) buttons.append(button) buttons = [buttons] markup = list(map(list, zip(*buttons))) # create pagination experience here page_buttons = pagination_button(total, page, per_page, intent, company=company) markup.append(page_buttons) markup.append([ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]) elif not comp: # company input cannot be recognised without elasticsearch assistance detect_intent_text(os.environ.get('PROJECT_ID'), chat_id, intent, 'en') response_text = "Sorry, I can't find the company you are interested in, can you please specify the company with full name?" else: response_text = render_template('telebot/price_alert.html', company=comp, company_url=COMPANY_INFO_URL, header="Query Result") if user.has_subscribed(comp): markup = [[ telegram.InlineKeyboardButton( text="Unsubsribe", callback_data="unsubscribeCompany@{}".format( comp.stock_code)), telegram.InlineKeyboardButton( text="Set Price Alert", callback_data="setPriceAlert@{}".format( comp.stock_code)) ]] else: markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany@{}".format( comp.stock_code)) ]] markup.append([ telegram.InlineKeyboardButton( text="ℹ️ Help", callback_data="getAgentInformation") ]) elif intent == "subscribeCompany": if not company: # no company is typed detect_intent_text(os.environ.get('PROJECT_ID'), chat_id, intent, 'en') response_text = 'Please input the stock name that you are interested in.' elif not comp and current_app.elasticsearch: # no specific company is found in db response_text = 'This is the list of stocks that are nearest to your input.' query, total = Company.search(company, page, per_page) target_companies = query.all() buttons = [] for target_company in target_companies: button = telegram.InlineKeyboardButton( text="{stock_name}: {company_name} ({stock_code})". format(stock_name=target_company.stock_name, company_name=target_company.company_name, stock_code=target_company.stock_code), callback_data="subscribeCompany@{}".format( target_company.stock_code)) buttons.append(button) buttons = [buttons] markup = list(map(list, zip(*buttons))) # create pagination experience here page_buttons = pagination_button(total, page, per_page, intent, company=company) markup.append(page_buttons) markup.append([ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]) elif not comp: # company input cannot be recognised without elasticsearch assistance detect_intent_text(os.environ.get('PROJECT_ID'), chat_id, intent, 'en') response_text = "Sorry, I can't find the company you are interested in, can you please specify the company with full name?" elif not user: # if new user if TelegramSubscriber.query.filter_by(chat_id=chat_id).first(): user = TelegramSubscriber.query.filter_by( chat_id=chat_id).first() user.activate() else: user = TelegramSubscriber(chat_id=chat_id, username=chat.username, first_name=chat.first_name, last_name=chat.last_name) db.session.add(user) user.subscribes(comp) response_text = "Welcome {}! Thank you for your first subscription on {}".format( chat.first_name, comp.company_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany") ], [ telegram.InlineKeyboardButton( text="Check Subscription", callback_data="getSubscribedCompany"), telegram.InlineKeyboardButton( text="Set Price Alert", callback_data="setPriceAlert") ], [ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] elif user.has_subscribed(comp): # user already subscribed to the company response_text = "Sorry, you are already subscribed to {}.".format( comp.stock_name) else: # all conditions checked, user can now subscribe to the company user.subscribes(comp) response_text = "Thank you! You are now subscribed to {}.".format( comp.stock_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany"), telegram.InlineKeyboardButton( text="Undo", callback_data="unsubscribeCompany@{}".format( comp.stock_code)) ], [ telegram.InlineKeyboardButton( text="Check Subscription", callback_data="getSubscribedCompany"), telegram.InlineKeyboardButton( text="Set Price Alert", callback_data="setPriceAlert") ], [ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] elif intent == "unsubscribeCompany": if not user: # user has not subscribed before response_text = 'Hi {}, seems like it is your first time here, try /start or /help.'.format( chat.first_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany") ], [ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] elif not company or not comp: # no company is typed # can consider putting in the list of subscribed company as markup in pagination response_text = "Please select the stocks that you would like to unsubscribe." subscribed_companies = Company.query.filter( Company.subscriber.any(id=user.id)).order_by( Company.stock_name).paginate(page, per_page, False) # subscribed_companies = user.subscribed_company.order_by(Company.stock_name).paginate(page, per_page, False) buttons = [] for subscribed_company in subscribed_companies.items: button = telegram.InlineKeyboardButton( text="{stock_name}: {company_name} ({stock_code})". format(stock_name=subscribed_company.stock_name, company_name=subscribed_company.company_name, stock_code=subscribed_company.stock_code), callback_data="unsubscribeCompany@{}".format( subscribed_company.stock_code)) buttons.append(button) buttons = [buttons] markup = list(map(list, zip(*buttons))) # create pagination experience here page_buttons = pagination_button(subscribed_companies.total, page, per_page, intent, company=company) markup.append(page_buttons) markup.append([ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]) elif user.has_subscribed(comp): # user has subscribed to the company, will proceed to unsubscribe user.unsubscribes(comp) response_text = "Thank you! You are now unsubscribed from {}.".format( comp.stock_name) markup = [[ telegram.InlineKeyboardButton( text="Unsubscribe", callback_data="unsubscribeCompany"), telegram.InlineKeyboardButton( text="Undo", callback_data="subscribeCompany@{}".format( comp.stock_code)) ], [ telegram.InlineKeyboardButton( text="Check Subscription", callback_data="getSubscribedCompany"), telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] else: # user has not subcribed to the specific company response_text = 'You have not subscribed to {}.'.format( comp.stock_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany"), telegram.InlineKeyboardButton( text="Unsubscribe", callback_data="unsubscribeCompany") ], [ telegram.InlineKeyboardButton( text="Check Subscription", callback_data="getSubscribedCompany"), telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] elif intent == "setPriceAlert": if not user: # user has not subscribed before response_text = 'Hi {}, seems like it is your first time here, try /start or /help.'.format( chat.first_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany") ]] elif not company or not comp: # no company is typed # can consider putting in the list of subscribed company as markup in pagination response_text = "Please select the stock that you would like to set price alert for." subscribed_companies = Company.query.filter( Company.subscriber.any(id=user.id)).order_by( Company.stock_name).paginate(page, per_page, False) buttons = [] for subscribed_company in subscribed_companies.items: button = telegram.InlineKeyboardButton( text="{stock_name}: {company_name} ({stock_code})". format(stock_name=subscribed_company.stock_name, company_name=subscribed_company.company_name, stock_code=subscribed_company.stock_code), callback_data="setPriceAlert@{}".format( subscribed_company.stock_code)) buttons.append(button) buttons = [buttons] markup = list(map(list, zip(*buttons))) # create pagination experience here page_buttons = pagination_button(subscribed_companies.total, page, per_page, intent, company=company) markup.append(page_buttons) markup.append([ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]) elif not price and price != 0.0: # prompt users to input desired price response_text = "Please type the desired price." print(company) detect_intent_text(os.environ.get('PROJECT_ID'), chat_id, intent + " " + str(company), 'en') else: # all conditions checked, user exists, company exists with desired price user.set_price_alert(comp, price) response_text = "Your price alert has been subscribed successfully. You will be notified once the price is fulfilled." elif intent == "getSubscribedCompany": if not user: # user has not subscribed before response_text = 'Hi {}, seems like it is your first time here, try /start or /help.'.format( chat.first_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany") ], [ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] elif len(user.subscribed_company) == 0: # user has not subscribed to any companies response_text = "Hi {}, seems like it's been a while since you left us, try /start or /help to get started again!".format( chat.first_name) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany") ], [ telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] else: # retrieve all companies that the user has subscribed to response_text = user.company_message( message= "Thank you for subscribing, this is your subscription list:" ) markup = [[ telegram.InlineKeyboardButton( text="Subscribe", callback_data="subscribeCompany"), telegram.InlineKeyboardButton( text="Unsubscribe", callback_data="unsubscribeCompany") ], [ telegram.InlineKeyboardButton( text="Set Price Alert", callback_data="setPriceAlert"), telegram.InlineKeyboardButton( text="ℹ️ Back to Help", callback_data="getAgentInformation") ]] elif 'optOut' in intent: if not user: # user have not subscribed before response_text = 'Sorry, you are not subscribed to us.' elif intent == 'optOutConfirmed': user.optout() response_text = "Sorry to see you go, please drop us a feedback here and we will improve our bot. Thank you." elif intent == 'optOutFeedback': user.deactivate() # constructing user's name in string if user.first_name and user.last_name: user_name = user.first_name + " " + user.last_name elif user.first_name: user_name = user.first_name elif user.last_name: user_name = user.last_name else: user_name = None send_email('Feedback from Telegram User', sender='no-reply@' + current_app.config['MAIL_SERVER'], recipients=current_app.config['ADMINS'], text_body=render_template('email/feedback.txt', user=user_name, feedback_text=text), html_body=render_template('email/feedback.html', user=user_name, feedback_text=text)) response_text = "Thank you for your feedback. Our team has received your feedback and we hope to see you again." else: response_text = "Are you sure to opt out? Selecting 'Yes' is irreversible and will delete all your subscription record." markup = [[ telegram.InlineKeyboardButton( text="⭕ Yes", callback_data="optOutConfirmed"), telegram.InlineKeyboardButton( text="❎ No", callback_data="getAgentInformation") ]] else: # intent not recognised, call default fallback return check_intent(chat, "defaultFallbackIntent", callback_query=True) if not markup and intent != 'optOutConfirmed': markup = [[ telegram.InlineKeyboardButton( text="ℹ️ Help", callback_data="getAgentInformation") ]] # Checking if it is last item, if last then break else go next if not companies or company_ind == len(companies) - 1: break else: company_ind += 1 resp = {'response_text': response_text, 'markup': markup} return resp