Create python proactive messaging with microsoft bot framework - python

What are the steps to create a push notification/proactive messaging bot using Python with microsoft bot framework? Since there's no official documentation yet, I don't really know where to start.
I have imported the following:
from botbuilder.schema import Activity, ActivityTypes, ConversationReference
How can it be used and what's a very simple example?

I worked a sample demo which based on state management sample for you .
Pls follow the setps to make it work :
1.Adding code below into app.py :
#APP.route("/api/notify", methods=["POST"])
def notify():
if request.headers["Content-Type"] == "application/json":
body = request.json
else:
return Response(status=415)
activity = Activity().deserialize(body)
auth_header = (
request.headers["Authorization"] if "Authorization" in request.headers else ""
)
async def aux_func(turn_context):
await BOT.on_turn(turn_context)
try:
task = LOOP.create_task(
ADAPTER.process_activity(activity, auth_header, aux_func)
)
LOOP.run_until_complete(task)
return Response(status=201)
except Exception as exception:
raise exception
2.Modify function on_message_activity in state_management_bot.py as code below
async def on_message_activity(self, turn_context: TurnContext):
# Get the state properties from the turn context.
if(turn_context.activity.channel_id != 'notify'):
await turn_context.send_activity("You asid:" + turn_context.activity.text);
else:
await turn_context.send_activity("You get a notify : "+ turn_context.activity.text);
Run this sample locally on Azure bot emulator, click the message from bot and note the conversation id and serviceUrl :
Use postman or restclient to do a post call to trigger the notify endpoint with json content :
{
"text": "this is a notify sent from outside ",
"textFormat": "plain",
"type": "message",
"channelId": "notify",
"from": {
"id": "backend",
"name": "xxxxx",
"role": "xxxxxx"
},
"conversation": {
"id": "<conversation id>"
},
"recipient": {
"id": "",
"name": "bot",
"role": "bot"
},
"serviceUrl": "<service URL>"
}
Result :

Related

Create modal in slack using python

