Commit 3cf04f37 authored by sachitha's avatar sachitha

RASA chatbot added

parent 211177b5
FROM python:3.7.7-stretch AS BASE
RUN apt-get update \
&& apt-get --assume-yes --no-install-recommends install \
build-essential \
curl \
git \
jq \
libgomp1 \
vim
WORKDIR /app
# upgrade pip version
RUN pip install --no-cache-dir --upgrade pip
RUN pip install rasa==2.8.1
ADD config.yml config.yml
ADD domain.yml domain.yml
ADD credentials.yml credentials.yml
ADD endpoints.yml endpoints.yml
\ No newline at end of file
# This files contains your custom actions which can be used to run
# custom Python code.
#
# See this guide on how to implement these action:
# https://rasa.com/docs/rasa/custom-actions
# This is a simple example for a custom action which utters "Hello World!"
# from typing import Any, Text, Dict, List
#
# from rasa_sdk import Action, Tracker
# from rasa_sdk.executor import CollectingDispatcher
#
#
# class ActionHelloWorld(Action):
#
# def name(self) -> Text:
# return "action_hello_world"
#
# def run(self, dispatcher: CollectingDispatcher,
# tracker: Tracker,
# domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:
#
# dispatcher.utter_message(text="Hello World!")
#
# return []
# Configuration for Rasa NLU.
# https://rasa.com/docs/rasa/nlu/components/
language: en
pipeline:
# # No configuration for the NLU pipeline was provided. The following default pipeline was used to train your model.
# # If you'd like to customize it, uncomment and adjust the pipeline.
# # See https://rasa.com/docs/rasa/tuning-your-model for more information.
# - name: WhitespaceTokenizer
# - name: RegexFeaturizer
# - name: LexicalSyntacticFeaturizer
# - name: CountVectorsFeaturizer
# - name: CountVectorsFeaturizer
# analyzer: char_wb
# min_ngram: 1
# max_ngram: 4
# - name: DIETClassifier
# epochs: 100
# constrain_similarities: true
# - name: EntitySynonymMapper
# - name: ResponseSelector
# epochs: 100
# constrain_similarities: true
# - name: FallbackClassifier
# threshold: 0.3
# ambiguity_threshold: 0.1
# Configuration for Rasa Core.
# https://rasa.com/docs/rasa/core/policies/
policies:
# # No configuration for policies was provided. The following default policies were used to train your model.
# # If you'd like to customize them, uncomment and adjust the policies.
# # See https://rasa.com/docs/rasa/policies for more information.
# - name: MemoizationPolicy
# - name: RulePolicy
# - name: UnexpecTEDIntentPolicy
# max_history: 5
# epochs: 100
# - name: TEDPolicy
# max_history: 5
# epochs: 100
# constrain_similarities: true
# This file contains the credentials for the voice & chat platforms
# which your bot is using.
# https://rasa.com/docs/rasa/messaging-and-voice-channels
# rest:
custom_channels.custom_rest.RestInput:
# # you don't need to provide anything here - this channel doesn't
# # require any credentials
#facebook:
# verify: "<verify>"
# secret: "<your secret>"
# page-access-token: "<your page access token>"
#slack:
# slack_token: "<your slack token>"
# slack_channel: "<the slack channel>"
# slack_signing_secret: "<your slack signing secret>"
#socketio:
# user_message_evt: <event name for user message>
# bot_message_evt: <event name for bot messages>
# session_persistence: <true/false>
#mattermost:
# url: "https://<mattermost instance>/api/v4"
# token: "<bot token>"
# webhook_url: "<callback URL>"
# This entry is needed if you are using Rasa X. The entry represents credentials
# for the Rasa X "channel", i.e. Talk to your bot and Share with guest testers.
rasa:
url: "http://localhost:5002/api"
import asyncio
import inspect
import json
import logging
from asyncio import Queue, CancelledError
from sanic import Blueprint, response
from sanic.request import Request
from sanic.response import HTTPResponse
from typing import Text, Dict, Any, Optional, Callable, Awaitable, NoReturn
import rasa.utils.endpoints
from rasa.core.channels.channel import (
InputChannel,
CollectingOutputChannel,
UserMessage,
)
logger = logging.getLogger(__name__)
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("recipient_id", None)
# noinspection PyMethodMayBeStatic
def _extract_message(self, req: Request) -> Optional[Text]:
return req.json.get("text", None)
def _extract_input_channel(self, req: Request) -> Text:
return req.json.get("input_channel") or self.name()
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]]:
async def stream(resp: Any) -> None:
q = 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:
custom_webhook = Blueprint(
"custom_webhook_{}".format(type(self).__name__),
inspect.getmodule(self).__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) -> 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:
logger.error(
f"Message handling timed out for " f"user message '{text}'."
)
except Exception:
logger.exception(
f"An exception occured while handling "
f"user message '{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)."""
@classmethod
def name(cls) -> Text:
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)
\ No newline at end of file
version: "2.0"
nlu:
- intent: greet
examples: |
- hey
- hello
- hi
- hello there
- good morning
- good evening
- moin
- hey there
- let's go
- hey dude
- goodmorning
- goodevening
- good afternoon
- intent: goodbye
examples: |
- good afternoon
- cu
- good by
- cee you later
- good night
- bye
- goodbye
- have a nice day
- see you around
- bye bye
- see you later
- intent: affirm
examples: |
- yes
- y
- indeed
- of course
- that sounds good
- correct
- intent: deny
examples: |
- no
- n
- never
- I don't think so
- don't like that
- no way
- not really
- intent: mood_great
examples: |
- perfect
- great
- amazing
- feeling like a king
- wonderful
- I am feeling very good
- I am great
- I am amazing
- I am going to save the world
- super stoked
- extremely good
- so so perfect
- so good
- so perfect
- intent: mood_unhappy
examples: |
- my day was horrible
- I am sad
- I don't feel very well
- I am disappointed
- super sad
- I'm so sad
- sad
- very sad
- unhappy
- not good
- not very good
- extremly sad
- so saad
- so sad
- intent: bot_challenge
examples: |
- are you a bot
- are you a human
- am I talking to a bot
- am I talking to a human
- intent: neck_pain
examples: |
- I have a neck pain
- my neck is hurting
- having a neck pain
- oh my neck is hurting
- my neck hurts
- intent: spinal_pain
examples: |
- I have a back pain
- I have a spinal pain
- my back is hurting
- having a spinal pain
- having a back pain
- oh my back is hurting
- oh my spine is hurting
- my back hurts
- my back it hurts
- my spine it hurts
- intent: heart_attact
examples: |
- i have a heart attack
- I am having a heart attact
- hart attact
- I am a heart patient
- heart patient
- heart problem
- chest pain
- chest ache
- intent: asathma
examples: |
- I have asathma
- I am an asathma patient
- I am having asathma
- Have asathma
- asathma
- intent: sleep_apnea
examples: |
- I have sleep apnea
- I am having sleep apnea
- Have sleep apnea
- sleep apnea
- intent: stress
examples: |
- I am stressed
- Stressed today
- stressed
- Depressed today
- Depressed
- tired today
- bit tired
- tired
version: "2.0"
rules:
- rule: Say goodbye anytime the user says goodbye
steps:
- intent: goodbye
- action: utter_goodbye
- rule: Say 'I am a bot' anytime the user challenges
steps:
- intent: bot_challenge
- action: utter_iamabot
version: "2.0"
stories:
- story: happy path
steps:
- intent: greet
- action: utter_greet
- intent: mood_great
- action: utter_happy
- story: neck pain
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_have_a_pain
- intent: neck_pain
- action: utter_neck_pain
- action: utter_get_well_soon
- story: heart attact
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_have_a_pain
- intent: heart_attact
- action: utter_heart_attact
- action: utter_get_well_soon
- story: asathma
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_have_a_pain
- intent: asathma
- action: utter_asathma
- action: utter_get_well_soon
- story: sleep_apnea
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_have_a_pain
- intent: sleep_apnea
- action: utter_sleep_apnea
- action: utter_get_well_soon
- story: stress
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_have_a_pain
- intent: stress
- action: utter_stress
- action: utter_get_well_soon
- story: spinal pain
steps:
- intent: greet
- action: utter_greet
- intent: mood_unhappy
- action: utter_have_a_pain
- intent: spinal_pain
- action: utter_spinal_pain
- action: utter_get_well_soon
version: '3.4'
services:
duckling-server:
image: rasa/duckling:latest
ports:
- 8000:8000
networks:
- all
rasa-server:
image: rasa-bot:latest
working_dir: /app
build: "./"
restart: always
volumes:
- ./actions:/app/actions
- ./data:/app/data
command: bash -c "rm -rf models/* && rasa train && rasa run --enable-api --cors \"*\" --debug"
ports:
- '5006:5005'
public: true
networks:
- all
rasa-actions-server:
image: rasa-bot:latest
working_dir: /app
build: "./"
restart: always
volumes:
- ./actions:/app/actions
- ./utils:/app/utils
command: ["rasa", "run", "actions"]
ports:
- '5055:5055'
networks:
- all
networks:
all:
driver: bridge
driver_opts:
com.docker.network.enable_ipv6: "true"
\ No newline at end of file
version: "2.0"
intents:
- greet
- goodbye
- affirm
- deny
- mood_great
- mood_unhappy
- bot_challenge
- neck_pain
- spinal_pain
- stress
- asathma
- heart_attact
- sleep_apnea
responses:
utter_greet:
- text: "Hey! How are you?"
utter_have_a_pain:
- text: "Do you have any pain"
utter_neck_pain:
- text: "Two sleeping positions are easiest on the neck: on your side or on your back. If you sleep on your back, choose a rounded pillow to support the natural curve of your neck, with a flatter pillow cushioning your head."
image: "https://marvel-b1-cdn.bc0a.com/f00000000041628/ix-cdn.b2e5.com/images/41628/41628_0a4e16da5830416f9b6b90b050b4c688_1653408647.jpeg"
utter_spinal_pain:
- text: "The best position to avoid back pain is lying flat on your back. Even so, many people find it the hardest way to enjoy deep sleep. For optimal spine alignment, place one pillow underneath your head or neck and another underneath your knees."
image: "https://healthmatters.nyp.org/wp-content/uploads/2021/06/back-pain-and-sleep-slide-back.jpg"
utter_stress:
- text: "Specifically, sleeping on the side or back is considered more beneficial than sleeping on the stomach. In either of these sleep positions, it's easier to keep your spine supported and balanced, which relieves pressure on the spinal tissues and enables your muscles to relax and recover."
image: "https://healthmatters.nyp.org/wp-content/uploads/2021/06/back-pain-and-sleep-slide-back.jpg"
utter_sleep_apnea:
- text: "Side sleeping with your back mostly straight is the best position for sleep apnea sufferers according to the Sleep Better Council. Research shows that sleeping on the left side reduces sleep apnea even more than sleeping on the right."
image: "https://www.sleepcycle.com/wp-content/uploads/2022/02/the-sleep-positions-for-sleep-apnea.jpg"
utter_asathma:
- text: "1. Lie on your back with your shoulders and neck elevated. 2. Lie on your left side with a pillow between your legs. 3. Lie on your back with your head elevated and your knees bent with a pillow under knees."
image: "https://post.healthline.com/wp-content/uploads/2021/03/sleeping-in-bed-many-pillows-732x549-thumbnail.jpg"
utter_heart_attact:
- text: "Sleeping on your right side may be the best option for people with heart failure. Although some people think sleeping on your right side could restrict blood flow back to the heart, there's not enough evidence to prove that it's harmful."
image: "https://post.healthline.com/wp-content/uploads/2021/01/Older_Female_Side_Sleeping_1200x628-facebook-1200x628.jpg"
utter_cheer_up:
- text: "Here is something to cheer you up:"
image: "https://i.imgur.com/nGF1K8f.jpg"
utter_did_that_help:
- text: "Did that help you?"
utter_get_well_soon:
- text: "Getwel soon!"
utter_happy:
- text: "Great, carry on!"
utter_goodbye:
- text: "Bye"
utter_iamabot:
- text: "I am a bot, powered by Rasa."
session_config:
session_expiration_time: 60
carry_over_slots_to_new_session: true
# This file contains the different endpoints your bot can use.
# Server where the models are pulled from.
# https://rasa.com/docs/rasa/model-storage#fetching-models-from-a-server
#models:
# url: http://my-server.com/models/default_core@latest
# wait_time_between_pulls: 10 # [optional](default: 100)
# Server which runs your custom actions.
# https://rasa.com/docs/rasa/custom-actions
#action_endpoint:
# url: "http://localhost:5055/webhook"
# Tracker store which is used to store the conversations.
# By default the conversations are stored in memory.
# https://rasa.com/docs/rasa/tracker-stores
#tracker_store:
# type: redis
# url: <host of the redis instance, e.g. localhost>
# port: <port of your redis instance, usually 6379>
# db: <number of your database within redis, e.g. 0>
# password: <password used for authentication>
# use_ssl: <whether or not the communication is encrypted, default false>
#tracker_store:
# type: mongod
# url: <url to your mongo instance, e.g. mongodb://localhost:27017>
# db: <name of the db within your mongo instance, e.g. rasa>
# username: <username used for authentication>
# password: <password used for authentication>
# Event broker which all conversation events should be streamed to.
# https://rasa.com/docs/rasa/event-brokers
#event_broker:
# url: localhost
# username: username
# password: password
# queue: queue
# None of the test stories failed - all good!
\ No newline at end of file
[
{
"text": "good afternoon",
"intent": "goodbye",
"intent_prediction": {
"name": "greet",
"confidence": 0.5742628574371338
}
}
]
\ No newline at end of file
{
"mood_great": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 14,
"confused_with": {}
},
"neck_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 5,
"confused_with": {}
},
"asathma": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 5,
"confused_with": {}
},
"stress": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 8,
"confused_with": {}
},
"spinal_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 10,
"confused_with": {}
},
"heart_attact": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 8,
"confused_with": {}
},
"goodbye": {
"precision": 1.0,
"recall": 0.9090909090909091,
"f1-score": 0.9523809523809523,
"support": 11,
"confused_with": {
"greet": 1
}
},
"affirm": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 6,
"confused_with": {}
},
"deny": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 7,
"confused_with": {}
},
"mood_unhappy": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 14,
"confused_with": {}
},
"sleep_apnea": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 4,
"confused_with": {}
},
"greet": {
"precision": 0.9285714285714286,
"recall": 1.0,
"f1-score": 0.962962962962963,
"support": 13,
"confused_with": {}
},
"bot_challenge": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 4,
"confused_with": {}
},
"accuracy": 0.9908256880733946,
"macro avg": {
"precision": 0.9945054945054945,
"recall": 0.9930069930069931,
"f1-score": 0.9934879934879935,
"support": 109
},
"weighted avg": {
"precision": 0.991480996068152,
"recall": 0.9908256880733946,
"f1-score": 0.9907771467404496,
"support": 109
}
}
\ No newline at end of file
# No warnings for test stories
\ No newline at end of file
{
"utter_happy": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2
},
"utter_get_well_soon": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 6
},
"utter_stress": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"action_listen": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 25
},
"mood_great": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2
},
"neck_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"spinal_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"utter_greet": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 8
},
"utter_spinal_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"utter_asathma": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"mood_unhappy": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 6
},
"utter_iamabot": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"bot_challenge": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"utter_heart_attact": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"stress": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"utter_have_a_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 6
},
"heart_attact": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"asathma": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"sleep_apnea": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"utter_sleep_apnea": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"utter_neck_pain": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 1
},
"goodbye": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2
},
"utter_goodbye": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 2
},
"greet": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 8
},
"accuracy": 1.0,
"macro avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 81
},
"weighted avg": {
"precision": 1.0,
"recall": 1.0,
"f1-score": 1.0,
"support": 81
},
"conversation_accuracy": {
"accuracy": 1.0,
"correct": 10,
"with_warnings": 0,
"total": 10
}
}
\ No newline at end of file
#### This file contains tests to evaluate that your bot behaves as expected.
#### If you want to learn more, please see the docs: https://rasa.com/docs/rasa/testing-your-assistant
stories:
- story: happy path 1
steps:
- user: |
hello there!
intent: greet
- action: utter_greet
- user: |
amazing
intent: mood_great
- action: utter_happy
- story: neck pain 1
steps:
- user: |
hi
intent: greet
- action: utter_greet
- user: |
not good
intent: mood_unhappy
- action: utter_have_a_pain
- user: |
neck pain
intent: neck_pain
- action: utter_neck_pain
- action: utter_get_well_soon
- story: back pain 1
steps:
- user: |
hi
intent: greet
- action: utter_greet
- user: |
not good
intent: mood_unhappy
- action: utter_have_a_pain
- user: |
back pain
intent: spinal_pain
- action: utter_spinal_pain
- action: utter_get_well_soon
- story: stress 1
steps:
- user: |
hi
intent: greet
- action: utter_greet
- user: |
not good
intent: mood_unhappy
- action: utter_have_a_pain
- user: |
i am stressed
intent: stress
- action: utter_stress
- action: utter_get_well_soon
- story: asathma 1
steps:
- user: |
hi
intent: greet
- action: utter_greet
- user: |
not good
intent: mood_unhappy
- action: utter_have_a_pain
- user: |
i have asathma
intent: asathma
- action: utter_asathma
- action: utter_get_well_soon
- story: heart attact 1
steps:
- user: |
hi
intent: greet
- action: utter_greet
- user: |
not good
intent: mood_unhappy
- action: utter_have_a_pain
- user: |
i have a hear attact
intent: heart_attact
- action: utter_heart_attact
- action: utter_get_well_soon
- story: sleep_apnea 1
steps:
- user: |
hi
intent: greet
- action: utter_greet
- user: |
not good
intent: mood_unhappy
- action: utter_have_a_pain
- user: |
i have sleep apnea
intent: sleep_apnea
- action: utter_sleep_apnea
- action: utter_get_well_soon
- story: happy path 2
steps:
- user: |
hello there!
intent: greet
- action: utter_greet
- user: |
amazing
intent: mood_great
- action: utter_happy
- user: |
bye-bye!
intent: goodbye
- action: utter_goodbye
- story: say goodbye
steps:
- user: |
bye-bye!
intent: goodbye
- action: utter_goodbye
- story: bot challenge
steps:
- user: |
are you a bot?
intent: bot_challenge
- action: utter_iamabot
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment