UNPKG

40.2 kBMarkdownView Raw
1# **craft ai** isomorphic javascript client #
2
3[![Version](https://img.shields.io/npm/v/craft-ai.svg?style=flat-square)](https://npmjs.org/package/craft-ai) [![Build](https://img.shields.io/travis/craft-ai/craft-ai-client-js/master.svg?style=flat-square)](https://travis-ci.org/craft-ai/craft-ai-client-js) [![License](https://img.shields.io/badge/license-BSD--3--Clause-42358A.svg?style=flat-square)](LICENSE) [![Dependencies](https://img.shields.io/david/craft-ai/craft-ai-client-js.svg?style=flat-square)](https://david-dm.org/craft-ai/craft-ai-client-js) [![Dev Dependencies](https://img.shields.io/david/dev/craft-ai/craft-ai-client-js.svg?style=flat-square)](https://david-dm.org/craft-ai/craft-ai-client-js#info=devDependencies)
4
5[**craft ai**'s Explainable AI API](http://craft.ai) enables product & operational teams to quickly deploy and run explainable AIs. craft ai decodes your data streams to deliver self-learning services.
6
7## Get Started!
8
9### 0 - Signup
10
11If you're reading this you are probably already registered with **craft ai**, if not, head to [`https://beta.craft.ai/signup`](https://beta.craft.ai/signup).
12
13### 1 - Create a project
14
15Once your account is setup, let's create your first **project**! Go in the 'Projects' tab in the **craft ai** control center at [`https://beta.craft.ai/inspector`](https://beta.craft.ai/inspector), and press **Create a project**.
16
17Once it's done, you can click on your newly created project to retrieve its tokens. There are two types of tokens: **read** and **write**. You'll need the **write** token to create, update and delete your agent.
18
19### 2 - Setup
20
21#### Install ####
22
23##### [Node.js](https://nodejs.org/en/) / [Webpack](http://webpack.github.io) / [Browserify](http://browserify.org) #####
24
25Let's first install the package from npm.
26
27```sh
28npm install craft-ai --save
29```
30Then import it in your code
31
32```js
33const craftai = require('craft-ai').createClient;
34```
35
36or using [es2015](https://babeljs.io/docs/learn-es2015/) syntax
37
38```js
39import craftai from 'craft-ai';
40```
41
42##### Plain Old Javascript #####
43
44Thanks to [npmcdn](https://npmcdn.com), you can include the pre-generated bundle in your html file, for the latest version use
45
46```html
47<script type="text/javascript" src="https://npmcdn.com/craft-ai/dist/craft-ai.min.js"></script>
48```
49
50to include a specific version specify it in the url like
51
52```html
53<script type="text/javascript" src="https://npmcdn.com/craft-ai@0.1.13/dist/craft-ai.min.js"></script>
54```
55
56#### Initialize ####
57
58```js
59// The token you retrieved for a given project
60const client = craftai('{token}');
61```
62
63### 3 - Create an agent
64
65**craft ai** is based on the concept of **agents**. In most use cases, one agent is created per user or per device.
66
67An agent is an independent module that stores the history of the **context** of its user or device's context, and learns which **decision** to take based on the evolution of this context in the form of a **decision tree**.
68
69In this example, we will create an agent that learns the **decision model** of a light bulb based on the time of the day and the number of people in the room. In practice, it means the agent's context have 4 properties:
70
71- `peopleCount` which is a `continuous` property,
72- `timeOfDay` which is a `time_of_day` property,
73- `timezone`, a property of type `timezone` needed to generate proper values for `timeOfDay` (cf. the [context properties type section](#context-properties-types) for further information),
74- and finally `lightbulbState` which is an `enum` property that is also the output.
75
76> :information_source: `timeOfDay` is auto-generated, you will find more information below.
77
78```js
79const AGENT_ID = 'my_first_agent';
80
81client.createAgent(
82 {
83 context: {
84 peopleCount: {
85 type: 'continuous'
86 },
87 timeOfDay: {
88 type: 'time_of_day'
89 },
90 timezone: {
91 type: 'timezone'
92 },
93 lightbulbState: {
94 type: 'enum'
95 }
96 },
97 output: [ 'lightbulbState' ]
98 },
99 AGENT_ID
100)
101.then(function(agent) {
102 console.log('Agent ' + agent.id + ' successfully created!');
103})
104.catch(function(error) {
105 console.error('Error!', error);
106});
107```
108
109Pretty straightforward to test! Open [`https://beta.craft.ai/inspector`](https://beta.craft.ai/inspector), select you project and your agent is now listed.
110
111Now, if you run that a second time, you'll get an error: the agent `'my_first_agent'` is already existing. Let's see how we can delete it before recreating it.
112
113```js
114const AGENT_ID = 'my_first_agent';
115
116client.deleteAgent(AGENT_ID)
117.then(function() {
118 console.log('Agent ' + AGENT_ID + ' no longer exists.');
119 return client.createAgent(/*...*/);
120})
121.then(function(agent) {
122 console.log('Agent ' + agent.id + ' successfully created!');
123})
124.catch(function(error) {
125 console.error('Error!', error);
126});
127```
128
129_For further information, check the ['create agent' reference documentation](#create)._
130
131### 4 - Add context operations
132
133We have now created our first agent but it is not able to do much, yet. To learn a decision model it needs to be provided with data, in **craft ai** these are called context operations.
134
135Please note that only value changes are sent, thus if an operation doesn't contain a value, the previous known value is used.
136
137In the following we add 8 operations:
138
1391. The initial one sets the initial state of the agent, on July 25 2016 at 5:30, in Paris, nobody is there and the light is off;
1402. At 7:02, someone enters the room the light is turned on;
1413. At 7:15, someone else enters the room;
1424. At 7:31, the light is turned off;
1435. At 8:12, everyone leaves the room;
1446. At 19:23, 2 persons enter the room;
1457. At 22:35, the light is turned on;
1468. At 23:06, everyone leaves the room and the light is turned off.
147
148
149```js
150const AGENT_ID = 'my_first_agent';
151
152// for the purpose of this test, we delete and recreate the agent
153client.deleteAgent(AGENT_ID)
154.then(function() {
155 console.log('Agent ' + AGENT_ID + ' no longer exists.');
156 return client.createAgent(/*...*/);
157})
158.then(function(agent) {
159 console.log('Agent ' + agent.id + ' successfully created!');
160 return client.addAgentContextOperations(
161 AGENT_ID,
162 [
163 {
164 timestamp: 1469410200,
165 context: {
166 timezone: '+02:00',
167 peopleCount: 0,
168 lightbulbState: 'OFF'
169 }
170 },
171 {
172 timestamp: 1469415720,
173 context: {
174 peopleCount: 1,
175 lightbulbState: 'ON'
176 }
177 },
178 {
179 timestamp: 1469416500,
180 context: {
181 peopleCount: 2
182 }
183 },
184 {
185 timestamp: 1469417460,
186 context: {
187 lightbulbState: 'OFF'
188 }
189 },
190 {
191 timestamp: 1469419920,
192 context: {
193 peopleCount: 0
194 }
195 },
196 {
197 timestamp: 1469460180,
198 context: {
199 peopleCount: 2
200 }
201 },
202 {
203 timestamp: 1469471700,
204 context: {
205 lightbulbState: 'ON'
206 }
207 },
208 {
209 timestamp: 1469473560,
210 context: {
211 peopleCount: 0,
212 lightbulbState: 'OFF'
213 }
214 }
215 ]
216 )
217 .then(function() {
218 return agent;
219 });
220})
221.then(function(agent) {
222 console.log('Successfully added initial operations to agent ' + agent.id + '.');
223})
224.catch(function(error) {
225 console.error('Error!', error);
226});
227```
228
229In real-world applications, you'll probably do the same kind of things when the agent is created and then, regularly throughout the lifetime of the agent with newer data.
230
231_For further information, check the ['add context operations' reference documentation](#add-operations)._
232
233### 5 - Compute the decision tree
234
235The agent has acquired a context history, we can now compute a decision tree from it! A decision tree models the output, allowing us to estimate what the output would be in a given context.
236
237The decision tree is computed at a given timestamp, which means it will consider the context history from the creation of this agent up to this moment. Let's first try to compute the decision tree at midnight on July 26, 2016.
238
239```js
240const AGENT_ID = 'my_first_agent';
241
242// for the purpose of this test, we delete and recreate the agent
243client.deleteAgent(AGENT_ID)
244.then(function() {
245 console.log('Agent ' + AGENT_ID + ' no longer exists.');
246 return client.createAgent(/*...*/);
247})
248.then(function(agent) {
249 console.log('Agent ' + agent.id + ' successfully created!');
250 return client.addAgentContextOperations(AGENT_ID, /*...*/)
251 .then(function() {
252 return agent;
253 });
254})
255.then(function(agent) {
256 console.log('Successfully added initial operations to agent ' + agent.id + '.');
257 return client.getAgentDecisionTree(AGENT_ID, 1469476800);
258})
259.then(function(tree) {
260 console.log('Decision tree retrieved!', tree);
261})
262.catch(function(error) {
263 console.error('Error!', error);
264});
265```
266
267Try to retrieve the tree at different timestamps to see how it gradually learns from the new operations. To visualize the trees, use the [inspector](https://beta.craft.ai/inspector)!
268
269_For further information, check the ['compute decision tree' reference documentation](#compute)._
270
271### 6 - Take a decision
272
273Once the decision tree is computed it can be used to take a decision. In our case it is basically answering this type of question: "What is the anticipated **state of the lightbulb** at 7:15 if there are 2 persons in the room ?".
274
275```js
276const AGENT_ID = 'my_first_agent';
277
278// for the purpose of this test, we delete and recreate the agent
279client.deleteAgent(AGENT_ID)
280.then(function() {
281 console.log('Agent ' + AGENT_ID + ' no longer exists.');
282 return client.createAgent(/*...*/);
283})
284.then(function(agent) {
285 console.log('Agent ' + agent.id + ' successfully created!');
286 return client.addAgentContextOperations(AGENT_ID, /*...*/)
287 .then(function() {
288 return agent;
289 });
290})
291.then(function(agent) {
292 console.log('Successfully added initial operations to agent ' + agent.id + '.');
293 return client.getAgentDecisionTree(AGENT_ID, 1469476800);
294})
295.then(function(tree) {
296 console.log('Decision tree retrieved!', tree);
297 const res = craftai.interpreter.decide(tree, {
298 timezone: '+02:00',
299 timeOfDay: 7.25,
300 peopleCount: 2
301 });
302 console.log('The anticipated lightbulb state is "' + res.output.lightbulbState.predicted_value + '".');
303})
304.catch(function(error) {
305 console.error('Error!', error);
306});
307```
308
309_For further information, check the ['take decision' reference documentation](#take-decision)._
310
311### Node.JS starter kit ###
312
313If you prefer to get started from an existing code base, the official Node.JS starter kit can get you there! Retrieve the sources locally and follow the "readme" to get a fully working **SmartHome** app using _real-world_ data.
314
315> [:package: _Get the **craft ai** Node.JS Starter Kit_](https://github.com/craft-ai/craft-ai-starterkit-nodejs)
316
317## API
318
319### Project
320
321**craft ai** agents belong to **projects**. In the current version, each identified users defines a owner and can create projects for themselves, in the future we will introduce shared projects.
322
323### Configuration
324
325Each agent has a configuration defining:
326
327- the context schema, i.e. the list of property keys and their type (as defined in the following section),
328- the output properties, i.e. the list of property keys on which the agent takes decisions,
329
330> :warning: In the current version, only one output property can be provided.
331
332- the `time_quantum`, i.e. the minimum amount of time, in seconds, that is meaningful for an agent; context updates occurring faster than this quantum won't be taken into account. As a rule of thumb, you should always choose the largest value that seems right and reduce it, if necessary, after some tests.
333- the `learning_period`, i.e. the maximum amount of time, in seconds, that matters for an agent; the agent's decision model can ignore context that is older than this duration. You should generally choose the smallest value that fits this description.
334
335> :warning: if no time_quantum is specified, the default value is 600.
336
337> :warning: if no learning_period is specified, the default value is 15000 time quantums.
338
339> :warning: the maximum learning_period value is 55000 \* time_quantum.
340
341#### Context properties types
342
343##### Base types: `enum` and `continuous`
344
345`enum` and `continuous` are the two base **craft ai** types:
346
347- an `enum` property is a string;
348- a `continuous` property is a real number.
349
350> :warning: the absolute value of a `continuous` property must be less than 10<sup>20</sup>.
351
352##### Time types: `timezone`, `time_of_day`, `day_of_week`, `day_of_month` and `month_of_year`
353
354**craft ai** defines the following types related to time:
355
356- a `time_of_day` property is a real number belonging to **[0.0; 24.0[**, each value represents the number of hours in the day since midnight (e.g. 13.5 means 13:30),
357- a `day_of_week` property is an integer belonging to **[0, 6]**, each value represents a day of the week starting from Monday (0 is Monday, 6 is Sunday).
358- a `day_of_month` property is an integer belonging to **[1, 31]**, each value represents a day of the month.
359- a `month_of_year` property is an integer belonging to **[1, 12]**, each value represents a month of the year.
360- a `timezone` property can be:
361 * a string value representing the timezone as an offset from UTC, supported formats are:
362
363 - **±[hh]:[mm]**,
364 - **±[hh][mm]**,
365 - **±[hh]**,
366
367 where `hh` represent the hour and `mm` the minutes from UTC (eg. `+01:30`)), between `-12:00` and
368 `+14:00`.
369
370 * an integer belonging to **[-720, 840]** which represents the timezone as an offset from UTC:
371
372 - in hours if the integer belongs to **[-15, 15]**
373 - in minutes otherwise
374
375 * an abbreviation among the following:
376
377 - **UTC** or **Z** Universal Time Coordinated,
378 - **GMT** Greenwich Mean Time, as UTC,
379 - **BST** British Summer Time, as UTC+1 hour,
380 - **IST** Irish Summer Time, as UTC+1,
381 - **WET** Western Europe Time, as UTC,
382 - **WEST** Western Europe Summer Time, as UTC+1,
383 - **CET** Central Europe Time, as UTC+1,
384 - **CEST** Central Europe Summer Time, as UTC+2,
385 - **EET** Eastern Europe Time, as UTC+2,
386 - **EEST** Eastern Europe Summer Time, as UTC+3,
387 - **MSK** Moscow Time, as UTC+3,
388 - **MSD** Moscow Summer Time, as UTC+4,
389 - **AST** Atlantic Standard Time, as UTC-4,
390 - **ADT** Atlantic Daylight Time, as UTC-3,
391 - **EST** Eastern Standard Time, as UTC-5,
392 - **EDT** Eastern Daylight Saving Time, as UTC-4,
393 - **CST** Central Standard Time, as UTC-6,
394 - **CDT** Central Daylight Saving Time, as UTC-5,
395 - **MST** Mountain Standard Time, as UTC-7,
396 - **MDT** Mountain Daylight Saving Time, as UTC-6,
397 - **PST** Pacific Standard Time, as UTC-8,
398 - **PDT** Pacific Daylight Saving Time, as UTC-7,
399 - **HST** Hawaiian Standard Time, as UTC-10,
400 - **AKST** Alaska Standard Time, as UTC-9,
401 - **AKDT** Alaska Standard Daylight Saving Time, as UTC-8,
402 - **AEST** Australian Eastern Standard Time, as UTC+10,
403 - **AEDT** Australian Eastern Daylight Time, as UTC+11,
404 - **ACST** Australian Central Standard Time, as UTC+9.5,
405 - **ACDT** Australian Central Daylight Time, as UTC+10.5,
406 - **AWST** Australian Western Standard Time, as UTC+8.
407
408> :information_source: By default, the values of the `time_of_day` and `day_of_week`
409> properties are generated from the [`timestamp`](#timestamp) of an agent's
410> state and the agent's current `timezone`. Therefore, whenever you use generated
411> `time_of_day` and/or `day_of_week` in your configuration, you **must** provide a
412> `timezone` value in the context. There can only be one `timezone` property.
413>
414> If you wish to provide their values manually, add `is_generated: false` to the
415> time types properties in your configuration. In this case, since you provide the values, the
416> `timezone` property is not required, and you must update the context whenever
417> one of these time values changes in a way that is significant for your system.
418
419##### Examples
420
421Let's take a look at the following configuration. It is designed to model the **color**
422of a lightbulb (the `lightbulbColor` property, defined as an output) depending
423on the **outside light intensity** (the `lightIntensity` property), the **time
424of the day** (the `time` property) and the **day of the week** (the `day`
425property).
426
427`day` and `time` values will be generated automatically, hence the need for
428`timezone`, the current Time Zone, to compute their value from given
429[`timestamps`](#timestamp).
430
431The `time_quantum` is set to 100 seconds, which means that if the lightbulb
432color is changed from red to blue then from blue to purple in less that 1
433minutes and 40 seconds, only the change from red to purple will be taken into
434account.
435
436The `learning_period` is set to 108 000 seconds (one month) , which means that
437the state of the lightbulb from more than a month ago can be ignored when learning
438the decision model.
439
440```json
441{
442 "context": {
443 "lightIntensity": {
444 "type": "continuous"
445 },
446 "time": {
447 "type": "time_of_day"
448 },
449 "day": {
450 "type": "day_of_week"
451 },
452 "timezone": {
453 "type": "timezone"
454 },
455 "lightbulbColor": {
456 "type": "enum"
457 }
458 },
459 "output": ["lightbulbColor"],
460 "time_quantum": 100,
461 "learning_period": 108000
462}
463```
464
465In this second example, the `time` property is not generated, no property of
466type `timezone` is therefore needed. However values of `time` must be manually
467provided continuously.
468
469```json
470{
471 "context": {
472 "time": {
473 "type": "time_of_day",
474 "is_generated": false
475 },
476 "lightIntensity": {
477 "type": "continuous"
478 },
479 "lightbulbColor": {
480 "type": "enum"
481 }
482 },
483 "output": ["lightbulbColor"],
484 "time_quantum": 100,
485 "learning_period": 108000
486}
487```
488
489### Timestamp
490
491**craft ai** API heavily relies on `timestamps`. A `timestamp` is an instant represented as a [Unix time](https://en.wikipedia.org/wiki/Unix_time), that is to say the amount of seconds elapsed since Thursday, 1 January 1970 at midnight UTC. In most programming languages this representation is easy to retrieve, you can refer to [**this page**](https://github.com/techgaun/unix-time/blob/master/README.md) to find out how.
492
493#### `craftai.Time` ####
494
495The `craftai.Time` class facilitates the handling of time types in **craft ai**. It is able to extract the different **craft ai** formats from various _datetime_ representations, thanks to [Moment.js](http://momentjs.com).
496
497From a unix timestamp and an explicit UTC offset:
498
499```js
500const t1 = new craftai.Time(1465496929, '+10:00');
501
502// t1 === {
503// utc: '2016-06-09T18:28:49.000Z',
504// timestamp: 1465496929,
505// day_of_week: 4,
506// day_of_month: 10,
507// month_of_year: 6,
508// time_of_day: 4.480277777777778,
509// timezone: '+10:00'
510// }
511```
512
513From a unix timestamp and using the local UTC offset:
514
515```js
516const t2 = new craftai.Time(1465496929);
517
518// Value are valid if in Paris !
519// t2 === {
520// utc: '2016-06-09T18:28:49.000Z',
521// timestamp: 1465496929,
522// day_of_week: 3,
523// day_of_month: 9,
524// month_of_year: 6,
525// time_of_day: 20.480277777777776,
526// timezone: '+02:00'
527// }
528```
529
530From a [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string:
531
532```js
533const t3 = new craftai.Time('1977-04-22T01:00:00-05:00');
534
535// t3 === {
536// utc: '1977-04-22T06:00:00.000Z',
537// timestamp: 230536800,
538// day_of_week: 4,
539// time_of_day: 1,
540// day_of_month: 22,
541// month_of_year: 4,
542// timezone: '-05:00'
543// }
544```
545
546From a [moment](http://momentjs.com) (or [moment timezone](http://momentjs.com/timezone/)) instance:
547
548```js
549const t4 = new craftai.Time(moment.tz('2017-05-31 12:45:00', 'Asia/Dubai'), '-08:00'));
550
551// t4 === {
552// utc: '2017-05-31T08:45:00.000Z',
553// timestamp: 1496220300,
554// day_of_week: 2,
555// day_of_month: 31,
556// month_of_year: 5,
557// time_of_day: 0.75,
558// timezone: '-08:00'
559// }
560```
561
562Retrieve the current time with the local UTC offset:
563
564```js
565const now = new craftai.Time();
566```
567
568Retrieve the current time with a given UTC offset:
569
570```js
571const nowP5 = new craftai.Time(undefined, '+05:00');
572```
573
574### Advanced configuration
575
576The following **advanced** configuration parameters can be set in specific cases. They are **optional**. Usually you would not need them.
577
578- **`operations_as_events`** is a boolean, either `true` or `false`. The default value is `false`. If it is set to true, all context operations are treated as events, as opposed to context updates. This is appropriate if the data for an agent is made of events that have no duration, and if many events are more significant than a few. If `operations_as_events` is `true`, `learning_period` and the advanced parameter `tree_max_operations` must be set as well. In that case, `time_quantum` is ignored because events have no duration, as opposed to the evolution of an agent's context over time.
579- **`tree_max_operations`** is a positive integer. It **can and must** be set only if `operations_as_events` is `true`. It defines the maximum number of events on which a single decision tree can be based. It is complementary to `learning_period`, which limits the maximum age of events on which a decision tree is based.
580- **`tree_max_depth`** is a positive integer. It defines the maximum depth of decision trees, which is the maximum distance between the root node and a leaf (terminal) node. A depth of 0 means that the tree is made of a single root node. By default, `tree_max_depth` is set to 6 if the output is categorical (e.g. `enum`), or to 4 if the output is numerical (e.g. `continuous`).
581
582These advanced configuration parameters are optional, and will appear in the agent information returned by **craft ai** only if you set them to something other than their default value. If you intend to use them in a production environment, please get in touch with us.
583
584### Agent
585
586#### Create
587
588Create a new agent, and create its [configuration](#configuration).
589
590> The agent's identifier is a case sensitive string between 1 and 36 characters long. It only accepts letters, digits, hyphen-minuses and underscores (i.e. the regular expression `/[a-zA-Z0-9_-]{1,36}/`).
591
592```js
593client.createAgent(
594 { // The configuration
595 context: {
596 peopleCount: {
597 type: 'continuous'
598 },
599 timeOfDay: {
600 type: 'time_of_day'
601 },
602 timezone: {
603 type: 'timezone'
604 },
605 lightbulbState: {
606 type: 'enum'
607 }
608 },
609 output: [ 'lightbulbState' ],
610 time_quantum: 100,
611 learning_period: 108000
612 },
613 'impervious_kraken' // id for the agent, if undefined a random id is generated
614)
615.then(function(agent) {
616 // Work on the agent here
617 // agent = {
618 // "_version": <version>
619 // "id": <agent_id>,
620 // "configuration": {
621 // "context": {
622 // "peopleCount": {
623 // "type": "continuous"
624 // },
625 // "timeOfDay": {
626 // "type": "time_of_day"
627 // },
628 // "timezone": {
629 // "type": "timezone"
630 // },
631 // "lightbulbState": {
632 // "type": "enum"
633 // }
634 // },
635 // "output": [ "lightbulbState" ],
636 // "time_quantum": 100,
637 // "learning_period": 108000
638 // }
639 // }
640})
641.catch(function(error) {
642 // Catch errors here
643})
644```
645
646#### Delete
647
648```js
649client.deleteAgent(
650 'impervious_kraken' // The agent id
651)
652.then(function() {
653 // The agent was successfully deleted
654})
655.catch(function(error) {
656 // Catch errors here
657})
658```
659
660#### Retrieve
661
662```js
663client.getAgent(
664 'impervious_kraken' // The agent id
665)
666.then(function(agent) {
667 // Agent details
668})
669.catch(function(error) {
670 // Catch errors here
671})
672```
673
674#### List
675
676```js
677client.listAgents()
678.then(function(agentIds) {
679 // list of agent ids, eg. ['impervious_kraken', 'impervious_kraken']
680})
681.catch(function(error) {
682 // Catch errors here
683})
684```
685
686#### Create and retrieve shared url
687
688Create and get a shareable url to view an agent tree.
689Only one url can be created at a time.
690
691```js
692client.getSharedAgentInspectorUrl(
693 'impervious_kraken', // The agent id.
694 1464600256 // optional, the timestamp for which you want to inspect the tree.
695)
696.then(function(url) {
697 // Url to the agent's inspector
698})
699.catch(function(error) {
700 // Catch errors here
701})
702```
703
704#### Delete shared url
705
706Delete a shareable url.
707The previous url cannot access the agent tree anymore.
708
709```js
710client.deleteSharedAgentInspectorUrl(
711 'impervious_kraken' // The agent id.
712)
713.then(function() {
714 // return nothing
715})
716.catch(function(error) {
717 // Catch errors here
718})
719```
720
721
722
723### Context
724
725#### Add operations
726
727```js
728client.addAgentContextOperations(
729 'impervious_kraken', // The agent id
730 [ // The list of operations
731 {
732 timestamp: 1469410200, // Operation timestamp
733 context: {
734 timezone: '+02:00',
735 peopleCount: 0,
736 lightbulbState: 'OFF'
737 }
738 },
739 {
740 timestamp: 1469415720,
741 context: {
742 peopleCount: 1,
743 lightbulbState: 'ON'
744 }
745 },
746 {
747 timestamp: 1469416500,
748 context: {
749 peopleCount: 2
750 }
751 },
752 {
753 timestamp: 1469417460,
754 context: {
755 lightbulbState: 'OFF'
756 }
757 },
758 {
759 timestamp: 1469419920,
760 context: {
761 peopleCount: 0
762 }
763 },
764 {
765 timestamp: 1469460180,
766 context: {
767 peopleCount: 2
768 }
769 },
770 {
771 timestamp: 1469471700,
772 context: {
773 lightbulbState: 'ON'
774 }
775 },
776 {
777 timestamp: 1469473560,
778 context: {
779 peopleCount: 0
780 }
781 }
782 ]
783)
784.then(function() {
785 // The operations where successfully added to agent context on the server side
786})
787.catch(function(error) {
788 // Catch errors here
789})
790```
791
792#### List operations
793
794```js
795client.getAgentContextOperations(
796 'impervious_kraken', // The agent id
797 1478894153, // Optional, the **start** timestamp from which the
798 // operations are retrieved (inclusive bound)
799 1478895266, // Optional, the **end** timestamp up to which the
800 /// operations are retrieved (inclusive bound)
801)
802.then(function(operations) {
803 // Work on operations
804})
805.catch(function(error) {
806 // Catch errors here
807})
808```
809
810> This call can generate multiple requests to the craft ai API as results are paginated.
811
812#### Retrieve state
813
814```js
815client.getAgentContext(
816 'impervious_kraken', // The agent id
817 1469473600 // The timestamp at which the context state is retrieved
818)
819.then(function(context) {
820 // Work on context
821})
822.catch(function(error) {
823 // Catch errors here
824})
825```
826
827#### Retrieve state history
828
829```js
830client.getAgentStateHistory(
831 'impervious_kraken', // The agent id
832 1478894153, // Optional, the **start** timestamp from which the
833 // operations are retrieved (inclusive bound)
834 1478895266, // Optional, the **end** timestamp up to which the
835 /// operations are retrieved (inclusive bound)
836)
837.then(function(stateHistory) {
838 // Work on states history
839})
840.catch(function(error) {
841 // Catch errors here
842})
843```
844
845### Decision tree
846
847Decision trees are computed at specific timestamps, directly by **craft ai** which learns from the context operations [added](#add-operations) throughout time.
848
849When you [compute](#compute) a decision tree, **craft ai** returns an object containing:
850
851- the **API version**
852- the agent's configuration as specified during the agent's [creation](#create-agent)
853- the tree itself as a JSON object:
854
855 - Internal nodes are represented by a `"decision_rule"` object and a `"children"` array. The first one, contains the `"property`, and the `"property"`'s value, to decide which child matches a context.
856 - Leaves have a `"predicted_value"`, `"confidence"` and `"decision_rule"` object for this value, instead of a `"children"` array. `"predicted_value`" is an estimation of the output in the contexts matching the node. `"confidence"` is a number between 0 and 1 that indicates how confident **craft ai** is that the output is a reliable prediction. When the output is a numerical type, leaves also have a `"standard_deviation"` that indicates a margin of error around the `"predicted_value"`.
857 - The root only contains a `"children"` array.
858
859#### Compute
860
861```js
862client.getAgentDecisionTree(
863 'impervious_kraken', // The agent id
864 1469473600 // The timestamp at which the decision tree is retrieved
865)
866.then(function(tree) {
867 // Works with the given tree
868 console.log(tree);
869 /* Outputted tree is the following
870 {
871 "_version": "1.1.0",
872 "trees": {
873 "lightbulbState": {
874 "children": [
875 {
876 "children": [
877 {
878 "confidence": 0.6774609088897705,
879 "decision_rule": {
880 "operand": 0.5,
881 "operator": "<",
882 "property": "peopleCount"
883 },
884 "predicted_value": "OFF"
885 },
886 {
887 "confidence": 0.8630361557006836,
888 "decision_rule": {
889 "operand": 0.5,
890 "operator": ">=",
891 "property": "peopleCount"
892 },
893 "predicted_value": "ON"
894 }
895 ],
896 "decision_rule": {
897 "operand": [
898 5,
899 5.6666665
900 ],
901 "operator": "[in[",
902 "property": "timeOfDay"
903 }
904 },
905 {
906 "children": [
907 {
908 "confidence": 0.9947378635406494,
909 "decision_rule": {
910 "operand": [
911 5.6666665,
912 20.666666
913 ],
914 "operator": "[in[",
915 "property": "timeOfDay"
916 },
917 "predicted_value": "OFF"
918 },
919 {
920 "children": [
921 {
922 "confidence": 0.969236433506012,
923 "decision_rule": {
924 "operand": 1,
925 "operator": "<",
926 "property": "peopleCount"
927 },
928 "predicted_value": "OFF"
929 },
930 {
931 "confidence": 0.8630361557006836,
932 "decision_rule": {
933 "operand": 1,
934 "operator": ">=",
935 "property": "peopleCount"
936 },
937 "predicted_value": "ON"
938 }
939 ],
940 "decision_rule": {
941 "operand": [
942 20.666666,
943 5
944 ],
945 "operator": "[in[",
946 "property": "timeOfDay"
947 }
948 }
949 ],
950 "decision_rule": {
951 "operand": [
952 5.6666665,
953 5
954 ],
955 "operator": "[in[",
956 "property": "timeOfDay"
957 }
958 }
959 ]
960 }
961 },
962 "configuration": {
963 "time_quantum": 600,
964 "learning_period": 9000000,
965 "context": {
966 "peopleCount": {
967 "type": "continuous"
968 },
969 "timeOfDay": {
970 "type": "time_of_day",
971 "is_generated": true
972 },
973 "timezone": {
974 "type": "timezone"
975 },
976 "lightbulbState": {
977 "type": "enum"
978 }
979 },
980 "output": [
981 "lightbulbState"
982 ]
983 }
984 }
985 */
986})
987.catch(function(error) {
988 if (error instanceof craftai.errors.CraftAiLongRequestTimeOutError) {
989    // Handle timeout errors here
990  }
991 else {
992 // Handle other errors here
993 }
994})
995```
996
997#### Take decision
998
999> :information_source: To take a decision, first compute the decision tree then use the **offline interpreter**.
1000
1001### Advanced client configuration ###
1002
1003The simple configuration to create the `client` is just the token. For special needs, additional advanced configuration can be provided.
1004
1005#### Amount of operations sent in one chunk ####
1006
1007`client.addAgentContextOperations` splits the provided operations into chunks in order to limit the size of the http requests to the craft ai API. In the client configuration, `operationsChunksSize` can be increased in order to limit the number of request, or decreased when large http requests cause errors.
1008
1009```js
1010const client = craftai({
1011 // Mandatory, the token
1012 token: '{token}',
1013 // Optional, default value is 500
1014 operationsChunksSize: {max_number_of_operations_sent_at_once}
1015});
1016```
1017
1018#### Timeout duration for decision trees retrieval ####
1019
1020It is possible to increase or decrease the timeout duration of `client.getAgentDecisionTree`, for exemple to account for especially long computations.
1021
1022```js
1023const client = craftai({
1024 // Mandatory, the token
1025 token: '{token}',
1026 // Optional, default value is 5 minutes (300000)
1027 decisionTreeRetrievalTimeout: {timeout_duration_for_decision_trees_retrieval}
1028});
1029```
1030
1031#### Proxy ####
1032
1033> :information_source: This setting can only be set in Node.js environements. In a browser environement the settings of the browser will be used automatically.
1034
1035It is possible to provide proxy configuration in the `proxy` property of the client configuration. It will be used to call the craft ai API (through HTTPS). The expected format is a host name or IP and port, optionally preceded by credentials such as `http://user:pass@10.10.1.10:1080`.
1036
1037```js
1038const client = craftai({
1039 // Mandatory, the token
1040 token: '{token}',
1041 // Optional, no default value
1042 proxy: 'http://{user}:{password}@{host_or_ip}:{port}'
1043});
1044```
1045## Interpreter ##
1046
1047The decision tree interpreter can be used offline from decisions tree computed through the API.
1048
1049### Take decision ###
1050
1051```js
1052// `tree` is the decision tree as retrieved through the craft ai REST API
1053const tree = { ... };
1054// Compute the decision with specifying every context field
1055const decision = craftai.interpreter.decide(
1056 tree,
1057 {
1058 timezone: '+02:00',
1059 timeOfDay: 7.5,
1060 peopleCount: 3
1061 });
1062
1063// Or Compute the decision on a context created from the given one and filling the
1064// `day_of_week`, `time_of_day` and `timezone` properties from the given `Time`
1065const decision = craftai.interpreter.decide(
1066 tree,
1067 {
1068 timezone: '+02:00',
1069 peopleCount: 3
1070 },
1071 new craftai.Time('2010-01-01T07:30:30'));
1072```
1073
1074> Any number of partial contexts and/or `craftai.Time` instances can be provided to `decide`, it follows the same semantics as [Object.assign(...)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign): the later arguments overriding the properties value from the previous ones)
1075
1076A computed `decision` on an `enum` type would look like:
1077
1078```js
1079{
1080 context: { // In which context the decision was taken
1081 timezone: '+02:00',
1082 timeOfDay: 7.5,
1083 peopleCount: 3
1084 },
1085 output: { // The decision itself
1086 lightbulbState: {
1087 predicted_value: 'ON',
1088 confidence: 0.9937745256361138, // The confidence in the decision
1089 decision_rules: [ // The ordered list of decision_rules that were validated to reach this decision
1090 {
1091 property: 'timeOfDay',
1092 operator: '>=',
1093 operand: 6
1094 },
1095 {
1096 property: 'peopleCount',
1097 operator: '>=',
1098 operand: 2
1099 }
1100 ]
1101 }
1102 }
1103}
1104```
1105
1106A `decision` for a numerical output type would look like:
1107
1108```js
1109 output: {
1110 lightbulbIntensity: {
1111 predicted_value: 10.5,
1112 standard_deviation: 1.25,
1113 confidence: ...,
1114 decision_rules: [ ... ]
1115 }
1116 }
1117```
1118
1119A `decision` in a case where the tree cannot make a prediction:
1120
1121```js
1122 decision: {
1123 lightbulbState: {
1124 predicted_value: null, // No decision
1125 confidence: 0, // Zero confidence if the decision is null
1126 decision_rules: [ ... ]
1127 }
1128 },
1129```
1130
1131### Take multiple decisions ###
1132
1133From the tree previously retrieved, ask for multiple decisions.
1134
1135```js
1136// `tree` is the decision tree as retrieved through the craft ai REST API
1137const tree = { ... };
1138// Pass an array containing each context on which you want to take a decision
1139const decisions = craftai.interpreter.decideFromContextsArray(tree, [
1140 {
1141 timezone: '+02:00',
1142 peopleCount: 3,
1143 timeOfDay: 7.5
1144 },
1145 {
1146 timezone: '+02:00',
1147 peopleCount: 4,
1148 timeOfDay: 7.5
1149 },
1150 {
1151 timezone: '+02:00',
1152 peopleCount: 0,
1153 timeOfDay: 4.5
1154 }
1155])
1156```
1157
1158Results for `craftai.interpreter.decideFromContextsArray` would look like:
1159
1160```js
1161[
1162 {
1163 context: { // In which context the decision was taken
1164 timezone: '+02:00',
1165 timeOfDay: 7.5,
1166 peopleCount: 3
1167 },
1168 output: { // The decision itself
1169 lightbulbState: {
1170 predicted_value: 'ON',
1171 confidence: 0.9937745256361138, // The confidence in the decision
1172 decision_rules: [ // The ordered list of decision_rules that were validated to reach this decision
1173 {
1174 property: 'timeOfDay',
1175 operator: '>=',
1176 operand: 6
1177 },
1178 {
1179 property: 'peopleCount',
1180 operator: '>=',
1181 operand: 2
1182 }
1183 ]
1184 }
1185 }
1186 },
1187 {
1188 context: {
1189 timezone: '+02:00',
1190 timeOfDay: 7.5,
1191 peopleCount: 4
1192 },
1193 output: {
1194 lightbulbState: {
1195 predicted_value: 'ON',
1196 confidence: 0.9937745256361138,
1197 decision_rules: [
1198 {
1199 property: 'timeOfDay',
1200 operator: '>=',
1201 operand: 6
1202 },
1203 {
1204 property: 'peopleCount',
1205 operator: '>=',
1206 operand: 2
1207 }
1208 ]
1209 }
1210 }
1211 },
1212 {
1213 context: {
1214 timezone: '+02:00',
1215 timeOfDay: 4.5,
1216 peopleCount: 0
1217 },
1218 output: {
1219 lightbulbState: {
1220 predicted_value: 'OFF',
1221 confidence: 0.9545537233352661,
1222 decision_rules: [ // The ordered list of decision_rules that were validated to reach this decision
1223 {
1224 property: 'timeOfDay',
1225 operator: '<',
1226 operand: 5.666666507720947
1227 },
1228 {
1229 property: 'peopleCount',
1230 operator: '<',
1231 operand: 1
1232 }
1233 ]
1234 }
1235 }
1236 }
1237]
1238```
1239
1240### Reduce decision rules ###
1241
1242From a list of decision rules, as retrieved when taking a decision, when taking a decision compute an equivalent & minimal list of rules.
1243
1244```js
1245// `decision` is the decision tree as retrieved from taking a decision
1246const decision = craftai.interpreter.decide( ... );
1247
1248// `decisionRules` is the decision rules that led to decision for the `lightBulbState` value
1249const decisionRules = decision.output.lightBulbState.decision_rules;
1250
1251// `minimalDecisionRules` has the mininum list of rules strictly equivalent to `decisionRules`
1252const minimalDecisionRules = craftai.interpreter.reduceDecisionRules(decisionRules)
1253```
1254
1255### Format decision rules ###
1256
1257From a list of decision rules, compute a _human readable_ version of these rules, in english.
1258
1259```js
1260// `decision` is the decision tree as retrieved from taking a decision
1261const decision = craftai.interpreter.decide( ... );
1262
1263// `decisionRules` is the decision rules that led to decision for the `lightBulbState` value
1264const decisionRules = decision.output.lightBulbState.decision_rules;
1265
1266// `decisionRulesStr` is a human readable string representation of the rules.
1267const decisionRulesStr = craftai.interpreter.reduceDecisionRules.formatDecisionRules(decisionRules);
1268```
1269
1270### Get decision rules properties ###
1271
1272Retrieve the context properties that matters to a previously computed tree.
1273
1274```js
1275// `tree` is the decision tree as retrieved through the craft ai REST API
1276const tree = { ... };
1277
1278const decisionRules = craftai.interpreter.getDecisionRulesProperties(tree)
1279```
1280
1281Results for `craftai.interpreter.getDecisionRulesProperties` would look like:
1282
1283```js
1284[
1285 {
1286 property: 'timeOfDay',
1287 is_generated: true,
1288 type: 'time_of_day'
1289 }
1290]
1291```
1292
1293## Logging ##
1294
1295The **craft ai** client is using [visionmedia/debug](https://www.npmjs.com/package/debug) under the namespace `'craft-ai:client:*'`, please refer to their documentation for further information.