Can't receive update messages from user - python

I am trying to create a bot that receives a response from the user and asks again if needed. The problem is that after:
update.reply_text("Did you report all you working hour on freshdesk for this week?, ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
I can't get the new updates. The message text remains /start in the first print, and the second print doesn't work at all.
How can I get correctly the response from the user? Can it be an issue related to ReplyMarkup?
def check_the_week(bot, update):
agent_username = update.message.from_user['username']
parameters = {"username": agent_username}
url = "{}/weekly_hours/".format(API_URL)
report = get_request_forwarder(url=url, method="GET", parameters=parameters)["messages"]
reply_keyboard = [['YES', 'NO']]
bot.send_message(
chat_id=update.message.chat_id,
text=report,
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)) # sends the total nr of hours
print update.message.text
update.reply_text("Did you report all you working hour on freshdesk for this week?",
ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
print update.message.text
if update.message.text == "YES":
update.message.reply_text(text="Are you sure?", reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
# Asks confirmation
if update.message.text == "YES":
update.message.reply_text(text="Thank you for reporting your working hours in time!")
elif update.message.text == "NO":
update.message.reply_text(text="Please, check you time reports and add missing")
elif update.message.text == "NO":
update.message.reply_text(text="Please, check you time reports and add missing")
def main():
# Create the EventHandler and pass it your bot's token.
updater = Updater(TELEGRAM_TOKEN)
j = updater.job_queue
# # Get the dispatcher to register handlers
dp = updater.dispatcher
# # Start the Bot
dp.add_handler(CommandHandler("start", check_the_week))
# Send information to manager by command
updater.start_polling()
updater.idle()
print("bot started")
if __name__ == '__main__':
main()

Because you are using a CommandHandler, which is only used to capture a single command at a time.
What you want to do can be achieved by using a ConversationHandler. Please read the example scripts here and here. Also you can read more details on the handler here.

Related

Python Telegram Bot is not Ideling on Heroku

I am using heroku to deploy my telegram bot. I am using free dynos. So, to save dyno hours I want my app to go idle after 30 mins of inactivity which it should.
https://www.heroku.com/dynos
But, my app get random GET requests after 25mins or so. So, my app never goes to idle.
Note:
My app is not yet on production so I cannot figure out why I am getting ping every 25min.
here is my code:
import telegram.ext
import bot
from config import TOKEN,PORT
def start(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("Welcome! to Football Story Bot")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
def help(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("""
The following commands are available:
/start -> Welcome Message
/help -> This Message
/streams -> list of matches
""")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
def streams(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("Searching for available matches")
all_matches_name_list = bot.all_matches_name()
link_str=''
if(all_matches_name_list==None):
update.message.reply_text("We are experiencing problem.Try again later, if problem persists then contact admin")
return None
for links in all_matches_name_list:
link_str+=links+'\n'
update.message.reply_text(link_str)
update.message.reply_text("End Of Detected Matches")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
def handle_message(update,context):
id = update.message.chat.id
if(id == (hidden) or id == (hidden)):
update.message.reply_text("Searching for available streams")
link_str=''
sending_message=''
for chars in update.message.text:
if(chars=='#'):
break
sending_message+=chars
individual_link = bot.selected_match(bot.all_matches_name(),sending_message)
if(individual_link==None):
update.message.reply_text("We are experiencing problem.Try again later, if problem persists then contact admin hai tw")
return None
if(len(individual_link)==0):
update.message.reply_text("No links found. Links are updated 30min before match. If link is not found till Kick Off then contact admin")
return None
for links in individual_link:
link_str+=links+'\n\n'
update.message.reply_text(link_str)
update.message.reply_text("End Of Streaming Links")
else:
update.message.reply_text("""
We have detected unusual request from your device.
You have been banned from the service until further notice,
""")
updater = telegram.ext.Updater(TOKEN,use_context=True)
disp = updater.dispatcher
disp.add_handler(telegram.ext.CommandHandler("start",start))
disp.add_handler(telegram.ext.CommandHandler("help",help))
disp.add_handler(telegram.ext.CommandHandler("streams",streams))
disp.add_handler(telegram.ext.MessageHandler(telegram.ext.Filters.command,handle_message))
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN,
webhook_url="(my app link)" + TOKEN)
updater.idle()

Running a cron scheduler within a running thread

I'm writing a telegram bot and I want to schedule it to send an automated message every day at a specific timing, cron style. I am using apscheduler to do it but I could not get the cron function to work. The interval scheduling works fine but it is not what I want.
I don't want to execute the .py file outside because I need the telegram bot to detect user's /start message.
So what I wanted to do was to detect user's /start message and then start the scheduler. Thereafter, the bot will send a message to the user everyday 8pm night.
Cron scheduling doesn't start and I don't know why. I suspect it is because it can't run within the main thread that I am running? Any advice would be helpful! Thank you.
import time
import telepot
import json
from telepot.loop import MessageLoop
from telepot.namedtuple import ReplyKeyboardMarkup # for custom keyboard
from telepot.delegate import pave_event_space, per_chat_id, create_open
from apscheduler.schedulers.blocking import BlockingScheduler
## Load token
TOKEN = 'TOKEN NUMBER'
# The main body
class main(telepot.helper.ChatHandler): # Implement continuous dialogue with user using DelegatorBot
global counter1
counter1 = 0
global counter2
counter2 = 0
def __init__(self, *args, **kwargs):
super(main, self).__init__(*args, **kwargs)
# Initialize and create empty dictionary for storing data.
self.indicator = '0'
self.data = {} # initialize an empty dictionary for storing data.
def on_chat_message(self, msg):
content_type, chat_type, chat_id = telepot.glance(msg) # this is very important.
# Debugging
print(content_type, chat_type, chat_id)
print(msg['text'])
global counter1
global counter2
scheduler = BackgroundScheduler()
#scheduler_cron = BlockingScheduler()
# Survey function
def survey():...
return
def repeat_message():
bot.sendMessage(chat_id, text='type /survey to repeat survey.')
print("Reminder sent.")
scheduler_cron.add_job(repeat_message, 'cron', day='*', week='*', day_of_week='*', hour=20, minute=00)
# Detect start messages.
while True:
if counter2 == 11: # If survey ends AKA 11 Qns done. Restart the counters.
counter1 = 0
counter2 = 0
# once bot starts, ask user to repeat survey at a specific time of the day.
if counter1 == 0: # If survey ends or at the very beginning of using the bot.
# Start message.
if msg['text'] == '/start': # /starts initiates bot. User gets greeted with a welcome message describing what the bot will do.
bot.sendMessage(chat_id,
text='Hello there.',
parse_mode='Markdown')
scheduler_cron.start()
print("Scheduler started.")
# Start survey after initializing the bot
elif msg['text'] == '/survey': # /survey initiates survey.
print("Survey started...")
#counter1 = 0
counter1 += 1
else:
bot.sendMessage(chat_id, text='I do not recognise your message.')
msg['text'] = '' # resets msg.
# User starts survey
if counter1 == 1: # if user types /survey, counter1 +=1 and when counter1 == 1, run survey function.
survey() # starts survey
counter2 += 1
break
bot = telepot.DelegatorBot(TOKEN, [pave_event_space()(per_chat_id(), create_open, main, timeout=60),])
MessageLoop(bot).run_as_thread() # Initiates the bot on telegram. Listens for user's response. If this is stopped, the entire bot stops.
print('Listening...')
while True:
time.sleep(1)
EDIT: I found out that apscheduler's cron does not work if I have another thread running in the background as stated in their documents:
BlockingScheduler: use when the scheduler is the only thing running in your process
BackgroundScheduler: use when you’re not using any of the frameworks below, and want the scheduler to run in the background inside your application
So it means I can't use apscheduler to make my bot work. Anyone know of any cron-like alternatives that allows me to schedule my telegram bot to fire message to users at specific timings of the day? Preferably, it has to be something that works with the telegram API.

Restart a conversation in Dialogflow

Hello stack overflow community,
I would like your help in the following problem:
Currently I am running a Dialogflow chatbot that has some intents and gives back some responses. The chat bot works perfectly until now. For your information, I use webhook to get back responses.
Here is a screenshot of my intents flow: dialogflow chatbot
What I struggle to do is to give the user the opportunity to rerun the whole conversation from the start. Do you know how can I achieve this in Dialogflow?
Python code snippet to run webhook:
app = Flask(__name__)
# default route
#app.route('/')
def index():
return 'Chatbot is online and running!'
#app.route('/webhook', methods=['GET', 'POST'])
def webhook():
# return response
req = request.get_json(force=True, silent = True)
action = req.get('queryResult').get('action')
intent_name = req.get('queryResult').get('intent').get('displayName')
if action == "get_results" and intent_name == 'KellyMovieBot':
return make_response(jsonify(suggest_movie(req)))
elif action == "ask_question" and intent_name == 'ask_first_time':
return make_response(jsonify(propose_second_movie(req)))
elif action == "thanks_giving_end" and intent_name == "thanks_giving":
return make_response(jsonify(thanks(req)))
elif action == "rerun_conversation" and intent_name == "rerun_conversation":
user_answer = req.get('queryResult').get('parameters').get('user_answer')
if user_answer == "No" or user_answer == "no":
return {'fulfillmentText': "Enjoy your film!"}
elif user_answer == "Yes" or user_answer == "yes":
return {'fulfillmentText': "Let's start again..."}
# run the app
if __name__ == '__main__':
app.run()
Note: The functions suggest_movie(), propose_second_movie(), thanks() are three functions that have been created in order to return 3 different outputs based on the communication flow.
What I want is find the correct syntax that will allow me to RERUN the whole conversation again if the user says 'Yes' else Dialogflow should end the conversation.
I would appreciate any help or advise you can give me!
You can do this by sending a follow-up event rather than a response. In this case when the user responds with yes, in your code, you'd return:
{
"followupEventInput": {
"name": "KellyMovieBot",
"languageCode": "en-US"
}
}
Make sure your KellyMovieBot intent has the same event name. You don't have to use the specified value, but the event name as sent in the response should also match the event name as configured on the intent.
https://cloud.google.com/dialogflow/docs/events-custom#invoke_event_from_webhook

Telegram timed response

I am currently working on a Telegram Bot using the python api. I am using this example here https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/conversationbot.py. With that example I want the bot to have a timed response.
For example if the user does not respond within 30 sec send a "Are you still there message" or something and after 1 min end the conversation. The reason I want to implement something like this is because the conversation does not close if there is no response. It is in that state until the I end the script. Therefore the user can not send /start command to start all over. I was able to find this https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/ext/conversationhandler.py where it states I can enable allow_reentry. I did and it sort of solves that issue where the user can start a new converation over and over using the command /start. But I would still like to have the conversation end after a set amount of time. To end a conversation I need to return ConversationHandler.END
I have tried a while loop counting down from 9 with a time.sleep of 2 each time. with it reading the response update.message.text but it only reads the command /start which means I can never advance in the script, unless I return it using return GENDER but I am not able to find a method in which I can tell when the user has chosen the gender to then return GENDER.
So how do I implement an timer based response? Thank You
from telegram import (ReplyKeyboardMarkup)
from telegram.ext import (Updater, CommandHandler, MessageHandler, Filters, RegexHandler,
ConversationHandler)
import logging
# Enable logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)
GENDER, PHOTO, LOCATION, BIO = range(4)
def start(bot, update):
reply_keyboard = [['Boy', 'Girl', 'Other']]
bot.sendMessage(update.message.chat_id,
text='Hi! My name is Professor Bot. I will hold a conversation with you. '
'Send /cancel to stop talking to me.\n\n'
'Are you a boy or a girl?',
reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True))
return GENDER
def gender(bot, update):
user = update.message.from_user
logger.info("Gender of %s: %s" % (user.first_name, update.message.text))
bot.sendMessage(update.message.chat_id,
text='I see! Please send me a photo of yourself, '
'so I know what you look like, or send /skip if you don\'t want to.')
return PHOTO
def photo(bot, update):
user = update.message.from_user
photo_file = bot.getFile(update.message.photo[-1].file_id)
photo_file.download('user_photo.jpg')
logger.info("Photo of %s: %s" % (user.first_name, 'user_photo.jpg'))
bot.sendMessage(update.message.chat_id, text='Gorgeous! Now, send me your location please, '
'or send /skip if you don\'t want to.')
return LOCATION
def skip_photo(bot, update):
user = update.message.from_user
logger.info("User %s did not send a photo." % user.first_name)
bot.sendMessage(update.message.chat_id, text='I bet you look great! Now, send me your '
'location please, or send /skip.')
return LOCATION
def location(bot, update):
user = update.message.from_user
user_location = update.message.location
logger.info("Location of %s: %f / %f"
% (user.first_name, user_location.latitude, user_location.longitude))
bot.sendMessage(update.message.chat_id, text='Maybe I can visit you sometime! '
'At last, tell me something about yourself.')
return BIO
def skip_location(bot, update):
user = update.message.from_user
logger.info("User %s did not send a location." % user.first_name)
bot.sendMessage(update.message.chat_id, text='You seem a bit paranoid! '
'At last, tell me something about yourself.')
return BIO
def bio(bot, update):
user = update.message.from_user
logger.info("Bio of %s: %s" % (user.first_name, update.message.text))
bot.sendMessage(update.message.chat_id,
text='Thank you! I hope we can talk again some day.')
return ConversationHandler.END
def cancel(bot, update):
user = update.message.from_user
logger.info("User %s canceled the conversation." % user.first_name)
bot.sendMessage(update.message.chat_id,
text='Bye! I hope we can talk again some day.')
return ConversationHandler.END
def error(bot, update, error):
logger.warn('Update "%s" caused error "%s"' % (update, error))
def main():
# Create the EventHandler and pass it your bot's token.
updater = Updater("TOKEN")
# Get the dispatcher to register handlers
dp = updater.dispatcher
# Add conversation handler with the states GENDER, PHOTO, LOCATION and BIO
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start)],
states={
GENDER: [RegexHandler('^(Boy|Girl|Other)$', gender)],
PHOTO: [MessageHandler([Filters.photo], photo),
CommandHandler('skip', skip_photo)],
LOCATION: [MessageHandler([Filters.location], location),
CommandHandler('skip', skip_location)],
BIO: [MessageHandler([Filters.text], bio)]
},
fallbacks=[CommandHandler('cancel', cancel)],
allow_reentry=True
)
dp.add_handler(conv_handler)
# log all errors
dp.add_error_handler(error)
# Start the Bot
updater.start_polling()
# Run the bot until the you presses Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT. This should be used most of the time, since
# start_polling() is non-blocking and will stop the bot gracefully.
updater.idle()
You can use the JobQueue for that.
You can see an example here: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/timerbot.py
Make sure to initialize your handler with pass_job_queue=True (as shown in the above example).