I am using the python slack bolt. https://api.slack.com/start/building/bolt-python#create
I created the example in the link and was able to make a home tab page but I want to create a modal from a message in a channel, not a home page view. I have looked everywhere for a basic example but I can't get any MODALS to work with what I have learned from slack's own documentation. This is the only examples I can find (which came from slack's own documentation after you read the starting out page).
Here is the test example that works but shows up with a home page instead of a modal:
SLACK_BOT_TOKEN="slackbottokenstring"
SLACK_SIGNING_SECRET="slacksigningsecretstring"
import os
# Use the package we installed
from slack_bolt import App
# Initializes your app with your bot token and signing secret
app = App(
token = SLACK_BOT_TOKEN,
signing_secret = SLACK_SIGNING_SECRET
# token=os.environ.get("SLACK_BOT_TOKEN"),
# signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
)
# Add functionality here
#app.event("app_home_opened")
def update_home_tab(client, event, logger):
try:
# views.publish is the method that your app uses to push a view to the Home tab
client.views_publish(
# the user that opened your app's app home
user_id=event["user"],
# the view object that appears in the app home
view={
"type": "home",
"callback_id": "home_view",
# body of the view
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Welcome to your _App's Home_* :tada:"
}
},
{
"type": "divider"
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "This button won't do much for now but you can set up a listener for it using the `actions()` method and passing its unique `action_id`. See an example in the `examples` folder within your Bolt app."
}
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Click me!"
}
}
]
}
]
}
)
except Exception as e:
logger.error(f"Error publishing home tab: {e}")
# Start your app
if __name__ == "__main__":
app.start(port=int(os.environ.get("PORT", 3000)))
And that works:
But if I try to change it to a modal, it fails:
CODE:
#app.event("app_home_opened")
def update_home_tab(client, event, logger):
try:
# views.publish is the method that your app uses to push a view to the Home tab
client.views_publish(
# the user that opened your app's app home
user_id=event["user"],
# the view object that appears in the app home
view={
"type": "modal",
"callback_id": "modal-identifier",
"title": {
"type": "plain_text",
"text": "Just a modal"
},
"blocks": [
{
"type": "section",
"block_id": "section-identifier",
"text": {
"type": "mrkdwn",
"text": "*Welcome* to ~my~ Block Kit _modal_!"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Just a button",
},
"action_id": "button-identifier",
}
}
],
}
)
Error:
127.0.0.1 - - [14/Aug/2022 15:21:15] "POST /slack/events HTTP/1.1" 200 -
Error publishing home tab: The request to the Slack API failed. (url: https://www.slack.com/api/views.publish)
The server responded with: {'ok': False, 'error': 'invalid_arguments', 'response_metadata': {'messages': ['[ERROR] failed to match all allowed schemas [json-pointer:/view]', '[ERROR] unsupported type: modal [json-pointer:/view/type]']}}
I am following the view structure design in a json object like it says here: https://api.slack.com/surfaces/modals/using#composing_views
I figured out what I had to do but it was kinda annoying, I want to just say that first. There are a couple reasons as to why it was annoying to figure out.
There is no direct python example from the website, BUT slack does have a github where they show a modal example.
Using specifically Modals require than just making text blocks in a chat. It requires some weird thing called a trigger_id which you get from initiating a specific response that would cause slack to send an object over to your endpoint. The problem is that there is no example of this. If you are going through slack's tutorial, they ONLY show you how to create a url for making a bot that event listens and responds to messages. You can make your own url using flask but since I am using the bolt slack module, they wrap there own stuff around flask which makes it hard to make basic decorators for flask. - In other words, the slack documentation is super confusing for modals and they don't have any real examples for modals with bolt python.
after doing days of research in my spare time, I was finally able to get an example working where you can COPY AND PASTE this code. You just need your bot token secret and signing key which you can set in your environment or as a string if you are just testing around in your local computer.
SLACK_BOT_TOKEN="slackbottokenstring"
SLACK_SIGNING_SECRET="slacksigningsecretstring"
import os
# Use the package we installed
from slack_bolt import App
from slack_bolt.adapter.flask import SlackRequestHandler
from flask import Flask, request
flask_app = Flask(__name__)
# Initializes your app with your bot token and signing secret
app = App(
token = SLACK_BOT_TOKEN,
signing_secret = SLACK_SIGNING_SECRET
# token=os.environ.get("SLACK_BOT_TOKEN"),
# signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
)
handler = SlackRequestHandler(app)
#flask_app.route("/slack/events", methods=["POST"])
def slack_events():
return handler.handle(request)
#app.shortcut("SearchMessagesID")
def handle_shortcuts(ack, body, logger,client):
ack()
logger.info(body)
print(body)
res = client.views_open(
trigger_id=body["trigger_id"],
view={
"type": "modal",
"callback_id": "modal-identifier",
"title": {
"type": "plain_text",
"text": "Just a modal"
},
"blocks": [
{
"type": "section",
"block_id": "section-identifier",
"text": {
"type": "mrkdwn",
"text": "*Welcome* to ~my~ Block Kit _modal_!"
},
"accessory": {
"type": "button",
"text": {
"type": "plain_text",
"text": "Just a button",
},
"action_id": "button-identifier",
}
}
],
}
)
# Start your app
if __name__ == "__main__":
app.start(port=int(os.environ.get("PORT", 3000)))

Python - Read messages from Service bus topic and then store them in a container with the same name

I am new to this, but the code seems to be not working.
Intension is to read json message from Service bus endpoint and then copy and store them in a blob container, but to keep the integrity constant throughout need to keep the name as is.
Do not have much knowledge on this , collected these codes from some blog.
Also if i can listen without func that will also help
Here is the code piece:
with receiver:
for msg in receiver:
print(str(msg))
logging.info('Python ServiceBus trigger processed an Topics: %s', msg.get_body().decode('utf-8'))
#receiver.complete_message(msg)
temp_path = tempfile.gettempdir()
# Create a file in the local data directory to upload and download
local_file_name = str(uuid.uuid4()) + ".txt"
upload_file_path = os.path.join(temp_path, local_file_name)
# Write text to the file
file = open(upload_file_path, 'w')
file.write(msg.get_body().decode('utf-8'))
file.close()
# Create a blob client using the local file name as the name for the blob
blob_client = blob_service_client.get_blob_client(container=container_name, blob=local_file_name)
print("\nUploading to Azure Storage as blob:\n\t" + local_file_name)
# Upload the created file
with open(upload_file_path, "rb") as data:
blob_client.upload_blob(data)
Here we need to create a function where we can configure messages to read which are received from Service Bus queues.
For this we need to mention the bindings in function.json file as below:
serviceBusTrigger:
{
"bindings": [
{
"type": "serviceBusTrigger",
"name": "inputMessage",
"connection": "AzureServiceBusConnectionString",
"queueName": "inputqueue",
"accessRights": "listen",
"direction": "in"
},
{
"type": "blob",
"name": "inputBlob",
"path": "container/{inputMessage}",
"connection": "EnterConnection",
"direction": "in"
}
],
"disabled": false
}
queueTrigger:
{
"bindings": [
{
"type": "blob",
"name": "inputBlob",
"path": "incontainer/{queueTrigger}",
"connection": "testweblog_STORAGE",
"direction": "in"
},
{
"type": "queueTrigger",
"name": "myQueue",
"queueName": "myqueue",
"connection": " EnterConnection _STORAGE",
"direction": "in"
}
],
"disabled": false
}
For more information about the triggers please refer to input and output triggers:
A queue is basically for first-in-first-out messages. When a message comes from the service bus, the service bus queue trigger gets fired and the Azure Function is called. In the Azure Function, we can process the message and then deliver it to destination.
Below is the sample code to receive service bus queue.
Import os
from azure.servicebus import ServiceBusClient
CONNECTION_STR = os.environ['SERVICE_BUS_CONNECTION_STR']
QUEUE_NAME = os.environ["SERVICE_BUS_QUEUE_NAME"]
servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR)
with servicebus_client:
receiver = servicebus_client.get_queue_receiver(queue_name=QUEUE_NAME)
with receiver:
received_msgs = receiver.receive_messages(max_message_count=10, max_wait_time=5)
for msg in received_msgs:
print(str(msg))
receiver.complete_message(msg)
print("Receive is done.")
For more information refer to Azure Service Bus client library for Python
servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR, logging_enable=True)
msg_topic="XYZ"
with servicebus_client:
receiver = servicebus_client.get_subscription_receiver(topic_name=TOPIC_NAME, subscription_name=SUBSCRIPTION_NAME, max_wait_time=5)
with receiver:
for msg in receiver:
print(str(msg))
msg_topic=msg
print(str(msg_topic))
receiver.complete_message(msg)
block_blob_service=BlockBlobService(account_name='stgidpdev',account_key='ZZZZ')
block_blob_service.create_container('servicebuscontainer',public_access=PublicAccess.Container)
print('Container Created')
#from azure.storage.blob import ContentSetting
block_blob_service.create_blob_from_text('servicebuscontainer','myblockblob',str(msg_topic),content_settings=None)

