├── .angular-cli.json ├── .cfignore ├── .dockerignore ├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile ├── Jenkinsfile ├── LICENSE ├── README.md ├── buildPackage.sh ├── chart └── casewcsbroker │ ├── .helmignore │ ├── Chart.yaml │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── configmap.yaml │ ├── deployment.yaml │ ├── ingress.yaml │ └── service.yaml │ ├── values-temp.yaml │ └── values.yaml ├── client ├── app │ ├── advisor │ │ ├── advisor.component.ts │ │ ├── advisor.css │ │ ├── advisor.service.ts │ │ └── advisorMain.html │ ├── app.component.html │ ├── app.component.ts │ ├── app.module.ts │ ├── conv │ │ ├── Sentence.ts │ │ ├── conversation.component.ts │ │ ├── conversation.css │ │ ├── conversation.html │ │ └── conversation.service.ts │ ├── home.component.css │ ├── home.component.html │ └── home.component.ts ├── assets │ └── images │ │ ├── tree-sm.png │ │ └── watson-globe.png ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── typings.d.ts ├── doc ├── cloudant-cred.png ├── define-responses.png ├── demo │ ├── demo-home.png │ ├── demoscript.md │ └── it-support-bot.png ├── demoflow.md ├── design │ ├── README.md │ ├── empathy-map.png │ ├── itsupport-persona.png │ └── syst-ctx.png ├── dialog.png ├── icp │ ├── README.md │ └── cyan-on-icp.png ├── integrate-bpm.md ├── istio.md ├── persistence.md ├── readme │ ├── WCS-ra.png │ ├── angular2-comps.png │ ├── angular2-nodejs.png │ └── trigger-from-wcs.png ├── tutorial │ ├── Add-condition.png │ ├── Add-greetings.png │ ├── Ask-Watson.png │ ├── README-new.md │ ├── README.md │ ├── README.older.md │ ├── add-app-acc-node.png │ ├── add-child.png │ ├── api-credential.png │ ├── app-access-conditions.png │ ├── bmx-conv-tool.png │ ├── bmx-watson-serv.png │ ├── byod-node1.png │ ├── byod-resp.png │ ├── byod-ut.png │ ├── byod.png │ ├── click-url.png │ ├── device-brand.png │ ├── device-type.png │ ├── get-parameters.png │ ├── get-product-name.png │ ├── goodbyes-intent.png │ ├── greetings.png │ ├── no-product-name.png │ ├── slot-enabled.png │ ├── supplier-intent.png │ ├── supplier-node-no.png │ ├── supplier-node-yes.png │ ├── supplier-node.png │ ├── trigger-process.png │ ├── tryitout.png │ ├── ut-app-abc.png │ ├── wcs-build-intents.png │ ├── wcs-conv-greeting.png │ ├── wcs-conv-wksp.png │ ├── wcs-dev-tasks.png │ ├── wcs-diag-abc-ut.png │ ├── wcs-diag-access.png │ ├── wcs-diag-add-node.png │ ├── wcs-diag-bool.png │ ├── wcs-diag-greeting.png │ ├── wcs-diag-ut.png │ ├── wcs-dialog.png │ ├── wcs-entities-panel.png │ ├── wcs-entities.png │ ├── wcs-intent-question.png │ ├── wcs-otherwise.png │ ├── wcs-otherwisejson.png │ ├── wcs-ra.png │ ├── wcs-training.png │ ├── wcs-two-nodes.png │ ├── wcs-view.png │ └── wcs-wkp.png ├── use-apis.md ├── watson_conversations_icon.png ├── wcs-broker.yaml ├── wcs-save-cloudant.png ├── wcs-save-on-prem.png └── wds-itg.md ├── manifest.yml ├── package-lock.json ├── package.json ├── server ├── config │ ├── config-templ.json │ └── config.json ├── routes │ ├── api.js │ └── features │ │ ├── conversation.js │ │ ├── persist.js │ │ ├── slack-listener.js │ │ └── supplier-bpm-client.js └── server.js ├── test ├── testAdvisor.js └── testNodeServer.js └── wcs-workspace ├── ITSupport-Entities.csv ├── ITSupport-Intents.csv ├── ITsupport-workspace.json └── sodb-workspace.json /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "itsupport-app" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "client", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "e2e": { 33 | "protractor": { 34 | "config": "./protractor.conf.js" 35 | } 36 | }, 37 | "lint": [ 38 | { 39 | "project": "client/tsconfig.app.json" 40 | }, 41 | { 42 | "project": "client/tsconfig.spec.json" 43 | }, 44 | { 45 | "project": "e2e/tsconfig.e2e.json" 46 | } 47 | ], 48 | "test": { 49 | "karma": { 50 | "config": "./karma.conf.js" 51 | } 52 | }, 53 | "defaults": { 54 | "styleExt": "css", 55 | "component": {} 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /.cfignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | vcap-local.json 3 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **.md 2 | docs 3 | build 4 | .git 5 | .gitignore 6 | Jenkinsfile 7 | README.md 8 | helm 9 | test 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # helm 12 | chart/casewcsbroker*.tgz 13 | 14 | # IDEs and editors 15 | /.idea 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # IDE - VSCode 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | 30 | # misc 31 | /.sass-cache 32 | /connect.lock 33 | npm-debug.log 34 | testem.log 35 | /typings 36 | /helm/casewcsbroker/values.yaml 37 | /server/config/config.json 38 | 39 | 40 | #System Files 41 | .DS_Store 42 | Thumbs.db 43 | 44 | # tool 45 | ClientBpm.js 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to IBM Cloud Architecture reference applications 2 | Anyone can contribute to IBM Cloud Architecture reference applications and their associated projects, whether you are an IBMer or not. 3 | We welcome your collaboration & contributions happily, as our reference applications are meant to reflect your real world scenarios. 4 | There are multiple ways to contribute: report bugs and improvement suggestions, improve documentation, and contribute code. 5 | 6 | 7 | ## Bug reports, documentation changes, and feature requests 8 | 9 | If you would like to contribute your experience with an IBM Cloud Architecture project back to the project in the form of encountered bug reports, necessary documentation changes, or new feature requests, this can be done through the use of the repository's [**Issues**](#) list. 10 | 11 | Before opening a new issue, please reference the existing list to make sure a similar or duplicate item does not already exist. Otherwise, please be as explicit as possible when creating the new item and be sure to include the following: 12 | 13 | - **Bug reports** 14 | - Specific Project Version 15 | - Deployment environment 16 | - A minimal, but complete, setup of steps to recreate the problem 17 | - **Documentation changes** 18 | - URL to existing incorrect or incomplete documentation (either in the project's GitHub repo or external product documentation) 19 | - Updates required to correct current inconsistency 20 | - If possible, a link to a project fork, sample, or workflow to expose the gap in documentation. 21 | - **Feature requests** 22 | - Complete description of project feature request, including but not limited to, components of the existing project that are impacted, as well as additional components that may need to be created. 23 | - A minimal, but complete, setup of steps to recreate environment necessary to identify the new feature's current gap. 24 | 25 | The more explicit and thorough you are in opening GitHub Issues, the more efficient your interaction with the maintainers will be. When creating the GitHub Issue for your bug report, documentation change, or feature request, be sure to add as many relevant labels as necessary (that are defined for that specific project). These will vary by project, but will be helpful to the maintainers in quickly triaging your new GitHub issues. 26 | 27 | ## Code contributions 28 | 29 | We really value contributions, and to maximize the impact of code contributions, we request that any contributions follow the guidelines below. If you are new to open source contribution and would like some more pointers or guidance, you may want to check out [**Your First PR**](http://yourfirstpr.github.io/) and [**First Timers Only**](https://www.firsttimersonly.com/). These are a few projects that help on-board new contributors to the overall process. 30 | 31 | ### Coding and Pull Requests best practices 32 | - Please ensure you follow the coding standard and code formatting used throughout the existing code base. 33 | - This may vary project by project, but any specific diversion from normal language standards will be explicitly noted. 34 | - One feature / bug fix / documentation update per pull request 35 | - Always pull the latest changes from upstream and rebase before creating any pull request. 36 | - New pull requests should be created against the `integration` branch of the repository, if available. 37 | - This ensures new code is included in full-stack integration tests before being merged into the `master` branch 38 | - All new features must be accompanied by associated tests. 39 | - Make sure all tests pass locally before submitting a pull request. 40 | - Include tests with every feature enhancement, improve tests with every bug fix 41 | 42 | ### Github and git flow 43 | 44 | The internet is littered with guides and information on how to use and understand git. 45 | However, here's a compact guide that follows the suggested workflow 46 | 47 | ![Github flow](https://ibm-cloud-architecture.github.io/assets/img/github_flow.png) 48 | 49 | 1. Fork the desired repo in github. 50 | 51 | 2. Clone your repo to your local computer. 52 | 53 | 3. Add the upstream repository 54 | 55 | Note: Guide for step 1-3 here: [forking a repo](https://help.github.com/articles/fork-a-repo/) 56 | 57 | 4. Create new development branch off the targeted upstream branch. This will often be `master`. 58 | 59 | ``` 60 | git checkout -b master 61 | ``` 62 | 63 | 5. Do your work: 64 | - Write your code 65 | - Write your tests 66 | - Pass your tests locally 67 | - Commit your intermediate changes as you go and as appropriate 68 | - Repeat until satisfied 69 | 70 | 6. Fetch latest upstream changes (in case other changes had been delivered upstream while you were developing your new feature). 71 | 72 | ``` 73 | git fetch upstream 74 | ``` 75 | 7. Rebase to the latest upstream changes, resolving any conflicts. This will 'replay' your local commits, one by one, after the changes delivered upstream while you were locally developing, letting you manually resolve any conflict. 76 | 77 | ``` 78 | git branch --set-upstream-to=upstream/master 79 | git rebase 80 | ``` 81 | Instructions on how to manually resolve a conflict and commit the new change or skip your local replayed commit will be presented on screen by the git CLI. 82 | 83 | 8. Push the changes to your repository 84 | 85 | ``` 86 | git push origin 87 | ``` 88 | 89 | 9. Create a pull request against the same targeted upstream branch. 90 | 91 | [Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) 92 | 93 | Once the pull request has been reviewed, accepted and merged into the main github repository, you should synchronise your remote and local forked github repository `master` branch with the upstream master branch. To do so: 94 | 95 | 10. Pull to your local forked repository the latest changes upstream (that is, the pull request). 96 | 97 | ``` 98 | git pull upstream master 99 | ``` 100 | 101 | 11. Push those latest upstream changes pulled locally to your remote forked repository. 102 | 103 | ``` 104 | git push origin master 105 | ``` 106 | 107 | ### What happens next? 108 | - All pull requests will be automatically built and unit tested by travis-ci, when implemented by that specific project. 109 | - You can determine if a given project is enabled for travis-ci unit tests by the existence of a `.travis.yml` file in the root of the repository or branch. 110 | - When in use, all travis-ci unit tests must pass completely before any further review or discussion takes place. 111 | - The repository maintainer will then inspect the commit and, if accepted, will pull the code into the upstream branch. 112 | - Should a maintainer or reviewer ask for changes to be made to the pull request, these can be made locally and pushed to your forked repository and branch. 113 | - Commits passing this stage will make it into the next release cycle for the given project. 114 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | MAINTAINER https://github.com/ibm-cloud-architecture - IBM - Jerome Boyer 3 | 4 | COPY . /wcsbroker 5 | WORKDIR /wcsbroker 6 | # RUN npm install && \ 7 | # npm install -g @angular/cli && \ 8 | # npm run build 9 | ENV PORT 3001 10 | EXPOSE 3001 11 | 12 | CMD node server/server.js 13 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('build') { 5 | steps { 6 | sh './buildPackage.sh' 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /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, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the 13 | copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other 16 | entities that control, are controlled by, or are under common control with 17 | that entity. For the purposes of this definition, "control" means (i) the 18 | power, direct or indirect, to cause the direction or management of such 19 | entity, whether by contract or otherwise, or (ii) ownership of 20 | fifty percent (50%) or more of the outstanding shares, or (iii) beneficial 21 | ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity exercising 24 | 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 source, 28 | and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation 31 | or translation of a Source form, including but not limited to compiled 32 | object code, generated documentation, and conversions to 33 | other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or Object 36 | form, made available under the License, as indicated by a copyright notice 37 | that is included in or attached to the work (an example is provided in the 38 | Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object form, 41 | that is based on (or derived from) the Work and for which the editorial 42 | revisions, annotations, elaborations, or other modifications represent, 43 | as a whole, an original work of authorship. For the purposes of this 44 | License, Derivative Works shall not include works that remain separable 45 | from, or merely link (or bind by name) to the interfaces of, the Work and 46 | Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including the original 49 | version of the Work and any modifications or additions to that Work or 50 | Derivative Works thereof, that is intentionally submitted to Licensor for 51 | inclusion in the Work by the copyright owner or by an individual or 52 | Legal Entity authorized to submit on behalf of the copyright owner. 53 | For the purposes of this definition, "submitted" means any form of 54 | electronic, verbal, or written communication sent to the Licensor or its 55 | representatives, including but not limited to communication on electronic 56 | mailing lists, source code control systems, and issue tracking systems 57 | that are managed by, or on behalf of, the Licensor for the purpose of 58 | discussing and improving the Work, but excluding communication that is 59 | conspicuously marked or otherwise designated in writing by the copyright 60 | owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity on 63 | behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. 67 | 68 | Subject to the terms and conditions of this License, each Contributor 69 | hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 70 | royalty-free, irrevocable copyright license to reproduce, prepare 71 | Derivative Works of, publicly display, publicly perform, sublicense, 72 | and distribute the Work and such Derivative Works in 73 | Source or Object form. 74 | 75 | 3. Grant of Patent License. 76 | 77 | Subject to the terms and conditions of this License, each Contributor 78 | hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 79 | royalty-free, irrevocable (except as stated in this section) patent 80 | license to make, have made, use, offer to sell, sell, import, and 81 | otherwise transfer the Work, where such license applies only to those 82 | patent claims licensable by such Contributor that are necessarily 83 | infringed by their Contribution(s) alone or by combination of their 84 | Contribution(s) with the Work to which such Contribution(s) was submitted. 85 | If You institute patent litigation against any entity (including a 86 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 87 | Contribution incorporated within the Work constitutes direct or 88 | contributory patent infringement, then any patent licenses granted to 89 | You under this License for that Work shall terminate as of the date such 90 | litigation is filed. 91 | 92 | 4. Redistribution. 93 | 94 | You may reproduce and distribute copies of the Work or Derivative Works 95 | thereof in any medium, with or without modifications, and in Source or 96 | Object form, provided that You meet the following conditions: 97 | 98 | 1. You must give any other recipients of the Work or Derivative Works a 99 | copy of this License; and 100 | 101 | 2. You must cause any modified files to carry prominent notices stating 102 | that You changed the files; and 103 | 104 | 3. You must retain, in the Source form of any Derivative Works that You 105 | distribute, all copyright, patent, trademark, and attribution notices from 106 | the Source form of the Work, excluding those notices that do not pertain 107 | to any part of the Derivative Works; and 108 | 109 | 4. If the Work includes a "NOTICE" text file as part of its distribution, 110 | then any Derivative Works that You distribute must include a readable copy 111 | of the attribution notices contained within such NOTICE file, excluding 112 | those notices that do not pertain to any part of the Derivative Works, 113 | in at least one of the following places: within a NOTICE text file 114 | distributed as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, within a 116 | display generated by the Derivative Works, if and wherever such 117 | third-party notices normally appear. The contents of the NOTICE file are 118 | for informational purposes only and do not modify the License. 119 | You may add Your own attribution notices within Derivative Works that You 120 | distribute, alongside or as an addendum to the NOTICE text from the Work, 121 | provided that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and may 125 | provide additional or different license terms and conditions for use, 126 | reproduction, or distribution of Your modifications, or for any such 127 | Derivative Works as a whole, provided Your use, reproduction, and 128 | distribution of the Work otherwise complies with the conditions 129 | stated in this License. 130 | 131 | 5. Submission of Contributions. 132 | 133 | Unless You explicitly state otherwise, any Contribution intentionally 134 | submitted for inclusion in the Work by You to the Licensor shall be under 135 | the terms and conditions of this License, without any additional 136 | terms or conditions. Notwithstanding the above, nothing herein shall 137 | supersede or modify the terms of any separate license agreement you may 138 | have executed with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. 141 | 142 | This License does not grant permission to use the trade names, trademarks, 143 | service marks, or product names of the Licensor, except as required for 144 | reasonable and customary use in describing the origin of the Work and 145 | reproducing the content of the NOTICE file. 146 | 147 | 7. Disclaimer of Warranty. 148 | 149 | Unless required by applicable law or agreed to in writing, Licensor 150 | provides the Work (and each Contributor provides its Contributions) 151 | on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 152 | either express or implied, including, without limitation, any warranties 153 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS 154 | FOR A PARTICULAR PURPOSE. You are solely responsible for determining the 155 | appropriateness of using or redistributing the Work and assume any risks 156 | associated with Your exercise of permissions under this License. 157 | 158 | 8. Limitation of Liability. 159 | 160 | In no event and under no legal theory, whether in tort 161 | (including negligence), contract, or otherwise, unless required by 162 | applicable law (such as deliberate and grossly negligent acts) or agreed 163 | to in writing, shall any Contributor be liable to You for damages, 164 | including any direct, indirect, special, incidental, or consequential 165 | damages of any character arising as a result of this License or out of 166 | the use or inability to use the Work (including but not limited to damages 167 | for loss of goodwill, work stoppage, computer failure or malfunction, 168 | or any and all other commercial damages or losses), even if such 169 | Contributor has been advised of the possibility of such damages. 170 | 171 | 9. Accepting Warranty or Additional Liability. 172 | 173 | While redistributing the Work or Derivative Works thereof, You may choose 174 | to offer, and charge a fee for, acceptance of support, warranty, 175 | indemnity, or other liability obligations and/or rights consistent with 176 | this License. However, in accepting such obligations, You may act only 177 | on Your own behalf and on Your sole responsibility, not on behalf of any 178 | other Contributor, and only if You agree to indemnify, defend, and hold 179 | each Contributor harmless for any liability incurred by, or claims 180 | asserted against, such Contributor by reason of your accepting any such 181 | warranty or additional liability. 182 | 183 | END OF TERMS AND CONDITIONS 184 | 185 | APPENDIX: How to apply the Apache License to your work 186 | 187 | To apply the Apache License to your work, attach the following boilerplate 188 | notice, with the fields enclosed by brackets "[]" replaced with your own 189 | identifying information. (Don't include the brackets!) The text should be 190 | enclosed in the appropriate comment syntax for the file format. We also 191 | recommend that a file or class name and description of purpose be included 192 | on the same "printed page" as the copyright notice for easier 193 | identification within third-party archives. 194 | 195 | Copyright {{ year }} {{ organization }} 196 | 197 | Licensed under the Apache License, Version 2.0 (the "License"); 198 | you may not use this file except in compliance with the License. 199 | You may obtain a copy of the License at 200 | 201 | http://www.apache.org/licenses/LICENSE-2.0 202 | 203 | Unless required by applicable law or agreed to in writing, software 204 | distributed under the License is distributed on an "AS IS" BASIS, 205 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 206 | or implied. See the License for the specific language governing 207 | permissions and limitations under the License. 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cognitive Architecture: Conversation Broker 2 | This project offers a set of simple APIs in front of Watson Conversation to be consumed by your web interface, your mobile app, or micro service or even a business process running on [IBM BPM on Cloud](http://www-03.ibm.com/software/products/en/business-process-manager-cloud). It is implemented as a micro service, using resiliency and light weight implementation, packaging and deployment model. 3 | 4 | This project is part of the **IBM Cognitive Reference Architecture** compute model available at https://github.com/ibm-cloud-architecture/refarch-cognitive. 5 | # Table of Contents 6 | * [Introduction](#introduction) 7 | * [Skill set](https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker#expected-knowledge) 8 | * [Tutorial](doc/tutorial/README.md) 9 | * [Pre-requisites](https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker#prerequisites) 10 | * [Design considerations](./doc/design/README.md) 11 | * [Code explanation](#code-explanation) 12 | * [Build and Deploy](https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker#build-and-deploy) 13 | * [Compendium](https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker#compendium) 14 | 15 | # Introduction 16 | This implementation addresses multiple facets for developing a cloud native cognitive app: 17 | * How to facade Watson Conversation to support service orchestration, persistence, conversations chaining... and any business logic needed to support an integrated hybrid chat bot. 18 | * How to implement an 'IT Support' chat bot with Watson Conversation, with an exported [workspace](wcs-workspace/ITsupport-workspace.json). This is a common business requirement to use chat bot to address internal staff queries about IT applications or hardware. A second workspace is also delivered to support conversation inside a BPM coach to ask for help in the context of a process ([Supplier on boarding help](wcs-workspace/ITsupport-workspace.json)). 19 | * A complete set of aspects to support production deployment like logging, monitoring, resiliency, security. 20 | 21 | The project includes an [angular js](http://angular.io) web application to illustrate a simple conversation chat user interface which itself uses the broker APIs. The project is designed as a micro service, deployable as a containerized application on [IBM Bluemix](http://www.bluemix.net) [Kubernetes](https://www.ibm.com/blogs/bluemix/2017/03/kubernetes-now-available-ibm-bluemix-container-service/) Cluster. The concept of broker is presented in the [IBM Cognitive Reference Architecture for Conversation](https://www.ibm.com/devops/method/content/architecture/cognitiveArchitecture#engagementDomain), specially illustrated as 'Conversation Logic' in the figure below: 22 | 23 | ![WCS Reference Architecture](doc/readme/WCS-ra.png) 24 | 25 | ## Current Version 26 | The current version is used for IBM internal [training](./doc/tutorial/README.md) and demonstration: it is functional and supports the following features: 27 | * User interface is done with [Angular js](angular.io) and support a simple input field to enter questions to Watson and get a chat type of user experience. There are two interface versions: one with tutorial and one without. 28 | * The supported questions depend on the Intents defined in Watson Conversation. Two proposed Watson Conversation workspaces are available under the folder [wcs-workspace](./wcs-workspace) as JSON files: 29 | * one to support the CASE Inc IT support chat bot solution. 30 | * one to support the supplier on boarding business process contextual help. 31 | * one to advise user for migration to cloud. 32 | * Support the Backend for Front end pattern with a nodejs/ expressjs application which exposes a HTTP POST /api/conversation end point. 33 | * Support the integration to BPM on cloud by triggering a business process via SOAP request by getting customer name and product name from the conversation. See explanation [here](doc/integrate-bpm.md) 34 | * Support persisting the conversation inside a document oriented database like [Cloudand DB on bluemix](https://console.ng.bluemix.net/catalog/services/cloudant-nosql-db). See detail [here](doc/persistence.md) 35 | 36 | You may fork this project for your own purpose and develop on top of it. If you want to contribute please submit a pull request on this repository, see [rule of contribution](https://github.com/ibm-cloud-architecture/refarch-cognitive#contribute) 37 | 38 | 39 | # Expected knowledge 40 | On top of the [common](https://github.com/ibm-cloud-architecture/refarch-cognitive#Expected-skill-set) skill set defined for *cyan compute* the reader needs to get some good understanding of the following concepts: 41 | * Know how to design a Watson Conversation, if not familiar doing the attached [step by step tutorial](./doc/tutorial/README.md) should help you developing the Watson Conversation workspace with intent, entities definition and conversation flow needed for the IT support demonstration. 42 | * The following [article](doc/persistence.md) addresses how to persist the conversation in Cloud based document database like Cloudant or an on-premise database. 43 | 44 | # Prerequisites 45 | 46 | * You need your own github.com account 47 | * You need to have a Bluemix account, and know how to use cloud foundry command line interface to push the application to Bluemix. 48 | * You need to have [nodejs](https://nodejs.org/en/) installed on your computer with the [npm](https://www.npmjs.com/) installer tool. 49 | * Clone current repository, or if you want to work on the code, fork it in your own github repository and then clone your forked repository on your local computer. 50 | 51 | ``` 52 | git clone https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker 53 | cd refarch-cognitive-conversation-broker 54 | npm install 55 | ``` 56 | * You need to install Angular 2 command line interface [cli.angular.io](http://cli.angular.io) tool ``` sudo npm install -g @angular/cli``` on Mac for example. 57 | * You need to install [nodemon](https://nodemon.io/) with ``` sudo npm install -g nodemo``` 58 | 59 | 60 | 61 | # Code explanation 62 | The project is split into two parts: the client side that is an Angular 2 single page application (code under client folder) and the server which is an expressjs app with code under folder: 63 | ![Component view](doc/readme/angular2-comps.png) 64 | 65 | ## Demonstration script 66 | If you want to see the conversation working go to the [deployed app](http://refarch-wcs-broker.mybluemix.net/) and run the following [demonstration script](doc/demo/demoscript.md). 67 | 68 | ## Server side 69 | The code is under the *server/* folder. The server.js is the main javascript entry point code, started when the *npm start* command is executed. 70 | The server uses *expressjs*, serves a index.html page for the angular front end, and delegates to another javascript module (routes/api.js) any HTTP calls to url starting with **/api/***. 71 | Expressjs is a routing and middleware web framework used to simplify web server implementation in nodejs. An app is a series of middleware function calls. [See expressjs.com](http://expressjs.com/en/guide/using-middleware.html) for more details. 72 | The cfenv is used to deploy the application in Bluemix as a cloud foundry application. 73 | 74 | ```javascript 75 | const express = require('express'); 76 | const app = express(); 77 | 78 | var config = require('./config/config.json'); 79 | require('./routes/api')(app,config) 80 | 81 | / Catch all other routes and return the index file 82 | app.get('*', (req, res) => { 83 | res.sendFile(path.join(__dirname, '../dist/index.html')); 84 | }); 85 | 86 | // get the app environment from Cloud Foundry 87 | var appEnv = cfenv.getAppEnv(); 88 | /** 89 | * Get port from environment or local config parameters. 90 | */ 91 | const port = process.env.PORT || config.port; 92 | .. 93 | 94 | ``` 95 | When a user enters the hostname url without any web context, the index.html page will be presented. Any URL with the pattern http://hostname/api will be supported by api.js script. 96 | 97 | *dist* is a folder for scripts built with @angular/cli **ng build** command, so it contains the user interface generated code. 98 | 99 | This code needs to be improved with authentication and authorization controls. 100 | 101 | The package.json file specifies the minimum dependencies for the server and client codes. The interesting dependencies is the watson-developer-cloud module needed to interact with any on cloude Watson service. 102 | ``` 103 | "dependencies": { 104 | ... 105 | "body-parser": "^1.15.0", 106 | "cookie-parser": "^1.4.1", 107 | "express": "^4.13.x", 108 | "express-session": "1.13.0", 109 | "request": "^2.72.0", 110 | "watson-developer-cloud": "^2.x", 111 | ``` 112 | 113 | The [api.js](./server/routes/api.js) defines the URLs to be used by *angular 2* AJAX calls. The user interactions in the Browser are supported by Angular 2, with its own Router mechanism and with its DOM rendering capabilities via directives and components. When there is a need to send data to the server for calling one of the Cognitive Service, an AJAX calls is done and the server will respond asynchronously later. 114 | 115 | *api.js* uses the [express.js](http://https://expressjs.com) middleware router to handle URL mapping. 116 | 117 | ```javascript 118 | module.exports = function(app,config) { 119 | 120 | // Support REST call 121 | app.post('/api/conversation',function(req,res){ 122 | if(!req.body){ 123 | res.status(400).send({error:'no post body'}); 124 | } else { 125 | if (req.body.context.type !== undefined && req.body.context.type == "sodb") { 126 | conversation.sobdConversation(config,req,res); 127 | } else { 128 | conversation.itSupportConversation(config,req,res); 129 | } 130 | } 131 | }); 132 | } 133 | ``` 134 | 135 | On the HTTP POST to /api/conversation the text is in the request body, and can be sent to Watson conversation. The code here is illustrating how to support different conversations from the user interface: for demonstration purpose the base interface is using the IT support conversation, but there is a second conversation for the Supplier on boarding business process (sobd) to use, so a second interface is used, and the context.type variable will help to understand what conversation is called. 136 | 137 | The second piece of interesting code is the Watson Conversation Broker under routes/features/conversation.js 138 | 139 | This code is straight forward, it uses the configuration given as parameter then interacts with Watson cloud developer javascript APIs. 140 | 141 | ```javascript 142 | module.exports = { 143 | /** 144 | Specific logic for the conversation related to IT support. From the response the 145 | code could dispatch to BPM. 146 | It persists the conversation to remote cloudant DB 147 | */ 148 | itSupportConversation : function(config,req,res) { 149 | // this logic applies when the response is expected to be a value to be added to a context variable 150 | // the context variable name was set by the conversation dialog 151 | if (req.body.context.action === "getVar") { 152 | req.body.context[req.body.context.varname] = req.body.text; 153 | } 154 | sendMessage(config,req,config.conversation.workspace1,res,processITSupportResponse); 155 | }, // itSupportConversation 156 | } 157 | var sendMessage = function(config,req,wkid,res,next){ 158 | conversation = watson.conversation({ 159 | username: config.conversation.username, 160 | password: config.conversation.password, 161 | version: config.conversation.version, 162 | version_date: config.conversation.versionDate}); 163 | 164 | conversation.message(...); 165 | } 166 | ``` 167 | 168 | The two exposed functions are used to separate the call to the different Watson Conversation workspace. Remember a Watson Conversation service can have one to many workspaces. The settings are externalized in the config/config.json file. 169 | ``` 170 | "conversation" :{ 171 | "version":"2017-02-03", 172 | "username":"291d93 ae533", 173 | "password":"aDF QlD", 174 | "workspace1":"1a3b0abfc1", 175 | "conversationId":"ITSupportConversation", 176 | "workspace2":"80b459cd2405", 177 | "usePersistence": true 178 | }, 179 | ``` 180 | Finally the last method is to send the text and conversation context to Watson Conversation. 181 | 182 | As the conversation holds a context object to keep information between different interactions, the code specifies a set of needed attributes: input, context and workspace ID which can be found in the Watson Conversation Service. If the context is empty from the first query, the conversationId is added. See [Watson Conversation API](https://www.ibm.com/watson/developercloud/conversation/api/v1/) for information about the context. 183 | 184 | ### Service orchestration 185 | A broker code is doing service orchestration. There are two examples illustrated in the `conversation.js` code via the **next** function given as parameter to sendMessage. For example if the dialog flow adds an **action** variable in the context then the code can test on it and call a remote service. 186 | 187 | ```javascript 188 | ... 189 | if (rep.context.action === "trigger" && rep.context.actionName === "supplierOnBoardingProcess") { 190 | bpmoc.callBPMSupplierProcess(rep.context.customerName,rep.context.productName); 191 | } 192 | } 193 | 194 | ``` 195 | 196 | See this [note](doc/integrate-bpm.md) for BPM integration details. 197 | 198 | We can also persist the conversation flow inside a document oriented database, for detail consult[this note](doc/persistence.md) 199 | 200 | ### User interface controls 201 | A classical usage of the conversation is to propose a predefined set of answers the end user can select from. The user interface can propose a HTML button for each option. The 'Advisor' page is defining such UI controls: 202 | ```html 203 |
204 |
205 |
206 |
207 |
208 | 209 |
210 |
211 |
212 | ``` 213 | The options are built in the controller `advisor.component.ts` using the response coming from the server: 214 | ``` 215 | s.options=data.context.predefinedResponses; 216 | ``` 217 | 218 | The context is the Watson Conversation context object and the `predefinedResponses` is an attribute added by the Watson conversation dialog. The figure below illustrates this settings in one of the response: 219 | 220 | ![](doc/define-responses.png) 221 | 222 | ## Angular 4 client app 223 | The code is under *client* folder. It was built using the Angular command line interface (`ng new ``). The `ng` tool with the `new` command creates the foundation for a simple Angular web app with the tooling to build and run a light server so the UI developer can work on the layout and screen flow without any backend. It is possible to use the angular server and be able to develop and test the user interface using the command: 224 | ``` 225 | $ ng serve 226 | or 227 | $ ng build 228 | ``` 229 | And use the URL http://localhost:4200. 230 | 231 | In the current project this type of testing is no more necessary as the server code exists and supports the REST api needed by the user interface. So to run the server use the npm command: 232 | ``` 233 | $ npm run dev 234 | ``` 235 | And then use the URL with the port number reported by the trace: 236 | ``` 237 | [1] [nodemon] starting `node server/server server/server` 238 | [1] info: ** No persistent storage method specified! Data may be lost when process shuts down. 239 | [1] info: ** Setting up custom handlers for processing Slack messages 240 | [1] info: ** API CALL: https://slack.com/api/rtm.start 241 | [1] Server v0.0.1 starting on http://localhost:3001 242 | ``` 243 | 244 | ## Client code organization 245 | Under the client folder the first important file to consider is the `index.html` which loads the angular 2 app. 246 | 247 | The following code illustrates the most important parts: 248 | * including bootstrap css 249 | * loading the angular *app-root* directive 250 | * and as we use client side url routing the base href="/" is added to the HTML header section to give *Angular* the url base context. 251 | 252 | ```html 253 | 254 | 255 | 256 | 257 | 258 | Welcome to IT Support App... Loading AppComponent content here .. 259 | 260 | ``` 261 | 262 | The main.ts script is a standard **Angular 2** typescript file to load the main module. Nothing to add. 263 | 264 | The *app-root* tag is defined in the `app/app.components.ts`. This file uses a base html, used as template for header, body and footer parts. The body part will be injected using the Angular 2 routing mechanism. 265 | ```html 266 | 267 | ``` 268 | Most of the user interactions on the Browser are supported by Angular 2, with its Router mechanism and its DOM rendering capabilities via directives and components. When there is a need to send data to the server for persistence or calling one of the Cognitive Service, an AJAX calls is done and the server will respond asynchronously later. 269 | 270 | The application uses a unique route, as of now, but the approach should help you to add more elements as user interface components. 271 | 272 | The application routing is defined in the app.module.ts as 273 | ```javascript 274 | const routes: Routes = [ 275 | { path: '', component: HomeComponent }, 276 | { path: 'conversation/:type', component: ConversationComponent }, 277 | // otherwise redirect to home 278 | { path: '**', redirectTo: '' } 279 | ] 280 | ``` 281 | This module defines the different components of the application, the imports and routes. The routes json object declares the URLs internal to the angular app and which components is supporting it. So when /conversation will be reached the ConversationComponent will be loaded. The `:type` is used to control the different user interface for the chatbot. 282 | 283 | A home component serves the body content of the main page. It, simply, displays a link to the conversation user interface. The conversation could have been integrated directly into the home page. 284 | ```html 285 |
286 |

