@peopl-health/nexus 1.1.1 → 1.1.4
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 +2 -46
- package/examples/basic-usage.js +65 -49
- package/examples/consumer-server.js +10 -9
- package/lib/config/airtableConfig.js +45 -0
- package/lib/{utils → config}/mongoAuthConfig.js +3 -13
- package/lib/controllers/assistantController.js +8 -22
- package/lib/controllers/conversationController.js +1 -1
- package/lib/controllers/messageController.js +24 -12
- package/lib/controllers/templateController.js +28 -8
- package/lib/core/NexusMessaging.js +97 -0
- package/lib/routes/index.js +58 -7
- package/lib/services/airtableService.js +82 -0
- package/lib/services/appointmentService.js +55 -0
- package/lib/services/assistantService.js +296 -0
- package/lib/services/conversationService.js +274 -0
- package/lib/services/whatsappService.js +23 -0
- package/lib/utils/index.js +1 -25
- package/package.json +4 -2
- package/lib/utils/twilioHelper.js +0 -75
- package/lib/utils/whatsappHelper.js +0 -60
package/README.md
CHANGED
|
@@ -231,52 +231,8 @@ const { setupDefaultRoutes } = require('@peopl-health/nexus');
|
|
|
231
231
|
|
|
232
232
|
const app = express();
|
|
233
233
|
|
|
234
|
-
//
|
|
235
|
-
|
|
236
|
-
// Assistant controllers
|
|
237
|
-
activeAssistantController: (req, res) => { /* your logic */ },
|
|
238
|
-
createAssistantController: (req, res) => { /* your logic */ },
|
|
239
|
-
listAssistantController: (req, res) => { /* your logic */ },
|
|
240
|
-
addInsAssistantController: (req, res) => { /* your logic */ },
|
|
241
|
-
addMsgAssistantController: (req, res) => { /* your logic */ },
|
|
242
|
-
getInfoAssistantController: (req, res) => { /* your logic */ },
|
|
243
|
-
switchAssistantController: (req, res) => { /* your logic */ },
|
|
244
|
-
stopAssistantController: (req, res) => { /* your logic */ },
|
|
245
|
-
|
|
246
|
-
// Conversation controllers
|
|
247
|
-
getConversationController: (req, res) => { /* your logic */ },
|
|
248
|
-
searchConversationsController: (req, res) => { /* your logic */ },
|
|
249
|
-
getConversationsByNameController: (req, res) => { /* your logic */ },
|
|
250
|
-
getConversationMessagesController: (req, res) => { /* your logic */ },
|
|
251
|
-
getNewMessagesController: (req, res) => { /* your logic */ },
|
|
252
|
-
getConversationReplyController: (req, res) => { /* your logic */ },
|
|
253
|
-
sendTemplateToNewNumberController: (req, res) => { /* your logic */ },
|
|
254
|
-
markMessagesAsReadController: (req, res) => { /* your logic */ },
|
|
255
|
-
|
|
256
|
-
// Media controllers
|
|
257
|
-
getMediaController: (req, res) => { /* your logic */ },
|
|
258
|
-
handleFileUpload: (req, res) => { /* your logic */ },
|
|
259
|
-
|
|
260
|
-
// Message controllers
|
|
261
|
-
sendMessageController: (req, res) => { /* your logic */ },
|
|
262
|
-
sendBulkMessageController: (req, res) => { /* your logic */ },
|
|
263
|
-
sendBulkMessageAirtableController: (req, res) => { /* your logic */ },
|
|
264
|
-
|
|
265
|
-
// Template controllers
|
|
266
|
-
createTemplate: (req, res) => { /* your logic */ },
|
|
267
|
-
listTemplates: (req, res) => { /* your logic */ },
|
|
268
|
-
getPredefinedTemplates: (req, res) => { /* your logic */ },
|
|
269
|
-
getTemplate: (req, res) => { /* your logic */ },
|
|
270
|
-
getCompleteTemplate: (req, res) => { /* your logic */ },
|
|
271
|
-
createFlow: (req, res) => { /* your logic */ },
|
|
272
|
-
deleteFlow: (req, res) => { /* your logic */ },
|
|
273
|
-
submitForApproval: (req, res) => { /* your logic */ },
|
|
274
|
-
checkApprovalStatus: (req, res) => { /* your logic */ },
|
|
275
|
-
deleteTemplate: (req, res) => { /* your logic */ }
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
// Setup all default routes with one line
|
|
279
|
-
setupDefaultRoutes(app, myControllers);
|
|
234
|
+
// Setup all default routes with built-in controllers (one line!)
|
|
235
|
+
setupDefaultRoutes(app);
|
|
280
236
|
|
|
281
237
|
// Add your custom routes
|
|
282
238
|
app.get('/api/custom', myCustomController);
|
package/examples/basic-usage.js
CHANGED
|
@@ -1,54 +1,70 @@
|
|
|
1
|
-
const
|
|
2
|
-
require('
|
|
3
|
-
|
|
4
|
-
async function main() {
|
|
5
|
-
const nexus = new Nexus();
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
// Initialize with minimal configuration
|
|
9
|
-
await nexus.initialize({
|
|
10
|
-
providerConfig: {
|
|
11
|
-
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
12
|
-
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
13
|
-
phoneNumber: process.env.TWILIO_PHONE_NUMBER
|
|
14
|
-
}
|
|
15
|
-
});
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const { NexusMessaging, setupDefaultRoutes } = require('@peopl-health/nexus');
|
|
16
3
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
onMessage: async (messageData) => {
|
|
20
|
-
await nexus.sendMessage({
|
|
21
|
-
to: messageData.from,
|
|
22
|
-
message: `Echo: ${messageData.message}`
|
|
23
|
-
});
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
onCommand: async (messageData) => {
|
|
27
|
-
const { command } = messageData.command;
|
|
28
|
-
const responses = {
|
|
29
|
-
help: 'Commands: /help, /status',
|
|
30
|
-
status: `Status: ${nexus.isConnected() ? 'Online' : 'Offline'}`
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
await nexus.sendMessage({
|
|
34
|
-
to: messageData.from,
|
|
35
|
-
message: responses[command] || `Unknown command: ${command}`
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
});
|
|
4
|
+
const app = express();
|
|
5
|
+
app.use(express.json());
|
|
39
6
|
|
|
40
|
-
|
|
7
|
+
async function startServer() {
|
|
8
|
+
// Initialize Nexus with all services
|
|
9
|
+
const nexus = new NexusMessaging();
|
|
10
|
+
|
|
11
|
+
await nexus.initialize({
|
|
12
|
+
// MongoDB connection
|
|
13
|
+
mongoUri: process.env.MONGODB_URI,
|
|
41
14
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
15
|
+
// Messaging provider
|
|
16
|
+
provider: 'twilio',
|
|
17
|
+
providerConfig: {
|
|
18
|
+
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
19
|
+
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
20
|
+
phoneNumber: process.env.TWILIO_PHONE_NUMBER
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Set up all default API routes with built-in controllers
|
|
25
|
+
setupDefaultRoutes(app);
|
|
26
|
+
|
|
27
|
+
// Add webhook endpoint for incoming messages
|
|
28
|
+
app.post('/webhook', async (req, res) => {
|
|
29
|
+
try {
|
|
30
|
+
await nexus.processIncomingMessage(req.body);
|
|
31
|
+
res.status(200).send('OK');
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error('Webhook error:', error);
|
|
34
|
+
res.status(500).send('Error');
|
|
35
|
+
}
|
|
36
|
+
});
|
|
47
37
|
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
// Custom endpoint example
|
|
39
|
+
app.get('/status', (req, res) => {
|
|
40
|
+
res.json({
|
|
41
|
+
connected: nexus.isConnected(),
|
|
42
|
+
provider: 'twilio',
|
|
43
|
+
mongodb: nexus.mongodb?.readyState === 1,
|
|
44
|
+
airtable: !!nexus.airtable
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Example using Airtable
|
|
49
|
+
app.get('/airtable-test', async (req, res) => {
|
|
50
|
+
try {
|
|
51
|
+
const calendarBase = nexus.getAirtableBase('calendar');
|
|
52
|
+
// Use calendarBase to interact with Airtable
|
|
53
|
+
res.json({ success: true, message: 'Airtable connection ready' });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
res.status(500).json({ error: error.message });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const PORT = process.env.PORT || 3000;
|
|
60
|
+
app.listen(PORT, () => {
|
|
61
|
+
console.log(`Server running on port ${PORT}`);
|
|
62
|
+
console.log('Available endpoints:');
|
|
63
|
+
console.log('- POST /webhook - Webhook for incoming messages');
|
|
64
|
+
console.log('- GET /status - Connection status');
|
|
65
|
+
console.log('- GET /airtable-test - Test Airtable connection');
|
|
66
|
+
console.log('- All Nexus API routes under /api/*');
|
|
67
|
+
});
|
|
68
|
+
}
|
|
53
69
|
|
|
54
|
-
|
|
70
|
+
startServer().catch(console.error);
|
|
@@ -13,16 +13,19 @@ let assistants = {};
|
|
|
13
13
|
|
|
14
14
|
async function initializeNexus() {
|
|
15
15
|
await nexus.initialize({
|
|
16
|
-
|
|
16
|
+
// MongoDB connection
|
|
17
|
+
mongoUri: process.env.MONGODB_URI,
|
|
18
|
+
|
|
19
|
+
// Messaging provider
|
|
20
|
+
provider: process.env.MESSAGING_PROVIDER || 'twilio',
|
|
17
21
|
providerConfig: {
|
|
18
22
|
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
19
23
|
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
20
24
|
phoneNumber: process.env.TWILIO_PHONE_NUMBER
|
|
21
25
|
},
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
},
|
|
26
|
+
|
|
27
|
+
// LLM provider
|
|
28
|
+
llm: 'openai',
|
|
26
29
|
llmConfig: {
|
|
27
30
|
apiKey: process.env.OPENAI_API_KEY
|
|
28
31
|
}
|
|
@@ -31,14 +34,12 @@ async function initializeNexus() {
|
|
|
31
34
|
assistants = {
|
|
32
35
|
sales: new ExampleAssistant({
|
|
33
36
|
assistantId: process.env.SALES_ASSISTANT_ID,
|
|
34
|
-
llmClient: nexus.getLLMProvider()
|
|
35
|
-
storage: nexus.getStorage(),
|
|
37
|
+
llmClient: nexus.getLLMProvider(),
|
|
36
38
|
nexus: nexus
|
|
37
39
|
}),
|
|
38
40
|
support: new ExampleAssistant({
|
|
39
41
|
assistantId: process.env.SUPPORT_ASSISTANT_ID,
|
|
40
|
-
llmClient: nexus.getLLMProvider()
|
|
41
|
-
storage: nexus.getStorage(),
|
|
42
|
+
llmClient: nexus.getLLMProvider(),
|
|
42
43
|
nexus: nexus
|
|
43
44
|
})
|
|
44
45
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const Airtable = require('airtable');
|
|
2
|
+
|
|
3
|
+
const airtableConfig = {
|
|
4
|
+
apiKey: process.env.AIRTABLE_API_KEY,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// Configurable base IDs - users can override via environment variables
|
|
8
|
+
const Calendar_ID = process.env.AIRTABLE_CALENDAR_ID || 'appIjEstWR6972tbF';
|
|
9
|
+
const Config_ID = process.env.AIRTABLE_CONFIG_ID || 'app9K4EvGI8McC8jF';
|
|
10
|
+
const Historial_Clinico_ID = process.env.AIRTABLE_HISTORIAL_CLINICO_ID || 'appdUpGUS06XIzVnY';
|
|
11
|
+
const Logging_ID = process.env.AIRTABLE_LOGGING_ID || 'appQ7YhzfebRDbSPJ';
|
|
12
|
+
const Monitoreo_ID = process.env.AIRTABLE_MONITOREO_ID || 'appdvraKSdp0XVn5n';
|
|
13
|
+
const Programa_Juntas_ID = process.env.AIRTABLE_PROGRAMA_JUNTAS_ID || 'appKFWzkcDEWlrXBE';
|
|
14
|
+
const Symptoms_ID = process.env.AIRTABLE_SYMPTOMS_ID || 'appQRhZlQ9tMfYZWJ';
|
|
15
|
+
const Webinars_Leads_ID = process.env.AIRTABLE_WEBINARS_LEADS_ID || 'appzjpVXTI0TgqGPq';
|
|
16
|
+
|
|
17
|
+
// Initialize Airtable only if API key is provided
|
|
18
|
+
let airtable = null;
|
|
19
|
+
if (airtableConfig.apiKey) {
|
|
20
|
+
airtable = new Airtable({ apiKey: airtableConfig.apiKey });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = {
|
|
24
|
+
airtable,
|
|
25
|
+
config: airtableConfig,
|
|
26
|
+
Calendar_ID,
|
|
27
|
+
Config_ID,
|
|
28
|
+
Historial_Clinico_ID,
|
|
29
|
+
Logging_ID,
|
|
30
|
+
Monitoreo_ID,
|
|
31
|
+
Programa_Juntas_ID,
|
|
32
|
+
Symptoms_ID,
|
|
33
|
+
Webinars_Leads_ID,
|
|
34
|
+
|
|
35
|
+
// Helper function to get base by ID
|
|
36
|
+
getBase: (baseId = process.env.AIRTABLE_BASE_ID) => {
|
|
37
|
+
if (!airtable) {
|
|
38
|
+
throw new Error('Airtable not configured. Please set AIRTABLE_API_KEY environment variable.');
|
|
39
|
+
}
|
|
40
|
+
if (!baseId) {
|
|
41
|
+
throw new Error('Airtable base ID not provided. Please set AIRTABLE_BASE_ID environment variable or pass baseId parameter.');
|
|
42
|
+
}
|
|
43
|
+
return airtable.base(baseId);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
const { MongoClient } = require('mongodb');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
try {
|
|
5
|
-
baileys = require('baileys');
|
|
6
|
-
} catch (error) {
|
|
7
|
-
baileys = null;
|
|
8
|
-
}
|
|
3
|
+
const { proto, Curve, signedKeyPair, generateRegistrationId } = require('baileys');
|
|
9
4
|
const { randomBytes } = require('crypto');
|
|
10
5
|
|
|
11
6
|
async function connectToMongo(mongoClient) {
|
|
@@ -19,11 +14,6 @@ async function connectToMongo(mongoClient) {
|
|
|
19
14
|
}
|
|
20
15
|
|
|
21
16
|
async function initAuthCreds() {
|
|
22
|
-
if (!baileys) {
|
|
23
|
-
throw new Error('Baileys is required for auth credentials but not installed');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const { proto, Curve, signedKeyPair, generateRegistrationId } = baileys;
|
|
27
17
|
const identityKey = Curve.generateKeyPair();
|
|
28
18
|
return {
|
|
29
19
|
noiseKey: Curve.generateKeyPair(),
|
|
@@ -120,8 +110,8 @@ async function useMongoDBAuthState(uri, dbName, sessionId) {
|
|
|
120
110
|
const data = {};
|
|
121
111
|
await Promise.all(ids.map(async (id) => {
|
|
122
112
|
let value = await readData(`${type}-${id}`);
|
|
123
|
-
if (type === 'app-state-sync-key'
|
|
124
|
-
value =
|
|
113
|
+
if (type === 'app-state-sync-key') {
|
|
114
|
+
value = proto.Message.AppStateSyncKeyData.fromObject(data);
|
|
125
115
|
}
|
|
126
116
|
data[id] = value;
|
|
127
117
|
}));
|
|
@@ -17,28 +17,14 @@ try {
|
|
|
17
17
|
// Models not available
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// Optional service imports
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const assistantService = require('../services/assistantService');
|
|
29
|
-
createAssistant = assistantService.createAssistant;
|
|
30
|
-
addMsgAssistant = assistantService.addMsgAssistant;
|
|
31
|
-
addInsAssistant = assistantService.addInsAssistant;
|
|
32
|
-
getThreadInfo = assistantService.getThreadInfo;
|
|
33
|
-
switchAssistant = assistantService.switchAssistant;
|
|
34
|
-
} catch (e) {
|
|
35
|
-
// Service not available
|
|
36
|
-
}
|
|
37
|
-
try {
|
|
38
|
-
sendMessage = require('../services/whatsappService')?.sendMessage;
|
|
39
|
-
} catch (e) {
|
|
40
|
-
// Service not available
|
|
41
|
-
}
|
|
20
|
+
// Optional service imports - stub functions for missing services
|
|
21
|
+
const getRecordByFilter = () => Promise.resolve(null);
|
|
22
|
+
const createAssistant = () => Promise.resolve({ success: false, error: 'Service not available' });
|
|
23
|
+
const addMsgAssistant = () => Promise.resolve({ success: false, error: 'Service not available' });
|
|
24
|
+
const addInsAssistant = () => Promise.resolve({ success: false, error: 'Service not available' });
|
|
25
|
+
const getThreadInfo = () => Promise.resolve(null);
|
|
26
|
+
const switchAssistant = () => Promise.resolve({ success: false, error: 'Service not available' });
|
|
27
|
+
const sendMessage = () => Promise.resolve({ success: false, error: 'Service not available' });
|
|
42
28
|
|
|
43
29
|
|
|
44
30
|
const activeAssistantController = async (req, res) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { Message } = require('../models/messageModel');
|
|
2
|
-
const { sendMessage } = require('../services/whatsappService');
|
|
3
2
|
const { fetchConversationData, processConversations } = require('../services/conversationService');
|
|
3
|
+
const { sendMessage } = require('../core/NexusMessaging');
|
|
4
4
|
|
|
5
5
|
const getConversationController = async (req, res) => {
|
|
6
6
|
const startTime = Date.now();
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
// Import from Nexus core
|
|
2
|
+
const { sendMessage } = require('../core/NexusMessaging');
|
|
3
|
+
|
|
4
|
+
// Stub for missing model
|
|
5
|
+
const ScheduledMessage = {
|
|
6
|
+
create: () => Promise.resolve({ success: false, error: 'Model not available' }),
|
|
7
|
+
find: () => Promise.resolve([]),
|
|
8
|
+
findById: () => Promise.resolve(null),
|
|
9
|
+
deleteOne: () => Promise.resolve({ success: false, error: 'Model not available' })
|
|
10
|
+
};
|
|
2
11
|
|
|
3
|
-
|
|
4
|
-
const
|
|
12
|
+
// Stub functions for missing services
|
|
13
|
+
const getRecordByFilter = () => Promise.resolve(null);
|
|
14
|
+
const sendScheduledMessage = () => Promise.resolve({ success: false, error: 'Service not available' });
|
|
5
15
|
|
|
6
16
|
const moment = require('moment-timezone');
|
|
7
17
|
|
|
@@ -21,7 +31,7 @@ const sendMessageController = async (req, res) => {
|
|
|
21
31
|
const sendMoment = sendTime ? moment.tz(sendTime, timeZone) + 2500 : new Date();
|
|
22
32
|
|
|
23
33
|
try {
|
|
24
|
-
const
|
|
34
|
+
const messageData = {
|
|
25
35
|
fileUrl,
|
|
26
36
|
message,
|
|
27
37
|
fileType,
|
|
@@ -33,14 +43,16 @@ const sendMessageController = async (req, res) => {
|
|
|
33
43
|
author,
|
|
34
44
|
extraDelay: 0,
|
|
35
45
|
variables
|
|
36
|
-
}
|
|
37
|
-
await
|
|
38
|
-
console.log(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
};
|
|
47
|
+
await ScheduledMessage.create(messageData);
|
|
48
|
+
console.log('Sending message with data:', messageData);
|
|
49
|
+
|
|
50
|
+
const result = await sendMessage(messageData);
|
|
51
|
+
|
|
52
|
+
res.status(200).json({
|
|
53
|
+
success: true,
|
|
54
|
+
message: 'Message sent successfully',
|
|
55
|
+
messageId: result?.sid || result?.id
|
|
44
56
|
});
|
|
45
57
|
} catch (err) {
|
|
46
58
|
console.error('Error scheduling individual message:', err.message);
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
1
|
+
// Stub functions for missing services
|
|
2
|
+
const TwilioService = {
|
|
3
|
+
createTemplate: () => Promise.resolve({ success: false, error: 'Service not available' }),
|
|
4
|
+
deleteTemplate: () => Promise.resolve({ success: false, error: 'Service not available' }),
|
|
5
|
+
listTemplates: () => Promise.resolve([]),
|
|
6
|
+
getTemplate: () => Promise.resolve(null)
|
|
7
|
+
};
|
|
8
|
+
const handleApiError = (res, error, message) => {
|
|
9
|
+
console.error(message, error);
|
|
10
|
+
return res.status(500).json({ success: false, error: message });
|
|
11
|
+
};
|
|
3
12
|
|
|
4
|
-
//
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
// Stub imports for missing dependencies
|
|
14
|
+
const Template = class { constructor() {} };
|
|
15
|
+
const TemplateModel = {
|
|
16
|
+
create: () => Promise.resolve({ success: false, error: 'Model not available' }),
|
|
17
|
+
find: () => Promise.resolve([]),
|
|
18
|
+
findById: () => Promise.resolve(null)
|
|
19
|
+
};
|
|
20
|
+
const predefinedTemplates = [];
|
|
9
21
|
|
|
10
22
|
/**
|
|
11
23
|
* Create a new template and store it in both Twilio and our database
|
|
@@ -616,6 +628,15 @@ const getCompleteTemplate = async (req, res) => {
|
|
|
616
628
|
}
|
|
617
629
|
};
|
|
618
630
|
|
|
631
|
+
// Flow functions (inline since templateFlowController was removed)
|
|
632
|
+
const createFlow = async (req, res) => {
|
|
633
|
+
return res.status(501).json({ success: false, error: 'Flow creation not available' });
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
const deleteFlow = async (req, res) => {
|
|
637
|
+
return res.status(501).json({ success: false, error: 'Flow deletion not available' });
|
|
638
|
+
};
|
|
639
|
+
|
|
619
640
|
module.exports = {
|
|
620
641
|
createTemplate,
|
|
621
642
|
listTemplates,
|
|
@@ -625,7 +646,6 @@ module.exports = {
|
|
|
625
646
|
checkApprovalStatus,
|
|
626
647
|
deleteTemplate,
|
|
627
648
|
getCompleteTemplate,
|
|
628
|
-
// Flow functions from templateFlowController
|
|
629
649
|
createFlow,
|
|
630
650
|
deleteFlow
|
|
631
651
|
};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
const { TwilioProvider } = require('../adapters/TwilioProvider');
|
|
2
2
|
const { BaileysProvider } = require('../adapters/BaileysProvider');
|
|
3
|
+
const mongoose = require('mongoose');
|
|
4
|
+
const { airtable, getBase } = require('../config/airtableConfig');
|
|
5
|
+
const OpenAI = require('openai');
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Core messaging class that manages providers and message handling
|
|
@@ -9,6 +12,9 @@ class NexusMessaging {
|
|
|
9
12
|
this.config = config;
|
|
10
13
|
this.provider = null;
|
|
11
14
|
this.messageStorage = null;
|
|
15
|
+
this.mongodb = null;
|
|
16
|
+
this.airtable = airtable;
|
|
17
|
+
this.llmProvider = null;
|
|
12
18
|
this.handlers = {
|
|
13
19
|
onMessage: null,
|
|
14
20
|
onInteractive: null,
|
|
@@ -19,6 +25,97 @@ class NexusMessaging {
|
|
|
19
25
|
};
|
|
20
26
|
}
|
|
21
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Initialize MongoDB connection
|
|
30
|
+
* @param {string} mongoUri - MongoDB connection string
|
|
31
|
+
*/
|
|
32
|
+
async initializeMongoDB(mongoUri = process.env.MONGODB_URI) {
|
|
33
|
+
if (!mongoUri) {
|
|
34
|
+
throw new Error('MongoDB URI not provided. Please set MONGODB_URI environment variable or pass mongoUri parameter.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
await mongoose.connect(mongoUri);
|
|
39
|
+
this.mongodb = mongoose.connection;
|
|
40
|
+
console.log('MongoDB connected successfully');
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error('MongoDB connection failed:', error);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get Airtable base instance
|
|
49
|
+
* @param {string} baseId - Airtable base ID
|
|
50
|
+
*/
|
|
51
|
+
getAirtableBase(baseId) {
|
|
52
|
+
return getBase(baseId);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initialize LLM provider
|
|
57
|
+
* @param {string} llmType - LLM provider type ('openai')
|
|
58
|
+
* @param {Object} llmConfig - LLM configuration
|
|
59
|
+
*/
|
|
60
|
+
initializeLLM(llmType, llmConfig) {
|
|
61
|
+
switch (llmType.toLowerCase()) {
|
|
62
|
+
case 'openai':
|
|
63
|
+
if (!llmConfig.apiKey) {
|
|
64
|
+
throw new Error('OpenAI API key is required');
|
|
65
|
+
}
|
|
66
|
+
this.llmProvider = new OpenAI({
|
|
67
|
+
apiKey: llmConfig.apiKey
|
|
68
|
+
});
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unsupported LLM provider: ${llmType}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Get LLM provider instance
|
|
77
|
+
*/
|
|
78
|
+
getLLMProvider() {
|
|
79
|
+
return this.llmProvider;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Initialize Nexus with all services
|
|
84
|
+
* @param {Object} options - Configuration options
|
|
85
|
+
*/
|
|
86
|
+
async initialize(options = {}) {
|
|
87
|
+
const {
|
|
88
|
+
provider,
|
|
89
|
+
providerConfig,
|
|
90
|
+
mongoUri,
|
|
91
|
+
messageStorage,
|
|
92
|
+
llm,
|
|
93
|
+
llmConfig
|
|
94
|
+
} = options;
|
|
95
|
+
|
|
96
|
+
// Initialize MongoDB if URI provided
|
|
97
|
+
if (mongoUri || process.env.MONGODB_URI) {
|
|
98
|
+
await this.initializeMongoDB(mongoUri);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Initialize messaging provider
|
|
102
|
+
if (provider && providerConfig) {
|
|
103
|
+
await this.initializeProvider(provider, providerConfig);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Initialize LLM provider
|
|
107
|
+
if (llm && llmConfig) {
|
|
108
|
+
this.initializeLLM(llm, llmConfig);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Set message storage
|
|
112
|
+
if (messageStorage) {
|
|
113
|
+
this.setMessageStorage(messageStorage);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
|
|
22
119
|
/**
|
|
23
120
|
* Initialize messaging with specified provider
|
|
24
121
|
* @param {string} providerType - 'twilio' or 'baileys'
|
package/lib/routes/index.js
CHANGED
|
@@ -64,13 +64,64 @@ const createRouter = (routeDefinitions, controllers) => {
|
|
|
64
64
|
return router;
|
|
65
65
|
};
|
|
66
66
|
|
|
67
|
-
//
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
// Import built-in controllers
|
|
68
|
+
const assistantController = require('../controllers/assistantController');
|
|
69
|
+
const conversationController = require('../controllers/conversationController');
|
|
70
|
+
const mediaController = require('../controllers/mediaController');
|
|
71
|
+
const messageController = require('../controllers/messageController');
|
|
72
|
+
const templateController = require('../controllers/templateController');
|
|
73
|
+
|
|
74
|
+
// Built-in controllers mapping
|
|
75
|
+
const builtInControllers = {
|
|
76
|
+
// Assistant controllers
|
|
77
|
+
activeAssistantController: assistantController.activeAssistantController,
|
|
78
|
+
addInsAssistantController: assistantController.addInsAssistantController,
|
|
79
|
+
addMsgAssistantController: assistantController.addMsgAssistantController,
|
|
80
|
+
createAssistantController: assistantController.createAssistantController,
|
|
81
|
+
getInfoAssistantController: assistantController.getInfoAssistantController,
|
|
82
|
+
listAssistantController: assistantController.listAssistantController,
|
|
83
|
+
switchAssistantController: assistantController.switchAssistantController,
|
|
84
|
+
stopAssistantController: assistantController.stopAssistantController,
|
|
85
|
+
|
|
86
|
+
// Conversation controllers
|
|
87
|
+
getConversationController: conversationController.getConversationController,
|
|
88
|
+
searchConversationsController: conversationController.searchConversationsController,
|
|
89
|
+
getConversationsByNameController: conversationController.getConversationsByNameController,
|
|
90
|
+
getConversationMessagesController: conversationController.getConversationMessagesController,
|
|
91
|
+
getNewMessagesController: conversationController.getNewMessagesController,
|
|
92
|
+
getConversationReplyController: conversationController.getConversationReplyController,
|
|
93
|
+
sendTemplateToNewNumberController: conversationController.sendTemplateToNewNumberController,
|
|
94
|
+
markMessagesAsReadController: conversationController.markMessagesAsReadController,
|
|
95
|
+
|
|
96
|
+
// Media controllers
|
|
97
|
+
getMediaController: mediaController.getMediaController,
|
|
98
|
+
handleFileUpload: mediaController.handleFileUpload,
|
|
99
|
+
|
|
100
|
+
// Message controllers
|
|
101
|
+
sendMessageController: messageController.sendMessageController,
|
|
102
|
+
sendBulkMessageController: messageController.sendBulkMessageController,
|
|
103
|
+
sendBulkMessageAirtableController: messageController.sendBulkMessageAirtableController,
|
|
104
|
+
|
|
105
|
+
// Template controllers
|
|
106
|
+
createTemplate: templateController.createTemplate,
|
|
107
|
+
listTemplates: templateController.listTemplates,
|
|
108
|
+
getPredefinedTemplates: templateController.getPredefinedTemplates,
|
|
109
|
+
getTemplate: templateController.getTemplate,
|
|
110
|
+
getCompleteTemplate: templateController.getCompleteTemplate,
|
|
111
|
+
createFlow: templateController.createFlow,
|
|
112
|
+
deleteFlow: templateController.deleteFlow,
|
|
113
|
+
submitForApproval: templateController.submitForApproval,
|
|
114
|
+
checkApprovalStatus: templateController.checkApprovalStatus,
|
|
115
|
+
deleteTemplate: templateController.deleteTemplate
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Helper function to setup all default routes using built-in controllers
|
|
119
|
+
const setupDefaultRoutes = (app) => {
|
|
120
|
+
app.use('/api/assistant', createRouter(assistantRouteDefinitions, builtInControllers));
|
|
121
|
+
app.use('/api/conversation', createRouter(conversationRouteDefinitions, builtInControllers));
|
|
122
|
+
app.use('/api/media', createRouter(mediaRouteDefinitions, builtInControllers));
|
|
123
|
+
app.use('/api/message', createRouter(messageRouteDefinitions, builtInControllers));
|
|
124
|
+
app.use('/api/template', createRouter(templateRouteDefinitions, builtInControllers));
|
|
74
125
|
};
|
|
75
126
|
|
|
76
127
|
module.exports = {
|