I have set up a telegram bot using webhooks in python on google cloud functions. Based on some sample code from the internet I got it to work as a simple echo-bot however the structure is very different to the bots I coded before using long polling:
# main.py
import os
import telegram
def webhook(request):
bot = telegram.Bot(token=os.environ["TELEGRAM_TOKEN"])
if request.method == "POST":
update = telegram.Update.de_json(request.get_json(force=True), bot)
chat_id = update.message.chat.id
# Reply with the same message
bot.sendMessage(chat_id=chat_id, text=update.message.text)
return "ok"
I do not understand how to add any more handlers or different functions to this, especially because cloud functions needs me to name only one function to run from the script (in this case the webhook function).
How can I convert the above logic to the one I am more familiar with below:
import os
TOKEN = "TOKEN"
PORT = int(os.environ.get('PORT', '8443'))
updater = Updater(TOKEN)
# add example handler
def start(update, context):
context.bot.send_message(chat_id=update.message.chat_id, text="Hello, I am dice bot and I will roll some tasty dice for you.")
start_handler = CommandHandler('start', start)
dispatcher.add_handler(start_handler)
# start webhook polling
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN)
updater.bot.set_webhook("https://<appname>.herokuapp.com/" + TOKEN)
updater.idle()
This code has the same structure as long polling so I know how to add additional handlers. However it has two problems:
It is the code snippet from the documentation for heroku, so I do not know whether this works the same for google cloud functions
This does not produce one function I can call in cloud functions, I tried wrapping all my code above in one big function webhook and simply running that but it does not work (and does not produce an error on my google dashboard).
Any help is appreciated!
I found this github telebot repo from yukuku with the setup of a telegram bot on App Engine and the webhook implementation using python. As mentioned before you may want to use App Engine in order to implement your bot with many functions on the same main.py file.
I just tried and it's working for me.
i did that here's my snippet
from telegram import Bot,Update
from telegram.ext import CommandHandler,Dispatcher
import os
TOKEN = os.getenv('TOKEN')
bot = Bot(token=TOKEN)
dispatcher = Dispatcher(bot,None,workers=0)
def start(update,context):
context.bot.send_message(chat_id=update.effective_chat.id,text="I am a bot, you can talk to me")
dispatcher.add_handler(CommandHandler('start',start))
def main(request):
update = Update.de_json(request.get_json(force=True), bot)
dispatcher.process_update(update)
return "OK"
# below function to be used only once to set webhook url on telegram
def set_webhook(request):
global bot
global TOKEN
s = bot.setWebhook(f"{URL}/{TOKEN}") # replace your functions URL,TOKEN
if s:
return "Webhook Setup OK"
else:
return "Webhook Setup Failed"
Related
I made code for my discord bot and used UptimeRobot to keep it running constantly but then it my bot just stopped working randomly and I'm not sure why. It worked once and maybe ran for a few hours and now it completely won't work, even if I get rid of the 'keep_alive' code.
UptimeRobot - https://uptimerobot.com Discord Bot Tutorial - https://www.youtube.com/watch?v=SPTfmiYiuok | Time - 58:47
Main:
[Start of code]
import os
import random
import discord
from keep_alive import keep_alive
[ALL MY CODE/COMMANDS]
Then at the end of is this [my commands] ---->
keep_alive()
my_secret = os.environ['TOKEN']
client.run[my_secret]
[NEW FILE-KEEP_ALIVE.PY]
from flask import Flask
from threading import Thread
app = Flask('')
#app.route('/')
def home():
return "Hello. I am alive!"
def run():
app.run(host='0.0.0.0',port=8080)
def keep_alive():
t = Thread(target=run)
t.start()
You should not use free hosting services, they are usually really bad. You should get a paid one (you not need to spend money on it and get premium servers) you can try amazon aws free trail. it should be enough for the discord bot and run 24/7 for 12 months. Other than that, if you need more ressouces you can find a hosting provider, register with a virtual creditcard, order the stuff you like and freeze the vcc. a good vcc provider is revolut.
I'm working on an API function that takes an input from one web service (Knack), runs a number of functions to create a payload to send to another (PandaDoc), and then eventually closes by executing a POST back to Knack with the URL to the newly created PandaDoc.
Here's the start of my code:
from flask import Flask, request, Response
from flask_restful import Resource, Api, reqparse
import price_calculator
import requests
from pandadoc import build_payload, create, send, get_event_details, send_document_to_knack
app = Flask(__name__)
api = Api(app)
class Pricing(Resource):
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('eventId', required=True, type=str)
args = parser.parse_args()
price_list = price_calculator.price_calc(event_id=args['eventId'])
pandadoc_payload = build_payload(price_list=price_list, event_id=args['eventId'])
create_meta = create(payload=pandadoc_payload)
# Code should pause here to listen for response from respond()
# I'll add some code here to compare webhook data to args['eventId'] to make sure it's the same document
recipient_email = get_event_details(event_id=args['eventId'])['client_email']
send_meta = send(doc_id=create_meta['id'], recipient_email=recipient_email)
knack = send_document_to_knack(event_id=args['eventId'], doc_id=create_meta['id'])
return {
'Price List': price_list,
'PandaDoc Meta': create_meta
}, 200
#app.route('/webhook', methods=['POST'])
def respond():
data = request.json[0]['data']
args = {
'doc_id': data['id'],
'doc_status': data['status']
}
return Response(status=200)
However, PandaDoc publishes documents asynchronously, which means it takes anywhere from 3-5 seconds for the doc to be published once I execute create_meta. PandaDoc offers a webhook for when a document status is updated (published), and I have figured out how to listen for that webhook. However, I somehow need the function post() to pause until it receives the webhook, so I can compare the payload from the webhook to the existing data (to make sure it's the same document) and then retreive the document ID to send back to Knack.
How can I get my post() function to pause and wait for the results of the webhook? I'd love for it to move on as soon as the webhook posts, rather than setting a fixed time...
I welcome any other feedback on the code, too, as I'm still relatively new to creating APIs in Python! Thanks.
You can use PandaDoc python SDK (ensure_document_created method to poll until the document is created)
Let me know if you have any other questions.
I don't program with Python too much, so I'm not 100% sure about this answer but I think that Python has an await system.
I think something like this could be done:
async def myFunction():
await myFunctionThatTakesSomeTimeToRun()
I recently made a discord bot and ran in on repl.it as it has free hosting (I use uptime robot). But, when I run main.py the uptime robot says that the website that I use for keep_alive() is "Down" and when I try to access the website from my browser it doesn't load either saying that the site "can't be reached". When I close the repl.it tab my bot goes offline as well.
Repl.it is not made for hosting discord bot's it's prone to rate limits.
It's good for writing code online and hosting basic web apps or collaborating with others while coding.
You should definitely invest in a proper host like PebbleHost, PloxHost and etc if you need something to write code online. However, a VPS provider like Linode, Digitalcoean or even PloxHost would be more beneficial as you have your own dedicated IP and are not affected by rate limits from other users. However, this does require knowledge of Linux.
For your issue of your keep_alive you should try this:
from flask import Flask
from threading import Thread
import time
app = Flask('')
#app.route('/')
def home():
return "Hello World!"
def run():
app.run(host='0.0.0.0',port=8080)#127.0.0.1 or ::
def keep_alive():
t = Thread(target=run)
t.start()
Then in your main.py:
from keep_alive import keep_alive
keep_alive()
You should take a look at UptimeRobot to send pings to the URL of the web server associated with the repl. This video is for node.js but should apply to python as well on the UptimeRobot chunk
I create a Telegram bot using Python, here is the code:
TOKEN = BOT TOKEN
# deploy
def run(updater):
PORT = int(os.environ.get('PORT', '8443'))
updater.start_webhook(listen="0.0.0.0",
port=PORT,
url_path=TOKEN)
updater.bot.set_webhook("Azure WEB APP URL".format(TOKEN))
def start_handler(bot, update):
do something
def callback_func(bot, job):
do something
def trigger_callback(bot, update, job_queue):
logger.info("User {} trigger bot".format(update.effective_user["id"]))
bot.send_message(chat_id=update.message.chat_id, text='Starting!')
job_queue.run_repeating(callback_sql, 600, context=update.message.chat_id)
def stop_callback(bot, update, job_queue):
logger.info("User {} stop bot".format(update.effective_user["id"]))
bot.send_message(chat_id=update.message.chat_id,
text='Stoped!')
job_queue.stop()
if __name__ == '__main__':
logger.info("Starting bot")
updater = Updater(TOKEN)
updater.dispatcher.add_handler(CommandHandler('start', start_handler))
updater.dispatcher.add_handler(CommandHandler('trigger', trigger_callback, pass_job_queue=True))
updater.dispatcher.add_handler(CommandHandler('stop', stop_callback, pass_job_queue=True))
run(updater)
I have test the Bot in local and it run perfectly. So now how can I deploy it to the Azure Cloud??? Thank guys for you helping!!!
I see the introduction about Azure Bot Service but don't know how to do!
It's actually pretty easy:
Install azure cli, then create a requirements.txt file in the root of your python app with the libraries you need. For example:
python-telegram-bot>=13.3,<=13.3
Open Powershell or Bash, depending on your OS, and run
az webapp up -n <app-name> -g <rg-name> --sku <your-sku> --location <your-location>
A few notes:
Name the main file app.py so that Azure will run it automatically
Configure Always On on your app service in Configuration -> General Settings. This will always keep the bot running. Otherwise Azure will turn it off when idle and only restart it when the website is requested. As your bot works in pull mode, it will never be restared again unless you do it manually, so you need the Always On feature. You'll need a B1 or App Service Plan or better, the free plan does not support Always On.
I'm currently trying to integrate dialogflow with twilio. I want to be able to parse the voice response that my customer gives to the bot. How do I get the voice response; and send response back based on certain voice texts.
As of now; when someone calls the phone it replies Hello; then I want to be able to grab what customer replies; then respond it back appropriately. So far I am using the webhook "A call comes in".
Would this require extra library that translates voice to text? Or does twilio offer it.
import os
from twilio.rest import Client
from flask import Flask
from twilio.twiml.voice_response import VoiceResponse
app = Flask(__name__)
# using os.environ['account_sid']
#app.route('/voice', methods=["GET","POST"])
def voice():
resp = VoiceResponse()
resp.say("hello")
return str(resp)
if __name__ == "__main__":
app.run(debug=True)
What you are looking for is the voice gather command. Twilio does offer speech recognition itself with this command.
from twilio.twiml.voice_response import Gather, VoiceResponse, Say
response = VoiceResponse()
gather = Gather(input='speech dtmf', timeout=3, num_digits=1)
gather.say('Hello!')
response.append(gather)
print(response)
Documentation here -> https://www.twilio.com/docs/voice/twiml/gather