@alan-ai/alan-sdk-web 1.8.115 → 1.8.117

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.
@@ -6,6 +6,7 @@ export interface AlanButton {
6
6
  activate: () => Promise<void>;
7
7
  deactivate: () => void;
8
8
  isActive: () => boolean;
9
+ isModelReady: () => boolean;
9
10
  remove: () => void;
10
11
  sendText: (text: string) => void;
11
12
  theme: {
@@ -16,7 +16,7 @@ export interface AlanButtonOptions {
16
16
  onCommand?: (commandData: object) => void;
17
17
  onEvent?: (event: object) => void;
18
18
  onButtonState?: (state: string) => void;
19
- onConnectionStatus?: (status: string) => void;
19
+ onConnectionStatus?: (status: string, event: object) => void;
20
20
  textChat?: {
21
21
  closeDelay?: number;
22
22
  showBtnIfChatOpen?: boolean;
package/dist/alan_lib.js CHANGED
@@ -224,10 +224,10 @@
224
224
 
225
225
  function ConnectionWrapper() {
226
226
  var _this = this;
227
- this._worker = new Worker(window.URL.createObjectURL(new Blob(["(function(ns) {\n 'use strict';\n\n var SENT_TS = 1;\n var REMOTE_TS = 2;\n var TIMESTAMP = 3;\n var AUDIO_DATA = 4;\n var JSON_DATA = 5;\n\n AlanFrame.fields = [\n propUint64(SENT_TS, 'sentTs'),\n propUint64(REMOTE_TS, 'remoteTs'),\n propUint64(TIMESTAMP, 'timestamp'),\n propBytes(AUDIO_DATA, 'audioData'),\n propJson(JSON_DATA, 'jsonData'),\n ];\n\n function AlanFrameProp(type, name, sizeF, readF, writeF) {\n this.type = type;\n this.name = name;\n this.sizeF = sizeF;\n this.writeF = writeF;\n this.readF = readF;\n }\n\n function fixedSize(size) {\n return function() {\n return size;\n }\n }\n\n function bufferSize(buffer) {\n return 4 + byteLength(buffer);\n }\n\n function writeUIntN(uint8array, value, nBytes, offset) {\n for (var i = 0; i < nBytes; i++ ) {\n uint8array[offset + i] = 0xFF & value;\n value /= 256;\n }\n }\n\n function readUIntN(uint8array, nBytes, offset) {\n var r = 0;\n for (var i = nBytes - 1; i >= 0; i-- ) {\n r *= 256;\n r += 0xFF & uint8array[offset + i];\n }\n return r;\n }\n\n function writeUInt64(uint8array, value, offset) {\n writeUIntN(uint8array, value, 8, offset);\n }\n\n function readUInt64(uint8array, offset) {\n return readUIntN(uint8array, 8, offset);\n }\n\n function writeUInt32(uint8array, value, offset) {\n writeUIntN(uint8array, value, 4, offset);\n }\n\n function readUInt32(uint8array, offset) {\n return readUIntN(uint8array, 4, offset);\n }\n\n function writeBuffer(uint8array, buffer, offset) {\n buffer = toUint8(buffer);\n writeUInt32(uint8array, buffer.length, offset);\n for (var i = 0; i < buffer.length; i++ ) {\n uint8array[offset + 4 + i] = buffer[i];\n }\n }\n\n function readBuffer(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('buffer too big');\n }\n return uint8array.subarray(offset + 4, offset + 4 + size);\n }\n\n function readUTF8(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('string too big');\n }\n return String.fromCharCode.apply(null, uint8array.slice(offset + 4, offset + 4 + size));\n }\n\n function writeUTF8(uint8array, string, offset) {\n writeUInt32(uint8array, string.length, offset);\n for (var i = 0; i < string.length; i++ ) {\n uint8array[offset + 4 + i] = string.charCodeAt(i);\n }\n }\n\n function sizeUTF8(string) {\n return 4 + string.length;\n }\n\n function propUint32(type, name) {\n return new AlanFrameProp(type, name, fixedSize(4), readUInt32, writeUInt32);\n }\n\n function propUint64(type, name) {\n return new AlanFrameProp(type, name, fixedSize(8), readUInt64, writeUInt64);\n }\n\n function propBytes(type, name) {\n return new AlanFrameProp(type, name, bufferSize, readBuffer, writeBuffer);\n }\n\n function propJson(type, name) {\n return new AlanFrameProp(type, name, sizeUTF8, readUTF8, writeUTF8);\n }\n\n AlanFrame.fieldByType = function(type) {\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var frame = AlanFrame.fields[i];\n if (frame.type === type) {\n return frame;\n }\n }\n throw new Error('invalid field: ' + type);\n };\n\n function AlanFrame() {\n this.version = 1;\n }\n\n AlanFrame.prototype.write = function() {\n var result = new Uint8Array(this.writeSize());\n var offset = 1;\n result[0] = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n result[offset++] = field.type;\n field.writeF(result, value, offset);\n offset += field.sizeF(value);\n }\n }\n return result.buffer;\n };\n\n /**\n * @returns UInt8Array\n */\n AlanFrame.prototype.writeSize = function() {\n var size = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n size += 1 + field.sizeF(value);\n }\n }\n return size;\n };\n\n AlanFrame.prototype.toString = function() {\n var first = true, str = '';\n for (var k in this) {\n if (this.hasOwnProperty(k)) {\n if (first) {\n str += k + ' = ';\n first = false;\n } else {\n str += ', ' + k + ' = ';\n }\n var v = this[k];\n if (typeof(v) === 'object') {\n str += 'bytes[' + byteLength(v) + ']';\n } else {\n str += v;\n }\n }\n }\n return str;\n };\n\n function byteLength(b) {\n if (b instanceof Uint8Array) {\n return b.length;\n }\n if (b instanceof ArrayBuffer) {\n return b.byteLength;\n }\n }\n\n function toArrayBuffer(buffer) {\n if (buffer instanceof ArrayBuffer) {\n return buffer;\n }\n return buffer.buffer;\n }\n\n function toUint8(buffer) {\n if (buffer instanceof Uint8Array) {\n return buffer;\n }\n if (buffer instanceof ArrayBuffer) {\n return new Uint8Array(buffer);\n }\n throw new Error('invalid buffer type');\n }\n\n function parse(uint8array) {\n uint8array = toUint8(uint8array);\n var r = new AlanFrame();\n var offset = 0;\n r.version = uint8array[offset++];\n while (offset < uint8array.length) {\n var frame = AlanFrame.fieldByType(uint8array[offset++]);\n r[frame.name] = frame.readF(uint8array, offset);\n offset += frame.sizeF(r[frame.name]);\n }\n return r;\n }\n\n ns.create = function() {\n return new AlanFrame();\n };\n\n ns.parse = parse;\n\n})(typeof(window) !== 'undefined' ? (function() {window.alanFrame = {}; return window.alanFrame; })() :\n typeof(WorkerGlobalScope) !== 'undefined' ? (function() {alanFrame = {}; return alanFrame; })() :\n exports);\n\n\n'use strict';\n\n\n\nvar ALAN_OFF = 'off';\nvar ALAN_SPEAKING = 'speaking';\nvar ALAN_LISTENING = 'listening';\n\nfunction ConnectionImpl(config, auth, mode) {\n var _this = this;\n this._config = config;\n this._auth = auth;\n this._mode = mode;\n this._projectId = config.projectId;\n this._url = config.url;\n this._connected = false;\n this._authorized = false;\n this._dialogId = null;\n this._callId = 1;\n this._callSent = {};\n this._callWait = [];\n this._failed = false;\n this._closed = false;\n this._reconnectTimeout = 100;\n this._cleanups = [];\n this._format = null;\n this._formatSent = false;\n this._frameQueue = [];\n this._remoteSentTs = 0;\n this._remoteRecvTs = 0;\n this._rtt = 25;\n this._rttAlpha = 1./16;\n this._alanState = ALAN_OFF;\n this._sendTimer = setInterval(_this._flushQueue.bind(_this), 50);\n this._visualState = {};\n this._addCleanup(function() {clearInterval(_this._sendTimer);});\n this._connect();\n console.log('Alan: connection created');\n}\n\nConnectionImpl.prototype._addCleanup = function(f) {\n this._cleanups.push(f);\n};\n\nConnectionImpl.prototype._onConnectStatus = function(s) {\n console.log('Alan: connection status - ' + s);\n this._fire('connectStatus', s);\n};\n\nConnectionImpl.prototype._fire = function(event, object) {\n if (event === 'options') {\n if (object.versions) {\n object.versions['alanbase:web'] = this._config.version;\n }\n }\n postMessage(['fireEvent', event, object]);\n};\n\nConnectionImpl.prototype._connect = function() {\n var _this = this;\n if (this._socket) {\n console.error('socket is already connected');\n return;\n }\n console.log('Alan: connecting - ' + getConnectionDetails(this._url));\n this._socket = new WebSocket(this._url);\n this._socket.binaryType = 'arraybuffer';\n console.time('Alan: connection time');\n this._socket.onopen = function(e) {\n console.info('Alan: connected');\n _this._connected = true;\n _this._reconnectTimeout = 100;\n _this._fire('connection', {status: 'connected'});\n console.timeEnd('Alan: connection time');\n if (_this._auth) {\n _this._fire('connection', {status: 'authorizing'});\n _this._callAuth();\n } else {\n _this._callWait.forEach(function(c) { _this._sendCall(c); });\n _this._callWait = [];\n _this._onConnectStatus('connected');\n }\n };\n this._socket.onmessage = function(msg) {\n if (msg.data instanceof ArrayBuffer) {\n var f = alanFrame.parse(msg.data);\n if (f.sentTs > 0) {\n _this._remoteSentTs = f.sentTs;\n _this._remoteRecvTs = Date.now();\n } else {\n _this._remoteSentTs = null;\n _this._remoteRecvTs = null;\n }\n var rtt = 0;\n if (f.remoteTs) {\n rtt = Date.now() - f.remoteTs;\n }\n _this._rtt = _this._rttAlpha * rtt + (1 - _this._rttAlpha) * _this._rtt;\n var uint8 = new Uint8Array(f.audioData);\n var frame = uint8;\n postMessage(['alanAudio', 'playFrame', frame]);\n } else if (typeof(msg.data) === 'string') {\n msg = JSON.parse(msg.data);\n if (msg.i) {\n var c = _this._callSent[msg.i];\n delete _this._callSent[msg.i];\n if (c && c.callback) {\n c.callback(msg.e, msg.r);\n }\n } else if (msg.e) {\n if (msg.e === 'text') {\n postMessage(['alanAudio', 'playText', msg.p]);\n } else if (msg.e === 'afterText') {\n postMessage(['alanAudio', 'playAfterText', msg.p]);\n } else if (msg.e === 'showPopup') {\n postMessage(['alanAudio', 'showPopup', msg.p]);\n } else if (msg.e === 'showButtons') {\n postMessage(['alanAudio', 'showButtons', msg.p]);\n } else if (msg.e === 'command') {\n postMessage(['alanAudio', 'playCommand', msg.p]);\n } else if (msg.e === 'inactivity') {\n postMessage(['alanAudio', 'stop']);\n } else {\n _this._fire(msg.e, msg.p);\n }\n }\n } else {\n console.error('invalid message type');\n }\n };\n this._socket.onerror = function(evt) {\n _this._onConnectStatus('error');\n console.error('Alan: connection closed due to error: ', evt);\n };\n this._socket.onclose = function(evt) {\n console.info('Alan: connection closed');\n _this._connected = false;\n _this._authorized = false;\n _this._socket = null;\n _this._onConnectStatus('disconnected');\n if (!_this._failed && _this._reconnectTimeout && !_this._closed) {\n console.log('Alan: reconnecting in %s ms.', _this._reconnectTimeout);\n _this._reConnect = setTimeout(_this._connect.bind(_this), _this._reconnectTimeout);\n if (_this._reconnectTimeout < 3000) {\n _this._reconnectTimeout *= 2;\n } else {\n _this._reconnectTimeout += 500;\n }\n _this._reconnectTimeout = Math.min(7000, _this._reconnectTimeout);\n }\n };\n this._addCleanup(function() {\n if (this._socket) {\n this._socket.close();\n this._socket = null;\n }\n });\n};\n\nConnectionImpl.prototype._callAuth = function() {\n var _this = this;\n var callback = function(err, r) {\n if (!err && r.status === 'authorized') {\n _this._authorized = true;\n _this._formatSent = false;\n if (r.dialogId) {\n postMessage(['setDialogId', r.dialogId]);\n _this._dialogId = r.dialogId;\n }\n _this._onAuthorized();\n _this._onConnectStatus('authorized');\n } else if (err === 'auth-failed') {\n _this._onConnectStatus('auth-failed');\n if (_this._socket) {\n _this._socket.close();\n _this._socket = null;\n _this._failed = true;\n }\n } else {\n _this._onConnectStatus('invalid-auth-response');\n console.log('Alan: invalid auth response', err, r);\n }\n };\n var authParam = this._auth;\n authParam.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (this._dialogId) {\n authParam.dialogId = this._dialogId;\n }\n authParam.mode = this._mode;\n this._sendCall({cid: this._callId++, method: '_auth_', callback: callback, param: authParam});\n return this;\n};\n\nConnectionImpl.prototype._sendCall = function(call) {\n this._sendFormatIfNeeded(false);\n this._socket.send(JSON.stringify({i: call.cid, m: call.method, p: call.param}));\n if (call.callback) {\n this._callSent[call.cid] = call;\n }\n};\n\nConnectionImpl.prototype._onAuthorized = function() {\n var _this = this;\n this._callWait.forEach(function(c) {\n _this._sendCall(c);\n });\n this._callWait = [];\n};\n\nConnectionImpl.prototype.close = function() {\n for (var i = 0; i < this._cleanups.length; i++ ) {\n this._cleanups[i]();\n }\n this._cleanups = [];\n this._closed = true;\n \n if (this._socket && (this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)) {\n this._socket.close();\n this._socket = null;\n }\n console.log('Alan: closed connection to: ' + getConnectionDetails(this._url));\n //close(); TODO: delete it!\n};\n\nConnectionImpl.prototype.call = function(cid, method, param) {\n var call = {cid: cid, method: method, param: param, callback: function(err, obj) {\n if (cid) {\n postMessage(['callback', cid, err, obj]);\n }\n }};\n if (this._authorized || this._connected && !this._auth) {\n this._sendCall(call);\n } else {\n this._callWait.push(call);\n }\n};\n\nConnectionImpl.prototype.setVisual = function(state) {\n this._visualState = state;\n this.call(null, '_visual_', state);\n};\n\nConnectionImpl.prototype._sendFrame = function(frame) {\n if (!this._socket) {\n console.error('sendFrame to closed socket');\n return;\n }\n frame.sentTs = Date.now();\n if (this._remoteSentTs > 0 && this._remoteRecvTs > 0) {\n frame.remoteTs = this._remoteSentTs + Date.now() - this._remoteRecvTs;\n }\n this._socket.send(frame.write());\n};\n\nConnectionImpl.prototype._listen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'listen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_LISTENING;\n};\n\nConnectionImpl.prototype._stopListen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'stopListen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_OFF;\n};\n\nConnectionImpl.prototype._onAudioFormat = function(format) {\n this._formatSent = false;\n this._format = format;\n};\n\nConnectionImpl.prototype._onMicFrame = function(sampleRate, frame) {\n if (this._alanState === ALAN_SPEAKING) {\n return;\n }\n if (this._alanState === ALAN_OFF) {\n this._listen();\n }\n if (this._alanState !== ALAN_LISTENING) {\n console.error('invalid alan state: ' + this._alanState);\n return;\n }\n this._sendFormatIfNeeded(true);\n var f = alanFrame.create();\n f.audioData = frame;\n this._frameQueue.push(f);\n};\n\nConnectionImpl.prototype._sendFormatIfNeeded = function(inQueue) {\n if (!this._format || this._formatSent) {\n return;\n }\n this._formatSent = true;\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({format: this._format});\n if (inQueue) {\n this._frameQueue.push(f);\n } else {\n this._sendFrame(f);\n }\n};\n\nConnectionImpl.prototype._flushQueue = function() {\n if (!this._socket || !this._connected) {\n var d = 0;\n while (this._frameQueue.length > 100 && !this._frameQueue[0].jsonData) {\n this._frameQueue.shift();\n d++;\n }\n if (d > 0) {\n console.error('dropped: %s, frames', d);\n }\n return;\n }\n while (this._frameQueue.length > 0 && this._socket && this._socket.bufferedAmount < 64 * 1024) {\n this._sendFrame(this._frameQueue.shift());\n }\n};\n\nfunction getConnectionDetails(url){\n var urlParts = url.split('/');\n var host = urlParts[2];\n \n // Find the index of 'ws_project' in the URL parts\n var wsProjectIndex = -1;\n for (var i = 0; i < urlParts.length; i++) {\n if (urlParts[i] === 'ws_project') {\n wsProjectIndex = i;\n break;\n }\n }\n \n var projectId = wsProjectIndex !== -1 ? urlParts[wsProjectIndex + 1] : null;\n var environment = wsProjectIndex !== -1 ? urlParts[wsProjectIndex + 2] : null;\n\n if (projectId && environment && host) {\n return ' (ProjectID: ' + projectId + ', environment: ' + environment + ', host: ' + host + ')';\n }\n\n return url;\n}\n\nfunction connectProject(config, auth, mode) {\n var c = new ConnectionImpl(config, auth, mode);\n c.onAudioEvent = function(event, arg1, arg2) {\n if (event === 'format') {\n c._onAudioFormat(arg1);\n } else if (event === 'frame') {\n c._onMicFrame(arg1, arg2);\n } else if (event === 'micStop') {\n c._stopListen();\n } else if (event === 'playStart') {\n // ignore\n } else {\n console.error('unknown audio event: ' + event, arg1, arg2);\n }\n };\n return c;\n}\n\nvar factories = {\n connectProject: connectProject,\n};\n\nvar currentConnect = null;\n\nonmessage = function(e) {\n var name = e.data[0];\n try {\n if (!currentConnect) {\n currentConnect = factories[name].apply(null, e.data.slice(1, e.data.length));\n } else {\n currentConnect[name].apply(currentConnect, e.data.slice(1, e.data.length));\n }\n } catch(e) {\n console.error('error calling: ' + name, e);\n }\n};\n"], {type: 'text/javascript'})));
227
+ this._worker = new Worker(window.URL.createObjectURL(new Blob(["(function(ns) {\n 'use strict';\n\n var SENT_TS = 1;\n var REMOTE_TS = 2;\n var TIMESTAMP = 3;\n var AUDIO_DATA = 4;\n var JSON_DATA = 5;\n\n AlanFrame.fields = [\n propUint64(SENT_TS, 'sentTs'),\n propUint64(REMOTE_TS, 'remoteTs'),\n propUint64(TIMESTAMP, 'timestamp'),\n propBytes(AUDIO_DATA, 'audioData'),\n propJson(JSON_DATA, 'jsonData'),\n ];\n\n function AlanFrameProp(type, name, sizeF, readF, writeF) {\n this.type = type;\n this.name = name;\n this.sizeF = sizeF;\n this.writeF = writeF;\n this.readF = readF;\n }\n\n function fixedSize(size) {\n return function() {\n return size;\n }\n }\n\n function bufferSize(buffer) {\n return 4 + byteLength(buffer);\n }\n\n function writeUIntN(uint8array, value, nBytes, offset) {\n for (var i = 0; i < nBytes; i++ ) {\n uint8array[offset + i] = 0xFF & value;\n value /= 256;\n }\n }\n\n function readUIntN(uint8array, nBytes, offset) {\n var r = 0;\n for (var i = nBytes - 1; i >= 0; i-- ) {\n r *= 256;\n r += 0xFF & uint8array[offset + i];\n }\n return r;\n }\n\n function writeUInt64(uint8array, value, offset) {\n writeUIntN(uint8array, value, 8, offset);\n }\n\n function readUInt64(uint8array, offset) {\n return readUIntN(uint8array, 8, offset);\n }\n\n function writeUInt32(uint8array, value, offset) {\n writeUIntN(uint8array, value, 4, offset);\n }\n\n function readUInt32(uint8array, offset) {\n return readUIntN(uint8array, 4, offset);\n }\n\n function writeBuffer(uint8array, buffer, offset) {\n buffer = toUint8(buffer);\n writeUInt32(uint8array, buffer.length, offset);\n for (var i = 0; i < buffer.length; i++ ) {\n uint8array[offset + 4 + i] = buffer[i];\n }\n }\n\n function readBuffer(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('buffer too big');\n }\n return uint8array.subarray(offset + 4, offset + 4 + size);\n }\n\n function readUTF8(uint8array, offset) {\n var size = readUInt32(uint8array, offset);\n if (size > 1024 * 1024) {\n throw new Error('string too big');\n }\n return String.fromCharCode.apply(null, uint8array.slice(offset + 4, offset + 4 + size));\n }\n\n function writeUTF8(uint8array, string, offset) {\n writeUInt32(uint8array, string.length, offset);\n for (var i = 0; i < string.length; i++ ) {\n uint8array[offset + 4 + i] = string.charCodeAt(i);\n }\n }\n\n function sizeUTF8(string) {\n return 4 + string.length;\n }\n\n function propUint32(type, name) {\n return new AlanFrameProp(type, name, fixedSize(4), readUInt32, writeUInt32);\n }\n\n function propUint64(type, name) {\n return new AlanFrameProp(type, name, fixedSize(8), readUInt64, writeUInt64);\n }\n\n function propBytes(type, name) {\n return new AlanFrameProp(type, name, bufferSize, readBuffer, writeBuffer);\n }\n\n function propJson(type, name) {\n return new AlanFrameProp(type, name, sizeUTF8, readUTF8, writeUTF8);\n }\n\n AlanFrame.fieldByType = function(type) {\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var frame = AlanFrame.fields[i];\n if (frame.type === type) {\n return frame;\n }\n }\n throw new Error('invalid field: ' + type);\n };\n\n function AlanFrame() {\n this.version = 1;\n }\n\n AlanFrame.prototype.write = function() {\n var result = new Uint8Array(this.writeSize());\n var offset = 1;\n result[0] = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n result[offset++] = field.type;\n field.writeF(result, value, offset);\n offset += field.sizeF(value);\n }\n }\n return result.buffer;\n };\n\n /**\n * @returns UInt8Array\n */\n AlanFrame.prototype.writeSize = function() {\n var size = 1;\n for (var i = 0; i < AlanFrame.fields.length; i++ ) {\n var field = AlanFrame.fields[i];\n var value = this[field.name];\n if (value) {\n size += 1 + field.sizeF(value);\n }\n }\n return size;\n };\n\n AlanFrame.prototype.toString = function() {\n var first = true, str = '';\n for (var k in this) {\n if (this.hasOwnProperty(k)) {\n if (first) {\n str += k + ' = ';\n first = false;\n } else {\n str += ', ' + k + ' = ';\n }\n var v = this[k];\n if (typeof(v) === 'object') {\n str += 'bytes[' + byteLength(v) + ']';\n } else {\n str += v;\n }\n }\n }\n return str;\n };\n\n function byteLength(b) {\n if (b instanceof Uint8Array) {\n return b.length;\n }\n if (b instanceof ArrayBuffer) {\n return b.byteLength;\n }\n }\n\n function toArrayBuffer(buffer) {\n if (buffer instanceof ArrayBuffer) {\n return buffer;\n }\n return buffer.buffer;\n }\n\n function toUint8(buffer) {\n if (buffer instanceof Uint8Array) {\n return buffer;\n }\n if (buffer instanceof ArrayBuffer) {\n return new Uint8Array(buffer);\n }\n throw new Error('invalid buffer type');\n }\n\n function parse(uint8array) {\n uint8array = toUint8(uint8array);\n var r = new AlanFrame();\n var offset = 0;\n r.version = uint8array[offset++];\n while (offset < uint8array.length) {\n var frame = AlanFrame.fieldByType(uint8array[offset++]);\n r[frame.name] = frame.readF(uint8array, offset);\n offset += frame.sizeF(r[frame.name]);\n }\n return r;\n }\n\n ns.create = function() {\n return new AlanFrame();\n };\n\n ns.parse = parse;\n\n})(typeof(window) !== 'undefined' ? (function() {window.alanFrame = {}; return window.alanFrame; })() :\n typeof(WorkerGlobalScope) !== 'undefined' ? (function() {alanFrame = {}; return alanFrame; })() :\n exports);\n\n\n'use strict';\n\n\n\nvar ALAN_OFF = 'off';\nvar ALAN_SPEAKING = 'speaking';\nvar ALAN_LISTENING = 'listening';\n\nfunction ConnectionImpl(config, auth, mode) {\n var _this = this;\n this._config = config;\n this._auth = auth;\n this._mode = mode;\n this._projectId = config.projectId;\n this._url = config.url;\n this._connected = false;\n this._authorized = false;\n this._dialogId = null;\n this._callId = 1;\n this._callSent = {};\n this._callWait = [];\n this._failed = false;\n this._closed = false;\n this._reconnectTimeout = 100;\n this._cleanups = [];\n this._format = null;\n this._formatSent = false;\n this._frameQueue = [];\n this._remoteSentTs = 0;\n this._remoteRecvTs = 0;\n this._rtt = 25;\n this._rttAlpha = 1./16;\n this._alanState = ALAN_OFF;\n this._sendTimer = setInterval(_this._flushQueue.bind(_this), 50);\n this._visualState = {};\n this._addCleanup(function() {clearInterval(_this._sendTimer);});\n this._connect();\n console.log('Alan: connection created');\n}\n\nConnectionImpl.prototype._addCleanup = function(f) {\n this._cleanups.push(f);\n};\n\nConnectionImpl.prototype._onConnectStatus = function(s, evt) {\n console.log('Alan: connection status - ' + s);\n this._fire('connectStatus', s, evt ? {\n code: evt.code,\n reason: evt.reason,\n wasClean: evt.wasClean,\n } : {});\n};\n\nConnectionImpl.prototype._fire = function(event, object, data) {\n if (event === 'options') {\n if (object.versions) {\n object.versions['alanbase:web'] = this._config.version;\n }\n }\n postMessage(['fireEvent', event, object, data]);\n};\n\nConnectionImpl.prototype._connect = function() {\n var _this = this;\n if (this._socket) {\n console.error('socket is already connected');\n return;\n }\n console.log('Alan: connecting - ' + getConnectionDetails(this._url));\n this._socket = new WebSocket(this._url);\n this._socket.binaryType = 'arraybuffer';\n console.time('Alan: connection time');\n this._socket.onopen = function(e) {\n console.info('Alan: connected');\n _this._connected = true;\n _this._reconnectTimeout = 100;\n _this._fire('connection', {status: 'connected'});\n console.timeEnd('Alan: connection time');\n if (_this._auth) {\n _this._fire('connection', {status: 'authorizing'});\n _this._callAuth();\n } else {\n _this._callWait.forEach(function(c) { _this._sendCall(c); });\n _this._callWait = [];\n _this._onConnectStatus('connected');\n }\n };\n this._socket.onmessage = function(msg) {\n if (msg.data instanceof ArrayBuffer) {\n var f = alanFrame.parse(msg.data);\n if (f.sentTs > 0) {\n _this._remoteSentTs = f.sentTs;\n _this._remoteRecvTs = Date.now();\n } else {\n _this._remoteSentTs = null;\n _this._remoteRecvTs = null;\n }\n var rtt = 0;\n if (f.remoteTs) {\n rtt = Date.now() - f.remoteTs;\n }\n _this._rtt = _this._rttAlpha * rtt + (1 - _this._rttAlpha) * _this._rtt;\n var uint8 = new Uint8Array(f.audioData);\n var frame = uint8;\n postMessage(['alanAudio', 'playFrame', frame]);\n } else if (typeof(msg.data) === 'string') {\n msg = JSON.parse(msg.data);\n if (msg.i) {\n var c = _this._callSent[msg.i];\n delete _this._callSent[msg.i];\n if (c && c.callback) {\n c.callback(msg.e, msg.r);\n }\n } else if (msg.e) {\n if (msg.e === 'text') {\n postMessage(['alanAudio', 'playText', msg.p]);\n } else if (msg.e === 'afterText') {\n postMessage(['alanAudio', 'playAfterText', msg.p]);\n } else if (msg.e === 'showPopup') {\n postMessage(['alanAudio', 'showPopup', msg.p]);\n } else if (msg.e === 'showButtons') {\n postMessage(['alanAudio', 'showButtons', msg.p]);\n } else if (msg.e === 'command') {\n postMessage(['alanAudio', 'playCommand', msg.p]);\n } else if (msg.e === 'inactivity') {\n postMessage(['alanAudio', 'stop']);\n } else {\n _this._fire(msg.e, msg.p);\n }\n }\n } else {\n console.error('invalid message type');\n }\n };\n this._socket.onerror = function(evt) {\n _this._onConnectStatus('error', evt);\n console.error('Alan: connection closed due to error: ', evt);\n };\n this._socket.onclose = function(evt) {\n console.info('Alan: connection closed');\n _this._connected = false;\n _this._authorized = false;\n _this._socket = null;\n _this._onConnectStatus('disconnected', evt);\n if (!_this._failed && _this._reconnectTimeout && !_this._closed) {\n console.log('Alan: reconnecting in %s ms.', _this._reconnectTimeout);\n _this._reConnect = setTimeout(_this._connect.bind(_this), _this._reconnectTimeout);\n if (_this._reconnectTimeout < 3000) {\n _this._reconnectTimeout *= 2;\n } else {\n _this._reconnectTimeout += 500;\n }\n _this._reconnectTimeout = Math.min(7000, _this._reconnectTimeout);\n }\n };\n this._addCleanup(function() {\n if (this._socket) {\n this._socket.close();\n this._socket = null;\n }\n });\n};\n\nConnectionImpl.prototype._callAuth = function() {\n var _this = this;\n var callback = function(err, r) {\n if (!err && r.status === 'authorized') {\n _this._authorized = true;\n _this._formatSent = false;\n if (r.dialogId) {\n postMessage(['setDialogId', r.dialogId]);\n _this._dialogId = r.dialogId;\n }\n _this._onAuthorized();\n _this._onConnectStatus('authorized');\n } else if (err === 'auth-failed') {\n _this._onConnectStatus('auth-failed');\n if (_this._socket) {\n _this._socket.close();\n _this._socket = null;\n _this._failed = true;\n }\n } else {\n _this._onConnectStatus('invalid-auth-response');\n console.log('Alan: invalid auth response', err, r);\n }\n };\n var authParam = this._auth;\n authParam.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n if (this._dialogId) {\n authParam.dialogId = this._dialogId;\n }\n authParam.mode = this._mode;\n this._sendCall({cid: this._callId++, method: '_auth_', callback: callback, param: authParam});\n return this;\n};\n\nConnectionImpl.prototype._sendCall = function(call) {\n this._sendFormatIfNeeded(false);\n this._socket.send(JSON.stringify({i: call.cid, m: call.method, p: call.param}));\n if (call.callback) {\n this._callSent[call.cid] = call;\n }\n};\n\nConnectionImpl.prototype._onAuthorized = function() {\n var _this = this;\n this._callWait.forEach(function(c) {\n _this._sendCall(c);\n });\n this._callWait = [];\n};\n\nConnectionImpl.prototype.close = function() {\n for (var i = 0; i < this._cleanups.length; i++ ) {\n this._cleanups[i]();\n }\n this._cleanups = [];\n this._closed = true;\n \n if (this._socket && (this._socket.readyState === WebSocket.OPEN || this._socket.readyState === WebSocket.CONNECTING)) {\n this._socket.close();\n this._socket = null;\n }\n console.log('Alan: closed connection to: ' + getConnectionDetails(this._url));\n //close(); TODO: delete it!\n};\n\nConnectionImpl.prototype.call = function(cid, method, param) {\n var call = {cid: cid, method: method, param: param, callback: function(err, obj) {\n if (cid) {\n postMessage(['callback', cid, err, obj]);\n }\n }};\n if (this._authorized || this._connected && !this._auth) {\n this._sendCall(call);\n } else {\n this._callWait.push(call);\n }\n};\n\nConnectionImpl.prototype.setVisual = function(state) {\n this._visualState = state;\n this.call(null, '_visual_', state);\n};\n\nConnectionImpl.prototype._sendFrame = function(frame) {\n if (!this._socket) {\n console.error('sendFrame to closed socket');\n return;\n }\n frame.sentTs = Date.now();\n if (this._remoteSentTs > 0 && this._remoteRecvTs > 0) {\n frame.remoteTs = this._remoteSentTs + Date.now() - this._remoteRecvTs;\n }\n this._socket.send(frame.write());\n};\n\nConnectionImpl.prototype._listen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'listen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_LISTENING;\n};\n\nConnectionImpl.prototype._stopListen = function() {\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({signal: 'stopListen'});\n this._frameQueue.push(f);\n this._alanState = ALAN_OFF;\n};\n\nConnectionImpl.prototype._onAudioFormat = function(format) {\n this._formatSent = false;\n this._format = format;\n};\n\nConnectionImpl.prototype._onMicFrame = function(sampleRate, frame) {\n if (this._alanState === ALAN_SPEAKING) {\n return;\n }\n if (this._alanState === ALAN_OFF) {\n this._listen();\n }\n if (this._alanState !== ALAN_LISTENING) {\n console.error('invalid alan state: ' + this._alanState);\n return;\n }\n this._sendFormatIfNeeded(true);\n var f = alanFrame.create();\n f.audioData = frame;\n this._frameQueue.push(f);\n};\n\nConnectionImpl.prototype._sendFormatIfNeeded = function(inQueue) {\n if (!this._format || this._formatSent) {\n return;\n }\n this._formatSent = true;\n var f = alanFrame.create();\n f.jsonData = JSON.stringify({format: this._format});\n if (inQueue) {\n this._frameQueue.push(f);\n } else {\n this._sendFrame(f);\n }\n};\n\nConnectionImpl.prototype._flushQueue = function() {\n if (!this._socket || !this._connected) {\n var d = 0;\n while (this._frameQueue.length > 100 && !this._frameQueue[0].jsonData) {\n this._frameQueue.shift();\n d++;\n }\n if (d > 0) {\n console.error('dropped: %s, frames', d);\n }\n return;\n }\n while (this._frameQueue.length > 0 && this._socket && this._socket.bufferedAmount < 64 * 1024) {\n this._sendFrame(this._frameQueue.shift());\n }\n};\n\nfunction getConnectionDetails(url){\n var urlParts = url.split('/');\n var host = urlParts[2];\n \n // Find the index of 'ws_project' in the URL parts\n var wsProjectIndex = -1;\n for (var i = 0; i < urlParts.length; i++) {\n if (urlParts[i] === 'ws_project') {\n wsProjectIndex = i;\n break;\n }\n }\n \n var projectId = wsProjectIndex !== -1 ? urlParts[wsProjectIndex + 1] : null;\n var environment = wsProjectIndex !== -1 ? urlParts[wsProjectIndex + 2] : null;\n\n if (projectId && environment && host) {\n return ' (ProjectID: ' + projectId + ', environment: ' + environment + ', host: ' + host + ')';\n }\n\n return url;\n}\n\nfunction connectProject(config, auth, mode) {\n var c = new ConnectionImpl(config, auth, mode);\n c.onAudioEvent = function(event, arg1, arg2) {\n if (event === 'format') {\n c._onAudioFormat(arg1);\n } else if (event === 'frame') {\n c._onMicFrame(arg1, arg2);\n } else if (event === 'micStop') {\n c._stopListen();\n } else if (event === 'playStart') {\n // ignore\n } else {\n console.error('unknown audio event: ' + event, arg1, arg2);\n }\n };\n return c;\n}\n\nvar factories = {\n connectProject: connectProject,\n};\n\nvar currentConnect = null;\n\nonmessage = function(e) {\n var name = e.data[0];\n try {\n if (!currentConnect) {\n currentConnect = factories[name].apply(null, e.data.slice(1, e.data.length));\n } else {\n currentConnect[name].apply(currentConnect, e.data.slice(1, e.data.length));\n }\n } catch(e) {\n console.error('error calling: ' + name, e);\n }\n};\n"], {type: 'text/javascript'})));
228
228
  this._worker.onmessage = function(e) {
229
229
  if (e.data[0] === 'fireEvent') {
230
- _this._fire(e.data[1], e.data[2]);
230
+ _this._fire(e.data[1], e.data[2], e.data[3]);
231
231
  return;
232
232
  }
233
233
  if (e.data[0] === 'alanAudio') {
@@ -328,11 +328,11 @@
328
328
  this._worker.terminate();
329
329
  };
330
330
 
331
- ConnectionWrapper.prototype._fire = function(event, object) {
331
+ ConnectionWrapper.prototype._fire = function(event, object, data) {
332
332
  var h = this._handlers[event];
333
333
  if (h) {
334
334
  for (var i = 0; i < h.length; i++ ) {
335
- h[i](object);
335
+ h[i](object, data);
336
336
  }
337
337
  }
338
338
  };
@@ -98082,6 +98082,9 @@
98082
98082
  opacity:0.8;
98083
98083
  }`;
98084
98084
  }
98085
+ keyFrames += getStyleSheetMarker() + `.alan-btn__chat-send-btn.alan-btn__disconnected {
98086
+ pointer-events: none!important;
98087
+ }`;
98085
98088
  keyFrames += getStyleSheetMarker() + `.alan-btn__chat-mic-btn {
98086
98089
  position: absolute;
98087
98090
  left: 0px;
@@ -98875,7 +98878,9 @@
98875
98878
  width:${likeDislikeBtnWidth}px;
98876
98879
  min-width:${likeDislikeBtnWidth}px;
98877
98880
  height:${likeDislikeBtnHeight}px;
98881
+ max-height:${likeDislikeBtnHeight}px;
98878
98882
  min-height:${likeDislikeBtnHeight}px;
98883
+ overflow: hidden;
98879
98884
  ` : ``};
98880
98885
 
98881
98886
  }`;
@@ -98888,7 +98893,9 @@
98888
98893
  width:${likeDislikeBtnWidth}px;
98889
98894
  min-width:${likeDislikeBtnWidth}px;
98890
98895
  height:${likeDislikeBtnHeight}px;
98896
+ max-height:${likeDislikeBtnHeight}px;
98891
98897
  min-height:${likeDislikeBtnHeight}px;
98898
+ overflow: hidden;
98892
98899
  ` : ``};
98893
98900
  }`;
98894
98901
  keyFrames += styleSheetMarker + `.alan-btn__chat-response__copy-btn {
@@ -98900,7 +98907,9 @@
98900
98907
  width:${copyBtnWidth}px;
98901
98908
  min-width:${copyBtnWidth}px;
98902
98909
  height:${copyBtnHeight}px;
98910
+ max-height:${copyBtnHeight}px;
98903
98911
  min-height:${copyBtnHeight}px;
98912
+ overflow: hidden;
98904
98913
  ` : ``};
98905
98914
  }`;
98906
98915
  const bottomBtnsBgColor = textChatOptions?.bubbles?.response?.bottomBtns?.backgroundColor?.hover || `#dcddde`;
@@ -98919,14 +98928,17 @@
98919
98928
  keyFrames += styleSheetMarker + `.alan-btn__chat-response__copy-btn svg {
98920
98929
  width: 20px;
98921
98930
  }`;
98922
- keyFrames += styleSheetMarker + `.alan-btn__chat-response__copy-btn svg path {
98923
- fill: ${bottomBtnsColor};
98931
+ const customCopyIcon = textChatOptions?.bubbles?.response?.copyBtnAppearance?.default?.icon?.svg || textChatOptions?.bubbles?.response?.copyBtnAppearance?.selected?.icon?.svg;
98932
+ keyFrames += styleSheetMarker + ` .alan-btn__chat-response__copy-btn:not(.preview) svg path {
98933
+ fill: ${bottomBtnsColor};
98924
98934
  }`;
98925
- keyFrames += styleSheetMarker + `.alan-btn__chat-response__like-btn svg path {
98926
- fill: ${bottomBtnsColor};
98935
+ const customLikeIcon = textChatOptions?.bubbles?.response?.likeBtnAppearance?.default?.icon?.svg || textChatOptions?.bubbles?.response?.likeBtnAppearance?.selected?.icon?.svg;
98936
+ const customDislikeIcon = textChatOptions?.bubbles?.response?.dislikeBtnAppearance?.default?.icon?.svg || textChatOptions?.bubbles?.response?.dislikeBtnAppearance?.selected?.icon?.svg;
98937
+ keyFrames += styleSheetMarker + ` .alan-btn__chat-response__like-btn:not(.preview) svg path {
98938
+ fill: ${bottomBtnsColor};
98927
98939
  }`;
98928
- keyFrames += styleSheetMarker + `.alan-btn__chat-response__dislike-btn svg path {
98929
- fill: ${bottomBtnsColor};
98940
+ keyFrames += styleSheetMarker + ` .alan-btn__chat-response__dislike-btn:not(.preview) svg path {
98941
+ fill: ${bottomBtnsColor};
98930
98942
  }`;
98931
98943
  keyFrames += styleSheetMarker + `.alan-btn__chat-graph {
98932
98944
  display: none;
@@ -101024,24 +101036,46 @@ code.hljs {
101024
101036
  }
101025
101037
 
101026
101038
  // alan_btn/src/textChat/buildCommandsBlock.ts
101027
- function buildCommandsBlock(msg, textChatOptions) {
101039
+ function buildCommandsBlock(msg, textChatOptions, customClasses = "") {
101028
101040
  const isBlockVisible = msg.ctx?.enableFeedback || textChatOptions?.bubbles?.response?.copyBtn;
101029
101041
  return `<div class="alan-btn__chat-response-commands-wrapper ${isBlockVisible !== true ? "alan-btn__chat-response-commands-wrapper-hidden" : ""}">
101030
101042
  <div class="alan-btn__chat-response-commands-wrapper-content">
101031
- ${buildCopyBtnContent(msg)}
101043
+ ${buildCopyBtnContent(msg, textChatOptions, customClasses)}
101032
101044
  ${msg.ctx?.enableFeedback ? `
101033
- <span class="alan-btn__chat-response__like-btn ${msg.liked >= 1 ? "selected" : ""}">${getLikeSvgIcon(msg)}</span>
101034
- <span class="alan-btn__chat-response__dislike-btn ${msg.liked <= -1 ? "selected" : ""}">${getDislikeSvgIcon(msg)}</span>` : ""}
101045
+ <span class="alan-btn__chat-response__like-btn ${customClasses} ${msg.liked >= 1 ? "selected" : ""}">${getLikeSvgIcon(msg, textChatOptions)}</span>
101046
+ <span class="alan-btn__chat-response__dislike-btn ${customClasses} ${msg.liked <= -1 ? "selected" : ""}">${getDislikeSvgIcon(msg, textChatOptions)}</span>` : ""}
101035
101047
  </div></div>`;
101036
101048
  }
101037
- function getLikeSvgIcon(msg) {
101038
- return msg.liked === 1 ? chatIcons.likeSelected : chatIcons.like;
101049
+ function getLikeSvgIcon(msg, textChatOptions) {
101050
+ const likeIcon = textChatOptions?.bubbles?.response?.likeBtnAppearance?.default?.icon?.svg || chatIcons.like;
101051
+ const likeIconSelected = textChatOptions?.bubbles?.response?.likeBtnAppearance?.selected?.icon?.svg || chatIcons.likeSelected;
101052
+ return msg.liked === 1 ? likeIconSelected : likeIcon;
101053
+ }
101054
+ function getDislikeSvgIcon(msg, textChatOptions) {
101055
+ const dislikeIcon = textChatOptions?.bubbles?.response?.dislikeBtnAppearance?.default?.icon?.svg || chatIcons.dislike;
101056
+ const dislikeIconSelected = textChatOptions?.bubbles?.response?.dislikeBtnAppearance?.selected?.icon?.svg || chatIcons.dislikeSelected;
101057
+ return msg.liked === -1 ? dislikeIconSelected : dislikeIcon;
101058
+ }
101059
+ function setSvgClass(svg, className) {
101060
+ if (!svg || typeof svg !== "string") return "";
101061
+ if (/class\s*=\s*["'][^"']*["']/i.test(svg)) {
101062
+ return svg.replace(/class\s*=\s*(["'])([^"']*)\1/i, (match, quote, classes) => {
101063
+ if ((classes || "").split(/\s+/).includes(className)) return match;
101064
+ return `class=${quote}${className} ${classes}${quote}`;
101065
+ });
101066
+ }
101067
+ return svg.replace(/<svg\b/i, `<svg class="${className}"`);
101039
101068
  }
101040
- function getDislikeSvgIcon(msg) {
101041
- return msg.liked === -1 ? chatIcons.dislikeSelected : chatIcons.dislike;
101069
+ function getCopySvgIcon(textChatOptions) {
101070
+ const copyIcon = textChatOptions?.bubbles?.response?.copyBtnAppearance?.default?.icon?.svg || chatIcons.copy;
101071
+ return setSvgClass(copyIcon, "alan-btn__copy-icon");
101042
101072
  }
101043
- function buildCopyBtnContent(msg) {
101044
- const copyBtn = `<div class = "alan-btn__chat-response__copy-btn">${chatIcons.copy}${chatIcons.copied}</div>`;
101073
+ function getCopiedSvgIcon(textChatOptions) {
101074
+ const copiedIcon = textChatOptions?.bubbles?.response?.copyBtnAppearance?.selected?.icon?.svg || chatIcons.copied;
101075
+ return setSvgClass(copiedIcon, "alan-btn__copied-icon");
101076
+ }
101077
+ function buildCopyBtnContent(msg, textChatOptions, customClasses) {
101078
+ const copyBtn = `<div class = "alan-btn__chat-response__copy-btn ${customClasses}">${getCopySvgIcon(textChatOptions)}${getCopiedSvgIcon(textChatOptions)}</div>`;
101045
101079
  if (msg.initLoad) return copyBtn;
101046
101080
  return msg.type === "response" && isFinalMessage(msg) ? copyBtn : "";
101047
101081
  }
@@ -101054,12 +101088,12 @@ code.hljs {
101054
101088
  }
101055
101089
  }
101056
101090
  }
101057
- function resetStylesForLikeAndDislikeBtns(curMsgBubble, msg) {
101091
+ function resetStylesForLikeAndDislikeBtns(curMsgBubble, msg, textChatOptions) {
101058
101092
  const likeBtnEl = curMsgBubble.querySelector(".alan-btn__chat-response__like-btn");
101059
101093
  const dislikeBtnEl = curMsgBubble.querySelector(".alan-btn__chat-response__dislike-btn");
101060
101094
  if (likeBtnEl && dislikeBtnEl) {
101061
- likeBtnEl.innerHTML = getLikeSvgIcon(msg);
101062
- dislikeBtnEl.innerHTML = getDislikeSvgIcon(msg);
101095
+ likeBtnEl.innerHTML = getLikeSvgIcon(msg, textChatOptions);
101096
+ dislikeBtnEl.innerHTML = getDislikeSvgIcon(msg, textChatOptions);
101063
101097
  }
101064
101098
  }
101065
101099
  function deleteHiddenImagesWithCode(str) {
@@ -143607,8 +143641,8 @@ Expat https://libexpat.github.io
143607
143641
  // alan_btn/alan_btn.ts
143608
143642
  (function(ns) {
143609
143643
  const uiState10 = getUIState();
143610
- uiState10.lib.version = "alan-version.1.8.115".replace("alan-version.", "");
143611
- window.alanLib = { version: "alan-version.1.8.115".replace("alan-version.", "") };
143644
+ uiState10.lib.version = "alan-version.1.8.117".replace("alan-version.", "");
143645
+ window.alanLib = { version: "alan-version.1.8.117".replace("alan-version.", "") };
143612
143646
  if (window.alanBtn) {
143613
143647
  console.warn("Alan: the Alan Button source code has already added (v." + uiState10.lib.version + ")");
143614
143648
  }
@@ -143774,6 +143808,9 @@ Expat https://libexpat.github.io
143774
143808
  isActive: function() {
143775
143809
  return isAlanActive;
143776
143810
  },
143811
+ isModelReady: function() {
143812
+ return isModelReady;
143813
+ },
143777
143814
  sendText: (text5) => {
143778
143815
  _sendText(text5);
143779
143816
  },
@@ -143867,6 +143904,8 @@ Expat https://libexpat.github.io
143867
143904
  window.tutorProject.off("text", onTextCbInMicBtn);
143868
143905
  window.tutorProject.off("queryProgress", onQueryProgressCb);
143869
143906
  window.tutorProject.off("parsed", onParsedCbInMicBtn);
143907
+ window.tutorProject.off("modelUpdate", onModelUpdate);
143908
+ window.tutorProject.off("scripts", onScriptsUpdate);
143870
143909
  alanAudio.off("command", onCommandCbInMicBtn);
143871
143910
  alanAudio.off("afterText", onAfterTextCbInMicBtn);
143872
143911
  document.removeEventListener("click", alanBtnClickEventListener);
@@ -143919,6 +143958,7 @@ Expat https://libexpat.github.io
143919
143958
  "default": "ONLINE",
143920
143959
  "offline": "OFFLINE",
143921
143960
  "disconnected": "CONNECTING",
143961
+ "modelIsUpdating": "MODEL_IS_UPDATING",
143922
143962
  "listening": "LISTEN",
143923
143963
  "understood": "PROCESS",
143924
143964
  "intermediate": "PROCESS",
@@ -143933,6 +143973,7 @@ Expat https://libexpat.github.io
143933
143973
  var INTERMEDIATE = "intermediate";
143934
143974
  var UNDERSTOOD = "understood";
143935
143975
  var DISCONNECTED = "disconnected";
143976
+ var MODEL_IS_UPDATING = "modelIsUpdating";
143936
143977
  var OFFLINE = "offline";
143937
143978
  var LOW_VOLUME = "lowVolume";
143938
143979
  var PERMISSION_DENIED = "permissionDenied";
@@ -143953,6 +143994,9 @@ Expat https://libexpat.github.io
143953
143994
  var previousState = null;
143954
143995
  var isAlanSpeaking = false;
143955
143996
  var isAlanActive = false;
143997
+ var isModelReady = false;
143998
+ var modelHash = null;
143999
+ var scriptHash = null;
143956
144000
  var isLeftAligned = false;
143957
144001
  var isRightAligned = true;
143958
144002
  var isBottomAligned = false;
@@ -144687,6 +144731,8 @@ Expat https://libexpat.github.io
144687
144731
  window.tutorProject.on("text", onTextCbInMicBtn);
144688
144732
  window.tutorProject.on("queryProgress", onQueryProgressCb);
144689
144733
  window.tutorProject.on("parsed", onParsedCbInMicBtn);
144734
+ window.tutorProject.on("modelUpdate", onModelUpdate);
144735
+ window.tutorProject.on("scripts", onScriptsUpdate);
144690
144736
  alanAudio.on("command", onCommandCbInMicBtn);
144691
144737
  alanAudio.on("afterText", onAfterTextCbInMicBtn);
144692
144738
  }
@@ -145437,7 +145483,7 @@ Expat https://libexpat.github.io
145437
145483
  }
145438
145484
  return options2;
145439
145485
  }
145440
- function onConnectStatusChange(res) {
145486
+ function onConnectStatusChange(res, event) {
145441
145487
  if (res === "disconnected") {
145442
145488
  if (previousState !== OFFLINE) {
145443
145489
  switchState(getDefaultBtnState(DISCONNECTED));
@@ -145462,20 +145508,23 @@ ${getSavedDialogId() || "-"} (prev. dialog)`);
145462
145508
  onNewDialogAutoReconnect();
145463
145509
  } else {
145464
145510
  if (!(0, import_lodash2.isEmpty)(prevUserId) && (0, import_lodash2.isEmpty)(uiState10.userInfo.userId)) {
145465
- savePrevUserId(uiState10.userInfo.userId);
145466
- connectToNewDialog();
145467
- return;
145511
+ if (prevUserId !== "default") {
145512
+ savePrevUserId(uiState10.userInfo.userId);
145513
+ connectToNewDialog();
145514
+ return;
145515
+ }
145468
145516
  }
145469
145517
  saveDialogId(dialogId);
145470
145518
  restoreMessagesInChat(true);
145471
145519
  }
145520
+ saveDialogId(dialogId);
145472
145521
  console.info(`Alan: curDialogId:
145473
145522
  ${curDialogId}`);
145474
145523
  sendSyncPageState(null, "onConnectStatusChange");
145475
145524
  }
145476
145525
  }
145477
145526
  if (options.onConnectionStatus) {
145478
- options.onConnectionStatus(res);
145527
+ options.onConnectionStatus(res, event);
145479
145528
  }
145480
145529
  }
145481
145530
  function onMicAllowed() {
@@ -145499,9 +145548,13 @@ ${curDialogId}`);
145499
145548
  if (window.tutorProject) {
145500
145549
  window.tutorProject.off("recognized", onRecognizedCbInMicBtn);
145501
145550
  window.tutorProject.off("parsed", onParsedCbInMicBtn);
145551
+ window.tutorProject.off("modelUpdate", onModelUpdate);
145552
+ window.tutorProject.off("scripts", onScriptsUpdate);
145502
145553
  window.tutorProject.off("options", onOptionsReceived);
145503
145554
  window.tutorProject.on("recognized", onRecognizedCbInMicBtn);
145504
145555
  window.tutorProject.on("parsed", onParsedCbInMicBtn);
145556
+ window.tutorProject.on("modelUpdate", onModelUpdate);
145557
+ window.tutorProject.on("scripts", onScriptsUpdate);
145505
145558
  window.tutorProject.on("options", onOptionsReceived);
145506
145559
  }
145507
145560
  }
@@ -145524,6 +145577,8 @@ ${curDialogId}`);
145524
145577
  window.tutorProject.off("recognized", onRecognizedCbInMicBtn);
145525
145578
  window.tutorProject.off("connectStatus", onConnectStatusChange);
145526
145579
  window.tutorProject.off("options", onOptionsReceived);
145580
+ window.tutorProject.off("modelUpdate", onModelUpdate);
145581
+ window.tutorProject.off("scripts", onScriptsUpdate);
145527
145582
  }
145528
145583
  if (options.onMicStopped) {
145529
145584
  options.onMicStopped();
@@ -145665,6 +145720,37 @@ ${curDialogId}`);
145665
145720
  deactivateAlanButton();
145666
145721
  }
145667
145722
  }
145723
+ function onScriptsUpdate(e) {
145724
+ scriptHash = e.hash;
145725
+ if (scriptHash && modelHash) {
145726
+ if (scriptHash === modelHash) {
145727
+ isModelReady = true;
145728
+ switchState(DEFAULT);
145729
+ sendSyncPageState(null, "model_is_ready");
145730
+ } else {
145731
+ isModelReady = false;
145732
+ switchState(MODEL_IS_UPDATING);
145733
+ manageAutocompeteInChat();
145734
+ }
145735
+ }
145736
+ }
145737
+ function onModelUpdate(e) {
145738
+ if (e?.modelHash && e?.scriptHash) {
145739
+ if (e?.modelHash !== e?.scriptHash) {
145740
+ isModelReady = false;
145741
+ switchState(MODEL_IS_UPDATING);
145742
+ modelHash = e.modelHash;
145743
+ scriptHash = e.scriptHash;
145744
+ manageAutocompeteInChat();
145745
+ } else {
145746
+ isModelReady = true;
145747
+ switchState(DEFAULT);
145748
+ modelHash = e.modelHash;
145749
+ scriptHash = e.scriptHash;
145750
+ sendSyncPageState(null, "model_is_ready");
145751
+ }
145752
+ }
145753
+ }
145668
145754
  function onParsedCbInMicBtn(e) {
145669
145755
  const event = Object.assign(e, { name: "parsed" });
145670
145756
  storeSocketHistory(event);
@@ -146013,7 +146099,7 @@ ${curDialogId}`);
146013
146099
  msg.liked = msg.liked !== -1 ? -1 : 0;
146014
146100
  }
146015
146101
  changeMsgLikeStatus(msg, options);
146016
- resetStylesForLikeAndDislikeBtns(curMsgBubble, msg);
146102
+ resetStylesForLikeAndDislikeBtns(curMsgBubble, msg, uiState10.textChat.options);
146017
146103
  saveMessageHistory();
146018
146104
  }
