@toothfairyai/cli 1.1.0 → 1.1.2
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/bin/toothfairy.js +868 -856
- package/package.json +1 -1
- package/src/api.js +573 -377
package/src/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const axios = require(
|
|
2
|
-
const fs = require(
|
|
3
|
-
const path = require(
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
4
|
|
|
5
5
|
class ToothFairyAPI {
|
|
6
6
|
constructor(
|
|
@@ -17,8 +17,8 @@ class ToothFairyAPI {
|
|
|
17
17
|
this.workspaceId = workspaceId;
|
|
18
18
|
this.verbose = verbose;
|
|
19
19
|
this.headers = {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
'x-api-key': apiKey,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -29,20 +29,20 @@ class ToothFairyAPI {
|
|
|
29
29
|
headers: this.headers,
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
if (method ===
|
|
32
|
+
if (method === 'POST' || method === 'PUT') {
|
|
33
33
|
if (data) {
|
|
34
34
|
data = { workspaceid: this.workspaceId, ...data };
|
|
35
35
|
}
|
|
36
36
|
config.data = data;
|
|
37
|
-
} else if (method ===
|
|
37
|
+
} else if (method === 'GET' && data) {
|
|
38
38
|
// For GET requests with data, add as query parameters
|
|
39
39
|
const params = new URLSearchParams(data);
|
|
40
40
|
config.url += `?${params.toString()}`;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
if (this.verbose) {
|
|
44
|
-
const chalk = require(
|
|
45
|
-
console.error(chalk.dim(
|
|
44
|
+
const chalk = require('chalk');
|
|
45
|
+
console.error(chalk.dim('\n--- API Request Debug ---'));
|
|
46
46
|
console.error(chalk.dim(`Method: ${method}`));
|
|
47
47
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
48
48
|
console.error(
|
|
@@ -53,15 +53,15 @@ class ToothFairyAPI {
|
|
|
53
53
|
chalk.dim(`Data: ${JSON.stringify(config.data, null, 2)}`)
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
|
-
console.error(chalk.dim(
|
|
56
|
+
console.error(chalk.dim('----------------------\n'));
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
try {
|
|
60
60
|
const response = await axios(config);
|
|
61
61
|
|
|
62
62
|
if (this.verbose) {
|
|
63
|
-
const chalk = require(
|
|
64
|
-
console.error(chalk.dim(
|
|
63
|
+
const chalk = require('chalk');
|
|
64
|
+
console.error(chalk.dim('\n--- API Response Debug ---'));
|
|
65
65
|
console.error(
|
|
66
66
|
chalk.dim(`Status: ${response.status} ${response.statusText}`)
|
|
67
67
|
);
|
|
@@ -73,14 +73,14 @@ class ToothFairyAPI {
|
|
|
73
73
|
console.error(
|
|
74
74
|
chalk.dim(`Response Data: ${JSON.stringify(response.data, null, 2)}`)
|
|
75
75
|
);
|
|
76
|
-
console.error(chalk.dim(
|
|
76
|
+
console.error(chalk.dim('------------------------\n'));
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
return response.data;
|
|
80
80
|
} catch (error) {
|
|
81
81
|
if (this.verbose) {
|
|
82
|
-
const chalk = require(
|
|
83
|
-
console.error(chalk.red(
|
|
82
|
+
const chalk = require('chalk');
|
|
83
|
+
console.error(chalk.red('\n--- API Error Debug ---'));
|
|
84
84
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
85
85
|
if (error.response) {
|
|
86
86
|
console.error(
|
|
@@ -110,13 +110,13 @@ class ToothFairyAPI {
|
|
|
110
110
|
)
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
|
-
console.error(chalk.red(
|
|
113
|
+
console.error(chalk.red('---------------------\n'));
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
if (error.response) {
|
|
117
117
|
throw new Error(
|
|
118
118
|
`HTTP ${error.response.status}: ${
|
|
119
|
-
error.response.data.message ||
|
|
119
|
+
error.response.data.message || 'API request failed'
|
|
120
120
|
}`
|
|
121
121
|
);
|
|
122
122
|
}
|
|
@@ -125,39 +125,39 @@ class ToothFairyAPI {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
async createChat(chatData) {
|
|
128
|
-
return this._makeRequest(
|
|
128
|
+
return this._makeRequest('POST', 'chat/create', chatData);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
async updateChat(chatData) {
|
|
132
|
-
return this._makeRequest(
|
|
132
|
+
return this._makeRequest('POST', 'chat/update', chatData);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
async getChat(chatId) {
|
|
136
|
-
return this._makeRequest(
|
|
136
|
+
return this._makeRequest('GET', `chat/get/${chatId}`);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
async createMessage(messageData) {
|
|
140
|
-
return this._makeRequest(
|
|
140
|
+
return this._makeRequest('POST', 'chat_message/create', messageData);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
async getMessage(messageId) {
|
|
144
|
-
return this._makeRequest(
|
|
144
|
+
return this._makeRequest('GET', `chat_message/get/${messageId}`);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
async getAllChats() {
|
|
148
|
-
return this._makeRequest(
|
|
148
|
+
return this._makeRequest('GET', 'chat/list', {
|
|
149
149
|
workspaceid: this.workspaceId,
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
async getAllMessagesByChat(chatid) {
|
|
153
|
-
return this._makeRequest(
|
|
153
|
+
return this._makeRequest('GET', 'chat_message/by_chat', {
|
|
154
154
|
chatid: chatid,
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
async getAgentResponse(agentData) {
|
|
159
159
|
const config = {
|
|
160
|
-
method:
|
|
160
|
+
method: 'POST',
|
|
161
161
|
url: `${this.aiUrl}/chatter`,
|
|
162
162
|
headers: this.headers,
|
|
163
163
|
data: { workspaceid: this.workspaceId, ...agentData },
|
|
@@ -170,7 +170,7 @@ class ToothFairyAPI {
|
|
|
170
170
|
if (error.response) {
|
|
171
171
|
throw new Error(
|
|
172
172
|
`HTTP ${error.response.status}: ${
|
|
173
|
-
error.response.data.message ||
|
|
173
|
+
error.response.data.message || 'Agent request failed'
|
|
174
174
|
}`
|
|
175
175
|
);
|
|
176
176
|
}
|
|
@@ -185,7 +185,8 @@ class ToothFairyAPI {
|
|
|
185
185
|
customerId = null,
|
|
186
186
|
providerId = null,
|
|
187
187
|
customerInfo = {},
|
|
188
|
-
attachments = {}
|
|
188
|
+
attachments = {},
|
|
189
|
+
chatId = null
|
|
189
190
|
) {
|
|
190
191
|
try {
|
|
191
192
|
// Use defaults for optional parameters
|
|
@@ -193,66 +194,92 @@ class ToothFairyAPI {
|
|
|
193
194
|
customerId ||
|
|
194
195
|
`cli-user-${
|
|
195
196
|
Math.abs(
|
|
196
|
-
message.split(
|
|
197
|
+
message.split('').reduce((a, b) => {
|
|
197
198
|
a = (a << 5) - a + b.charCodeAt(0);
|
|
198
199
|
return a & a;
|
|
199
200
|
}, 0)
|
|
200
201
|
) % 10000
|
|
201
202
|
}`;
|
|
202
|
-
phoneNumber = phoneNumber ||
|
|
203
|
-
providerId = providerId ||
|
|
203
|
+
phoneNumber = phoneNumber || '+1234567890';
|
|
204
|
+
providerId = providerId || 'default-sms-provider';
|
|
204
205
|
|
|
205
206
|
// Process file attachments if provided
|
|
206
207
|
const processedAttachments = await this._processAttachments(attachments);
|
|
207
208
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
209
|
+
if (chatId) {
|
|
210
|
+
// Use existing chat - create message in existing chat
|
|
211
|
+
const messageData = {
|
|
212
|
+
chatID: chatId,
|
|
213
|
+
text: message,
|
|
214
|
+
role: 'user',
|
|
215
|
+
userID: 'CLI',
|
|
216
|
+
...processedAttachments,
|
|
217
|
+
};
|
|
218
|
+
const createdMessage = await this.createMessage(messageData);
|
|
219
|
+
// console.log(`Message created: ${createdMessage.id}`);;
|
|
220
|
+
|
|
221
|
+
const agentData = {
|
|
222
|
+
chatid: chatId,
|
|
223
|
+
messages: [
|
|
224
|
+
{
|
|
225
|
+
text: createdMessage.text,
|
|
226
|
+
role: createdMessage.role,
|
|
227
|
+
userID: createdMessage.userID || 'System User',
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
agentid: agentId,
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const agentResponse = await this.getAgentResponse(agentData);
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
chatId: chatId,
|
|
237
|
+
messageId: createdMessage.id,
|
|
238
|
+
agentResponse: agentResponse,
|
|
239
|
+
};
|
|
240
|
+
} else {
|
|
241
|
+
// No chatId provided - let API create chat automatically
|
|
242
|
+
// Prepare message data for automatic chat creation
|
|
243
|
+
const messageData = {
|
|
244
|
+
text: message,
|
|
245
|
+
role: 'user',
|
|
246
|
+
userID: customerId,
|
|
247
|
+
};
|
|
236
248
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
249
|
+
// Only include attachment fields if they have content
|
|
250
|
+
if (processedAttachments.images && processedAttachments.images.length > 0) {
|
|
251
|
+
messageData.images = processedAttachments.images;
|
|
252
|
+
}
|
|
253
|
+
if (processedAttachments.audios && processedAttachments.audios.length > 0) {
|
|
254
|
+
messageData.audios = processedAttachments.audios;
|
|
255
|
+
}
|
|
256
|
+
if (processedAttachments.videos && processedAttachments.videos.length > 0) {
|
|
257
|
+
messageData.videos = processedAttachments.videos;
|
|
258
|
+
}
|
|
259
|
+
if (processedAttachments.files && processedAttachments.files.length > 0) {
|
|
260
|
+
messageData.files = processedAttachments.files;
|
|
261
|
+
}
|
|
250
262
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
263
|
+
// Send agent request without chatid - API will create chat and message automatically
|
|
264
|
+
const agentData = {
|
|
265
|
+
// No chatid - let API create the chat
|
|
266
|
+
messages: [messageData],
|
|
267
|
+
agentid: agentId,
|
|
268
|
+
// Include chat creation data since we're not pre-creating
|
|
269
|
+
phoneNumber: phoneNumber,
|
|
270
|
+
customerId: customerId,
|
|
271
|
+
providerId: providerId,
|
|
272
|
+
customerInfo: customerInfo,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const agentResponse = await this.getAgentResponse(agentData);
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
chatId: agentResponse.chatId || 'auto-generated',
|
|
279
|
+
messageId: agentResponse.messageId || 'auto-generated',
|
|
280
|
+
agentResponse: agentResponse,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
256
283
|
} catch (error) {
|
|
257
284
|
console.error(`Error in sendMessageToAgent: ${error.message}`);
|
|
258
285
|
throw error;
|
|
@@ -261,7 +288,7 @@ class ToothFairyAPI {
|
|
|
261
288
|
|
|
262
289
|
async searchDocuments(text, topK = 10, metadata = null) {
|
|
263
290
|
if (topK < 1 || topK > 50) {
|
|
264
|
-
throw new Error(
|
|
291
|
+
throw new Error('topK must be between 1 and 50');
|
|
265
292
|
}
|
|
266
293
|
|
|
267
294
|
const searchData = {
|
|
@@ -274,7 +301,7 @@ class ToothFairyAPI {
|
|
|
274
301
|
}
|
|
275
302
|
|
|
276
303
|
const config = {
|
|
277
|
-
method:
|
|
304
|
+
method: 'POST',
|
|
278
305
|
url: `${this.aiUrl}/searcher`,
|
|
279
306
|
headers: this.headers,
|
|
280
307
|
data: { workspaceid: this.workspaceId, ...searchData },
|
|
@@ -287,7 +314,7 @@ class ToothFairyAPI {
|
|
|
287
314
|
if (error.response) {
|
|
288
315
|
throw new Error(
|
|
289
316
|
`HTTP ${error.response.status}: ${
|
|
290
|
-
error.response.data.message ||
|
|
317
|
+
error.response.data.message || 'Search request failed'
|
|
291
318
|
}`
|
|
292
319
|
);
|
|
293
320
|
}
|
|
@@ -329,7 +356,7 @@ class ToothFairyAPI {
|
|
|
329
356
|
* - 'sse_event': All raw SSE events (only when showProgress=true)
|
|
330
357
|
*
|
|
331
358
|
* The onEvent callback receives: (eventType, eventData) => {}
|
|
332
|
-
*
|
|
359
|
+
*
|
|
333
360
|
* When showProgress is true, all SSE events will be emitted to the onEvent callback
|
|
334
361
|
* with the 'sse_event' type, providing access to all raw events from the streaming
|
|
335
362
|
* endpoint, similar to the CLI's --show-progress flag behavior.
|
|
@@ -343,7 +370,8 @@ class ToothFairyAPI {
|
|
|
343
370
|
customerInfo = {},
|
|
344
371
|
onEvent,
|
|
345
372
|
attachments = {},
|
|
346
|
-
showProgress = false
|
|
373
|
+
showProgress = false,
|
|
374
|
+
chatId = null
|
|
347
375
|
) {
|
|
348
376
|
try {
|
|
349
377
|
// Use defaults for optional parameters
|
|
@@ -351,204 +379,372 @@ class ToothFairyAPI {
|
|
|
351
379
|
customerId ||
|
|
352
380
|
`cli-user-${
|
|
353
381
|
Math.abs(
|
|
354
|
-
message.split(
|
|
382
|
+
message.split('').reduce((a, b) => {
|
|
355
383
|
a = (a << 5) - a + b.charCodeAt(0);
|
|
356
384
|
return a & a;
|
|
357
385
|
}, 0)
|
|
358
386
|
) % 10000
|
|
359
387
|
}`;
|
|
360
|
-
phoneNumber = phoneNumber ||
|
|
361
|
-
providerId = providerId ||
|
|
388
|
+
phoneNumber = phoneNumber || '+1234567890';
|
|
389
|
+
providerId = providerId || 'default-sms-provider';
|
|
362
390
|
|
|
363
391
|
// Process file attachments if provided
|
|
364
392
|
const processedAttachments = await this._processAttachments(attachments);
|
|
365
393
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
channelSettings: {
|
|
372
|
-
sms: {
|
|
373
|
-
isEnabled: true,
|
|
374
|
-
recipient: phoneNumber,
|
|
375
|
-
providerID: providerId,
|
|
376
|
-
},
|
|
377
|
-
},
|
|
378
|
-
customerId: customerId,
|
|
379
|
-
customerInfo: customerInfo,
|
|
380
|
-
isAIReplying: true,
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
const createdChat = await this.createChat(chatData);
|
|
384
|
-
if (this.verbose) {
|
|
385
|
-
console.debug(`Chat created: ${createdChat.id}`);
|
|
386
|
-
}
|
|
394
|
+
if (chatId) {
|
|
395
|
+
// Use existing chat - create message in existing chat
|
|
396
|
+
if (this.verbose) {
|
|
397
|
+
console.debug(`Using existing chat: ${chatId}`);
|
|
398
|
+
}
|
|
387
399
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
}
|
|
400
|
+
const messageData = {
|
|
401
|
+
chatID: chatId,
|
|
402
|
+
text: message,
|
|
403
|
+
role: 'user',
|
|
404
|
+
userID: 'CLI',
|
|
405
|
+
...processedAttachments,
|
|
406
|
+
};
|
|
407
|
+
const createdMessage = await this.createMessage(messageData);
|
|
408
|
+
if (this.verbose) {
|
|
409
|
+
console.debug(`Message created: ${createdMessage.id}`);
|
|
410
|
+
}
|
|
400
411
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
412
|
+
// Prepare agent data for streaming with existing chat
|
|
413
|
+
const agentData = {
|
|
414
|
+
workspaceid: this.workspaceId,
|
|
415
|
+
chatid: chatId,
|
|
416
|
+
messages: [
|
|
417
|
+
{
|
|
418
|
+
text: createdMessage.text,
|
|
419
|
+
role: createdMessage.role,
|
|
420
|
+
userID: createdMessage.userID || 'System User',
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
agentid: agentId,
|
|
424
|
+
};
|
|
413
425
|
|
|
414
|
-
|
|
415
|
-
|
|
426
|
+
// Stream the agent response using the dedicated streaming URL
|
|
427
|
+
const streamUrl = `${this.aiStreamUrl}/agent`;
|
|
428
|
+
|
|
429
|
+
return new Promise((resolve, reject) => {
|
|
430
|
+
// For POST requests with EventSource, we need to use a different approach
|
|
431
|
+
// EventSource doesn't support POST requests directly, so we'll use axios with streaming
|
|
432
|
+
const config = {
|
|
433
|
+
method: 'POST',
|
|
434
|
+
url: streamUrl,
|
|
435
|
+
headers: {
|
|
436
|
+
...this.headers,
|
|
437
|
+
Accept: 'text/event-stream',
|
|
438
|
+
'Cache-Control': 'no-cache',
|
|
439
|
+
},
|
|
440
|
+
data: agentData,
|
|
441
|
+
responseType: 'stream',
|
|
442
|
+
timeout: 300000, // 5 minute timeout
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
axios(config)
|
|
446
|
+
.then((response) => {
|
|
447
|
+
let buffer = '';
|
|
448
|
+
|
|
449
|
+
response.data.on('data', (chunk) => {
|
|
450
|
+
buffer += chunk.toString();
|
|
451
|
+
|
|
452
|
+
// Process complete lines
|
|
453
|
+
const lines = buffer.split('\n');
|
|
454
|
+
buffer = lines.pop() || ''; // Keep the incomplete line in buffer
|
|
455
|
+
|
|
456
|
+
for (const line of lines) {
|
|
457
|
+
if (line.trim() === '') continue;
|
|
458
|
+
|
|
459
|
+
if (line.startsWith('data: ')) {
|
|
460
|
+
const dataStr = line.slice(6); // Remove 'data: ' prefix
|
|
461
|
+
|
|
462
|
+
try {
|
|
463
|
+
const eventData = JSON.parse(dataStr);
|
|
464
|
+
|
|
465
|
+
// If showProgress is enabled, emit all events
|
|
466
|
+
if (showProgress) {
|
|
467
|
+
// Emit all events with their raw structure
|
|
468
|
+
onEvent('sse_event', eventData);
|
|
469
|
+
}
|
|
416
470
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
471
|
+
// Standard event processing (always executed for backward compatibility)
|
|
472
|
+
if (eventData.status) {
|
|
473
|
+
if (eventData.status === 'connected') {
|
|
474
|
+
onEvent('status', eventData);
|
|
475
|
+
} else if (eventData.status === 'complete') {
|
|
476
|
+
onEvent('status', eventData);
|
|
477
|
+
} else if (eventData.status === 'inProgress') {
|
|
478
|
+
// Parse metadata to understand what's happening
|
|
479
|
+
let metadata = {};
|
|
480
|
+
if (eventData.metadata) {
|
|
481
|
+
try {
|
|
482
|
+
metadata = JSON.parse(eventData.metadata);
|
|
483
|
+
} catch (e) {
|
|
484
|
+
metadata = { raw_metadata: eventData.metadata };
|
|
485
|
+
}
|
|
486
|
+
}
|
|
432
487
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
488
|
+
// Determine progress type
|
|
489
|
+
if (metadata.agent_processing_status) {
|
|
490
|
+
const processingStatus =
|
|
491
|
+
metadata.agent_processing_status;
|
|
492
|
+
onEvent('progress', {
|
|
493
|
+
...eventData,
|
|
494
|
+
processing_status: processingStatus,
|
|
495
|
+
metadata_parsed: metadata,
|
|
496
|
+
});
|
|
497
|
+
} else {
|
|
498
|
+
onEvent('progress', {
|
|
499
|
+
...eventData,
|
|
500
|
+
metadata_parsed: metadata,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
} else if (eventData.status === 'fulfilled') {
|
|
504
|
+
// Final response with complete data
|
|
505
|
+
onEvent('complete', eventData);
|
|
506
|
+
}
|
|
507
|
+
} else if (eventData.text && eventData.type === 'message') {
|
|
508
|
+
// This is streaming text data
|
|
509
|
+
onEvent('data', eventData);
|
|
510
|
+
} else if (
|
|
511
|
+
eventData.type === 'message' &&
|
|
512
|
+
eventData.images !== undefined
|
|
513
|
+
) {
|
|
514
|
+
// Additional message metadata (images, files, etc.)
|
|
515
|
+
onEvent('metadata', eventData);
|
|
516
|
+
} else if (
|
|
517
|
+
eventData.type === 'message' &&
|
|
518
|
+
eventData.callbackMetadata
|
|
519
|
+
) {
|
|
520
|
+
// Callback metadata with function details and execution plan
|
|
521
|
+
onEvent('callback', eventData);
|
|
522
|
+
} else if (eventData.type === 'chat_created' || eventData.event === 'chat_created') {
|
|
523
|
+
// Chat creation event
|
|
524
|
+
onEvent('chat_created', eventData);
|
|
525
|
+
} else {
|
|
526
|
+
// Generic event data
|
|
527
|
+
onEvent('unknown', eventData);
|
|
528
|
+
}
|
|
529
|
+
} catch (e) {
|
|
530
|
+
console.error(
|
|
531
|
+
`Failed to parse SSE data: ${dataStr}, error: ${e.message}`
|
|
532
|
+
);
|
|
533
|
+
onEvent('error', {
|
|
534
|
+
error: 'json_decode_error',
|
|
535
|
+
raw_data: dataStr,
|
|
536
|
+
message: e.message,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
});
|
|
436
542
|
|
|
437
|
-
|
|
438
|
-
|
|
543
|
+
response.data.on('end', () => {
|
|
544
|
+
resolve();
|
|
545
|
+
});
|
|
439
546
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
547
|
+
response.data.on('error', (error) => {
|
|
548
|
+
onEvent('error', {
|
|
549
|
+
error: 'stream_error',
|
|
550
|
+
message: error.message,
|
|
551
|
+
});
|
|
552
|
+
reject(error);
|
|
553
|
+
});
|
|
554
|
+
})
|
|
555
|
+
.catch((error) => {
|
|
556
|
+
onEvent('error', {
|
|
557
|
+
error: 'request_error',
|
|
558
|
+
message: error.message,
|
|
559
|
+
});
|
|
560
|
+
reject(error);
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
} else {
|
|
564
|
+
// No chatId provided - let streaming API create chat automatically
|
|
565
|
+
if (this.verbose) {
|
|
566
|
+
console.debug('No chatId provided - letting API create chat automatically');
|
|
567
|
+
}
|
|
443
568
|
|
|
444
|
-
|
|
445
|
-
|
|
569
|
+
// Prepare message data for automatic chat creation
|
|
570
|
+
const messageData = {
|
|
571
|
+
text: message,
|
|
572
|
+
role: 'user',
|
|
573
|
+
userID: customerId,
|
|
574
|
+
};
|
|
446
575
|
|
|
447
|
-
|
|
448
|
-
|
|
576
|
+
// Only include attachment fields if they have content
|
|
577
|
+
if (processedAttachments.images && processedAttachments.images.length > 0) {
|
|
578
|
+
messageData.images = processedAttachments.images;
|
|
579
|
+
}
|
|
580
|
+
if (processedAttachments.audios && processedAttachments.audios.length > 0) {
|
|
581
|
+
messageData.audios = processedAttachments.audios;
|
|
582
|
+
}
|
|
583
|
+
if (processedAttachments.videos && processedAttachments.videos.length > 0) {
|
|
584
|
+
messageData.videos = processedAttachments.videos;
|
|
585
|
+
}
|
|
586
|
+
if (processedAttachments.files && processedAttachments.files.length > 0) {
|
|
587
|
+
messageData.files = processedAttachments.files;
|
|
588
|
+
}
|
|
449
589
|
|
|
450
|
-
|
|
451
|
-
|
|
590
|
+
// Send agent request without chatid - API will create chat and message automatically
|
|
591
|
+
const agentData = {
|
|
592
|
+
workspaceid: this.workspaceId,
|
|
593
|
+
// No chatid - let API create the chat
|
|
594
|
+
messages: [messageData],
|
|
595
|
+
agentid: agentId,
|
|
596
|
+
// Include chat creation data since we're not pre-creating
|
|
597
|
+
phoneNumber: phoneNumber,
|
|
598
|
+
customerId: customerId,
|
|
599
|
+
providerId: providerId,
|
|
600
|
+
customerInfo: customerInfo,
|
|
601
|
+
};
|
|
452
602
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
603
|
+
// Stream the agent response using the dedicated streaming URL
|
|
604
|
+
const streamUrl = `${this.aiStreamUrl}/agent`;
|
|
605
|
+
|
|
606
|
+
return new Promise((resolve, reject) => {
|
|
607
|
+
// For POST requests with EventSource, we need to use a different approach
|
|
608
|
+
// EventSource doesn't support POST requests directly, so we'll use axios with streaming
|
|
609
|
+
const config = {
|
|
610
|
+
method: 'POST',
|
|
611
|
+
url: streamUrl,
|
|
612
|
+
headers: {
|
|
613
|
+
...this.headers,
|
|
614
|
+
Accept: 'text/event-stream',
|
|
615
|
+
'Cache-Control': 'no-cache',
|
|
616
|
+
},
|
|
617
|
+
data: agentData,
|
|
618
|
+
responseType: 'stream',
|
|
619
|
+
timeout: 300000, // 5 minute timeout
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
axios(config)
|
|
623
|
+
.then((response) => {
|
|
624
|
+
let buffer = '';
|
|
625
|
+
|
|
626
|
+
response.data.on('data', (chunk) => {
|
|
627
|
+
buffer += chunk.toString();
|
|
628
|
+
|
|
629
|
+
// Process complete lines
|
|
630
|
+
const lines = buffer.split('\n');
|
|
631
|
+
buffer = lines.pop() || ''; // Keep the incomplete line in buffer
|
|
632
|
+
|
|
633
|
+
for (const line of lines) {
|
|
634
|
+
if (line.trim() === '') continue;
|
|
635
|
+
|
|
636
|
+
if (line.startsWith('data: ')) {
|
|
637
|
+
const dataStr = line.slice(6); // Remove 'data: ' prefix
|
|
638
|
+
|
|
639
|
+
try {
|
|
640
|
+
const eventData = JSON.parse(dataStr);
|
|
641
|
+
|
|
642
|
+
// If showProgress is enabled, emit all events
|
|
643
|
+
if (showProgress) {
|
|
644
|
+
// Emit all events with their raw structure
|
|
645
|
+
onEvent('sse_event', eventData);
|
|
646
|
+
}
|
|
458
647
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
648
|
+
// Standard event processing (always executed for backward compatibility)
|
|
649
|
+
if (eventData.status) {
|
|
650
|
+
if (eventData.status === 'connected') {
|
|
651
|
+
onEvent('status', eventData);
|
|
652
|
+
} else if (eventData.status === 'complete') {
|
|
653
|
+
onEvent('status', eventData);
|
|
654
|
+
} else if (eventData.status === 'inProgress') {
|
|
655
|
+
// Parse metadata to understand what's happening
|
|
656
|
+
let metadata = {};
|
|
657
|
+
if (eventData.metadata) {
|
|
658
|
+
try {
|
|
659
|
+
metadata = JSON.parse(eventData.metadata);
|
|
660
|
+
} catch (e) {
|
|
661
|
+
metadata = { raw_metadata: eventData.metadata };
|
|
662
|
+
}
|
|
473
663
|
}
|
|
474
|
-
}
|
|
475
664
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
665
|
+
// Determine progress type
|
|
666
|
+
if (metadata.agent_processing_status) {
|
|
667
|
+
const processingStatus =
|
|
668
|
+
metadata.agent_processing_status;
|
|
669
|
+
onEvent('progress', {
|
|
670
|
+
...eventData,
|
|
671
|
+
processing_status: processingStatus,
|
|
672
|
+
metadata_parsed: metadata,
|
|
673
|
+
});
|
|
674
|
+
} else {
|
|
675
|
+
onEvent('progress', {
|
|
676
|
+
...eventData,
|
|
677
|
+
metadata_parsed: metadata,
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
} else if (eventData.status === 'fulfilled') {
|
|
681
|
+
// Final response with complete data
|
|
682
|
+
onEvent('complete', eventData);
|
|
490
683
|
}
|
|
491
|
-
} else if (eventData.
|
|
492
|
-
//
|
|
493
|
-
onEvent('
|
|
684
|
+
} else if (eventData.text && eventData.type === 'message') {
|
|
685
|
+
// This is streaming text data
|
|
686
|
+
onEvent('data', eventData);
|
|
687
|
+
} else if (
|
|
688
|
+
eventData.type === 'message' &&
|
|
689
|
+
eventData.images !== undefined
|
|
690
|
+
) {
|
|
691
|
+
// Additional message metadata (images, files, etc.)
|
|
692
|
+
onEvent('metadata', eventData);
|
|
693
|
+
} else if (
|
|
694
|
+
eventData.type === 'message' &&
|
|
695
|
+
eventData.callbackMetadata
|
|
696
|
+
) {
|
|
697
|
+
// Callback metadata with function details and execution plan
|
|
698
|
+
onEvent('callback', eventData);
|
|
699
|
+
} else if (
|
|
700
|
+
eventData.type === 'chat_created' ||
|
|
701
|
+
eventData.event === 'chat_created'
|
|
702
|
+
) {
|
|
703
|
+
// Chat creation event
|
|
704
|
+
onEvent('chat_created', eventData);
|
|
705
|
+
} else {
|
|
706
|
+
// Generic event data
|
|
707
|
+
onEvent('unknown', eventData);
|
|
494
708
|
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
} else if (
|
|
505
|
-
eventData.type === 'message' &&
|
|
506
|
-
eventData.callbackMetadata
|
|
507
|
-
) {
|
|
508
|
-
// Callback metadata with function details and execution plan
|
|
509
|
-
onEvent('callback', eventData);
|
|
510
|
-
} else {
|
|
511
|
-
// Generic event data
|
|
512
|
-
onEvent('unknown', eventData);
|
|
709
|
+
} catch (e) {
|
|
710
|
+
console.error(
|
|
711
|
+
`Failed to parse SSE data: ${dataStr}, error: ${e.message}`
|
|
712
|
+
);
|
|
713
|
+
onEvent('error', {
|
|
714
|
+
error: 'json_decode_error',
|
|
715
|
+
raw_data: dataStr,
|
|
716
|
+
message: e.message,
|
|
717
|
+
});
|
|
513
718
|
}
|
|
514
|
-
} catch (e) {
|
|
515
|
-
console.error(
|
|
516
|
-
`Failed to parse SSE data: ${dataStr}, error: ${e.message}`
|
|
517
|
-
);
|
|
518
|
-
onEvent("error", {
|
|
519
|
-
error: "json_decode_error",
|
|
520
|
-
raw_data: dataStr,
|
|
521
|
-
message: e.message,
|
|
522
|
-
});
|
|
523
719
|
}
|
|
524
720
|
}
|
|
525
|
-
}
|
|
526
|
-
});
|
|
721
|
+
});
|
|
527
722
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
723
|
+
response.data.on('end', () => {
|
|
724
|
+
resolve();
|
|
725
|
+
});
|
|
531
726
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
727
|
+
response.data.on('error', (error) => {
|
|
728
|
+
onEvent('error', {
|
|
729
|
+
error: 'stream_error',
|
|
730
|
+
message: error.message,
|
|
731
|
+
});
|
|
732
|
+
reject(error);
|
|
733
|
+
});
|
|
734
|
+
})
|
|
735
|
+
.catch((error) => {
|
|
736
|
+
onEvent('error', {
|
|
737
|
+
error: 'request_error',
|
|
535
738
|
message: error.message,
|
|
536
739
|
});
|
|
537
740
|
reject(error);
|
|
538
741
|
});
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
onEvent("error", {
|
|
542
|
-
error: "request_error",
|
|
543
|
-
message: error.message,
|
|
544
|
-
});
|
|
545
|
-
reject(error);
|
|
546
|
-
});
|
|
547
|
-
});
|
|
742
|
+
});
|
|
743
|
+
}
|
|
548
744
|
} catch (error) {
|
|
549
745
|
console.error(`Error in sendMessageToAgentStream: ${error.message}`);
|
|
550
|
-
onEvent(
|
|
551
|
-
error:
|
|
746
|
+
onEvent('error', {
|
|
747
|
+
error: 'setup_error',
|
|
552
748
|
message: error.message,
|
|
553
749
|
});
|
|
554
750
|
throw error;
|
|
@@ -569,24 +765,24 @@ class ToothFairyAPI {
|
|
|
569
765
|
});
|
|
570
766
|
|
|
571
767
|
if (importType) {
|
|
572
|
-
params.append(
|
|
768
|
+
params.append('importType', importType);
|
|
573
769
|
}
|
|
574
770
|
|
|
575
771
|
if (contentType) {
|
|
576
|
-
params.append(
|
|
772
|
+
params.append('contentType', contentType);
|
|
577
773
|
}
|
|
578
774
|
|
|
579
775
|
const config = {
|
|
580
|
-
method:
|
|
776
|
+
method: 'GET',
|
|
581
777
|
url: `${this.baseUrl}/documents/requestPreSignedURL?${params.toString()}`,
|
|
582
778
|
headers: this.headers,
|
|
583
779
|
};
|
|
584
780
|
|
|
585
781
|
if (this.verbose) {
|
|
586
|
-
const chalk = require(
|
|
587
|
-
console.error(chalk.dim(
|
|
782
|
+
const chalk = require('chalk');
|
|
783
|
+
console.error(chalk.dim('\n--- Upload URL Request Debug ---'));
|
|
588
784
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
589
|
-
console.error(chalk.dim(
|
|
785
|
+
console.error(chalk.dim('----------------------------\n'));
|
|
590
786
|
}
|
|
591
787
|
|
|
592
788
|
try {
|
|
@@ -596,7 +792,7 @@ class ToothFairyAPI {
|
|
|
596
792
|
if (error.response) {
|
|
597
793
|
throw new Error(
|
|
598
794
|
`HTTP ${error.response.status}: ${
|
|
599
|
-
error.response.data.message ||
|
|
795
|
+
error.response.data.message || 'Upload URL request failed'
|
|
600
796
|
}`
|
|
601
797
|
);
|
|
602
798
|
}
|
|
@@ -656,14 +852,14 @@ class ToothFairyAPI {
|
|
|
656
852
|
finalContentType
|
|
657
853
|
);
|
|
658
854
|
if (this.verbose) {
|
|
659
|
-
const chalk = require(
|
|
660
|
-
console.error(chalk.dim(
|
|
855
|
+
const chalk = require('chalk');
|
|
856
|
+
console.error(chalk.dim('\n--- File Upload URL response ---'));
|
|
661
857
|
console.error(chalk.dim(`Raw response: ${JSON.stringify(uploadData)}`));
|
|
662
858
|
}
|
|
663
859
|
|
|
664
860
|
// Parse the nested response structure
|
|
665
861
|
let parsedUploadData;
|
|
666
|
-
if (uploadData.body && typeof uploadData.body ===
|
|
862
|
+
if (uploadData.body && typeof uploadData.body === 'string') {
|
|
667
863
|
try {
|
|
668
864
|
parsedUploadData = JSON.parse(uploadData.body);
|
|
669
865
|
} catch (error) {
|
|
@@ -676,18 +872,18 @@ class ToothFairyAPI {
|
|
|
676
872
|
}
|
|
677
873
|
|
|
678
874
|
if (!parsedUploadData.uploadURL) {
|
|
679
|
-
throw new Error(
|
|
875
|
+
throw new Error('Failed to get upload URL from server');
|
|
680
876
|
}
|
|
681
877
|
|
|
682
878
|
// Upload file to S3
|
|
683
879
|
const fileData = fs.readFileSync(filePath);
|
|
684
880
|
|
|
685
881
|
const uploadConfig = {
|
|
686
|
-
method:
|
|
882
|
+
method: 'PUT',
|
|
687
883
|
url: parsedUploadData.uploadURL,
|
|
688
884
|
data: fileData,
|
|
689
885
|
headers: {
|
|
690
|
-
|
|
886
|
+
'Content-Type': finalContentType,
|
|
691
887
|
},
|
|
692
888
|
maxContentLength: Infinity,
|
|
693
889
|
maxBodyLength: Infinity,
|
|
@@ -706,8 +902,8 @@ class ToothFairyAPI {
|
|
|
706
902
|
};
|
|
707
903
|
|
|
708
904
|
if (this.verbose) {
|
|
709
|
-
const chalk = require(
|
|
710
|
-
console.error(chalk.dim(
|
|
905
|
+
const chalk = require('chalk');
|
|
906
|
+
console.error(chalk.dim('\n--- File Upload Debug ---'));
|
|
711
907
|
console.error(chalk.dim(`File: ${filePath}`));
|
|
712
908
|
console.error(chalk.dim(`Original filename: ${originalFilename}`));
|
|
713
909
|
console.error(chalk.dim(`Sanitized filename: ${sanitizedFilename}`));
|
|
@@ -716,7 +912,7 @@ class ToothFairyAPI {
|
|
|
716
912
|
console.error(chalk.dim(`Content type: ${finalContentType}`));
|
|
717
913
|
console.error(chalk.dim(`Size: ${fileSizeInMB.toFixed(2)}MB`));
|
|
718
914
|
console.error(chalk.dim(`Upload URL: ${parsedUploadData.uploadURL}`));
|
|
719
|
-
console.error(chalk.dim(
|
|
915
|
+
console.error(chalk.dim('------------------------\n'));
|
|
720
916
|
}
|
|
721
917
|
|
|
722
918
|
try {
|
|
@@ -728,7 +924,7 @@ class ToothFairyAPI {
|
|
|
728
924
|
// Remove S3 bucket prefix from filePath to get clean filename for download
|
|
729
925
|
downloadFilename = parsedUploadData.filePath.replace(
|
|
730
926
|
/^s3:\/\/[^/]+\//,
|
|
731
|
-
|
|
927
|
+
''
|
|
732
928
|
);
|
|
733
929
|
}
|
|
734
930
|
|
|
@@ -746,7 +942,7 @@ class ToothFairyAPI {
|
|
|
746
942
|
if (error.response) {
|
|
747
943
|
throw new Error(
|
|
748
944
|
`Upload failed: HTTP ${error.response.status}: ${
|
|
749
|
-
error.response.data?.message ||
|
|
945
|
+
error.response.data?.message || 'File upload failed'
|
|
750
946
|
}`
|
|
751
947
|
);
|
|
752
948
|
}
|
|
@@ -762,7 +958,7 @@ class ToothFairyAPI {
|
|
|
762
958
|
* @param {string} context - Context for the download (default: "pdf")
|
|
763
959
|
* @returns {Promise<Object>} - Download URL and metadata
|
|
764
960
|
*/
|
|
765
|
-
async getDownloadUrl(filename, workspaceId, context =
|
|
961
|
+
async getDownloadUrl(filename, workspaceId, context = 'pdf') {
|
|
766
962
|
const params = new URLSearchParams({
|
|
767
963
|
filename: filename,
|
|
768
964
|
context: context,
|
|
@@ -770,7 +966,7 @@ class ToothFairyAPI {
|
|
|
770
966
|
});
|
|
771
967
|
|
|
772
968
|
const config = {
|
|
773
|
-
method:
|
|
969
|
+
method: 'GET',
|
|
774
970
|
url: `${
|
|
775
971
|
this.baseUrl
|
|
776
972
|
}/documents/requestDownloadURLIncognito?${params.toString()}`,
|
|
@@ -778,10 +974,10 @@ class ToothFairyAPI {
|
|
|
778
974
|
};
|
|
779
975
|
|
|
780
976
|
if (this.verbose) {
|
|
781
|
-
const chalk = require(
|
|
782
|
-
console.error(chalk.dim(
|
|
977
|
+
const chalk = require('chalk');
|
|
978
|
+
console.error(chalk.dim('\n--- Download URL Request Debug ---'));
|
|
783
979
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
784
|
-
console.error(chalk.dim(
|
|
980
|
+
console.error(chalk.dim('-----------------------------\n'));
|
|
785
981
|
}
|
|
786
982
|
|
|
787
983
|
try {
|
|
@@ -791,7 +987,7 @@ class ToothFairyAPI {
|
|
|
791
987
|
if (error.response) {
|
|
792
988
|
throw new Error(
|
|
793
989
|
`HTTP ${error.response.status}: ${
|
|
794
|
-
error.response.data.message ||
|
|
990
|
+
error.response.data.message || 'Download URL request failed'
|
|
795
991
|
}`
|
|
796
992
|
);
|
|
797
993
|
}
|
|
@@ -813,7 +1009,7 @@ class ToothFairyAPI {
|
|
|
813
1009
|
filename,
|
|
814
1010
|
workspaceId,
|
|
815
1011
|
outputPath,
|
|
816
|
-
context =
|
|
1012
|
+
context = 'pdf',
|
|
817
1013
|
onProgress = null
|
|
818
1014
|
) {
|
|
819
1015
|
// Get download URL
|
|
@@ -824,7 +1020,7 @@ class ToothFairyAPI {
|
|
|
824
1020
|
);
|
|
825
1021
|
|
|
826
1022
|
if (!downloadData.url) {
|
|
827
|
-
throw new Error(
|
|
1023
|
+
throw new Error('Failed to get download URL from server');
|
|
828
1024
|
}
|
|
829
1025
|
|
|
830
1026
|
// Ensure output directory exists
|
|
@@ -835,9 +1031,9 @@ class ToothFairyAPI {
|
|
|
835
1031
|
|
|
836
1032
|
// Download file
|
|
837
1033
|
const downloadConfig = {
|
|
838
|
-
method:
|
|
1034
|
+
method: 'GET',
|
|
839
1035
|
url: downloadData.url,
|
|
840
|
-
responseType:
|
|
1036
|
+
responseType: 'stream',
|
|
841
1037
|
onDownloadProgress: onProgress
|
|
842
1038
|
? (progressEvent) => {
|
|
843
1039
|
if (progressEvent.total) {
|
|
@@ -855,11 +1051,11 @@ class ToothFairyAPI {
|
|
|
855
1051
|
};
|
|
856
1052
|
|
|
857
1053
|
if (this.verbose) {
|
|
858
|
-
const chalk = require(
|
|
859
|
-
console.error(chalk.dim(
|
|
1054
|
+
const chalk = require('chalk');
|
|
1055
|
+
console.error(chalk.dim('\n--- File Download Debug ---'));
|
|
860
1056
|
console.error(chalk.dim(`Download URL: ${downloadData.url}`));
|
|
861
1057
|
console.error(chalk.dim(`Output Path: ${outputPath}`));
|
|
862
|
-
console.error(chalk.dim(
|
|
1058
|
+
console.error(chalk.dim('---------------------------\n'));
|
|
863
1059
|
}
|
|
864
1060
|
|
|
865
1061
|
try {
|
|
@@ -870,7 +1066,7 @@ class ToothFairyAPI {
|
|
|
870
1066
|
response.data.pipe(writer);
|
|
871
1067
|
|
|
872
1068
|
return new Promise((resolve, reject) => {
|
|
873
|
-
writer.on(
|
|
1069
|
+
writer.on('finish', () => {
|
|
874
1070
|
const stats = fs.statSync(outputPath);
|
|
875
1071
|
resolve({
|
|
876
1072
|
success: true,
|
|
@@ -879,13 +1075,13 @@ class ToothFairyAPI {
|
|
|
879
1075
|
sizeInMB: (stats.size / (1024 * 1024)).toFixed(2),
|
|
880
1076
|
});
|
|
881
1077
|
});
|
|
882
|
-
writer.on(
|
|
1078
|
+
writer.on('error', reject);
|
|
883
1079
|
});
|
|
884
1080
|
} catch (error) {
|
|
885
1081
|
if (error.response) {
|
|
886
1082
|
throw new Error(
|
|
887
1083
|
`Download failed: HTTP ${error.response.status}: ${
|
|
888
|
-
error.response.data?.message ||
|
|
1084
|
+
error.response.data?.message || 'File download failed'
|
|
889
1085
|
}`
|
|
890
1086
|
);
|
|
891
1087
|
}
|
|
@@ -901,11 +1097,11 @@ class ToothFairyAPI {
|
|
|
901
1097
|
*/
|
|
902
1098
|
_sanitizeFilename(filename) {
|
|
903
1099
|
// Remove non-alphanumeric characters except dots
|
|
904
|
-
let sanitized = filename.replace(/[^a-zA-Z0-9.]/g,
|
|
1100
|
+
let sanitized = filename.replace(/[^a-zA-Z0-9.]/g, '');
|
|
905
1101
|
|
|
906
1102
|
// Check length limit
|
|
907
1103
|
if (sanitized.length > 100) {
|
|
908
|
-
throw new Error(
|
|
1104
|
+
throw new Error('File name cannot be more than 100 characters.');
|
|
909
1105
|
}
|
|
910
1106
|
|
|
911
1107
|
// Add timestamp prefix like frontend
|
|
@@ -924,20 +1120,20 @@ class ToothFairyAPI {
|
|
|
924
1120
|
const ext = path.extname(filePath).toLowerCase().slice(1);
|
|
925
1121
|
|
|
926
1122
|
// Image extensions
|
|
927
|
-
const imageExts = [
|
|
1123
|
+
const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg'];
|
|
928
1124
|
// Video extensions
|
|
929
|
-
const videoExts = [
|
|
1125
|
+
const videoExts = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm'];
|
|
930
1126
|
// Audio extensions
|
|
931
|
-
const audioExts = [
|
|
1127
|
+
const audioExts = ['wav', 'mp3', 'aac', 'ogg', 'flac'];
|
|
932
1128
|
|
|
933
1129
|
if (imageExts.includes(ext)) {
|
|
934
|
-
return
|
|
1130
|
+
return 'imported-image';
|
|
935
1131
|
} else if (videoExts.includes(ext)) {
|
|
936
|
-
return
|
|
1132
|
+
return 'imported_video_files';
|
|
937
1133
|
} else if (audioExts.includes(ext)) {
|
|
938
|
-
return
|
|
1134
|
+
return 'imported_audio_files';
|
|
939
1135
|
} else {
|
|
940
|
-
return
|
|
1136
|
+
return 'imported_doc_files';
|
|
941
1137
|
}
|
|
942
1138
|
}
|
|
943
1139
|
|
|
@@ -951,38 +1147,38 @@ class ToothFairyAPI {
|
|
|
951
1147
|
const ext = path.extname(filePath).toLowerCase().slice(1);
|
|
952
1148
|
|
|
953
1149
|
const contentTypes = {
|
|
954
|
-
txt:
|
|
955
|
-
md:
|
|
956
|
-
html:
|
|
957
|
-
pdf:
|
|
958
|
-
json:
|
|
959
|
-
jsonl:
|
|
960
|
-
wav:
|
|
961
|
-
mp4:
|
|
962
|
-
png:
|
|
963
|
-
jpg:
|
|
964
|
-
jpeg:
|
|
965
|
-
csv:
|
|
966
|
-
docx:
|
|
967
|
-
xlsx:
|
|
968
|
-
pptx:
|
|
969
|
-
ppt:
|
|
970
|
-
java:
|
|
971
|
-
py:
|
|
972
|
-
js:
|
|
973
|
-
ts:
|
|
974
|
-
tsx:
|
|
975
|
-
jsx:
|
|
976
|
-
yaml:
|
|
977
|
-
yml:
|
|
978
|
-
sql:
|
|
979
|
-
sh:
|
|
980
|
-
php:
|
|
981
|
-
csharp:
|
|
982
|
-
rb:
|
|
1150
|
+
txt: 'text/plain',
|
|
1151
|
+
md: 'text/markdown',
|
|
1152
|
+
html: 'text/html',
|
|
1153
|
+
pdf: 'application/pdf',
|
|
1154
|
+
json: 'application/json',
|
|
1155
|
+
jsonl: 'application/json',
|
|
1156
|
+
wav: 'audio/wav',
|
|
1157
|
+
mp4: 'video/mp4',
|
|
1158
|
+
png: 'image/png',
|
|
1159
|
+
jpg: 'image/jpeg',
|
|
1160
|
+
jpeg: 'image/jpeg',
|
|
1161
|
+
csv: 'text/csv',
|
|
1162
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
1163
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
1164
|
+
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
1165
|
+
ppt: 'application/vnd.ms-powerpoint',
|
|
1166
|
+
java: 'text/plain',
|
|
1167
|
+
py: 'text/plain',
|
|
1168
|
+
js: 'text/plain',
|
|
1169
|
+
ts: 'text/plain',
|
|
1170
|
+
tsx: 'text/plain',
|
|
1171
|
+
jsx: 'text/plain',
|
|
1172
|
+
yaml: 'text/plain',
|
|
1173
|
+
yml: 'text/plain',
|
|
1174
|
+
sql: 'text/plain',
|
|
1175
|
+
sh: 'text/plain',
|
|
1176
|
+
php: 'text/plain',
|
|
1177
|
+
csharp: 'text/plain',
|
|
1178
|
+
rb: 'text/plain',
|
|
983
1179
|
};
|
|
984
1180
|
|
|
985
|
-
return contentTypes[ext] ||
|
|
1181
|
+
return contentTypes[ext] || 'application/octet-stream';
|
|
986
1182
|
}
|
|
987
1183
|
|
|
988
1184
|
/**
|
|
@@ -993,18 +1189,18 @@ class ToothFairyAPI {
|
|
|
993
1189
|
*/
|
|
994
1190
|
_getDocumentType(filePath) {
|
|
995
1191
|
// Check if it's a URL
|
|
996
|
-
if (filePath.startsWith(
|
|
997
|
-
return
|
|
1192
|
+
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
|
1193
|
+
return 'readComprehensionUrl';
|
|
998
1194
|
}
|
|
999
1195
|
|
|
1000
1196
|
// Check if it's a PDF file
|
|
1001
1197
|
const ext = path.extname(filePath).toLowerCase().slice(1);
|
|
1002
|
-
if (ext ===
|
|
1003
|
-
return
|
|
1198
|
+
if (ext === 'pdf') {
|
|
1199
|
+
return 'readComprehensionPdf';
|
|
1004
1200
|
}
|
|
1005
1201
|
|
|
1006
1202
|
// For all other file types (Excel, CSV, etc.)
|
|
1007
|
-
return
|
|
1203
|
+
return 'readComprehensionFile';
|
|
1008
1204
|
}
|
|
1009
1205
|
|
|
1010
1206
|
/**
|
|
@@ -1023,9 +1219,9 @@ class ToothFairyAPI {
|
|
|
1023
1219
|
filePath,
|
|
1024
1220
|
userId,
|
|
1025
1221
|
title = null,
|
|
1026
|
-
folderId =
|
|
1222
|
+
folderId = 'mrcRoot',
|
|
1027
1223
|
topics = [],
|
|
1028
|
-
status =
|
|
1224
|
+
status = 'published',
|
|
1029
1225
|
scope = null
|
|
1030
1226
|
) {
|
|
1031
1227
|
try {
|
|
@@ -1035,7 +1231,7 @@ class ToothFairyAPI {
|
|
|
1035
1231
|
// Use filename as title if not provided
|
|
1036
1232
|
let documentTitle = title;
|
|
1037
1233
|
if (!documentTitle) {
|
|
1038
|
-
if (filePath.startsWith(
|
|
1234
|
+
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
|
1039
1235
|
documentTitle = filePath;
|
|
1040
1236
|
} else {
|
|
1041
1237
|
documentTitle = path.basename(filePath);
|
|
@@ -1044,7 +1240,7 @@ class ToothFairyAPI {
|
|
|
1044
1240
|
|
|
1045
1241
|
// Determine external path based on file type
|
|
1046
1242
|
let externalPath;
|
|
1047
|
-
if (type ===
|
|
1243
|
+
if (type === 'readComprehensionUrl') {
|
|
1048
1244
|
externalPath = filePath; // Use URL directly
|
|
1049
1245
|
} else {
|
|
1050
1246
|
// For files, construct S3 path
|
|
@@ -1062,14 +1258,14 @@ class ToothFairyAPI {
|
|
|
1062
1258
|
topics: topics,
|
|
1063
1259
|
folderid: folderId,
|
|
1064
1260
|
external_path: externalPath,
|
|
1065
|
-
source:
|
|
1261
|
+
source: 'api',
|
|
1066
1262
|
status: status,
|
|
1067
1263
|
...(scope && { scope: scope }),
|
|
1068
1264
|
},
|
|
1069
1265
|
],
|
|
1070
1266
|
};
|
|
1071
1267
|
|
|
1072
|
-
return await this._makeRequest(
|
|
1268
|
+
return await this._makeRequest('POST', 'doc/create', documentData);
|
|
1073
1269
|
} catch (error) {
|
|
1074
1270
|
console.error(`Error creating document: ${error.message}`);
|
|
1075
1271
|
throw error;
|
|
@@ -1100,7 +1296,7 @@ class ToothFairyAPI {
|
|
|
1100
1296
|
},
|
|
1101
1297
|
};
|
|
1102
1298
|
|
|
1103
|
-
return await this._makeRequest(
|
|
1299
|
+
return await this._makeRequest('POST', 'doc/update', updateData);
|
|
1104
1300
|
} catch (error) {
|
|
1105
1301
|
console.error(`Error updating document: ${error.message}`);
|
|
1106
1302
|
throw error;
|
|
@@ -1115,7 +1311,7 @@ class ToothFairyAPI {
|
|
|
1115
1311
|
*/
|
|
1116
1312
|
async deleteDocument(documentId) {
|
|
1117
1313
|
try {
|
|
1118
|
-
return await this._makeRequest(
|
|
1314
|
+
return await this._makeRequest('DELETE', `doc/delete/${documentId}`);
|
|
1119
1315
|
} catch (error) {
|
|
1120
1316
|
console.error(`Error deleting document: ${error.message}`);
|
|
1121
1317
|
throw error;
|
|
@@ -1130,7 +1326,7 @@ class ToothFairyAPI {
|
|
|
1130
1326
|
*/
|
|
1131
1327
|
async getDocument(documentId) {
|
|
1132
1328
|
try {
|
|
1133
|
-
return await this._makeRequest(
|
|
1329
|
+
return await this._makeRequest('GET', `doc/get/${documentId}`);
|
|
1134
1330
|
} catch (error) {
|
|
1135
1331
|
console.error(`Error getting document: ${error.message}`);
|
|
1136
1332
|
throw error;
|
|
@@ -1152,7 +1348,7 @@ class ToothFairyAPI {
|
|
|
1152
1348
|
async createEntity(
|
|
1153
1349
|
userId,
|
|
1154
1350
|
label,
|
|
1155
|
-
type =
|
|
1351
|
+
type = 'topic',
|
|
1156
1352
|
description = null,
|
|
1157
1353
|
emoji = null,
|
|
1158
1354
|
parentEntity = null,
|
|
@@ -1170,7 +1366,7 @@ class ToothFairyAPI {
|
|
|
1170
1366
|
...(backgroundColor && { backgroundColor: backgroundColor }),
|
|
1171
1367
|
};
|
|
1172
1368
|
|
|
1173
|
-
return await this._makeRequest(
|
|
1369
|
+
return await this._makeRequest('POST', 'entity/create', entityData);
|
|
1174
1370
|
} catch (error) {
|
|
1175
1371
|
console.error(`Error creating entity: ${error.message}`);
|
|
1176
1372
|
throw error;
|
|
@@ -1197,7 +1393,7 @@ class ToothFairyAPI {
|
|
|
1197
1393
|
...fields,
|
|
1198
1394
|
};
|
|
1199
1395
|
|
|
1200
|
-
return await this._makeRequest(
|
|
1396
|
+
return await this._makeRequest('POST', 'entity/update', updateData);
|
|
1201
1397
|
} catch (error) {
|
|
1202
1398
|
console.error(`Error updating entity: ${error.message}`);
|
|
1203
1399
|
throw error;
|
|
@@ -1212,7 +1408,7 @@ class ToothFairyAPI {
|
|
|
1212
1408
|
*/
|
|
1213
1409
|
async deleteEntity(entityId) {
|
|
1214
1410
|
try {
|
|
1215
|
-
return await this._makeRequest(
|
|
1411
|
+
return await this._makeRequest('DELETE', `entity/delete/${entityId}`);
|
|
1216
1412
|
} catch (error) {
|
|
1217
1413
|
console.error(`Error deleting entity: ${error.message}`);
|
|
1218
1414
|
throw error;
|
|
@@ -1227,7 +1423,7 @@ class ToothFairyAPI {
|
|
|
1227
1423
|
*/
|
|
1228
1424
|
async getEntity(entityId) {
|
|
1229
1425
|
try {
|
|
1230
|
-
return await this._makeRequest(
|
|
1426
|
+
return await this._makeRequest('GET', `entity/get/${entityId}`);
|
|
1231
1427
|
} catch (error) {
|
|
1232
1428
|
console.error(`Error getting entity: ${error.message}`);
|
|
1233
1429
|
throw error;
|
|
@@ -1246,7 +1442,7 @@ class ToothFairyAPI {
|
|
|
1246
1442
|
if (limit) {
|
|
1247
1443
|
params.limit = limit;
|
|
1248
1444
|
}
|
|
1249
|
-
return await this._makeRequest(
|
|
1445
|
+
return await this._makeRequest('GET', 'entity/list', params);
|
|
1250
1446
|
} catch (error) {
|
|
1251
1447
|
console.error(`Error listing entities: ${error.message}`);
|
|
1252
1448
|
throw error;
|
|
@@ -1284,7 +1480,7 @@ class ToothFairyAPI {
|
|
|
1284
1480
|
...(status && { status: status }),
|
|
1285
1481
|
...(parent && { parent: parent }),
|
|
1286
1482
|
};
|
|
1287
|
-
return await this._makeRequest(
|
|
1483
|
+
return await this._makeRequest('POST', 'folder/create', folderData);
|
|
1288
1484
|
} catch (error) {
|
|
1289
1485
|
console.error(`Error creating folder: ${error.message}`);
|
|
1290
1486
|
throw error;
|
|
@@ -1319,7 +1515,7 @@ class ToothFairyAPI {
|
|
|
1319
1515
|
...(status && { status: status }),
|
|
1320
1516
|
...(parent !== null && { parent: parent }),
|
|
1321
1517
|
};
|
|
1322
|
-
return await this._makeRequest(
|
|
1518
|
+
return await this._makeRequest('POST', 'folder/update', updateData);
|
|
1323
1519
|
} catch (error) {
|
|
1324
1520
|
console.error(`Error updating folder: ${error.message}`);
|
|
1325
1521
|
throw error;
|
|
@@ -1334,7 +1530,7 @@ class ToothFairyAPI {
|
|
|
1334
1530
|
*/
|
|
1335
1531
|
async deleteFolder(folderId) {
|
|
1336
1532
|
try {
|
|
1337
|
-
return await this._makeRequest(
|
|
1533
|
+
return await this._makeRequest('DELETE', `folder/delete/${folderId}`);
|
|
1338
1534
|
} catch (error) {
|
|
1339
1535
|
console.error(`Error deleting folder: ${error.message}`);
|
|
1340
1536
|
throw error;
|
|
@@ -1349,7 +1545,7 @@ class ToothFairyAPI {
|
|
|
1349
1545
|
*/
|
|
1350
1546
|
async getFolder(folderId) {
|
|
1351
1547
|
try {
|
|
1352
|
-
return await this._makeRequest(
|
|
1548
|
+
return await this._makeRequest('GET', `folder/get/${folderId}`);
|
|
1353
1549
|
} catch (error) {
|
|
1354
1550
|
console.error(`Error getting folder: ${error.message}`);
|
|
1355
1551
|
throw error;
|
|
@@ -1376,7 +1572,7 @@ class ToothFairyAPI {
|
|
|
1376
1572
|
if (offset) {
|
|
1377
1573
|
params.offset = offset;
|
|
1378
1574
|
}
|
|
1379
|
-
return await this._makeRequest(
|
|
1575
|
+
return await this._makeRequest('GET', 'folder/list', params);
|
|
1380
1576
|
} catch (error) {
|
|
1381
1577
|
console.error(`Error listing folders: ${error.message}`);
|
|
1382
1578
|
throw error;
|
|
@@ -1426,7 +1622,7 @@ class ToothFairyAPI {
|
|
|
1426
1622
|
...(promptPlaceholder && { promptPlaceholder: promptPlaceholder }),
|
|
1427
1623
|
...(availableToAgents && { availableToAgents: availableToAgents }),
|
|
1428
1624
|
};
|
|
1429
|
-
return await this._makeRequest(
|
|
1625
|
+
return await this._makeRequest('POST', 'prompt/create', promptData);
|
|
1430
1626
|
} catch (error) {
|
|
1431
1627
|
console.error(`Error creating prompt: ${error.message}`);
|
|
1432
1628
|
throw error;
|
|
@@ -1479,7 +1675,7 @@ class ToothFairyAPI {
|
|
|
1479
1675
|
availableToAgents: availableToAgents,
|
|
1480
1676
|
}),
|
|
1481
1677
|
};
|
|
1482
|
-
return await this._makeRequest(
|
|
1678
|
+
return await this._makeRequest('POST', 'prompt/update', updateData);
|
|
1483
1679
|
} catch (error) {
|
|
1484
1680
|
console.error(`Error updating prompt: ${error.message}`);
|
|
1485
1681
|
throw error;
|
|
@@ -1494,7 +1690,7 @@ class ToothFairyAPI {
|
|
|
1494
1690
|
*/
|
|
1495
1691
|
async deletePrompt(promptId) {
|
|
1496
1692
|
try {
|
|
1497
|
-
return await this._makeRequest(
|
|
1693
|
+
return await this._makeRequest('DELETE', `prompt/delete/${promptId}`);
|
|
1498
1694
|
} catch (error) {
|
|
1499
1695
|
console.error(`Error deleting prompt: ${error.message}`);
|
|
1500
1696
|
throw error;
|
|
@@ -1509,7 +1705,7 @@ class ToothFairyAPI {
|
|
|
1509
1705
|
*/
|
|
1510
1706
|
async getPrompt(promptId) {
|
|
1511
1707
|
try {
|
|
1512
|
-
return await this._makeRequest(
|
|
1708
|
+
return await this._makeRequest('GET', `prompt/get/${promptId}`);
|
|
1513
1709
|
} catch (error) {
|
|
1514
1710
|
console.error(`Error getting prompt: ${error.message}`);
|
|
1515
1711
|
throw error;
|
|
@@ -1536,7 +1732,7 @@ class ToothFairyAPI {
|
|
|
1536
1732
|
if (offset) {
|
|
1537
1733
|
params.offset = offset;
|
|
1538
1734
|
}
|
|
1539
|
-
return await this._makeRequest(
|
|
1735
|
+
return await this._makeRequest('GET', 'prompt/list', params);
|
|
1540
1736
|
} catch (error) {
|
|
1541
1737
|
console.error(`Error listing prompts: ${error.message}`);
|
|
1542
1738
|
throw error;
|
|
@@ -1561,18 +1757,18 @@ class ToothFairyAPI {
|
|
|
1561
1757
|
};
|
|
1562
1758
|
|
|
1563
1759
|
const config = {
|
|
1564
|
-
method:
|
|
1760
|
+
method: 'POST',
|
|
1565
1761
|
url: `${this.baseUrl}/media/audio_generation`,
|
|
1566
1762
|
headers: {
|
|
1567
|
-
|
|
1568
|
-
|
|
1763
|
+
'Content-Type': 'application/json',
|
|
1764
|
+
'x-api-key': this.headers['x-api-key'],
|
|
1569
1765
|
},
|
|
1570
1766
|
data: speechData,
|
|
1571
1767
|
};
|
|
1572
1768
|
|
|
1573
1769
|
if (this.verbose) {
|
|
1574
|
-
const chalk = require(
|
|
1575
|
-
console.error(chalk.dim(
|
|
1770
|
+
const chalk = require('chalk');
|
|
1771
|
+
console.error(chalk.dim('\n--- Speech Generation Request Debug ---'));
|
|
1576
1772
|
console.error(chalk.dim(`Method: ${config.method}`));
|
|
1577
1773
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
1578
1774
|
console.error(
|
|
@@ -1581,28 +1777,28 @@ class ToothFairyAPI {
|
|
|
1581
1777
|
console.error(
|
|
1582
1778
|
chalk.dim(`Data: ${JSON.stringify(config.data, null, 2)}`)
|
|
1583
1779
|
);
|
|
1584
|
-
console.error(chalk.dim(
|
|
1780
|
+
console.error(chalk.dim('--------------------------------------\n'));
|
|
1585
1781
|
}
|
|
1586
1782
|
|
|
1587
1783
|
const response = await axios(config);
|
|
1588
1784
|
|
|
1589
1785
|
if (this.verbose) {
|
|
1590
|
-
const chalk = require(
|
|
1591
|
-
console.error(chalk.dim(
|
|
1786
|
+
const chalk = require('chalk');
|
|
1787
|
+
console.error(chalk.dim('\n--- Speech Generation Response Debug ---'));
|
|
1592
1788
|
console.error(
|
|
1593
1789
|
chalk.dim(`Status: ${response.status} ${response.statusText}`)
|
|
1594
1790
|
);
|
|
1595
1791
|
console.error(
|
|
1596
1792
|
chalk.dim(`Response Data: ${JSON.stringify(response.data, null, 2)}`)
|
|
1597
1793
|
);
|
|
1598
|
-
console.error(chalk.dim(
|
|
1794
|
+
console.error(chalk.dim('---------------------------------------\n'));
|
|
1599
1795
|
}
|
|
1600
1796
|
|
|
1601
1797
|
return response.data;
|
|
1602
1798
|
} catch (error) {
|
|
1603
1799
|
if (this.verbose) {
|
|
1604
|
-
const chalk = require(
|
|
1605
|
-
console.error(chalk.red(
|
|
1800
|
+
const chalk = require('chalk');
|
|
1801
|
+
console.error(chalk.red('\n--- Speech Generation Error Debug ---'));
|
|
1606
1802
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
1607
1803
|
if (error.response) {
|
|
1608
1804
|
console.error(
|
|
@@ -1616,7 +1812,7 @@ class ToothFairyAPI {
|
|
|
1616
1812
|
)
|
|
1617
1813
|
);
|
|
1618
1814
|
}
|
|
1619
|
-
console.error(chalk.red(
|
|
1815
|
+
console.error(chalk.red('------------------------------------\n'));
|
|
1620
1816
|
}
|
|
1621
1817
|
console.error(`Error generating speech: ${error.message}`);
|
|
1622
1818
|
throw error;
|
|
@@ -1639,18 +1835,18 @@ class ToothFairyAPI {
|
|
|
1639
1835
|
};
|
|
1640
1836
|
|
|
1641
1837
|
const config = {
|
|
1642
|
-
method:
|
|
1838
|
+
method: 'POST',
|
|
1643
1839
|
url: `${this.baseUrl}/media/audio`,
|
|
1644
1840
|
headers: {
|
|
1645
|
-
|
|
1646
|
-
|
|
1841
|
+
'Content-Type': 'application/json',
|
|
1842
|
+
'x-api-key': this.headers['x-api-key'],
|
|
1647
1843
|
},
|
|
1648
1844
|
data: audioData,
|
|
1649
1845
|
};
|
|
1650
1846
|
|
|
1651
1847
|
if (this.verbose) {
|
|
1652
|
-
const chalk = require(
|
|
1653
|
-
console.error(chalk.dim(
|
|
1848
|
+
const chalk = require('chalk');
|
|
1849
|
+
console.error(chalk.dim('\n--- Audio Processing Request Debug ---'));
|
|
1654
1850
|
console.error(chalk.dim(`Method: ${config.method}`));
|
|
1655
1851
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
1656
1852
|
console.error(
|
|
@@ -1659,28 +1855,28 @@ class ToothFairyAPI {
|
|
|
1659
1855
|
console.error(
|
|
1660
1856
|
chalk.dim(`Data: ${JSON.stringify(config.data, null, 2)}`)
|
|
1661
1857
|
);
|
|
1662
|
-
console.error(chalk.dim(
|
|
1858
|
+
console.error(chalk.dim('------------------------------------\n'));
|
|
1663
1859
|
}
|
|
1664
1860
|
|
|
1665
1861
|
const response = await axios(config);
|
|
1666
1862
|
|
|
1667
1863
|
if (this.verbose) {
|
|
1668
|
-
const chalk = require(
|
|
1669
|
-
console.error(chalk.dim(
|
|
1864
|
+
const chalk = require('chalk');
|
|
1865
|
+
console.error(chalk.dim('\n--- Audio Processing Response Debug ---'));
|
|
1670
1866
|
console.error(
|
|
1671
1867
|
chalk.dim(`Status: ${response.status} ${response.statusText}`)
|
|
1672
1868
|
);
|
|
1673
1869
|
console.error(
|
|
1674
1870
|
chalk.dim(`Response Data: ${JSON.stringify(response.data, null, 2)}`)
|
|
1675
1871
|
);
|
|
1676
|
-
console.error(chalk.dim(
|
|
1872
|
+
console.error(chalk.dim('-------------------------------------\n'));
|
|
1677
1873
|
}
|
|
1678
1874
|
|
|
1679
1875
|
return response.data;
|
|
1680
1876
|
} catch (error) {
|
|
1681
1877
|
if (this.verbose) {
|
|
1682
|
-
const chalk = require(
|
|
1683
|
-
console.error(chalk.red(
|
|
1878
|
+
const chalk = require('chalk');
|
|
1879
|
+
console.error(chalk.red('\n--- Audio Processing Error Debug ---'));
|
|
1684
1880
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
1685
1881
|
if (error.response) {
|
|
1686
1882
|
console.error(
|
|
@@ -1694,7 +1890,7 @@ class ToothFairyAPI {
|
|
|
1694
1890
|
)
|
|
1695
1891
|
);
|
|
1696
1892
|
}
|
|
1697
|
-
console.error(chalk.red(
|
|
1893
|
+
console.error(chalk.red('----------------------------------\n'));
|
|
1698
1894
|
}
|
|
1699
1895
|
console.error(`Error processing audio: ${error.message}`);
|
|
1700
1896
|
throw error;
|
|
@@ -1721,16 +1917,16 @@ class ToothFairyAPI {
|
|
|
1721
1917
|
try {
|
|
1722
1918
|
// Validate attachment limits
|
|
1723
1919
|
if (attachments.images && attachments.images.length > 1) {
|
|
1724
|
-
throw new Error(
|
|
1920
|
+
throw new Error('Maximum 1 image attachment allowed');
|
|
1725
1921
|
}
|
|
1726
1922
|
if (attachments.audios && attachments.audios.length > 1) {
|
|
1727
|
-
throw new Error(
|
|
1923
|
+
throw new Error('Maximum 1 audio attachment allowed');
|
|
1728
1924
|
}
|
|
1729
1925
|
if (attachments.videos && attachments.videos.length > 1) {
|
|
1730
|
-
throw new Error(
|
|
1926
|
+
throw new Error('Maximum 1 video attachment allowed');
|
|
1731
1927
|
}
|
|
1732
1928
|
if (attachments.files && attachments.files.length > 5) {
|
|
1733
|
-
throw new Error(
|
|
1929
|
+
throw new Error('Maximum 5 file attachments allowed');
|
|
1734
1930
|
}
|
|
1735
1931
|
|
|
1736
1932
|
// Process images
|
|
@@ -1786,10 +1982,10 @@ class ToothFairyAPI {
|
|
|
1786
1982
|
}
|
|
1787
1983
|
|
|
1788
1984
|
if (this.verbose) {
|
|
1789
|
-
const chalk = require(
|
|
1790
|
-
console.error(chalk.dim(
|
|
1985
|
+
const chalk = require('chalk');
|
|
1986
|
+
console.error(chalk.dim('\n--- Processed Attachments ---'));
|
|
1791
1987
|
console.error(chalk.dim(`Result: ${JSON.stringify(result, null, 2)}`));
|
|
1792
|
-
console.error(chalk.dim(
|
|
1988
|
+
console.error(chalk.dim('-----------------------------\n'));
|
|
1793
1989
|
}
|
|
1794
1990
|
|
|
1795
1991
|
return result;
|