├── .github
├── trigger.txt
└── workflows
│ ├── cicd.yml
│ ├── cleanup-branch.yml
│ └── cleanup-nightly.yml
├── .gitignore
├── .pre-commit-config.yaml
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── actions
├── __init__.py
├── actions.py
├── custom_forms.py
├── custom_forms_config.yml
├── handoff.py
├── handoff_config.yml
├── parsing.py
├── profile_db.py
└── requirements-actions.txt
├── chatroom_handoff.html
├── config.yml
├── credentials.yml
├── data
├── nlu
│ └── nlu.yml
├── rules
│ ├── rules.yml
│ └── rules_handoff.yml
└── stories
│ ├── stories.yml
│ ├── stories_switch_from_pay_credit_card.yml
│ ├── stories_switch_from_search_transactions.yml
│ └── stories_switch_from_transfer_money.yml
├── deploy
├── gcr-auth.json
└── values.yml
├── domain.yml
├── endpoints.yml
├── handoff.gif
├── images
├── cicd.png
└── financial-demo-eks-test-vpc.png
├── pyproject.toml
├── requirements-dev.txt
├── requirements.txt
├── run_rasa_action_server_with_ide.py
├── run_rasa_shell_with_ide.py
├── run_rasa_test_with_ide.py
├── scripts
├── delete_all_test_clusters.py
├── patch_gcr_auth_json.py
├── smoketest.py
└── wait_for_external_ip.sh
├── setup.cfg
└── tests
├── __init__.py
├── conftest.py
├── data
├── all_slots_filled_tracker.json
├── empty_tracker.json
├── pay_cc_confirmed.json
└── pay_cc_not_confirmed.json
├── db_test.py
├── test_actions.py
└── test_stories.yml
/.github/trigger.txt:
--------------------------------------------------------------------------------
1 | # A dummy file to trigger the workflow without making any actual change.
2 | # Just change something arbitrary in this text, like a space .
--------------------------------------------------------------------------------
/.github/workflows/cicd.yml:
--------------------------------------------------------------------------------
1 | # DISABLED until we change the workflow to reflect the actual live deployment
2 | # name: financial-demo cicd
3 |
4 | # on:
5 | # workflow_dispatch:
6 | # push:
7 | # paths:
8 | # - 'data/**'
9 | # - 'config.yml'
10 | # - 'domain.yml'
11 | # - 'actions/**'
12 | # - 'requirements.txt'
13 | # - 'Dockerfile'
14 | # - '.github/trigger.txt'
15 |
16 | # env:
17 | # # Keep these values in sync with the values in the Makefile
18 | # AWS_REGION: us-west-2
19 | # AWS_ECR_URI: 024629701212.dkr.ecr.us-west-2.amazonaws.com
20 | # AWS_ECR_REPOSITORY: financial-demo
21 | # AWS_S3_BUCKET_NAME: rasa-financial-demo
22 |
23 | # # Notes:
24 | # # (-) rasa & rasa-sdk versions are extracted from `requirements.txt`
25 | # # (-) TODO: extract this from Makefile
26 | # RASA_ENTERPRISE_VERSION: "1.1.0"
27 |
28 | # jobs:
29 | # params:
30 | # name: params
31 | # runs-on: ubuntu-latest
32 | # # Map step outputs to job outputs, for use by downstream jobs
33 | # outputs:
34 | # git_branch: ${{ steps.git.outputs.git_branch }}
35 | # do_deploy_to_prod_cluster: ${{ steps.git.outputs.do_deploy_to_prod_cluster }}
36 |
37 | # rasa_enterprise_version: ${{ steps.versions.outputs.rasa_enterprise_version }}
38 | # rasa_version: ${{ steps.versions.outputs.rasa_version }}
39 | # rasa_sdk_version: ${{ steps.versions.outputs.rasa_sdk_version }}
40 |
41 | # do_training: ${{ steps.rasa_model.outputs.do_training }}
42 |
43 | # aws_region: ${{ steps.aws.outputs.aws_region }}
44 | # aws_s3: ${{ steps.aws.outputs.aws_s3 }}
45 |
46 | # do_create_test_cluster: ${{ steps.aws.outputs.do_create_test_cluster }}
47 |
48 | # steps:
49 | # - name: git
50 | # id: git
51 | # run: |
52 | # echo $GITHUB_REF
53 | # git_branch=$(echo ${GITHUB_REF##*/})
54 |
55 | # echo "::set-output name=git_branch::$git_branch"
56 |
57 | # if [[ $git_branch == "main" ]]
58 | # then
59 | # echo "::set-output name=do_deploy_to_prod_cluster::true"
60 | # else
61 | # echo "::set-output name=do_deploy_to_prod_cluster::false"
62 | # fi
63 |
64 | # - name: checkout
65 | # uses: actions/checkout@v2
66 |
67 | # - name: files
68 | # id: files
69 | # if: github.event_name == 'push'
70 | # uses: jitterbit/get-changed-files@v1
71 |
72 | # - name: Configure AWS Credentials
73 | # uses: aws-actions/configure-aws-credentials@v1
74 | # with:
75 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
76 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
77 | # aws-region: ${{ env.AWS_REGION }}
78 |
79 | # - name: versions
80 | # id: versions
81 | # run: |
82 | # rasa_version=$( cat requirements.txt | grep 'rasa\[spacy\]' | cut -d'=' -f 3 )-spacy-en
83 | # rasa_sdk_version=$( cat requirements.txt | grep 'rasa-sdk' | cut -d'=' -f 3 )
84 |
85 | # echo "::set-output name=rasa_enterprise_version::${{ env.RASA_ENTERPRISE_VERSION }}"
86 | # echo "::set-output name=rasa_version::$rasa_version"
87 | # echo "::set-output name=rasa_sdk_version::$rasa_sdk_version"
88 |
89 | # - name: rasa_model
90 | # id: rasa_model
91 | # run: |
92 | # github_event_name=$(echo ${GITHUB_EVENT_NAME})
93 | # echo "github_event_name: $github_event_name"
94 |
95 | # aws_s3_rasa_model_exists=$( make aws-s3-rasa-model-exists )
96 | # echo "aws_s3_rasa_model_exists: $aws_s3_rasa_model_exists"
97 |
98 | # if [[ $github_event_name == 'workflow_dispatch' ]] || \
99 | # [[ $aws_s3_rasa_model_exists == 'false' ]] || \
100 | # [[ "${{ steps.files.outputs.all }}" == *"data/"* ]] || \
101 | # [[ "${{ steps.files.outputs.all }}" == *"config.yml"* ]] || \
102 | # [[ "${{ steps.files.outputs.all }}" == *"domain.yml"* ]] || \
103 | # [[ "${{ steps.files.outputs.all }}" == *"requirements.txt"* ]]
104 | # then
105 | # echo "::set-output name=do_training::true"
106 | # else
107 | # echo "::set-output name=do_training::false"
108 | # fi
109 |
110 | # - name: aws
111 | # id: aws
112 | # run: |
113 | # echo "::set-output name=aws_region::${{ env.AWS_REGION }}"
114 | # echo "::set-output name=aws_s3::${{ env.AWS_S3_BUCKET_NAME }}"
115 |
116 | # if [[ $(make aws-eks-cluster-exists) = True ]]
117 | # then
118 | # echo "::set-output name=do_create_test_cluster::false"
119 | # else
120 | # echo "::set-output name=do_create_test_cluster::true"
121 | # fi
122 |
123 |
124 |
125 | # params_summary:
126 | # name: params_summary
127 | # runs-on: ubuntu-latest
128 | # needs: [params]
129 | # steps:
130 | # - name: params_summary
131 | # run: |
132 | # echo git_branch: ${{ needs.params.outputs.git_branch }}
133 | # echo do_deploy_to_prod_cluster: ${{ needs.params.outputs.do_deploy_to_prod_cluster }}
134 |
135 | # echo rasa_enterprise_version : ${{ needs.params.outputs.rasa_enterprise_version }}
136 | # echo rasa_version : ${{ needs.params.outputs.rasa_version }}
137 | # echo rasa_sdk_version : ${{ needs.params.outputs.rasa_sdk_version }}
138 |
139 | # echo do_training: ${{ needs.params.outputs.do_training }}
140 |
141 | # echo aws_region: ${{ needs.params.outputs.aws_region }}
142 | # echo aws_s3: ${{ needs.params.outputs.aws_s3 }}
143 |
144 | # echo do_create_test_cluster: ${{ needs.params.outputs.do_create_test_cluster }}
145 |
146 | # # - name: Dump GitHub context
147 | # # env:
148 | # # GITHUB_CONTEXT: ${{ toJSON(github) }}
149 | # # run: |
150 | # # echo "$GITHUB_CONTEXT"
151 | # # exit 1
152 |
153 |
154 | # action_server:
155 | # name: action_server (to AWS ECR)
156 | # runs-on: ubuntu-latest
157 | # needs: [params, params_summary]
158 | # steps:
159 | # - name: checkout
160 | # uses: actions/checkout@v2
161 |
162 | # - name: Set up Python 3.7
163 | # uses: actions/setup-python@v2
164 | # with:
165 | # python-version: 3.7
166 |
167 | # - name: Cache pip
168 | # # see: https://docs.github.com/en/actions/guides/building-and-testing-python#caching-dependencies
169 | # uses: actions/cache@v2
170 | # with:
171 | # path: ~/.cache/pip
172 | # key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }}
173 | # restore-keys: |
174 | # ${{ runner.os }}-pip-
175 | # ${{ runner.os }}-
176 |
177 |
178 | # - name: Configure AWS Credentials
179 | # uses: aws-actions/configure-aws-credentials@v1
180 | # with:
181 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
182 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
183 | # aws-region: ${{ env.AWS_REGION }}
184 |
185 | # - name: Do it all
186 | # run: |
187 | # python -m pip install -U pip
188 | # pip install -r requirements-dev.txt
189 | # make lint
190 | # make types
191 | # make test
192 | # make aws-ecr-docker-login
193 | # make docker-pull
194 | # make docker-build
195 | # make docker-push
196 |
197 | # rasa_model:
198 | # name: rasa_model (to AWS S3)
199 | # runs-on: ubuntu-latest
200 | # needs: [params, params_summary]
201 | # services:
202 | # # Label used to access the service container
203 | # duckling:
204 | # image: rasa/duckling
205 | # ports:
206 | # # Maps port 8000 on service container to port 8000 on host VM
207 | # - 8000:8000
208 | # steps:
209 | # - name: checkout
210 | # if: needs.params.outputs.do_training == 'true'
211 | # uses: actions/checkout@v2
212 |
213 | # - name: Install dependencies
214 | # if: needs.params.outputs.do_training == 'true'
215 | # run: |
216 | # python -m pip install -U pip
217 | # pip install -r requirements.txt
218 | # python -m spacy download en_core_web_md
219 | # python -m spacy link en_core_web_md en
220 |
221 | # - name: Configure AWS Credentials
222 | # if: needs.params.outputs.do_training == 'true'
223 | # uses: aws-actions/configure-aws-credentials@v1
224 | # with:
225 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
226 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
227 | # aws-region: ${{ needs.params.outputs.aws_region }}
228 |
229 | # - name: Do it all
230 | # if: needs.params.outputs.do_training == 'true'
231 | # run: |
232 | # make rasa-train
233 | # make rasa-test
234 | # make aws-s3-upload-rasa-model
235 |
236 | # aws_eks_create_test_cluster:
237 | # name: aws_eks_create_test_cluster
238 | # runs-on: ubuntu-latest
239 | # needs: [params, params_summary]
240 | # steps:
241 | # - name: checkout
242 | # if: needs.params.outputs.do_create_test_cluster == 'true'
243 | # uses: actions/checkout@v2
244 |
245 | # - name: Configure AWS Credentials
246 | # if: needs.params.outputs.do_create_test_cluster == 'true'
247 | # uses: aws-actions/configure-aws-credentials@v1
248 | # with:
249 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
250 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
251 | # aws-region: ${{ needs.params.outputs.aws_region }}
252 |
253 | # - name: Do it all
254 | # if: needs.params.outputs.do_create_test_cluster == 'true'
255 | # run: |
256 | # make install-eksctl
257 | # make install-kubectl
258 | # make aws-eks-cluster-create
259 |
260 | # deploy_to_test_cluster:
261 | # name: deploy_to_test_cluster
262 | # runs-on: ubuntu-latest
263 | # needs: [params, aws_eks_create_test_cluster, rasa_model, action_server]
264 | # steps:
265 | # - name: checkout
266 | # uses: actions/checkout@v2
267 |
268 | # - name: Configure AWS Credentials
269 | # uses: aws-actions/configure-aws-credentials@v1
270 | # with:
271 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
272 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
273 | # aws-region: ${{ needs.params.outputs.aws_region }}
274 |
275 | # - name: install CLIs & dependencies
276 | # run: |
277 | # make install-eksctl
278 | # make install-kubectl
279 | # make install-helm
280 | # make install-jp
281 |
282 | # - name: configure kubectl
283 | # run: |
284 | # make aws-eks-cluster-update-kubeconfig
285 |
286 | # - name: create namespace if not exists
287 | # run: |
288 | # make aws-eks-namespace-create
289 |
290 | # # Enable cluster to pull the private rasa enterprise image
291 | # - name: create/refresh gcr-pull-secret
292 | # env:
293 | # GCR_AUTH_JSON_PRIVATE_KEY_ID: ${{ secrets.GCR_AUTH_JSON_PRIVATE_KEY_ID }}
294 | # GCR_AUTH_JSON_PRIVATE_KEY: ${{ secrets.GCR_AUTH_JSON_PRIVATE_KEY }}
295 | # GCR_AUTH_JSON_CLIENT_EMAIL: ${{ secrets.GCR_AUTH_JSON_CLIENT_EMAIL }}
296 | # GCR_AUTH_JSON_CLIENT_ID: ${{ secrets.GCR_AUTH_JSON_CLIENT_ID }}
297 | # run: |
298 | # make pull-secret-gcr-create
299 |
300 | # # Enable cluster to pull the private action server image
301 | # - name: create/refresh ecr-pull-secret
302 | # run: |
303 | # make pull-secret-ecr-create
304 |
305 | # - name: Install or Upgrade Rasa Enterprise
306 | # env:
307 | # GLOBAL_POSTGRESQL_POSTGRESQLPASSWORD: ${{ secrets.GLOBAL_POSTGRESQL_POSTGRESQLPASSWORD }}
308 | # GLOBAL_REDIS_PASSWORD: ${{ secrets.GLOBAL_REDIS_PASSWORD }}
309 | # RABBITMQ_RABBITMQ_PASSWORD: ${{ secrets.RABBITMQ_RABBITMQ_PASSWORD }}
310 | # RASAX_DEBUG_MODE: true
311 | # RASAX_INITIALUSER_USERNAME: ${{ secrets.RASAX_INITIALUSER_USERNAME }}
312 | # RASAX_INITIALUSER_PASSWORD: ${{ secrets.RASAX_INITIALUSER_PASSWORD }}
313 | # RASAX_JWTSECRET: ${{ secrets.RASAX_JWTSECRET }}
314 | # RASAX_PASSWORDSALT: ${{ secrets.RASAX_PASSWORDSALT }}
315 | # RASAX_TOKEN: ${{ secrets.RASAX_TOKEN }}
316 | # RASA_TOKEN: ${{ secrets.RASA_TOKEN }}
317 | # run: |
318 | # make rasa-enterprise-install
319 |
320 | # - name: Check Rasa Enterprise Health
321 | # run: |
322 | # # Need to give rasa-prod container some time...
323 | # sleep 30
324 | # make rasa-enterprise-check-health
325 |
326 | # - name: Deploy rasa model
327 | # env:
328 | # RASAX_INITIALUSER_USERNAME: ${{ secrets.RASAX_INITIALUSER_USERNAME }}
329 | # RASAX_INITIALUSER_PASSWORD: ${{ secrets.RASAX_INITIALUSER_PASSWORD }}
330 |
331 | # run: |
332 | # make aws-s3-download-rasa-model
333 | # make rasa-enterprise-model-delete
334 | # make rasa-enterprise-model-upload
335 | # sleep 2
336 | # make rasa-enterprise-model-tag
337 | # # Give rasa-prod some time to unpack & load the model
338 | # sleep 60
339 |
340 | # - name: Smoketest
341 | # env:
342 | # RASAX_INITIALUSER_USERNAME: ${{ secrets.RASAX_INITIALUSER_USERNAME }}
343 | # RASAX_INITIALUSER_PASSWORD: ${{ secrets.RASAX_INITIALUSER_PASSWORD }}
344 | # run: |
345 | # make rasa-enterprise-smoketest
346 |
347 |
348 | # deploy_to_prod_cluster:
349 | # name: deploy_to_prod_cluster
350 | # runs-on: ubuntu-latest
351 | # needs: [params, deploy_to_test_cluster]
352 | # if: ${{ needs.params.outputs.do_deploy_to_prod_cluster == 'true' }}
353 | # steps:
354 | # - name: checkout
355 | # uses: actions/checkout@v2
356 |
357 | # - name: Configure AWS Credentials
358 | # uses: aws-actions/configure-aws-credentials@v1
359 | # with:
360 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
361 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
362 | # aws-region: ${{ needs.params.outputs.aws_region }}
363 |
364 | # - name: install CLIs & dependencies
365 | # run: |
366 | # make install-eksctl
367 | # make install-kubectl
368 | # make install-helm
369 | # make install-jp
370 |
371 | # - name: configure kubectl
372 | # run: |
373 | # make aws-eks-cluster-update-kubeconfig AWS_EKS_CLUSTER_NAME=financial-demo-production
374 |
375 | # - name: create namespace if not exists
376 | # run: |
377 | # make aws-eks-namespace-create
378 |
379 | # # Enable cluster to pull the private rasa enterprise image
380 | # - name: create/refresh gcr-pull-secret
381 | # env:
382 | # GCR_AUTH_JSON_PRIVATE_KEY_ID: ${{ secrets.GCR_AUTH_JSON_PRIVATE_KEY_ID }}
383 | # GCR_AUTH_JSON_PRIVATE_KEY: ${{ secrets.GCR_AUTH_JSON_PRIVATE_KEY }}
384 | # GCR_AUTH_JSON_CLIENT_EMAIL: ${{ secrets.GCR_AUTH_JSON_CLIENT_EMAIL }}
385 | # GCR_AUTH_JSON_CLIENT_ID: ${{ secrets.GCR_AUTH_JSON_CLIENT_ID }}
386 | # run: |
387 | # make pull-secret-gcr-create
388 |
389 | # # Enable cluster to pull the private action server image
390 | # - name: create/refresh ecr-pull-secret
391 | # run: |
392 | # make pull-secret-ecr-create
393 |
394 | # - name: Install or Upgrade Rasa Enterprise
395 | # env:
396 | # GLOBAL_POSTGRESQL_POSTGRESQLPASSWORD: ${{ secrets.GLOBAL_POSTGRESQL_POSTGRESQLPASSWORD }}
397 | # GLOBAL_REDIS_PASSWORD: ${{ secrets.GLOBAL_REDIS_PASSWORD }}
398 | # RABBITMQ_RABBITMQ_PASSWORD: ${{ secrets.RABBITMQ_RABBITMQ_PASSWORD }}
399 | # RASAX_DEBUG_MODE: false
400 | # RASAX_INITIALUSER_USERNAME: ${{ secrets.RASAX_INITIALUSER_USERNAME }}
401 | # RASAX_INITIALUSER_PASSWORD: ${{ secrets.RASAX_INITIALUSER_PASSWORD }}
402 | # RASAX_JWTSECRET: ${{ secrets.RASAX_JWTSECRET }}
403 | # RASAX_PASSWORDSALT: ${{ secrets.RASAX_PASSWORDSALT }}
404 | # RASAX_TOKEN: ${{ secrets.RASAX_TOKEN }}
405 | # RASA_TOKEN: ${{ secrets.RASA_TOKEN }}
406 | # run: |
407 | # make rasa-enterprise-install
408 |
409 | # - name: Check Rasa Enterprise Health
410 | # run: |
411 | # # Need to give rasa-prod container some time...
412 | # sleep 30
413 | # make rasa-enterprise-check-health
414 |
415 | # - name: Deploy rasa model
416 | # env:
417 | # RASAX_INITIALUSER_USERNAME: ${{ secrets.RASAX_INITIALUSER_USERNAME }}
418 | # RASAX_INITIALUSER_PASSWORD: ${{ secrets.RASAX_INITIALUSER_PASSWORD }}
419 |
420 | # run: |
421 | # make aws-s3-download-rasa-model
422 | # make rasa-enterprise-model-delete
423 | # make rasa-enterprise-model-upload
424 | # sleep 2
425 | # make rasa-enterprise-model-tag
426 | # # Give rasa-prod some time to unpack & load the model
427 | # sleep 60
428 |
429 | # - name: Smoketest
430 | # env:
431 | # RASAX_INITIALUSER_USERNAME: ${{ secrets.RASAX_INITIALUSER_USERNAME }}
432 | # RASAX_INITIALUSER_PASSWORD: ${{ secrets.RASAX_INITIALUSER_PASSWORD }}
433 | # run: |
434 | # make rasa-enterprise-smoketest
435 |
--------------------------------------------------------------------------------
/.github/workflows/cleanup-branch.yml:
--------------------------------------------------------------------------------
1 | # # Cleans up infrastructure & artifacts. Manually & when branch gets deleted
2 |
3 | # # Note: the workflow_dispatch & schedule events will only trigger if the workflow
4 | # # file is on the default (main) branch.
5 |
6 | # # See:
7 | # # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#workflow_dispatch
8 | # # https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow
9 | # # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#schedule
10 | # name: financial-demo cleanup-branch
11 |
12 | # on:
13 | # workflow_dispatch:
14 | # delete:
15 |
16 | # env:
17 | # # Keep these values in sync with the values in the Makefile
18 | # AWS_REGION: us-west-2
19 | # AWS_ECR_URI: 024629701212.dkr.ecr.us-west-2.amazonaws.com
20 | # AWS_ECR_REPOSITORY: financial-demo
21 | # AWS_S3_BUCKET_NAME: rasa-financial-demo
22 |
23 | # jobs:
24 | # cleanup_deleted_branch:
25 | # if: github.event.ref_type == 'branch'
26 | # name: cleanup_deleted_branch
27 | # runs-on: ubuntu-latest
28 | # steps:
29 | # - name: checkout
30 | # uses: actions/checkout@v2
31 |
32 | # - name: Set up Python 3.7
33 | # uses: actions/setup-python@v2
34 | # with:
35 | # python-version: 3.7
36 |
37 | # - name: Cache pip
38 | # # see: https://docs.github.com/en/actions/guides/building-and-testing-python#caching-dependencies
39 | # uses: actions/cache@v2
40 | # with:
41 | # path: ~/.cache/pip
42 | # key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }}
43 | # restore-keys: |
44 | # ${{ runner.os }}-pip-
45 | # ${{ runner.os }}-
46 |
47 |
48 | # - name: Configure AWS Credentials
49 | # uses: aws-actions/configure-aws-credentials@v1
50 | # with:
51 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
52 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
53 | # aws-region: ${{ env.AWS_REGION }}
54 |
55 | # - name: install CLIs & dependencies
56 | # run: |
57 | # make install-eksctl
58 | # make install-kubectl
59 | # make install-helm
60 | # make install-jp
61 |
62 | # - name: Cleanup ECR
63 | # run: |
64 | # echo "Delete action server image of branch ${{ github.event.ref }}"
65 | # make aws-ecr-docker-login
66 | # make aws-ecr-delete-image GIT_BRANCH_NAME=${{ github.event.ref }}
67 |
68 | # - name: Cleanup S3
69 | # run: |
70 | # echo "Delete rasa model of branch ${{ github.event.ref }}"
71 | # make aws-s3-delete-rasa-model GIT_BRANCH_NAME=${{ github.event.ref }}
72 |
73 | # - name: Cleanup EKS & all Persistent Volume Claims / Persistent Volumes
74 | # run: |
75 | # echo "Delete test cluster of branch ${{ github.event.ref }} and PVCs"
76 | # make aws-eks-cluster-update-kubeconfig GIT_BRANCH_NAME=${{ github.event.ref }}
77 | # make rasa-enterprise-uninstall
78 | # make rasa-enterprise-delete-pvc-all
79 | # make aws-eks-cluster-delete GIT_BRANCH_NAME=${{ github.event.ref }}
80 |
--------------------------------------------------------------------------------
/.github/workflows/cleanup-nightly.yml:
--------------------------------------------------------------------------------
1 | # # Cleans up EKS test clusters. Manually & every night at 3:30 UTC
2 |
3 | # # Note: the workflow_dispatch & schedule events will only trigger if the workflow
4 | # # file is on the default (main) branch.
5 |
6 | # # See:
7 | # # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#workflow_dispatch
8 | # # https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow
9 | # # https://docs.github.com/en/actions/reference/events-that-trigger-workflows#schedule
10 | # name: financial-demo cleanup-nightly
11 |
12 | # on:
13 | # workflow_dispatch:
14 | # schedule:
15 | # - cron: '30 3 * * *'
16 |
17 |
18 | # env:
19 | # # Keep these values in sync with the values in the Makefile
20 | # AWS_REGION: us-west-2
21 |
22 | # jobs:
23 | # cleanup_nightly:
24 | # name: cleanup_nightly
25 | # runs-on: ubuntu-latest
26 | # steps:
27 | # - name: checkout
28 | # uses: actions/checkout@v2
29 |
30 | # - name: Set up Python 3.7
31 | # uses: actions/setup-python@v2
32 | # with:
33 | # python-version: 3.7
34 |
35 | # - name: Cache pip
36 | # # see: https://docs.github.com/en/actions/guides/building-and-testing-python#caching-dependencies
37 | # uses: actions/cache@v2
38 | # with:
39 | # path: ~/.cache/pip
40 | # key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }}
41 | # restore-keys: |
42 | # ${{ runner.os }}-pip-
43 | # ${{ runner.os }}-
44 |
45 |
46 | # - name: Configure AWS Credentials
47 | # uses: aws-actions/configure-aws-credentials@v1
48 | # with:
49 | # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
50 | # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
51 | # aws-region: ${{ env.AWS_REGION }}
52 |
53 | # - name: install CLIs & dependencies
54 | # run: |
55 | # make install-eksctl
56 | # make install-kubectl
57 | # make install-helm
58 | # make install-jp
59 |
60 | # - name: Cleanup EKS
61 | # run: |
62 | # echo "Delete all test clusters"
63 | # make aws-eks-cluster-delete-all-test-clusters
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # IDE Stuff
10 | .vscode/
11 | .history
12 | *.DS_Store
13 | *.wpr
14 | *.wpu
15 |
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | *.egg-info/
31 | .installed.cfg
32 | *.egg
33 | MANIFEST
34 |
35 | # PyInstaller
36 | # Usually these files are written by a python script from a template
37 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
38 | *.manifest
39 | *.spec
40 |
41 | # Installer logs
42 | pip-log.txt
43 | pip-delete-this-directory.txt
44 |
45 | # Unit test / coverage reports
46 | htmlcov/
47 | .tox/
48 | .coverage
49 | .coverage.*
50 | .cache
51 | nosetests.xml
52 | coverage.xml
53 | *.cover
54 | .hypothesis/
55 | .pytest_cache/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 | db.sqlite3
65 |
66 | # Flask stuff:
67 | instance/
68 | .webassets-cache
69 |
70 | # Scrapy stuff:
71 | .scrapy
72 |
73 | # Sphinx documentation
74 | docs/_build/
75 |
76 | # PyBuilder
77 | target/
78 |
79 | # Jupyter Notebook
80 | .ipynb_checkpoints
81 |
82 | # pyenv
83 | .python-version
84 |
85 | # celery beat schedule file
86 | celerybeat-schedule
87 |
88 | # SageMath parsed files
89 | *.sage.py
90 |
91 | # Environments
92 | #.env
93 | .venv
94 | env/
95 | venv/
96 | ENV/
97 | env.bak/
98 | venv.bak/
99 |
100 | # Spyder project settings
101 | .spyderproject
102 | .spyproject
103 |
104 | # Rope project settings
105 | .ropeproject
106 |
107 | # mkdocs documentation
108 | /site
109 |
110 | # mypy
111 | .mypy_cache/
112 |
113 | # pytype
114 | .pytype/
115 |
116 | # Rasa stuff
117 | models/
118 | *.db*
119 | *.dot
120 | terms/
121 | results/
122 |
123 | # Secret & local files
124 | secret/
125 | run_rasa*
126 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/ambv/black
3 | rev: stable
4 | hooks:
5 | - id: black
6 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM rasa/rasa-sdk:3.1.0
2 |
3 | COPY actions /app/actions
4 |
5 | USER root
6 | RUN pip install --no-cache-dir -r /app/actions/requirements-actions.txt
7 |
8 | USER 1001
9 | CMD ["start", "--actions", "actions"]
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/actions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RasaHQ/financial-demo/7627cebef1571d55855b886cf4ac20459af9566c/actions/__init__.py
--------------------------------------------------------------------------------
/actions/custom_forms.py:
--------------------------------------------------------------------------------
1 | """Customization to deal nicely with repeated slot validation failures."""
2 | import abc
3 | from typing import Dict, Text, Any, List
4 | import logging
5 | import pathlib
6 | import ruamel.yaml
7 | from rasa_sdk import utils
8 | from rasa_sdk.forms import FormValidationAction
9 | from rasa_sdk.events import (
10 | SlotSet,
11 | EventType,
12 | LoopInterrupted,
13 | ActionExecutionRejected,
14 | )
15 | from rasa_sdk import Tracker
16 | from rasa_sdk.executor import CollectingDispatcher
17 |
18 |
19 | logger = logging.getLogger(__name__)
20 |
21 | # these slots are used to store information needed to nicely deal with
22 | # repeated slot validation failures
23 | RVF_SLOT = "repeated_validation_failures"
24 | CF_SLOT = "AA_CONTINUE_FORM"
25 |
26 |
27 | here = pathlib.Path(__file__).parent.absolute()
28 | custom_forms_config = (
29 | ruamel.yaml.safe_load(open(f"{here}/custom_forms_config.yml", "r")) or {}
30 | ).get("custom_forms", {})
31 |
32 | MAX_VALIDATION_FAILURES = custom_forms_config.get("max_validation_failures", 2)
33 |
34 |
35 | class CustomFormValidationAction(FormValidationAction, metaclass=abc.ABCMeta):
36 | """Validates if slot values are valid and handles repeated validation failures.
37 |
38 | To use, you add the following to your bot:
39 |
40 | (-) Include these two intents:
41 | - affirm
42 | - deny
43 |
44 | (-) In domain.yml define these slots:
45 |
46 | slots:
47 | repeated_validation_failures:
48 | type: any
49 | AA_CONTINUE_FORM:
50 | type: any
51 |
52 | (-) In domain.yml, for each form, declare 'AA_CONTINUE_FORM' as first required slot.
53 |
54 | For example:
55 |
56 | forms:
57 | cc_payment_form:
58 | AA_CONTINUE_FORM:
59 | - type: from_intent
60 | intent: affirm
61 | value: yes
62 | - type: from_intent
63 | intent: deny
64 | value: no
65 | - type: from_text
66 | intent:
67 | - inform
68 | - cc_payment_form
69 |
70 | (-) In domain.yml, for each form, define the 'utter_{form}_AA_CONTINUE_FORM' response,
71 | using /affirm & /deny buttons.
72 |
73 | For example:
74 |
75 | utter_ask_cc_payment_form_AA_CONTINUE_FORM:
76 | - buttons:
77 | - payload: /affirm
78 | title: Yes
79 | - payload: /deny
80 | title: No, cancel the transaction
81 | text: Would you like to continue scheduling the credit card payment?
82 |
83 | (-) In the custom action Class that validates slots, subclass from
84 | 'CustomFormValidationAction' instead of from 'FormValidationAction'.
85 | Optionally, add an 'explain_{slot}' method for every slot that the bot
86 | should explain in some detail if the user is repeatedly provides answer that
87 | cannot be validated.
88 |
89 | For example:
90 |
91 | class ValidatePayCCForm(CustomFormValidationAction):
92 | async def explain_credit_card(
93 | self,
94 | value: Text,
95 | dispatcher: CollectingDispatcher,
96 | tracker: Tracker,
97 | domain: Dict[Text, Any],
98 | ) -> Dict[Text, Any]:
99 |
100 | # Bot utters a message that explains the slot
101 | dispatcher.utter_message( )
102 |
103 | # optionally, you can set slots by returning a dict
104 | return {}
105 | """
106 |
107 | # Avoids registering this class as a custom action
108 | @abc.abstractmethod
109 | def name(self) -> Text:
110 | """Unique identifier of the CustomFormValidationAction"""
111 |
112 | raise NotImplementedError("A CustomFormValidationAction must implement a name")
113 |
114 | async def validate(
115 | self,
116 | dispatcher: CollectingDispatcher,
117 | tracker: Tracker,
118 | domain: Dict,
119 | ) -> List[EventType]:
120 | """Validates slots by calling a validation function for each slot.
121 |
122 | Calls an explain function for the requested slot when validation fails
123 | MAX_VALIDATION_FAILURES in a row, and sets 'AA_CONTINUE_FORM' slot to None, which
124 | triggers the bot to utter the 'utter_ask_{form}_AA_CONTINUE_FORM' template.
125 |
126 | Args:
127 | dispatcher: the dispatcher which is used to send messages back to the user.
128 | tracker: the conversation tracker for the current user.
129 | domain: the bot's domain.
130 | Returns:
131 | `SlotSet` events for every validated slot.
132 | """
133 | events = []
134 |
135 | if not tracker.get_slot(CF_SLOT):
136 | events.append(SlotSet(CF_SLOT, "yes"))
137 |
138 | events.extend(await super().validate(dispatcher, tracker, domain))
139 |
140 | events.extend(
141 | await self.repeated_validation_failures(dispatcher, tracker, domain, events)
142 | )
143 |
144 | return events
145 |
146 | async def repeated_validation_failures(
147 | self,
148 | dispatcher: CollectingDispatcher,
149 | tracker: Tracker,
150 | domain: Dict,
151 | events: List[EventType],
152 | ) -> List[EventType]:
153 | """Updates the slot repeated_validation_failures, and sets required form slot
154 | `AA_CONTINUE_FORM` to None when the threshold is reached.
155 |
156 | This will trigger utter_ask_{form}_AA_CONTINUE_FORM, asking the user if they want
157 | to continue with this form or not.
158 | """
159 | rvf_events: List[EventType] = []
160 | requested_slot = tracker.get_slot("requested_slot")
161 |
162 | # Only do this while form is asking for a certain slot
163 | if not requested_slot:
164 | return rvf_events
165 |
166 | # if the requested slot was not extracted, interupt the form
167 | interrupt_form = False
168 | if not events:
169 | interrupt_form = True
170 | else:
171 | for event in events:
172 | if event["event"] == "slot" and event["name"] == "requested_slot":
173 | interrupt_form = True
174 |
175 | if interrupt_form:
176 | # Sending LoopInterrupted will prevent rasa.core from asking for the slot
177 | rvf_events.append(LoopInterrupted(is_interrupted=True))
178 |
179 | # Sending ActionExecutionRejected will allow rasa.core to predict
180 | # something else before continuing with the form
181 | rvf_events.append(ActionExecutionRejected(action_name=self.form_name()))
182 |
183 | return rvf_events
184 |
185 | # Skip if validate_{slot} turned off the form by setting requested_slot to None
186 | for event in events:
187 | if (
188 | event["event"] == "slot"
189 | and event["name"] == "requested_slot"
190 | and not event["value"]
191 | ):
192 | rvf_events.append(SlotSet(RVF_SLOT, 0))
193 | return rvf_events
194 |
195 | rvf = tracker.get_slot(RVF_SLOT)
196 | if rvf:
197 | rvf = int(rvf)
198 | else:
199 | # initialize counter to 0
200 | rvf = 0
201 |
202 | # check if validation of the requested_slot failed
203 | validation_failed = True
204 | for event in events:
205 | if (
206 | event["event"] == "slot"
207 | and event["name"] == requested_slot
208 | and event["value"]
209 | ):
210 | validation_failed = False
211 | break
212 |
213 | # keep track of repeated validation failures
214 | if validation_failed:
215 | rvf += 1
216 | else:
217 | rvf = 0
218 |
219 | if rvf >= MAX_VALIDATION_FAILURES:
220 | rvf_events.extend(
221 | await self.explain_requested_slot(dispatcher, tracker, domain)
222 | )
223 | # reset counter
224 | rvf = 0
225 |
226 | # Triggers 'utter_ask_{form}_AA_CONTINUE_FORM'
227 | rvf_events.append(SlotSet(CF_SLOT, None))
228 |
229 | rvf_events.append(SlotSet(RVF_SLOT, rvf))
230 | return rvf_events
231 |
232 | async def explain_requested_slot(
233 | self,
234 | dispatcher: CollectingDispatcher,
235 | tracker: Tracker,
236 | domain: Dict[Text, Any],
237 | ) -> List[EventType]:
238 | """Explains requested slot by calling an explain function for the slot.
239 |
240 | Args:
241 | dispatcher: the dispatcher which is used to
242 | send messages back to the user.
243 | tracker: the conversation tracker for the current user.
244 | domain: the bot's domain.
245 | Returns:
246 | `SlotSet` events for the explained slot (Optional).
247 | """
248 | slot_name = tracker.get_slot("requested_slot")
249 | if not slot_name:
250 | return []
251 |
252 | slot_value = tracker.get_slot(slot_name)
253 |
254 | method_name = f"explain_{slot_name.replace('-','_')}"
255 | explain_method = getattr(self, method_name, None)
256 |
257 | if not explain_method:
258 | logger.debug(
259 | f"Skipping explanation for `{slot_name}`: there is no explanation "
260 | "method specified."
261 | )
262 | return []
263 |
264 | slots = {}
265 | explanation_output = await utils.call_potential_coroutine(
266 | explain_method(slot_value, dispatcher, tracker, domain)
267 | )
268 |
269 | if explanation_output:
270 | slots.update(explanation_output)
271 |
272 | return [SlotSet(slot, value) for slot, value in slots.items()]
273 |
274 | async def validate_AA_CONTINUE_FORM(
275 | self,
276 | value: Text,
277 | dispatcher: CollectingDispatcher,
278 | tracker: Tracker,
279 | domain: Dict[Text, Any],
280 | ) -> Dict[Text, Any]:
281 | """Validates value of 'AA_CONTINUE_FORM' slot"""
282 | if value == "yes":
283 | return {CF_SLOT: value}
284 |
285 | if value == "no":
286 | # This will activate rule 'Submit ---_form' to cancel the operation
287 | return {
288 | "requested_slot": None,
289 | "zz_confirm_form": "no",
290 | CF_SLOT: value,
291 | }
292 |
293 | # The user's answer was not valid. Just re-set it to None.
294 | return {CF_SLOT: None}
295 |
--------------------------------------------------------------------------------
/actions/custom_forms_config.yml:
--------------------------------------------------------------------------------
1 | custom_forms:
2 | # When validation of required slots fails this many times:
3 | # (-) Bot will explain the slot if user explain_{slot} method exists
4 | # (-) Bot will ask to continue with the form or not
5 | max_validation_failures: 2
6 |
--------------------------------------------------------------------------------
/actions/handoff.py:
--------------------------------------------------------------------------------
1 | from rasa_sdk import Tracker, Action
2 | from rasa_sdk.executor import CollectingDispatcher
3 |
4 | import ruamel.yaml
5 | import pathlib
6 | from typing import Dict, Text, Any, List
7 | from rasa_sdk.events import EventType
8 |
9 | here = pathlib.Path(__file__).parent.absolute()
10 | handoff_config = (
11 | ruamel.yaml.safe_load(open(f"{here}/handoff_config.yml", "r")) or {}
12 | ).get("handoff_hosts", {})
13 |
14 |
15 | class ActionHandoffOptions(Action):
16 | def name(self) -> Text:
17 | return "action_handoff_options"
18 |
19 | async def run(
20 | self,
21 | dispatcher: CollectingDispatcher,
22 | tracker: Tracker,
23 | domain: Dict[Text, Any],
24 | ) -> List[EventType]:
25 |
26 | if not any([config.get("url") for bot, config in handoff_config.items()]):
27 | dispatcher.utter_message(template="utter_no_handoff")
28 | else:
29 | buttons = [
30 | {
31 | "title": config.get("title"),
32 | "payload": f'/trigger_handoff{{"handoff_to":"{bot}"}}',
33 | }
34 | for bot, config in handoff_config.items()
35 | ]
36 | dispatcher.utter_message(
37 | text=(
38 | "I can't transfer you to a human, "
39 | "but I can transfer you to one of these bots"
40 | ),
41 | buttons=buttons,
42 | )
43 | return []
44 |
45 |
46 | class ActionHandoff(Action):
47 | def name(self) -> Text:
48 | return "action_handoff"
49 |
50 | async def run(
51 | self,
52 | dispatcher: CollectingDispatcher,
53 | tracker: Tracker,
54 | domain: Dict[Text, Any],
55 | ) -> List[EventType]:
56 |
57 | dispatcher.utter_message(template="utter_handoff")
58 | handoff_to = tracker.get_slot("handoff_to")
59 |
60 | handoff_bot = handoff_config.get(handoff_to, {})
61 | url = handoff_bot.get("url")
62 |
63 | if url:
64 | if tracker.get_latest_input_channel() == "rest":
65 | dispatcher.utter_message(
66 | json_message={
67 | "handoff_host": url,
68 | "title": handoff_bot.get("title"),
69 | }
70 | )
71 | else:
72 | dispatcher.utter_message(
73 | template="utter_wouldve_handed_off", handoffhost=url
74 | )
75 | else:
76 | dispatcher.utter_message(template="utter_no_handoff")
77 |
78 | return []
79 |
--------------------------------------------------------------------------------
/actions/handoff_config.yml:
--------------------------------------------------------------------------------
1 | handoff_hosts:
2 | helpdesk_assistant:
3 | title: "Helpdesk Assistant"
4 | url: "http://localhost:5005"
5 | ## you can add more handoff hosts to this list e.g.
6 | # moodbot:
7 | # title: "MoodBot"
8 | # url: "http://localhost:5007"
9 |
10 |
--------------------------------------------------------------------------------
/actions/parsing.py:
--------------------------------------------------------------------------------
1 | from dateutil import relativedelta, parser
2 | from typing import Dict, Text, Any, Optional
3 | from rasa_sdk import Tracker
4 |
5 |
6 | def close_interval_duckling_time(
7 | timeinfo: Dict[Text, Any]
8 | ) -> Optional[Dict[Text, Any]]:
9 | grain = timeinfo.get("to", timeinfo.get("from", {})).get("grain")
10 | start = timeinfo.get("from", {}).get("value")
11 | end = timeinfo.get("to", {}).get("value")
12 | if (start or end) and not (start and end):
13 | deltaargs = {f"{grain}s": 1}
14 | delta = relativedelta.relativedelta(**deltaargs)
15 | if start:
16 | parsedstart = parser.isoparse(start)
17 | parsedend = parsedstart + delta
18 | end = parsedend.isoformat()
19 | elif end:
20 | parsedend = parser.isoparse(end)
21 | parsedstart = parsedend - delta
22 | start = parsedstart.isoformat()
23 | return {
24 | "start_time": start,
25 | "start_time_formatted": format_isotime_by_grain(start, grain),
26 | "end_time": end,
27 | "end_time_formatted": format_isotime_by_grain(end, grain),
28 | "grain": grain,
29 | }
30 |
31 |
32 | def make_interval_from_value_duckling_time(
33 | timeinfo: Dict[Text, Any]
34 | ) -> Dict[Text, Any]:
35 | grain = timeinfo.get("grain")
36 | start = timeinfo.get("value")
37 | parsedstart = parser.isoparse(start)
38 | deltaargs = {f"{grain}s": 1}
39 | delta = relativedelta.relativedelta(**deltaargs)
40 | parsedend = parsedstart + delta
41 | end = parsedend.isoformat()
42 | return {
43 | "start_time": start,
44 | "start_time_formatted": format_isotime_by_grain(start, grain),
45 | "end_time": end,
46 | "end_time_formatted": format_isotime_by_grain(end, grain),
47 | "grain": grain,
48 | }
49 |
50 |
51 | def parse_duckling_time_as_interval(
52 | timeentity: Dict[Text, Any]
53 | ) -> Optional[Dict[Text, Any]]:
54 | timeinfo = timeentity.get("additional_info", {})
55 | if timeinfo.get("type") == "interval":
56 | return close_interval_duckling_time(timeinfo)
57 | elif timeinfo.get("type") == "value":
58 | return make_interval_from_value_duckling_time(timeinfo)
59 |
60 |
61 | def format_isotime_by_grain(isotime, grain=None):
62 | value = parser.isoparse(isotime)
63 | grain_format = {
64 | "second": "%I:%M:%S%p, %A %b %d, %Y",
65 | "day": "%A %b %d, %Y",
66 | "week": "%A %b %d, %Y",
67 | "month": "%b %Y",
68 | "year": "%Y",
69 | }
70 | timeformat = grain_format.get(grain, "%I:%M%p, %A %b %d, %Y")
71 | time_formatted = value.strftime(timeformat)
72 | return time_formatted
73 |
74 |
75 | def parse_duckling_time(timeentity: Dict[Text, Any]) -> Optional[Dict[Text, Any]]:
76 | try:
77 | timeinfo = timeentity.get("additional_info", {})
78 | except AttributeError:
79 | return {"time": None}
80 | if timeinfo.get("type") == "value":
81 | value = timeinfo.get("value")
82 | grain = timeinfo.get("grain")
83 | parsedtime = {
84 | "time": value,
85 | "time_formatted": format_isotime_by_grain(value, grain),
86 | "grain": grain,
87 | }
88 | return parsedtime
89 |
90 |
91 | def get_entity_details(
92 | tracker: Tracker, entity_type: Text
93 | ) -> Optional[Dict[Text, Any]]:
94 | all_entities = tracker.latest_message.get("entities", [])
95 | entities = [e for e in all_entities if e.get("entity") == entity_type]
96 | if entities:
97 | return entities[0]
98 |
99 |
100 | def parse_duckling_currency(entity: Dict[Text, Any]) -> Optional[Dict[Text, Any]]:
101 | if entity.get("entity") == "amount-of-money":
102 | amount = entity.get("additional_info", {}).get("value")
103 | currency = entity.get("additional_info", {}).get("unit")
104 | return {"amount-of-money": f"{amount:.2f}", "currency": currency}
105 | elif entity.get("entity") == "number":
106 | amount = entity.get("value")
107 | return {"amount-of-money": f"{amount:.2f}", "currency": "$"}
108 |
--------------------------------------------------------------------------------
/actions/profile_db.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sqlalchemy as sa
3 | from sqlalchemy import Column, Integer, String, DateTime, REAL
4 | from sqlalchemy.orm import Session, sessionmaker
5 | from sqlalchemy.ext.declarative import declarative_base
6 | from sqlalchemy.engine.base import Engine
7 | from typing import Dict, Text, List, Union, Optional
8 |
9 | from random import choice, randrange, sample, randint
10 | from numpy import arange
11 | from datetime import datetime, timedelta
12 | import pytz
13 |
14 | utc = pytz.UTC
15 |
16 | GENERAL_ACCOUNTS = {
17 | "recipient": [
18 | "katy parrow",
19 | "evan oslo",
20 | "william baker",
21 | "karen lancaster",
22 | "kyle gardner",
23 | "john jacob",
24 | "percy donald",
25 | "lisa macintyre",
26 | ],
27 | "vendor": ["target", "starbucks", "amazon"],
28 | "depositor": ["interest", "employer"],
29 | }
30 |
31 | ACCOUNT_NUMBER_LENGTH = 12
32 | CREDIT_CARD_NUMBER_LENGTH = 14
33 |
34 |
35 | Base = declarative_base()
36 |
37 |
38 | class Account(Base):
39 | """Accounts table.
40 | `session_id` is only meaningful for accounts generated by conversation sessions,
41 | when it is equal to `tracker.sender_id`.
42 | Since `id` autoincrements, it is used to generate unique account numbers by
43 | adding leading zeros to it.
44 | """
45 |
46 | __tablename__ = "account"
47 | id = Column(Integer, primary_key=True)
48 | session_id = Column(String(255))
49 | account_holder_name = Column(String(255))
50 | currency = Column(String(255))
51 |
52 |
53 | class CreditCard(Base):
54 | """Credit cards table. `account_id` is an `Account.id`"""
55 |
56 | __tablename__ = "creditcards"
57 | id = Column(Integer, primary_key=True)
58 | credit_card_name = Column(String(255))
59 | minimum_balance = Column(REAL)
60 | current_balance = Column(REAL)
61 | account_id = Column(Integer)
62 |
63 |
64 | class Transaction(Base):
65 | """Transactions table. `to/from_acount_number` are `Account.id`s with leading zeros"""
66 |
67 | __tablename__ = "transactions"
68 | id = Column(Integer, primary_key=True)
69 | timestamp = Column(DateTime)
70 | amount = Column(REAL)
71 | from_account_number = Column(String(14))
72 | to_account_number = Column(String(14))
73 |
74 |
75 | class RecipientRelationship(Base):
76 | """Valid recipients table. `account_id` and `recipient_account_id` are `Account.id`'s"""
77 |
78 | __tablename__ = "recipient_relationships"
79 | id = Column(Integer, primary_key=True)
80 | account_id = Column(Integer)
81 | recipient_account_id = Column(Integer)
82 | recipient_nickname = Column(String(255))
83 |
84 |
85 | def create_database(database_engine: Engine, database_name: Text):
86 | """Try to connect to the database. Create it if it does not exist"""
87 | try:
88 | database_engine.connect()
89 | except sa.exc.OperationalError:
90 | default_db_url = f"sqlite:///{database_name}.db"
91 | default_engine = sa.create_engine(default_db_url)
92 | conn = default_engine.connect()
93 | conn.execute("commit")
94 | conn.execute(f"CREATE DATABASE {database_name}")
95 | conn.close()
96 |
97 |
98 | class ProfileDB:
99 | def __init__(self, db_engine: Engine):
100 | self.engine = db_engine
101 | self.create_tables()
102 | self.session = self.get_session()
103 |
104 | def get_session(self) -> Session:
105 | return sessionmaker(bind=self.engine, autoflush=True)()
106 |
107 | def create_tables(self):
108 | CreditCard.__table__.create(self.engine, checkfirst=True)
109 | Transaction.__table__.create(self.engine, checkfirst=True)
110 | RecipientRelationship.__table__.create(self.engine, checkfirst=True)
111 | Account.__table__.create(self.engine, checkfirst=True)
112 |
113 | def get_account(self, id: int):
114 | """Get an `Account` object based on an `Account.id`"""
115 | return self.session.query(Account).filter(Account.id == id).first()
116 |
117 | def get_account_from_session_id(self, session_id: Text):
118 | """Get an `Account` object based on a `Account.session_id`"""
119 | # if the action server restarts in the middle of a conversation, the db will need to be repopulated outside of an action_session_start
120 | if not self.check_session_id_exists(session_id):
121 | self.populate_profile_db(session_id)
122 | account = (
123 | self.session.query(Account).filter(Account.session_id == session_id).first()
124 | )
125 | return account
126 |
127 | @staticmethod
128 | def get_account_number(account: Union[CreditCard, Account]):
129 | """Get a bank or credit card account number by adding the appropriate number of leading zeros to an `Account.id`"""
130 | if type(account) is CreditCard:
131 | return f"%0.{CREDIT_CARD_NUMBER_LENGTH}d" % account.id
132 | else:
133 | return f"%0.{ACCOUNT_NUMBER_LENGTH}d" % account.id
134 |
135 | def get_account_from_number(self, account_number: Text):
136 | """Get a bank or credit card account based on an account number"""
137 | if len(account_number) == CREDIT_CARD_NUMBER_LENGTH:
138 | return (
139 | self.session.query(CreditCard)
140 | .filter(CreditCard.id == int(account_number))
141 | .first()
142 | )
143 | else:
144 | return (
145 | self.session.query(Account)
146 | .filter(Account.id == int(account_number))
147 | .first()
148 | )
149 |
150 | def get_recipient_from_name(self, session_id: Text, recipient_name: Text):
151 | """Get a recipient based on the nickname.
152 | Take the first one if there are multiple that match.
153 | """
154 | account = self.get_account_from_session_id(session_id)
155 | recipient = (
156 | self.session.query(RecipientRelationship)
157 | .filter(RecipientRelationship.account_id == account.id)
158 | .filter(RecipientRelationship.recipient_nickname == recipient_name.lower())
159 | .first()
160 | )
161 | recipient_account = self.get_account(recipient.recipient_account_id)
162 | return recipient_account
163 |
164 | def list_known_recipients(self, session_id: Text):
165 | """List recipient nicknames available to an account holder"""
166 | recipients = (
167 | self.session.query(RecipientRelationship.recipient_nickname)
168 | .filter(
169 | RecipientRelationship.account_id
170 | == self.get_account_from_session_id(session_id).id
171 | )
172 | .all()
173 | )
174 | return [recipient.recipient_nickname for recipient in recipients]
175 |
176 | def check_session_id_exists(self, session_id: Text):
177 | """Check if an account for `session_id` already exists"""
178 | return self.session.query(
179 | self.session.query(Account.session_id)
180 | .filter(Account.session_id == session_id)
181 | .exists()
182 | ).scalar()
183 |
184 | def get_account_balance(self, session_id: Text):
185 | """Get the account balance for an account"""
186 | account_number = self.get_account_number(
187 | self.get_account_from_session_id(session_id)
188 | )
189 | spent = float(
190 | self.session.query(sa.func.sum(Transaction.amount))
191 | .filter(Transaction.from_account_number == account_number)
192 | .all()[0][0]
193 | )
194 | earned = float(
195 | self.session.query(sa.func.sum(Transaction.amount))
196 | .filter(Transaction.to_account_number == account_number)
197 | .all()[0][0]
198 | )
199 | return earned - spent
200 |
201 | def get_currency(self, session_id: Text):
202 | """Get the currency for an account"""
203 | return (
204 | self.session.query(Account.currency)
205 | .filter(Account.session_id == session_id)
206 | .first()[0]
207 | )
208 |
209 | def search_transactions(
210 | self,
211 | session_id: Text,
212 | start_time: Optional[datetime] = None,
213 | end_time: Optional[datetime] = None,
214 | deposit: bool = False,
215 | vendor: Optional[Text] = None,
216 | ):
217 | """Find all transactions for an account between `start_time` and `end_time`.
218 | Looks for spend transactions by default, set `deposit` to `True` to search earnings.
219 | Looks for transactions with anybody by default, set `vendor` to search by vendor
220 | """
221 | account = self.get_account_from_session_id(session_id)
222 | account_number = self.get_account_number(account)
223 | if deposit:
224 | transactions = self.session.query(Transaction).filter(
225 | Transaction.to_account_number == account_number
226 | )
227 | elif vendor:
228 | to_account = (
229 | self.session.query(Account.id)
230 | .filter(Account.session_id.startswith("vendor_"))
231 | .filter(Account.account_holder_name == vendor.lower())
232 | .first()
233 | )
234 | to_account_number = self.get_account_number(to_account)
235 | transactions = (
236 | self.session.query(Transaction)
237 | .filter(Transaction.from_account_number == account_number)
238 | .filter(Transaction.to_account_number == to_account_number)
239 | )
240 | else:
241 | transactions = self.session.query(Transaction).filter(
242 | Transaction.from_account_number == account_number
243 | )
244 | if start_time:
245 | transactions = transactions.filter(Transaction.timestamp >= start_time)
246 | if end_time:
247 | transactions = transactions.filter(Transaction.timestamp <= end_time)
248 |
249 | return transactions
250 |
251 | def list_credit_cards(self, session_id: Text):
252 | """List valid credit cards for an acccount"""
253 | account = self.get_account_from_session_id(session_id)
254 | cards = (
255 | self.session.query(CreditCard)
256 | .filter(CreditCard.account_id == account.id)
257 | .all()
258 | )
259 | return [card.credit_card_name for card in cards]
260 |
261 | def get_credit_card(self, session_id: Text, credit_card_name: Text):
262 | """Get a `CreditCard` object based on the card's name and the `session_id`"""
263 | account = self.get_account_from_session_id(session_id)
264 | return (
265 | self.session.query(CreditCard)
266 | .filter(CreditCard.account_id == account.id)
267 | .filter(CreditCard.credit_card_name == credit_card_name.lower())
268 | .first()
269 | )
270 |
271 | def get_credit_card_balance(
272 | self,
273 | session_id: Text,
274 | credit_card_name: Text,
275 | balance_type: Text = "current_balance",
276 | ):
277 | """Get the balance for a credit card based on its name and the balance type"""
278 | balance_type = "_".join(balance_type.split())
279 | card = self.get_credit_card(session_id, credit_card_name)
280 | return getattr(card, balance_type)
281 |
282 | @staticmethod
283 | def list_balance_types():
284 | """List valid balance types for credit cards"""
285 | return [
286 | " ".join(name.split("_"))
287 | for name in CreditCard.__table__.columns.keys()
288 | if name.endswith("balance")
289 | ]
290 |
291 | def list_vendors(self):
292 | """List valid vendors"""
293 | vendors = (
294 | self.session.query(Account.account_holder_name)
295 | .filter(Account.session_id.startswith("vendor_"))
296 | .all()
297 | )
298 | return [vendor.account_holder_name for vendor in vendors]
299 |
300 | def pay_off_credit_card(
301 | self, session_id: Text, credit_card_name: Text, amount: float
302 | ):
303 | """Do a transaction to move the specified amount from an account to a credit card"""
304 | account = self.get_account_from_session_id(session_id)
305 | account_number = self.get_account_number(account)
306 | credit_card = (
307 | self.session.query(CreditCard)
308 | .filter(CreditCard.account_id == account.id)
309 | .filter(CreditCard.credit_card_name == credit_card_name.lower())
310 | .first()
311 | )
312 | self.transact(
313 | account_number,
314 | self.get_account_number(credit_card),
315 | amount,
316 | )
317 | credit_card.current_balance -= amount
318 | if amount < credit_card.minimum_balance:
319 | credit_card.minimum_balance -= amount
320 | else:
321 | credit_card.minimum_balance = 0
322 | self.session.commit()
323 |
324 | def add_session_account(self, session_id: Text, name: Optional[Text] = ""):
325 | """Add a new account for a new session_id. Assumes no such account exists yet."""
326 | self.session.add(
327 | Account(session_id=session_id, account_holder_name=name, currency="$")
328 | )
329 |
330 | def add_credit_cards(self, session_id: Text):
331 | """Populate the creditcard table for a given session_id"""
332 | credit_card_names = ["iron bank", "credit all", "emblem", "justice bank"]
333 | credit_cards = [
334 | CreditCard(
335 | credit_card_name=cardname,
336 | minimum_balance=choice([20, 30, 40]),
337 | current_balance=choice(
338 | [round(amount, 2) for amount in list(arange(20, 500, 0.01))]
339 | ),
340 | account_id=self.get_account_from_session_id(session_id).id,
341 | )
342 | for cardname in credit_card_names
343 | ]
344 | self.session.add_all(credit_cards)
345 |
346 | def check_general_accounts_populated(
347 | self, general_account_names: Dict[Text, List[Text]]
348 | ):
349 | """Check whether tables have been populated with global values for vendors, recipients, and depositors"""
350 | account_names = set(
351 | [
352 | name
353 | for list_names in general_account_names.values()
354 | for name in list_names
355 | ]
356 | )
357 | existing_accounts = self.session.query(Account.account_holder_name).filter(
358 | Account.account_holder_name.in_(account_names)
359 | )
360 | existing_account_names = set(
361 | [account.account_holder_name for account in existing_accounts.all()]
362 | )
363 | return account_names == existing_account_names
364 |
365 | def add_general_accounts(self, general_account_names: Dict[Text, List[Text]]):
366 | """Populate tables with global values for vendors, recipients, and depositors"""
367 | general_accounts = [
368 | Account(session_id=f"{prefix}_{id}", account_holder_name=name)
369 | for prefix, names in general_account_names.items()
370 | for id, name in enumerate(names)
371 | ]
372 |
373 | for account in general_accounts:
374 | self.session.merge(account)
375 | self.session.commit()
376 |
377 | def add_recipients(self, session_id: Text):
378 | """Populate recipients table"""
379 | account = self.get_account_from_session_id(session_id)
380 | recipients = (
381 | self.session.query(Account.account_holder_name, Account.id)
382 | .filter(Account.session_id.startswith("recipient_"))
383 | .all()
384 | )
385 | session_recipients = sample(recipients, choice(list(range(3, len(recipients)))))
386 | relationships = [
387 | RecipientRelationship(
388 | account_id=account.id,
389 | recipient_account_id=recipient.id,
390 | recipient_nickname=recipient.account_holder_name,
391 | )
392 | for recipient in session_recipients
393 | ]
394 | self.session.add_all(relationships)
395 |
396 | def add_transactions(self, session_id: Text):
397 | """Populate transactions table for a session ID with random transactions"""
398 | account_number = self.get_account_number(
399 | self.get_account_from_session_id(session_id)
400 | )
401 | vendors = (
402 | self.session.query(Account)
403 | .filter(Account.session_id.startswith("vendor_"))
404 | .all()
405 | )
406 | depositors = (
407 | self.session.query(Account)
408 | .filter(Account.session_id.startswith("depositor_"))
409 | .all()
410 | )
411 |
412 | start_date = utc.localize(datetime(2019, 1, 1))
413 | end_date = utc.localize(datetime.now())
414 | number_of_days = (end_date - start_date).days
415 |
416 | for vendor in vendors:
417 | rand_spend_amounts = sample(
418 | [round(amount, 2) for amount in list(arange(5, 50, 0.01))],
419 | number_of_days // 2,
420 | )
421 |
422 | rand_dates = [
423 | (start_date + timedelta(days=randrange(number_of_days)))
424 | for x in range(0, len(rand_spend_amounts))
425 | ]
426 |
427 | spend_transactions = [
428 | Transaction(
429 | from_account_number=account_number,
430 | to_account_number=self.get_account_number(vendor),
431 | amount=amount,
432 | timestamp=date,
433 | )
434 | for amount, date in zip(rand_spend_amounts, rand_dates)
435 | ]
436 |
437 | self.session.add_all(spend_transactions)
438 |
439 | for depositor in depositors:
440 | if depositor.account_holder_name == "interest":
441 | rand_deposit_amounts = sample(
442 | [round(amount, 2) for amount in list(arange(5, 20, 0.01))],
443 | number_of_days // 30,
444 | )
445 | else:
446 | rand_deposit_amounts = sample(
447 | [round(amount, 2) for amount in list(arange(1000, 2000, 0.01))],
448 | number_of_days // 14,
449 | )
450 |
451 | rand_dates = [
452 | (start_date + timedelta(days=randrange(number_of_days)))
453 | for x in range(0, len(rand_deposit_amounts))
454 | ]
455 |
456 | deposit_transactions = [
457 | Transaction(
458 | from_account_number=self.get_account_number(depositor),
459 | to_account_number=account_number,
460 | amount=amount,
461 | timestamp=date,
462 | )
463 | for amount, date in zip(rand_deposit_amounts, rand_dates)
464 | ]
465 |
466 | self.session.add_all(deposit_transactions)
467 |
468 | def populate_profile_db(self, session_id: Text):
469 | """Initialize the database for a conversation session.
470 | Will populate all tables with sample values.
471 | If general accounts have already been populated, it will only
472 | add account-holder-specific values to tables.
473 | """
474 | if not self.check_general_accounts_populated(GENERAL_ACCOUNTS):
475 | self.add_general_accounts(GENERAL_ACCOUNTS)
476 | if not self.check_session_id_exists(session_id):
477 | self.add_session_account(session_id)
478 | self.add_recipients(session_id)
479 | self.add_transactions(session_id)
480 | self.add_credit_cards(session_id)
481 |
482 | self.session.commit()
483 |
484 | def transact(
485 | self, from_account_number: Text, to_account_number: Text, amount: float
486 | ):
487 | """Add a transation to the transaction table"""
488 | timestamp = datetime.now()
489 | transaction = Transaction(
490 | from_account_number=from_account_number,
491 | to_account_number=to_account_number,
492 | amount=amount,
493 | timestamp=timestamp,
494 | )
495 | self.session.add(transaction)
496 | self.session.commit()
497 |
--------------------------------------------------------------------------------
/actions/requirements-actions.txt:
--------------------------------------------------------------------------------
1 | python-dateutil==2.8.1
2 | numpy~=1.19.2
3 | pytz~=2019.3
4 | ruamel.yaml
5 | sqlalchemy~=1.3.22
6 |
--------------------------------------------------------------------------------
/chatroom_handoff.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
19 |
--------------------------------------------------------------------------------
/config.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 | language: en
3 | pipeline:
4 | - name: WhitespaceTokenizer
5 | - name: RegexFeaturizer
6 | - name: LexicalSyntacticFeaturizer
7 | - name: CountVectorsFeaturizer
8 | - name: CountVectorsFeaturizer
9 | analyzer: "char_wb"
10 | min_ngram: 1
11 | max_ngram: 4
12 | - name: DIETClassifier
13 | epochs: 100
14 | - name: FallbackClassifier
15 | threshold: 0.7
16 | - name: DucklingEntityExtractor
17 | url: http://localhost:8000
18 | dimensions:
19 | - amount-of-money
20 | - time
21 | - number
22 | - name: SpacyNLP
23 | model: "en_core_web_md"
24 | case_sensitive: false
25 | - name: "SpacyEntityExtractor"
26 | # Note: It is not possible to use the SpacyTokenizer + SpacyFeaturizer in
27 | # combination with the WhitespaceTokenizer, and as a result the
28 | # PERSON extraction by Spacy is not very robust.
29 | # Because of this, the nlu training data is annotated as well, and the
30 | # DIETClassifier will also extract PERSON entities .
31 | dimensions: ["PERSON"]
32 | - name: EntitySynonymMapper
33 | policies:
34 | - name: AugmentedMemoizationPolicy
35 | - name: TEDPolicy
36 | epochs: 40
37 | - name: RulePolicy
38 | core_fallback_threshold: 0.4
39 | core_fallback_action_name: "action_default_fallback"
40 | enable_fallback_prediction: True
41 |
--------------------------------------------------------------------------------
/credentials.yml:
--------------------------------------------------------------------------------
1 | # This file contains the credentials for the voice & chat platforms
2 | # which your bot is using.
3 | # https://rasa.com/docs/rasa/user-guide/messaging-and-voice-channels/
4 |
5 | rest:
6 | # # you don't need to provide anything here - this channel doesn't
7 | # # require any credentials
8 |
9 |
10 | #facebook:
11 | # verify: ""
12 | # secret: ""
13 | # page-access-token: ""
14 |
15 | #slack:
16 | # slack_token: ""
17 | # slack_channel: ""
18 | # proxy: ""
19 |
20 | #socketio:
21 | # user_message_evt:
22 | # bot_message_evt:
23 | # session_persistence:
24 |
25 | #mattermost:
26 | # url: "https:///api/v4"
27 | # token: ""
28 | # webhook_url: ""
29 |
30 | # This entry is needed if you are using Rasa X. The entry represents credentials
31 | # for the Rasa X "channel", i.e. Talk to your bot and Share with guest testers.
32 | rasa:
33 | url: "http://localhost:5002/api"
34 |
--------------------------------------------------------------------------------
/data/nlu/nlu.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 | nlu:
3 | - intent: check_human
4 | examples: |
5 | - are you a bot?
6 | - am i speaking to an ai?
7 | - are you a human or a bot?
8 | - are you real?
9 | - are you virtual?
10 | - are you an ai?
11 | - aren't you a bot
12 | - are you a chatbot
13 | - are you a rasa bot?
14 | - are you a real bot?
15 | - are you a robot
16 | - are you ai
17 | - are you artificial
18 | - are you artificial intelligence
19 | - are you real
20 | - are you really a bot
21 | - are you robot
22 | - are you sure that you're a bot?
23 | - bot?
24 | - intent: affirm
25 | examples: |
26 | - indeed
27 | - correct
28 | - that sounds good
29 | - yes
30 | - yess please
31 | - of course
32 | - yup
33 | - yeah
34 | - yes please
35 | - yes plz
36 | - Sure
37 | - Ok
38 | - sweet
39 | - cool,
40 | - yes...
41 | - y
42 | - ok
43 | - ye
44 | - okay
45 | - That would be great
46 | - YES
47 | - YUP
48 | - Yea
49 | - Yeah
50 | - Yeah sure
51 | - Yep
52 | - Yep that's fine
53 | - Yep!
54 | - Yepp
55 | - Yes
56 | - Yes I do
57 | - Yes please
58 | - Yes please!
59 | - Yes, I accept
60 | - intent: ask_transfer_charge
61 | examples: |
62 | - Will I be charged for transferring money
63 | - do transfers cost something?
64 | - is there a transfer charge?
65 | - Is there a charge
66 | - will i be charged for a transaction?
67 | - do xfers cost something?
68 | - is there a transfer fee
69 | - is there a xfer fee
70 | - how much is the transfer fee
71 | - whats the cost of transferring money
72 | - what am I charged upon money transfer
73 | - are you gonna bill me for this exchange
74 | - whats the xfer price for this account
75 | - okay but how much to move this money?
76 | - how much is the fee to shift my money around
77 | - if I send money to someone will I be charged extra for that?
78 | - is there a charge when I send money to someone
79 | - what is the fee for sending money to someone else
80 | - I sent money to my friend will I be charged extra for that
81 | - what is the percentage fee for transactions to another person
82 | - are there any transaction fees or charges I should know about?
83 | - tell me about transfer fees
84 | - intent: check_balance
85 | examples: |
86 | - How much money is on my account?
87 | - How much money is on my [bank](account_type) account?
88 | - what's my [balance](amount-of-money)?
89 | - what's my [current balance](amount-of-money)?
90 | - What's left on that account?
91 | - How much do I have on that account?
92 | - What's the [balance](amount-of-money) on that account?
93 | - How much money is left on that account?
94 | - what is my account [balance](amount-of-money)
95 | - what's my account [balance](amount-of-money)?
96 | - what's my account [balance](amount-of-money)
97 | - whats my account [balance](amount-of-money)
98 | - what is my [bank](account_type) account [balance](amount-of-money)
99 | - what's my [bank](account_type) account [balance](amount-of-money)?
100 | - what's my [bank](account_type) account [balance](amount-of-money)
101 | - whats my [bank](account_type) account [balance](amount-of-money)
102 | - What's my [credit card](account_type) [balance](amount-of-money)
103 | - What's my [credit](account_type) [balance](amount-of-money)
104 | - How much money do I owe on my [credit cards](account_type)
105 | - Show me my [credit card](account_type) [balance](amount-of-money)
106 | - What [credit](account_type) accounts do I have
107 | - Show me my [credit](account_type) accounts
108 | - Whats the [balance](amount-of-money) on my [credit](account_type) account
109 | - What's my [credit](account_type) account
110 | - What's my [emblem](credit_card) [card](account_type) [balance](amount-of-money)
111 | - Show me my [iron bank](credit_card) [balance](amount-of-money)
112 | - What's my [justice bank](credit_card) [balance](amount-of-money)
113 | - What's the [balance](amount-of-money) on the [justice bank](credit_card) account
114 | - what's my [emblm](credit_card) [credit card](account_type) [balance](amount-of-money)?
115 | - what's my [credit card](account_type) [balance](amount-of-money)?
116 | - what's my [credit card](account_type) account [balance](amount-of-money)?
117 | - What is my [emblem](credit_card) [card](account_type) [balance](amount-of-money)?
118 | - whats my [credit card](account_type) [balance](amount-of-money)
119 | - What is my [emblem](credit_card) [balance](amount-of-money)?
120 | - whats my [emblm](credit_card) [card](account_type) [balance](amount-of-money)?
121 | - what's my [embelm](credit_card)'s [card](account_type) [balance](amount-of-money)?
122 | - what's my [emblm](credit_card) account [balance](amount-of-money)?
123 | - How much money have i spent lately>
124 | - I should check my [credit card]{"entity": "account_type", "value": "credit"} [balance](amount-of-money) [first](account_type)
125 | - check my [credit card]{"entity": "account_type", "value": "credit"} [balance](amount-of-money)
126 | - check my [credit card]{"entity": "account_type", "value": "credit"} [balance](amount-of-money) [first](account_type)
127 | - Can you tell me my account [balance](amount-of-money)?
128 | - Hello, I would like to know how much money is in much money is in my account
129 | - hi, whats my account bal please
130 | - so.... what's my [balance](amount-of-money)?
131 | - whats my [current balance](amount-of-money)
132 | - What's my [balance](amount-of-money)?
133 | - How much money do I have?
134 | - Yeah, I like coffee 👀 But how much money do I have?
135 | - Yeah, I know 😀 Since it's so nice: How much money do I have?
136 | - what places have I spent money?
137 | - Wait, I'll have to check my balance first. Can you do that please?
138 | - Hi, I need to know how much money is in my [checking](account_type) account
139 | - Balance please
140 | - intent: check_earnings
141 | examples: |
142 | - How much money went into my account last month?
143 | - How much money did I make last year?
144 | - What did I earn last month?
145 | - How much did I make last month?
146 | - How much money did I make last week?
147 | - how much was deposited in my account last month?
148 | - how much was deposited in my account in the last two weeks?
149 | - check deposits for last week
150 | - total deposits over last year
151 | - how much was deposited in January
152 | - how much money have I earned?
153 | - what did I earn?
154 | - How much have i earned?
155 | - how much did I make
156 | - am I rich yet?
157 | - am I a millionaire
158 | - how much cash is rolling through my account
159 | - how much money is in the money making machine account?
160 | - what did I make in the last year?
161 | - show me how much I've earned in the last week
162 | - can i afford to go on vacation
163 | - rent is due soon how much do I have in my account
164 | - intent: deny
165 | examples: |
166 | - not really
167 | - no
168 | - I don't think so
169 | - never
170 | - no way
171 | - nope
172 | - no thanks
173 | - I dunno
174 | - Nothing!
175 | - nevermind
176 | - n
177 | - i decline
178 | - i don not like this
179 | - i don't think so
180 | - i don't want either of those
181 | - i don't want to
182 | - i don't want to give you my email
183 | - i dont want to
184 | - i dont want to accept :P lol
185 | - i guess it means - no
186 | - i'm afraid not
187 | - i'm not sure
188 | - intent: goodbye
189 | examples: |
190 | - see you later
191 | - goodbye
192 | - i'm done
193 | - quit
194 | - stop
195 | - bye
196 | - Adios
197 | - BYEE
198 | - GOODBYE
199 | - Thanks a lot. See ya later
200 | - have a good day. time to go, bye
201 | - bye bye
202 | - ok i gtg
203 | - bye bye bot
204 | - bye for now
205 | - bye udo
206 | - bye was nice talking to you
207 | - bye!
208 | - byee
209 | - catch you later
210 | - ciao
211 | - cya
212 | - farewell
213 | - good bye
214 | - good bye rasa bot!
215 | - good night
216 | - goodbye
217 | - goodbye.
218 | - goodnight
219 | - gotta go
220 | - intent: greet
221 | examples: |
222 | - yo
223 | - good morning
224 | - hi
225 | - hey there
226 | - hey
227 | - good evening
228 | - hello
229 | - Hello?
230 | - HEY
231 | - hello are you still there
232 | - hallo
233 | - HI
234 | - Hey
235 | - Hi
236 | - hi!
237 | - hello there
238 | - hi there
239 | - Hello
240 | - hello its ella
241 | - Hola.
242 | - welcome
243 | - howdy
244 | - good day
245 | - intent: inform
246 | examples: |
247 | - $10
248 | - 5000
249 | - 500
250 | - $100
251 | - $500
252 | - 100 dollars
253 | - 1000 dollars
254 | - tomorrow
255 | - next week
256 | - yesterday
257 | - for today
258 | - last week
259 | - the past month
260 | - the past two days
261 | - the last two weeks
262 | - at [amazon](vendor_name)
263 | - [starbucks](vendor_name)
264 | - at [target](vendor_name)
265 | - at [starbucks](vendor_name)
266 | - [target](vendor_name)
267 | - [Amazon](vendor_name)
268 | - [Starbucks](vendor_name)
269 | - [Target](vendor_name)
270 | - I want to pay the [current balance](amount-of-money)
271 | - [current balance](amount-of-money)
272 | - [full](amount-of-money)
273 | - in [full](amount-of-money)
274 | - the [full balance](amount-of-money)
275 | - [minimum balance](amount-of-money)
276 | - I want to pay the [minimum balance](amount-of-money)
277 | - the [current balance](amount-of-money)
278 | - the [minimum balance](amount-of-money)
279 | - my [minimum balance](amount-of-money)
280 | - my [current balance](amount-of-money)
281 | - [emblem](credit_card) [card](account_type)
282 | - all [cards](account_type)
283 | - [iron bank](credit_card) [card](account_type)
284 | - [justice bank](credit_card) [card](account_type)
285 | - [emblem](credit_card)
286 | - [iron bank](credit_card)
287 | - [justice bank](credit_card)
288 | - [emblem](credit_card) account
289 | - [iron bank](credit_card) account
290 | - [justice bank](credit_card) account
291 | - [emblem](credit_card) [credit card](account_type)
292 | - [iron bank](credit_card) [credit card](account_type)
293 | - [justice bank](credit_card) [credit card](account_type)
294 | - my [emblem](credit_card) [credit card](account_type)
295 | - my [iron bank](credit_card) [credit card](account_type)
296 | - my [justice bank](credit_card) [credit card](account_type)
297 | - my [emblem](credit_card) [card](account_type)
298 | - my [iron bank](credit_card) [card](account_type)
299 | - my [justice bank](credit_card) [card](account_type)
300 | - towards my [emblem](credit_card) [card](account_type)
301 | - towards my [iron bank](credit_card) [card](account_type)
302 | - towards my [justice bank](credit_card) [card](account_type)
303 | - for sunday
304 | - for friday
305 | - for tomorrow
306 | - for saturday
307 | - I want to pay the [minimum balance](amount-of-money) on my [emblem](credit_card) [credit card](account_type) today
308 | - today
309 | - Please schedule it for the first of next month
310 | - a hundred dollars
311 | - [mastercard](credit_card)
312 | - [visa](credit_card)
313 | - [american express](credit_card)
314 | - my [rasa](credit_card) account
315 | - my [credit card]{"entity": "account_type", "value": "credit"} account ending in 4321
316 | - My [Visa](credit_card) account
317 | - A friend.
318 | - [Alexandra](PERSON)?
319 | - today please
320 | - [Iron Bank](credit_card)
321 | - My [visa](credit_card)
322 | - [Bob](PERSON)
323 | - [bill](PERSON)
324 | - [anusha](PERSON)
325 | - [John](PERSON)
326 | - [gary](PERSON)
327 | - [Claire](PERSON)
328 | - [Imani](PERSON)
329 | - [darnell](PERSON)
330 | - [Guangchen](PERSON)
331 | - [cheng](PERSON)
332 | - to my [brother](PERSON)
333 | - to my [sister](PERSON)
334 | - my [dad](PERSON)
335 | - William Baker
336 | - Evan Oslo
337 | - Lisa Macintyre
338 | - Karen Lancaster
339 | - Percy Donald
340 | - Kyle Gardner
341 | - Katy Parrow
342 | - Percy please
343 | - Laura Schilling
344 | - In that case, let's go with Percy
345 | - My chase
346 | - Jane
347 | - Melinda
348 | - Sara
349 | - my wife's
350 | - Andreas
351 | - htthis weekend
352 | - all of them
353 | - Darren Smith
354 | - Percy
355 | - percy donald
356 | - danIelle smilanich
357 | - [Gringtos](credit_card)
358 | - intent: pay_cc
359 | examples: |
360 | - I would like to pay the [minimum balance](amount-of-money) on my [embelm](credit_card) [card](account_type)
361 | - I want to pay my [credit card](account_type)
362 | - I want to pay my [card](account_type)
363 | - Pay my [card](account_type)
364 | - I want to pay my [justice bank](credit_card) bill
365 | - Pay my [discover](credit_card)
366 | - I want to pay my [iron bank](credit_card) bill
367 | - Pay my [visa](credit_card)
368 | - I want to pay my [visa](credit_card) bill
369 | - Pay my [mastercard](credit_card)
370 | - I want to pay my [MasterCard](credit_card) bill
371 | - I want to pay my [credit card](account_type) bill
372 | - I want to pay the [current balance](amount-of-money) on my [credit card](account_type)
373 | - can you help me pay the [current balance](amount-of-money) on my [credit card](account_type)
374 | - i want to pay off my [credit card](account_type)
375 | - I want to pay off my [credit card](account_type)
376 | - i want to pay my [credit card](account_type)
377 | - i want to pay off my [emblem](credit_card) [credit card](account_type)
378 | - I want to pay my [current balance](amount-of-money) on my [embelm](credit_card) [credit card](account_type)
379 | - i want to pay my [current balance](amount-of-money) on my [emblem](credit_card) [credit card](account_type)
380 | - I want to pay $500 on my [emblem](credit_card) [credit card](account_type) on Sunday
381 | - I want to pay my [current balance](amount-of-money) on my [emblem](credit_card) [credit card](account_type) today
382 | - i need to pay off my [emblm](credit_card) [credit card](account_type)
383 | - Please schedule a payment towards my [credit card](account_type) for April 12th
384 | - Can I schedule a payment towards my [credit card](account_type) for tomorrow?
385 | - Pay off my [minimum balance](amount-of-money) please
386 | - i would like to pay $1200 to my [credit card]{"entity": "account_type", "value": "credit"}
387 | - I would also like to pay my [visa](credit_card) bill
388 | - Pay off my [credit card]{"entity": "account_type", "value": "credit"}, please
389 | - I guess it is. Since it's so much, let's pay off my [credit](account_type)
390 | - Let's pay that [credit card]{"entity": "account_type", "value": "credit"} bill
391 | - I want to pay 100 dollars toward my [Emblem](credit_card) [card](account_type), tomorrow
392 | - pay 100 towards [emblem](credit_card) [card](account_type), tomorrow
393 | - id like to pay my bill
394 | - could I pay off my [credit card]{"entity": "account_type", "value": "credit"}?
395 | - pay off my [credit card]{"entity": "account_type", "value": "credit"}
396 | - i wanna pay my [credit card]{"entity": "account_type", "value": "credit"}
397 | - pay a bill
398 | - can I pay my [card]{"entity": "account_type", "value": "credit"}?
399 | - intent: search_transactions
400 | examples: |
401 | - how much did I spend at [Target](vendor_name) this week?
402 | - what is my typical spending at [Amazon](vendor_name)?
403 | - I want to check my spending history
404 | - how much did I spend at [Starbucks](vendor_name) last week?
405 | - I need to check my spending history
406 | - I want to check my spending
407 | - I want to check my spending history at [starbucks](vendor_name)
408 | - i want to check my spending history
409 | - i want to see my transaction history
410 | - I want to search my past transactions
411 | - can I search my transaction history
412 | - can I look at past transactions
413 | - I want to search my transactions with [amazon](vendor_name)
414 | - can i seem my transactions with [target](vendor_name)
415 | - how much did i spend at [starbucks](vendor_name) last month?
416 | - what did i spend last month?
417 | - How much did I spend last month?
418 | - What did I spend at [Legoland](vendor_name) last month?
419 | - What did I spend at [Legoland](vendor_name) last year?
420 | - how much did i spend at [starbucks](vendor_name) last year
421 | - Yes! How much did I spend on [Starbucks](vendor_name) last month?
422 | - How much did I spend at Burger King last month?
423 | - what places have I spent money?
424 | - What did I spend at [Starbucks](vendor_name) in may?
425 | - How much money did I lose to [starbucks](vendor_name) in may?
426 | - Oh how much did I actually spend at [target](vendor_name) last month? I'd love to know.
427 | - Can you tell me how much I spent at [Ikea](vendor_name) this month?
428 | - Can you tell me how much I spent at coffeeshops this month?
429 | - Can you tell me how much I spent on coffee this month?
430 | - What did I spend at [Costco](vendor_name) last month?
431 | - what did I spend at [target](vendor_name) last month
432 | - where did I spend the most money last month?
433 | - intent: thankyou
434 | examples: |
435 | - thank you goodbye
436 | - okay thank you goodbye
437 | - thank you bye
438 | - um okay thank you good bye
439 | - thank you
440 | - and thats all thank you and good bye
441 | - okay thank you
442 | - thanks
443 | - thanks goodbye
444 | - thank you and good bye
445 | - Thanks!
446 | - Awesome, you are a good bot!
447 | - great!
448 | - I see, thanks
449 | - Oh thats good!
450 | - it's good :-)
451 | - thnaks
452 | - good job bot
453 | - great
454 | - thanks for the help
455 | - thanks you
456 | - thanks!
457 | - thankyou
458 | - thnks
459 | - thx
460 | - thanks for your information
461 | - thanks f
462 | - intent: transfer_money
463 | examples: |
464 | - I want to pay [John](PERSON)
465 | - I want to transfer $100 to [Bob](PERSON)
466 | - can i transfer money to [Sally](PERSON)
467 | - I want to transfer money
468 | - I want to pay someone
469 | - can I pay someone
470 | - I need to transfer money to a friend
471 | - can I transfer money to my [mom](PERSON)
472 | - I want to pay [Bert](PERSON)
473 | - pay my friend
474 | - transfer money
475 | - I want to transfer $100 to [Tommy](PERSON)
476 | - i want to transfer $400 to [Akela](PERSON)
477 | - I want to pay [Paula Handy](PERSON)
478 | - pay Katy Parrow $40 please
479 | - transfer $60 to [Jason Jacob](PERSON)
480 | - pay [Evan Oslo](PERSON)
481 | - pay [Lisa](PERSON) please
482 | - can I transfer money to [Kyle Gardner](PERSON)?
483 | - Pay [Karen](PERSON) 60 Euros
484 | - pay [Mona](PERSON) $60
485 | - transfer $60 to [Sally](PERSON)
486 | - need to transfer money
487 | - II want to transfer to [Kelly](PERSON)
488 | - Pay [Percy](PERSON) $50
489 | - Pay $50 to [Pat](PERSON)
490 | - Ok pay [Emma](PERSON)
491 | - pay [Emanual](PERSON)
492 | - i want to transfer $100 to [Jane smith](PERSON)
493 | - i want to transfer $100 to my [daughter](PERSON)
494 | - i want to transfer money please
495 | - i mean i want to transfer money
496 | - I need to pay a friend.
497 | - transfer money to [ethan oswald](PERSON)
498 | - transfer money to [sara](PERSON)
499 | - I need to transfer money to my grandma [Judith](PERSON).
500 | - i want to transfer money to [Latisha](PERSON)
501 | - I need to make an urgent transfer to [Bob](PERSON), can you do it?
502 | - Ahh, okay so I want to make a transfer to [Bob](PERSON).
503 | - Can I transfer money to a friend?
504 | - I need to transfer money to [Jeff](PERSON), my son
505 | - I need to send money to my kid
506 | - I need to transfer money
507 | - send $50 to [john jacob](PERSON)
508 | - I need to transfer money to my co-worker who paid for lunch
509 | - Hi I like to send money
510 | - I'd like to send 50$ to [John](PERSON)
511 | - Hi I like to send money to [John](PERSON)
512 | - Please transfer 50 dollars to [Andreas](PERSON)
513 | - I would like to transfer money to [Philipp](PERSON)
514 | - I would like to transfer 50$ to [Joschka](PERSON)
515 | - intent: check_recipients
516 | examples: |
517 | - Who can I send money to?
518 | - Who are my known recipients
519 | - Show me my list of recipients
520 | - Show the recipient list
521 | - Show me people I can send money to
522 | - Who is a valid payee
523 | - who can I pay?
524 | - who can I transfer money?
525 | - who's in my recipient list?
526 | - who can I transfer money to?
527 | - Who is on your list?
528 | - who is in my list of kown recipients?
529 | - Who all can I transfer money to?
530 | - Who can I transfer money to?
531 | - Okay. Who can I transfer money to then?
532 | - can I see the list of known recipients?
533 | - tell me who I can share my money with
534 | - whats my recipient list
535 | - can I send money to anyone?
536 | - who exactly am I able to send money to
537 | - if I want to transfer money can i send it to anyone
538 | - show me my money sending list
539 | - intent: help
540 | examples: |
541 | - help
542 | - what can you do?
543 | - what can I ask you?
544 | - what do you do?
545 | - what can you help me with?
546 | - help me
547 | - help, what do you do
548 | - how do I use this
549 | - how can you help me
550 | - What are the things that you can do?
551 | - What else can you help me with?
552 | - can you do anything else?
553 | - can you help me?
554 | - come back
555 | - cool! can I do something else here?
556 | - hello what can you do for me
557 | - help
558 | - help me
559 | - help please
560 | - help pls
561 | - help?
562 | - hep me
563 | - intent: human_handoff
564 | examples: |
565 | - handoff
566 | - operator
567 | - I want a human
568 | - can I speak to an agent
569 | - real agent please
570 | - real human
571 | - chat with a live agent
572 | - give me a person please
573 | - i want to talk to a human
574 | - transfer to a human
575 | - Please give me to a human
576 | - can I talk to human?
577 | - can I talk to human
578 | - talk to human
579 | - i want human :(
580 | - can i talk to human
581 | - i want to talk to a human
582 | - i want to speak to human
583 | - can i talk to a real person?
584 | - connect me to a real person
585 | - I need a real person
586 | - can i took with a real person
587 | - let me speak to a real person
588 | - let me speak to a real person please
589 | - i want to talk to a real person
590 | - intent: out_of_scope
591 | examples: |
592 | - what is the square root of 5
593 | - I want to know the weather
594 | - what is the meaning of life.
595 | - Fridge Isn't Running
596 | - my tv isn't working
597 | - I want a pizza
598 | - my washing machine isn't working
599 | - what year is it
600 | - order a pizza
601 | - I want to order a pizza
602 | - what is the weather today
603 | - what is the weather
604 | - what the weather today ?
605 | - hows the weather
606 | - tell me a joke
607 | - Can I get a hamburger?
608 | - Can YouTube talk?
609 | - Can you call me back ?
610 | - Can you give me your datacenter's password
611 | - Can you give me your datacenter's password?
612 | - Can you make sandwiches?
613 | - Can you please send me an uber
614 | - ofif fsdfafsfs
615 | - synonym: credit
616 | examples: |
617 | - credit card
618 | - credit cards
619 | - credit account
620 | - credit accounts
621 | - card
622 | - cards
623 | - credit card account
624 | - synonym: emblem
625 | examples: |
626 | - emblm
627 | - embelm
628 | - Emblem
629 | - synonym: current balance
630 | examples: |
631 | - balance
632 | - full
633 | - full balance
634 |
--------------------------------------------------------------------------------
/data/rules/rules.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 |
3 | rules:
4 |
5 | - rule: Confirm that the bot is not a human
6 | steps:
7 | - intent: check_human
8 | - action: utter_bot
9 |
10 | - rule: Ask the user to rephrase whenever they send a message with low NLU confidence
11 | steps:
12 | - intent: nlu_fallback
13 | - action: utter_default
14 |
15 | - rule: answer out of scope
16 | steps:
17 | - intent: out_of_scope
18 | - action: utter_out_of_scope
19 |
20 | - rule: greet
21 | steps:
22 | - intent: greet
23 | - action: utter_greet
24 | - action: utter_help
25 |
26 | - rule: say goodbye
27 | steps:
28 | - intent: goodbye
29 | - action: utter_goodbye
30 |
31 | - rule: help
32 | steps:
33 | - intent: help
34 | - action: utter_help
35 |
36 | - rule: thankyou
37 | steps:
38 | - intent: thankyou
39 | - action: utter_noworries
40 |
41 | - rule: is there a transfer charge
42 | steps:
43 | - intent: ask_transfer_charge
44 | - action: action_show_transfer_charge
45 |
46 | - rule: Show list of known recipients
47 | steps:
48 | - intent: check_recipients
49 | - action: action_show_recipients
50 |
51 | - rule: Show balance (bank account or credit card, based on account_type)
52 | steps:
53 | - intent: check_balance
54 | - action: action_show_balance
55 |
56 | - rule: Activate cc_payment_form when no other form is active
57 | condition:
58 | # this condition allows stories to handle form switching
59 | - active_loop: null
60 | steps:
61 | - intent: pay_cc
62 | - action: cc_payment_form
63 | - active_loop: cc_payment_form
64 |
65 | - rule: Activate transfer_money_form when no other form is active
66 | condition:
67 | # this condition allows stories to handle form switching
68 | - active_loop: null
69 | steps:
70 | - intent: transfer_money
71 | - action: transfer_money_form
72 | - active_loop: transfer_money_form
73 |
74 | - rule: Activate transaction_search_form when no other form is active
75 | condition:
76 | # this condition allows stories to handle form switching
77 | - active_loop: null
78 | steps:
79 | - or:
80 | - intent: search_transactions
81 | - intent: check_earnings
82 | - action: transaction_search_form
83 | - active_loop: transaction_search_form
84 |
85 | - rule: Submit cc_payment_form while not switched from previous form
86 | condition:
87 | - active_loop: cc_payment_form
88 | - slot_was_set:
89 | - previous_form_name: null
90 | steps:
91 | - action: cc_payment_form
92 | - active_loop: null
93 | - slot_was_set:
94 | - requested_slot: null
95 | - action: action_pay_cc
96 |
97 | - rule: Submit transfer_money_form while not switched from previous form
98 | condition:
99 | - active_loop: transfer_money_form
100 | - slot_was_set:
101 | - previous_form_name: null
102 | steps:
103 | - action: transfer_money_form
104 | - active_loop: null
105 | - slot_was_set:
106 | - requested_slot: null
107 | - action: action_transfer_money
108 |
109 | - rule: Submit transaction_search_form while not switched from previous form
110 | condition:
111 | - active_loop: transaction_search_form
112 | - slot_was_set:
113 | - previous_form_name: null
114 | steps:
115 | - action: transaction_search_form
116 | - active_loop: null
117 | - slot_was_set:
118 | - requested_slot: null
119 | - action: action_transaction_search
120 |
--------------------------------------------------------------------------------
/data/rules/rules_handoff.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 |
3 | rules:
4 |
5 | - rule: Handoff intent from other bot's handoff triggers greeting
6 | steps:
7 | - intent: handoff
8 | - action: utter_greet
9 |
10 | - rule: Provide handoff options
11 | steps:
12 | - intent: human_handoff
13 | - action: utter_ask_handoff
14 | - action: action_handoff_options
15 |
16 | - rule: Execute handoff
17 | steps:
18 | - action: action_handoff_options
19 | - intent: trigger_handoff
20 | - action: action_handoff
21 |
22 | - rule: Deny handoff
23 | steps:
24 | - action: action_handoff_options
25 | - intent: deny
26 | - action: utter_ask_whatelse
27 |
--------------------------------------------------------------------------------
/data/stories/stories.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 |
3 | stories:
4 |
5 | - story: say ok when user affirms after utter_help
6 | steps:
7 | - action: utter_help
8 | - intent: affirm
9 | - action: utter_ok
10 |
11 | - story: say ok when user affirms after action_show_balance
12 | steps:
13 | - action: action_show_balance
14 | - intent: affirm
15 | - action: utter_ok
16 |
17 | - story: say ok when user affirms after action_show_recipients
18 | steps:
19 | - action: action_show_recipients
20 | - intent: affirm
21 | - action: utter_ok
22 |
23 | - story: say ok when user affirms after action_show_transfer_charge
24 | steps:
25 | - action: action_show_transfer_charge
26 | - intent: affirm
27 | - action: utter_ok
28 |
--------------------------------------------------------------------------------
/data/stories/stories_switch_from_pay_credit_card.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 |
3 | stories:
4 |
5 | - story: pay credit card + switch to search transactions or transfer money, deny
6 | steps:
7 | - intent: pay_cc
8 | - action: cc_payment_form
9 | - active_loop: cc_payment_form
10 | - or:
11 | - intent: search_transactions
12 | - intent: check_earnings
13 | - intent: transfer_money
14 | - action: action_switch_forms_ask
15 | - slot_was_set:
16 | - next_form_name: another form
17 | - intent: deny
18 | - action: action_switch_forms_deny
19 | - slot_was_set:
20 | - next_form_name: null
21 | - action: cc_payment_form
22 | - active_loop: cc_payment_form
23 |
24 | - story: pay credit card + switch to search transactions, affirm + switch back, deny
25 | steps:
26 | - intent: pay_cc
27 | - action: cc_payment_form
28 | - active_loop: cc_payment_form
29 | - or:
30 | - intent: search_transactions
31 | - intent: check_earnings
32 | - action: action_switch_forms_ask
33 | - slot_was_set:
34 | - next_form_name: transaction_search_form
35 | - intent: affirm
36 | - action: action_switch_forms_affirm
37 | - slot_was_set:
38 | - next_form_name: null
39 | - slot_was_set:
40 | - previous_form_name: cc_payment_form
41 | - action: transaction_search_form
42 | - active_loop: transaction_search_form
43 | - active_loop: null
44 | - slot_was_set:
45 | - requested_slot: null
46 | - action: action_transaction_search
47 | - action: action_switch_back_ask
48 | - slot_was_set:
49 | - previous_form_name: null
50 | - intent: deny
51 | - action: utter_ask_whatelse
52 |
53 | - story: pay credit card + switch to transfer money, affirm + switch back, deny
54 | steps:
55 | - intent: pay_cc
56 | - action: cc_payment_form
57 | - active_loop: cc_payment_form
58 | - intent: transfer_money
59 | - action: action_switch_forms_ask
60 | - slot_was_set:
61 | - next_form_name: transfer_money_form
62 | - intent: affirm
63 | - action: action_switch_forms_affirm
64 | - slot_was_set:
65 | - next_form_name: null
66 | - slot_was_set:
67 | - previous_form_name: cc_payment_form
68 | - action: transfer_money_form
69 | - active_loop: transfer_money_form
70 | - active_loop: null
71 | - slot_was_set:
72 | - requested_slot: null
73 | - action: action_transfer_money
74 | - action: action_switch_back_ask
75 | - slot_was_set:
76 | - previous_form_name: null
77 | - intent: deny
78 | - action: utter_ask_whatelse
79 |
80 | - story: pay credit card + switch to search transactions, affirm + switch back, affirm
81 | steps:
82 | - intent: pay_cc
83 | - action: cc_payment_form
84 | - active_loop: cc_payment_form
85 | - or:
86 | - intent: search_transactions
87 | - intent: check_earnings
88 | - action: action_switch_forms_ask
89 | - slot_was_set:
90 | - next_form_name: transaction_search_form
91 | - intent: affirm
92 | - action: action_switch_forms_affirm
93 | - slot_was_set:
94 | - next_form_name: null
95 | - slot_was_set:
96 | - previous_form_name: cc_payment_form
97 | - action: transaction_search_form
98 | - active_loop: transaction_search_form
99 | - active_loop: null
100 | - slot_was_set:
101 | - requested_slot: null
102 | - action: action_transaction_search
103 | - action: action_switch_back_ask
104 | - slot_was_set:
105 | - previous_form_name: null
106 | - intent: affirm
107 | - action: cc_payment_form
108 | - active_loop: cc_payment_form
109 |
110 | - story: pay credit card + switch to transfer money, affirm + switch back, affirm
111 | steps:
112 | - intent: pay_cc
113 | - action: cc_payment_form
114 | - active_loop: cc_payment_form
115 | - intent: transfer_money
116 | - action: action_switch_forms_ask
117 | - slot_was_set:
118 | - next_form_name: transfer_money_form
119 | - intent: affirm
120 | - action: action_switch_forms_affirm
121 | - slot_was_set:
122 | - next_form_name: null
123 | - slot_was_set:
124 | - previous_form_name: cc_payment_form
125 | - action: transfer_money_form
126 | - active_loop: transfer_money_form
127 | - active_loop: null
128 | - slot_was_set:
129 | - requested_slot: null
130 | - action: action_transfer_money
131 | - action: action_switch_back_ask
132 | - slot_was_set:
133 | - previous_form_name: null
134 | - intent: affirm
135 | - action: cc_payment_form
136 | - active_loop: cc_payment_form
137 |
--------------------------------------------------------------------------------
/data/stories/stories_switch_from_search_transactions.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 |
3 | stories:
4 |
5 | - story: search transactions + switch to transfer money or pay credit card, deny
6 | steps:
7 | - or:
8 | - intent: search_transactions
9 | - intent: check_earnings
10 | - action: transaction_search_form
11 | - active_loop: transaction_search_form
12 | - or:
13 | - intent: transfer_money
14 | - intent: pay_cc
15 | - action: action_switch_forms_ask
16 | - slot_was_set:
17 | - next_form_name: another form
18 | - intent: deny
19 | - action: action_switch_forms_deny
20 | - slot_was_set:
21 | - next_form_name: null
22 | - action: transaction_search_form
23 | - active_loop: transaction_search_form
24 |
25 | - story: search transactions + switch to transfer money, affirm + switch back, deny
26 | steps:
27 | - or:
28 | - intent: search_transactions
29 | - intent: check_earnings
30 | - action: transaction_search_form
31 | - active_loop: transaction_search_form
32 | - intent: transfer_money
33 | - action: action_switch_forms_ask
34 | - slot_was_set:
35 | - next_form_name: transfer_money_form
36 | - intent: affirm
37 | - action: action_switch_forms_affirm
38 | - slot_was_set:
39 | - next_form_name: null
40 | - slot_was_set:
41 | - previous_form_name: transaction_search_form
42 | - action: transfer_money_form
43 | - active_loop: transfer_money_form
44 | - active_loop: null
45 | - slot_was_set:
46 | - requested_slot: null
47 | - action: action_transfer_money
48 | - action: action_switch_back_ask
49 | - slot_was_set:
50 | - previous_form_name: null
51 | - intent: deny
52 | - action: utter_ask_whatelse
53 |
54 | - story: search transactions + switch to pay credit card, affirm + switch back, deny
55 | steps:
56 | - or:
57 | - intent: search_transactions
58 | - intent: check_earnings
59 | - action: transaction_search_form
60 | - active_loop: transaction_search_form
61 | - intent: pay_cc
62 | - action: action_switch_forms_ask
63 | - slot_was_set:
64 | - next_form_name: cc_payment_form
65 | - intent: affirm
66 | - action: action_switch_forms_affirm
67 | - slot_was_set:
68 | - next_form_name: null
69 | - slot_was_set:
70 | - previous_form_name: transaction_search_form
71 | - action: cc_payment_form
72 | - active_loop: cc_payment_form
73 | - active_loop: null
74 | - slot_was_set:
75 | - requested_slot: null
76 | - action: action_pay_cc
77 | - action: action_switch_back_ask
78 | - slot_was_set:
79 | - previous_form_name: null
80 | - intent: deny
81 | - action: utter_ask_whatelse
82 |
83 | - story: search transactions + switch to transfer money, affirm + switch back, affirm
84 | steps:
85 | - or:
86 | - intent: search_transactions
87 | - intent: check_earnings
88 | - action: transaction_search_form
89 | - active_loop: transaction_search_form
90 | - intent: transfer_money
91 | - action: action_switch_forms_ask
92 | - slot_was_set:
93 | - next_form_name: transfer_money_form
94 | - intent: affirm
95 | - action: action_switch_forms_affirm
96 | - slot_was_set:
97 | - next_form_name: null
98 | - slot_was_set:
99 | - previous_form_name: transaction_search_form
100 | - action: transfer_money_form
101 | - active_loop: transfer_money_form
102 | - active_loop: null
103 | - slot_was_set:
104 | - requested_slot: null
105 | - action: action_transfer_money
106 | - action: action_switch_back_ask
107 | - slot_was_set:
108 | - previous_form_name: null
109 | - intent: affirm
110 | - action: transaction_search_form
111 | - active_loop: transaction_search_form
112 |
113 | - story: search transactions + switch to pay credit card, affirm + switch back, affirm
114 | steps:
115 | - or:
116 | - intent: search_transactions
117 | - intent: check_earnings
118 | - action: transaction_search_form
119 | - active_loop: transaction_search_form
120 | - intent: pay_cc
121 | - action: action_switch_forms_ask
122 | - slot_was_set:
123 | - next_form_name: cc_payment_form
124 | - intent: affirm
125 | - action: action_switch_forms_affirm
126 | - slot_was_set:
127 | - next_form_name: null
128 | - slot_was_set:
129 | - previous_form_name: transaction_search_form
130 | - action: cc_payment_form
131 | - active_loop: cc_payment_form
132 | - active_loop: null
133 | - slot_was_set:
134 | - requested_slot: null
135 | - action: action_pay_cc
136 | - action: action_switch_back_ask
137 | - slot_was_set:
138 | - previous_form_name: null
139 | - intent: affirm
140 | - action: transaction_search_form
141 | - active_loop: transaction_search_form
142 |
--------------------------------------------------------------------------------
/data/stories/stories_switch_from_transfer_money.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 |
3 | stories:
4 |
5 | - story: transfer money + switch to search transactions or pay credit card, deny
6 | steps:
7 | - intent: transfer_money
8 | - action: transfer_money_form
9 | - active_loop: transfer_money_form
10 | - or:
11 | - intent: search_transactions
12 | - intent: check_earnings
13 | - intent: pay_cc
14 | - action: action_switch_forms_ask
15 | - slot_was_set:
16 | - next_form_name: another form
17 | - intent: deny
18 | - action: action_switch_forms_deny
19 | - slot_was_set:
20 | - next_form_name: null
21 | - action: transfer_money_form
22 | - active_loop: transfer_money_form
23 |
24 | - story: transfer money + switch to search transactions, affirm + switch back, deny
25 | steps:
26 | - intent: transfer_money
27 | - action: transfer_money_form
28 | - active_loop: transfer_money_form
29 | - or:
30 | - intent: search_transactions
31 | - intent: check_earnings
32 | - action: action_switch_forms_ask
33 | - slot_was_set:
34 | - next_form_name: transaction_search_form
35 | - intent: affirm
36 | - action: action_switch_forms_affirm
37 | - slot_was_set:
38 | - next_form_name: null
39 | - slot_was_set:
40 | - previous_form_name: transfer_money_form
41 | - action: transaction_search_form
42 | - active_loop: transaction_search_form
43 | - active_loop: null
44 | - slot_was_set:
45 | - requested_slot: null
46 | - action: action_transaction_search
47 | - action: action_switch_back_ask
48 | - slot_was_set:
49 | - previous_form_name: null
50 | - intent: deny
51 | - action: utter_ask_whatelse
52 |
53 | - story: transfer money + switch to pay credit card, affirm + switch back, deny
54 | steps:
55 | - intent: transfer_money
56 | - action: transfer_money_form
57 | - active_loop: transfer_money_form
58 | - intent: pay_cc
59 | - action: action_switch_forms_ask
60 | - slot_was_set:
61 | - next_form_name: cc_payment_form
62 | - intent: affirm
63 | - action: action_switch_forms_affirm
64 | - slot_was_set:
65 | - next_form_name: null
66 | - slot_was_set:
67 | - previous_form_name: transfer_money_form
68 | - action: cc_payment_form
69 | - active_loop: cc_payment_form
70 | - active_loop: null
71 | - slot_was_set:
72 | - requested_slot: null
73 | - action: action_pay_cc
74 | - action: action_switch_back_ask
75 | - slot_was_set:
76 | - previous_form_name: null
77 | - intent: deny
78 | - action: utter_ask_whatelse
79 |
80 | - story: transfer money+ switch to search transactions, affirm + switch back, affirm
81 | steps:
82 | - intent: transfer_money
83 | - action: transfer_money_form
84 | - active_loop: transfer_money_form
85 | - or:
86 | - intent: search_transactions
87 | - intent: check_earnings
88 | - action: action_switch_forms_ask
89 | - slot_was_set:
90 | - next_form_name: transaction_search_form
91 | - intent: affirm
92 | - action: action_switch_forms_affirm
93 | - slot_was_set:
94 | - next_form_name: null
95 | - slot_was_set:
96 | - previous_form_name: transfer_money_form
97 | - action: transaction_search_form
98 | - active_loop: transaction_search_form
99 | - active_loop: null
100 | - slot_was_set:
101 | - requested_slot: null
102 | - action: action_transaction_search
103 | - action: action_switch_back_ask
104 | - slot_was_set:
105 | - previous_form_name: null
106 | - intent: affirm
107 | - action: transfer_money_form
108 | - active_loop: transfer_money_form
109 |
110 | - story: transfer money+ switch to pay credit card, affirm + switch back, affirm
111 | steps:
112 | - intent: transfer_money
113 | - action: transfer_money_form
114 | - active_loop: transfer_money_form
115 | - intent: pay_cc
116 | - action: action_switch_forms_ask
117 | - slot_was_set:
118 | - next_form_name: cc_payment_form
119 | - intent: affirm
120 | - action: action_switch_forms_affirm
121 | - slot_was_set:
122 | - next_form_name: null
123 | - slot_was_set:
124 | - previous_form_name: transfer_money_form
125 | - action: cc_payment_form
126 | - active_loop: cc_payment_form
127 | - active_loop: null
128 | - slot_was_set:
129 | - requested_slot: null
130 | - action: action_pay_cc
131 | - action: action_switch_back_ask
132 | - slot_was_set:
133 | - previous_form_name: null
134 | - intent: affirm
135 | - action: transfer_money_form
136 | - active_loop: transfer_money_form
137 |
--------------------------------------------------------------------------------
/deploy/gcr-auth.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "service_account",
3 | "project_id": "rasa-platform",
4 | "private_key_id": "set_as_environment_variable-GCR_AUTH_JSON_PRIVATE_KEY_ID",
5 | "private_key": "set_as_environment_variable-GCR_AUTH_JSON_PRIVATE_KEY",
6 | "client_email": "set_as_environment_variable-GCR_AUTH_JSON_CLIENT_EMAIL",
7 | "client_id": "set_as_environment_variable-GCR_AUTH_JSON_CLIENT_ID",
8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9 | "token_uri": "https://accounts.google.com/o/oauth2/token",
10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11 | "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/rasa-testing%40rasa-platform.iam.gserviceaccount.com"
12 | }
--------------------------------------------------------------------------------
/deploy/values.yml:
--------------------------------------------------------------------------------
1 | # debugMode enables / disables the debug mode for Rasa and Rasa X
2 | debugMode: "set_as_environment_variable-RASAX_DEBUG_MODE"
3 | # nginx ingress controller
4 | nginx:
5 | service:
6 | port: 80
7 | # docker pull secret for private images
8 | images:
9 | imagePullSecrets:
10 | - name: "gcr-pull-secret"
11 | - name: "ecr-pull-secret"
12 | # action server image
13 | app:
14 | name: "set_as_environment_variable-APP_NAME"
15 | tag: "set_as_environment_variable-APP_TAG"
16 | # rasax specific settings
17 | rasax:
18 | tag: "set_as_environment_variable-RASAX_TAG"
19 | # name of the Rasa Enterprise image to use
20 | name: "gcr.io/rasa-platform/rasa-x-ee"
21 | # initialUser is the user which is created upon the initial start of Rasa Enterprise
22 | initialUser:
23 | # username specifies a name of this user
24 | username: "set_as_environment_variable-RASAX_INITIALUSER_USERNAME"
25 | # password for the Rasa Enterprise user
26 | password: "set_as_environment_variable-RASAX_INITIALUSER_PASSWORD"
27 | # passwordSalt Rasa X uses to salt the user passwords
28 | passwordSalt: "set_as_environment_variable-RASAX_PASSWORDSALT"
29 | # token Rasa X accepts as authentication token from other Rasa services
30 | token: "set_as_environment_variable-RASAX_TOKEN"
31 | # jwtSecret which is used to sign the jwtTokens of the users
32 | jwtSecret: "set_as_environment_variable-RASAX_JWTSECRET"
33 | # rasa: Settings common for all Rasa containers
34 | rasa:
35 | tag: "set_as_environment_variable-RASA_TAG"
36 | # token Rasa accepts as authentication token from other Rasa services
37 | token: "set_as_environment_variable-RASA_TOKEN"
38 | livenessProbe:
39 | # initialProbeDelay for the `livenessProbe`
40 | initialProbeDelay: 60
41 | # RabbitMQ specific settings
42 | rabbitmq:
43 | # rabbitmq settings of the subchart
44 | rabbitmq:
45 | # password which is used for the authentication
46 | password: "set_as_environment_variable-RABBITMQ_RABBITMQ_PASSWORD"
47 | # global settings of the used subcharts
48 | global:
49 | # postgresql: global settings of the postgresql subchart
50 | postgresql:
51 | # postgresqlPassword is the password which is used when the postgresqlUsername equals "postgres"
52 | postgresqlPassword: "set_as_environment_variable-GLOBAL_POSTGRESQL_POSTGRESQLPASSWORD"
53 | # redis: global settings of the redis subchart
54 | redis:
55 | # password to use in case there no external secret was provided
56 | password: "set_as_environment_variable-GLOBAL_REDIS_PASSWORD"
--------------------------------------------------------------------------------
/domain.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 | session_config:
3 | session_expiration_time: 0
4 | carry_over_slots_to_new_session: true
5 | intents:
6 | - check_human
7 | - transfer_money:
8 | use_entities: []
9 | - inform
10 | - pay_cc:
11 | use_entities: []
12 | - greet
13 | - goodbye
14 | - affirm
15 | - deny
16 | - thankyou
17 | - ask_transfer_charge
18 | - search_transactions:
19 | use_entities: []
20 | - check_balance:
21 | use_entities:
22 | - credit_card
23 | - account_type
24 | - check_earnings:
25 | use_entities: []
26 | - check_recipients
27 | - out_of_scope
28 | - session_start
29 | - restart
30 | - trigger_handoff
31 | - handoff
32 | - human_handoff
33 | - help
34 | - nlu_fallback
35 | entities:
36 | - amount-of-money
37 | - credit_card
38 | - payment_date
39 | - vendor_name
40 | - time
41 | - PERSON
42 | - number
43 | - account_type
44 | - handoff_to
45 | - search_type
46 | slots:
47 | AA_CONTINUE_FORM:
48 | type: any
49 | influence_conversation: false
50 | mappings:
51 | - intent: affirm
52 | type: from_intent
53 | value: yes
54 | conditions:
55 | - active_loop: cc_payment_form
56 | requested_slot: AA_CONTINUE_FORM
57 | - active_loop: transfer_money_form
58 | requested_slot: AA_CONTINUE_FORM
59 | - active_loop: transaction_search_form
60 | requested_slot: AA_CONTINUE_FORM
61 | - intent: deny
62 | type: from_intent
63 | value: no
64 | conditions:
65 | - active_loop: cc_payment_form
66 | requested_slot: AA_CONTINUE_FORM
67 | - active_loop: transfer_money_form
68 | requested_slot: AA_CONTINUE_FORM
69 | - active_loop: transaction_search_form
70 | requested_slot: AA_CONTINUE_FORM
71 | - intent:
72 | - inform
73 | - cc_payment_form
74 | type: from_text
75 | conditions:
76 | - active_loop: cc_payment_form
77 | requested_slot: AA_CONTINUE_FORM
78 | - intent:
79 | - inform
80 | - transfer_money_form
81 | type: from_text
82 | conditions:
83 | - active_loop: transfer_money_form
84 | requested_slot: AA_CONTINUE_FORM
85 | - intent:
86 | - inform
87 | - transaction_search_form
88 | type: from_text
89 | conditions:
90 | - active_loop: transaction_search_form
91 | requested_slot: AA_CONTINUE_FORM
92 | PERSON:
93 | type: any
94 | influence_conversation: false
95 | mappings:
96 | - entity: PERSON
97 | type: from_entity
98 | conditions:
99 | - active_loop: transfer_money_form
100 | requested_slot: PERSON
101 | - intent:
102 | - inform
103 | - transfer_money_form
104 | type: from_text
105 | conditions:
106 | - active_loop: transfer_money_form
107 | requested_slot: PERSON
108 | - type: from_entity
109 | entity: PERSON
110 | account_type:
111 | type: any
112 | influence_conversation: false
113 | mappings:
114 | - type: from_entity
115 | entity: account_type
116 | amount-of-money:
117 | type: any
118 | influence_conversation: false
119 | mappings:
120 | - entity: amount-of-money
121 | not_intent:
122 | - check_balance
123 | - check_earnings
124 | type: from_entity
125 | conditions:
126 | - active_loop: cc_payment_form
127 | requested_slot: amount-of-money
128 | - active_loop: transfer_money_form
129 | requested_slot: amount-of-money
130 | - entity: number
131 | not_intent:
132 | - check_balance
133 | - check_earnings
134 | type: from_entity
135 | conditions:
136 | - active_loop: cc_payment_form
137 | requested_slot: amount-of-money
138 | - active_loop: transfer_money_form
139 | requested_slot: amount-of-money
140 | - intent:
141 | - inform
142 | - cc_payment_form
143 | type: from_text
144 | conditions:
145 | - active_loop: cc_payment_form
146 | requested_slot: amount-of-money
147 | - intent:
148 | - inform
149 | - transfer_money_form
150 | type: from_text
151 | conditions:
152 | - active_loop: transfer_money_form
153 | requested_slot: amount-of-money
154 | - type: from_entity
155 | entity: amount-of-money
156 | amount_transferred:
157 | type: any
158 | initial_value: 0
159 | influence_conversation: false
160 | mappings:
161 | - type: custom
162 | credit_card:
163 | type: any
164 | influence_conversation: false
165 | mappings:
166 | - entity: credit_card
167 | type: from_entity
168 | conditions:
169 | - active_loop: cc_payment_form
170 | requested_slot: credit_card
171 | - intent:
172 | - inform
173 | - cc_payment_form
174 | type: from_text
175 | conditions:
176 | - active_loop: cc_payment_form
177 | requested_slot: credit_card
178 | - type: from_entity
179 | entity: credit_card
180 | currency:
181 | type: any
182 | influence_conversation: false
183 | initial_value: $
184 | mappings:
185 | - type: custom
186 | end_time:
187 | type: any
188 | influence_conversation: false
189 | mappings:
190 | - type: custom
191 | end_time_formatted:
192 | type: any
193 | influence_conversation: false
194 | mappings:
195 | - type: custom
196 | grain:
197 | type: any
198 | influence_conversation: false
199 | mappings:
200 | - type: custom
201 | handoff_to:
202 | type: any
203 | influence_conversation: false
204 | mappings:
205 | - type: from_entity
206 | entity: handoff_to
207 | next_form_name:
208 | type: text
209 | influence_conversation: true
210 | mappings:
211 | - type: custom
212 | number:
213 | type: any
214 | influence_conversation: false
215 | mappings:
216 | - type: from_entity
217 | entity: number
218 | payment_amount_type:
219 | type: any
220 | initial_value: ''
221 | influence_conversation: false
222 | mappings:
223 | - type: custom
224 | previous_form_name:
225 | type: text
226 | influence_conversation: true
227 | mappings:
228 | - type: custom
229 | repeated_validation_failures:
230 | type: any
231 | influence_conversation: false
232 | mappings:
233 | - type: custom
234 | requested_slot:
235 | type: any
236 | influence_conversation: false
237 | mappings:
238 | - type: custom
239 | search_type:
240 | type: any
241 | influence_conversation: false
242 | mappings:
243 | - intent: search_transactions
244 | type: from_trigger_intent
245 | value: spend
246 | - intent: check_earnings
247 | type: from_trigger_intent
248 | value: deposit
249 | - type: from_entity
250 | entity: search_type
251 | conditions:
252 | - active_loop: transaction_search_form
253 | - type: from_entity
254 | entity: search_type
255 | start_time:
256 | type: any
257 | influence_conversation: false
258 | mappings:
259 | - type: custom
260 | start_time_formatted:
261 | type: any
262 | influence_conversation: false
263 | mappings:
264 | - type: custom
265 | time:
266 | type: any
267 | influence_conversation: false
268 | mappings:
269 | - entity: time
270 | type: from_entity
271 | conditions:
272 | - active_loop: cc_payment_form
273 | requested_slot: time
274 | - active_loop: transaction_search_form
275 | requested_slot: time
276 | - intent:
277 | - inform
278 | - cc_payment_form
279 | type: from_text
280 | conditions:
281 | - active_loop: cc_payment_form
282 | requested_slot: time
283 | - intent:
284 | - inform
285 | - transaction_search_form
286 | type: from_text
287 | conditions:
288 | - active_loop: transaction_search_form
289 | requested_slot: time
290 | - type: from_entity
291 | entity: time
292 | time_formatted:
293 | type: any
294 | influence_conversation: false
295 | mappings:
296 | - type: custom
297 | vendor_name:
298 | type: any
299 | influence_conversation: false
300 | mappings:
301 | - type: from_entity
302 | entity: vendor_name
303 | zz_confirm_form:
304 | type: any
305 | influence_conversation: false
306 | mappings:
307 | - intent: affirm
308 | type: from_intent
309 | value: yes
310 | conditions:
311 | - active_loop: cc_payment_form
312 | requested_slot: zz_confirm_form
313 | - active_loop: transfer_money_form
314 | requested_slot: zz_confirm_form
315 | - active_loop: transaction_search_form
316 | requested_slot: zz_confirm_form
317 | - intent: deny
318 | type: from_intent
319 | value: no
320 | conditions:
321 | - active_loop: cc_payment_form
322 | requested_slot: zz_confirm_form
323 | - active_loop: transfer_money_form
324 | requested_slot: zz_confirm_form
325 | - active_loop: transaction_search_form
326 | requested_slot: zz_confirm_form
327 | - intent:
328 | - inform
329 | - cc_payment_form
330 | type: from_text
331 | conditions:
332 | - active_loop: cc_payment_form
333 | requested_slot: zz_confirm_form
334 | - intent:
335 | - inform
336 | - transfer_money_form
337 | type: from_text
338 | conditions:
339 | - active_loop: transfer_money_form
340 | requested_slot: zz_confirm_form
341 | - intent:
342 | - inform
343 | - transaction_search_form
344 | type: from_text
345 | conditions:
346 | - active_loop: transaction_search_form
347 | requested_slot: zz_confirm_form
348 | responses:
349 | utter_out_of_scope:
350 | - text: Sorry, I'm not sure how to respond to that. Type "help" for assistance.
351 | utter_ask_transfer_money_form_amount-of-money:
352 | - text: How much money do you want to transfer?
353 | utter_ask_transfer_money_form_PERSON:
354 | - text: Who do you want to transfer money to?
355 | utter_goodbye:
356 | - text: Bye
357 | utter_noworries:
358 | - text: You're welcome :)
359 | utter_transfer_complete:
360 | - text: Successfully transferred {currency}{amount-of-money} to {PERSON}.
361 | utter_transfer_charge:
362 | - text: You are entitled to six transfers within a statement cycle before being charged. For subsequent transfers you will be charged {currency}10 per transaction.
363 | utter_ask_cc_payment_form_amount-of-money:
364 | - text: How much do you want to pay?
365 | utter_ask_cc_payment_form_credit_card:
366 | - text: Towards which credit card account do you want to make a payment?
367 | utter_ask_cc_payment_form_time:
368 | - text: For which date would you like to schedule the payment?
369 | utter_ask_transaction_search_form_vendor_name:
370 | - text: For which vendor do you want to see transactions? e.g Starbucks, Target, Amazon
371 | utter_ask_transaction_search_form_time:
372 | - text: In which timeframe would you like to search for transactions?
373 | utter_ask_transaction_search_form_search_type:
374 | - text: Would you like to search incoming or outgoing transactions?
375 | buttons:
376 | - title: Incoming (earnings)
377 | payload: /inform{"search_type":"deposit"}'
378 | - title: Outgoing (spending)
379 | payload: /inform{"search_type":"spend"}'
380 | utter_no_payment_amount:
381 | - text: Sorry, I don't understand that payment amount.
382 | utter_no_paymentdate:
383 | - text: Sorry, that is not a valid payment date.
384 | utter_no_creditcard:
385 | - text: Sorry, that is not a valid credit card account to make payments towards.
386 | utter_no_vendor_name:
387 | - text: Sorry, that's not a recognized vendor.
388 | utter_no_transactdate:
389 | - text: Sorry, that's not a recognized time frame.
390 | utter_cc_pay_scheduled:
391 | - text: Payment of {currency}{amount-of-money}{payment_amount_type} towards your {credit_card} account scheduled to be paid at {time_formatted}.
392 | utter_searching_spend_transactions:
393 | - text: Searching transactions{vendor_name} between {start_time_formatted} and {end_time_formatted}...
394 | utter_found_spend_transactions:
395 | - text: I found {numtransacts} transactions{vendor_name} totalling {currency}{total}.
396 | utter_searching_deposit_transactions:
397 | - text: Searching deposits made to your account between {start_time_formatted} and {end_time_formatted}...
398 | utter_found_deposit_transactions:
399 | - text: I found {numtransacts} deposits made to your account totalling {currency}{total}
400 | utter_ask_rephrase:
401 | - text: I didn't quite understand that. Can you rephrase?
402 | utter_ok:
403 | - text: 👍
404 | utter_ask_continue:
405 | - text: Would you like to continue?
406 | utter_default:
407 | - text: I didn't quite understand that. Could you rephrase?
408 | utter_ask_cc_payment_form_AA_CONTINUE_FORM:
409 | - buttons:
410 | - payload: /affirm
411 | title: Yes
412 | - payload: /deny
413 | title: No, cancel the transaction
414 | text: Would you like to continue scheduling the credit card payment?
415 | utter_ask_transfer_money_form_AA_CONTINUE_FORM:
416 | - buttons:
417 | - payload: /affirm
418 | title: Yes
419 | - payload: /deny
420 | title: No, cancel the transfer
421 | text: Would you like to continue scheduling the money transfer?
422 | utter_ask_transaction_search_form_AA_CONTINUE_FORM:
423 | - buttons:
424 | - payload: /affirm
425 | title: Yes
426 | - payload: /deny
427 | title: No, cancel the search
428 | text: Would you like to continue the transaction search?
429 | utter_ask_cc_payment_form_zz_confirm_form:
430 | - buttons:
431 | - payload: /affirm
432 | title: Yes
433 | - payload: /deny
434 | title: No, cancel the transaction
435 | text: Would you like to schedule a payment of {currency}{amount-of-money}{payment_amount_type} towards your {credit_card} account for {time_formatted}?
436 | utter_ask_transfer_money_form_zz_confirm_form:
437 | - buttons:
438 | - payload: /affirm
439 | title: Yes
440 | - payload: /deny
441 | title: No, cancel the transaction
442 | text: Would you like to transfer {currency}{amount-of-money} to {PERSON}?
443 | utter_cc_pay_cancelled:
444 | - text: Credit card account payment cancelled.
445 | utter_transfer_cancelled:
446 | - text: Transfer cancelled.
447 | utter_transaction_search_cancelled:
448 | - text: Transaction search cancelled.
449 | utter_account_balance:
450 | - text: Your bank account balance is {currency}{init_account_balance}.
451 | utter_changed_account_balance:
452 | - text: Your bank account balance was {currency}{init_account_balance} and is now {currency}{account_balance} after transfers and payments.
453 | utter_unknown_recipient:
454 | - text: Sorry, {PERSON} is not in your list of known recipients.
455 | utter_insufficient_funds:
456 | - text: Sorry, you don't have enough money to do that!
457 | utter_insufficient_funds_specific:
458 | - text: The {payment_amount_type} on your {credit_card} credit card is {amount-of-money}, so you have insufficient funds to pay it off.
459 | utter_credit_card_balance:
460 | - text: The current balance for your {credit_card} account is {currency}{credit_card_balance}.
461 | utter_nothing_due:
462 | - text: Your don't owe any money on your {credit_card} credit card bill.
463 | utter_recipients:
464 | - text: These are your known recpients to whom you can send money:{formatted_recipients}
465 | utter_greet:
466 | - text: Hi! I'm your Financial Assistant!
467 | utter_ask_handoff:
468 | - text: It looks like you want to be transferred to a human agent.
469 | utter_handoff:
470 | - text: Alright, I'll try to transfer you.
471 | utter_wouldve_handed_off:
472 | - text: If you were talking to me via chatroom, I would have handed you off to {handoffhost}.
473 | utter_no_handoff:
474 | - text: Since you haven't configured a host to hand off to, I can't send you anywhere!
475 | utter_ask_whatelse:
476 | - text: What else can I help you with?
477 | utter_bot:
478 | - text: I'm a virtual assistant made with Rasa.
479 | utter_help:
480 | - text: "I can help you with your financial accounts. \nYou can ask me things like: \n- What's my account balance? \n- Pay off my credit card \n- What did I spend at Target last month? \n- I need to transfer money"
481 | actions:
482 | - action_session_start
483 | - action_restart
484 | - action_show_balance
485 | - action_show_recipients
486 | - action_show_transfer_charge
487 | - action_handoff
488 | - action_handoff_options
489 | - action_pay_cc
490 | - action_transfer_money
491 | - action_transaction_search
492 | - action_ask_transaction_search_form_zz_confirm_form
493 | - action_switch_forms_ask
494 | - action_switch_forms_deny
495 | - action_switch_forms_affirm
496 | - action_switch_back_ask
497 | - validate_cc_payment_form
498 | - validate_transfer_money_form
499 | - validate_transaction_search_form
500 | forms:
501 | cc_payment_form:
502 | ignored_intents: []
503 | required_slots:
504 | - AA_CONTINUE_FORM
505 | - credit_card
506 | - amount-of-money
507 | - time
508 | - zz_confirm_form
509 | transfer_money_form:
510 | ignored_intents: []
511 | required_slots:
512 | - AA_CONTINUE_FORM
513 | - PERSON
514 | - amount-of-money
515 | - zz_confirm_form
516 | transaction_search_form:
517 | ignored_intents: []
518 | required_slots:
519 | - AA_CONTINUE_FORM
520 | - search_type
521 | - time
522 | - zz_confirm_form
523 |
--------------------------------------------------------------------------------
/endpoints.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 | # This file contains the different endpoints your bot can use.
3 |
4 | # Server where the models are pulled from.
5 | # https://rasa.com/docs/rasa/user-guide/running-the-server/#fetching-models-from-a-server/
6 |
7 | #models:
8 | # url: http://my-server.com/models/default_core@latest
9 | # wait_time_between_pulls: 10 # [optional](default: 100)
10 |
11 | # Server which runs your custom actions.
12 | # https://rasa.com/docs/rasa/core/actions/#custom-actions/
13 |
14 | action_endpoint:
15 | url: "http://localhost:5056/webhook"
16 |
17 | # Tracker store which is used to store the conversations.
18 | # By default the conversations are stored in memory.
19 | # https://rasa.com/docs/rasa/api/tracker-stores/
20 |
21 | #tracker_store:
22 | # type: redis
23 | # url:
24 | # port:
25 | # db:
26 | # password:
27 | # use_ssl:
28 |
29 | #tracker_store:
30 | # type: mongod
31 | # url:
32 | # db:
33 | # username:
34 | # password:
35 |
36 | # Event broker which all conversation events should be streamed to.
37 | # https://rasa.com/docs/rasa/api/event-brokers/
38 |
39 | #event_broker:
40 | # url: localhost
41 | # username: username
42 | # password: password
43 | # queue: queue
44 |
--------------------------------------------------------------------------------
/handoff.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RasaHQ/financial-demo/7627cebef1571d55855b886cf4ac20459af9566c/handoff.gif
--------------------------------------------------------------------------------
/images/cicd.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RasaHQ/financial-demo/7627cebef1571d55855b886cf4ac20459af9566c/images/cicd.png
--------------------------------------------------------------------------------
/images/financial-demo-eks-test-vpc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RasaHQ/financial-demo/7627cebef1571d55855b886cf4ac20459af9566c/images/financial-demo-eks-test-vpc.png
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.black]
2 | line-length = 88
3 | target-version = [ "py36", "py37", "py38",]
4 | exclude = "((.eggs | .git | .mypy_cache | .pytest_cache | build | dist))"
5 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | -r requirements.txt
2 | # action to create report PR
3 | pytablewriter
4 |
5 | # python lint/format/types
6 | black~=20.8b1
7 | flake8~=3.8.4
8 | pytype==2019.7.11
9 | pre-commit
10 |
11 | # python test
12 | pytest-cov~=2.10.1
13 | coveralls~=3.0.1
14 | pytest~=5.4.3
15 | pytest-sanic~=1.6.2
16 | pytest-asyncio~=0.14.0
17 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | -r actions/requirements-actions.txt
2 |
3 | rasa[spacy]==3.1.0
4 |
5 | # Sync with `Dockerfile`
6 | rasa-sdk==3.1.0
7 |
--------------------------------------------------------------------------------
/run_rasa_action_server_with_ide.py:
--------------------------------------------------------------------------------
1 | """This script allows use of an IDE (Wing, Pycharm, ...) to debug custom actions:
2 |
3 | (-) Place this script in same location as your actions.py
4 | (-) Open & run it from within your IDE
5 | (-) Now you can put breakpoints in your actions.py, but also explore the internals of the
6 | rasa_sdk action server itself.
7 | """
8 |
9 | import os
10 | import sys
11 |
12 | # insert path of this script in syspath so actions.py will be found
13 | sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
14 |
15 | #
16 | # This is exactly like issuing the command:
17 | # $ rasa run actions
18 | #
19 | sys.argv.append('run')
20 | sys.argv.append('actions')
21 | sys.argv.append('--actions')
22 | sys.argv.append('actions')
23 | sys.argv.append('--port')
24 | sys.argv.append('5056')
25 | sys.argv.append('--debug')
26 |
27 | if __name__ == '__main__':
28 | from rasa.__main__ import main
29 |
30 | main()
31 |
--------------------------------------------------------------------------------
/run_rasa_shell_with_ide.py:
--------------------------------------------------------------------------------
1 | """This script allows use of an IDE (Wing, Pycharm, ...) to run the rasa shell:
2 |
3 | (-) Place this script in root of Rasa bot project
4 | (-) Open & run it from within your IDE
5 |
6 | (-) In Wing, use External Console for better experience.
7 | """
8 |
9 | import os
10 | import sys
11 |
12 | # insert path of this script in syspath so custom modules will be found
13 | sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
14 |
15 | #
16 | # This is exactly like issuing the command:
17 | # $ rasa shell --debug
18 | #
19 |
20 | #
21 | sys.argv.append("shell")
22 | sys.argv.append("--enable-api")
23 | sys.argv.append("--debug")
24 |
25 | if __name__ == "__main__":
26 | from rasa.__main__ import main
27 |
28 | main()
29 |
--------------------------------------------------------------------------------
/run_rasa_test_with_ide.py:
--------------------------------------------------------------------------------
1 | """This script allows use of an IDE (Wing, Pycharm, ...) to run the rasa shell:
2 |
3 | (-) Place this script in root of Rasa bot project
4 | (-) Open & run it from within your IDE
5 |
6 | (-) In Wing, use External Console for better experience.
7 | """
8 |
9 | import os
10 | import sys
11 |
12 | # insert path of this script in syspath so custom modules will be found
13 | sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
14 |
15 | #
16 | # This is exactly like issuing the command:
17 | # $ rasa shell --debug
18 | #
19 |
20 | #
21 | sys.argv.append("shell")
22 | sys.argv.append("--enable-api")
23 | sys.argv.append("--debug")
24 |
25 | if __name__ == "__main__":
26 | from rasa.__main__ import main
27 |
28 | main()
29 |
--------------------------------------------------------------------------------
/scripts/delete_all_test_clusters.py:
--------------------------------------------------------------------------------
1 | """Deletes all EKS test clusters prefixed with `financial-demo-`"""
2 | import sys
3 | import subprocess
4 | import json
5 | import pprint
6 | from pathlib import Path
7 |
8 | cwd = Path(__file__).parent.parent
9 | print("--\ncwd={cwd}")
10 |
11 | ###################################
12 | print("--\nGet the EKS test clusters for financial-demo")
13 | cmd = [
14 | "eksctl",
15 | "get",
16 | "cluster",
17 | "--output",
18 | "json",
19 | ]
20 |
21 | try:
22 | cp = subprocess.run(cmd, check=True, capture_output=True)
23 |
24 | except subprocess.CalledProcessError as e:
25 | print(e.stderr.decode("utf-8"))
26 | sys.exit(e.returncode)
27 |
28 | # all clusters
29 | clusters = [x["metadata"]["name"] for x in json.loads(cp.stdout.decode("utf-8"))]
30 |
31 | # financial-demo test clusters
32 | clusters = [
33 | c
34 | for c in clusters
35 | if c.startswith("financial-demo-") and c != "financial-demo-production"
36 | ]
37 |
38 | print(f"Found {len(clusters)} financial-demo test clusters")
39 | if len(clusters) > 0:
40 | pprint.pprint(clusters)
41 |
42 | ###################################
43 | for cluster in clusters:
44 | print(f"--\nCleaning up EKS test cluster: {cluster}")
45 |
46 | try:
47 | # Note: see http://www.gnu.org/software/automake/manual/html_node/Tricks-For-Silencing-Make.html
48 | print(f"----\nSet kubeconfig to look at this cluster")
49 | cmd = [
50 | "make",
51 | "--no-print-directory",
52 | "aws-eks-cluster-update-kubeconfig",
53 | f"AWS_EKS_CLUSTER_NAME={cluster}",
54 | ]
55 | subprocess.run(cmd, check=True, capture_output=False, cwd=cwd)
56 |
57 | print(f"----\nUninstall rasa enterprise")
58 | cmd = ["make", "--no-print-directory", "rasa-enterprise-uninstall"]
59 | subprocess.run(cmd, check=True, capture_output=False, cwd=cwd)
60 |
61 | print(f"----\nDelete Storage (PVCs)")
62 | cmd = ["make", "--no-print-directory", "rasa-enterprise-delete-pvc-all"]
63 | subprocess.run(cmd, check=True, capture_output=False, cwd=cwd)
64 |
65 | print(f"----\nDelete the EKS cluster")
66 | cmd = [
67 | "make",
68 | "--no-print-directory",
69 | "aws-eks-cluster-delete",
70 | f"AWS_EKS_CLUSTER_NAME={cluster}",
71 | ]
72 | subprocess.run(cmd, check=True, capture_output=False, cwd=cwd)
73 |
74 | except subprocess.CalledProcessError as e:
75 | print(e.stderr.decode("utf-8"))
76 | sys.exit(e.returncode)
77 |
--------------------------------------------------------------------------------
/scripts/patch_gcr_auth_json.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | with open('deploy/gcr-auth.json', 'r') as f:
4 | lines = f.readlines()
5 | for line in lines:
6 | print(
7 | line.replace(
8 | "set_as_environment_variable-GCR_AUTH_JSON_PRIVATE_KEY_ID",
9 | os.environ["GCR_AUTH_JSON_PRIVATE_KEY_ID"],
10 | )
11 | .replace(
12 | "set_as_environment_variable-GCR_AUTH_JSON_PRIVATE_KEY",
13 | os.environ["GCR_AUTH_JSON_PRIVATE_KEY"],
14 | )
15 | .replace(
16 | "set_as_environment_variable-GCR_AUTH_JSON_CLIENT_EMAIL",
17 | os.environ["GCR_AUTH_JSON_CLIENT_EMAIL"],
18 | )
19 | .replace(
20 | "set_as_environment_variable-GCR_AUTH_JSON_CLIENT_ID",
21 | os.environ["GCR_AUTH_JSON_CLIENT_ID"],
22 | ),
23 | end='',
24 | )
25 |
--------------------------------------------------------------------------------
/scripts/smoketest.py:
--------------------------------------------------------------------------------
1 | """Performs Rasa Enterprise smoke tests
2 |
3 | Rasa X HTTP API: https://rasa.com/docs/rasa-x/pages/http-api
4 |
5 | Rasa HTTP API: https://rasa.com/docs/rasa/pages/http-api
6 | (Use BASE_URL/core/... to reach rasa-production server directly)
7 | """
8 | from typing import Any
9 | import os
10 | import pprint
11 |
12 | from requests import request
13 |
14 | BASE_URL = os.environ.get("BASE_URL")
15 | USERNAME = os.environ.get("RASAX_INITIALUSER_USERNAME")
16 | PASSWORD = os.environ.get("RASAX_INITIALUSER_PASSWORD")
17 | VERBOSE = int(os.environ.get("VERBOSE", 1))
18 |
19 |
20 | def my_print(msg: Any, status_code: int = None) -> None:
21 | """Pretty print msg"""
22 | if VERBOSE > 0:
23 | if status_code:
24 | print(f"status_code: {status_code}")
25 |
26 | if isinstance(msg, (list, dict)):
27 | pprint.pprint(msg)
28 | else:
29 | print(msg)
30 |
31 |
32 | quit = False
33 | if not BASE_URL:
34 | my_print("Please set environment variable: BASE_URL")
35 | quit = True
36 | if not USERNAME:
37 | my_print("Please set environment variable: RASAX_INITIALUSER_USERNAME")
38 | quit = True
39 | if not PASSWORD:
40 | my_print("Please set environment variable: RASAX_INITIALUSER_PASSWORD")
41 | quit = True
42 | if quit:
43 | exit(1)
44 |
45 | ###################################
46 | my_print("--\nBASE_URL")
47 | my_print(BASE_URL)
48 |
49 | ###################################
50 | my_print("--\nRasa X Health check")
51 |
52 | url = f"{BASE_URL}/api/health"
53 | r = request("GET", url)
54 | if r.status_code != 200:
55 | my_print(r.json(), r.status_code)
56 | exit(1)
57 |
58 | status_rasa_production = r.json().get("production", {}).get("status")
59 | status_rasa_worker = r.json().get("worker", {}).get("status")
60 |
61 | my_print(r.json(), r.status_code)
62 |
63 | if status_rasa_production != 200:
64 | my_print(f'rasa-production not OK!\nstatus = {status_rasa_production}')
65 | exit(1)
66 |
67 | if status_rasa_worker != 200:
68 | my_print(f'rasa-worker not OK!\nstatus = {status_rasa_worker}')
69 | exit(1)
70 |
71 |
72 | ###################################
73 | my_print("--\nGet access_token")
74 |
75 | url = f"{BASE_URL}/api/auth"
76 | payload = {"username": USERNAME, "password": PASSWORD}
77 | headers = {"Content-Type": "application/json"}
78 | r = request("POST", url, json=payload, headers=headers)
79 | if r.status_code != 200:
80 | my_print(r.json(), r.status_code)
81 | exit(1)
82 |
83 | access_token = r.json().get("access_token")
84 |
85 | if not access_token:
86 | my_print("access_token is empty???")
87 | exit(1)
88 |
89 | ###################################
90 | my_print("--\nCheck tagged production model")
91 |
92 | url = f"{BASE_URL}/api/projects/default/models"
93 | payload = {}
94 | headers = {"Authorization": f"Bearer {access_token}"}
95 | params = {'tag': 'production'}
96 | r = request("GET", url, json=payload, headers=headers, params=params)
97 | if r.status_code != 200:
98 | my_print(r.json(), r.status_code)
99 | exit(1)
100 |
101 | production_model = r.json()[0].get("model")
102 | my_print(f"Found production model: {production_model}")
103 |
104 | ###################################
105 | my_print("--\nSay hi")
106 |
107 | url = f"{BASE_URL}/api/chat"
108 | payload = {"message": "hi"}
109 | headers = {"Authorization": f"Bearer {access_token}"}
110 | params = {}
111 | r = request("POST", url, json=payload, headers=headers, params=params)
112 | if r.status_code != 200 or r.json() == []:
113 | my_print(r.json(), r.status_code)
114 | if r.status_code == 200 and r.json() == []:
115 | print(
116 | "Bot responded, but the response is empty.\n"
117 | "Probably the model is not loaded yet by rasa-prod container.\n"
118 | "Confirm by running `make rasa-enterprise-smoketest locally`.\n"
119 | "If so, increase sleep time in pipeline after tagging of production model."
120 | )
121 | exit(1)
122 |
123 | my_print(r.json(), r.status_code)
124 |
125 | ###################################
126 | my_print("--\nSmoke tests passed")
127 | exit(0)
128 |
--------------------------------------------------------------------------------
/scripts/wait_for_external_ip.sh:
--------------------------------------------------------------------------------
1 | AWS_EKS_NAMEPACE=${1:-"my-namespace"}
2 | AWS_EKS_RELEASE_NAME=${2:-"my-release"}
3 | ATTEMPTS=${3:-100}
4 | COUNT=1;
5 | IP=""
6 | while [ -z $IP ]; do
7 | IP=$(kubectl --namespace ${AWS_EKS_NAMEPACE} get service ${AWS_EKS_RELEASE_NAME}-rasa-x-nginx --output jsonpath='{.status.loadBalancer.ingress[0].hostname}')
8 | if [[ $COUNT -eq $ATTEMPTS ]]; then
9 | echo "# Limit of $ATTEMPTS attempts has exceeded."
10 | exit 1
11 | fi
12 | if [[ -z "$IP" ]]; then
13 | echo -e "$(( COUNT++ ))... \c"
14 | sleep 2
15 | fi
16 | done
17 | echo 'Found External IP'
18 | echo 'Login at: http://'$IP':80/login'
19 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 88
3 | # See these resources for descriptions of the error codes:
4 | # E***, F***, W*** : https://flake8.pycqa.org/en/latest/user/error-codes.html
5 | # D***: http://www.pydocstyle.org/en/stable/error_codes.html
6 | ignore = W503, E121, E126, E211, E225, E501, E203, E402, F401, F811,
7 | D100, # ignore missing docstrings in public module
8 | D104, # ignore missing docstrings in public package
9 | docstring-convention = google
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RasaHQ/financial-demo/7627cebef1571d55855b886cf4ac20459af9566c/tests/__init__.py
--------------------------------------------------------------------------------
/tests/conftest.py:
--------------------------------------------------------------------------------
1 | import os
2 | from pathlib import Path
3 | import pytest
4 | import json
5 | import sqlalchemy as sa
6 |
7 | from rasa_sdk.executor import CollectingDispatcher
8 | from rasa_sdk import Tracker
9 |
10 | here = Path(__file__).parent.resolve()
11 |
12 | EMPTY_TRACKER = Tracker.from_dict(json.load(open(here / "./data/empty_tracker.json")))
13 | PAY_CC_NOT_CONFIRMED = Tracker.from_dict(
14 | json.load(open(here / "./data/pay_cc_not_confirmed.json"))
15 | )
16 | PAY_CC_CONFIRMED = Tracker.from_dict(
17 | json.load(open(here / "./data/pay_cc_confirmed.json"))
18 | )
19 | DATABASE_URL = os.environ.setdefault("DATABASE_URL", "postgresql:///postgres")
20 |
21 |
22 | @pytest.fixture
23 | def dispatcher():
24 | return CollectingDispatcher()
25 |
26 |
27 | @pytest.fixture
28 | def domain():
29 | return dict()
30 |
31 |
32 | # @pytest.fixture
33 | # def session():
34 | # engine = sa.create_engine(DATABASE_URL)
35 | # db_session = sessionmaker(bind=engine)()
36 |
37 | # try:
38 | # yield db_session
39 | # finally:
40 | # db_session.close()
41 | # Base.metadata.drop_all(engine)
42 |
--------------------------------------------------------------------------------
/tests/data/all_slots_filled_tracker.json:
--------------------------------------------------------------------------------
1 | {
2 | "sender_id": "someone",
3 | "slots": {
4 | "AA_CONTINUE_FORM": null,
5 | "PERSON": null,
6 | "account_type": null,
7 | "amount-of-money": null,
8 | "amount_transferred":null,
9 | "credit_card": null,
10 | "currency": null,
11 | "end_time": null,
12 | "end_time_formatted": null,
13 | "grain": null,
14 | "handoff_to": null,
15 | "next_form_name": null,
16 | "number": null,
17 | "payment_amount_type": null,
18 | "previous_form_name": null,
19 | "repeated_validation_failures": null,
20 | "requested_slot": null,
21 | "search_type": null,
22 | "start_time": null,
23 | "start_time_formatted": null,
24 | "time": null,
25 | "time_formatted": null,
26 | "vendor_name": null,
27 | "zz_confirm_form": null
28 | },
29 | "latest_message": {
30 | "intent": {},
31 | "entities": [],
32 | "text": null,
33 | "message_id": null,
34 | "metadata": {}
35 | },
36 | "latest_event_time": 1607396994.449022,
37 | "followup_action": null,
38 | "paused": false,
39 | "events": [
40 | {
41 | "event": "action",
42 | "timestamp": 1607396994.448949,
43 | "name": "action_session_start",
44 | "policy": null,
45 | "confidence": 1.0
46 | },
47 | {
48 | "event": "session_started",
49 | "timestamp": 1607396994.44901
50 | },
51 | {
52 | "event": "action",
53 | "timestamp": 1607396994.449022,
54 | "name": "action_listen",
55 | "policy": null,
56 | "confidence": null
57 | }
58 | ],
59 | "latest_input_channel": null,
60 | "active_loop": {},
61 | "latest_action": {
62 | "action_name": "action_listen"
63 | },
64 | "latest_action_name": "action_listen"
65 | }
66 |
--------------------------------------------------------------------------------
/tests/data/empty_tracker.json:
--------------------------------------------------------------------------------
1 | {
2 | "sender_id": "someone",
3 | "slots": {
4 | "AA_CONTINUE_FORM": null,
5 | "PERSON": null,
6 | "account_type": null,
7 | "amount-of-money": null,
8 | "amount_transferred":null,
9 | "credit_card": null,
10 | "currency": null,
11 | "end_time": null,
12 | "end_time_formatted": null,
13 | "grain": null,
14 | "handoff_to": null,
15 | "next_form_name": null,
16 | "number": null,
17 | "payment_amount_type": null,
18 | "previous_form_name": null,
19 | "repeated_validation_failures": null,
20 | "requested_slot": null,
21 | "search_type": null,
22 | "start_time": null,
23 | "start_time_formatted": null,
24 | "time": null,
25 | "time_formatted": null,
26 | "vendor_name": null,
27 | "zz_confirm_form": null
28 | },
29 | "latest_message": {
30 | "intent": {},
31 | "entities": [],
32 | "text": null,
33 | "message_id": null,
34 | "metadata": {}
35 | },
36 | "latest_event_time": 1607396994.449022,
37 | "followup_action": null,
38 | "paused": false,
39 | "events": [
40 | {
41 | "event": "action",
42 | "timestamp": 1607396994.448949,
43 | "name": "action_session_start",
44 | "policy": null,
45 | "confidence": 1.0
46 | },
47 | {
48 | "event": "session_started",
49 | "timestamp": 1607396994.44901
50 | },
51 | {
52 | "event": "action",
53 | "timestamp": 1607396994.449022,
54 | "name": "action_listen",
55 | "policy": null,
56 | "confidence": null
57 | }
58 | ],
59 | "latest_input_channel": null,
60 | "active_loop": {},
61 | "latest_action": {
62 | "action_name": "action_listen"
63 | },
64 | "latest_action_name": "action_listen"
65 | }
66 |
--------------------------------------------------------------------------------
/tests/data/pay_cc_confirmed.json:
--------------------------------------------------------------------------------
1 | {
2 | "sender_id": "someone",
3 | "slots": {
4 | "zz_confirm_form": "yes",
5 | "credit_card": "justice bank",
6 | "amount-of-money": "301.33",
7 | "amount_transferred": "301.32"
8 | },
9 | "latest_message": {
10 | "intent": {},
11 | "entities": [],
12 | "text": null,
13 | "message_id": null,
14 | "metadata": {}
15 | },
16 | "latest_event_time": 1607396994.449022,
17 | "followup_action": null,
18 | "paused": false,
19 | "events": [
20 | {
21 | "event": "action",
22 | "timestamp": 1607396994.448949,
23 | "name": "action_session_start",
24 | "policy": null,
25 | "confidence": 1.0
26 | },
27 | {
28 | "event": "session_started",
29 | "timestamp": 1607396994.44901
30 | },
31 | {
32 | "event": "action",
33 | "timestamp": 1607396994.449022,
34 | "name": "action_listen",
35 | "policy": null,
36 | "confidence": null
37 | }
38 | ],
39 | "latest_input_channel": null,
40 | "active_loop": {},
41 | "latest_action": {
42 | "action_name": "action_listen"
43 | },
44 | "latest_action_name": "action_listen"
45 | }
46 |
--------------------------------------------------------------------------------
/tests/data/pay_cc_not_confirmed.json:
--------------------------------------------------------------------------------
1 | {
2 | "sender_id": "someone",
3 | "slots": {
4 | "zz_confirm_form": "no"
5 | },
6 | "latest_message": {
7 | "intent": {},
8 | "entities": [],
9 | "text": null,
10 | "message_id": null,
11 | "metadata": {}
12 | },
13 | "latest_event_time": 1607396994.449022,
14 | "followup_action": null,
15 | "paused": false,
16 | "events": [
17 | {
18 | "event": "action",
19 | "timestamp": 1607396994.448949,
20 | "name": "action_session_start",
21 | "policy": null,
22 | "confidence": 1.0
23 | },
24 | {
25 | "event": "session_started",
26 | "timestamp": 1607396994.44901
27 | },
28 | {
29 | "event": "action",
30 | "timestamp": 1607396994.449022,
31 | "name": "action_listen",
32 | "policy": null,
33 | "confidence": null
34 | }
35 | ],
36 | "latest_input_channel": null,
37 | "active_loop": {},
38 | "latest_action": {
39 | "action_name": "action_listen"
40 | },
41 | "latest_action_name": "action_listen"
42 | }
43 |
--------------------------------------------------------------------------------
/tests/db_test.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sqlalchemy as sa
3 | import pytest
4 |
5 | from actions.profile_db import (
6 | GENERAL_ACCOUNTS,
7 | create_database,
8 | ProfileDB,
9 | Account,
10 | )
11 |
12 | PROFILE_DB_NAME = os.environ.get("PROFILE_DB_NAME", "profile")
13 | PROFILE_DB_URL = os.environ.get("PROFILE_DB_URL", f"sqlite:///{PROFILE_DB_NAME}.db")
14 | ENGINE = sa.create_engine(PROFILE_DB_URL)
15 | create_database(ENGINE, PROFILE_DB_NAME)
16 |
17 | profile_db = ProfileDB(ENGINE)
18 | profile_db.create_tables()
19 |
20 | session_id = "test"
21 | profile_db.populate_profile_db(session_id)
22 | currency = profile_db.get_currency(session_id)
23 |
24 | account = profile_db.get_account_from_session_id(session_id)
25 | account_number = profile_db.get_account_number(account)
26 | account_from_number = profile_db.get_account_from_number(account_number)
27 |
28 | recipient_names = profile_db.list_known_recipients(session_id)
29 | recipient_name = recipient_names[0]
30 | recipient = profile_db.get_recipient_from_name(session_id, recipient_name)
31 | recipient_account_number = profile_db.get_account_number(recipient)
32 |
33 | account_balance = profile_db.get_account_balance(session_id)
34 | profile_db.transact(account_number, recipient_account_number, 100)
35 | account_balance_now = profile_db.get_account_balance(session_id)
36 |
37 | credit_cards = profile_db.list_credit_cards(session_id)
38 | balance_types = profile_db.list_balance_types()
39 |
40 |
41 | def test_profile_initialization():
42 | assert profile_db.check_session_id_exists(session_id)
43 | assert profile_db.check_general_accounts_populated(GENERAL_ACCOUNTS)
44 | assert profile_db.get_currency(session_id) == "$"
45 |
46 |
47 | def test_account_from_account_number():
48 | assert account is account_from_number
49 |
50 |
51 | def test_transact():
52 | assert account_balance_now == account_balance - 100
53 |
54 |
55 | def test_cc_payment_1():
56 | credit_card_name = credit_cards[0]
57 | balance_type = balance_types[0]
58 |
59 | credit_card_balance = profile_db.get_credit_card_balance(
60 | session_id, credit_card_name, balance_type
61 | )
62 | profile_db.pay_off_credit_card(session_id, credit_card_name, credit_card_balance)
63 | credit_card_balance_now = profile_db.get_credit_card_balance(
64 | session_id, credit_card_name, balance_type
65 | )
66 | assert credit_card_balance_now == 0
67 |
68 |
69 | def test_cc_payment_2():
70 | credit_card_name = credit_cards[1]
71 | balance_type = balance_types[1]
72 |
73 | credit_card_balance = profile_db.get_credit_card_balance(
74 | session_id, credit_card_name, balance_type
75 | )
76 | profile_db.pay_off_credit_card(session_id, credit_card_name, credit_card_balance)
77 | credit_card_balance_now = profile_db.get_credit_card_balance(
78 | session_id, credit_card_name, balance_type
79 | )
80 | assert credit_card_balance_now == 0
81 |
--------------------------------------------------------------------------------
/tests/test_actions.py:
--------------------------------------------------------------------------------
1 | import json
2 | import pytest
3 |
4 | from rasa_sdk.executor import CollectingDispatcher, Tracker
5 | from rasa_sdk.events import SlotSet, ActionExecuted, SessionStarted
6 |
7 | from tests.conftest import EMPTY_TRACKER, PAY_CC_CONFIRMED, PAY_CC_NOT_CONFIRMED
8 | from actions import actions
9 |
10 |
11 | @pytest.mark.asyncio
12 | async def test_run_action_session_start(dispatcher, domain):
13 | tracker = EMPTY_TRACKER
14 | action = actions.ActionSessionStart()
15 | events = await action.run(dispatcher, tracker, domain)
16 | expected_events = [
17 | SessionStarted(),
18 | SlotSet("currency", "$"),
19 | ActionExecuted("action_listen"),
20 | ]
21 | assert events == expected_events
22 |
23 |
24 | async def test_action_pay_cc_not_confirmed(dispatcher, domain):
25 | tracker = PAY_CC_NOT_CONFIRMED
26 | action = actions.ActionPayCC()
27 | events = await action.run(dispatcher, tracker, domain)
28 | expected_events = [
29 | SlotSet("AA_CONTINUE_FORM", None),
30 | SlotSet("zz_confirm_form", None),
31 | SlotSet("credit_card", None),
32 | SlotSet("account_type", None),
33 | SlotSet("amount-of-money", None),
34 | SlotSet("time", None),
35 | SlotSet("time_formatted", None),
36 | SlotSet("start_time", None),
37 | SlotSet("end_time", None),
38 | SlotSet("start_time_formatted", None),
39 | SlotSet("end_time_formatted", None),
40 | SlotSet("grain", None),
41 | SlotSet("number", None),
42 | ]
43 | expected_response = "utter_cc_pay_cancelled"
44 | assert events == expected_events
45 | assert dispatcher.messages[0]["response"] == expected_response
46 |
47 |
48 | async def test_action_pay_cc_confirmed(dispatcher, domain):
49 | tracker = EMPTY_TRACKER
50 | action = actions.ActionSessionStart()
51 | await action.run(dispatcher, tracker, domain)
52 | tracker = PAY_CC_CONFIRMED
53 | action = actions.ActionPayCC()
54 | events = await action.run(dispatcher, tracker, domain)
55 | expected_events = [
56 | SlotSet("AA_CONTINUE_FORM", None),
57 | SlotSet("zz_confirm_form", None),
58 | SlotSet("credit_card", None),
59 | SlotSet("account_type", None),
60 | SlotSet("amount-of-money", None),
61 | SlotSet("time", None),
62 | SlotSet("time_formatted", None),
63 | SlotSet("start_time", None),
64 | SlotSet("end_time", None),
65 | SlotSet("start_time_formatted", None),
66 | SlotSet("end_time_formatted", None),
67 | SlotSet("grain", None),
68 | SlotSet("number", None),
69 | SlotSet("amount_transferred", value=602.65),
70 | ]
71 | expected_response = "utter_cc_pay_scheduled"
72 | assert events == expected_events
73 | assert dispatcher.messages[0]["response"] == expected_response
74 |
--------------------------------------------------------------------------------
/tests/test_stories.yml:
--------------------------------------------------------------------------------
1 | version: "3.1"
2 | stories:
3 | - story: greet/bye path
4 | steps:
5 | - intent: greet
6 | user: |-
7 | hi
8 | - action: utter_greet
9 | - action: utter_help
10 | - intent: goodbye
11 | user: |-
12 | bye
13 | - action: utter_goodbye
14 | - story: say goodbye
15 | steps:
16 | - intent: goodbye
17 | user: |-
18 | bye
19 | - action: utter_goodbye
20 | - story: help
21 | steps:
22 | - intent: help
23 | user: |-
24 | how do I use this
25 | - action: utter_help
26 | - story: out of scope
27 | steps:
28 | - intent: out_of_scope
29 | user: |-
30 | I want to order a pizza
31 | - action: utter_out_of_scope
32 | - story: is there a transfer charge
33 | steps:
34 | - intent: ask_transfer_charge
35 | user: |-
36 | is there a transfer charge
37 | - action: action_show_transfer_charge
38 | - story: Show list of known recipients
39 | steps:
40 | - intent: check_recipients
41 | user: |-
42 | Who can I send money to?
43 | - action: action_show_recipients
44 | - story: Show bank account balance
45 | steps:
46 | - intent: check_balance
47 | user: |-
48 | How much money is on my account?
49 | - action: action_show_balance
50 | - story: Show specific credit card account balance
51 | steps:
52 | - intent: check_balance
53 | user: |-
54 | What's my [emblem](credit_card) [card]{"entity": "account_type", "value": "credit"} [balance]{"entity": "amount-of-money", "value": "current balance"}
55 | - action: action_show_balance
56 | - story: Show all credit cards account balances
57 | steps:
58 | - intent: check_balance
59 | user: |-
60 | What are my [credit](account_type) accounts
61 | - action: action_show_balance
62 | - story: check list of known recipients
63 | steps:
64 | - intent: check_recipients
65 | user: |-
66 | Show me my list of recipients
67 | - action: action_show_recipients
68 | - story: from Rasa X 56efe3eaf7c0456db86a6669421f885c
69 | steps:
70 | - intent: help
71 | user: |-
72 | help
73 | - action: utter_help
74 | - intent: greet
75 | user: |-
76 | hello
77 | - action: utter_greet
78 | - action: utter_help
79 | - intent: thankyou
80 | user: |-
81 | Thanks!
82 | - action: utter_noworries
83 | - story: from Rasa X 56efe3eaf7c0456db86a6669421f885c (if intent were right)
84 | steps:
85 | - intent: help
86 | user: |-
87 | help
88 | - action: utter_help
89 | - intent: greet
90 | user: |-
91 | hello
92 | - action: utter_greet
93 | - action: utter_help
94 | - intent: affirm
95 | user: |-
96 | That sounds good
97 | - action: utter_ok
98 | - story: pay credit card happy path
99 | steps:
100 | - intent: pay_cc
101 | user: |-
102 | i want to pay off my [emblm]{"entity": "credit_card", "value": "emblem"}
103 | - action: cc_payment_form
104 | - active_loop: cc_payment_form
105 | - active_loop: null
106 | - action: action_pay_cc
107 | - story: transfer money happy path w/o recipient
108 | steps:
109 | - intent: transfer_money
110 | user: |-
111 | i want to transfer money
112 | - action: transfer_money_form
113 | - active_loop: transfer_money_form
114 | - active_loop: null
115 | - action: action_transfer_money
116 | - story: transfer money happy path w/ recipient
117 | steps:
118 | - intent: transfer_money
119 | user: |-
120 | i want to transfer money to [Latisha](PERSON)
121 | - slot_was_set:
122 | - PERSON: Latisha
123 | - action: transfer_money_form
124 | - active_loop: transfer_money_form
125 | - active_loop: null
126 | - action: action_transfer_money
127 | - story: check earnings happy path
128 | steps:
129 | - intent: check_earnings
130 | user: |-
131 | how much did I earn [in January 2019]{"entity": "time", "value": "2019-01-01T00:00:00.000-08:00"}
132 | - action: transaction_search_form
133 | - active_loop: transaction_search_form
134 | - active_loop: null
135 | - action: action_transaction_search
136 | - story: search transactions happy path
137 | steps:
138 | - intent: search_transactions
139 | user: |-
140 | I want to search my spending history'
141 | - action: transaction_search_form
142 | - active_loop: transaction_search_form
143 | - active_loop: null
144 | - action: action_transaction_search
145 | - story: greet + search transactions happy path + thankyou
146 | steps:
147 | - intent: greet
148 | user: |-
149 | hi
150 | - action: utter_greet
151 | - action: utter_help
152 | - intent: search_transactions
153 | user: |-
154 | I want to search my spending history'
155 | - action: transaction_search_form
156 | - active_loop: transaction_search_form
157 | - active_loop: null
158 | - action: action_transaction_search
159 | - intent: thankyou
160 | user: |-
161 | Thanks!
162 | - action: utter_noworries
163 | - story: Show bank account balance + transfer money
164 | steps:
165 | - intent: check_balance
166 | user: |-
167 | How much money is on my account?
168 | - action: action_show_balance
169 | - intent: transfer_money
170 | user: |-
171 | i want to transfer money
172 | - action: transfer_money_form
173 | - active_loop: transfer_money_form
174 | - active_loop: null
175 | - action: action_transfer_money
176 | - story: Show bank account balance + thankyou + transfer money
177 | steps:
178 | - intent: check_balance
179 | user: |-
180 | How much money is on my account?
181 | - action: action_show_balance
182 | - intent: thankyou
183 | user: |-
184 | Thanks!
185 | - action: utter_noworries
186 | - intent: transfer_money
187 | user: |-
188 | i want to transfer money
189 | - action: transfer_money_form
190 | - active_loop: transfer_money_form
191 | - active_loop: null
192 | - action: action_transfer_money
193 | - story: Show bank account balance + ok + transfer money
194 | steps:
195 | - intent: check_balance
196 | user: |-
197 | How much money is on my account?
198 | - action: action_show_balance
199 | - intent: affirm
200 | user: |-
201 | Ok
202 | - action: utter_ok
203 | - intent: transfer_money
204 | user: |-
205 | i want to transfer money
206 | - action: transfer_money_form
207 | - active_loop: transfer_money_form
208 | - active_loop: null
209 | - action: action_transfer_money
210 | - story: Show bank account balance + ok + show recipients + ok + show transfer charge + ok + transfer money
211 | steps:
212 | - intent: check_balance
213 | user: |-
214 | How much money is on my account?
215 | - action: action_show_balance
216 | - intent: affirm
217 | user: |-
218 | Ok
219 | - action: utter_ok
220 | - intent: check_recipients
221 | user: |-
222 | Who can I send money to?
223 | - action: action_show_recipients
224 | - intent: affirm
225 | user: |-
226 | Ok
227 | - action: utter_ok
228 | - intent: ask_transfer_charge
229 | user: |-
230 | is there a transfer charge
231 | - action: action_show_transfer_charge
232 | - intent: affirm
233 | user: |-
234 | Ok
235 | - action: utter_ok
236 | - intent: transfer_money
237 | user: |-
238 | i want to transfer money
239 | - action: transfer_money_form
240 | - active_loop: transfer_money_form
241 | - active_loop: null
242 | - action: action_transfer_money
243 | - story: Show bank account balance + ok + pay credit card
244 | steps:
245 | - intent: check_balance
246 | user: |-
247 | How much money is on my account?
248 | - action: action_show_balance
249 | - intent: affirm
250 | user: |-
251 | Ok
252 | - action: utter_ok
253 | - intent: pay_cc
254 | user: |-
255 | i want to pay off my [emblm]{"entity": "credit_card", "value": "emblem"}
256 | - action: cc_payment_form
257 | - active_loop: cc_payment_form
258 | - active_loop: null
259 | - action: action_pay_cc
260 | - story: pay credit card and afterwards check account balance
261 | steps:
262 | - intent: pay_cc
263 | user: |-
264 | i want to pay off my [emblm]{"entity": "credit_card", "value": "emblem"}
265 | - action: cc_payment_form
266 | - active_loop: cc_payment_form
267 | - active_loop: null
268 | - action: action_pay_cc
269 | - intent: check_balance
270 | user: |-
271 | How much money is on my account?
272 | - action: action_show_balance
273 | - story: Pay CC, while in form ask account balance
274 | steps:
275 | - intent: pay_cc
276 | user: |-
277 | pay [credit card]{"entity": "account_type", "value": "credit"}
278 | - action: cc_payment_form
279 | - active_loop: cc_payment_form
280 | - slot_was_set:
281 | - AA_CONTINUE_FORM: yes
282 | - slot_was_set:
283 | - requested_slot: credit_card
284 | - intent: check_balance
285 | user: |-
286 | How much money is on my [bank](account_type) account?
287 | - slot_was_set:
288 | - account_type: bank
289 | - action: action_show_balance
290 | - action: cc_payment_form
291 | - slot_was_set:
292 | - requested_slot: null
293 | - active_loop: null
294 | - action: action_pay_cc
295 | - story: transfer money, while in form ask transfer charge
296 | steps:
297 | - intent: transfer_money
298 | user: |-
299 | i want to transfer money
300 | - action: transfer_money_form
301 | - active_loop: transfer_money_form
302 | - intent: ask_transfer_charge
303 | user: |-
304 | is there a transfer charge
305 | - action: action_show_transfer_charge
306 | - action: transfer_money_form
307 | - slot_was_set:
308 | - requested_slot: null
309 | - active_loop: null
310 | - action: action_transfer_money
311 | - story: transfer money, while in form ask known recipients
312 | steps:
313 | - intent: transfer_money
314 | user: |-
315 | i want to transfer money
316 | - action: transfer_money_form
317 | - active_loop: transfer_money_form
318 | - intent: check_recipients
319 | user: |-
320 | Who can I send money to?
321 | - action: action_show_recipients
322 | - action: transfer_money_form
323 | - slot_was_set:
324 | - requested_slot: null
325 | - active_loop: null
326 | - action: action_transfer_money
327 | - story: transfer money, while in form ask balance
328 | steps:
329 | - intent: transfer_money
330 | user: |-
331 | i want to transfer money
332 | - action: transfer_money_form
333 | - active_loop: transfer_money_form
334 | - intent: check_balance
335 | user: |-
336 | What is my account [balance]{"entity": "amount-of-money", "value": "current balance"}?
337 | - action: action_show_balance
338 | - action: transfer_money_form
339 | - slot_was_set:
340 | - requested_slot: null
341 | - active_loop: null
342 | - action: action_transfer_money
343 | - story: transfer money, while in form ask known recipients and transfer charge
344 | steps:
345 | - intent: transfer_money
346 | user: |-
347 | i want to transfer money
348 | - action: transfer_money_form
349 | - active_loop: transfer_money_form
350 | - intent: check_recipients
351 | user: |-
352 | Who can I send money to?
353 | - action: action_show_recipients
354 | - action: transfer_money_form
355 | - intent: ask_transfer_charge
356 | user: |-
357 | is there a transfer charge
358 | - action: action_show_transfer_charge
359 | - action: transfer_money_form
360 | - slot_was_set:
361 | - requested_slot: null
362 | - active_loop: null
363 | - action: action_transfer_money
364 | - story: pay credit card + switch to transfer money, deny
365 | steps:
366 | - intent: pay_cc
367 | user: |-
368 | pay [credit card]{"entity": "account_type", "value": "credit"}
369 | - action: cc_payment_form
370 | - active_loop: cc_payment_form
371 | - intent: transfer_money
372 | user: |-
373 | transfer money
374 | - action: action_switch_forms_ask
375 | - slot_was_set:
376 | - next_form_name: transfer_money_form
377 | - intent: deny
378 | - action: action_switch_forms_deny
379 | - slot_was_set:
380 | - next_form_name: null
381 | - action: cc_payment_form
382 | - active_loop: cc_payment_form
383 | - story: pay credit card + switch to search transactions, deny
384 | steps:
385 | - intent: pay_cc
386 | user: |-
387 | pay [credit card]{"entity": "account_type", "value": "credit"}
388 | - action: cc_payment_form
389 | - active_loop: cc_payment_form
390 | - intent: check_earnings
391 | user: |-
392 | check earnings
393 | - action: action_switch_forms_ask
394 | - slot_was_set:
395 | - next_form_name: transaction_search_form
396 | - intent: deny
397 | - action: action_switch_forms_deny
398 | - slot_was_set:
399 | - next_form_name: null
400 | - action: cc_payment_form
401 | - active_loop: cc_payment_form
402 | - story: search transactions + switch to transfer money, deny
403 | steps:
404 | - intent: check_earnings
405 | user: |-
406 | check earnings
407 | - action: transaction_search_form
408 | - active_loop: transaction_search_form
409 | - intent: transfer_money
410 | user: |-
411 | transfer money
412 | - action: action_switch_forms_ask
413 | - slot_was_set:
414 | - next_form_name: transfer_money_form
415 | - intent: deny
416 | - action: action_switch_forms_deny
417 | - slot_was_set:
418 | - next_form_name: null
419 | - action: transaction_search_form
420 | - active_loop: transaction_search_form
421 | - story: search transactions + switch to pay credit card, deny
422 | steps:
423 | - intent: check_earnings
424 | user: |-
425 | check earnings
426 | - action: transaction_search_form
427 | - active_loop: transaction_search_form
428 | - intent: pay_cc
429 | user: |-
430 | pay [credit card]{"entity": "account_type", "value": "credit"}
431 | - action: action_switch_forms_ask
432 | - slot_was_set:
433 | - next_form_name: cc_payment_form
434 | - intent: deny
435 | - action: action_switch_forms_deny
436 | - slot_was_set:
437 | - next_form_name: null
438 | - action: transaction_search_form
439 | - active_loop: transaction_search_form
440 | - story: transfer money + switch to search transactions, deny
441 | steps:
442 | - intent: transfer_money
443 | user: |-
444 | transfer money
445 | - action: transfer_money_form
446 | - active_loop: transfer_money_form
447 | - intent: check_earnings
448 | user: |-
449 | check earnings
450 | - action: action_switch_forms_ask
451 | - slot_was_set:
452 | - next_form_name: transaction_search_form
453 | - intent: deny
454 | - action: action_switch_forms_deny
455 | - slot_was_set:
456 | - next_form_name: null
457 | - action: transfer_money_form
458 | - active_loop: transfer_money_form
459 | - story: transfer money + switch to pay credit card, deny
460 | steps:
461 | - intent: transfer_money
462 | user: |-
463 | transfer money
464 | - action: transfer_money_form
465 | - active_loop: transfer_money_form
466 | - intent: pay_cc
467 | user: |-
468 | pay [credit card]{"entity": "account_type", "value": "credit"}
469 | - action: action_switch_forms_ask
470 | - slot_was_set:
471 | - next_form_name: cc_payment_form
472 | - intent: deny
473 | - action: action_switch_forms_deny
474 | - slot_was_set:
475 | - next_form_name: null
476 | - action: transfer_money_form
477 | - active_loop: transfer_money_form
478 | - story: pay credit card + switch to search transactions, affirm + switch back, deny
479 | steps:
480 | - intent: pay_cc
481 | user: |-
482 | pay [credit card]{"entity": "account_type", "value": "credit"}
483 | - action: cc_payment_form
484 | - active_loop: cc_payment_form
485 | - intent: check_earnings
486 | user: |-
487 | check earnings
488 | - action: action_switch_forms_ask
489 | - slot_was_set:
490 | - next_form_name: transaction_search_form
491 | - intent: affirm
492 | - action: action_switch_forms_affirm
493 | - slot_was_set:
494 | - next_form_name: null
495 | - slot_was_set:
496 | - previous_form_name: cc_payment_form
497 | - action: transaction_search_form
498 | - active_loop: transaction_search_form
499 | - active_loop: null
500 | - slot_was_set:
501 | - requested_slot: null
502 | - action: action_transaction_search
503 | - action: action_switch_back_ask
504 | - slot_was_set:
505 | - previous_form_name: null
506 | - intent: deny
507 | - action: utter_ask_whatelse
508 | - story: pay credit card + switch to transfer money, affirm + switch back, deny
509 | steps:
510 | - intent: pay_cc
511 | user: |-
512 | pay [credit card]{"entity": "account_type", "value": "credit"}
513 | - action: cc_payment_form
514 | - active_loop: cc_payment_form
515 | - intent: transfer_money
516 | user: |-
517 | transfer money
518 | - action: action_switch_forms_ask
519 | - slot_was_set:
520 | - next_form_name: transfer_money_form
521 | - intent: affirm
522 | - action: action_switch_forms_affirm
523 | - slot_was_set:
524 | - next_form_name: null
525 | - slot_was_set:
526 | - previous_form_name: cc_payment_form
527 | - action: transfer_money_form
528 | - active_loop: transfer_money_form
529 | - active_loop: null
530 | - slot_was_set:
531 | - requested_slot: null
532 | - action: action_transfer_money
533 | - action: action_switch_back_ask
534 | - slot_was_set:
535 | - previous_form_name: null
536 | - intent: deny
537 | - action: utter_ask_whatelse
538 | - story: search transactions + switch to transfer money, affirm + switch back, deny
539 | steps:
540 | - intent: check_earnings
541 | user: |-
542 | check earnings
543 | - action: transaction_search_form
544 | - active_loop: transaction_search_form
545 | - intent: transfer_money
546 | user: |-
547 | transfer money
548 | - action: action_switch_forms_ask
549 | - slot_was_set:
550 | - next_form_name: transfer_money_form
551 | - intent: affirm
552 | user: |-
553 | Yes
554 | - action: action_switch_forms_affirm
555 | - slot_was_set:
556 | - next_form_name: null
557 | - slot_was_set:
558 | - previous_form_name: transaction_search_form
559 | - action: transfer_money_form
560 | - active_loop: transfer_money_form
561 | - active_loop: null
562 | - slot_was_set:
563 | - requested_slot: null
564 | - action: action_transfer_money
565 | - action: action_switch_back_ask
566 | - slot_was_set:
567 | - previous_form_name: null
568 | - intent: deny
569 | user: |-
570 | No
571 | - action: utter_ask_whatelse
572 | - story: search transactions + switch to pay credit card, affirm + switch back, deny
573 | steps:
574 | - intent: check_earnings
575 | user: |-
576 | check earnings
577 | - action: transaction_search_form
578 | - active_loop: transaction_search_form
579 | - intent: pay_cc
580 | user: |-
581 | pay [credit card]{"entity": "account_type", "value": "credit"}
582 | - action: action_switch_forms_ask
583 | - slot_was_set:
584 | - next_form_name: cc_payment_form
585 | - intent: affirm
586 | - action: action_switch_forms_affirm
587 | - slot_was_set:
588 | - next_form_name: null
589 | - slot_was_set:
590 | - previous_form_name: transaction_search_form
591 | - action: cc_payment_form
592 | - active_loop: cc_payment_form
593 | - active_loop: null
594 | - slot_was_set:
595 | - requested_slot: null
596 | - action: action_pay_cc
597 | - action: action_switch_back_ask
598 | - slot_was_set:
599 | - previous_form_name: null
600 | - intent: deny
601 | - action: utter_ask_whatelse
602 | - story: transfer money + switch to search transactions, affirm + switch back, deny
603 | steps:
604 | - intent: transfer_money
605 | user: |-
606 | transfer money
607 | - action: transfer_money_form
608 | - active_loop: transfer_money_form
609 | - intent: check_earnings
610 | user: |-
611 | check earnings
612 | - action: action_switch_forms_ask
613 | - slot_was_set:
614 | - next_form_name: transaction_search_form
615 | - intent: affirm
616 | - action: action_switch_forms_affirm
617 | - slot_was_set:
618 | - next_form_name: null
619 | - slot_was_set:
620 | - previous_form_name: transfer_money_form
621 | - action: transaction_search_form
622 | - active_loop: transaction_search_form
623 | - active_loop: null
624 | - slot_was_set:
625 | - requested_slot: null
626 | - action: action_transaction_search
627 | - action: action_switch_back_ask
628 | - slot_was_set:
629 | - previous_form_name: null
630 | - intent: deny
631 | - action: utter_ask_whatelse
632 | - story: transfer money + switch to pay credit card, affirm + switch back, deny
633 | steps:
634 | - intent: transfer_money
635 | user: |-
636 | transfer money
637 | - action: transfer_money_form
638 | - active_loop: transfer_money_form
639 | - intent: pay_cc
640 | user: |-
641 | pay [credit card]{"entity": "account_type", "value": "credit"}
642 | - action: action_switch_forms_ask
643 | - slot_was_set:
644 | - next_form_name: cc_payment_form
645 | - intent: affirm
646 | - action: action_switch_forms_affirm
647 | - slot_was_set:
648 | - next_form_name: null
649 | - slot_was_set:
650 | - previous_form_name: transfer_money_form
651 | - action: cc_payment_form
652 | - active_loop: cc_payment_form
653 | - active_loop: null
654 | - slot_was_set:
655 | - requested_slot: null
656 | - action: action_pay_cc
657 | - action: action_switch_back_ask
658 | - slot_was_set:
659 | - previous_form_name: null
660 | - intent: deny
661 | - action: utter_ask_whatelse
662 | - story: pay credit card + switch to search transactions, affirm + switch back, affirm
663 | steps:
664 | - intent: pay_cc
665 | user: |-
666 | pay [credit card]{"entity": "account_type", "value": "credit"}
667 | - action: cc_payment_form
668 | - active_loop: cc_payment_form
669 | - intent: check_earnings
670 | user: |-
671 | check earnings
672 | - action: action_switch_forms_ask
673 | - slot_was_set:
674 | - next_form_name: transaction_search_form
675 | - intent: affirm
676 | - action: action_switch_forms_affirm
677 | - slot_was_set:
678 | - next_form_name: null
679 | - slot_was_set:
680 | - previous_form_name: cc_payment_form
681 | - action: transaction_search_form
682 | - active_loop: transaction_search_form
683 | - active_loop: null
684 | - slot_was_set:
685 | - requested_slot: null
686 | - action: action_transaction_search
687 | - action: action_switch_back_ask
688 | - slot_was_set:
689 | - previous_form_name: null
690 | - intent: affirm
691 | - action: cc_payment_form
692 | - active_loop: cc_payment_form
693 | - story: pay credit card + switch to transfer money, affirm + switch back, affirm
694 | steps:
695 | - intent: pay_cc
696 | user: |-
697 | pay [credit card]{"entity": "account_type", "value": "credit"}
698 | - action: cc_payment_form
699 | - active_loop: cc_payment_form
700 | - intent: transfer_money
701 | user: |-
702 | transfer money
703 | - action: action_switch_forms_ask
704 | - slot_was_set:
705 | - next_form_name: transfer_money_form
706 | - intent: affirm
707 | - action: action_switch_forms_affirm
708 | - slot_was_set:
709 | - next_form_name: null
710 | - slot_was_set:
711 | - previous_form_name: cc_payment_form
712 | - action: transfer_money_form
713 | - active_loop: transfer_money_form
714 | - active_loop: null
715 | - slot_was_set:
716 | - requested_slot: null
717 | - action: action_transfer_money
718 | - action: action_switch_back_ask
719 | - slot_was_set:
720 | - previous_form_name: null
721 | - intent: affirm
722 | - action: cc_payment_form
723 | - active_loop: cc_payment_form
724 | - story: search transactions + switch to transfer money, affirm + switch back, affirm
725 | steps:
726 | - intent: check_earnings
727 | user: |-
728 | check earnings
729 | - action: transaction_search_form
730 | - active_loop: transaction_search_form
731 | - intent: transfer_money
732 | user: |-
733 | transfer money
734 | - action: action_switch_forms_ask
735 | - slot_was_set:
736 | - next_form_name: transfer_money_form
737 | - intent: affirm
738 | user: |-
739 | Yes
740 | - action: action_switch_forms_affirm
741 | - slot_was_set:
742 | - next_form_name: null
743 | - slot_was_set:
744 | - previous_form_name: transaction_search_form
745 | - action: transfer_money_form
746 | - active_loop: transfer_money_form
747 | - active_loop: null
748 | - slot_was_set:
749 | - requested_slot: null
750 | - action: action_transfer_money
751 | - action: action_switch_back_ask
752 | - slot_was_set:
753 | - previous_form_name: null
754 | - intent: affirm
755 | user: |-
756 | Yes
757 | - action: transaction_search_form
758 | - active_loop: transaction_search_form
759 | - story: search transactions + switch to pay credit card, affirm + switch back, affirm
760 | steps:
761 | - intent: check_earnings
762 | user: |-
763 | check earnings
764 | - action: transaction_search_form
765 | - active_loop: transaction_search_form
766 | - intent: pay_cc
767 | user: |-
768 | pay [credit card]{"entity": "account_type", "value": "credit"}
769 | - action: action_switch_forms_ask
770 | - slot_was_set:
771 | - next_form_name: cc_payment_form
772 | - intent: affirm
773 | - action: action_switch_forms_affirm
774 | - slot_was_set:
775 | - next_form_name: null
776 | - slot_was_set:
777 | - previous_form_name: transaction_search_form
778 | - action: cc_payment_form
779 | - active_loop: cc_payment_form
780 | - active_loop: null
781 | - slot_was_set:
782 | - requested_slot: null
783 | - action: action_pay_cc
784 | - action: action_switch_back_ask
785 | - slot_was_set:
786 | - previous_form_name: null
787 | - intent: affirm
788 | - action: transaction_search_form
789 | - active_loop: transaction_search_form
790 | - story: transfer money+ switch to search transactions, affirm + switch back, affirm
791 | steps:
792 | - intent: transfer_money
793 | user: |-
794 | transfer money
795 | - action: transfer_money_form
796 | - active_loop: transfer_money_form
797 | - intent: check_earnings
798 | user: |-
799 | check earnings
800 | - action: action_switch_forms_ask
801 | - slot_was_set:
802 | - next_form_name: transaction_search_form
803 | - intent: affirm
804 | - action: action_switch_forms_affirm
805 | - slot_was_set:
806 | - next_form_name: null
807 | - slot_was_set:
808 | - previous_form_name: transfer_money_form
809 | - action: transaction_search_form
810 | - active_loop: transaction_search_form
811 | - active_loop: null
812 | - slot_was_set:
813 | - requested_slot: null
814 | - action: action_transaction_search
815 | - action: action_switch_back_ask
816 | - slot_was_set:
817 | - previous_form_name: null
818 | - intent: affirm
819 | - action: transfer_money_form
820 | - active_loop: transfer_money_form
821 | - story: transfer money+ switch to pay credit card, affirm + switch back, affirm
822 | steps:
823 | - intent: transfer_money
824 | user: |-
825 | transfer money
826 | - action: transfer_money_form
827 | - active_loop: transfer_money_form
828 | - intent: pay_cc
829 | user: |-
830 | pay [credit card]{"entity": "account_type", "value": "credit"}
831 | - action: action_switch_forms_ask
832 | - slot_was_set:
833 | - next_form_name: cc_payment_form
834 | - intent: affirm
835 | - action: action_switch_forms_affirm
836 | - slot_was_set:
837 | - next_form_name: null
838 | - slot_was_set:
839 | - previous_form_name: transfer_money_form
840 | - action: cc_payment_form
841 | - active_loop: cc_payment_form
842 | - active_loop: null
843 | - slot_was_set:
844 | - requested_slot: null
845 | - action: action_pay_cc
846 | - action: action_switch_back_ask
847 | - slot_was_set:
848 | - previous_form_name: null
849 | - intent: affirm
850 | - action: transfer_money_form
851 | - active_loop: transfer_money_form
852 | - story: providing a name must be inform intent
853 | steps:
854 | - intent: transfer_money
855 | user: |-
856 | i want to transfer money
857 | - action: transfer_money_form
858 | - active_loop: transfer_money_form
859 | - slot_was_set:
860 | - AA_CONTINUE_FORM: yes
861 | - slot_was_set:
862 | - requested_slot: PERSON
863 | - intent: inform
864 | user: |-
865 | [lisa](PERSON)
866 | - slot_was_set:
867 | - requested_slot: amount-of-money
868 | - action: transfer_money_form
869 |
--------------------------------------------------------------------------------