rasahq--rasa
dc6079821b
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
Automatic PR Merger / mergepal (push) Has been cancelled
CI Github Actions / Run Tests (push) Has been cancelled
Semgrep / Semgrep Workflow Security Scan (push) Has been cancelled
230 行
7.6 KiB
Python
230 行
7.6 KiB
Python
import json
|
|
|
|
import logging
|
|
import requests
|
|
from requests import Response
|
|
from sanic import Blueprint, response
|
|
from sanic.request import Request
|
|
from typing import Text, Dict, Any, List, Callable, Awaitable, Optional
|
|
|
|
from rasa.core.channels.channel import UserMessage, OutputChannel, InputChannel
|
|
from sanic.response import HTTPResponse
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MattermostBot(OutputChannel):
|
|
"""A Mattermost communication channel."""
|
|
|
|
@classmethod
|
|
def name(cls) -> Text:
|
|
return "mattermost"
|
|
|
|
@classmethod
|
|
def token_from_login(cls, url: Text, user: Text, password: Text) -> Optional[Text]:
|
|
"""Retrieve access token for mattermost user."""
|
|
data = {"login_id": user, "password": password}
|
|
r = requests.post(url + "/users/login", data=json.dumps(data))
|
|
if r.status_code == 200:
|
|
return r.headers["Token"]
|
|
else:
|
|
logger.error(f"Failed to login mattermost user {user}. Response: {r}")
|
|
return None
|
|
|
|
def __init__(
|
|
self, url: Text, token: Text, bot_channel: Text, webhook_url: Optional[Text]
|
|
) -> None:
|
|
self.url = url
|
|
self.token = token
|
|
self.bot_channel = bot_channel
|
|
self.webhook_url = webhook_url
|
|
|
|
super(MattermostBot, self).__init__()
|
|
|
|
def _post_message_to_channel(self, channel_id: Text, message: Text) -> Response:
|
|
return self._post_data_to_channel(
|
|
{"channel_id": channel_id, "message": message}
|
|
)
|
|
|
|
def _post_data_to_channel(self, data: Dict[Text, Any]) -> Response:
|
|
"""Send a message to a mattermost channel."""
|
|
headers = {"Authorization": "Bearer " + self.token}
|
|
r = requests.post(self.url + "/posts", headers=headers, data=json.dumps(data))
|
|
if not r.status_code == 200:
|
|
logger.error(
|
|
f"Failed to send message to mattermost channel "
|
|
f"{data.get('channel_id')}. Response: {r}"
|
|
)
|
|
return r
|
|
|
|
async def send_text_message(
|
|
self, recipient_id: Text, text: Text, **kwargs: Any
|
|
) -> None:
|
|
for message_part in text.strip().split("\n\n"):
|
|
self._post_message_to_channel(self.bot_channel, message_part)
|
|
|
|
async def send_custom_json(
|
|
self, recipient_id: Text, json_message: Dict[Text, Any], **kwargs: Any
|
|
) -> None:
|
|
json_message.setdefault("channel_id", self.bot_channel)
|
|
json_message.setdefault("message", "")
|
|
|
|
self._post_data_to_channel(json_message)
|
|
|
|
async def send_image_url(
|
|
self, recipient_id: Text, image: Text, **kwargs: Any
|
|
) -> None:
|
|
"""Sends an image."""
|
|
self._post_data_to_channel(
|
|
{
|
|
"channel_id": self.bot_channel,
|
|
"props": {"attachments": [{"image_url": image}]},
|
|
}
|
|
)
|
|
|
|
async def send_text_with_buttons(
|
|
self,
|
|
recipient_id: Text,
|
|
text: Text,
|
|
buttons: List[Dict[Text, Any]],
|
|
**kwargs: Any,
|
|
) -> None:
|
|
"""Sends buttons to the output."""
|
|
# buttons are a list of objects: [(option_name, payload)]
|
|
# See https://docs.mattermost.com/developer/interactive-messages.html#message-buttons # noqa: E501
|
|
|
|
actions = [
|
|
{
|
|
"name": button["title"],
|
|
"integration": {
|
|
"url": self.webhook_url,
|
|
"context": {"action": button["payload"]},
|
|
},
|
|
}
|
|
for button in buttons
|
|
]
|
|
|
|
props = {"attachments": [{"actions": actions}]}
|
|
|
|
self._post_data_to_channel(
|
|
{"channel_id": self.bot_channel, "message": text, "props": props}
|
|
)
|
|
|
|
|
|
class MattermostInput(InputChannel):
|
|
"""Mattermost input channel implemenation."""
|
|
|
|
@classmethod
|
|
def name(cls) -> Text:
|
|
return "mattermost"
|
|
|
|
@classmethod
|
|
def from_credentials(cls, credentials: Optional[Dict[Text, Any]]) -> InputChannel:
|
|
if credentials is None:
|
|
cls.raise_missing_credentials_exception()
|
|
|
|
token = credentials.get("token")
|
|
|
|
return cls(credentials.get("url"), token, credentials.get("webhook_url"))
|
|
|
|
def __init__(self, url: Text, token: Text, webhook_url: Text) -> None:
|
|
"""Create a Mattermost input channel.
|
|
Needs a couple of settings to properly authenticate and validate
|
|
messages.
|
|
|
|
Args:
|
|
url: Your Mattermost team url including /v4 example
|
|
https://mysite.example.com/api/v4
|
|
token: Your mattermost bot token
|
|
webhook_url: The mattermost callback url as specified
|
|
in the outgoing webhooks in mattermost example
|
|
https://mysite.example.com/webhooks/mattermost/webhook
|
|
"""
|
|
self.url = url
|
|
self.token = token
|
|
self.webhook_url = webhook_url
|
|
|
|
async def message_with_trigger_word(
|
|
self,
|
|
on_new_message: Callable[[UserMessage], Awaitable[None]],
|
|
output: Dict[Text, Any],
|
|
metadata: Optional[Dict],
|
|
) -> None:
|
|
# splitting to get rid of the @botmention
|
|
# trigger we are using for this
|
|
split_message = output["text"].split(" ", 1)
|
|
if len(split_message) >= 2:
|
|
message = split_message[1]
|
|
else:
|
|
message = output["text"]
|
|
|
|
await self._handle_message(
|
|
message, output["user_id"], output["channel_id"], metadata, on_new_message
|
|
)
|
|
|
|
async def action_from_button(
|
|
self,
|
|
on_new_message: Callable[[UserMessage], Awaitable[None]],
|
|
output: Dict[Text, Any],
|
|
metadata: Optional[Dict],
|
|
) -> None:
|
|
# get the action, the buttons triggers
|
|
action = output["context"]["action"]
|
|
|
|
await self._handle_message(
|
|
action, output["user_id"], output["channel_id"], metadata, on_new_message
|
|
)
|
|
|
|
async def _handle_message(
|
|
self,
|
|
message: Text,
|
|
sender_id: Text,
|
|
bot_channel: Text,
|
|
metadata: Optional[Dict],
|
|
on_new_message: Callable[[UserMessage], Awaitable[None]],
|
|
) -> None:
|
|
try:
|
|
out_channel = MattermostBot(
|
|
self.url, self.token, bot_channel, self.webhook_url
|
|
)
|
|
user_msg = UserMessage(
|
|
message,
|
|
out_channel,
|
|
sender_id,
|
|
input_channel=self.name(),
|
|
metadata=metadata,
|
|
)
|
|
await on_new_message(user_msg)
|
|
except Exception as e:
|
|
logger.error(f"Exception when trying to handle message.{e}")
|
|
logger.debug(e, exc_info=True)
|
|
|
|
def blueprint(
|
|
self, on_new_message: Callable[[UserMessage], Awaitable[None]]
|
|
) -> Blueprint:
|
|
mattermost_webhook = Blueprint("mattermost_webhook", __name__)
|
|
|
|
@mattermost_webhook.route("/", methods=["GET"])
|
|
async def health(_: Request) -> HTTPResponse:
|
|
return response.json({"status": "ok"})
|
|
|
|
@mattermost_webhook.route("/webhook", methods=["POST"])
|
|
async def webhook(request: Request) -> HTTPResponse:
|
|
output = request.json
|
|
|
|
if not output:
|
|
return response.text("")
|
|
|
|
metadata = self.get_metadata(request)
|
|
# handle normal message with trigger_word
|
|
if "trigger_word" in output:
|
|
await self.message_with_trigger_word(on_new_message, output, metadata)
|
|
|
|
# handle context actions from buttons
|
|
elif "context" in output:
|
|
await self.action_from_button(on_new_message, output, metadata)
|
|
|
|
return response.text("success")
|
|
|
|
return mattermost_webhook
|