@toothfairyai/cli 1.1.1 → 1.1.3
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 +576 -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,96 @@ 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
|
-
recipient: phoneNumber,
|
|
216
|
-
providerID: providerId,
|
|
217
|
-
},
|
|
218
|
-
},
|
|
219
|
-
customerId: customerId,
|
|
220
|
-
customerInfo: customerInfo,
|
|
221
|
-
isAIReplying: true,
|
|
222
|
-
};
|
|
209
|
+
if (chatId) {
|
|
210
|
+
// Use existing chat - let REST endpoint handle message creation
|
|
211
|
+
const messageData = {
|
|
212
|
+
text: message,
|
|
213
|
+
role: 'user',
|
|
214
|
+
userID: 'CLI',
|
|
215
|
+
};
|
|
223
216
|
|
|
224
|
-
|
|
225
|
-
|
|
217
|
+
// Only include attachment fields if they have content
|
|
218
|
+
if (processedAttachments.images && processedAttachments.images.length > 0) {
|
|
219
|
+
messageData.images = processedAttachments.images;
|
|
220
|
+
}
|
|
221
|
+
if (processedAttachments.audios && processedAttachments.audios.length > 0) {
|
|
222
|
+
messageData.audios = processedAttachments.audios;
|
|
223
|
+
}
|
|
224
|
+
if (processedAttachments.videos && processedAttachments.videos.length > 0) {
|
|
225
|
+
messageData.videos = processedAttachments.videos;
|
|
226
|
+
}
|
|
227
|
+
if (processedAttachments.files && processedAttachments.files.length > 0) {
|
|
228
|
+
messageData.files = processedAttachments.files;
|
|
229
|
+
}
|
|
226
230
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
231
|
+
const agentData = {
|
|
232
|
+
chatid: chatId,
|
|
233
|
+
messages: [messageData],
|
|
234
|
+
agentid: agentId,
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const agentResponse = await this.getAgentResponse(agentData);
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
chatId: agentResponse.chatId || chatId,
|
|
241
|
+
messageId: agentResponse.messageId || 'auto-generated',
|
|
242
|
+
agentResponse: agentResponse,
|
|
243
|
+
};
|
|
244
|
+
} else {
|
|
245
|
+
// No chatId provided - let API create chat automatically
|
|
246
|
+
// Prepare message data for automatic chat creation
|
|
247
|
+
const messageData = {
|
|
248
|
+
text: message,
|
|
249
|
+
role: 'user',
|
|
250
|
+
userID: customerId,
|
|
251
|
+
};
|
|
236
252
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
253
|
+
// Only include attachment fields if they have content
|
|
254
|
+
if (processedAttachments.images && processedAttachments.images.length > 0) {
|
|
255
|
+
messageData.images = processedAttachments.images;
|
|
256
|
+
}
|
|
257
|
+
if (processedAttachments.audios && processedAttachments.audios.length > 0) {
|
|
258
|
+
messageData.audios = processedAttachments.audios;
|
|
259
|
+
}
|
|
260
|
+
if (processedAttachments.videos && processedAttachments.videos.length > 0) {
|
|
261
|
+
messageData.videos = processedAttachments.videos;
|
|
262
|
+
}
|
|
263
|
+
if (processedAttachments.files && processedAttachments.files.length > 0) {
|
|
264
|
+
messageData.files = processedAttachments.files;
|
|
265
|
+
}
|
|
250
266
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
267
|
+
// Send agent request without chatid - API will create chat and message automatically
|
|
268
|
+
const agentData = {
|
|
269
|
+
// No chatid - let API create the chat
|
|
270
|
+
messages: [messageData],
|
|
271
|
+
agentid: agentId,
|
|
272
|
+
// Include chat creation data since we're not pre-creating
|
|
273
|
+
phoneNumber: phoneNumber,
|
|
274
|
+
customerId: customerId,
|
|
275
|
+
providerId: providerId,
|
|
276
|
+
customerInfo: customerInfo,
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
const agentResponse = await this.getAgentResponse(agentData);
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
chatId: agentResponse.chatId || 'auto-generated',
|
|
283
|
+
messageId: agentResponse.messageId || 'auto-generated',
|
|
284
|
+
agentResponse: agentResponse,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
256
287
|
} catch (error) {
|
|
257
288
|
console.error(`Error in sendMessageToAgent: ${error.message}`);
|
|
258
289
|
throw error;
|
|
@@ -261,7 +292,7 @@ class ToothFairyAPI {
|
|
|
261
292
|
|
|
262
293
|
async searchDocuments(text, topK = 10, metadata = null) {
|
|
263
294
|
if (topK < 1 || topK > 50) {
|
|
264
|
-
throw new Error(
|
|
295
|
+
throw new Error('topK must be between 1 and 50');
|
|
265
296
|
}
|
|
266
297
|
|
|
267
298
|
const searchData = {
|
|
@@ -274,7 +305,7 @@ class ToothFairyAPI {
|
|
|
274
305
|
}
|
|
275
306
|
|
|
276
307
|
const config = {
|
|
277
|
-
method:
|
|
308
|
+
method: 'POST',
|
|
278
309
|
url: `${this.aiUrl}/searcher`,
|
|
279
310
|
headers: this.headers,
|
|
280
311
|
data: { workspaceid: this.workspaceId, ...searchData },
|
|
@@ -287,7 +318,7 @@ class ToothFairyAPI {
|
|
|
287
318
|
if (error.response) {
|
|
288
319
|
throw new Error(
|
|
289
320
|
`HTTP ${error.response.status}: ${
|
|
290
|
-
error.response.data.message ||
|
|
321
|
+
error.response.data.message || 'Search request failed'
|
|
291
322
|
}`
|
|
292
323
|
);
|
|
293
324
|
}
|
|
@@ -329,7 +360,7 @@ class ToothFairyAPI {
|
|
|
329
360
|
* - 'sse_event': All raw SSE events (only when showProgress=true)
|
|
330
361
|
*
|
|
331
362
|
* The onEvent callback receives: (eventType, eventData) => {}
|
|
332
|
-
*
|
|
363
|
+
*
|
|
333
364
|
* When showProgress is true, all SSE events will be emitted to the onEvent callback
|
|
334
365
|
* with the 'sse_event' type, providing access to all raw events from the streaming
|
|
335
366
|
* endpoint, similar to the CLI's --show-progress flag behavior.
|
|
@@ -343,7 +374,8 @@ class ToothFairyAPI {
|
|
|
343
374
|
customerInfo = {},
|
|
344
375
|
onEvent,
|
|
345
376
|
attachments = {},
|
|
346
|
-
showProgress = false
|
|
377
|
+
showProgress = false,
|
|
378
|
+
chatId = null
|
|
347
379
|
) {
|
|
348
380
|
try {
|
|
349
381
|
// Use defaults for optional parameters
|
|
@@ -351,207 +383,374 @@ class ToothFairyAPI {
|
|
|
351
383
|
customerId ||
|
|
352
384
|
`cli-user-${
|
|
353
385
|
Math.abs(
|
|
354
|
-
message.split(
|
|
386
|
+
message.split('').reduce((a, b) => {
|
|
355
387
|
a = (a << 5) - a + b.charCodeAt(0);
|
|
356
388
|
return a & a;
|
|
357
389
|
}, 0)
|
|
358
390
|
) % 10000
|
|
359
391
|
}`;
|
|
360
|
-
phoneNumber = phoneNumber ||
|
|
361
|
-
providerId = providerId ||
|
|
392
|
+
phoneNumber = phoneNumber || '+1234567890';
|
|
393
|
+
providerId = providerId || 'default-sms-provider';
|
|
362
394
|
|
|
363
395
|
// Process file attachments if provided
|
|
364
396
|
const processedAttachments = await this._processAttachments(attachments);
|
|
365
397
|
|
|
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
|
-
};
|
|
398
|
+
if (chatId) {
|
|
399
|
+
// Use existing chat - let SSE endpoint handle message creation
|
|
400
|
+
if (this.verbose) {
|
|
401
|
+
console.debug(`Using existing chat: ${chatId}`);
|
|
402
|
+
}
|
|
382
403
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
404
|
+
const messageData = {
|
|
405
|
+
text: message,
|
|
406
|
+
role: 'user',
|
|
407
|
+
userID: 'CLI',
|
|
408
|
+
};
|
|
387
409
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
410
|
+
// Only include attachment fields if they have content
|
|
411
|
+
if (processedAttachments.images && processedAttachments.images.length > 0) {
|
|
412
|
+
messageData.images = processedAttachments.images;
|
|
413
|
+
}
|
|
414
|
+
if (processedAttachments.audios && processedAttachments.audios.length > 0) {
|
|
415
|
+
messageData.audios = processedAttachments.audios;
|
|
416
|
+
}
|
|
417
|
+
if (processedAttachments.videos && processedAttachments.videos.length > 0) {
|
|
418
|
+
messageData.videos = processedAttachments.videos;
|
|
419
|
+
}
|
|
420
|
+
if (processedAttachments.files && processedAttachments.files.length > 0) {
|
|
421
|
+
messageData.files = processedAttachments.files;
|
|
422
|
+
}
|
|
400
423
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
userID: createdMessage.userID || "System User",
|
|
409
|
-
},
|
|
410
|
-
],
|
|
411
|
-
agentid: agentId,
|
|
412
|
-
};
|
|
424
|
+
// Prepare agent data for streaming with existing chat
|
|
425
|
+
const agentData = {
|
|
426
|
+
workspaceid: this.workspaceId,
|
|
427
|
+
chatid: chatId,
|
|
428
|
+
messages: [messageData],
|
|
429
|
+
agentid: agentId,
|
|
430
|
+
};
|
|
413
431
|
|
|
414
|
-
|
|
415
|
-
|
|
432
|
+
// Stream the agent response using the dedicated streaming URL
|
|
433
|
+
const streamUrl = `${this.aiStreamUrl}/agent`;
|
|
434
|
+
|
|
435
|
+
return new Promise((resolve, reject) => {
|
|
436
|
+
// For POST requests with EventSource, we need to use a different approach
|
|
437
|
+
// EventSource doesn't support POST requests directly, so we'll use axios with streaming
|
|
438
|
+
const config = {
|
|
439
|
+
method: 'POST',
|
|
440
|
+
url: streamUrl,
|
|
441
|
+
headers: {
|
|
442
|
+
...this.headers,
|
|
443
|
+
Accept: 'text/event-stream',
|
|
444
|
+
'Cache-Control': 'no-cache',
|
|
445
|
+
},
|
|
446
|
+
data: agentData,
|
|
447
|
+
responseType: 'stream',
|
|
448
|
+
timeout: 300000, // 5 minute timeout
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
axios(config)
|
|
452
|
+
.then((response) => {
|
|
453
|
+
let buffer = '';
|
|
454
|
+
|
|
455
|
+
response.data.on('data', (chunk) => {
|
|
456
|
+
buffer += chunk.toString();
|
|
457
|
+
|
|
458
|
+
// Process complete lines
|
|
459
|
+
const lines = buffer.split('\n');
|
|
460
|
+
buffer = lines.pop() || ''; // Keep the incomplete line in buffer
|
|
461
|
+
|
|
462
|
+
for (const line of lines) {
|
|
463
|
+
if (line.trim() === '') continue;
|
|
464
|
+
|
|
465
|
+
if (line.startsWith('data: ')) {
|
|
466
|
+
const dataStr = line.slice(6); // Remove 'data: ' prefix
|
|
467
|
+
|
|
468
|
+
try {
|
|
469
|
+
const eventData = JSON.parse(dataStr);
|
|
470
|
+
|
|
471
|
+
// If showProgress is enabled, emit all events
|
|
472
|
+
if (showProgress) {
|
|
473
|
+
// Emit all events with their raw structure
|
|
474
|
+
onEvent('sse_event', eventData);
|
|
475
|
+
}
|
|
416
476
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
477
|
+
// Standard event processing (always executed for backward compatibility)
|
|
478
|
+
if (eventData.status) {
|
|
479
|
+
if (eventData.status === 'connected') {
|
|
480
|
+
onEvent('status', eventData);
|
|
481
|
+
} else if (eventData.status === 'complete') {
|
|
482
|
+
onEvent('status', eventData);
|
|
483
|
+
} else if (eventData.status === 'inProgress') {
|
|
484
|
+
// Parse metadata to understand what's happening
|
|
485
|
+
let metadata = {};
|
|
486
|
+
if (eventData.metadata) {
|
|
487
|
+
try {
|
|
488
|
+
metadata = JSON.parse(eventData.metadata);
|
|
489
|
+
} catch (e) {
|
|
490
|
+
metadata = { raw_metadata: eventData.metadata };
|
|
491
|
+
}
|
|
492
|
+
}
|
|
432
493
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
494
|
+
// Determine progress type
|
|
495
|
+
if (metadata.agent_processing_status) {
|
|
496
|
+
const processingStatus =
|
|
497
|
+
metadata.agent_processing_status;
|
|
498
|
+
onEvent('progress', {
|
|
499
|
+
...eventData,
|
|
500
|
+
processing_status: processingStatus,
|
|
501
|
+
metadata_parsed: metadata,
|
|
502
|
+
});
|
|
503
|
+
} else {
|
|
504
|
+
onEvent('progress', {
|
|
505
|
+
...eventData,
|
|
506
|
+
metadata_parsed: metadata,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
} else if (eventData.status === 'fulfilled') {
|
|
510
|
+
// Final response with complete data
|
|
511
|
+
onEvent('complete', eventData);
|
|
512
|
+
}
|
|
513
|
+
} else if (eventData.text && eventData.type === 'message') {
|
|
514
|
+
// This is streaming text data
|
|
515
|
+
onEvent('data', eventData);
|
|
516
|
+
} else if (
|
|
517
|
+
eventData.type === 'message' &&
|
|
518
|
+
eventData.images !== undefined
|
|
519
|
+
) {
|
|
520
|
+
// Additional message metadata (images, files, etc.)
|
|
521
|
+
onEvent('metadata', eventData);
|
|
522
|
+
} else if (
|
|
523
|
+
eventData.type === 'message' &&
|
|
524
|
+
eventData.callbackMetadata
|
|
525
|
+
) {
|
|
526
|
+
// Callback metadata with function details and execution plan
|
|
527
|
+
onEvent('callback', eventData);
|
|
528
|
+
} else if (eventData.type === 'chat_created' || eventData.event === 'chat_created') {
|
|
529
|
+
// Chat creation event
|
|
530
|
+
onEvent('chat_created', eventData);
|
|
531
|
+
} else {
|
|
532
|
+
// Generic event data
|
|
533
|
+
onEvent('unknown', eventData);
|
|
534
|
+
}
|
|
535
|
+
} catch (e) {
|
|
536
|
+
console.error(
|
|
537
|
+
`Failed to parse SSE data: ${dataStr}, error: ${e.message}`
|
|
538
|
+
);
|
|
539
|
+
onEvent('error', {
|
|
540
|
+
error: 'json_decode_error',
|
|
541
|
+
raw_data: dataStr,
|
|
542
|
+
message: e.message,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
});
|
|
436
548
|
|
|
437
|
-
|
|
438
|
-
|
|
549
|
+
response.data.on('end', () => {
|
|
550
|
+
resolve();
|
|
551
|
+
});
|
|
439
552
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
553
|
+
response.data.on('error', (error) => {
|
|
554
|
+
onEvent('error', {
|
|
555
|
+
error: 'stream_error',
|
|
556
|
+
message: error.message,
|
|
557
|
+
});
|
|
558
|
+
reject(error);
|
|
559
|
+
});
|
|
560
|
+
})
|
|
561
|
+
.catch((error) => {
|
|
562
|
+
onEvent('error', {
|
|
563
|
+
error: 'request_error',
|
|
564
|
+
message: error.message,
|
|
565
|
+
});
|
|
566
|
+
reject(error);
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
} else {
|
|
570
|
+
// No chatId provided - let streaming API create chat automatically
|
|
571
|
+
if (this.verbose) {
|
|
572
|
+
console.debug('No chatId provided - letting API create chat automatically');
|
|
573
|
+
}
|
|
443
574
|
|
|
444
|
-
|
|
445
|
-
|
|
575
|
+
// Prepare message data for automatic chat creation
|
|
576
|
+
const messageData = {
|
|
577
|
+
text: message,
|
|
578
|
+
role: 'user',
|
|
579
|
+
userID: customerId,
|
|
580
|
+
};
|
|
446
581
|
|
|
447
|
-
|
|
448
|
-
|
|
582
|
+
// Only include attachment fields if they have content
|
|
583
|
+
if (processedAttachments.images && processedAttachments.images.length > 0) {
|
|
584
|
+
messageData.images = processedAttachments.images;
|
|
585
|
+
}
|
|
586
|
+
if (processedAttachments.audios && processedAttachments.audios.length > 0) {
|
|
587
|
+
messageData.audios = processedAttachments.audios;
|
|
588
|
+
}
|
|
589
|
+
if (processedAttachments.videos && processedAttachments.videos.length > 0) {
|
|
590
|
+
messageData.videos = processedAttachments.videos;
|
|
591
|
+
}
|
|
592
|
+
if (processedAttachments.files && processedAttachments.files.length > 0) {
|
|
593
|
+
messageData.files = processedAttachments.files;
|
|
594
|
+
}
|
|
449
595
|
|
|
450
|
-
|
|
451
|
-
|
|
596
|
+
// Send agent request without chatid - API will create chat and message automatically
|
|
597
|
+
const agentData = {
|
|
598
|
+
workspaceid: this.workspaceId,
|
|
599
|
+
// No chatid - let API create the chat
|
|
600
|
+
messages: [messageData],
|
|
601
|
+
agentid: agentId,
|
|
602
|
+
// Include chat creation data since we're not pre-creating
|
|
603
|
+
phoneNumber: phoneNumber,
|
|
604
|
+
customerId: customerId,
|
|
605
|
+
providerId: providerId,
|
|
606
|
+
customerInfo: customerInfo,
|
|
607
|
+
};
|
|
452
608
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
609
|
+
// Stream the agent response using the dedicated streaming URL
|
|
610
|
+
const streamUrl = `${this.aiStreamUrl}/agent`;
|
|
611
|
+
|
|
612
|
+
return new Promise((resolve, reject) => {
|
|
613
|
+
// For POST requests with EventSource, we need to use a different approach
|
|
614
|
+
// EventSource doesn't support POST requests directly, so we'll use axios with streaming
|
|
615
|
+
const config = {
|
|
616
|
+
method: 'POST',
|
|
617
|
+
url: streamUrl,
|
|
618
|
+
headers: {
|
|
619
|
+
...this.headers,
|
|
620
|
+
Accept: 'text/event-stream',
|
|
621
|
+
'Cache-Control': 'no-cache',
|
|
622
|
+
},
|
|
623
|
+
data: agentData,
|
|
624
|
+
responseType: 'stream',
|
|
625
|
+
timeout: 300000, // 5 minute timeout
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
axios(config)
|
|
629
|
+
.then((response) => {
|
|
630
|
+
let buffer = '';
|
|
631
|
+
|
|
632
|
+
response.data.on('data', (chunk) => {
|
|
633
|
+
buffer += chunk.toString();
|
|
634
|
+
|
|
635
|
+
// Process complete lines
|
|
636
|
+
const lines = buffer.split('\n');
|
|
637
|
+
buffer = lines.pop() || ''; // Keep the incomplete line in buffer
|
|
638
|
+
|
|
639
|
+
for (const line of lines) {
|
|
640
|
+
if (line.trim() === '') continue;
|
|
641
|
+
|
|
642
|
+
if (line.startsWith('data: ')) {
|
|
643
|
+
const dataStr = line.slice(6); // Remove 'data: ' prefix
|
|
644
|
+
|
|
645
|
+
try {
|
|
646
|
+
const eventData = JSON.parse(dataStr);
|
|
647
|
+
|
|
648
|
+
// If showProgress is enabled, emit all events
|
|
649
|
+
if (showProgress) {
|
|
650
|
+
// Emit all events with their raw structure
|
|
651
|
+
onEvent('sse_event', eventData);
|
|
652
|
+
}
|
|
458
653
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
654
|
+
// Standard event processing (always executed for backward compatibility)
|
|
655
|
+
if (eventData.status) {
|
|
656
|
+
if (eventData.status === 'connected') {
|
|
657
|
+
onEvent('status', eventData);
|
|
658
|
+
} else if (eventData.status === 'complete') {
|
|
659
|
+
onEvent('status', eventData);
|
|
660
|
+
} else if (eventData.status === 'inProgress') {
|
|
661
|
+
// Parse metadata to understand what's happening
|
|
662
|
+
let metadata = {};
|
|
663
|
+
if (eventData.metadata) {
|
|
664
|
+
try {
|
|
665
|
+
metadata = JSON.parse(eventData.metadata);
|
|
666
|
+
} catch (e) {
|
|
667
|
+
metadata = { raw_metadata: eventData.metadata };
|
|
668
|
+
}
|
|
473
669
|
}
|
|
474
|
-
}
|
|
475
670
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
671
|
+
// Determine progress type
|
|
672
|
+
if (metadata.agent_processing_status) {
|
|
673
|
+
const processingStatus =
|
|
674
|
+
metadata.agent_processing_status;
|
|
675
|
+
onEvent('progress', {
|
|
676
|
+
...eventData,
|
|
677
|
+
processing_status: processingStatus,
|
|
678
|
+
metadata_parsed: metadata,
|
|
679
|
+
});
|
|
680
|
+
} else {
|
|
681
|
+
onEvent('progress', {
|
|
682
|
+
...eventData,
|
|
683
|
+
metadata_parsed: metadata,
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
} else if (eventData.status === 'fulfilled') {
|
|
687
|
+
// Final response with complete data
|
|
688
|
+
onEvent('complete', eventData);
|
|
490
689
|
}
|
|
491
|
-
} else if (eventData.
|
|
492
|
-
//
|
|
493
|
-
onEvent('
|
|
690
|
+
} else if (eventData.text && eventData.type === 'message') {
|
|
691
|
+
// This is streaming text data
|
|
692
|
+
onEvent('data', eventData);
|
|
693
|
+
} else if (
|
|
694
|
+
eventData.type === 'message' &&
|
|
695
|
+
eventData.images !== undefined
|
|
696
|
+
) {
|
|
697
|
+
// Additional message metadata (images, files, etc.)
|
|
698
|
+
onEvent('metadata', eventData);
|
|
699
|
+
} else if (
|
|
700
|
+
eventData.type === 'message' &&
|
|
701
|
+
eventData.callbackMetadata
|
|
702
|
+
) {
|
|
703
|
+
// Callback metadata with function details and execution plan
|
|
704
|
+
onEvent('callback', eventData);
|
|
705
|
+
} else if (
|
|
706
|
+
eventData.type === 'chat_created' ||
|
|
707
|
+
eventData.event === 'chat_created'
|
|
708
|
+
) {
|
|
709
|
+
// Chat creation event
|
|
710
|
+
onEvent('chat_created', eventData);
|
|
711
|
+
} else {
|
|
712
|
+
// Generic event data
|
|
713
|
+
onEvent('unknown', eventData);
|
|
494
714
|
}
|
|
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 if (eventData.type === 'chat_created' || eventData.event === 'chat_created') {
|
|
511
|
-
// Chat creation event
|
|
512
|
-
onEvent('chat_created', eventData);
|
|
513
|
-
} else {
|
|
514
|
-
// Generic event data
|
|
515
|
-
onEvent('unknown', eventData);
|
|
715
|
+
} catch (e) {
|
|
716
|
+
console.error(
|
|
717
|
+
`Failed to parse SSE data: ${dataStr}, error: ${e.message}`
|
|
718
|
+
);
|
|
719
|
+
onEvent('error', {
|
|
720
|
+
error: 'json_decode_error',
|
|
721
|
+
raw_data: dataStr,
|
|
722
|
+
message: e.message,
|
|
723
|
+
});
|
|
516
724
|
}
|
|
517
|
-
} catch (e) {
|
|
518
|
-
console.error(
|
|
519
|
-
`Failed to parse SSE data: ${dataStr}, error: ${e.message}`
|
|
520
|
-
);
|
|
521
|
-
onEvent("error", {
|
|
522
|
-
error: "json_decode_error",
|
|
523
|
-
raw_data: dataStr,
|
|
524
|
-
message: e.message,
|
|
525
|
-
});
|
|
526
725
|
}
|
|
527
726
|
}
|
|
528
|
-
}
|
|
529
|
-
});
|
|
727
|
+
});
|
|
530
728
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
729
|
+
response.data.on('end', () => {
|
|
730
|
+
resolve();
|
|
731
|
+
});
|
|
534
732
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
733
|
+
response.data.on('error', (error) => {
|
|
734
|
+
onEvent('error', {
|
|
735
|
+
error: 'stream_error',
|
|
736
|
+
message: error.message,
|
|
737
|
+
});
|
|
738
|
+
reject(error);
|
|
739
|
+
});
|
|
740
|
+
})
|
|
741
|
+
.catch((error) => {
|
|
742
|
+
onEvent('error', {
|
|
743
|
+
error: 'request_error',
|
|
538
744
|
message: error.message,
|
|
539
745
|
});
|
|
540
746
|
reject(error);
|
|
541
747
|
});
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
onEvent("error", {
|
|
545
|
-
error: "request_error",
|
|
546
|
-
message: error.message,
|
|
547
|
-
});
|
|
548
|
-
reject(error);
|
|
549
|
-
});
|
|
550
|
-
});
|
|
748
|
+
});
|
|
749
|
+
}
|
|
551
750
|
} catch (error) {
|
|
552
751
|
console.error(`Error in sendMessageToAgentStream: ${error.message}`);
|
|
553
|
-
onEvent(
|
|
554
|
-
error:
|
|
752
|
+
onEvent('error', {
|
|
753
|
+
error: 'setup_error',
|
|
555
754
|
message: error.message,
|
|
556
755
|
});
|
|
557
756
|
throw error;
|
|
@@ -572,24 +771,24 @@ class ToothFairyAPI {
|
|
|
572
771
|
});
|
|
573
772
|
|
|
574
773
|
if (importType) {
|
|
575
|
-
params.append(
|
|
774
|
+
params.append('importType', importType);
|
|
576
775
|
}
|
|
577
776
|
|
|
578
777
|
if (contentType) {
|
|
579
|
-
params.append(
|
|
778
|
+
params.append('contentType', contentType);
|
|
580
779
|
}
|
|
581
780
|
|
|
582
781
|
const config = {
|
|
583
|
-
method:
|
|
782
|
+
method: 'GET',
|
|
584
783
|
url: `${this.baseUrl}/documents/requestPreSignedURL?${params.toString()}`,
|
|
585
784
|
headers: this.headers,
|
|
586
785
|
};
|
|
587
786
|
|
|
588
787
|
if (this.verbose) {
|
|
589
|
-
const chalk = require(
|
|
590
|
-
console.error(chalk.dim(
|
|
788
|
+
const chalk = require('chalk');
|
|
789
|
+
console.error(chalk.dim('\n--- Upload URL Request Debug ---'));
|
|
591
790
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
592
|
-
console.error(chalk.dim(
|
|
791
|
+
console.error(chalk.dim('----------------------------\n'));
|
|
593
792
|
}
|
|
594
793
|
|
|
595
794
|
try {
|
|
@@ -599,7 +798,7 @@ class ToothFairyAPI {
|
|
|
599
798
|
if (error.response) {
|
|
600
799
|
throw new Error(
|
|
601
800
|
`HTTP ${error.response.status}: ${
|
|
602
|
-
error.response.data.message ||
|
|
801
|
+
error.response.data.message || 'Upload URL request failed'
|
|
603
802
|
}`
|
|
604
803
|
);
|
|
605
804
|
}
|
|
@@ -659,14 +858,14 @@ class ToothFairyAPI {
|
|
|
659
858
|
finalContentType
|
|
660
859
|
);
|
|
661
860
|
if (this.verbose) {
|
|
662
|
-
const chalk = require(
|
|
663
|
-
console.error(chalk.dim(
|
|
861
|
+
const chalk = require('chalk');
|
|
862
|
+
console.error(chalk.dim('\n--- File Upload URL response ---'));
|
|
664
863
|
console.error(chalk.dim(`Raw response: ${JSON.stringify(uploadData)}`));
|
|
665
864
|
}
|
|
666
865
|
|
|
667
866
|
// Parse the nested response structure
|
|
668
867
|
let parsedUploadData;
|
|
669
|
-
if (uploadData.body && typeof uploadData.body ===
|
|
868
|
+
if (uploadData.body && typeof uploadData.body === 'string') {
|
|
670
869
|
try {
|
|
671
870
|
parsedUploadData = JSON.parse(uploadData.body);
|
|
672
871
|
} catch (error) {
|
|
@@ -679,18 +878,18 @@ class ToothFairyAPI {
|
|
|
679
878
|
}
|
|
680
879
|
|
|
681
880
|
if (!parsedUploadData.uploadURL) {
|
|
682
|
-
throw new Error(
|
|
881
|
+
throw new Error('Failed to get upload URL from server');
|
|
683
882
|
}
|
|
684
883
|
|
|
685
884
|
// Upload file to S3
|
|
686
885
|
const fileData = fs.readFileSync(filePath);
|
|
687
886
|
|
|
688
887
|
const uploadConfig = {
|
|
689
|
-
method:
|
|
888
|
+
method: 'PUT',
|
|
690
889
|
url: parsedUploadData.uploadURL,
|
|
691
890
|
data: fileData,
|
|
692
891
|
headers: {
|
|
693
|
-
|
|
892
|
+
'Content-Type': finalContentType,
|
|
694
893
|
},
|
|
695
894
|
maxContentLength: Infinity,
|
|
696
895
|
maxBodyLength: Infinity,
|
|
@@ -709,8 +908,8 @@ class ToothFairyAPI {
|
|
|
709
908
|
};
|
|
710
909
|
|
|
711
910
|
if (this.verbose) {
|
|
712
|
-
const chalk = require(
|
|
713
|
-
console.error(chalk.dim(
|
|
911
|
+
const chalk = require('chalk');
|
|
912
|
+
console.error(chalk.dim('\n--- File Upload Debug ---'));
|
|
714
913
|
console.error(chalk.dim(`File: ${filePath}`));
|
|
715
914
|
console.error(chalk.dim(`Original filename: ${originalFilename}`));
|
|
716
915
|
console.error(chalk.dim(`Sanitized filename: ${sanitizedFilename}`));
|
|
@@ -719,7 +918,7 @@ class ToothFairyAPI {
|
|
|
719
918
|
console.error(chalk.dim(`Content type: ${finalContentType}`));
|
|
720
919
|
console.error(chalk.dim(`Size: ${fileSizeInMB.toFixed(2)}MB`));
|
|
721
920
|
console.error(chalk.dim(`Upload URL: ${parsedUploadData.uploadURL}`));
|
|
722
|
-
console.error(chalk.dim(
|
|
921
|
+
console.error(chalk.dim('------------------------\n'));
|
|
723
922
|
}
|
|
724
923
|
|
|
725
924
|
try {
|
|
@@ -731,7 +930,7 @@ class ToothFairyAPI {
|
|
|
731
930
|
// Remove S3 bucket prefix from filePath to get clean filename for download
|
|
732
931
|
downloadFilename = parsedUploadData.filePath.replace(
|
|
733
932
|
/^s3:\/\/[^/]+\//,
|
|
734
|
-
|
|
933
|
+
''
|
|
735
934
|
);
|
|
736
935
|
}
|
|
737
936
|
|
|
@@ -749,7 +948,7 @@ class ToothFairyAPI {
|
|
|
749
948
|
if (error.response) {
|
|
750
949
|
throw new Error(
|
|
751
950
|
`Upload failed: HTTP ${error.response.status}: ${
|
|
752
|
-
error.response.data?.message ||
|
|
951
|
+
error.response.data?.message || 'File upload failed'
|
|
753
952
|
}`
|
|
754
953
|
);
|
|
755
954
|
}
|
|
@@ -765,7 +964,7 @@ class ToothFairyAPI {
|
|
|
765
964
|
* @param {string} context - Context for the download (default: "pdf")
|
|
766
965
|
* @returns {Promise<Object>} - Download URL and metadata
|
|
767
966
|
*/
|
|
768
|
-
async getDownloadUrl(filename, workspaceId, context =
|
|
967
|
+
async getDownloadUrl(filename, workspaceId, context = 'pdf') {
|
|
769
968
|
const params = new URLSearchParams({
|
|
770
969
|
filename: filename,
|
|
771
970
|
context: context,
|
|
@@ -773,7 +972,7 @@ class ToothFairyAPI {
|
|
|
773
972
|
});
|
|
774
973
|
|
|
775
974
|
const config = {
|
|
776
|
-
method:
|
|
975
|
+
method: 'GET',
|
|
777
976
|
url: `${
|
|
778
977
|
this.baseUrl
|
|
779
978
|
}/documents/requestDownloadURLIncognito?${params.toString()}`,
|
|
@@ -781,10 +980,10 @@ class ToothFairyAPI {
|
|
|
781
980
|
};
|
|
782
981
|
|
|
783
982
|
if (this.verbose) {
|
|
784
|
-
const chalk = require(
|
|
785
|
-
console.error(chalk.dim(
|
|
983
|
+
const chalk = require('chalk');
|
|
984
|
+
console.error(chalk.dim('\n--- Download URL Request Debug ---'));
|
|
786
985
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
787
|
-
console.error(chalk.dim(
|
|
986
|
+
console.error(chalk.dim('-----------------------------\n'));
|
|
788
987
|
}
|
|
789
988
|
|
|
790
989
|
try {
|
|
@@ -794,7 +993,7 @@ class ToothFairyAPI {
|
|
|
794
993
|
if (error.response) {
|
|
795
994
|
throw new Error(
|
|
796
995
|
`HTTP ${error.response.status}: ${
|
|
797
|
-
error.response.data.message ||
|
|
996
|
+
error.response.data.message || 'Download URL request failed'
|
|
798
997
|
}`
|
|
799
998
|
);
|
|
800
999
|
}
|
|
@@ -816,7 +1015,7 @@ class ToothFairyAPI {
|
|
|
816
1015
|
filename,
|
|
817
1016
|
workspaceId,
|
|
818
1017
|
outputPath,
|
|
819
|
-
context =
|
|
1018
|
+
context = 'pdf',
|
|
820
1019
|
onProgress = null
|
|
821
1020
|
) {
|
|
822
1021
|
// Get download URL
|
|
@@ -827,7 +1026,7 @@ class ToothFairyAPI {
|
|
|
827
1026
|
);
|
|
828
1027
|
|
|
829
1028
|
if (!downloadData.url) {
|
|
830
|
-
throw new Error(
|
|
1029
|
+
throw new Error('Failed to get download URL from server');
|
|
831
1030
|
}
|
|
832
1031
|
|
|
833
1032
|
// Ensure output directory exists
|
|
@@ -838,9 +1037,9 @@ class ToothFairyAPI {
|
|
|
838
1037
|
|
|
839
1038
|
// Download file
|
|
840
1039
|
const downloadConfig = {
|
|
841
|
-
method:
|
|
1040
|
+
method: 'GET',
|
|
842
1041
|
url: downloadData.url,
|
|
843
|
-
responseType:
|
|
1042
|
+
responseType: 'stream',
|
|
844
1043
|
onDownloadProgress: onProgress
|
|
845
1044
|
? (progressEvent) => {
|
|
846
1045
|
if (progressEvent.total) {
|
|
@@ -858,11 +1057,11 @@ class ToothFairyAPI {
|
|
|
858
1057
|
};
|
|
859
1058
|
|
|
860
1059
|
if (this.verbose) {
|
|
861
|
-
const chalk = require(
|
|
862
|
-
console.error(chalk.dim(
|
|
1060
|
+
const chalk = require('chalk');
|
|
1061
|
+
console.error(chalk.dim('\n--- File Download Debug ---'));
|
|
863
1062
|
console.error(chalk.dim(`Download URL: ${downloadData.url}`));
|
|
864
1063
|
console.error(chalk.dim(`Output Path: ${outputPath}`));
|
|
865
|
-
console.error(chalk.dim(
|
|
1064
|
+
console.error(chalk.dim('---------------------------\n'));
|
|
866
1065
|
}
|
|
867
1066
|
|
|
868
1067
|
try {
|
|
@@ -873,7 +1072,7 @@ class ToothFairyAPI {
|
|
|
873
1072
|
response.data.pipe(writer);
|
|
874
1073
|
|
|
875
1074
|
return new Promise((resolve, reject) => {
|
|
876
|
-
writer.on(
|
|
1075
|
+
writer.on('finish', () => {
|
|
877
1076
|
const stats = fs.statSync(outputPath);
|
|
878
1077
|
resolve({
|
|
879
1078
|
success: true,
|
|
@@ -882,13 +1081,13 @@ class ToothFairyAPI {
|
|
|
882
1081
|
sizeInMB: (stats.size / (1024 * 1024)).toFixed(2),
|
|
883
1082
|
});
|
|
884
1083
|
});
|
|
885
|
-
writer.on(
|
|
1084
|
+
writer.on('error', reject);
|
|
886
1085
|
});
|
|
887
1086
|
} catch (error) {
|
|
888
1087
|
if (error.response) {
|
|
889
1088
|
throw new Error(
|
|
890
1089
|
`Download failed: HTTP ${error.response.status}: ${
|
|
891
|
-
error.response.data?.message ||
|
|
1090
|
+
error.response.data?.message || 'File download failed'
|
|
892
1091
|
}`
|
|
893
1092
|
);
|
|
894
1093
|
}
|
|
@@ -904,11 +1103,11 @@ class ToothFairyAPI {
|
|
|
904
1103
|
*/
|
|
905
1104
|
_sanitizeFilename(filename) {
|
|
906
1105
|
// Remove non-alphanumeric characters except dots
|
|
907
|
-
let sanitized = filename.replace(/[^a-zA-Z0-9.]/g,
|
|
1106
|
+
let sanitized = filename.replace(/[^a-zA-Z0-9.]/g, '');
|
|
908
1107
|
|
|
909
1108
|
// Check length limit
|
|
910
1109
|
if (sanitized.length > 100) {
|
|
911
|
-
throw new Error(
|
|
1110
|
+
throw new Error('File name cannot be more than 100 characters.');
|
|
912
1111
|
}
|
|
913
1112
|
|
|
914
1113
|
// Add timestamp prefix like frontend
|
|
@@ -927,20 +1126,20 @@ class ToothFairyAPI {
|
|
|
927
1126
|
const ext = path.extname(filePath).toLowerCase().slice(1);
|
|
928
1127
|
|
|
929
1128
|
// Image extensions
|
|
930
|
-
const imageExts = [
|
|
1129
|
+
const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'svg'];
|
|
931
1130
|
// Video extensions
|
|
932
|
-
const videoExts = [
|
|
1131
|
+
const videoExts = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm'];
|
|
933
1132
|
// Audio extensions
|
|
934
|
-
const audioExts = [
|
|
1133
|
+
const audioExts = ['wav', 'mp3', 'aac', 'ogg', 'flac'];
|
|
935
1134
|
|
|
936
1135
|
if (imageExts.includes(ext)) {
|
|
937
|
-
return
|
|
1136
|
+
return 'imported-image';
|
|
938
1137
|
} else if (videoExts.includes(ext)) {
|
|
939
|
-
return
|
|
1138
|
+
return 'imported_video_files';
|
|
940
1139
|
} else if (audioExts.includes(ext)) {
|
|
941
|
-
return
|
|
1140
|
+
return 'imported_audio_files';
|
|
942
1141
|
} else {
|
|
943
|
-
return
|
|
1142
|
+
return 'imported_doc_files';
|
|
944
1143
|
}
|
|
945
1144
|
}
|
|
946
1145
|
|
|
@@ -954,38 +1153,38 @@ class ToothFairyAPI {
|
|
|
954
1153
|
const ext = path.extname(filePath).toLowerCase().slice(1);
|
|
955
1154
|
|
|
956
1155
|
const contentTypes = {
|
|
957
|
-
txt:
|
|
958
|
-
md:
|
|
959
|
-
html:
|
|
960
|
-
pdf:
|
|
961
|
-
json:
|
|
962
|
-
jsonl:
|
|
963
|
-
wav:
|
|
964
|
-
mp4:
|
|
965
|
-
png:
|
|
966
|
-
jpg:
|
|
967
|
-
jpeg:
|
|
968
|
-
csv:
|
|
969
|
-
docx:
|
|
970
|
-
xlsx:
|
|
971
|
-
pptx:
|
|
972
|
-
ppt:
|
|
973
|
-
java:
|
|
974
|
-
py:
|
|
975
|
-
js:
|
|
976
|
-
ts:
|
|
977
|
-
tsx:
|
|
978
|
-
jsx:
|
|
979
|
-
yaml:
|
|
980
|
-
yml:
|
|
981
|
-
sql:
|
|
982
|
-
sh:
|
|
983
|
-
php:
|
|
984
|
-
csharp:
|
|
985
|
-
rb:
|
|
1156
|
+
txt: 'text/plain',
|
|
1157
|
+
md: 'text/markdown',
|
|
1158
|
+
html: 'text/html',
|
|
1159
|
+
pdf: 'application/pdf',
|
|
1160
|
+
json: 'application/json',
|
|
1161
|
+
jsonl: 'application/json',
|
|
1162
|
+
wav: 'audio/wav',
|
|
1163
|
+
mp4: 'video/mp4',
|
|
1164
|
+
png: 'image/png',
|
|
1165
|
+
jpg: 'image/jpeg',
|
|
1166
|
+
jpeg: 'image/jpeg',
|
|
1167
|
+
csv: 'text/csv',
|
|
1168
|
+
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
1169
|
+
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
1170
|
+
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
1171
|
+
ppt: 'application/vnd.ms-powerpoint',
|
|
1172
|
+
java: 'text/plain',
|
|
1173
|
+
py: 'text/plain',
|
|
1174
|
+
js: 'text/plain',
|
|
1175
|
+
ts: 'text/plain',
|
|
1176
|
+
tsx: 'text/plain',
|
|
1177
|
+
jsx: 'text/plain',
|
|
1178
|
+
yaml: 'text/plain',
|
|
1179
|
+
yml: 'text/plain',
|
|
1180
|
+
sql: 'text/plain',
|
|
1181
|
+
sh: 'text/plain',
|
|
1182
|
+
php: 'text/plain',
|
|
1183
|
+
csharp: 'text/plain',
|
|
1184
|
+
rb: 'text/plain',
|
|
986
1185
|
};
|
|
987
1186
|
|
|
988
|
-
return contentTypes[ext] ||
|
|
1187
|
+
return contentTypes[ext] || 'application/octet-stream';
|
|
989
1188
|
}
|
|
990
1189
|
|
|
991
1190
|
/**
|
|
@@ -996,18 +1195,18 @@ class ToothFairyAPI {
|
|
|
996
1195
|
*/
|
|
997
1196
|
_getDocumentType(filePath) {
|
|
998
1197
|
// Check if it's a URL
|
|
999
|
-
if (filePath.startsWith(
|
|
1000
|
-
return
|
|
1198
|
+
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
|
1199
|
+
return 'readComprehensionUrl';
|
|
1001
1200
|
}
|
|
1002
1201
|
|
|
1003
1202
|
// Check if it's a PDF file
|
|
1004
1203
|
const ext = path.extname(filePath).toLowerCase().slice(1);
|
|
1005
|
-
if (ext ===
|
|
1006
|
-
return
|
|
1204
|
+
if (ext === 'pdf') {
|
|
1205
|
+
return 'readComprehensionPdf';
|
|
1007
1206
|
}
|
|
1008
1207
|
|
|
1009
1208
|
// For all other file types (Excel, CSV, etc.)
|
|
1010
|
-
return
|
|
1209
|
+
return 'readComprehensionFile';
|
|
1011
1210
|
}
|
|
1012
1211
|
|
|
1013
1212
|
/**
|
|
@@ -1026,9 +1225,9 @@ class ToothFairyAPI {
|
|
|
1026
1225
|
filePath,
|
|
1027
1226
|
userId,
|
|
1028
1227
|
title = null,
|
|
1029
|
-
folderId =
|
|
1228
|
+
folderId = 'mrcRoot',
|
|
1030
1229
|
topics = [],
|
|
1031
|
-
status =
|
|
1230
|
+
status = 'published',
|
|
1032
1231
|
scope = null
|
|
1033
1232
|
) {
|
|
1034
1233
|
try {
|
|
@@ -1038,7 +1237,7 @@ class ToothFairyAPI {
|
|
|
1038
1237
|
// Use filename as title if not provided
|
|
1039
1238
|
let documentTitle = title;
|
|
1040
1239
|
if (!documentTitle) {
|
|
1041
|
-
if (filePath.startsWith(
|
|
1240
|
+
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
|
1042
1241
|
documentTitle = filePath;
|
|
1043
1242
|
} else {
|
|
1044
1243
|
documentTitle = path.basename(filePath);
|
|
@@ -1047,7 +1246,7 @@ class ToothFairyAPI {
|
|
|
1047
1246
|
|
|
1048
1247
|
// Determine external path based on file type
|
|
1049
1248
|
let externalPath;
|
|
1050
|
-
if (type ===
|
|
1249
|
+
if (type === 'readComprehensionUrl') {
|
|
1051
1250
|
externalPath = filePath; // Use URL directly
|
|
1052
1251
|
} else {
|
|
1053
1252
|
// For files, construct S3 path
|
|
@@ -1065,14 +1264,14 @@ class ToothFairyAPI {
|
|
|
1065
1264
|
topics: topics,
|
|
1066
1265
|
folderid: folderId,
|
|
1067
1266
|
external_path: externalPath,
|
|
1068
|
-
source:
|
|
1267
|
+
source: 'api',
|
|
1069
1268
|
status: status,
|
|
1070
1269
|
...(scope && { scope: scope }),
|
|
1071
1270
|
},
|
|
1072
1271
|
],
|
|
1073
1272
|
};
|
|
1074
1273
|
|
|
1075
|
-
return await this._makeRequest(
|
|
1274
|
+
return await this._makeRequest('POST', 'doc/create', documentData);
|
|
1076
1275
|
} catch (error) {
|
|
1077
1276
|
console.error(`Error creating document: ${error.message}`);
|
|
1078
1277
|
throw error;
|
|
@@ -1103,7 +1302,7 @@ class ToothFairyAPI {
|
|
|
1103
1302
|
},
|
|
1104
1303
|
};
|
|
1105
1304
|
|
|
1106
|
-
return await this._makeRequest(
|
|
1305
|
+
return await this._makeRequest('POST', 'doc/update', updateData);
|
|
1107
1306
|
} catch (error) {
|
|
1108
1307
|
console.error(`Error updating document: ${error.message}`);
|
|
1109
1308
|
throw error;
|
|
@@ -1118,7 +1317,7 @@ class ToothFairyAPI {
|
|
|
1118
1317
|
*/
|
|
1119
1318
|
async deleteDocument(documentId) {
|
|
1120
1319
|
try {
|
|
1121
|
-
return await this._makeRequest(
|
|
1320
|
+
return await this._makeRequest('DELETE', `doc/delete/${documentId}`);
|
|
1122
1321
|
} catch (error) {
|
|
1123
1322
|
console.error(`Error deleting document: ${error.message}`);
|
|
1124
1323
|
throw error;
|
|
@@ -1133,7 +1332,7 @@ class ToothFairyAPI {
|
|
|
1133
1332
|
*/
|
|
1134
1333
|
async getDocument(documentId) {
|
|
1135
1334
|
try {
|
|
1136
|
-
return await this._makeRequest(
|
|
1335
|
+
return await this._makeRequest('GET', `doc/get/${documentId}`);
|
|
1137
1336
|
} catch (error) {
|
|
1138
1337
|
console.error(`Error getting document: ${error.message}`);
|
|
1139
1338
|
throw error;
|
|
@@ -1155,7 +1354,7 @@ class ToothFairyAPI {
|
|
|
1155
1354
|
async createEntity(
|
|
1156
1355
|
userId,
|
|
1157
1356
|
label,
|
|
1158
|
-
type =
|
|
1357
|
+
type = 'topic',
|
|
1159
1358
|
description = null,
|
|
1160
1359
|
emoji = null,
|
|
1161
1360
|
parentEntity = null,
|
|
@@ -1173,7 +1372,7 @@ class ToothFairyAPI {
|
|
|
1173
1372
|
...(backgroundColor && { backgroundColor: backgroundColor }),
|
|
1174
1373
|
};
|
|
1175
1374
|
|
|
1176
|
-
return await this._makeRequest(
|
|
1375
|
+
return await this._makeRequest('POST', 'entity/create', entityData);
|
|
1177
1376
|
} catch (error) {
|
|
1178
1377
|
console.error(`Error creating entity: ${error.message}`);
|
|
1179
1378
|
throw error;
|
|
@@ -1200,7 +1399,7 @@ class ToothFairyAPI {
|
|
|
1200
1399
|
...fields,
|
|
1201
1400
|
};
|
|
1202
1401
|
|
|
1203
|
-
return await this._makeRequest(
|
|
1402
|
+
return await this._makeRequest('POST', 'entity/update', updateData);
|
|
1204
1403
|
} catch (error) {
|
|
1205
1404
|
console.error(`Error updating entity: ${error.message}`);
|
|
1206
1405
|
throw error;
|
|
@@ -1215,7 +1414,7 @@ class ToothFairyAPI {
|
|
|
1215
1414
|
*/
|
|
1216
1415
|
async deleteEntity(entityId) {
|
|
1217
1416
|
try {
|
|
1218
|
-
return await this._makeRequest(
|
|
1417
|
+
return await this._makeRequest('DELETE', `entity/delete/${entityId}`);
|
|
1219
1418
|
} catch (error) {
|
|
1220
1419
|
console.error(`Error deleting entity: ${error.message}`);
|
|
1221
1420
|
throw error;
|
|
@@ -1230,7 +1429,7 @@ class ToothFairyAPI {
|
|
|
1230
1429
|
*/
|
|
1231
1430
|
async getEntity(entityId) {
|
|
1232
1431
|
try {
|
|
1233
|
-
return await this._makeRequest(
|
|
1432
|
+
return await this._makeRequest('GET', `entity/get/${entityId}`);
|
|
1234
1433
|
} catch (error) {
|
|
1235
1434
|
console.error(`Error getting entity: ${error.message}`);
|
|
1236
1435
|
throw error;
|
|
@@ -1249,7 +1448,7 @@ class ToothFairyAPI {
|
|
|
1249
1448
|
if (limit) {
|
|
1250
1449
|
params.limit = limit;
|
|
1251
1450
|
}
|
|
1252
|
-
return await this._makeRequest(
|
|
1451
|
+
return await this._makeRequest('GET', 'entity/list', params);
|
|
1253
1452
|
} catch (error) {
|
|
1254
1453
|
console.error(`Error listing entities: ${error.message}`);
|
|
1255
1454
|
throw error;
|
|
@@ -1287,7 +1486,7 @@ class ToothFairyAPI {
|
|
|
1287
1486
|
...(status && { status: status }),
|
|
1288
1487
|
...(parent && { parent: parent }),
|
|
1289
1488
|
};
|
|
1290
|
-
return await this._makeRequest(
|
|
1489
|
+
return await this._makeRequest('POST', 'folder/create', folderData);
|
|
1291
1490
|
} catch (error) {
|
|
1292
1491
|
console.error(`Error creating folder: ${error.message}`);
|
|
1293
1492
|
throw error;
|
|
@@ -1322,7 +1521,7 @@ class ToothFairyAPI {
|
|
|
1322
1521
|
...(status && { status: status }),
|
|
1323
1522
|
...(parent !== null && { parent: parent }),
|
|
1324
1523
|
};
|
|
1325
|
-
return await this._makeRequest(
|
|
1524
|
+
return await this._makeRequest('POST', 'folder/update', updateData);
|
|
1326
1525
|
} catch (error) {
|
|
1327
1526
|
console.error(`Error updating folder: ${error.message}`);
|
|
1328
1527
|
throw error;
|
|
@@ -1337,7 +1536,7 @@ class ToothFairyAPI {
|
|
|
1337
1536
|
*/
|
|
1338
1537
|
async deleteFolder(folderId) {
|
|
1339
1538
|
try {
|
|
1340
|
-
return await this._makeRequest(
|
|
1539
|
+
return await this._makeRequest('DELETE', `folder/delete/${folderId}`);
|
|
1341
1540
|
} catch (error) {
|
|
1342
1541
|
console.error(`Error deleting folder: ${error.message}`);
|
|
1343
1542
|
throw error;
|
|
@@ -1352,7 +1551,7 @@ class ToothFairyAPI {
|
|
|
1352
1551
|
*/
|
|
1353
1552
|
async getFolder(folderId) {
|
|
1354
1553
|
try {
|
|
1355
|
-
return await this._makeRequest(
|
|
1554
|
+
return await this._makeRequest('GET', `folder/get/${folderId}`);
|
|
1356
1555
|
} catch (error) {
|
|
1357
1556
|
console.error(`Error getting folder: ${error.message}`);
|
|
1358
1557
|
throw error;
|
|
@@ -1379,7 +1578,7 @@ class ToothFairyAPI {
|
|
|
1379
1578
|
if (offset) {
|
|
1380
1579
|
params.offset = offset;
|
|
1381
1580
|
}
|
|
1382
|
-
return await this._makeRequest(
|
|
1581
|
+
return await this._makeRequest('GET', 'folder/list', params);
|
|
1383
1582
|
} catch (error) {
|
|
1384
1583
|
console.error(`Error listing folders: ${error.message}`);
|
|
1385
1584
|
throw error;
|
|
@@ -1429,7 +1628,7 @@ class ToothFairyAPI {
|
|
|
1429
1628
|
...(promptPlaceholder && { promptPlaceholder: promptPlaceholder }),
|
|
1430
1629
|
...(availableToAgents && { availableToAgents: availableToAgents }),
|
|
1431
1630
|
};
|
|
1432
|
-
return await this._makeRequest(
|
|
1631
|
+
return await this._makeRequest('POST', 'prompt/create', promptData);
|
|
1433
1632
|
} catch (error) {
|
|
1434
1633
|
console.error(`Error creating prompt: ${error.message}`);
|
|
1435
1634
|
throw error;
|
|
@@ -1482,7 +1681,7 @@ class ToothFairyAPI {
|
|
|
1482
1681
|
availableToAgents: availableToAgents,
|
|
1483
1682
|
}),
|
|
1484
1683
|
};
|
|
1485
|
-
return await this._makeRequest(
|
|
1684
|
+
return await this._makeRequest('POST', 'prompt/update', updateData);
|
|
1486
1685
|
} catch (error) {
|
|
1487
1686
|
console.error(`Error updating prompt: ${error.message}`);
|
|
1488
1687
|
throw error;
|
|
@@ -1497,7 +1696,7 @@ class ToothFairyAPI {
|
|
|
1497
1696
|
*/
|
|
1498
1697
|
async deletePrompt(promptId) {
|
|
1499
1698
|
try {
|
|
1500
|
-
return await this._makeRequest(
|
|
1699
|
+
return await this._makeRequest('DELETE', `prompt/delete/${promptId}`);
|
|
1501
1700
|
} catch (error) {
|
|
1502
1701
|
console.error(`Error deleting prompt: ${error.message}`);
|
|
1503
1702
|
throw error;
|
|
@@ -1512,7 +1711,7 @@ class ToothFairyAPI {
|
|
|
1512
1711
|
*/
|
|
1513
1712
|
async getPrompt(promptId) {
|
|
1514
1713
|
try {
|
|
1515
|
-
return await this._makeRequest(
|
|
1714
|
+
return await this._makeRequest('GET', `prompt/get/${promptId}`);
|
|
1516
1715
|
} catch (error) {
|
|
1517
1716
|
console.error(`Error getting prompt: ${error.message}`);
|
|
1518
1717
|
throw error;
|
|
@@ -1539,7 +1738,7 @@ class ToothFairyAPI {
|
|
|
1539
1738
|
if (offset) {
|
|
1540
1739
|
params.offset = offset;
|
|
1541
1740
|
}
|
|
1542
|
-
return await this._makeRequest(
|
|
1741
|
+
return await this._makeRequest('GET', 'prompt/list', params);
|
|
1543
1742
|
} catch (error) {
|
|
1544
1743
|
console.error(`Error listing prompts: ${error.message}`);
|
|
1545
1744
|
throw error;
|
|
@@ -1564,18 +1763,18 @@ class ToothFairyAPI {
|
|
|
1564
1763
|
};
|
|
1565
1764
|
|
|
1566
1765
|
const config = {
|
|
1567
|
-
method:
|
|
1766
|
+
method: 'POST',
|
|
1568
1767
|
url: `${this.baseUrl}/media/audio_generation`,
|
|
1569
1768
|
headers: {
|
|
1570
|
-
|
|
1571
|
-
|
|
1769
|
+
'Content-Type': 'application/json',
|
|
1770
|
+
'x-api-key': this.headers['x-api-key'],
|
|
1572
1771
|
},
|
|
1573
1772
|
data: speechData,
|
|
1574
1773
|
};
|
|
1575
1774
|
|
|
1576
1775
|
if (this.verbose) {
|
|
1577
|
-
const chalk = require(
|
|
1578
|
-
console.error(chalk.dim(
|
|
1776
|
+
const chalk = require('chalk');
|
|
1777
|
+
console.error(chalk.dim('\n--- Speech Generation Request Debug ---'));
|
|
1579
1778
|
console.error(chalk.dim(`Method: ${config.method}`));
|
|
1580
1779
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
1581
1780
|
console.error(
|
|
@@ -1584,28 +1783,28 @@ class ToothFairyAPI {
|
|
|
1584
1783
|
console.error(
|
|
1585
1784
|
chalk.dim(`Data: ${JSON.stringify(config.data, null, 2)}`)
|
|
1586
1785
|
);
|
|
1587
|
-
console.error(chalk.dim(
|
|
1786
|
+
console.error(chalk.dim('--------------------------------------\n'));
|
|
1588
1787
|
}
|
|
1589
1788
|
|
|
1590
1789
|
const response = await axios(config);
|
|
1591
1790
|
|
|
1592
1791
|
if (this.verbose) {
|
|
1593
|
-
const chalk = require(
|
|
1594
|
-
console.error(chalk.dim(
|
|
1792
|
+
const chalk = require('chalk');
|
|
1793
|
+
console.error(chalk.dim('\n--- Speech Generation Response Debug ---'));
|
|
1595
1794
|
console.error(
|
|
1596
1795
|
chalk.dim(`Status: ${response.status} ${response.statusText}`)
|
|
1597
1796
|
);
|
|
1598
1797
|
console.error(
|
|
1599
1798
|
chalk.dim(`Response Data: ${JSON.stringify(response.data, null, 2)}`)
|
|
1600
1799
|
);
|
|
1601
|
-
console.error(chalk.dim(
|
|
1800
|
+
console.error(chalk.dim('---------------------------------------\n'));
|
|
1602
1801
|
}
|
|
1603
1802
|
|
|
1604
1803
|
return response.data;
|
|
1605
1804
|
} catch (error) {
|
|
1606
1805
|
if (this.verbose) {
|
|
1607
|
-
const chalk = require(
|
|
1608
|
-
console.error(chalk.red(
|
|
1806
|
+
const chalk = require('chalk');
|
|
1807
|
+
console.error(chalk.red('\n--- Speech Generation Error Debug ---'));
|
|
1609
1808
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
1610
1809
|
if (error.response) {
|
|
1611
1810
|
console.error(
|
|
@@ -1619,7 +1818,7 @@ class ToothFairyAPI {
|
|
|
1619
1818
|
)
|
|
1620
1819
|
);
|
|
1621
1820
|
}
|
|
1622
|
-
console.error(chalk.red(
|
|
1821
|
+
console.error(chalk.red('------------------------------------\n'));
|
|
1623
1822
|
}
|
|
1624
1823
|
console.error(`Error generating speech: ${error.message}`);
|
|
1625
1824
|
throw error;
|
|
@@ -1642,18 +1841,18 @@ class ToothFairyAPI {
|
|
|
1642
1841
|
};
|
|
1643
1842
|
|
|
1644
1843
|
const config = {
|
|
1645
|
-
method:
|
|
1844
|
+
method: 'POST',
|
|
1646
1845
|
url: `${this.baseUrl}/media/audio`,
|
|
1647
1846
|
headers: {
|
|
1648
|
-
|
|
1649
|
-
|
|
1847
|
+
'Content-Type': 'application/json',
|
|
1848
|
+
'x-api-key': this.headers['x-api-key'],
|
|
1650
1849
|
},
|
|
1651
1850
|
data: audioData,
|
|
1652
1851
|
};
|
|
1653
1852
|
|
|
1654
1853
|
if (this.verbose) {
|
|
1655
|
-
const chalk = require(
|
|
1656
|
-
console.error(chalk.dim(
|
|
1854
|
+
const chalk = require('chalk');
|
|
1855
|
+
console.error(chalk.dim('\n--- Audio Processing Request Debug ---'));
|
|
1657
1856
|
console.error(chalk.dim(`Method: ${config.method}`));
|
|
1658
1857
|
console.error(chalk.dim(`URL: ${config.url}`));
|
|
1659
1858
|
console.error(
|
|
@@ -1662,28 +1861,28 @@ class ToothFairyAPI {
|
|
|
1662
1861
|
console.error(
|
|
1663
1862
|
chalk.dim(`Data: ${JSON.stringify(config.data, null, 2)}`)
|
|
1664
1863
|
);
|
|
1665
|
-
console.error(chalk.dim(
|
|
1864
|
+
console.error(chalk.dim('------------------------------------\n'));
|
|
1666
1865
|
}
|
|
1667
1866
|
|
|
1668
1867
|
const response = await axios(config);
|
|
1669
1868
|
|
|
1670
1869
|
if (this.verbose) {
|
|
1671
|
-
const chalk = require(
|
|
1672
|
-
console.error(chalk.dim(
|
|
1870
|
+
const chalk = require('chalk');
|
|
1871
|
+
console.error(chalk.dim('\n--- Audio Processing Response Debug ---'));
|
|
1673
1872
|
console.error(
|
|
1674
1873
|
chalk.dim(`Status: ${response.status} ${response.statusText}`)
|
|
1675
1874
|
);
|
|
1676
1875
|
console.error(
|
|
1677
1876
|
chalk.dim(`Response Data: ${JSON.stringify(response.data, null, 2)}`)
|
|
1678
1877
|
);
|
|
1679
|
-
console.error(chalk.dim(
|
|
1878
|
+
console.error(chalk.dim('-------------------------------------\n'));
|
|
1680
1879
|
}
|
|
1681
1880
|
|
|
1682
1881
|
return response.data;
|
|
1683
1882
|
} catch (error) {
|
|
1684
1883
|
if (this.verbose) {
|
|
1685
|
-
const chalk = require(
|
|
1686
|
-
console.error(chalk.red(
|
|
1884
|
+
const chalk = require('chalk');
|
|
1885
|
+
console.error(chalk.red('\n--- Audio Processing Error Debug ---'));
|
|
1687
1886
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
1688
1887
|
if (error.response) {
|
|
1689
1888
|
console.error(
|
|
@@ -1697,7 +1896,7 @@ class ToothFairyAPI {
|
|
|
1697
1896
|
)
|
|
1698
1897
|
);
|
|
1699
1898
|
}
|
|
1700
|
-
console.error(chalk.red(
|
|
1899
|
+
console.error(chalk.red('----------------------------------\n'));
|
|
1701
1900
|
}
|
|
1702
1901
|
console.error(`Error processing audio: ${error.message}`);
|
|
1703
1902
|
throw error;
|
|
@@ -1724,16 +1923,16 @@ class ToothFairyAPI {
|
|
|
1724
1923
|
try {
|
|
1725
1924
|
// Validate attachment limits
|
|
1726
1925
|
if (attachments.images && attachments.images.length > 1) {
|
|
1727
|
-
throw new Error(
|
|
1926
|
+
throw new Error('Maximum 1 image attachment allowed');
|
|
1728
1927
|
}
|
|
1729
1928
|
if (attachments.audios && attachments.audios.length > 1) {
|
|
1730
|
-
throw new Error(
|
|
1929
|
+
throw new Error('Maximum 1 audio attachment allowed');
|
|
1731
1930
|
}
|
|
1732
1931
|
if (attachments.videos && attachments.videos.length > 1) {
|
|
1733
|
-
throw new Error(
|
|
1932
|
+
throw new Error('Maximum 1 video attachment allowed');
|
|
1734
1933
|
}
|
|
1735
1934
|
if (attachments.files && attachments.files.length > 5) {
|
|
1736
|
-
throw new Error(
|
|
1935
|
+
throw new Error('Maximum 5 file attachments allowed');
|
|
1737
1936
|
}
|
|
1738
1937
|
|
|
1739
1938
|
// Process images
|
|
@@ -1789,10 +1988,10 @@ class ToothFairyAPI {
|
|
|
1789
1988
|
}
|
|
1790
1989
|
|
|
1791
1990
|
if (this.verbose) {
|
|
1792
|
-
const chalk = require(
|
|
1793
|
-
console.error(chalk.dim(
|
|
1991
|
+
const chalk = require('chalk');
|
|
1992
|
+
console.error(chalk.dim('\n--- Processed Attachments ---'));
|
|
1794
1993
|
console.error(chalk.dim(`Result: ${JSON.stringify(result, null, 2)}`));
|
|
1795
|
-
console.error(chalk.dim(
|
|
1994
|
+
console.error(chalk.dim('-----------------------------\n'));
|
|
1796
1995
|
}
|
|
1797
1996
|
|
|
1798
1997
|
return result;
|