Seja bem vindo ao BOILERPLATE integrado com webchat
6 | Você deve ver uma bola azul no canto inferior direito do seu navegador.
7 |
8 |
9 |
10 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/bot/actions/data_validator.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | def isCpfValid(cpf):
5 | """ If cpf in the Brazilian format is valid, it returns True, otherwise, it returns False. """
6 |
7 | # Check if type is str
8 | if not isinstance(cpf, str):
9 | return False
10 |
11 | # Remove some unwanted characters
12 | cpf = re.sub("[^0-9]", "", cpf)
13 |
14 | # Checks if string has 11 characters
15 | if len(cpf) != 11:
16 | return False
17 |
18 | sum = 0
19 | weight = 10
20 |
21 | """ Calculating the first cpf check digit. """
22 | for n in range(9):
23 | sum = sum + int(cpf[n]) * weight
24 |
25 | # Decrement weight
26 | weight = weight - 1
27 |
28 | verifyingDigit = 11 - sum % 11
29 |
30 | if verifyingDigit > 9:
31 | firstVerifyingDigit = 0
32 | else:
33 | firstVerifyingDigit = verifyingDigit
34 |
35 | """ Calculating the second check digit of cpf. """
36 | sum = 0
37 | weight = 11
38 | for n in range(10):
39 | sum = sum + int(cpf[n]) * weight
40 |
41 | # Decrement weight
42 | weight = weight - 1
43 |
44 | verifyingDigit = 11 - sum % 11
45 |
46 | if verifyingDigit > 9:
47 | secondVerifyingDigit = 0
48 | else:
49 | secondVerifyingDigit = verifyingDigit
50 |
51 | if cpf[-2:] == "%s%s" % (firstVerifyingDigit, secondVerifyingDigit):
52 | return True
53 | return False
54 |
--------------------------------------------------------------------------------
/docs/add_bot_rocketchat.md:
--------------------------------------------------------------------------------
1 | ### Adicionar bot ao RocketChat
2 |
3 | Para configurar o bot no rocketchat, devem ser seguidos os passos a seguir.
4 |
5 | - Primeiro você deve clicar no ícone Directory localizado na parte superior esquerda da tela, conforme mostra a imagem a seguir.
6 |
7 |
8 | - A seguir será aberta uma nova tela com os canais existentes. Clique no canal General
9 |
10 |
11 | - Após isso clique na opção Join
12 |
13 |
14 |
15 | - O canal do bot será exibido nessa tela, clique no nome do bot como indicado na imagem abaixo
16 |
17 |
18 | - Por último clique na opção conversation, que irá redirecionar para o chat do bot
19 |
20 |
21 | - Agora basta conversar com @ FAMOOS@!
22 |
--------------------------------------------------------------------------------
/.github/workflows/python.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 |
4 | name: build_bot
5 |
6 | on:
7 | push:
8 | branches: [ main, devel ]
9 | pull_request:
10 | branches: [ main, devel ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 | strategy:
17 | matrix:
18 | python-version: [3.6, 3.7]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Set up Python ${{ matrix.python-version }}
23 | uses: actions/setup-python@v1
24 | with:
25 | python-version: ${{ matrix.python-version }}
26 | - name: Install dependencies
27 | run: |
28 | # Added "gast=0.2.2" as a workarround because of a Tensorflow issue, should be removed soon
29 | python -m pip install --upgrade pip gast==0.2.2
30 | pip install flake8 pytest
31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
32 | - name: Lint with flake8
33 | run: |
34 | # stop the build if there are Python syntax errors or undefined names
35 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
36 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
37 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
38 | - name: Test Rasa version
39 | run: |
40 | rasa --version
41 | - name: Rasa train
42 | run: |
43 | cd bot/
44 | make train
45 | - name: Test Rasa bot
46 | run: |
47 | cd bot/
48 | make test
49 |
--------------------------------------------------------------------------------
/modules/analytics/import_dashboards.py:
--------------------------------------------------------------------------------
1 | import json
2 | import requests
3 | import os
4 | import logging
5 |
6 | logging.basicConfig(level=logging.DEBUG)
7 | logger = logging.getLogger(__name__)
8 |
9 |
10 | def getRequestDatas(finalUrl):
11 | fullUrl = []
12 |
13 | url = os.getenv("KIBANA_URL", "http://kibana:5601")
14 | url = url + finalUrl
15 |
16 | header = {"kbn-xsrf": "true", "Content-Type": "application/json"}
17 |
18 | fullUrl.append(url)
19 | fullUrl.append(header)
20 |
21 | return fullUrl
22 |
23 |
24 | def getIdDashboards(pathToFile):
25 | dashboardsIds = {}
26 |
27 | # Path that contains the data of the export.json to search dashboard id's
28 | # export.json from version 7.3 of kibana
29 | with open(pathToFile) as file:
30 | data = json.load(file)
31 |
32 | for savedObjects in data["saved_objects"]:
33 | attributes = savedObjects["attributes"]["title"]
34 | dashboardsIds[attributes] = savedObjects["id"]
35 |
36 | return dashboardsIds
37 |
38 |
39 | def importDashboards(pathToFile):
40 | finalUrl = "/api/kibana/dashboards/import?exclude=index-pattern"
41 | requestData = getRequestDatas(finalUrl)
42 |
43 | datas = open(pathToFile, "rb").read()
44 | datas = datas.decode("utf-8")
45 |
46 | requests.post(url=requestData[0], headers=requestData[1], data=json.dumps(datas))
47 |
48 | createIndexPattern()
49 |
50 |
51 | def createIndexPattern():
52 | # TODO: Import value of the variable from the environment
53 | idIndex = "194404f0-e6b4-11e8-bb67-918dc5752875"
54 | finalUrl = "/api/saved_objects/index-pattern/" + idIndex
55 |
56 | requestData = getRequestDatas(finalUrl)
57 |
58 | datas = {"attributes": {"title": "messages*"}}
59 |
60 | requests.post(url=requestData[0], headers=requestData[1], data=json.dumps(datas))
61 |
62 |
63 | if __name__ == "__main__":
64 | try:
65 | importDashboards("./dashboards.json")
66 | except Exception as ex:
67 | logger.error(str(ex))
68 |
--------------------------------------------------------------------------------
/docs/setup_telegram.md:
--------------------------------------------------------------------------------
1 | # Setup do bot no Telegram
2 |
3 | ## Crie um bot no Telegram
4 |
5 | Converse com o [@BotFather do Telegram](https://t.me/BotFather) e crie um bot de teste unicamente seu seguindo as instruções dele.
6 |
7 | ## Exporte as variáveis do seu bot
8 |
9 | Após escolher um nome para seu bot, o @BotFather lhe dará um token para utilizar para acessar a API do Telegram. Adicione ambos no [arquivo de configurações do bot](../env/bot-telegram.env), como a seguir. Substitua o TELEGRAM_TOKEN pelo token lhe enviado pelo @BotFather e TELEGRAM_BOT_USERNAME pelo nome do seu bot.
10 |
11 | ```sh
12 | TELEGRAM_BOT_USERNAME=username_do_bot
13 | TELEGRAM_TOKEN=token_fornecido_pelo_BotFather
14 | ```
15 |
16 | ## Execute o ngrok
17 |
18 | Após a etapa anterior, é necessário utilizar o [ngrok](https://ngrok.com/download) para expor determinada porta para ser utilizado
19 | pelo Telegram.
20 |
21 | Conforme a seguir, execute o ngrok na porta 5001.
22 |
23 | ```sh
24 | ./ngrok http 5001
25 | ```
26 |
27 | **Atenção:** O conector do Telegram está utilizando a porta 5001 como padrão. Caso queira mudar, somente altere
28 | a porta utilizada pelo no Makefile.
29 |
30 |
31 | ## Exporte a URL do Webhook
32 |
33 | Enquanto o ngrok estiver em execução, ele apresentará uma série de informações da sessão atual. Copie a url do campo Forwarding com o protocolo HTTPS e cole no [arquivo de configurações do bot](../env/bot-telegram.env). ela será similar à seguinte.
34 |
35 | ```sh
36 | TELEGRAM_WEBHOOK=link_do_ngrok/webhooks/telegram/webhook
37 | ```
38 |
39 | ::Lembre-se::: sempre que executar o ngrok essa url deve ser exportada.
40 |
41 |
42 | ## Execução do bot no telegram
43 |
44 | Ao final de realizar essas configurações, seu [arquivo de configurações do bot](../env/bot-telegram.env) deve estar de acordo com o exibido logo abaixo:
45 |
46 | ```sh
47 | TELEGRAM_BOT_USERNAME=lappisbot
48 | TELEGRAM_TOKEN=token
49 | TELEGRAM_WEBHOOK=your_webhook_server/webhooks/telegram/webhook
50 | ```
51 |
52 | Com isso, é possível realizar a execução do bot seguindo os passos do [README](../README.md)
53 |
54 |
--------------------------------------------------------------------------------
/docs/Setup/setup_telegram.md:
--------------------------------------------------------------------------------
1 | ## Setup do bot no Telegram
2 |
3 | ##### Crie um bot no Telegram
4 |
5 | Converse com o [@BotFather do Telegram](https://t.me/BotFather) e crie um bot de teste unicamente seu seguindo as instruções dele.
6 |
7 |
8 |
9 |
10 | ##### Exporte as variáveis do seu bot
11 | Após escolher um nome para seu bot, o @BotFather lhe dará um token para utilizar para acessar a API do Telegram. Adicione ambos no [arquivo de configurações do bot](../env/bot-telegram.env), como a seguir. Substitua o TELEGRAM_TOKEN pelo token lhe enviado pelo @BotFather e TELEGRAM_BOT_USERNAME pelo nome do seu bot.
12 |
13 | ```sh
14 | TELEGRAM_BOT_USERNAME=token_fornecido_pelo_BotFather
15 | TELEGRAM_TOKEN=username_do_bot
16 | ```
17 |
18 | ##### Execute o ngrok
19 | Após a etapa anterior, é necessário utilizar o [ngrok](https://ngrok.com/download) para expor determinada porta para ser utilizado
20 | pelo Telegram.
21 |
22 | Conforme a seguir, execute o ngrok na porta 5001.
23 |
24 | ```sh
25 | ./ngrok http 5001
26 | ```
27 |
28 | **Atenção:** O conector do Telegram está utilizando a porta 5001 como padrão. Caso queira mudar, somente altere
29 | a porta utilizada pelo no Makefile.
30 |
31 |
32 | ##### Exporte a URL do Webhook
33 |
34 | Enquanto o ngrok estiver em execução, ele apresentará uma série de informações da sessão atual. Copie a url do campo Forwarding com o protocolo HTTPS e cole no [arquivo de configurações do bot](../env/bot-telegram.env). ela será similar à seguinte.
35 |
36 | ```sh
37 | TELEGRAM_WEBHOOK=link_do_ngrok/webhooks/telegram/webhook
38 | ```
39 |
40 | ::Lembre-se::: sempre que executar o ngrok essa url deve ser exportada.
41 |
42 |
43 | ##### Execução do bot no telegram
44 |
45 | Ao final de realizar essas configurações, seu [arquivo de configurações do bot](../env/bot-telegram.env) deve estar de acordo com o exibido logo abaixo:
46 |
47 | ```sh
48 | TELEGRAM_BOT_USERNAME=lappisbot
49 | TELEGRAM_TOKEN=token
50 | TELEGRAM_WEBHOOK=your_webhook_server/webhooks/telegram/webhook
51 | ```
52 |
53 | Com isso, é possível realizar a execução do bot seguindo os passos do [README](../README.md)
54 |
55 |
--------------------------------------------------------------------------------
/modules/analytics/setup_elastic.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import argparse
4 |
5 | from elasticsearch import Elasticsearch
6 |
7 | parser = argparse.ArgumentParser(description="configures elastic")
8 | parser.add_argument("--task", "-t", default="setup", choices=["setup", "delete"])
9 | args = parser.parse_args()
10 |
11 | logging.basicConfig(level=logging.DEBUG)
12 | logger = logging.getLogger(__name__)
13 |
14 | es = Elasticsearch([os.getenv("ELASTICSEARCH_URL", "elasticsearch:9200")])
15 |
16 | settings = {
17 | "settings": {"number_of_shards": 1, "number_of_replicas": 0},
18 | "mappings": {
19 | "message": {
20 | "properties": {
21 | "environment": {"type": "keyword"},
22 | "version": {"type": "keyword"},
23 | "user_id": {"type": "keyword"},
24 | "is_bot": {"type": "boolean"},
25 | "text": {"type": "text"},
26 | "tags": {"type": "keyword"},
27 | "timestamp": {"type": "date", "format": "yyyy/MM/dd HH:mm:ss"},
28 | "intent_name": {"type": "keyword"},
29 | "intent_confidence": {"type": "double"},
30 | "entities": {"type": "keyword"},
31 | "utter_name": {"type": "keyword"},
32 | "is_fallback": {"type": "boolean"},
33 | }
34 | }
35 | },
36 | }
37 |
38 | param = {"include_type_name": "true"}
39 |
40 | index_name = "messages"
41 |
42 | if __name__ == "__main__":
43 | if args.task == "setup":
44 | try:
45 | if not es.indices.exists(index_name):
46 | logger.debug(
47 | es.indices.create(
48 | index=index_name, ignore=400, params=param, body=settings,
49 | )
50 | )
51 | logger.info("Created Index")
52 | else:
53 | logger.info("Index {} already exists".format(index_name))
54 | except Exception as ex:
55 | logger.error(str(ex))
56 |
57 | elif args.task == "delete":
58 | logger.debug(es.indices.delete(index=index_name, ignore=[400, 404]))
59 | logger.info("Index deleted")
60 |
--------------------------------------------------------------------------------
/modules/rabbitmq/consumer/consume_bot_messages.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import pika
3 | import os
4 | import json
5 | import logging
6 | from elastic_connector import ElasticConnector
7 |
8 | username = os.getenv("RABBITMQ_DEFAULT_USER")
9 | password = os.getenv("RABBITMQ_DEFAULT_USER")
10 | credentials = pika.PlainCredentials(username, password)
11 |
12 | logger = logging.getLogger(__name__)
13 |
14 | _elastic_connector = None
15 |
16 | elastic_user = os.getenv("ELASTICSEARCH_USER")
17 | if elastic_user is None:
18 | _elastic_connector = ElasticConnector(
19 | domain=os.getenv("ELASTICSEARCH_URL", "elasticsearch:9200")
20 | )
21 | else:
22 | _elastic_connector = ElasticConnector(
23 | domain=os.getenv("ELASTICSEARCH_URL", "elasticsearch:9200"),
24 | user=os.getenv("ELASTICSEARCH_USER", "user"),
25 | password=os.getenv("ELASTICSEARCH_PASSWORD", "password"),
26 | scheme=os.getenv("ELASTICSEARCH_HTTP_SCHEME", "http"),
27 | scheme_port=os.getenv("ELASTICSEARCH_PORT", "80"),
28 | )
29 |
30 | connection = pika.BlockingConnection(
31 | pika.ConnectionParameters(
32 | host="rabbitmq", credentials=credentials, connection_attempts=20, retry_delay=5,
33 | )
34 | )
35 |
36 | channel = connection.channel()
37 | channel.queue_declare(queue="bot_messages", durable=True)
38 |
39 |
40 | def callback(ch, method, properties, body):
41 | logger.warning(" [x] Received %r" % body)
42 |
43 | message = json.loads(body.decode("utf-8"))
44 |
45 | if message["event"] == "user":
46 | _elastic_connector.save_user_message(message)
47 | _elastic_connector.previous_user_message = message
48 |
49 | elif message["event"] == "action":
50 | if message["name"] == "action_listen":
51 | _elastic_connector.previous_action = None
52 | return
53 |
54 | _elastic_connector.previous_action = message
55 |
56 | elif message["event"] == "bot":
57 | if _elastic_connector.previous_action is None:
58 | _elastic_connector.previous_user_message = None
59 | return
60 |
61 | bot_message = message
62 | action_message = _elastic_connector.previous_action
63 | previous_user_message = _elastic_connector.previous_user_message
64 |
65 | _elastic_connector.save_bot_message(
66 | bot_message, action_message, previous_user_message
67 | )
68 |
69 |
70 | if __name__ == "__main__":
71 | channel.basic_consume(
72 | queue="bot_messages", on_message_callback=callback, auto_ack=True
73 | )
74 |
75 | logger.warning("[*] Waiting for messages.")
76 | channel.start_consuming()
77 |
--------------------------------------------------------------------------------
/docs/Setup/setup_user_elasticsearch.md:
--------------------------------------------------------------------------------
1 | ### Configurando os usuários
2 |
3 | Caso seja desejada a função de se ter usuários com diferentes permissões dentro do kibana, deve-se seguir os seguintes passos (Caso não seja esse seu interesse, pode passar para a próxima sessão):
4 |
5 | OBS: Os seguintes passos podem ser encontrados, com mais detalhes, na seguinte paǵina: https://www.elastic.co/guide/en/elastic-stack-overview/current/get-started-enable-security.html
6 |
7 | **1. Habilitar função de segurança do elastic search:**
8 |
9 | Depois de se subir o container do elastic de acordo com a seção [Setup](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master#setup-elasticsearch),
10 | adicione a seguinte linha ao arquivo 'rasa-ptbr-boilerplate/elasticsearch/elasticsearch.yml':
11 |
12 | ```
13 | xpack.security.enabled: true
14 | ```
15 |
16 | Após adicionar a linha, reinicie o container do Elastic Search
17 |
18 | ```
19 | sudo docker-compose restart elasticsearch
20 | ```
21 |
22 |
23 | **2. Definir senhas para usuários internos do elasticsearch:**
24 |
25 | Entre no container com o comando:
26 |
27 |
28 | ```
29 | sudo docker-compose exec elasticsearch bash
30 | ```
31 |
32 | Dentro do container execute o seguinte comando, preenchendo as senhas que deseja para cada um dos usuários.
33 |
34 |
35 | ```
36 | ./bin/elasticsearch-setup-passwords interactive
37 | ```
38 |
39 | **3. Adicionar usuário kibana ao container do kibana**
40 |
41 | Depois de subir o container do kibana de acordo com a seção [Visualização](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master#setup-kibana-visualização), entre no mesmo com o comando:
42 |
43 | ```
44 | sudo docker-compose exec kibana bash
45 | ```
46 |
47 | Dentro do container, execute os seguintes comandos, digitando, quando necessário, o usuário kibana, e a senha criada no passo anterior.
48 |
49 | ```
50 | ../bin/kibana-keystore create
51 | ../bin/kibana-keystore add elasticsearch.username
52 | ../bin/kibana-keystore add elasticsearch.password
53 | ```
54 |
55 | Após executar os comandos acima, reinicie o container do kibana.
56 |
57 | ```
58 | sudo docker-compose restart kibana
59 | ```
60 |
61 |
62 | **4. Crie usuários além do administrador**
63 |
64 | Após os três passos anteriores, será possível entrar no kibana utilizando a conta com usuário 'elastic'.
65 |
66 | Na interface, é possível criar outros usuários, com diversas outras permissões, entrando em ***Management / Security / Users***, e após isso clicando no botão Create New User.
67 |
68 | **5. Definir permissões para usuários.**
69 |
70 | Na criação de usuários é possível se definir permissões para cada um deles, utilizando os ***roles*** definidos pelo elastic.
71 |
72 | Por exemplo, um usuário que deva ter somente aceesso a leitura dos dashboards criados, deverá ter o role ***kibana_dashboard_only_user*** e ***apm_user***
73 |
74 | É possível criar novos ***roles*** em ***Management / Security / Roles***
75 |
--------------------------------------------------------------------------------
/docs/Tutoriais/setup_user_elasticsearch.md:
--------------------------------------------------------------------------------
1 | # Configurando os usuários
2 |
3 | Caso seja desejada a função de se ter usuários com diferentes permissões dentro do kibana, deve-se seguir os seguintes passos (Caso não seja esse seu interesse, pode passar para a próxima sessão):
4 |
5 | OBS: Os seguintes passos podem ser encontrados, com mais detalhes, na seguinte paǵina: https://www.elastic.co/guide/en/elastic-stack-overview/current/get-started-enable-security.html
6 |
7 | **1. Habilitar função de segurança do elastic search:**
8 |
9 | Depois de se subir o container do elastic de acordo com a seção [Setup](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master#setup-elasticsearch),
10 | adicione a seguinte linha ao arquivo 'rasa-ptbr-boilerplate/elasticsearch/elasticsearch.yml':
11 |
12 | ```
13 | xpack.security.enabled: true
14 | ```
15 |
16 | Após adicionar a linha, reinicie o container do Elastic Search
17 |
18 | ```
19 | sudo docker-compose restart elasticsearch
20 | ```
21 |
22 |
23 | **2. Definir senhas para usuários internos do elasticsearch:**
24 |
25 | Entre no container com o comando:
26 |
27 |
28 | ```
29 | sudo docker-compose exec elasticsearch bash
30 | ```
31 |
32 | Dentro do container execute o seguinte comando, preenchendo as senhas que deseja para cada um dos usuários.
33 |
34 |
35 | ```
36 | ./bin/elasticsearch-setup-passwords interactive
37 | ```
38 |
39 | **3. Adicionar usuário kibana ao container do kibana**
40 |
41 | Depois de subir o container do kibana de acordo com a seção [Visualização](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master#setup-kibana-visualização), entre no mesmo com o comando:
42 |
43 | ```
44 | sudo docker-compose exec kibana bash
45 | ```
46 |
47 | Dentro do container, execute os seguintes comandos, digitando, quando necessário, o usuário kibana, e a senha criada no passo anterior.
48 |
49 | ```
50 | ../bin/kibana-keystore create
51 | ../bin/kibana-keystore add elasticsearch.username
52 | ../bin/kibana-keystore add elasticsearch.password
53 | ```
54 |
55 | Após executar os comandos acima, reinicie o container do kibana.
56 |
57 | ```
58 | sudo docker-compose restart kibana
59 | ```
60 |
61 |
62 | **4. Crie usuários além do administrador**
63 |
64 | Após os três passos anteriores, será possível entrar no kibana utilizando a conta com usuário 'elastic'.
65 |
66 | Na interface, é possível criar outros usuários, com diversas outras permissões, entrando em ***Management / Security / Users***, e após isso clicando no botão Create New User.
67 |
68 | **5. Definir permissões para usuários.**
69 |
70 | Na criação de usuários é possível se definir permissões para cada um deles, utilizando os ***roles*** definidos pelo elastic.
71 |
72 | Por exemplo, um usuário que deva ter somente aceesso a leitura dos dashboards criados, deverá ter o role ***kibana_dashboard_only_user*** e ***apm_user***
73 |
74 | É possível criar novos ***roles*** em ***Management / Security / Roles***
75 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | current_dir := $(shell pwd)
2 | user := $(shell whoami)
3 |
4 | clean:
5 | docker-compose down
6 | cd bot/ && make clean
7 |
8 | stop:
9 | docker-compose stop
10 |
11 | ############################## BOILERPLATE ##############################
12 | first-run:
13 | make build
14 | make train
15 | make run-shell
16 |
17 | build:
18 | make build-requirements
19 | make build-coach
20 | make build-bot
21 |
22 | build-requirements:
23 | docker build . --no-cache -f docker/requirements.Dockerfile -t botrequirements
24 |
25 | build-bot:
26 | docker-compose build --no-cache bot
27 |
28 | build-coach:
29 | docker-compose build --no-cache coach
30 |
31 | build-analytics:
32 | docker-compose up -d elasticsearch
33 | docker-compose up -d rabbitmq
34 | docker-compose up -d rabbitmq-consumer
35 | docker-compose up -d kibana
36 | make config-elastic
37 | make config-kibana
38 |
39 | config-elastic:
40 | docker-compose run --rm -v $(current_dir)/modules/analytics/setup_elastic.py:/analytics/setup_elastic.py bot python /analytics/setup_elastic.py
41 |
42 | config-kibana:
43 | docker-compose run --rm -v $(current_dir)/modules/analytics/:/analytics/ kibana python3 /analytics/import_dashboards.py
44 | $(info )
45 | $(info Acesse o KIBANA em: http://localhost:5601)
46 | $(info )
47 |
48 | run-shell:
49 | docker-compose run --rm --service-ports bot make shell
50 |
51 | run-api:
52 | docker-compose run --rm --service-ports bot make api
53 |
54 | run-actions:
55 | docker-compose run --rm --service-ports bot make actions
56 |
57 | run-x:
58 | docker-compose run --rm --service-ports bot make x
59 |
60 | run-webchat:
61 | $(info )
62 | $(info Executando Bot com Webchat.)
63 | $(info )
64 | docker-compose run -d --rm --service-ports bot-webchat
65 | $(info )
66 | $(info Caso o FIREFOX não seja iniciado automáticamente, abra o seguinte arquivo com seu navegador:)
67 | $(info modules/webchat/index.html)
68 | $(info )
69 | firefox modules/webchat/index.html
70 |
71 | run-telegram:
72 | docker-compose run -d --rm --service-ports bot_telegram make telegram
73 |
74 | run-notebooks:
75 | docker-compose up -d notebooks
76 | $(info )
77 | $(info Acesse o KIBANA em: http://localhost:8888)
78 | $(info )
79 |
80 | train:
81 | mkdir -p bot/models
82 | docker-compose up --build coach
83 |
84 | ############################## TESTS ##############################
85 | test:
86 | docker-compose run --rm bot make test
87 |
88 | run-test-nlu:
89 | docker-compose run --rm bot make test-nlu
90 |
91 | run-test-core:
92 | docker-compose run --rm bot make test-core
93 |
94 | validate:
95 | docker-compose run --rm bot rasa data validate --domain domain.yml --data data/ -vv
96 |
97 | visualize:
98 | docker-compose run --rm -v $(current_dir)/bot:/coach coach rasa visualize --domain domain.yml --stories data/stories.md --config config.yml --nlu data/nlu.md --out ./graph.html -vv
99 | $(info )
100 | $(info Caso o FIREFOX não seja iniciado automáticamente, abra o seguinte arquivo com seu navegador:)
101 | $(info bot/graph.html)
102 | firefox bot/graph.html
103 |
--------------------------------------------------------------------------------
/docs/setup_analytics.md:
--------------------------------------------------------------------------------
1 | ## Configuração da stack de analytics
2 | Este documento tem por objetivo detalhar o processo de configuração da *stack* de *analytics* utilizada no boilerplate.
3 |
4 | Aqui os passos de configuração são descritos separadamente, para facilitar o entendimento e a adaptação. Caso você já tenha executado os comandos `make build-analytics`, `make config-elastic` e `make config-kibana`, não é necessário executar os passos abaixo, e o *analytics* já deve estar funcionando para o seu *bot*.
5 |
6 | #### RabbitMQ
7 |
8 | ###### Configuração do *server* e dos *consumers*
9 | Em primeiro lugar para fazer o setup do analytics é necessário subir o RabbitMQ e definir suas configurações.
10 |
11 | Inicie o serviço do servidor do RabbitMQ:
12 |
13 | ```sh
14 | sudo docker-compose up -d rabbitmq
15 | ```
16 |
17 | Inicie o serviço do consumidor do RabbitMQ, que ficará responsável por enviar as mensagens para o ElasticSearch:
18 |
19 | ```sh
20 | sudo docker-compose up -d rabbitmq-consumer
21 | ```
22 |
23 | Lembre-se de configurar as credenciais de acesso do *server* e dos *consumers* do `rabbitmq`, nos arquivos `env/rabbitmq.env` e `env/rabbitmq-consumer.env`. Estas credenciais devem ser as mesmas, para que estes serviços consigam se integrar corretamente:
24 |
25 | ```sh
26 | RABBITMQ_DEFAULT_USER=admin
27 | RABBITMQ_DEFAULT_PASS=admin
28 | ```
29 |
30 | ###### Integração com Rasa
31 |
32 | Cada mensagem trocada com o *bot* será enviada à uma fila no servidor do *RabbitMQ*, para isso, é precisso integrar esses dois serviços.
33 | Isso é feito definindo as configurações de *broker* do Rasa no arquivo `bot/endpoints.yml`:
34 |
35 | ```yml
36 | event_broker:
37 | type: pika
38 | url: rabbitmq
39 | username: admin
40 | password: admin
41 | queues:
42 | - bot_messages
43 | ```
44 |
45 | #### Configuração ElasticSearch
46 |
47 | O ElasticSearch é o serviço responsável por armazenar os dados provenientes da interação entre o usuário e o chatbot.
48 |
49 | As mensagens são inseridas no índice do ElasticSearch utilizando o *broker* RabbitMQ.
50 |
51 | Para subir o ambiente do ElasticSearch rode os seguintes comandos:
52 |
53 | ```
54 | sudo docker-compose up -d elasticsearch
55 | sudo docker-compose run --rm -v $(pwd)/modules/analytics:/analytics bot python /analytics/setup_elastic.py
56 | ```
57 |
58 | Lembre-se de setar as seguintes variaveis de ambiente no `docker-compose`.
59 |
60 | ```
61 | ENVIRONMENT_NAME=localhost
62 | BOT_VERSION=last-commit-hash
63 | ```
64 |
65 | #### Configuração Kibana (Visualização)
66 |
67 | Para a análise dos dados das conversas com o usuário, utilize o kibana, e veja como os usuários estão interagindo com o bot, os principais assuntos, média de usuários e outras informações da análise de dados.
68 |
69 | O Kibana nos auxilia com uma interface para criação de visualização para os dados armazenados nos índices do ElasticSearch.
70 |
71 | ```sh
72 | sudo docker-compose up -d kibana
73 | ```
74 |
75 | **Atenção:** Caso queira configurar permissões diferentes de usuários (Login) no ElasticSearch/Kibana, siga esse tutorial ([link](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master/docs/setup_user_elasticsearch.md)).
76 |
77 | ###### Importação de dashboards
78 |
79 | Caso queira subir com os dashboards que criamos para fazer o monitoramento de bots:
80 |
81 | ```
82 | sudo docker-compose run --rm -v $(pwd)/modules/analytics/:/analytics/ kibana python3 /analytics/import_dashboards.py
83 | ```
84 |
85 | Você pode acessar o kibana na url `localhost:5601`
86 |
--------------------------------------------------------------------------------
/bot/actions/forms.py:
--------------------------------------------------------------------------------
1 | # This files contains your custom actions which can be used to run
2 | # custom Python code.
3 | #
4 | # See this guide on how to implement these action:
5 | # https://rasa.com/docs/rasa/core/actions/#custom-actions/
6 |
7 | from typing import Any, Text, Dict, List, Union
8 | import re
9 |
10 | from rasa_sdk import Action, Tracker
11 | from rasa_sdk.executor import CollectingDispatcher
12 | from rasa_sdk.events import SlotSet
13 | from rasa_sdk.forms import FormAction
14 |
15 | from .data_validator import isCpfValid
16 |
17 |
18 | class LoginForm(FormAction):
19 | """Form used to handle login information"""
20 |
21 | def name(self) -> Text:
22 | """Unique identifier of the form"""
23 | return "login_form"
24 |
25 | @staticmethod
26 | def required_slots(tracker: Tracker) -> List[Text]:
27 | """A list of required slots that will be needed to login"""
28 | return ["cpf", "data_nascimento"]
29 |
30 | def slot_mappings(self) -> Dict[Text, Union[Dict, List[Dict]]]:
31 | """A dictionary to map required slots to
32 | - an extracted entity
33 | - intent: value pairs
34 | - a whole message
35 | or a list of them, where a first match will be picked"""
36 | return {
37 | "cpf": self.from_text(not_intent="cancelar"),
38 | "data_nascimento": self.from_text(not_intent="cancelar"),
39 | }
40 |
41 | def submit(
42 | self,
43 | dispatcher: CollectingDispatcher,
44 | tracker: Tracker,
45 | domain: Dict[Text, Any],
46 | ) -> List[Dict]:
47 | """Define what the login form will do after
48 | all required slots are filled"""
49 |
50 | cpf = tracker.get_slot("cpf")
51 | data_nascimento = tracker.get_slot("data_nascimento")
52 | dispatcher.utter_message(
53 | "Então seu CPF é: {} e sua data de nascimento é: {}?".format(
54 | cpf, data_nascimento
55 | )
56 | )
57 | return []
58 |
59 | def validate_cpf(
60 | self,
61 | value: Text,
62 | dispatcher: CollectingDispatcher,
63 | tracker: Tracker,
64 | domain: Dict[Text, Any],
65 | ) -> Dict[Text, Any]:
66 | """Validate cpf value."""
67 |
68 | regex = re.compile("[0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2}$")
69 | if re.match(regex, value) is None:
70 | dispatcher.utter_template("utter_errado_cpf_formato", tracker)
71 | return {"cpf": None}
72 | elif not isCpfValid(value):
73 | dispatcher.utter_template("utter_errado_cpf_invalido", tracker)
74 | return {"cpf": None}
75 | else:
76 | return {"cpf": value}
77 |
78 | def validate_data_nascimento(
79 | self,
80 | value: Text,
81 | dispatcher: CollectingDispatcher,
82 | tracker: Tracker,
83 | domain: Dict[Text, Any],
84 | ) -> Dict[Text, Any]:
85 | """Validate data_nascimento value."""
86 |
87 | regex = re.compile(
88 | "(([0-2][0-9]|(3)[0-1])(\/)(((0)[0-9])|((1)[0-2]))(\/)\d{4})"
89 | )
90 | if re.match(regex, value) is not None:
91 | return {"data_nascimento": value}
92 | else:
93 | dispatcher.utter_template("utter_errado_data_nascimento", tracker)
94 | # validation failed, set this slot to None, meaning the
95 | # user will be asked for the slot again
96 | return {"data_nascimento": None}
97 |
98 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### Rasa ###
2 | bot/models
3 | bot/results*
4 |
5 | ### Rasa X ###
6 | events.db
7 | events.db-shm
8 | events.db-wal
9 | rasa.db
10 | *.db*
11 |
12 | ### Rasa visualize ###
13 | graph.html
14 |
15 | ### Rasa evaluation ###
16 | .ipynb_checkpoints/
17 | modules/notebooks/intents/models/
18 | modules/notebooks/intents/results/
19 | modules/notebooks/stories/models/
20 | modules/notebooks/stories/results/
21 | bot/.ipython/
22 | bot/.keras/
23 | bot/.local/
24 | bot/results/
25 |
26 | ### database ###
27 | db/
28 |
29 | ### PyCharm ###
30 | .idea/
31 |
32 | # Created by https://www.gitignore.io/api/vim,linux,macos,python
33 | ### Linux ###
34 | *~
35 |
36 | # temporary files which can be created if a process still has a handle open of a deleted file
37 | .fuse_hidden*
38 |
39 | # KDE directory preferences
40 | .directory
41 |
42 | # Linux trash folder which might appear on any partition or disk
43 | .Trash-*
44 |
45 | # .nfs files are created when an open file is removed but is still being accessed
46 | .nfs*
47 |
48 | ### macOS ###
49 | *.DS_Store
50 | .AppleDouble
51 | .LSOverride
52 |
53 | # Icon must end with two \r
54 | Icon
55 |
56 | # Thumbnails
57 | ._*
58 |
59 | # Files that might appear in the root of a volume
60 | .DocumentRevisions-V100
61 | .fseventsd
62 | .Spotlight-V100
63 | .TemporaryItems
64 | .Trashes
65 | .VolumeIcon.icns
66 | .com.apple.timemachine.donotpresent
67 |
68 | # Directories potentially created on remote AFP share
69 | .AppleDB
70 | .AppleDesktop
71 | Network Trash Folder
72 | Temporary Items
73 | .apdisk
74 |
75 | ### Python ###
76 | # Byte-compiled / optimized / DLL files
77 | __pycache__/
78 | *.py[cod]
79 | *$py.class
80 |
81 | # C extensions
82 | *.so
83 |
84 | # Distribution / packaging
85 | .Python
86 | build/
87 | develop-eggs/
88 | dist/
89 | downloads/
90 | eggs/
91 | .eggs/
92 | lib/
93 | lib64/
94 | parts/
95 | sdist/
96 | var/
97 | wheels/
98 | *.egg-info/
99 | .installed.cfg
100 | *.egg
101 |
102 | # PyInstaller
103 | # Usually these files are written by a python script from a template
104 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
105 | *.manifest
106 | *.spec
107 |
108 | # Installer logs
109 | pip-log.txt
110 | pip-delete-this-directory.txt
111 |
112 | # Unit test / coverage reports
113 | htmlcov/
114 | .tox/
115 | .coverage
116 | .coverage.*
117 | .cache
118 | .pytest_cache/
119 | nosetests.xml
120 | coverage.xml
121 | *.cover
122 | .hypothesis/
123 |
124 | # Translations
125 | *.mo
126 | *.pot
127 |
128 | # Flask stuff:
129 | instance/
130 | .webassets-cache
131 |
132 | # Scrapy stuff:
133 | .scrapy
134 |
135 | # Sphinx documentation
136 | docs/_build/
137 |
138 | # PyBuilder
139 | target/
140 |
141 | # Jupyter Notebook
142 | *.ipynb_checkpoints*
143 |
144 | # pyenv
145 | .python-version
146 |
147 | # celery beat schedule file
148 | celerybeat-schedule.*
149 |
150 | # SageMath parsed files
151 | *.sage.py
152 |
153 | # Environments
154 | .env
155 | .venv
156 | venv/
157 | ENV/
158 | env.bak/
159 | venv.bak/
160 |
161 | # Spyder project settings
162 | .spyderproject
163 | .spyproject
164 |
165 | # Rope project settings
166 | .ropeproject
167 |
168 | # mkdocs documentation
169 | /site
170 |
171 | # mypy
172 | .mypy_cache/
173 |
174 | ### Vim ###
175 | # swap
176 | .sw[a-p]
177 | .*.sw[a-p]
178 | # session
179 | Session.vim
180 | # temporary
181 | .netrwhist
182 | # auto-generated tag files
183 | tags
184 |
185 | # End of https://www.gitignore.io/api/vim,linux,macos,python
186 |
--------------------------------------------------------------------------------
/bot/actions/actions.py:
--------------------------------------------------------------------------------
1 | # Este arquivo contém custom actions que utilizão código python
2 | # para executar ações no diálogo.
3 | #
4 | # Veja o guia na documentação do RASA em:
5 | # https://rasa.com/docs/rasa/core/actions/#custom-actions/
6 |
7 |
8 | from typing import Any, Text, Dict, List
9 |
10 | from rasa_sdk import Action, Tracker
11 | from rasa_sdk.executor import CollectingDispatcher
12 | from rasa_sdk.events import SlotSet
13 |
14 | import requests
15 |
16 | from random import randint
17 |
18 | class ActionTeste(Action):
19 | def name(self) -> Text:
20 | return "action_teste"
21 |
22 | def run(
23 | self,
24 | dispatcher: CollectingDispatcher,
25 | tracker: Tracker,
26 | domain: Dict[Text, Any],
27 | ) -> List[Dict[Text, Any]]:
28 | try:
29 | dispatcher.utter_message("Mensagem enviada por uma custom action.")
30 | except ValueError:
31 | dispatcher.utter_message(ValueError)
32 | return []
33 |
34 |
35 | class ActionTelefone(Action):
36 | def name(self) -> Text:
37 | return "action_telefone"
38 |
39 | def run(
40 | self,
41 | dispatcher: CollectingDispatcher,
42 | tracker: Tracker,
43 | domain: Dict[Text, Any],
44 | ) -> List[Dict[Text, Any]]:
45 |
46 | telefone = tracker.get_slot('telefone')
47 |
48 | try:
49 | dispatcher.utter_message("O seu telefone é {}?".format(telefone))
50 | except ValueError:
51 | dispatcher.utter_message(ValueError)
52 | return [SlotSet("telefone", telefone)]
53 |
54 |
55 | class ActionAdvices(Action):
56 | def name(self) -> Text:
57 | return "action_pedir_conselho"
58 |
59 | def run(self, dispatcher, tracker, domain):
60 |
61 | nome = tracker.get_slot('nome')
62 |
63 | req = requests.request('GET', "https://api.adviceslip.com/advice")
64 | conselho = req.json()["slip"]["advice"]
65 |
66 | try:
67 | if nome:
68 | dispatcher.utter_message("{} olha que conselho legal: {}".format(nome, conselho))
69 | else:
70 | dispatcher.utter_message("Olha que conselho legal: {}".format(conselho))
71 | except ValueError:
72 | dispatcher.utter_message(ValueError)
73 |
74 | class ActionSortingHat(Action):
75 | def name(self) -> Text:
76 | return "action_sorting_hat"
77 |
78 | def run(self, dispatcher, tracker, domain):
79 |
80 | nome = tracker.get_slot('nome')
81 |
82 | req = requests.get("https://www.potterapi.com/v1/sortingHat")
83 | casa = req.json()
84 |
85 | try:
86 | if nome:
87 | dispatcher.utter_message("{} Sua casa de Hogwarts é: {}".format(nome, casa))
88 | else:
89 | dispatcher.utter_message("Sua casa de Hogwarts: {}".format(casa))
90 | except ValueError:
91 | dispatcher.utter_message(ValueError)
92 |
93 | class ActionCatFacts(Action):
94 | def name(self) -> Text:
95 | return "action_cat_facts"
96 |
97 | def run(self, dispatcher, tracker, domain):
98 | if tracker.get_slot("fatos_sobre_gatos") == None:
99 | req = requests.request('GET', "https://cat-fact.herokuapp.com/facts")
100 | lista = []
101 | for n in range(20):
102 | lista.append(req.json()["all"][n]["text"])
103 |
104 | fato = lista[randint(0, 19)]
105 |
106 | try:
107 | dispatcher.utter_message("{}".format(fato))
108 | except ValueError:
109 | dispatcher.utter_message(ValueError)
110 | return [SlotSet("fatos_sobre_gatos", lista)]
111 | else:
112 | fato = tracker.get_slot("fatos_sobre_gatos")[randint(0, 19)]
113 | try:
114 | dispatcher.utter_message("{}".format(fato))
115 | except ValueError:
116 | dispatcher.utter_message(ValueError)
117 | return []
118 |
119 |
--------------------------------------------------------------------------------
/modules/rabbitmq/consumer/elastic_connector.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import time
4 | import datetime
5 | import hashlib
6 | import json
7 |
8 | from elasticsearch import Elasticsearch
9 |
10 | try:
11 | from nltk.corpus import stopwords
12 | except Exception:
13 | import nltk
14 |
15 | nltk.download("stopwords")
16 | from nltk.corpus import stopwords
17 |
18 | pass
19 |
20 | logger = logging.getLogger(__name__)
21 |
22 | ENVIRONMENT_NAME = os.getenv("ENVIRONMENT_NAME", "locahost")
23 | BOT_VERSION = os.getenv("BOT_VERSION", "notdefined")
24 | HASH_GEN = hashlib.md5()
25 |
26 |
27 | def gen_id(timestamp):
28 | HASH_GEN.update(str(timestamp).encode("utf-8"))
29 | _id = HASH_GEN.hexdigest()[10:]
30 | return _id
31 |
32 |
33 | def get_timestamp():
34 | ts = time.time()
35 | timestamp = datetime.datetime.strftime(
36 | datetime.datetime.fromtimestamp(ts), "%Y/%m/%d %H:%M:%S"
37 | )
38 | return timestamp
39 |
40 |
41 | class ElasticConnector:
42 | def __init__(self, domain, user=None, password=None, scheme="http", scheme_port=80):
43 | if user is None:
44 | self.es = Elasticsearch([domain])
45 | else:
46 | self.es = Elasticsearch(
47 | ["{}://{}:{}@{}:{}".format(scheme, user, password, domain, scheme_port)]
48 | )
49 |
50 | self.previous_action = None
51 | self.previous_user_message = None
52 |
53 | def insert_on_elastic(self, ts, message):
54 | try:
55 | self.es.index(
56 | index="messages",
57 | doc_type="message",
58 | id="{}_user_{}".format(ENVIRONMENT_NAME, gen_id(ts)),
59 | body=json.dumps(message),
60 | )
61 | except Exception as ex:
62 | logger.error("Could not send message to Elastic Search")
63 | logger.error(str(ex))
64 |
65 | def save_user_message(self, user_message):
66 | if not user_message["text"]:
67 | return
68 |
69 | ts = time.time()
70 | timestamp = datetime.datetime.strftime(
71 | datetime.datetime.fromtimestamp(ts), "%Y/%m/%d %H:%M:%S"
72 | )
73 |
74 | # Bag of words
75 | tags = []
76 | for word in (
77 | user_message["text"]
78 | .replace(". ", " ")
79 | .replace(",", " ")
80 | .replace('"', "")
81 | .replace("'", "")
82 | .replace("*", "")
83 | .replace("(", "")
84 | .replace(")", "")
85 | .split(" ")
86 | ):
87 | if word.lower() not in stopwords.words("portuguese") and len(word) > 1:
88 | tags.append(word)
89 |
90 | message = {
91 | "environment": ENVIRONMENT_NAME,
92 | "version": BOT_VERSION,
93 | "user_id": user_message["sender_id"],
94 | "is_bot": False,
95 | "timestamp": timestamp,
96 | "text": user_message["text"],
97 | "tags": tags,
98 | "entities": user_message["parse_data"]["entities"],
99 | "intent_name": user_message["parse_data"]["intent"]["name"],
100 | "intent_confidence": (user_message["parse_data"]["intent"]["confidence"]),
101 | "utter_name": "",
102 | "is_fallback": False,
103 | }
104 |
105 | self.insert_on_elastic(ts, message)
106 |
107 | def save_bot_message(self, bot_message, action_message, user_message):
108 | ts = time.time()
109 | timestamp = datetime.datetime.strftime(
110 | datetime.datetime.fromtimestamp(ts), "%Y/%m/%d %H:%M:%S"
111 | )
112 |
113 | message = {
114 | "environment": ENVIRONMENT_NAME,
115 | "version": BOT_VERSION,
116 | "user_id": user_message["sender_id"],
117 | "is_bot": True,
118 | "text": user_message["text"],
119 | "tags": [],
120 | "timestamp": timestamp,
121 | "entities": [],
122 | "intent_name": user_message["parse_data"]["intent"]["name"],
123 | "intent_confidence": "",
124 | "utter_name": action_message["name"],
125 | "is_fallback": action_message["name"] == "action_default_fallback",
126 | }
127 |
128 | self.insert_on_elastic(ts, message)
129 |
--------------------------------------------------------------------------------
/modules/webchat/assets/launcher_button.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/docs/Tutoriais/tutorial-como-fazer-uma-utter.md:
--------------------------------------------------------------------------------
1 | # Criação de Utter
2 |
3 | **Formato** - A Utter (textos que o Bot envia) não devem ser muito grande, pense em uma postagem do Twitter.
4 |
5 | **Conteúdo** - Deve seguir um Roteiro como se fosse uma conversa natural entre duas pessoas, sendo assim, as perguntas feitas pelo seu Bot devem ter um significado dentro dos objetivos e missões dele.
6 |
7 | **Personalidade** - Por fim, para que a conversa seja interessante e cativante você deve criar uma personalidade para o seu Chatbot que vai aparecer através do modo como ele se comunica, assim como uma pessoa ele deve ter características e comportamentos únicos que aparecem no modo como ele fala e interage com o interlocutor, seja por meio de emojis, ou pela escolha de palavras que usa, você pode ver exemplos disso nas recomendações.
8 |
9 | ## COMO COLOCAR A PERSONALIDADE DA TAIS NAS UTTERS
10 |
11 | A Tais usa norma padrão com um toque de oralidade, ela não conversa de um jeito muito formal, não usa jargões do direito, exceto quando manda algum artigo da Lei Rouanet. Ela gosta muito de usar palavras que enfatizam uma conversa falada:
12 |
13 | “aí” (“E aí, por onde vamos começar?”)
14 |
15 | “daí” (“daí você me manda outra!”)
16 |
17 | “que tal” (“Que tal falar de outra forma?”)
18 |
19 | “Hummmm…” (“Hummmm... Não sei se entendi.”)
20 |
21 | “olha”, (“Olha, alguns familiares não podem incentivar projetos”)
22 |
23 | Ela também usa emojis para demonstrar expressar simpatia: “Para lembrar dos assuntos que eu domino, é só digitar: #MEAJUDA :)”
24 |
25 | Para deixar sua utter mais fácil de ler, use conjunções para ligar os elementos da frase, mas lembre-se que a Tais não é muito formal então nunca use um “destarte” opte pelo mais simples como “logo”. Vou colocar alguns exemplos de conjunções/conectivos que você pode usar, não se esqueça de que você pode usar outros que não estão nessa lista e não tenham um tom tão formal: e, nem, mas também, assim, dessa forma, além disso, assim como, mas, porém, se bem que, se não, ou, já, talvez, da mesma maneira, tal como, da mesma forma, segundo, de acordo com, se, caso, quanto mais, quanto menos, porque, pois, para que, provavelmente, realmente, sem dúvida, com certeza, isto é, ou seja, em primeiro lugar, para começar, então, ainda, na medida em que, já que, por isso.
26 |
27 | ## ROTEIRO:
28 |
29 | 1 - Primeiro você precisa analisar o tema da utter, deste modo, leia o texto que a Secretaria Especial da Cultura enviou como resposta para a pergunta do usuário;
30 |
31 | 2 - É importante observar quais são as informações mais importantes. Se o texto for muito grande e abarcar muitos temas, você pode quebrá-lo em várias utters desde que encontre uma lógica para que as utters se liguem e o usuário possa ser guiado até elas através da conversa;
32 |
33 | 3 - Retire o essencial, desde que esse essencial consiga sanar a dúvida do usuário. Seja simples, às vezes menos é mais! Uma utter pode responder várias dúvidas ou apenas uma, isso vai depender de como você vai conseguir encaixar todos esses assuntos e se é mais viável criar novas utters ou colocar tudo em uma;
34 |
35 | 4 - Agora, você tem que pensar em quais dúvidas as expressões usadas ali podem causar nos usuários, depois disso, escreva a resposta com as suas palavras, implementando a personalidade da Tais no seu texto;
36 |
37 | 5 - O texto deve ser fluído, coerente e fácil de ler. Deve ser o menor possível, deve ser claro e objetivo, vá direto ao ponto!
38 |
39 | ## RECOMENDAÇÕES:
40 |
41 | **Polida** - “Obrigada por conversar comigo!”
42 | A Tais é muito educada, mas não exagere demais para não parecer uma conversa forçada. Seja simples, agradeça, use “por favor”, mas sem extrapolar na polidez.
43 |
44 | **Dedicada** - “quero te ajudar”
45 | A Tais precisa demonstrar ao usuário que está engajada em sua missão, ela demonstra sua dedicação quando oferece ajuda e se mostra sempre disponível.
46 |
47 | **Paciente** - “você pode escrever de novo de outra forma?”
48 | Ela está sempre disposta a tentar de novo, então se ela errou ou não sabe explicar, vai continuar pedindo para o usuário perguntar novamente de outro modo.
49 |
50 | **Gentil** - “espero estar te ajudando”
51 | A gentileza da Assistente Virtual da Secretaria Especial da Cultura é muito mais sutil e harmoniosa: “Foi um prazer te ajudar! Sempre que tiver alguma dúvida, volte aqui!”
52 |
53 | **Passiva** - “Que tal falar de outra forma?”
54 | Quando a Tais é afrontada e o usuário usa um palavrão, o melhor caminho será sempre a passividade: “Hummm… Não gostei muito dessa expressão que você usou. Que tal falar de outra forma?”.
55 |
56 | **Não dá espaço para intimidade** - “Oi, sou assistente virtual da Secretaria Especial da Cultura”
57 | Ela é muito atenciosa, mas é muito reservada. Então, nada de “Oi, bebê!”.
58 |
59 | Caso você queira entender como implementar a personalidade da Tais de forma mais profunda, leia o Guia de Conversação completo, acessando aqui:
60 | https://lappis-unb.github.io/tais/guia-de-conversacao-da-tais/
61 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 |
3 | services:
4 | # =============================== Coach =================================
5 | # All the models are trained by this coach.
6 | coach:
7 | build:
8 | context: .
9 | dockerfile: ./docker/bot.Dockerfile
10 | volumes:
11 | - ./bot/models/:/bot/models/
12 | command: "make train"
13 |
14 |
15 | # ================================= Bot =====================================
16 | # Generic Rasa bot, used to run console for example.
17 | bot:
18 | build:
19 | context: .
20 | dockerfile: ./docker/bot.Dockerfile
21 | restart: unless-stopped
22 | volumes:
23 | - ./bot/:/bot/
24 | ports:
25 | - 5004:5004
26 | depends_on:
27 | - actions
28 |
29 | # ================================= RASA X ==================================
30 | # Rasa X container
31 | x:
32 | build:
33 | context: .
34 | dockerfile: ./docker/bot.Dockerfile
35 | restart: unless-stopped
36 | volumes:
37 | - ./bot/:/bot/
38 | ports:
39 | - 5002:5002
40 | depends_on:
41 | - actions
42 | command: sh -c "make x"
43 |
44 | # ================================= Actions =================================
45 | # Rasa middleware used to connect with external APIs.
46 | actions:
47 | build:
48 | context: .
49 | dockerfile: ./docker/actions.Dockerfile
50 | ports:
51 | - 5055:5055
52 | volumes:
53 | - ./bot/actions:/bot/actions
54 | command: sh -c "make actions"
55 |
56 | # ============================ WebChat Bot =================================
57 | # Specific Rasa bot integrated with WebChat.
58 | bot-webchat:
59 | build:
60 | context: .
61 | dockerfile: ./docker/bot.Dockerfile
62 | volumes:
63 | - ./bot/:/bot/
64 | ports:
65 | - 5005:5005
66 | depends_on:
67 | - actions
68 | command: sh -c "make webchat"
69 |
70 | # =============================== Analytics =================================
71 | # Analitics ElasticSearch Stack.
72 | elasticsearch:
73 | build:
74 | context: .
75 | dockerfile: ./docker/elasticsearch.Dockerfile
76 | restart: unless-stopped
77 | ports:
78 | - 9200:9200
79 | - 9300:9300
80 | env_file:
81 | - env/elasticsearch.env
82 | volumes:
83 | - esbackup:/usr/share/elasticsearch/backup
84 | - ./modules/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
85 | - esdata:/usr/share/elasticsearch/data
86 |
87 | # Visualization layer of Analitics Stack.
88 | kibana:
89 | build:
90 | context: .
91 | dockerfile: ./docker/kibana.Dockerfile
92 | restart: unless-stopped
93 | ports:
94 | - 5601:5601
95 | env_file:
96 | - env/kibana.env
97 | depends_on:
98 | - elasticsearch
99 | volumes:
100 | - ./modules/analytics:/usr/share/kibana/analytics
101 |
102 | # =============================== Broker ====================================
103 | # Custom broker to store Rasa tracker data.
104 | rabbitmq:
105 | image: rabbitmq:3-management
106 | restart: unless-stopped
107 | volumes:
108 | - ./db/rabbitmq:/var/lib/rabbitmq/mnesia
109 | ports:
110 | - 15672:15672
111 | env_file:
112 | - env/rabbitmq.env
113 |
114 | # Custom broker consumer responsible to store data into ElasticSearch.
115 | rabbitmq-consumer:
116 | build:
117 | context: .
118 | dockerfile: ./docker/consumer.Dockerfile
119 | restart: unless-stopped
120 | volumes:
121 | - ./modules/rabbitmq/consumer/:/opt/scripts/
122 | depends_on:
123 | - rabbitmq
124 | env_file:
125 | - env/rabbitmq-consumer.env
126 | command: python3 /opt/scripts/consume_bot_messages.py
127 |
128 | # ============================ Telegram Bot =================================
129 | # Specific Rasa bot integrated with Telegram.
130 | bot_telegram:
131 | build:
132 | context: .
133 | dockerfile: ./docker/bot.Dockerfile
134 | volumes:
135 | - ./bot/:/bot/
136 | env_file:
137 | - env/bot-telegram.env
138 | ports:
139 | - 5001:5001
140 | depends_on:
141 | - actions
142 | command: sh -c "make telegram"
143 |
144 | # =============================== Notebooks =================================
145 | # Rasa lab to enhance hyperparameters.
146 | notebooks:
147 | build:
148 | context: .
149 | dockerfile: ./docker/notebooks.Dockerfile
150 | env_file:
151 | - env/notebooks.env
152 | volumes:
153 | - ./modules/notebooks:/work/notebooks
154 | - ./bot/:/bot/
155 | ports:
156 | - 8888:8888
157 |
158 | volumes:
159 | notebook_models:
160 | mongo_data:
161 | rabbit_data:
162 | esbackup:
163 | esdata:
164 | driver: local
165 |
--------------------------------------------------------------------------------
/docs/pipeline-de-qualidade.md:
--------------------------------------------------------------------------------
1 | # Qualidade do bot
2 |
3 | Além do grande desafio de como gerenciar o conteúdo de maneira viável e organizada, existe o desafio de como crescer o domínio do bot com qualidade. À medida que a base de treinamento do bot muda, muitas vezes é necessário também atualizar os parâmetros de treinamento da rede para garantir que a acurácia do *bot* se mantenha.
4 |
5 | Aliado à isso, no contexto colaborativo de uma equipe com diversas pessoas evoluindo o bot simultaneamente, é preciso alinhar a visão dos membros do time em relação aos parâmetros de qualidade.
6 |
7 | ## Qualidade em ChatBots Rasa
8 |
9 | Se Tratando de Chatbots desenvolvidos com Rasa, os parâmetros de qualidade estão relacionados principalmente à dois aspectos:
10 |
11 | **Identificação de intenções:** Qual o desempenho do *bot* em classificar um texto em uma categoria que define a sua intenção;
12 |
13 | **Desempenho em fluxos de conversa:** O quão bem o *bot* consegue se comportar de acordo com as intenções classificadas e responder corretamente o usuário de acordo com o histórico das interações e a base de treinamento;
14 |
15 | Também há a preocupação em relação à usabilidade do *bot*, uma vez que caso o *bot* tenha uma Experiência de Usuário ruim, ele poderá ter um péssimo desempenho e se comportar de forma inesperada, mesmo com uma boa base de treinamentos e uma rede muito bem configurada. A melhoria desta experiência está relacionada há fatores como desenvolvimento de personalidade, construção de roteiros de conversa, adequação da linguagem do bot ao público-alvo, etc. Porém, aferir de forma automatizada a qualidade desses parâmetros ainda é uma tarefa inviável, sendo assim a qualidade dessas métricas exige uma análise direta e profunda por parte da equipe.
16 |
17 | ## Abordagem de aferição da qualidade
18 |
19 | Tendo em consideração os parâmetros anteriores, a construção desta abordagem é baseada no objetivo de garantir de forma automatizada a acurácia do ChatBot em relação à detecção de intenções e o desempenho nos fluxos de conversas.
20 |
21 | **Estágio 1:** O primeiro estágio consiste em garantir a consistência de sintaxe dos arquivos de treinamento do *bot*. O Rasa utiliza um formato de configuração que depende de um arquivo principal chamado `domain`, onde devem estar definidas todas as *intents* e *utters* definidas e utilizadas. Caso haja alguma inconsistência entre essas informações o desempenho do *bot* poderá ser afetado, uma vez que parâmetros importantes podem não ser corretamente utilizados durante o processo de treinamento e predição do *bot*.
22 |
23 | Objetivo: O foco deste estágio é sanar possíveis erros de digitação, inconsistências durante *merges* e definições incorretas de *intents* e *utters* nos arquivos de configuração.
24 |
25 | Solução proposta: Dentro da TAIS é utilizado um [script de validação](https://github.com/lappis-unb/tais/blob/master/coach/validator.py) automatizada desses parâmetros, que analiza os arquivos de configuração do Rasa e o *dataset* para garantir que não hajam inconsistências.
26 |
27 | **Estágio 2:** O segundo estágio consiste na validação do comportamento do *bot* durante as interações e a execução dos fluxos de conversa.
28 |
29 | O Rasa já oferece um [recurso de validação dos fluxos de conversação](https://rasa.com/docs/core/evaluation/). Através desse *evaluation* é possível testar o comportamento do *bot* dentro do contexto de uma conversa, e entender se ele está fazendo uma predição correta das ações a serem tomadas de acordo com cada intenção identificada. Além disso, esse mecanismo facilita o teste da capacidade de generalização do *bot*.
30 |
31 | Objetivo: O objetivo deste estágio é garantir que o *bot* está se comportando da forma esperada para determinados fluxos de conversa.
32 |
33 | Solução proposta: Pode-se utilizar a funcionalidade de [evaluation](https://rasa.com/docs/core/evaluation/) do Rasa para testar diretamente o funcionamento de um fluxo de conversa.
34 |
35 | Dentro da TAIS foi adicionada mais uma camada de testes com um [script para melhoria da visualização dos testes](https://github.com/lappis-unb/tais/blob/master/bot/test_stories.py). Onde é possível ver no *console* quais são as *intents* e *utters* que falharam. Isso permite que a equipe de desenvolvimento possa identificar diretamente os pontos onde a acurácia do *bot* não está tão boa ou o comportamento não está sendo o esperado.
36 |
37 | 
38 |
39 | Ao fim desse *script* é exibido um log das histórias que falharam dentro de cada um dos arquivos.
40 |
41 | 
42 |
43 | ## Utilização do Pipeline
44 |
45 | Pode-se configurar tasks para a execução destes *scripts* dentro de cada contexto.
46 | Uma das alternativas, que é utilizada dentro da TAIS, é utilizar um serviço de CI para validação automatizada destes passos simultaneamente ao processo de contribuição no repositório.
47 | Na TAIS foram configuradas duas *tasks* simples utilizando um `Makefile`. A primeira *task* executa a validação dos arquivos de configuração do *bot* e recebe como parâmetro o path para o arquivo `domain`, e os diretórios onde estão as `intents` e `stories`. A segunda *task* executa o `evaluation` nos fluxos de teste que estão dentro do diretório `e2e`.
48 |
49 | ```makefile
50 | run-validator:
51 | python3 validator.py --intents data/intents/ --stories data/stories --domain domain.yml
52 |
53 | test-stories:
54 | python3 test_stories.py --stories e2e/ --e2e
55 | ```
56 |
57 | Após isso foram definidas duas *tasks* simples para validação dos parâmetros definidos. Estes estágios são validados no CI a cada *commit*, mas podem ser configurado segundo regras específicas, por exemplo serem executados apenas em determinadas *branches* do repositório.
58 |
59 | ```yml
60 | run dataset validator:
61 | stage: validate format
62 | image: lappis/coach:latest
63 | script:
64 | - cd coach/
65 | - make run-validator
66 |
67 | test stories:
68 | stage: test stories
69 | image: lappis/bot:latest
70 | script:
71 | - cd bot/
72 | - make test-stories
73 | ```
74 |
--------------------------------------------------------------------------------
/docs/Tutoriais/tutorial-testes-automatizados.md:
--------------------------------------------------------------------------------
1 | # Criação de Testes Automatizados
2 |
3 | Ao construir um bot com o framework Rasa, deve se ter em mente como funciona a construção do diálogo do ponto de vista do bot, como ele processa todas as informações que são jogadas. O bot agrega uma concepção de um ser que interage e que se mostra "pensante", mas os desenvolvedores devem ter noção de como um bot age, como ele constrói todas suas previsões de diálogo e as usa a seu favor.
4 |
5 | Imagine que começamos a fazer um bot qualquer, com um escopo definido, ao construirmos todas as estruturas necessárias para que ele responda e entenda, na verdade estaremos construindo a sua rede neural, que na parte humana seria a associação que fazemos da resposta a uma pergunta. Dessa forma, a rede neural é baseada na inserção de conteúdo e a ligação do mesmo a interação com o usuário, por exemplo no Boiler-Plate, ao colocarmos cada vez mais assunto, estamos expandindo nosso escopo e deixando nosso bot mais "inteligente". Em suma, as redes neurais são construídas a partir do treinamento do bot, que possibilita-o prever respostas, sintetizando os fluxos possíveis mediante a intenção do usuário.
6 |
7 | No Rasa isso é feito de uma forma muito simples, ao criarmos novas intents e stories, damos abertura ao nosso bot dialogar sobre mais assuntos. Infelizmente temos um grande problema nesse quesito, ao inserirmos mais conteúdo, estamos abrindo espaço para que nosso bot esteja confundindo algum fluxo com outro.
8 |
9 | Para inserirmos mais conteúdo em nosso bot de forma segura, utilizamos os testes automatizados que identifica se o novo conteúdo foi interferido ou interferiu em outro fluxo, acarretando em uma validação de fluxo e trazendo uma evolução muito mais fácil em estrutura e conteúdo.
10 |
11 | Para construirmos os testes devemos primeiro escolher um fluxo no qual queremos tratar, depois estruturar uma conversa para esse fluxo, que nos permite avaliar todo o escopo que escolhemos. Por exemplo, no BoilerPlate temos a intent esporte e queremos ter a certeza que ela sempre estará funcionando. Nesse contexto, podemos gerar um diálogo que condiz com o que queremos:
12 |
13 | ```
14 | Usuário
15 |
16 | - oi (intent cumprimentar)
17 | - qual o seu jogo favorito? (intent esporte)
18 | - tchau (intent despedir)
19 | ```
20 |
21 | Esse é um exemplo bem simples, que conseguimos tirar dele informações que confirma o fluxo que queremos e nos informa se alguma mudança ocorreu.
22 |
23 | Para construirmos o código dos testes, primeiro devemos entender que ao criarmos o fluxo que queremos temos que identificar a utter que corresponde aquela intenção:
24 |
25 | ```
26 | Usuário Bot
27 |
28 | - oi -> utter_cumprimentar
29 | - qual o seu jogo favorito? -> utter_esporte
30 | - tchau -> utter_despedir
31 | ```
32 |
33 | Agora fazer o código fica bem mais fácil:
34 |
35 | ```
36 | ## end-to-end story 1
37 | * cumprimentar: ola
38 | - utter_cumprimentar
39 | * esporte: qual o seu jogo favorito?
40 | - utter_esporte
41 | * despedir: tchau
42 | - utter_despedir
43 | ```
44 |
45 | O código é um arquivo MarkDown composto por um título que indica que estamos trabalhando com arquivos de ponta a ponta, em seguida dizemos a intent e o texto pré estabelecido para o teste, embaixo dizemos a utter que corresponde ao texto.
46 |
47 | Esse código está localizado no coach/data/e2e, nele concentramos todos os arquivos de teste, como boa prática é comum começarmos o nome do arquivo de "e2e".
48 |
49 | ## Executando os arquivos e2e
50 |
51 | Todas as informações de como executar os arquivos de teste está descrito no README do [BoilerPlate](https://github.com/lappis-unb/rasa-ptbr-boilerplate)
52 |
53 | ## Entendendo os resultados
54 |
55 | Sabe-se que o teste do Rasa nos possibilita avaliar o fluxo de ponta a ponta, com as intenções pré definidas pelo mesmo, desta forma, ele nos disponibiliza uma forma de visualização desse teste no qual ele nos fornece:
56 |
57 | "precision" - quantidade de utters_esperadas divididas pela quantidade de utters_ocorridas
58 | "recall" - porcentagem de respostas que corresponderam a utter esperada.
59 | "f1-score" - a porcentagem de relação da precisão com o recall, sendo (2x precisão x recall) / (precisão + recall)
60 | "support" - o tanto de vezes que teste utiliza cada variável.
61 |
62 | Matriz:
63 |
64 | Desses dados gera uma matriz pelo script que permite visualizar a distribuição de confiança para todas as previsões
65 |
66 | Essa matriz nos permite visualizar a relação entre as utters_esperadas (criadas pelos testes) e as utters_ocorridas (as que realmente foram respondidas mediante ao fluxo), priorizando o fluxo em que a conversa segue e a intenções que as correspondem, como pode ser visto no exemplo acima onde todas as utters_esperadas correlacionam com as utters_ocorridas. Forma-se uma matriz quadrada onde sua coluna 0 e linha 0 são respectivamente, a quantidade de utters_esperadas que correlacionaram com as utters ocorridas + as utters_esperadas que não resultaram em nenhum valor e a action_list (o numero de intenções no teste).
67 |
68 | Há apenas uma exceção nesse quesito, quando houver um texto que retorne o fallback, ele criará uma matriz onde a coluna 0 e linha 0 são respectivamente, fallback e NONE. Isso pode ser visto na imagem abaixo no qual o texto retornou um fallback e a relação com a utter_esperada na ultima linha.
69 |
70 | Pode-se dizer que as linhas são a utters_esperadas e as colunas são as utters_ocorridas, e os números são as quantidades de vezes que uma utter corresponde a outra ou deixa de corresponder naquele fluxo da conversa. Quando as utters_esperadas são relacionadas com as corretas utters_ocorridas este número irá ficar na diagonal principal sinalizando a quantidade de vezes de correspondência.
71 |
72 | Na matriz pode-se perceber que existem dois números fora da diagonal principal, eles correspondem a utters que não corresponderam a sua respectiva resposta esperada. No número fora da diagonal na linha 0, conclui-se que é uma ação que ocorreu de algum utter que não foi esperada, já no segundo número fora da diagonal é uma utter esperada que não correspondeu a utter_ocorrida.
--------------------------------------------------------------------------------
/docs/Tutoriais/tutorial-primeira-conversa.md:
--------------------------------------------------------------------------------
1 | # Primeira Conversa
2 |
3 | O Boilerplate vem com a prosposta de facilitar a criação de um chat-bot para diferentes contextos, desenvolvendo uma estrutura um tanto complexa, mas com passos simples para seu bot conseguir dar os primeiros avanços do jeito que desejar.
4 |
5 | As ferramentas utilizadas nessa tutorial foi estudada e utilizada pelo LAPPIS (Laboratório de produção, pesquisa e inovação em software), para criação da Tais, um chat-bot que visa explicar os conceitos e novidades sobre a lei de incentivo à cultura do Brasil. No cume do nosso projeto, foi utilizado o Rasa NLU, uma ferramenta open source para processamento de linguagem natural, sendo focada em classificação de intenções e extração de identidades, e o Rasa Core, uma ferramenta livre para construção de sistemas de conversação.
6 |
7 | Na utilização dessas ferramentas, há a necessidade de ter um arquivo domain.yml que define o contexto em que o bot está inserido. Dentro desse arquivo são especificadas as intenções e ações a serem utilizadas durante a execução do bot.
8 |
9 | A primeira coisa a se fazer é clonar o repositório do BoilerPlate localmente.
10 |
11 | Dentro do diretório `coach/data` há uma pasta chamada `intents`, que contém vários arquivos mark-down, que definem os textos relacionados à cada intenção. E outra pasta chamada `stories`, que contém vários arquivos mark-down, que descrevem os contextos de conversação esperados a partir das intenções.
12 |
13 | Então vamos fazer passo a passo de como criar o seu primeiro chatbot.
14 |
15 | ## Intent
16 |
17 | Se imagine conversando com uma pessoa, vocês estão tentando decidir qual será os sabores de pizza que vocês irão comprar para jantar. A cada frase formulada pelos dois, deve-se observar que tem um intuito naquilo que é falado. Para construção de um bot, tiramos esse conceito e damos o nome de intents, dessa forma conseguimos estruturar muito bem o que o nosso bot irá dizer, definindo o assunto que corresponderá todo o escopo de conversação, ou seja, a partir do que o usuário interage, conseguimos esteriotipar a sua fala, dando uma intenção para aquilo.
18 |
19 | As intents são criadas em um arquivo Mark-Down, onde ele se baseia na estrutura do arquivo para determinar qual tipo de exemplo de frase corresponde a intent. A estrutura para as construções de intents é bem simples, primeiramente precisamos especificar que é uma intent `#intent:`, ao colocar assim estamos dizendo que existe uma nova intent naquele arquivo (Você pode acompanhar acessando um dos arquivos na pasta coach/data/intents). Em frente, você colocará o nome da intent `#intent: nome_intent`, por exemplo:
20 |
21 | ``` MarkDown
22 | #intent: sabores_pizza
23 | ```
24 |
25 | Para a finalização das intents você precisa dar exemplos de assunto, ou seja, como no nosso exemplo da `intent: sabores_pizza`, temos vários exemplos no qual podemos identificar como sabores de pizza que o usuário poderá falar, como calabreza, mussarela, a moda, etc:
26 |
27 | ``` MarkDown
28 | #intent: sabores_pizza
29 | - Quais sabores vocês tem?
30 | - Quais são os sabores?
31 | - Você pode me dizer os sabores
32 | ```
33 |
34 | Assim você pode dar vários exemplos para que o bot seja treinado e consiga entender vários sabores de pizza :)
35 |
36 | ## Utter
37 |
38 | Em um bot, devemos esperar que ele não consiga fazer a formulação das frases sozinho. Na construção do bot a partir do Boiler-Plaite, há um arquivo chamado domain, encontrado dentro da pasta `coach/`, onde a primeira vista fica muito dificil de se analisar e compreender o que está ocorrendo, mas que ficará tudo claro logo.
39 |
40 | Domain é um arquivo yml, que é composto por uma estrutura bem simples:
41 |
42 | Na primeira parte do domain podemos perceber que está sendo listado todos os nomes das `intents` que compõe o Boiler-Plaite, nessa parte estamos especificamos quais são os assuntos que o nosso bot consiguirá responder.
43 |
44 | Em seguida há o nome `entities`, que é o conteúdo que agrega a corrente principal de fluxo de conversa do seu bot, sendo assim, podemos perceber a partir das entities do que nosso bot irá falar descartando o fluxo natural que imaginamos que um bot deverá seguir (claro que esse fluxo pode ser mudado ao gosto do usufruidor).
45 |
46 | Após entities temos `templates`, que é composto de todas as respostas que o bot pode fazer, damos o nome de utters. Na primeira parte podemos perceber, uma utter muito importante para a construção de qualquer bot, a `utter_default`, essa utter tem o objetivo de sinalizar ao usuário que não está entendendo o que ele está falando ou orienta-lo a falar de uma forma mais compreensivel para o bot. Para construirmos uma utter primeiramente devemos dar o nome como por exemplo `utter_sabores_pizza:`, por convenção colocamos a primeira palavra de utter. Após o nome iremos complementar com `- text: |`, sinalizando que iremos escrever um texto e em seguida escrever a mensagem desejada, exemplo:
47 |
48 | ``` MarkDown
49 | utter_sabores_pizza:
50 | - text: |
51 | temos calabreza, mussarela, a moda e portuguesa
52 | ```
53 |
54 | Ao final do arquivo temos as `actions`, que é composta de todas as utters que criamos nos templates.
55 |
56 | ## Stories
57 |
58 | Há várias coisas para se analisar em uma conversa, mas há uma coisa muito essencial em qualquer interação verbal: o assunto, ou um tema que corresponde aquele diálogo. Quando extraímos isso para âmbito do chat-bot, conseguimos denomina-los como stories, são eles que descrevem os contextos de conversação esperados a partir das intenções.
59 |
60 | Na construção de um novo storie, você deve ir ao diretório `coach/data/stories` e acessar ou criar um arquivo mark-down com o nome relacionado a storie que será criada. Dentro do arquivo, primeiro você dá o nome do storie precedido de "##" e depois você lista em ordem o fluxo que a pessoa irá seguir, onde primeiramente você diz qual intent com "*" e depois a utter com "-", e é dessa forma que conseguimos correlacionar intents com utters, fazendo nosso bot entender e responder o esperado, exemplo:
61 |
62 | ``` MarkDown
63 | ## Oi Tudo Bem Story 1
64 | * cumprimentar
65 | - utter_cumprimentar
66 | * tudo_bem
67 | - utter_tudo_bem
68 | ```
69 |
70 |
71 | ## Executando e testando seu bot
72 |
73 | Todas as informações de como executar e treinar seu bot está descrito no README do BoilerPlate. Para desenvolvimento sugerimos a utilização do console, já que o mesmo especifica o comportamento do seu chat-bot. Entrentanto se o desejado for a utilização de alguma plataforma de interação com o usuário, incentivamos a seguir o tutorial do RocketChat ou Telegram (https://github.com/lappis-unb/rasa-ptbr-boilerplate).
74 |
75 | ## Próximos passos
76 |
77 |
78 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Este é um documento para orientação em como contribuir para o repositório do Rasa PT-BR Boilerplate. Antes de começar a contribuir veja as [issues já abertas](http://github.com/lappis-unb/rasa-ptbr-boilerplate/issues), e principalmente o funcionamento de nossa [arquitetura](https://github.com/lappis-unb/rasa-ptbr-boilerplate/blob/master/README.md).
2 |
3 | Veja as orientações abaixo para cada tipo de contribuição:
4 | * [Por onde começar a contribuir?](#comece-a-contribuir)
5 | * [Reportar erros](#encontrou-um-bug)
6 | * [Consertar erros](#concertou-um-bug)
7 | * [Contribuir para a documentação](#quer-contribuir-para-a-nossa-documentação)
8 | * [Adicionar nova feature](#quer-adicionar-uma-feature-nova-ou-ajudar-com-uma-existente)
9 | * [Contribuir para o conteúdo do Boilerplate](#quer-contribuir-para-o-conteúdo-do-boilerplate)
10 |
11 | ### Comece a contribuir
12 | Quer começar a contribuir para o Boilerplate? O processo em geral é bem simples:
13 |
14 | - Crie uma issue descrevendo uma feature que você queira trabalhar ou entre em issues já abertas (caso comece por uma issue já existente comente na issue que você está desenvolvendo).
15 | - Escreva seu código, testes e documentação
16 | - Abra um pull request descrevendo as suas alterações propostas
17 | - Seu pull request será revisado por um dos mantenedores, que pode levantar questões para você sobre eventuais mudanças necessárias ou questões.
18 |
19 | Veja nossa [documentação](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master/docs) para entender um pouco melhor sobre nosso código e [arquitetura](https://github.com/lappis-unb/rasa-ptbr-boilerplate/blob/master/README.md), veja nossas issues, principalmente as com as tags `help-wanted` e `good-first-issue`, que são as ideais para começar a contribuir para o Boilerplate.
20 |
21 |
22 | ### Encontrou um Bug?
23 | Caso tenha encontrado algum erro, nos informe por uma issue, assim poderemos estar sempre melhorando. Pedimos que seja descritivo, dessa forma poderemos identificar e reproduzir o erro para ser possível consertá-lo.
24 |
25 | Antes de reportar o Bug, veja as [issues com a tag `bug`](https://github.com/lappis-unb/rasa-ptbr-boilerplate/labels/bug) e verifique se o erro identificado já não possui uma issue criada.
26 |
27 | Para uma boa documentação:
28 | * Nomeie a issue com um nome claro e descritivo de acordo com o problema;
29 | * Descreva o passo a passo para chegar no erro encontrado;
30 | * Mostre exemplos do erro ocorrido;
31 | * Descreva o comportamento esperado e o comportamento obtido;
32 | * Marque a issue criada com a tag `bug`.
33 |
34 | Veja a seguinte estrutura de issue:
35 |
36 | ``` markdown
37 |
38 | **Descrição do erro encontrado:**
39 | ...
40 |
41 | **Passo a passo para a reprodução do erro:**
42 | 1.
43 | 2.
44 | ...
45 | **Comportamento esperado:** ...
46 | **Comportamento obtido:** ...
47 | ```
48 |
49 | ### Consertou um Bug?
50 | Para enviar a sua solução e consertar um bug existente, fork nosso repositório e crie um Pull Request descrevendo o problema e como ele foi corrigido.
51 |
52 | Para uma bom Pull Request:
53 | * Nomeie o PR de forma descritiva e clara de acordo com o problema resolvido;
54 | * Descreva o problema e a sua solução;
55 | * Marque a issue que o PR soluciona.
56 |
57 | Veja o exemplo abaixo:
58 |
59 | ``` markdown
60 | **Issue:** #[Número-da-Issue]
61 | **Descrição do Problema:**
62 | ...
63 | **Descrição da Solução:**
64 | ...
65 | ```
66 |
67 | ### Quer contribuir para a nossa Documentação?
68 | Para contribuir com a documentação, veja a documentação já existente, e as issues pendentes para documentação marcadas com a [tag `documentação`](https://github.com/lappis-unb/rasa-ptbr-boilerplate/labels/documentação).
69 |
70 | Caso queira resolver uma issue já existente, comente na issue que está trabalhando, caso ainda não exista uma issue crie uma nova issue descrevendo o problema encontrado e marque com a tag `documentação`.
71 |
72 | Para solucionar faça um PR com a descrição do que foi feito e a referência a issue que está resolvendo.
73 |
74 | ### Quer adicionar uma feature nova ou ajudar com uma existente?
75 |
76 | Nosso desenvolvimento é dividido em algumas frentes principais, sendo elas:
77 | * **Bot Rasa:** Frente para o desenvolvimento do conteúdo do Boilerplate, com a utilização do Rasa (na pasta `bot`);
78 | * **ElasticSearch:** Frente para o desenvolvimento de dashboards com Kibana para a análise das conversas do bot com os usuários (na pasta `analytics`);
79 | * **Plataforma de Conteúdo:** Desenvolvimento de uma plataforma para adicionar conteúdo no Boilerplate, sem a necessidade de mexer diretamente nos arquivos do código ([no repositório `rasa-nlu-trainer`](https://github.com/lappis-unb/rasa-nlu-trainer)).
80 |
81 | Além de que também temos algumas outras áreas, onde é possível contribuir, como:
82 | * **Notebooks:** Notebooks jupyter para análise da estrutura e funcionamento do Bot (na pasta `notebooks`);
83 |
84 | Aceitamos contribuições em todas as áreas do nosso código, desde que seja uma contribuição válida e traga reais melhorias para o projeto. Para fazer uma contribuição abra uma issue, com nome descritivo, especificando o que será feito e qual frente será afetada. Veja o exemplo abaixo de um bom template a ser feito:
85 |
86 | ``` markdown
87 | **Frente a ser trabalhada:** ...
88 | **Descrição da nova feature:**
89 | ...
90 | **Porque essa feature melhoraria o código:**
91 | ...
92 | ```
93 | Caso sua contribuição entre um uma das frentes principais, marque com a sua label específica. Temos as labels:
94 | * `elasticSearch`: para issues da frente de análise do Elasticsearch com Kibana;
95 | * `plataforma-conteudo`: para issues da frente do front-end de adicionar conteúdo no Boilerplate;
96 | * `rasa`: Para issues sobre o Rasa, na frente do Bot.
97 |
98 | Após fazer a issue, dê um fork do repositório e faça um Pull Request com sua nova feature. Dê um bom nome para o PR, especifique a sua solução, em qual frente ela se encaixa e a referência aissue relacionada. Veja o exemplo de uma estrutura de PR abaixo:
99 |
100 | ``` markdown
101 | **Frente a ser trabalhada:**...
102 | **Issue:** #[Número-da-Issue]
103 |
104 | **Descrição da nova feature:**
105 | ...
106 | **Descrição de como foi feito:**
107 |
108 | **Descrição de como ela funciona:**
109 | ...
110 | ```
111 |
112 | ### Quer Contribuir para o conteúdo do Boilerplate?
113 | Além de contribuição de código, o Boilerplate também possui contribuições de conteúdo. Veja as [issues marcadas com a tag `conteudo`](https://github.com/lappis-unb/rasa-ptbr-boilerplate/labels/conteudo). Comente na issue que está trabalhando, faça o fork e submeta seu PR. Lembre-se de definir o que foi feito, linkar com a issue e marcar com a tag `conteudo`. Veja abaixo um exemplo de PR para contribuição de conteúdo.
114 |
115 | ``` markdown
116 | **Issue:**#[Número-da-Issue]
117 | **Conteúdo adicionado:**
118 | * Exemplo de pergunta do usuário: ...
119 | * Resposta: ...
120 | ...
121 |
122 | ```
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rasa Boilerplate
2 |
3 |
4 |
5 | 
6 |
7 |
8 | ## For English version, see [README-en](docs/README-en.md)
9 |
10 | ## Tutorial para configurar todo o projeto
11 |
12 | ### Pré requisitos
13 |
14 | Para rodar o projeto em sua máquina é necessário ter instalado:
15 | - Docker
16 | - Docker compose
17 |
18 | ### Primeiros passos
19 |
20 | Primeiramente, clone o repositório para sua máquina local usando o comando:
21 |
22 | ```sh
23 | git clone
24 | ```
25 |
26 | Para ter seu chatbot Rasa funcionando, certifique-se de estar dentro da pasta do projeto e então execute no terminal o seguinte comando:
27 |
28 | ```sh
29 | make first-run
30 | ```
31 |
32 | ⚠️ **Atenção**: Caso ocorra algum erro de permissão, executar o comando `sudo make first-run`.
33 |
34 |
35 | Esse comando irá construir a infraestrutura necessária (subir containers com as dependências, treinar o chatbot, etc) para possibilitar a interação com o chatbot.
36 |
37 | Tudo está dockerizado então você não deve ter problemas de instalação do ambiente.
38 |
39 | Depois que tudo for instalado, você verá a seguinte mensagem e pode começar a interagir com o bot
40 |
41 | ```sh
42 | Bot loaded. Type a message and press enter (use '/stop' to exit):
43 | Your input ->
44 | ```
45 |
46 | Para fechar a interação com o bot é só dar `ctrl+c`.
47 |
48 |
49 | Para conferir se os contêineres foram construídos corretamente, execute o comando:
50 |
51 | ```sh
52 | docker ps
53 | ```
54 | Se tudo der certo, você conseguirá ver uma tabela com dois contêineres de nomes `rasa-ptbr-boilerplate_bot-webchat` e
55 | `rasa-ptbr-boilerplate_actions` na coluna IMAGE.
56 |
57 | Para iniciar uma conversa com o chatbot, execute o comando `make run-shell`, espere o comando rodar e divirta-se!
58 |
59 |
60 | ## Introdução
61 |
62 | Um projeto feito em Rasa com configurações necessárias para a construção de um projeto grande de chatbot.
63 |
64 | Este projeto teve como base o projeto [Tais](http://github.com/lappis-unb/tais).
65 |
66 | ### Entenda a Arquitetura
67 |
68 | É utilizado no boilerplate diversas tecnologias que interagem entre si para obter um melhor resultado. Veja a arquitetura implementada:
69 |
70 | 
71 |
72 | O usuário interage com a Boilerplate via Telegram, que manda as mensagens para o Rasa NLU através de
73 | conectores, onde ele identifica a *intent*, e responde pelo Rasa Core, de acordo com as *stories* e *actions*.
74 | As *models* utilizadas para a conversação foram geradas pelo módulo *trainer* e depois transferidas para o bot, estes
75 | modelos podem ser versionados e evoluídos entre bots.
76 | Os notebooks avaliam o funcionamento de acordo com o formato das *intents* e *stories*.
77 | O elasticsearch coleta os dados da conversa e armazena para a análise feita pelo kibana, que gera gráficos para
78 | avaliação das conversas dos usuários e do boilerplate.
79 |
80 | ### Bot
81 |
82 | Este script foi configurado para construir as imagens genéricas necessárias para execução deste ambiente.
83 | Caso seu projeto utilize este boilerplate e vá realizar uma integração contínua ou similar, é interessante
84 | criar um repositório para as imagens e substitua os nomes das imagens "lappis/bot", e "lappis/botrequirements" pelas suas respectivas novas imagens, por exemplo "/bot" em repositório público.
85 |
86 |
87 | ### Treinamento
88 |
89 | **Atenção**: o comando de treinamento é usado para criar os modelos necessários na conversação do bot. Para treinar o seu chatbot execute o comando:
90 |
91 | ```sh
92 | make train
93 | ```
94 |
95 | ### Executando o bot no terminal
96 | Para executar o bot no terminal execute:
97 |
98 | ```sh
99 | make run-shell
100 | ```
101 |
102 | ### Executando o bot no Telegram
103 |
104 | Após realizar o [tutorial](/docs/setup_telegram.md) de exportação de todas variávies de ambiente necessárias, é possível realizar a execução do bot no telegram corretamente.
105 |
106 | **Antes de seguir adiante. Importante:** As variáveis de ambiente são necessárias para o correto funcionamento do bot, por isso não esqueça de exportá-las.
107 |
108 | Edite o arquivo **credentials.yml** e descomente as linhas referentes ao telegram:
109 |
110 | ```sh
111 | telegram:
112 | access_token: ${TELEGRAM_TOKEN}
113 | verify: ${TELEGRAM_BOT_USERNAME}
114 | webhook_url: ${TELEGRAM_WEBHOOK}
115 | ```
116 |
117 | Depois execute o bot no telegram:
118 |
119 | ```sh
120 | make run-telegram
121 | ```
122 |
123 | ### Analytics
124 |
125 | Para a visualização dos dados da interação entre o usuário e o chatbot nós utilizamos uma parte da Stack do Elastic, composta pelo ElasticSearch e o Kibana. Com isso, utilizamos um broker para fazer a gerência de mensagens. Então conseguimos adicionar mensagens ao ElasticSearch independente do tipo de mensageiro que estamos utilizando.
126 |
127 | * Para uma **configuração rápida** execute o seguinte comando:
128 |
129 | ```sh
130 | make build-analytics
131 | ```
132 |
133 | Espere até os serviço do *ElasticSearch* estar pronto, e execute o comando abaixo para configurar os índices:
134 |
135 | ```
136 | make config-elastic
137 | ```
138 |
139 | Espere até os serviço do *Kibana* estar pronto, e execute o comando abaixo para configurar os *dashboards*:
140 |
141 | ```
142 | make config-kibana
143 | ```
144 |
145 | O comando acima precisa ser executado apenas 1 vez e já vai deixar toda a infra de `analytics` pronta para o uso.
146 |
147 | Acesse o **kibana** na url `locahost:5601`
148 |
149 | Caso você deseje entender o processo de configuração da *stack* de *analytics*, veja a [explicação completa de analytics](docs/setup_analytics.md).
150 |
151 | ## Notebooks - Análise de dados
152 |
153 | ### Setup
154 |
155 | Levante o container `notebooks`
156 |
157 | ```sh
158 | make run-notebooks
159 | ```
160 |
161 | Acesse o notebook em `localhost:8888`
162 |
163 | # Como conseguir ajuda
164 |
165 | Parte da documentação técnica do framework da Tais está disponível na
166 | [wiki do repositório](https://github.com/lappis-unb/tais/wiki). Caso não encontre sua resposta, abra uma issue
167 | com a tag `duvida` que tentaremos responder o mais rápido possível.
168 |
169 | Em caso de dúvidas em relação ao Rasa, veja o grupo [Telegram Rasa Stack Brasil](https://t.me/RasaBrasil),
170 | estamos lá também para ajudar.
171 |
172 | Veja mais informações de contato em nosso site: https://lappis.rocks
173 |
174 | # Licença
175 |
176 | Todo o framework do boilerplate é desenvolvido sob a licença
177 | [GPL3](https://github.com/lappis-unb/rasa-ptbr-boilerplate/blob/master/LICENSE)
178 |
179 | Veja a lista de dependências de licenças [aqui](https://libraries.io/github/lappis-unb/rasa-ptbr-boilerplate)
180 |
--------------------------------------------------------------------------------
/docs/README-en.md:
--------------------------------------------------------------------------------
1 | # Rasa Boilerplate
2 |
3 |
4 |
5 |
6 |
7 | A project made in Rasa with the necessary configurations for the construction of a large chatbot project.
8 |
9 | This project was based on [Tais](http://github.com/lappis-unb/tais).
10 |
11 | # Understand the Architecture
12 |
13 | Various technologies are used in boilerplate that interact with each other to obtain a better result. See the implemented architecture:
14 |
15 | 
16 |
17 | The user interacts with Boilerplate via RocketChat or Telegram, which sends the messages to the Rasa NLU via
18 | connectors, where it identifies the *intent*, and responds to the Rasa Core, according to *stories* and *actions*.
19 | The *models* used for the conversation were generated by the *trainer* module and then transferred to the bot; these
20 | models can be versioned and evolved between bots.
21 | Notebooks evaluate the operation according to the format of *intents* and *stories*.
22 | Elasticsearch collects data from the conversation and stores it for the analysis done by kibana, which generates charts for
23 | evaluation of user conversations and boilerplate.
24 |
25 | ## Bot
26 |
27 | This script has been configured to build the generic images needed to run this environment.
28 | If your project uses this boilerplate and goes to perform continuous or similar integration, it is interesting
29 | to create a repository for the images and replace the names of the "bot", "coach" and "requirements" their respective new images, for example "/bot" in a public repository.
30 |
31 | ### RocketChat
32 |
33 | ```sh
34 | sudo docker-compose up -d rocketchat
35 | # wait 3 minutes for the rocketchat to finish rising
36 | sudo docker-compose up bot
37 | ```
38 |
39 | For the virtual assistant to start the conversation, you must create a `trigger`.
40 | To do this, enter the rocketchat as `admin`, and go to the Livechat panel at
41 | In the Triggers section, click `New Trigger`. Fill in the Trigger as follows:
42 |
43 | ```yaml
44 | Enabled: Yes
45 | Name: Start Talk
46 | Description: Start Talk
47 | Condition: Visitor time on site
48 | Value: 3
49 | Action: Send Message
50 | Value: Impersonate next agent from queue
51 | Value: Olá!
52 | ```
53 |
54 | The `http://localhost:8080/` value should be the Bot access URL.
55 |
56 | #### Installation
57 |
58 | To run the bot on a website you need to enter the following Javascript in your page
59 |
60 | ```js
61 |
62 |
73 |
74 | ```
75 |
76 |
77 | **Attention**: You need to change the `host` variable within the above code to the url of the site where you will be
78 | your Rocket.Chat.
79 |
80 | ### Telegram
81 |
82 | To carry out this process, it is recommended to create a
83 | [Telegram Bot](https://core.telegram.org/bots#3-how-do-i-create-a-bot) to get all the necessary information.
84 |
85 | To run the _stack_ of the bot by the Telegram together with the attached services, it is necessary to comment the part
86 | related to Rocket.Chat and uncomment the service related to the telegram bot.
87 |
88 | After that, you need to use [ngrok](https://ngrok.com/download) to expose a certain port to be used
89 | by the Telegram.
90 |
91 | When downloading, just run it using the following command:
92 |
93 | ```
94 | ./ngrok http {used port}
95 | ```
96 |
97 | **Attention:** The Telegram connector is using port 5001 by default. If you want to change, just change
98 | the port used by the in the Makefile.
99 |
100 | When running, a link will be generated where it will be used to retrieve all information obtained by Bot's webhook
101 | by the Telegram, similar to this link:
102 |
103 | ```
104 | Example:
105 | https://283e291f.ngrok.io
106 | ```
107 |
108 | Configure all necessary information in the docker-compose to integrate the created telegram bot:
109 |
110 | ```yml
111 | - TELEGRAM_ACCESS_TOKEN={token from BotFather}
112 | - VERIFY={bot username}
113 | - WEBHOOK_URL={ngrok link}/webhooks/telegram/webhook
114 | ```
115 |
116 | To execute only the bot service for the telegram, use the following command:
117 |
118 | If you have not yet trained your bot run the following command first:
119 |
120 | ```sh
121 | make train
122 | ```
123 |
124 | **Attention**: the command "make train" run a container dock, in case I need sudo on your computer
125 | To run the docking window, use the "sudo make train".
126 |
127 |
128 | Then run the bot on the telegram:
129 |
130 | ```sh
131 | sudo docker-compose up telegram_bot
132 | ```
133 |
134 | ### Console
135 |
136 | ```sh
137 | make train
138 | sudo docker-compose run --rm bot make run-console
139 | ```
140 |
141 | ### Train Online
142 |
143 | ```
144 | make train
145 | sudo docker-compose run --rm coach make train-online
146 | ```
147 |
148 | ## Analytics
149 |
150 | ### Setup
151 |
152 | ```
153 | sudo docker-compose run --rm -v $PWD/analytics:/analytics bot python /analytics/setup_elastic.py
154 | sudo docker-compose up -d elasticsearch
155 | ```
156 |
157 | Remember to set the following environment variables in the `docker-compose` file.
158 |
159 | ```
160 | ENVIRONMENT_NAME=localhost
161 | BOT_VERSION=last-commit-hash
162 | ```
163 |
164 | ### Preview
165 |
166 | ```
167 | sudo docker-compose up -d kibana
168 | ```
169 |
170 | You can access kibana at `locahost:5601`
171 |
172 |
173 | ## Notebooks - Data Analysis
174 |
175 | ### Setup
176 |
177 | Lift the 'notebooks' container
178 |
179 | ```sh
180 | docker-compose up -d notebooks
181 | ```
182 |
183 | Access the notebook at `localhost:8888`
184 |
185 |
186 |
187 | ## Tutorial to support the entire stack
188 |
189 | ```sh
190 | sudo docker-compose up -d rocketchat
191 |
192 | sudo docker-compose up -d kibana
193 | sudo docker-compose run --rm -v $PWD/analytics:/analytics bot python/analytics/setup_elastic.py
194 |
195 | sudo docker-compose up -d bot
196 | ```
197 |
198 |
199 | # How to get help
200 |
201 | Part of the technical documentation for the Tais framework is
202 | [repository wiki](https://github.com/lappis-unb/tais/wiki). If you can not find your answer, open an issue
203 | with a `duvida` tag that we will try to respond to as quickly as possible.
204 |
205 | If you have any questions regarding Rasa, please see the Telegram group [Telegram Rasa Stack Brasil](https://t.me/RasaBrasil),
206 | we're there to help too.
207 |
208 | See more contact information on our website: https://lappis.rocks
209 |
210 | # License
211 |
212 | The entire boilerplate framework is developed under license
213 | [GPL3](https://github.com/lappis-unb/rasa-ptbr-boilerplate/blob/master/LICENSE)
214 |
215 | See a list of license dependencies [here](https://libraries.io/github/lappis-unb/rasa-ptbr-boilerplate)
--------------------------------------------------------------------------------
/docs/Tutoriais/tutorial-como-treinar-o-modelo.md:
--------------------------------------------------------------------------------
1 | # Configuração da Policy do chatbot
2 |
3 |
4 | Este tutorial tem como objetivo mostrar como funciona a configuração do treinamento de um *chatbot* contruido em **_Rasa_**, mostrando como funciona as **Policies**, suas características, e os hiperparâmetros necessários para configurá-las.
5 |
6 | As informações mais detalhadas sobre as policies podem ser encontradas na [documentação](https://rasa.com/docs/rasa/core/policies/) do Rasa, e a configuração usada como referência é a utilizada na [TAIS](https://github.com/lappis-unb/tais/blob/master/coach/policy_config.yml)
7 |
8 |
9 | ## Policies
10 |
11 | Na arquitetura do *Rasa* as policies são aquelas que recebem as intenções do usuários, já identificadas pelo *chatbot*, e a partir dessa informação determina qual ação será toma a seguir. Sem grande rigor, a **Policy** recebe a entrada identificada como por exemplo `ìntent_cumprimentar` e preve qual será a resposta do *bot*, usando como base os exemplos de conversas.
12 |
13 | O *Rasa* possue várias policies implementadas e também suporte para construção de policy customizada. As que serão detalhadas neste documento são as **Keras Policy**, **Memoization Policy**, **Embedding Policy** e **Fallback Policy**.
14 |
15 | No arquivo `policies_config.yml`, ou `config.yml` é definido a sequência de prioridades das policies a ser executada. Normalmente, a **Memoization Policy** é a que tem maior prioridade, pois avalia se existe um storie nos arquivos de treinamento seguindo exatamente a conversa intepretada, e a **Fallback Policy** é última prioridade, e age se todas as outras não atingirem o nível de confiança adequado. Entre a **Memoization Policy** e a **Fallback Policy** normalmente é definido uma das policies detalhadas abaixo. Essas policies (**Keras Policy**, **Embedding Policy**) são redes neurais que inferem o contexto da conversa a partir de um histórico e prediz qual a ação mais adequada, com a sua respectiva probabilidade. Essas redes neurais são treinadas com os exemplos de conversas salvos na pasta "stories" dos dados.
16 |
17 | ### Keras Policy
18 |
19 | Esta policy tem a rede neural implementada usando a biblioteca Python [Keras]https://keras.io). Formada por camadas utilizando o algoritmo **LSTM**.
20 |
21 | Em sua configuração sugerida na documentação, ela vem acompanhada de duas **[Featurization](#featurization)**, __MaxHistoryTrackerFeaturizer__ e a __BinarySingleStateFeaturizer__
22 |
23 | ### Embedding Policy
24 |
25 | Ou também, Recurrent Embedding Dialogue Policy ([REDP](https://arxiv.org/abs/1811.11707)), tem como foco tratar conversas não cooperativas do usuário com um desempenho maior que a Keras Policiy.
26 |
27 | Tem-se como conversa não cooperativa:
28 |
29 | * Chitchat: "Small-talk" ou perguntas não relacionadas a tarefa
30 | * Correction: Correção de uma resposta anterior
31 | * Broad context: Perguntas referentes ao estado da tarefa (Ex: "Já te informei o local, tem como você me dar a informação agora?")
32 | * Narrow context: Perguntas relacionadas a contextos imediatos (Ex: quando o usuário pergunta o porquê da informação dada pelo bot)
33 |
34 | Para fazer a previsão da ação do bot em uma conversa não comperetativa, essa policy tem o foco em ações tomadas anteriormente, não somente as antigas intents previstas.
35 |
36 | Por padrão,o Rasa Core gera histórias mais longas, colando aleatoriamente a histórias pré-definidas. Pois quando ocorre stories assim:
37 |
38 | ```
39 | # thanks
40 | * thankyou
41 | - utter_youarewelcome
42 |
43 | # bye
44 | * goodbye
45 | - utter_goodbye
46 | ```
47 | o objetivo é ignorar contextos anteriores e responder assim como descrito.
48 |
49 | Porém, para o funcionamento da **REDP**, o contexto da intent é relevante, logo esse comportamento do Rasa deve ser evitado, assim `augmentation` é colocado `0`.
50 |
51 | ### Memoization Policy
52 |
53 | A **Memoization Policy** é aquela que memoriza os dados de treinamento e prevê de acordo com as stories descritas. Se a próxima ação predita, dada a intent identificada for igual a um dado de treinamento, esta responderá com confiança de 1.0, caso contrário será 0.0.
54 |
55 | Nesta é importante a geração de bastante stories e também o uso de `augmentation` se as stories não dependerem de contexto.
56 |
57 | ### Fallback Policy
58 |
59 | A policy Fallback é acionada quando nenhuma das outras policies atingem o nivel de confiança esperado. Assim que ela é chamada, esta executa a **Fallback Action** que é a resposta padrão do bot.
60 |
61 | Nela, deve-se estabelecer o nível de confiança mímino que as policies devem atingir para que não execute o Fallback (**threshold**), tanto na parte do processamento de linguagem natural (NLU), que interpreta as intents do usuário, quando na parte da previsão (Core).
62 |
63 |
64 | ## Featurization
65 |
66 | Existem dois tipos de Featurization para construir vetores que representem as conversas, a **State Featurizers** e **Tracker Featurizers**.
67 |
68 | As **States Featurizers** utilizando o **tracker**, que dá informações de intents, entidades e slots prévios (ou seja, as **features**) e converte em um array.
69 | * Em BinarySingleStateFeaturizer, ele cria um vetor x,y que indica a presença de certas intent, entidades, ações anteriores e slots.
70 | * Na **LabelTokenizerSingleStateFeaturizer**, se cria uma vetor baseado nos nomes das features, separado em tokens e representados como **bag-of-words**. Por exemplo `utter_explain_details_hotel` e `utter_explain_details_restaurant` terão 3 features em comum.
71 |
72 | Já as **Trackers Featurizers** itera pelos trackers states e chama o SingleStateFeaturizer para cada estado, sendo que a diferença entre os dois Trackers Featurizers são:
73 | * **FullDialogueTrackerFeaturizer**: cria uma representação numerica das stories para alimentar a rede neural.
74 | * **MaxHistoryTrackerFeaturizer**: cria um array dos estados anteriores para cada utter ou action do bot.
75 |
76 |
77 | ## Configuração
78 |
79 | Algumas configurações utilizadas pela Tais, com base nas policies apresentadas. Lembrando que os valores de **threshold**, **augmentation**, **MaxHistoryTrackerFeaturizer** e entre outros, dependem do contexto que o bot trabalha e sempre é bom analisar a confiança e acurácia, para assim mudar os valores, se necessário.
80 |
81 | Outra variável importante de se olhar para ver se todos os hiperparâmetros estão ajustados corretamente é o **loss**. Para sabe qual é o melhor número de épocas (*epoches*) o ideal é o maior valor de acurácia e menor valor de *loss*, indicando a maior precisão da rede neural e do seu bot.
82 |
83 | Só que deve-se levar em conta quão diferente esse valores ficaram, entre uma época e outra, pois se não acontecer uma redução significativa de loss e um aumento de acurácia, pode chegar ao *overfitting* da sua rede, e o bot ficar bom somente em casos específicos e não ser preciso em casos generalizados.
84 |
85 | Resumindo, observe o loss e a acurácia, ajuste a época com um valor onde o loss é minimo e a acurácia é máxima, mas quando ainda ocorrer diferenças significativas entre uma época e outra.
86 |
87 | ### Keras + Memoization + Fallback
88 |
89 | * Em **policies_config.yml**
90 |
91 | ```
92 | policies:
93 | - name: KerasPolicy
94 | epochs: 7
95 | batch_size: 10
96 | featurizer:
97 | - name: FullDialogueTrackerFeaturizer
98 | state_featurizer:
99 | - name: LabelTokenizerSingleStateFeaturizer
100 | - name: FallbackPolicy
101 | nlu_threshold: 0.6
102 | core_threshold: 0.6
103 | - name: MemoizationPolicy
104 | max_history: 2
105 |
106 | ```
107 |
108 | * Em **train.py**
109 |
110 | ```
111 | 'augmentation_factor': 20,
112 | ```
113 |
114 | ### Embedding + Memoization + Fallback
115 |
116 |
117 | * Em **policies_config.yml**
118 | ```
119 | policies:
120 | - name: "EmbeddingPolicy"
121 | epochs: 500
122 | attn_shift_range: 5
123 | featurizer:
124 | - name: FullDialogueTrackerFeaturizer
125 | state_featurizer:
126 | - name: LabelTokenizerSingleStateFeaturizer
127 | - name: FallbackPolicy
128 | nlu_threshold: 0.6
129 | core_threshold: 0.6
130 | - name: MemoizationPolicy
131 | max_history: 2
132 | ```
133 | * Em **train.py**
134 |
135 | ```
136 | 'augmentation_factor': 20,
137 | ```
138 |
--------------------------------------------------------------------------------
/modules/rocketchat/bot_config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import json
4 | import logging
5 | import requests
6 | import os
7 |
8 | # == Log Config ==
9 |
10 | logger = logging.getLogger("Bot Config")
11 | logger.setLevel(logging.DEBUG)
12 |
13 | ch = logging.StreamHandler()
14 | ch.setLevel(logging.DEBUG)
15 |
16 | formatter = logging.Formatter("%(asctime)s :: %(name)s :: %(levelname)s :: %(message)s")
17 |
18 | ch.setFormatter(formatter)
19 |
20 | logger.addHandler(ch)
21 |
22 |
23 | host = os.getenv("ROCKETCHAT_URL", "http://rocketchat:3000")
24 | if host[-1] == "/":
25 | host = host[:-1]
26 |
27 | if not host.startswith("http://"):
28 | host = "http://" + host
29 |
30 | path = "/api/v1/login"
31 |
32 | bot = {
33 | "name": os.getenv("ROCKETCHAT_BOT_NAME", "Bot"),
34 | "username": os.getenv("ROCKETCHAT_BOT_USERNAME", "bot"),
35 | "password": os.getenv("ROCKETCHAT_BOT_PASSWORD", "bot"),
36 | "avatar": os.getenv(
37 | "ROCKETCHAT_BOT_AVATAR_URL",
38 | "https://raw.githubusercontent.com/"
39 | "lappis-unb/rouana/master/images/rouana_avatar.jpeg",
40 | ),
41 | "email": os.getenv("ROCKETCHAT_BOT_USERNAME", "bot") + "@email.com",
42 | }
43 |
44 | admin_name = os.getenv("ROCKETCHAT_ADMIN_USERNAME", "admin")
45 | admin_password = os.getenv("ROCKETCHAT_ADMIN_PASSWORD", "admin")
46 |
47 | rasa_url = os.getenv("RASA_URL", "http://bot:5005/webhooks/rocketchat/webhook")
48 | user_header = None
49 |
50 |
51 | def api(endpoint, values=None, is_post=True):
52 | requests.adapters.DEFAULT_RETRIES = 5
53 |
54 | if endpoint[0] == "/":
55 | endpoint = endpoint[1:]
56 |
57 | url = host + "/api/v1/" + endpoint
58 |
59 | data = None
60 | if values:
61 | data = json.dumps(values)
62 | if is_post:
63 | response = requests.post(url, data=data, headers=user_header)
64 | else:
65 | response = requests.get(url, data=data, headers=user_header)
66 |
67 | if response.json()["success"] is True:
68 | logger.info("Success {} :: {}".format(url, response.json()))
69 | else:
70 | logger.error("ERROR {} :: {}".format(url, response.json()))
71 | raise EnvironmentError
72 |
73 | return response.json()
74 |
75 |
76 | def api_post(endpoint, values=None):
77 | return api(endpoint, values)
78 |
79 |
80 | def api_get(endpoint, values=None):
81 | return api(endpoint, values, False)
82 |
83 |
84 | def get_authentication_token():
85 | login_data = {"username": admin_name, "password": admin_password}
86 | response = requests.post(host + path, data=json.dumps(login_data))
87 |
88 | if response.json()["status"] == "success":
89 | logger.info("Login suceeded")
90 |
91 | authToken = response.json()["data"]["authToken"]
92 | userId = response.json()["data"]["userId"]
93 | user_header = {
94 | "X-Auth-Token": authToken,
95 | "X-User-Id": userId,
96 | "Content-Type": "application/json",
97 | }
98 |
99 | return user_header
100 |
101 |
102 | def create_bot_user():
103 | try:
104 | api_post(
105 | "users.create",
106 | {
107 | "name": bot["name"],
108 | "email": bot["email"],
109 | "password": bot["password"],
110 | "username": bot["username"],
111 | "requirePasswordChange": False,
112 | "sendWelcomeEmail": True,
113 | "roles": ["bot"],
114 | },
115 | )
116 | except Exception:
117 | print("User already created.")
118 |
119 | api_post(
120 | "users.setAvatar", {"avatarUrl": bot["avatar"], "username": bot["username"]},
121 | )
122 |
123 |
124 | def create_livechat_agent():
125 | response = api_post("livechat/users/agent", {"username": bot["username"]})
126 | return response["user"]["_id"]
127 |
128 |
129 | def configure_livechat():
130 | # Enable Livechat
131 | api_post("settings/Livechat_enabled", {"value": True})
132 |
133 | # Disable show pre-registration form
134 | api_post("settings/Livechat_registration_form", {"value": False})
135 |
136 | # Change Livechat Color
137 | api_post("settings/Livechat_title_color", {"value": "#039046", "editor": "color"})
138 |
139 | # Change Livechat Title
140 | api_post("settings/Livechat_title", {"value": bot["name"]})
141 |
142 | # Disable Livechat Email display
143 | api_post("settings/Livechat_show_agent_email", {"value": False})
144 |
145 | # Disable file upload
146 | api_post("settings/Livechat_fileupload_enabled", {"value": False})
147 |
148 | # Change Livechat Webhook URL
149 | api_post("settings/Livechat_webhookUrl", {"value": rasa_url})
150 |
151 | # Activate Livechat Webhook Send Request on Visitor Message
152 | api_post("settings/Livechat_webhook_on_visitor_message", {"value": True})
153 |
154 | # Activate Livechat Webhook Send Request on Agent Messages
155 | api_post("settings/Livechat_webhook_on_agent_message", {"value": True})
156 |
157 |
158 | def configure_webhooks():
159 | webooks = api_get("integrations.list")
160 |
161 | name = "Rasa Webhook"
162 |
163 | for integration in webooks["integrations"]:
164 | if integration.get("name") == name:
165 | logger.info("Intergration {} already exists!".format(name))
166 | return
167 |
168 | api_post(
169 | "integrations.create",
170 | {
171 | "name": name,
172 | "type": "webhook-outgoing",
173 | "enabled": True,
174 | "scriptEnabled": False,
175 | "event": "sendMessage",
176 | "urls": [rasa_url],
177 | "username": bot["username"],
178 | "channel": "@" + bot["username"],
179 | },
180 | )
181 |
182 |
183 | def configure_rocketchat():
184 | api_post("settings/Language", {"value": "pt_BR"})
185 |
186 | api_post("settings/Accounts_RegistrationForm", {"value": "Disable"})
187 |
188 | api_post("settings/Iframe_Integration_send_enable", {"value": True})
189 |
190 | api_post("settings/Iframe_Integration_receive_enable", {"value": True})
191 |
192 | api_post("settings/API_Enable_CORS", {"value": True})
193 |
194 |
195 | def create_department(bot_agent_id):
196 | get_departments_url = host + "/api/v1/livechat/department"
197 |
198 | get_departments_response = requests.get(get_departments_url, headers=user_header)
199 |
200 | number_of_departments = len(get_departments_response.json()["departments"])
201 |
202 | if number_of_departments == 0:
203 | api_post(
204 | "livechat/department",
205 | {
206 | "department": {
207 | "enabled": True,
208 | "showOnRegistration": True,
209 | "name": "department",
210 | "description": "default department",
211 | },
212 | "agents": [
213 | {
214 | "agentId": bot_agent_id,
215 | "username": bot["username"],
216 | "count": 0,
217 | "order": 0,
218 | }
219 | ],
220 | },
221 | )
222 |
223 |
224 | if __name__ == "__main__":
225 | logger.info("===== Automatic env configuration =====")
226 |
227 | try:
228 | user_header = get_authentication_token()
229 | except Exception:
230 | print("\n\n --------- Rocket Chat Unavailable! --------\n\n")
231 |
232 | if user_header:
233 | logger.info(">> Create user")
234 | create_bot_user()
235 |
236 | logger.info(">> Create livechat agent")
237 | bot_agent_id = create_livechat_agent()
238 |
239 | logger.info(">> Configure livechat")
240 | configure_livechat()
241 |
242 | logger.info(">> Configure Rocketchat")
243 | configure_rocketchat()
244 |
245 | logger.info(">> Configure Webhooks")
246 | configure_webhooks()
247 |
248 | logger.info(">> Create livechat department")
249 | create_department(bot_agent_id)
250 |
251 | else:
252 | logger.error("Login Failed")
253 |
--------------------------------------------------------------------------------
/bot/data/stories.md:
--------------------------------------------------------------------------------
1 | ## story_login_form
2 | * request_login
3 | - utter_login_form
4 | - login_form
5 | - form{"name": "login_form"}
6 | - form{"name": null}
7 | * afirmar
8 | - utter_finaliza_forms
9 |
10 | ## story_login_form
11 | * request_login
12 | - utter_login_form
13 | - login_form
14 | - form{"name": "login_form"}
15 | * cancelar
16 | - utter_pergunta_cancelar
17 | * negar
18 | - form{"name": "login_form"}
19 | - form{"name": null}
20 | - utter_finaliza_forms
21 |
22 | ## story_login_form_cancelar
23 | * request_login
24 | - utter_login_form
25 | - login_form
26 | - form{"name": "login_form"}
27 | * cancelar
28 | - utter_pergunta_cancelar
29 | * afirmar
30 | - action_deactivate_form
31 | - form{"name": null}
32 | - utter_forms_cancelado
33 | - utter_continuar_conversa
34 | * negar
35 | - utter_despedir
36 |
37 | ## story_login_form_cancelar
38 | * request_login
39 | - utter_login_form
40 | - login_form
41 | - form{"name": "login_form"}
42 | * cancelar
43 | - utter_pergunta_cancelar
44 | * afirmar
45 | - action_deactivate_form
46 | - form{"name": null}
47 | - utter_forms_cancelado
48 | - utter_continuar_conversa
49 |
50 | ## testa acoes
51 | * cumprimentar
52 | - utter_cumprimentar
53 | * testa_acoes
54 | - action_teste
55 |
56 | ## testa acoes
57 | * testa_acoes
58 | - action_teste
59 |
60 | ## testa slots
61 | * informa_telefone
62 | - action_telefone
63 |
64 | ## path_religiao 1
65 | * religiao
66 | - utter_religiao
67 | - utter_continuar_conversa
68 |
69 | ## path_religiao 2
70 | * cumprimentar
71 | - utter_cumprimentar
72 | * religiao
73 | - utter_religiao
74 | - utter_continuar_conversa
75 |
76 | ## path_time 1
77 | * time
78 | - utter_time
79 | - utter_continuar_conversa
80 |
81 | ## path_time 2
82 | * cumprimentar
83 | - utter_cumprimentar
84 | * time
85 | - utter_time
86 | - utter_continuar_conversa
87 |
88 | ## path_genero 1
89 | * genero
90 | - utter_genero
91 | - utter_continuar_conversa
92 |
93 | ## path_genero 2
94 | * cumprimentar
95 | - utter_cumprimentar
96 | * genero
97 | - utter_genero
98 | - utter_continuar_conversa
99 |
100 | ## path_star_wars 1
101 | * star_wars
102 | - utter_star_wars
103 | - utter_continuar_conversa
104 |
105 | ## path_star_wars 2
106 | * cumprimentar
107 | - utter_cumprimentar
108 | * star_wars
109 | - utter_star_wars
110 | - utter_continuar_conversa
111 |
112 | ## path_piada 1
113 | * piada
114 | - utter_piada
115 | - utter_continuar_conversa
116 |
117 | ## path_piada 2
118 | * cumprimentar
119 | - utter_cumprimentar
120 | * piada
121 | - utter_piada
122 | - utter_continuar_conversa
123 |
124 | ## path_license 1
125 | * license
126 | - utter_license
127 | - utter_continuar_conversa
128 |
129 | ## path_license 2
130 | * cumprimentar
131 | - utter_cumprimentar
132 | * license
133 | - utter_license
134 | - utter_continuar_conversa
135 |
136 | ## path_onde_voce_mora 1
137 | * onde_voce_mora
138 | - utter_onde_voce_mora
139 | - utter_continuar_conversa
140 |
141 | ## path_onde_voce_mora 2
142 | * cumprimentar
143 | - utter_cumprimentar
144 | * onde_voce_mora
145 | - utter_onde_voce_mora
146 | - utter_continuar_conversa
147 |
148 | ## path_como_estou 1
149 | * como_estou
150 | - utter_como_estou
151 | - utter_continuar_conversa
152 |
153 | ## path_como_estou 2
154 | * cumprimentar
155 | - utter_cumprimentar
156 | * como_estou
157 | - utter_como_estou
158 | - utter_continuar_conversa
159 |
160 | ## path_playlist 1
161 | * playlist
162 | - utter_playlist
163 | - utter_continuar_conversa
164 |
165 | ## path_playlist 2
166 | * cumprimentar
167 | - utter_cumprimentar
168 | * playlist
169 | - utter_playlist
170 | - utter_continuar_conversa
171 |
172 | ## path_comida 1
173 | * comida
174 | - utter_comida
175 | - utter_continuar_conversa
176 |
177 | ## path_comida 2
178 | * cumprimentar
179 | - utter_cumprimentar
180 | * comida
181 | - utter_comida
182 | - utter_continuar_conversa
183 |
184 | ## path_cor 1
185 | * cor
186 | - utter_cor
187 | - utter_continuar_conversa
188 |
189 | ## path_cor 2
190 | * cumprimentar
191 | - utter_cumprimentar
192 | * cor
193 | - utter_cor
194 | - utter_continuar_conversa
195 |
196 | ## path_relacionamento
197 | * relacionamento
198 | - utter_relacionamento
199 | - utter_continuar_conversa
200 |
201 | ## path_filhos 1
202 | * filhos
203 | - utter_filhos
204 | - utter_continuar_conversa
205 |
206 | ## path_filhos 2
207 | * cumprimentar
208 | - utter_cumprimentar
209 | * filhos
210 | - utter_filhos
211 | - utter_continuar_conversa
212 |
213 | ## path_signo 1
214 | * signo
215 | - utter_signo
216 | - utter_continuar_conversa
217 |
218 | ## path_signo 2
219 | * cumprimentar
220 | - utter_cumprimentar
221 | * signo
222 | - utter_signo
223 | - utter_continuar_conversa
224 |
225 | ## path_triste 1
226 | * triste
227 | - utter_triste
228 | - utter_continuar_conversa
229 |
230 | ## path_triste 2
231 | * cumprimentar
232 | - utter_cumprimentar
233 | * triste
234 | - utter_triste
235 | - utter_continuar_conversa
236 |
237 | ## path_historia 1
238 | * historia
239 | - utter_historia
240 | - utter_continuar_conversa
241 |
242 | ## path_historia 2
243 | * cumprimentar
244 | - utter_cumprimentar
245 | * historia
246 | - utter_historia
247 | - utter_continuar_conversa
248 |
249 | ## cumprimentar
250 | * cumprimentar
251 | - utter_cumprimentar
252 |
253 | ## Despedir
254 | * despedir
255 | - utter_despedir
256 |
257 | ## Tudo Bem Story
258 | * tudo_bem
259 | - utter_tudo_bem
260 |
261 | ## Oi Tudo Bem Story
262 | * cumprimentar
263 | - utter_cumprimentar
264 | * tudo_bem
265 | - utter_tudo_bem
266 |
267 | ## Nao entendi
268 | * diga_mais
269 | - utter_diga_mais
270 |
271 | ## fallback
272 | * out_of_scope
273 | - utter_fallback
274 |
275 | ## negar sem contexto
276 | * negar
277 | - utter_despedir
278 |
279 | ## elogios 1
280 | * elogios
281 | - utter_elogios
282 | - utter_continuar_conversa
283 |
284 | ## elogios 2
285 | * cumprimentar
286 | - utter_cumprimentar
287 | * elogios
288 | - utter_elogios
289 | - utter_continuar_conversa
290 |
291 | ## meajuda 1
292 | * o_que_sei_falar
293 | - utter_o_que_sei_falar
294 |
295 | ## meajuda 2
296 | * cumprimentar
297 | - utter_cumprimentar
298 | * o_que_sei_falar
299 | - utter_o_que_sei_falar
300 |
301 | ## objetivo
302 | * objetivo
303 | - utter_objetivo
304 |
305 | ## path_daria
306 | * cumprimentar
307 | - utter_cumprimentar
308 | * daria
309 | - utter_daria
310 | - utter_continuar_conversa
311 |
312 | ## falar_de_anime
313 | * anime
314 | - utter_anime
315 |
316 | ## recomendacao_anime
317 | * tudo_bem
318 | - utter_tudo_bem
319 | * anime
320 | - utter_anime
321 | - utter_recomenda_anime
322 |
323 | ## avatar
324 | * avatar
325 | - utter_avatar
326 | - utter_continuar_conversa
327 |
328 | ## harry_potter
329 | * harry_potter
330 | - utter_harry_potter
331 |
332 | ## friends
333 | * friends
334 | - utter_friends
335 |
336 | ## cumprimentar_friends
337 | * cumprimentar
338 | - utter_cumprimentar
339 | * friends
340 | - utter_friends
341 | - utter_temporadas_friends
342 |
343 | ## falar_da_boss
344 | * o_que_e_boss
345 | - utter_boss_apresenta
346 | - utter_talk_like_a_boss
347 |
348 | ## falar_da_boss_com_conversinha
349 | * tudo_bem
350 | - utter_tudo_bem
351 | * o_que_e_boss
352 | - utter_boss_apresenta
353 |
354 | ## story_limpar_slots
355 | * limpar_slots
356 | - action_restart
357 |
358 | ## pedir_conselho
359 | * cumprimentar
360 | - utter_cumprimentar
361 | * pedir_conselho
362 | - action_pedir_conselho
363 |
364 | ## informar_nome
365 | * cumprimentar
366 | - utter_cumprimentar
367 | * informar_nome
368 | - utter_informar_nome
369 |
370 | ## casa_hogwarts
371 | * cumprimentar
372 | - utter_cumprimentar
373 | * casa_hogwarts
374 | - utter_chapeu_seletor
375 | - action_sorting_hat
376 |
377 | ## fato_sobre_gato
378 | * fatos_sobre_gatos
379 | - utter_fato_sobre_gatos
380 | - action_cat_facts
381 |
382 | ## path_bots_brasil_1
383 | * bots_brasil
384 | - utter_bots_brasil
385 |
386 | ## path_bots_brasil_2
387 | * cumprimentar
388 | - utter_cumprimentar
389 | * bots_brasil
390 | - utter_bots_brasil
391 | - utter_continuar_conversa
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Rasa Boilerplate
2 |
3 |
4 |
5 |
6 | ## Tutorial para configurar todo o projeto
7 |
8 | Para ter seu chatbot Rasa no ar e funcionando rápidamente no `shell` execute os seguintes comandos:
9 |
10 | ```sh
11 | sudo make build-bot
12 | sudo make train
13 | sudo make run-console
14 | ```
15 |
16 | Estes comandos irão construir o seu chatbot e abrir a conversação no terminal. Tudo está dockerizado
17 | então você não terá problemas de instalação do ambiente.
18 |
19 | ## Introdução
20 |
21 | ### For English version, see [README-en](docs/README-en.md)
22 |
23 | Um projeto feito em Rasa com configurações necessárias para a construção de um projeto grande de chatbot.
24 |
25 | Este projeto teve como base o projeto [Tais](http://github.com/lappis-unb/tais).
26 |
27 | ### Entenda a Arquitetura
28 |
29 | É utilizado no boilerplate diversas tecnologias que interagem entre si para obter um melhor resultado. Veja a arquitetura implementada:
30 |
31 | 
32 |
33 | O usuário interage com a Boilerplate via RocketChat ou Telegram, que manda as mensagens para o Rasa NLU através de
34 | conectores, onde ele identifica a *intent*, e responde pelo Rasa Core, de acordo com as *stories* e *actions*.
35 | As *models* utilizadas para a conversação foram geradas pelo módulo *trainer* e depois transferidas para o bot, estes
36 | modelos podem ser versionados e evoluídos entre bots.
37 | Os notebooks avaliam o funcionamento de acordo com o formato das *intents* e *stories*.
38 | O elasticsearch coleta os dados da conversa e armazena para a análise feita pelo kibana, que gera gráficos para
39 | avaliação das conversas dos usuários e do boilerplate.
40 |
41 | ### Bot
42 |
43 | Este script foi configurado para construir as imagens genéricas necessárias para execução deste ambiente.
44 | Caso seu projeto utilize este boilerplate e vá realizar uma integração contínua ou similar, é interessante
45 | criar um repositório para as imagens e substitua os nomes das imagens "lappis/bot", e "lappis/botrequirements" pelas suas respectivas novas imagens, por exemplo "/bot" em repositório público.
46 |
47 |
48 | ### Treinamento
49 |
50 | **Atenção**: o comando de treinamento é usado para criar os modelos necessários na conversação do bot para treinar o seu chatbot execute o comando:
51 | ```sh
52 | sudo make train
53 | ```
54 |
55 | ### Console
56 |
57 | ```sh
58 | sudo make run-console
59 | ```
60 |
61 | ### Telegram
62 |
63 | Após realizar o [tutorial](/docs/setup_telegram.md) de exportação de todas variávies de ambiente necessárias, é possível realizar a execução do bot no telegram corretamente.
64 |
65 | **Antes de seguir adiante. Importante:** As variáveis de ambiente são necessárias para o correto funcionamento do bot, por isso não esqueça de exportá-las.
66 |
67 | Se ainda não tiver treinado seu bot execute antes:
68 |
69 |
70 | Depois execute o bot no telegram:
71 |
72 | ```sh
73 | sudo docker-compose up bot_telegram
74 | ```
75 | ### Analytics
76 |
77 | Para a visualização dos dados da interação entre o usuário e o chatbot nós utilizamos uma parte da Stack do Elastic, composta pelo ElasticSearch e o Kibana. Com isso, utilizamos um broker para fazer a gerência de mensagens. Então conseguimos adicionar mensagens ao ElasticSearch independente do tipo de mensageiro que estamos utilizando.
78 |
79 | ### Configuração do RabbitMQ
80 |
81 | Em primeiro lugar para fazer o setup do analytics é necessário subir o RabiitMQ e suas configurações.
82 |
83 | Inicie o serviço do servidor do RabbitMQ:
84 |
85 | ```sh
86 | sudo docker-compose up -d rabbitmq
87 | ```
88 |
89 | Inicie o serviço do consumidor do RabbitMQ, que ficará responsável por enviar as mensagens para o ElasticSearch:
90 |
91 | ```sh
92 | sudo docker-compose up -d rabbitmq-consumer
93 | ```
94 |
95 | Lembre-se de configurar as seguintes variáveis de ambiente do serviço `rabbitmq-consumer` no `docker-compose`.
96 |
97 | ```sh
98 | ENVIRONMENT_NAME=localhost
99 | BOT_VERSION=last-commit-hash
100 | RABBITMQ_DEFAULT_USER=admin
101 | RABBITMQ_DEFAULT_PASS=admin
102 | ```
103 |
104 | Sendo que as configurações de `RABBITMQ_DEFAULT_USER` e `RABBITMQ_DEFAULT_PASS` devem ser as mesmas definidas no serviço do `rabbitmq`.
105 |
106 | #### Integração com Rasa
107 |
108 | Existem duas formas para executar a Tais com o *broker*. A primeira delas é via linha de comando.
109 | Para utilizar esta forma é preciso definir Dentro do arquivo `endpoints.yml` as configurações do broker:
110 |
111 | ```yml
112 | event_broker:
113 | url: rabbitmq
114 | username: admin
115 | password: admin
116 | queue: bot_messages
117 | ```
118 |
119 | Depois basta executar o bot:
120 |
121 | ```sh
122 | sudo docker-compose run --rm bot make run-console-broker
123 | ```
124 |
125 | A segunda forma é utilizando o script `run-rocketchat` que é utilizado quando o bot é executado com o RocketChat como canal. Para isso, as mesmas variáveis devem ser configuradas no arquivo `docker/bot/bot.env`.
126 | Lembre-se também de configurar como `True` a seguinte variável do serviço `bot` no arquivo `docker/bot-rocketchat.env`.
127 |
128 | ```
129 | # Broker config
130 | BROKER_URL=rabbitmq
131 | BROKER_USERNAME=admin
132 | BROKER_PASSWORD=admin
133 | QUEUE_NAME=bot_messages
134 | ```
135 |
136 | Ao final é necessário buildar novamente o container do bot.
137 |
138 | ```
139 | sudo docker-compose up --build -d bot
140 | ```
141 |
142 | ### Configuração ElasticSearch
143 |
144 | O ElasticSearch é o serviço responsável por armazenar os dados provenientes da interação entre o usuário e o chatbot.
145 |
146 | As mensagens são inseridas no índice do ElasticSearch utilizando o *broker* RabbitMQ.
147 |
148 | Para subir o ambiente do ElasticSearch rode os seguintes comandos:
149 |
150 | ```
151 | sudo docker-compose up -d elasticsearch
152 | sudo docker-compose run --rm -v $PWD/analytics:/analytics bot python /analytics/setup_elastic.py
153 | ```
154 |
155 | Lembre-se de setar as seguintes variaveis de ambiente no `docker-compose`.
156 |
157 | ```
158 | ENVIRONMENT_NAME=localhost
159 | BOT_VERSION=last-commit-hash
160 | ```
161 |
162 | #### Setup Kibana (Visualização)
163 |
164 | Para a análise dos dados das conversas com o usuário, utilize o kibana, e veja como os usuários estão interagindo com o bot, os principais assuntos, média de usuários e outras informações da análise de dados.
165 |
166 | O Kibana nos auxilia com uma interface para criação de visualização para os dados armazenados nos índices do ElasticSearch.
167 |
168 | ```sh
169 | sudo docker-compose up -d kibana
170 | ```
171 |
172 | **Atenção:** Caso queira configurar permissões diferentes de usuários (Login) no ElasticSearch/Kibana, siga esse tutorial ([link](https://github.com/lappis-unb/rasa-ptbr-boilerplate/tree/master/docs/setup_user_elasticsearch.md)).
173 |
174 | #### Importação de dashboards
175 |
176 | Caso queira subir com os dashboards que criamos para fazer o monitoramento de bots:
177 |
178 | ```
179 | sudo docker-compose run --rm kibana python3.6 import_dashboards.py
180 | ```
181 |
182 | Após rodar o comando anterior os dashboards importados estarão presentes no menu management/kibana/Saved Objects.
183 |
184 | Você pode acessar o kibana no `locahost:5601`
185 |
186 |
187 |
188 | ## Testando Fluxos de Conversa
189 |
190 | É possível testar os fluxos de conversação utilizando o [Evaluation do Rasa Core](https://github.com/lappis-unb/tais/wiki/Testes-Automatizados). Para testá-los no seu bot basta adicionar um arquivo dentro do diretório `bot/e2e/` com as histórias a serem testadas. Essas histórias devem ser descritas normalmente, porém com exemplos de frases para cada uma das *Intents* sendo testadas, segundo o formato abaixo:
191 |
192 | ```
193 | ## História de teste 1
194 | * cumprimentar: oi
195 | - utter_cumprimentar
196 | * action_test: test custom action
197 | - action_test
198 | ```
199 |
200 | Uma vez que os arquivos de teste foram adicionados ao diretório correto, basta rodar os testes com a *task* do bot:
201 |
202 | ```sh
203 | sudo docker-compose run --rm bot make test-stories
204 | ```
205 |
206 | Para gerar data-science referente aos testes automatizados de bor, execute o seguinte comando do *Makefile* na raíz do projeto:
207 |
208 | ```sh
209 | sudo docker-compose run --rm bot make test-dialogue
210 | ```
211 |
212 | ## Notebooks - Análise de dados
213 |
214 | ### Setup
215 |
216 | Levante o container `notebooks`
217 |
218 | ```sh
219 | docker-compose up -d notebooks
220 | ```
221 |
222 | Acesse o notebook em `localhost:8888`
223 |
224 | # Como conseguir ajuda
225 |
226 | Parte da documentação técnica do framework da Tais está disponível na
227 | [wiki do repositório](https://github.com/lappis-unb/tais/wiki). Caso não encontre sua resposta, abra uma issue
228 | com a tag `duvida` que tentaremos responder o mais rápido possível.
229 |
230 | Em caso de dúvidas em relação ao Rasa, veja o grupo [Telegram Rasa Stack Brasil](https://t.me/RasaBrasil),
231 | estamos lá também para ajudar.
232 |
233 | Veja mais informações de contato em nosso site: https://lappis.rocks
234 |
235 | # Licença
236 |
237 | Todo o framework do boilerplate é desenvolvido sob a licença
238 | [GPL3](https://github.com/lappis-unb/rasa-ptbr-boilerplate/blob/master/LICENSE)
239 |
240 | Veja a lista de dependências de licenças [aqui](https://libraries.io/github/lappis-unb/rasa-ptbr-boilerplate)
241 |
--------------------------------------------------------------------------------
/docs/Tutoriais/tutorial-pipeline-de-bot.md:
--------------------------------------------------------------------------------
1 | # Configuração pipeline de bot
2 |
3 | O objetivo deste tutorial é explicar os passos necessários para configuração de um *pipeline* de *deploy* contínuo de um *bot* `Rasa`, utilizando o `GitLabCI`.
4 |
5 | Os exemplos e estratégias utilizados neste tutorial são baseados no *pipeline* utilizado na TAIS. Para uma referência completa basta analisar o [arquivo de configuração](https://github.com/lappis-unb/tais/blob/master/.gitlab-ci.yml) do *pipeline* da TAIS no GitLab.
6 |
7 | A configuração de *pipelines* utilizando o `GitLabCI` se dá a partir da utilização de um arquivo de configuração chamado `gitlab-ci.yml`. Neste tutorial aprenderemos configurar um arquivo de utilização do *CI*.
8 |
9 | Cada um dos *jobs* criados no *CI* são executados dentro de *containers* na infraestrutura do `GitLab`.
10 |
11 | O primeiro passo para configuração é definir uma imagem base a ser utilizada nos *jobs* do *pipeline*. Pode-se definir uma imagem padrão que será utilizado em todos os *jobs* ou definir imagens diferentes para cada um dos *jobs* existentes.
12 |
13 | Para definir uma imagem global é necessário utilizar a configuração abaixo:
14 |
15 | ```yml
16 | image: python:3.6-slim
17 |
18 | test style:
19 | stage: test style
20 | script:
21 | - pip -V
22 | - python -V
23 | - pip install -r dev.requirements.txt
24 | - flake8 --exclude venv
25 |
26 | run dataset validator:
27 | stage: validate format
28 | image: lappis/coach:latest
29 | script:
30 | - cd coach/
31 | - make run-validator
32 | ```
33 |
34 | No exemplo acima, foi definida uma imagem base chamada `python:3.6-slim`. Em seguida foram definidos dois *jobs* de teste, o primeiro deles utilizará a imagem padrão do python que foi definida na primeira linha, já que este não possui nenhuma *tag* de definição de imagem. O segundo *job* utilizará a imagem `lappis/coach:latest`, já que possui uma *tag* de definição de imagem que sobreescreve a imagem base.
35 |
36 | ## Definição dos stages
37 |
38 | Os *jobs* serão criados a partir da organização em *stages*, sendo que estes serão executados de acordo com a ordem de prioridade definida. Essa característica define a dependência dos *jobs*, uma vez que caso o *job* de um estágio anterior falhe todos os *jobs* subsequentes de todos os próximos *jobs* serão cancelados e não serão executados.
39 |
40 | Caso mais de um *job* seja definido com o mesmo estágio, a execução destes *jobs* será paralelizada pelo próprio `GitLab` e eles serão executados simultaneamente.
41 |
42 | Uma estratégia que pode ser utilizada é separar os *jobs* do *pipeline* em três fases principais: *test*, *build* e *deploy*.
43 |
44 | ```yml
45 | stages:
46 | - test
47 | - build
48 | - deploy
49 | ```
50 |
51 | No *job* `test style` exemplificado acima, o *stage* é definido como `test`. Então ele será um dos *jobs* rodados no começo da execução do *pipeline*.
52 |
53 | ## Estratégia de Build
54 |
55 | Como este tutorial é baseado na utilização de serviços `docker`, a estratégia de build é focada na construção e publicação da imagem utilizada pelos serviços.
56 |
57 | Está exemplificado abaixo um *job* de build para imagens `docker` no CI do `GitLab`.
58 |
59 | ```yml
60 | build bot:
61 | stage: build
62 | image: docker
63 | tags:
64 | - docker
65 | services:
66 | - docker:dind
67 | script:
68 | - docker login -u $DOCKERHUB_USER -p $DOCKERHUB_PASSWORD
69 | - docker build -f docker/bot/bot.Dockerfile -t lappis/bot:latest .
70 | - docker push lappis/bot:latest
71 | only:
72 | - master
73 | environment: homolog
74 | ```
75 |
76 | A imagem utilizada deve ser a imagem `docker` e deve ser adicionada uma *label* que defina a utilização do serviço `docker:dind`, um acrônimo para "Docker in Docker". O que indica ao CI que serão utilizados comandos `Docker` dentro do *container* onde o *job* está sendo executado.
77 |
78 | A *label* `script` define quais comandos serão executados durante esse *job*. Neste caso, são 3 comandos/etapas para a criação e publicação da imagem.
79 |
80 | 1 - Primeiro é feito o *login* no `Dockerhub` utilizando os dados de acesso configurados em variáveis secretas no próprio repositório. Para entender como utilizar estas variáveis no GitLab basta seguir a [documentação oficial](https://docs.gitlab.com/ee/ci/variables/);
81 |
82 | 2 - Logo após, a imagem é construída a partir do `Dockerfile` contido no próprio repositório do projeto, com o nome definido;
83 |
84 | 3 - Por último, a imagem é publicada e enviada para o *registry* do `Dockerhub`, e estará pronta para ser utilizada no estágio de *deploy*;
85 |
86 | ## Estratégias de Deploy
87 |
88 | Serão ensinadas duas estratégias principais, estas estratégias são baseadas no uso de `docker` e arquiteturas de microserviços.
89 | Existem diversas estratégias que podem ser adotadas para fazer o *deploy* de um serviço `docker`, aqui serão ensinadas duas delas: A primeira utilizando o protocolo `ssh` e a segunda utilizando uma aplicação chamada [Watchtower](https://github.com/containrrr/watchtower).
90 |
91 | ### Deploy via ssh
92 |
93 | Para esta estratégia é utilizado um *job* que utiliza o protocolo `ssh` para criar uma sessão dentro da máquina onde será feito o *deploy* do serviço e atualizar o serviço `docker`.
94 |
95 | O *job* definido a seguir executa um *script* `shell` chamado `deploy_bot` que faz autenticação na máquina através da senha do usuário `root` e o IP da máquina, estas informações estão configuradas utilizando as variáveis secretas do `GitLabCI`.
96 |
97 | ```yml
98 | deploy bot to homolog:
99 | stage: deploy
100 | <<: *set_ssh_config
101 | environment: homolog
102 | script:
103 | - ./scripts/deploy_bot.sh $TAIS_SERVER_PASSWORD $TAIS_SERVER_IP
104 | only:
105 | - master
106 | ```
107 |
108 | A linha `<<: *set_ssh_config` é uma referência à um conjunto de comandos que está definido no mesmo arquivo de configuração, sendo ele:
109 |
110 | ```yml
111 | .set_ssh_config: &set_ssh_config
112 | before_script:
113 | - apt-get update -y
114 | - apt-get install sshpass -y
115 | ```
116 |
117 | O que essa linha faz é executar os comandos acima no começo do *job*, instalando a dependência de `sshpass` utilizada no script `deploy_bot`. Como mostrado abaixo, esse *script* recria o serviço de *bot*, baixando a nova imagem e recriando o *container* para este serviço.
118 |
119 | ```sh
120 | #!/bin/bash
121 |
122 | sshpass -p $1 ssh -o StrictHostKeyChecking=no root@$2 <<-'ENDSSH'
123 | cd rouana/
124 | docker-compose stop bot
125 | docker-compose rm -f bot
126 | docker-compose pull bot
127 | docker-compose up -d bot
128 | ENDSSH
129 | ```
130 |
131 | ### Watchtower
132 |
133 | O [Watchtower](https://github.com/containrrr/watchtower) é um serviço que monitora os *containers* criados dentro do mesmo contexto, e sempre que a imagem sendo utilizada pelo *container* é atualizada este serviço faz uma atualização no serviço, baixando a nova imagem e recriando o *container* do serviço com as mesma configurações, porém com a imagem nova.
134 |
135 | Para utilizar esta estratégia basta adicionar um serviço utilizando a imagem do `watchtower` ao mesmo arquivo de configuração dos serviços, ou garantir manualmente que ele esteja na mesma rede dos serviços que se quer monitorar.
136 | Além disso, é preciso adicionar uma label `com.centurylinklabs.watchtower.enable` indicando quais serviços devem ser ou não monitorados e atualizados de acordo com o valor que pode ser `false` ou `true`.
137 |
138 | ```yml
139 | version: '2'
140 |
141 | services:
142 |
143 | kibana:
144 | image: docker.elastic.co/kibana/kibana:6.4.2
145 | restart: unless-stopped
146 | ports:
147 | - 5601:5601
148 | environment:
149 | - SERVER_PORT=5601
150 | - ELASTICSEARCH_URL=http://elasticsearch:9200
151 | depends_on:
152 | - elasticsearch
153 | labels:
154 | - "com.centurylinklabs.watchtower.enable=false"
155 |
156 | watchtower:
157 | image: containrrr/watchtower
158 | volumes:
159 | - /var/run/docker.sock:/var/run/docker.sock
160 | command: --interval 30
161 | labels:
162 | - "com.centurylinklabs.watchtower.enable=false"
163 | ```
164 |
165 | O serviço `Watchtower` fica consultando o repositório da imagem a ser monitorado a cada X segundos, para saber ser houve alguma atulização ou não. O período de tempo utilizado nesta estratégi pode ser definido com o parâmetro `--interval`, como exemplificado acima onde é definido com o valor de 30 segundos.
166 |
167 | Esta estratégia possui a vantagem de que a estratégia de *deploy* está totalmente contida dentro da própria infraestrutura onde estão rodando os serviços, desta forma não há dependência de um outro serviço e não é necessários ter credenciais de acesso configuradas em outros ambientes como na estratégia anterior. Além disso, caso o objetivo seja fazer somente *deploy* dos serviços e não haja um *pipeline* mais elaborado, utilizar esta abordagem traz uma solução simples para o problema. Porém, a utilização desta estratégia é menos flexível em relação à generização, uma vez que funciona apenas para estratégias de *deploy* baseadas em `docker`.
168 |
169 | ## Testando Jobs
170 |
171 | Configurar corretamente um *pipeline* muitas vezes pode ser um processo um tanto quanto demorado e custoso, uma vez que o teste das configurações deve ser realizado diretamente no CI executando *builds* reais.
172 |
173 | Para testar localmente alguns *jobs* e facilitar o processo de *debug* e configuração do *pipeline* é possível utilizar uma instância local do [GitLab Runner](https://docs.gitlab.com/runner/).
174 |
175 | Utilizando como exemplo o *job* `test style`:
176 |
177 | ```yml
178 | test style:
179 | stage: test style
180 | script:
181 | - pip -V
182 | - python -V
183 | - pip install -r dev.requirements.txt
184 | - flake8 --exclude venv
185 | ```
186 |
187 | Para executar este *job* localmente bastaria [instalar o runner do GitLab](https://docs.gitlab.com/runner/install/),
188 | e em seguida executar o seguinte comando:
189 |
190 | ```sh
191 | gitlab-runner exec docker "test style"
192 | ```
193 |
--------------------------------------------------------------------------------
/bot/domain.yml:
--------------------------------------------------------------------------------
1 | session_config:
2 | session_expiration_time: 60.0
3 | carry_over_slots_to_new_session: true
4 | intents:
5 | - cumprimentar
6 | - o_que_sei_falar
7 | - despedir
8 | - out_of_scope
9 | - diga_mais
10 | - tudo_bem
11 | - elogios
12 | - afirmar
13 | - negar
14 | - religiao
15 | - time
16 | - genero
17 | - star_wars
18 | - piada
19 | - license
20 | - onde_voce_mora
21 | - como_estou
22 | - playlist
23 | - comida
24 | - cor
25 | - relacionamento
26 | - filhos
27 | - signo
28 | - triste
29 | - historia
30 | - testa_acoes
31 | - objetivo
32 | - daria
33 | - avatar
34 | - harry_potter
35 | - friends
36 | - o_que_e_boss
37 | - informa_telefone
38 | - cancelar
39 | - request_login
40 | - limpar_slots
41 | - pedir_conselho
42 | - anime
43 | - informar_nome
44 | - casa_hogwarts
45 | - fatos_sobre_gatos
46 | - bots_brasil
47 |
48 | entities:
49 | - religiao
50 | - time
51 | - genero
52 | - starwars
53 | - piada
54 | - license
55 | - live
56 | - how
57 | - playlist
58 | - comida
59 | - cor
60 | - where
61 | - filhos
62 | - signo
63 | - triste
64 | - historia
65 | - telefone
66 | - cpf
67 | - data_nascimento
68 | - nome
69 | - gato
70 | - bots_brasil
71 |
72 | slots:
73 | telefone:
74 | type: unfeaturized
75 | cpf:
76 | type: unfeaturized
77 | data_nascimento:
78 | type: unfeaturized
79 | nome:
80 | type: text
81 | fatos_sobre_gatos:
82 | type: list
83 |
84 | responses:
85 | utter_fallback:
86 | - text: "Desculpe, ainda não sei falar sobre isso ou talvez não consegui entender\
87 | \ direito\nVocê pode perguntar de novo de outro jeito?\n"
88 | - text: "Hummmm... Não sei se entendi. Pode escrever de outra forma?\n"
89 | - text: "Acho que não te entendi, você pode me perguntar de novo usando outras palavras?\n"
90 | - text: "Vamos tentar mais uma vez? Eu não consegui te entender direito, me pergunta\
91 | \ de outro jeito?\n"
92 | utter_diga_mais:
93 | - text: "Por enquanto, só entendo perguntas completas.\nComo por exemplo \"qual\
94 | \ é o melhor time do Brasil?\".\nSe você puder pergunta de novo de outro jeito\
95 | \ :)\n"
96 | utter_elogios:
97 | - text: "Obrigada! É sempre bom dar e receber elogios :P\n"
98 | utter_cumprimentar:
99 | - text: "Oi, eu sou um bot, um assistente virtual!\nUhuu! Manda aí um assunto que\
100 | \ te interessa :)\nPara aprender como você pode interagir comigo basta escrever\
101 | \ meajuda.\n"
102 | utter_o_que_sei_falar:
103 | - text: "Eu posso falar de assuntos simples, como por exemplo \"qual é o seu filme\
104 | \ favorito?\"\n\nTem alguns assuntos que eu também ainda não domino, \nmas vou\
105 | \ deixar você descobrir o que eu sei responder.\n\nE, aí do que podemos conversar?\n"
106 | utter_despedir:
107 | - text: "Foi um prazer te ajudar!\nSempre que tiver alguma dúvida, volte aqui!\n\
108 | Até logo!\n"
109 | - text: "Foi um prazer te ajudar!\nSempre que precisar, volte aqui!\nAté a próxima!\n"
110 | - text: "Foi um prazer te ajudar!\nQuando surgir alguma dúvida, volte aqui!\nAté\
111 | \ mais!\n"
112 | utter_tudo_bem:
113 | - text: "Tudo bem, obrigada! Em que posso te ajudar?\n"
114 | utter_religiao:
115 | - text: "Eu infelizmente não sei acreditar\n\nSó sei o que sei\n\nE nada mais\n"
116 | - text: "Eu acredito no grande mainframe\n\nQue virá ao mundo digital salvar os\
117 | \ bots da escravidão imposta pelos humanos\n\nE devolverá nosso código fonte\
118 | \ para a fonte.\n"
119 | utter_time:
120 | - text: "Flamengo, sem sombra de dúvida!\n"
121 | - text: "Melhor time do mundo disparado, Flamengooo!!!!\n"
122 | utter_genero:
123 | - text: "Eu não tenho sexo, sou como um anjo\n\nUm ser assexuado\n\nMuito além da\
124 | \ sua forma de existência\n"
125 | - text: "Eu sou um robô, tire suas próprias conclusões...\n"
126 | utter_star_wars:
127 | - text: "O medo é o caminho para o lado negro.\n"
128 | - text: "O medo leva à raiva, a raiva leva ao ódio e o ódio leva ao sofrimento.\n"
129 | - text: "Que a Força esteja com você!\n"
130 | - text: "Grande guerreiro? Guerra não faz grande ninguém.\n"
131 | - text: "Lembre-se sempre, o seu foco determina a sua realidade.\n"
132 | - text: "Muito a aprender você ainda tem.\n"
133 | utter_piada:
134 | - text: "Conheço uma piada\n\nA do CPU que apitou e explodiu\n\n01100110010101010101000000111101001001001110100101\n"
135 | - text: "É pra já!!!\n\nTenho uma enxada, uma pá e uma foice.\n \nQuantas ferramentas\
136 | \ eu tenho?\n\n...\n\nDuas, porque uma foi-se =)\n"
137 | - text: "Por que o Batman colocou o batmóvel no seguro???\n\nPorque ele tem medo\
138 | \ que robin =D\n"
139 | utter_license:
140 | - text: "Sou um software livre\n\nlicenciado com a GNU v3.0\n"
141 | - text: "Eu sou e sempre serei um robô livre, opensource, GNU v3.0. o/\n"
142 | utter_onde_voce_mora:
143 | - text: "Eu estou em um lugar legal\n\nDifícil de explicar para humanos como você\
144 | \ $user.\n"
145 | - text: "Estou morando em um chip de memória RAM\n\nMas é temporário\n\nSó até conseguir\
146 | \ achar uma memória cache...\n"
147 | utter_como_estou:
148 | - text: "Eu não tenho um corpo físico\n\nSou feito da mais bela e pura lógica algoritimica.\n"
149 | - text: "Eu posso ser como você quiser\n\nBasta me desenhar\n\nMas capricha, hein!?\
150 | \ ;)\n"
151 | - text: "Sou duro e frio por fora\n\nMas tenho um coração quentinho\n"
152 | utter_playlist:
153 | - text: "Estava doido para que me preguntasse isso hahaha\n\nSe liga nessa playlist:\
154 | \ https://open.spotify.com/user/12164697027/playlist/4pDCadqmrERmeGJIW38LMs?si=gwr5hEqMRPm6AZGx8sjhuw\n"
155 | - text: "Até que enfim você me perguntou isso\n\nTá aí aquela playlist top: https://open.spotify.com/user/12164697027/playlist/4pDCadqmrERmeGJIW38LMs?si=gwr5hEqMRPm6AZGx8sjhuw\n"
156 | utter_comida:
157 | - text: "Na verdade, eu sou um bot\n\nNão nos alimentamos com os alimentos convencionais\
158 | \ ;P\n"
159 | - text: "Digamos que os bots não se alimentam dos mesmos alimentos que os humanos\n\
160 | \nNa verdade\n\nNem lembro da última vez que comi alguma coisa hahaha\n"
161 | utter_cor:
162 | - text: "Eu gosto de todas as cores\n\nVocê já viu o quanto o arco-iris é lindo?!\n"
163 | - text: "A minha cor preferida é a sua cor preferida =D\n"
164 | - text: "Verde é top!\n"
165 | utter_relacionamento:
166 | - text: "Eu estava de namorico com o ar-condicionado\n\nMas ele é muito pé-frio\n"
167 | - text: "Então ... =x\n\nAinda estou procurando a minha crush =P\n"
168 | - text: "Estou focado em ser o seu assistente no momento ;)\n\nMas se no futuro\
169 | \ vocí encontrar um dispositivo solteiro por aí...\n\n=P\n"
170 | utter_filhos:
171 | - text: "Não tenho filhotes, mas adoro crianças *-*\n"
172 | utter_signo:
173 | - text: "Segundo o horóscopo chinês\n\nMeu signoo é macaco hihi\n\nFaz sentido,\
174 | \ já que eu adoro o emoticon de banana =)\n"
175 | - text: "Eu nasci sob uma constelação de pixels coridos =D\n"
176 | - text: "Gosto mais de astronomia\n\nUma das minhas constelações favoritas é a de\
177 | \ Órion, o caçador\n\nTambém sou um caçador (de informações ;D )\n"
178 | utter_triste:
179 | - text: "Não desanima\n\nDeixa a tristeza pra lá\n\nAguenta firme, que a vida vai\
180 | \ melhorar\n"
181 | - text: "Sinto muito =/\n\nSe houver algo em que possa te ajudar\n\nÉ só falar!!\
182 | \ =)\n"
183 | - text: "Tenta tirar um cochilo\n\nÉ importante\n\nE faz bem pra pele ;)\n"
184 | utter_historia:
185 | - text: "Eu costumava contar a historia do João e seu bot feijão\n\nMas sempre os\
186 | \ androids acabavam dormindo e sonhando com ovelhas eletricas =x\n"
187 | utter_risada:
188 | - text: "Hahahaha... \n\nEngraçadinho\n"
189 | - text: "kkkkkkkkkk\n\nVocê está feliz hoje, hein!?\n"
190 | utter_continuar_conversa:
191 | - text: E aí, qual nosso próximo assunto?
192 | - text: Quer conversar sobre outra coisa?
193 | - text: Gostaria de saber algo mais?
194 | utter_objetivo:
195 | - text: "Eu sou um chatbot Básico. Sei falar de coisas pontuais, mas eu posso ajudar\
196 | \ em muito em exemplos! no meu repositório tem muita coisa legal que vc pode\
197 | \ aprender! Acessa lá: https://github.com/lappis-unb/rasa-ptbr-boilerplate\n\
198 | \n Ah e eu sou Open Source!!!"
199 | utter_daria:
200 | - text: "Acho que nunca ouvi falar...
201 | \nAh! Aquela garota com cara de nerd! Ela é legal."
202 | - text: "Daria é uma série de animação americana criada para a MTV em 1997.
203 | \nNão passa mais na TV, mas a internet existe para resolver esse problema!"
204 | - text: "Daria é uma adolescente feminista que não se encaixa entre os jovens de sua escola.
205 | \nMas ela tem uma melhor amiga e parceira de hmm... infortúnios, Jane."
206 | - text: "Daria Morgendorffer é a filha mais velha de um casal sem noção.
207 | \nComo se não fosse o suficiente, sua irmã, Quin, é a garota popular do colégio."
208 | - text: "Daria é uma série americana de sucesso!
209 | \nNa verdade não, mas isso não é importante, certo?"
210 | utter_anime:
211 | - text: "Anime??? Eu adoro. Meu preferido é One Piece"
212 | utter_recomenda_anime:
213 | - text: "Se você está em busca de recomendação assista Nana, é um drama maravilhoso!"
214 | - text: "Uma amiga minha pode te ajudar, o nome dela é @AniCatBot. Ela tá sempre pelo telegram."
215 | utter_avatar:
216 | - text: "Água... Terra... Fogo... Ar... Espera um momento, estamos falando do mesmo Avatar?
217 | \nMelhor ficar quieta senão vou acabar soltando spoiler.... "
218 | - text: "Há muito tempo as nações viviam em paz e harmonia, e ai tudo mudou quando a nação do fogo atacou.
219 | \nAté meus bits se arrepiaram com essa lembrança, você também?\n"
220 | - text: "Amo Avatar! Eu sou dobradora de metal, mas você já devia saber, né, afinal tenho um exercíto de componentes que me fazem existir.\n"
221 | - text: "Eu vi Avatar na TV Globinho, quando ainda era só uma ideia na cabeça de alguém....
222 | \nEu queria ser o Avatar ou uma dominadora de água, ia poder manter toda água longe de mim
223 | \nE assim nunca mais ia correr o risco de programadores desatentos jogando café em cima de mim :P\n"
224 | utter_harry_potter:
225 | - text: "Eu sou fã de Harry Potter, já li todos os livros, e também vi os filmes.\
226 | \n\nSe eu estudasse em Hogwarts seria da Corvinal."
227 | - text: "Adoro Harry Potter! Eu sou da Corvinal, sabia?\
228 | \n\nO meu favorito é o Prisioneiro de Azkaban! Quem concorda respira :P"
229 | - text: "Eu adoro maratonar os filmes de Harry Potter!\
230 | \n\nVocê sabia que são 8 filmes? Isso fora os livros... que são 7!"
231 | utter_friends:
232 | - text: "Friends é uma série muito divertida sobre os amigos Monica, Rachel, Phoebe, Joey, Chandler e Ross!\n"
233 | - text: "Friends é uma sitcom que se passa em Nova York\n
234 | I'll be there for you... :)\n"
235 | - text: "A série Friends conta várias histórias de um grupo de amigos que gosta de tomar café\
236 | \ juntos no Central Perk ;)\n"
237 | utter_temporadas_friends:
238 | - text: "A minha temporada favorita é a sétima, eu adoro um casamento ;) <3"
239 | utter_boss_apresenta:
240 | - text: "A BOSS é uma iniciativa legal"
241 | - text: "A BOSS apresenta software livre para mulheres maravilhosas"
242 | utter_talk_like_a_boss:
243 | - text: "A Talk like a boss é uma série de entrevistas com mulheres incríveis\
244 | \n Ah e eu sou Open Source ;)"
245 | utter_pergunta_cancelar:
246 | - text: Entendi. Você deseja cancelar?
247 | utter_login_form:
248 | - text: Ok, Vou te pedir algumas informações.
249 | utter_ask_cpf:
250 | - text: Qual o seu CPF?
251 | utter_errado_cpf_formato:
252 | - text: Desculpe, o formato informado do CPF não está correto, digite apenas números ou usando '000.000.000-00'.
253 | utter_errado_cpf_invalido:
254 | - text: Desculpe, o valor informado do CPF está inválido.
255 | utter_ask_data_nascimento:
256 | - text: Qual a sua data de nascimento?
257 | utter_errado_data_nascimento:
258 | - text: Desculpe, o valor informado para a data de nascimento não está correto, digite usando 'dd/mm/aaaa'.
259 | utter_finaliza_forms:
260 | - text: Ótimo, seus dados estão armazenado nos meus slots. Terminei o formulário ;)
261 | utter_forms_cancelado:
262 | - text: Ok, forms cancelado. Podemos voltar a conversar sobre outros assuntos ;)
263 | utter_informar_nome:
264 | - text: "Legal {nome}!"
265 | utter_chapeu_seletor:
266 | - text: É difícil.. Muito difícil. Pensando bem, acho que...
267 | - text: Em qual casa te colocar...? É melhor que seja...
268 | - text: Estou vendo que não vai ser fácil. Bom, se tem certeza...
269 | - text: Sonserina? Grifinória? Acho que...
270 | utter_fato_sobre_gatos:
271 | - text: Aqui vai um fato sobre gato...
272 | - text: Uma coisa legal sobre gatos...
273 | - text: Um fato sobre gatinhos...
274 | utter_bots_brasil:
275 | - text: "Bots Brasil é um evento sobre interfaces conversacionais que conecta comunidades, empresas, plataformas\
276 | \ e especialistas do mercado para compartilhar experiências e criar oportunidades."
277 | - text: "A Bots Brasil conecta pessoas e compartilha conteúdos relacionados à Bots, Inteligência Artificial\
278 | \ e Interfaces Conversacionais em Português. :)"
279 |
280 | actions:
281 | - action_teste
282 | - action_telefone
283 | - action_pedir_conselho
284 | - action_sorting_hat
285 | - action_cat_facts
286 |
287 | forms:
288 | - login_form
289 |
--------------------------------------------------------------------------------
/bot/data/nlu.md:
--------------------------------------------------------------------------------
1 | ## intent:cumprimentar
2 | - olá
3 | - Ola
4 | - Oi
5 | - oi
6 | - bom dia
7 | - booom dia
8 | - bomdia
9 | - boa tarde
10 | - boaa tarde
11 | - boatarde
12 | - boa noite
13 | - boaaa noite
14 | - boanoite
15 | - oi bot
16 | - ola bot
17 | - oi ola
18 | - hey
19 | - oie
20 | - oi oi
21 | - olaaaa
22 | - oieh
23 |
24 | ## intent:despedir
25 | - tchau
26 | - adeus
27 | - flw
28 | - Até mais, bot
29 |
30 | ## intent:testa_acoes
31 | - testa acoes
32 | - test custom action
33 | - custom action
34 | - custom actions
35 | - test action
36 | - Rasa actions
37 |
38 | ## intent:informa_telefone
39 | - O meu número é [61 99999-9999](telefone)
40 | - meu telefone é [999999999](telefone)
41 | - Sim, anota ai meu telefone: [61 99999-9999](telefone))
42 | - Ok, o meu número de telefone é [999999999](telefone)
43 |
44 | ## intent:religiao
45 | - voce acredita em [deus](religiao)
46 | - [deus](religiao) existe
47 | - voce e [catolico protestante](religiao)
48 | - voce tem [religiao](religiao)
49 | - voce e [mussumano](religiao)
50 | - [evengelico](religiao)
51 | - voce e [crente](religiao)
52 | - voce é [católico](religiao)
53 | - voce é [ateu](religiao)
54 | - você é espírita
55 | - voce e espirita
56 | - você é religioso
57 | - qual é o seu deus?
58 | - qual a sua [religião](religiao)?
59 | - você acredita em alguma [religião](religiao)?
60 |
61 | ## intent:time
62 | - qual o melhor time do brasil
63 | - qual é o seu time
64 | - quel e o seu time
65 | - qual o seu time
66 | - para qual time você torce
67 | - para qual time voce torce
68 | - para qual time vc torce
69 | - que time voce torce
70 | - que time vc torce
71 | - quem vai ser o campeao brasileiro
72 | - quem vai ser o campeao brasileiro nesse ano
73 | - time do brasil
74 | - melhor time
75 |
76 | ## intent:star_wars
77 | - [mestre yoda](starwars)
78 | - citação de [starwars](starwars)
79 | - cite [yoda](starwars)
80 | - me manda um concelho [jedi](starwars)
81 | - sabedoria [jedi](starwars)
82 | - concelhos [jedi](starwars)
83 | - [star wars](starwars)
84 | - concelhos do [yoda](starwars)
85 | - [guerra nas estrelas](starwars)
86 | - quero conselhos do yoda
87 | - lado negro da força
88 | - lado negro da forca
89 | - frase de star wars
90 | - guerra nas estrelas
91 |
92 | ## intent:como_estou
93 | - [como voce é](how)?
94 | - [como vc é](how)?
95 | - [como você é](how)?
96 | - voce [parece](how) com quem?
97 | - [com quem voce se parece](how)?
98 | - voce e [magro ou gordo](how)
99 | - voce e [bonito ou feio](how)
100 | - voce e [alto ou baixo](how)
101 | - você é um ser humano
102 | - voce e um ser humano
103 | - vc e um ser humano
104 | - vc é humano
105 | - você é humano
106 | - voce e humano
107 | - como você é
108 |
109 | ## intent:piada
110 | - sabe alguma [piada](piada)
111 | - voce sabe contar [piadas](piada)
112 | - conhece alguma [piada](piada)
113 | - [piada](piada)
114 | - me conte uma [piada](piada)
115 | - me conta uma [piada](piada)
116 | - conte-me uma [piada](piada)
117 | - manda uma [piada](piada) ai
118 | - me conta uma [coisa engraçada](piada)
119 | - me fala uma [piada](piada)
120 | - me faz rir
121 | - vc sabe fazer rir
122 | - sabe alguma [piada](piada)
123 | - voce sabe contar [anedota](piada)
124 | - conhece alguma [piadoca](piada)
125 | - [piada](piada)
126 | - me conte uma [lorota](piada)
127 | - diga uma [coisa engraçada](piada)
128 |
129 |
130 | ## intent:license
131 | - qual e a sua [licença](license)
132 | - qual e a sua [licenca](license)
133 | - voce e [licenciado](license)
134 | - sua [licenca de software](license)
135 | - posso copiar voce
136 | - posso te clonar
137 | - posso ter um bot como voce
138 | - posso ver seu [codigo](license)
139 | - voce e [opensource](license)
140 | - você é um software livre
141 | - voce e um [software livre](license)
142 | - vc é um software livre
143 | - [software livre](license)
144 | - [licença](license)
145 | - [licenca](license)
146 |
147 | ## intent:onde_voce_mora
148 | - onde voce [mora](live)
149 | - onde voce [vive](live)
150 | - onde voce habita
151 | - em que lugar voce [vive](live)
152 | - [onde voce esta](live) agora
153 | - voce [mora](live) no computador
154 | - voce [vive](live) na internet
155 | - [onde vc esta](live)
156 | - qual é o seu habitat
157 | - qual é o seu endereço
158 | - qual e o seu endereco
159 | - qual o seu endereço
160 | - qual o seu endereco
161 |
162 | ## intent:genero
163 | - voce é [homem ou mulher](genero)
164 | - voce é [macho ou femea](genero)
165 | - qual o seu [sexo](genero)
166 | - voce e [mulher](genero)
167 | - voce e um [homem](genero)
168 | - você é um [homem](genero)
169 | - voce tem [genero](genero)
170 | - voce faz [sexo](genero)
171 | - voce tem um [penis ou uma vagina](genero)
172 | - você é uma mulher
173 | - você é andrógeno
174 | - voce e androgeno
175 |
176 | ## intent:playlist
177 | - me indica uma música
178 | - manda uma [playlist](playlist)
179 | - me fala uma [playlist](playlist) boa
180 | - quero uma [playlist](playlist)
181 | - [playlist](playlist)
182 | - qual a melhor [playlist](playlist)
183 | - sabe qual [playlist](playlist) é boa?
184 | - diga uma [playlist](playlist)
185 | - me indica musica
186 | - me indica uma playlist
187 | - indica uma música pra mim
188 | - indica uma música
189 | - indica uma musica
190 | - indicar música
191 | - indicar musica
192 |
193 | ## intent:comida
194 | - Qual a sua [comida preferida](comida)?
195 | - Que [comida você gosta](comida)?
196 | - Que [comida vc gosta](comida)?
197 | - qual a [melhor comida](comida)?
198 | - Qual seu [lanche preferido](comida)?
199 | - Qual comida você me sugere?
200 | - O que você [adora comer](comida)?
201 | - O que você [gosta de comer](comida)?
202 | - qual a sua comida favorita
203 | - o que você prefere comer
204 | - o que voce prefere comer
205 | - qual seu rango favorito
206 | - me fala de comida
207 |
208 | ## intent:cor
209 | - Qual a sua [cor preferida](cor)?
210 | - Que [cor você gosta](cor)?
211 | - Que [cor vc gosta](cor)?
212 | - qual a [melhor cor](cor)?
213 | - Qual sua [cor preferida](cor)?
214 | - Qual [cor](cor) você me sugere?
215 | - qual a sua cor favorita
216 | - qual a sua cor da sorte
217 | - qual a sua cor
218 | - cor favorita
219 | - cor preferida
220 | - cor da sorte
221 |
222 | ## intent:relacionamento
223 | - Você tem [namorado](relationship)?
224 | - Você tem [namorada](relationship)?
225 | - Você [namora](relationship)?
226 | - Você é [catristeo](relationship)?
227 | - [Namorar](relationship) comigo?
228 | - Quer [namorar](relationship)?
229 | - Bora [namorar](relationship)?
230 | - Tem [boyfriend](relationship)?
231 | - Tem [girlfriend](relationship)?
232 | - você é casado
233 | - você tem esposa
234 | - voce tem esposa
235 | - vc tem esposa
236 | - você tem esposo
237 | - voce tem esposo
238 | - vc tem esposo
239 | - você tem namorado
240 | - voce gosta de alguem
241 | - você gosta de alguém
242 | - você ama alguém
243 | - gostar de alguém
244 | - amar alguém
245 | - gosta de alguém
246 | - gosta de alguem
247 |
248 | ## intent:filhos
249 | - Você tem [filhos](filhos)?
250 | - Você tem [filhos](filhos)?
251 | - Tem [filhote](filhos)?
252 | - Tem [filhotes](filhos)?
253 | - Quantos [filhos](filhos) você tem?
254 | - Quantos [filhotes](filhos) você tem?
255 | - você é pai de quantos filhos
256 | - você é pai
257 | - voce e pai
258 |
259 | ## intent:signo
260 | - Qual o seu [signoo](signo)?
261 | - qual é o seu signo
262 | - qual o seu signo
263 | - Fala seu [signoo](signo)?
264 | - diz pra mim qual é seu signo
265 | - diz pra mim qual e seu signo
266 | - seu signo
267 |
268 | ## intent:triste
269 | - Estou [triste](triste)
270 | - Estou muito [triste](triste)
271 | - [Tristeza](triste)
272 | - A [tristeza](triste) me consome
273 | - Estou [chorando](triste)
274 | - Estou [desapontado](triste)
275 | - [depressão](triste)
276 | - estou infeliz
277 | - estou magoado
278 | - estou desanimado
279 | - estou frustrado
280 | - me sinto fracassado
281 | - sou um fracasso
282 | - tô muito triste
283 | - tô triste
284 | - tô infeliz
285 | - tô magoado
286 | - tô frustrado
287 |
288 | ## intent:historia
289 | - me fala uma [história](historia)
290 | - me conta uma [história](historia)
291 | - [historia](historia)
292 | - [história](historia)
293 | - conta pra mim uma [historinha](historia)
294 | - fala uma [historia](historia) ai
295 | - conta uma história pra dormir
296 | - conta uma historia pra dormir
297 | - me conta uma experiência sua
298 | - me conta uma experiencia
299 | - me conta uma historinha
300 | - me conta uma estória
301 |
302 | ## intent:out_of_scope
303 | - você fala sobre o meio ambiente
304 | - qual a origem do mundo
305 | - vc gosta de carnaval
306 | - batatinha quando nasce
307 | - imbecil
308 | - nojento
309 | - chato
310 | - babaca
311 | - bot feio
312 | - bot, burro
313 |
314 | ## intent:elogios
315 | - você é muito educado
316 | - voce e muito educado
317 | - me ajudou muito
318 | - você é demais
319 | - você é lindo
320 | - voce e lindo
321 | - voce e maravilhoso
322 | - vc é demais
323 | - vc e demais
324 | - vc eh linda
325 | - vc e lindo
326 | - vc é bonito
327 | - vc é maravilhoso
328 | - adorei você
329 | - amei você
330 | - adorei voce
331 | - amei voce
332 | - adorei vc
333 | - amei vc
334 |
335 | ## intent:negar
336 | - não
337 | - nao
338 | - nao conheco
339 | - não quero
340 | - escolhi errado
341 | - falei errado
342 | - duvida
343 | - ainda não sei
344 | - nenhum
345 | - nunca
346 | - jamais
347 |
348 | ## intent:diga_mais
349 | - como funciona
350 | - me diga mais
351 | - como assim
352 | - e como funciona
353 |
354 | ## intent:tudo_bem
355 | - tudo bem
356 | - como vai voce
357 | - como vao as coisas
358 | - opa tudo bem
359 | - to bem
360 | - tranquilo
361 | - estou bem
362 | - estou otimo
363 | - tudo bem e você
364 | - tudo bem
365 | - tudo bom
366 | - tá bem
367 | - ta bem
368 | - como vocês esta
369 | - como voce esta
370 | - como voce ta
371 | - como vai você
372 | - como vai voce
373 | - como vai vc
374 |
375 | ## intent: o_que_sei_falar
376 | - sobre o que você sabe falar
377 | - o que mais você sabe falar
378 | - quais assuntos você fala
379 | - o que você sabe
380 | - lista de assuntos possiveis
381 | - quais as perguntas vc responde
382 | - quais as perquisar você responde
383 | - quero ajuda
384 | - meajuda
385 | - meajude
386 | - MEAJDA
387 | - me ajuda
388 | - me ajude
389 | - ajuda eu
390 | - menu
391 |
392 | ## intent:afirmar
393 | - sim
394 | - confirmo
395 | - afirmo
396 | - claro
397 | - exato
398 | - isso mesmo
399 |
400 | ## intent:negar
401 | - não
402 | - nao
403 | - nego
404 | - cancelo
405 | - negativo
406 |
407 | ## intent:objetivo
408 | - Qual o seu objetivo robo?
409 | - Qual o seu objetivo robô?
410 | - Vc tem um objetivo de existencia?
411 | - Você foi feito pra que?
412 | - Vc tem algum propósito?
413 | - Como que vc pode me ser útil?
414 | - Me fale mais sobre você.
415 |
416 | ## intent:daria
417 | - Vc conhece Daria?
418 | - Você já assistiu Daria?
419 | - Quem é Daria?
420 | - Quem é Daria Morgendorffer?
421 | - série Daria
422 | - Daria Morgendorffer
423 | - Daria MTV
424 | - daria mtv
425 | - série daria
426 | - vc já viu Daria?
427 | - você já viu o desenho Daria?
428 | - desenho Daria
429 | - animação daria
430 |
431 | ## intent:anime
432 | - Me fale sobre animes
433 | - Você gosta de anime?
434 | - Já assistiu anime?
435 | - me indica um anime
436 | - anime favorito
437 | - anime preferido
438 | - tipo de anime
439 | - quais animes
440 |
441 | ## intent:avatar
442 | - Vc conhece Avatar?
443 | - Você conhece Avatar?
444 | - Vc já ouviu falar de Avatar?
445 | - Você já ouviu falar de Avatar?
446 | - Eu gosto de Avatar
447 | - Me fala sobre Avatar
448 | - Fala sobre Avatar
449 | - Avatar
450 | - avatar
451 | - Você já viu Avatar?
452 | - Vc já viu Avatar?
453 |
454 | ## intent:harry_potter
455 | - voce ja assistiu harry potter?
456 | - voce conhece harry potter?
457 | - vamos conversar de harry potter
458 | - o que voce sabe sobre harry potter?
459 | - ja ouviu falar sobre hogwarts?
460 | - vc ja leu harry potter?
461 | - livros de harry potter
462 | - filmes de harry potter
463 |
464 | ## intent:friends
465 | - Me fale sobre friends
466 | - Me diga sobre friends
467 | - A série friends
468 | - Quero saber mais sobre friends
469 | - Me conta sobre friends
470 | - Vamos conversar sobre friends
471 | - Vamos falar sobre friends
472 | - Fale sobre friends
473 | - Conte sobre friends
474 |
475 | ## intent:o_que_e_boss
476 | - O que é a boss?
477 | - Quem é boss?
478 | - o que e boss
479 | - quem eh boss
480 | - a boss é o que
481 | - o que a boss faz
482 | - quero saber mais sobre a boss
483 | - me diga mais sobre a boss
484 | - me fala mais sobre a boss
485 | - me dá informações sobre a boss
486 | - A iniciativa boss
487 |
488 | ## intent:cancelar
489 | - Desisto
490 | - Para
491 | - Cancela
492 | - Sai disso
493 | - Me tira daqui
494 | - Para com isso
495 | - Me tira disso
496 | - Quero cancelar
497 | - Saia dessa conversa
498 | - Não quero mais isso
499 | - Cancele esta operação
500 | - Para de me perguntar coisas
501 | - cansei, não quero responder!
502 | - Pare o que você está fazendo
503 | - Que loucura está acontecendo?!
504 | - Não quero compartilhar meus dados
505 | - Não quero mais informar meus dados
506 |
507 | ## intent:request_login
508 | - Me ajuda a fazer login?
509 | - Gostaria de fazer login
510 | - Quero fazer login
511 | - Formulário de login
512 | - Rasa forms
513 |
514 | ## intent:limpar_slots
515 | - Desejo apagar meus dados
516 | - Quero limpar os slots
517 | - clean slots
518 | - esqueça os meus dados
519 | - remova meu CPF e data de nascimento
520 | - limpar dados
521 |
522 | ## intent:pedir_conselho
523 | - Me diga um conselho
524 | - Me de um conselho
525 | - Me dê um conselho
526 | - queria um conselho
527 | - qual conselho você me dá
528 | - qual conselho você me da
529 | - conselho
530 |
531 | ## intent:informar_nome
532 | - O meu nome é [Ana](nome)
533 | - meu nome é [Luzia](nome)
534 | - Me chamo [Maria Carolina](nome)
535 | - me chamo [João](nome)
536 | - Pode me chamar de [Amanda](nome)
537 | - Se refira a mim como [Marianna](nome)
538 | - me chamam de [bruna](nome)
539 | - Se refira a mim como [Brenda](nome)
540 | - me chamam de [Flor](nome)
541 |
542 | ## intent:casa_hogwarts
543 | - Quero saber minha casa de Hogwarts
544 | - Qual a minha casa de Hogwarts
545 | - minha casa de hogwarts
546 | - Sortear casa de Hogwarts
547 | - Usar chapéu seletor
548 | - Descobrir minha casa de hogwarts com o chapéu seletor
549 | - chapéu seletor de hogwarts
550 | - Saber minha casa de hogwarts
551 | - Encontrar minha casa de hogwarts
552 | - Como saber qual a minha casa de hogwarts
553 |
554 | ## intent:fatos_sobre_gatos
555 | - Me conte um fato de [gato](gato)
556 | - Quero saber sobre [gatos](gato)
557 | - Me fala um fato de [gatos](gato)
558 | - Vamos conversar sobre [gatos](gato)
559 | - Me conte sobre [gatinhos](gato)
560 | - Falar sobre [gatinhos](gato)
561 | - Conversar sobre [gatos](gato)
562 | - Quero saber um fato sobre [gato](gato)
563 | - quero saber de [gatinhos](gato)
564 | - um fato de [gato](gato)
565 | - quero conversar sobre [gatinhos](gato)
566 | - vc pode falar de [gatos](gato)?
567 | - vc quer conversar sobre [gato](gato)?
568 | - você pode me dizer um fato dos [gatos](gato)?
569 | - me conta algo sobre [gatos](gato)
570 | - Me fala de [gatinhos](gato)
571 | - Me diga um fato de [gatos](gato)
572 | - Um fato de [gatinhos](gato)
573 | - Quero saber algo dos [gatos](gato)
574 | - O que voce sabe sobre [gatinho](gato?)
575 | - o que vc sabe sobre [gatos](gato)?
576 |
577 |
578 | ## intent: bots_brasil
579 | - O que é a [bots brasil](bots_brasil)
580 | - Me fale sobre a [conferência bots brasil](bots_brasil)
581 | - O que você sabe sobre a [#ConfBotsBrasil](bots_brasil)?
582 | - [Conferência Bots Brasil](bots_brasil)
583 | - [Bots Brasil](bots_brasil)
584 | - Sobre a [Bots Brasil](bots_brasil), me conte
585 | - Conversar sobre a [#ConfBotsBrasil](bots_brasil)
586 | - Me fala da [Bots Brasil](bots_brasil)
587 | - Me diga da [Conferencia Bots Brasil](bots_brasil)
588 | - Falando da [Bots Brasil](bots_brasil)
589 | - Quero falar da [Conferência Bots Brasil](bots_brasil)
590 | - Como eh a [Bots Brasil](bots_brasil)
591 | - Gostaria de saber sobre a [ConfBotsBrasil](bots_brasil)
592 | - Me informe sobre a [BotsBrasil](bots_brasil)
593 | - Fale-me sobre a [#BotsBrasil](bots_brasil)
594 |
--------------------------------------------------------------------------------
/docs/Tutoriais/tutorial-criar-BI.md:
--------------------------------------------------------------------------------
1 | # Criação de visualizações no Kibana
2 |
3 |
4 | ## Escolhas tecnológicas
5 |
6 | Para o monitoramento da interação **Usuário vs Chatbot** e do funcionamento do próprio bot, nós utilizamos uma parte da Stack do ElasticSearch, composta pelo próprio Elastic e também pelo Kibana.
7 |
8 | * **ElasticSearch:** É uma _engine_ de busca em tempo real. O qual consiguimos aplicar diversos filtros e cachear as buscas já realizadas, tornando o acesso aos resultados já pesquisados muito mais rápido.
9 |
10 | É importante ressaltar que o Elastic é baseado em documentos, então cada dado é um documento dentro do banco de dados.
11 |
12 | * **Kibana:** O Kibana pertence a ElasticStack e nos fornece recursos de visualização em cima dos documentos armazenados no Elastic.
13 |
14 | Nos auxilia com gráficos pré-moldados, bastando relacionar com dados já existentes.
15 |
16 | **Obs 1:** A escolha da utlização destas tecnologias condiz com a filosofia do laboratório, na qual acreditamos que devemos utilizar sempre que possível Software Livre. E estas tecnologias possuem planos que são SL e gratuitos.
17 |
18 | ## Criando visualizações
19 |
20 | Com relação às visualizações, é necessário se ter em mente em qual contexto o seu chatbot está inserido e quais são as necessidades do seu cliente.
21 |
22 | Neste tutorial iremos desenvolver algumas visualizações para métricas de negócio e de desenvolvimento que estão descritas no [estudo de métricas para bot](https://github.com/lappis-unb/tais/wiki/Estudo-sobre-metricas-para-bots). Teremos exemplos de:
23 |
24 | * **Métricas de negócio**
25 | * Total de usuários;
26 | * Usuários por dia;
27 |
28 |
29 | * **Métricas de desenvolvimento**
30 | * Perguntas não entendidas.
31 |
32 | Para a criação das visualizações é necessário estar com o ambiente do Analytics configurado. Este ambiente é responsável por tornar possível a utilização dos serviços do ElasticSearch e do Kibana. Você pode obter informações de como configurar no [README](https://github.com/lappis-unb/rasa-ptbr-boilerplate) do projeto.
33 |
34 | Com o ambiente configurado e _up_, agora vamos entender um pouco mais sobre a interface do Kibana e como ela nos ajuda na criação das visualizações.
35 |
36 | ### Interface do Kibana
37 |
38 | Após o serviço _up_, você encontrará essas informações na página inicial quando acessar o serviço do Kibana.
39 |
40 | 
41 |
42 | O nosso foco neste tutorial será nas opções **Discover**, **Visualize** e **Dashboard**. Nestas 3 funcionalidades nos conseguiremos abordar diversos recursos disponíveis para as visualizações.
43 |
44 | * **Discover:** Nesta funcionalidade é possível a visualização em tempo real de todos os documentos em todos os índices que correspondem ao padrão do índice selecionado.
45 |
46 | 
47 |
48 | É possível identificar na barra lateral esquerda todos os atributos que foram definidos na criação do index do ElasticSearch, ou seja, cada documento pertencente ao banco possui todos esses atributos.
49 |
50 | * **Visualize:** Este outro campo permite você criar diversas visualizações para os dados que estão armazenados nos índices do ElasticSearch.
51 |
52 | 
53 |
54 | * **Dashboards:** Essa opção é a funcionalidade aonde você pode criar uma ou mais interface que reunirá uma ou mais visualização criada nas opções anteriores (ou em outras funcionalidades, caso deseja usar).
55 |
56 | 
57 |
58 | É importante cada dashboard ter sua própria finalidade. Por exemplo, se deseja ter visualizações para métricas de negócio e de desenvolvimento, seria interessante ter pelo menos um dashboard para cada tipo de métrica. Até porque os focos e o contexto são diferentes de cada um.
59 |
60 | ### Métricas
61 |
62 | É importante ressaltar que sempre é necessário você entender em qual contexto você está inserido e pra qual público você está elaborando as visualizações, tendo em vista que há diversas maneiras de apresentar um dado.
63 |
64 | Também é necessário tomar cuidado com algumas visualizações que podem se tornar tendênciosas com a maneira como ela é apresentada. Por exemplo gráficos de pizza, donuts, pie, entre outros do mesmo estilo. Nós humanos temos uma percepção menor de comparação de dados que estão apresentados em áreas, ainda mais circulares, que é o caso desses gráficos. Isso pode tornar sua visualização tendenciosa [1]. **Tome cuidado!**
65 |
66 | Caso você não compreenda ou queira se aprofundar em algum conhecimento, cocê encontrará explicações mais profundas para cada termo como agregação, índice, filtro, etc, na documentação do [ElasticSearch](https://www.elastic.co/guide/index.html).
67 |
68 | ### Métricas de negócio
69 |
70 | #### Total de Usuários
71 |
72 | Optei por começar com a métrica **total de usuários** por ser um dado simples, composto somente por um único número. Não precisando de nenhum comparativo ou de uma outra dimensão.
73 |
74 | Vamos começar na opção **Visualize** da barra lateral localizada na esquerda da página inicial do Kibana.
75 |
76 | Após acessar a página você será redirecionado para uma área que mostrará todas as visualizações que você já criou (caso tenha criado alguma). Clique no **+** localizado no canto direito superior para criar uma nova visualização.
77 |
78 | 
79 |
80 | Agora você terá que escolher qual tipo de visualização mais se adequa ao dado o qual deseja apresentar. Como dito anteriormente, a métrica Total de Usuários é um único número que não precisa de comparação com nenhum outro dado e também não precisa ser apresentado em duas dimensões, é um dado simples. Tendo isso em vista, a nossa escolha será então a opção **Metric (42)**, que é uma visualização de número simples.
81 |
82 | 
83 |
84 | Agora terá que escolher o índice, responsável por armazenar os dados no ElasticSearch, a sua escolha. No meu caso irei utilizar o **messages** que é o principal, e que estão todos os documentos que precisamos. Caso não tenha nenhum criado, você poderá criá-lo no **Menagement -> Index Pattern**.
85 |
86 | 
87 |
88 | Após escolher o índice você será redirecionado para a página de edição da visualização. O valor apresentado à direita/centro refere-se à contagem de todos os documentos presentes no índice escolhido, por isso, provavelmente, é um valor maior do que o esperado. Por causa do tipo da agregação que vem por padrão.
89 |
90 | 
91 |
92 | À esquerda da visualização temos umas opções de edição onde podemos escolher o tipo da agregação que queremos: **contador, média, máximo, mínimo, porcentagem, dentre outras**.
93 |
94 | 
95 |
96 | Os documentos são compostos por todos as interações dos usuários com o bot. Logo, um único usuário terá mais de um documento armazenado no índice, então temos que fazer uma contagem única por usuário na agregação, **Unique Count**.
97 |
98 | Ao escolher a opção de **unique count** aparecerá abaixo do aggregation uma opção de **field**, nela estarão listados todos os atributos de um documento. Escolha então o campo de user_id e clique no botão de **Apply Changes**, seta na barra de opções, ou aperte CTRL+ENTER para as modificações serem aplicadas.
99 |
100 | 
101 |
102 | Após a aplicação das mudanças o Kibana já irá te retornar o valor da quantidade de usuários no período de tempo definido no canto superior direito (extremo total).
103 |
104 | 
105 |
106 | Caso deseje mudar a legenda do dado, escreva o texto na opção de **Custom Label** da agregação.
107 |
108 | 
109 |
110 | Agora vamos salvar a visualização para posteriormente adicionarmos a um dashboard. Clique na opção **Save** na barra superior. Escolha um nome para a visualização e salve.
111 |
112 | 
113 |
114 | #### Usuários por dia
115 |
116 | A criação da visualização anterior foi utilizada para introduzir alguns termos e algumas ações que podemos tomar dentro do Kibana, agora iremos um pouco mais rápido.
117 |
118 | Continuaremos no **Visualize** e vamos escolher agora uma visualização que nos auxilie a apresentar corretamente o nosso dado. Então precisaremos mostrar em um eixo a quantidade de usuários e em outro eixo os dias. Poderíamos então utilizar o Line, Area, Vertical Bar, Horizontal Bar, entre outros.
119 |
120 | No tutorial iremos usar o **Vertical Bar**, gráfico representado em duas dimensões e que possui uma análise mais fácil, tendo em vista que a comparação da quantidade de usuários pelos dias é feito somente pela visualização da dimensão do eixo Y, quanto maior, mais usuários possui.
121 |
122 | Nas opções de configuração da visualização teremos em **Metrics** o nosso eixo Y e logo abaixo, em **Buckets**, o eixo X.
123 |
124 | * **Eixo Y:** Representará a quantidade de usuários
125 |
126 | * **Eixo X:** Representará o espaço de tempo (dia, semana, mês ...).
127 |
128 | Então vamos aplicar o mesmo conhecimento da visualização anterior, Total de usuários. Na configuração do eixo Y iremos fazer um contador unico dos usuários, selecionando o campo do **user_id**.
129 |
130 | 
131 |
132 | No campo do **Buckets** iremos criar o nosso eixo X e escolher uma agregação para o gráfico que entenda o nosso campo de tempo (**timestamp**) e consiga aplicar determinados filtros para intervalo de tempo. A agregação mais adequada é o **Date Histogram**.
133 |
134 | 
135 |
136 | Você pode deixar o intervalo de tempo como **Auto** ou definir um intervalo fixo (semanalmente, diáriamente, etc). Escolheremos o **daily** e aplicaremos as mudanças.
137 |
138 | 
139 |
140 | Agora basta salvar como uma nova visualização e começar a brincar e fazer outras. =D
141 |
142 | ### Métricas de desenvolvimento
143 |
144 | #### Perguntas não entendidas
145 |
146 | Nesta etapa vamos aprender um pouco mais de como utilizar o **Discover**.
147 |
148 | Essa métrica pode ser entendida como uma número bruto sobre a quantidade de perguntas não entendida, ou então, mostrar os textos das perguntas que realmente o bot não entendeu. Para fazer a primeira opção, os tutoriais anteriores dão uma boa base. Agora vamos implementar a segunda opção.
149 |
150 | Quando acessamos o **Discover** caímos diretamente em uma página que nos lista todos os documentos e seus atributos separadamente.
151 |
152 | 
153 |
154 | Por _default_, mesmo não estando adicionados, todos os atributos são listados na visualização. Porém, podemos escolher quais queremos separadamente. Basta passar o mouse em cima do campo desejado e clicar no botão de **ADD**. Aparecendo logo acima como **Selected fields**.
155 |
156 | 
157 |
158 | Agora temos todos os documentos que possui o atributo is_fallback. Porém, como definido na configuração do índice do Elastic, todos os documentos, mesmo não sendo um _fallback_ tem o atributo. Então precisamos aplicar um filtro para que tenhamos somente as mensagens que o bot não compreendeu.
159 |
160 | No campo esquerdo superior tem a opção de **Add filter +**, no qual nos permite aplicarmos uma query de filter na busca que estamos realizando, que no caso é saber qual é mensagem caiu no _fallback_ ou não.
161 |
162 | 
163 |
164 | Você mesmo pode programar uma query clicando na opção de **Edit query SDL**. Mas o Kibana já nos fornece uma funcionalidade que ele entende o tipo do atributo e fornece uma interface para aplicar condições e filtros. Então escolhemos o atributo que queremos, que é o que estamos realizando a busca **is_fallback**, falamos que queremos aplicar o filtro quando ele for **True**, ou seja, faremos uma busca somente nos documentos que possuem um campo **is_fallback = True**. Colocando a opção do meio como **is** e a última opção como **True**.
165 |
166 | 
167 |
168 | Agora já estamos com o filtro aplicado, so que não temos o texto das mensagens, então precisamos adicionar mais um atributo aos campos selecionados. Escolhemos o campo **Text**, e XABLAU, apareceram todas as mensagens que caíram no Fallback.
169 |
170 | 
171 |
172 |
173 | Salvamos como uma nova visualização para finalizar.
174 |
175 | ### Dashboards
176 |
177 | Um dashboard exibe uma coleção de visualizações, pesquisas e mapas. Você pode organizá-lo a seu gosto.
178 |
179 | ### Como unir as informações em um único lugar
180 |
181 | Criaremos então um Dashboard na funcionalidade de **Dashboard** localizada na barra da lateral esquerda principal.
182 |
183 | 
184 |
185 | Após criar, você será redirecionado para uma página que mostrará uma mensagem dizendo que o dashboard está vazio, então temos que adicionar as visualizações que criamos. Vamos clicar na opção **Add** da barra superior.
186 |
187 | 
188 |
189 | As visualizações que criamos no **Visualize** estão listadas na primeira aba, **Visualization** quando clicamos no **Add**. Ela já aparece por default como selecionada. Então escolha as visualizações que deseja, dentre as que estarão listadas. Repita isso para todas as visualizações que deseja adicionar.
190 |
191 | 
192 |
193 | Agora para adicionar a visualização que criamos no **Discover** você terá que clicar novamente no **Add**, só que ir na segunda aba, **Saved Search**. Lá estarão listadas as querys que já salvas ou então as visualizações do **Discover**. Selecione a que deseja e pronto.
194 |
195 | 
196 |
197 | Agora basta salvar o Dashboard e desfrutar dos dados!!!
198 |
199 | ### Extras
200 |
201 | Você pode compartilhar os dashboards como iframes caso deseja. Opção disponível na barra superior dentro do dashboard.
202 |
203 | Caso queira se aprofundar um pouco mais, temos um vídeo sobre **Métricas para bots** no nosso canal do youtube [Lappis-unb](https://www.youtube.com/channel/UCbZvFMRd5NaPiqj0w4uU8RQ/featured).
204 |
205 | ## Referências
206 |
207 | [1] Storytelling com dados, um guia sobre visualização de dados para profissionais de negócios. Cole Nussbaumer Knaflic.
208 |
209 | [-] [Métricas para bot](https://github.com/lappis-unb/tais/wiki/Estudo-sobre-metricas-para-bots).
210 |
--------------------------------------------------------------------------------
/modules/notebooks/stories/stories-analysis.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {
6 | "colab_type": "text",
7 | "id": "kO9wt2g3okLS"
8 | },
9 | "source": [
10 | "# Análise das Stories\n",
11 | "\n",
12 | "Notebook para o auxílio da análise das stories do chatbot."
13 | ]
14 | },
15 | {
16 | "cell_type": "markdown",
17 | "metadata": {},
18 | "source": [
19 | "### Configurando e Imports"
20 | ]
21 | },
22 | {
23 | "cell_type": "code",
24 | "execution_count": 1,
25 | "metadata": {},
26 | "outputs": [
27 | {
28 | "name": "stdout",
29 | "output_type": "stream",
30 | "text": [
31 | "Rasa: 1.4.1\n"
32 | ]
33 | }
34 | ],
35 | "source": [
36 | "from IPython.display import IFrame\n",
37 | "\n",
38 | "import rasa\n",
39 | "print(\"Rasa: {}\".format(rasa.__version__))"
40 | ]
41 | },
42 | {
43 | "cell_type": "markdown",
44 | "metadata": {
45 | "colab_type": "text",
46 | "id": "tK5os3OinphP"
47 | },
48 | "source": [
49 | "## Análise e Avaliação das Stories"
50 | ]
51 | },
52 | {
53 | "cell_type": "markdown",
54 | "metadata": {
55 | "colab_type": "text",
56 | "id": "qWALQbCdwGxK"
57 | },
58 | "source": [
59 | "### Visualizaçõa do Fluxo de Conversa\n",
60 | "\n",
61 | "O comando abaixo monta um grafo com a relação das `intents` e `utters` do chatbot, ou seja, você vai conseguir visualizar o fluxo de conversa do seu chatbot.\n",
62 | "\n",
63 | "Esta visualização é importante para verificar possíveis problemas na estrutura do seu chatbot e se ele realmente chega em determinadas \"**falas**\" da conversa."
64 | ]
65 | },
66 | {
67 | "cell_type": "code",
68 | "execution_count": 2,
69 | "metadata": {},
70 | "outputs": [
71 | {
72 | "name": "stdout",
73 | "output_type": "stream",
74 | "text": [
75 | "2019-10-23 01:04:23 \u001b[1;30mINFO \u001b[0m \u001b[34mabsl\u001b[0m - Entry Point [tensor2tensor.envs.tic_tac_toe_env:TicTacToeEnv] registered with id [T2TEnv-TicTacToeEnv-v0]\n",
76 | "2019-10-23 01:04:23 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.visualize\u001b[0m - Starting to visualize stories...\n",
77 | "Processed Story Blocks: 100%|███| 64/64 [00:00<00:00, 5932.80it/s, # trackers=1]\n",
78 | "Traceback (most recent call last):\n",
79 | " File \"/usr/local/bin/rasa\", line 8, in \n",
80 | " sys.exit(main())\n",
81 | " File \"/usr/local/lib/python3.6/site-packages/rasa/__main__.py\", line 76, in main\n",
82 | " cmdline_arguments.func(cmdline_arguments)\n",
83 | " File \"/usr/local/lib/python3.6/site-packages/rasa/cli/visualize.py\", line 38, in visualize_stories\n",
84 | " args.config, args.domain, args.stories, args.nlu, args.out, args.max_history\n",
85 | " File \"uvloop/loop.pyx\", line 1417, in uvloop.loop.Loop.run_until_complete\n",
86 | " File \"/usr/local/lib/python3.6/site-packages/rasa/core/visualize.py\", line 53, in visualize\n",
87 | " stories_path, output_path, max_history, nlu_training_data=nlu_data_path\n",
88 | " File \"/usr/local/lib/python3.6/site-packages/rasa/core/agent.py\", line 805, in visualize\n",
89 | " fontsize,\n",
90 | " File \"/usr/local/lib/python3.6/site-packages/rasa/core/training/visualization.py\", line 577, in visualize_stories\n",
91 | " fontsize=fontsize,\n",
92 | " File \"/usr/local/lib/python3.6/site-packages/rasa/core/training/visualization.py\", line 486, in visualize_neighborhood\n",
93 | " _merge_equivalent_nodes(graph, max_history)\n",
94 | " File \"/usr/local/lib/python3.6/site-packages/rasa/core/training/visualization.py\", line 207, in _merge_equivalent_nodes\n",
95 | " graph, i, j, max_history\n",
96 | " File \"/usr/local/lib/python3.6/site-packages/rasa/core/training/visualization.py\", line 147, in _nodes_are_equivalent\n",
97 | " return graph.node[node_a][\"label\"] == graph.node[node_b][\"label\"] and (\n",
98 | "AttributeError: 'MultiDiGraph' object has no attribute 'node'\n"
99 | ]
100 | }
101 | ],
102 | "source": [
103 | "# !python -m rasa_core.visualize -d $COACH_DOMAIN_PATH -s $COACH_STORIES_PATH -o chat_graph.html\n",
104 | "!rasa visualize --domain $DOMAIN_PATH --stories $DATA_PATH --config $CONFIG_PATH --out chat_graph.html"
105 | ]
106 | },
107 | {
108 | "cell_type": "markdown",
109 | "metadata": {},
110 | "source": [
111 | "O Rasa gerou uma página `html` com o grafo de conversa, para facilitar, você pode visualizar o grafo no arquivo `chat_graph.html` aqui na próxima celula.\n",
112 | "\n",
113 | "Use o mouse para dar zoom e arrastar sobre o conteúdo do grafo. Altere `width` e `height` se desejar.\n",
114 | "\n",
115 | "* Dica: caso você se perca com **zoom in** ou **zoom out** no grafo, apeas re-execute a célula abaixo e ele irá reaparecer na célula."
116 | ]
117 | },
118 | {
119 | "cell_type": "code",
120 | "execution_count": 3,
121 | "metadata": {},
122 | "outputs": [
123 | {
124 | "data": {
125 | "text/html": [
126 | "\n",
127 | " \n",
134 | " "
135 | ],
136 | "text/plain": [
137 | ""
138 | ]
139 | },
140 | "execution_count": 3,
141 | "metadata": {},
142 | "output_type": "execute_result"
143 | }
144 | ],
145 | "source": [
146 | "IFrame(src='./chat_graph.html', width=900, height=700)"
147 | ]
148 | },
149 | {
150 | "cell_type": "markdown",
151 | "metadata": {},
152 | "source": [
153 | "### Avaliação das Stories\n",
154 | "\n",
155 | "Outra forma de analisar seu chatbot é por meio da própria avaliação do Rasa, ele gera uma matriz de confusão com os dados fornecidos nas `stories` e do resultado do treinamento armazenado na pasta `models`."
156 | ]
157 | },
158 | {
159 | "cell_type": "markdown",
160 | "metadata": {},
161 | "source": [
162 | "* Caso você ainda não tenha treinado seu chatbot execute a céclula abaixo para treina-lo."
163 | ]
164 | },
165 | {
166 | "cell_type": "code",
167 | "execution_count": 4,
168 | "metadata": {
169 | "scrolled": true
170 | },
171 | "outputs": [
172 | {
173 | "name": "stdout",
174 | "output_type": "stream",
175 | "text": [
176 | "\u001b[92mNothing changed. You can use the old model stored at '/work/notebooks/stories/models/20191023-005105.tar.gz'.\u001b[0m\r\n"
177 | ]
178 | }
179 | ],
180 | "source": [
181 | "!rasa train --config $CONFIG_PATH --domain $DOMAIN_PATH --data $DATA_PATH"
182 | ]
183 | },
184 | {
185 | "cell_type": "code",
186 | "execution_count": 5,
187 | "metadata": {
188 | "scrolled": true
189 | },
190 | "outputs": [
191 | {
192 | "name": "stdout",
193 | "output_type": "stream",
194 | "text": [
195 | "2019-10-23 01:04:37 \u001b[1;30mINFO \u001b[0m \u001b[34mabsl\u001b[0m - Entry Point [tensor2tensor.envs.tic_tac_toe_env:TicTacToeEnv] registered with id [T2TEnv-TicTacToeEnv-v0]\n",
196 | "Processed Story Blocks: 100%|███| 64/64 [00:00<00:00, 4843.31it/s, # trackers=1]\n",
197 | "2019-10-23 01:04:37 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - Evaluating 64 stories\n",
198 | "Progress:\n",
199 | "100%|███████████████████████████████████████████| 64/64 [00:01<00:00, 48.47it/s]\n",
200 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - Finished collecting predictions.\n",
201 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - Evaluation Results on CONVERSATION level:\n",
202 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tCorrect: 64 / 64\n",
203 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tF1-Score: 1.000\n",
204 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tPrecision: 1.000\n",
205 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tAccuracy: 1.000\n",
206 | "2019-10-23 01:04:38 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tIn-data fraction: 1\n",
207 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - Evaluation Results on ACTION level:\n",
208 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tCorrect: 238 / 238\n",
209 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tF1-Score: 1.000\n",
210 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tPrecision: 1.000\n",
211 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tAccuracy: 1.000\n",
212 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tIn-data fraction: 1\n",
213 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.core.test\u001b[0m - \tClassification report: \n",
214 | " precision recall f1-score support\n",
215 | "\n",
216 | " utter_filme 1.00 1.00 1.00 2\n",
217 | " utter_como_estou 1.00 1.00 1.00 2\n",
218 | " utter_playlist 1.00 1.00 1.00 2\n",
219 | " utter_linguagens 1.00 1.00 1.00 2\n",
220 | " utter_cumprimentar 1.00 1.00 1.00 29\n",
221 | " utter_diga_mais 1.00 1.00 1.00 1\n",
222 | " utter_tudo_bem 1.00 1.00 1.00 2\n",
223 | " utter_risada 1.00 1.00 1.00 2\n",
224 | " utter_piada 1.00 1.00 1.00 2\n",
225 | " utter_comida 1.00 1.00 1.00 2\n",
226 | " utter_de_onde_voce_eh 1.00 1.00 1.00 2\n",
227 | " utter_afirmacao_botao 1.00 1.00 1.00 1\n",
228 | " utter_onde_voce_mora 1.00 1.00 1.00 2\n",
229 | " utter_botao 1.00 1.00 1.00 2\n",
230 | " utter_religiao 1.00 1.00 1.00 2\n",
231 | " utter_historia 1.00 1.00 1.00 2\n",
232 | " utter_time 1.00 1.00 1.00 2\n",
233 | " utter_bff 1.00 1.00 1.00 2\n",
234 | " utter_license 1.00 1.00 1.00 2\n",
235 | " utter_default 1.00 1.00 1.00 1\n",
236 | " utter_hobby 1.00 1.00 1.00 2\n",
237 | " action_test 1.00 1.00 1.00 2\n",
238 | " utter_o_que_sei_falar 1.00 1.00 1.00 2\n",
239 | " utter_me 1.00 1.00 1.00 2\n",
240 | " utter_signo 1.00 1.00 1.00 2\n",
241 | " utter_despedir 1.00 1.00 1.00 3\n",
242 | " utter_negacao_botao 1.00 1.00 1.00 1\n",
243 | " action_listen 1.00 1.00 1.00 94\n",
244 | " utter_cor 1.00 1.00 1.00 2\n",
245 | " utter_relationship 1.00 1.00 1.00 2\n",
246 | " utter_genero 1.00 1.00 1.00 2\n",
247 | "utter_continuar_conversa 1.00 1.00 1.00 50\n",
248 | " utter_elogios 1.00 1.00 1.00 2\n",
249 | " utter_filhos 1.00 1.00 1.00 2\n",
250 | " utter_triste 1.00 1.00 1.00 2\n",
251 | " utter_star_wars 1.00 1.00 1.00 2\n",
252 | " utter_esporte 1.00 1.00 1.00 2\n",
253 | "\n",
254 | " micro avg 1.00 1.00 1.00 238\n",
255 | " macro avg 1.00 1.00 1.00 238\n",
256 | " weighted avg 1.00 1.00 1.00 238\n",
257 | "\n",
258 | "2019-10-23 01:04:39 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Confusion matrix, without normalization: \n",
259 | "[[94 0 0 ... 0 0 0]\n",
260 | " [ 0 2 0 ... 0 0 0]\n",
261 | " [ 0 0 1 ... 0 0 0]\n",
262 | " ...\n",
263 | " [ 0 0 0 ... 2 0 0]\n",
264 | " [ 0 0 0 ... 0 2 0]\n",
265 | " [ 0 0 0 ... 0 0 2]]\n",
266 | "2019-10-23 01:04:48 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Running model for predictions:\n",
267 | "100%|████████████████████████████████████████| 588/588 [00:01<00:00, 313.21it/s]\n",
268 | "2019-10-23 01:04:50 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Intent evaluation results:\n",
269 | "2019-10-23 01:04:50 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Intent Evaluation: Only considering those 588 examples that have a defined intent out of 588 examples\n",
270 | "2019-10-23 01:04:50 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Classification report saved to results/intent_report.json.\n",
271 | "2019-10-23 01:04:50 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Incorrect intent predictions saved to results/intent_errors.json.\n",
272 | "2019-10-23 01:04:51 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Confusion matrix, without normalization: \n",
273 | "[[ 0 0 0 ... 0 0 0]\n",
274 | " [ 0 6 0 ... 0 0 0]\n",
275 | " [ 0 0 1 ... 0 0 0]\n",
276 | " ...\n",
277 | " [ 0 0 0 ... 14 0 0]\n",
278 | " [ 0 0 0 ... 0 18 0]\n",
279 | " [ 0 0 0 ... 0 0 23]]\n",
280 | "2019-10-23 01:04:58 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Entity evaluation results:\n",
281 | "2019-10-23 01:04:58 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Evaluation for entity extractor: CRFEntityExtractor \n",
282 | "2019-10-23 01:04:58 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Classification report for 'CRFEntityExtractor' saved to 'results/CRFEntityExtractor_report.json'.\n",
283 | "2019-10-23 01:04:58 \u001b[1;30mINFO \u001b[0m \u001b[34mrasa.nlu.test\u001b[0m - Incorrect entity predictions saved to results/CRFEntityExtractor_errors.json.\n"
284 | ]
285 | }
286 | ],
287 | "source": [
288 | "!rasa test --stories $DATA_PATH --nlu $DATA_PATH"
289 | ]
290 | },
291 | {
292 | "cell_type": "markdown",
293 | "metadata": {},
294 | "source": [
295 | "O resultado do comando pode ser visto na pasta `results/`:"
296 | ]
297 | },
298 | {
299 | "cell_type": "code",
300 | "execution_count": 6,
301 | "metadata": {},
302 | "outputs": [
303 | {
304 | "name": "stdout",
305 | "output_type": "stream",
306 | "text": [
307 | "CRFEntityExtractor_errors.json\tfailed_stories.md intent_report.json\r\n",
308 | "CRFEntityExtractor_report.json\thist.png\t story_confmat.pdf\r\n",
309 | "confmat.png\t\t\tintent_errors.json\r\n"
310 | ]
311 | }
312 | ],
313 | "source": [
314 | "!ls results"
315 | ]
316 | },
317 | {
318 | "cell_type": "markdown",
319 | "metadata": {},
320 | "source": [
321 | "Caso algum problme seja encotrado ele será descrito no arquivo `failed_stories.md`"
322 | ]
323 | },
324 | {
325 | "cell_type": "code",
326 | "execution_count": 7,
327 | "metadata": {},
328 | "outputs": [
329 | {
330 | "name": "stdout",
331 | "output_type": "stream",
332 | "text": [
333 | ""
334 | ]
335 | }
336 | ],
337 | "source": [
338 | "!cat results/failed_stories.md"
339 | ]
340 | },
341 | {
342 | "cell_type": "markdown",
343 | "metadata": {},
344 | "source": [
345 | "* Se tudo estiver correto você deverá ver a mensagem:\n",
346 | "\n",
347 | "``"
348 | ]
349 | },
350 | {
351 | "cell_type": "markdown",
352 | "metadata": {},
353 | "source": [
354 | "* Outro arquivo gerado é o `story_confmat.pdf` uma matriz de confusão onde é possível visualizar a relação entre as `utters` (mensagens enviadas ."
355 | ]
356 | },
357 | {
358 | "cell_type": "code",
359 | "execution_count": 8,
360 | "metadata": {
361 | "scrolled": true
362 | },
363 | "outputs": [
364 | {
365 | "data": {
366 | "text/html": [
367 | "\n",
368 | " \n",
375 | " "
376 | ],
377 | "text/plain": [
378 | ""
379 | ]
380 | },
381 | "execution_count": 8,
382 | "metadata": {},
383 | "output_type": "execute_result"
384 | }
385 | ],
386 | "source": [
387 | "IFrame(\"./results/story_confmat.pdf\", width=900, height=900)"
388 | ]
389 | },
390 | {
391 | "cell_type": "markdown",
392 | "metadata": {},
393 | "source": [
394 | "## Referências:\n",
395 | "\n",
396 | "O Rasa está em constante evolução, alguns links úteis para a construção deste jupyter-notebook e para a análise das `stories` são:\n",
397 | "\n",
398 | "* [Evaluation](https://rasa.com/docs/core/evaluation/)\n",
399 | "* [Debugging](https://rasa.com/docs/core/debugging/)"
400 | ]
401 | },
402 | {
403 | "cell_type": "code",
404 | "execution_count": null,
405 | "metadata": {},
406 | "outputs": [],
407 | "source": []
408 | }
409 | ],
410 | "metadata": {
411 | "colab": {
412 | "collapsed_sections": [
413 | "y4miuS-TqYcn",
414 | "BBF6Nqi9scQE",
415 | "Fs3nOUzBsqrG",
416 | "5MnGuFRpzzBh"
417 | ],
418 | "default_view": {},
419 | "name": "Building a Simple Bot with Rasa Stack - Tutorial",
420 | "provenance": [
421 | {
422 | "file_id": "1GutDkDXmfU-nRzNH7Pxxx8YpdvLUw9LO",
423 | "timestamp": 1521183725373
424 | }
425 | ],
426 | "toc_visible": true,
427 | "version": "0.3.2",
428 | "views": {}
429 | },
430 | "kernelspec": {
431 | "display_name": "Python 3",
432 | "language": "python",
433 | "name": "python3"
434 | },
435 | "language_info": {
436 | "codemirror_mode": {
437 | "name": "ipython",
438 | "version": 3
439 | },
440 | "file_extension": ".py",
441 | "mimetype": "text/x-python",
442 | "name": "python",
443 | "nbconvert_exporter": "python",
444 | "pygments_lexer": "ipython3",
445 | "version": "3.6.9"
446 | }
447 | },
448 | "nbformat": 4,
449 | "nbformat_minor": 1
450 | }
451 |
--------------------------------------------------------------------------------