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()
Related
I am using Python + Flask to build an app that takes a user CSV file and enriches it with data from an API.
My objective:
User uploads CSV file [done]
A payment amount is set and presented on Stripe payment page [done]
Once user pays, then the CSV file is enriched with data from an API (a column is appended), and is emailed to the user. [enriching and emailing is done. I just don't know how to make it wait + match payment to correct csv]
My question:
How can I make sure that the CSV file is not enriched/emailed to the user until the Stripe payment is completed?
I have set up a webhook. The problem is, I don't know how to match up the CSV file the user uploaded with the actual payment_id from Stripe to make sure I send them the right file.
I'm sure I am just blanking on some concept here, so any directional help is appreciated.
If you want to wait for Stripe to complete a payment before executing a Python function, you'll need to implement a webhook that listens for the payment_intent.succeeded event in Stripe. When this event is triggered, it indicates that the payment has been completed successfully, and you can then execute your Python function.
Here's a basic outline of the steps you'll need to take:
Implement a webhook endpoint in your application that listens for the payment_intent.succeeded event in Stripe.
In the webhook endpoint, when the payment_intent.succeeded event is triggered, you can call your Python function.
Configure the webhook endpoint in your Stripe dashboard to send the payment_intent.succeeded event to your application.
Here's a simple example implementation in Flask:
from flask import Flask, request
app = Flask(__name__)
#app.route("/webhook", methods=["POST"])
def webhook():
# Retrieve the event data from the request
event_json = request.get_json()
# Check if the event is a payment_intent.succeeded event
if event_json["type"] == "payment_intent.succeeded":
# Call your Python function here
execute_python_function()
return "success"
def execute_python_function():
# Your Python function code goes here
...
if __name__ == "__main__":
app.run(debug=True)
Note that this is just a basic example, and you'll need to modify it to meet the specific needs of your application. You'll also need to ensure that your webhook endpoint is secured and can only be accessed by Stripe.
I used the sample code to receive a call from a number to twilio number.
Now I need to save the recording as mp3. I cant understand how to do it. I tried to call various parameters but failed. I am new to twilio.
> `from flask import Flask
from twilio.twiml.voice_response import VoiceResponse
app = Flask(__name__)
#app.route("/record", methods=['GET', 'POST'])
def record():
"""Returns TwiML which prompts the caller to record a message"""
# Start our TwiML response
response = VoiceResponse()
# Use <Say> to give the caller some instructions
response.say('Hello. Please leave a message after the beep.')
# Use <Record> to record the caller's message
response.record()
# End the call with <Hangup>
response.hangup()
return str(response)
def record(response):
# function to save file to .wav format
if __name__ == "__main__":
app.run(debug = True)
I followed the link but cant understand how to link it with flask to save the file.
https://www.twilio.com/docs/voice/api/recording?code-sample=code-filter-recordings-with-range-match&code-language=Python&code-sdk-version=6.x
Twilio developer evangelist here.
When you use <Record> to record a user, you can provide a URL as the recordingStatusCallback attribute. Then, when the recording is ready, Twilio will make a request to that URL with the details about the recording.
So, you can update your record TwiML to something like this:
# Use <Record> to record the caller's message
response.record(
recording_status_callback="/recording-complete",
recording_status_callback_event="completed"
)
Then you will need a new route for /recording-complete in which you receive the callback and download the file. There is a good post on how to download files in response to a webhook but it covers MMS messages. However, we can take what we learn from there to download the recording.
First, install and import the requests library. Also import request from Flask
import requests
from flask import Flask, request
Then, create the /recording-complete endpoint. We'll read the recording URL from the request. You can see all the request parameters in the documentation. Then we'll open a file using the recording SID as the file name, download the recording using requests and write the contents of the recording to the file. We can then respond with an empty <Response/>.
#app.route("/recording-complete", methods=['GET', 'POST'])
def recording_complete():
response = VoiceResponse()
# The recording url will return a wav file by default, or an mp3 if you add .mp3
recording_url = request.values['RecordingUrl'] + '.mp3'
filename = request.values['RecordingSid'] + '.mp3'
with open('{}/{}'.format("directory/to/download/to", filename), 'wb') as f:
f.write(requests.get(recording_url).content)
return str(resp)
Let me know how you get on with that.
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"
I'm learning python and as a project I'm trying to create a program that will recieve an SMS message, process it, and then depending on what is in that message, send back information.
I am using Twilio in python with Flask and ngrok to do all the SMS stuff, but I am still not sure how to actually receive an SMS as data that I can read and process, as there is no documentation that I can find on it. It would be great if someone could help me with this.
I already know how to receive and send SMS with Twilio, I just need to know how to get the precise message that was sent to my Twilio number.
I believe you already know how to configure Twilio to hit your endpoint when a message comes in. If you configure at Twilio for a POST request, then the data passed to you from Twilio will be in request.form.
If you take a look at Twilio's example here:
(https://www.twilio.com/docs/sms/tutorials/how-to-receive-and-reply-python)
indeed the example makes no use of the data that is coming in.
The modified code below shows some data that is available from the request (and you can write your code depending on what you'd like to do with it).
the number from where the message was sent request.form['From'],
your Twilio number request.form['To']
and the body of the message request.form['Body']
from flask import Flask, request, redirect
from twilio.twiml.messaging_response import MessagingResponse
app = Flask(__name__)
#app.route("/sms", methods=['POST'])
def sms_reply():
"""Respond to incoming calls with a simple text message."""
# Use this data in your application logic
from_number = request.form['From']
to_number = request.form['To']
body = request.form['Body']
# Start our TwiML response
resp = MessagingResponse()
# Add a message
resp.message("The Robots are coming! Head for the hills!")
return str(resp)
if __name__ == "__main__":
app.run(debug=True)
Some other parameters are also available in the request:
MessageSid
SmsSid
AccountSid
MessagingServiceSid
From
To
Body
NumMedia
Docs: (https://www.twilio.com/docs/sms/twiml#request-parameters)
Also you can find more examples if you google for "twilio blog python flask"
I made a GroupMe bot that is supposed to echo what a specific user says, but in ALL CAPS. I used this blog to set up the bot which runs on a python server using gunicorn and Flask which is then hosted with Heroku. I have generated the bot ID and the bot successfully echoes the user, but it does so twice. I used this short code to operate the bot:
import os
import json
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from flask import Flask, request
app = Flask(__name__)
bot_id_var = 'TEST_BOT_ID'
# The url that we want to POST to
POST_url = 'https://api.groupme.com/v3/bots/post'
#app.route('/', methods=['POST'])
def webhook():
json_data = request.get_json()
if json_data['name'] == 'Dylan Powers':
# Make the message all upper case
message = json_data['text'].upper()
send_message(message)
# Constructs the message that we would like to send
def send_message(message):
POST_data = {
# Get the bot ID from environment variables
'bot_id': os.getenv(bot_id_var),
'text': message
}
request = Request(POST_url, urlencode(POST_data).encode())
json = urlopen(request).read().decode()
TEST_BOT_ID refers to an environment variable that I created that holds the bot's ID. Does anybody know why this is posting twice to group chats?