146019
146105
  document.removeEventListener("click", performLikeOrDislike);
@@ -146526,6 +146612,8 @@ ${curDialogId}`);
146526
146612
  window.tutorProject.off("text", onTextCbInMicBtn);
146527
146613
  window.tutorProject.off("queryProgress", onQueryProgressCb);
146528
146614
  window.tutorProject.off("parsed", onParsedCbInMicBtn);
146615
+ window.tutorProject.off("modelUpdate", onModelUpdate);
146616
+ window.tutorProject.off("scripts", onScriptsUpdate);
146529
146617
  window.tutorProject.off("connectStatus", onConnectStatusChange);
146530
146618
  window.tutorProject.off("options", onOptionsReceived);
146531
146619
  alanAudio.off("command", onCommandCbInMicBtn);
@@ -146607,6 +146695,10 @@ ${curDialogId}`);
146607
146695
  }
146608
146696
  async function _sendText(text5) {
146609
146697
  manageAutocompeteInChat();
146698
+ if (!canMsgBeSent()) {
146699
+ console.warn("Alan: message cannot be sent. Model is not ready or connection is not established.");
146700
+ return;
146701
+ }
146610
146702
  var msg = { text: text5, type: "request", name: "text" };
146611
146703
  sentMessageInd = null;
146612
146704
  clearMessageProgressStatusInterval();
@@ -146644,6 +146736,12 @@ ${curDialogId}`);
146644
146736
  clearTimeout(lastSendMsgTs);
146645
146737
  lastSendMsgTs = null;
146646
146738
  }
146739
+ function canMsgBeSent() {
146740
+ if (!isModelReady || state === DISCONNECTED || state === OFFLINE) {
146741
+ return false;
146742
+ }
146743
+ return true;
146744
+ }
146647
146745
  const sendMessageToTextChat = throttle(async function sendMessageToTextChat2() {
146648
146746
  var textareaEl = getChatTextareaEl();
146649
146747
  var textareaHolderEl = document.getElementById("textarea-holder");
@@ -146652,6 +146750,9 @@ ${curDialogId}`);
146652
146750
  if (lastSendMsgTs || text5?.length > maxChars) {
146653
146751
  return;
146654
146752
  }