Threading in a irc Chat bot

Writing a chat bot that i think needs more then 1 thread. First Main thread reads constantly the chat. From time to time I need to check the moderators which i need to get from an URL((JSON)) and provide to the main thread so he can for example ban someone but not an moderator.
First Question: How do i make a thread run every 30 secs. I dont want to pause it. I want to run it, finish after getting the moderators list and then after some time run it again.
Code of Main File:
#Requests module, which gets JSON data from an url
#To get moderators in the chat.
def secondThread():
while(True):
getModsList()
def chatReading():
#Creates socket to the twitch irc chat
s = openSocket()
#Joins a specific chat room
joinRoom(s)
while(True):
#Revieves messages from irc
derp = s.recv(8192)
derp=derp.decode('utf-8')
temp = str.split(derp, "\n")
readbuffer = temp.pop()
#Loop which prints scanned thing from twitch irc chat
for line in temp:
#Time stamp
print(time.strftime('%X'), end=" : ")
#Pings server back
pingPong(s, line)
#This just displays the message recieved more readable User:Message
try:
print(getUser(line) + " typed :" + getMessage(line))
except (IndexError, UnicodeEncodeError):
print("Not an user")
def main():
thread_1 = threading.Thread(target=chatReading, args=[])
thread_2 = threading.Thread(target=secondThread, args=[])
thread_1.start()
thread_2.start()
if __name__ == '__main__':
main()
Second file with getModList
moderators = None
def getModsList():
gotList = False
while(gotList != True):
jsonList = requests.get(CHANNEL_GROUP)
#If the jsonList status_code == 200 that means that it got the list,
#every other number is bad.
statusFlag=jsonList.status_code
if(statusFlag == 200):
gotList = True
else:
print("Failed to get mods list, trying again")
continue
jsonList=jsonList.json()
#this gets the mods list
moderators = jsonList['chatters']['moderators']
time.sleep(10)
Second question would be more an advice. How do i plan the project? Its my first more serious project and I'm having trouble see how to plan it. I want to add later more funcionality to the bot like commands for user, mods, a raffle where a user by command can join only once, and after 5 minutes a winner is chosen. Thanks in advance.

Categories

Resources