├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── apiai.sublime-project ├── examples └── get_contexts.js ├── index.d.ts ├── index.js ├── module ├── apiai.js ├── contexts_request.js ├── delete_contexts_request.js ├── developer_request.js ├── event_request.js ├── exceptions.js ├── get_contexts_request.js ├── intent_request.js ├── json_api_dev_request.js ├── json_api_request.js ├── query_dev_request.js ├── query_request.js ├── request.js ├── text_request.js ├── tts_request.js ├── user_entities_request.js └── voice_request.js ├── package.json ├── samples ├── 1.wav ├── ann_smith.wav ├── delete_contexts.js ├── event_request.js ├── facebook │ ├── .dockerignore │ ├── .gitignore │ ├── Dockerfile │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ ├── src │ │ └── app.js │ └── test │ │ └── app_test.js ├── kik │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ └── src │ │ └── app.js ├── line │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ └── src │ │ ├── app.js │ │ ├── linebot.js │ │ └── linebotconfig.js ├── rus_example.wav ├── server.js ├── skype │ ├── .gitignore │ ├── LICENSE │ ├── LICENSE.txt │ ├── README.md │ ├── app.js │ ├── app.json │ ├── package.json │ ├── skypebot.js │ └── skypebotconfig.js ├── spark │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ └── src │ │ ├── app.js │ │ ├── sparkbot.js │ │ └── sparkbotconfig.js ├── telegram │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ └── src │ │ ├── app.js │ │ ├── telegrambot.js │ │ └── telegrambotconfig.js ├── text_request.js ├── text_request_chinese.js ├── text_request_no_ssl.js ├── text_request_with_contexts.js ├── text_request_with_entities.js ├── text_request_with_parameters.js ├── tropo │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ └── src │ │ ├── app.js │ │ ├── tropobot.js │ │ └── tropobotconfig.js ├── tts_request.js ├── twilio │ ├── bot │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── app.json │ │ ├── package.json │ │ └── src │ │ │ ├── app.js │ │ │ ├── twiliobot.js │ │ │ └── twiliobotconfig.js │ └── ip-messaging │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── app.json │ │ ├── package.json │ │ └── src │ │ ├── app.js │ │ ├── twiliobot.js │ │ └── twiliobotconfig.js ├── twitter │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── app.json │ ├── package.json │ └── src │ │ ├── app.js │ │ ├── twitterbot.js │ │ └── twitterbotconfig.js ├── user_entities_request.js └── voice_request.js └── typescript_examples ├── text_request.ts ├── tts_request.ts └── user_entities_request.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | 29 | # Mac OS 30 | .DS_Store 31 | 32 | # IDEA 33 | api-ai-node-js.iml 34 | .idea/ -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node" : true, 3 | "undef": true, 4 | "unused": true, 5 | "strict": true 6 | } -------------------------------------------------------------------------------- /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 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fork of Node.js SDK for Api.ai - with ability to work on intents 2 | 3 | This is a fork of the official Node.js client for [Api.ai](http://api.ai) - where we have added the ability to work with intents (create, udpate, list and remove). 4 | Note that this fork requires the developer token as well - it's also suitable for other Api.ai objects that work with the developer token. 5 | 6 | * [Installation](#installation) 7 | * [Usage](#usage) 8 | 9 | # Installation 10 | 11 | * Install [Node.js](https://nodejs.org/) 12 | * Install Api.ai SDK with `npm`: 13 | ```shell 14 | npm install apiai 15 | ``` 16 | 17 | # Usage 18 | * Create `main.js` file with the following code: 19 | ```javascript 20 | var apiai = require('apiai'); 21 | 22 | var app = apiai("", ""); 23 | 24 | function ask(text, options) { 25 | return new Promise((resolve, reject) => { 26 | var defaultOptions = { 27 | sessionId: '', // use any arbitrary id - doesn't matter 28 | }; 29 | 30 | let request = app.textRequest(text, Object.assign(defaultOptions, options)); 31 | 32 | request.on('response', (response) => { 33 | return resolve(response); 34 | }); 35 | 36 | request.on('error', (error) => { 37 | return reject(error); 38 | }); 39 | 40 | request.end(); 41 | }) 42 | } 43 | 44 | function getAllIntents(options) { 45 | return new Promise((resolve, reject) => { 46 | let request = app.intentGetRequest(options); 47 | 48 | request.on('response', (response) => { 49 | return resolve(response); 50 | }); 51 | 52 | request.on('error', (error) => { 53 | return reject(error); 54 | }); 55 | 56 | request.end(); 57 | }) 58 | } 59 | 60 | // ask something 61 | ask('') 62 | .then(response => { 63 | console.log(response); 64 | }).catch(error => { 65 | console.log(error) 66 | }); 67 | 68 | // get list of all intents 69 | getAllIntents() 70 | .then(intents => { 71 | console.log(intents); 72 | }).catch(error => { 73 | console.log(error) 74 | }); 75 | 76 | 77 | ``` 78 | * Run following command. 79 | ```shell 80 | node main.js 81 | ``` 82 | * Your can find more examples in [`samples`](samples) directory. 83 | -------------------------------------------------------------------------------- /apiai.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "build_systems": 3 | [ 4 | { 5 | "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)" 6 | } 7 | ], 8 | "folders": 9 | [ 10 | { 11 | "follow_symlinks": true, 12 | "path": "." 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /examples/get_contexts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2017 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var apiai = require("apiai"); 10 | 11 | var app = apiai("YOUR_ACCESS_TOKEN"); 12 | 13 | var options = { 14 | sessionId: '' 15 | }; 16 | 17 | var request = app.getContextsRequest(options); 18 | 19 | request.on('response', function(response) { 20 | // response = [ 21 | // { name: "contextName" } 22 | // ] 23 | console.log(response); 24 | }); 25 | 26 | request.on('error', function(error) { 27 | console.log(error); 28 | }); 29 | 30 | request.end(); 31 | 32 | var requestSingle = app.getContextsRequest(options, 'contextName'); 33 | 34 | requestSingle.on('response', function(response) { 35 | console.log(response); 36 | }); 37 | 38 | requestSingle.on('error', function(error) { 39 | console.log(error); 40 | }); 41 | 42 | request.end(); 43 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for apiai 3.0.4 2 | // Project: https://github.com/api-ai/apiai-nodejs-client.git 3 | // Definitions by: Dmitry Kuragin 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | 6 | /// 7 | /// 8 | 9 | 10 | /* =================== USAGE =================== 11 | import * as apiai from "apiai"; 12 | const app = apiai("YOUR_ACCESS_TOKEN"); 13 | =============================================== */ 14 | 15 | import * as events from "events"; 16 | import * as stream from "stream"; 17 | 18 | declare const apiai: apiai.ApiaiStatic; 19 | 20 | export as namespace apiai; 21 | 22 | export = apiai; 23 | 24 | declare namespace apiai { 25 | interface ApiaiStatic { 26 | (clientAccessToken: string, options?: ApplicationOptions): Application; 27 | } 28 | 29 | /** 30 | * Base request options. Not uses directly, for inherits only. 31 | */ 32 | interface RequestOptions { 33 | endpoint?: string; 34 | } 35 | 36 | /** 37 | * Base class or interface for all inherited requests. 38 | * Not uses directly, for inherits only. 39 | */ 40 | interface Request extends events.EventEmitter { 41 | write(buffer: Buffer | string): void; 42 | end(): void; 43 | } 44 | 45 | /** 46 | * Base class or interface for all inherited requests. 47 | * Not uses directly, for inherits only. 48 | */ 49 | interface JSONApiRequest extends Request { 50 | 51 | } 52 | 53 | /** 54 | * Base query request options. 55 | * See details at https://docs.api.ai/docs/query 56 | */ 57 | interface QueryRequestOptions extends RequestOptions { 58 | timezone?: string; 59 | resetContexts?: boolean; 60 | sessionId: string; 61 | contexts?: [any]; 62 | entities?: [any]; 63 | version?: string; 64 | requestSource?: string; 65 | originalRequest?: any; 66 | } 67 | 68 | /** 69 | * Base query request. 70 | */ 71 | interface QueryRequest extends JSONApiRequest { 72 | 73 | } 74 | 75 | /** 76 | * Text Request options. 77 | */ 78 | interface TextRequestOptions extends QueryRequestOptions { 79 | 80 | } 81 | 82 | /** 83 | * Text Request. 84 | */ 85 | interface TextRequest extends QueryRequest { 86 | query: string | [string]; 87 | } 88 | 89 | /** 90 | * Event Request options. 91 | */ 92 | interface EventRequestOptions extends QueryRequestOptions { 93 | 94 | } 95 | 96 | /** 97 | * Event model for setn event request. 98 | */ 99 | interface Event { 100 | name: string; 101 | data?: { [key: string]: any; }; 102 | } 103 | 104 | /** 105 | * Text Request. 106 | */ 107 | interface EventRequest extends QueryRequest { 108 | event: Event; 109 | } 110 | 111 | /** 112 | * Contexts Request options. 113 | */ 114 | interface ContextsRequestOptions extends RequestOptions { 115 | sessionId: string; 116 | } 117 | 118 | /** 119 | * Contexts Request. 120 | */ 121 | interface ContextsRequest extends JSONApiRequest { 122 | contexts: [any]; 123 | } 124 | 125 | /** 126 | * Delete Contexts Request options. 127 | */ 128 | interface DeleteContextsRequestOptions extends RequestOptions { 129 | sessionId: string; 130 | } 131 | 132 | /** 133 | * Delete Contexts Request. 134 | */ 135 | interface DeleteContextsRequest extends JSONApiRequest { 136 | 137 | } 138 | 139 | /** 140 | * UserEntityEntry model for user entities request. 141 | */ 142 | interface UserEntityEntry { 143 | value: string; 144 | synonyms: [string]; 145 | } 146 | 147 | /** 148 | * UserEntity model for user entities request. 149 | */ 150 | interface UserEntity { 151 | name: string; 152 | extend: boolean; 153 | entries: [UserEntityEntry]; 154 | } 155 | 156 | /** 157 | * UserEntity model for user entities request. 158 | */ 159 | interface UserEntitiesBody { 160 | sessionId: string; 161 | entities: [UserEntity]; 162 | } 163 | 164 | /** 165 | * UserEntities Request options. 166 | */ 167 | interface UserEntitiesRequestOptions extends RequestOptions { 168 | 169 | } 170 | 171 | /** 172 | * UserEntities Request. 173 | */ 174 | interface UserEntitiesRequest extends JSONApiRequest { 175 | user_entities_body: UserEntitiesBody; 176 | } 177 | 178 | /** 179 | * TTS Request options (deprecated) 180 | */ 181 | 182 | //interface TTSRequestOptions extends RequestOptions { 183 | // language?: string; 184 | // writeStream: stream.Writable; 185 | //} 186 | 187 | /** 188 | * TTS Request (deprecated) 189 | */ 190 | //interface TTSRequest extends Request { 191 | 192 | //} 193 | 194 | /** 195 | * Application options. This options uses for 196 | * default parameters for requests. 197 | */ 198 | interface ApplicationOptions { 199 | language?: string; 200 | hostname?: string; 201 | version?: string; 202 | endpoint?: string; 203 | requestSource?: string; 204 | secure?: boolean; 205 | } 206 | 207 | /** 208 | * Application is factory for requests to api.ai service. 209 | */ 210 | interface Application { 211 | textRequest(query: string | [string], options: TextRequestOptions): TextRequest; 212 | eventRequest(event: Event, options: EventRequestOptions): EventRequest; 213 | contextsRequest(contexts: [any], options: ContextsRequestOptions): ContextsRequest; 214 | deleteContextsRequest(options: DeleteContextsRequestOptions): DeleteContextsRequest; 215 | userEntitiesRequest(user_entities_body: UserEntitiesBody, options?: UserEntitiesRequestOptions): UserEntitiesRequest; 216 | // Text to speech (TTS) has been deprecated 217 | //ttsRequest(text: string, options: TTSRequestOptions): TTSRequest; 218 | } 219 | } 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | module.exports = require("./module/apiai"); -------------------------------------------------------------------------------- /module/apiai.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Module dependencies. 11 | * @private 12 | */ 13 | 14 | var https = require('https'); 15 | var http = require('http'); 16 | 17 | var ContextsRequest = require('./contexts_request').ContextsRequest; 18 | var GetContextsRequest = require('./get_contexts_request').GetContextsRequest; 19 | var DeleteContextsRequest = require('./delete_contexts_request').DeleteContextsRequest; 20 | var TextRequest = require('./text_request').TextRequest; 21 | var IntentRequest = require('./intent_request').IntentRequest; 22 | var EventRequest = require('./event_request').EventRequest; 23 | var VoiceRequest = require('./voice_request').VoiceRequest; 24 | var UserEntitiesRequest = require('./user_entities_request').UserEntitiesRequest; 25 | // Text to speech (TTS) has been deprecated 26 | // var TTSRequest = require('./tts_request').TTSRequest; 27 | 28 | /** 29 | * Module variables. 30 | * @private 31 | */ 32 | 33 | var version = '20150910'; 34 | var language = 'en'; 35 | var hostname = 'api.api.ai'; 36 | var endpoint = '/v1/'; 37 | var defaultSource = 'node'; 38 | 39 | /** 40 | * Module exports. 41 | * @public 42 | */ 43 | 44 | exports = module.exports = createApplication; 45 | 46 | /** 47 | * Old version function for creation application instance. 48 | * @param {string} clientAccessToken Access token. You can get it on https://api.ai 49 | * @param {string} developerAccessToken Access token. You can get it on https://api.ai 50 | * @param {string} subscriptionKey Subscribtion key. It has not been used anymore. 51 | * @param {object} _options Default option for apllication. 52 | * @return {Application} [description] 53 | */ 54 | function createApplicationDeprecated(clientAccessToken, developerAccessToken, subscriptionKey, _options) { 55 | var options = _options || {}; 56 | 57 | if (!clientAccessToken) { 58 | throw new Error('\'clientAccessToken\' cannot be empty.'); 59 | } 60 | if (!developerAccessToken) { 61 | throw new Error('\'clientAccessToken\' cannot be empty.'); 62 | } 63 | 64 | return new Application(clientAccessToken, developerAccessToken, options); 65 | } 66 | 67 | /** 68 | * New version function for creation application instance. 69 | * @param {string} clientAccessToken Access token. You can get it on https://api.ai 70 | * @param {string} developerAccessToken Access token. You can get it on https://api.ai 71 | * @param {string} subscriptionKey Subscribtion key. It has not been used anymore. 72 | * @param {object} _options Default option for apllication. 73 | * @return {Application} [description] 74 | */ 75 | function createApplicationNew(clientAccessToken, developerAccessToken, _options) { 76 | var options = _options || {}; 77 | 78 | if (!clientAccessToken) { 79 | throw new Error('\'clientAccessToken\' cannot be empty.'); 80 | } 81 | if (!developerAccessToken) { 82 | throw new Error('\'clientAccessToken\' cannot be empty.'); 83 | } 84 | 85 | return new Application(clientAccessToken, developerAccessToken, options); 86 | } 87 | 88 | /** 89 | * Create an api.ai application. 90 | * 91 | * @param {*} args [description] 92 | * @return {Function} 93 | * @api public 94 | */ 95 | function createApplication() { 96 | if (arguments.length > 2) { 97 | if (typeof arguments[1] == "string") { 98 | return createApplicationDeprecated.apply(this, arguments); 99 | } else if (typeof arguments[1] == "object") { 100 | return createApplicationNew.apply(this, arguments); 101 | } else { 102 | throw new Error('Wrong parameters of initialization.'); 103 | } 104 | } else { 105 | return createApplicationNew.apply(this, arguments); 106 | } 107 | } 108 | 109 | function Application (clientAccessToken, developerAccessToken, options) { 110 | var self = this; 111 | 112 | self.language = options.language || language; 113 | 114 | self.clientAccessToken = clientAccessToken; 115 | self.developerAccessToken = developerAccessToken; 116 | 117 | self.hostname = options.hostname || hostname; 118 | self.version = options.version || version; 119 | 120 | self.endpoint = options.endpoint || endpoint; 121 | self.requestSource = options.requestSource || defaultSource; 122 | 123 | if ('secure' in options) { 124 | self.secure = options.secure; 125 | } else { 126 | self.secure = true; 127 | } 128 | 129 | var _http = self.secure ? https : http; 130 | self._agent = new _http.Agent({ keepAlive: true }); 131 | } 132 | 133 | Application.prototype.contextsRequest = function(contexts, options) { 134 | var self = this; 135 | 136 | var opt = options || {}; 137 | 138 | if (!('endpoint' in opt)) { 139 | opt.endpoint = self.endpoint; 140 | } 141 | 142 | return new ContextsRequest(self, contexts, opt); 143 | }; 144 | 145 | /** 146 | * Get all/one contexts for session by ID. 147 | * @param {object} options Options for GetContextsRequest. Should contain sessionId. 148 | * @param {string} [context] Name of the context to retreive or empty/null to get all contexts. 149 | * @return {ContextsRequest} Returns a ContextsRequest object. 150 | */ 151 | Application.prototype.getContextsRequest = function(options, context) { 152 | var self = this; 153 | 154 | var opt = options || {}; 155 | 156 | if (!('endpoint' in opt)) { 157 | opt.endpoint = self.endpoint; 158 | } 159 | 160 | return new GetContextsRequest(self, opt, context); 161 | } 162 | 163 | /** 164 | * Delete/Reset all contexts for session by ID. 165 | * @param {object} options Options for DeleteContextsRequest. Should contain sessionId. 166 | * @param {string} [context] Name of the context to delete or empty/null to delete all contexts. 167 | * @return {ContextsRequest} Returns a ContextsRequest object. 168 | */ 169 | Application.prototype.deleteContextsRequest = function(options, context) { 170 | var self = this; 171 | 172 | var opt = options || {}; 173 | 174 | if (!('endpoint' in opt)) { 175 | opt.endpoint = self.endpoint; 176 | } 177 | 178 | return new DeleteContextsRequest(self, opt, context); 179 | } 180 | 181 | /** 182 | * [textRequest description] 183 | * @param {[type]} query [description] 184 | * @param {[type]} options [description] 185 | * @return {[type]} [description] 186 | */ 187 | Application.prototype.textRequest = function(query, options) { 188 | var self = this; 189 | var opt = options || {}; 190 | 191 | if (!('endpoint' in opt)) { 192 | opt.endpoint = self.endpoint; 193 | } 194 | 195 | if (!('version' in opt)) { 196 | opt.version = self.version; 197 | } 198 | 199 | return new TextRequest(self, query, opt); 200 | }; 201 | 202 | Application.prototype.intentGetRequest = function(options, intent) { 203 | var self = this; 204 | var opt = options || {}; 205 | 206 | if (!('endpoint' in opt)) { 207 | opt.endpoint = self.endpoint; 208 | } 209 | 210 | if (!('version' in opt)) { 211 | opt.version = self.version; 212 | } 213 | 214 | opt.method = 'GET'; 215 | opt.path = 'intents'; 216 | 217 | return new IntentRequest(self, opt, intent); 218 | }; 219 | 220 | Application.prototype.intentPostRequest = function(options, intent) { 221 | var self = this; 222 | var opt = options || {}; 223 | 224 | if (!('endpoint' in opt)) { 225 | opt.endpoint = self.endpoint; 226 | } 227 | 228 | if (!('version' in opt)) { 229 | opt.version = self.version; 230 | } 231 | 232 | opt.method = 'POST'; 233 | opt.path = 'intents'; 234 | 235 | return new IntentRequest(self, opt, intent); 236 | }; 237 | Application.prototype.eventRequest = function(event, options) { 238 | var self = this; 239 | var opt = options || {}; 240 | 241 | if (!('endpoint' in opt)) { 242 | opt.endpoint = self.endpoint; 243 | } 244 | 245 | if (!('version' in opt)) { 246 | opt.version = self.version; 247 | } 248 | 249 | return new EventRequest(self, event, opt); 250 | }; 251 | 252 | /** 253 | * Make voice request object. 254 | * @param {object} [options={}] Optionos for voice request. 255 | * @param {string} [options.endpoint] [description] 256 | * @param {string} [options.version] [description] 257 | * @return {VoiceRequest} [description] 258 | * @deprecated since version 2.0 259 | */ 260 | Application.prototype.voiceRequest = function(options) { 261 | var self = this; 262 | var opt = options || {}; 263 | 264 | if (!('endpoint' in opt)) { 265 | opt.endpoint = self.endpoint; 266 | } 267 | 268 | if (!('version' in opt)) { 269 | opt.version = self.version; 270 | } 271 | 272 | return new VoiceRequest(self, opt); 273 | }; 274 | 275 | /** 276 | * [userEntitiesRequest description] 277 | * @param {[type]} user_entities_body [description] 278 | * @param {[type]} options [description] 279 | * @return {[type]} [description] 280 | */ 281 | Application.prototype.userEntitiesRequest = function(user_entities_body, options) { 282 | var self = this; 283 | var opt = options || {}; 284 | 285 | if (!('endpoint' in opt)) { 286 | opt.endpoint = self.endpoint; 287 | } 288 | 289 | return new UserEntitiesRequest(self, user_entities_body, opt); 290 | }; 291 | 292 | // Text to speech (TTS) has been deprecated 293 | // Application.prototype.ttsRequest = function(text, options) { 294 | // var self = this; 295 | // var opt = options || {}; 296 | 297 | // if (!('endpoint' in opt)) { 298 | // opt.endpoint = self.endpoint; 299 | // } 300 | 301 | // return new TTSRequest(self, text, opt); 302 | // }; 303 | -------------------------------------------------------------------------------- /module/contexts_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var JSONApiRequest = require('./json_api_request').JSONApiRequest; 10 | var util = require('util'); 11 | 12 | exports.ContextsRequest = module.exports.ContextsRequest = ContextsRequest; 13 | 14 | util.inherits(ContextsRequest, JSONApiRequest); 15 | 16 | function ContextsRequest(application, contexts, options) { 17 | var self = this; 18 | 19 | self.contexts = contexts; 20 | self.sessionId = options.sessionId; 21 | 22 | ContextsRequest.super_.apply(this, [application, options]); 23 | } 24 | 25 | ContextsRequest.prototype._headers = function() { 26 | var headers = ContextsRequest.super_.prototype._headers.apply(this, arguments); 27 | 28 | headers['Content-Type'] = 'application/json; charset=utf-8'; 29 | 30 | return headers; 31 | }; 32 | 33 | ContextsRequest.prototype._requestOptions = function() { 34 | var request_options = ContextsRequest.super_.prototype._requestOptions.apply(this, arguments); 35 | 36 | request_options.path = this.endpoint + 'contexts?sessionId=' + this.sessionId; 37 | request_options.method = 'POST'; 38 | 39 | return request_options; 40 | }; 41 | 42 | ContextsRequest.prototype.end = function() { 43 | var self = this; 44 | 45 | self.write(JSON.stringify(self.contexts)); 46 | 47 | ContextsRequest.super_.prototype.end.apply(this, arguments); 48 | }; -------------------------------------------------------------------------------- /module/delete_contexts_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var JSONApiRequest = require('./json_api_request').JSONApiRequest; 10 | var util = require('util'); 11 | 12 | exports.DeleteContextsRequest = module.exports.DeleteContextsRequest = DeleteContextsRequest; 13 | 14 | util.inherits(DeleteContextsRequest, JSONApiRequest); 15 | 16 | function DeleteContextsRequest(application, options, context) { 17 | var self = this; 18 | 19 | if (context) { 20 | self.context = context; 21 | } 22 | self.sessionId = options.sessionId; 23 | 24 | DeleteContextsRequest.super_.apply(this, [application, options]); 25 | } 26 | 27 | DeleteContextsRequest.prototype._headers = function() { 28 | var headers = DeleteContextsRequest.super_.prototype._headers.apply(this, arguments); 29 | 30 | headers['Content-Type'] = 'application/json; charset=utf-8'; 31 | 32 | return headers; 33 | }; 34 | 35 | DeleteContextsRequest.prototype._requestOptions = function() { 36 | var request_options = DeleteContextsRequest.super_.prototype._requestOptions.apply(this, arguments); 37 | var contextPath = this.context ? '/' + context : ''; 38 | 39 | request_options.path = this.endpoint + 'contexts' + contextPath + '?sessionId=' + this.sessionId; 40 | request_options.method = 'DELETE'; 41 | 42 | return request_options; 43 | }; 44 | -------------------------------------------------------------------------------- /module/developer_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var Request = require('./request').Request; 10 | var util = require('util'); 11 | 12 | exports.DeveloperRequest = module.exports.DeveloperRequest = DeveloperRequest; 13 | 14 | util.inherits(DeveloperRequest, Request); 15 | 16 | function DeveloperRequest(application, options) { 17 | this.developerAccessToken = application.developerAccessToken; 18 | DeveloperRequest.super_.apply(this, arguments); 19 | } 20 | 21 | DeveloperRequest.prototype._headers = function() { 22 | var self = this; 23 | 24 | return { 25 | 'Accept': 'application/json', 26 | 'Authorization': 'Bearer ' + self.developerAccessToken, 27 | 'api-request-source': self.requestSource 28 | }; 29 | }; -------------------------------------------------------------------------------- /module/event_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var QueryRequest = require('./query_request').QueryRequest; 10 | var util = require('util'); 11 | 12 | exports.EventRequest = module.exports.EventRequest = EventRequest; 13 | 14 | util.inherits(EventRequest, QueryRequest); 15 | 16 | function EventRequest(application, event, options) { 17 | EventRequest.super_.apply(this, [application, options]); 18 | 19 | var self = this; 20 | self.event = event; 21 | } 22 | 23 | EventRequest.prototype._headers = function() { 24 | var headers = EventRequest.super_.prototype._headers.apply(this, arguments); 25 | 26 | headers['Content-Type'] = 'application/json; charset=utf-8'; 27 | 28 | return headers; 29 | }; 30 | 31 | EventRequest.prototype._jsonRequestParameters = function() { 32 | var self = this; 33 | 34 | var json = EventRequest.super_.prototype._jsonRequestParameters.apply(this, arguments); 35 | 36 | json.event = self.event; 37 | 38 | return json; 39 | }; 40 | 41 | EventRequest.prototype.end = function() { 42 | var self = this; 43 | 44 | self.write(JSON.stringify(self._jsonRequestParameters())); 45 | 46 | EventRequest.super_.prototype.end.apply(this, arguments); 47 | }; 48 | -------------------------------------------------------------------------------- /module/exceptions.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var util = require('util'); 10 | 11 | exports.ServerError = module.exports.ServerError = ServerError; 12 | 13 | util.inherits(ServerError, Error); 14 | 15 | function ServerError (statusCode, responseBody, message) { 16 | var self = this; 17 | 18 | Error.captureStackTrace(this, ServerError); 19 | 20 | self.statusCode = statusCode; 21 | self.responseBody = responseBody; 22 | 23 | this.name = this.constructor.name; 24 | this.message = message; 25 | 26 | ServerError.super_.apply(this, []); 27 | } 28 | -------------------------------------------------------------------------------- /module/get_contexts_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var JSONApiRequest = require('./json_api_request').JSONApiRequest; 10 | var util = require('util'); 11 | 12 | exports.GetContextsRequest = module.exports.GetContextsRequest = GetContextsRequest; 13 | 14 | util.inherits(GetContextsRequest, JSONApiRequest); 15 | 16 | function GetContextsRequest(application, options, context) { 17 | var self = this; 18 | 19 | if (context) { 20 | self.context = context; 21 | } 22 | self.sessionId = options.sessionId; 23 | 24 | GetContextsRequest.super_.apply(this, [application, options]); 25 | } 26 | 27 | GetContextsRequest.prototype._headers = function() { 28 | var headers = GetContextsRequest.super_.prototype._headers.apply(this, arguments); 29 | 30 | headers['Content-Type'] = 'application/json; charset=utf-8'; 31 | 32 | return headers; 33 | }; 34 | 35 | GetContextsRequest.prototype._requestOptions = function() { 36 | var request_options = GetContextsRequest.super_.prototype._requestOptions.apply(this, arguments); 37 | var contextPath = this.context ? '/' + context : ''; 38 | 39 | request_options.path = this.endpoint + 'contexts' + contextPath + '?sessionId=' + this.sessionId; 40 | request_options.method = 'GET'; 41 | 42 | return request_options; 43 | }; 44 | -------------------------------------------------------------------------------- /module/intent_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var QueryDeveloperRequest = require('./query_dev_request').QueryDeveloperRequest; 10 | var util = require('util'); 11 | 12 | exports.IntentRequest = module.exports.IntentRequest = IntentRequest; 13 | 14 | util.inherits(IntentRequest, QueryDeveloperRequest); 15 | 16 | function IntentRequest(application, options, intent) { 17 | IntentRequest.super_.apply(this, [application, options]); 18 | 19 | var self = this; 20 | self.intent = intent; 21 | } 22 | 23 | IntentRequest.prototype._headers = function() { 24 | var headers = IntentRequest.super_.prototype._headers.apply(this, arguments); 25 | 26 | headers['Content-Type'] = 'application/json; charset=utf-8'; 27 | 28 | return headers; 29 | }; 30 | 31 | IntentRequest.prototype._jsonRequestParameters = function() { 32 | var self = this; 33 | 34 | var json = IntentRequest.super_.prototype._jsonRequestParameters.apply(this, arguments); 35 | 36 | if(self.intent != undefined) 37 | json.intent = self.intent; 38 | 39 | return json; 40 | }; 41 | 42 | IntentRequest.prototype.end = function() { 43 | var self = this; 44 | 45 | self.write(JSON.stringify(self._jsonRequestParameters())); 46 | 47 | IntentRequest.super_.prototype.end.apply(this, arguments); 48 | }; -------------------------------------------------------------------------------- /module/json_api_dev_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var DeveloperRequest = require('./developer_request').DeveloperRequest; 10 | var util = require('util'); 11 | 12 | var ServerError = require('./exceptions').ServerError; 13 | 14 | exports.JSONApiDeveloperRequest = module.exports.JSONApiDeveloperRequest = JSONApiDeveloperRequest; 15 | 16 | util.inherits(JSONApiDeveloperRequest, DeveloperRequest); 17 | 18 | function JSONApiDeveloperRequest() { 19 | JSONApiDeveloperRequest.super_.apply(this, arguments); 20 | } 21 | 22 | JSONApiDeveloperRequest.prototype._handleResponse = function(response) { 23 | var self = this; 24 | 25 | var body = ''; 26 | 27 | response.on('data', function(chunk) { 28 | body += chunk; 29 | }); 30 | 31 | response.on('end', function() { 32 | if (response.statusCode >= 200 && response.statusCode <= 299) { 33 | try { 34 | var json_body = JSON.parse(body); 35 | self.emit('response', json_body); 36 | } catch (error) { 37 | // JSON.parse can throw only one exception, SyntaxError 38 | // All another exceptions throwing from user function, 39 | // because it just rethrowing for better error handling. 40 | 41 | if (error instanceof SyntaxError) { 42 | self.emit('error', error); 43 | } else { 44 | throw error; 45 | } 46 | } 47 | } else { 48 | var error = new ServerError(response.statusCode, body, 'Wrong response status code.'); 49 | self.emit('error', error); 50 | } 51 | }); 52 | }; -------------------------------------------------------------------------------- /module/json_api_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var Request = require('./request').Request; 10 | var util = require('util'); 11 | 12 | var ServerError = require('./exceptions').ServerError; 13 | 14 | exports.JSONApiRequest = module.exports.JSONApiRequest = JSONApiRequest; 15 | 16 | util.inherits(JSONApiRequest, Request); 17 | 18 | function JSONApiRequest () { 19 | JSONApiRequest.super_.apply(this, arguments); 20 | } 21 | 22 | JSONApiRequest.prototype._handleResponse = function(response) { 23 | var self = this; 24 | 25 | var body = ''; 26 | 27 | response.on('data', function(chunk) { 28 | body += chunk; 29 | }); 30 | 31 | response.on('end', function() { 32 | if (response.statusCode >= 200 && response.statusCode <= 299) { 33 | try { 34 | var json_body = JSON.parse(body); 35 | self.emit('response', json_body); 36 | } catch (error) { 37 | // JSON.parse can throw only one exception, SyntaxError 38 | // All another exceptions throwing from user function, 39 | // because it just rethrowing for better error handling. 40 | 41 | if (error instanceof SyntaxError) { 42 | self.emit('error', error); 43 | } else { 44 | throw error; 45 | } 46 | } 47 | } else { 48 | var error = new ServerError(response.statusCode, body, 'Wrong response status code.'); 49 | self.emit('error', error); 50 | } 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /module/query_dev_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var JSONApiDeveloperRequest = require('./json_api_dev_request').JSONApiDeveloperRequest; 10 | var util = require('util'); 11 | 12 | exports.QueryDeveloperRequest = module.exports.QueryDeveloperRequest = QueryDeveloperRequest; 13 | 14 | util.inherits(QueryDeveloperRequest, JSONApiDeveloperRequest); 15 | 16 | function QueryDeveloperRequest(application, options) { 17 | var self = this; 18 | 19 | if (!('method' in options)) { 20 | throw new Error('Must specify method (POST/GET).'); 21 | } 22 | if (!('path' in options)) { 23 | throw new Error('Must specify path.'); 24 | } 25 | if ('version' in options) { 26 | self.version = options.version; 27 | } 28 | 29 | self.method = options.method; 30 | self.path = options.path; 31 | 32 | QueryDeveloperRequest.super_.apply(this, arguments); 33 | } 34 | 35 | QueryDeveloperRequest.prototype._requestOptions = function() { 36 | var self = this; 37 | 38 | var path = self.path; 39 | 40 | if (self.hasOwnProperty("version")) { 41 | path += '?v=' + self.version; 42 | } 43 | 44 | var request_options = QueryDeveloperRequest.super_.prototype._requestOptions.apply(this, arguments); 45 | 46 | request_options.path = self.endpoint + path; 47 | request_options.method = self.method; 48 | 49 | return request_options; 50 | }; 51 | 52 | QueryDeveloperRequest.prototype._jsonRequestParameters = function() { 53 | var self = this; 54 | 55 | var json = { 56 | 57 | }; 58 | 59 | return json; 60 | }; -------------------------------------------------------------------------------- /module/query_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var JSONApiRequest = require('./json_api_request').JSONApiRequest; 10 | var util = require('util'); 11 | 12 | exports.QueryRequest = module.exports.QueryRequest = QueryRequest; 13 | 14 | util.inherits(QueryRequest, JSONApiRequest); 15 | 16 | function QueryRequest (application, options) { 17 | var self = this; 18 | 19 | self.language = application.language; 20 | 21 | if ('timezone' in options) { 22 | self.timezone = options.timezone; 23 | } 24 | 25 | if ('resetContexts' in options) { 26 | self.resetContexts = options.resetContexts; 27 | } 28 | 29 | if ('contexts' in options) { 30 | self.contexts = options.contexts; 31 | } 32 | 33 | if ('entities' in options) { 34 | self.entities = options.entities; 35 | } 36 | 37 | if ('sessionId' in options) { 38 | self.sessionId = options.sessionId; 39 | } else { 40 | throw Error( 41 | 'Now \'sessionId\' is required parameter. Please add this parameter to \'options\' of request.\n' + 42 | 'Like following example:\n' + 43 | '> var app = ...\n' + 44 | '> request = app.textRequest("Hello", {sessionId: "UNIQUE_SESSION_ID"})\n' + 45 | '> ... \n' 46 | ); 47 | } 48 | 49 | if ('version' in options) { 50 | self.version = options.version; 51 | } 52 | 53 | if ('requestSource' in application) { 54 | self.requestSource = application.requestSource; 55 | } 56 | 57 | if ('originalRequest' in options) { 58 | self.originalRequest = options.originalRequest; 59 | } 60 | 61 | QueryRequest.super_.apply(this, arguments); 62 | } 63 | 64 | QueryRequest.prototype._requestOptions = function() { 65 | var self = this; 66 | 67 | var path = 'query'; 68 | 69 | if (self.hasOwnProperty("version")) { 70 | path += '?v=' + self.version; 71 | } 72 | 73 | var request_options = QueryRequest.super_.prototype._requestOptions.apply(this, arguments); 74 | 75 | request_options.path = self.endpoint + path; 76 | request_options.method = 'POST'; 77 | 78 | return request_options; 79 | }; 80 | 81 | QueryRequest.prototype._jsonRequestParameters = function() { 82 | var self = this; 83 | 84 | var json = { 85 | 'lang': self.language, 86 | 'timezone': self.timezone 87 | }; 88 | 89 | if ('resetContexts' in self) { 90 | json.resetContexts = self.resetContexts; 91 | } 92 | 93 | if ('contexts' in self) { 94 | json.contexts = self.contexts; 95 | } 96 | 97 | if ('entities' in self) { 98 | json.entities = self.entities; 99 | } 100 | 101 | if ('sessionId' in self) { 102 | json.sessionId = self.sessionId; 103 | } 104 | 105 | if ('originalRequest' in self) { 106 | json.originalRequest = self.originalRequest; 107 | } 108 | 109 | return json; 110 | }; 111 | -------------------------------------------------------------------------------- /module/request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var EventEmitter = require('events').EventEmitter; 10 | var util = require('util'); 11 | var https = require('https'); 12 | var http = require('http'); 13 | 14 | exports.Request = module.exports.Request = Request; 15 | 16 | util.inherits(Request, EventEmitter); 17 | 18 | function Request (application, options) { 19 | var self = this; 20 | 21 | self.clientAccessToken = application.clientAccessToken; 22 | 23 | self.hostname = application.hostname; 24 | 25 | self.endpoint = options.endpoint; 26 | self.requestSource = application.requestSource; 27 | 28 | var _http = application.secure ? https : http; 29 | 30 | var requestOptions = self._requestOptions(); 31 | 32 | requestOptions.agent = application._agent; 33 | 34 | var request = _http.request(requestOptions, function(response) { 35 | self._handleResponse(response); 36 | }); 37 | 38 | request.on('error', function(error) { 39 | self.emit('error', error); 40 | }); 41 | 42 | self.request = request; 43 | } 44 | 45 | Request.prototype._handleResponse = function(response) { 46 | throw new Error("Can't call abstract method!"); 47 | }; 48 | 49 | Request.prototype._headers = function() { 50 | var self = this; 51 | 52 | return { 53 | 'Accept': 'application/json', 54 | 'Authorization': 'Bearer ' + self.clientAccessToken, 55 | 'api-request-source': self.requestSource 56 | }; 57 | }; 58 | 59 | Request.prototype._requestOptions = function() { 60 | var self = this; 61 | 62 | return { 63 | hostname: self.hostname, 64 | headers: self._headers(), 65 | }; 66 | }; 67 | 68 | Request.prototype.write = function(chunk) { 69 | this.request.write(chunk); 70 | }; 71 | 72 | Request.prototype.end = function() { 73 | this.request.end(); 74 | }; 75 | -------------------------------------------------------------------------------- /module/text_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var QueryRequest = require('./query_request').QueryRequest; 10 | var util = require('util'); 11 | 12 | exports.TextRequest = module.exports.TextRequest = TextRequest; 13 | 14 | util.inherits(TextRequest, QueryRequest); 15 | 16 | function TextRequest (application, query, options) { 17 | TextRequest.super_.apply(this, [application, options]); 18 | 19 | var self = this; 20 | self.query = query; 21 | } 22 | 23 | TextRequest.prototype._headers = function() { 24 | var headers = TextRequest.super_.prototype._headers.apply(this, arguments); 25 | 26 | headers['Content-Type'] = 'application/json; charset=utf-8'; 27 | 28 | return headers; 29 | }; 30 | 31 | TextRequest.prototype._jsonRequestParameters = function() { 32 | var self = this; 33 | 34 | var json = TextRequest.super_.prototype._jsonRequestParameters.apply(this, arguments); 35 | 36 | json.query = self.query; 37 | 38 | return json; 39 | }; 40 | 41 | TextRequest.prototype.end = function() { 42 | var self = this; 43 | 44 | self.write(JSON.stringify(self._jsonRequestParameters())); 45 | 46 | TextRequest.super_.prototype.end.apply(this, arguments); 47 | }; 48 | -------------------------------------------------------------------------------- /module/tts_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | // Text to speech (TTS) has been deprecated 8 | 9 | // 'use strict'; 10 | 11 | // var Request = require('./request').Request; 12 | // var util = require('util'); 13 | 14 | // exports.TTSRequest = module.exports.TTSRequest = TTSRequest; 15 | 16 | // util.inherits(TTSRequest, Request); 17 | 18 | // function TTSRequest(application, text, options) { 19 | // var self = this; 20 | 21 | // self.text = text; 22 | 23 | // self.language = options.language || options.lang || 'en-US'; 24 | 25 | // if('writeStream' in options){ 26 | // self.writeStream = options.writeStream; 27 | // } else { 28 | // throw new Error('\'writeStream\' cannot be empty.'); 29 | // } 30 | 31 | // TTSRequest.super_.apply(this, [application, options]); 32 | // } 33 | 34 | // TTSRequest.prototype._headers = function() { 35 | // var self = this; 36 | // var headers = TTSRequest.super_.prototype._headers.apply(this, arguments); 37 | 38 | // headers['Accept-Language'] = self.language; 39 | 40 | // return headers; 41 | // }; 42 | 43 | // TTSRequest.prototype._requestOptions = function() { 44 | // var self = this; 45 | // var request_options = TTSRequest.super_.prototype._requestOptions.apply(this, arguments); 46 | 47 | // request_options.path = self.endpoint + 'tts?text=' + encodeURI(self.text); 48 | // request_options.method = 'GET'; 49 | 50 | // return request_options; 51 | // }; 52 | 53 | // TTSRequest.prototype._handleResponse = function(response) { 54 | // var self = this; 55 | // response.pipe(self.writeStream); 56 | // }; 57 | 58 | -------------------------------------------------------------------------------- /module/user_entities_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var JSONApiRequest = require('./json_api_request').JSONApiRequest; 10 | var util = require('util'); 11 | 12 | exports.UserEntitiesRequest = module.exports.UserEntitiesRequest = UserEntitiesRequest; 13 | 14 | util.inherits(UserEntitiesRequest, JSONApiRequest); 15 | 16 | function UserEntitiesRequest(application, user_entities_body, options) { 17 | var self = this; 18 | 19 | self.user_entities_body = user_entities_body; 20 | 21 | UserEntitiesRequest.super_.apply(this, [application, options]); 22 | } 23 | 24 | UserEntitiesRequest.prototype._headers = function() { 25 | var headers = UserEntitiesRequest.super_.prototype._headers.apply(this, arguments); 26 | 27 | headers['Content-Type'] = 'application/json; charset=utf-8'; 28 | 29 | return headers; 30 | }; 31 | 32 | UserEntitiesRequest.prototype._requestOptions = function() { 33 | var request_options = UserEntitiesRequest.super_.prototype._requestOptions.apply(this, arguments); 34 | 35 | request_options.path = this.endpoint + 'userEntities'; 36 | request_options.method = 'POST'; 37 | 38 | return request_options; 39 | }; 40 | 41 | UserEntitiesRequest.prototype.end = function() { 42 | var self = this; 43 | 44 | if ( 45 | (!('user_entities_body' in self)) || 46 | (!('entities' in self.user_entities_body)) 47 | ) 48 | { 49 | throw Error( 50 | 'Data format for user untities request was changed. \n' + 51 | 'See details: https://docs.api.ai/docs/userentities \n' + 52 | '...or see examples.' 53 | ); 54 | } 55 | 56 | self.write(JSON.stringify(self.user_entities_body)); 57 | 58 | UserEntitiesRequest.super_.prototype.end.apply(this, arguments); 59 | }; 60 | -------------------------------------------------------------------------------- /module/voice_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var QueryRequest = require('./query_request').QueryRequest; 10 | var util = require('util'); 11 | 12 | exports.VoiceRequest = module.exports.VoiceRequest = VoiceRequest; 13 | 14 | var CRLF = '\r\n'; 15 | 16 | util.inherits(VoiceRequest, QueryRequest); 17 | 18 | function VoiceRequest (application, options) { 19 | var self = this; 20 | self.boundary = self._generateBoundary(); 21 | 22 | VoiceRequest.super_.apply(this, [application, options]); 23 | 24 | self._sendMetaData(); 25 | } 26 | 27 | VoiceRequest.prototype._generateBoundary = function() { 28 | return (new Date()).getTime().toString(); 29 | }; 30 | 31 | VoiceRequest.prototype._headers = function() { 32 | var self = this; 33 | 34 | var headers = VoiceRequest.super_.prototype._headers.apply(this, arguments); 35 | 36 | headers['Content-Type'] = 'multipart/form-data; boundary=' + self.boundary; 37 | headers['Transfer-Encoding'] = 'chunked'; 38 | 39 | return headers; 40 | }; 41 | 42 | VoiceRequest.prototype._sendMetaData = function() { 43 | var self = this; 44 | 45 | var data = '--' + self.boundary + CRLF; 46 | data += 'Content-Disposition: form-data; name="request"' + CRLF; 47 | data += "Content-Type: application/json" + CRLF + CRLF; 48 | 49 | data += JSON.stringify(self._jsonRequestParameters()); 50 | 51 | data += CRLF + '--' + self.boundary + CRLF; 52 | data += 'Content-Disposition: form-data; name="voiceData"' + CRLF; 53 | data += 'Content-Type: audio/wav' + CRLF + CRLF; 54 | 55 | self.write(data); 56 | }; 57 | 58 | VoiceRequest.prototype.end = function() { 59 | var self = this; 60 | 61 | var lastDataChunk = CRLF + '--' + self.boundary + '--' + CRLF; 62 | 63 | self.write(lastDataChunk); 64 | 65 | VoiceRequest.super_.prototype.end.apply(this, arguments); 66 | }; 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai", 3 | "version": "4.0.2", 4 | "description": "Node.js SDK for api.ai", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "directories": { 8 | "example": "examples" 9 | }, 10 | "files": [ 11 | "index.js", 12 | "index.d.ts", 13 | "module/" 14 | ], 15 | "scripts": { 16 | "build:live": "NODE_ENV=development nodemon --exec ./node_modules/.bin/ts-node -- ./typescript_examples/text_request.ts" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/api-ai/apiai-nodejs-client.git" 21 | }, 22 | "keywords": [ 23 | "apiai", 24 | "NLU", 25 | "natural", 26 | "language", 27 | "understanding" 28 | ], 29 | "author": "Dmitriy Kuragin", 30 | "license": "Apache 2.0", 31 | "bugs": { 32 | "url": "https://github.com/api-ai/api-ai-node-js/issues" 33 | }, 34 | "homepage": "https://github.com/api-ai/api-ai-node-js#readme", 35 | "devDependencies": { 36 | "@types/node": "^7.0.5", 37 | "nodemon": "^1.11.0", 38 | "ts-node": "^2.1.0", 39 | "typescript": "^2.1.4", 40 | "typing": "^0.1.9", 41 | "typings": "^2.0.0", 42 | "typescript": "^2.1.6" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /samples/1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidniki02/apiai-nodejs-client/110f1d8a060b7089551196dc6ac286bf7c502a7e/samples/1.wav -------------------------------------------------------------------------------- /samples/ann_smith.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidniki02/apiai-nodejs-client/110f1d8a060b7089551196dc6ac286bf7c502a7e/samples/ann_smith.wav -------------------------------------------------------------------------------- /samples/delete_contexts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2017 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var apiai = require("apiai"); 10 | 11 | var app = apiai("YOUR_ACCESS_TOKEN"); 12 | 13 | var options = { 14 | sessionId: '' 15 | }; 16 | 17 | var request = app.deleteContextsRequest(options); 18 | 19 | request.on('response', function(response) { 20 | console.log(response); 21 | }); 22 | 23 | request.on('error', function(error) { 24 | console.log(error); 25 | }); 26 | 27 | request.end(); 28 | -------------------------------------------------------------------------------- /samples/event_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var util = require('util'); 10 | // var apiai = require("../module/apiai"); 11 | var apiai = require("apiai"); 12 | 13 | var options = { 14 | // hostname: 'eap.api.ai', 15 | }; 16 | 17 | var app = apiai("", options); 18 | 19 | var event = { 20 | name: "network.connect", 21 | data: { 22 | param1: "param1 value", 23 | } 24 | }; 25 | 26 | var options = { 27 | sessionId: '' 28 | }; 29 | 30 | var request = app.eventRequest(event, options); 31 | 32 | request.on('response', function(response) { 33 | console.log(util.inspect(response, false, null)); 34 | }); 35 | 36 | request.on('error', function(error) { 37 | console.log(error); 38 | }); 39 | 40 | request.end(); 41 | -------------------------------------------------------------------------------- /samples/facebook/.dockerignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | coverage/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /samples/facebook/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | npm-debug.log -------------------------------------------------------------------------------- /samples/facebook/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6 2 | 3 | MAINTAINER xVir 4 | 5 | RUN mkdir -p /usr/app/src 6 | 7 | WORKDIR /usr/app 8 | COPY . /usr/app 9 | 10 | EXPOSE 5000 11 | 12 | RUN npm install 13 | CMD ["npm", "start"] 14 | -------------------------------------------------------------------------------- /samples/facebook/README.md: -------------------------------------------------------------------------------- 1 | # api-ai-facebook 2 | Facebook bot sources for Api.ai integration 3 | 4 | ## Deploy with Heroku 5 | Follow [these instructions](https://docs.api.ai/docs/facebook-integration#hosting-fb-messenger-bot-with-heroku). 6 | Then, 7 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 8 | 9 | ## Deploy with Docker 10 | 11 | ```bash 12 | docker run -it --name fb_bot \ 13 | -p :5000 \ 14 | -e APIAI_ACCESS_TOKEN="API.AI client access token" \ 15 | -e FB_PAGE_ACCESS_TOKEN="Facebook Page Access Token" \ 16 | -e FB_VERIFY_TOKEN="Facebook Verify Token" \ 17 | -e APIAI_LANG="en" \ 18 | xvir/api-ai-facebook 19 | ``` 20 | 21 | ## Note about languages: 22 | When you deploy the app manually to Heroku, the APIAI_LANG not filled with a value. 23 | You need to provide language parameter according to your agent settings in the form of two-letters code. 24 | 25 | * "en" 26 | * "ru" 27 | * "de" 28 | * "pt" 29 | * "pt-BR" 30 | * "es" 31 | * "fr" 32 | * "it" 33 | * "ja" 34 | * "ko" 35 | * "zh-CN" 36 | * "zh-HK" 37 | * "zh-TW" 38 | -------------------------------------------------------------------------------- /samples/facebook/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Facebook integration", 3 | "description": "Api.ai Facebook integration allows you to create Facebook bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/api-ai-facebook", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "facebook", "natural language"], 7 | "env": { 8 | "APIAI_ACCESS_TOKEN": { 9 | "description": "Client access token for Api.ai", 10 | "value": "" 11 | }, 12 | "FB_VERIFY_TOKEN": { 13 | "description": "Verification code", 14 | "value": "" 15 | }, 16 | "FB_PAGE_ACCESS_TOKEN": { 17 | "description": "Page Access Token", 18 | "value": "" 19 | }, 20 | "APIAI_LANG": { 21 | "description": "Agent language", 22 | "value": "", 23 | "required": false 24 | } 25 | }, 26 | "engines": { 27 | "node": "6.9.5" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/facebook/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-ai-facebook", 3 | "version": "1.1.0", 4 | "description": "API.AI Facebook Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "mocha", 9 | "coverage": "istanbul cover _mocha" 10 | }, 11 | "author": "Danil Skachkov (https://api.ai)", 12 | "license": "ISC", 13 | "dependencies": { 14 | "apiai": "^3.0.3", 15 | "async": "^2.0.0", 16 | "body-parser": "^1.15.2", 17 | "express": "^4.13.3", 18 | "html-entities": "^1.2.0", 19 | "json-bigint": "^0.2.0", 20 | "node-uuid": "^1.4.7", 21 | "request": "^2.73.0" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/api-ai/api-ai-facebook" 26 | }, 27 | "devDependencies": { 28 | "rewire": "^2.5.2", 29 | "should": "^11.2.0", 30 | "supertest": "^3.0.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/facebook/test/app_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const APIAI_ACCESS_TOKEN = 'api_ai_access_token'; 4 | const FB_VERIFY_TOKEN = 'fb_verify_token'; 5 | const FB_PAGE_ACCESS_TOKEN = 'fb_access_token'; 6 | const APIAI_LANG = 'en'; 7 | 8 | process.env['APIAI_ACCESS_TOKEN'] = APIAI_ACCESS_TOKEN; 9 | process.env['FB_VERIFY_TOKEN'] = FB_VERIFY_TOKEN; 10 | process.env['FB_PAGE_ACCESS_TOKEN'] = FB_PAGE_ACCESS_TOKEN; 11 | process.env['APIAI_LANG'] = APIAI_LANG; 12 | 13 | const supertest = require('supertest'); 14 | const should = require('should'); 15 | const rewire = require('rewire'); 16 | const app = rewire('../src/app'); 17 | 18 | const server = supertest.agent('http://localhost:5000'); 19 | 20 | describe('app', () => { 21 | 22 | beforeEach((done) => { 23 | done(); 24 | }); 25 | 26 | it('should pass verification', function (done) { 27 | 28 | const challengeValue = 'secret'; 29 | const verifyToken = FB_VERIFY_TOKEN; 30 | 31 | server 32 | .get(`/webhook?hub.verify_token=${verifyToken}&hub.challenge=${challengeValue}`) 33 | .set('Accept', 'text/plain') 34 | .expect(200, challengeValue) 35 | .end((err, res) => { 36 | if (err) return done(err); 37 | done(); 38 | }); 39 | }); 40 | 41 | it('should fail verification if wrong params', function (done) { 42 | 43 | const challengeValue = 'secret'; 44 | const verifyToken = 'wrongtoken'; 45 | 46 | server 47 | .get(`/webhook?hub.verify_token=${verifyToken}&hub.challenge=${challengeValue}`) 48 | .set('Accept', 'text/plain') 49 | .expect(200, "Error, wrong validation token") 50 | .end((err, res) => { 51 | if (err) return done(err); 52 | done(); 53 | }); 54 | }); 55 | 56 | it("/webhook should response", function (done) { 57 | 58 | let fbBot = app.__get__('facebookBot'); 59 | fbBot.processEvent = ()=>{}; 60 | 61 | // https://developers.facebook.com/docs/messenger-platform/webhook-reference#common_format 62 | server 63 | .post('/webhook') 64 | .set('Accept', 'application/json') 65 | .send({ 66 | entry: [ 67 | { 68 | messaging: [ 69 | { 70 | sender: { 71 | id: "99102094378730843167656799" 72 | }, 73 | message: { 74 | text: "hello" 75 | } 76 | } 77 | ] 78 | } 79 | ] 80 | }) 81 | .expect(200, {status: "ok"}) 82 | .end((err, res) => { 83 | if (err) return done(err); 84 | done(); 85 | }); 86 | }); 87 | 88 | it("/webhook should response on postback", function (done) { 89 | 90 | let fbBot = app.__get__('facebookBot'); 91 | fbBot.processEvent = ()=>{}; 92 | 93 | server 94 | .post('/webhook') 95 | .set('Accept', 'application/json') 96 | .send({ 97 | entry: [ 98 | { 99 | messaging: [ 100 | { 101 | sender: { 102 | id: "99102094378730843167656799" 103 | }, 104 | postback: { 105 | payload: "hello" 106 | } 107 | } 108 | ] 109 | } 110 | ] 111 | }) 112 | .expect(200, {status: "ok"}) 113 | .end((err, res) => { 114 | if (err) return done(err); 115 | done(); 116 | }); 117 | }); 118 | 119 | it("doRichContentResponse should process all rich content types", (done) => { 120 | let textMessage = {type: 0, speech: 'sample speech'}; 121 | let wrongTextMessage = {type: 0}; 122 | 123 | let fbTextMessage = {text: 'sample speech'}; 124 | 125 | let cardMessage1 = { 126 | "title": "Kitten", 127 | "subtitle": "Cat", 128 | "imageUrl": "https://example.com/cat.jpg", 129 | "buttons": [ 130 | { 131 | "text": "Buy", 132 | "postback": "buy" 133 | } 134 | ], 135 | "type": 1 136 | }; 137 | 138 | let cardMessage2 = { 139 | "title": "Gnome", 140 | "imageUrl": "https://example.com/gnome.png", 141 | "buttons": [ 142 | { 143 | "text": "Info", 144 | "postback": "info" 145 | }, 146 | { 147 | "text": "Gnome info", 148 | "postback": "https://example.com/gnome" 149 | } 150 | ], 151 | "type": 1 152 | }; 153 | 154 | let fbCardsMessage = { 155 | attachment: { 156 | type: "template", 157 | payload: { 158 | template_type: "generic", 159 | elements: [ 160 | { 161 | title: 'Kitten', 162 | image_url: 'https://example.com/cat.jpg', 163 | subtitle: 'Cat', 164 | buttons: [{type: 'postback', title: 'Buy', payload: 'buy'}] 165 | }, 166 | { 167 | title: 'Gnome', 168 | image_url: 'https://example.com/gnome.png', 169 | buttons: [ 170 | {type: 'postback', title: 'Info', payload: 'info'}, 171 | {type: 'web_url', title: 'Gnome info', url: 'https://example.com/gnome'} 172 | ] 173 | } 174 | ] 175 | } 176 | } 177 | }; 178 | 179 | let repliesMessage = {type: 2, title: 'Replies title', replies: ['first', 'second']}; 180 | let fbRepliesMessage = {text: 'Replies title', 181 | quick_replies: [ 182 | { 183 | content_type: 'text', 184 | title: 'first', 185 | payload: 'first' 186 | }, 187 | { 188 | content_type: 'text', 189 | title: 'second', 190 | payload: 'second' 191 | }] 192 | }; 193 | 194 | let repliesMessage2 = {type: 2, replies: ['without title']}; 195 | let fbRepliesMessage2 = { 196 | text: 'Choose an item', 197 | quick_replies: [ 198 | { 199 | content_type: 'text', 200 | title: 'without title', 201 | payload: 'without title' 202 | } 203 | ] 204 | }; 205 | 206 | let wrongRepliesMessage = {type: 2}; 207 | 208 | let imageMessage = {type: 3, imageUrl: 'https://example.com/1.png'}; 209 | let fbImageMessage = {attachment: {type: 'image', payload: {url: 'https://example.com/1.png'}}}; 210 | 211 | let wrongImageMessage = {type: 3}; 212 | 213 | let payloadMessage = {type:4, payload: {facebook: {text: 'some facebook payload'}}}; 214 | let fbPayloadMessage = {text: 'some facebook payload'}; 215 | 216 | let wrongPayloadMessage = {type: 4}; 217 | 218 | let unknownType = {type: 10, someData: {}}; 219 | 220 | let cardMessage3 = { 221 | "title": "Kitten", 222 | "imageUrl": "https://example.com/cat.jpg", 223 | "buttons": [ 224 | { 225 | "text": "More Info" 226 | } 227 | ], 228 | "type": 1 229 | }; 230 | let fbCardMessage2 = { 231 | attachment: { 232 | type: "template", 233 | payload: { 234 | template_type: "generic", 235 | elements: [ 236 | { 237 | title: 'Kitten', 238 | image_url: 'https://example.com/cat.jpg', 239 | buttons: [{type: 'postback', title: 'More Info', payload: 'More Info'}] 240 | } 241 | ] 242 | } 243 | } 244 | }; 245 | 246 | let expectedMessages = [fbTextMessage, fbCardsMessage, fbRepliesMessage, fbRepliesMessage2, fbImageMessage, fbPayloadMessage, fbCardMessage2]; 247 | let counter = 0; 248 | let resultMessages = []; 249 | 250 | let fbBot = app.__get__('facebookBot'); 251 | 252 | fbBot.messagesDelay = 10; 253 | 254 | fbBot.sendFBSenderAction = (sender, action) => { 255 | return Promise.resolve(); 256 | }; 257 | 258 | fbBot.sendFBMessage = (sender, messageData) => { 259 | counter += 1; 260 | resultMessages.push(messageData); 261 | return Promise.resolve(); 262 | }; 263 | 264 | 265 | fbBot.doRichContentResponse('senderId', [ 266 | textMessage, 267 | wrongTextMessage, 268 | cardMessage1, 269 | cardMessage2, 270 | repliesMessage, 271 | repliesMessage2, 272 | wrongRepliesMessage, 273 | unknownType, 274 | imageMessage, 275 | wrongImageMessage, 276 | payloadMessage, 277 | wrongPayloadMessage, 278 | cardMessage3 279 | ]) 280 | .then(() => { 281 | resultMessages.should.deepEqual(expectedMessages); 282 | done(); 283 | }) 284 | .catch(done); 285 | }); 286 | 287 | it("chunkString should split string to parts", () => { 288 | 289 | let fbBot = app.__get__('facebookBot'); 290 | let chunkString = fbBot.chunkString; 291 | 292 | let stringToSplit = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; 293 | let expected = ['Lorem ipsum ', 'dolor sit amet, ', 'consectetur ', 'adipiscing ', 'elit.']; 294 | 295 | let result = chunkString(stringToSplit, 15); 296 | result.forEach(s => s.length.should.lessThan(17)); 297 | 298 | result.should.deepEqual(expected); 299 | }); 300 | 301 | it("getEventText should get right text", () => { 302 | 303 | const fbBot = app.__get__('facebookBot'); 304 | const getEventText = fbBot.getEventText; 305 | 306 | should(getEventText({})).be.equal(null); 307 | should(getEventText({message: {}})).be.equal(null); 308 | 309 | const expectedText = 'expectedText'; 310 | 311 | const simpleMessage = { 312 | "message": { 313 | "text": expectedText, 314 | } 315 | }; 316 | getEventText(simpleMessage).should.be.equal(expectedText); 317 | 318 | const postbackMessage = { 319 | "postback": { 320 | "payload": expectedText 321 | } 322 | }; 323 | getEventText(postbackMessage).should.be.equal(expectedText); 324 | 325 | const quickReplyMessage = { 326 | "message": { 327 | "text": "Red", 328 | "quick_reply": { 329 | "payload": expectedText 330 | } 331 | } 332 | }; 333 | getEventText(quickReplyMessage).should.be.equal(expectedText); 334 | 335 | }); 336 | 337 | }); -------------------------------------------------------------------------------- /samples/kik/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Optional npm cache directory 29 | .npm 30 | 31 | # Optional REPL history 32 | .node_repl_history 33 | >>>>>>> 772905ea961ba965027ba86a3011355968b93b72 34 | -------------------------------------------------------------------------------- /samples/kik/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 | -------------------------------------------------------------------------------- /samples/kik/README.md: -------------------------------------------------------------------------------- 1 | # api-ai-kik-bot 2 | Kik bot SDK for Api.ai 3 | 4 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/kik/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Kik integration", 3 | "description": "Api.ai Kik integration allows you to create Kik bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/api-ai-kik-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "kik", "natural language"], 7 | "env": { 8 | "APP_NAME": { 9 | "description": "Copy App Name here", 10 | "value": "" 11 | }, 12 | "KIK_API_KEY": { 13 | "description": "Kik Api key", 14 | "value": "" 15 | }, 16 | "APIAI_ACCESS_TOKEN": { 17 | "description": "Client access token for Api.ai", 18 | "value": "" 19 | }, 20 | "APIAI_LANG": { 21 | "description": "Agent language", 22 | "value": "", 23 | "required": false 24 | } 25 | }, 26 | "engines": { 27 | "node": "5.10.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/kik/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-ai-kik-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Kik Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "@kikinteractive/kik": "^2.0.2", 14 | "apiai": "^2.0.0", 15 | "body-parser": "^1.15.0", 16 | "html-entities": "^1.2.0", 17 | "node-uuid": "^1.4.7", 18 | "request": "^2.71.0" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/api-ai/api-ai-kik-bot" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/kik/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const Bot = require('@kikinteractive/kik'); 5 | const uuid = require('node-uuid'); 6 | const request = require('request'); 7 | const http = require('http'); 8 | 9 | const REST_PORT = (process.env.PORT || 5000); 10 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 11 | const APIAI_LANG = process.env.APIAI_LANG || 'en'; 12 | const KIK_API_KEY = process.env.KIK_API_KEY; 13 | const SERVICE_URL = "https://" + process.env.APP_NAME + ".herokuapp.com"; 14 | 15 | const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "kik"}); 16 | const sessionIds = new Map(); 17 | 18 | let bot = new Bot({ 19 | username: 'apiai.bot', 20 | apiKey: KIK_API_KEY, 21 | baseUrl: SERVICE_URL 22 | }); 23 | 24 | function isDefined(obj) { 25 | if (typeof obj == 'undefined') { 26 | return false; 27 | } 28 | 29 | if (!obj) { 30 | return false; 31 | } 32 | 33 | return obj != null; 34 | } 35 | 36 | bot.updateBotConfiguration(); 37 | 38 | bot.onTextMessage((message) => { 39 | // message format from https://dev.kik.com/#/docs/messaging#receiving-messages 40 | console.log("chatId " + message.chatId); 41 | console.log("from " + message.from); 42 | 43 | let chatId = message.chatId; 44 | let messageText = message.body; 45 | 46 | if (messageText) { 47 | if (!sessionIds.has(chatId)) { 48 | sessionIds.set(chatId, uuid.v1()); 49 | } 50 | 51 | let apiaiRequest = apiAiService.textRequest(messageText, 52 | { 53 | sessionId: sessionIds.get(chatId) 54 | }); 55 | 56 | apiaiRequest.on('response', (response) => { 57 | if (isDefined(response.result)) { 58 | let responseText = response.result.fulfillment.speech; 59 | let responseData = response.result.fulfillment.data; 60 | let action = response.result.action; 61 | 62 | if (isDefined(responseData) && isDefined(responseData.kik)) { 63 | try { 64 | // message can be formatted according to https://dev.kik.com/#/docs/messaging#message-formats 65 | console.log('Response as formatted message'); 66 | message.reply(responseData.kik); 67 | } catch (err) { 68 | message.reply(err.message); 69 | } 70 | } else if (isDefined(responseText)) { 71 | console.log('Response as text message'); 72 | message.reply(responseText); 73 | } 74 | } 75 | }); 76 | 77 | apiaiRequest.on('error', (error) => console.error(error)); 78 | apiaiRequest.end(); 79 | } 80 | }); 81 | 82 | const server = http 83 | .createServer(bot.incoming()) 84 | .listen(REST_PORT); -------------------------------------------------------------------------------- /samples/line/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/line/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 | -------------------------------------------------------------------------------- /samples/line/README.md: -------------------------------------------------------------------------------- 1 | # apiai-line-bot 2 | 3 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/line/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Line integration", 3 | "description": "Api.ai Line integration allows you to create Line bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-line-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "line", "natural language"], 7 | "env": { 8 | "APIAI_ACCESS_TOKEN": { 9 | "description": "Client access token for Api.ai", 10 | "value": "" 11 | }, 12 | "APIAI_LANG": { 13 | "description": "Agent language", 14 | "value": "en", 15 | "required": false 16 | }, 17 | "LINE_CHANNEL_ID": { 18 | "description": "Channel ID from Line dashboard", 19 | "value": "" 20 | }, 21 | "LINE_CHANNEL_SECRET": { 22 | "description": "Channel Secret from Line dashboard", 23 | "value": "" 24 | }, 25 | "LINE_MID": { 26 | "description": "MID from Line dashboard", 27 | "value": "" 28 | } 29 | }, 30 | "engines": { 31 | "node": "5.10.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/line/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-line-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Line Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "2.0.5", 14 | "body-parser": "^1.15.0", 15 | "console-stamp": "^0.2.1", 16 | "express": "^4.13.4", 17 | "node-uuid": "^1.4.7", 18 | "request": "^2.71.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/line/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const bodyParser = require('body-parser'); 5 | const crypto = require('crypto'); 6 | 7 | const LineBot = require('./linebot'); 8 | const LineBotConfig = require('./linebotconfig'); 9 | 10 | const REST_PORT = (process.env.PORT || 5000); 11 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 12 | 13 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 14 | const APIAI_LANG = process.env.APIAI_LANG; 15 | 16 | const LINE_CHANNEL_ID = process.env.LINE_CHANNEL_ID; 17 | const LINE_CHANNEL_SECRET = process.env.LINE_CHANNEL_SECRET; 18 | const LINE_MID = process.env.LINE_MID; 19 | 20 | // console timestamps 21 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 22 | 23 | const botConfig = new LineBotConfig(APIAI_ACCESS_TOKEN, APIAI_LANG, 24 | LINE_CHANNEL_ID, 25 | LINE_CHANNEL_SECRET, 26 | LINE_MID); 27 | 28 | const bot = new LineBot(botConfig); 29 | 30 | const app = express(); 31 | 32 | app.use(bodyParser.json({ 33 | verify: function(req, res, buf, encoding) { 34 | // raw body for signature check 35 | req.rawBody = buf.toString(); 36 | } 37 | })); 38 | 39 | app.post('/webhook', (req, res) => { 40 | 41 | console.log('POST received'); 42 | 43 | let signature = req.get('X-LINE-ChannelSignature'); 44 | let rawBody = req.rawBody; 45 | let hash = crypto.createHmac('sha256', LINE_CHANNEL_SECRET).update(rawBody).digest('base64'); 46 | 47 | if (hash != signature) { 48 | console.log("Unauthorized request"); 49 | return res.status(401).send('Wrong request signature'); 50 | } 51 | 52 | try { 53 | 54 | if (req.body.result) { 55 | req.body.result.forEach(function (item) { 56 | bot.processMessage(item, res); 57 | }); 58 | } 59 | 60 | } catch (err) { 61 | return res.status(400).send('Error while processing ' + err.message); 62 | } 63 | }); 64 | 65 | app.listen(REST_PORT, function () { 66 | console.log('Rest service ready on port ' + REST_PORT); 67 | }); -------------------------------------------------------------------------------- /samples/line/src/linebot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const request = require('request'); 6 | 7 | module.exports = class LineBot { 8 | 9 | get apiaiService() { 10 | return this._apiaiService; 11 | } 12 | 13 | set apiaiService(value) { 14 | this._apiaiService = value; 15 | } 16 | 17 | get botConfig() { 18 | return this._botConfig; 19 | } 20 | 21 | set botConfig(value) { 22 | this._botConfig = value; 23 | } 24 | 25 | get sessionIds() { 26 | return this._sessionIds; 27 | } 28 | 29 | set sessionIds(value) { 30 | this._sessionIds = value; 31 | } 32 | 33 | constructor(botConfig) { 34 | this._botConfig = botConfig; 35 | var apiaiOptions = { 36 | language: botConfig.apiaiLang, 37 | requestSource: "line" 38 | }; 39 | 40 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 41 | this._sessionIds = new Map(); 42 | } 43 | 44 | processMessage(message, res) { 45 | if (this._botConfig.devConfig) { 46 | console.log("message", message); 47 | } 48 | 49 | if (message.content && message.content.from && message.content.text) { 50 | let chatId = message.content.from; 51 | let messageText = message.content.text; 52 | 53 | console.log(chatId, messageText); 54 | 55 | if (messageText) { 56 | if (!this._sessionIds.has(chatId)) { 57 | this._sessionIds.set(chatId, uuid.v1()); 58 | } 59 | 60 | let apiaiRequest = this._apiaiService.textRequest(messageText, 61 | { 62 | sessionId: this._sessionIds.get(chatId) 63 | }); 64 | 65 | apiaiRequest.on('response', (response) => { 66 | if (LineBot.isDefined(response.result)) { 67 | let responseText = response.result.fulfillment.speech; 68 | 69 | if (LineBot.isDefined(responseText)) { 70 | console.log('Response as text message'); 71 | this.postLineMessage(chatId, responseText); 72 | } else { 73 | console.log('Received empty speech'); 74 | } 75 | } else { 76 | console.log('Received empty result') 77 | } 78 | }); 79 | 80 | apiaiRequest.on('error', (error) => console.error(error)); 81 | apiaiRequest.end(); 82 | } 83 | else { 84 | console.log('Empty message'); 85 | } 86 | } else { 87 | console.log('Empty message'); 88 | } 89 | } 90 | 91 | postLineMessage(to, text) { 92 | request.post("https://trialbot-api.line.me/v1/events", { 93 | headers: { 94 | 'X-Line-ChannelID': this._botConfig.channelId, 95 | 'X-Line-ChannelSecret': this._botConfig.channelSecret, 96 | 'X-Line-Trusted-User-With-ACL': this._botConfig.MID 97 | }, 98 | json: { 99 | to: [to], 100 | toChannel: 1383378250, 101 | eventType: "138311608800106203", 102 | content: { 103 | contentType: 1, 104 | toType: 1, 105 | text: text 106 | } 107 | } 108 | }, function (error, response, body) { 109 | if (error) { 110 | console.error('Error while sending message', error); 111 | return; 112 | } 113 | 114 | if (response.statusCode != 200) { 115 | console.error('Error status code while sending message', body); 116 | return; 117 | } 118 | 119 | console.log('Send message succeeded'); 120 | }); 121 | } 122 | 123 | static isDefined(obj) { 124 | if (typeof obj == 'undefined') { 125 | return false; 126 | } 127 | 128 | if (!obj) { 129 | return false; 130 | } 131 | 132 | return obj != null; 133 | } 134 | } -------------------------------------------------------------------------------- /samples/line/src/linebotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class LineBotConfig { 4 | 5 | get apiaiAccessToken() { 6 | return this._apiaiAccessToken; 7 | } 8 | 9 | set apiaiAccessToken(value) { 10 | this._apiaiAccessToken = value; 11 | } 12 | 13 | get apiaiLang() { 14 | return this._apiaiLang; 15 | } 16 | 17 | set apiaiLang(value) { 18 | this._apiaiLang = value; 19 | } 20 | 21 | get channelId() { 22 | return this._channelId; 23 | } 24 | 25 | set channelId(value) { 26 | this._channelId = value; 27 | } 28 | 29 | get channelSecret() { 30 | return this._channelSecret; 31 | } 32 | 33 | set channelSecret(value) { 34 | this._channelSecret = value; 35 | } 36 | 37 | get MID() { 38 | return this._MID; 39 | } 40 | 41 | set MID(value) { 42 | this._MID = value; 43 | } 44 | 45 | get devConfig() { 46 | return this._devConfig; 47 | } 48 | 49 | set devConfig(value) { 50 | this._devConfig = value; 51 | } 52 | 53 | constructor(apiaiAccessToken, apiaiLang, channelId, channelSecret, MID) { 54 | this._apiaiAccessToken = apiaiAccessToken; 55 | this._apiaiLang = apiaiLang; 56 | this._channelId = channelId; 57 | this._channelSecret = channelSecret; 58 | this._MID = MID; 59 | } 60 | 61 | toPlainDoc() { 62 | return { 63 | apiaiAccessToken: this._apiaiAccessToken, 64 | apiaiLang: this._apiaiLang, 65 | channelId: this._channelId, 66 | channelSecret: this.channelSecret, 67 | MID: this._MID 68 | } 69 | } 70 | 71 | static fromPlainDoc(doc) { 72 | return new LineBotConfig( 73 | doc.apiaiAccessToken, 74 | doc.apiaiLang, 75 | doc.channelId, 76 | doc.channelSecret, 77 | doc.MID); 78 | } 79 | }; -------------------------------------------------------------------------------- /samples/rus_example.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidniki02/apiai-nodejs-client/110f1d8a060b7089551196dc6ac286bf7c502a7e/samples/rus_example.wav -------------------------------------------------------------------------------- /samples/server.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var http = require('http'); 10 | // var apiai = require("../module/apiai"); 11 | var apiai = require("apiai"); 12 | 13 | var app = apiai("YOUR_ACCESS_TOKEN"); 14 | 15 | var code = 405; 16 | 17 | var server = http.createServer(function(request, response) { 18 | if (request.method == 'POST' && request.url == '/upload') { 19 | var voiceRequest = app.voiceRequest(); 20 | 21 | voiceRequest.on('response', function(_response) { 22 | response.end(JSON.stringify(_response)); 23 | }); 24 | 25 | voiceRequest.on('error', function(error) { 26 | console.log(error); 27 | response.end(); 28 | }); 29 | 30 | request.on('data', function(chunk) { 31 | voiceRequest.write(chunk); 32 | }); 33 | 34 | request.on('end', function() { 35 | voiceRequest.end(); 36 | }); 37 | } else { 38 | response.writeHead(code, {}); 39 | response.end(); 40 | } 41 | 42 | console.log(request.headers); 43 | }); 44 | 45 | server.listen(8000); 46 | 47 | // cat ann_smith.wav | curl -v -X POST --data-binary @- -H "Transfer-Encoding: chunked" -H "Content-Type: audio/wav" http://localhost:8000/upload 48 | -------------------------------------------------------------------------------- /samples/skype/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/skype/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 | -------------------------------------------------------------------------------- /samples/skype/README.md: -------------------------------------------------------------------------------- 1 | # apiai-skype-bot 2 | 3 | Before you start the bot you need install the dependencies using 4 | `npm install`. 5 | 6 | Make sure you defined you environment variables APP_ID and APP_SECRET and 7 | that they contain MSA OAuth credentials. 8 | 9 | You can start the bot with `node app.js`. By default the server will 10 | be listening on port 5000. 11 | So service endpoint will be "https://example.com:5000/chat" 12 | 13 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 14 | -------------------------------------------------------------------------------- /samples/skype/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const express = require('express'); 5 | const bodyParser = require('body-parser'); 6 | 7 | const SkypeBot = require('./skypebot'); 8 | const SkypeBotConfig = require('./skypebotconfig'); 9 | 10 | const REST_PORT = (process.env.PORT || 5000); 11 | 12 | const botConfig = new SkypeBotConfig( 13 | process.env.APIAI_ACCESS_TOKEN, 14 | process.env.APIAI_LANG, 15 | process.env.APP_ID, 16 | process.env.APP_SECRET 17 | ); 18 | 19 | const skypeBot = new SkypeBot(botConfig); 20 | 21 | // console timestamps 22 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 23 | 24 | const app = express(); 25 | app.use(bodyParser.json()); 26 | 27 | app.post('/chat', skypeBot.botService.listen()); 28 | 29 | app.listen(REST_PORT, function () { 30 | console.log('Rest service ready on port ' + REST_PORT); 31 | }); -------------------------------------------------------------------------------- /samples/skype/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Skype integration", 3 | "description": "Api.ai Skype integration allows you to create Skype bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-skype-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "skype", "natural language"], 7 | "env": { 8 | "APIAI_ACCESS_TOKEN": { 9 | "description": "Client access token for Api.ai", 10 | "value": "" 11 | }, 12 | "APIAI_LANG": { 13 | "description": "Agent language", 14 | "value": "en", 15 | "required": false 16 | }, 17 | "APP_ID": { 18 | "description": "Microsoft App ID", 19 | "value": "" 20 | }, 21 | "APP_SECRET": { 22 | "description": "Microsoft App Password", 23 | "value": "" 24 | } 25 | }, 26 | "engines": { 27 | "node": "5.10.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/skype/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-skype-bot", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node app.js" 9 | }, 10 | "keywords": [], 11 | "engines": { 12 | "node": ">=5.6.0" 13 | }, 14 | "author": "", 15 | "license": "Apache-2.0", 16 | "dependencies": { 17 | "apiai": "^2.0.5", 18 | "body-parser": "^1.15.1", 19 | "botbuilder": "^3.1.1", 20 | "console-stamp": "^0.2.2", 21 | "express": "^4.13.4", 22 | "node-uuid": "^1.4.7" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /samples/skype/skypebot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const botbuilder = require('botbuilder'); 6 | 7 | module.exports = class SkypeBot { 8 | 9 | get apiaiService() { 10 | return this._apiaiService; 11 | } 12 | 13 | set apiaiService(value) { 14 | this._apiaiService = value; 15 | } 16 | 17 | get botConfig() { 18 | return this._botConfig; 19 | } 20 | 21 | set botConfig(value) { 22 | this._botConfig = value; 23 | } 24 | 25 | get botService() { 26 | return this._botService; 27 | } 28 | 29 | set botService(value) { 30 | this._botService = value; 31 | } 32 | 33 | get sessionIds() { 34 | return this._sessionIds; 35 | } 36 | 37 | set sessionIds(value) { 38 | this._sessionIds = value; 39 | } 40 | 41 | constructor(botConfig) { 42 | this._botConfig = botConfig; 43 | var apiaiOptions = { 44 | language: botConfig.apiaiLang, 45 | requestSource: "skype" 46 | }; 47 | 48 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 49 | this._sessionIds = new Map(); 50 | 51 | this.botService = new botbuilder.ChatConnector({ 52 | appId: this.botConfig.skypeAppId, 53 | appPassword: this.botConfig.skypeAppSecret 54 | }); 55 | 56 | this._bot = new botbuilder.UniversalBot(this.botService); 57 | 58 | this._bot.dialog('/', (session) => { 59 | if (session.message && session.message.text) { 60 | this.processMessage(session); 61 | } 62 | }); 63 | 64 | } 65 | 66 | processMessage(session) { 67 | 68 | let messageText = session.message.text; 69 | let sender = session.message.address.conversation.id; 70 | 71 | if (messageText && sender) { 72 | 73 | console.log(sender, messageText); 74 | 75 | if (!this._sessionIds.has(sender)) { 76 | this._sessionIds.set(sender, uuid.v1()); 77 | } 78 | 79 | let apiaiRequest = this._apiaiService.textRequest(messageText, 80 | { 81 | sessionId: this._sessionIds.get(sender), 82 | originalRequest: { 83 | data: session.message, 84 | source: "skype" 85 | } 86 | }); 87 | 88 | apiaiRequest.on('response', (response) => { 89 | if (this._botConfig.devConfig) { 90 | console.log(sender, "Received api.ai response"); 91 | } 92 | 93 | if (SkypeBot.isDefined(response.result) && SkypeBot.isDefined(response.result.fulfillment)) { 94 | let responseText = response.result.fulfillment.speech; 95 | let responseMessages = response.result.fulfillment.messages; 96 | 97 | if (SkypeBot.isDefined(responseMessages) && responseMessages.length > 0) { 98 | this.doRichContentResponse(session, responseMessages); 99 | } else if (SkypeBot.isDefined(responseText)) { 100 | console.log(sender, 'Response as text message'); 101 | session.send(responseText); 102 | 103 | } else { 104 | console.log(sender, 'Received empty speech'); 105 | } 106 | } else { 107 | console.log(sender, 'Received empty result'); 108 | } 109 | }); 110 | 111 | apiaiRequest.on('error', (error) => { 112 | console.error(sender, 'Error while call to api.ai', error); 113 | }); 114 | 115 | apiaiRequest.end(); 116 | } else { 117 | console.log('Empty message'); 118 | } 119 | } 120 | 121 | doRichContentResponse(session, messages) { 122 | 123 | for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) { 124 | let message = messages[messageIndex]; 125 | 126 | switch (message.type) { 127 | //message.type 0 means text message 128 | case 0: 129 | { 130 | 131 | if (SkypeBot.isDefined(message.speech)) { 132 | session.send(message.speech); 133 | } 134 | 135 | } 136 | 137 | break; 138 | 139 | //message.type 1 means card message 140 | case 1: 141 | { 142 | let heroCard = new botbuilder.HeroCard(session).title(message.title); 143 | 144 | if (SkypeBot.isDefined(message.subtitle)) { 145 | heroCard = heroCard.subtitle(message.subtitle) 146 | } 147 | 148 | if (SkypeBot.isDefined(message.imageUrl)) { 149 | heroCard = heroCard.images([botbuilder.CardImage.create(session, message.imageUrl)]); 150 | } 151 | 152 | if (SkypeBot.isDefined(message.buttons)) { 153 | 154 | let buttons = []; 155 | 156 | for (let buttonIndex = 0; buttonIndex < message.buttons.length; buttonIndex++) { 157 | let messageButton = message.buttons[buttonIndex]; 158 | if (messageButton.text) { 159 | let postback = messageButton.postback; 160 | if (!postback) { 161 | postback = messageButton.text; 162 | } 163 | 164 | let button; 165 | 166 | if (postback.startsWith("http")) { 167 | button = botbuilder.CardAction.openUrl(session, postback, messageButton.text); 168 | } else { 169 | button = botbuilder.CardAction.postBack(session, postback, messageButton.text); 170 | } 171 | 172 | buttons.push(button); 173 | } 174 | } 175 | 176 | heroCard.buttons(buttons); 177 | 178 | } 179 | 180 | let msg = new botbuilder.Message(session).attachments([heroCard]); 181 | session.send(msg); 182 | 183 | } 184 | 185 | break; 186 | 187 | //message.type 2 means quick replies message 188 | case 2: 189 | { 190 | 191 | let replies = []; 192 | 193 | let heroCard = new botbuilder.HeroCard(session).title(message.title); 194 | 195 | if (SkypeBot.isDefined(message.replies)) { 196 | 197 | for (let replyIndex = 0; replyIndex < message.replies.length; replyIndex++) { 198 | let messageReply = message.replies[replyIndex]; 199 | let reply = botbuilder.CardAction.postBack(session, messageReply, messageReply); 200 | replies.push(reply); 201 | } 202 | 203 | heroCard.buttons(replies); 204 | } 205 | 206 | let msg = new botbuilder.Message(session).attachments([heroCard]); 207 | session.send(msg); 208 | 209 | } 210 | 211 | break; 212 | 213 | //message.type 3 means image message 214 | case 3: 215 | { 216 | let heroCard = new botbuilder.HeroCard(session).images([botbuilder.CardImage.create(session, message.imageUrl)]); 217 | let msg = new botbuilder.Message(session).attachments([heroCard]); 218 | session.send(msg); 219 | } 220 | 221 | break; 222 | 223 | default: 224 | 225 | break; 226 | } 227 | } 228 | 229 | } 230 | 231 | static isDefined(obj) { 232 | if (typeof obj == 'undefined') { 233 | return false; 234 | } 235 | 236 | if (!obj) { 237 | return false; 238 | } 239 | 240 | return obj != null; 241 | } 242 | } -------------------------------------------------------------------------------- /samples/skype/skypebotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class SkypeBotConfig { 4 | 5 | get apiaiAccessToken() { 6 | return this._apiaiAccessToken; 7 | } 8 | 9 | set apiaiAccessToken(value) { 10 | this._apiaiAccessToken = value; 11 | } 12 | 13 | get apiaiLang() { 14 | return this._apiaiLang; 15 | } 16 | 17 | set apiaiLang(value) { 18 | this._apiaiLang = value; 19 | } 20 | 21 | get skypeBotId() { 22 | return this._skypeBotId; 23 | } 24 | 25 | set skypeBotId(value) { 26 | this._skypeBotId = value; 27 | } 28 | 29 | get skypeAppId() { 30 | return this._skypeAppId; 31 | } 32 | 33 | set skypeAppId(value) { 34 | this._skypeAppId = value; 35 | } 36 | 37 | get skypeAppSecret() { 38 | return this._skypeAppSecret; 39 | } 40 | 41 | set skypeAppSecret(value) { 42 | this._skypeAppSecret = value; 43 | } 44 | 45 | get devConfig() { 46 | return this._devConfig; 47 | } 48 | 49 | set devConfig(value) { 50 | this._devConfig = value; 51 | } 52 | 53 | constructor(apiaiAccessToken, apiaiLang, appId, appSecret) { 54 | this._apiaiAccessToken = apiaiAccessToken; 55 | this._apiaiLang = apiaiLang; 56 | this._skypeAppId = appId; 57 | this._skypeAppSecret = appSecret; 58 | } 59 | 60 | toPlainDoc() { 61 | return { 62 | apiaiAccessToken: this._apiaiAccessToken, 63 | apiaiLang: this._apiaiLang, 64 | skypeAppId: this._skypeAppId, 65 | skypeAppSecret: this._skypeAppSecret 66 | } 67 | } 68 | 69 | static fromPlainDoc(doc){ 70 | return new SkypeBotConfig( 71 | doc.apiaiAccessToken, 72 | doc.apiaiLang, 73 | doc.skypeAppId, 74 | doc.skypeAppSecret); 75 | } 76 | }; -------------------------------------------------------------------------------- /samples/spark/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | config.json -------------------------------------------------------------------------------- /samples/spark/README.md: -------------------------------------------------------------------------------- 1 | # apiai-spark-bot 2 | 3 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/spark/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Spark integration", 3 | "description": "Api.ai Spark integration allows you to create Spark bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-spark-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "spark", "natural language"], 7 | "env": { 8 | "APP_NAME": { 9 | "description": "Copy App Name here", 10 | "value": "" 11 | }, 12 | "APIAI_ACCESS_TOKEN": { 13 | "description": "Client access token for Api.ai", 14 | "value": "" 15 | }, 16 | "SPARK_ACCESS_TOKEN": { 17 | "description": "Spark Access Token", 18 | "value": "" 19 | }, 20 | "APIAI_LANG": { 21 | "description": "Agent language", 22 | "value": "en", 23 | "required": false 24 | } 25 | }, 26 | "engines": { 27 | "node": "6.9.4" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/spark/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-spark-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Spark Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "^3.0.3", 14 | "assert": "^1.4.0", 15 | "async": "^2.1.4", 16 | "body-parser": "^1.15.0", 17 | "console-stamp": "^0.2.1", 18 | "express": "^4.13.4", 19 | "request": "^2.71.0", 20 | "uuid": "^3.0.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/spark/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const express = require('express'); 5 | const bodyParser = require('body-parser'); 6 | const request = require('request'); 7 | 8 | const SparkBot = require('./sparkbot'); 9 | const SparkBotConfig = require('./sparkbotconfig'); 10 | 11 | const REST_PORT = (process.env.PORT || 5000); 12 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 13 | 14 | const APP_NAME = process.env.APP_NAME; 15 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 16 | const APIAI_LANG = process.env.APIAI_LANG; 17 | 18 | const SPARK_ACCESS_TOKEN = process.env.SPARK_ACCESS_TOKEN; 19 | 20 | let baseUrl = ""; 21 | if (APP_NAME) { 22 | // Heroku case 23 | baseUrl = `https://${APP_NAME}.herokuapp.com`; 24 | } else { 25 | console.error('Set up the url of your service here and remove exit code!'); 26 | process.exit(1); 27 | } 28 | 29 | let bot; 30 | 31 | // console timestamps 32 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 33 | 34 | function startBot() { 35 | 36 | console.log("Starting bot"); 37 | 38 | const botConfig = new SparkBotConfig( 39 | APIAI_ACCESS_TOKEN, 40 | APIAI_LANG, 41 | SPARK_ACCESS_TOKEN); 42 | 43 | botConfig.devConfig = DEV_CONFIG; 44 | 45 | bot = new SparkBot(botConfig, baseUrl + '/webhook'); 46 | 47 | bot.loadProfile() 48 | .then((profile) => { 49 | bot.setProfile(profile); 50 | bot.setupWebhook(); 51 | }) 52 | .catch((err) => { 53 | console.error(err); 54 | }); 55 | } 56 | 57 | startBot(); 58 | 59 | const app = express(); 60 | app.use(bodyParser.json()); 61 | 62 | app.post('/webhook', (req, res) => { 63 | console.log('POST webhook'); 64 | 65 | try { 66 | if (bot) { 67 | bot.processMessage(req, res); 68 | } 69 | } catch (err) { 70 | return res.status(400).send('Error while processing ' + err.message); 71 | } 72 | }); 73 | 74 | app.listen(REST_PORT, () => { 75 | console.log('Rest service ready on port ' + REST_PORT); 76 | }); -------------------------------------------------------------------------------- /samples/spark/src/sparkbotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class SparkBotConfig { 4 | 5 | get apiaiAccessToken() { 6 | return this._apiaiAccessToken; 7 | } 8 | 9 | set apiaiAccessToken(value) { 10 | this._apiaiAccessToken = value; 11 | } 12 | 13 | get apiaiLang() { 14 | return this._apiaiLang; 15 | } 16 | 17 | set apiaiLang(value) { 18 | this._apiaiLang = value; 19 | } 20 | 21 | get sparkToken() { 22 | return this._sparkToken; 23 | } 24 | 25 | set sparkToken(value) { 26 | this._sparkToken = value; 27 | } 28 | 29 | get devConfig() { 30 | return this._devConfig; 31 | } 32 | 33 | set devConfig(value) { 34 | this._devConfig = value; 35 | } 36 | 37 | constructor(apiaiAccessToken, apiaiLang, sparkToken) { 38 | this._apiaiAccessToken = apiaiAccessToken; 39 | this._apiaiLang = apiaiLang; 40 | this._sparkToken = sparkToken; 41 | } 42 | 43 | toPlainDoc() { 44 | return { 45 | apiaiAccessToken: this._apiaiAccessToken, 46 | apiaiLang: this._apiaiLang, 47 | sparkToken: this._sparkToken 48 | } 49 | } 50 | 51 | static fromPlainDoc(doc) { 52 | return new SparkBotConfig( 53 | doc.apiaiAccessToken, 54 | doc.apiaiLang, 55 | doc.sparkToken); 56 | } 57 | }; -------------------------------------------------------------------------------- /samples/telegram/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/telegram/README.md: -------------------------------------------------------------------------------- 1 | # apiai-telegram-bot 2 | 3 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/telegram/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Telegram integration", 3 | "description": "Api.ai Telegram integration allows you to create Telegram bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-telegram-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "telegram", "natural language"], 7 | "env": { 8 | "APP_NAME": { 9 | "description": "Copy App Name here", 10 | "value": "" 11 | }, 12 | "TELEGRAM_TOKEN": { 13 | "description": "Telegram bot token", 14 | "value": "" 15 | }, 16 | "APIAI_ACCESS_TOKEN": { 17 | "description": "Client access token for Api.ai", 18 | "value": "" 19 | }, 20 | "APIAI_LANG": { 21 | "description": "Agent language", 22 | "value": "en", 23 | "required": false 24 | } 25 | }, 26 | "engines": { 27 | "node": "5.10.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/telegram/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-telegram-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Telegram Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "^2.0.7", 14 | "body-parser": "^1.15.2", 15 | "console-stamp": "^0.2.2", 16 | "express": "^4.14.0", 17 | "node-uuid": "^1.4.7", 18 | "request": "^2.74.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/telegram/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const express = require('express'); 5 | const bodyParser = require('body-parser'); 6 | 7 | const TelegramBot = require('./telegrambot'); 8 | const TelegramBotConfig = require('./telegrambotconfig'); 9 | 10 | const REST_PORT = (process.env.PORT || 5000); 11 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 12 | 13 | const APP_NAME = process.env.APP_NAME; 14 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 15 | const APIAI_LANG = process.env.APIAI_LANG; 16 | const TELEGRAM_TOKEN = process.env.TELEGRAM_TOKEN; 17 | 18 | var baseUrl = ""; 19 | if (APP_NAME) { 20 | // Heroku case 21 | baseUrl = `https://${APP_NAME}.herokuapp.com`; 22 | } else { 23 | console.error('Set up the url of your service here and remove exit code!'); 24 | process.exit(1); 25 | } 26 | 27 | // console timestamps 28 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 29 | 30 | const botConfig = new TelegramBotConfig( 31 | APIAI_ACCESS_TOKEN, 32 | APIAI_LANG, 33 | TELEGRAM_TOKEN); 34 | 35 | botConfig.devConfig = DEV_CONFIG; 36 | 37 | const bot = new TelegramBot(botConfig, baseUrl); 38 | bot.start(() => { 39 | console.log("Bot started"); 40 | }, 41 | (errStatus) => { 42 | console.error('It seems the TELEGRAM_TOKEN is wrong! Please fix it.') 43 | }); 44 | 45 | 46 | const app = express(); 47 | app.use(bodyParser.json()); 48 | 49 | app.post('/webhook', (req, res) => { 50 | console.log('POST webhook'); 51 | 52 | try { 53 | bot.processMessage(req, res); 54 | } catch (err) { 55 | return res.status(400).send('Error while processing ' + err.message); 56 | } 57 | }); 58 | 59 | app.listen(REST_PORT, function () { 60 | console.log('Rest service ready on port ' + REST_PORT); 61 | }); -------------------------------------------------------------------------------- /samples/telegram/src/telegrambot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const request = require('request'); 6 | 7 | module.exports = class TelegramBot { 8 | 9 | get apiaiService() { 10 | return this._apiaiService; 11 | } 12 | 13 | set apiaiService(value) { 14 | this._apiaiService = value; 15 | } 16 | 17 | get botConfig() { 18 | return this._botConfig; 19 | } 20 | 21 | set botConfig(value) { 22 | this._botConfig = value; 23 | } 24 | 25 | get sessionIds() { 26 | return this._sessionIds; 27 | } 28 | 29 | set sessionIds(value) { 30 | this._sessionIds = value; 31 | } 32 | 33 | constructor(botConfig, baseUrl) { 34 | this._botConfig = botConfig; 35 | var apiaiOptions = { 36 | language: botConfig.apiaiLang, 37 | requestSource: "telegram" 38 | }; 39 | 40 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 41 | this._sessionIds = new Map(); 42 | 43 | this._webhookUrl = baseUrl + '/webhook'; 44 | console.log('Starting bot on ' + this._webhookUrl); 45 | 46 | this._telegramApiUrl = 'https://api.telegram.org/bot' + botConfig.telegramToken; 47 | } 48 | 49 | start(responseCallback, errCallback){ 50 | // https://core.telegram.org/bots/api#setwebhook 51 | request.post(this._telegramApiUrl + '/setWebhook', { 52 | json: { 53 | url: this._webhookUrl 54 | } 55 | }, function (error, response, body) { 56 | 57 | if (error) { 58 | console.error('Error while /setWebhook', error); 59 | if (errCallback){ 60 | errCallback(error); 61 | } 62 | return; 63 | } 64 | 65 | if (response.statusCode != 200) { 66 | console.error('Error status code while /setWebhook', body); 67 | if (errCallback) { 68 | errCallback('Error status code while setWebhook ' + body); 69 | } 70 | return; 71 | } 72 | 73 | console.log('Method /setWebhook completed', body); 74 | if (responseCallback) { 75 | responseCallback('Method /setWebhook completed ' + body) 76 | } 77 | }); 78 | } 79 | 80 | processMessage(req, res) { 81 | if (this._botConfig.devConfig) { 82 | console.log("body", req.body); 83 | } 84 | 85 | let updateObject = req.body; 86 | 87 | if (updateObject && updateObject.message) { 88 | let msg = updateObject.message; 89 | 90 | var chatId; 91 | 92 | if (msg.chat) { 93 | chatId = msg.chat.id; 94 | } 95 | 96 | let messageText = msg.text; 97 | 98 | console.log(chatId, messageText); 99 | 100 | if (chatId && messageText) { 101 | if (!this._sessionIds.has(chatId)) { 102 | this._sessionIds.set(chatId, uuid.v1()); 103 | } 104 | 105 | let apiaiRequest = this._apiaiService.textRequest(messageText, 106 | { 107 | sessionId: this._sessionIds.get(chatId) 108 | }); 109 | 110 | apiaiRequest.on('response', (response) => { 111 | if (TelegramBot.isDefined(response.result)) { 112 | let responseText = response.result.fulfillment.speech; 113 | let responseData = response.result.fulfillment.data; 114 | 115 | if (TelegramBot.isDefined(responseData) && TelegramBot.isDefined(responseData.telegram)) { 116 | 117 | console.log('Response as formatted message'); 118 | 119 | let telegramMessage = responseData.telegram; 120 | telegramMessage.chat_id = chatId; 121 | 122 | this.reply(telegramMessage); 123 | TelegramBot.createResponse(res, 200, 'Message processed'); 124 | 125 | } else if (TelegramBot.isDefined(responseText)) { 126 | console.log('Response as text message'); 127 | this.reply({ 128 | chat_id: chatId, 129 | text: responseText 130 | }); 131 | TelegramBot.createResponse(res, 200, 'Message processed'); 132 | 133 | } else { 134 | console.log('Received empty speech'); 135 | TelegramBot.createResponse(res, 200, 'Received empty speech'); 136 | } 137 | } else { 138 | console.log('Received empty result'); 139 | TelegramBot.createResponse(res, 200, 'Received empty result'); 140 | } 141 | }); 142 | 143 | apiaiRequest.on('error', (error) => { 144 | console.error('Error while call to api.ai', error); 145 | TelegramBot.createResponse(res, 200, 'Error while call to api.ai'); 146 | }); 147 | apiaiRequest.end(); 148 | } 149 | else { 150 | console.log('Empty message'); 151 | return TelegramBot.createResponse(res, 200, 'Empty message'); 152 | } 153 | } else { 154 | console.log('Empty message'); 155 | return TelegramBot.createResponse(res, 200, 'Empty message'); 156 | } 157 | } 158 | 159 | reply(msg) { 160 | // https://core.telegram.org/bots/api#sendmessage 161 | request.post(this._telegramApiUrl + '/sendMessage', { 162 | json: msg 163 | }, function (error, response, body) { 164 | if (error) { 165 | console.error('Error while /sendMessage', error); 166 | return; 167 | } 168 | 169 | if (response.statusCode != 200) { 170 | console.error('Error status code while /sendMessage', body); 171 | return; 172 | } 173 | 174 | console.log('Method /sendMessage succeeded'); 175 | }); 176 | } 177 | 178 | static createResponse(resp, code, message) { 179 | return resp.status(code).json({ 180 | status: { 181 | code: code, 182 | message: message 183 | } 184 | }); 185 | } 186 | 187 | static isDefined(obj) { 188 | if (typeof obj == 'undefined') { 189 | return false; 190 | } 191 | 192 | if (!obj) { 193 | return false; 194 | } 195 | 196 | return obj != null; 197 | } 198 | } -------------------------------------------------------------------------------- /samples/telegram/src/telegrambotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class TelegramBotConfig { 4 | 5 | get apiaiAccessToken() { 6 | return this._apiaiAccessToken; 7 | } 8 | 9 | set apiaiAccessToken(value) { 10 | this._apiaiAccessToken = value; 11 | } 12 | 13 | get apiaiLang() { 14 | return this._apiaiLang; 15 | } 16 | 17 | set apiaiLang(value) { 18 | this._apiaiLang = value; 19 | } 20 | 21 | get telegramToken() { 22 | return this._telegramToken; 23 | } 24 | 25 | set telegramToken(value) { 26 | this._telegramToken = value; 27 | } 28 | 29 | get devConfig() { 30 | return this._devConfig; 31 | } 32 | 33 | set devConfig(value) { 34 | this._devConfig = value; 35 | } 36 | 37 | constructor(apiaiAccessToken, apiaiLang, telegramToken) { 38 | this._apiaiAccessToken = apiaiAccessToken; 39 | this._apiaiLang = apiaiLang; 40 | this._telegramToken = telegramToken; 41 | } 42 | 43 | toPlainDoc() { 44 | return { 45 | apiaiAccessToken: this._apiaiAccessToken, 46 | apiaiLang: this._apiaiLang, 47 | telegramToken: this._telegramToken 48 | } 49 | } 50 | 51 | static fromPlainDoc(doc){ 52 | return new TelegramBotConfig( 53 | doc.apiaiAccessToken, 54 | doc.apiaiLang, 55 | doc.telegramToken); 56 | } 57 | }; -------------------------------------------------------------------------------- /samples/text_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var app = apiai("YOUR_ACCESS_TOKEN"); 13 | 14 | var options = { 15 | sessionId: '' 16 | }; 17 | 18 | var request = app.textRequest('Hello', options); 19 | 20 | request.on('response', function(response) { 21 | console.log(response); 22 | }); 23 | 24 | request.on('error', function(error) { 25 | console.log(error); 26 | }); 27 | 28 | request.end(); 29 | -------------------------------------------------------------------------------- /samples/text_request_chinese.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var app = apiai("YOUR_ACCESS_TOKEN", { 13 | language: 'zh-CN' 14 | }); 15 | 16 | var options = { 17 | sessionId: '' 18 | }; 19 | 20 | var request = app.textRequest('什么叫发票', options); 21 | 22 | request.on('response', function(response) { 23 | console.log(response); 24 | }); 25 | 26 | request.on('error', function(error) { 27 | console.log(error); 28 | }); 29 | 30 | request.end(); 31 | -------------------------------------------------------------------------------- /samples/text_request_no_ssl.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var options = { 13 | secure: false, 14 | hostname: 'openapi-dev', 15 | endpoint: '/api/' 16 | }; 17 | 18 | var app = apiai("YOUR_ACCESS_TOKEN", options); 19 | 20 | var options = { 21 | sessionId: '' 22 | }; 23 | 24 | var request = app.textRequest('Hello', options); 25 | 26 | request.on('response', function(response) { 27 | console.log(response); 28 | }); 29 | 30 | request.on('error', function(error) { 31 | console.log(error); 32 | }); 33 | 34 | request.end(); 35 | -------------------------------------------------------------------------------- /samples/text_request_with_contexts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var app = apiai("YOUR_ACCESS_TOKEN"); 13 | 14 | var options = { 15 | sessionId: '', 16 | contexts: [ 17 | { 18 | name: 'context_number_one', 19 | parameters: { 20 | 'some_parameter_of_context': 'parameter value 1' 21 | } 22 | } 23 | ] 24 | }; 25 | 26 | var request = app.textRequest('Hello', options); 27 | 28 | request.on('response', function(response) { 29 | console.log(JSON.stringify(response, null, ' ')); 30 | }); 31 | 32 | request.on('error', function(error) { 33 | console.log(error); 34 | }); 35 | 36 | request.end(); 37 | -------------------------------------------------------------------------------- /samples/text_request_with_entities.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var app = apiai("ACCESS_TOKEN"); 13 | 14 | var entities = [ 15 | { 16 | name: "dwarfs", 17 | entries: [ 18 | { 19 | value: "Ori", 20 | synonyms: [ 21 | "ori", 22 | "Nori" 23 | ] 24 | }, 25 | { 26 | value: "bifur", 27 | synonyms: [ 28 | "Bofur", 29 | "Bombur" 30 | ] 31 | } 32 | ] 33 | } 34 | ]; 35 | 36 | var options = { 37 | entities: entities, 38 | sessionId: '' 39 | }; 40 | 41 | var request = app.textRequest('Hello ori', options); 42 | 43 | request.on('response', function(response) { 44 | 45 | console.log(JSON.stringify(response, null, 4)); 46 | }); 47 | 48 | request.on('error', function(error) { 49 | console.log(error); 50 | }); 51 | 52 | request.end(); 53 | -------------------------------------------------------------------------------- /samples/text_request_with_parameters.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var app = apiai("YOUR_ACCESS_TOKEN"); 13 | 14 | var options = { 15 | sessionId: '' 16 | }; 17 | 18 | var request = app.textRequest('Hello', options); 19 | 20 | request.on('response', function(response) { 21 | console.log(response); 22 | }); 23 | 24 | request.on('error', function(error) { 25 | console.log(error); 26 | }); 27 | 28 | request.end(); 29 | -------------------------------------------------------------------------------- /samples/tropo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/tropo/README.md: -------------------------------------------------------------------------------- 1 | # apiai-tropo-bot 2 | 3 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/tropo/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Tropo integration", 3 | "description": "Api.ai Tropo integration allows you to create Tropo bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-tropo-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "tropo", "natural language"], 7 | "env": { 8 | "APIAI_ACCESS_TOKEN": { 9 | "description": "Client access token for Api.ai", 10 | "value": "" 11 | }, 12 | "APIAI_LANG": { 13 | "description": "Agent language", 14 | "value": "en", 15 | "required": false 16 | } 17 | }, 18 | "engines": { 19 | "node": "5.10.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/tropo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-tropo-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Tropo Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "^2.0.7", 14 | "body-parser": "^1.15.2", 15 | "console-stamp": "^0.2.2", 16 | "express": "^4.14.0", 17 | "node-uuid": "^1.4.7", 18 | "request": "^2.74.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/tropo/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const bodyParser = require('body-parser'); 5 | 6 | const TropoBot = require('./tropobot'); 7 | const TropoBotConfig = require('./tropobotconfig'); 8 | 9 | const REST_PORT = (process.env.PORT || 5000); 10 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 11 | 12 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 13 | const APIAI_LANG = process.env.APIAI_LANG; 14 | 15 | // console timestamps 16 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 17 | 18 | const botConfig = new TropoBotConfig(APIAI_ACCESS_TOKEN, APIAI_LANG); 19 | const bot = new TropoBot(botConfig); 20 | 21 | const app = express(); 22 | 23 | app.use(bodyParser.json()); 24 | 25 | app.post('/sms', (req, res) => { 26 | 27 | console.log('POST sms received'); 28 | 29 | try { 30 | bot.processMessage(req, res); 31 | } catch (err) { 32 | return res.status(400).send('Error while processing ' + err.message); 33 | } 34 | }); 35 | 36 | app.listen(REST_PORT, function () { 37 | console.log('Rest service ready on port ' + REST_PORT); 38 | }); -------------------------------------------------------------------------------- /samples/tropo/src/tropobot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const request = require('request'); 6 | 7 | module.exports = class TropoBot { 8 | 9 | get apiaiService() { 10 | return this._apiaiService; 11 | } 12 | 13 | set apiaiService(value) { 14 | this._apiaiService = value; 15 | } 16 | 17 | get botConfig() { 18 | return this._botConfig; 19 | } 20 | 21 | set botConfig(value) { 22 | this._botConfig = value; 23 | } 24 | 25 | get sessionIds() { 26 | return this._sessionIds; 27 | } 28 | 29 | set sessionIds(value) { 30 | this._sessionIds = value; 31 | } 32 | 33 | constructor(botConfig) { 34 | this._botConfig = botConfig; 35 | var apiaiOptions = { 36 | language: botConfig.apiaiLang, 37 | requestSource: "tropo" 38 | }; 39 | 40 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 41 | this._sessionIds = new Map(); 42 | } 43 | 44 | processMessage(req, res) { 45 | if (this._botConfig.devConfig) { 46 | console.log("body", req.body); 47 | } 48 | 49 | if (req.body && req.body.session && req.body.session.from && req.body.session.initialText) { 50 | let chatId = req.body.session.from.id; 51 | let messageText = req.body.session.initialText; 52 | 53 | console.log(chatId, messageText); 54 | 55 | if (messageText) { 56 | if (!this._sessionIds.has(chatId)) { 57 | this._sessionIds.set(chatId, uuid.v1()); 58 | } 59 | 60 | let apiaiRequest = this._apiaiService.textRequest(messageText, 61 | { 62 | sessionId: this._sessionIds.get(chatId) 63 | }); 64 | 65 | apiaiRequest.on('response', (response) => { 66 | if (TropoBot.isDefined(response.result)) { 67 | let responseText = response.result.fulfillment.speech; 68 | 69 | if (TropoBot.isDefined(responseText)) { 70 | console.log('Response as text message'); 71 | 72 | res.status(200).json({ 73 | tropo: [{say: {value: responseText}}] 74 | }); 75 | 76 | } else { 77 | console.log('Received empty speech'); 78 | return res.status(400).end('Received empty speech'); 79 | } 80 | } else { 81 | console.log('Received empty result'); 82 | return res.status(400).end('Received empty result'); 83 | } 84 | }); 85 | 86 | apiaiRequest.on('error', (error) => console.error(error)); 87 | apiaiRequest.end(); 88 | } 89 | else { 90 | console.log('Empty message'); 91 | return res.status(400).end('Empty message'); 92 | } 93 | } else { 94 | console.log('Empty message'); 95 | return res.status(400).end('Empty message'); 96 | } 97 | } 98 | 99 | static isDefined(obj) { 100 | if (typeof obj == 'undefined') { 101 | return false; 102 | } 103 | 104 | if (!obj) { 105 | return false; 106 | } 107 | 108 | return obj != null; 109 | } 110 | } -------------------------------------------------------------------------------- /samples/tropo/src/tropobotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class TropoBotConfig { 4 | 5 | get apiaiAccessToken() { 6 | return this._apiaiAccessToken; 7 | } 8 | 9 | set apiaiAccessToken(value) { 10 | this._apiaiAccessToken = value; 11 | } 12 | 13 | get apiaiLang() { 14 | return this._apiaiLang; 15 | } 16 | 17 | set apiaiLang(value) { 18 | this._apiaiLang = value; 19 | } 20 | 21 | get devConfig() { 22 | return this._devConfig; 23 | } 24 | 25 | set devConfig(value) { 26 | this._devConfig = value; 27 | } 28 | 29 | constructor(apiaiAccessToken, apiaiLang) { 30 | this._apiaiAccessToken = apiaiAccessToken; 31 | this._apiaiLang = apiaiLang; 32 | } 33 | 34 | toPlainDoc() { 35 | return { 36 | apiaiAccessToken: this._apiaiAccessToken, 37 | apiaiLang: this._apiaiLang 38 | } 39 | } 40 | 41 | static fromPlainDoc(doc){ 42 | return new TropoBotConfig( 43 | doc.apiaiAccessToken, 44 | doc.apiaiLang); 45 | } 46 | }; -------------------------------------------------------------------------------- /samples/tts_request.js: -------------------------------------------------------------------------------- 1 | /* Text to speech (TTS) is deprecated */ 2 | 3 | // 'use strict'; 4 | 5 | // // var apiai = require("../module/apiai"); 6 | // var fs = require("fs"); 7 | // var apiai = require("apiai"); 8 | 9 | // var app = apiai("YOUR_ACCESS_TOKEN"); 10 | 11 | 12 | // var file = fs.createWriteStream('hello-world-tts.wav'); 13 | 14 | // file.on('finish',function() { 15 | // console.log('wav file ready'); 16 | // }); 17 | 18 | // file.on('error', function(err) { 19 | // console.log(err); 20 | // }); 21 | 22 | // var tts_request_options = { 23 | // language: 'en-US', 24 | // writeStream: file 25 | // }; 26 | 27 | // var tts_request = app.ttsRequest('Hello world!', tts_request_options); 28 | 29 | // tts_request.end(); 30 | -------------------------------------------------------------------------------- /samples/twilio/bot/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/twilio/bot/README.md: -------------------------------------------------------------------------------- 1 | # apiai-twilio-bot 2 | -------------------------------------------------------------------------------- /samples/twilio/bot/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Twilio integration", 3 | "description": "Api.ai Twilio integration allows you to create Twilio bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-twilio-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "twilio", "natural language"], 7 | "env": { 8 | "APIAI_ACCESS_TOKEN": { 9 | "description": "Client access token for Api.ai", 10 | "value": "" 11 | }, 12 | "APIAI_LANG": { 13 | "description": "Agent language", 14 | "value": "en", 15 | "required": false 16 | } 17 | }, 18 | "engines": { 19 | "node": "5.10.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/twilio/bot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-twilio-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Twilio Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "^3.0.3", 14 | "body-parser": "^1.15.0", 15 | "console-stamp": "^0.2.1", 16 | "express": "^4.13.4", 17 | "node-uuid": "^1.4.7", 18 | "request": "^2.71.0", 19 | "xml-escape": "^1.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/twilio/bot/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | const bodyParser = require('body-parser'); 5 | 6 | const TwilioBot = require('./twiliobot'); 7 | const TwilioBotConfig = require('./twiliobotconfig'); 8 | 9 | const REST_PORT = (process.env.PORT || 5000); 10 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 11 | 12 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 13 | const APIAI_LANG = process.env.APIAI_LANG; 14 | 15 | // console timestamps 16 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 17 | 18 | const botConfig = new TwilioBotConfig(APIAI_ACCESS_TOKEN, APIAI_LANG); 19 | const bot = new TwilioBot(botConfig); 20 | 21 | const app = express(); 22 | 23 | app.use(bodyParser.urlencoded({extended: true})); 24 | 25 | app.post('/sms', (req, res) => { 26 | 27 | console.log('POST sms received'); 28 | 29 | try { 30 | bot.processMessage(req, res); 31 | } catch (err) { 32 | return res.status(400).send('Error while processing ' + err.message); 33 | } 34 | }); 35 | 36 | app.listen(REST_PORT, function () { 37 | console.log('Rest service ready on port ' + REST_PORT); 38 | }); -------------------------------------------------------------------------------- /samples/twilio/bot/src/twiliobot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const request = require('request'); 6 | const xmlescape = require('xml-escape'); 7 | 8 | module.exports = class TwilioBot { 9 | 10 | get apiaiService() { 11 | return this._apiaiService; 12 | } 13 | 14 | set apiaiService(value) { 15 | this._apiaiService = value; 16 | } 17 | 18 | get botConfig() { 19 | return this._botConfig; 20 | } 21 | 22 | set botConfig(value) { 23 | this._botConfig = value; 24 | } 25 | 26 | get sessionIds() { 27 | return this._sessionIds; 28 | } 29 | 30 | set sessionIds(value) { 31 | this._sessionIds = value; 32 | } 33 | 34 | constructor(botConfig) { 35 | this._botConfig = botConfig; 36 | var apiaiOptions = { 37 | language: botConfig.apiaiLang, 38 | requestSource: "twilio" 39 | }; 40 | 41 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 42 | this._sessionIds = new Map(); 43 | } 44 | 45 | processMessage(req, res) { 46 | if (this._botConfig.devConfig) { 47 | console.log("body", req.body); 48 | } 49 | 50 | if (req.body && req.body.From && req.body.Body) { 51 | let chatId = req.body.From; 52 | let messageText = req.body.Body; 53 | 54 | console.log(chatId, messageText); 55 | 56 | if (messageText) { 57 | if (!this._sessionIds.has(chatId)) { 58 | this._sessionIds.set(chatId, uuid.v4()); 59 | } 60 | 61 | let apiaiRequest = this._apiaiService.textRequest(messageText, 62 | { 63 | sessionId: this._sessionIds.get(chatId), 64 | originalRequest: { 65 | data: req.body, 66 | source: "twilio" 67 | } 68 | }); 69 | 70 | apiaiRequest.on('response', (response) => { 71 | if (TwilioBot.isDefined(response.result)) { 72 | let responseText = response.result.fulfillment.speech; 73 | 74 | if (TwilioBot.isDefined(responseText)) { 75 | console.log('Response as text message'); 76 | res.setHeader("Content-Type", "application/xml"); 77 | res.status(200).end("" + xmlescape(responseText) + ""); 78 | } else { 79 | console.log('Received empty speech'); 80 | } 81 | } else { 82 | console.log('Received empty result') 83 | } 84 | }); 85 | 86 | apiaiRequest.on('error', (error) => console.error(error)); 87 | apiaiRequest.end(); 88 | } 89 | else { 90 | console.log('Empty message'); 91 | return res.status(400).end('Empty message'); 92 | } 93 | } else { 94 | console.log('Empty message'); 95 | return res.status(400).end('Empty message'); 96 | } 97 | } 98 | 99 | static isDefined(obj) { 100 | if (typeof obj == 'undefined') { 101 | return false; 102 | } 103 | 104 | if (!obj) { 105 | return false; 106 | } 107 | 108 | return obj != null; 109 | } 110 | } -------------------------------------------------------------------------------- /samples/twilio/bot/src/twiliobotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class TwilioBotConfig { 4 | 5 | get apiaiAccessToken() { 6 | return this._apiaiAccessToken; 7 | } 8 | 9 | set apiaiAccessToken(value) { 10 | this._apiaiAccessToken = value; 11 | } 12 | 13 | get apiaiLang() { 14 | return this._apiaiLang; 15 | } 16 | 17 | set apiaiLang(value) { 18 | this._apiaiLang = value; 19 | } 20 | 21 | get devConfig() { 22 | return this._devConfig; 23 | } 24 | 25 | set devConfig(value) { 26 | this._devConfig = value; 27 | } 28 | 29 | constructor(apiaiAccessToken, apiaiLang) { 30 | this._apiaiAccessToken = apiaiAccessToken; 31 | this._apiaiLang = apiaiLang; 32 | } 33 | 34 | toPlainDoc() { 35 | return { 36 | apiaiAccessToken: this._apiaiAccessToken, 37 | apiaiLang: this._apiaiLang 38 | } 39 | } 40 | 41 | static fromPlainDoc(doc){ 42 | return new TwilioBotConfig( 43 | doc.apiaiAccessToken, 44 | doc.apiaiLang); 45 | } 46 | }; -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/README.md: -------------------------------------------------------------------------------- 1 | # apiai-twilio-ip-bot 2 | 3 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Twilio Ip", 3 | "description": "Api.ai Twilio Ip Messaging bot", 4 | "repository": "https://github.com/api-ai/twilio-ip-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": ["api.ai", "twilio", "natural language"], 7 | "env": { 8 | "APIAI_ACCESS_TOKEN": { 9 | "description": "Client access token for Api.ai", 10 | "value": "" 11 | }, 12 | "APIAI_LANG": { 13 | "description": "Agent language", 14 | "value": "en", 15 | "required": false 16 | }, 17 | "ACCOUNT_SID": { 18 | "description": "Account Sid", 19 | "value": "" 20 | }, 21 | "SERVICE_SID": { 22 | "description": "Service Sid", 23 | "value": "" 24 | }, 25 | "SIGNING_KEY_SID": { 26 | "description": "Signing key SID", 27 | "value": "" 28 | }, 29 | "SIGNING_KEY_SECRET": { 30 | "description": "Signing key Secret", 31 | "value": "" 32 | } 33 | }, 34 | "engines": { 35 | "node": "5.10.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-twilio-ip-bot", 3 | "version": "1.0.0", 4 | "description": "API.AI Twilio Ip Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "2.0.5", 14 | "body-parser": "^1.15.0", 15 | "console-stamp": "^0.2.1", 16 | "express": "^4.13.4", 17 | "node-uuid": "^1.4.7", 18 | "request": "^2.71.0", 19 | "twilio": "^2.9.1", 20 | "twilio-common": "^0.1.5", 21 | "twilio-ip-messaging": "^0.10.6" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | const TwilioBot = require('./twiliobot'); 6 | const TwilioBotConfig = require('./twiliobotconfig'); 7 | 8 | const REST_PORT = (process.env.PORT || 5000); 9 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 10 | 11 | const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN; 12 | const APIAI_LANG = process.env.APIAI_LANG; 13 | 14 | const ACCOUNT_SID = process.env.ACCOUNT_SID; 15 | const SERVICE_SID = process.env.SERVICE_SID; 16 | const SIGNING_KEY_SID = process.env.SIGNING_KEY_SID; 17 | const SIGNING_KEY_SECRET = process.env.SIGNING_KEY_SECRET; 18 | 19 | // console timestamps 20 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 21 | 22 | const botConfig = new TwilioBotConfig(APIAI_ACCESS_TOKEN, APIAI_LANG, ACCOUNT_SID, SERVICE_SID, SIGNING_KEY_SID, SIGNING_KEY_SECRET); 23 | const bot = new TwilioBot(botConfig); 24 | bot.start(); 25 | 26 | const app = express(); 27 | app.listen(REST_PORT, function () { 28 | console.log('Rest service ready on port ' + REST_PORT); 29 | }); -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/src/twiliobot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const request = require('request'); 6 | 7 | const TwilioIPMessaging = require('twilio-ip-messaging'); 8 | const TwilioCommon = require('twilio-common'); 9 | var AccessToken = require('twilio').AccessToken; 10 | var IpMessagingGrant = AccessToken.IpMessagingGrant; 11 | 12 | module.exports = class TwilioBot { 13 | 14 | get apiaiService() { 15 | return this._apiaiService; 16 | } 17 | 18 | set apiaiService(value) { 19 | this._apiaiService = value; 20 | } 21 | 22 | get botConfig() { 23 | return this._botConfig; 24 | } 25 | 26 | set botConfig(value) { 27 | this._botConfig = value; 28 | } 29 | 30 | get sessionIds() { 31 | return this._sessionIds; 32 | } 33 | 34 | set sessionIds(value) { 35 | this._sessionIds = value; 36 | } 37 | 38 | constructor(botConfig) { 39 | this._botConfig = botConfig; 40 | var apiaiOptions = { 41 | language: botConfig.apiaiLang, 42 | requestSource: "twilio-ip" 43 | }; 44 | 45 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 46 | this._sessionIds = new Map(); 47 | } 48 | 49 | start() { 50 | this.getToken() 51 | .then((token) => { 52 | this._accessManager = new TwilioCommon.AccessManager(token); 53 | this._client = TwilioIPMessaging(this._accessManager); 54 | 55 | this._client.on('messageAdded', (message) => this.processMessage(message)); 56 | 57 | return this._client.initialize(); 58 | }) 59 | .then(()=> { 60 | console.log("IP client initialized"); 61 | 62 | this.tryToJoin(); 63 | }) 64 | .catch((err) => { 65 | console.error(err); 66 | }); 67 | } 68 | 69 | getToken() { 70 | return new Promise((resolve, reject) => { 71 | var appName = this.botConfig.apiaiAccessToken; 72 | var deviceId = "server"; 73 | 74 | // Create a unique ID for the client on their current device 75 | var endpointId = "TwilioChat:" + this.botConfig.botIdentity + ":browser"; 76 | 77 | // Create a "grant" which enables a client to use IPM as a given user, 78 | // on a given device 79 | var ipmGrant = new IpMessagingGrant({ 80 | serviceSid: this.botConfig.serviceSid, 81 | endpointId: endpointId 82 | }); 83 | 84 | // Create an access token which we will sign and return to the client, 85 | // containing the grant we just created 86 | var token = new AccessToken( 87 | this.botConfig.accountSid, 88 | this.botConfig.signingKeySid, 89 | this.botConfig.signingKeySecret 90 | ); 91 | token.addGrant(ipmGrant); 92 | token.identity = this.botConfig.botIdentity; 93 | 94 | resolve(token.toJwt()); 95 | }); 96 | } 97 | 98 | processMessage(message) { 99 | console.log("message", message); 100 | 101 | if (message.body && message.channel && message.channel.sid) { 102 | let chatId = message.channel.sid; 103 | let messageText = message.body; 104 | let currentChannel = message.channel; 105 | 106 | if (message.author == this.botConfig.botIdentity) { 107 | // skip bot's messages 108 | return; 109 | } 110 | 111 | console.log(chatId, messageText); 112 | 113 | if (messageText) { 114 | if (!this._sessionIds.has(chatId)) { 115 | this._sessionIds.set(chatId, uuid.v1()); 116 | } 117 | 118 | let apiaiRequest = this._apiaiService.textRequest(messageText, 119 | { 120 | sessionId: this._sessionIds.get(chatId) 121 | }); 122 | 123 | apiaiRequest.on('response', (response) => { 124 | if (TwilioBot.isDefined(response.result)) { 125 | let responseText = response.result.fulfillment.speech; 126 | 127 | if (TwilioBot.isDefined(responseText)) { 128 | console.log('Response as text message'); 129 | 130 | currentChannel.sendMessage(responseText) 131 | .then(()=>{ 132 | console.log("Message sent"); 133 | }) 134 | .catch((err) =>{ 135 | console.log("Error while sending message", err); 136 | }); 137 | } else { 138 | console.log('Received empty speech'); 139 | } 140 | } else { 141 | console.log('Received empty result'); 142 | } 143 | }); 144 | 145 | apiaiRequest.on('error', (error) => console.error(error)); 146 | apiaiRequest.end(); 147 | } 148 | else { 149 | console.log('Empty message'); 150 | } 151 | } else { 152 | console.log('Empty message'); 153 | } 154 | } 155 | 156 | static isDefined(obj) { 157 | if (typeof obj == 'undefined') { 158 | return false; 159 | } 160 | 161 | if (!obj) { 162 | return false; 163 | } 164 | 165 | return obj != null; 166 | } 167 | 168 | tryToJoin() { 169 | this._client.getChannelByUniqueName('bot_channel') 170 | .then((channel)=> { 171 | if (!channel) { 172 | this._client.createChannel({ 173 | uniqueName: 'bot_channel', 174 | friendlyName: 'Channel for API.AI bot' 175 | }).then(function (createdChannel) { 176 | console.log("Created channel 'bot_channel'"); 177 | createdChannel.join().then(()=>{ 178 | createdChannel.sendMessage("Hello, I'm API.AI Bot."); 179 | }); 180 | }); 181 | } else { 182 | channel.join().then(()=>{ 183 | channel.sendMessage("Hello, I'm API.AI Bot."); 184 | }); 185 | } 186 | }) 187 | .catch((err) => { 188 | console.error(err); 189 | }) 190 | } 191 | } -------------------------------------------------------------------------------- /samples/twilio/ip-messaging/src/twiliobotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class TwilioBotConfig { 4 | 5 | get botIdentity() { 6 | return this._botIdentity; 7 | } 8 | 9 | set botIdentity(value) { 10 | this._botIdentity = value; 11 | } 12 | 13 | get apiaiAccessToken() { 14 | return this._apiaiAccessToken; 15 | } 16 | 17 | set apiaiAccessToken(value) { 18 | this._apiaiAccessToken = value; 19 | } 20 | 21 | get apiaiLang() { 22 | return this._apiaiLang; 23 | } 24 | 25 | set apiaiLang(value) { 26 | this._apiaiLang = value; 27 | } 28 | 29 | get accountSid() { 30 | return this._accountSid; 31 | } 32 | 33 | set accountSid(value) { 34 | this._accountSid = value; 35 | } 36 | 37 | get serviceSid() { 38 | return this._serviceSid; 39 | } 40 | 41 | set serviceSid(value) { 42 | this._serviceSid = value; 43 | } 44 | 45 | get signingKeySid() { 46 | return this._signingKeySid; 47 | } 48 | 49 | set signingKeySid(value) { 50 | this._signingKeySid = value; 51 | } 52 | 53 | get signingKeySecret() { 54 | return this._signingKeySecret; 55 | } 56 | 57 | set signingKeySecret(value) { 58 | this._signingKeySecret = value; 59 | } 60 | 61 | get devConfig() { 62 | return this._devConfig; 63 | } 64 | 65 | set devConfig(value) { 66 | this._devConfig = value; 67 | } 68 | 69 | constructor(apiaiAccessToken, apiaiLang, accountSid, serviceSid, signingKeySid, signingKeySecret) { 70 | this.botIdentity = "bot"; 71 | this._apiaiAccessToken = apiaiAccessToken; 72 | this._apiaiLang = apiaiLang; 73 | this._accountSid = accountSid; 74 | this._serviceSid = serviceSid; 75 | this._signingKeySid = signingKeySid; 76 | this._signingKeySecret = signingKeySecret; 77 | } 78 | }; -------------------------------------------------------------------------------- /samples/twitter/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log -------------------------------------------------------------------------------- /samples/twitter/README.md: -------------------------------------------------------------------------------- 1 | # apiai-twitter-bot 2 | 3 | [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) -------------------------------------------------------------------------------- /samples/twitter/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "API.AI Twitter integration", 3 | "description": "Api.ai Twitter integration allows you to create Twitter bots with natural language understanding based on Api.ai technology.", 4 | "repository": "https://github.com/api-ai/apiai-twitter-bot", 5 | "logo": "http://xvir.github.io/img/apiai.png", 6 | "keywords": [ 7 | "api.ai", 8 | "twitter", 9 | "natural language" 10 | ], 11 | "env": { 12 | "APIAI_ACCESS_TOKEN": { 13 | "description": "Client access token for Api.ai", 14 | "value": "" 15 | }, 16 | "APIAI_LANG": { 17 | "description": "Agent language", 18 | "value": "en", 19 | "required": false 20 | }, 21 | "BOT_NAME": { 22 | "description": "Username of your Twitter account", 23 | "value": "" 24 | }, 25 | "CONSUMER_KEY": { 26 | "description": "Consumer Key (API Key) from Application Settings", 27 | "value": "" 28 | }, 29 | "CONSUMER_SECRET": { 30 | "description": "Consumer Secret (API Secret) from Application Settings", 31 | "value": "" 32 | }, 33 | "ACCESS_TOKEN": { 34 | "description": "Access Token", 35 | "value": "" 36 | }, 37 | "ACCESS_TOKEN_SECRET": { 38 | "description": "Access Token Secret", 39 | "value": "" 40 | } 41 | }, 42 | "engines": { 43 | "node": "5.10.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/twitter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "apiai-twitter-bot", 3 | "version": "1.0.1", 4 | "description": "API.AI Twitter Bot", 5 | "main": "src/app.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Danil Skachkov (https://api.ai)", 11 | "license": "Apache-2.0", 12 | "dependencies": { 13 | "apiai": "^2.0.7", 14 | "body-parser": "^1.15.0", 15 | "console-stamp": "^0.2.1", 16 | "express": "^4.13.4", 17 | "node-uuid": "^1.4.7", 18 | "twit": "^2.2.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/twitter/src/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const express = require('express'); 4 | 5 | const TwitterBot = require('./twitterbot'); 6 | const TwitterBotConfig = require('./twitterbotconfig'); 7 | 8 | const REST_PORT = (process.env.PORT || 5000); 9 | const DEV_CONFIG = process.env.DEVELOPMENT_CONFIG == 'true'; 10 | 11 | // console timestamps 12 | require('console-stamp')(console, 'yyyy.mm.dd HH:MM:ss.l'); 13 | 14 | const botConfig = new TwitterBotConfig( 15 | process.env.APIAI_ACCESS_TOKEN, 16 | process.env.APIAI_LANG, 17 | process.env.BOT_NAME, 18 | process.env.CONSUMER_KEY, 19 | process.env.CONSUMER_SECRET, 20 | process.env.ACCESS_TOKEN, 21 | process.env.ACCESS_TOKEN_SECRET 22 | ); 23 | 24 | botConfig.devConfig = DEV_CONFIG; 25 | 26 | const bot = new TwitterBot(botConfig); 27 | bot.start(); 28 | 29 | const app = express(); 30 | app.listen(REST_PORT, function () { 31 | console.log('Rest service ready on port ' + REST_PORT); 32 | }); -------------------------------------------------------------------------------- /samples/twitter/src/twitterbot.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const apiai = require('apiai'); 4 | const uuid = require('node-uuid'); 5 | const Twit = require('twit'); 6 | 7 | module.exports = class TwitterBot { 8 | 9 | get apiaiService() { 10 | return this._apiaiService; 11 | } 12 | 13 | set apiaiService(value) { 14 | this._apiaiService = value; 15 | } 16 | 17 | get botConfig() { 18 | return this._botConfig; 19 | } 20 | 21 | set botConfig(value) { 22 | this._botConfig = value; 23 | } 24 | 25 | get sessionIds() { 26 | return this._sessionIds; 27 | } 28 | 29 | set sessionIds(value) { 30 | this._sessionIds = value; 31 | } 32 | 33 | constructor(botConfig) { 34 | this._botConfig = botConfig; 35 | var apiaiOptions = { 36 | language: botConfig.apiaiLang, 37 | requestSource: "twitter" 38 | }; 39 | 40 | this._apiaiService = apiai(botConfig.apiaiAccessToken, apiaiOptions); 41 | this._sessionIds = new Map(); 42 | 43 | this._botnameRegexp = new RegExp("(" + this.escapeRegExp("@" + this.botConfig.botName) + ")", "gi"); 44 | } 45 | 46 | start() { 47 | this._t = new Twit({ 48 | consumer_key: this.botConfig.consumerKey, 49 | consumer_secret: this.botConfig.consumerSecret, 50 | access_token: this.botConfig.accessToken, 51 | access_token_secret: this.botConfig.accessTokenSecret 52 | }); 53 | 54 | this._stream = this._t.stream('user'); 55 | 56 | this._stream.on('tweet', (tweet) => { 57 | console.log('tweet'); 58 | this.processMessage(tweet); 59 | }); 60 | 61 | this._stream.on('direct_message', (dm) => { 62 | console.log('direct_message'); 63 | this.processDirectMessage(dm); 64 | }); 65 | } 66 | 67 | stop() { 68 | this._stream.stop() 69 | } 70 | 71 | processMessage(tweet) { 72 | if (this._botConfig.devConfig) { 73 | console.log("body", tweet); 74 | } 75 | 76 | if (tweet.text && tweet.user) { 77 | let chatId = tweet.user.id_str; 78 | let messageText = tweet.text; 79 | let userName = tweet.user.screen_name; 80 | 81 | if (this.botConfig.botName.toLowerCase() == tweet.user.screen_name.toLowerCase()) { 82 | // bot received his own tweet 83 | return; 84 | } 85 | 86 | if (!tweet.entities.user_mentions || tweet.entities.user_mentions.length == 0) { 87 | return; 88 | } 89 | 90 | //we will check if tweet contains mention of the bot 91 | let mentions = tweet.entities.user_mentions; 92 | let bot_mention = mentions.find((mention) => { 93 | return mention.screen_name.toLowerCase() == this.botConfig.botName.toLowerCase(); 94 | }); 95 | 96 | if (!bot_mention) { 97 | return; 98 | } 99 | 100 | if (tweet.entities.urls.length > 0) { 101 | // don't respond to tweets containing links 102 | return; 103 | } 104 | 105 | if (tweet.retweeted_status) { 106 | // ignore retweets 107 | return; 108 | } 109 | 110 | // remove bot mention from message text 111 | messageText = messageText.replace(this._botnameRegexp, ""); 112 | 113 | console.log(chatId, messageText); 114 | 115 | if (messageText) { 116 | if (!this._sessionIds.has(chatId)) { 117 | this._sessionIds.set(chatId, uuid.v1()); 118 | } 119 | 120 | let apiaiRequest = this._apiaiService.textRequest(messageText, 121 | { 122 | sessionId: this._sessionIds.get(chatId) 123 | }); 124 | 125 | apiaiRequest.on('response', (response) => { 126 | if (TwitterBot.isDefined(response.result) 127 | && response.result.fulfillment 128 | && response.result.fulfillment.speech) { 129 | 130 | let responseText = "@" + userName + " " + response.result.fulfillment.speech; 131 | 132 | if (responseText.length > 140) { 133 | responseText = responseText.substr(0, 139) + "…"; 134 | } 135 | 136 | console.log('Response as text message'); 137 | this._t.post('statuses/update', {status: responseText, in_reply_to_status_id: tweet.id_str}, (err, data, response) => { 138 | if (err) { 139 | console.error('Response as tweet error', err); 140 | } else { 141 | console.log('Response as tweet succeeded'); 142 | } 143 | }); 144 | 145 | } else { 146 | console.log('Received empty result') 147 | } 148 | }); 149 | 150 | apiaiRequest.on('error', (error) => console.error(error)); 151 | apiaiRequest.end(); 152 | } 153 | else { 154 | console.log('Empty message'); 155 | 156 | } 157 | } else { 158 | console.log('Empty message'); 159 | 160 | } 161 | } 162 | 163 | processDirectMessage(dm) { 164 | let text = dm.direct_message.text; 165 | let sender = dm.direct_message.sender_id_str; 166 | let chatId = "dm_" + sender; 167 | let recipient = dm.direct_message.recipient_id_str; 168 | 169 | if (sender != recipient && text) { 170 | 171 | if (!this._sessionIds.has(chatId)) { 172 | this._sessionIds.set(chatId, uuid.v1()); 173 | } 174 | 175 | let apiaiRequest = this._apiaiService.textRequest(text, 176 | { 177 | sessionId: this._sessionIds.get(chatId) 178 | }); 179 | 180 | apiaiRequest.on('response', (response) => { 181 | if (TwitterBot.isDefined(response.result) 182 | && response.result.fulfillment 183 | && response.result.fulfillment.speech) { 184 | 185 | let responseText = response.result.fulfillment.speech; 186 | 187 | console.log('Response as text message'); 188 | this._t.post('direct_messages/new', { 189 | user_id: sender, 190 | text: responseText 191 | }, (err, data, response) => { 192 | if (err) { 193 | console.error('Response error', err); 194 | } else { 195 | console.log('Response as direct message succeeded'); 196 | } 197 | }); 198 | 199 | } else { 200 | console.log('Received empty result') 201 | } 202 | }); 203 | 204 | apiaiRequest.on('error', (error) => console.error(error)); 205 | apiaiRequest.end(); 206 | } 207 | } 208 | 209 | escapeRegExp(str) { 210 | return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 211 | } 212 | 213 | static isDefined(obj) { 214 | if (typeof obj == 'undefined') { 215 | return false; 216 | } 217 | 218 | if (!obj) { 219 | return false; 220 | } 221 | 222 | return obj != null; 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /samples/twitter/src/twitterbotconfig.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = class TwitterBotConfig { 4 | 5 | get botName() { 6 | return this._botName; 7 | } 8 | 9 | set botName(value) { 10 | this._botName = value; 11 | } 12 | 13 | get apiaiAccessToken() { 14 | return this._apiaiAccessToken; 15 | } 16 | 17 | set apiaiAccessToken(value) { 18 | this._apiaiAccessToken = value; 19 | } 20 | 21 | get apiaiLang() { 22 | return this._apiaiLang; 23 | } 24 | 25 | set apiaiLang(value) { 26 | this._apiaiLang = value; 27 | } 28 | 29 | get consumerKey() { 30 | return this._consumerKey; 31 | } 32 | 33 | set consumerKey(value) { 34 | this._consumerKey = value; 35 | } 36 | 37 | get consumerSecret() { 38 | return this._consumerSecret; 39 | } 40 | 41 | set consumerSecret(value) { 42 | this._consumerSecret = value; 43 | } 44 | 45 | get accessToken() { 46 | return this._accessToken; 47 | } 48 | 49 | set accessToken(value) { 50 | this._accessToken = value; 51 | } 52 | 53 | get accessTokenSecret() { 54 | return this._accessTokenSecret; 55 | } 56 | 57 | set accessTokenSecret(value) { 58 | this._accessTokenSecret = value; 59 | } 60 | 61 | get devConfig() { 62 | return this._devConfig; 63 | } 64 | 65 | set devConfig(value) { 66 | this._devConfig = value; 67 | } 68 | 69 | constructor(apiaiAccessToken, apiaiLang, botName, consumerKey, consumerSecret, accessToken, accessTokenSecret) { 70 | this.apiaiAccessToken = apiaiAccessToken; 71 | this.apiaiLang = apiaiLang; 72 | 73 | this.botName = botName; 74 | this.consumerKey = consumerKey; 75 | this.consumerSecret = consumerSecret; 76 | this.accessToken = accessToken; 77 | this.accessTokenSecret = accessTokenSecret; 78 | } 79 | }; -------------------------------------------------------------------------------- /samples/user_entities_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | // var apiai = require("../module/apiai"); 10 | var apiai = require("apiai"); 11 | 12 | var app = apiai("YOUR_ACCESS_TOKEN"); 13 | 14 | var sessionId = "Some unique sessionId"; 15 | 16 | var user_entities = [{ 17 | name: 'Application', 18 | extend: false, 19 | entries: [ 20 | { 21 | value: 'Firefox', 22 | synonyms: ['Firefox'] 23 | }, 24 | { 25 | value: 'XCode', 26 | synonyms: ['XCode'] 27 | }, 28 | { 29 | value: 'Sublime Text', 30 | synonyms: ['Sublime Text'] 31 | } 32 | ] 33 | }]; 34 | 35 | var user_entities_body = { 36 | sessionId: sessionId, 37 | entities: user_entities 38 | }; 39 | 40 | var user_entities_request = app.userEntitiesRequest(user_entities_body); 41 | 42 | user_entities_request.on('response', function(response) { 43 | console.log('User entities response: '); 44 | console.log(JSON.stringify(response, null, 4)); 45 | 46 | var request = app.textRequest('open XCode', {sessionId: sessionId}); 47 | 48 | request.on('response', function(response) { 49 | console.log('Query response: '); 50 | console.log(JSON.stringify(response, null, 4)); 51 | }); 52 | 53 | request.on('error', function(error) { 54 | console.log(error); 55 | }); 56 | 57 | request.end(); 58 | }); 59 | 60 | user_entities_request.on('error', function(error) { 61 | console.log(error); 62 | }); 63 | 64 | user_entities_request.end(); 65 | -------------------------------------------------------------------------------- /samples/voice_request.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * apiai 3 | * Copyright(c) 2015 http://api.ai/ 4 | * Apache 2.0 Licensed 5 | */ 6 | 7 | 'use strict'; 8 | 9 | var fs = require("fs"); 10 | 11 | // var apiai = require("../module/apiai"); 12 | var apiai = require("apiai"); 13 | 14 | var app = apiai("YOUR_ACCESS_TOKEN", { 15 | language: 'ru' 16 | }); 17 | 18 | var options = { 19 | sessionId: '' 20 | }; 21 | 22 | var request = app.voiceRequest(options); 23 | 24 | request.on('response', function(response) { 25 | console.log(response); 26 | }); 27 | 28 | request.on('error', function(error) { 29 | console.log(error); 30 | }); 31 | 32 | fs.readFile("rus_example.wav", function(error, buffer) { 33 | if (error) { 34 | console.log(error); 35 | } else { 36 | request.write(buffer); 37 | } 38 | 39 | request.end(); 40 | }); 41 | -------------------------------------------------------------------------------- /typescript_examples/text_request.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | "use strict"; 4 | 5 | import * as apiai from "../"; 6 | 7 | const app = apiai("YOUR_ACCESS_TOKEN"); 8 | 9 | let request = app.textRequest("Hello", {sessionId: "UNIQUE_SESSION_ID"}); 10 | 11 | request.on("response", function (response) { 12 | console.log("response: " + JSON.stringify(response, null, " ")); 13 | }); 14 | 15 | request.on("error", function(error) { 16 | console.log("error: " + error); 17 | }); 18 | 19 | request.end(); 20 | -------------------------------------------------------------------------------- /typescript_examples/tts_request.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // Text to speech (TTS) has been deprecated 5 | 6 | // "use strict"; 7 | 8 | // import * as apiai from "../"; 9 | // import * as fs from "fs"; 10 | 11 | // const app = apiai("YOUR_ACCESS_TOKEN"); 12 | 13 | // let file = fs.createWriteStream("hello-world-tts.wav"); 14 | 15 | // file.on("finish", function() { 16 | // console.log("wav file ready"); 17 | // }); 18 | 19 | // file.on("error", function(err) { 20 | // console.log(err); 21 | // }); 22 | 23 | // let request = app.ttsRequest("Hello world", {writeStream: file}); 24 | 25 | // request.end(); 26 | -------------------------------------------------------------------------------- /typescript_examples/user_entities_request.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | "use strict"; 4 | 5 | import * as apiai from "../"; 6 | 7 | const app = apiai("YOUR_ACCESS_TOKEN"); 8 | 9 | const sessionId = "UNIQUE_SESSION_ID"; 10 | 11 | let user_entities_request = app.userEntitiesRequest({ 12 | sessionId: sessionId, 13 | entities: [ 14 | { 15 | name: "Application", 16 | extend: false, 17 | entries: [ 18 | { 19 | value: "Firefox", 20 | synonyms: ["Firefox", "fox"] 21 | }, 22 | { 23 | value: "XCode", 24 | synonyms: ["XCode", "xcode"] 25 | } 26 | ] 27 | } 28 | ] 29 | }); 30 | 31 | user_entities_request.on("response", function (response) { 32 | let text_request = app.textRequest("Open XCode", {sessionId: sessionId}); 33 | 34 | text_request.on("response", function (response) { 35 | console.log("response: " + JSON.stringify(response, null, " ")); 36 | }); 37 | 38 | text_request.on("error", function (error) { 39 | console.log("error: " + JSON.stringify(error, null, " ")); 40 | }); 41 | 42 | text_request.end(); 43 | }); 44 | 45 | user_entities_request.on("error", function(error) { 46 | console.log("error: " + JSON.stringify(error, null, " ")); 47 | }); 48 | 49 | user_entities_request.end(); 50 | --------------------------------------------------------------------------------