How to send response to actions-on-google in Python?

I'm making an action-on-google assistant. I'm able to receive the request in JSON format by using Flask to establish webhook in Python. But I've no idea how to send the response back to the assistant.
enter image description here
enter image description here
import os, sys
from flask import Flask, request, send_from_directory, make_response
from googleactions import AppRequest, AppResponse, SimpleResponse
class operation():
def justPrint(self):
print("Hi dear user")
print(AppResponse('告訴我故事發生什麼事吧').json())
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
return "hello world"
#app.route('/', methods=['POST'])
def webhook():
req = request.get_json()
print(req)
op = operation()
getattr(op, req['handler']['name'])()
return 'ok', 200
if __name__ == "__main__":
app.run(debug=True, port=8080)
Your Flask server should return a JSON response in the correct format. It looks like you may be using the googleactions package, but unfortunately that package seems to be out-of-date with the response format expected by Actions Builder.
You should consult the JSON schema for the HandlerResponse type. As it is JSON schema, you can use a tool like Quicktype to generate the appropriate classes for additional syntax support.
The schema file also includes definitions for the internal types.
"HandlerResponse": {
"description": "Represents a response sent from a developer's fulfillment to Actions on\nGoogle.",
"type": "object",
"properties": {
"prompt": {
"description": "Optional. Represents the prompts to be sent to the user, these prompts\nwill be appended to previously added messages unless explicitly\noverwritten.",
"$ref": "#/definitions/Prompt"
},
"scene": {
"description": "Optional. Represents the current and next scene. If `Scene.next` is set\nthe runtime will immediately transition to the specified scene.",
"$ref": "#/definitions/Scene"
},
"session": {
"description": "Optional. Describes data for the current session, session\nparameters can be created, updated, or removed by the fulfillment.",
"$ref": "#/definitions/Session"
},
"user": {
"description": "Optional. Use to specify user parameters to send back.",
"$ref": "#/definitions/User"
},
"home": {
"description": "Optional. Used to specify parameters related to the HomeGraph structure\nthat the target device belongs to. See\nhttps://developers.google.com/actions/smarthome/concepts/homegraph.",
"$ref": "#/definitions/Home"
},
"device": {
"description": "Optional. Use to move between Assistant devices the user has access to.",
"$ref": "#/definitions/Device"
},
"expected": {
"description": "Optional. Describes the expectations for the next dialog turn.",
"$ref": "#/definitions/Expected"
}
}
},

