Send push notification through Dialogflow in python for google actions app - dialogflow-es

I was trying to buid an app to send push notification throguh dialogflow fullfuillment to user. I followed this link, now I've got the update permission (see screenshot 1 and 2 at the bottom of the quetion). I followed the stackoverflow thread to write this piece of python code to send a notification, I'm able to run it, and got a status code of 200, but I never receive my test notification on my GoogleHomeApp/Google speaker. Can you help?
import io
import json
import requests
from google.oauth2 import service_account
import google.auth.transport.requests
PATH_TO_SERVICE_ACCOUNT = 'account.json'
REQUIRED_SCOPE = 'https://www.googleapis.com/auth/actions.fulfillment.conversation'
# Get access token
with io.open(PATH_TO_SERVICE_ACCOUNT, 'r', encoding='utf-8') as json_fi:
credentials_info = json.load(json_fi)
credentials = service_account.Credentials.from_service_account_info(
credentials_info, scopes=[REQUIRED_SCOPE])
request = google.auth.transport.requests.Request()
credentials.refresh(request)
headers = {
'Authorization': 'Bearer ' + credentials.token
}
text = 'Hello, this is a test notification'
user_id = "ABwppHFyNFT1fqDRmEug_k2ZKu43hM7xbLmgShN_ESww0iwPLQh-BU6n4T-e3rUOiVqRBWNn5q6bOg"
payload = {
'customPushMessage': {
'userNotification': {
'title': 'Recent News',
'text': text,
},
'target': {
'userId': user_id,
'intent': 'Recent News',
# Expects a IETF BCP-47 language code (i.e. en-US)
'locale': 'en-US'
}
}
}
r = requests.request("POST", 'https://actions.googleapis.com/v2/conversations:send', data=json.dumps(payload), headers=headers)
print(f"A push notification has been sent to user {user_id} with status code {r.status_code}.")
This is the screenshot of simulator:
This is the logs I got on my localhost, shows that I got the permission to send push notification to the user.
I went to the stackdriver logging to check the logs, this is what i got:

If you go to the Official Push Notifications Documentation you'll find the note which indicates that as of now, push notifications are not supported on the voice-activated speakers.
Soon they might release the update but we never know! You might ask the support team regarding the updates.

Related

Service Error 500 coming when testing google calendar api in Django Framework

I am trying to develop a to do notes app in django framework. And I want to integrate Google Calendar Api with this project to sync tasks with google calendar. I followed the steps from this website: https://blog.benhammond.tech/connecting-google-cal-api-and-django#comments-list
But when I try to test the demo page of website, it shows Service Error 503. Please let me kindly know how to fix the problem! I only know some basics of django.
Here's my calendar API Code-
from decouple import config
from google.oauth2 import service_account
import googleapiclient.discovery
import datetime
import json
CAL_ID = "104a92a3cd198c2062645e570737318d05c2dfb2f1361e64b743a4b0e223de66#group.calendar.google.com"
SCOPES = ['https://www.googleapis.com/auth/calendar']
SERVICE_ACCOUNT_FILE = json.load(open('google-credentials.json'))
def test_calendar():
print("RUNNING TEST_CALENDAR()")
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = googleapiclient.discovery.build(
'calendar', 'v3', credentials=credentials)
print(service)
# CREATE A NEW EVENT
new_event = {
'summary': "New Task 1",
'location': 'Kolkata, WB',
'description': 'Description of Task 1',
'start': {
'date': f"{datetime.date.today()}",
'timeZone': 'America/New_York',
},
'end': {
'date': f"{datetime.date.today() + datetime.timedelta(days=3)}",
'timeZone': 'America/New_York',
},
}
service.events().insert(calendarId=CAL_ID, body=new_event).execute()
print('Event created')
# GET ALL EXISTING EVENTS
events_result = service.events().list(
calendarId=CAL_ID, maxResults=2500).execute()
events = events_result.get('items', [])
# LOG THEM ALL OUT IN DEV TOOLS CONSOLE
for e in events:
print(e)
# uncomment the following lines to delete each existing item in the calendar
#event_id = e['id']
# service.events().delete(calendarId=CAL_ID, eventId=event_id).execute()
return events
The interpreter when it runs the test_calendar() function , it doesn't prints the services.
This should let me see the demo page of django where list task are shown taken from the google calender.