Conversation

287 |

Start a simple IT support problem shooting conversation

288 |

289 |
290 | ``` 291 | 292 | So the last important component is app/conv/conversation which defines a simple view which combines a scrolling area where the dialog will be displayed and an input field to let the user entering his request or answer. 293 | 294 | The presented *div* part lists the text from an array of existing sentences, as we want to present the complete conversation history. The syntax is using Angular 2 `for loop` to get each element of the array `currentDialog` and then add the text of this object in a div. 295 | 296 | ```html 297 |
298 |
299 |
300 |
301 | 302 |
303 | 304 |
305 |
306 |
307 |
308 |
309 |
310 | ``` 311 | Th `*ngIf` is an Angular 2 construct to apply condition on the html element it controls. Here the approach is to present different css class depending of the interaction direction: 312 | ![dialog css](doc/dialog.png) 313 | 314 | The conversation component uses the constructor to do a first call to Watson Conversation so the greetings intent is processed and Watson starts the dialog. If we do not use this technic, the user has to start the conversation, and most likely the greeting will not happen as a user will not start by a "hello" query but directly by his/her request. 315 | ```javascript 316 | export class ConversationComponent { 317 | 318 | 319 | constructor(private convService : ConversationService, private route: ActivatedRoute){ 320 | // depending of the url parameters the layout can be simple or more demo oriented with instruction in html 321 | this.type=this.route.snapshot.params['type']; 322 | // Uncomment this line if you do not have a conversation_start trigger in a node of your dialog 323 | this.callConversationBFF("Hello"); 324 | } 325 | } 326 | ``` 327 | 328 | ![Conversation Start](doc/tutorial/wcs-conv-greeting.png) 329 | 330 | When the user click to the **Send** button the following code is executed to create a Sentence and then delegates to a second method 331 | ``` 332 | // method called from html button 333 | submit(){ 334 | let obj:Sentence = new Sentence(); 335 | obj.direction="to-watson"; 336 | obj.text=this.queryString; 337 | this.currentDialog.push(obj); 338 | this.callConversationBFF(this.queryString); 339 | this.queryString=""; 340 | } 341 | ``` 342 | 343 | The second function uses the conversation service to send the user input, and waits ( via subscribe to promise) to get Watson response as calls are asynchronous. 344 | ```javascript 345 | callConversationBFF(msg:string) { 346 | this.convService.submitMessage(msg,this.context).subscribe( 347 | data => {console.log(data) 348 | this.context=data.context; 349 | let s:Sentence = new Sentence(); 350 | s.direction="from-watson"; 351 | s.text=data.text; 352 | this.currentDialog.push(s) 353 | }, 354 | error => { 355 | return "Error occurs in conversation processing" 356 | } 357 | ) 358 | } 359 | ``` 360 | 361 | The conversation component needs to have the currentDialog, and as it is a sentence we need to add a Sentence.ts under the conv folder. Sentence is a basic class with a text and a direction. The direction will be used to present who is speaking: to-watson when the user chat, from-watson when Watson answer. 362 | 363 | The Context variable is used to keep conversation context between each interaction, this is an important mechanism in Watson conversation to exchange data between application and dialog flow. It is detailed in *Using the context* section of the [tutorial](https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/blob/master/doc/tutorial/README.md#using-context-object) 364 | 365 | The conversation.service.ts defines the method to do the HTTP request to the backend for frontend server running in nodejs as presented in previous section. 366 | 367 | ```javascript 368 | submitMessage(msg:string,ctx:any): Observable{ 369 | let bodyString = JSON.stringify( { text:msg,context:ctx }); 370 | let headers = new Headers({ 'Content-Type': 'application/json' }); 371 | let options = new RequestOptions({ headers: headers }) 372 | return this.http.post(this.convUrl,bodyString,options) 373 | .map((res:Response) => res.json()) 374 | } 375 | ``` 376 | The HTTP module is injected via the constructor and the submitMessage use the HTTP module with the post operation. 377 | As the call is asynchronous, we want the function to return a promise. To do so we need to import `rxjs` module and use its `map` function. 378 | The method declares the message and the context parameters. The context variable is here to keep the Watson conversation context so it can be sent back to the service so dialog context is kept. We need to propagate to the client as the conversation is with a unique client, where the server is serving multiple web browser. 379 | 380 | 381 | ## Link to your Watson Conversation service 382 | You need to create a Watson Conversation Service in IBM Bluemix, get the credential and update the file config/config.json with your own credential: 383 | ``` 384 | { 385 | "conversation" :{ 386 | "version":"2017-02-03", 387 | "username":"", 388 | "password":"", 389 | "workspace1":"", 390 | "conversationId":"", 391 | "usePersistence": false 392 | } 393 | } 394 | ``` 395 | If you want to use persistence, you need to create a Cloudant Service and define the credential in the same file. 396 | 397 | ## Exposed REST APIs 398 | The exposed API is: 399 | ``` 400 | title: conversation-broker 401 | case: 402 | - operations: 403 | - verb: post 404 | path: /api/conversation/base 405 | data: {context:{}, text: "a question"} 406 | ``` 407 | 408 | The body should content at least the {text: message} json object. The context object is optional, it will be added with the Watson Conversation ID reference in the code on the first call to the service. 409 | 410 | 411 | # Build and Deploy 412 | 413 | ## Build 414 | You can clone the repository, and uses the following commands: 415 | ``` 416 | # Install all the dependencies defined in the package.json 417 | $ npm install 418 | # Install angular Command Line Interface for compiling code 419 | $ sudo npm install -g @angular/cli 420 | # the previous commands are to prepare the environment 421 | 422 | # to compile the angular code 423 | $ ng build 424 | # to test the server with mocha 425 | $ npm test 426 | ``` 427 | 428 | Execute locally 429 | ``` 430 | # execute with a build of angular code and start the server in monitoring mode, 431 | # so change to server restarts the server. 432 | $ npm run dev 433 | 434 | # You can also execute the app without compilation and monitoring 435 | $ npm start 436 | ``` 437 | 438 | ## Deploy to Bluemix as Cloud Foundry 439 | To be able to deploy to bluemix, you need a bluemix account and the command line interface. 440 | You can use the ```cf push ``` 441 | You can use also this one click button. 442 | [![Deploy to Bluemix](https://bluemix.net/deploy/button.png)](https://bluemix.net/deploy?repository=https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker) 443 | 444 | 445 | ## Deploy to IBM Cloud Private 446 | See the detailed [note here](doc/icp/README.md) 447 | 448 | # Compendium 449 | 450 | * [Cognitive conversation paper](https://www.ibm.com/devops/method/content/architecture/cognitiveConversationDomain) 451 | * [Build dialog flow](https://console.bluemix.net/docs/services/conversation/dialog-build.html#dialog-build) 452 | 453 | 454 | # Contribute 455 | See the process in [main cognitive repository](https://github.com/ibm-cloud-architecture/refarch-cognitive). 456 | -------------------------------------------------------------------------------- /buildPackage.sh: -------------------------------------------------------------------------------- 1 | # To better unit test jenkins build we externalize the build process in a shell 2 | # then call the shell from jenkins on the build server 3 | echo "Build..." 4 | #rc=$(npm run build 2>&1) 5 | if [[ $rc == *"ERROR"* ]]; then 6 | echo "Build failed ..." 7 | echo $rc 8 | exit 9 | fi 10 | 11 | echo "Unit test..." 12 | rc=$(npm test 2>&1) 13 | if [[ $rc == *"fail"* || $rc == *"Error"* ]]; then 14 | echo "Tests failed" 15 | echo $rc 16 | exit 17 | fi 18 | echo "Dockerize...." 19 | # docker build -t case/wcsbroker . 20 | # docker tag case/wcsbroker mycluster.cfc:8500/default/casewcsbroker:v0.0.1 21 | # cd helm; helm package casewcsbroker 22 | -------------------------------------------------------------------------------- /chart/casewcsbroker/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *~ 18 | # Various IDEs 19 | .project 20 | .idea/ 21 | *.tmproj 22 | -------------------------------------------------------------------------------- /chart/casewcsbroker/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | description: A Helm chart for Kubernetes for the Watson Conversation Broker 3 | name: casewcsbroker 4 | version: 0.0.1 5 | -------------------------------------------------------------------------------- /chart/casewcsbroker/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if .Values.ingress.hostname }} 3 | http://{{- .Values.ingress.hostname }} 4 | {{- else if contains "NodePort" .Values.service.type }} 5 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }}) 6 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 7 | echo http://$NODE_IP:$NODE_PORT 8 | {{- else if contains "LoadBalancer" .Values.service.type }} 9 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 10 | You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' 11 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') 12 | echo http://$SERVICE_IP:{{ .Values.service.externalPort }} 13 | {{- else if contains "ClusterIP" .Values.service.type }} 14 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "fullname" . }}" -o jsonpath="{.items[0].metadata.name}") 15 | echo "Visit http://127.0.0.1:8080 to use your application" 16 | kubectl port-forward $POD_NAME 8080:{{ .Values.service.externalPort }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /chart/casewcsbroker/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 7 | {{- end -}} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | */}} 13 | {{- define "fullname" -}} 14 | {{- $name := default .Chart.Name .Values.nameOverride -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /chart/casewcsbroker/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" 7 | data: 8 | config.json: |+ 9 | { 10 | "conversation" :{ 11 | "version" : "{{ .Values.config.conversation.version }}", 12 | "versionDate": "{{ .Values.config.conversation.versionDate }}", 13 | "username": "{{ .Values.config.conversation.username }}", 14 | "password": "{{ .Values.config.conversation.password }}", 15 | "workspace1":"{{ .Values.config.conversation.workspace1 }}", 16 | "workspace2":"{{ .Values.config.conversation.workspace2 }}", 17 | "workspace3":"{{ .Values.config.conversation.workspace3 }}", 18 | "conversationId": "{{ .Values.config.conversation.conversationId }}", 19 | "usePersistence": "{{ .Values.config.conversation.usePersistence }}" 20 | }, 21 | "bpmoc" :{ 22 | "serverName": "{{ .Values.config.bpmoc.serverName }}", 23 | "processName": "{{ .Values.config.bpmoc.processName }}", 24 | "basicAuth": "{{ .Values.config.bpmoc.basicAuth }}" 25 | }, 26 | "dbCredentials" : { 27 | "url": "{{ .Values.config.dbCredentials.url }}" 28 | }, 29 | "debug": "{{ .Values.config.debug }}", 30 | "port": "{{ .Values.config.port }}" 31 | } 32 | -------------------------------------------------------------------------------- /chart/casewcsbroker/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" 7 | spec: 8 | replicas: {{ .Values.replicaCount }} 9 | revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} 10 | template: 11 | metadata: 12 | labels: 13 | app: {{ template "fullname" . }} 14 | spec: 15 | containers: 16 | - name: {{ .Chart.Name }} 17 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 18 | imagePullPolicy: {{ .Values.image.pullPolicy }} 19 | livenessProbe: 20 | httpGet: 21 | path: /healthz 22 | port: {{ .Values.service.internalPort }} 23 | initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds}} 24 | periodSeconds: {{ .Values.livenessProbe.periodSeconds}} 25 | ports: 26 | - containerPort: {{ .Values.service.internalPort }} 27 | volumeMounts: 28 | - name: config 29 | mountPath: /wcsbroker/server/config.json 30 | subPath: config.json 31 | resources: 32 | {{ toYaml .Values.resources | indent 10 }} 33 | volumes: 34 | - name: config 35 | configMap: 36 | name: {{ template "fullname" . }} 37 | restartPolicy: Always 38 | terminationGracePeriodSeconds: 30 39 | dnsPolicy: ClusterFirst 40 | securityContext: {} 41 | imagePullSecrets: 42 | - name: admin.registrykey 43 | - name: default-token-45n44 44 | schedulerName: default-scheduler 45 | -------------------------------------------------------------------------------- /chart/casewcsbroker/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.enabled -}} 2 | {{- $serviceName := include "fullname" . -}} 3 | {{- $servicePort := .Values.service.externalPort -}} 4 | apiVersion: extensions/v1beta1 5 | kind: Ingress 6 | metadata: 7 | name: {{ template "fullname" . }} 8 | labels: 9 | app: {{ template "fullname" . }} 10 | chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" 11 | release: "{{ .Release.Name }}" 12 | heritage: "{{ .Release.Service }}" 13 | annotations: 14 | {{- range $key, $value := .Values.ingress.annotations }} 15 | {{ $key }}: {{ $value | quote }} 16 | {{- end }} 17 | spec: 18 | rules: 19 | {{- range $host := .Values.ingress.hosts }} 20 | - host: {{ $host }} 21 | http: 22 | paths: 23 | - path: / 24 | backend: 25 | serviceName: {{ $serviceName }} 26 | servicePort: {{ $servicePort }} 27 | {{- end -}} 28 | {{- if .Values.ingress.tls }} 29 | tls: 30 | {{ toYaml .Values.ingress.tls | indent 4 }} 31 | {{- end -}} 32 | {{- end -}} 33 | -------------------------------------------------------------------------------- /chart/casewcsbroker/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "fullname" . }} 5 | labels: 6 | chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" 7 | spec: 8 | type: {{ .Values.service.type }} 9 | ports: 10 | - port: {{ .Values.service.externalPort }} 11 | targetPort: {{ .Values.service.internalPort }} 12 | protocol: TCP 13 | name: {{ .Values.service.name }} 14 | selector: 15 | app: {{ template "fullname" . }} 16 | -------------------------------------------------------------------------------- /chart/casewcsbroker/values-temp.yaml: -------------------------------------------------------------------------------- 1 | # Default values for casewcsbroker. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | replicaCount: 1 5 | revisionHistoryLimit: 1 6 | image: 7 | repository: jbcluster.icp:8500/default/casewcsbroker 8 | tag: 0.0.1 9 | pullPolicy: IfNotPresent 10 | livenessProbe: 11 | initialDelaySeconds: 40 12 | periodSeconds: 2 13 | service: 14 | name: casewcsbroker 15 | type: ClusterIP 16 | externalPort: 3001 17 | internalPort: 3001 18 | ingress: 19 | enabled: false 20 | # Used to create Ingress record (should used with service.type: ClusterIP). 21 | hosts: 22 | - casewcsbroker.local 23 | annotations: 24 | # kubernetes.io/ingress.class: nginx 25 | # kubernetes.io/tls-acme: "true" 26 | tls: 27 | # Secrets must be manually created in the namespace. 28 | # - secretName: chart-example-tls 29 | # hosts: 30 | # - chart-example.local 31 | config: 32 | conversation: 33 | version : v1 34 | versionDate: 2017-02-03 35 | username: <> 36 | password: <> 37 | workspace1: 1a3b01f3-4757-444d-a933-a1e648babfc1 38 | workspace2: 80b451cc-d4eb-43bf-a4ac-359599cd2405 39 | workspace3: 6c5ba7ac-4925-4ab4-bbc6-03f05e539407 40 | conversationId: CyanConversations 41 | usePersistence: false 42 | bpmoc: 43 | serverName: vhost001.bpm.ibmcloud.com 44 | processName: SOBD/SOAPStart.tws 45 | basicAuth: <> 46 | dbCredentials: 47 | url: https://01bcc074-b3a0-4b07-93c6-eade6fb3ce50-bluemix:....-bluemix.cloudant.com 48 | debug: true 49 | port: 3001 50 | resources: 51 | limits: 52 | cpu: 100m 53 | memory: 128Mi 54 | requests: 55 | cpu: 100m 56 | memory: 128Mi 57 | -------------------------------------------------------------------------------- /chart/casewcsbroker/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for casewcsbroker. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | replicaCount: 1 5 | revisionHistoryLimit: 1 6 | image: 7 | repository: greencluster.icp:8500/cyancompute/wcsbroker 8 | tag: v0.0.1 9 | pullPolicy: Always 10 | livenessProbe: 11 | initialDelaySeconds: 40 12 | periodSeconds: 10 13 | service: 14 | name: wcsbrokersvc 15 | type: ClusterIP 16 | externalPort: 3001 17 | internalPort: 3001 18 | ingress: 19 | enabled: true 20 | # Used to create Ingress record (should used with service.type: ClusterIP). 21 | hosts: 22 | - wcsbroker.cyan.case 23 | annotations: 24 | # kubernetes.io/ingress.class: nginx 25 | # kubernetes.io/tls-acme: "true" 26 | tls: 27 | # Secrets must be manually created in the namespace. 28 | # - secretName: chart-example-tls 29 | # hosts: 30 | # - chart-example.local 31 | config: 32 | conversation: 33 | version : v1 34 | versionDate: 2017-02-03 35 | username: 291d9397-073f-46d9-b0d2-11b54e6ae533 36 | password: aDFBIIPYkQlD 37 | workspace1: 1a3b01f3-4757-444d-a933-a1e648babfc1 38 | workspace2: 80b451cc-d4eb-43bf-a4ac-359599cd2405 39 | workspace3: 6c5ba7ac-4925-4ab4-bbc6-03f05e539407 40 | conversationId: CyanConversations 41 | usePersistence: false 42 | bpmoc: 43 | serverName: vhost001.bpm.ibmcloud.com 44 | processName: SOBD/SOAPStart.tws 45 | basicAuth: Y29nbml0aXZlYnBtZW1haWxAZ21haWwuY29tOmNvZ25pdGl2ZQ== 46 | dbCredentials: 47 | url: https://01bcc074-b3a0-4b07-93c6-eade6fb3ce50-bluemix:cd68d33a28d499bc6211810a56a0b99393a699190630f7811c438149be944500@01bcc074-b3a0-4b07-93c6-eade6fb3ce50-bluemix.cloudant.com 48 | debug: true 49 | port: 3001 50 | resources: 51 | limits: 52 | cpu: 100m 53 | memory: 128Mi 54 | requests: 55 | cpu: 100m 56 | memory: 128Mi 57 | -------------------------------------------------------------------------------- /client/app/advisor/advisor.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, AfterViewChecked, ElementRef, ViewChild, OnInit} from '@angular/core'; 2 | import { AdvisorService } from './advisor.service'; 3 | import { Sentence } from "../conv/Sentence"; 4 | 5 | @Component({ 6 | //moduleId: module.id, 7 | selector: 'advisor', 8 | styleUrls:['advisor.css'], 9 | templateUrl:'advisorMain.html' 10 | }) 11 | 12 | export class AdvisorComponent implements OnInit, AfterViewChecked{ 13 | currentDialog : Sentence[]=[]; 14 | context:any={}; 15 | message:string; 16 | /** 17 | When creating a conversation component call Watson to get a greetings message as defined in the Dialog. This is more user friendly. 18 | */ 19 | constructor(private convService : AdvisorService){ 20 | // Uncomment this line if you do not have a conversation_start trigger in a node of your dialog 21 | this.callConversationBFF("Hello"); 22 | } 23 | 24 | @ViewChild('scrollMe') private myScrollContainer: ElementRef; 25 | 26 | ngOnInit() { 27 | this.scrollToBottom(); 28 | } 29 | 30 | ngAfterViewChecked() { 31 | this.scrollToBottom(); 32 | } 33 | 34 | scrollToBottom(): void { 35 | try { 36 | this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight; 37 | } catch(err) { } 38 | } 39 | 40 | // variable used for the input field in html page to get user query 41 | queryString="" 42 | 43 | callConversationBFF(msg:string) { 44 | this.convService.submitMessage(msg,this.context).subscribe( 45 | data => { 46 | this.context=data.context; 47 | let s:Sentence = new Sentence(); 48 | s.direction="from-watson"; 49 | s.text=data.text; 50 | s.options=data.context.predefinedResponses; 51 | this.currentDialog.push(s); 52 | this.queryString=""; 53 | }, 54 | error => { 55 | return "Error occurs in conversation processing" 56 | } 57 | ) 58 | } 59 | 60 | submit(){ 61 | let obj:Sentence = new Sentence(); 62 | obj.direction="to-watson"; 63 | obj.text=this.queryString; 64 | this.currentDialog.push(obj); 65 | this.callConversationBFF(this.queryString); 66 | this.queryString=""; 67 | } 68 | 69 | advisorResponse(resp) { 70 | let obj:Sentence = new Sentence(); 71 | obj.direction="to-watson"; 72 | this.queryString=resp; 73 | obj.text=resp; 74 | this.currentDialog.push(obj); 75 | this.callConversationBFF(resp); 76 | } 77 | 78 | keyMessage(event){ 79 | if(event.keyCode == 13) { 80 | this.submit(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /client/app/advisor/advisor.css: -------------------------------------------------------------------------------- 1 | .conversation-container { 2 | border-style: solid; 3 | max-width: 900px; 4 | margin: 30px auto; 5 | border-width : 2px; 6 | border-radius: 8px; 7 | border-color: #blue; 8 | } 9 | 10 | .scrolling-box { 11 | padding: 0px 5px; 12 | height: calc(100vh - 200px); 13 | max-height: 600px; 14 | overflow-x: hidden; 15 | overflow-y: auto; 16 | } 17 | 18 | .message-box { 19 | margin: 20px 0px; 20 | overflow: hidden; 21 | } 22 | 23 | .to-watson { 24 | margin-left: 30%; 25 | } 26 | .to-watson-icon { 27 | float: right; 28 | font-size: 40px; 29 | } 30 | .to-watson-text { 31 | padding: 0px 20px; 32 | border-radius: 20px; 33 | float: right; 34 | background: #af4b08; 35 | color:white; 36 | max-width: calc(100% - 60px); 37 | } 38 | 39 | .from-watson { 40 | max-width: 70%; 41 | } 42 | .from-watson-icon { 43 | float: left; 44 | } 45 | .from-watson-text { 46 | background: #3353d6; 47 | padding: 15px 20px; 48 | border-radius: 20px; 49 | float: left; 50 | color:white; 51 | max-width: calc(100% - 60px); 52 | } 53 | -------------------------------------------------------------------------------- /client/app/advisor/advisor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Headers, Http,Response,RequestOptions } from '@angular/http'; 3 | import 'rxjs/add/operator/toPromise'; 4 | import {Observable} from 'rxjs/Rx'; 5 | import 'rxjs/add/operator/map'; 6 | 7 | 8 | @Injectable() 9 | export class AdvisorService { 10 | private convUrl ='/api/advisor/'; 11 | 12 | constructor(private http: Http) { 13 | }; 14 | 15 | submitMessage(msg:string,ctx:any): Observable{ 16 | let bodyString = JSON.stringify( { text:msg,context:ctx }); 17 | 18 | let headers = new Headers({ 'Content-Type': 'application/json' }); 19 | let options = new RequestOptions({ headers: headers }) 20 | return this.http.post(this.convUrl,bodyString,options) 21 | .map((res:Response) => res.json()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/app/advisor/advisorMain.html: -------------------------------------------------------------------------------- 1 | 6 |
7 |
8 |

Welcome to CASE Advisor!. This application is designed to help you determine the fit and applicability of a particular project to the Hybrid & Private Solution typeand to ensure the quality and compliance with best practices of the project outcome. Here are some query we can help you with:

9 |
    10 |
  • How to migrate existing application to IBM cloud?
  • 11 |
  • What are WAS options available in IBM Cloud Private?
  • 12 |
  • What lift and shift tools for traditional WAS are available in IBM Cloud Private
  • 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 50 | 51 |
52 |
53 |
54 |
55 |
56 | -------------------------------------------------------------------------------- /client/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Watson Conversation Broker

4 |
5 | 6 |
7 |

© IBM | Cloud Architecture Service Engineering | {{version}}

8 |
9 |
10 | -------------------------------------------------------------------------------- /client/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html' 6 | }) 7 | export class AppComponent { 8 | version:string ="v0.0.7 1/17/2018" 9 | } 10 | -------------------------------------------------------------------------------- /client/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpModule } from '@angular/http'; 5 | import { RouterModule, Routes } from '@angular/router'; 6 | 7 | import { AppComponent } from './app.component'; 8 | import { ConversationComponent} from './conv/conversation.component'; 9 | import { ConversationService } from './conv/conversation.service'; 10 | import { HomeComponent } from './home.component'; 11 | import { AdvisorComponent} from './advisor/advisor.component'; 12 | import { AdvisorService } from './advisor/advisor.service'; 13 | 14 | 15 | const routes: Routes = [ 16 | { path: '', component: HomeComponent }, 17 | { path: 'conversation/:type', component: ConversationComponent }, 18 | { path: 'advisor', component: AdvisorComponent}, 19 | // otherwise redirect to home 20 | { path: '**', redirectTo: '' } 21 | ] 22 | 23 | @NgModule({ 24 | declarations: [ 25 | AppComponent, 26 | HomeComponent, 27 | ConversationComponent, 28 | AdvisorComponent 29 | ], 30 | imports: [ 31 | BrowserModule, 32 | FormsModule, 33 | HttpModule, 34 | RouterModule.forRoot(routes) 35 | ], 36 | providers: [ConversationService,AdvisorService], 37 | bootstrap: [AppComponent] 38 | }) 39 | export class AppModule { } 40 | -------------------------------------------------------------------------------- /client/app/conv/Sentence.ts: -------------------------------------------------------------------------------- 1 | export class Sentence { 2 | direction: string; 3 | text : string; 4 | options: string[]; 5 | } 6 | -------------------------------------------------------------------------------- /client/app/conv/conversation.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, AfterViewChecked, ElementRef, ViewChild, OnInit} from '@angular/core'; 2 | import { ConversationService } from './conversation.service'; 3 | import { Sentence } from "./Sentence"; 4 | import {ActivatedRoute, Params} from '@angular/router'; 5 | 6 | @Component({ 7 | moduleId: module.id, 8 | selector: 'conversation', 9 | styleUrls:['conversation.css'], 10 | templateUrl:'conversation.html' 11 | }) 12 | 13 | export class ConversationComponent implements OnInit, AfterViewChecked { 14 | currentDialog : Sentence[]=[]; 15 | context={'type':'base'}; // used to keep the Conversation context 16 | message:string; 17 | type:string = "base"; 18 | /** 19 | When creating a conversation component call Watson to get a greetings message as defined in the Dialog. This is more user friendly. 20 | */ 21 | constructor(private convService : ConversationService, private route: ActivatedRoute){ 22 | // depending of the url parameters the layout can be simple or more demo oriented with instruction in html 23 | this.type=this.route.snapshot.params['type']; 24 | // Uncomment this line if you do not have a conversation_start trigger in a node of your dialog 25 | this.callConversationBFF("Hello"); 26 | } 27 | 28 | @ViewChild('scrollMe') private myScrollContainer: ElementRef; 29 | 30 | ngOnInit() { 31 | this.scrollToBottom(); 32 | } 33 | 34 | ngAfterViewChecked() { 35 | this.scrollToBottom(); 36 | } 37 | 38 | scrollToBottom(): void { 39 | try { 40 | this.myScrollContainer.nativeElement.scrollTop = this.myScrollContainer.nativeElement.scrollHeight; 41 | } catch(err) { } 42 | } 43 | 44 | 45 | // variable used for the input field in html page to get user query 46 | queryString="" 47 | 48 | callConversationBFF(msg:string) { 49 | this.context['type']=this.type; // inject the type of caller so the BFF can call different conversation workspace 50 | this.convService.submitMessage(msg,this.context).subscribe( 51 | data => { 52 | this.context=data.context; 53 | let s:Sentence = new Sentence(); 54 | s.direction="from-watson"; 55 | s.text=data.output.text[0]; 56 | this.currentDialog.push(s) 57 | }, 58 | error => { 59 | return "Error occurs in conversation processing" 60 | } 61 | ) 62 | } 63 | 64 | // method called from html button 65 | submit(){ 66 | let obj:Sentence = new Sentence(); 67 | obj.direction="to-watson"; 68 | obj.text=this.queryString; 69 | this.currentDialog.push(obj); 70 | this.callConversationBFF(this.queryString); 71 | this.queryString=""; 72 | } 73 | 74 | // instead to click on button if user hits enter/return key 75 | keyMessage(event){ 76 | if(event.keyCode == 13) { 77 | this.submit(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /client/app/conv/conversation.css: -------------------------------------------------------------------------------- 1 | .conversation-container { 2 | border-style: solid; 3 | max-width: 700px; 4 | margin: 30px auto; 5 | border-width : 2px; 6 | border-radius: 8px; 7 | border-color: #blue; 8 | } 9 | 10 | .scrolling-box { 11 | padding: 0px 5px; 12 | height: calc(100vh - 200px); 13 | max-height: 500px; 14 | overflow-x: hidden; 15 | overflow-y: auto; 16 | } 17 | 18 | .message-box { 19 | margin: 20px 0px; 20 | overflow: hidden; 21 | } 22 | 23 | .to-watson { 24 | margin-left: 30%; 25 | } 26 | .to-watson-icon { 27 | float: right; 28 | font-size: 40px; 29 | } 30 | .to-watson-text { 31 | padding: 0px 20px; 32 | border-radius: 20px; 33 | float: right; 34 | background: #a9ef1c; 35 | color:white; 36 | max-width: calc(100% - 60px); 37 | } 38 | 39 | .from-watson { 40 | max-width: 70%; 41 | } 42 | .from-watson-icon { 43 | float: left; 44 | } 45 | .from-watson-text { 46 | background: #8bc9ef; 47 | color: white; 48 | padding: 15px 20px; 49 | border-radius: 20px; 50 | float: left; 51 | max-width: calc(100% - 60px); 52 | } 53 | -------------------------------------------------------------------------------- /client/app/conv/conversation.html: -------------------------------------------------------------------------------- 1 | 6 |
7 |
8 |

Welcome to IT Support, which handles conversation for internal IT application support. You can ask simple question like:

9 |
    10 |
  • I could not access application AbC
  • 11 |
  • How can I reset my password
  • 12 |
  • what is the business process for supplier on boarding?
  • 13 |
  • how to bring my ipad for work?
  • 14 |
15 |
16 |

The supplier on boarding business process deployed on IBM BPM on Cloud can be triggered automatically from this conversation broker for the dialog flow. To demonstrate you need an account on BPM on Cloud demo server and do the following steps:

17 |
    18 |
  • How to access supplier on boarding process
  • 19 |
  • for company name enter IBM
  • 20 |
  • for product name enter Watson or another IBM product
  • 21 |
22 |

The process is created and the business process calls Watson Discovery to search the company / product in the News collection, the user can then claims a task in his working basket on BPM Process portal to see the search results and assess the risk to add this supplier as business partner. If accepted the supplier is added to the blockchain network

23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 | 34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 51 | 52 |
53 |
54 |
55 |
56 |
57 | -------------------------------------------------------------------------------- /client/app/conv/conversation.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Headers, Http,Response,RequestOptions } from '@angular/http'; 3 | import 'rxjs/add/operator/toPromise'; 4 | import {Observable} from 'rxjs/Rx'; 5 | import 'rxjs/add/operator/map'; 6 | 7 | 8 | @Injectable() 9 | export class ConversationService { 10 | private convUrl ='/api/conversation/'; 11 | private convIoTUrl ='/api/ac/conversation/'; 12 | 13 | constructor(private http: Http) { 14 | }; 15 | 16 | submitMessage(msg:string,ctx:any): Observable{ 17 | let bodyString = JSON.stringify( { text:msg,context:ctx }); 18 | let headers = new Headers({ 'Content-Type': 'application/json' }); 19 | let options = new RequestOptions({ headers: headers }); 20 | return this.http.post(this.convUrl,bodyString,options) 21 | .map((res:Response) => res.json()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /client/app/home.component.css: -------------------------------------------------------------------------------- 1 | .roundRect { 2 | margin: auto; 3 | border-width : 2px; 4 | border-radius: 8px; 5 | margin-right: 15px; 6 | margin-bottom: 15px; 7 | padding: 20px; 8 | marging: 10px; 9 | height:220px; 10 | width:330px; 11 | border-style: solid; 12 | border-color: #blue; 13 | background-color: white; 14 | } 15 | -------------------------------------------------------------------------------- /client/app/home.component.html: -------------------------------------------------------------------------------- 1 |
2 |

Welcome to the Watson Conversation Broker Demo

3 |

This user interface is used to demonstrated the conversations broker in action, used to orchestrate Watson Conversation Service with other backend services.

4 |

For more information about code and content see the repository in github.com IBM Cloud Architecture

5 |

For a deep dive tutorial on how the IT support conversation is done see the garage method site

6 |
7 |

IT Support Bot

8 |

Start a simple IT support problem shooting conversation - for demonstration of the broker's capabilities

9 |

10 |
11 |
12 |

Integrated Chatbot

13 |

Simplest interface without help, used in BPM coach iframe

14 |

15 |
16 |
17 |

CASE Advisor

18 |

Ask hybrid cloud question to our expert bot

19 |

20 |
21 |
22 | -------------------------------------------------------------------------------- /client/app/home.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | /* 4 | Main page component to display access to the different demo features. 5 | */ 6 | 7 | @Component({ 8 | selector: 'home', 9 | styleUrls: ['./home.component.css'], 10 | templateUrl: './home.component.html' 11 | }) 12 | 13 | export class HomeComponent { 14 | constructor(private router: Router) { 15 | } 16 | 17 | 18 | conversation(){ 19 | this.router.navigate(['conversation/base']); 20 | } 21 | // ADD Here methods to be called from HTLM button to route to other component 22 | conversationSodb(){ 23 | this.router.navigate(['conversation/sodb']); 24 | } 25 | 26 | advisor(){ 27 | this.router.navigate(['advisor']); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/assets/images/tree-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/client/assets/images/tree-sm.png -------------------------------------------------------------------------------- /client/assets/images/watson-globe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/client/assets/images/watson-globe.png -------------------------------------------------------------------------------- /client/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /client/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /client/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/client/favicon.ico -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Watson Conversation Broker 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | Welcome to Watson Conversation Broker demos, loading... 16 | 17 | 18 | -------------------------------------------------------------------------------- /client/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | // for dev use from './environments/environment'; 6 | import { environment } from './environments/environment.prod'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule); 13 | -------------------------------------------------------------------------------- /client/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/set'; 35 | 36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 37 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 38 | 39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */ 40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 41 | 42 | 43 | /** Evergreen browsers require these. **/ 44 | import 'core-js/es6/reflect'; 45 | import 'core-js/es7/reflect'; 46 | 47 | 48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/ 49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 50 | 51 | 52 | 53 | /*************************************************************************************************** 54 | * Zone JS is required by Angular itself. 55 | */ 56 | import 'zone.js/dist/zone'; // Included with Angular CLI. 57 | 58 | 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | 64 | /** 65 | * Date, currency, decimal and percent pipes. 66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 67 | */ 68 | // import 'intl'; // Run `npm install --save intl`. 69 | -------------------------------------------------------------------------------- /client/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /client/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare var __karma__: any; 17 | declare var require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /client/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "declaration": false, 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "lib": [ 9 | "es2016", 10 | "dom" 11 | ], 12 | "outDir": "../out-tsc/app", 13 | "target": "es5", 14 | "module": "es2015", 15 | "baseUrl": "", 16 | "types": [] 17 | }, 18 | "exclude": [ 19 | "test.ts", 20 | "**/*.spec.ts" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /client/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "declaration": false, 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "lib": [ 9 | "es2016" 10 | ], 11 | "outDir": "../out-tsc/spec", 12 | "module": "commonjs", 13 | "target": "es6", 14 | "baseUrl": "", 15 | "types": [ 16 | "jasmine", 17 | "node" 18 | ] 19 | }, 20 | "files": [ 21 | "test.ts" 22 | ], 23 | "include": [ 24 | "**/*.spec.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /client/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: { 3 | id: string; 4 | }; 5 | -------------------------------------------------------------------------------- /doc/cloudant-cred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/cloudant-cred.png -------------------------------------------------------------------------------- /doc/define-responses.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/define-responses.png -------------------------------------------------------------------------------- /doc/demo/demo-home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/demo/demo-home.png -------------------------------------------------------------------------------- /doc/demo/demoscript.md: -------------------------------------------------------------------------------- 1 | # Demonstration script 2 | Welcome to IT Support demonstration, which handles conversation for internal IT application support. 3 | 4 | # Use case 5 | The support director wants to modernize the way to support internal staff and offload his team from basic work. Currently 20000 tickets are issued in a year. 50% of the calls are answered in 7 minutes whereas there are many situations that reach up to 70 minutes for resolution. 92% of the calls are resolved by level 1 support. Employees of the Case Inc engage with customer support mostly through phones. Today, call center agents struggle to find some of the answers in a timely fashion as the systems are not integrated. This results in loss of productivity and frustration on the part of the bank employees. Level 1 support team get frustrated at times because of unavailability of the right information and proper guidance. The Level 1 support has to consult the Level 2 support team members to get some answers. 6 | 7 | The deployed application is visible here: [http://refarch-wcs-broker.mybluemix.net/](http://refarch-wcs-broker.mybluemix.net/) 8 | 9 | The home page has two choices 10 | ![Home](demo-home.png) 11 | 12 | ## IT support Conversation 13 | In the home page click to *Ask IT Support* button to reach the IT Support chat bot. The left side of the page gives summary of the demo steps 14 | 15 | ![IT Support bot](it-support-bot.png) 16 | 17 | You can now ask simple questions like: 18 | * I could not access application AbC 19 | * How can I reset my password 20 | * what is the business process for supplier on boarding? 21 | * how to bring my ipad for work? 22 | 23 | ### Triggering a business process from the conversation 24 | 25 | The supplier on boarding business process deployed on [IBM BPM on Cloud](https://vhost001.bpm.ibmcloud.com/) can be triggered automatically by this conversation broker code as defined in the dialog flow. 26 | ![](../tutorial/supplier-node-yes.png) 27 | 28 | The diagram above illustrates the dialog flow to support the **supplier on boarding** intent classification. The Watson response is **Do you want me to trigger the process for you?**. Then when the user answers *yes* the flow is asking for company name and then product name. 29 | 30 | To demonstrate you need an account on BPM on Cloud demo server and do the following steps: 31 | 32 | * How to access supplier on boarding process 33 | * for company name enter IBM 34 | * for product name enter Watson or another IBM product 35 | 36 | ![](../readme/trigger-from-wcs.png) 37 | 38 | The process is created and the business process calls Watson Discovery to search the company / product in the *News* collection, as illustrated by the process flow: 39 | ![BPD](https://github.com/ibm-cloud-architecture/refarch-cognitive-supplier-process/blob/master/docs/bpm-supplieronboarding.png) 40 | 41 | The user can then claim a task in his working basket on BPM Process portal 42 | ![Process Portal](https://github.com/ibm-cloud-architecture/refarch-cognitive-supplier-process/blob/master/docs/SOBD-processcenter.png) 43 | 44 | To see the search results and assess the risk to add this supplier as business partner. 45 | ![WDS results](https://github.com/ibm-cloud-architecture/refarch-cognitive-supplier-process/blob/master/docs/wds-results.png) 46 | 47 | If accepted the supplier is added to the blockchain network. 48 | 49 | ## Integrate Chatbot 50 | 51 | The chat bot user interface can be embedded inside a BPM coach and called from a *Get help* button. The action triggers a popup window, which is an iframe, which call the conversation broker user interface to the url: [http://refarch-wcs-broker.mybluemix.net/conversation/sodb](http://refarch-wcs-broker.mybluemix.net/conversation/sodb). 52 | As illustrated in the screen shot below: 53 | 54 | ![chat bot in iframe](https://github.com/ibm-cloud-architecture/refarch-cognitive-supplier-process/blob/master/docs/bpm-wcs-iframe.png) 55 | 56 | For detail on the implementation of the process see this [repository](https://github.com/ibm-cloud-architecture/refarch-cognitive-supplier-process) 57 | -------------------------------------------------------------------------------- /doc/demo/it-support-bot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/demo/it-support-bot.png -------------------------------------------------------------------------------- /doc/demoflow.md: -------------------------------------------------------------------------------- 1 | # Demonstration flow 2 | ## Triggering the supplier on boarding process from interaction 3 | 4 | When accessing the CASE Inc internal portal at the URL [http://caseincapp.mybluemix.net/](http://caseincapp.mybluemix.net/) a user can access the Help@Case IT support application, which trigger a conversation. In the entry field enter the message: **what is the process for supplier on boarding?**. 5 | The response is: **Do you want me to trigger a process for you?** 6 | The bot ask about company and product name and then return the URL of the process portal to claim the task to continue the supplier on boarding process. 7 | ![Complete flow](doc/readme/trigger-from-wcs.png) 8 | -------------------------------------------------------------------------------- /doc/design/README.md: -------------------------------------------------------------------------------- 1 | # Design considerations 2 | When designing a chatbot, you need to assess the following requirements: 3 | * who are the end users of the bot? 4 | * what is the expected level of competency they will have to interact with the bot? 5 | * what kind of channel and interaction? channels being existing chat bot software, or develop a new one in web, and interactions meaning voice or text, and click predefined responses. 6 | * The need to have text to speech and speech to text 7 | * Is there need to present parallel information in separate part of the user interface to give more context to the conversation response, like a map, a graphic, explanation... 8 | * Do we need to know the location of the user? 9 | * Do we need to know the user's 'journey' inside the web site (click stream history?) 10 | * Do we need to leverage existing customer profile to drive conversation content? 11 | * Do we want to assess emotional analysis? 12 | * Is there any conversation switching requirement? (Switching to a human) 13 | * how the conversation is supposed to end? 14 | * What are the goals of the end users? They should be clearly assessed as they are source for intent definitions. 15 | * do we need to ask for 5 stars feedback at the end of the conversation 16 | * What are the expected metrics to gather? 17 | The typical ones are: 18 | * total number of sessions 19 | * stars per sessions 20 | * # of transfer to human 21 | * # of turn per session 22 | * # of misses: reaching no node in the dialog or the default one. 23 | 24 | 25 | ## Applying Design Thinking 26 | When implementing a cognitive solution, we may want to apply the [Design Thinking](https://www.ibm.com/devops/method/content/think/practice_design_thinking/) methodology as it helps transforming a business improvement idea to concrete business application end users will use. The principles of empathy with users, prototyping or Minimum Viable Product and tolerance for failure are applied as part of the method. 27 | The storyboarding is one of such Design Thinking practice, where personas’ challenges and pains are addressed via stories. When engaging with a project team the first main exercise is to gather the requirements around Cognitive system and the use of the potential new application. The following application can help to formalize those requirements [Innovation Workshop](http://iwapp.mybluemix.net/). 28 | Empathy maps are developed. First we need to gather is the list of Personas as presented in screen shot below: 29 | ![persona](itsupport-persona.png) 30 | then we need to develop with the project team and end users the empathy map to address pains and challenge but more data points so we can be more in empathy with the user of the application. The following diagram is a map for the internal user persona developed using [Mural](https://app.mural.ly). 31 | ![empathy map](empathy-map.png) 32 | 33 | Another artifact to build, as soon as possible, and then enhance over time, is a System Context Diagram which helps assessing what are the systems to interact with. 34 | 35 | ![system context view](syst-ctx.png) 36 | 37 | The system context serves also to organize the work into teams, micro services development and crowd sourcing work for the Natural Language training tasks. 38 | 39 | The end user interacts with a WebApp developed with nodejs deployed as Cloud Foundry App on Bluemix. The main component is the Watson Conversation service, but the application could be connected to Watson Discovery to complement the dialog with searching into a knowledge corpus and to an event driven service which can aggregate the business application states: When an end user is complaining about not able to access a given business application, the Conversation could generate an action, which will lead to get real time state of the application. This state management is supported by Operational Decision Management Advanced which is a complex event processing platform. See proposed enhancement in 40 | 41 | The dialog is stateless, meaning that it does not retain information from one interchange to the next. Your application is responsible for maintaining any continuing information. However, the application can pass information to the dialog, and the dialog can update the context information and pass it back to the application. So each conversation solution needs to include this service orchestration to control data gathering and dialog context. 42 | -------------------------------------------------------------------------------- /doc/design/empathy-map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/design/empathy-map.png -------------------------------------------------------------------------------- /doc/design/itsupport-persona.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/design/itsupport-persona.png -------------------------------------------------------------------------------- /doc/design/syst-ctx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/design/syst-ctx.png -------------------------------------------------------------------------------- /doc/dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/dialog.png -------------------------------------------------------------------------------- /doc/icp/README.md: -------------------------------------------------------------------------------- 1 | # Deploy Conversation Broker to IBM Cloud Private 2 | We propose to package the code as a docker image, build a helm chart and then publish it to an ICP instance. To support higher availability we propose to have 3 replicas for the application, and expose it, via Ingress rule, so it can be visible outside of the ICP cluster. The target deployment may look like the following diagram where the webapp is running in pod as container and is deployed in 3 instances to support high availability: 3 | ![](cyan-on-icp.png) 4 | 5 | ## Prerequisites 6 | If you do not have an ICP installed you can use the following [note](https://github.com/ibm-cloud-architecture/refarch-cognitive/blob/master/doc/icp/README.md) to do a 'developer' installation of ICP Community Edition. 7 | 8 | ## Build 9 | This project includes a docker file to build a docker image of the broker micro-service. You can build the image to your local repository using the command: 10 | ``` 11 | # first build the App 12 | $ npm run build 13 | $ docker build -t ibmcase/wcsbroker . 14 | $ docker images 15 | ``` 16 | Then tag your local image with the name of the remote server where the docker registry resides, and the namespace to use. (`mycluster.icp:8500` is the ICP master server name) 17 | ``` 18 | $ docker tag ibmcase/wcsbroker mycluster.icp:8500/cyancompute/wcsbroker:v0.0.1 19 | $ docker images 20 | ``` 21 | An image with the scope namespace is only accessible from within the namespace that it was pushed to. 22 | 23 | ## Push docker image to ICP private docker repository 24 | 25 | If you have copied the ICP master host certificate / public key to the /etc/docker/certs.d/: folder on you local computer, you should be able to login to remote docker engine. (If not see this section: [Access ICP docker](https://github.com/ibm-cloud-architecture/refarch-integration/blob/master/docs/icp/README.md#access-to-icp-private-repository)) Use a user known by ICP. 26 | ``` 27 | docker login mycluster.icp:8500 28 | User: admin 29 | ``` 30 | Push the image 31 | ``` 32 | docker push mycluster.icp:8500/cyancompute/wcsbroker:v0.0.1 33 | ``` 34 | More informations could be found [here](https://www.ibm.com/developerworks/community/blogs/fe25b4ef-ea6a-4d86-a629-6f87ccf4649e/entry/Working_with_the_local_docker_registry_from_Spectrum_Conductor_for_Containers?lang=en) 35 | 36 | ## Build the helm package 37 | Helm is a package manager to deploy application and service to Kubernetes cluster. Package definitions are charts which are yaml files to be shareable between teams. 38 | 39 | The first time you need to build a chart for the web app. Select a chart name (casewcsbroker) and then use the command: 40 | ``` 41 | cd chart 42 | helm init casewcsbroker 43 | ``` 44 | 45 | This creates yaml files and simple set of folders. Those files play a role to define the configuration and package for kubernetes. Under the templates folder the yaml files use parameters coming from helm, the `values.yaml` and `chart.yaml`. 46 | 47 | ### Chart.yaml 48 | This is a global parameter file. Set the version and name attributes, they will be used in `deployment.yaml`. Each time you deploy a new version of your app you can just change the version number. The values in the `Chart.yaml` are used in the templates. 49 | 50 | ### Add configMap templates 51 | The broker micro service uses external configuration file, `config.json` to define parameters to access remote end points. When running on container within kubernetes it is good practice to externalize application configuration in `config map`. To do so we need to create a new template **templates/configmap.yaml**. This file uses the same structure as the config.json file but externalizes the parameter values from the values.yaml so that developer can changes only one file to control the configuration. 52 | 53 | ```yaml 54 | apiVersion: v1 55 | kind: ConfigMap 56 | metadata: 57 | name: {{ template "fullname" . }} 58 | labels: 59 | chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" 60 | data: 61 | config.json: |+ 62 | { 63 | "conversation" :{ 64 | "version" : "{{ .Values.config.conversation.version }}", 65 | "versionDate": "{{ .Values.config.conversation.versionDate }}", 66 | "username": "{{ .Values.config.conversation.username }}", 67 | "password": "{{ .Values.config.conversation.password }}", 68 | "workspace1":"{{ .Values.config.conversation.workspace1 }}", 69 | "workspace2":"{{ .Values.config.conversation.workspace2 }}", 70 | "workspace3":"{{ .Values.config.conversation.workspace3 }}", 71 | "conversationId": "{{ .Values.config.conversation.conversationId }}", 72 | "usePersistence": "{{ .Values.config.conversation.usePersistence }}" 73 | }, 74 | 75 | ``` 76 | ### Modify deployment.yaml 77 | To 'ingect' the configuration from the configMap to the server nodejs app, the trick is to specify that the `config.json` file is coming from a logical volume. To do so we need to define a Volume to mount to the config.json file in the deployment.yaml as the following: 78 | In the deployment.yaml we add a volumeMount point to the container specification: 79 | 80 | ```yaml 81 | spec: 82 | containers: 83 | - name: {{ .Chart.Name }} 84 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" 85 | imagePullPolicy: {{ .Values.image.pullPolicy }} 86 | ports: 87 | - containerPort: {{ .Values.service.internalPort }} 88 | volumeMounts: 89 | - name: config 90 | mountPath: /wcsbroker/server/config.json 91 | subPath: config.json 92 | ``` 93 | the path `/wcsbroker` comes from the dockerfile, working directory declaration. 94 | 95 | ```docker 96 | COPY . /wcsbroker 97 | WORKDIR /wcsbroker 98 | ``` 99 | so the mountPath will overwrite the `config.json` file. 100 | 101 | The volume name (config) is arbitrary but needs to match a volume declared later in the deployment.yaml. 102 | 103 | ```yaml 104 | 105 | volumes: 106 | - name: config 107 | configMap: 108 | name: {{ template "fullname" . }} 109 | ``` 110 | One volume, named `config` uses the configMap named using the template name of the helm package and match the configMap we defined above. 111 | 112 | ### Service and ingress 113 | To expose the broker to other components deployed into the cluster we need to declare a service. `Services` group a set of pods and provide network connection to these pods for other services in the cluster without exposing the actual private IP address of each pod. As Pods are ephemeral in nature, resources like IP addresses allocated to it cannot be static. You can use Kubernetes services to make an app available to other pods inside the cluster or to expose an app to the internet or private network. This a decoupling capability. 114 | 115 | Each Service also gets an IP address (known as ClusterIP), which is routable only inside the cluster. A Service does the load balancing while selecting the Pods for forwarding the data/traffic. It uses the `labels` attribute to get the pods (see the declaration `spec.selector.app` below). 116 | 117 | The templates/service.yaml was create by the command `helm create casewcsbroker`. 118 | ```yaml 119 | spec: 120 | type: {{ .Values.service.type }} 121 | ports: 122 | - port: {{ .Values.service.externalPort }} 123 | targetPort: {{ .Values.service.internalPort }} 124 | protocol: TCP 125 | name: {{ .Values.service.name }} 126 | selector: 127 | app: {{ template "fullname" . }} 128 | ``` 129 | The `port` is the port number the service will be seen, while target port is the one of the webapp running in the pod. In `values.yaml` file the ports are set as 130 | ```yaml 131 | service: 132 | name: wcsbrokersvc 133 | type: ClusterIP 134 | externalPort: 6100 135 | internalPort: 6100 136 | ``` 137 | The type `ClusterIP` for the service exposes it on a cluster internal IP network. It is reachable only from within the cluster. The routing is managed by the kube-proxy component in each worker nodes using Iptables. ClusterIP addresses are set by the master node when the services are created. 138 | 139 | `Ingress` was introduce in k8s v1.1 and provide load balancing, SSL and name-based virtual hosting. It is a collection of rules that allow inbound connections to reach the cluster services using HTTP protocol. It is a OSI layer 7 service. 140 | There is one important component to make implement the service contract of ingress: the ingress controller. In ICP it is a `nginx ingress` controller running in the proxy node that will implement the load balancing. 141 | 142 | The templates/ingress.yaml file created defines a rule to route traffic 143 | ``` 144 | spec: 145 | rules: 146 | {{- range $host := .Values.ingress.hosts }} 147 | - host: {{ $host }} 148 | http: 149 | paths: 150 | - path: / 151 | backend: 152 | serviceName: {{ $serviceName }} 153 | servicePort: {{ $servicePort }} 154 | {{- end -}} 155 | ``` 156 | This ingress configuration will be POSTed to the API server running in k8s master node. Each rule matches against all incoming requests arriving to the master node. the `backend` is a service:port combination as described in the service. 157 | 158 | 159 | ### values.yaml 160 | Specify in this file the docker image name and tag as you deployed into the docker private registry. 161 | ```yaml 162 | iimage: 163 | repository: mycluster.icp:8500/cyancompute/wcsbroker 164 | tag: v0.0.1 165 | pullPolicy: Always 166 | ``` 167 | 168 | Try to align the number of helm package with docker image tag. 169 | 170 | Finally declare the config values to point to the conversation parameters: 171 | ```yaml 172 | config: 173 | conversation: 174 | version : v1 175 | versionDate: 2017-02-03 176 | username: 291d9e533... 177 | password: aDFBlD... 178 | workspace1: 1a3bfc1... 179 | conversationId: ITSupportConversation 180 | usePersistence: false 181 | ``` 182 | 183 | 184 | ## Build and deploy the application package with helm 185 | ``` 186 | $ cd chart 187 | $ helm lint casewcsbroker 188 | # if you do not have issue ... 189 | $ helm install --name wcsbroker --namespace cyancompute casewcsbroker 190 | 191 | LAST DEPLOYED: Tue Nov 21 10:53:58 2017 192 | NAMESPACE: cyancompute 193 | STATUS: DEPLOYED 194 | 195 | RESOURCES: 196 | ==> v1beta1/Ingress 197 | NAME HOSTS ADDRESS PORTS AGE 198 | wcsbroker-casewcsbroker wcsbroker.cyan.case 172.16.40.31 80 5m 199 | 200 | ==> v1/ConfigMap 201 | NAME DATA AGE 202 | wcsbroker-casewcsbroker 1 7m 203 | 204 | ==> v1/Service 205 | NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE 206 | wcsbroker-casewcsbroker 10.101.0.80 3001/TCP 7m 207 | 208 | ==> v1beta1/Deployment 209 | NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE 210 | wcsbroker-casewcsbroker 3 3 3 0 7m 211 | 212 | 213 | NOTES: 214 | 1. Get the application URL by running these commands: 215 | export POD_NAME=$(kubectl get pods --namespace cyancompute -l "app=wcsbroker-casewcsbroker" -o jsonpath="{.items[0].metadata.name}") 216 | echo "Visit http://127.0.0.1:8080 to use your application" 217 | kubectl port-forward $POD_NAME 8080:3001 218 | ``` 219 | From the above we can see that a deployment was created in kubernetes, the `casewcsbroker` container runs on three pods and a service got created to expose the deployment on the node at the cluster IP `10.101.0.80`. The NOTES section tells us how to access the pod from our local machine from port 8080. Connection made on the localhost port 8080 are forwarded to port 3001 of the pod. This is one way to test the application. 220 | 221 | ![](helm-install-out.png) 222 | From the above we can see that a deployment was created in kubernetes, the casewcsbroker runs on one pod and a service got created to expose the deployment on the cluster IP on port 3001. And the NOTES section tells us how to access the pod. 223 | 224 | You can login to ICP console and look at the Workload > Helm Release 225 | ![](app-deployed.png) 226 | 227 | ### Use helm upgrade 228 | When you want to change the version of the application: 229 | ``` 230 | $ helm list --namespace cyancompute 231 | $ helm upgrade wcsbroker 232 | ``` 233 | 234 | ### Verify the app is deployed 235 | ``` 236 | helm ls --all casewcsbroker 237 | ``` 238 | Point a web browser to http://wcsbroker.cyan.case to access the Application. Be sure to modify your local /etc/hosts file to map the name to the IP address of the cluster proxy server. Or use a new DNS entry with the same mapping. 239 | -------------------------------------------------------------------------------- /doc/icp/cyan-on-icp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/icp/cyan-on-icp.png -------------------------------------------------------------------------------- /doc/integrate-bpm.md: -------------------------------------------------------------------------------- 1 | # Integrate with BPM 2 | A business process can expose a web service end point to be callable from a remote soap client. As illustrated in the [demonstration flow](demoflow.md) the conversation is getting company name and product name and then trigger the process. The creation of the process is in fact a call to the exposed SOAP service. 3 | 4 | The client code is in the server/routes/features supplier-bpm-client.js. The exported function has two parameters: the company name and product name. The method prepare the SOAP envelope and a SOAP body which is based on the WSDL of the web service. 5 | 6 | ```javascript 7 | exports.callBPMSupplierProcess = function(company,product) { 8 | var xmlBody = ''+ 9 | ''+ 10 | ''+ 11 | ''+ 12 | ''+ company+''+ 13 | '' + product+ ''+ 14 | ''+ 15 | ''+ 16 | ''; 17 | console.log(xmlBody); 18 | request.post( 19 | {url:'https://'+config.bpmoc.serverName 20 | + '/bpm/dev/teamworks/webservices/' 21 | + config.bpmoc.processName, 22 | body : xmlBody, 23 | headers: {'Content-Type': 'text/xml', 24 | 'Authorization': 'Basic ' + config.bpmoc.basicAuth 25 | } 26 | }, 27 | function (error, response, body) { 28 | if (!error && response.statusCode == 200) { 29 | console.log(response.body) 30 | } 31 | } 32 | ); 33 | } 34 | ``` 35 | 36 | The URL for the BPM on cloud server is define in the env.json configuration file. 37 | *This code will be protected by circuit breaker in the future.* 38 | 39 | The orchestration logic is integrate in the response management from Watson Conversation call. This code is in api.js and is looking at the conversation **context** json object to access some variable defined by the conversation developer: 40 | 41 | ```javascript 42 | ... 43 | if (rep.context.action === "trigger" 44 | && rep.context.actionName === "supplierOnBoardingProcess") { 45 | bpmoc.callBPMSupplierProcess(rep.context.customerName,rep.context.productName); 46 | } 47 | ``` 48 | the action name is the business process name and the action *trigger*, so delegate the processing to the BPM client. 49 | -------------------------------------------------------------------------------- /doc/istio.md: -------------------------------------------------------------------------------- 1 | # istio integration 2 | 3 | # Installation 4 | * Download istio from [release page](https://github.com/istio/istio/releases) 5 | * Follow the installation instruction [here]() 6 | Some updates to complete the installation on minikube. 7 | * Add the Role and Cluster role as defined in yaml file: install/kubernetes/istio-rbac-beta.yaml. (The apply command may not work as stated in istio doc.) 8 | ``` 9 | $ kubectl create -f install/kubernetes/istio-rbac-beta.yaml 10 | 11 | clusterrole "istio-pilot" created 12 | clusterrole "istio-ca" created 13 | clusterrole "istio-sidecar" created 14 | clusterrolebinding "istio-pilot-admin-role-binding" created 15 | clusterrolebinding "istio-ca-role-binding" created 16 | clusterrolebinding "istio-ingress-admin-role-binding" created 17 | clusterrolebinding "istio-egress-admin-role-binding" created 18 | clusterrolebinding "istio-sidecar-role-binding" created 19 | ``` 20 | * Installed istio without Auth 21 | ``` 22 | kubectl apply -f install/kubernetes/istio.yaml 23 | 24 | configmap "istio-mixer" created 25 | service "istio-mixer" created 26 | deployment "istio-mixer" created 27 | configmap "istio" created 28 | service "istio-pilot" created 29 | serviceaccount "istio-pilot-service-account" created 30 | deployment "istio-pilot" created 31 | service "istio-ingress" created 32 | serviceaccount "istio-ingress-service-account" created 33 | deployment "istio-ingress" created 34 | service "istio-egress" created 35 | serviceaccount "istio-egress-service-account" created 36 | deployment "istio-egress" created 37 | ``` 38 | 39 | * Enabled tracing 40 | Grafana addon provides an Istio dashboard visualization of the metrics. 41 | 42 | The ServiceGraph addon provides a textual (JSON) representation and a graphical visualization of the service interaction graph for the cluster. 43 | 44 | ``` 45 | $ kubectl apply -f install/kubernetes/addons/prometheus.yaml 46 | 47 | configmap "prometheus" created 48 | service "prometheus" created 49 | deployment "prometheus" created 50 | 51 | $ kubectl apply -f install/kubernetes/addons/grafana.yaml 52 | $ kubectl apply -f install/kubernetes/addons/servicegraph.yaml 53 | ``` 54 | 55 | 56 | # Run in minikube 57 | Be sure to start minikube with Role Base Access Control mode: 58 | `minikube start --extra-config=apiserver.Authorization.Mode=RBAC` 59 | -------------------------------------------------------------------------------- /doc/persistence.md: -------------------------------------------------------------------------------- 1 | # Persisting the conversation 2 | An important feature for a conversation broker micro service is to be able to persist the conversation interactions into a document oriented database so that developers and business analysts can identify when the conversation dialog flow was not able to address the user's query. In this article we are presenting how to persist the Watson Conversation Response to a Bluemix CloudandDB database and also how to use an internal / on-premise data source to persist the conversation 3 | 4 | # Bluemix Cloudant Integration 5 | The approach is to add a feature into the server layer to implement the [Data Access Object](https://en.wikipedia.org/wiki/Data_access_object) pattern that can be enabled easily in the router layer of the broker. The DAO is using the Cloudant API to access an Cloudant instance running in Bluemix. 6 | ![](wcs-save-cloudant.png) 7 | 8 | ## Pre-requisites 9 | To be able to persist on Bluemix Cloudant service you need to add such a service. The steps are: 10 | * In Bluemix Catalog use the 'Data & Analytics' choices under the Services. Select Cloudant NoSQL DB, specify a name and create the service. 11 | * Launch the Database tools from the newly created service and add a new database called: 'wcsdb' 12 | * Get the service credential for username and password and URL as illustrated in figure below, you will need them for the data access layer component added to the Conversation broker 13 | ![credentials](cloudant-cred.png) 14 | 15 | ## Bluemix Cloudant Integration 16 | 17 | The script on the server side is server/routes/features/persist.js. It uses the javascript cloudant client library, define the database 18 | ```javascript 19 | var config = require('../env.json'); 20 | const cloudant = require('cloudant')(config.dbCredentials.url); 21 | var db = cloudant.use('wcsdb'); 22 | ``` 23 | 24 | and then expose a set of CRUD functions: 25 | ```javascript 26 | saveConversation : function(conv,next){ 27 | if (conv.context !== undefined) { 28 | if (conv.context.revId !== undefined) { 29 | conv._id=conv.context.persistId; 30 | conv._rev=conv.context.revId; 31 | 32 | } 33 | } 34 | db.insert(conv, function(err, data) { 35 | if (err) { 36 | next({error: err.message}); 37 | } else { 38 | next(data); 39 | } 40 | }); 41 | }, 42 | ``` 43 | The code above is using the _id and _rev attributes of the persisted conversation so call to db.insert will update existing record/document when the document is already there. When there is no _id a new documented is added. This update mechanism is important to keep a unique conversation document for each interaction with Watson Conversation. The content of the conversation includes the path and nodes visited during the interactions. 44 | ``` 45 | "_node_output_map": { 46 | "Start the conversation": [ 47 | 0 48 | ], 49 | "Otherwise": [ 50 | 0 51 | ], 52 | "node_4_1489854990975": [ 53 | 0 54 | ], 55 | "Watson trigger the process": [ 56 | 0 57 | ], 58 | "node_1_1492819089967": [ 59 | 0 60 | ], 61 | "node_1_1496247132094": [ 62 | 0 63 | ] 64 | }, 65 | "branch_exited": true, 66 | "branch_exited_reason": "completed" 67 | 68 | ``` 69 | The dialog flow developer can use this information to tune the flow, address new case / intent or scope out requests. 70 | 71 | The database configuration is done inside a env.json file 72 | ``` 73 | "dbCredentials" : { 74 | "url": "https://username:pwd@xxxxx-bluemix.cloudant.com" 75 | }, 76 | "usePersistence": true 77 | ``` 78 | 79 | # Persist Conversation on an On-premise database 80 | The alternative is to use an on-premise data base to keep conversation trace behind the firewall. The hybrid integration is generally demonstrated and validated by the following architecture [content](https://github.com/ibm-cloud-architecture/refarch-integration), using API Connect, Secure Gateway and Exposed data access layer API. For this DAO the schema may look like the diagram below: 81 | ![](wcs-save-on-prem.png) 82 | The DAO is using Request javascript module to do HTTP calls to a secure gateway configured in Bluemix, which get connection from a Secure Gateway Client running on one of the internal, behind the firewall, server. You can read details on configuration from Hybrid integration github repository [here](https://github.com/ibm-cloud-architecture/refarch-integration-utilities/blob/master/docs/ConfigureSecureGateway.md) 83 | 84 | The secure gateway destination can be the API Connect gateway server with API URLs specified as part of an API product. The API may be a pass through or performing an interface mapping between REST and other protocol. Using more recent technology the back-end can expose REST api directly on top of a document oriented DB. If the choice is to design a relational database, then you need to take care of the structure as the content from conversation can change overtime with new product version, and the context object, being an open JSON object, any structure can be defined during the Watson Conversation design time. 85 | -------------------------------------------------------------------------------- /doc/readme/WCS-ra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/readme/WCS-ra.png -------------------------------------------------------------------------------- /doc/readme/angular2-comps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/readme/angular2-comps.png -------------------------------------------------------------------------------- /doc/readme/angular2-nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/readme/angular2-nodejs.png -------------------------------------------------------------------------------- /doc/readme/trigger-from-wcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/readme/trigger-from-wcs.png -------------------------------------------------------------------------------- /doc/tutorial/Add-condition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/Add-condition.png -------------------------------------------------------------------------------- /doc/tutorial/Add-greetings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/Add-greetings.png -------------------------------------------------------------------------------- /doc/tutorial/Ask-Watson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/Ask-Watson.png -------------------------------------------------------------------------------- /doc/tutorial/README-new.md: -------------------------------------------------------------------------------- 1 | # IT Support Chat bot Tutorial 2 | 3 | Implement a simple **IT support** help-me conversation chatbot. The chatbot helps to streamline IT support queries by automating the dialog flow. 4 | Updates: 10/03/2017 5 | 6 | ## Business use case 7 | The support director wants to modernize the way to support internal staff and offload his team from basic work. Currently 20000 tickets are issued in a year. 50% of the calls are answered in 7 minutes whereas there are many situations that reach up to 70 minutes for resolution. 92% of the calls are resolved by level 1 support. Employees of the Case Inc engage with customer support mostly through phones. Today, call center agents struggle to find some of the answers in a timely fashion as the systems are not integrated. This results in loss of productivity and frustration on the part of the bank employees. Level 1 support team get frustrated at times because of unavailability of the right information and proper guidance. The Level 1 support has to consult the Level 2 support team members to get some answers. 8 | 9 | As presented in the [Watson Conversation reference architecture diagram](https://www.ibm.com/devops/method/content/architecture/cognitiveArchitecture) this tutorial addresses the Ground Truth development with the conversation flow design (E) and the run time processing (4,7), integrated with chatbot interface (1), and controlled by the application logic - or **broker** micro service. 10 | ![Reference Architecture Diagram](wcs-ra.png) 11 | 12 | ## Table of Contents 13 | This tutorial was ported to the IBM Cloud Garage method tutorial web site at https://www.ibm.com/devops/method/tutorials/watson_conversation_support. 14 | In this tutorial, you complete the following tasks: 15 | 16 | * [What is Watson Conversation (Quick Summary)](#watson-conversation-quick-summary) 17 | * [Create Watson conversation service](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=1) and [workspace](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=2) 18 | * [Defining intents to help natural language processing](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=3) 19 | * [Unit test intents](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=4) 20 | * [Add entities to improve language understanding](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=5) 21 | * [Building simple dialog flow](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=6) 22 | * [Using the context object for more advanced dialog](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=7) 23 | * [Using the api](#task-8---using-api) 24 | 25 | 26 | # Watson Conversation Quick Summary 27 | To have a quick understanding of Watson Conversation, you may want to read the [product overview](https://www.ibm.com/watson/developercloud/doc/conversation/index.html) section. 28 | ![Conversation Components](wcs-view.png) 29 | 30 | As a summary, you use the Watson Conversation service to create **chatbot**. This is the generic term for a piece of software that provides automated responses to user input. The bot is hosted in the cloud and is highly available. All the information that defines your bot's behavior is contained in a **workspace**. 31 | 32 | You create an **application** that enables your users to interact with the bot. The application passes user's input to the bot, possibly with some additional context information, and presents responses from the bot to the user. 33 | 34 | The bot is **stateless**, that is, it does not retain information from one interchange to the next. The application is responsible for maintaining any continuing information. However, the application can pass information to the bot, and the bot can update the **context** information and pass it back to the application. 35 | 36 | The bot uses natural language understanding and machine learning to extract meaning from the user's input. This process identifies the user's **intent**, which is the goal or purpose of the asked question. It can also identify an **entity**, which is a term, a noun that is mentioned in the input and narrow the purpose of the request. You train your bot to recognize intents and entities in the input submitted by users. To train your bot on intents, you supply lots of examples of user's input and indicate which intents they map to. 37 | 38 | To train your bot on entities, you list the values for each entity and synonyms that users might enter. 39 | Note: the names of intents and entities, and the text of examples, values, and synonyms, can be exposed in URLs when an application interacts with your bot. Do not store sensitive or personal information in these artifacts. 40 | As you add information, the bot trains itself; you do not have to take any action to initiate the training. 41 | 42 | Finally, after you train your system to recognize intents and entities, you teach it how to respond when it recognizes those intents and entities. You use the **dialog** builder to create conversations with users, providing responses based on the intents and entities that the bot recognizes in their inputs. A dialog is composed of multiple flows and subFlows to design the multiple interactions of the conversation. Intent is supported by a dialog flow. 43 | 44 | You should also read [Cognitive Conversation introduction](https://www.ibm.com/devops/method/content/architecture/cognitiveConversationDomain) 45 | 46 | # Hands on lab - Step by step 47 | As mentioned above the training was ported to the Garage Method [Tutorial section](https://www.ibm.com/devops/method/tutorials/watson_conversation_support) so you should follow the step by step instruction from this web site, but as new product capabilities were introduced since the last publish, we are specifying below some change to the tutorial that will stay here until they are ported to the method web site. 48 | 49 | ## Task 1 - Create Conversation Service 50 | New screen shots: 51 | ![](bmx-watson-serv.png) 52 | 53 | ![](bmx-conv-tool.png) 54 | 55 | ## Task 2 - Creating a workspace 56 | New screen 57 | ![](wcs-conv-wksp.png) 58 | 59 | ## Task 3 - Creating intents 60 | 61 | New screens 62 | 63 | ![Intents](wcs-build-intents.png) 64 | 65 | ![Questions](wcs-intent-question.png) 66 | 67 | ![goodbyes](goodbyes-intent.png) 68 | 69 | ![greetings](greetings.png) 70 | 71 | ## Task 4 - Intent Unit testing 72 | 73 | New screens 74 | ![Ask Watson](Ask-Watson.png) 75 | 76 | ![try it](tryitout.png) 77 | 78 | 79 | ## Task 5 - Adding entities 80 | New screens 81 | ![](wcs-entities-panel.png) 82 | 83 | ![entities](wcs-entities.png) 84 | 85 | ![Test entity](ut-app-abc.png) 86 | 87 | ## Task 6 - Building the dialog 88 | New screens 89 | ![Dialog](wcs-dialog.png) 90 | 91 | ![](wcs-two-nodes.png) 92 | 93 | ### Defining Greetings node 94 | 95 | The first node, named Welcome, is executed when conversation starts. As we have defined the **#greeting** intent, you want to add a new node to do something when Watson Conversation classifies the user input to be a greeting. So select the `welcome` node and click to the `Add node below` menu choice: 96 | ![](Add-greetings.png) 97 | 98 | 99 | ![Greeting Node](wcs-diag-greeting.png) 100 | 101 | 102 | ![Dialog-ut](wcs-diag-ut.png) 103 | 104 | At each node level, you can expand the conversation by adding node at the same level, and the flows will be parallel or by adding a child node to create a dependent track of conversation, so the conversation branches out into a tree structure. 105 | 106 | ### Managing Anything else use case 107 | 108 | ![](wcs-otherwise.png) 109 | 110 | ![](wcs-otherwisejson.png) 111 | 112 | ### Defining the 'access application' dialog flow 113 | Click the "Handle Greetings" node and then click **Add node below** menu item. Name the new node Handle application access... 114 | 115 | ![Add node](add-app-acc-node.png) 116 | 117 | 118 | ![](Add-condition.png) 119 | 120 | ![Abc Access](app-access-conditions.png) 121 | 122 | 123 | ![Unit testing AbC access](wcs-diag-abc-ut.png) 124 | 125 | 126 | The evaluation round works in two stages. In the first stage, the dialog tries to find an answer in the child nodes of the contextual node. That is, the dialog tries to match all the conditions of the child nodes of the contextual node. If the final condition has a condition of "true," meaning that it is to be used if none of its siblings are matched, that node's response is processed. 127 | 128 | 129 | ## Task 7 - Advanced Dialog Work 130 | In this task the following is updated: 131 | 132 | ### Adding variables to context 133 | Suppose you want to return an actionable URL, meaning that the response includes a URL variable that the user can click to go to a new page. To try this scenario, you will present the URL of a business process that is deployed on IBM BPM on Cloud. 134 | 135 | If you did not import the intents definition from the lab csv file, you need to add a new intent to support the user's query about accessing the "Supplier on boarding business process". 136 | ![Supplier on boarding](supplier-intent.png) 137 | 138 | Add a new node to the dialog flow under the **Application access** node. Named it **Handling supplier on boarding**, specify the intent, **#SupplierOnBoarding** and then in the response access the Advanced editor so we can edit the *json* response object: 139 | 140 | ![Supplier node](supplier-node.png) 141 | 142 | The response object includes an *output* object with the text to present and a *context* object. The *context* object has new variable named *url* to give IBM BPM on Cloud access and an *action* variable to control the behavior of the broker code. When the user enters a question like "I want to access the supplier on boarding business process,” the returned object looks like this example: 143 | ```json 144 | {"intents": [ 145 | { 146 | "intent": "supplieronboarding", 147 | "confidence": 0.940047025680542 148 | } 149 | ], 150 | "entities": [ 151 | { 152 | "entity": "supplier", 153 | "value": "supplier" 154 | } 155 | ], 156 | "input": { 157 | "text": " I want to access the supplier on boarding business process" 158 | }, 159 | "output": { 160 | "log_messages": [], 161 | "text": [ 162 | "To access the Supplier On Boarding business process use the url: " 163 | ], 164 | "nodes_visited": [ 165 | "Supplier On Boarding", 166 | "Provide URL for Supplier on boarding" 167 | ] 168 | }, 169 | "context": { 170 | "conversation_id": "Conversation-ut", 171 | "system": { 172 | "dialog_stack": [ 173 | { 174 | "dialog_node": "root" 175 | } 176 | ], 177 | "dialog_turn_counter": 1, 178 | "dialog_request_counter": 1 179 | }, 180 | "url": "https://vhost001.bpm.ibmcloud.com/bpm/dev/ProcessPortal/dashboards/SYSRP/RESPONSIVE_WORK", 181 | "action":"click" 182 | } 183 | } 184 | ``` 185 | The code that calls the Watson Conversation API can take the URL value and create a hyperlink in HTML so that the display has an actionable link 186 | ```javascript 187 | if (rep.context.url != undefined) { 188 | if (rep.context.action === "click") { 189 | rep.text=rep.output.text[0] + "Here" 190 | } 191 | } 192 | ``` 193 | The actionable link is shown in the last interaction, with the clickable button added to the message: 194 | ![](click-url.png) 195 | Much can be done on the context object. For example, the application code can add elements in the context object before it calls the Conversation service. Then, at the condition level in a node, tests can be done on those elements. 196 | 197 | To use a context variable in your condition, use one of these formats: 198 | ``` 199 | $variable_name:value 200 | $variable_name == 'value' 201 | ``` 202 | The value of the condition might have been set by the application or in the response portion of a previous dialog node. In the next test, the canAccessSOD context variable is a Boolean that is set by accessing an internal authorization service that, for example, returns true if a user ID can access an application. 203 | 204 | ### Using slots 205 | This section replaces 'add a hierarchical flow'. 206 | 207 | In this section we will add a dialog flow to address when a user wants to bring his own device. We will support only certain brand and device. So we need to get those information. What we want to achieve could be illustrated by the following dialog: 208 | ![](byod-ut.png) 209 | From the first query: "I want to bring my phone", Watson Conversation was able to get the **#BYOD** intent and the entity **@deviceType:phone**, so the dialog flow ask the brand of the device. If the device type was not extracted it will have ask a question about the type of device the user wants to bring. 210 | 211 | A older way to support this different combination is to add a hierarchy of nodes and code the conditions on entity. Since the August release, there is the **slot** concept makes it more simple to implement. Use slots to get the information you need before you can respond accurately to the user. 212 | 213 | 1. If you did not import the intent and entities before, create a new entity for bring your own device question, like illustrated below: 214 | ![byod](byod.png) 215 | 1. Create the entities @deviceBrand and @deviceType: 216 | ![device-brand](device-brand.png) 217 | 218 | ![device-type](device-type.png) 219 | 1. Add a new flow, by adding a top level node, with the `#BYOD` intent as recognize condition/ Select the Customize menu on the right to enable slots for this node: 220 | ![](slot-enabled.png) 221 | 222 | Once done the condition part changes to **Then check for:** 223 | ![](byod-node1.png) 224 | 225 | You should be able to add 2 slots: 226 | * Check for entity @deviceBrand, save the result in a context variable named **$deviceBrand**, and if not present ask: "What is the brand of your device?" 227 | * Check for the entity @deviceType, saved in **$deviceType** with question: "What is the type of your device (tablet, smartphone, computer)?" 228 | 229 | Slots make it possible for the service to answer follow-up questions without having to re-establish the user's goal. 230 | 231 | For the response part you can use the advanced dialog to enter a output text to display the content of the device type and brand: 232 | ![](byod-resp.png) 233 | 234 | Be sure to set to *wait for user input* in the *And then* action part. 235 | 236 | ### Using interaction to get parameters to call a web service 237 | The last example is more complex, but it represents a common pattern: in the context of a dialog flow, the set of interactions aim to gather input parameters so that after the interaction is done, the broker code can call a web service and pass the parameters as part of the payload. 238 | 239 | In this example, the BPM supplier onboarding process can be triggered via a SOAP call. There are two input parameters: the company name and the product name. The client code is in the conversation broker code as a feature in the server/routes/features/supplier-bpm-client.js file. 240 | 241 | As the focus is on the dialog, you must modify the previous flow to handle the 'Supplier process' intent. The first node asks whether the user wants the chatbot to trigger the process, as shown in this image: 242 | ![](supplier-node.png) 243 | 244 | When the response is no, you use the previous behavior by providing the URL to BPM Process portal so that the user can start the process manually. 245 | ![](supplier-node-no.png) 246 | 247 | When the response is yes, the two next interactions are used to get the company name and product name. You can try to reproduce the following structure 248 | ![](get-parameters.png) 249 | 250 | Outside of the output.text which provides a question about the company, the context uses two variables to help driving the broker code: the action is set to getVar and the varname to the name of the variable to add to the context via code. The following figure illustrates that on a **yes** response the bot will ask about the supplier node. 251 | ![](supplier-node-yes.png) 252 | 253 | The broker code dynamically adds the specified variable in the context to keep the data for the next interaction. The following code is in the function to manage the user's response before it calls the Conversation service: 254 | 255 | ```javascript 256 | if (req.body.context.action === "getVar") { 257 | req.body.context[req.body.context.varname] = req.body.text; 258 | } 259 | ``` 260 | 261 | The same approach is done in for the product name: 262 | 263 | ![](get-product-name.png) 264 | 265 | During the dialog execution if the end user does not give the product or the company name, a specific node in the dialog flow identify the missing parameters and routes back the dialog flow to the node asking for the missing parameter. The figure below illustrates the 'Jump to...' constraint added to the node definition so the dialog flow goes back to the 'Get Product name' node. 266 | 267 | ![](no-product-name.png) 268 | 269 | Finally when all the parameters are set the interaction set the action to **trigger**, so the broke call can perform the soap call to the service. 270 | 271 | ![](trigger-process.png) 272 | 273 | ## Task 8 - Using API 274 | To use API you need the service credential and use tool to preform HTTP request. See this separate [instructions](../use-apis.md). 275 | 276 | For understanding the **broker** code see [this section of the readme](https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker#code-explanation) 277 | 278 | ## Final solution 279 | If you need to see the current solution, load the exported conversation workspace as json file into your Conversation tools. The file is under **./wcs-workspace/ITsupport-workspace.json**. 280 | 281 | ## Learn More 282 | * A super simple chat bot designed for customer service [here](https://www.ibm.com/blogs/watson/2016/12/build-chat-bot) 283 | * Watson Conversation simple [Product tutorial](https://www.ibm.com/watson/developercloud/doc/conversation/tutorial.html) 284 | -------------------------------------------------------------------------------- /doc/tutorial/README.md: -------------------------------------------------------------------------------- 1 | # IT Support Chat bot Tutorial 2 | 3 | Implement a simple **IT support** help-me conversation chatbot. The chatbot helps to streamline IT support queries by automating the dialog flow. 4 | Updates: 10/03/2017 5 | 6 | ## Business use case 7 | The support director wants to modernize the way to support internal staff and offload his team from basic work. Currently 20000 tickets are issued in a year. 50% of the calls are answered in 7 minutes whereas there are many situations that reach up to 70 minutes for resolution. 92% of the calls are resolved by level 1 support. Employees of the Case Inc engage with customer support mostly through phones. Today, call center agents struggle to find some of the answers in a timely fashion as the systems are not integrated. This results in loss of productivity and frustration on the part of the bank employees. Level 1 support team get frustrated at times because of unavailability of the right information and proper guidance. The Level 1 support has to consult the Level 2 support team members to get some answers. 8 | 9 | As presented in the [Watson Conversation reference architecture diagram](https://www.ibm.com/devops/method/content/architecture/cognitiveArchitecture) this tutorial addresses the Ground Truth development with the conversation flow design (E) and the run time processing (4,7), integrated with chatbot interface (1), and controlled by the application logic - or **broker** micro service. 10 | ![Reference Architecture Diagram](wcs-ra.png) 11 | 12 | 13 | This tutorial was ported to the IBM Cloud Garage method tutorial web site at https://www.ibm.com/devops/method/tutorials/watson_conversation_support. 14 | In this tutorial, you complete the following tasks: 15 | 16 | * [What is Watson Conversation (Quick Summary)](#watson-conversation-quick-summary) 17 | * [Create Watson conversation service](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=1) and [workspace](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=2) 18 | * [Defining intents to help natural language processing](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=3) 19 | * [Unit test intents](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=4) 20 | * [Add entities to improve language understanding](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=5) 21 | * [Building simple dialog flow](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=6) 22 | * [Using the context object for more advanced dialog](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=7) 23 | * [Using the api](https://www.ibm.com/devops/method/tutorials/watson_conversation_support?task=8) 24 | 25 | 26 | # Watson Conversation Quick Summary 27 | To have a quick understanding of Watson Conversation, you may want to read the [product overview](https://www.ibm.com/watson/developercloud/doc/conversation/index.html) section. 28 | ![Conversation Components](wcs-view.png) 29 | 30 | As a summary, you use the Watson Conversation service to create **chatbot**. This is the generic term for a piece of software that provides automated responses to user input. The bot is hosted in the cloud and is highly available. All the information that defines your bot's behavior is contained in a **workspace**. 31 | 32 | You create an **application** that enables your users to interact with the bot. The application passes user's input to the bot, possibly with some additional context information, and presents responses from the bot to the user. 33 | 34 | The bot is **stateless**, that is, it does not retain information from one interchange to the next. The application is responsible for maintaining any continuing information. However, the application can pass information to the bot, and the bot can update the **context** information and pass it back to the application. 35 | 36 | The bot uses natural language understanding and machine learning to extract meaning from the user's input. This process identifies the user's **intent**, which is the goal or purpose of the asked question. It can also identify an **entity**, which is a term, a noun that is mentioned in the input and narrow the purpose of the request. You train your bot to recognize intents and entities in the input submitted by users. To train your bot on intents, you supply lots of examples of user's input and indicate which intents they map to. 37 | 38 | To train your bot on entities, you list the values for each entity and synonyms that users might enter. 39 | Note: the names of intents and entities, and the text of examples, values, and synonyms, can be exposed in URLs when an application interacts with your bot. Do not store sensitive or personal information in these artifacts. 40 | As you add information, the bot trains itself; you do not have to take any action to initiate the training. 41 | 42 | Finally, after you train your system to recognize intents and entities, you teach it how to respond when it recognizes those intents and entities. You use the **dialog** builder to create conversations with users, providing responses based on the intents and entities that the bot recognizes in their inputs. A dialog is composed of multiple flows and subFlows to design the multiple interactions of the conversation. Intent is supported by a dialog flow. 43 | 44 | You should also read [Cognitive Conversation introduction](https://www.ibm.com/devops/method/content/architecture/cognitiveConversationDomain) 45 | 46 | # Hands on lab - Step by step 47 | As mentioned above the training was ported to the Garage Method [Tutorial section](https://www.ibm.com/devops/method/tutorials/watson_conversation_support) so you should follow the step by step instruction from this web site. 48 | 49 | 50 | ## Final solution 51 | If you need to see the current solution, load the exported conversation workspace as json file into your Conversation tools. The file is under **./wcs-workspace/ITsupport-workspace.json**. 52 | 53 | ## Learn More 54 | * A super simple chat bot designed for customer service [here](https://www.ibm.com/blogs/watson/2016/12/build-chat-bot) 55 | * Watson Conversation simple [Product tutorial](https://www.ibm.com/watson/developercloud/doc/conversation/tutorial.html) 56 | -------------------------------------------------------------------------------- /doc/tutorial/add-app-acc-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/add-app-acc-node.png -------------------------------------------------------------------------------- /doc/tutorial/add-child.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/add-child.png -------------------------------------------------------------------------------- /doc/tutorial/api-credential.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/api-credential.png -------------------------------------------------------------------------------- /doc/tutorial/app-access-conditions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/app-access-conditions.png -------------------------------------------------------------------------------- /doc/tutorial/bmx-conv-tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/bmx-conv-tool.png -------------------------------------------------------------------------------- /doc/tutorial/bmx-watson-serv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/bmx-watson-serv.png -------------------------------------------------------------------------------- /doc/tutorial/byod-node1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/byod-node1.png -------------------------------------------------------------------------------- /doc/tutorial/byod-resp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/byod-resp.png -------------------------------------------------------------------------------- /doc/tutorial/byod-ut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/byod-ut.png -------------------------------------------------------------------------------- /doc/tutorial/byod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/byod.png -------------------------------------------------------------------------------- /doc/tutorial/click-url.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/click-url.png -------------------------------------------------------------------------------- /doc/tutorial/device-brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/device-brand.png -------------------------------------------------------------------------------- /doc/tutorial/device-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/device-type.png -------------------------------------------------------------------------------- /doc/tutorial/get-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/get-parameters.png -------------------------------------------------------------------------------- /doc/tutorial/get-product-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/get-product-name.png -------------------------------------------------------------------------------- /doc/tutorial/goodbyes-intent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/goodbyes-intent.png -------------------------------------------------------------------------------- /doc/tutorial/greetings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/greetings.png -------------------------------------------------------------------------------- /doc/tutorial/no-product-name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/no-product-name.png -------------------------------------------------------------------------------- /doc/tutorial/slot-enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/slot-enabled.png -------------------------------------------------------------------------------- /doc/tutorial/supplier-intent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/supplier-intent.png -------------------------------------------------------------------------------- /doc/tutorial/supplier-node-no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/supplier-node-no.png -------------------------------------------------------------------------------- /doc/tutorial/supplier-node-yes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/supplier-node-yes.png -------------------------------------------------------------------------------- /doc/tutorial/supplier-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/supplier-node.png -------------------------------------------------------------------------------- /doc/tutorial/trigger-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/trigger-process.png -------------------------------------------------------------------------------- /doc/tutorial/tryitout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/tryitout.png -------------------------------------------------------------------------------- /doc/tutorial/ut-app-abc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/ut-app-abc.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-build-intents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-build-intents.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-conv-greeting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-conv-greeting.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-conv-wksp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-conv-wksp.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-dev-tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-dev-tasks.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-diag-abc-ut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-diag-abc-ut.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-diag-access.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-diag-access.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-diag-add-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-diag-add-node.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-diag-bool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-diag-bool.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-diag-greeting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-diag-greeting.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-diag-ut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-diag-ut.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-dialog.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-entities-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-entities-panel.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-entities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-entities.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-intent-question.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-intent-question.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-otherwise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-otherwise.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-otherwisejson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-otherwisejson.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-ra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-ra.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-training.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-training.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-two-nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-two-nodes.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-view.png -------------------------------------------------------------------------------- /doc/tutorial/wcs-wkp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/tutorial/wcs-wkp.png -------------------------------------------------------------------------------- /doc/use-apis.md: -------------------------------------------------------------------------------- 1 | # Use Watson Conversation API 2 | In this article we use curl to trigger the conversation dialog. The reference is at https://www.ibm.com/watson/developercloud/conversation/api/v1/. The API is protected by user authentication. To access to the user and password use Bluemix Conversation service and then the Credential: 3 | ![Credential](tutorial/api-credential.png) 4 | -------------------------------------------------------------------------------- /doc/watson_conversations_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/watson_conversations_icon.png -------------------------------------------------------------------------------- /doc/wcs-broker.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | swagger: "2.0" 3 | info: 4 | x-ibm-name: "convbroker" 5 | title: "Watson conversation broker" 6 | description: "This api aims to expose a simple REST verb to interact with Watson Conversation. The broker is an important element to front end Watson Conversation so data can be injected into the dialog or other components can be easily integrated to deliver an end-to-end chat bot solution." 7 | version: "0.0.1" 8 | schemes: 9 | - "https" 10 | host: "$(catalog.host)" 11 | basePath: "/api" 12 | consumes: 13 | - "application/json" 14 | produces: 15 | - "application/json" 16 | paths: 17 | /conversation: 18 | post: 19 | responses: 20 | 200: 21 | description: "200 is success" 22 | summary: Send the user\'s question/message to Watson Conversation. The message can include context variables. 23 | -------------------------------------------------------------------------------- /doc/wcs-save-cloudant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/wcs-save-cloudant.png -------------------------------------------------------------------------------- /doc/wcs-save-on-prem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker/454410a008e466b584fd51ff698a84d2cfc804e6/doc/wcs-save-on-prem.png -------------------------------------------------------------------------------- /doc/wds-itg.md: -------------------------------------------------------------------------------- 1 | # Integrate Watson Discovery In Conversation 2 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | applications: 2 | - path: . 3 | name: refarch-cogni-conversation-broker 4 | host: refarch-wcs-broker 5 | instances: 1 6 | domain: mybluemix.net 7 | memory: 256M 8 | disk_quota: 1024M 9 | services: 10 | - CyanConversations 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RefArchConvBroker", 3 | "version": "0.0.1", 4 | "license": "MIT", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/ibm-cloud-architecture/refarch-cognitive-conversation-broker.git" 8 | }, 9 | "engines": { 10 | "node": "6.x", 11 | "npm": "5.x" 12 | }, 13 | "author": "Jerome Boyer", 14 | "scripts": { 15 | "ng": "ng", 16 | "start": "node server/server", 17 | "dev": "concurrently \"ng build\" \"nodemon server/server\"", 18 | "build": "ng build", 19 | "test": "mocha" 20 | }, 21 | "private": true, 22 | "dependencies": { 23 | "@angular/animations": "^4.3.0", 24 | "@angular/common": "^4.3.0", 25 | "@angular/core": "^4.3.0", 26 | "@angular/forms": "^4.3.0", 27 | "@angular/http": "^4.3.0", 28 | "@angular/platform-browser": "^4.3.0", 29 | "@angular/platform-browser-dynamic": "^4.3.0", 30 | "@angular/platform-server": "^4.3.0", 31 | "@angular/router": "^4.3.0", 32 | "@angular/compiler": "^4.3.0", 33 | "core-js": "^2.4.1", 34 | "cfenv": "^1.0.0", 35 | "rxjs": "^5.4.1", 36 | "zone.js": "^0.8.4", 37 | "cloudant": "^1.4.x", 38 | "body-parser": "^1.17.2", 39 | "bootstrap": "^3.3.7", 40 | "cookie-parser": "^1.4.3", 41 | "express": "^4.15.3", 42 | "express-session": "^1.13.0", 43 | "extend": "^3.0.0", 44 | "request": "^2.72.0", 45 | "vcap_services": "^0.1.7", 46 | "watson-developer-cloud": "^2.32.x", 47 | "botkit": "^0.2.2", 48 | "ibm_db": "^2.1.0" 49 | }, 50 | "devDependencies": { 51 | "@angular/cli": "1.2.0", 52 | "@angular/compiler-cli": "^4.0.0", 53 | "@angular/language-service": "^4.0.0", 54 | "typescript": "~2.3.3", 55 | "@types/node": "~6.0.60", 56 | "@types/jasmine": "2.5.38", 57 | "chai": "^4.0.0", 58 | "mocha": "^3.4.2", 59 | "concurrently": "^3.5.0", 60 | "nodemon": "^1.11.0" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /server/config/config-templ.json: -------------------------------------------------------------------------------- 1 | { 2 | "conversation" :{ 3 | "version":"2017-02-03", 4 | "username":"", 5 | "password":"", 6 | "workspace1":"", 7 | "workspace2":"", 8 | "conversationId":"", 9 | "usePersistence": true 10 | }, 11 | "bpmoc" :{ 12 | "servername":"", 13 | "processname":"", 14 | "basicAuth":"" 15 | }, 16 | "dbCredentials" : { 17 | "url": "https://...-bluemix:...-bluemix.cloudant.com" 18 | }, 19 | "debug":true 20 | } 21 | -------------------------------------------------------------------------------- /server/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "conversation" :{ 3 | "version" : "v1", 4 | "versionDate":"2017-02-03", 5 | "username":"291d9397-073f-46d9-b0d2-11b54e6ae533", 6 | "password":"aDFBIIPYkQlD", 7 | "workspace1":"1a3b01f3-4757-444d-a933-a1e648babfc1", 8 | "conversationId":"CyanConversations", 9 | "workspace2":"80b451cc-d4eb-43bf-a4ac-359599cd2405", 10 | "workspace3":"6c5ba7ac-4925-4ab4-bbc6-03f05e539407", 11 | "usePersistence": false 12 | }, 13 | "bpmoc" :{ 14 | "serverName":"vhost001.bpm.ibmcloud.com", 15 | "processName":"SOBD/SOAPStart.tws", 16 | "basicAuth":"Y29nbml0aXZlYnBtZW1haWxAZ21haWwuY29tOmNvZ25pdGl2ZQ==" 17 | }, 18 | "dbCredentials" : { 19 | "url": "https://01bcc074-b3a0-4b07-93c6-eade6fb3ce50-bluemix:cd68d33a28d499bc6211810a56a0b99393a699190630f7811c438149be944500@01bcc074-b3a0-4b07-93c6-eade6fb3ce50-bluemix.cloudant.com" 20 | }, 21 | "debug":true, 22 | "port": 3001, 23 | "version": "v0.0.7" 24 | } 25 | -------------------------------------------------------------------------------- /server/routes/api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | const express = require('express'); 17 | const conversation = require('./features/conversation'); 18 | //var slacklisterner = require('./features/slack-listener'); 19 | 20 | /** Export the APIs for the front end */ 21 | module.exports = function(app,config) { 22 | /* GET api listing. */ 23 | app.get('/', (req, res) => { 24 | res.send('API supported: GET /api; POST /api/conversation; '); 25 | }); 26 | app.get('/healthz',(req,res) => { 27 | res.send('UP and running'); 28 | }); 29 | // Support REST call 30 | app.post('/api/conversation',function(req,res){ 31 | if(!req.body){ 32 | res.status(400).send({error:'no post body'}); 33 | } else { 34 | if (req.body.context.type !== undefined && req.body.context.type == "sodb") { 35 | conversation.sobdConversation(config,req,res); 36 | } else { 37 | conversation.itSupportConversation(config,req,res); 38 | } 39 | } 40 | }); 41 | app.post('/api/advisor',function(req,res){ 42 | if(!req.body){ 43 | res.status(400).send({error:'no post body'}); 44 | } else { 45 | conversation.advisor(config,req,res); 46 | } 47 | }); 48 | 49 | } // exports 50 | -------------------------------------------------------------------------------- /server/routes/features/conversation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | const watson = require('watson-developer-cloud'); 17 | const bpmoc = require('./supplier-bpm-client'); 18 | const persist= require('./persist'); 19 | 20 | module.exports = { 21 | /** 22 | Specific logic for the conversation related to IT support. From the response the 23 | code could dispatch to BPM. 24 | It persists the conversation to remote cloudant DB 25 | */ 26 | itSupportConversation : function(config,req,res) { 27 | // this logic applies when the response is expected to be a value to be added to a context variable 28 | // the context variable name was set by the conversation dialog 29 | if (req.body.context.action === "getVar") { 30 | req.body.context[req.body.context.varname] = req.body.text; 31 | } 32 | sendMessage(config,req,config.conversation.workspace1,res,processITSupportResponse); 33 | }, // itSupportConversation 34 | 35 | sobdConversation : function(config,req,res) { 36 | sendMessage(config,req,config.conversation.workspace2,res,function(config,res,response) { 37 | if (config.debug) {console.log(" SOBD <<< "+JSON.stringify(response,null,2));} 38 | if (response.Error !== undefined) { 39 | res.status(500).send({'text':response.Error}); 40 | } else { 41 | res.status(200).send(response); 42 | } 43 | }); 44 | }, 45 | advisor : function(config,req,res) { 46 | if ( req.body.context !== undefined) { 47 | req.body.context.action=""; 48 | req.body.context.predefinedResponses=""; 49 | } 50 | sendMessage(config,req,config.conversation.workspace3,res,function(config,res,response) { 51 | if (config.debug) {console.log(" Advisor <<< "+JSON.stringify(response,null,2));} 52 | if (response.Error !== undefined) { 53 | res.status(500).send({'text':response.Error}); 54 | } else { 55 | response.text="

"+response.output.text[0]+"

"; 56 | /* 57 | if (response.context.action !== undefined && response.context.action == "predefinedResponses") { 58 | for (var sr in response.context.predefinedResponses) { 59 | response.text=response.text+ 60 | "
" 63 | +response.context.predefinedResponses[sr]+"" 64 | console.log(response.text) 65 | } 66 | } 67 | */ 68 | if (response.context.action === "click") { 69 | response.text= response.text+ "
"+response.context.buttonText+"" 70 | } 71 | res.status(200).send(response); 72 | } 73 | }); 74 | } 75 | } // exports 76 | 77 | // ------------------------------------------------------------ 78 | // Private 79 | // ------------------------------------------------------------ 80 | var sendMessage = function(config,req,wkid,res,next){ 81 | var message =req.body; 82 | if (config.debug) { 83 | console.log("--- Connect to Watson Conversation named: " + config.conversation.conversationId); 84 | console.log(">>> "+JSON.stringify(message,null,2)); 85 | } 86 | if (message.context.conversation_id === undefined) { 87 | message.context["conversation_id"]=config.conversation.conversationId; 88 | } 89 | conversation = watson.conversation({ 90 | username: config.conversation.username, 91 | password: config.conversation.password, 92 | version: config.conversation.version, 93 | version_date: config.conversation.versionDate}); 94 | 95 | conversation.message( 96 | { 97 | workspace_id: wkid, 98 | input: {'text': message.text}, 99 | context: message.context 100 | }, 101 | function(err, response) { 102 | if (err) { 103 | console.log('error:', err); 104 | next(config,res,{'Error': "Communication error with Watson Service. Please contact your administrator"}); 105 | } else { 106 | if (config.conversation.usePersistence) { 107 | response.context.persistId=req.body.context.persistId; 108 | response.context.revId=req.body.context.revId; 109 | persist.saveConversation(config,response,function(persistRep){ 110 | response.context.persistId=persistRep.id; 111 | response.context.revId=persistRep.rev; 112 | console.log("Conversation persisted, response is now: "+JSON.stringify(response,null,2)); 113 | next(config,res,response); 114 | }); 115 | } else { 116 | next(config,res,response); 117 | } 118 | } 119 | } 120 | ); 121 | 122 | } // sendMessage 123 | 124 | var processITSupportResponse = function(config,res,response){ 125 | if (config.debug) {console.log(" BASE <<< "+JSON.stringify(response,null,2));} 126 | if (response.Error !== undefined) { 127 | res.status(500).send(response); 128 | } else { 129 | // Here apply orchestration logic 130 | if (response.context.url != undefined) { 131 | if (response.context.action === "click") { 132 | response.text=response.output.text[0] + "Here" 133 | } 134 | } else if (response.context.action === "trigger" 135 | && response.context.actionName === "supplierOnBoardingProcess") { 136 | bpmoc.callBPMSupplierProcess(config,response.context.customerName,response.context.productName); 137 | } else if (response.context.action == "predefinedResponses") { 138 | 139 | } 140 | res.status(200).send(response); 141 | } 142 | } // processITSupportResponse 143 | -------------------------------------------------------------------------------- /server/routes/features/persist.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | /** 17 | This module perists the conversation content to a cloudant DB. It implements the data access object patterb 18 | Author: IBM - Jerome Boyer 19 | */ 20 | 21 | 22 | 23 | module.exports= { 24 | saveConversation : function(config,conv,next){ 25 | var cloudant = require('cloudant')(config.dbCredentials.url); 26 | var db = cloudant.use('wcsdb'); 27 | if (conv.context !== undefined) { 28 | if (conv.context.revId !== undefined) { 29 | conv._id=conv.context.persistId; 30 | conv._rev=conv.context.revId; 31 | } 32 | } 33 | db.insert(conv, function(err, data) { 34 | if (err) { 35 | next({error: err.message}); 36 | } else { 37 | next(data); 38 | } 39 | }); 40 | }, // saveConversation 41 | getAllConversations: function(cid,next){ 42 | var cloudantquery = { 43 | "selector": { 44 | "conv_id": cid 45 | } 46 | }; 47 | db.find(cloudantquery, function(err, data) { 48 | if (err) { 49 | next({error: err.message}) 50 | } else { 51 | next(data.docs); 52 | } 53 | }); 54 | }, 55 | getConversationById: function(id,next){ 56 | var cloudantquery = { 57 | "selector": { 58 | "_id": id 59 | } 60 | }; 61 | db.find(cloudantquery, function(err, data) { 62 | if (err) { 63 | next({error: err.message}) 64 | } else { 65 | if(data.docs.length > 0){ 66 | next(data.docs[0]); 67 | } else { 68 | next({error: 'no conversation found with _id: ' + id}); 69 | } 70 | } 71 | }); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /server/routes/features/slack-listener.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | var Botkit = require('botkit'); 17 | var config = require('../env.json'); 18 | var extend = require('extend'); 19 | var conversation = require('./conversation'); 20 | var context={}; 21 | 22 | // Configure your bot. 23 | var slackController = Botkit.slackbot(); 24 | var slackconfig = extend(config.slack); 25 | var slackBot = slackController.spawn({ 26 | token: slackconfig.token 27 | }); 28 | 29 | slackController.hears(['.*'], ['direct_message', 'direct_mention', 'mention'], function(bot, message) { 30 | //call here your watson conversation api 31 | var payload={"text":message.text,"context":context}; 32 | conversation.submit(payload,function(response) { 33 | context=response.context; 34 | bot.reply(message,response.output.text[0]); 35 | }); 36 | }); 37 | // then open the socket 38 | slackBot.startRTM(); 39 | -------------------------------------------------------------------------------- /server/routes/features/supplier-bpm-client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | * This is a BPM on Cloud client code to mae a SOAP request to trigger a process 17 | Author: IBM - Jerome Boyer 18 | */ 19 | var request = require('request'); 20 | 21 | /* 22 | Prepare a soap request using the product and company names for BPM on cloud 23 | deployed application. 24 | ATTENTION this code is not generic and the SOAP message depends on the exposed 25 | web service definition of the process application deployed on BPM on Cloud 26 | */ 27 | module.exports ={ 28 | callBPMSupplierProcess : function(config,company,product) { 29 | var xmlBody = ''+ 30 | ''+ 31 | ''+ 32 | ''+ 33 | ''+ company+''+ 34 | '' + product+ ''+ 35 | ''+ 36 | ''+ 37 | ''; 38 | console.log(xmlBody); 39 | request.post( 40 | {url:'https://'+config.bpmoc.serverName 41 | + '/bpm/dev/teamworks/webservices/' 42 | + config.bpmoc.processName, 43 | body : xmlBody, 44 | headers: {'Content-Type': 'text/xml', 45 | 'Authorization': 'Basic ' + config.bpmoc.basicAuth 46 | } 47 | }, 48 | function (error, response, body) { 49 | if (!error && response.statusCode == 200) { 50 | console.log(response.body) 51 | } 52 | } 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2017 IBM Corp. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // Get dependencies 17 | const express = require('express'); 18 | const path = require('path'); 19 | 20 | const bodyParser = require('body-parser'); 21 | 22 | const app = express(); 23 | 24 | // Parsers for POST JSON PAYLOAD 25 | app.use(bodyParser.json()); 26 | app.use(bodyParser.urlencoded({ extended: false })); 27 | 28 | // Point static path to dist 29 | app.use(express.static(path.join(__dirname, '../dist'))); 30 | 31 | // Set specific api routes 32 | var config = require('./config/config.json'); 33 | require('./routes/api')(app,config); 34 | 35 | // Catch all other routes and return the index file 36 | app.get('*', (req, res) => { 37 | res.sendFile(path.join(__dirname, '../dist/index.html')); 38 | }); 39 | 40 | 41 | // start server on the specified port and binding host 42 | const port = process.env.PORT || config.port; 43 | app.listen(port, '0.0.0.0', function() { 44 | console.log("Conversation Broker Service "+ config.version+" starting on " + port); 45 | console.log(" Use your web browser: http://localhost:"+port); 46 | }); 47 | -------------------------------------------------------------------------------- /test/testAdvisor.js: -------------------------------------------------------------------------------- 1 | 2 | var http = require('http'); 3 | var assert=require('assert'); 4 | 5 | 6 | var options = { 7 | host: 'localhost', 8 | headers: { 9 | "accept": "application/json", 10 | "content-type": "application/json" 11 | }, 12 | method: 'POST', 13 | port: process.env.PORT || 3001, 14 | path: '/api/advisor' 15 | }; 16 | 17 | var callback = function(response){ 18 | var responseString = ''; 19 | response.on('data', function (chunk) { 20 | responseString += chunk; 21 | }); 22 | 23 | response.on('end', function () { 24 | console.log(JSON.parse(responseString )); 25 | }); 26 | }; 27 | 28 | var sendMessage = function(aText,ctxt,done) { 29 | console.log(">>> "+ aText ); 30 | var req=http.request(options, done); 31 | req.write(JSON.stringify({text: aText,context: ctxt})); 32 | req.end(); 33 | } 34 | 35 | var processResponse = function(response,next) { 36 | var responseString = ''; 37 | response.on('data', function (chunk) { 38 | responseString += chunk; 39 | }); 40 | response.on('end', function () { 41 | repp=JSON.parse(responseString); 42 | console.log("<<<< ", repp ); 43 | next(repp); 44 | }); 45 | } 46 | 47 | var handleITteam = function(response) { 48 | processResponse(response, function(repp) { 49 | assert.equal(repp.intents[0].intent,"wasapp"); 50 | sendMessage("Your IT team",repp.context,callback); 51 | }) 52 | } // own IT 53 | 54 | var handleWASND = function(response) { 55 | processResponse(response, function(repp) { 56 | assert.equal(repp.intents[0].intent,"wasapp"); 57 | sendMessage("Your IT team",repp.context,callback); 58 | }) 59 | } // own IT 60 | 61 | var handleWASapp = function(response) { 62 | processResponse(response, function(repp) { 63 | assert.equal(repp.intents[0].intent,"wasapp"); 64 | sendMessage("yes",repp.context,handleWASND); 65 | }) 66 | } // WAS app 67 | 68 | var handleSingleApp = function(response) { 69 | processResponse(response, function(repp) { 70 | assert.equal(repp.intents[0].intent,"singleApp") 71 | sendMessage("websphere",repp.context,handleWASapp); 72 | }) 73 | } //single app 74 | 75 | 76 | var handleMigrateToCloud = function(response){ 77 | processResponse(response, function(repp) { 78 | assert.equal(repp.intents[0].intent,"migrateToCloud") 79 | sendMessage("single application",repp.context,handleSingleApp); 80 | }) 81 | }; // migrate to the cloud 82 | 83 | 84 | // send migration to the cloud 85 | var handleGreeting = function(response) { 86 | processResponse(response, function(repp) { 87 | assert.equal(repp.intents[0].intent,"Greetings") 88 | sendMessage("I want migrate application to the cloud",repp.context,handleMigrateToCloud); 89 | }) 90 | } 91 | 92 | // process WAS app migration flow starting by hello 93 | sendMessage("hello", {conversation_id:"CyanConversations"},handleGreeting); 94 | -------------------------------------------------------------------------------- /test/testNodeServer.js: -------------------------------------------------------------------------------- 1 | var expect = require('chai').expect; 2 | var http = require('http'); 3 | 4 | // Below code demonstrates using various methods of testing 5 | describe('Testing Server', function() { 6 | 7 | before(function(done){ 8 | require(process.cwd() + '/server/server'); 9 | setTimeout(done, 5000); // Waiting 5 seconds for server to start 10 | this.timeout(10000); 11 | }); 12 | /* 13 | it('Public endpoint returns "healthz"', function(done){ 14 | var responseString = ''; 15 | 16 | var options = { 17 | host: 'localhost', 18 | port: process.env.PORT || 3001, 19 | path: '/healthz' 20 | }; 21 | 22 | var callback = function(response){ 23 | response.on('data', function (chunk) { 24 | responseString += chunk; 25 | }); 26 | 27 | response.on('end', function () { 28 | expect(responseString).to.include('UP'); 29 | done(); 30 | }); 31 | }; 32 | 33 | http.request(options, callback).end(); 34 | }); 35 | */ 36 | it('Test advisor migration flow',function(done){ 37 | var responseString = ''; 38 | var options = { 39 | host: 'localhost', 40 | headers: { 41 | "accept": "application/json", 42 | "content-type": "application/json" 43 | }, 44 | method: 'POST', 45 | port: process.env.PORT || 3001, 46 | path: '/api/advisor' 47 | }; 48 | var callback = function(response){ 49 | response.on('data', function (chunk) { 50 | responseString += chunk; 51 | }); 52 | 53 | response.on('end', function () { 54 | console.log(JSONstringify(responseString,null,2)); 55 | done(); 56 | }); 57 | }; 58 | 59 | var req=http.request(options, callback); 60 | req.write("{\"text\": \"migrate to the cloud\",\"conversationId\":\" \"}"); 61 | req.end(); 62 | }); 63 | 64 | }); 65 | -------------------------------------------------------------------------------- /wcs-workspace/ITSupport-Entities.csv: -------------------------------------------------------------------------------- 1 | deviceBrand,Apple,apple,,,, 2 | deviceBrand,Dell,dell,,,, 3 | deviceBrand,Lenovo,lenovo,,,, 4 | deviceBrand,Motorola,moto,motorola,nexus,, 5 | deviceBrand,Samsung,galaxy,notes,samsung,, 6 | deviceType,laptop,computer,workstation,,, 7 | deviceType,phone,android,iphone,cell phone,mobile,smartphone 8 | deviceType,tablet,ipad,kindle,galaxy,, 9 | yes-no,no,n,,,, 10 | yes-no,yes,y,,,, 11 | supplier,supplier,company,partner,,, 12 | password,password,,,,, -------------------------------------------------------------------------------- /wcs-workspace/ITSupport-Intents.csv: -------------------------------------------------------------------------------- 1 | Hello,Greetings 2 | Hi,Greetings 3 | How are you?,Greetings 4 | Bonjour,Greetings 5 | Howdy,Greetings 6 | What's up?,Greetings 7 | Good Morning!,Greetings 8 | Namaste,Greetings 9 | Ola,Greetings 10 | What is up,Greetings 11 | hey,Greetings 12 | bye,Goodbye 13 | bye-bye,Goodbye 14 | ciao,Goodbye 15 | have a good day,Goodbye 16 | take care,Goodbye 17 | see you later,Goodbye 18 | ttyl,Goodbye 19 | How can I reset my password?,ResetPassword 20 | "I could not login in this morning, is my password expired?",ResetPassword 21 | How can I change my password?,ResetPassword 22 | How can I reset the access password for the application AbC?,ResetPassword 23 | What are the different options to reset my password?,ResetPassword 24 | I want to reset my intranet password,ResetPassword 25 | I want to access to supplier due diligence business process,SupplierOnboarding 26 | I want to board new supplier,SupplierOnboarding 27 | On-boarding a new supplier,SupplierOnboarding 28 | Supplier due diligence,SupplierOnboarding 29 | What is the process to on-board a new supplier?,SupplierOnboarding 30 | What is the URL of the business process for on-boarding a supplier?,SupplierOnboarding 31 | I have a new supplier what is the procedure to access it,SupplierOnboarding 32 | bring my laptop,BYOD 33 | bring my phone,BYOD 34 | byod,BYOD 35 | bring my tablet,BYOD 36 | use my iphone for work,BYOD 37 | use my phone for business,BYOD 38 | use my own smartphone for work,BYOD 39 | use my ipad for business,BYOD 40 | I want to bring my own device,BYOD 41 | How to access product inventory?,ApplicationAccess 42 | How to access reimbursement process?,ApplicationAccess 43 | How to book a travel?,ApplicationAccess 44 | How to get access to business application AbC?,ApplicationAccess 45 | I want to access application,ApplicationAccess 46 | What is the status of the business application?,ApplicationAccess 47 | I want to access application AbC,ApplicationAccess 48 | I want to access Innovation Workshop,ApplicationAccess -------------------------------------------------------------------------------- /wcs-workspace/ITsupport-workspace.json: -------------------------------------------------------------------------------- 1 | {"name":"SupportHelpDesk","created":"2017-02-17T21:51:51.656Z","intents":[{"intent":"Greetings","created":"2017-04-26T15:19:54.725Z","updated":"2017-04-26T15:19:54.725Z","examples":[{"text":"Good afternoon","created":"2017-04-26T15:19:54.725Z","updated":"2017-04-26T15:19:54.725Z"},{"text":"Good day","created":"2017-04-26T15:19:54.725Z","updated":"2017-04-26T15:19:54.725Z"},{"text":"Hello","created":"2017-04-26T15:19:54.725Z","updated":"2017-04-26T15:19:54.725Z"},{"text":"Hi","created":"2017-04-26T15:19:54.725Z","updated":"2017-04-26T15:19:54.725Z"},{"text":"Good morning","created":"2017-04-26T15:19:54.725Z","updated":"2017-04-26T15:19:54.725Z"}],"description":null},{"intent":"SupplierOnBoarding","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-28T22:33:01.384Z","examples":[{"text":"on boarding new supplier","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-01T18:27:27.236Z"},{"text":"supplier due diligence","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-01T18:27:27.236Z"},{"text":"access to supplier due diligence","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-01T18:27:27.236Z"},{"text":"I want to board new supplier","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-01T18:27:27.236Z"},{"text":"what is the process to on board new supplier?","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-01T18:27:27.236Z"},{"text":"what is the url of the business process for on boarding supplier?","created":"2017-03-01T18:27:27.236Z","updated":"2017-03-01T18:27:27.236Z"}],"description":null},{"intent":"ApplicationAccess","created":"2017-02-18T01:19:50.662Z","updated":"2017-03-28T22:50:48.457Z","examples":[{"text":"How to access product inventory?","created":"2017-02-18T01:19:50.662Z","updated":"2017-02-18T01:19:50.662Z"},{"text":"Where is the financial portal?","created":"2017-02-18T01:19:50.662Z","updated":"2017-02-18T01:19:50.662Z"},{"text":"How to book a travel?","created":"2017-02-18T01:19:50.662Z","updated":"2017-02-18T01:19:50.662Z"},{"text":"How to access reimbursement process?","created":"2017-02-18T01:19:50.662Z","updated":"2017-02-18T01:19:50.662Z"},{"text":"How to get access to business application AbC?","created":"2017-02-18T01:19:50.662Z","updated":"2017-02-18T01:19:50.662Z"},{"text":"What is the status of the business application?","created":"2017-02-18T01:19:50.662Z","updated":"2017-02-18T01:19:50.662Z"},{"text":"I want to access application AbC","created":"2017-02-20T18:51:53.958Z","updated":"2017-02-20T18:51:53.958Z"},{"text":"I want to access application","created":"2017-02-20T21:55:34.590Z","updated":"2017-02-20T21:55:34.590Z"}],"description":null},{"intent":"ResetPassword","created":"2017-02-18T01:24:28.013Z","updated":"2017-03-28T22:33:09.547Z","examples":[{"text":"password expired","created":"2017-02-28T19:23:58.294Z","updated":"2017-02-28T19:23:58.294Z"},{"text":"How can I reset the access password for application AbC?","created":"2017-02-18T01:24:28.013Z","updated":"2017-02-18T01:24:28.013Z"},{"text":"How can I change my password?","created":"2017-02-18T01:24:28.013Z","updated":"2017-02-18T01:24:28.013Z"},{"text":"How can I reset my password?","created":"2017-02-18T01:24:28.013Z","updated":"2017-02-18T01:24:28.013Z"},{"text":"I could not login this morning my password expired","created":"2017-02-18T01:24:28.013Z","updated":"2017-02-28T19:23:45.527Z"}],"description":null},{"intent":"BYOD","created":"2017-04-25T17:30:09.660Z","updated":"2017-06-24T18:33:40.276Z","examples":[{"text":"bring my iphone","created":"2017-06-24T18:33:40.276Z","updated":"2017-06-24T18:33:40.276Z"},{"text":"use my ipad for business","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"},{"text":"use my own smartphone for work","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"},{"text":"use my own phone","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"},{"text":"bring my tablet","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"},{"text":"bring my laptop","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"},{"text":"I want to bring my own device","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"},{"text":"byod","created":"2017-04-25T23:07:20.324Z","updated":"2017-04-25T23:07:20.324Z"},{"text":"use my phone for business","created":"2017-04-25T17:30:09.660Z","updated":"2017-04-25T17:30:09.660Z"}],"description":null},{"intent":"Goodbyes","created":"2017-02-20T18:28:14.346Z","updated":"2017-03-28T22:46:39.697Z","examples":[{"text":"Bye","created":"2017-02-20T18:28:14.346Z","updated":"2017-02-20T18:28:14.346Z"},{"text":"See ya","created":"2017-02-20T18:28:14.346Z","updated":"2017-02-20T18:28:14.346Z"},{"text":"later","created":"2017-02-20T18:28:14.346Z","updated":"2017-02-20T18:28:14.346Z"},{"text":"I'm out","created":"2017-02-20T18:28:14.346Z","updated":"2017-02-20T18:28:14.346Z"},{"text":"Goodbye!","created":"2017-02-20T18:28:14.346Z","updated":"2017-02-20T18:28:14.346Z"},{"text":"Farewell","created":"2017-02-20T18:28:14.346Z","updated":"2017-02-20T18:28:14.346Z"},{"text":"ttyl","created":"2017-03-28T22:46:39.697Z","updated":"2017-03-28T22:46:39.697Z"}],"description":null}],"updated":"2017-10-03T22:56:42.579Z","entities":[{"entity":"deviceType","values":[{"type":"synonyms","value":"laptop","created":"2017-04-25T17:34:56.336Z","updated":"2017-04-25T17:34:56.336Z","metadata":null,"synonyms":["computer"]},{"type":"synonyms","value":"tablet","created":"2017-04-25T17:33:16.881Z","updated":"2017-04-25T17:33:53.442Z","metadata":null,"synonyms":["ipad","Galaxy","kindle"]},{"type":"synonyms","value":"phone","created":"2017-04-25T17:33:16.881Z","updated":"2017-04-25T23:44:39.320Z","metadata":null,"synonyms":["cell phone","mobile","smartphone","telephone","iphone","android","nexus","moto g"]}],"created":"2017-04-25T17:33:16.881Z","updated":"2017-04-25T23:44:39.320Z","metadata":null,"description":null},{"entity":"sys-location","values":[],"created":"2017-05-04T08:47:20.504Z","updated":"2017-05-04T08:47:20.504Z","metadata":null,"description":null},{"entity":"deviceBrand","values":[{"type":"synonyms","value":"Dell","created":"2017-04-25T22:33:39.292Z","updated":"2017-04-25T22:33:39.292Z","metadata":null,"synonyms":["dell"]},{"type":"synonyms","value":"Apple","created":"2017-04-25T22:33:39.292Z","updated":"2017-04-25T22:33:50.923Z","metadata":null,"synonyms":["apple"]},{"type":"synonyms","value":"Samsung","created":"2017-04-26T00:00:14.197Z","updated":"2017-04-26T00:00:14.197Z","metadata":null,"synonyms":["samsung","galaxy","notes"]},{"type":"synonyms","value":"Lenovo","created":"2017-04-25T22:34:07.359Z","updated":"2017-04-25T22:34:07.359Z","metadata":null,"synonyms":["lenovo"]},{"type":"synonyms","value":"Motorola","created":"2017-04-26T00:00:59.541Z","updated":"2017-04-26T00:00:59.541Z","metadata":null,"synonyms":["moto","motorola","nexus"]},{"type":"synonyms","value":"IBM","created":"2017-04-26T20:22:51.852Z","updated":"2017-04-26T20:22:51.852Z","metadata":null,"synonyms":["ibm"]}],"created":"2017-04-25T22:33:39.292Z","updated":"2017-05-04T08:46:51.378Z","metadata":null,"description":null,"fuzzy_match":true},{"entity":"password","values":[{"type":"synonyms","value":"password","created":"2017-02-28T20:45:23.191Z","updated":"2017-02-28T20:45:23.191Z","metadata":null,"synonyms":[]}],"created":"2017-02-28T20:45:23.191Z","updated":"2017-02-28T20:45:23.191Z","metadata":null,"description":null},{"entity":"sys-person","values":[],"created":"2017-05-04T08:47:20.488Z","updated":"2017-05-04T08:47:20.488Z","metadata":null,"description":null},{"entity":"sys-date","values":[],"created":"2017-05-04T08:47:20.623Z","updated":"2017-05-04T08:47:20.623Z","metadata":null,"description":null},{"entity":"supplier","values":[{"type":"synonyms","value":"supplier","created":"2017-03-01T21:36:12.110Z","updated":"2017-03-01T21:36:12.110Z","metadata":null,"synonyms":[]}],"created":"2017-03-01T21:36:12.110Z","updated":"2017-03-01T21:36:12.110Z","metadata":null,"description":null},{"entity":"sys-percentage","values":[],"created":"2017-05-04T08:47:20.672Z","updated":"2017-05-04T08:47:20.672Z","metadata":null,"description":null},{"entity":"sys-time","values":[],"created":"2017-05-04T08:47:20.707Z","updated":"2017-05-04T08:47:20.707Z","metadata":null,"description":null},{"entity":"sys-number","values":[],"created":"2017-05-04T08:47:21.355Z","updated":"2017-05-04T08:47:21.355Z","metadata":null,"description":null},{"entity":"application","values":[{"type":"synonyms","value":"AbC","created":"2017-02-18T01:26:04.944Z","updated":"2017-02-18T01:26:04.944Z","metadata":null,"synonyms":["Order management"]},{"type":"synonyms","value":"InventoryPlus","created":"2017-02-18T01:26:04.944Z","updated":"2017-02-18T01:26:49.788Z","metadata":null,"synonyms":["IP","Inventory","Racktus"]},{"type":"synonyms","value":"Innovation Workshop","created":"2017-02-20T22:14:09.404Z","updated":"2017-02-20T22:14:09.404Z","metadata":null,"synonyms":["iw"]},{"type":"synonyms","value":"ExpenseReport","created":"2017-02-18T01:26:04.944Z","updated":"2017-03-28T22:51:26.246Z","metadata":null,"synonyms":["expense","expense reimbursement"]}],"created":"2017-02-18T01:26:04.944Z","updated":"2017-06-23T23:48:33.779Z","metadata":null,"description":null,"fuzzy_match":true},{"entity":"sys-currency","values":[],"created":"2017-05-04T08:47:20.660Z","updated":"2017-05-04T08:47:20.660Z","metadata":null,"description":null},{"entity":"yes-no","values":[{"type":"synonyms","value":"yes","created":"2017-03-18T16:33:39.541Z","updated":"2017-03-18T16:33:39.541Z","metadata":null,"synonyms":["y"]},{"type":"synonyms","value":"no","created":"2017-03-18T16:33:39.541Z","updated":"2017-03-18T16:33:39.541Z","metadata":null,"synonyms":["n"]}],"created":"2017-03-18T16:33:39.541Z","updated":"2017-03-18T16:33:39.541Z","metadata":null,"description":null}],"language":"en","metadata":{"api_version":{"major_version":"v1","minor_version":"2017-05-26"}},"description":"Conversation to address internal user's request for IT support","dialog_nodes":[{"type":"slot","title":"slot_4_1503686198203","output":null,"parent":"Bring device","context":null,"created":"2017-08-25T18:36:38.502Z","updated":"2017-08-25T18:36:45.132Z","metadata":null,"variable":"$deviceType","next_step":null,"conditions":null,"description":null,"dialog_node":"slot_4_1503686198203","previous_sibling":"slot_1_1503686065244"},{"type":"slot","title":"slot_1_1503686065244","output":null,"parent":"Bring device","context":null,"created":"2017-08-25T18:34:25.978Z","updated":"2017-08-25T18:35:47.761Z","metadata":null,"variable":"$deviceBrand","next_step":null,"conditions":null,"description":null,"dialog_node":"slot_1_1503686065244","previous_sibling":null},{"type":"response_condition","title":null,"output":{"text":{"values":["I am triggering the supplier on boarding process. The process task is visible at : https://vhost001.bpm.ibmcloud.com/bpm/dev/ProcessPortal"],"selection_policy":"sequential"}},"parent":"Trigger the process","context":{"action":"trigger","actionName":"supplierOnBoardingProcess","actionType":"bpm"},"created":"2017-05-31T16:12:12.374Z","updated":"2017-05-31T16:13:25.815Z","metadata":null,"next_step":null,"conditions":null,"description":null,"dialog_node":"node_1_1496247132094","previous_sibling":null},{"title":"No product name provided","output":{"text":{"values":["I need the product name to trigger the process"],"selection_policy":"sequential"}},"parent":"Get Product name","context":null,"created":"2017-04-27T00:55:27.613Z","updated":"2017-10-03T00:07:26.641Z","metadata":null,"next_step":{"behavior":"jump_to","selector":"body","dialog_node":"Get Product name"},"conditions":"","description":null,"dialog_node":"No product name provided","previous_sibling":"Trigger the process"},{"type":"response_condition","title":null,"output":{"text":{"values":["What is the product name?"],"selection_policy":"sequential"}},"parent":"Get Product name","context":{"action":"getVar","varname":"productName"},"created":"2017-04-21T23:58:10.257Z","updated":"2017-10-03T22:56:42.579Z","metadata":null,"next_step":null,"conditions":"","description":null,"dialog_node":"node_1_1492819089967","previous_sibling":"No product name provided"},{"title":"Trigger the process","output":{},"parent":"Get Product name","context":null,"created":"2017-04-22T01:17:53.727Z","updated":"2017-05-31T16:12:13.172Z","metadata":null,"next_step":null,"conditions":"$productName != \"\"","description":null,"dialog_node":"Trigger the process","previous_sibling":null},{"title":"No customer name was provided","output":{},"parent":"Watson trigger the process","context":null,"created":"2017-04-22T00:30:10.158Z","updated":"2017-10-03T00:07:40.298Z","metadata":null,"next_step":{"behavior":"jump_to","selector":"body","dialog_node":"Watson trigger the process"},"conditions":"","description":null,"dialog_node":"No customer name was provided","previous_sibling":"Get Product name"},{"title":"Get Product name","output":{},"parent":"Watson trigger the process","context":null,"created":"2017-03-18T20:11:02.979Z","updated":"2017-04-22T00:54:10.155Z","metadata":null,"next_step":null,"conditions":"$customerName != \"\"","description":null,"dialog_node":"Get Product name","previous_sibling":null},{"type":"response_condition","title":null,"output":{"text":{"values":["I need at least a customer name to be able to trigger the process automatically"],"selection_policy":"sequential"}},"parent":"No customer name was provided","context":{"action":"getVar","varname":"customerName"},"created":"2017-04-22T00:30:17.074Z","updated":"2017-10-03T00:07:40.624Z","metadata":null,"next_step":null,"conditions":"","description":null,"dialog_node":"node_5_1492821016920","previous_sibling":null},{"type":"event_handler","title":"handler_3_1503686065244","output":{"text":"What is the brand of your device?"},"parent":"slot_1_1503686065244","context":null,"created":"2017-08-25T18:34:26.710Z","updated":"2017-10-02T23:26:42.307Z","metadata":null,"next_step":null,"conditions":null,"event_name":"focus","description":null,"dialog_node":"handler_3_1503686065244","previous_sibling":"handler_2_1503686065244"},{"type":"event_handler","title":"handler_2_1503686065244","output":null,"parent":"slot_1_1503686065244","context":{"deviceBrand":"@deviceBrand"},"created":"2017-08-25T18:34:26.403Z","updated":"2017-08-25T18:35:48.024Z","metadata":null,"next_step":null,"conditions":"@deviceBrand","event_name":"input","description":null,"dialog_node":"handler_2_1503686065244","previous_sibling":null},{"type":"response_condition","title":null,"output":{"text":{"values":["To access the Innovation Workshop app go to http://iwapp.mybluemix.net"],"selection_policy":"sequential"}},"parent":"Application Access","context":null,"created":"2017-04-25T16:49:35.233Z","updated":"2017-05-31T21:29:04.454Z","metadata":null,"next_step":null,"conditions":"@application:(Innovation Workshop)","description":null,"dialog_node":"node_5_1493138975035","previous_sibling":"node_4_1493138837571"},{"type":"response_condition","title":null,"output":{"text":{"values":["To access Inventory Plus go to URL: http://inventoryplus.caseinc.com/ws"],"selection_policy":"sequential"}},"parent":"Application Access","context":null,"created":"2017-04-25T16:52:35.685Z","updated":"2017-04-26T16:10:45.094Z","metadata":null,"next_step":null,"conditions":" @application:InventoryPlus","description":null,"dialog_node":"node_7_1493139155516","previous_sibling":"node_5_1493138975035"},{"type":"response_condition","title":null,"output":{"text":{"values":["To access expense report tool go to Start > Application > CaseInc Tools > Expense Report"],"selection_policy":"sequential"}},"parent":"Application Access","context":null,"created":"2017-04-25T16:47:17.948Z","updated":"2017-04-26T16:10:32.280Z","metadata":null,"next_step":null,"conditions":" @application:ExpenseReport","description":null,"dialog_node":"node_4_1493138837571","previous_sibling":"node_3_1493138746298"},{"type":"response_condition","title":null,"output":{"text":{"values":["What application do you want to access: InventoryPlus, AbC, Innovation Workshop, Expense report?"],"selection_policy":"sequential"}},"parent":"Application Access","context":null,"created":"2017-04-25T16:50:33.216Z","updated":"2017-04-26T16:11:07.092Z","metadata":null,"next_step":null,"conditions":null,"description":null,"dialog_node":"node_6_1493139033045","previous_sibling":"node_7_1493139155516"},{"type":"response_condition","title":null,"output":{"text":{"values":["To go to application AbC use the following URL: http://w3.caseinc.com/abc56"],"selection_policy":"sequential"}},"parent":"Application Access","context":null,"created":"2017-04-25T16:45:46.631Z","updated":"2017-06-24T02:24:58.524Z","metadata":null,"next_step":null,"conditions":" @application:AbC","description":null,"dialog_node":"node_3_1493138746298","previous_sibling":null},{"title":"User wants access only","output":{"text":["Understand, so to access the Supplier On Boarding business process use the url: "]},"parent":"Supplier On Boarding","context":{"url":"https://vhost001.bpm.ibmcloud.com/bpm/dev/teamworks/executecf?modelID=1.15ec1db4-9051-41d4-8cbe-6053016ed917&snapshotID=2064.f1d3870c-f42a-49c1-b19a-d866f1f95cba","action":"click"},"created":"2017-03-18T16:32:25.120Z","updated":"2017-05-04T17:23:58.906Z","metadata":null,"next_step":null,"conditions":"@yes-no:no","description":null,"dialog_node":"User wants access only","previous_sibling":"node_4_1489854990975"},{"title":"Watson trigger the process","output":{"text":{"values":["what is the supplier company name?"],"selection_policy":"sequential"}},"parent":"Supplier On Boarding","context":{"action":"getVar","varname":"customerName"},"created":"2017-03-18T16:38:43.613Z","updated":"2017-05-04T12:57:36.721Z","metadata":null,"next_step":null,"conditions":"@yes-no:yes","description":null,"dialog_node":"Watson trigger the process","previous_sibling":"User wants access only"},{"type":"response_condition","title":null,"output":{"text":{"values":["Do you want me to trigger the process for you?"],"selection_policy":"sequential"}},"parent":"Supplier On Boarding","context":null,"created":"2017-03-18T16:36:31.122Z","updated":"2017-10-02T23:57:17.769Z","metadata":null,"next_step":null,"conditions":"","description":null,"dialog_node":"node_4_1489854990975","previous_sibling":null},{"type":"event_handler","title":"handler_6_1503686198203","output":{"text":"What is the type of your device (tablet, smartphone, computer)?"},"parent":"slot_4_1503686198203","context":null,"created":"2017-08-25T18:36:39.263Z","updated":"2017-10-02T23:46:47.080Z","metadata":null,"next_step":null,"conditions":null,"event_name":"focus","description":null,"dialog_node":"handler_6_1503686198203","previous_sibling":"handler_5_1503686198203"},{"type":"event_handler","title":"handler_5_1503686198203","output":null,"parent":"slot_4_1503686198203","context":{"deviceType":"@deviceType"},"created":"2017-08-25T18:36:38.857Z","updated":"2017-08-25T18:36:45.442Z","metadata":null,"next_step":null,"conditions":"@deviceType","event_name":"input","description":null,"dialog_node":"handler_5_1503686198203","previous_sibling":null},{"title":"Supplier On Boarding","output":{},"parent":null,"context":null,"created":"2017-03-01T18:27:56.841Z","updated":"2017-04-21T23:54:12.347Z","metadata":null,"next_step":null,"conditions":"#SupplierOnBoarding","description":null,"dialog_node":"Supplier On Boarding","previous_sibling":"Bring device"},{"title":"Handle Greetings","output":{"text":{"values":["Hi, I'm IBM Watson help desk support bot, how can I help you?","Hi, I am Watson, how can I help you?","Watson bot here, do you need some help?"],"selection_policy":"random"}},"parent":null,"context":null,"created":"2017-02-17T22:03:04.140Z","updated":"2017-06-24T02:24:43.732Z","metadata":null,"next_step":null,"conditions":"#Greetings","description":null,"dialog_node":"Handle Greetings","previous_sibling":"Start the conversation"},{"type":"frame","title":"Bring device","output":{"text":{"values":["You want to bring a $deviceType from $deviceBrand, let me check our policies..."],"selection_policy":"sequential"}},"parent":null,"context":{"action":"AssessByodPolicy"},"created":"2017-04-25T17:38:17.168Z","updated":"2017-08-25T18:41:37.485Z","metadata":null,"next_step":null,"conditions":"#BYOD","description":null,"dialog_node":"Bring device","previous_sibling":"Application Access"},{"title":"Reset Password","output":{"text":{"values":["To reset your password go to https://w3.caseinc.com/password/changepwd.wss"],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-03-18T16:20:10.862Z","updated":"2017-04-21T23:39:54.096Z","metadata":null,"next_step":null,"conditions":"#ResetPassword","description":null,"dialog_node":"Reset Password","previous_sibling":"Supplier On Boarding"},{"title":"Application Access","output":{},"parent":null,"context":null,"created":"2017-02-18T00:57:30.543Z","updated":"2017-04-25T16:51:32.640Z","metadata":null,"next_step":null,"conditions":"#ApplicationAccess","description":null,"dialog_node":"Application Access","previous_sibling":"Handle Greetings"},{"title":"Otherwise","output":{"text":{"values":["I do not understand you, so may be rephrase your request, thank you."],"selection_policy":"sequential"},"Missing case":true},"parent":null,"context":null,"created":"2017-03-11T00:38:18.857Z","updated":"2017-04-25T19:59:27.722Z","metadata":null,"next_step":null,"conditions":"True","description":null,"dialog_node":"Otherwise","previous_sibling":"Reset Password"},{"title":"Start the conversation","output":{"text":{"values":["Welcome to IT support chat bot"],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-04-25T20:32:53.367Z","updated":"2017-04-26T15:45:49.093Z","metadata":null,"next_step":null,"conditions":"conversation_start","description":null,"dialog_node":"Start the conversation","previous_sibling":null}],"workspace_id":"1a3b01f3-4757-444d-a933-a1e648babfc1","counterexamples":[],"learning_opt_out":false} -------------------------------------------------------------------------------- /wcs-workspace/sodb-workspace.json: -------------------------------------------------------------------------------- 1 | {"name":"SupplierOnboardingRevised","created":"2017-04-25T16:38:17.148Z","intents":[{"intent":"hi","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","examples":[{"text":"what's up?","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what should i ask you","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"What do I do?","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what?","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"Hi","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"Help","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"hello","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"}],"description":null},{"intent":"Process","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","examples":[{"text":"what's the process","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what should I do now","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what next","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"What is the process of onboarding a supplier","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what are the next steps in the process","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"how does this work","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"After the risk is set, can you explain the process","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"}],"description":null},{"intent":"ViewWatsonResult","created":"2017-04-25T16:38:17.148Z","updated":"2017-06-07T01:23:15.748Z","examples":[{"text":"How to interpret Discovery results","created":"2017-06-07T01:20:18.701Z","updated":"2017-06-07T01:20:18.701Z"},{"text":"What can I get from the discovery results","created":"2017-06-07T01:20:48.716Z","updated":"2017-06-07T01:20:48.716Z"},{"text":"I do not understand the results returned","created":"2017-06-07T01:22:05.193Z","updated":"2017-06-07T01:22:05.193Z"},{"text":"What does this result table mean","created":"2017-06-07T01:22:39.742Z","updated":"2017-06-07T01:22:39.742Z"},{"text":"can you explain the meaning of the returned item?","created":"2017-06-07T01:23:15.748Z","updated":"2017-06-07T01:23:15.748Z"}],"description":null},{"intent":"SupplierCriteria","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","examples":[{"text":"what's valuable in a supplier","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what's important in a supplier","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"What matters in a supplier","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"What do we look for in a supplier","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"how do I know a supplier is good","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"Can you tell me about the supplier","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"}],"description":null},{"intent":"MgmtOverview","created":"2017-04-25T16:38:17.148Z","updated":"2017-06-07T01:21:37.422Z","examples":[{"text":"When managers will be involved","created":"2017-06-07T00:59:43.848Z","updated":"2017-06-07T00:59:43.848Z"},{"text":"What is the escalation procedure","created":"2017-06-07T00:59:53.562Z","updated":"2017-06-07T00:59:53.562Z"},{"text":"is there a manager escalation procedure","created":"2017-06-07T01:00:06.986Z","updated":"2017-06-07T01:00:06.986Z"},{"text":"how does management overview work?","created":"2017-06-07T01:00:27.326Z","updated":"2017-06-07T01:00:27.326Z"},{"text":"when should I involve a management to look at supplier application?","created":"2017-06-07T01:21:37.422Z","updated":"2017-06-07T01:21:37.422Z"}],"description":null},{"intent":"DocumentValue","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","examples":[{"text":"where is a documents value","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what matters in our document","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what matters for our document","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what is valuable in a document","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"what do we look for in a document","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"How do we know a document has value","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"},{"text":"how do I know what to add to discovery","created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z"}],"description":null}],"updated":"2017-06-07T01:23:15.748Z","entities":[],"language":"en","metadata":null,"description":"Revised Supplier Onboarding to test better intents and a more functional service","dialog_nodes":[{"go_to":null,"title":"Document","output":{"text":{"values":["The documents we are looking for are any documents that have strong connotative usages for the NLC processing"],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","metadata":null,"conditions":"#DocumentValue","description":null,"dialog_node":"Document","previous_sibling":"Supplier"},{"go_to":null,"title":"Process","output":{"text":{"values":["The steps of the process are to initially search by company and product. Step 2 is to view the returned discovered articles from the Watson service, each article is assigned an NLC score that is automatically processed and a relevancy score. The user has to manually review each of the articles and assign a risk rating from 1-10. After that the user continues on and sees a list of options. This includes ending the request, or approving. If no at risk scores, automatically approve, otherwise, send for managerial review and approval."],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","metadata":null,"conditions":"#Process","description":null,"dialog_node":"Process","previous_sibling":"Document"},{"go_to":null,"title":"Supplier","output":{"text":{"values":["What is important in a supplier is positive articles with high sentiment assessment, high relevancy, and easy readability for a low manual risk score."],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-04-25T16:38:17.148Z","updated":"2017-06-07T01:18:51.858Z","metadata":null,"conditions":"#SupplierCriteria","description":null,"dialog_node":"Supplier","previous_sibling":"Welcome"},{"go_to":null,"title":"Welcome","output":{"text":{"values":["Hi, I'm the Supplier Onboarding chatbot! You should ask me any questions about the process like \"How do we know a document has value?\" or \"What is the process?\" You can even ask me \"What is valuable in a supplier?\""],"selection_policy":"sequential"}},"parent":null,"context":null,"created":"2017-04-25T16:38:17.148Z","updated":"2017-04-25T16:38:17.148Z","metadata":null,"conditions":"#hi","description":null,"dialog_node":"Welcome","previous_sibling":null}],"workspace_id":"80b451cc-d4eb-43bf-a4ac-359599cd2405","counterexamples":[]} --------------------------------------------------------------------------------