I only get one whatsapp answer via dialogflow instead of multiple replies

How do I get multiple 'text answers' in whatsApp? When I add more than one 'text response' in intents they work normally in the dialogFlow console.
But when I repeat the same question on whatsapp I get only one answer box instead of 3, for example, that I had created.
I am using twilio to communicate with the whatsapp API. I also use Horoku cloud services to host the application.
Everything works normal. But I received only one message box instead of multiple in whatsapp.
I think the problem is my python code 'app.py'.
app.py
#app.route("/") #just to test Heroku cloud services
def hello():
return "Hello, World!"
#app.route("/sms", methods=['POST'])
def sms_reply():
"""Respond to incoming calls with a simple text message."""
# Fetch the message
msg = request.form.get('Body')
phone_no = request.form.get('From')
reply = fetch_reply(msg, phone_no)
# Create reply
resp = MessagingResponse()
resp.message(reply)
enter code here
return str(resp)
utils.py
import dialogflow_v2 as dialogflow
dialogflow_session_client = dialogflow.SessionsClient()
PROJECT_ID = "weather-husgcf"
def detect_intent_from_text(text, session_id, language_code='pt-BR'):
session = dialogflow_session_client.session_path(PROJECT_ID, session_id)
text_input = dialogflow.types.TextInput(text=text, language_code=language_code)
query_input = dialogflow.types.QueryInput(text=text_input)
response = dialogflow_session_client.detect_intent(session=session, query_input=query_input)
return response.query_result
def fetch_reply(query, session_id):
response = detect_intent_from_text(query, session_id)
return response.fulfillment_text
https://i.imgur.com/a/b2QSYUB "ScreenShots"
Twilio developer evangelist here.
In your fetch_reply method you call on the query_result's fulfillment_text property. According the QueryResult documentation fulfillmentText is deprecated/legacy:
The text to be pronounced to the user or shown on the screen. Note: This is a legacy field, fulfillmentMessages should be preferred.
The fullfillmentMessages property is defined as a list of Message objects. So to return all 3 of your messages your code should probably loop through the messages adding them to the response, something like this:
def fetch_reply(query, session_id):
response = detect_intent_from_text(query, session_id)
return response.fulfillment_messages
Then your route should look something like this:
#app.route("/sms", methods=['POST'])
def sms_reply():
"""Respond to incoming calls with a simple text message."""
# Fetch the message
msg = request.form.get('Body')
phone_no = request.form.get('From')
replies = fetch_reply(msg, phone_no)
# Create reply
resp = MessagingResponse()
for reply in replies:
resp.message(reply.text)
return str(resp)
I haven't tested this, just worked from the DialogFlow documentation. Let me know if it helps.
Old-ish question but here's the answer (Dialogflow v2).
Assuming you have some sort of sendMessage(mobile_num, text) function, you iterate over the fulfillment_messages like this:
for message in response.query_result.fulfillment_messages:
sendMessage(mobile_num, message.text.text[0])
From the webhook you get a json like this:
{
"queryText": string,
"languageCode": string,
"speechRecognitionConfidence": number,
"action": string,
"parameters": {
object
},
"allRequiredParamsPresent": boolean,
"cancelsSlotFilling": boolean,
"fulfillmentText": string,
"fulfillmentMessages": [
{
"text": {
"text": [
"Some text"
]
}
},
{
"text": {
"text": [
"Some more text"
]
}
},
],
"webhookSource": string,
"webhookPayload": {
object
},
"outputContexts": [
{
object (Context)
}
],
"intent": {
object (Intent)
},
"intentDetectionConfidence": number,
"diagnosticInfo": {
object
},
"sentimentAnalysisResult": {
object (SentimentAnalysisResult)
}
}
where fulfillmentMessages is an array you have to iterate over.
Hope this helps.

