[
  {
    "path": ".github/workflows/continuous-integration.yml",
    "content": "name: Continuous Integration\non:\n  push:\n    branches:\n    - main\n    paths:\n    - 'actions/**'\n    - '.github/workflows/continuous-integration.yml'\n\njobs:\n  docker:\n    name: Build Action Server Docker Image\n    runs-on: ubuntu-latest\n    env:\n      DOCKERHUB_USERNAME: oakela\n    steps:\n      - name: Checkout git repository 🕝\n        uses: actions/checkout@v2\n      - name: Build Actions Server Image\n        uses: RasaHQ/rasa-action-server-gha@main\n        with:\n          actions_directory: 'actions'\n          requirements_file: 'actions/requirements-actions.txt'\n          docker_registry_login: ${{ env.DOCKERHUB_USERNAME }}\n          docker_registry_password: ${{ secrets.DOCKERHUB_PASSWORD }}\n          docker_image_name: 'rasa/helpdesk-assistant'\n          docker_image_tag: 'latest'\n          rasa_sdk_version: '3.0.0'\n"
  },
  {
    "path": ".github/workflows/lint_and_test.yml",
    "content": "name: Lint and Test\non:\n  push:\n    branches:\n      - main\n    paths-ignore:\n    - \"README.md\"\n    - \"Makefile\"\n    - \"Dockerfile\"\n\njobs:\n  lint-testing:\n    name: Code Formatting Tests\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n    - name: Set up Python 3.7\n      uses: actions/setup-python@v1\n      with:\n        python-version: 3.7\n    - name: Install dependencies\n      run: |\n        python -m pip install -U pip\n        pip install -r requirements-dev.txt\n    - name: Code Formatting Tests\n      working-directory: ${{ github.workspace }}\n      run: |\n        make lint\n  type-testing:\n    name: Type Tests\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n    - name: Set up Python 3.6\n      uses: actions/setup-python@v1\n      with:\n        python-version: 3.6\n    - name: Install dependencies\n      run: |\n        python -m pip install -U pip\n        pip install -r requirements-dev.txt\n    - name: Type Checking\n      working-directory: ${{ github.workspace }}\n      run: |\n        make types\n  training-testing:\n    name: Training and Testing\n    runs-on: ubuntu-latest\n    needs: [lint-testing, type-testing]\n    steps:\n      - uses: actions/checkout@v1\n      - id: files\n        uses: jitterbit/get-changed-files@v1\n      - name: set_training\n        if: |\n            contains(  steps.files.outputs.all, 'data/' )\n            || contains(  steps.files.outputs.all, 'config.yml' )\n            || contains(  steps.files.outputs.all, 'domain.yml' )\n        run: echo \"RUN_TRAINING=true\" >> $GITHUB_ENV\n      - name: Rasa Train and Test GitHub Action\n        if: env.RUN_TRAINING == 'true'\n        uses: RasaHQ/rasa-train-test-gha@main\n        with:\n          rasa_version: '3.0.0'\n          test_type: all\n          data_validate: true\n          cross_validation: true\n          publish_summary: true\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n      - name: Upload model\n        if: github.ref == 'refs/heads/main'\n        uses: actions/upload-artifact@main\n        with:\n          name: model\n          path: models\n"
  },
  {
    "path": ".github/workflows/lint_and_test_pr.yml",
    "content": "name: Lint and Test PR\non:\n  pull_request:\n    paths-ignore:\n    - \"README.md\"\n    - \"Makefile\"\n    - \"Dockerfile\"\n\njobs:\n  lint-testing:\n    name: Code Formatting Tests\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n    - name: Set up Python 3.7\n      uses: actions/setup-python@v1\n      with:\n        python-version: 3.7\n    - name: Install dependencies\n      run: |\n        python -m pip install -U pip\n        pip install -r requirements-dev.txt\n    - name: Code Formatting Tests\n      working-directory: ${{ github.workspace }}\n      run: |\n        make lint\n  type-testing:\n    name: Type Tests\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v1\n    - name: Set up Python 3.7\n      uses: actions/setup-python@v1\n      with:\n        python-version: 3.7\n    - name: Install dependencies\n      run: |\n        python -m pip install -U pip\n        pip install -r requirements-dev.txt\n    - name: Type Checking\n      working-directory: ${{ github.workspace }}\n      run: |\n        make types\n  training-testing:\n    name: Training and Testing\n    runs-on: ubuntu-latest\n    needs: [lint-testing, type-testing]\n    steps:\n      - uses: actions/checkout@v1\n      - id: files\n        uses: jitterbit/get-changed-files@v1\n      - name: set_training\n        if: |\n            contains(  steps.files.outputs.all, 'data/' )\n            || contains(  steps.files.outputs.all, 'config.yml' )\n            || contains(  steps.files.outputs.all, 'domain.yml' )\n        run: echo \"RUN_TRAINING=true\" >> $GITHUB_ENV\n      - name: Rasa Train and Test GitHub Action\n        if: env.RUN_TRAINING == 'true'\n        uses: RasaHQ/rasa-train-test-gha@main\n        with:\n          rasa_version: '3.0.0'\n          test_type: all\n          data_validate: true\n          cross_validation: true\n          publish_summary: true\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n      - name: Upload model\n        if: github.ref == 'refs/heads/main'\n        uses: actions/upload-artifact@main\n        with:\n          name: model\n          path: models\n"
  },
  {
    "path": ".gitignore",
    "content": "# Standard Ignores\nvenv\n__pycache__/\n.DS_Store\n.vscode/\n.history/\n.pytype/\n\n# Rasa Ignores\ncredentials.yml\n*.db-*\nrasa.db*\n*.db\nresults/\nmodels/\nsnow_connector.py\nchatroom/\n.idea/"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n-   repo: https://github.com/ambv/black\n    rev: stable\n    hooks:\n    - id: black\n"
  },
  {
    "path": "Dockerfile.chatroom",
    "content": "# docker build -t chatroom -f Dockerfile.chatroom\n# docker run --name chatroom -p 8080:3000 -d chatroom\nFROM node:14\n\nRUN node --version\n\nRUN git clone https://github.com/RasaHQ/chatroom.git\n\nWORKDIR /chatroom\n\nRUN curl -o- -L https://yarnpkg.com/install.sh | bash\nRUN yarn\n\n# replace default chatroom index.html\nCOPY chatroom_handoff.html index.html\n\nRUN yarn build\n\nEXPOSE 8080\n\nCMD [ \"yarn\", \"serve\" ]"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2020 Rasa Technologies GmbH\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "help:\n\t@echo \"make\"\n\t@echo \"    clean\"\n\t@echo \"        Remove Python/build artifacts.\"\n\t@echo \"    formatter\"\n\t@echo \"        Apply black formatting to code.\"\n\t@echo \"    lint\"\n\t@echo \"        Lint code with flake8, and check if black formatter should be applied.\"\n\t@echo \"    types\"\n\t@echo \"        Check for type errors using pytype.\"\n\t@echo \"    validate\"\n\t@echo \"        Runs the rasa data validate to verify data.\"\n\t@echo \"    test\"\n\t@echo \"        Runs the rasa test suite checking for issues.\"\n\t@echo \"    crossval\"\n\t@echo \"        Runs the rasa cross validation tests and creates results.md\"\n\t@echo \"    shell\"\n\t@echo \"        Runs the rasa train and rasa shell for testing\"\n\n\nclean:\n\tfind . -name '*.pyc' -exec rm -f {} +\n\tfind . -name '*.pyo' -exec rm -f {} +\n\tfind . -name '*~' -exec rm -f  {} +\n\trm -rf build/\n\trm -rf .pytype/\n\trm -rf dist/\n\trm -rf docs/_build\n\nformatter:\n\tblack actions --line-length 79\n\nlint:\n\tflake8 actions\n\tblack --check actions\n\ntypes:\n\tpytype --keep-going actions\n\nvalidate:\n\trasa train\n\trasa data validate --debug\n\ntest:\n\trasa train\n\trasa test --fail-on-prediction-errors\n\ncrossval:\n\trasa test nlu -f 5 --cross-validation\n\tpython format_results.py\n\nshell:\n\trasa train --debug\n\trasa shell --debug"
  },
  {
    "path": "README.md",
    "content": "# Rasa Helpdesk Assistant Example\n\nThis is a Rasa chatbot example demonstrating how to build an AI assistant for an IT Helpdesk. It includes an integration with the Service Now API to open incident reports and check on incident report statuses. Below is an example conversation, showing the bot helping a user open a support ticket and query its status. You can use this chatbot as a starting point for building customer service assistants or as a template for collecting required pieces of information from a user before making an API call.\n\nHere is an example of a conversation you can have with this bot:\n\n![Screenshot](./screenshots/demo_ss.png?raw=true)\n\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n**Table of Contents**\n\n- [Rasa Helpdesk Assistant Example](#rasa-helpdesk-assistant-example)\n  - [Setup](#setup)\n    - [Install the dependencies](#install-the-dependencies)\n    - [Optional: Connect to a ServiceNow instance](#optional-connect-to-a-servicenow-instance)\n  - [Running the bot](#running-the-bot)\n  - [Things you can ask the bot](#things-you-can-ask-the-bot)\n  - [Example conversations](#example-conversations)\n  - [Handoff](#handoff)\n    - [Try it out](#try-it-out)\n    - [How it works](#how-it-works)\n    - [Bot-side configuration](#bot-side-configuration)\n  - [Testing the bot](#testing-the-bot)\n  - [Rasa X Deployment](#rasa-x-deployment)\n    - [Action Server Image](#action-server-image)\n  - [Notes on Chatroom](#notes-on-chatroom)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n## Setup\n\n### Install the dependencies\n\nIn a Python3 virtual environment run:\n\n```bash\npip install -r requirements.txt\n```\n\nTo install development dependencies, run:\n\n```bash\npip install -r requirements-dev.txt\npre-commit install\n```\n\n> With pre-commit installed, the `black` and `doctoc` hooks will run on every `git commit`.\n> If any changes are made by the hooks, you will need to re-add changed files and re-commit your changes.\n\n### Optional: Connect to a ServiceNow instance\n\nYou can run this bot without connecting to a ServiceNow instance, in which case it will\nsend responses without creating an incident or checking the actual status of one.\nTo run the bot  without connecting ServiceNow,\nyou don't need to change anything in `actions/snow_credentials.yml`; `localmode` should already be set\nto `true`\n\nIf you do want to connect to ServiceNow, you can get your own free Developer instance\nto test this with [here](https://developer.servicenow.com/app.do#!/home)\n\nTo connect to your ServiceNow developer instance, configure the following in `actions/snow_credentials.yml`:\n\n- `snow_instance` - This is the address of the ServiceNow developer instance, you don't need the leading https.\n\n- `snow_user` - The username of the service account for the ServiceNow developer instance\n\n- `snow_pw` - The password of the service account for the ServiceNow developer instance\n\n- `localmode` -  Whether the action server should **not** try to reach out to a `snow_instance` based on the credentials in `actions/snow_credentials.yml`. When set to `True` (default in the code), it will just take all the data in and message out the information that would normally be sent.\n\n## Running the bot\n\nUse `rasa train` to train a model.\n\nThen, to run, first set up your action server in one terminal window:\n\n```bash\nrasa run actions\n```\n\nIn another window, run the duckling server (for entity extraction):\n\n```bash\ndocker run -p 8000:8000 rasa/duckling\n```\n\nThen to talk to the bot, run:\n\n```bash\nrasa shell --debug\n```\n\nNote that `--debug` mode will produce a lot of output meant to help you understand how the bot is working\nunder the hood. You can also add this flag to the action server command. To simply talk to the bot, you can remove this flag.\n\nYou can also try out the bot locally using Rasa X by running\n\n```bash\nrasa x\n```\n\nRefer to our guided workflow in the [Wiki page](https://github.com/RasaHQ/helpdesk-assistant/wiki/Using-Rasa-X-with-the-Helpdesk-Assistant) for how to get started with Rasa X in local mode.\n\n## Things you can ask the bot\n\nThe bot has two main skills:\n1. Opening an incident in ServiceNow.\n2. Checking the status of incidents in ServiceNow by email address of the caller. It will prompt the user to re-use previously provided (during the chat session) email addresses, if any exist.\nFor the purposes of illustration, the bot recognizes the following as requests to open an incident:\n\n1. Asking to open an incident directly e.g. \"I want to open an incident\"\n2. Asking about a problem resetting their password e.g. \"I can't reset my password\"\n3. Asking about a problem with outlook/email e.g. \"I can't log in to my outlook\"\n\nTake a look at `data/nlu.md` to see what the bot is currently trained to recognize.\n\nIt can also respond to requests for help (e.g. \"help me\").\n\nIf configured, the bot can also hand off to another bot in response to the user asking for handoff. More [details on handoff](#handoff) below.\n\n## Example conversations\n\nWith `localmode=true`:\n\n```\nBot loaded. Type a message and press enter (use '/stop' to exit):\nYour input ->  hi\n    Hello!\n    I can help you open a service request ticket, or check the status of your open incidents.\n    You can ask me things like:\n    - Open an incident\n    - Help me reset my password\n    - I'm having a issue with my email\n    - What's the status of the ticket I opened?\nYour input ->  i have a problem with my email\n    What is your email address?\nYour input ->  anything@example.com\n    ? What is the priority of this issue?\nYour input -> 1: low (/inform{\"priority\":\"low\"})\n    What is the problem description for the issue?\nYour input ->  Can't log in to my email\n    ? Should I open an incident with the following details?\n    email: anything@example.com\n    problem description: Can't log in to my email\n    title: Problem with email\nYour input -> priority: low  1: Yes (/affirm)\n    An incident with the following details would be opened if ServiceNow was connected:\n    email: anything@example.com\n    problem description: Can't log in to my email\n    title: Problem with email\n    priority: low\nYour input ->  thanks. Can i check the status of my other tickets?\n    Would you like to use the last email address you used, anything@example.com?\nYour input ->  Yes please\n    Since ServiceNow isn't connected, I'm making this up!\n    The most recent incident for anything@example.com is currently awaiting triage\n```\n\nWith `localmode=false`:\n\nWith a Service Now instance connected, it will check if the email address is in the instance database and provide an incident number for the final response:\n\n```\nYour input ->  help me reset my password\n    What is your email address?\nYour input ->  idontexist@example.com\n    Sorry, \"idontexist@example.com\" isn't in our incident management system. Please try again.\n    What is your email address?\nYour input ->  abraham.lincoln@example.com\n    ? What is the priority of this issue?\nYour input -> 3: high (/inform{\"priority\":\"high\"})\n    What is the problem description for the issue?\nYour input ->  Password stuck in a loop\n    ? Should I open an incident with the following details?\n    email: abraham.lincoln@example.com\n    problem description: Password stuck in a loop\n    title: Problem resetting password\n    priority: high\nYour input ->  1: Yes (/affirm)\n    Successfully opened up incident INC0010008 for you.  Someone will reach out soon.\nYour input ->  Can I check the status of my tickets?\n    Would you like to use the last email address you used, abraham.lincoln@example.com?\nYour input ->  Yes please\n    Incident INC0010002: \"Email Log in problem\", opened on 2020-05-21 09:57:06 is currently in progress\n    Incident INC0010008: \"Problem resetting password\", opened on 2020-05-21 12:12:49 is currently awaiting triage\nYour input ->  thanks\n    You're welcome!\n```\n\n\n## Handoff\n\nThis bot includes a simple skill for handing off the conversation to another bot or a human.\nThis demo relies on [this fork of chatroom](https://github.com/RasaHQ/chatroom) to work, however you\ncould implement similar behaviour in another channel and then use that instead. See the chatroom README for\nmore details on channel-side configuration.\n\n\nUsing the default set up, the handoff skill enables this kind of conversation with two bots:\n\n<img src=\"./handoff.gif\" width=\"200\">\n\n### Try it out\n\nThe simplest way to use the handoff feature is to do the following:\n\n1. Clone [chatroom](https://github.com/RasaHQ/chatroom) and [Financial-Demo](https://github.com/RasaHQ/Financial-Demo) alongside this repo\n2. In the chatroom repo, install the dependencies:\n```bash\nyarn install\n```\n3. In the chatroom repo, build and serve chatroom:\n```bash\nyarn build\nyarn serve\n```\n4. In the Financial-Demo repo, install the dependencies and train a model (see the Financial-Demo README)\n5. In the Helpdesk-Assistant repo (i.e. this repo), run the rasa server and action server at the default ports (shown here for clarity)\n   In one terminal window:\n    ```bash\n    rasa run --enable-api --cors \"*\" --port 5005 --debug\n    ```\n    In another terminal window:\n    ```bash\n    rasa run actions --port 5055 --debug\n    ```\n6. In the Financial-Demo repo, run the rasa server and action server at **the non-default ports shown below**\n   In one terminal window:\n    ```bash\n    rasa run --enable-api --cors \"*\" --port 5006 --debug\n    ```\n    In another terminal window:\n    ```bash\n    rasa run actions --port 5056 --debug\n    ```\n7. Open `chatroom_handoff.html` in a browser to see handoff in action\n\n\n### How it works\n\nUsing chatroom, the general approach is as follows:\n\n1. User asks original bot for a handoff.\n2. The original bot handles the request and eventually\n   sends a message with the following custom json payload:\n    ```\n        {\n            \"handoff_host\": \"<url of handoff host endpoint>\",\n            \"title\": \"<title for bot/channel handed off to>\"\n            }\n    ```\n    This message is not displayed in the Chatroom window.\n3. Chatroom switches the host to the specified `handoff_host`\n4. The original bot no longer receives any messages.\n5. The handoff host receives the message `/handoff{\"from_host\":\"<original bot url\">}`\n6. The handoff host should be configured to respond to this message with something like,\n   \"Hi, I'm <so and so>, how can I help you??\"\n7. The handoff host can send a message in the same format as specified above to hand back to the original bot.\n   In this case the same pattern repeats, but with\n   the roles reversed. It could also hand off to yet another bot/human.\n\n### Bot-side configuration\n\nThe \"try it out\" section doesn't require any further configuration; this section is for those\nwho want to change or further understand the set up.\n\nFor this demo, the user can ask for a human, but they'll be offered a bot (or bots) instead,\nso that the conversation looks like this:\n\n\nFor handoff to work, you need at least one \"handoff_host\". You can specify any number of handoff hosts in the file `actions/hanodff_config.yml`.\n```\nhandoff_hosts:\n    financial_demo:\n      title: \"Financial Demo\"\n      url: \"http://localhost:5006\"\n    ## you can add more handoff hosts to this list e.g.\n    # moodbot:\n    #   title: \"MoodBot\"\n    #   url: \"http://localhost:5007\"\n```\n\nHandoff hosts can be other locally running rasa bots, or anything that serves responses in the format that chatroom\naccepts. If a handoff host is not a rasa bot, you will of course want to update the response text to tell the user\nwho/what they are being handed off to.\n\nThe [Financial-Demo](https://github.com/RasaHQ/Financial-Demo) bot has been set up to handle handoff in exactly the same way as Helpdesk-Assistant,\nso the simplest way to see handoff in action is to clone Financial-Demo alongside this repo.\n\nIf you list other locally running bots as handoff hosts, make sure the ports on which the various rasa servers & action servers are running do not conflict with each other.\n\n\n## Testing the bot\n\nYou can test the bot on the test conversations by running  `rasa test`.\nThis will run [end-to-end testing](https://rasa.com/docs/rasa/user-guide/testing-your-assistant/#end-to-end-testing) on the conversations in `tests/conversation_tests.md`.\n\n## Rasa X Deployment\n\nTo [deploy helpdesk-assistant](https://rasa.com/docs/rasa/user-guide/how-to-deploy/), it is highly recommended to make use of the\n[one line deploy script](https://rasa.com/docs/rasa-x/installation-and-setup/one-line-deploy-script/) for Rasa X. As part of the deployment, you'll need to set up [git integration](https://rasa.com/docs/rasa-x/installation-and-setup/integrated-version-control/#connect-your-rasa-x-server-to-a-git-repository) to pull in your data and\nconfigurations, and build or pull an action server image.\n\n### Action Server Image\n\nYou will need to have docker installed in order to build the action server image. If you haven't made any changes to the action code, you can also use\nthe [public image on Dockerhub](https://hub.docker.com/r/rasa/helpdesk-assistant) instead of building it yourself.\n\n\nSee the Dockerfile for what is included in the action server image,\n\nTo build the image:\n\n```bash\ndocker build . -t <name of your custom image>:<tag of your custom image>\n```\n\nTo test the container locally, you can then run the action server container with:\n\n```bash\ndocker run -p 5055:5055 <name of your custom image>:<tag of your custom image>\n```\n\nOnce you have confirmed that the container works as it should, you can push the container image to a registry with `docker push`\n\nIt is recommended to use an[automated CI/CD process](https://rasa.com/docs/rasa/user-guide/setting-up-ci-cd) to keep your action server up to date in a production environment.\n\n## Notes on Chatroom\n\nIf you want to try the transfer to another bot feature, you'll need to use Chatroom.  As of this writing, the main Scalable Minds chatroom [project](https://github.com/scalableminds/chatroom) has not included this feature so you will need to build from a fork. The following docker commands will build an image from the adapted Chatroom and run it.\n\n```\ndocker build -t chatroom -f Dockerfile.chatroom .\ndocker run --name chatroom -p 8080:8080 -d chatroom\n```\n\nFrom the `docker-compose.yml` below, you can start chatroom with `docker-compose up -d`\n\nHere's an example docker-compose.yml for this image. Note that the initial Rasa endpoint URL is hard coded in `chatroom_handoff.html`; to use your locally running bot, point it to `http://localhost:5005`.\n\n```\nversion: \"3.4\"\n\nservices:\n  chatroom:\n    image: chatroom\n    build:\n      context: ./\n      dockerfile: Dockerfile.chatroom\n    ports:\n      - \"8080:8080\"\n    command: [ \"yarn\", \"serve\" ]\n```\n"
  },
  {
    "path": "actions/__init__.py",
    "content": ""
  },
  {
    "path": "actions/actions.py",
    "content": "import logging\nfrom typing import Dict, Text, Any, List\nfrom rasa_sdk import Tracker\nfrom rasa_sdk.executor import CollectingDispatcher, Action\nfrom rasa_sdk.forms import FormValidationAction\nfrom rasa_sdk.events import AllSlotsReset, SlotSet\nfrom actions.snow import SnowAPI\nimport random\n\n\nlogger = logging.getLogger(__name__)\nvers = \"vers: 0.1.0, date: Apr 2, 2020\"\nlogger.debug(vers)\n\nsnow = SnowAPI()\nlocalmode = snow.localmode\nlogger.debug(f\"Local mode: {snow.localmode}\")\n\n\nclass ActionAskEmail(Action):\n    def name(self) -> Text:\n        return \"action_ask_email\"\n\n    def run(\n        self,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> List[Dict]:\n        if tracker.get_slot(\"previous_email\"):\n            dispatcher.utter_message(template=f\"utter_ask_use_previous_email\",)\n        else:\n            dispatcher.utter_message(template=f\"utter_ask_email\")\n        return []\n\n\ndef _validate_email(\n    value: Text,\n    dispatcher: CollectingDispatcher,\n    tracker: Tracker,\n    domain: Dict[Text, Any],\n) -> Dict[Text, Any]:\n    \"\"\"Validate email is in ticket system.\"\"\"\n    if not value:\n        return {\"email\": None, \"previous_email\": None}\n    elif isinstance(value, bool):\n        value = tracker.get_slot(\"previous_email\")\n\n    if localmode:\n        return {\"email\": value}\n\n    results = snow.email_to_sysid(value)\n    caller_id = results.get(\"caller_id\")\n\n    if caller_id:\n        return {\"email\": value, \"caller_id\": caller_id}\n    elif isinstance(caller_id, list):\n        dispatcher.utter_message(template=\"utter_no_email\")\n        return {\"email\": None}\n    else:\n        dispatcher.utter_message(results.get(\"error\"))\n        return {\"email\": None}\n\n\nclass ValidateOpenIncidentForm(FormValidationAction):\n    def name(self) -> Text:\n        return \"validate_open_incident_form\"\n\n    def validate_email(\n        self,\n        value: Text,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> Dict[Text, Any]:\n        \"\"\"Validate email is in ticket system.\"\"\"\n        return _validate_email(value, dispatcher, tracker, domain)\n\n    def validate_priority(\n        self,\n        value: Text,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> Dict[Text, Any]:\n        \"\"\"Validate priority is a valid value.\"\"\"\n\n        if value.lower() in snow.priority_db():\n            return {\"priority\": value}\n        else:\n            dispatcher.utter_message(template=\"utter_no_priority\")\n            return {\"priority\": None}\n\n\nclass ActionOpenIncident(Action):\n    def name(self) -> Text:\n        return \"action_open_incident\"\n\n    def run(\n        self,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> List[Dict]:\n        \"\"\"Create an incident and return details or\n        if localmode return incident details as if incident\n        was created\n        \"\"\"\n\n        priority = tracker.get_slot(\"priority\")\n        email = tracker.get_slot(\"email\")\n        problem_description = tracker.get_slot(\"problem_description\")\n        incident_title = tracker.get_slot(\"incident_title\")\n        confirm = tracker.get_slot(\"confirm\")\n        if not confirm:\n            dispatcher.utter_message(\n                template=\"utter_incident_creation_canceled\"\n            )\n            return [AllSlotsReset(), SlotSet(\"previous_email\", email)]\n\n        if localmode:\n            message = (\n                f\"An incident with the following details would be opened \"\n                f\"if ServiceNow was connected:\\n\"\n                f\"email: {email}\\n\"\n                f\"problem description: {problem_description}\\n\"\n                f\"title: {incident_title}\\npriority: {priority}\"\n            )\n        else:\n            snow_priority = snow.priority_db().get(priority)\n            response = snow.create_incident(\n                description=problem_description,\n                short_description=incident_title,\n                priority=snow_priority,\n                email=email,\n            )\n            incident_number = (\n                response.get(\"content\", {}).get(\"result\", {}).get(\"number\")\n            )\n            if incident_number:\n                message = (\n                    f\"Successfully opened up incident {incident_number} \"\n                    f\"for you. Someone will reach out soon.\"\n                )\n            else:\n                message = (\n                    f\"Something went wrong while opening an incident for you. \"\n                    f\"{response.get('error')}\"\n                )\n        dispatcher.utter_message(message)\n        return [AllSlotsReset(), SlotSet(\"previous_email\", email)]\n\n\nclass IncidentStatusForm(FormValidationAction):\n    def name(self) -> Text:\n        return \"validate_incident_status_form\"\n\n    def validate_email(\n        self,\n        value: Text,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> Dict[Text, Any]:\n        \"\"\"Validate email is in ticket system.\"\"\"\n        return _validate_email(value, dispatcher, tracker, domain)\n\n\nclass ActionCheckIncidentStatus(Action):\n    def name(self) -> Text:\n        return \"action_check_incident_status\"\n\n    def run(\n        self,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> List[Dict]:\n        \"\"\"Look up all incidents associated with email address\n           and return status of each\"\"\"\n\n        email = tracker.get_slot(\"email\")\n\n        incident_states = {\n            \"New\": \"is currently awaiting triage\",\n            \"In Progress\": \"is currently in progress\",\n            \"On Hold\": \"has been put on hold\",\n            \"Closed\": \"has been closed\",\n        }\n        if localmode:\n            status = random.choice(list(incident_states.values()))\n            message = (\n                f\"Since ServiceNow isn't connected, I'm making this up!\\n\"\n                f\"The most recent incident for {email} {status}\"\n            )\n        else:\n            incidents_result = snow.retrieve_incidents(email)\n            incidents = incidents_result.get(\"incidents\")\n            if incidents:\n                message = \"\\n\".join(\n                    [\n                        f'Incident {i.get(\"number\")}: '\n                        f'\"{i.get(\"short_description\")}\", '\n                        f'opened on {i.get(\"opened_at\")} '\n                        f'{incident_states.get(i.get(\"incident_state\"))}'\n                        for i in incidents\n                    ]\n                )\n\n            else:\n                message = f\"{incidents_result.get('error')}\"\n\n        dispatcher.utter_message(message)\n        return [AllSlotsReset(), SlotSet(\"previous_email\", email)]\n"
  },
  {
    "path": "actions/handoff.py",
    "content": "from rasa_sdk import Tracker, Action\nfrom rasa_sdk.executor import CollectingDispatcher\n\nimport ruamel.yaml\nimport pathlib\nfrom typing import Dict, Text, Any, List\nfrom rasa_sdk.events import EventType\n\nhere = pathlib.Path(__file__).parent.absolute()\nhandoff_config = (\n    ruamel.yaml.safe_load(open(f\"{here}/handoff_config.yml\", \"r\")) or {}\n).get(\"handoff_hosts\", {})\n\n\nclass ActionHandoffOptions(Action):\n    def name(self) -> Text:\n        return \"action_handoff_options\"\n\n    async def run(\n        self,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> List[EventType]:\n\n        if not any(\n            [config.get(\"url\") for bot, config in handoff_config.items()]\n        ):\n            dispatcher.utter_message(template=\"utter_no_handoff\")\n        else:\n            buttons = [\n                {\n                    \"title\": config.get(\"title\"),\n                    \"payload\": f'/trigger_handoff{{\"handoff_to\":\"{bot}\"}}',\n                }\n                for bot, config in handoff_config.items()\n            ]\n            dispatcher.utter_message(\n                text=\"I can't transfer you to a human, \\\n                      but I can transfer you to one of these bots\",\n                buttons=buttons,\n            )\n        return []\n\n\nclass ActionHandoff(Action):\n    def name(self) -> Text:\n        return \"action_handoff\"\n\n    async def run(\n        self,\n        dispatcher: CollectingDispatcher,\n        tracker: Tracker,\n        domain: Dict[Text, Any],\n    ) -> List[EventType]:\n\n        dispatcher.utter_message(template=\"utter_handoff\")\n        handoff_to = tracker.get_slot(\"handoff_to\")\n\n        handoff_bot = handoff_config.get(handoff_to, {})\n        url = handoff_bot.get(\"url\")\n\n        if url:\n            if tracker.get_latest_input_channel() == \"rest\":\n                dispatcher.utter_message(\n                    json_message={\n                        \"handoff_host\": url,\n                        \"title\": handoff_bot.get(\"title\"),\n                    }\n                )\n            else:\n                dispatcher.utter_message(\n                    template=\"utter_wouldve_handed_off\", handoffhost=url\n                )\n        else:\n            dispatcher.utter_message(template=\"utter_no_handoff\")\n\n        return []\n"
  },
  {
    "path": "actions/handoff_config.yml",
    "content": "handoff_hosts:\n    financial_demo:\n      title: \"Financial Assistant\"\n      url: \"http://localhost:5006\"\n    ## you can add more handoff hosts to this list e.g.\n    # moodbot:\n    #   title: \"MoodBot\"\n    #   url: \"http://localhost:5007\""
  },
  {
    "path": "actions/requirements-actions.txt",
    "content": "pytablewriter\nrequests\nruamel.yaml"
  },
  {
    "path": "actions/snow.py",
    "content": "import logging\nimport requests\nimport json\nimport pathlib\nimport ruamel.yaml\nfrom typing import Dict, Text, Any\n\nlogger = logging.getLogger(__name__)\n\nhere = pathlib.Path(__file__).parent.absolute()\n\njson_headers = {\n    \"Content-Type\": \"application/json\",\n    \"Accept\": \"application/json\",\n}\n\n\nclass SnowAPI(object):\n    \"\"\"class to connect to the ServiceNow API\"\"\"\n\n    def __init__(self):\n        snow_config = (\n            ruamel.yaml.safe_load(open(f\"{here}/snow_credentials.yml\", \"r\"))\n            or {}\n        )\n        self.snow_user = snow_config.get(\"snow_user\")\n        self.snow_pw = snow_config.get(\"snow_pw\")\n        self.snow_instance = snow_config.get(\"snow_instance\")\n        self.localmode = snow_config.get(\"localmode\", True)\n        self.base_api_url = \"https://{}/api/now\".format(self.snow_instance)\n\n    def handle_request(\n        self, request_method=requests.get, request_args={}\n    ) -> Dict[Text, Any]:\n        result = dict()\n        try:\n            response = request_method(**request_args)\n            result[\"status_code\"] = response.status_code\n            if response.status_code >= 200 < 300:\n                result[\"content\"] = response.json()\n            else:\n                error = (\n                    f\"ServiceNow error: {response.status_code}: \"\n                    f'{response.json().get(\"error\",{}).get(\"message\")}'\n                )\n                logger.debug(error)\n                result[\"error\"] = error\n        except requests.exceptions.Timeout:\n            error = \"Could not connect to ServiceNow (Timeout)\"\n            logger.debug(error)\n            result[\"error\"] = error\n        return result\n\n    def email_to_sysid(self, email) -> Dict[Text, Any]:\n        lookup_url = (\n            f\"{self.base_api_url}/table/sys_user?\"\n            f\"sysparm_query=email={email}&sysparm_display_value=true\"\n        )\n        request_args = {\n            \"url\": lookup_url,\n            \"auth\": (self.snow_user, self.snow_pw),\n            \"headers\": json_headers,\n        }\n        result = self.handle_request(requests.get, request_args)\n        records = result.get(\"content\", {}).get(\"result\")\n        if len(records) == 1:\n            caller_id = records[0].get(\"sys_id\")\n            result[\"caller_id\"] = caller_id\n        elif isinstance(records, list):\n            result[\"caller_id\"] = []\n            result[\"error\"] = (\n                f\"Could not retrieve caller id; \"\n                f\"{records} records found for email {email}\"\n            )\n        return result\n\n    def retrieve_incidents(self, email) -> Dict[Text, Any]:\n        result = self.email_to_sysid(email)\n        caller_id = result.get(\"caller_id\")\n        if caller_id:\n            incident_url = (\n                f\"{self.base_api_url}/table/incident?\"\n                f\"sysparm_query=caller_id={caller_id}\"\n                f\"&sysparm_display_value=true\"\n            )\n            request_args = {\n                \"url\": incident_url,\n                \"auth\": (self.snow_user, self.snow_pw),\n                \"headers\": json_headers,\n            }\n            result = self.handle_request(requests.get, request_args)\n            incidents = result.get(\n                \"content\", {}  # pytype: disable=attribute-error\n            ).get(\"result\")\n            if incidents:\n                result[\"incidents\"] = incidents\n            elif isinstance(incidents, list):\n                result[\"error\"] = f\"No incidents on record for {email}\"\n        return result\n\n    def create_incident(\n        self, description, short_description, priority, email\n    ) -> Dict[Text, Any]:\n        result = self.email_to_sysid(email)\n        caller_id = result.get(\"caller_id\")\n        if caller_id:\n            incident_url = f\"{self.base_api_url}/table/incident\"\n            data = {\n                \"opened_by\": caller_id,\n                \"short_description\": short_description,\n                \"description\": description,\n                \"urgency\": priority,\n                \"caller_id\": caller_id,\n                \"comments\": description,\n            }\n            request_args = {\n                \"url\": incident_url,\n                \"auth\": (self.snow_user, self.snow_pw),\n                \"headers\": json_headers,\n                \"data\": json.dumps(data),\n            }\n            result = self.handle_request(requests.post, request_args)\n        return result\n\n    @staticmethod\n    def priority_db() -> Dict[str, int]:\n        \"\"\"Database of supported priorities\"\"\"\n        priorities = {\"low\": 3, \"medium\": 2, \"high\": 1}\n        return priorities\n"
  },
  {
    "path": "actions/snow_credentials.yml",
    "content": "# snow_instance: \"dev97377.service-now.com\"\n# snow_user: \"admin\"\n# snow_pw: \"mySnowinstance1\"\n# localmode: false"
  },
  {
    "path": "chatroom_handoff.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  <link rel=\"stylesheet\" href=\"./dist/Chatroom.css\" />\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"./index.css\">\n</head>\n<body>\n  <div class=\"chat-container\"></div>\n\n  <script src=\"./dist/Chatroom.js\"></script>\n  <script type=\"text/javascript\">\n    var chatroom = new window.Chatroom({\n      host: \"http://helpdesk-assistant.rasa.com\",\n      title: \"Helpdesk Assistant\",\n      container: document.querySelector(\".chat-container\"),\n      welcomeMessage: \"Hi, how may I help you?\"\n      // speechRecognition: \"en-US\",\n      // voiceLang: \"en-US\"\n    });\n    chatroom.openChat();\n  </script>\n</body>\n</html>"
  },
  {
    "path": "config.yml",
    "content": "language: en\npipeline:\n  - name: WhitespaceTokenizer\n  - name: RegexFeaturizer\n  - name: LexicalSyntacticFeaturizer\n  - name: CountVectorsFeaturizer\n  - name: CountVectorsFeaturizer\n    analyzer: \"char_wb\"\n    min_ngram: 1\n    max_ngram: 4\n  - name: DIETClassifier\n    epochs: 150\n    random_seed: 1\n  - name: FallbackClassifier\n    threshold: 0.7\n  - name: DucklingEntityExtractor\n    url: http://localhost:8000\n    dimensions:\n    - email\n  - name: EntitySynonymMapper\npolicies:\n  - name: AugmentedMemoizationPolicy\n    max_history: 4\n  - name: TEDPolicy\n    max_history: 4\n    epochs: 100\n  - name: RulePolicy\n    core_fallback_threshold: 0.4\n    core_fallback_action_name: \"action_default_fallback\"\n    enable_fallback_prediction: True\n\n"
  },
  {
    "path": "data/handoff.yml",
    "content": "version: \"3.0\"\nstories:\n- story: handoff\n  steps:\n  - intent: human_handoff\n  - action: utter_ask_handoff\n  - action: action_handoff_options\n  - intent: trigger_handoff\n  - action: action_handoff\n\n- story: handoff\n  steps:\n  - intent: human_handoff\n  - action: utter_ask_handoff\n  - action: action_handoff_options\n  - intent: trigger_handoff\n    entities:\n    - handoff_to: financial_demo\n  - action: action_handoff\n\n- story: handoff deny\n  steps:\n  - intent: human_handoff\n  - action: utter_ask_handoff\n  - action: action_handoff_options\n  - intent: deny\n  - action: utter_ask_whatelse\n"
  },
  {
    "path": "data/nlu.yml",
    "content": "version: \"3.0\"\nnlu:\n- intent: greet\n  examples: |\n    - hey\n    - hello\n    - hi\n    - good morning\n    - good evening\n    - hey there\n    - hi there\n    - hello there\n    - greetings\n    - Hi\n    - helo\n    - Hi!\n    - Hi'\n    - Hi,\n    - Hi, bot\n    - Hieee\n    - Hieeeeeeeeeeeee\n    - Hola\n    - What is up?\n    - Whats up\n    - Whats up my bot\n    - Whats up?\n    - ayyyy whaddup\n    - bonjour\n    - ey boss\n    - I said, helllllloooooO!!!!\n    - Well hello there ;)\n- intent: goodbye\n  examples: |\n    - bye\n    - goodbye\n    - see you around\n    - see you later\n    - see ya\n    - buh bye\n    - Bye\n    - Bye bye\n    - adios\n    - adios?\n    - bye :P\n    - bye bot\n    - bye bye\n    - bye bye bot\n    - bye for now\n    - bye udo\n    - bye was nice talking to you\n    - bye!\n    - byee\n    - catch you later\n    - ciao\n    - cya\n    - farewell\n    - good bye\n    - good bye rasa bot!\n    - good night\n    - goodbye\n    - goodbye.\n    - goodnight\n    - gotta go\n    - ok Bye\n    - ok bye\n    - ok, bye\n    - ok.bye\n    - see u later\n    - see ya\n    - see you\n    - see you . bye\n    - take care\n    - then bye\n    - tlak to you later\n    - toodle-oo\n    - byr\n- intent: thank\n  examples: |\n    - thanks!\n    - thank you\n    - thanks a lot\n    - great thanks\n    - appreciate it\n    - cool thanks\n    - Cool. Thanks\n    - Great, thanks\n    - Thank you so much\n    - Thank's!\n    - Thanks bot\n    - Thanks for that\n    - Thanks!\n    - amazing, thanks\n    - cool thank you\n    - cool, thanks\n    - danke\n    - great thanks\n    - ok thanks\n    - ok thanks\n    - ok thanks!\n    - perfect thank you\n    - thank u\n    - thank you\n    - thank you anyways\n    - thanks\n    - thanks a bunch for everything\n    - thanks a lot\n    - thanks for the help\n    - thanks you\n    - thanks!\n    - thankyou\n    - thnks\n    - thx\n    - yes thanks\n    - thanks for your information\n    - thanks f\n- intent: bot_challenge\n  examples: |\n    - are you a bot?\n    - are you a human?\n    - am I talking to a bot?\n    - am I talking to a human?\n    - you are a bot right\n    - aren't you a bot\n    - Are you a bot?\n    - are you a BOT\n    - are you a bot?\n    - are you a chatbot\n    - are you a rasa bot?\n    - are you a real bot?\n    - are you a robot\n    - are you ai\n    - are you artificial\n    - are you artificial intelligence\n    - are you bot\n    - are you bot?\n    - are you rasa bot?\n    - are you real\n    - are you real lol\n    - are you really a bot\n    - are you robot\n    - are you sure that you're a bot?\n    - bot?\n    - cuz you are a bot\n    - i guess you are a chatbot\n    - oh are you chatbot?\n    - tell me, are you a bot?\n    - what are you, a bot?\n    - you are a robot\n    - you are ai\n    - you are chatbot\n    - you're a bot\n    - you robo\n    - real bot then?\n    - are you really a bbot?\n- intent: password_reset\n  examples: |\n    - need to reset my password\n    - need help resetting my password\n    - I can't reset my password\n    - need help with my password\n    - having issues resetting my password\n    - freaking password won't work\n    - reset my password\n    - password reset\n    - forgot my password and can't reset it\n    - uh password reset help please\n    - I'm having so many problems resetting my password\n    - Can you reset my password reset\n    - My pass word isn't working for me what do I do\n    - How can I reconfigure my pass word\n    - pass word reset?\n    - forgot my pass word again what now\n    - password help fix \n    - show me how to set password again\n    - can you tell me how to change my password\n    - change pass word\n    - I forgot my password what can I do\n    - forgot my password help me reset it pls\n- intent: open_incident\n  examples: |\n    - I need to open an incident\n    - Can you open a case for me\n    - I have an issue I need to open a incident for\n    - open incident\n    - can you help me open a incident please\n    - I want to open a new incident\n    - I want to open a incident\n    - I'm having a weird issue.\n    - I'm having a problem\n    - I'm having a issue I need to open a incident for.\n    - I have a issue I need to open a case for.\n    - open an incident for aileen.mottern@example.com\n    - open an [urgent]{\"entity\": \"priority\", \"value\": \"high\"} issue\n    - I want to open an incident, but it's [low](priority) priority\n    - I need to open a helpdesk ticket. it's [really important]{\"entity\": \"priority\", \"value\": \"high\"}\n    - open an incident\n    - open an incedent\n    - i want to open an incident\n    - i wanna open a incident\n    - I want to open a ticket\n    - can I open a ticket\n    - pls help me open tix support\n    - ticket support incident open now can you do that for me\n- intent: help\n  examples: |\n    - I need help\n    - what can you help me with\n    - can you help me\n    - what can you do\n    - I need some help\n    - help me\n    - can you please help me\n    - problem\n    - big problem\n    - How can you help me\n    - How you help me?\n    - I need some help\n    - What are my options\n    - What are you able to do?\n    - What can I ask you?\n    - What can I do?\n    - What can you demo\n    - What can you do for me?\n    - What can you do?\n    - What can you tell me?\n    - What do you do\n    - anything els\n    - are there any other options?\n    - can I ask you anything else?\n    - can you do anything else?\n    - can you help me?\n    - come back\n    - cool! can I do something else here?\n    - hello what can you do for me\n    - help\n    - help me\n    - help please\n    - help pls\n    - help?\n    - hep me\n- intent: problem_email\n  examples: |\n    - my outlook application won't open\n    - I'm having issues with outlook.\n    - issues with outlook\n    - outlook application will not open\n    - there's a problem with my email\n    - something is broken with outlook\n    - I can't log in to my email\n    - can't log in to outlook\n    - my email won't let me log in\n    - i have a problem with my email\n    - can't get to slack\n    - i cant open my email\n    - i can't able to login\n    - I'm having trouble logging into my email\n    - can you help me with me with my email please\n    - what can you do about my email it's not working\n    - can you fix outlook for me I don't know what to do\n    - something isn't right with my e-mail\n    - can you help me with my e-mail account\n    - my internet mail isn't working\n    - outlook is showing me a weird message\n    - email isn't loading can you help\n- intent: inform\n  examples: |\n    - my email is test@example.com\n    - my email is abraham.lincoln@example.com\n    - name.name@example.com\n    - it is admin@example.com\n    - aileen.mottern@example.com\n    - [low](priority)\n    - [medium](priority)\n    - [high](priority)\n    - it should be a [low](priority) priority\n    - it should be [medium](priority)\n    - [escalated]{\"entity\": \"priority\", \"value\": \"high\"}\n    - [escalate]{\"entity\": \"priority\", \"value\": \"high\"}\n    - [super high](priority)\n    - john\n    - the priority is [high](priority)\n    - test@gmail.com\n    - xyz@example.com\n    - my email is ella@rasa.com\n    - abraham.lincoln@example.com\n    - steve\n    - sara@rasa.com\n    - [urgent]{\"entity\": \"priority\", \"value\": \"high\"}\n    - [critical]{\"entity\": \"priority\", \"value\": \"high\"}\n- intent: out_of_scope\n  examples: |\n    - what is the square root of 5\n    - I want to know the weather\n    - what is the meaning of life.\n    - Fridge Isn't Running\n    - my tv isn't working\n    - I want a pizza\n    - my washing machine isn't working\n    - what year is it\n    - order a pizza\n    - I want to order a pizza\n    - what is the weather today\n    - what is the weather\n    - how old are you?\n    - add two plus two\n    - Hdjejene\n    - asd\n    - title\n    - how about the forecast\n    - foolish\n    - joke\n    - Can I get a hamburger?\n    - Can YouTube talk?\n    - Can you call me back ?\n    - Can you give me your datacenter's password\n    - Can you give me your datacenter's password?\n    - Can you make sandwiches?\n    - Can you please send me an uber\n- intent: incident_status\n  examples: |\n    - I want to check if my ticket has been closed\n    - what's the status of my incident?\n    - Has the incident been closed yet?\n    - Is my ticket in progress?\n    - What has happened with my open ticket?\n    - what's going on with the incident I opened?\n    - Do I have any open incidents at the moment?\n    - Can I check the status of my open tickets?\n    - Can I see the status of the ticket I opened?\n    - Check ticket status\n    - check incident status\n    - ok, try looking it up for abraham.lincoln@example.com\n    - look up ticket status for abel.tuter@example.com\n    - my ticket status\n    - What's the status of the ticket I opened?\n    - what's my ticket status\n    - how is my ticket going\n    - an updates on my incident ticket?\n    - I opened an issue last week how is it doing now\n    - can you check the status my email is sara@rasa.com\n    - has the ticket been closed yet?\n    - is my issue still open\n- intent: affirm\n  examples: |\n    - yes\n    - yes please\n    - yes I would\n    - please do\n    - yup\n    - yep\n    - that's right\n    - indeed\n    - Yes, please\n    - yeah\n    - sure\n    - yes thanks\n    - That would be great\n    - YES\n    - YUP\n    - Yea\n    - Yeah\n    - Yeah sure\n    - Yep\n    - Yep that's fine\n    - Yep!\n    - Yepp\n    - Yes\n    - Yes I do\n    - Yes please\n    - Yes please!\n    - Yes, I accept\n- intent: deny\n  examples: |\n    - no\n    - nope\n    - no thanks\n    - not that one\n    - don't use that\n    - please no\n    - no don't do that\n    - no, use abraham.lincoln@example.com\n    - Neither\n    - Never\n    - Nevermind\n    - No thank you\n    - No, not really.\n    - No, thank you\n    - No.\n    - Nopes\n    - Not really\n    - absolutely not\n    - decline\n    - definitely not\n    - deny\n    - na\n    - nah\n    - nah I'm good\n- intent: human_handoff\n  examples: |\n    - I want a human\n    - can I speak to an agent\n    - real agent please\n    - real human\n    - chat with a live agent\n    - give me a person please\n    - i want to talk to a human\n    - can you transfer me to a human?\n    - handoff\n    - talk to a human\n    - i need to talk to a human\n    - human please\n    - i need help from a human\n    - i need help from a real human\n    - give me a human\n    - i want to talk to human\n    - i want a representative\n    - i want to talk to a person\n    - I don't wanna talk to a bot\n    - I dont like to talk to a machine\n    - I want to talk to a human\n    - I want to talk to the founders\n    - are there also humans working for your company?\n    - can I speak to a person?\n    - can i please speak to a human?\n    - can you forward me to your team\n    - can you please connect me to a real rasa employee?\n    - can you put me in touch with a human?\n    - do you have human support ?\n    - gimme a proper human\n    - give me a human now\n    - human handoff\n    - i dont wanna talk to a bot\n    - i want to speak to a real person\n    - i want to speak to customer service\n    - i want to talk to a human\n    - i want to talk to a person\n    - i want to talk to human\n    - i want to talk to someone at rasa\n    - i want to talk to someone else\n    - i want to talk to someone who is smarter than you\n    - i would like to speak to a person\n    - i'd rather speak with a real rasa employee\n    - id like to talk to a real rasa employee\n    - let me speak with a real person please\n    - let me talk to a human\n    - let me talk to a real person\n    - please give me a human\n    - service agent\n    - someone from customer care\n    - speak to a real person\n    - talking to a bot is stupid\n    - that's annoying I'd like to speak to someone real\n    - thats not helping, can i talk to human?\n    - wrong i want to speak to a human\n    - can i speak to human\n    - can i speak to your human\n    - i want to chat with human\n    - How do I talk to a human\n    - talk with a human\n    - Can i talk to a human instead\n    - nevermind.... you're not human ... I need to talk to a live person\n    - Can you get a human to assist me?\n    - Can i talk to a human?\n    - Can I talk to a human\n    - Can I speak to a human?\n    - can i speak to a human\n    - no, i want to talk to human\n    - can you hand a conversation over to a human?\n    - can I talk to human?\n    - can I talk to human\n    - talk to human\n    - i want human :(\n    - can i talk to human\n    - i want to talk to a human\n    - i want to speak to human\n    - can i talk to a real person?\n    - connect me to a real person\n    - I need a real person\n    - can i took with a real person\n    - let me speak to a real person\n    - let me speak to a real person please\n    - i want to talk to a real person\n- synonym: high\n  examples: |\n    - urgent\n    - really important\n    - escalated\n    - escalate\n"
  },
  {
    "path": "data/rules.yml",
    "content": "version: \"3.0\"\nrules:\n  - rule: handoff intent from other bot's handoff triggers greeting\n    steps:\n    - intent: handoff\n    - action: utter_greet\n\n  - rule: Ask the user to rephrase whenever they send a message with low NLU confidence\n    steps:\n    - intent: nlu_fallback\n    - action: utter_default\n\n  - rule: answer bot challenge\n    steps:\n    - intent: bot_challenge\n    - action: utter_iamabot\n\n  - rule: start open incident form\n    steps:\n    - or:\n      - intent: open_incident\n      - intent: password_reset\n      - intent: problem_email\n    - action: open_incident_form\n    - active_loop: open_incident_form\n\n  - rule: submit open incident form\n    condition:\n      - active_loop: open_incident_form\n    steps:\n    - action: open_incident_form\n    - active_loop: null\n    - action: action_open_incident\n\n  - rule: start incident status form\n    steps:\n    - intent: incident_status\n    - action: incident_status_form\n    - active_loop: incident_status_form\n\n  - rule: submit incident status form\n    condition:\n      - active_loop: incident_status_form\n    steps:\n    - action: incident_status_form\n    - active_loop: null\n    - action: action_check_incident_status\n"
  },
  {
    "path": "data/stories.yml",
    "content": "version: \"3.0\"\nstories:\n\n- story: answer out of scope\n  steps:\n  - intent: out_of_scope\n  - action: utter_out_of_scope\n\n- story: give help\n  steps:\n  - intent: help\n  - action: utter_help\n\n- story: thank\n  steps:\n  - intent: thank\n  - action: utter_welcome\n\n- story: greet + give info\n  steps:\n  - intent: greet\n  - action: utter_greet\n  - action: utter_help\n\n- story: say goodbye\n  steps:\n  - intent: goodbye\n  - action: utter_goodbye\n\n- story: open incident form interrupted\n  steps:\n  - or:\n    - intent: open_incident\n    - intent: password_reset\n    - intent: problem_email\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - intent: help\n  - action: utter_help\n  - action: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: open incident form interrupted\n  steps:\n  - or:\n    - intent: open_incident\n    - intent: password_reset\n    - intent: problem_email\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - intent: out_of_scope\n  - action: utter_out_of_scope\n  - action: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: incident status form interrupted\n  steps:\n  - intent: incident_status\n  - action: incident_status_form\n  - active_loop: incident_status_form\n  - intent: help\n  - action: utter_help\n  - action: incident_status_form\n  - active_loop: null\n  - action: action_check_incident_status\n\n- story: incident status form interrupted\n  steps:\n  - intent: incident_status\n  - action: incident_status_form\n  - active_loop: incident_status_form\n  - intent: out_of_scope\n  - action: utter_out_of_scope\n  - action: incident_status_form\n  - active_loop: null\n  - action: action_check_incident_status\n\n- story: incident status form switch to open incident\n  steps:\n  - intent: incident_status\n  - action: incident_status_form\n  - active_loop: incident_status_form\n  - or:\n    - intent: open_incident\n    - intent: password_reset\n    - intent: problem_email\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: open incident form switch to incident status form\n  steps:\n  - or:\n    - intent: open_incident\n    - intent: password_reset\n    - intent: problem_email\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - intent: incident_status\n  - action: incident_status_form\n  - active_loop: incident_status_form\n  - active_loop: null\n  - action: action_check_incident_status\n"
  },
  {
    "path": "domain.yml",
    "content": "version: '3.0'\nsession_config:\n  session_expiration_time: 0.0\n  carry_over_slots_to_new_session: true\nintents:\n- greet\n- goodbye\n- bot_challenge\n- password_reset\n- inform\n- thank\n- help\n- problem_email\n- open_incident:\n    use_entities: []\n- incident_status\n- out_of_scope\n- restart\n- affirm\n- deny\n- trigger_handoff\n- human_handoff\n- handoff\nentities:\n- email\n- priority\n- handoff_to\nslots:\n  confirm:\n    type: bool\n    influence_conversation: false\n    mappings:\n    - type: from_intent\n      intent: affirm\n      value: true\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: confirm\n    - type: from_intent\n      intent: deny\n      value: false\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: confirm\n  previous_email:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: custom\n  caller_id:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: custom\n  email:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: from_entity\n      entity: email\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: email\n      - active_loop: incident_status_form\n        requested_slot: email\n    - type: from_intent\n      intent: affirm\n      value: true\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: email\n      - active_loop: incident_status_form\n        requested_slot: email\n    - type: from_intent\n      intent: deny\n      value: false\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: email\n      - active_loop: incident_status_form\n        requested_slot: email\n    - type: from_entity\n      entity: email\n  incident_title:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: from_trigger_intent\n      intent: password_reset\n      value: Problem resetting password\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: incident_title\n    - type: from_trigger_intent\n      intent: problem_email\n      value: Problem with email\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: incident_title\n    - type: from_text\n      not_intent:\n      - incident_status\n      - bot_challenge\n      - help\n      - affirm\n      - deny\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: incident_title\n  priority:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: from_entity\n      entity: priority\n      conditions:\n      - active_loop: open_incident_form\n    - type: from_entity\n      entity: priority\n  problem_description:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: from_text\n      not_intent:\n      - incident_status\n      - bot_challenge\n      - help\n      - affirm\n      - deny\n      conditions:\n      - active_loop: open_incident_form\n        requested_slot: problem_description\n  requested_slot:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: custom\n  handoff_to:\n    type: text\n    influence_conversation: false\n    mappings:\n    - type: from_entity\n      entity: handoff_to\nresponses:\n  utter_out_of_scope:\n  - text: Sorry, I'm not sure how to respond to that. Type \"help\" for assistance.\n  utter_greet:\n  - text: Hallo! I'm your IT Helpdesk Assistant.\n  utter_goodbye:\n  - text: Goodbye!\n  utter_iamabot:\n  - text: I am a bot, powered by Rasa.\n  utter_ask_email:\n  - text: What is your email address?\n  utter_ask_incident_title:\n  - text: What should we use for the title of this incident?\n  utter_ask_problem_description:\n  - text: What is the problem description for the issue?\n  utter_ask_priority:\n  - text: What is the priority of this issue?\n    buttons:\n    - payload: /inform{\"priority\":\"low\"}\n      title: low\n    - payload: /inform{\"priority\":\"medium\"}\n      title: medium\n    - payload: /inform{\"priority\":\"high\"}\n      title: high\n  utter_no_priority:\n  - text: Sorry \"{priority}\" is not a valid priority. Please try again.\n  utter_no_email:\n  - text: Sorry, \"{email}\" isn't in our incident management system. Please try again.\n  utter_help:\n  - text: \"I can help you open a service request ticket, or check the status of your open incidents. \\nYou can ask me things like: \\n- Open an incident \\n- Help me reset my password \\n- I'm having a issue with my email \\n- What's the status of the ticket I opened?\"\n  utter_welcome:\n  - text: You're welcome!\n  utter_default:\n  - text: I didn't quite understand that. Could you rephrase?\n  utter_ask_use_previous_email:\n  - text: Would you like to use the last email address you used, {previous_email}?\n  utter_ask_confirm:\n  - text: \"Should I open an incident with the following details? \\n    email: {email} \\n    problem description: {problem_description} \\n    title: {incident_title} \\n    priority: {priority}\"\n    buttons:\n    - title: Yes\n      payload: /affirm\n    - title: No, cancel the incident\n      payload: /deny\n  utter_incident_creation_canceled:\n  - text: Alright, I have cancelled the incident.\n  utter_ask_whatelse:\n  - text: What else can I help you with?\n  utter_ask_handoff:\n  - text: It looks like you want to be transferred to a human agent.\n  utter_handoff:\n  - text: Alright, I'll try to transfer you.\n  utter_wouldve_handed_off:\n  - text: If you were talking to me via chatroom, I would have handed you off to {handoffhost}.\n  utter_no_handoff:\n  - text: Since you haven't configured a host to hand off to, I can't send you anywhere!\nforms:\n  open_incident_form:\n    ignored_intents: []\n    required_slots:\n    - email\n    - priority\n    - problem_description\n    - incident_title\n    - confirm\n  incident_status_form:\n    ignored_intents: []\n    required_slots:\n    - email\nactions:\n- action_ask_email\n- action_check_incident_status\n- action_handoff\n- action_handoff_options\n- action_open_incident\n- validate_open_incident_form\n- validate_incident_status_form\n"
  },
  {
    "path": "endpoints.yml",
    "content": "# This file contains the different endpoints your bot can use.\n\n# Server where the models are pulled from.\n# https://rasa.com/docs/rasa/user-guide/running-the-server/#fetching-models-from-a-server/\n\n#models:\n#  url: http://my-server.com/models/default_core@latest\n#  wait_time_between_pulls:  10   # [optional](default: 100)\n\n# Server which runs your custom actions.\n# https://rasa.com/docs/rasa/core/actions/#custom-actions/\n\naction_endpoint:\n url: \"http://localhost:5055/webhook\"\n\n# Tracker store which is used to store the conversations.\n# By default the conversations are stored in memory.\n# https://rasa.com/docs/rasa/api/tracker-stores/\n\n#tracker_store:\n#    type: redis\n#    url: <host of the redis instance, e.g. localhost>\n#    port: <port of your redis instance, usually 6379>\n#    db: <number of your database within redis, e.g. 0>\n#    password: <password used for authentication>\n#    use_ssl: <whether or not the communication is encrypted, default false>\n\n#tracker_store:\n#    type: mongod\n#    url: <url to your mongo instance, e.g. mongodb://localhost:27017>\n#    db: <name of the db within your mongo instance, e.g. rasa>\n#    username: <username used for authentication>\n#    password: <password used for authentication>\n\n# Event broker which all conversation events should be streamed to.\n# https://rasa.com/docs/rasa/api/event-brokers/\n\n#event_broker:\n#  url: localhost\n#  username: username\n#  password: password\n#  queue: queue\n"
  },
  {
    "path": "format_results.py",
    "content": "from pytablewriter import MarkdownTableWriter\nimport json\n\n\ndef intent_table():\n    writer = MarkdownTableWriter()\n    writer.table_name = \"Intent Cross-Validation Results (5 folds)\"\n\n    with open(\"results/intent_report.json\", \"r\") as f:\n        data = json.loads(f.read())\n\n    cols = [\"support\", \"f1-score\", \"confused_with\"]\n    writer.headers = [\"class\"] + cols\n\n    classes = list(data.keys())\n    try:\n        classes.remove(\"accuracy\")\n    except:\n        pass\n    classes.sort(key=lambda x: data[x][\"support\"], reverse=True)\n\n    def format_cell(data, c, k):\n        if not data[c].get(k):\n            return \"N/A\"\n        if k == \"confused_with\":\n            return \", \".join([f\"{k}({v})\" for k, v in data[c][k].items()])\n        else:\n            return data[c][k]\n\n    writer.value_matrix = [\n        [c] + [format_cell(data, c, k) for k in cols] for c in classes\n    ]\n\n    return writer.dumps()\n\n\ndef entity_table():\n\n    writer = MarkdownTableWriter()\n    writer.table_name = \"Entity Cross-Validation Results (5 folds)\"\n\n    with open(\"results/DIETClassifier_report.json\", \"r\") as f:\n        data = json.loads(f.read())\n\n    cols = [\"support\", \"f1-score\", \"precision\", \"recall\"]\n    writer.headers = [\"entity\"] + cols\n\n    classes = list(data.keys())\n    classes.sort(key=lambda x: data[x][\"support\"], reverse=True)\n\n    def format_cell(data, c, k):\n        if not data[c].get(k):\n            return \"N/A\"\n        else:\n            return data[c][k]\n\n    writer.value_matrix = [\n        [c] + [format_cell(data, c, k) for k in cols] for c in classes\n    ]\n\n    return writer.dumps()\n\n\nintents = intent_table()\nentities = entity_table()\n\nwith open(\"results.md\", \"w\") as f:\n    f.write(intents)\n    f.write(\"\\n\\n\\n\")\n    f.write(entities)\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[tool.black]\nline-length = 79\ninclude = '\\.pyi?$'\nexclude = '''\n/(\n    \\.git\n  | \\.hg\n  | \\.mypy_cache\n  | \\.tox\n  | \\.venv\n  | _build\n  | buck-out\n  | build\n  | dist\n)/\n'''\n"
  },
  {
    "path": "requirements-dev.txt",
    "content": "-r requirements.txt\n\n# lint/format/types\nblack==19.10b0\nflake8==3.7.8\npytype==2019.7.11\npre-commit"
  },
  {
    "path": "requirements.txt",
    "content": "rasa~=3.0.0\nrasa-sdk~=3.0.0  # if you change this, make sure to change the Dockerfile to match\n-r actions/requirements-actions.txt\n"
  },
  {
    "path": "tests/test_conversations.yml",
    "content": "version: \"2.0\"\nstories:\n- story: bot challenge\n  steps:\n  - intent: bot_challenge\n    user: |-\n      Are you a bot?\n  - action: utter_iamabot\n\n- story: out of scope\n  steps:\n  - intent: out_of_scope\n    user: |-\n      I want a pizza\n  - action: utter_out_of_scope\n\n- story: open incident\n  steps:\n  - intent: greet\n    user: |-\n      hello\n  - action: utter_greet\n  - action: utter_help\n  - intent: open_incident\n    user: |-\n      I need to open an incident\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: open password reset incident\n  steps:\n  - intent: password_reset\n    user: |-\n      I'm having issues with my password\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: email incident\n  steps:\n  - intent: greet\n    user: |-\n      hello\n  - action: utter_greet\n  - action: utter_help\n  - intent: problem_email\n    user: |-\n      I have a problem with my email\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: interrupted\n  steps:\n  - intent: problem_email\n    user: |-\n      I have a problem with my email\n  - action: open_incident_form\n  - active_loop: open_incident_form\n  - intent: help\n  - action: utter_help\n  - action: open_incident_form\n  - active_loop: null\n  - action: action_open_incident\n\n- story: greet + thank\n  steps:\n  - intent: greet\n    user: |-\n      Hey there\n  - action: utter_greet\n  - action: utter_help\n  - intent: thank\n    user: |-\n      Awesome, thanks!\n  - action: utter_welcome\n\n- story: user requests a human handoff\n  steps:\n  - intent: human_handoff\n    user: |-\n      I want to talk to a person now\n  - action: utter_ask_handoff\n  - action: action_handoff_options\n  - intent: deny\n    user: |-\n      uh no\n  - action: utter_ask_whatelse\n\n- story: User says something out of scope\n  steps:\n  - intent: out_of_scope\n    user: |-\n      Can you get me a pizza\n  - action: utter_out_of_scope\n\n- story: trigger handoff\n  steps:\n  - intent: human_handoff\n    user: |-\n      give me a human\n  - action: utter_ask_handoff\n  - action: action_handoff_options\n  - intent: trigger_handoff\n  - action: action_handoff\n\n- story: Test fallback\n  steps:\n  - intent: nlu_fallback\n  - action: utter_default\n\n- story: incident status happy path \n  steps:\n  - intent: greet\n    user: |-\n      Hey there\n  - action: utter_greet\n  - action: utter_help\n  - intent: incident_status\n    user: |-\n      Can you check the status of my incident\n  - action: incident_status_form\n  - active_loop: incident_status_form\n  - active_loop: null\n  - action: action_check_incident_status\n\n"
  }
]