@aiqa/sdk 0.0.0

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/src/config.ts ADDED
@@ -0,0 +1,29 @@
1
+ export const MINIMAL_SUPPORT_VERSION = '1.0.0';
2
+
3
+ export interface SDKConfig {
4
+ url?: string;
5
+ jwtToken?: string;
6
+ path?: string;
7
+ enableLogging?: boolean;
8
+ }
9
+
10
+ let config: SDKConfig = {
11
+ url: 'ws://localhost:3025',
12
+ path: '/ws',
13
+ enableLogging: true
14
+ };
15
+
16
+ export function setConfig(newConfig: SDKConfig) {
17
+ config = { ...config, ...newConfig };
18
+ }
19
+
20
+ export function getConfig(): SDKConfig {
21
+ return config;
22
+ }
23
+
24
+ export function isLoggingEnabled(): boolean {
25
+ return config.enableLogging !== false; // Default to true if not explicitly set to false
26
+ }
27
+
28
+ export default config;
29
+
package/src/enum.ts ADDED
@@ -0,0 +1,16 @@
1
+ export enum Methods {
2
+ INIT_AUDIO_RECORDER = "INIT_AUDIO_RECORDER",
3
+ IS_ALIVE = "IS_ALIVE",
4
+
5
+ CREATE_APPLICATION = "CREATE_APPLICATION",
6
+ GET_APPLICATION = "GET_APPLICATION",
7
+ UPDATE_APPLICATION = "UPDATE_APPLICATION",
8
+ SET_ACTIVE_APPLICATION = "SET_ACTIVE_APPLICATION",
9
+ GET_ACTIVE_APPLICATION = "GET_ACTIVE_APPLICATION",
10
+
11
+ START_RECORDING = "START_RECORDING",
12
+ STOP_RECORDING = "STOP_RECORDING",
13
+ IS_RECORDING = "IS_RECORDING",
14
+
15
+ ADD_FACT = "ADD_FACT"
16
+ }
package/src/index.ts ADDED
@@ -0,0 +1,428 @@
1
+ import { Methods } from "./enum";
2
+ import service from "./service";
3
+ import { TApplication, TApplicationPayload, TApplicationFactPayload, TApplicationFact, TResponse, TFactIsMatched, TResult } from "./types";
4
+ import { setConfig, SDKConfig } from "./config";
5
+
6
+
7
+ const AiQaSdk = class {
8
+ events: {};
9
+
10
+ constructor(config?: SDKConfig) {
11
+ this.events = {};
12
+
13
+ if (config) {
14
+ setConfig(config);
15
+ }
16
+
17
+ // Проверяем есть ли соединение с ПайтонАпп и если нет, то мы кидаем ошибку. Установите или запустите приложение
18
+ // Постоянно должно стучатся и постоянно пытаться подключится
19
+ // После подключения проверить версию и кинуть ошибку если не совпадает версия
20
+ }
21
+
22
+ configure(config: SDKConfig) {
23
+ setConfig(config);
24
+ }
25
+
26
+ on(name: string, callback: (...args: any[]) => any) {
27
+ this.events[name] = callback;
28
+ }
29
+
30
+ off(name: string) {
31
+ delete this.events[name];
32
+ }
33
+
34
+ connect() {
35
+ service.connect(this.events);
36
+ }
37
+
38
+ disconnect() {
39
+ service.disconnect()
40
+ }
41
+
42
+ /// Is Alive
43
+
44
+
45
+
46
+ isAlive(cb: ({isAlive, error}: TResponse) => void) {
47
+ try {
48
+ const result = service.getStatus();
49
+ cb({isAlive: result})
50
+ }
51
+ catch(error) {
52
+ cb({error})
53
+ }
54
+ };
55
+
56
+ async isAliveAsync(): Promise<boolean> {
57
+ return new Promise(async (resolve, reject) => {
58
+ try {
59
+ const result = service.getStatus();
60
+ resolve(result);
61
+ }
62
+ catch(e) {
63
+ reject(e)
64
+ }
65
+ })
66
+ };
67
+
68
+ /// Get Application ??????
69
+
70
+ getApplication(id: string, cb:({application, error}: TResponse) => void) {
71
+ service.sendMessage(Methods.GET_APPLICATION, {id})
72
+ .then((application: TApplication) => {
73
+ cb({application})
74
+ })
75
+ .catch(({error}) => {
76
+ cb({error})
77
+ })
78
+ }
79
+
80
+ async getApplicationAsync(id: string): Promise<TApplication> {
81
+ return new Promise(async (resolve, reject) => {
82
+ try {
83
+ const application = await service.sendMessage(Methods.GET_APPLICATION, {id});
84
+ //@ts-ignore
85
+ resolve(application)
86
+ }
87
+ catch(e) {
88
+ reject(e)
89
+ }
90
+ })
91
+ }
92
+
93
+ /// Update Application
94
+
95
+ updateApplication(id: string, referenceId: string, cb: ({application, error}: TResponse) => void) {
96
+ service.sendMessage(Methods.UPDATE_APPLICATION, {id, referenceId})
97
+ .then((application: TApplication) => {
98
+ cb({application})
99
+ })
100
+ .catch(({error}) => {
101
+ cb({error})
102
+ })
103
+ }
104
+
105
+ async updateApplicationAsync(id: string, referenceId: string): Promise<TApplication> {
106
+ return new Promise(async (resolve, reject) => {
107
+ try {
108
+ const application = await service.sendMessage(Methods.UPDATE_APPLICATION, {id, referenceId});
109
+ //@ts-ignore
110
+ resolve(application)
111
+ }
112
+ catch(e) {
113
+ reject(e)
114
+ }
115
+ })
116
+ }
117
+
118
+ /// Create Application
119
+
120
+ createApplication(data: TApplicationPayload, cb: ({application, error}: TResponse) => void) {
121
+ service.sendMessage(Methods.CREATE_APPLICATION, data)
122
+ .then((application: TApplication) => {
123
+ cb({application})
124
+ })
125
+ .catch(({error}) => {
126
+ cb({error})
127
+ })
128
+ }
129
+
130
+ async createApplicationAsync(data: TApplicationPayload): Promise<TApplication> {
131
+ return new Promise(async (resolve, reject) => {
132
+ try {
133
+ const application = await service.sendMessage(Methods.CREATE_APPLICATION, data);
134
+ //@ts-ignore
135
+ resolve(application)
136
+ }
137
+ catch(e) {
138
+ reject(e)
139
+ }
140
+ })
141
+ }
142
+
143
+ /// Set Active Application
144
+
145
+ setActiveApplication(applicationId: string, cb: ({applicationIsActive, error}: TResponse) => void) {
146
+ service.sendMessage(Methods.SET_ACTIVE_APPLICATION, {applicationId, active: true})
147
+ .then((result: TResult) => {
148
+ if (!!result.error) {
149
+ cb({error: result.error})
150
+ } else if (typeof result.data === 'boolean') {
151
+ cb({applicationIsActive: result.data})
152
+ } else {
153
+ cb({error: new Error(`Type of response data for ${Methods.SET_ACTIVE_APPLICATION} method is not equal Boolean`)});
154
+ }
155
+ })
156
+ .catch((error: Error) => {
157
+ cb({error});
158
+ })
159
+ }
160
+
161
+ async setActiveApplicationAsync(applicationId: string): Promise<boolean> {
162
+ return new Promise(async (resolve, reject) => { //What return?
163
+ try {
164
+ const result = await service.sendMessage(Methods.SET_ACTIVE_APPLICATION, {applicationId, active: true});
165
+ //@ts-ignore
166
+ if (!!result.error) {
167
+ //@ts-ignore
168
+ reject(result.error)
169
+ //@ts-ignore
170
+ } else if (typeof result.data === 'boolean') {
171
+ //@ts-ignore
172
+ resolve(result.data)
173
+ } else {
174
+ reject(new Error(`Type of response data for ${Methods.SET_ACTIVE_APPLICATION} method is not equal Boolean`));
175
+ }
176
+ }
177
+ catch(e) {
178
+ reject(e)
179
+ }
180
+ })
181
+ }
182
+
183
+ /// Get Active Application
184
+
185
+ getActiveApplication(cb: ({application, error}: TResponse) => void) {
186
+ service.sendMessage(Methods.GET_ACTIVE_APPLICATION)
187
+ .then((application: TApplication | null) => {
188
+ cb({application})
189
+ })
190
+ .catch((error: Error) => {
191
+ cb({error});
192
+ })
193
+ }
194
+
195
+ async getActiveApplicationAsync(): Promise<TApplication | null> {
196
+ return new Promise(async (resolve, reject) => {
197
+ try {
198
+ const result = await service.sendMessage(Methods.GET_ACTIVE_APPLICATION);
199
+ //@ts-ignore
200
+ resolve(result)
201
+ }
202
+ catch(e) {
203
+ reject(e);
204
+ }
205
+ })
206
+ }
207
+
208
+ /// Reset Active Application
209
+ //ToDo Reset application is needed applicationId?
210
+ resetActiveApplication(cb: ({applicationIsActive, error}: TResponse) => void) {
211
+ service.sendMessage(Methods.SET_ACTIVE_APPLICATION, {active: false})
212
+ .then((result: TResult) => {
213
+ if (!!result.error) {
214
+ cb({error: result.error})
215
+ } else if (typeof result.data === 'boolean') {
216
+ cb({applicationIsActive: result.data})
217
+ } else {
218
+ cb({error: new Error(`Type of response data for ${Methods.SET_ACTIVE_APPLICATION} method is not equal Boolean`)});
219
+ }
220
+ })
221
+ .catch((error: Error) => {
222
+ cb({error});
223
+ })
224
+ }
225
+
226
+ async resetActiveApplicationAsync(): Promise<boolean> {
227
+ return new Promise(async (resolve, reject) => {
228
+ try {
229
+ const result = await service.sendMessage(Methods.SET_ACTIVE_APPLICATION, {active: false});
230
+ //@ts-ignore
231
+ if (!!result.error) {
232
+ //@ts-ignore
233
+ reject(result.error)
234
+ //@ts-ignore
235
+ } else if (typeof result.data === 'boolean') {
236
+ //@ts-ignore
237
+ resolve(result.data)
238
+ } else {
239
+ reject(new Error(`Type of response data for ${Methods.SET_ACTIVE_APPLICATION} method is not equal Boolean`));
240
+ }
241
+ }
242
+ catch(e) {
243
+ reject(e);
244
+ }
245
+ })
246
+ }
247
+
248
+ /// Add Fact
249
+
250
+ addFact(fact: TApplicationFactPayload, cb: ({factIsMatched, error}: TResponse) => void){
251
+ service.sendMessage(Methods.ADD_FACT, fact)
252
+ .then((result: TFactIsMatched) => {
253
+ cb({factIsMatched: result})
254
+ })
255
+ .catch((error: Error) => {
256
+ cb({error});
257
+ })
258
+ }
259
+
260
+ async addFactAsync (fact: TApplicationFactPayload): Promise<TFactIsMatched> {
261
+ return new Promise(async (resolve, reject) => {
262
+ try {
263
+ const result = await service.sendMessage(Methods.ADD_FACT, fact);
264
+ //@ts-ignore
265
+ resolve(result);
266
+ }
267
+ catch(e) {
268
+ reject(e);
269
+ }
270
+ })
271
+ }
272
+
273
+ /// Start Recording
274
+
275
+ startRecording(cb: ({recordingIsStarted, error}: TResponse) => void) {
276
+ service.sendMessage(Methods.START_RECORDING)
277
+ .then((result: TResult) => {
278
+ if (typeof result.data === 'boolean') {
279
+ cb({recordingIsStarted: result.data})
280
+ } else {
281
+ cb({error: new Error(`Type of response data for ${Methods.START_RECORDING} method is not equal Boolean`)})
282
+ }
283
+ })
284
+ .catch((error: Error) => {
285
+ cb({error})
286
+ })
287
+ }
288
+
289
+ async startRecordingAsync(): Promise<boolean> {
290
+ return new Promise(async (resolve, reject) => {
291
+ try {
292
+ const result = await service.sendMessage(Methods.START_RECORDING);
293
+ //@ts-ignore
294
+ if (!!result.error) {
295
+ //@ts-ignore
296
+ reject(result.error)
297
+ //@ts-ignore
298
+ } else if (typeof result.data === 'boolean') {
299
+ //@ts-ignore
300
+ resolve(result.data)
301
+ } else {
302
+ reject(new Error(`Type of response data for ${Methods.START_RECORDING} method is not equal Boolean`))
303
+ }
304
+ }
305
+ catch(error) {
306
+ reject(error)
307
+ }
308
+ })
309
+ }
310
+
311
+ /// Stop Recording
312
+
313
+ stopRecording(cb: ({recordingIsStopped, error}: TResponse) => void) {
314
+ service.sendMessage(Methods.STOP_RECORDING)
315
+ .then((result: TResult) => {
316
+ if (!!result.error) {
317
+ cb({error: result.error})
318
+ } else if (typeof result.data === 'boolean') {
319
+ cb({recordingIsStopped: result.data})
320
+ } else {
321
+ cb({error: new Error(`Type of response data for ${Methods.STOP_RECORDING} method is not equal Boolean`)})
322
+ }
323
+ })
324
+ .catch((error) => {
325
+ cb({error})
326
+ })
327
+ }
328
+
329
+ async stopRecordingAsync(): Promise<boolean> {
330
+ return new Promise(async (resolve, reject) => {
331
+ try {
332
+ const result = await service.sendMessage(Methods.STOP_RECORDING);
333
+ //@ts-ignore
334
+ if (!!result.error) {
335
+ //@ts-ignore
336
+ reject(result.error)
337
+ //@ts-ignore
338
+ } else if (typeof result.data === 'boolean') {
339
+ //@ts-ignore
340
+ resolve(result.data)
341
+ } else {
342
+ reject(new Error(`Type of response data for ${Methods.STOP_RECORDING} method is not equal Boolean`))
343
+ }
344
+ }
345
+ catch(error) {
346
+ reject(error)
347
+ }
348
+ })
349
+ }
350
+
351
+ /// Is Recording Now
352
+
353
+ isRecordingNow(cb: ({recordingIsActive, error}: TResponse) => void) {
354
+ service.sendMessage(Methods.IS_RECORDING)
355
+ .then((result: TResult) => {
356
+ if (!!result.error) {
357
+ cb({error: result.error})
358
+ } else if (typeof result.data === 'boolean') {
359
+ cb({recordingIsActive: result.data})
360
+ } else {
361
+ cb({error: new Error(`Type of response data for ${Methods.IS_RECORDING} method is not equal Boolean`)})
362
+ }
363
+ })
364
+ .catch((error: Error) => {
365
+ cb({error})
366
+ })
367
+ };
368
+
369
+ async isRecordingNowAsync(): Promise<boolean> {
370
+ return new Promise(async (resolve, reject) => {
371
+ try {
372
+ const result = await service.sendMessage(Methods.IS_RECORDING);
373
+ //@ts-ignore
374
+ if (!!result.error) {
375
+ //@ts-ignore
376
+ reject(result.error)
377
+ //@ts-ignore
378
+ } else if (typeof result.data === 'boolean') {
379
+ //@ts-ignore
380
+ resolve(result.data)
381
+ } else {
382
+ reject(new Error(`Type of response data for ${Methods.IS_RECORDING} method is not equal Boolean`))
383
+ }
384
+ }
385
+ catch(e) {
386
+ reject(e)
387
+ }
388
+ })
389
+ };
390
+ };
391
+
392
+ export default AiQaSdk;
393
+
394
+
395
+ /**
396
+ Validation for
397
+
398
+ - createApplication
399
+ policyNumber: string;
400
+ product: string;
401
+ insuredPhone: string;
402
+ clientName: string;
403
+
404
+ - addFact
405
+ {
406
+ "conversationId": "",
407
+ "applicationAliasKey": "",
408
+ "factId": "",
409
+ "fact_status": true,
410
+ "value": "string"
411
+ }
412
+
413
+ if user set wrong data we can make throw or call callback / reject function
414
+
415
+ and optional checking arg for
416
+
417
+ - getApplication
418
+ check string argument
419
+
420
+ - setApplication
421
+ check string argument
422
+
423
+ - onClick Play/Stop
424
+ check is the application active
425
+
426
+ - addFact
427
+ check is the application active
428
+ */
package/src/logger.ts ADDED
@@ -0,0 +1,37 @@
1
+ import { isLoggingEnabled } from "./config";
2
+
3
+ class Logger {
4
+ log(...args: any[]): void {
5
+ if (isLoggingEnabled()) {
6
+ console.log(...args);
7
+ }
8
+ }
9
+
10
+ error(...args: any[]): void {
11
+ if (isLoggingEnabled()) {
12
+ console.error(...args);
13
+ }
14
+ }
15
+
16
+ warn(...args: any[]): void {
17
+ if (isLoggingEnabled()) {
18
+ console.warn(...args);
19
+ }
20
+ }
21
+
22
+ info(...args: any[]): void {
23
+ if (isLoggingEnabled()) {
24
+ console.info(...args);
25
+ }
26
+ }
27
+
28
+ debug(...args: any[]): void {
29
+ if (isLoggingEnabled()) {
30
+ console.debug(...args);
31
+ }
32
+ }
33
+ }
34
+
35
+ export const logger = new Logger();
36
+ export default logger;
37
+
@@ -0,0 +1,139 @@
1
+ import { MINIMAL_SUPPORT_VERSION, getConfig } from "../config";
2
+ import { Methods } from "../enum";
3
+ import { TApplication, TApplicationFact, TFactIsMatched, TResult } from "../types";
4
+ import logger from "../logger";
5
+
6
+ // Use global io from CDN (loaded in index.html)
7
+ // @ts-ignore - window.io is loaded via CDN before this script
8
+ const io = (typeof window !== 'undefined' ? (window as any).io : null);
9
+
10
+ const queue: any[] = [];
11
+ const listenersList: any[] = [];
12
+ const excludedMessages: string[] = ['app_version'];
13
+
14
+ const service = {
15
+ connect(events) {
16
+ const self = this;
17
+ const config = getConfig();
18
+
19
+ logger.log('INIT WEBSOCKET', config.url);
20
+
21
+ if (!config.url) {
22
+ logger.log("WebSocket address is required.");
23
+ return;
24
+ }
25
+
26
+ const socketOptions: any = {
27
+ reconnectionDelayMax: 10000,
28
+ path: config.path || '/ws',
29
+ };
30
+
31
+ if (config.jwtToken) {
32
+ socketOptions.extraHeaders = {
33
+ 'Authorization': `Bearer ${config.jwtToken}`
34
+ };
35
+ }
36
+
37
+ this.websocketClient = io(config.url, socketOptions);
38
+
39
+ this.websocketClient.on('connect', () => {
40
+ logger.log("WebSocket connection established");
41
+
42
+ !!events['connect'] && events['connect']();
43
+ });
44
+
45
+ this.websocketClient.on('app_version', (version: string = '1.0.0') => {
46
+ if(!(MINIMAL_SUPPORT_VERSION <= version)) {
47
+ self.websocketClient.disconnect();
48
+ throw new Error (`You version of AIQAapp is out of date. Your version is ${version}. Required >= ${MINIMAL_SUPPORT_VERSION}. Please update your app.`)
49
+ } else {
50
+ self.websocketClient.emit(Methods.INIT_AUDIO_RECORDER, JSON.stringify({init: true})); //TODO Try remove JSON.stringify
51
+ }
52
+ })
53
+
54
+ this.websocketClient.on('close', (event) => {
55
+ logger.log("WebSocket connection closed", event);
56
+ !!events['close'] && events['close']();
57
+ });
58
+
59
+ this.websocketClient.on('disconnect', () => {
60
+ logger.log('Disconnected from WebSocket server');
61
+ !!events['disconnect'] && events['disconnect']();
62
+ });
63
+
64
+ this.websocketClient.io.on("error", (error) => {
65
+ logger.log("error", error);
66
+ !!events['error'] && events['error']();
67
+ });
68
+
69
+ this.websocketClient.io.on("reconnect_attempt", (attempt) => {
70
+ logger.log('reconnect_attempt', attempt);
71
+ !!events['reconnect_attempt'] && events['reconnect_attempt']();
72
+ });
73
+
74
+ this.websocketClient.io.on("reconnect_error", (error) => {
75
+ logger.log("reconnect_error", error);
76
+ !!events['reconnect_error'] && events['reconnect_error']();
77
+ });
78
+
79
+ this.websocketClient.io.on("reconnect_failed", (error) => {
80
+ logger.log("reconnect_failed", error);
81
+ !!events['reconnect_failed'] && events['reconnect_failed']();
82
+ });
83
+
84
+ this.websocketClient.onAny((eventName: string, eventData: any) => {
85
+ logger.log("Message from server:", eventName, eventData);
86
+ logger.log("excludedMessages", excludedMessages);
87
+ if(eventName && !excludedMessages.includes(eventName)) {
88
+ const response = eventData ? JSON.parse(eventData) : {};
89
+ const item = queue.find((item) => item.addressee === eventName);
90
+ const listener = listenersList.find((item) => item.addressee === eventName);
91
+
92
+ if (item && response.data) {
93
+ item.resolve({data: response.data});
94
+ self.removeFromQueue(item);
95
+ } else if (listener && response.data) {
96
+ listener.callback({data: response.data});
97
+ } else if (item && response.error) {
98
+ item.reject({error: response.error});
99
+ self.removeFromQueue(item);
100
+ } else if (listener && response.error) {
101
+ listener.callback({error: response.error});
102
+ } else {
103
+ logger.error('Problem with receiving message');
104
+ }
105
+ }
106
+ })
107
+ },
108
+
109
+ disconnect() {
110
+ this.websocketClient.disconnect()
111
+ },
112
+
113
+ addListener(addressee: string, _checkAppVersion: () => void) {
114
+ listenersList.push({addressee, callback: _checkAppVersion});
115
+ },
116
+
117
+ sendMessage(addressee: string, data?: any): Promise<TApplication | TApplicationFact | TFactIsMatched | TResult> {
118
+ const self = this;
119
+ const promise: Promise<TApplication | TApplicationFact | TFactIsMatched | boolean> = new Promise((resolve, reject) => {
120
+ queue.push({addressee, resolve, reject});
121
+ self.websocketClient.emit(addressee, data ? JSON.stringify(data) : undefined); //TODO Try remove JSON.stringify
122
+ })
123
+
124
+ return promise
125
+ },
126
+
127
+ removeFromQueue(item) {
128
+ const index = queue.indexOf(item);
129
+ if (index > -1) { // only splice array when item is found
130
+ queue.splice(index, 1); // 2nd parameter means remove one item only
131
+ }
132
+ },
133
+
134
+ getStatus() {
135
+ return this.websocketClient.connected;
136
+ }
137
+ }
138
+
139
+ export default service;