My slack app seems to fail in interaction

I'm new to slack app development. Following this page: https://api.slack.com/messaging/interactivity/enabling, I'm trying to create a simple interactive slack-app that
is launched by a slash command
can interact with users through a button.
I use AWS API-gateway and Lambda as backends. Lambda functions are written in Python 3.6.
I succeeded in creating a slash command, but failed in updating a message after pushed the button.
Precise structure of my app
When I type the slash command /test in my slack channel, my app makes a post request to an API gateway (https://xxx.execute-api.ap-northeast-1.amazonaws.com/prod/test) and a lambda function returns the following response with a button.
The lambda function is as follows:
import json
import datetime
def lambda_handler(event, context):
try:
response = {
"statusCode": 200,
"response_type": "in_channel",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "This is a section block with a button."
},
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Button",
"emoji": True
},
"action_id": "test"
}
]
}
]
}
return response
except Exception as e:
return {"error": str(e)}
After the button pushed, my app sends a post request to another API gateway (https://xxx.execute-api.ap-northeast-1.amazonaws.com/prod/test2) and another lambda function receives a request like follows
{
'type':'block_actions',
'team':{
'id':'xxx',
'domain':'xxx'
},
'user':{
'id':'xxx',
'username':'xxx',
'name':'xxx',
'team_id':'xxx'
},
'api_app_id':'xxx',
'token':'xxx',
'container':{
'type':'message',
'message_ts':'1564687520.001900',
'channel_id':'xxx',
'is_ephemeral':False
},
'trigger_id':'xxx.yyy.zzz',
'channel':{
'id':'xxx',
'name':'slack_app_test'
},
'message':{
'type':'message',
'subtype':'bot_message',
'text':"This content can't be displayed.",
'ts':'1564687520.001900',
'bot_id':'xxx',
'blocks':[
{
'type':'section',
'block_id':'ygl6',
'text':{
'type':'mrkdwn',
'text':"This is a section block with a button. {'token': 'xxx', 'team_id': 'xxx', 'team_domain': 'xxx', 'channel_id': 'xxx', 'channel_name': 'slack_app_test', 'user_id': 'xxx', 'user_name': 'mail', 'command': '/recommend', 'response_url': '<https://hooks.slack.com/commands/xxx/yyy/zzz>', 'trigger_id': 'xxx.yyy.zzz'}",
'verbatim':False
}
},
{
'type':'actions',
'block_id':'jlzD',
'elements':[
{
'type':'button',
'action_id':'test',
'text':{
'type':'plain_text',
'text':'Button',
'emoji':True
}
}
]
}
]
},
'response_url':'https://hooks.slack.com/actions/xxx/yyy/zzz',
'actions':[
{
'action_id':'test',
'block_id':'jlzD',
'text':{
'type':'plain_text',
'text':'Button',
'emoji':True
},
'type':'button',
'action_ts':'1564687524.157943'
}
]
}
and try to make a response by the following lambda function:
import json
import urllib.request
def lambda_handler(event, context):
try:
response_url = event.get("response_url", None)
if response_url is not None:
headers = {"Content-Type" : "application/json"}
print("From slack. Response url: {}".format(response_url))
response = json.dumps({
"replace_original": True,
"response_type": "in_channel",
"text": "Success!"
})
request = urllib.request.Request(
response_url,
data=response,
method="POST",
headers=headers
)
return None
except Exception as e:
return {"error": str(e)}
When I look at Cloudwatch logs of the lambda function above, the function seems to successfully send a message to my slack app.
Problem
I expect that my app displays a message Success! after pushing the button, but no updates are shown (just showing a loading animation). Any ideas?

Categories

Resources