What's the right way to execute a Twilio Studio conversation flow?

Im learning how to set a twilio studio flow with python, I'm currently testing one of the templates that Twilio provides, and Im communicating with the bot from WhatsApp. However, I can only send the first message of the flow and if I send another message, this message pop up:
Unable to create record: Execution XXXXXXXXXXXXXXXXXXXXX is already active for this contact. End the active Execution before creating a new one
I tried to add .update(status='ended') to my variable, but it just kinda looped every time I sent a message, I know that every time that theres an incoming message it will trigger the conversation. So my question is, how can I continue the conversation flow without creating a new trigger every time that theres an incomming message?
Here's my flow in case it's necessary.
And this is the functions and endpoints that I'm using to trigger the action:
# twilio.route('/incoming_message', methods=['GET', 'POST'])
def incoming_message_data() -> str:
if request.method == 'POST':
response = {}
error, message, code = False, '', ''
message = incoming_message()
response.update({'sucess': True, 'message': message, 'message': f'{message}', 'status_code': 200, 'error': None, 'code': f'{code}'} if message and message != [{}]else {
'sucess': False, 'message': 'Message could not be sent', 'status_code': 400, 'error': f'{error}', 'code': f'{code}'})
return message
def twilio_studio_flow(phone_number: str) -> str:
'''
Twilio Studio Flow
'''
response = request.values.get('Body', '').lower()
execution = twilio_client.studio \
.v2 \
.flows(Config.TWILIO_STUDIO_FLOW_SID) \
.executions \
.create(to=(f'whatsapp:{phone_number}'), from_=Config.TWILIO_PHONE_NUMBER,
parameters={
"appointment_time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
})\
.update(status='ended')
def validate_phone_number(phone_number: str) -> bool:
'''
Validate phone number
'''
try:
phone = phonenumbers.parse(phone_number.strip(), None)
client = Client.query.filter_by(phone=phone_number).first()
return phonenumbers.is_valid_number(phone) and client is not None
except Exception:
return False
def incoming_message() -> str:
'''
Receive incoming messages
'''
# Get the message the user sent our Twilio number
incoming_message = request.values.get('Body', '').lower()
# Get the phone number of the person sending the text message
phone_number = request.values.get('From', None).replace('whatsapp:', '')
resp = MessagingResponse()
if validate_phone_number(phone_number) and incoming_message:
resp.message(twilio_studio_flow(phone_number))
else:
resp.message(
'Lo sentimos, no pudimos validar tu numero de telefono 😟')
return str(resp)
Thanks in advance for helping me :).
As I mentioned previously, I want to know the right way to execute a Twilio Studio. Honestly, I cheked the docs but it's a little bit unclear on how to this.
Based on your answer in the comments, I'd suggest to link the Studio flow directly to the WhatsApp sender in the console (instead of invoking the flow manually via the API).
To connect the Studio Flow to your WhatsApp number ("Sender"). Click on the Trigger (Start) Widget and locate the Webhook URL field in the right-hand menu. Copy that URL to your clipboard.
Next, navigate to your WhatsApp Senders in the Twilio console. Click to select the sender that you want to use with this Studio Flow. Paste the Webhook URL that you copied from your Studio Flow into the field Webhook URL for incoming messages. Don't forget to click Update WhatsApp Sender.
Now, any time you receive an inbound message on your selected WhatsApp-enabled sender (number), it will be routed to your new Studio Flow.
Taken from the documentation.

how do I sign up/in to another account in pyrogram

