@peopl-health/nexus 2.4.6 → 2.4.8

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.
Files changed (45) hide show
  1. package/examples/assistants/DoctorScheduleAssistant.js +3 -2
  2. package/lib/adapters/BaileysProvider.js +5 -4
  3. package/lib/adapters/TwilioProvider.js +20 -19
  4. package/lib/assistants/BaseAssistant.js +7 -6
  5. package/lib/config/awsConfig.js +14 -12
  6. package/lib/config/llmConfig.js +3 -2
  7. package/lib/config/mongoAuthConfig.js +5 -5
  8. package/lib/controllers/assistantController.js +12 -11
  9. package/lib/controllers/bugReportController.js +6 -5
  10. package/lib/controllers/conversationController.js +72 -71
  11. package/lib/controllers/interactionController.js +7 -6
  12. package/lib/controllers/mediaController.js +15 -13
  13. package/lib/controllers/messageController.js +7 -6
  14. package/lib/controllers/patientController.js +2 -1
  15. package/lib/controllers/qualityMessageController.js +5 -4
  16. package/lib/controllers/templateController.js +11 -9
  17. package/lib/controllers/uploadController.js +3 -1
  18. package/lib/core/NexusMessaging.js +18 -18
  19. package/lib/helpers/assistantHelper.js +8 -9
  20. package/lib/helpers/baileysHelper.js +4 -3
  21. package/lib/helpers/filesHelper.js +9 -8
  22. package/lib/helpers/llmsHelper.js +24 -9
  23. package/lib/helpers/mediaHelper.js +3 -2
  24. package/lib/helpers/messageHelper.js +12 -11
  25. package/lib/helpers/processHelper.js +24 -10
  26. package/lib/helpers/qrHelper.js +2 -1
  27. package/lib/helpers/twilioMediaProcessor.js +45 -35
  28. package/lib/helpers/whatsappHelper.js +3 -2
  29. package/lib/index.js +11 -14
  30. package/lib/interactive/index.js +11 -11
  31. package/lib/middleware/requestId.js +9 -14
  32. package/lib/models/messageModel.js +5 -4
  33. package/lib/providers/OpenAIAssistantsProvider.js +10 -9
  34. package/lib/providers/OpenAIResponsesProvider.js +18 -17
  35. package/lib/providers/OpenAIResponsesProviderTools.js +3 -5
  36. package/lib/providers/createProvider.js +2 -1
  37. package/lib/services/airtableService.js +39 -6
  38. package/lib/services/assistantService.js +20 -20
  39. package/lib/services/conversationService.js +16 -16
  40. package/lib/services/preprocessingHooks.js +3 -1
  41. package/lib/storage/MongoStorage.js +14 -14
  42. package/lib/utils/errorHandler.js +3 -1
  43. package/lib/utils/logger.js +35 -3
  44. package/lib/utils/sanitizer.js +0 -6
  45. package/package.json +1 -1
@@ -5,12 +5,13 @@ const { Thread } = require('../models/threadModel');
5
5
  const llmConfig = require('../config/llmConfig');
6
6
  const { Historial_Clinico_ID } = require('../config/airtableConfig');
7
7
  const { getRecordByFilter } = require('../services/airtableService');
8
+ const { logger } = require('../utils/logger');
8
9
 
9
10
  const Message = mongoose.models.Message;
10
11
 
