@peopl-health/nexus 1.1.4 → 1.1.6
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/lib/adapters/BaileysProvider.js +1 -1
- package/lib/config/awsConfig.js +103 -0
- package/lib/config/llmConfig.js +4 -0
- package/lib/controllers/assistantController.js +9 -28
- package/lib/core/NexusMessaging.js +15 -1
- package/lib/helpers/assistantHelper.js +292 -0
- package/lib/helpers/baileysHelper.js +149 -0
- package/lib/helpers/filesHelper.js +134 -0
- package/lib/helpers/llmsHelper.js +202 -0
- package/lib/helpers/mediaHelper.js +72 -0
- package/lib/helpers/mongoHelper.js +45 -0
- package/lib/helpers/qrHelper.js +22 -0
- package/lib/helpers/twilioHelper.js +138 -0
- package/lib/helpers/whatsappHelper.js +75 -0
- package/lib/services/assistantService.js +42 -46
- package/lib/storage/MongoStorage.js +3 -3
- package/package.json +4 -1
- package/lib/services/whatsappService.js +0 -23
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
const { Historial_Clinico_ID } = require('../config/airtableConfig.js');
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
let llmProvider = null;
|
|
4
|
+
const configureLLMProvider = (provider) => {
|
|
5
|
+
llmProvider = provider;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
let assistantConfig = null;
|
|
9
|
+
let assistantRegistry = {};
|
|
4
10
|
|
|
5
11
|
const { Message, formatTimestamp } = require('../models/messageModel.js');
|
|
6
12
|
const { Thread } = require('../models/threadModel.js');
|
|
@@ -9,26 +15,28 @@ const { checkRunStatus, getCurRow } = require('../helpers/assistantHelper.js');
|
|
|
9
15
|
const { processMessage, getLastMessages } = require('../helpers/assistantHelper.js');
|
|
10
16
|
const { delay } = require('../helpers/whatsappHelper.js');
|
|
11
17
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
const configureAssistants = (config) => {
|
|
19
|
+
if (!config) {
|
|
20
|
+
throw new Error('Assistant configuration is required');
|
|
21
|
+
}
|
|
22
|
+
assistantConfig = config;
|
|
23
|
+
};
|
|
17
24
|
|
|
25
|
+
const registerAssistant = (assistantId, AssistantClass) => {
|
|
26
|
+
assistantRegistry[assistantId] = AssistantClass;
|
|
27
|
+
};
|
|
18
28
|
|
|
19
29
|
const getAssistantById = (assistant_id, thread) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
case PATIENT_SCHEDULE_ASST:
|
|
28
|
-
return new PatientScheduleAssistant(thread);
|
|
29
|
-
default:
|
|
30
|
-
return new GeneralAssistant(thread);
|
|
30
|
+
if (!assistantConfig) {
|
|
31
|
+
throw new Error('Assistants not configured. Call configureAssistants() first.');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const AssistantClass = assistantRegistry[assistant_id];
|
|
35
|
+
if (!AssistantClass) {
|
|
36
|
+
throw new Error(`Assistant '${assistant_id}' not found. Available assistants: ${Object.keys(assistantRegistry).join(', ')}`);
|
|
31
37
|
}
|
|
38
|
+
|
|
39
|
+
return new AssistantClass(thread);
|
|
32
40
|
};
|
|
33
41
|
|
|
34
42
|
|
|
@@ -50,7 +58,7 @@ const createAssistant = async (code, assistant_id, messages=[], prevThread=null)
|
|
|
50
58
|
|
|
51
59
|
// Add new messages to memory
|
|
52
60
|
for (const message of messages) {
|
|
53
|
-
await
|
|
61
|
+
await llmProvider.beta.threads.messages.create(
|
|
54
62
|
initialThread.id, { role: 'assistant', content: message }
|
|
55
63
|
);
|
|
56
64
|
}
|
|
@@ -73,7 +81,7 @@ const createAssistant = async (code, assistant_id, messages=[], prevThread=null)
|
|
|
73
81
|
|
|
74
82
|
// Delete previous thread
|
|
75
83
|
if (prevThread) {
|
|
76
|
-
await
|
|
84
|
+
await llmProvider.beta.threads.del(prevThread.thread_id);
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
return thread;
|
|
@@ -87,7 +95,7 @@ const addMsgAssistant = async (code, inMessages, reply = false) => {
|
|
|
87
95
|
|
|
88
96
|
for (const message of inMessages) {
|
|
89
97
|
console.log(message);
|
|
90
|
-
await
|
|
98
|
+
await llmProvider.beta.threads.messages.create(
|
|
91
99
|
thread.thread_id, { role: 'assistant', content: message }
|
|
92
100
|
);
|
|
93
101
|
}
|
|
@@ -95,7 +103,7 @@ const addMsgAssistant = async (code, inMessages, reply = false) => {
|
|
|
95
103
|
if (!reply) return null;
|
|
96
104
|
|
|
97
105
|
const assistant = getAssistantById(thread.assistant_id, thread);
|
|
98
|
-
const run = await
|
|
106
|
+
const run = await llmProvider.beta.threads.runs.create(
|
|
99
107
|
thread.thread_id,
|
|
100
108
|
{
|
|
101
109
|
assistant_id: thread.assistant_id
|
|
@@ -106,7 +114,7 @@ const addMsgAssistant = async (code, inMessages, reply = false) => {
|
|
|
106
114
|
await checkRunStatus(assistant, run.thread_id, run.id);
|
|
107
115
|
await Thread.updateOne({ code: thread.code, active: true }, { $set: { run_id: null } });
|
|
108
116
|
|
|
109
|
-
const messages = await
|
|
117
|
+
const messages = await llmProvider.beta.threads.messages.list(run.thread_id, { run_id: run.id });
|
|
110
118
|
const ans = messages.data[0].content[0].text.value;
|
|
111
119
|
console.log('THE ANS IS', ans);
|
|
112
120
|
|
|
@@ -124,7 +132,7 @@ const addInsAssistant = async (code, instruction) => {
|
|
|
124
132
|
if (thread === null) return null;
|
|
125
133
|
|
|
126
134
|
const assistant = getAssistantById(thread.assistant_id, thread);
|
|
127
|
-
const run = await
|
|
135
|
+
const run = await llmProvider.beta.threads.runs.create(
|
|
128
136
|
thread.thread_id, {
|
|
129
137
|
assistant_id: thread.assistant_id,
|
|
130
138
|
additional_instructions: instruction,
|
|
@@ -138,7 +146,7 @@ const addInsAssistant = async (code, instruction) => {
|
|
|
138
146
|
await checkRunStatus(assistant, run.thread_id, run.id);
|
|
139
147
|
await Thread.updateOne({ code: thread.code, active: true }, { $set: { run_id: null } });
|
|
140
148
|
|
|
141
|
-
const messages = await
|
|
149
|
+
const messages = await llmProvider.beta.threads.messages.list(run.thread_id, { run_id: run.id });
|
|
142
150
|
console.log(messages.data[0].content);
|
|
143
151
|
const ans = messages.data[0].content[0].text.value;
|
|
144
152
|
|
|
@@ -166,7 +174,7 @@ const getThread = async (code, message = null) => {
|
|
|
166
174
|
|
|
167
175
|
while (thread && thread.run_id) {
|
|
168
176
|
console.log(`Wait for ${thread.run_id} to be executed`);
|
|
169
|
-
const run = await
|
|
177
|
+
const run = await llmProvider.beta.threads.runs.retrieve(thread.thread_id, thread.run_id);
|
|
170
178
|
if (run.status === 'cancelled' || run.status === 'expired' || run.status === 'completed') {
|
|
171
179
|
await Thread.updateOne({ code: code }, { $set: { run_id: null } });
|
|
172
180
|
}
|
|
@@ -204,11 +212,11 @@ const replyAssistant = async function (code, message_ = null, thread_ = null, ru
|
|
|
204
212
|
return null;
|
|
205
213
|
}
|
|
206
214
|
|
|
207
|
-
let activeRuns = await
|
|
215
|
+
let activeRuns = await llmProvider.beta.threads.runs.list(thread.thread_id);
|
|
208
216
|
console.log('ACTIVE RUNS:', activeRuns.length);
|
|
209
217
|
while (activeRuns.length > 0) {
|
|
210
218
|
console.log(`ACTIVE RUNS ${thread.thread_id}`);
|
|
211
|
-
activeRuns = await
|
|
219
|
+
activeRuns = await llmProvider.beta.threads.runs.list(thread.thread_id);
|
|
212
220
|
await delay(5000);
|
|
213
221
|
}
|
|
214
222
|
|
|
@@ -223,21 +231,6 @@ const replyAssistant = async function (code, message_ = null, thread_ = null, ru
|
|
|
223
231
|
|
|
224
232
|
if (urls.length > 0) {
|
|
225
233
|
console.log('urls', urls);
|
|
226
|
-
/*for (const url of urls) {
|
|
227
|
-
console.log("url", url);
|
|
228
|
-
await addRecord(Monitoreo_ID, 'estudios', [{"fields": {"estudios": urls,
|
|
229
|
-
"combined_estudios": [ { "url": url} ], "patient_id": [thread.patient_id]}}]);
|
|
230
|
-
}
|
|
231
|
-
const { pdfBuffer, processedFiles } = await combineImagesToPDF(code);
|
|
232
|
-
console.log("AFTER COMBINED IN BUFFER", processedFiles);
|
|
233
|
-
const key = `${code}-${Date.now()}-combined.pdf`;
|
|
234
|
-
await AWS.uploadBufferToS3(pdfBuffer, bucketName, key, "application/pdf");
|
|
235
|
-
const url = await AWS.generatePresignedUrl(bucketName, key);
|
|
236
|
-
console.log("New record", {"estudios": urls, "combined_estudios":
|
|
237
|
-
[ { "url": url} ], "patient_id": [thread.patient_id]});
|
|
238
|
-
await addRecord(Monitoreo_ID, 'estudios', [{"fields": {"estudios": urls,
|
|
239
|
-
"combined_estudios": [ { "url": url} ], "patient_id": [thread.patient_id]}}]);
|
|
240
|
-
await cleanupFiles(processedFiles);*/
|
|
241
234
|
}
|
|
242
235
|
|
|
243
236
|
thread = await getThread(code);
|
|
@@ -245,7 +238,7 @@ const replyAssistant = async function (code, message_ = null, thread_ = null, ru
|
|
|
245
238
|
if (!patientMsg || !thread || thread?.stopped) return null;
|
|
246
239
|
|
|
247
240
|
const assistant = getAssistantById(thread.assistant_id, thread);
|
|
248
|
-
const run = await
|
|
241
|
+
const run = await llmProvider.beta.threads.runs.create(
|
|
249
242
|
thread.thread_id,
|
|
250
243
|
{
|
|
251
244
|
assistant_id: thread.assistant_id,
|
|
@@ -261,7 +254,7 @@ const replyAssistant = async function (code, message_ = null, thread_ = null, ru
|
|
|
261
254
|
console.log('RUN STATUS', runStatus);
|
|
262
255
|
await Thread.updateOne({ code: thread.code, active: true }, { $set: { run_id: null } });
|
|
263
256
|
|
|
264
|
-
const messages = await
|
|
257
|
+
const messages = await llmProvider.beta.threads.messages.list(run.thread_id, { run_id: run.id });
|
|
265
258
|
const reply = messages.data?.[0]?.content?.[0]?.text?.value || '';
|
|
266
259
|
console.log(reply);
|
|
267
260
|
|
|
@@ -292,5 +285,8 @@ module.exports = {
|
|
|
292
285
|
replyAssistant,
|
|
293
286
|
addMsgAssistant,
|
|
294
287
|
addInsAssistant,
|
|
295
|
-
switchAssistant
|
|
288
|
+
switchAssistant,
|
|
289
|
+
configureAssistants,
|
|
290
|
+
registerAssistant,
|
|
291
|
+
configureLLMProvider
|
|
296
292
|
};
|
|
@@ -54,9 +54,9 @@ class MongoStorage {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
return {
|
|
57
|
-
Message: mongoose.model('Message', messageSchema),
|
|
58
|
-
Interaction: mongoose.model('Interaction', interactionSchema),
|
|
59
|
-
Thread: mongoose.model('Thread', threadSchema)
|
|
57
|
+
Message: mongoose.models.Message || mongoose.model('Message', messageSchema),
|
|
58
|
+
Interaction: mongoose.models.Interaction || mongoose.model('Interaction', interactionSchema),
|
|
59
|
+
Thread: mongoose.models.Thread || mongoose.model('Thread', threadSchema)
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peopl-health/nexus",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "Core messaging and assistant library for WhatsApp communication platforms",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -51,10 +51,12 @@
|
|
|
51
51
|
"license": "MIT",
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"airtable": "^0.12.2",
|
|
54
|
+
"aws-sdk": "2.1674.0",
|
|
54
55
|
"axios": "^1.5.0",
|
|
55
56
|
"dotenv": "^16.4.7",
|
|
56
57
|
"moment-timezone": "^0.5.43",
|
|
57
58
|
"mongoose": "^7.5.0",
|
|
59
|
+
"pdf-lib": "1.17.1",
|
|
58
60
|
"pino": "^8.15.0",
|
|
59
61
|
"pino-pretty": "^10.2.0",
|
|
60
62
|
"uuid": "^9.0.0"
|
|
@@ -69,6 +71,7 @@
|
|
|
69
71
|
"@types/node": "^20.5.0",
|
|
70
72
|
"eslint": "^8.47.0",
|
|
71
73
|
"jest": "^29.6.2",
|
|
74
|
+
"sharp": "0.32.6",
|
|
72
75
|
"typescript": "^5.1.6"
|
|
73
76
|
},
|
|
74
77
|
"engines": {
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
let sendMessage;
|
|
2
|
-
let sendScheduledMessage;
|
|
3
|
-
if (process.env.MESSAGING_PROVIDER === 'baileys') {
|
|
4
|
-
const baileyAdapter = require('../adapters/baileys');
|
|
5
|
-
console.log('Baileys adapter:', baileyAdapter);
|
|
6
|
-
console.log('Has sendMessage?', 'sendMessage' in baileyAdapter);
|
|
7
|
-
sendMessage = baileyAdapter.sendMessage;
|
|
8
|
-
sendScheduledMessage = baileyAdapter.sendScheduledMessage;
|
|
9
|
-
} else if (process.env.MESSAGING_PROVIDER === 'twilio') {
|
|
10
|
-
const { sendMessage: twilioSendMessage } = require('../messaging/messageService');
|
|
11
|
-
const { sendScheduledMessage: twilioSendScheduledMessage } = require('../messaging/scheduledMessageService');
|
|
12
|
-
const twilioAdapter = require('../adapters/twilio');
|
|
13
|
-
const twilioClient = twilioAdapter.twilioClient;
|
|
14
|
-
sendMessage = (messageData) => twilioSendMessage(twilioClient, messageData);
|
|
15
|
-
sendScheduledMessage = (messageData) => twilioSendScheduledMessage(twilioClient, messageData);
|
|
16
|
-
} else {
|
|
17
|
-
throw new Error('Unsupported MESSAGING_PROVIDER specified');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = {
|
|
21
|
-
sendMessage,
|
|
22
|
-
sendScheduledMessage
|
|
23
|
-
};
|