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
210 lines
6.8 KiB
Python
210 lines
6.8 KiB
Python
import asyncio
|
|
import copy
|
|
import inspect
|
|
import json
|
|
import logging
|
|
import structlog
|
|
from asyncio import Queue, CancelledError
|
|
from sanic import Blueprint, response
|
|
from sanic.request import Request
|
|
from sanic.response import HTTPResponse, ResponseStream
|
|
from typing import Text, Dict, Any, Optional, Callable, Awaitable, NoReturn, Union
|
|
|
|
import rasa.utils.endpoints
|
|
from rasa.core.channels.channel import (
|
|
InputChannel,
|
|
CollectingOutputChannel,
|
|
UserMessage,
|
|
)
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
structlogger = structlog.get_logger()
|
|
|
|
|
|
class RestInput(InputChannel):
|
|
"""A custom http input channel.
|
|
|
|
This implementation is the basis for a custom implementation of a chat
|
|
frontend. You can customize this to send messages to Rasa and
|
|
retrieve responses from the assistant.
|
|
"""
|
|
|
|
@classmethod
|
|
def name(cls) -> Text:
|
|
return "rest"
|
|
|
|
@staticmethod
|
|
async def on_message_wrapper(
|
|
on_new_message: Callable[[UserMessage], Awaitable[Any]],
|
|
text: Text,
|
|
queue: Queue,
|
|
sender_id: Text,
|
|
input_channel: Text,
|
|
metadata: Optional[Dict[Text, Any]],
|
|
) -> None:
|
|
collector = QueueOutputChannel(queue)
|
|
|
|
message = UserMessage(
|
|
text, collector, sender_id, input_channel=input_channel, metadata=metadata
|
|
)
|
|
await on_new_message(message)
|
|
|
|
await queue.put("DONE")
|
|
|
|
async def _extract_sender(self, req: Request) -> Optional[Text]:
|
|
return req.json.get("sender", None)
|
|
|
|
# noinspection PyMethodMayBeStatic
|
|
def _extract_message(self, req: Request) -> Optional[Text]:
|
|
return req.json.get("message", None)
|
|
|
|
def _extract_input_channel(self, req: Request) -> Text:
|
|
return req.json.get("input_channel") or self.name()
|
|
|
|
def get_metadata(self, request: Request) -> Optional[Dict[Text, Any]]:
|
|
"""Extracts additional information from the incoming request.
|
|
|
|
Implementing this function is not required. However, it can be used to extract
|
|
metadata from the request. The return value is passed on to the
|
|
``UserMessage`` object and stored in the conversation tracker.
|
|
|
|
Args:
|
|
request: incoming request with the message of the user
|
|
|
|
Returns:
|
|
Metadata which was extracted from the request.
|
|
"""
|
|
return request.json.get("metadata", None)
|
|
|
|
def stream_response(
|
|
self,
|
|
on_new_message: Callable[[UserMessage], Awaitable[None]],
|
|
text: Text,
|
|
sender_id: Text,
|
|
input_channel: Text,
|
|
metadata: Optional[Dict[Text, Any]],
|
|
) -> Callable[[Any], Awaitable[None]]:
|
|
"""Streams response to the client.
|
|
|
|
If the stream option is enabled, this method will be called to
|
|
stream the response to the client
|
|
|
|
Args:
|
|
on_new_message: sanic event
|
|
text: message text
|
|
sender_id: message sender_id
|
|
input_channel: input channel name
|
|
metadata: optional metadata sent with the message
|
|
|
|
Returns:
|
|
Sanic stream
|
|
"""
|
|
|
|
async def stream(resp: Any) -> None:
|
|
q: Queue = Queue()
|
|
task = asyncio.ensure_future(
|
|
self.on_message_wrapper(
|
|
on_new_message, text, q, sender_id, input_channel, metadata
|
|
)
|
|
)
|
|
while True:
|
|
result = await q.get()
|
|
if result == "DONE":
|
|
break
|
|
else:
|
|
await resp.write(json.dumps(result) + "\n")
|
|
await task
|
|
|
|
return stream
|
|
|
|
def blueprint(
|
|
self, on_new_message: Callable[[UserMessage], Awaitable[None]]
|
|
) -> Blueprint:
|
|
"""Groups the collection of endpoints used by rest channel."""
|
|
module_type = inspect.getmodule(self)
|
|
if module_type is not None:
|
|
module_name = module_type.__name__
|
|
else:
|
|
module_name = None
|
|
|
|
custom_webhook = Blueprint(
|
|
"custom_webhook_{}".format(type(self).__name__),
|
|
module_name,
|
|
)
|
|
|
|
# noinspection PyUnusedLocal
|
|
@custom_webhook.route("/", methods=["GET"])
|
|
async def health(request: Request) -> HTTPResponse:
|
|
return response.json({"status": "ok"})
|
|
|
|
@custom_webhook.route("/webhook", methods=["POST"])
|
|
async def receive(request: Request) -> Union[ResponseStream, HTTPResponse]:
|
|
sender_id = await self._extract_sender(request)
|
|
text = self._extract_message(request)
|
|
should_use_stream = rasa.utils.endpoints.bool_arg(
|
|
request, "stream", default=False
|
|
)
|
|
input_channel = self._extract_input_channel(request)
|
|
metadata = self.get_metadata(request)
|
|
|
|
if should_use_stream:
|
|
return response.stream(
|
|
self.stream_response(
|
|
on_new_message, text, sender_id, input_channel, metadata
|
|
),
|
|
content_type="text/event-stream",
|
|
)
|
|
else:
|
|
collector = CollectingOutputChannel()
|
|
# noinspection PyBroadException
|
|
try:
|
|
await on_new_message(
|
|
UserMessage(
|
|
text,
|
|
collector,
|
|
sender_id,
|
|
input_channel=input_channel,
|
|
metadata=metadata,
|
|
)
|
|
)
|
|
except CancelledError:
|
|
structlogger.error(
|
|
"rest.message.received.timeout", text=copy.deepcopy(text)
|
|
)
|
|
except Exception:
|
|
structlogger.exception(
|
|
"rest.message.received.failure", text=copy.deepcopy(text)
|
|
)
|
|
|
|
return response.json(collector.messages)
|
|
|
|
return custom_webhook
|
|
|
|
|
|
class QueueOutputChannel(CollectingOutputChannel):
|
|
"""Output channel that collects send messages in a list.
|
|
|
|
(doesn't send them anywhere, just collects them).
|
|
"""
|
|
|
|
# FIXME: this is breaking Liskov substitution principle
|
|
# and would require some user-facing refactoring to address
|
|
messages: Queue # type: ignore[assignment]
|
|
|
|
@classmethod
|
|
def name(cls) -> Text:
|
|
"""Name of QueueOutputChannel."""
|
|
return "queue"
|
|
|
|
# noinspection PyMissingConstructor
|
|
def __init__(self, message_queue: Optional[Queue] = None) -> None:
|
|
super().__init__()
|
|
self.messages = Queue() if not message_queue else message_queue
|
|
|
|
def latest_output(self) -> NoReturn:
|
|
raise NotImplementedError("A queue doesn't allow to peek at messages.")
|
|
|
|
async def _persist_message(self, message: Dict[Text, Any]) -> None:
|
|
await self.messages.put(message)
|