tango-app-api-audio-analytics 1.0.8 → 1.0.9
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/package.json +1 -1
- package/src/controllers/audioAnalytics.controller.js +1 -0
- package/src/controllers/cohortAnalytics.controller.js +11 -2
- package/src/controllers/conversationAnalytics.controller.js +34 -29
- package/src/dtos/audioAnalytics.dtos.js +5 -1
- package/src/services/conversation.service.js +79 -34
package/package.json
CHANGED
|
@@ -46,9 +46,18 @@ export const getCohortAnalysisCard = async ( req, res ) => {
|
|
|
46
46
|
clientId,
|
|
47
47
|
} );
|
|
48
48
|
|
|
49
|
+
if ( !summaryCard ) {
|
|
50
|
+
logger.warn( 'No data returned for cohort analysis summary card', { startDate, endDate, storeId, cohortType, clientId } );
|
|
51
|
+
return res.status( 204 ).json( {
|
|
52
|
+
status: 'error',
|
|
53
|
+
message: 'No data found for the given parameters',
|
|
54
|
+
code: 'DATA_NOT_FOUND',
|
|
55
|
+
timestamp: new Date().toISOString(),
|
|
56
|
+
} );
|
|
57
|
+
}
|
|
49
58
|
return res.status( 200 ).json( {
|
|
50
|
-
status: 'success',
|
|
51
|
-
data: summaryCard,
|
|
59
|
+
status: summaryCard?.status || 'success',
|
|
60
|
+
data: summaryCard?.data || [],
|
|
52
61
|
timestamp: new Date().toISOString(),
|
|
53
62
|
} );
|
|
54
63
|
} catch ( error ) {
|
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
exportConversationsFromLambda,
|
|
6
6
|
getConversationDetailsFromLambda,
|
|
7
7
|
exportConversationsToCSV,
|
|
8
|
-
filterConversationsBySearch,
|
|
9
|
-
sortConversations,
|
|
8
|
+
// filterConversationsBySearch,
|
|
9
|
+
// sortConversations,
|
|
10
10
|
} from '../services/conversation.service.js';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -34,6 +34,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
34
34
|
endDate,
|
|
35
35
|
storeId,
|
|
36
36
|
clientId,
|
|
37
|
+
cohortId,
|
|
37
38
|
isAI,
|
|
38
39
|
analyticsType,
|
|
39
40
|
searchValue,
|
|
@@ -71,13 +72,14 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
71
72
|
endDate,
|
|
72
73
|
storeId,
|
|
73
74
|
clientId,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
cohortId,
|
|
76
|
+
isExport,
|
|
77
|
+
limit,
|
|
78
|
+
offset,
|
|
77
79
|
} );
|
|
78
80
|
|
|
79
|
-
conversations = exportResponse.conversations || [];
|
|
80
|
-
totalCount = exportResponse.totalCount || conversations.length;
|
|
81
|
+
// conversations = exportResponse.conversations || [];
|
|
82
|
+
// totalCount = exportResponse.totalCount || conversations.length;
|
|
81
83
|
|
|
82
84
|
logger.info( {
|
|
83
85
|
message: 'Export Lambda response received',
|
|
@@ -85,15 +87,15 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
85
87
|
} );
|
|
86
88
|
|
|
87
89
|
// Apply search filter if provided
|
|
88
|
-
if ( searchValue ) {
|
|
89
|
-
|
|
90
|
-
}
|
|
90
|
+
// if ( searchValue ) {
|
|
91
|
+
// conversations = filterConversationsBySearch( conversations, searchValue );
|
|
92
|
+
// }
|
|
91
93
|
|
|
92
|
-
// Apply sorting
|
|
93
|
-
conversations = sortConversations( conversations, 'date', 'desc' );
|
|
94
|
+
// // Apply sorting
|
|
95
|
+
// conversations = sortConversations( conversations, 'date', 'desc' );
|
|
94
96
|
|
|
95
97
|
// Convert to CSV
|
|
96
|
-
const csv = await exportConversationsToCSV(
|
|
98
|
+
const csv = await exportConversationsToCSV( exportResponse.data );
|
|
97
99
|
res.setHeader( 'Content-Type', 'text/csv' );
|
|
98
100
|
res.setHeader( 'Content-Disposition', 'attachment; filename=conversations.csv' );
|
|
99
101
|
return res.send( csv );
|
|
@@ -116,23 +118,22 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
116
118
|
offset,
|
|
117
119
|
} );
|
|
118
120
|
|
|
119
|
-
conversations = lambdaResponse.conversations || [];
|
|
120
|
-
totalCount = lambdaResponse.totalCount || conversations.length;
|
|
121
|
+
// conversations = lambdaResponse.conversations || [];
|
|
122
|
+
// totalCount = lambdaResponse.totalCount || conversations.length;
|
|
121
123
|
|
|
122
|
-
// Apply search filter if provided
|
|
123
|
-
if ( searchValue ) {
|
|
124
|
-
|
|
125
|
-
}
|
|
124
|
+
// // Apply search filter if provided
|
|
125
|
+
// if ( searchValue ) {
|
|
126
|
+
// conversations = filterConversationsBySearch( conversations, searchValue );
|
|
127
|
+
// }
|
|
126
128
|
|
|
127
|
-
// Apply sorting
|
|
128
|
-
conversations = sortConversations( conversations, 'date', 'desc' );
|
|
129
|
+
// // Apply sorting
|
|
130
|
+
// conversations = sortConversations( conversations, 'date', 'desc' );
|
|
129
131
|
|
|
130
132
|
// Return paginated JSON response
|
|
131
133
|
return res.status( 200 ).json( {
|
|
132
134
|
status: 'success',
|
|
133
135
|
data: {
|
|
134
|
-
|
|
135
|
-
conversations,
|
|
136
|
+
lambdaResponse,
|
|
136
137
|
pagination: {
|
|
137
138
|
limit,
|
|
138
139
|
offset,
|
|
@@ -167,12 +168,16 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
167
168
|
export const getConversationDetails = async ( req, res ) => {
|
|
168
169
|
try {
|
|
169
170
|
const { conversationId } = req.params;
|
|
170
|
-
const {
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
const { cohortId } = req.body;
|
|
172
|
+
logger.info( {
|
|
173
|
+
message: 'Received request for conversation details',
|
|
174
|
+
conversationId,
|
|
175
|
+
cohortId,
|
|
176
|
+
} );
|
|
177
|
+
if ( !conversationId || !cohortId ) {
|
|
173
178
|
return res.status( 400 ).json( {
|
|
174
179
|
status: 'error',
|
|
175
|
-
message: 'Missing required parameters: conversationId,
|
|
180
|
+
message: 'Missing required parameters: conversationId, cohortId',
|
|
176
181
|
code: 'MISSING_PARAMETERS',
|
|
177
182
|
timestamp: new Date().toISOString(),
|
|
178
183
|
} );
|
|
@@ -181,13 +186,13 @@ export const getConversationDetails = async ( req, res ) => {
|
|
|
181
186
|
logger.info( {
|
|
182
187
|
message: 'Fetching conversation details',
|
|
183
188
|
conversationId,
|
|
184
|
-
|
|
189
|
+
cohortId,
|
|
185
190
|
} );
|
|
186
191
|
|
|
187
192
|
// Call Lambda to get conversation details
|
|
188
193
|
const conversationData = await getConversationDetailsFromLambda( {
|
|
189
194
|
conversationId,
|
|
190
|
-
|
|
195
|
+
cohortId,
|
|
191
196
|
} );
|
|
192
197
|
|
|
193
198
|
if ( !conversationData ) {
|
|
@@ -518,6 +518,7 @@ export const conversationsListValid = joi.object( {
|
|
|
518
518
|
endDate: joi.string().required().pattern( /^\d{4}-\d{2}-\d{2}$/ ).description( 'End date in YYYY-MM-DD format' ),
|
|
519
519
|
storeId: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of store IDs' ),
|
|
520
520
|
clientId: joi.array().items( joi.string() ).optional().description( 'Array of client IDs' ),
|
|
521
|
+
cohortType: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of cohort types' ),
|
|
521
522
|
isAI: joi.boolean().optional().description( 'Filter for AI-generated conversations' ),
|
|
522
523
|
analyticsType: joi.string().optional().valid( 'audio', 'text', 'all' ).description( 'Type of analytics' ),
|
|
523
524
|
searchValue: joi.string().optional().description( 'Search term' ),
|
|
@@ -530,7 +531,10 @@ export const conversationsListValid = joi.object( {
|
|
|
530
531
|
* Conversation Details Schema
|
|
531
532
|
*/
|
|
532
533
|
export const conversationDetailsValid = joi.object( {
|
|
533
|
-
|
|
534
|
+
cohortId: joi.alternatives().try(
|
|
535
|
+
joi.string(),
|
|
536
|
+
joi.array().items( joi.string() ).min( 1 ),
|
|
537
|
+
).required().description( 'Cohort ID or array of cohort IDs' ),
|
|
534
538
|
} ).strict();
|
|
535
539
|
|
|
536
540
|
/**
|
|
@@ -16,22 +16,34 @@ import { Parser } from 'json2csv';
|
|
|
16
16
|
export async function getCohortAnalysisFromLambda( params ) {
|
|
17
17
|
try {
|
|
18
18
|
const LAMBDA_ENDPOINT = JSON.parse( process.env.URL ) || 'http://lambda-api:8000';
|
|
19
|
-
logger.info( { message: 'Calling Lambda for cohort analysis', params } );
|
|
20
19
|
|
|
21
|
-
const
|
|
20
|
+
const payload = {
|
|
22
21
|
startDate: params.startDate,
|
|
23
22
|
endDate: params.endDate,
|
|
24
|
-
storeId: params.storeId,
|
|
25
|
-
cohortType: params.cohortType,
|
|
26
|
-
clientId: params.clientId,
|
|
27
|
-
}
|
|
23
|
+
storeId: Array.isArray( params.storeId ) ? params.storeId : [ params.storeId ],
|
|
24
|
+
cohort_id: Array.isArray( params.cohortType ) ? params.cohortType : [ params.cohortType ],
|
|
25
|
+
clientId: Array.isArray( params.clientId ) ? params.clientId : [ params.clientId ],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
logger.info( { message: 'Calling Lambda for cohort analysis', url: LAMBDA_ENDPOINT.cohortAnalysisCard, payload } );
|
|
29
|
+
|
|
30
|
+
const response = await axios.post( `${LAMBDA_ENDPOINT.cohortAnalysisCard}`, payload, {
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
},
|
|
28
34
|
timeout: 30000,
|
|
29
35
|
} );
|
|
30
36
|
|
|
31
|
-
logger.info( { message: 'Lambda response received', data: response.data } );
|
|
37
|
+
logger.info( { message: 'Lambda response received', status: response.status, data: response.data } );
|
|
32
38
|
return response.data;
|
|
33
39
|
} catch ( error ) {
|
|
34
|
-
logger.error( {
|
|
40
|
+
logger.error( {
|
|
41
|
+
error: error.message,
|
|
42
|
+
status: error.response?.status,
|
|
43
|
+
data: error.response?.data,
|
|
44
|
+
message: 'Error calling Lambda for cohort analysis',
|
|
45
|
+
params,
|
|
46
|
+
} );
|
|
35
47
|
throw new Error( `Failed to fetch cohort analysis: ${error.message}` );
|
|
36
48
|
}
|
|
37
49
|
}
|
|
@@ -92,24 +104,37 @@ export async function getConversationsListFromLambda( params ) {
|
|
|
92
104
|
export async function exportConversationsFromLambda( params ) {
|
|
93
105
|
try {
|
|
94
106
|
const LAMBDA_ENDPOINT = JSON.parse( process.env.URL ) || 'http://lambda-api:8000';
|
|
95
|
-
logger.info( { message: 'Calling Lambda for conversations export', params } );
|
|
96
107
|
|
|
97
|
-
const
|
|
108
|
+
const payload = {
|
|
98
109
|
startDate: params.startDate,
|
|
99
110
|
endDate: params.endDate,
|
|
100
|
-
storeId: params.storeId,
|
|
101
|
-
clientId: params.clientId,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
storeId: Array.isArray( params.storeId ) ? params.storeId : [ params.storeId ],
|
|
112
|
+
clientId: Array.isArray( params.clientId ) ? params.clientId : [ params.clientId ],
|
|
113
|
+
cohortId: params.cohortId,
|
|
114
|
+
isExport: params.isExport ?? true,
|
|
115
|
+
limit: params.limit || 10,
|
|
116
|
+
offset: params.offset || 0,
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
logger.info( { message: 'Calling Lambda for conversations export', url: LAMBDA_ENDPOINT.cohortConversationList, payload } );
|
|
120
|
+
|
|
121
|
+
const response = await axios.post( `${LAMBDA_ENDPOINT.cohortConversationList}`, payload, {
|
|
122
|
+
headers: {
|
|
123
|
+
'Content-Type': 'application/json',
|
|
124
|
+
},
|
|
106
125
|
timeout: 30000,
|
|
107
126
|
} );
|
|
108
127
|
|
|
109
|
-
logger.info( { message: 'Lambda response received for conversations export',
|
|
128
|
+
logger.info( { message: 'Lambda response received for conversations export', data: response.data } );
|
|
110
129
|
return response.data;
|
|
111
130
|
} catch ( error ) {
|
|
112
|
-
logger.error( {
|
|
131
|
+
logger.error( {
|
|
132
|
+
error: error.message,
|
|
133
|
+
status: error.response?.status,
|
|
134
|
+
data: error.response?.data,
|
|
135
|
+
message: 'Error calling Lambda for conversations export',
|
|
136
|
+
params,
|
|
137
|
+
} );
|
|
113
138
|
throw new Error( `Failed to export conversations: ${error.message}` );
|
|
114
139
|
}
|
|
115
140
|
}
|
|
@@ -124,18 +149,31 @@ export async function exportConversationsFromLambda( params ) {
|
|
|
124
149
|
export async function getConversationDetailsFromLambda( params ) {
|
|
125
150
|
try {
|
|
126
151
|
const LAMBDA_ENDPOINT = JSON.parse( process.env.URL ) || 'http://lambda-api:8000';
|
|
127
|
-
logger.info( { message: 'Calling Lambda for conversation details', params } );
|
|
128
152
|
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
153
|
+
const payload = {
|
|
154
|
+
audio_id: params.conversationId,
|
|
155
|
+
cohort_id: Array.isArray( params.cohortId ) ? params.cohortId : [ params.cohortId ],
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
logger.info( { message: 'Calling Lambda for conversation details', url: LAMBDA_ENDPOINT.cohortConversationDetail, payload } );
|
|
159
|
+
|
|
160
|
+
const response = await axios.post( `${LAMBDA_ENDPOINT.cohortConversationDetail}`, payload, {
|
|
161
|
+
headers: {
|
|
162
|
+
'Content-Type': 'application/json',
|
|
163
|
+
},
|
|
132
164
|
timeout: 30000,
|
|
133
165
|
} );
|
|
134
166
|
|
|
135
167
|
logger.info( { message: 'Lambda response received for conversation details', conversationId: params.conversationId } );
|
|
136
168
|
return response.data;
|
|
137
169
|
} catch ( error ) {
|
|
138
|
-
logger.error( {
|
|
170
|
+
logger.error( {
|
|
171
|
+
error: error.message,
|
|
172
|
+
status: error.response?.status,
|
|
173
|
+
data: error.response?.data,
|
|
174
|
+
message: 'Error calling Lambda for conversation details',
|
|
175
|
+
params,
|
|
176
|
+
} );
|
|
139
177
|
throw new Error( `Failed to fetch conversation details: ${error.message}` );
|
|
140
178
|
}
|
|
141
179
|
}
|
|
@@ -174,20 +212,27 @@ export async function exportConversationsToCSV( conversations, columns = null )
|
|
|
174
212
|
*/
|
|
175
213
|
export async function getCohortAnalysisSummaryCard( params ) {
|
|
176
214
|
try {
|
|
177
|
-
const
|
|
215
|
+
const paramavalue = {
|
|
216
|
+
startDate: params.startDate,
|
|
217
|
+
endDate: params.endDate,
|
|
218
|
+
storeId: params.storeId,
|
|
219
|
+
cohortType: params.cohortType,
|
|
220
|
+
clientId: params.clientId,
|
|
221
|
+
};
|
|
222
|
+
const lambdaResponse = await getCohortAnalysisFromLambda( paramavalue );
|
|
178
223
|
|
|
179
224
|
// Process response to create summary card
|
|
180
|
-
const summaryCard = {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
};
|
|
225
|
+
// const summaryCard = {
|
|
226
|
+
// totalConversations: lambdaResponse.totalConversations || 0,
|
|
227
|
+
// totalDuration: lambdaResponse.totalDuration || 0,
|
|
228
|
+
// averageRating: lambdaResponse.averageRating || 0,
|
|
229
|
+
// topCohorts: lambdaResponse.topCohorts || [],
|
|
230
|
+
// trendData: lambdaResponse.trendData || [],
|
|
231
|
+
// keyInsights: lambdaResponse.keyInsights || [],
|
|
232
|
+
// timestamp: new Date().toISOString(),
|
|
233
|
+
// };
|
|
189
234
|
|
|
190
|
-
return
|
|
235
|
+
return lambdaResponse;
|
|
191
236
|
} catch ( error ) {
|
|
192
237
|
logger.error( { error, message: 'Error getting cohort analysis summary card' } );
|
|
193
238
|
throw error;
|