I use Pyrogram — version 2.0 to create bot. I wanted to sing in/up to another number using the client I am connected to. That phone number may not have logged in to Telegram yet.
But when I use the "send_code" method, the session with which it used to connect gets terminated. I used API bot to get enough information (phone number, two-step verification, and code) and CLI bot to send code.
The code is like this:
import uvloop
from pyrogram import Client, filters
from pyrogram.types import Message
# Apply monkey patch listen
from pyromod import listen
uvloop.install()
api_bot = {
'name': 'my_bot',
'api_id': 5555555,
'api_hash': '932835f263b17eb623bd251d0',
'bot_token': '5225489486ZckBKhgGESKTHvZjQNuKXGtSHTpA'
}
proxy = {
"scheme": "socks5",
"hostname": "127.0.0.1",
"port": 9050,
}
client = Client(**api_bot, proxy=proxy)
async def login(name, phone_number, two_step_verification, chat_id) -> str or bool:
cli_bot = {
'name': '.....',
'api_id': 111111,
'api_hash': '...........',
'session_string': '...........................'
}
# In order to use the "send_code" method, we must connect to a client
async with Client(**cli_bot, proxy=proxy) as app:
await app.send_code(phone_number)
code = await app.ask(chat_id=chat_id,
text='send telegram code to me',
timeout=125)
# Connecting to the client whose number we received
async with Client(name, api_id, api_hash,
phone_number=phone_number,
phone_code=code,
in_memory=True,
password=two_step_verification,
proxy=proxy,
test_mode=True) as app:
session_string = await app.export_session_string()
if session_string:
with open(name + '.txt', 'w') as file:
string = (phone_number, two_step_verification, session_string, name)
file.write('\n'.join(string))
await client.send_message(chat_id, 'added successfully your phone number')
return True
#client.on_message(filters.private & (filters.contact | filters.text))
async def get_phone_number(app: Client, message: Message):
data = {'phone_number': '+11111111',
'name': 'jenny',
'two_step_verification': ''}
await(login(**data))
client.run()
and then get this error in line 34:
pyrogram.errors.exceptions.unauthorized_401.AuthKeyUnregistered: Telegram says: [401 AUTH_KEY_UNREGISTERED] - The key is not registered in the system. Delete your session file and login again (caused by "users.GetUsers")
Totally, I want to sign in/up to different accounts and extract their session-string. I don't know what is wrong with my code. Would you please guide me?

Can I send slack alert message through bot using python?

I want to alert everyone on Slack App, which I can do manually by sending #here in the channel.
But I want to send it using my bot.
So, I tried this:
import numpy as np
import requests
data = {
'token': token,
'channel': channel,
'as_user': True,
'text': "<#here>"
}
requests.post(url='https://slack.com/api/chat.postMessage', data=data)
But it send just a usual message, not an alert message.
How can I send an alert message using my bot?

Google Actions Push Notification with Python?