11
12
  const getConversationController = async (req, res) => {
12
13
  const startTime = Date.now();
13
- console.log('Starting getConversationController at', new Date().toISOString());
14
+ logger.info('Starting getConversationController at', new Date().toISOString());
14
15
 
15
16
  try {
16
17
  // Parse pagination parameters
@@ -19,10 +20,10 @@ const getConversationController = async (req, res) => {
19
20
  const skip = (page - 1) * limit;
20
21
  const filter = req.query.filter || 'all';
21
22
 
22
- console.log(`Pagination: page ${page}, limit ${limit}, skip ${skip}, filter: ${filter}`);
23
+ logger.info(`Pagination: page ${page}, limit ${limit}, skip ${skip}, filter: ${filter}`);
23
24
 
24
25
  if (!Message) {
25
- console.log('Message model not found, returning empty conversations list');
26
+ logger.info('Message model not found, returning empty conversations list');
26
27
  return res.status(200).json({
27
28
  success: true,
28
29
  conversations: [],
@@ -31,10 +32,10 @@ const getConversationController = async (req, res) => {
31
32
  }
32
33
 
33
34
  const messageCount = await Message.countDocuments({});
34
- console.log('Total message count:', messageCount);
35
+ logger.info('Total message count:', messageCount);
35
36
 
36
37
  if (messageCount === 0) {
37
- console.log('No messages found in database, returning empty conversations list');
38
+ logger.info('No messages found in database, returning empty conversations list');
38
39
  return res.status(200).json({
39
40
  success: true,
40
41
  conversations: [],
@@ -46,7 +47,7 @@ const getConversationController = async (req, res) => {
46
47
  const { conversations, total, nameMap, unreadMap } = await fetchConversationData(filter, skip, limit);
47
48
 
48
49
  if (!conversations || conversations.length === 0) {
49
- console.log('No conversations found, returning empty list');
50
+ logger.info('No conversations found, returning empty list');
50
51
  return res.status(200).json({
51
52
  success: true,
52
53
  conversations: [],
@@ -60,9 +61,9 @@ const getConversationController = async (req, res) => {
60
61
  const totalPages = Math.ceil(total / limit);
61
62
  const totalTime = Date.now() - startTime;
62
63
 
63
- console.log('Number of conversations found:', conversations?.length || 0);
64
- console.log(`Total controller execution time: ${totalTime}ms`);
65
- console.log(`Filter: ${filter}, Pagination: ${conversations.length} of ${total} conversations (page ${page}/${totalPages})`);
64
+ logger.info('Number of conversations found:', conversations?.length || 0);
65
+ logger.info(`Total controller execution time: ${totalTime}ms`);
66
+ logger.info(`Filter: ${filter}, Pagination: ${conversations.length} of ${total} conversations (page ${page}/${totalPages})`);
66
67
 
67
68
  res.status(200).json({
68
69
  success: true,
@@ -77,11 +78,11 @@ const getConversationController = async (req, res) => {
77
78
  hasPrev: page > 1
78
79
  }
79
80
  });
80
- console.log('Response sent successfully!');
81
+ logger.info('Response sent successfully!');
81
82
 
82
83
  } catch (error) {
83
- console.error('Error fetching conversations:', error);
84
- console.error('Error stack:', error.stack);
84
+ logger.error('Error fetching conversations:', error);
85
+ logger.error('Error stack:', error.stack);
85
86
  res.status(500).json({
86
87
  success: false,
87
88
  error: error.message || 'Failed to fetch conversations'
@@ -90,10 +91,10 @@ const getConversationController = async (req, res) => {
90
91
  };
91
92
 
92
93
  const getConversationMessagesController = async (req, res) => {
93
- console.log('Starting getConversationMessagesController at', new Date().toISOString());
94
+ logger.info('Starting getConversationMessagesController at', new Date().toISOString());
94
95
  try {
95
96
  const { phoneNumber } = req.params;
96
- console.log('Requested conversation for phone number:', phoneNumber);
97
+ logger.info('Requested conversation for phone number:', phoneNumber);
97
98
 
98
99
  if (!phoneNumber) {
99
100
  return res.status(400).json({
@@ -110,20 +111,20 @@ const getConversationMessagesController = async (req, res) => {
110
111
  try {
111
112
  query.createdAt = { $lt: new Date(before) };
112
113
  } catch (parseError) {
113
- console.warn('Invalid date format for before parameter:', before, parseError);
114
+ logger.warn('Invalid date format for before parameter:', before, parseError);
114
115
  query.createdAt = { $lt: before };
115
116
  }
116
117
  }
117
118
 
118
- console.log('Fetching conversation messages with query:', JSON.stringify(query));
119
- console.log('Using limit:', limit);
119
+ logger.info('Fetching conversation messages with query:', JSON.stringify(query));
120
+ logger.info('Using limit:', limit);
120
121
 
121
- console.log('About to execute Message.find with query:', JSON.stringify(query));
122
+ logger.info('About to execute Message.find with query:', JSON.stringify(query));
122
123
  let messages = [];
123
124
 
124
125
  try {
125
126
  const countResult = await Message.countDocuments(query);
126
- console.log(`Found ${countResult} messages matching query criteria`);
127
+ logger.info(`Found ${countResult} messages matching query criteria`);
127
128
 
128
129
  if (countResult > 0) {
129
130
  messages = await Message.find(query)
@@ -131,22 +132,22 @@ const getConversationMessagesController = async (req, res) => {
131
132
  .limit(limit)
132
133
  .lean();
133
134
 
134
- console.log(`Retrieved ${messages.length} messages, inspecting for potential issues...`);
135
+ logger.info(`Retrieved ${messages.length} messages, inspecting for potential issues...`);
135
136
 
136
137
  const problematicMessages = messages.filter(msg => {
137
138
  if (!msg || !msg.numero || !msg.createdAt) {
138
- console.warn('Found message missing required fields:', msg?._id || 'unknown');
139
+ logger.warn('Found message missing required fields:', msg?._id || 'unknown');
139
140
  return true;
140
141
  }
141
142
 
142
143
  if (msg.is_media === true) {
143
144
  if (!msg.media || typeof msg.media !== 'object') {
144
- console.warn('Found media message with invalid media data:', msg._id);
145
+ logger.warn('Found media message with invalid media data:', msg._id);
145
146
  return true;
146
147
  }
147
148
 
148
149
  if (msg.media && (typeof msg.media.data === 'function' || msg.media.data instanceof Buffer)) {
149
- console.warn('Found media message with Buffer data that might cause serialization issues:', msg._id);
150
+ logger.warn('Found media message with Buffer data that might cause serialization issues:', msg._id);
150
151
  return true;
151
152
  }
152
153
  }
@@ -155,25 +156,25 @@ const getConversationMessagesController = async (req, res) => {
155
156
  });
156
157
 
157
158
  if (problematicMessages.length > 0) {
158
- console.warn(`Found ${problematicMessages.length} potentially problematic messages`);
159
- console.log('First problematic message IDs:', problematicMessages.slice(0, 3).map(m => m?._id || 'unknown'));
159
+ logger.warn(`Found ${problematicMessages.length} potentially problematic messages`);
160
+ logger.info('First problematic message IDs:', problematicMessages.slice(0, 3).map(m => m?._id || 'unknown'));
160
161
  }
161
162
  } else {
162
- console.log('No messages found for this query');
163
+ logger.info('No messages found for this query');
163
164
  }
164
165
  } catch (err) {
165
- console.error('Database query error in message retrieval:', err);
166
+ logger.error('Database query error in message retrieval:', err);
166
167
  messages = [];
167
168
  }
168
169
 
169
- console.log(`Retrieved a total of ${messages?.length || 0} messages for phone number: ${phoneNumber}`);
170
+ logger.info(`Retrieved a total of ${messages?.length || 0} messages for phone number: ${phoneNumber}`);
170
171
 
171
172
  const sanitizedMessages = (messages || []).map(msg => {
172
173
  try {
173
174
  JSON.stringify(msg);
174
175
  return msg;
175
176
  } catch (serializationError) {
176
- console.error(`Found non-serializable message with ID ${msg._id}:`, serializationError);
177
+ logger.error(`Found non-serializable message with ID ${msg._id}:`, serializationError);
177
178
  return {
178
179
  _id: msg._id?.toString() || 'unknown',
179
180
  numero: msg.numero || phoneNumber,
@@ -187,16 +188,16 @@ const getConversationMessagesController = async (req, res) => {
187
188
  });
188
189
 
189
190
  const reversedMessages = sanitizedMessages.reverse();
190
- console.log(`Sending ${reversedMessages.length} sanitized messages in response`);
191
+ logger.info(`Sending ${reversedMessages.length} sanitized messages in response`);
191
192
 
192
193
  res.status(200).json({
193
194
  success: true,
194
195
  phoneNumber,
195
196
  messages: reversedMessages
196
197
  });
197
- console.log('Successfully sent conversation messages response');
198
+ logger.info('Successfully sent conversation messages response');
198
199
  } catch (error) {
199
- console.error(`Error fetching conversation for ${req.params?.phoneNumber || 'unknown'}:`, error);
200
+ logger.error(`Error fetching conversation for ${req.params?.phoneNumber || 'unknown'}:`, error);
200
201
  res.status(500).json({
201
202
  success: false,
202
203
  error: error.message || 'Failed to fetch conversation'
@@ -205,10 +206,10 @@ const getConversationMessagesController = async (req, res) => {
205
206
  };
206
207
 
207
208
  const getConversationReplyController = async (req, res) => {
208
- console.log('Starting getConversationReplyController at', new Date().toISOString());
209
+ logger.info('Starting getConversationReplyController at', new Date().toISOString());
209
210
  try {
210
211
  const { phoneNumber, message, mediaData, contentSid, variables } = req.body;
211
- console.log('Reply request params:', {
212
+ logger.info('Reply request params:', {
212
213
  phoneNumber,
213
214
  hasMessage: !!message,
214
215
  hasMediaData: !!mediaData,
@@ -226,7 +227,7 @@ const getConversationReplyController = async (req, res) => {
226
227
  const formattedPhoneNumber = phoneNumber?.startsWith('whatsapp:')
227
228
  ? phoneNumber
228
229
  : `whatsapp:${phoneNumber}`;
229
- console.log('Formatted phone number:', formattedPhoneNumber);
230
+ logger.info('Formatted phone number:', formattedPhoneNumber);
230
231
 
231
232
  const messageData = {
232
233
  code: formattedPhoneNumber,
@@ -235,11 +236,11 @@ const getConversationReplyController = async (req, res) => {
235
236
 
236
237
  // Handle template message (contentSid provided)
237
238
  if (contentSid) {
238
- console.log('Processing template message with contentSid:', contentSid);
239
+ logger.info('Processing template message with contentSid:', contentSid);
239
240
  messageData.contentSid = contentSid;
240
241
 
241
242
  if (variables && Object.keys(variables).length > 0) {
242
- console.log('Template variables:', JSON.stringify(variables));
243
+ logger.info('Template variables:', JSON.stringify(variables));
243
244
  messageData.variables = variables;
244
245
  }
245
246
 
@@ -255,7 +256,7 @@ const getConversationReplyController = async (req, res) => {
255
256
  }
256
257
  // Handle media message
257
258
  else if (mediaData && mediaData.fileUrl) {
258
- console.log('Processing media data:', { fileType: mediaData.fileType, hasFileUrl: !!mediaData.fileUrl, fileName: mediaData.fileName });
259
+ logger.info('Processing media data:', { fileType: mediaData.fileType, hasFileUrl: !!mediaData.fileUrl, fileName: mediaData.fileName });
259
260
  messageData.fileUrl = mediaData.fileUrl;
260
261
  messageData.fileType = mediaData.fileType || 'image';
261
262
 
@@ -272,19 +273,19 @@ const getConversationReplyController = async (req, res) => {
272
273
  messageData.body = message;
273
274
  }
274
275
 
275
- console.log('Sending message with data:', JSON.stringify(messageData));
276
+ logger.info('Sending message with data:', JSON.stringify(messageData));
276
277
  await sendMessage(messageData);
277
- console.log('Message sent successfully');
278
+ logger.info('Message sent successfully');
278
279
 
279
280
  res.status(200).json({
280
281
  success: true,
281
282
  message: 'Reply sent successfully'
282
283
  });
283
284
  } catch (error) {
284
- console.error('Error sending reply:', error);
285
- console.log('Request body:', JSON.stringify(req.body || {}));
285
+ logger.error('Error sending reply:', error);
286
+ logger.info('Request body:', JSON.stringify(req.body || {}));
286
287
  const errorMsg = error.message || 'Failed to send reply';
287
- console.error('Responding with error:', errorMsg);
288
+ logger.error('Responding with error:', errorMsg);
288
289
  res.status(500).json({
289
290
  success: false,
290
291
  error: errorMsg
@@ -306,7 +307,7 @@ const searchConversationsController = async (req, res) => {
306
307
  const maxLimit = 100;
307
308
  const parsedLimit = Math.min(parseInt(limit) || 50, maxLimit);
308
309
 
309
- console.log(`Searching conversations for query: "${query}"`);
310
+ logger.info(`Searching conversations for query: "${query}"`);
310
311
  const searchStartTime = Date.now();
311
312
 
312
313
  const escapedQuery = query.replace(/\+/g, '\\+');
@@ -341,7 +342,7 @@ const searchConversationsController = async (req, res) => {
341
342
  ]);
342
343
 
343
344
  const searchTime = Date.now() - searchStartTime;
344
- console.log(`Search completed in ${searchTime}ms, found ${conversations.length} conversations`);
345
+ logger.info(`Search completed in ${searchTime}ms, found ${conversations.length} conversations`);
345
346
 
346
347
  // Fetch names from Airtable and WhatsApp (same logic as fetchConversationData)
347
348
  const phoneNumbers = conversations.map(conv => conv._id).filter(Boolean);
@@ -362,7 +363,7 @@ const searchConversationsController = async (req, res) => {
362
363
  batch.map(p => `{whatsapp_id} = "${p}"`).join(', ') +
363
364
  ')';
364
365
  return getRecordByFilter(Historial_Clinico_ID, 'estado_general', formula).catch(error => {
365
- console.error('Error fetching Airtable batch for search:', error);
366
+ logger.error('Error fetching Airtable batch for search:', error);
366
367
  return [];
367
368
  });
368
369
  });
@@ -379,9 +380,9 @@ const searchConversationsController = async (req, res) => {
379
380
  }
380
381
  }
381
382
  });
382
- console.log(`Found ${Object.keys(airtableNameMap).length} names in Airtable for search results (${batches.length} batches)`);
383
+ logger.info(`Found ${Object.keys(airtableNameMap).length} names in Airtable for search results (${batches.length} batches)`);
383
384
  } catch (error) {
384
- console.error('Error fetching names from Airtable for search, falling back to nombre_whatsapp:', error);
385
+ logger.error('Error fetching names from Airtable for search, falling back to nombre_whatsapp:', error);
385
386
  }
386
387
  }
387
388
 
@@ -446,7 +447,7 @@ const searchConversationsController = async (req, res) => {
446
447
  });
447
448
 
448
449
  } catch (error) {
449
- console.error('Error searching conversations:', error);
450
+ logger.error('Error searching conversations:', error);
450
451
  res.status(500).json({
451
452
  success: false,
452
453
  error: error.message || 'Failed to search conversations'
@@ -479,7 +480,7 @@ const getConversationsByNameController = async (req, res) => {
479
480
  }))
480
481
  });
481
482
  } catch (error) {
482
- console.error('Error fetching conversations by name:', error);
483
+ logger.error('Error fetching conversations by name:', error);
483
484
  res.status(500).json({
484
485
  success: false,
485
486
  error: error.message || 'Failed to fetch conversations by name'
@@ -525,7 +526,7 @@ const getNewMessagesController = async (req, res) => {
525
526
  messages: messages
526
527
  });
527
528
  } catch (error) {
528
- console.error(`Error fetching new messages for ${req.params.phoneNumber}:`, error);
529
+ logger.error(`Error fetching new messages for ${req.params.phoneNumber}:`, error);
529
530
  res.status(500).json({
530
531
  success: false,
531
532
  error: error.message || 'Failed to fetch new messages'
@@ -534,7 +535,7 @@ const getNewMessagesController = async (req, res) => {
534
535
  };
535
536
 
536
537
  const markMessagesAsReadController = async (req, res) => {
537
- console.log('Starting markMessagesAsReadController at', new Date().toISOString());
538
+ logger.info('Starting markMessagesAsReadController at', new Date().toISOString());
538
539
  try {
539
540
  const { phoneNumber } = req.params;
540
541
 
@@ -545,7 +546,7 @@ const markMessagesAsReadController = async (req, res) => {
545
546
  });
546
547
  }
547
548
 
548
- console.log('Marking messages as read for phone number:', phoneNumber);
549
+ logger.info('Marking messages as read for phone number:', phoneNumber);
549
550
  const result = await Message.updateMany(
550
551
  {
551
552
  numero: phoneNumber,
@@ -564,8 +565,8 @@ const markMessagesAsReadController = async (req, res) => {
564
565
  modifiedCount: result.nModified || result.modifiedCount
565
566
  });
566
567
  } catch (error) {
567
- console.error(`Error marking messages as read for ${req.params?.phoneNumber || 'unknown'}:`, error);
568
- console.error('Error stack:', error.stack);
568
+ logger.error(`Error marking messages as read for ${req.params?.phoneNumber || 'unknown'}:`, error);
569
+ logger.error('Error stack:', error.stack);
569
570
  res.status(500).json({
570
571
  success: false,
571
572
  error: error.message || 'Failed to mark messages as read'
@@ -574,7 +575,7 @@ const markMessagesAsReadController = async (req, res) => {
574
575
  };
575
576
 
576
577
  const sendTemplateToNewNumberController = async (req, res) => {
577
- console.log('Starting sendTemplateToNewNumberController at', new Date().toISOString());
578
+ logger.info('Starting sendTemplateToNewNumberController at', new Date().toISOString());
578
579
  try {
579
580
  const { phoneNumber, templateId, variables } = req.body;
580
581
 
@@ -598,7 +599,7 @@ const sendTemplateToNewNumberController = async (req, res) => {
598
599
  : `whatsapp:${phoneNumber}`;
599
600
 
600
601
  // Log template details for debugging
601
- console.log('Sending template to new number with details:', {
602
+ logger.info('Sending template to new number with details:', {
602
603
  phoneNumber: formattedPhoneNumber,
603
604
  templateId,
604
605
  hasVariables: variables && Object.keys(variables).length > 0,
@@ -612,7 +613,7 @@ const sendTemplateToNewNumberController = async (req, res) => {
612
613
 
613
614
  if (variables && Object.keys(variables).length > 0) {
614
615
  messageData.variables = variables;
615
- console.log('Template variables:', JSON.stringify(variables));
616
+ logger.info('Template variables:', JSON.stringify(variables));
616
617
  }
617
618
 
618
619
  const message = await sendMessage(messageData);
@@ -623,7 +624,7 @@ const sendTemplateToNewNumberController = async (req, res) => {
623
624
  messageId: message.sid
624
625
  });
625
626
  } catch (error) {
626
- console.error('Error sending template to new number:', error);
627
+ logger.error('Error sending template to new number:', error);
627
628
  res.status(500).json({
628
629
  success: false,
629
630
  error: error.message || 'Failed to send template to new number'
@@ -632,14 +633,14 @@ const sendTemplateToNewNumberController = async (req, res) => {
632
633
  };
633
634
 
634
635
  const getOpenAIThreadMessagesController = async (req, res) => {
635
- console.log('Starting getOpenAIThreadMessagesController at', new Date().toISOString());
636
+ logger.info('Starting getOpenAIThreadMessagesController at', new Date().toISOString());
636
637
  try {
637
638
  const { phoneNumber } = req.params;
638
639
  const { limit = 50, order = 'desc', runId } = req.query;
639
640
  const variant = process.env.VARIANT || 'assistants';
640
641
 
641
- console.log('Fetching OpenAI thread messages for:', phoneNumber);
642
- console.log('Variant:', variant, 'Limit:', limit, 'Order:', order);
642
+ logger.info('Fetching OpenAI thread messages for:', phoneNumber);
643
+ logger.info('Variant:', variant, 'Limit:', limit, 'Order:', order);
643
644
 
644
645
  if (!phoneNumber) {
645
646
  return res.status(400).json({
@@ -654,22 +655,22 @@ const getOpenAIThreadMessagesController = async (req, res) => {
654
655
  }).sort({ createdAt: -1 });
655
656
 
656
657
  if (!thread) {
657
- console.log('No active OpenAI thread found for:', phoneNumber);
658
+ logger.info('No active OpenAI thread found for:', phoneNumber);
658
659
  return res.status(404).json({
659
660
  success: false,
660
661
  error: 'No active OpenAI thread found for this phone number'
661
662
  });
662
663
  }
663
664
 
664
- const conversationId = thread.getConversationId();
665
- console.log('Thread found - Conversation ID:', conversationId);
665
+ const conversationId = thread.conversation_id;
666
+ logger.info('Thread found - Conversation ID:', conversationId);
666
667
 
667
668
  const provider = llmConfig.getOpenAIProvider({ instantiate: true, variant });
668
669
  if (!provider) {
669
670
  throw new Error('OpenAI provider not initialized');
670
671
  }
671
672
 
672
- console.log('Using provider variant:', provider.getVariant());
673
+ logger.info('Using provider variant:', provider.getVariant());
673
674
 
674
675
  const queryParams = {
675
676
  threadId: conversationId,
@@ -679,13 +680,13 @@ const getOpenAIThreadMessagesController = async (req, res) => {
679
680
 
680
681
  if (variant === 'assistants' && runId) {
681
682
  queryParams.runId = runId;
682
- console.log('Including runId:', runId);
683
+ logger.info('Including runId:', runId);
683
684
  }
684
685
 
685
- console.log('Calling listMessages with params:', queryParams);
686
+ logger.info('Calling listMessages with params:', queryParams);
686
687
  const messages = await provider.listMessages(queryParams);
687
688
 
688
- console.log(`Retrieved ${messages?.data?.length || 0} messages from OpenAI`);
689
+ logger.info(`Retrieved ${messages?.data?.length || 0} messages from OpenAI`);
689
690
 
690
691
  res.status(200).json({
691
692
  success: true,
@@ -702,8 +703,8 @@ const getOpenAIThreadMessagesController = async (req, res) => {
702
703
  });
703
704
 
704
705
  } catch (error) {
705
- console.error('Error fetching OpenAI thread messages:', error);
706
- console.error('Error stack:', error.stack);
706
+ logger.error('Error fetching OpenAI thread messages:', error);
707
+ logger.error('Error stack:', error.stack);
707
708
  res.status(500).json({
708
709
  success: false,
709
710
  error: error.message || 'Failed to fetch OpenAI thread messages'
@@ -3,6 +3,7 @@ const { Message } = require('../models/messageModel');
3
3
  const { INTERACTION_QUALITY_VALUES } = require('../config/interactionConfig');
4
4
  const { addRecord, getRecordByFilter } = require('../services/airtableService');
5
5
  const { Logging_ID } = require('../config/airtableConfig');
6
+ const { logger } = require('../utils/logger');
6
7
 
7
8
  async function logInteractionToAirtable(messageIds, whatsapp_id, voter_username, description) {
8
9
  try {
@@ -21,7 +22,7 @@ async function logInteractionToAirtable(messageIds, whatsapp_id, voter_username,
21
22
  patientId = patientRecords[0].record_logging_id;
22
23
  }
23
24
  } catch (err) {
24
- console.warn('Could not find patient in estado_general:', err.message);
25
+ logger.warn('Could not find patient in estado_general:', err.message);
25
26
  }
26
27
 
27
28
  const airtableData = {
@@ -32,9 +33,9 @@ async function logInteractionToAirtable(messageIds, whatsapp_id, voter_username,
32
33
  };
33
34
 
34
35
  await addRecord(Logging_ID, 'interactions', airtableData);
35
- console.log('Interaction logged to Airtable successfully');
36
+ logger.info('Interaction logged to Airtable successfully');
36
37
  } catch (error) {
37
- console.error('Error logging interaction to Airtable:', error);
38
+ logger.error('Error logging interaction to Airtable:', error);
38
39
  }
39
40
  }
40
41
 
@@ -52,12 +53,12 @@ const addInteractionController = async (req, res) => {
52
53
  const interaction = await Interaction.create({ messages, whatsapp_id, voter_username, quality, description });
53
54
 
54
55
  logInteractionToAirtable(messages, whatsapp_id, voter_username, description).catch(err =>
55
- console.error('Background Airtable logging failed:', err)
56
+ logger.error('Background Airtable logging failed:', err)
56
57
  );
57
58
 
58
59
  res.status(201).json({ success: true, interaction });
59
60
  } catch (error) {
60
- console.error('Error adding interaction:', error);
61
+ logger.error('Error adding interaction:', error);
61
62
  res.status(500).json({ success: false, error: error.message });
62
63
  }
63
64
  };
@@ -68,7 +69,7 @@ const getInteractionsByWhatsappIdController = async (req, res) => {
68
69
  const interactions = await Interaction.find({ whatsapp_id }).populate('messages').sort({ createdAt: -1 });
69
70
  res.status(200).json({ success: true, whatsappId: whatsapp_id, count: interactions.length, interactions });
70
71
  } catch (error) {
71
- console.error('Error fetching interactions:', error);
72
+ logger.error('Error fetching interactions:', error);
72
73
  res.status(500).json({ success: false, error: error.message });
73
74
  }
74
75
  };
@@ -1,4 +1,6 @@
1
1
  const { s3, downloadFileFromS3 } = require('../config/awsConfig');
2
+ const { logger } = require('../utils/logger');
3
+
2
4
  const bucketName = process.env.AWS_S3_BUCKET_NAME;
3
5
 
4
6
 
@@ -6,11 +8,11 @@ const getMediaController = async (req, res) => {
6
8
  try {
7
9
  const { key } = req.params;
8
10
 
9
- console.log(`[MediaController] Received request for media file with key: ${key}`);
10
- console.log(`[MediaController] Original URL path: ${req.originalUrl}`);
11
+ logger.info(`[MediaController] Received request for media file with key: ${key}`);
12
+ logger.info(`[MediaController] Original URL path: ${req.originalUrl}`);
11
13
 
12
14
  if (!key || key.trim() === '') {
13
- console.error('[MediaController] Invalid key provided:', key);
15
+ logger.error('[MediaController] Invalid key provided:', key);
14
16
  return res.status(400).json({
15
17
  success: false,
16
18
  error: 'Invalid media key provided'
@@ -27,17 +29,17 @@ const getMediaController = async (req, res) => {
27
29
 
28
30
  let mediaKey = key;
29
31
 
30
- console.log(`[MediaController] Final S3 key to fetch: ${mediaKey}`);
32
+ logger.info(`[MediaController] Final S3 key to fetch: ${mediaKey}`);
31
33
 
32
34
  const fileData = await downloadFileFromS3(bucketName, mediaKey);
33
35
 
34
36
  if (!fileData || !fileData.Body) {
35
- console.error(`[MediaController] Media not found in S3: ${key}`);
37
+ logger.error(`[MediaController] Media not found in S3: ${key}`);
36
38
 
37
39
  if (s3) {
38
40
  try {
39
41
  const prefix = key.split('/') [0];
40
- console.log(`[MediaController] Checking S3 for objects with prefix: ${prefix}/`);
42
+ logger.info(`[MediaController] Checking S3 for objects with prefix: ${prefix}/`);
41
43
  s3.listObjectsV2({
42
44
  Bucket: bucketName,
43
45
  Prefix: prefix + '/',
@@ -45,22 +47,22 @@ const getMediaController = async (req, res) => {
45
47
  }).promise()
46
48
  .then(listData => {
47
49
  if (listData.Contents && listData.Contents.length > 0) {
48
- console.log(`[MediaController] Found ${listData.Contents.length} objects with similar prefix:`);
50
+ logger.info(`[MediaController] Found ${listData.Contents.length} objects with similar prefix:`);
49
51
  listData.Contents.forEach(item => {
50
- console.log(`[MediaController] - ${item.Key} (${item.Size} bytes)`);
52
+ logger.info(`[MediaController] - ${item.Key} (${item.Size} bytes)`);
51
53
  if (item.Key.includes(key.split('/').pop().substring(0, 10))) {
52
- console.log(`[MediaController] !!! POTENTIAL MATCH: ${item.Key}`);
54
+ logger.info(`[MediaController] !!! POTENTIAL MATCH: ${item.Key}`);
53
55
  }
54
56
  });
55
57
  } else {
56
- console.log(`[MediaController] No objects found with prefix: ${prefix}/`);
58
+ logger.info(`[MediaController] No objects found with prefix: ${prefix}/`);
57
59
  }
58
60
  })
59
61
  .catch(listErr => {
60
- console.error(`[MediaController] Error listing objects: ${listErr.message}`);
62
+ logger.error(`[MediaController] Error listing objects: ${listErr.message}`);
61
63
  });
62
64
  } catch (listErr) {
63
- console.error(`[MediaController] Error setting up bucket listing: ${listErr.message}`);
65
+ logger.error(`[MediaController] Error setting up bucket listing: ${listErr.message}`);
64
66
  }
65
67
  }
66
68
 
@@ -94,7 +96,7 @@ const getMediaController = async (req, res) => {
94
96
 
95
97
  res.send(fileData.Body);
96
98
  } catch (error) {
97
- console.error('Error serving media:', error);
99
+ logger.error('Error serving media:', error);
98
100
  res.status(500).json({
99
101
  success: false,
100
102
  error: 'Failed to retrieve media'
@@ -6,6 +6,7 @@ const {
6
6
  } = require('../core/NexusMessaging');
7
7
  const { getRecordByFilter: defaultGetRecordByFilter } = require('../services/airtableService');
8
8
  const runtimeConfig = require('../config/runtimeConfig');
9
+ const { logger } = require('../utils/logger');
9
10
  const moment = require('moment-timezone');
10
11
 
11
12
  const dependencies = {
@@ -131,7 +132,7 @@ const sendMessageController = async (req, res) => {
131
132
  messageId: pickMessageId(result, scheduledRecord)
132
133
  });
133
134
  } catch (err) {
134
- console.error('Error scheduling individual message:', err);
135
+ logger.error('Error scheduling individual message:', err);
135
136
  res.status(500).json({ status: false, error: err.message });
136
137
  }
137
138
  };
@@ -196,7 +197,7 @@ const sendBulkMessageController = async (req, res) => {
196
197
  })
197
198
  );
198
199
 
199
- console.log(`Send bulk of ${numSend} messages`);
200
+ logger.info(`Send bulk of ${numSend} messages`);
200
201
 
201
202
  const messageIds = sentMessages
202
203
  .map(({ result, scheduled }) => pickMessageId(result, scheduled))
@@ -208,7 +209,7 @@ const sendBulkMessageController = async (req, res) => {
208
209
  messageIds
209
210
  });
210
211
  } catch (err) {
211
- console.error('Error sending bulk messages:', err);
212
+ logger.error('Error sending bulk messages:', err);
212
213
  res.status(500).send(err.message);
213
214
  }
214
215
  };
@@ -307,7 +308,7 @@ const sendBulkMessageAirtableController = async (req, res) => {
307
308
  .map(({ result, scheduled }) => pickMessageId(result, scheduled))
308
309
  .filter((id) => id !== null);
309
310
 
310
- console.log(`Iterate over ${(rows || []).length} rows`);
311
+ logger.info(`Iterate over ${(rows || []).length} rows`);
311
312
 
312
313
  res.status(200).json({
313
314
  status: true,
@@ -315,7 +316,7 @@ const sendBulkMessageAirtableController = async (req, res) => {
315
316
  messageIds
316
317
  });
317
318
  } catch (err) {
318
- console.error('Error sending Airtable bulk messages:', err);
319
+ logger.error('Error sending Airtable bulk messages:', err);
319
320
  res.status(500).send(err.message);
320
321
  }
321
322
  };
@@ -343,7 +344,7 @@ const getLastInteractionController = async (req, res) => {
343
344
 
344
345
  return res.status(200).send({ message: 'Last interaction retrieved successfully.', lastMessage, minutes });
345
346
  } catch (error) {
346
- console.error(error);
347
+ logger.error(error);
347
348
  return res.status(500).send({ message: 'Failed to retrieve the last interaction.', error });
348
349
  }
349
350
  };