146753
+ if (!canMsgBeSent()) {
146754
+ return;
146755
+ }
146655
146756
  lastSendMsgTs = setTimeout(() => {
146656
146757
  enableTextareaInTheChat();
146657
146758
  }, 5e3);
@@ -146724,6 +146825,10 @@ ${curDialogId}`);
146724
146825
  manageSendButtonAvailability();
146725
146826
  }
146726
146827
  function manageAutocompeteInChat() {
146828
+ if (!isModelReady) {
146829
+ clearChatAutocomplete(false);
146830
+ return;
146831
+ }
146727
146832
  if (uiState10.textChat?.autocomplete?.enabled === true) {
146728
146833
  checkIfNewComplitionNeeded();
146729
146834
  fillChatAutocompleteDebounced();
@@ -146963,6 +147068,9 @@ ${curDialogId}`);
146963
147068
  let hasRefocusedTextarea = false;
146964
147069
  let previousTextValue = "";
146965
147070
  function sendSyncPageState(forceUpdate = false, reason) {
147071
+ if (!isModelReady) {
147072
+ return;
147073
+ }
146966
147074
  syncPageState(null, forceUpdate, reason);
146967
147075
  }
146968
147076
  function onChatTextAreaFocus() {
@@ -147635,6 +147743,12 @@ ${curDialogId}`);
147635
147743
  var textareaHolderDiv = footerHolderDiv || document.getElementById("textarea-holder-content");
147636
147744
  if (chatSendBtn) {
147637
147745
  chatSendBtn.innerHTML = getSendChatIcon(uiState10?.textChat?.options);
147746
+ if (!isModelReady) {
147747
+ chatSendBtn.innerHTML = chatIcons.disconnected;
147748
+ chatSendBtn.classList.add("alan-btn__disconnected");
147749
+ } else {
147750
+ chatSendBtn.classList.remove("alan-btn__disconnected");
147751
+ }
147638
147752
  if (!textareaInnerDiv || !textareaHolderDiv) return;
147639
147753
  if (uiState10?.textChat?.options?.footer?.layout?.name !== "send-btn-outside") {
147640
147754
  textareaInnerDiv.appendChild(chatSendBtn);
@@ -147920,8 +148034,8 @@ ${curDialogId}`);
147920
148034
  btnOval2.style.animation = "";
