├── .gitignore ├── LICENSE ├── images ├── alexa-skill-kit.png ├── architecture.png ├── facebook.png ├── lexbot.png ├── logo.png ├── slack.png └── sms.png ├── readme.adoc ├── slides.key ├── slides.pdf └── starwars-chatbot ├── pom.xml └── src └── main ├── java └── org │ └── sample │ └── aws │ └── chatbot │ └── starwars │ ├── alexa │ ├── StarwarsSpeechlet.java │ └── StarwarsSpeechletRequestStreamHandler.java │ ├── common │ ├── StarWarsIntent.java │ └── StarWarsResponse.java │ ├── db │ ├── DBUtil.java │ └── StarWarsCharacter.java │ └── lex │ └── StarWarsLexBot.java └── resources └── speech-assets └── interaction-model.json /.gitignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store 2 | **/target/ 3 | **/.idea 4 | **/*.iml 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /images/alexa-skill-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/alexa-skill-kit.png -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/architecture.png -------------------------------------------------------------------------------- /images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/facebook.png -------------------------------------------------------------------------------- /images/lexbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/lexbot.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/logo.png -------------------------------------------------------------------------------- /images/slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/slack.png -------------------------------------------------------------------------------- /images/sms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/images/sms.png -------------------------------------------------------------------------------- /readme.adoc: -------------------------------------------------------------------------------- 1 | :toc: 2 | 3 | = Build Your Own Chatbot using Java 4 | 5 | This repository explains how to create a Star Wars chatbot using Amazon Lex and Java. 6 | 7 | image::images/logo.png[width="50%"] 8 | 9 | The users can interact with this chatbot using the following means: 10 | 11 | . Voice (Alexa, Phone/Call) 12 | . Text (Phone/SMS, Facebook Messenger, Slack) 13 | 14 | Here are the key components of architecture: 15 | 16 | image::images/architecture.png[] 17 | 18 | == Deploy Lex bot and Alexa backend function using Java 19 | 20 | You need to install `org.sample.aws.lex:lex-java:0.2` dependency as explained at https://github.com/arun-gupta/lex-java#install-jar-locally before building this project. 21 | 22 | ``` 23 | mvn -f starwars-chatbot/pom.xml clean package install 24 | ``` 25 | 26 | ARN for Alexa function: `aws lambda get-function --function-name StarWarsChatbot --region us-east-1 | jq .Configuration.FunctionArn` 27 | 28 | NOTE: Getting Started with Alexa skill using Java is explained at https://github.com/arun-gupta/alexa-skill-java. 29 | 30 | == JSON Document 31 | 32 | Data is loaded as JSON documents in DynamoDB. Here is a sample JSON document: 33 | 34 | [source, json] 35 | ---- 36 | { 37 | "dead": true, 38 | "force-sensitive": true, 39 | "force-side": "light", 40 | "id": 1, 41 | "lightsaber": "green", 42 | "planet": "Dagobah", 43 | "quotes": [ 44 | "When nine hundred years old you reach, look as good you will not.", 45 | "Truly wonderful, the mind of a child is", 46 | "A Jedi uses the Force for knowledge and defense, never for attack", 47 | "That is why you fail.", 48 | "Adventure. Excitement. A Jedi craves not these things.", 49 | "Judge me by my size, do you?", 50 | "Fear is the path to the dark side", 51 | "Wars not make one great", 52 | "Do, or do not. There is no try", 53 | "Size matters not", 54 | "The dark side clouds everything", 55 | "Impossible to see the future is", 56 | "Clear your mind must be", 57 | "Much to learn you still have ... my old padawan" 58 | ], 59 | "weapon": "lightsaber", 60 | "whoami": "Yoda" 61 | } 62 | ---- 63 | 64 | Create Global Secondary Index on `whoami` 65 | 66 | == Different platforms 67 | 68 | === Lex 69 | 70 | http://docs.aws.amazon.com/lex/latest/dg/using-lambda.html 71 | 72 | image::images/lexbot.png[width="50%"] 73 | 74 | === Twilio/SMS 75 | 76 | . Send a message to 408-913-9827 as shown below: 77 | 78 | image::images/sms.png[width="50%"] 79 | 80 | Details: https://docs.aws.amazon.com/lex/latest/dg/twilio-bot-association.html 81 | 82 | === Facebook 83 | 84 | . Like https://www.facebook.com/Star-Wars-Chatbot-124902658243108/ 85 | . From http://messenger.com, send a message to this page as shown below: 86 | 87 | image::images/facebook.png[width="50%"] 88 | 89 | Details: http://docs.aws.amazon.com/lex/latest/dg/fb-bot-association.html 90 | 91 | === Slack 92 | 93 | . Get yourself invited: https://join.slack.com/t/starwarschatbot/shared_invite/MjM4OTU2MTEwMTE0LTE1MDUwOTgzMzItYzZmMjFhYTNiNA 94 | . DM with the app `star_wars_chatbot` and ask questions as shown below: 95 | 96 | image::images/slack.png[width="50%"] 97 | 98 | Details: https://docs.aws.amazon.com/lex/latest/dg/slack-bot-association.html 99 | 100 | === Alexa 101 | 102 | . Test using http://echosim.io or Alexa 103 | 104 | === Web 105 | 106 | TODO 107 | 108 | === Mobile 109 | 110 | TODO 111 | 112 | == Logging using Amazon CloudWatch 113 | 114 | == Monitoring using AWS X-Ray 115 | 116 | TODO 117 | 118 | == How to talk to the chatbot? 119 | 120 | Use phrase `Ask Star Wars` for Alexa, otherwise just the text as is. The list of questions is at https://github.com/arun-gupta/chatbot/wiki/Typical-Questions. 121 | 122 | -------------------------------------------------------------------------------- /slides.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/slides.key -------------------------------------------------------------------------------- /slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arun-gupta/chatbot/b66041c300251c49f0e6b62a943d26c177811793/slides.pdf -------------------------------------------------------------------------------- /starwars-chatbot/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | org.sample.aws.alexa 6 | starwars-chatbot 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | UTF-8 11 | 1.8 12 | 1.8 13 | 14 | 15 | 16 | 17 | 18 | com.amazon.alexa 19 | alexa-skills-kit 20 | 1.4.0 21 | compile 22 | 23 | 24 | 25 | com.amazonaws 26 | aws-java-sdk-dynamodb 27 | 1.11.127 28 | 29 | 30 | 31 | 32 | com.amazonaws 33 | aws-lambda-java-core 34 | 1.1.0 35 | 36 | 37 | com.amazonaws 38 | aws-java-sdk-lambda 39 | LATEST 40 | 41 | 42 | 43 | org.sample.aws.lex 44 | lex-java 45 | 0.2 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-shade-plugin 55 | 2.3 56 | 57 | false 58 | 59 | 60 | 61 | package 62 | 63 | shade 64 | 65 | 66 | 67 | 68 | 69 | com.github.seanroy 70 | lambda-maven-plugin 71 | 2.2.3 72 | 73 | ${project.basedir}/target/${project.artifactId}-${project.version}.jar 74 | ${project.version} 75 | starwars-chatbot 76 | us-east-1 77 | arn:aws:iam::091144949931:role/lambda_services 78 | true 79 | true 80 | 81 | 82 | java8 83 | 1024 84 | 30 85 | 86 | [ 87 | { 88 | "functionName":"StarWarsChatbot", 89 | "description":"Star Wars Chatbot", 90 | "handler":"org.sample.aws.chatbot.starwars.alexa.StarwarsSpeechletRequestStreamHandler", 91 | "triggers":[ 92 | { 93 | "integration":"Alexa Skills Kit" 94 | } 95 | ] 96 | }, 97 | { 98 | "functionName":"StarWarsLexbot", 99 | "description":"Star Wars Lexbot", 100 | "handler":"org.sample.aws.chatbot.starwars.lex.StarWarsLexBot", 101 | "triggers": [ 102 | { 103 | "integration": "Lex", 104 | "lexBotName": "StarWarsLexbot" 105 | } 106 | ] 107 | } 108 | ] 109 | 110 | 111 | 112 | 113 | install 114 | 115 | deploy-lambda 116 | 117 | 118 | 119 | 120 | 121 | 122 | starwars-chatbot 123 | 124 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/alexa/StarwarsSpeechlet.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.alexa; 2 | 3 | import org.sample.aws.chatbot.starwars.common.StarWarsIntent; 4 | import org.sample.aws.chatbot.starwars.common.StarWarsResponse; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.amazon.speech.slu.Intent; 9 | import com.amazon.speech.speechlet.IntentRequest; 10 | import com.amazon.speech.speechlet.LaunchRequest; 11 | import com.amazon.speech.speechlet.Session; 12 | import com.amazon.speech.speechlet.SessionEndedRequest; 13 | import com.amazon.speech.speechlet.SessionStartedRequest; 14 | import com.amazon.speech.speechlet.Speechlet; 15 | import com.amazon.speech.speechlet.SpeechletException; 16 | import com.amazon.speech.speechlet.SpeechletResponse; 17 | import com.amazon.speech.ui.PlainTextOutputSpeech; 18 | import com.amazon.speech.ui.Reprompt; 19 | import com.amazon.speech.ui.SimpleCard; 20 | 21 | /** 22 | * @author Arun Gupta 23 | */ 24 | public class StarwarsSpeechlet implements Speechlet { 25 | private static final Logger log = LoggerFactory.getLogger(StarwarsSpeechlet.class); 26 | 27 | @Override 28 | public void onSessionStarted(final SessionStartedRequest request, final Session session) 29 | throws SpeechletException { 30 | log.info("onSessionStarted requestId={}, sessionId={}", request.getRequestId(), 31 | session.getSessionId()); 32 | // any initialization logic goes here 33 | } 34 | 35 | @Override 36 | public SpeechletResponse onLaunch(final LaunchRequest request, final Session session) 37 | throws SpeechletException { 38 | log.info("onLaunch requestId={}, sessionId={}", request.getRequestId(), 39 | session.getSessionId()); 40 | return getWelcomeResponse(); 41 | } 42 | 43 | @Override 44 | public void onSessionEnded(final SessionEndedRequest request, final Session session) 45 | throws SpeechletException { 46 | log.info("onSessionEnded requestId={}, sessionId={}", request.getRequestId(), 47 | session.getSessionId()); 48 | // any cleanup logic goes here 49 | } 50 | 51 | @Override 52 | public SpeechletResponse onIntent(final IntentRequest request, final Session session) 53 | throws SpeechletException { 54 | log.info("onIntent requestId={}, sessionId={}", request.getRequestId(), 55 | session.getSessionId()); 56 | 57 | Intent intent = request.getIntent(); 58 | String intentName = (intent != null) ? intent.getName() : null; 59 | String character = intent.getSlot("character").getValue(); 60 | 61 | if (StarWarsIntent.QUOTES_INTENT.equals(intentName)) { 62 | return getQuotesResponse(character); 63 | } else if (StarWarsIntent.PLANET_INTENT.equals(intentName)) { 64 | return getPlanetResponse(character); 65 | } else if (StarWarsIntent.LIGHTSABER_INTENT.equals(intentName)) { 66 | return getLightsaberResponse(character); 67 | } else if (StarWarsIntent.FORCE_SENSITIVE_INTENT.equals(intentName)) { 68 | return getForceSensitiveResponse(character); 69 | } else if (StarWarsIntent.FORCE_SIDE_INTENT.equals(intentName)) { 70 | return getForceSideResponse(character); 71 | } else { 72 | throw new SpeechletException("Invalid Intent: " + intentName); 73 | } 74 | } 75 | 76 | /** 77 | * Creates and returns a {@code SpeechletResponse} with a welcome message. 78 | * 79 | * @return SpeechletResponse spoken and visual response for the given intent 80 | */ 81 | private SpeechletResponse getWelcomeResponse() { 82 | StarWarsResponse response = StarWarsResponse.getWelcomeResponse(); 83 | return getSpeechletResponseWithReprompt(response.getSpeechText(), response.getTitle()); 84 | } 85 | 86 | /** 87 | * Creates a {@code SpeechletResponse} for the help intent. 88 | * 89 | * @return SpeechletResponse spoken and visual response for the given intent 90 | */ 91 | private SpeechletResponse getHelpResponse() { 92 | StarWarsResponse response = StarWarsResponse.getWelcomeResponse(); 93 | return getSpeechletResponse(response.getSpeechText(), response.getTitle()); 94 | } 95 | 96 | private SpeechletResponse getQuotesResponse(String character) { 97 | StarWarsResponse response = StarWarsResponse.getQuotesResponse(character); 98 | return getSpeechletResponseWithReprompt(response.getSpeechText(), response.getTitle()); 99 | } 100 | 101 | private SpeechletResponse getPlanetResponse(String character) { 102 | StarWarsResponse response = StarWarsResponse.getPlanetResponse(character); 103 | return getSpeechletResponseWithReprompt(response.getSpeechText(), response.getTitle()); 104 | } 105 | 106 | private SpeechletResponse getLightsaberResponse(String character) { 107 | StarWarsResponse response = StarWarsResponse.getLightsaberResponse(character); 108 | return getSpeechletResponseWithReprompt(response.getSpeechText(), response.getTitle()); 109 | } 110 | 111 | private SpeechletResponse getForceSensitiveResponse(String name) { 112 | StarWarsResponse response = StarWarsResponse.getForceSensitiveResponse(name); 113 | return getSpeechletResponseWithReprompt(response.getSpeechText(), response.getTitle()); 114 | } 115 | 116 | private SpeechletResponse getForceSideResponse(String name) { 117 | StarWarsResponse response = StarWarsResponse.getForceSideResponse(name); 118 | return getSpeechletResponseWithReprompt(response.getSpeechText(), response.getTitle()); 119 | } 120 | 121 | private SimpleCard getCard(String title, String speechText) { 122 | // Create the Simple card content. 123 | SimpleCard card = new SimpleCard(); 124 | card.setTitle(title); 125 | card.setContent(speechText); 126 | return card; 127 | } 128 | 129 | private PlainTextOutputSpeech getSpeech(String speechText) { 130 | // Create the plain text output. 131 | PlainTextOutputSpeech speech = new PlainTextOutputSpeech(); 132 | speech.setText(speechText); 133 | 134 | return speech; 135 | } 136 | 137 | private SpeechletResponse getSpeechletResponse(String speechText, String title) { 138 | return SpeechletResponse.newTellResponse(getSpeech(speechText), getCard(speechText, title)); 139 | } 140 | 141 | private SpeechletResponse getSpeechletResponseWithReprompt(String speechText, String title) { 142 | // Create the plain text output. 143 | PlainTextOutputSpeech speech = getSpeech(speechText); 144 | 145 | // Create reprompt 146 | Reprompt reprompt = new Reprompt(); 147 | reprompt.setOutputSpeech(speech); 148 | 149 | return SpeechletResponse.newAskResponse(speech, reprompt, getCard(speechText, title)); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/alexa/StarwarsSpeechletRequestStreamHandler.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.alexa; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import com.amazon.speech.speechlet.lambda.SpeechletRequestStreamHandler; 7 | import org.sample.aws.chatbot.starwars.alexa.StarwarsSpeechlet; 8 | 9 | /** 10 | * This class is the handler for AWS Lambda function. 11 | * 12 | * @author Arun Gupta 13 | */ 14 | public class StarwarsSpeechletRequestStreamHandler extends SpeechletRequestStreamHandler { 15 | private static final Set SUPPORTED_APPLICATION_IDS = new HashSet<>(); 16 | static { 17 | SUPPORTED_APPLICATION_IDS.add("amzn1.ask.skill.81e128e4-dd7a-4585-aa16-e3d9b1459962"); 18 | } 19 | 20 | public StarwarsSpeechletRequestStreamHandler() { 21 | super(new StarwarsSpeechlet(), SUPPORTED_APPLICATION_IDS); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/common/StarWarsIntent.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.common; 2 | 3 | public final class StarWarsIntent { 4 | public static final String QUOTES_INTENT = "StarWarsQuotesIntent"; 5 | public static final String PLANET_INTENT = "StarWarsPlanetIntent"; 6 | public static final String LIGHTSABER_INTENT = "StarWarsLightsaberIntent"; 7 | public static final String FORCE_SENSITIVE_INTENT = "StarWarsForceSensitiveIntent"; 8 | public static final String FORCE_SIDE_INTENT = "StarWarsForceSideIntent"; 9 | public static final String QUESTION_INTENT = "StarWarsAskQuestionIntent"; 10 | } 11 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/common/StarWarsResponse.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.common; 2 | 3 | import org.sample.aws.chatbot.starwars.db.DBUtil; 4 | import org.sample.aws.chatbot.starwars.db.StarWarsCharacter; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Random; 10 | 11 | public class StarWarsResponse { 12 | String speechText; 13 | String title; 14 | Map sessionAttributes; 15 | 16 | private static final String help = "You can ask quotes, lightsaber color, Jedi or Sith questions."; 17 | 18 | public StarWarsResponse(String speechText, String title) { 19 | this.speechText = speechText; 20 | this.title = title; 21 | sessionAttributes = new HashMap<>(); 22 | } 23 | 24 | public String getSpeechText() { 25 | return speechText; 26 | } 27 | 28 | public String getTitle() { 29 | return title; 30 | } 31 | 32 | public Map getSessionAttributes() { 33 | return sessionAttributes; 34 | } 35 | 36 | public static StarWarsResponse getWelcomeResponse() { 37 | return new StarWarsResponse("Welcome to Star Wars Chatbot!" + help, "Star Wars Welcome"); 38 | } 39 | 40 | public static StarWarsResponse getHelpResponse() { 41 | return new StarWarsResponse(help, "Star Wars Help"); 42 | } 43 | 44 | public static StarWarsResponse getPlanetResponse(String name) { 45 | StarWarsCharacter character = DBUtil.getCharacter(name); 46 | 47 | String speechText; 48 | 49 | if (character != null && character.getName() != null) { 50 | String planet = character.getPlanet(); 51 | 52 | if (null == planet || planet.equals("")) { 53 | speechText = character.getName() + "'s planet is not known"; 54 | } else { 55 | speechText = character.getName() + " is from the planet " + planet; 56 | } 57 | } else { 58 | speechText = "Are you sure " + name + " was in Star Wars?"; 59 | } 60 | 61 | return new StarWarsResponse(speechText, "Star Wars Planet"); 62 | } 63 | 64 | public static StarWarsResponse getLightsaberResponse(String name) { 65 | StarWarsCharacter character = DBUtil.getCharacter(name); 66 | 67 | String speechText; 68 | 69 | if (character != null && character.getName() != null) { 70 | if (null == character.getLightsaberColor()) { 71 | speechText = character.getName() + " does not have a lightsaber"; 72 | } else { 73 | speechText = character.getName() + 74 | "'s ligthsaber is " + 75 | character.getLightsaberColor(); 76 | } 77 | } else { 78 | speechText = "Are you sure " + name + " was in Star Wars?"; 79 | } 80 | return new StarWarsResponse(speechText, "Star Wars Lightsaber"); 81 | } 82 | 83 | 84 | public static StarWarsResponse getQuotesResponse(String name) { 85 | StarWarsCharacter character = DBUtil.getCharacter(name); 86 | 87 | String speechText; 88 | 89 | if (character != null && character.getName() != null) { 90 | List list = character.getQuotes(); 91 | Random random = new Random(); 92 | speechText = "Here is a quote from " + 93 | character.getName() + 94 | ": \"" + 95 | list.get(random.nextInt(list.size())) + 96 | "\""; 97 | } else { 98 | speechText = "Are you sure " + name + " was in Star Wars?"; 99 | } 100 | 101 | // Create the Simple card content. 102 | return new StarWarsResponse(speechText, "Star Wars Quotes"); 103 | } 104 | 105 | 106 | public static StarWarsResponse getForceSensitiveResponse(String name) { 107 | StarWarsCharacter character = DBUtil.getCharacter(name); 108 | 109 | String speechText; 110 | 111 | if (character != null && character.getName() != null) { 112 | speechText = (character.isForceSensitive() ? "Yes, " : "No, ") + 113 | character.getName() + 114 | " is " + (character.isForceSensitive() ? "" : " not ") + 115 | " sensitive to the Force."; 116 | } else { 117 | speechText = "Are you sure " + name + " was in Star Wars?"; 118 | } 119 | 120 | // Create the Simple card content. 121 | return new StarWarsResponse(speechText, "Star Wars Force Sensitive"); 122 | } 123 | 124 | public static StarWarsResponse getForceSideResponse(String name) { 125 | StarWarsCharacter character = DBUtil.getCharacter(name); 126 | 127 | String speechText; 128 | 129 | if (character != null && character.getName() != null) { 130 | if (character.isForceSensitive()) { 131 | speechText = character.getName() + 132 | " is on the " + 133 | character.getForceSide() + 134 | " side, and so is a " + 135 | (character.getForceSide().equals("light") ? "Jedi" : "Sith"); 136 | } else { 137 | speechText = character.getName() + " is not sensitive to the Force"; 138 | } 139 | } else { 140 | speechText = "Are you sure " + name + " was in Star Wars?"; 141 | } 142 | 143 | // Create the Simple card content. 144 | return new StarWarsResponse(speechText, "Star Wars Force Side"); 145 | } 146 | 147 | public static StarWarsResponse getDialogueQuestion() { 148 | StarWarsCharacter character = DBUtil.getRandomCharacter(); 149 | List list = character.getQuotes(); 150 | 151 | Random random = new Random(); 152 | String speechText = "Who said \"" + list.get(random.nextInt(list.size())) + "\""; 153 | 154 | StarWarsResponse response = new StarWarsResponse(speechText, "Star Wars Quote Question"); 155 | response.sessionAttributes.put("character", character.getName()); 156 | response.sessionAttributes.put("question", speechText); 157 | 158 | return response; 159 | } 160 | 161 | public static StarWarsResponse getDialogueResponse() { 162 | String speechText = "Yep, you're right!"; 163 | 164 | return new StarWarsResponse(speechText, "Star Wars Quote Response"); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/db/DBUtil.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.db; 2 | 3 | import com.amazonaws.regions.Regions; 4 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; 5 | import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; 6 | import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; 7 | import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBScanExpression; 8 | import com.amazonaws.services.dynamodbv2.document.DynamoDB; 9 | import com.amazonaws.services.dynamodbv2.model.AttributeValue; 10 | import com.amazonaws.services.dynamodbv2.model.ScanRequest; 11 | import com.amazonaws.services.dynamodbv2.model.ScanResult; 12 | 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Random; 17 | 18 | /** 19 | * @author Arun Gupta 20 | */ 21 | public class DBUtil { 22 | 23 | private static AmazonDynamoDB dynamodbClient; 24 | 25 | private static AmazonDynamoDB getClient() { 26 | if (null != dynamodbClient) { 27 | return dynamodbClient; 28 | } 29 | 30 | String region = System.getProperty("DYNAMODB_REGION"); 31 | if (null == region) { 32 | System.err.println("Region not set, default \"" + Regions.US_EAST_1.name() + "\" is used"); 33 | region = Regions.US_EAST_1.name(); 34 | } 35 | System.out.println("DynamoDB region: " + region); 36 | 37 | dynamodbClient = AmazonDynamoDBClientBuilder.standard() 38 | .withRegion(region) 39 | .build(); 40 | 41 | return dynamodbClient; 42 | } 43 | 44 | private static int getCharactersCount() { 45 | ScanRequest scanRequest = new ScanRequest() 46 | .withTableName("starwars"); 47 | ScanResult result = getClient().scan(scanRequest); 48 | System.out.println("Total number of characters found: " + result.getCount()); 49 | 50 | // scanning only returns 1MB of data 51 | // need to aggressively scan and return an accurate count 52 | 53 | return result.getCount(); 54 | } 55 | 56 | public static StarWarsCharacter getRandomCharacter() { 57 | DynamoDBMapper mapper = new DynamoDBMapper(getClient()); 58 | Random random = new Random(); 59 | 60 | return mapper.load(StarWarsCharacter.class, random.nextInt(getCharactersCount()) + 1); 61 | } 62 | 63 | public static StarWarsCharacter getCharacter(String name) { 64 | System.out.println("Name: " + name); 65 | DynamoDBMapper mapper = new DynamoDBMapper(getClient()); 66 | Map eav = new HashMap<>(); 67 | eav.put(":name", new AttributeValue().withS(name.toLowerCase())); 68 | DynamoDBScanExpression scanExpression = new DynamoDBScanExpression() 69 | .withFilterExpression("whoami = :name") 70 | .withExpressionAttributeValues(eav); 71 | List list = mapper.scan(StarWarsCharacter.class, scanExpression); 72 | 73 | if (!list.isEmpty()) { 74 | return list.get(0); 75 | } 76 | 77 | return null; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/db/StarWarsCharacter.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.db; 2 | 3 | import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute; 4 | import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; 5 | import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author Arun Gupta 11 | */ 12 | @DynamoDBTable(tableName = "starwars") 13 | public class StarWarsCharacter { 14 | 15 | private int id; 16 | private String name; 17 | private String planet; 18 | private String lightsaberColor; 19 | private String ship; 20 | private String weapon; 21 | private boolean dead; 22 | private boolean forceSensitive; 23 | private String forceSide; 24 | private List quotes; 25 | 26 | public StarWarsCharacter() { 27 | } 28 | 29 | public StarWarsCharacter(int id, String name, String planet) { 30 | this.id = id; 31 | this.name = name; 32 | this.planet = planet; 33 | } 34 | 35 | @DynamoDBHashKey 36 | public int getId() { 37 | return id; 38 | } 39 | 40 | public void setId(int id) { 41 | this.id = id; 42 | } 43 | 44 | @DynamoDBHashKey(attributeName = "whoami") 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | @DynamoDBAttribute 54 | public String getPlanet() { 55 | return planet; 56 | } 57 | 58 | public void setPlanet(String planet) { 59 | this.planet = planet; 60 | } 61 | 62 | @DynamoDBAttribute(attributeName = "lightsaber") 63 | public String getLightsaberColor() { 64 | return lightsaberColor; 65 | } 66 | 67 | public void setLightsaberColor(String lightsaberColor) { 68 | this.lightsaberColor = lightsaberColor; 69 | } 70 | 71 | public String getShip() { 72 | return ship; 73 | } 74 | 75 | public void setShip(String ship) { 76 | this.ship = ship; 77 | } 78 | 79 | public String getWeapon() { 80 | return weapon; 81 | } 82 | 83 | public void setWeapon(String weapon) { 84 | this.weapon = weapon; 85 | } 86 | 87 | public boolean isDead() { 88 | return dead; 89 | } 90 | 91 | public void setDead(boolean dead) { 92 | this.dead = dead; 93 | } 94 | 95 | @DynamoDBAttribute(attributeName = "force-sensitive") 96 | public boolean isForceSensitive() { 97 | return forceSensitive; 98 | } 99 | 100 | public void setForceSensitive(boolean forceSensitive) { 101 | this.forceSensitive = forceSensitive; 102 | } 103 | 104 | @DynamoDBAttribute(attributeName = "force-side") 105 | public String getForceSide() { 106 | return forceSide; 107 | } 108 | 109 | public void setForceSide(String forceSide) { 110 | this.forceSide = forceSide; 111 | } 112 | 113 | public List getQuotes() { 114 | return quotes; 115 | } 116 | 117 | public void setQuotes(List quotes) { 118 | this.quotes = quotes; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/java/org/sample/aws/chatbot/starwars/lex/StarWarsLexBot.java: -------------------------------------------------------------------------------- 1 | package org.sample.aws.chatbot.starwars.lex; 2 | 3 | import com.amazonaws.services.lambda.runtime.Context; 4 | import com.amazonaws.services.lambda.runtime.RequestHandler; 5 | import org.sample.aws.chatbot.starwars.common.StarWarsIntent; 6 | import org.sample.aws.chatbot.starwars.common.StarWarsResponse; 7 | import org.sample.aws.lex.request.LexRequest; 8 | import org.sample.aws.lex.response.DialogAction; 9 | import org.sample.aws.lex.response.LexResponse; 10 | import org.sample.aws.lex.response.Message; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Map; 15 | 16 | public class StarWarsLexBot implements RequestHandler { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(StarWarsLexBot.class); 19 | 20 | @Override 21 | public LexResponse handleRequest(LexRequest request, Context context) { 22 | log.info("onIntent requestId={} intent={}", context.getAwsRequestId(), request.getCurrentIntent().getName()); 23 | 24 | String intent = request.getCurrentIntent().getName(); 25 | String character = request.getCurrentIntent().getSlots().get("character"); 26 | 27 | if (StarWarsIntent.QUOTES_INTENT.equals(intent)) { 28 | return getQuotesResponse(character); 29 | } else if (StarWarsIntent.PLANET_INTENT.equals(intent)) { 30 | return getPlanetResponse(character); 31 | } else if (StarWarsIntent.LIGHTSABER_INTENT.equals(intent)) { 32 | return getLightsaberResponse(character); 33 | } else if (StarWarsIntent.FORCE_SENSITIVE_INTENT.equals(intent)) { 34 | return getForceSensitiveResponse(character); 35 | } else if (StarWarsIntent.FORCE_SIDE_INTENT.equals(intent)) { 36 | return getForceSideResponse(character); 37 | } else if (StarWarsIntent.QUESTION_INTENT.equals(intent)) { 38 | 39 | String actualCharacter = request.getInputTranscript(); 40 | 41 | if (request.getSessionAttributes() == null) 42 | throw new RuntimeException("Session attributes are null"); 43 | String expectedCharacter = request.getSessionAttributes().get("character"); 44 | String question = request.getSessionAttributes().get("question"); 45 | 46 | System.out.println("expected/character: " + expectedCharacter); 47 | System.out.println("actual: " + actualCharacter); 48 | System.out.println("question: " + question); 49 | 50 | if (null != expectedCharacter && 51 | null != actualCharacter && 52 | expectedCharacter.toLowerCase().equals(actualCharacter.toLowerCase())) { 53 | return getDialogueResponse(); 54 | } else { 55 | return getDialogueQuestion(request.getSessionAttributes()); 56 | } 57 | } else { 58 | throw new RuntimeException("Invalid Intent: " + request.getCurrentIntent().getName()); 59 | } 60 | } 61 | 62 | private LexResponse getHelpResponse() { 63 | StarWarsResponse response = StarWarsResponse.getHelpResponse(); 64 | return getLexResponse(response.getSpeechText(), response.getTitle()); 65 | } 66 | 67 | private LexResponse getQuotesResponse(String name) { 68 | StarWarsResponse response = StarWarsResponse.getQuotesResponse(name); 69 | return getLexResponse(response.getSpeechText(), response.getTitle()); 70 | } 71 | 72 | private LexResponse getPlanetResponse(String name) { 73 | StarWarsResponse response = StarWarsResponse.getPlanetResponse(name); 74 | return getLexResponse(response.getSpeechText(), response.getTitle()); 75 | } 76 | 77 | private LexResponse getLightsaberResponse(String name) { 78 | StarWarsResponse response = StarWarsResponse.getLightsaberResponse(name); 79 | return getLexResponse(response.getSpeechText(), response.getTitle()); 80 | } 81 | 82 | private LexResponse getForceSensitiveResponse(String name) { 83 | StarWarsResponse response = StarWarsResponse.getForceSensitiveResponse(name); 84 | return getLexResponse(response.getSpeechText(), response.getTitle()); 85 | } 86 | 87 | private LexResponse getForceSideResponse(String name) { 88 | StarWarsResponse response = StarWarsResponse.getForceSideResponse(name); 89 | return getLexResponse(response.getSpeechText(), response.getTitle()); 90 | } 91 | 92 | private LexResponse getDialogueQuestion(Map sessionAttributes) { 93 | System.out.println("getDialogueQuestion"); 94 | 95 | LexResponse lexResponse = new LexResponse(); 96 | 97 | String answered = ""; 98 | String question = ""; 99 | 100 | if (sessionAttributes != null) { 101 | answered = sessionAttributes.get("answered"); 102 | question = sessionAttributes.get("question"); 103 | } 104 | 105 | if ((null == question) || 106 | (null != answered && answered.equals("yes"))) { 107 | System.out.println("Getting a new question"); 108 | StarWarsResponse response = StarWarsResponse.getDialogueQuestion(); 109 | String character = response.getSessionAttributes().get("character"); 110 | question = response.getSessionAttributes().get("question"); 111 | 112 | lexResponse.addAttribute("character", character); 113 | lexResponse.addAttribute("question", question); 114 | lexResponse.addAttribute("answered", "no"); 115 | } 116 | 117 | DialogAction dialogAction = new DialogAction(); 118 | dialogAction.setType(DialogAction.ELICIT_SLOT_TYPE); 119 | Message message = new Message(); 120 | message.setContentType(Message.CONTENT_TYPE_PLAIN_TEXT); 121 | message.setContent(question); 122 | dialogAction.setMessage(message); 123 | dialogAction.setIntentName(StarWarsIntent.QUESTION_INTENT); 124 | dialogAction.setSlotToElicit("AnswerSlot"); 125 | dialogAction.addSlots("AnswerSlot", ""); 126 | 127 | lexResponse.setDialogAction(dialogAction); 128 | 129 | return lexResponse; 130 | } 131 | 132 | private LexResponse getDialogueResponse() { 133 | StarWarsResponse response = StarWarsResponse.getDialogueResponse(); 134 | LexResponse lexResponse = getLexResponse(response.getSpeechText(), response.getTitle()); 135 | lexResponse.addAttribute("answered", "yes"); 136 | lexResponse.clearAttributes(); 137 | return lexResponse; 138 | } 139 | 140 | private LexResponse getLexResponse(String speechText, String title) { 141 | Message message = new Message(Message.CONTENT_TYPE_PLAIN_TEXT, speechText); 142 | DialogAction dialogAction = new DialogAction(DialogAction.CLOSE_TYPE, DialogAction.FULFILLMENT_STATE_FULFILLED, message); 143 | 144 | return new LexResponse(dialogAction); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /starwars-chatbot/src/main/resources/speech-assets/interaction-model.json: -------------------------------------------------------------------------------- 1 | { 2 | "intents": [ 3 | { 4 | "name": "StarWarsQuotesIntent", 5 | "samples": [ 6 | "Tell me a {character} quote", 7 | "Tell me a quote by {character}", 8 | "give me a quote from {character}", 9 | "give me a {character} quote" 10 | ], 11 | "slots": [ 12 | { 13 | "name": "character", 14 | "type": "StarWarsCharacters", 15 | "samples": [] 16 | } 17 | ] 18 | }, 19 | { 20 | "name": "StarWarsForceSensitiveIntent", 21 | "samples": [ 22 | "Is {character} force-sensitive", 23 | "Can {character} use the force" 24 | ], 25 | "slots": [ 26 | { 27 | "name": "character", 28 | "type": "StarWarsCharacters", 29 | "samples": [] 30 | } 31 | ] 32 | }, 33 | { 34 | "name": "StarWarsForceSideIntent", 35 | "samples": [ 36 | "What side of the force was {character} on", 37 | "Was {character} on the Light or Dark side of the force", 38 | "Was {character} affiliated with the Jedi or the Sith", 39 | "was {character} a jedi", 40 | "was {character} a sith" 41 | ], 42 | "slots": [ 43 | { 44 | "name": "character", 45 | "type": "StarWarsCharacters", 46 | "samples": [] 47 | } 48 | ] 49 | }, 50 | { 51 | "name": "StarWarsLightsaberIntent", 52 | "samples": [ 53 | "what is the color of {character} lightsaber", 54 | "what color is {character} lightsaber", 55 | "what\u0027s the color of {character} lightsaber" 56 | ], 57 | "slots": [ 58 | { 59 | "name": "character", 60 | "type": "StarWarsCharacters", 61 | "samples": [] 62 | } 63 | ] 64 | }, 65 | { 66 | "name": "StarWarsAskQuestionIntent", 67 | "samples": [ 68 | "Ask me a dialogue question", 69 | "Ask me a line question", 70 | "Ask me a quote", 71 | "Ask me a movie quote", 72 | "Ask me a quote someone said in the movie" 73 | ], 74 | "slots": [ 75 | { 76 | "name": "AnswerSlot", 77 | "type": "StarWarsCharacters", 78 | "samples": [] 79 | } 80 | ] 81 | }, 82 | { 83 | "name": "StarWarsPlanetIntent", 84 | "samples": [ 85 | "what planet is {character} from", 86 | "where is {character} from", 87 | "what planet was {character} born on", 88 | "where was {character} born", 89 | "what is {character} planet" 90 | ], 91 | "slots": [ 92 | { 93 | "name": "character", 94 | "type": "StarWarsCharacters", 95 | "samples": [] 96 | } 97 | ] 98 | } 99 | ], 100 | "types": [ 101 | { 102 | "name": "StarWarsCharacters", 103 | "values": [ 104 | { 105 | "name": { 106 | "value": "Princess Leia", 107 | "synonyms": [ 108 | "Leia" 109 | ] 110 | } 111 | }, 112 | { 113 | "name": { 114 | "value": "Luke Skywalker", 115 | "synonyms": [ 116 | "Luke" 117 | ] 118 | } 119 | }, 120 | { 121 | "name": { 122 | "value": "Obi-wan Kenobi", 123 | "synonyms": [ 124 | "Obi-wan" 125 | ] 126 | } 127 | }, 128 | { 129 | "name": { 130 | "value": "Boba Fett", 131 | "synonyms": [] 132 | } 133 | }, 134 | { 135 | "name": { 136 | "value": "Yoda", 137 | "synonyms": [] 138 | } 139 | }, 140 | { 141 | "name": { 142 | "value": "Han Solo", 143 | "synonyms": [ 144 | "Han" 145 | ] 146 | } 147 | }, 148 | { 149 | "name": { 150 | "value": "Emperor Palpatine", 151 | "synonyms": [ 152 | "Palpatine" 153 | ] 154 | } 155 | }, 156 | { 157 | "name": { 158 | "value": "Kylo Ren", 159 | "synonyms": [ 160 | "Ren" 161 | ] 162 | } 163 | }, 164 | { 165 | "name": { 166 | "value": "Darth Vader", 167 | "synonyms": [ 168 | "Vader" 169 | ] 170 | } 171 | } 172 | ] 173 | } 174 | ], 175 | "prompts": [ 176 | { 177 | "id": "Elicit.Intent-StarWarsQuotesIntent.IntentSlot-character", 178 | "promptVersion": "1.0", 179 | "definitionVersion": "1.0", 180 | "variations": [ 181 | { 182 | "type": "PlainText", 183 | "value": "Which character" 184 | } 185 | ] 186 | }, 187 | { 188 | "id": "Elicit.Intent-StarWarsForceSensitiveIntent.IntentSlot-character", 189 | "promptVersion": "1.0", 190 | "definitionVersion": "1.0", 191 | "variations": [ 192 | { 193 | "type": "PlainText", 194 | "value": "Which character" 195 | } 196 | ] 197 | }, 198 | { 199 | "id": "Elicit.Intent-StarWarsForceSideIntent.IntentSlot-character", 200 | "promptVersion": "1.0", 201 | "definitionVersion": "1.0", 202 | "variations": [ 203 | { 204 | "type": "PlainText", 205 | "value": "Which character" 206 | } 207 | ] 208 | }, 209 | { 210 | "id": "Elicit.Intent-StarWarsLightsaberIntent.IntentSlot-character", 211 | "promptVersion": "1.0", 212 | "definitionVersion": "1.0", 213 | "variations": [ 214 | { 215 | "type": "PlainText", 216 | "value": "Which character" 217 | } 218 | ] 219 | }, 220 | { 221 | "id": "Elicit.Intent-StarWarsAskQuestionIntent.IntentSlot-AnswerSlot", 222 | "promptVersion": "1.0", 223 | "definitionVersion": "1.0", 224 | "variations": [ 225 | { 226 | "type": "PlainText", 227 | "value": "Which character" 228 | } 229 | ] 230 | }, 231 | { 232 | "id": "Elicit.Intent-StarWarsPlanetIntent.IntentSlot-character", 233 | "promptVersion": "1.0", 234 | "definitionVersion": "1.0", 235 | "variations": [ 236 | { 237 | "type": "PlainText", 238 | "value": "Which character" 239 | } 240 | ] 241 | } 242 | ], 243 | "dialog": { 244 | "version": "1.0", 245 | "intents": [ 246 | { 247 | "name": "StarWarsQuotesIntent", 248 | "confirmationRequired": false, 249 | "prompts": {}, 250 | "slots": [ 251 | { 252 | "name": "character", 253 | "type": "StarWarsCharacters", 254 | "elicitationRequired": true, 255 | "confirmationRequired": false, 256 | "prompts": { 257 | "elicit": "Elicit.Intent-StarWarsQuotesIntent.IntentSlot-character" 258 | } 259 | } 260 | ] 261 | }, 262 | { 263 | "name": "StarWarsForceSensitiveIntent", 264 | "confirmationRequired": false, 265 | "prompts": {}, 266 | "slots": [ 267 | { 268 | "name": "character", 269 | "type": "StarWarsCharacters", 270 | "elicitationRequired": true, 271 | "confirmationRequired": false, 272 | "prompts": { 273 | "elicit": "Elicit.Intent-StarWarsForceSensitiveIntent.IntentSlot-character" 274 | } 275 | } 276 | ] 277 | }, 278 | { 279 | "name": "StarWarsForceSideIntent", 280 | "confirmationRequired": false, 281 | "prompts": {}, 282 | "slots": [ 283 | { 284 | "name": "character", 285 | "type": "StarWarsCharacters", 286 | "elicitationRequired": true, 287 | "confirmationRequired": false, 288 | "prompts": { 289 | "elicit": "Elicit.Intent-StarWarsForceSideIntent.IntentSlot-character" 290 | } 291 | } 292 | ] 293 | }, 294 | { 295 | "name": "StarWarsLightsaberIntent", 296 | "confirmationRequired": false, 297 | "prompts": {}, 298 | "slots": [ 299 | { 300 | "name": "character", 301 | "type": "StarWarsCharacters", 302 | "elicitationRequired": true, 303 | "confirmationRequired": false, 304 | "prompts": { 305 | "elicit": "Elicit.Intent-StarWarsLightsaberIntent.IntentSlot-character" 306 | } 307 | } 308 | ] 309 | }, 310 | { 311 | "name": "StarWarsAskQuestionIntent", 312 | "confirmationRequired": false, 313 | "prompts": {}, 314 | "slots": [ 315 | { 316 | "name": "AnswerSlot", 317 | "type": "StarWarsCharacters", 318 | "elicitationRequired": true, 319 | "confirmationRequired": false, 320 | "prompts": { 321 | "elicit": "Elicit.Intent-StarWarsAskQuestionIntent.IntentSlot-AnswerSlot" 322 | } 323 | } 324 | ] 325 | }, 326 | { 327 | "name": "StarWarsPlanetIntent", 328 | "confirmationRequired": false, 329 | "prompts": {}, 330 | "slots": [ 331 | { 332 | "name": "character", 333 | "type": "StarWarsCharacters", 334 | "elicitationRequired": true, 335 | "confirmationRequired": false, 336 | "prompts": { 337 | "elicit": "Elicit.Intent-StarWarsPlanetIntent.IntentSlot-character" 338 | } 339 | } 340 | ] 341 | } 342 | ] 343 | } 344 | } --------------------------------------------------------------------------------