@alan-ai/alan-sdk-web 1.8.28 → 1.8.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Alan voice assistant SDK for Web
1
+ # Alan AI: In-app voice assistant SDK for Web
2
2
 
3
3
  [Alan Platform](https://alan.app/) • [Alan Studio](https://studio.alan.app/register) • [Docs](https://alan.app/docs) • [FAQ](https://alan.app/docs/usage/additional/faq) •
4
4
  [Blog](https://alan.app/blog/) • [Twitter](https://twitter.com/alanvoiceai)
@@ -8,49 +8,49 @@
8
8
  [![CircleCI](https://circleci.com/gh/alan-ai/alan-sdk-web.svg?style=shield)](https://circleci.com/gh/alan-ai/alan-sdk-web)
9
9
 
10
10
 
11
- Quickly add voice to your app or website. Create a voice assistant or build a multimodal interface with two input modes — speech and gestures — working in sync.
11
+ Quickly add voice to your app with the Alan Platform. Create an in-app voice assistant to enable human-like conversations and provide a personalized voice experience for every user.
12
12
 
13
13
  <img src="https://storage.googleapis.com/alan-public-images/github/tablet-tasks.gif" height="325px" align="right"/>
14
14
 
15
15
 
16
16
  ## Alan is a Voice AI Platform
17
17
 
18
- Alan is a conversational voice AI platform that lets you create an intelligent voice assistant for your app. It offers all necessary tools to design, embed and host your conversational experiences:
18
+ Alan is a conversational voice AI platform that lets you create an intelligent voice assistant for your app. It offers all necessary tools to design, embed and host your voice solutions:
19
19
 
20
20
  #### Alan Studio
21
- A web portal where you can write, test and manage dialog scenarios for your voice assistant or chatbot.
21
+ A powerful web-based IDE where you can write, test and debug dialog scenarios for your voice assistant or chatbot.
22
22
 
23
23
  #### Alan Client SDKs
24
24
 
25
- With Alan Client SDKs, you can quickly embed Alan's voice to your app.
25
+ Alan's lightweight SDKs to quickly embed a voice assistant to your app.
26
26
 
27
27
  #### Alan Cloud
28
28
 
29
- Alan's AI-backend that maintains voice deployments and accomplishes all Spoken Language Understanding (SLU) and Natural Language Processing (NLP) tasks.
29
+ Alan's AI-backend powered by the industry’s best Automatic Speech Recognition (ASR), Natural Language Understanding (NLU) and Speech Synthesis. The Alan Cloud provisions and handles the infrastructure required to maintain your voice deployments and perform all the voice processing tasks.
30
30
 
31
31
  To get more details on how Alan works, see <a href="https://alan.app/platform" target="_blank">Alan Platform</a>.
32
32
 
33
33
  ## Why Alan?
34
34
 
35
35
  * **No or minimum changes to your UI**: To voice enable your app, you only need to get the Alan Client SDK and drop it to your app.
36
- * **Serverless environment**: No need to plan for, deploy and maintain any infrastructure or speech components. Alan does all maintenance and voice processing tasks on behalf of your app.
36
+ * **Serverless environment**: No need to plan for, deploy and maintain any infrastructure or speech components - the Alan Platform does the bulk of the work.
37
37
  * **On-the-fly updates**: All changes to the dialogs become available immediately.
38
38
  * **Voice flow testing and analytics**: Alan Studio provides advanced tools for testing your dialog flows and getting the analytics data on users' interactions, all in the same console.
39
39
 
40
40
 
41
41
  ## How to start
42
42
 
43
- To add voice a web app or page:
43
+ To create a voice assistant for your web app or page:
44
44
 
45
45
  1. <a href="https://studio.alan.app/register" target="_blank">Sign up for Alan Studio</a> to build voice scripts in JavaScript and test them.
46
- 2. Use the Alan Web SDK to embed the Alan button to your app or page. For details, see Alan AI documentation for the necessary framework:
47
-
48
- * <img src="https://alan.app/assets/about/js.svg" height="35px" align="center" style="border:0px"/> <a href="https://alan.app/docs/client-api/web/vanilla" target="_blank">JavaScript</a>
49
- * <img src="https://alan.app/assets/about/react.svg" height="35px" align="center" style="border:0px"/> <a href="https://alan.app/docs/client-api/web/react" target="_blank">React</a>
50
- * <img src="https://alan.app/assets/about/angular.svg" height="35px" align="center" style="border:0px"/> <a href="https://alan.app/docs/client-api/web/angular" target="_blank">Angular</a>
51
- * <img src="https://alan.app/assets/about/vue.svg" height="35px" align="center" style="border:0px"/> <a href="https://alan.app/docs/client-api/web/vue" target="_blank">Vue</a>
52
- * <img src="https://alan.app/assets/about/ember.svg" height="35px" align="center" style="border:0px"/> <a href="https://alan.app/docs/client-api/web/ember" target="_blank">Ember</a>
53
- * <img src="https://alan.app/assets/about/electron.svg" height="35px" align="center" style="border:0px"/> <a href="https://alan.app/docs/client-api/web/electron" target="_blank">Electron</a>
46
+ 2. Use the Alan Web SDK to embed a voice assistant to your app or page. For details, see Alan AI documentation for the necessary framework:
47
+
48
+ * <a href="https://alan.app/docs/client-api/web/vanilla" target="_blank">JavaScript</a>
49
+ * <a href="https://alan.app/docs/client-api/web/react" target="_blank">React</a>
50
+ * <a href="https://alan.app/docs/client-api/web/angular" target="_blank">Angular</a>
51
+ * <a href="https://alan.app/docs/client-api/web/vue" target="_blank">Vue</a>
52
+ * <a href="https://alan.app/docs/client-api/web/ember" target="_blank">Ember</a>
53
+ * <a href="https://alan.app/docs/client-api/web/electron" target="_blank">Electron</a>
54
54
 
55
55
 
56
56
  Check out our <a href="https://alan-ai.github.io/alan-sdk-web/" target="_blank">demo</a>.
package/dist/.DS_Store ADDED
Binary file
package/dist/alan_lib.js CHANGED
@@ -781,7 +781,7 @@
781
781
  (function(ns) {
782
782
  "use strict";
783
783
 
784
- var alanButtonVersion = '1.8.28';
784
+ var alanButtonVersion = '1.8.31';
785
785
 
786
786
  if (window.alanBtn) {
787
787
  console.warn('Alan: the Alan Button source code has already added (v.' + alanButtonVersion + ')');
@@ -903,9 +903,25 @@ function alanBtn(options) {
903
903
  var absolutePosition = false;
904
904
  var micWasStoppedByTimeout = false;
905
905
  var keepButtonPositionAfterDnD = false;
906
+
907
+ // Btn modes
908
+ var mode;
909
+
910
+ if (options.mode === 'tutor') {
911
+ mode = 'tutor';
912
+ pinned = true;
913
+ } else if (options.mode === 'demo') {
914
+ mode = 'demo';
915
+ } else {
916
+ mode = 'component';
917
+ }
906
918
 
907
919
  console.log('Alan: v.' + alanButtonVersion);
908
920
 
921
+ if (window.tutorProject && !isTutorMode()) {
922
+ throw new Error('The Alan Button instance has already been created. There cannot be two Alan Button instances created at the same time');
923
+ }
924
+
909
925
  var btnInstance = {
910
926
  // Common public API
911
927
  version: alanButtonVersion,
@@ -970,6 +986,7 @@ function alanBtn(options) {
970
986
  },
971
987
  //deprecated
972
988
  callClientApi: function (method, data, callback) {
989
+ console.error('The "callClientApi" method is deprecated. Please use the "callProjectApi: instead.\n\nSee more info here: https://alan.app/docs/client-api/methods/common-api/?highlight=callprojectapi#callprojectapi');
973
990
  if (btnDisabled) {
974
991
  return;
975
992
  }
@@ -980,6 +997,7 @@ function alanBtn(options) {
980
997
  },
981
998
  // deprecated
982
999
  setAuthData: function (data) {
1000
+ console.error('The "setAuthData" method is deprecated. Please use the "authData" property when you create the Alan Button.\n\nSee more info here: https://alan.app/docs/server-api/sending-data/authdata/?highlight=authdata');
983
1001
  if (btnDisabled) {
984
1002
  return;
985
1003
  }
@@ -1002,6 +1020,9 @@ function alanBtn(options) {
1002
1020
  alanAudio.stop();
1003
1021
  window.tutorProject.close();
1004
1022
  rootEl.remove();
1023
+ if(!isTutorMode()) {
1024
+ window.tutorProject = null;
1025
+ }
1005
1026
  },
1006
1027
  stop: function () {
1007
1028
  alanAudio.stop();
@@ -1043,18 +1064,6 @@ function alanBtn(options) {
1043
1064
  baseUrl = 'https://' + options.host;
1044
1065
  }
1045
1066
 
1046
- // Btn modes
1047
- var mode;
1048
-
1049
- if (options.mode === 'tutor') {
1050
- mode = 'tutor';
1051
- pinned = true;
1052
- } else if (options.mode === 'demo') {
1053
- mode = 'demo';
1054
- } else {
1055
- mode = 'component';
1056
- }
1057
-
1058
1067
  if (options.position === 'absolute' || options.pinned) {
1059
1068
  pinned = true;
1060
1069
  }
@@ -1435,6 +1444,7 @@ function alanBtn(options) {
1435
1444
 
1436
1445
  if (absolutePosition) {
1437
1446
  el.style.position = 'absolute';
1447
+ el.classList.add('absolute-positioned');
1438
1448
  }
1439
1449
  if (topPos) {
1440
1450
  el.style.bottom = '';
@@ -1479,6 +1489,7 @@ function alanBtn(options) {
1479
1489
  }
1480
1490
 
1481
1491
  applySizeSettingsToBlurLayers([btnOval1, btnOval2]);
1492
+ setTextPanelPosition(recognisedTextHolder);
1482
1493
  }
1483
1494
 
1484
1495
  // Define base styles for btn
@@ -2207,6 +2218,7 @@ function alanBtn(options) {
2207
2218
 
2208
2219
  // console.info('BTN: tutorProject', options.key);
2209
2220
  } else {
2221
+ console.error("The Alan Button key wasn't provided");
2210
2222
  switchState(getDefaultBtnState());
2211
2223
  }
2212
2224
  }
@@ -2239,7 +2251,7 @@ function alanBtn(options) {
2239
2251
  }
2240
2252
 
2241
2253
  var onresizeDebounced = debounce(function (e) {
2242
- togglePopupVisibility(true);
2254
+ togglePopupVisibility(true, true);
2243
2255
  }, 400);
2244
2256
 
2245
2257
  var windowPrevInnerHeight = window.innerHeight;
@@ -2250,6 +2262,8 @@ function alanBtn(options) {
2250
2262
  }
2251
2263
 
2252
2264
  window.onresize = function () {
2265
+ if (isTutorMode()) return;
2266
+ if (absolutePosition) return;
2253
2267
  var innerHeightDelta = Math.abs(windowPrevInnerHeight - window.innerHeight);
2254
2268
  var isMobileIos = (isMobile() || isIpadOS()) && isSafari();
2255
2269
  var orientationWasChanged = windowPrevOrientation !== window.orientation;
@@ -2260,14 +2274,18 @@ function alanBtn(options) {
2260
2274
  // innerHeightDelta === 95 - tablet ios smart banner is shown
2261
2275
  // innerHeightDelta === 0 - ios smart banner is hidden
2262
2276
 
2263
- console.info('LOGS', innerHeightDelta);
2277
+ var isVerticalResize = innerHeightDelta !== 0;
2264
2278
 
2265
2279
  var mobilePanelsWereShownOrHidden = isMobileIos &&
2266
2280
  (innerHeightDelta === 84 || innerHeightDelta === 95 || innerHeightDelta === 50 || innerHeightDelta === 0);
2267
2281
 
2268
2282
  windowPrevOrientation = window.orientation;
2269
2283
  windowPrevInnerHeight = window.innerHeight;
2270
- if (orientationWasChanged || btnWasMoved || mobilePanelsWereShownOrHidden) {
2284
+
2285
+ if ((orientationWasChanged ||
2286
+ btnWasMoved ||
2287
+ mobilePanelsWereShownOrHidden) &&
2288
+ isVerticalResize) {
2271
2289
  var rootElClientRect = rootEl.getBoundingClientRect();
2272
2290
  var newYPos;
2273
2291
  if (innerHeightDelta === 0) {
@@ -2290,9 +2308,9 @@ function alanBtn(options) {
2290
2308
  if (navigator.permissions) {
2291
2309
  navigator.permissions.query({ name: 'microphone' }).then(function (result) {
2292
2310
  if (result.state === 'prompt') {
2293
- if (options.showOverlayOnMicPermissionPrompt) {
2311
+ // if (options.showOverlayOnMicPermissionPrompt) {
2294
2312
  showPopup({ overlay: true, buttonUnderOverlay: true });
2295
- }
2313
+ // }
2296
2314
  sendClientEvent({ micPermissionPrompt: true });
2297
2315
  }
2298
2316
  if (result.state !== 'granted') {
@@ -2403,14 +2421,15 @@ function alanBtn(options) {
2403
2421
  }
2404
2422
  }
2405
2423
 
2406
- function showPopup(popupOptions) {
2424
+ function showPopup(popupOptions, keepPopupOverlay) {
2407
2425
  if (btnDisabled) return;
2426
+ if (popupIsVisible) return;
2427
+
2408
2428
  savedPopupOptions = popupOptions;
2409
2429
  var message = popupOptions.message;
2410
2430
  var buttonMarginInPopup = popupOptions.buttonMarginInPopup;
2411
2431
  var withOverlay = popupOptions.overlay;
2412
2432
  var _btnSize = parseInt(btnSize, 10);
2413
- var overlay = document.createElement('div');
2414
2433
  var popup = document.createElement('div');
2415
2434
  var rootElClientRect = rootEl.getBoundingClientRect();
2416
2435
  var maxZIndex = 2147483647;
@@ -2418,16 +2437,13 @@ function alanBtn(options) {
2418
2437
 
2419
2438
  popupIsVisible = true;
2420
2439
 
2421
- overlay.id = 'alan-overlay';
2422
2440
  popup.id = 'alan-overlay-popup';
2423
- overlay.classList.add('alan-overlay');
2424
2441
  popup.classList.add('alan-overlay-popup');
2425
2442
 
2426
2443
  if (popupOptions.buttonUnderOverlay !== true) {
2427
2444
  btn.style.zIndex = maxZIndex;
2428
2445
  }
2429
2446
 
2430
- overlay.style.zIndex = maxZIndex - 3;
2431
2447
  popup.style.zIndex = maxZIndex - 2;
2432
2448
 
2433
2449
  if (popupOptions.preventClick) {
@@ -2492,11 +2508,18 @@ function alanBtn(options) {
2492
2508
  }
2493
2509
 
2494
2510
  rootEl.appendChild(popup);
2495
- if (withOverlay) {
2511
+
2512
+ if (withOverlay && keepPopupOverlay !== true) {
2513
+ var overlay = document.createElement('div');
2514
+ overlay.id = 'alan-overlay';
2515
+ overlay.classList.add('alan-overlay');
2516
+ overlay.style.zIndex = maxZIndex - 3;
2496
2517
  rootEl.appendChild(overlay);
2518
+ overlay.addEventListener('click', hidePopup);
2497
2519
  }
2520
+
2498
2521
  closeIconImg.addEventListener('click', hidePopupByCloseIcon);
2499
- overlay.addEventListener('click', hidePopup);
2522
+
2500
2523
  document.addEventListener('keyup', hidePopupByEsc);
2501
2524
  let showPopupEvent = "showPopup";
2502
2525
  if (popupOptions.name) {
@@ -2517,7 +2540,7 @@ function alanBtn(options) {
2517
2540
  }
2518
2541
  }
2519
2542
 
2520
- function hidePopup(keepOptionsInMemory) {
2543
+ function hidePopup(keepOptionsInMemory, keepPopupOverlay) {
2521
2544
  if (keepOptionsInMemory !== true) {
2522
2545
  savedPopupOptions = null;
2523
2546
  }
@@ -2528,7 +2551,7 @@ function alanBtn(options) {
2528
2551
  if (overlayCloseIcon) {
2529
2552
  overlayCloseIcon.removeEventListener('click', hidePopup);
2530
2553
  }
2531
- if (overlay) {
2554
+ if (overlay && keepPopupOverlay !== true) {
2532
2555
  overlay.remove();
2533
2556
  overlay.removeEventListener('click', hidePopup);
2534
2557
  }
@@ -2543,14 +2566,14 @@ function alanBtn(options) {
2543
2566
 
2544
2567
  var savedPopupOptions;
2545
2568
 
2546
- function togglePopupVisibility(isVisible) {
2569
+ function togglePopupVisibility(isVisible, keepPopupOverlay) {
2547
2570
  var popup = rootEl.querySelector('#alan-overlay-popup');
2548
2571
  if (popup) {
2549
2572
  popup.style.visibility = isVisible ? 'visible' : 'hidden';
2550
2573
  if (isVisible) {
2551
- hidePopup(true);
2574
+ hidePopup(true, keepPopupOverlay);
2552
2575
  if (savedPopupOptions) {
2553
- showPopup(savedPopupOptions);
2576
+ showPopup(savedPopupOptions, keepPopupOverlay);
2554
2577
  }
2555
2578
  }
2556
2579
  }
@@ -2610,6 +2633,15 @@ function alanBtn(options) {
2610
2633
  }
2611
2634
  recognisedTextContent.innerHTML = recognisedText;
2612
2635
  }
2636
+ if (recognisedTextHolder.classList.contains('absolute-positioned')) {
2637
+ if (recognisedText.length < 33) {
2638
+ recognisedTextHolder.style.whiteSpace = 'nowrap';
2639
+ recognisedTextHolder.style.minWidth = 'auto';
2640
+ } else {
2641
+ recognisedTextHolder.style.minWidth = '236px';
2642
+ recognisedTextHolder.style.whiteSpace = 'normal';
2643
+ }
2644
+ }
2613
2645
 
2614
2646
  if (recognisedText.length > 60 && recognisedText.length <= 80) {
2615
2647
  recognisedTextHolder.classList.add('alanBtn-recognised-text-holder-long');
@@ -2700,10 +2732,10 @@ function alanBtn(options) {
2700
2732
  }
2701
2733
 
2702
2734
  if (data && data.web && data.web.hidden === true) {
2703
- hideAlanBtn();
2735
+ hideBtn();
2704
2736
  } else {
2705
2737
  // sendClientEvent({ buttonReady: true });
2706
- showAlanBtn();
2738
+ showBtn();
2707
2739
  }
2708
2740
  }
2709
2741
 
@@ -2916,7 +2948,9 @@ function alanBtn(options) {
2916
2948
  if (options.onCommand) {
2917
2949
  options.onCommand(e.data);
2918
2950
  }
2919
- switchState(LISTENING);
2951
+ if (isAlanActive) {
2952
+ switchState(LISTENING);
2953
+ }
2920
2954
  turnOffVoiceFn();
2921
2955
  }
2922
2956
 
@@ -3202,6 +3236,7 @@ function alanBtn(options) {
3202
3236
  } else if (newState === PERMISSION_DENIED) {
3203
3237
  rootEl.classList.add("alan-btn-permission-denied");
3204
3238
  currentErrMsg = MIC_BLOCKED_MSG;
3239
+ console.warn(MIC_BLOCKED_MSG);
3205
3240
  } else if (newState === NO_VOICE_SUPPORT || newState === NOT_SECURE_ORIGIN) {
3206
3241
  rootEl.classList.add("alan-btn-no-voice-support");
3207
3242
  if (newState === NO_VOICE_SUPPORT) {
@@ -3300,6 +3335,7 @@ function alanBtn(options) {
3300
3335
  el.style.opacity = 0;
3301
3336
  el.style.transition = 'opacity 300ms ease-in-out';
3302
3337
  el.style.animation = gradientAnimation;
3338
+ el.style.display = 'block';
3303
3339
  }
3304
3340
 
3305
3341
  function hideLayers(layers) {
@@ -3394,7 +3430,7 @@ function alanBtn(options) {
3394
3430
  //#endregion
3395
3431
 
3396
3432
  //#region Append layers to the rootEl
3397
- function showAlanBtn() {
3433
+ function showBtn() {
3398
3434
  rootEl.innerHTML = '';
3399
3435
 
3400
3436
  recognisedTextHolder.appendChild(recognisedTextContent);
@@ -3405,7 +3441,7 @@ function alanBtn(options) {
3405
3441
  sendClientEvent({ buttonReady: true });
3406
3442
  }
3407
3443
 
3408
- function hideAlanBtn() {
3444
+ function hideBtn() {
3409
3445
  if (!isTutorMode()) {
3410
3446
  alanAudio.stop();
3411
3447
  rootEl.innerHTML = '';
@@ -3482,7 +3518,7 @@ function alanBtn(options) {
3482
3518
  var alanBtnSavedOptions = null;
3483
3519
 
3484
3520
  if (isTutorMode()) {
3485
- showAlanBtn();
3521
+ showBtn();
3486
3522
  } else {
3487
3523
  if (isLocalStorageAvailable) {
3488
3524
  try {
@@ -3595,6 +3631,13 @@ function alanBtn(options) {
3595
3631
  curX = parseInt(rootEl.style.left, 10);
3596
3632
  curY = parseInt(rootEl.style.top, 10);
3597
3633
 
3634
+ if (Math.abs(tempDeltaX) < 15 && Math.abs(tempDeltaY) < 15) {
3635
+ afterMouseMove = false;
3636
+ dndBackAnimFinished = true;
3637
+ setButtonPosition();
3638
+ return;
3639
+ }
3640
+
3598
3641
  if (curX <= window.innerWidth / 2) {
3599
3642
  rootEl.style.setProperty('left', dndFinalHorPos + 'px', 'important');
3600
3643
  changeBtnSide('to-left');
@@ -3624,11 +3667,6 @@ function alanBtn(options) {
3624
3667
  setTimeout(function () {
3625
3668
  afterMouseMove = false;
3626
3669
  }, 300);
3627
-
3628
- if (Math.abs(tempDeltaX) < 15 && Math.abs(tempDeltaY) < 15) {
3629
- afterMouseMove = false;
3630
- dndBackAnimFinished = true;
3631
- }
3632
3670
  }
3633
3671
  }
3634
3672