147921
148035
  btnOval1.style.opacity = "0";
147922
148036
  btnOval2.style.opacity = "0";
147923
- } else if (newState === DISCONNECTED || newState === OFFLINE) {
147924
- if (newState === DISCONNECTED) {
148037
+ } else if (newState === DISCONNECTED || newState === OFFLINE || newState === MODEL_IS_UPDATING) {
148038
+ if (newState === DISCONNECTED || newState === MODEL_IS_UPDATING) {
147925
148039
  rootEl.classList.add("alan-btn-disconnected");
147926
148040
  }
147927
148041
  if (newState === OFFLINE) {
@@ -147943,7 +148057,7 @@ ${curDialogId}`);
147943
148057
  replyStateBtnIconImg
147944
148058
  ]
147945
148059
  );
147946
- if (newState === DISCONNECTED) {
148060
+ if (newState === DISCONNECTED || newState === MODEL_IS_UPDATING) {
147947
148061
  micIconDiv.style.opacity = "0";
147948
148062
  disconnectedMicLoaderIconImg.style.opacity = "1";
147949
148063
  } else {
@@ -147975,6 +148089,7 @@ ${curDialogId}`);
147975
148089
  if (textChatEl) {
147976
148090
  switch (newState) {
147977
148091
  case OFFLINE:
148092
+ case MODEL_IS_UPDATING:
147978
148093
  case DISCONNECTED:
147979
148094
  sendBtn.innerHTML = newState === OFFLINE ? chatIcons.noWiFi : chatIcons.disconnected;
147980
148095
  textChatEl.classList.add("alan-btn__disconnected");