dc6079821b
CI Github Actions / Run Tests (push) Waiting to run
Automatic PR Merger / mergepal (push) Waiting to run
Semgrep / Semgrep Workflow Security Scan (push) Waiting to run
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
332 lines
11 KiB
Python
332 lines
11 KiB
Python
import uuid
|
|
from typing import Text, Any
|
|
|
|
import jsonschema
|
|
import pytest
|
|
from sanic import Sanic, response
|
|
|
|
from rasa.core.nlg.callback import CallbackNaturalLanguageGenerator
|
|
from rasa.core.nlg.response import TemplatedNaturalLanguageGenerator
|
|
from rasa.utils.endpoints import EndpointConfig, read_endpoint_config
|
|
from rasa.core.agent import Agent
|
|
|
|
|
|
def nlg_app(base_url="/"):
|
|
|
|
app = Sanic("test_nlg")
|
|
|
|
@app.route(base_url, methods=["POST"])
|
|
async def generate(request):
|
|
"""Simple HTTP NLG generator, checks that the incoming request
|
|
is format according to the spec."""
|
|
|
|
nlg_request_format_spec = {
|
|
"type": "object",
|
|
"properties": {
|
|
"response": {"type": "string"},
|
|
"id": {"type": ["string", "null"]},
|
|
"arguments": {"type": "object"},
|
|
"tracker": {
|
|
"type": "object",
|
|
"properties": {
|
|
"sender_id": {"type": "string"},
|
|
"slots": {"type": "object"},
|
|
"latest_message": {"type": "object"},
|
|
"latest_event_time": {"type": "number"},
|
|
"paused": {"type": "boolean"},
|
|
"events": {"type": "array"},
|
|
},
|
|
},
|
|
"channel": {
|
|
"type": "object",
|
|
"properties": {"name": {"type": "string"}},
|
|
},
|
|
},
|
|
}
|
|
|
|
nlg_call = request.json
|
|
|
|
jsonschema.validate(nlg_call, nlg_request_format_spec)
|
|
|
|
if nlg_call.get("response") == "utter_greet":
|
|
response_dict = {"text": "Hey there!"}
|
|
else:
|
|
response_dict = {"text": "Sorry, didn't get that."}
|
|
return response.json(response_dict)
|
|
|
|
return app
|
|
|
|
|
|
# noinspection PyShadowingNames
|
|
@pytest.fixture()
|
|
def http_nlg(loop, sanic_client):
|
|
return loop.run_until_complete(sanic_client(nlg_app()))
|
|
|
|
|
|
async def test_nlg(http_nlg, trained_rasa_model: Text):
|
|
sender = str(uuid.uuid1())
|
|
|
|
nlg_endpoint = EndpointConfig.from_dict({"url": http_nlg.make_url("/")})
|
|
agent = Agent.load(trained_rasa_model, generator=nlg_endpoint)
|
|
|
|
response = await agent.handle_text("/greet", sender_id=sender)
|
|
assert len(response) == 1
|
|
assert response[0] == {"text": "Hey there!", "recipient_id": sender}
|
|
|
|
|
|
def test_nlg_endpoint_config_loading(endpoints_path: Text):
|
|
cfg = read_endpoint_config(endpoints_path, "nlg")
|
|
|
|
assert cfg == EndpointConfig.from_dict({"url": "http://localhost:5055/nlg"})
|
|
|
|
|
|
def test_nlg_schema_validation():
|
|
content = {"text": "Hey there!"}
|
|
assert CallbackNaturalLanguageGenerator.validate_response(content)
|
|
|
|
|
|
def test_nlg_schema_validation_empty_buttons():
|
|
content = {"text": "Hey there!", "buttons": []}
|
|
assert CallbackNaturalLanguageGenerator.validate_response(content)
|
|
|
|
|
|
def test_nlg_schema_validation_empty_image():
|
|
content = {"text": "Hey there!", "image": None}
|
|
assert CallbackNaturalLanguageGenerator.validate_response(content)
|
|
|
|
|
|
def test_nlg_schema_validation_empty_custom_dict():
|
|
content = {"custom": {}}
|
|
assert CallbackNaturalLanguageGenerator.validate_response(content)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"slot_name, slot_value",
|
|
[
|
|
("tag_w_underscore", "a"),
|
|
("tag with space", "bacon"),
|
|
("tag.with.dot", "chocolate"),
|
|
("tag-w-dash", "apple pie"),
|
|
("tag-w-$", "banana"),
|
|
("tag-w-@", "one"),
|
|
("tagCamelCase", "two"),
|
|
("tag-w-*", "three"),
|
|
("tag_w_underscore", "a"),
|
|
("tag.with.float.val", 1.3),
|
|
("tag-w-$", "banana"),
|
|
("tagCamelCase", "two"),
|
|
("empty_string", ""),
|
|
("null", None),
|
|
],
|
|
)
|
|
def test_nlg_fill_response_text(slot_name: Text, slot_value: Any):
|
|
response = {"text": f"{{{slot_name}}}"}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(response=response, filled_slots={slot_name: slot_value})
|
|
assert result == {"text": str(slot_value)}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"img_slot_name, img_slot_value",
|
|
[("url", "https://www.exampleimg.com"), ("img1", "https://www.appleimg.com")],
|
|
)
|
|
def test_nlg_fill_response_image(img_slot_name: Text, img_slot_value: Text):
|
|
response = {"image": f"{{{img_slot_name}}}"}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response, filled_slots={img_slot_name: img_slot_value}
|
|
)
|
|
assert result == {"image": str(img_slot_value)}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"slot_name, slot_value",
|
|
[
|
|
("tag_w_underscore", "a"),
|
|
("tag with space", "bacon"),
|
|
("tag.with.dot", "chocolate"),
|
|
("tag-w-dash", "apple pie"),
|
|
("tag-w-$", "banana"),
|
|
("tag-w-@", "one"),
|
|
("tagCamelCase", "two"),
|
|
("tag-w-*", "three"),
|
|
("tag_w_underscore", "a"),
|
|
("tag.with.float.val", 1.3),
|
|
("tag-w-$", "banana"),
|
|
("tagCamelCase", "two"),
|
|
("empty_string", ""),
|
|
("null", None),
|
|
],
|
|
)
|
|
def test_nlg_fill_response_custom(slot_name: Text, slot_value: Any):
|
|
response = {
|
|
"custom": {
|
|
"field": f"{{{slot_name}}}",
|
|
"properties": {"field_prefixed": f"prefix_{{{slot_name}}}"},
|
|
"bool_field": True,
|
|
"int_field:": 42,
|
|
"empty_field": None,
|
|
}
|
|
}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(response=response, filled_slots={slot_name: slot_value})
|
|
|
|
assert result == {
|
|
"custom": {
|
|
"field": str(slot_value),
|
|
"properties": {"field_prefixed": f"prefix_{slot_value}"},
|
|
"bool_field": True,
|
|
"int_field:": 42,
|
|
"empty_field": None,
|
|
}
|
|
}
|
|
|
|
|
|
def test_nlg_fill_response_custom_with_list():
|
|
response = {
|
|
"custom": {
|
|
"blocks": [{"fields": [{"text": "*Departure date:*\n{test}"}]}],
|
|
"other": ["{test}"],
|
|
}
|
|
}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(response=response, filled_slots={"test": 5})
|
|
assert result == {
|
|
"custom": {
|
|
"blocks": [{"fields": [{"text": "*Departure date:*\n5"}]}],
|
|
"other": ["5"],
|
|
}
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"response_text, expected",
|
|
[
|
|
('{{"variable":"{slot_1}"}}', '{"variable":"foo"}'),
|
|
("{slot_1} and {slot_2}", "foo and bar"),
|
|
("{{{slot_1}, {slot_2}!}}", "{foo, bar!}"),
|
|
("{{{slot_1}}}", "{foo}"),
|
|
("{{slot_1}}", "{slot_1}"),
|
|
],
|
|
)
|
|
def test_nlg_fill_response_text_with_json(response_text, expected):
|
|
response = {"text": response_text}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response, filled_slots={"slot_1": "foo", "slot_2": "bar"}
|
|
)
|
|
assert result == {"text": expected}
|
|
|
|
|
|
@pytest.mark.parametrize("slot_name, slot_value", [("tag_w_\n", "a")])
|
|
def test_nlg_fill_response_with_bad_slot_name(slot_name, slot_value):
|
|
response_text = f"{{{slot_name}}}"
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response={"text": response_text}, filled_slots={slot_name: slot_value}
|
|
)
|
|
assert result["text"] == response_text
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"text_slot_name, text_slot_value, img_slot_name, img_slot_value",
|
|
[
|
|
("tag_w_underscore", "a", "url", "https://www.exampleimg.com"),
|
|
("tag with space", "bacon", "img1", "https://www.appleimg.com"),
|
|
],
|
|
)
|
|
def test_nlg_fill_response_image_and_text(
|
|
text_slot_name, text_slot_value, img_slot_name, img_slot_value
|
|
):
|
|
response = {"text": f"{{{text_slot_name}}}", "image": f"{{{img_slot_name}}}"}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response,
|
|
filled_slots={text_slot_name: text_slot_value, img_slot_name: img_slot_value},
|
|
)
|
|
assert result == {"text": str(text_slot_value), "image": str(img_slot_value)}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"text_slot_name, text_slot_value, cust_slot_name, cust_slot_value",
|
|
[
|
|
("tag_w_underscore", "a", "tag.with.dot", "chocolate"),
|
|
("tag with space", "bacon", "tag-w-dash", "apple pie"),
|
|
],
|
|
)
|
|
def test_nlg_fill_response_text_and_custom(
|
|
text_slot_name, text_slot_value, cust_slot_name, cust_slot_value
|
|
):
|
|
response = {
|
|
"text": f"{{{text_slot_name}}}",
|
|
"custom": {
|
|
"field": f"{{{cust_slot_name}}}",
|
|
"properties": {"field_prefixed": f"prefix_{{{cust_slot_name}}}"},
|
|
},
|
|
}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response,
|
|
filled_slots={text_slot_name: text_slot_value, cust_slot_name: cust_slot_value},
|
|
)
|
|
assert result == {
|
|
"text": str(text_slot_value),
|
|
"custom": {
|
|
"field": str(cust_slot_value),
|
|
"properties": {"field_prefixed": f"prefix_{str(cust_slot_value)}"},
|
|
},
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"attach_slot_name, attach_slot_value", [("attach_file", "https://attach.pdf")]
|
|
)
|
|
def test_nlg_fill_response_attachment(attach_slot_name, attach_slot_value):
|
|
response = {"attachment": "{" + attach_slot_name + "}"}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response, filled_slots={attach_slot_name: attach_slot_value}
|
|
)
|
|
assert result == {"attachment": str(attach_slot_value)}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"button_slot_name, button_slot_value", [("button_1", "button_1")]
|
|
)
|
|
def test_nlg_fill_response_button(button_slot_name, button_slot_value):
|
|
response = {
|
|
"buttons": [
|
|
{
|
|
"payload": f'/choose{{{{"some_slot": "{{{button_slot_name}}}"}}}}',
|
|
"title": f"{{{button_slot_name}}}",
|
|
}
|
|
]
|
|
}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response, filled_slots={button_slot_name: button_slot_value}
|
|
)
|
|
assert result == {
|
|
"buttons": [
|
|
{
|
|
"payload": f'/choose{{"some_slot": "{button_slot_value}"}}',
|
|
"title": f"{button_slot_value}",
|
|
}
|
|
]
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"quick_replies_slot_name, quick_replies_slot_value", [("qreply", "reply 1")]
|
|
)
|
|
def test_nlg_fill_response_quick_replies(
|
|
quick_replies_slot_name, quick_replies_slot_value
|
|
):
|
|
response = {"quick_replies": f"{{{quick_replies_slot_name}}}"}
|
|
t = TemplatedNaturalLanguageGenerator(responses=dict())
|
|
result = t._fill_response(
|
|
response=response,
|
|
filled_slots={quick_replies_slot_name: quick_replies_slot_value},
|
|
)
|
|
assert result == {"quick_replies": str(quick_replies_slot_value)}
|