I'm trying to figure out how to initiate a push notification using DialogFlow/Google Actions. I've cobbled together some test code, but when I test it, I get a '403 Forbidden' response. Can somebody provide me a good example of how to do this using Python 3.
`
import urllib.request
import json
notification = {
'userNotification': {
'title': 'Test Notification',
},
'target': {
'userId': 'user-id here',
'intent': 'Notification Intent',
'locale': 'en-US',
}
}
my_url = 'https://actions.googleapis.com/v2/conversations:send'
access_token = 'access token here'
request = urllib.request.Request(my_url)
request.add_header('Content-Type', 'application/json; charset=utf-8')
payload = { 'auth': { 'bearer': access_token },
'json': 'true',
'body': { 'customPushMessage': notification, 'isInSandbox':
'true' } };
jsondata = json.dumps(payload)
jsondataasbytes = jsondata.encode('utf-8')
response = urllib.request.urlopen(request, jsondataasbytes)
`
Can anybody provide any suggestions about how to get this to work?
=============================================================
Update: I revised the auth header as suggested and now I'm getting '401:Unauthorized'. I'm not sure if I'm creating the access token properly. Here's how I'm doing it:
I created an RSA256 private key on the Google Console website. I use that key to encode a JWT containing these fields:
{
"iss": [
"My Service Name",
"\"my_service-account#service_name.iam.gserviceaccount.com\""
],
"iat": 1544018697,
"exp": 1544019898,
"aud":
"https://www.googleapis.com/auth/actions.fulfillment.conversation\"",
"sub": [
"Push Notification",
"\"my-service-account#service_name.iam.gserviceaccount.com\""
]
}
I don't know if this is correct: the documentation for all of this is hard to pull together.
UPDATE 2:
I modified the code suggested by Prisoner, and I'm now able to get what appears to be a valid access_token. This is the modified code:
from oauth2client.client import GoogleCredentials
service_account_file = 'path-to-service_account_file'
credentials = GoogleCredentials.from_stream(SERVICE_ACCOUNT_FILE)
access_token = credentials.get_access_token().access_token
When I try to use the access token, I'm still getting a '401 Unauthorized' response. Has anybody actually done this? If so, can you give me some specifics on the correct URL to use and how to format the urllib.request message?
You've placed some things into the body of the request that belong in the header. In particular, the "403 forbidden" suggests that the Authorization header is either wrong or missing, and in your case, it looks like it is missing since you're trying to put it in the body.
The body of what you're sending should just contain the JSON with the customPushMessage attribute.
I'm not very familiar with python, but I think something like this is more what you want:
request = urllib.request.Request(my_url)
request.add_header('Authorization', 'bearer '+access_token)
request.add_header('Content-Type', 'application/json; charset=utf-8')
payload = { 'customPushMessage': notification }
jsondata = json.dumps(payload)
jsondataasbytes = jsondata.encode('utf-8')
response = urllib.request.urlopen(request, jsondataasbytes)
If you continue to get the "403 Forbidden" message - make sure your access_token is current and is actually an access token. Access tokens are created from the service account key, but are not the key itself. They have a limited lifetime (usually 1 hour), while the key is long-lasting.
Update about generating an access token from the keys.
You can't just create and sign a JWT to use as an access token.
The easiest way is to use the Google APIs Client Library for Python, which includes a library to handle OAuth with service accounts.
I haven't tested, but you should be able to do something like this, setting SERVICE_ACCOUNT_FILE to the location of where the keys are stored.
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/actions.fulfillment.conversation']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
access_token = credentials.get_access_token()
Ok, I've figured out how to get the the access_token, so that part of the problem is solved. I've run into another problem getting updates permission working for my test account, but I'm going to post a new question to cover that. I adapted code from another answer and this seems to work:
# Adapted from https://stackoverflow.com/questions/51821919/how-to-send-push-notification-from-google-assistant-through-dialogflow-fulfilmen/51961677#51961677
import io
import json
import requests
from google.oauth2 import service_account
import google.auth.transport.requests
def send_notification(path_to_service_account="default", intent="default"):
if path_to_service_account == "default":
PATH_TO_SERVICE_ACCOUNT = 'path to downloaded service account json file from Google Cloud Console'
else:
PATH_TO_SERVICE_ACCOUNT = path_to_service_account
if intent == "default":
INTENT = 'Notification Intent'
else:
INTENT = intent
REQUIRED_SCOPE = 'https://www.googleapis.com/auth/actions.fulfillment.conversation'
USER_ID = 'user id here'
INTENT = 'Your intent name'
# Get access token
with io.open(PATH_TO_SERVICE_ACCOUNT, 'r', encoding='utf-8') as json_fi:
credentials_info = json.load(json_fi)
credentials = service_account.Credentials.from_service_account_info(
credentials_info, scopes=[REQUIRED_SCOPE])
request = google.auth.transport.requests.Request()
credentials.refresh(request)
headers = {
'Authorization': 'Bearer ' + credentials.token
}
payload = {
'customPushMessage': {
'userNotification': {
'title': 'App Title',
'text': 'Simple Text'
},
'target': {
'userId': USER_ID,
'intent': INTENT,
# Expects a IETF BCP-47 language code (i.e. en-US)
'locale': 'en-US'
}
}
}
r = requests.request("POST", 'https://actions.googleapis.com/v2/conversations:send', data=json.dumps(payload), headers=headers)
print(str(r.status_code) + ': ' + r.text)

Resources