@cloudbase/agent-adapter-adp 0.0.15 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -0
- package/dist/index.d.mts +39 -5
- package/dist/index.d.ts +39 -5
- package/dist/index.js +338 -87
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +338 -87
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -8
- package/CHANGELOG.md +0 -48
package/dist/index.mjs
CHANGED
|
@@ -29,7 +29,7 @@ function camelToSnakeKeys(obj) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// src/constant.ts
|
|
32
|
-
var
|
|
32
|
+
var DOCUMENT_MIME_TYPES = {
|
|
33
33
|
"text/plain": "txt",
|
|
34
34
|
"application/msword": "doc",
|
|
35
35
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx",
|
|
@@ -37,6 +37,15 @@ var MIME_TYPES = {
|
|
|
37
37
|
"application/vnd.ms-powerpoint": "ppt",
|
|
38
38
|
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "pptx"
|
|
39
39
|
};
|
|
40
|
+
var IMAGE_MIME_TYPES = {
|
|
41
|
+
"image/png": "png",
|
|
42
|
+
"image/jpeg": "jpg",
|
|
43
|
+
"image/bmp": "bmp"
|
|
44
|
+
};
|
|
45
|
+
var MIME_TYPES = {
|
|
46
|
+
...DOCUMENT_MIME_TYPES,
|
|
47
|
+
...IMAGE_MIME_TYPES
|
|
48
|
+
};
|
|
40
49
|
|
|
41
50
|
// src/types.ts
|
|
42
51
|
var ReplyMethod = /* @__PURE__ */ ((ReplyMethod2) => {
|
|
@@ -72,6 +81,7 @@ var CurrentNodeStatus = /* @__PURE__ */ ((CurrentNodeStatus2) => {
|
|
|
72
81
|
// src/agent.ts
|
|
73
82
|
import { randomUUID } from "crypto";
|
|
74
83
|
import { lke } from "tencentcloud-sdk-nodejs-lke";
|
|
84
|
+
import COS from "cos-nodejs-sdk-v5";
|
|
75
85
|
var AdpAgentError = class extends Error {
|
|
76
86
|
constructor(message, code) {
|
|
77
87
|
super(message);
|
|
@@ -82,73 +92,85 @@ var AdpAgentError = class extends Error {
|
|
|
82
92
|
var AdpAgent = class extends AbstractAgent {
|
|
83
93
|
constructor(config) {
|
|
84
94
|
super(config);
|
|
95
|
+
this.finalAppKey = "";
|
|
96
|
+
this.finalCloudCredential = {};
|
|
85
97
|
this.adpConfig = config.adpConfig;
|
|
98
|
+
this.finalAppKey = this.adpConfig.appKey || this.adpConfig.request?.body?.botAppKey || process.env.ADP_APP_KEY || "";
|
|
86
99
|
this.reqAppClient = axios.create({
|
|
87
100
|
baseURL: this.adpConfig.request?.baseUrl || "https://wss.lke.cloud.tencent.com"
|
|
88
101
|
});
|
|
89
102
|
const LkeClient = lke.v20231130.Client;
|
|
103
|
+
this.finalCloudCredential = {
|
|
104
|
+
secretId: this.adpConfig.credential?.secretId || process.env.TENCENTCLOUD_SECRETID,
|
|
105
|
+
secretKey: this.adpConfig.credential?.secretKey || process.env.TENCENTCLOUD_SECRETKEY,
|
|
106
|
+
token: this.adpConfig.credential?.token || process.env.TENCENTCLOUD_SESSIONTOKEN
|
|
107
|
+
};
|
|
90
108
|
this.reqLkeClient = new LkeClient({
|
|
91
|
-
credential:
|
|
92
|
-
secretId: this.adpConfig.credential?.secretId || process.env.TENCENTCLOUD_SECRETID,
|
|
93
|
-
secretKey: this.adpConfig.credential?.secretKey || process.env.TENCENTCLOUD_SECRETKEY,
|
|
94
|
-
token: this.adpConfig.credential?.token || process.env.TENCENTCLOUD_SESSIONTOKEN
|
|
95
|
-
}
|
|
109
|
+
credential: this.finalCloudCredential
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
generateRequestBody({
|
|
99
113
|
message,
|
|
100
114
|
fileInfos,
|
|
101
|
-
|
|
102
|
-
threadId,
|
|
103
|
-
forwardedProps
|
|
115
|
+
input
|
|
104
116
|
}) {
|
|
117
|
+
const { state, runId, threadId, forwardedProps } = input;
|
|
105
118
|
const requestBody = {
|
|
106
119
|
incremental: true,
|
|
107
120
|
stream: "enable",
|
|
108
121
|
...this.adpConfig.request?.body || {},
|
|
109
122
|
...forwardedProps || {},
|
|
110
|
-
botAppKey: this.
|
|
111
|
-
visitorBizId: forwardedProps?.visitorBizId || randomUUID(),
|
|
123
|
+
botAppKey: this.finalAppKey,
|
|
124
|
+
visitorBizId: state?.__request_context__?.id || forwardedProps?.visitorBizId || randomUUID(),
|
|
112
125
|
requestId: runId,
|
|
113
|
-
sessionId: threadId
|
|
126
|
+
sessionId: threadId,
|
|
114
127
|
content: message,
|
|
115
128
|
fileInfos
|
|
116
129
|
};
|
|
117
130
|
return requestBody;
|
|
118
131
|
}
|
|
119
|
-
// @ts-ignore
|
|
120
132
|
run(input) {
|
|
121
133
|
return new Observable((subscriber) => {
|
|
122
134
|
this._run(subscriber, input);
|
|
123
135
|
});
|
|
124
136
|
}
|
|
125
137
|
async _run(subscriber, input) {
|
|
138
|
+
let thinkingMessageSet = /* @__PURE__ */ new Set();
|
|
139
|
+
let thinkFinishedMessageSet = /* @__PURE__ */ new Set();
|
|
126
140
|
try {
|
|
127
|
-
const {
|
|
141
|
+
const { runId } = input;
|
|
142
|
+
const threadId = input.threadId || randomUUID();
|
|
128
143
|
subscriber.next({
|
|
129
144
|
type: EventType.RUN_STARTED,
|
|
130
145
|
runId,
|
|
131
146
|
threadId
|
|
132
147
|
});
|
|
133
|
-
if (!this.
|
|
148
|
+
if (!this.finalAppKey) {
|
|
134
149
|
throw new AdpAgentError(
|
|
135
|
-
"
|
|
150
|
+
"ADP_APP_KEY is required, check your env variables or config passed with the adapter",
|
|
136
151
|
"MISSING_APP_KEY"
|
|
137
152
|
);
|
|
138
153
|
}
|
|
139
|
-
const
|
|
140
|
-
|
|
154
|
+
const latestUserMessage = input.messages.filter((m) => m.role === "user").pop();
|
|
155
|
+
if (!latestUserMessage) {
|
|
156
|
+
throw new AdpAgentError(
|
|
157
|
+
"Message content format error, or empty content",
|
|
158
|
+
"INVALID_MESSAGE_FORMAT"
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const { message: docExtractedMessage, fileInfos } = await this.extractDocuments(latestUserMessage, threadId, subscriber);
|
|
162
|
+
const message = await this.convertAGUIMessagesToAdpMessages(docExtractedMessage);
|
|
141
163
|
if (!message) {
|
|
142
164
|
throw new AdpAgentError(
|
|
143
165
|
"Message content format error, or empty content",
|
|
144
|
-
"
|
|
166
|
+
"INVALID_MESSAGE_FORMAT"
|
|
145
167
|
);
|
|
146
168
|
}
|
|
147
|
-
if (
|
|
169
|
+
if (input.messages.length > 1) {
|
|
148
170
|
subscriber.next({
|
|
149
171
|
type: EventType.RAW,
|
|
150
172
|
rawEvent: {
|
|
151
|
-
message: `ADP handles message history itself, so that a total of ${
|
|
173
|
+
message: `ADP handles message history itself, so that a total of ${input.messages.length - 1} messages before and including last assistant message will be trimmed.`,
|
|
152
174
|
type: "warn"
|
|
153
175
|
}
|
|
154
176
|
});
|
|
@@ -156,9 +178,7 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
156
178
|
const requestBody = this.generateRequestBody({
|
|
157
179
|
message,
|
|
158
180
|
fileInfos,
|
|
159
|
-
|
|
160
|
-
threadId,
|
|
161
|
-
forwardedProps
|
|
181
|
+
input
|
|
162
182
|
});
|
|
163
183
|
const response = await this.reqAppClient.post(
|
|
164
184
|
this.adpConfig.request?.endpoint || "/v1/qbot/chat/sse",
|
|
@@ -169,7 +189,6 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
169
189
|
let buffer = "";
|
|
170
190
|
let interruptRequested = false;
|
|
171
191
|
let thinkingStart = false;
|
|
172
|
-
let thinkingMessageSet = /* @__PURE__ */ new Set();
|
|
173
192
|
for await (const chunk of sseStream) {
|
|
174
193
|
buffer += chunk.toString();
|
|
175
194
|
const parts = buffer.split("\n\n");
|
|
@@ -196,6 +215,22 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
196
215
|
}
|
|
197
216
|
switch (data.type) {
|
|
198
217
|
case "reply": {
|
|
218
|
+
const messageId = data.payload.record_id;
|
|
219
|
+
const isFinal = data.payload.is_final;
|
|
220
|
+
if (thinkingStart) {
|
|
221
|
+
thinkingStart = false;
|
|
222
|
+
for (const index of thinkingMessageSet) {
|
|
223
|
+
subscriber.next({
|
|
224
|
+
type: EventType.THINKING_TEXT_MESSAGE_END,
|
|
225
|
+
messageId: `${messageId}-think-${index}`
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
thinkingMessageSet.clear();
|
|
229
|
+
subscriber.next({
|
|
230
|
+
type: EventType.THINKING_END,
|
|
231
|
+
messageId
|
|
232
|
+
});
|
|
233
|
+
}
|
|
199
234
|
if (data.payload.is_from_self) {
|
|
200
235
|
if (data.payload.is_evil) {
|
|
201
236
|
throw new AdpAgentError(
|
|
@@ -206,8 +241,6 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
206
241
|
continue;
|
|
207
242
|
}
|
|
208
243
|
}
|
|
209
|
-
const messageId = data.payload.record_id;
|
|
210
|
-
const isFinal = data.payload.is_final;
|
|
211
244
|
data.payload.content = data.payload.content.replace(
|
|
212
245
|
/\\n/g,
|
|
213
246
|
"\n\n"
|
|
@@ -287,51 +320,47 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
287
320
|
});
|
|
288
321
|
}
|
|
289
322
|
data.payload.procedures.forEach((procedure) => {
|
|
290
|
-
|
|
291
|
-
|
|
323
|
+
const index = procedure.index.toString();
|
|
324
|
+
if (!thinkingMessageSet.has(index) && !thinkFinishedMessageSet.has(index)) {
|
|
325
|
+
thinkingMessageSet.add(index);
|
|
292
326
|
subscriber.next({
|
|
293
327
|
type: EventType.THINKING_TEXT_MESSAGE_START,
|
|
294
|
-
messageId
|
|
328
|
+
messageId: `${messageId}-think-${index}`,
|
|
295
329
|
delta: procedure.debugging.content
|
|
296
330
|
});
|
|
297
331
|
} else {
|
|
298
332
|
if (procedure.status === "processing") {
|
|
299
333
|
subscriber.next({
|
|
300
334
|
type: EventType.THINKING_TEXT_MESSAGE_CONTENT,
|
|
301
|
-
messageId
|
|
335
|
+
messageId: `${messageId}-think-${index}`,
|
|
302
336
|
delta: procedure.debugging.content
|
|
303
337
|
});
|
|
304
338
|
} else {
|
|
305
|
-
thinkingMessageSet.delete(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
339
|
+
thinkingMessageSet.delete(index);
|
|
340
|
+
if (!thinkFinishedMessageSet.has(index)) {
|
|
341
|
+
thinkFinishedMessageSet.add(index);
|
|
342
|
+
subscriber.next({
|
|
343
|
+
type: EventType.THINKING_TEXT_MESSAGE_END,
|
|
344
|
+
messageId: `${messageId}-think-${index}`
|
|
345
|
+
});
|
|
346
|
+
}
|
|
310
347
|
}
|
|
311
348
|
}
|
|
312
349
|
});
|
|
313
|
-
const allFinished = data.payload.procedures.every(
|
|
314
|
-
(procedure) => procedure.status !== "processing"
|
|
315
|
-
);
|
|
316
|
-
if (allFinished) {
|
|
317
|
-
thinkingStart = false;
|
|
318
|
-
thinkingMessageSet.clear();
|
|
319
|
-
subscriber.next({
|
|
320
|
-
type: EventType.THINKING_END,
|
|
321
|
-
messageId
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
350
|
break;
|
|
325
351
|
}
|
|
326
352
|
case "error": {
|
|
327
|
-
console.error(
|
|
353
|
+
console.error(
|
|
354
|
+
"[ERROR] ADP throws error: ",
|
|
355
|
+
JSON.stringify(data)
|
|
356
|
+
);
|
|
328
357
|
throw new AdpAgentError(
|
|
329
358
|
data.error.message,
|
|
330
|
-
`ADP_ERROR_${data.error.code}`
|
|
359
|
+
data.error.code ? `ADP_ERROR_${data.error.code}` : "ADP_ERROR_-1"
|
|
331
360
|
);
|
|
332
361
|
}
|
|
333
362
|
case "token_stat": {
|
|
334
|
-
console.debug(JSON.stringify(data));
|
|
363
|
+
console.debug("[DEBUG] ADP token stat: ", JSON.stringify(data));
|
|
335
364
|
break;
|
|
336
365
|
}
|
|
337
366
|
case "reference": {
|
|
@@ -361,7 +390,7 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
361
390
|
}
|
|
362
391
|
subscriber.complete();
|
|
363
392
|
} catch (e) {
|
|
364
|
-
console.error(JSON.stringify(e));
|
|
393
|
+
console.error("[ERROR] Uncaught error: ", JSON.stringify(e));
|
|
365
394
|
let code = "UNKNOWN_ERROR";
|
|
366
395
|
let message = JSON.stringify(e);
|
|
367
396
|
if (e instanceof AxiosError) {
|
|
@@ -377,31 +406,75 @@ var AdpAgent = class extends AbstractAgent {
|
|
|
377
406
|
message: `Sorry, an error occurred while running the agent: Error code ${code}, ${message}`
|
|
378
407
|
});
|
|
379
408
|
subscriber.complete();
|
|
409
|
+
} finally {
|
|
410
|
+
thinkingMessageSet.clear();
|
|
411
|
+
thinkFinishedMessageSet.clear();
|
|
380
412
|
}
|
|
381
413
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
let result = "";
|
|
385
|
-
let trimmed = messages.length;
|
|
386
|
-
for (const message of messages.reverse()) {
|
|
387
|
-
if (message.role === "assistant") {
|
|
388
|
-
break;
|
|
389
|
-
}
|
|
414
|
+
async convertAGUIMessagesToAdpMessages(message) {
|
|
415
|
+
let result = "";
|
|
390
416
|
if (message.role === "user") {
|
|
391
|
-
trimmed--;
|
|
392
417
|
let content = "";
|
|
393
418
|
if (typeof message.content === "string") {
|
|
394
419
|
content = message.content;
|
|
395
420
|
} else {
|
|
396
|
-
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
421
|
+
if (this.adpConfig.enableUpload) {
|
|
422
|
+
if (!this.finalCloudCredential.token) {
|
|
423
|
+
if (!this.finalCloudCredential.secretId) {
|
|
424
|
+
throw new AdpAgentError(
|
|
425
|
+
"TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
|
|
426
|
+
"MISSING_SECRET_ID"
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
if (!this.finalCloudCredential.secretKey) {
|
|
430
|
+
throw new AdpAgentError(
|
|
431
|
+
"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
|
|
432
|
+
"MISSING_SECRET_KEY"
|
|
433
|
+
);
|
|
434
|
+
}
|
|
403
435
|
}
|
|
404
|
-
|
|
436
|
+
const imageMap = /* @__PURE__ */ new Map();
|
|
437
|
+
const imagesToUpload = [];
|
|
438
|
+
message.content.forEach((item) => {
|
|
439
|
+
if (item.type === "binary") {
|
|
440
|
+
if (Object.keys(IMAGE_MIME_TYPES).includes(item.mimeType)) {
|
|
441
|
+
imagesToUpload.push(item);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
if (imagesToUpload.length) {
|
|
446
|
+
await this.uploadToCos(
|
|
447
|
+
imagesToUpload,
|
|
448
|
+
(data, _, file) => {
|
|
449
|
+
imageMap.set(
|
|
450
|
+
file.id || file.filename,
|
|
451
|
+
`https://${data.Location}`
|
|
452
|
+
);
|
|
453
|
+
},
|
|
454
|
+
(fileName, error) => {
|
|
455
|
+
throw new AdpAgentError(
|
|
456
|
+
`Upload image ${fileName} failed: ${error}`,
|
|
457
|
+
"UPLOAD_IMAGE_FAILED"
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
content = message.content.reduce((acc, cur) => {
|
|
463
|
+
if (cur.type === "text") {
|
|
464
|
+
return acc + `${cur.text} `;
|
|
465
|
+
} else if (cur.type === "binary") {
|
|
466
|
+
if (Object.keys(IMAGE_MIME_TYPES).includes(cur.mimeType)) {
|
|
467
|
+
if (imageMap.has(cur.id || cur.filename)) {
|
|
468
|
+
return acc + `}) `;
|
|
469
|
+
} else {
|
|
470
|
+
return acc;
|
|
471
|
+
}
|
|
472
|
+
} else return acc;
|
|
473
|
+
} else {
|
|
474
|
+
return acc;
|
|
475
|
+
}
|
|
476
|
+
}, "").trim();
|
|
477
|
+
}
|
|
405
478
|
}
|
|
406
479
|
result = `${message.role}: ${content}
|
|
407
480
|
${result}`;
|
|
@@ -409,36 +482,214 @@ ${result}`;
|
|
|
409
482
|
result = `${message.role}: ${message.content}
|
|
410
483
|
${result}`;
|
|
411
484
|
}
|
|
485
|
+
return result.trim();
|
|
412
486
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
const newMessages = messages.map((msg) => {
|
|
418
|
-
if (msg.role === "user" && Array.isArray(msg.content)) {
|
|
487
|
+
async extractDocuments(message, threadId, subscriber) {
|
|
488
|
+
const documentFiles = [];
|
|
489
|
+
let newMessage;
|
|
490
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
419
491
|
let newContent = [];
|
|
420
|
-
|
|
492
|
+
message.content.forEach((item) => {
|
|
421
493
|
if (item.type === "text") {
|
|
422
494
|
newContent.push(item);
|
|
423
495
|
} else if (item.type === "binary") {
|
|
424
|
-
if (Object.keys(
|
|
496
|
+
if (Object.keys(DOCUMENT_MIME_TYPES).includes(item.mimeType)) {
|
|
425
497
|
documentFiles.push(item);
|
|
498
|
+
} else {
|
|
499
|
+
newContent.push(item);
|
|
426
500
|
}
|
|
427
501
|
}
|
|
428
502
|
});
|
|
429
|
-
|
|
430
|
-
...
|
|
503
|
+
newMessage = {
|
|
504
|
+
...message,
|
|
431
505
|
content: newContent
|
|
432
506
|
};
|
|
433
|
-
} else
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
507
|
+
} else newMessage = message;
|
|
508
|
+
const fileInfos = [];
|
|
509
|
+
const successedFiles = [];
|
|
510
|
+
const failedFiles = [];
|
|
511
|
+
if (this.adpConfig.enableUpload) {
|
|
512
|
+
if (!this.finalCloudCredential.token) {
|
|
513
|
+
if (!this.finalCloudCredential.secretId) {
|
|
514
|
+
throw new AdpAgentError(
|
|
515
|
+
"TENCENTCLOUD_SECRETID is required, check your env variables or config passed with the adapter",
|
|
516
|
+
"MISSING_SECRET_ID"
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
if (!this.finalCloudCredential.secretKey) {
|
|
520
|
+
throw new AdpAgentError(
|
|
521
|
+
"TENCENTCLOUD_SECRETKEY is required, check your env variables or config passed with the adapter",
|
|
522
|
+
"MISSING_SECRET_KEY"
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
if (documentFiles.length) {
|
|
527
|
+
try {
|
|
528
|
+
await this.uploadToCos(
|
|
529
|
+
documentFiles,
|
|
530
|
+
(data, cosParams, file) => {
|
|
531
|
+
successedFiles.push({ data, cosParams, file });
|
|
532
|
+
},
|
|
533
|
+
(fileName, error) => {
|
|
534
|
+
failedFiles.push({ fileName, error });
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
} catch (e) {
|
|
538
|
+
console.error("Document upload failed: ", JSON.stringify(e));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (successedFiles.length) {
|
|
542
|
+
for (const { data: cosData, cosParams, file } of successedFiles) {
|
|
543
|
+
const extName = MIME_TYPES[file.mimeType];
|
|
544
|
+
const requestBody = {
|
|
545
|
+
sessionId: threadId,
|
|
546
|
+
botAppKey: this.finalAppKey,
|
|
547
|
+
requestId: randomUUID(),
|
|
548
|
+
cosBucket: cosParams.Bucket,
|
|
549
|
+
fileType: extName,
|
|
550
|
+
fileName: file.filename,
|
|
551
|
+
cosUrl: cosParams.UploadPath,
|
|
552
|
+
cosHash: cosData.headers?.["x-cos-hash-crc64ecma"] || "",
|
|
553
|
+
eTag: cosData.ETag,
|
|
554
|
+
size: file.data?.length.toString() || "0"
|
|
555
|
+
};
|
|
556
|
+
const response = await this.reqAppClient.post(
|
|
557
|
+
this.adpConfig.request?.docParseEndpoint || "/v1/qbot/chat/docParse",
|
|
558
|
+
camelToSnakeKeys(requestBody),
|
|
559
|
+
{ responseType: "stream" }
|
|
560
|
+
);
|
|
561
|
+
const sseStream = response.data;
|
|
562
|
+
let buffer = "";
|
|
563
|
+
for await (const chunk of sseStream) {
|
|
564
|
+
buffer += chunk.toString();
|
|
565
|
+
const parts = buffer.split("\n\n");
|
|
566
|
+
buffer = parts.pop() || "";
|
|
567
|
+
for (const part of parts) {
|
|
568
|
+
if (!part.trim()) continue;
|
|
569
|
+
const event = { data: "", event: "" };
|
|
570
|
+
for (const line of part.split("\n")) {
|
|
571
|
+
if (line.startsWith("data:")) {
|
|
572
|
+
event.data += line.slice(5);
|
|
573
|
+
} else if (line.startsWith("event:")) {
|
|
574
|
+
event.event = line.slice(6);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if (event.data) {
|
|
578
|
+
let data;
|
|
579
|
+
try {
|
|
580
|
+
data = JSON.parse(event.data);
|
|
581
|
+
} catch (e) {
|
|
582
|
+
throw new AdpAgentError(
|
|
583
|
+
`ADP returned invalid data: ${event.data}`,
|
|
584
|
+
"INVALID_DATA"
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
switch (data.type) {
|
|
588
|
+
case "parsing": {
|
|
589
|
+
subscriber.next({
|
|
590
|
+
type: EventType.RAW,
|
|
591
|
+
rawEvent: {
|
|
592
|
+
message: `Parsing document ${file.filename}: ${data.payload.process}%`,
|
|
593
|
+
type: "info"
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
if (data.payload.is_final) {
|
|
597
|
+
if (data.payload.error_message) {
|
|
598
|
+
subscriber.next({
|
|
599
|
+
type: EventType.RAW,
|
|
600
|
+
rawEvent: {
|
|
601
|
+
message: `Parsing document ${file.filename} failed: ${data.payload.error_message}`,
|
|
602
|
+
type: "error"
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
} else {
|
|
606
|
+
const fileNameNoExt = file.filename.split(".").splice(0, -1).join(".");
|
|
607
|
+
fileInfos.push({
|
|
608
|
+
docId: data.payload.doc_id,
|
|
609
|
+
fileName: fileNameNoExt,
|
|
610
|
+
fileType: extName,
|
|
611
|
+
fileSize: file.data?.length.toString() || "0",
|
|
612
|
+
fileUrl: `https://${cosData.Location}`
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
default: {
|
|
619
|
+
break;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return {
|
|
629
|
+
message: newMessage,
|
|
630
|
+
fileInfos,
|
|
631
|
+
failedFiles
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
async getCosParams(mimeType) {
|
|
635
|
+
const extName = MIME_TYPES?.[mimeType];
|
|
636
|
+
if (!extName) {
|
|
637
|
+
throw new Error(`Unsupported mime type: ${mimeType}`);
|
|
638
|
+
}
|
|
639
|
+
const isPicture = Object.keys(IMAGE_MIME_TYPES).includes(mimeType);
|
|
640
|
+
const bizIdRes = await this.reqLkeClient.DescribeRobotBizIDByAppKey({
|
|
641
|
+
AppKey: this.finalAppKey
|
|
642
|
+
});
|
|
643
|
+
const storageRes = await this.reqLkeClient.DescribeStorageCredential({
|
|
644
|
+
BotBizId: bizIdRes.BotBizId,
|
|
645
|
+
FileType: extName,
|
|
646
|
+
IsPublic: isPicture,
|
|
647
|
+
TypeKey: "realtime"
|
|
648
|
+
});
|
|
649
|
+
return storageRes;
|
|
650
|
+
}
|
|
651
|
+
async uploadToCos(files, onSuccess, onError) {
|
|
652
|
+
const promises = [];
|
|
653
|
+
for (const file of files) {
|
|
654
|
+
const extName = MIME_TYPES?.[file.mimeType];
|
|
655
|
+
if (!extName) {
|
|
656
|
+
onError(file.filename || "unknown-file", "Unsupported file type");
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
const cosParams = await this.getCosParams(file.mimeType);
|
|
660
|
+
const cosClient = new COS({
|
|
661
|
+
SecretId: cosParams.Credentials?.TmpSecretId,
|
|
662
|
+
SecretKey: cosParams.Credentials?.TmpSecretKey,
|
|
663
|
+
SecurityToken: cosParams.Credentials?.Token
|
|
664
|
+
});
|
|
665
|
+
if (!cosParams.Bucket || !cosParams.Region || !cosParams.UploadPath) {
|
|
666
|
+
onError(file.filename || "unknown-file", "Failed to get COS params");
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
const promise = new Promise((resolve, reject) => {
|
|
670
|
+
cosClient.putObject(
|
|
671
|
+
{
|
|
672
|
+
Bucket: cosParams.Bucket,
|
|
673
|
+
Region: cosParams.Region,
|
|
674
|
+
Key: cosParams.UploadPath,
|
|
675
|
+
Body: file.data
|
|
676
|
+
},
|
|
677
|
+
(err, data) => {
|
|
678
|
+
if (err) {
|
|
679
|
+
onError(file.filename || "unknown-file", err.message);
|
|
680
|
+
reject();
|
|
681
|
+
} else {
|
|
682
|
+
onSuccess(data, cosParams, file);
|
|
683
|
+
resolve();
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
);
|
|
687
|
+
});
|
|
688
|
+
promises.push(promise);
|
|
689
|
+
}
|
|
690
|
+
await Promise.allSettled(promises);
|
|
691
|
+
}
|
|
692
|
+
};
|
|
442
693
|
export {
|
|
443
694
|
AdpAgent,
|
|
444
695
|
AdpAgentError,
|