tango-app-api-audio-analytics 1.0.8 → 1.0.10
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 +44 -38
- 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,
|
|
@@ -61,7 +62,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
61
62
|
} );
|
|
62
63
|
|
|
63
64
|
let conversations;
|
|
64
|
-
let totalCount;
|
|
65
|
+
// let totalCount;
|
|
65
66
|
|
|
66
67
|
// If export is requested, call the export Lambda function
|
|
67
68
|
if ( isExport ) {
|
|
@@ -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,30 +118,30 @@ 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
|
-
data:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
},
|
|
135
|
+
data: lambdaResponse,
|
|
136
|
+
// {
|
|
137
|
+
// result: lambdaResponse,
|
|
138
|
+
// pagination: {
|
|
139
|
+
// limit,
|
|
140
|
+
// offset,
|
|
141
|
+
// total: totalCount,
|
|
142
|
+
// hasMore: ( offset + limit ) < totalCount,
|
|
143
|
+
// },
|
|
144
|
+
// },
|
|
143
145
|
timestamp: new Date().toISOString(),
|
|
144
146
|
} );
|
|
145
147
|
} catch ( error ) {
|
|
@@ -167,12 +169,16 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
167
169
|
export const getConversationDetails = async ( req, res ) => {
|
|
168
170
|
try {
|
|
169
171
|
const { conversationId } = req.params;
|
|
170
|
-
const {
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
const { cohortId } = req.body;
|
|
173
|
+
logger.info( {
|
|
174
|
+
message: 'Received request for conversation details',
|
|
175
|
+
conversationId,
|
|
176
|
+
cohortId,
|
|
177
|
+
} );
|
|
178
|
+
if ( !conversationId || !cohortId ) {
|
|
173
179
|
return res.status( 400 ).json( {
|
|
174
180
|
status: 'error',
|
|
175
|
-
message: 'Missing required parameters: conversationId,
|
|
181
|
+
message: 'Missing required parameters: conversationId, cohortId',
|
|
176
182
|
code: 'MISSING_PARAMETERS',
|
|
177
183
|
timestamp: new Date().toISOString(),
|
|
178
184
|
} );
|
|
@@ -181,13 +187,13 @@ export const getConversationDetails = async ( req, res ) => {
|
|
|
181
187
|
logger.info( {
|
|
182
188
|
message: 'Fetching conversation details',
|
|
183
189
|
conversationId,
|
|
184
|
-
|
|
190
|
+
cohortId,
|
|
185
191
|
} );
|
|
186
192
|
|
|
187
193
|
// Call Lambda to get conversation details
|
|
188
194
|
const conversationData = await getConversationDetailsFromLambda( {
|
|
189
195
|
conversationId,
|
|
190
|
-
|
|
196
|
+
cohortId,
|
|
191
197
|
} );
|
|
192
198
|
|
|
193
199
|
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;
|