tango-app-api-audio-analytics 1.0.32 → 1.0.33
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 +0 -1
- package/src/controllers/cohortAnalytics.controller.js +69 -1
- package/src/controllers/conversationAnalytics.controller.js +5 -0
- package/src/dtos/audioAnalytics.dtos.js +13 -0
- package/src/routes/audioAnalytics.routes.js +3 -2
- package/src/services/conversation.service.js +47 -2
package/package.json
CHANGED
|
@@ -329,7 +329,6 @@ export async function getChat( req, res ) {
|
|
|
329
329
|
export const callExternalStreamAPI = async ( req, res ) => {
|
|
330
330
|
try {
|
|
331
331
|
const { prompt, storeId, productModule, country, region, fromDate, toDate, clusters } = req.body;
|
|
332
|
-
console.log( 'Received request for external stream API with parameters:', req.body );
|
|
333
332
|
// Validation for required parameters
|
|
334
333
|
if ( !prompt ) {
|
|
335
334
|
logger.warn( 'Stream API call attempted without prompt' );
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// import { sampleCohortData } from '../models/cohortAnalysis.model.js';
|
|
2
2
|
import { logger } from 'tango-app-api-middleware';
|
|
3
|
-
import { getCohortAnalysisSummaryCard } from '../services/conversation.service.js';
|
|
3
|
+
import { getCohortAnalysisSummaryCard, getCohortSummaryCardFromLambda } from '../services/conversation.service.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Get Cohort Analysis Summary Card
|
|
@@ -71,6 +71,74 @@ export const getCohortAnalysisCard = async ( req, res ) => {
|
|
|
71
71
|
}
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Get Cohort Summary Card
|
|
76
|
+
* POST /cohort-summary-card
|
|
77
|
+
* @param {Object} req - Express request object
|
|
78
|
+
* @param {Object} req.body - Request body
|
|
79
|
+
* @param {string} req.body.startDate - Start date (YYYY-MM-DD)
|
|
80
|
+
* @param {string} req.body.endDate - End date (YYYY-MM-DD)
|
|
81
|
+
* @param {string[]} req.body.storeId - Array of store IDs
|
|
82
|
+
* @param {string[]} req.body.clientId - Array of client IDs
|
|
83
|
+
* @param {string[]} req.body.cohortId - Array of cohort IDs
|
|
84
|
+
* @param {Object} res - Express response object
|
|
85
|
+
* @return {void} Returns JSON response with cohort summary card data
|
|
86
|
+
*/
|
|
87
|
+
export const getCohortSummaryCard = async ( req, res ) => {
|
|
88
|
+
try {
|
|
89
|
+
const { startDate, endDate, storeId, clientId, cohortId } = req.body;
|
|
90
|
+
|
|
91
|
+
if ( !startDate || !endDate || !storeId || !clientId || !cohortId ) {
|
|
92
|
+
return res.status( 400 ).json( {
|
|
93
|
+
status: 'error',
|
|
94
|
+
message: 'Missing required parameters: startDate, endDate, storeId, clientId, cohortId',
|
|
95
|
+
code: 'MISSING_PARAMETERS',
|
|
96
|
+
timestamp: new Date().toISOString(),
|
|
97
|
+
} );
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
logger.info( {
|
|
101
|
+
message: 'Fetching cohort summary card',
|
|
102
|
+
startDate,
|
|
103
|
+
endDate,
|
|
104
|
+
storeId,
|
|
105
|
+
clientId,
|
|
106
|
+
cohortId,
|
|
107
|
+
} );
|
|
108
|
+
|
|
109
|
+
const lambdaResponse = await getCohortSummaryCardFromLambda( {
|
|
110
|
+
startDate,
|
|
111
|
+
endDate,
|
|
112
|
+
storeId,
|
|
113
|
+
clientId,
|
|
114
|
+
cohortId,
|
|
115
|
+
} );
|
|
116
|
+
|
|
117
|
+
if ( !lambdaResponse ) {
|
|
118
|
+
return res.status( 204 ).json( {
|
|
119
|
+
status: 'error',
|
|
120
|
+
message: 'No data found for the given parameters',
|
|
121
|
+
code: 'DATA_NOT_FOUND',
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
} );
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return res.status( 200 ).json( {
|
|
127
|
+
status: lambdaResponse?.status || 'success',
|
|
128
|
+
data: lambdaResponse?.data ?? lambdaResponse,
|
|
129
|
+
timestamp: new Date().toISOString(),
|
|
130
|
+
} );
|
|
131
|
+
} catch ( error ) {
|
|
132
|
+
logger.error( { error, message: 'Error fetching cohort summary card', body: req.body } );
|
|
133
|
+
return res.status( 500 ).json( {
|
|
134
|
+
status: 'error',
|
|
135
|
+
message: error.message || 'Internal server error',
|
|
136
|
+
code: 'INTERNAL_ERROR',
|
|
137
|
+
timestamp: new Date().toISOString(),
|
|
138
|
+
} );
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
74
142
|
/**
|
|
75
143
|
* Get Complete Cohort Analysis
|
|
76
144
|
* GET /cohort-analysis
|
|
@@ -39,6 +39,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
39
39
|
isAI,
|
|
40
40
|
analyticsType,
|
|
41
41
|
searchValue,
|
|
42
|
+
audioSource,
|
|
42
43
|
limit,
|
|
43
44
|
offset,
|
|
44
45
|
isExport,
|
|
@@ -81,6 +82,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
81
82
|
offset,
|
|
82
83
|
_id,
|
|
83
84
|
name,
|
|
85
|
+
audioSource,
|
|
84
86
|
} );
|
|
85
87
|
|
|
86
88
|
// conversations = exportResponse.conversations || [];
|
|
@@ -119,6 +121,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
119
121
|
isAI,
|
|
120
122
|
analyticsType,
|
|
121
123
|
searchValue,
|
|
124
|
+
audioSource,
|
|
122
125
|
limit,
|
|
123
126
|
offset,
|
|
124
127
|
_id,
|
|
@@ -189,6 +192,7 @@ export const getTranscriptsList = async ( req, res ) => {
|
|
|
189
192
|
isAI,
|
|
190
193
|
analyticsType,
|
|
191
194
|
searchValue,
|
|
195
|
+
audioSource,
|
|
192
196
|
limit,
|
|
193
197
|
offset,
|
|
194
198
|
isExport,
|
|
@@ -228,6 +232,7 @@ export const getTranscriptsList = async ( req, res ) => {
|
|
|
228
232
|
isAI,
|
|
229
233
|
analyticsType,
|
|
230
234
|
searchValue,
|
|
235
|
+
audioSource,
|
|
231
236
|
limit,
|
|
232
237
|
offset,
|
|
233
238
|
_id,
|
|
@@ -510,6 +510,17 @@ export const cohortAnalysisCardValid = joi.object( {
|
|
|
510
510
|
clientId: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of client IDs' ),
|
|
511
511
|
} ).strict();
|
|
512
512
|
|
|
513
|
+
/**
|
|
514
|
+
* Cohort Summary Card Schema
|
|
515
|
+
*/
|
|
516
|
+
export const cohortSummaryCardValid = joi.object( {
|
|
517
|
+
startDate: joi.string().required().pattern( /^\d{4}-\d{2}-\d{2}$/ ).description( 'Start date in YYYY-MM-DD format' ),
|
|
518
|
+
endDate: joi.string().required().pattern( /^\d{4}-\d{2}-\d{2}$/ ).description( 'End date in YYYY-MM-DD format' ),
|
|
519
|
+
storeId: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of store IDs' ),
|
|
520
|
+
clientId: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of client IDs' ),
|
|
521
|
+
cohortId: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of cohort IDs' ),
|
|
522
|
+
} ).strict();
|
|
523
|
+
|
|
513
524
|
/**
|
|
514
525
|
* Category Analysis Card Schema
|
|
515
526
|
*/
|
|
@@ -535,6 +546,7 @@ export const conversationsListValid = joi.object( {
|
|
|
535
546
|
isAI: joi.boolean().optional().description( 'Filter for AI-generated conversations' ),
|
|
536
547
|
analyticsType: joi.string().optional().valid( 'audio', 'text', 'all' ).description( 'Type of analytics' ),
|
|
537
548
|
searchValue: joi.string().optional().description( 'Search term' ),
|
|
549
|
+
audioSource: joi.string().optional().description( 'Audio source filter' ),
|
|
538
550
|
isExport: joi.boolean().optional().description( 'Flag to export as CSV' ),
|
|
539
551
|
limit: joi.number().integer().min( 1 ).max( 1000 ).optional().default( 10 ).description( 'Pagination limit' ),
|
|
540
552
|
offset: joi.number().integer().min( 0 ).optional().default( 0 ).description( 'Pagination offset' ),
|
|
@@ -552,6 +564,7 @@ export const transcriptListValid = joi.object( {
|
|
|
552
564
|
isAI: joi.boolean().optional().description( 'Filter for AI-generated conversations' ),
|
|
553
565
|
analyticsType: joi.string().optional().valid( 'audio', 'text', 'all' ).description( 'Type of analytics' ),
|
|
554
566
|
searchValue: joi.string().optional().description( 'Search term' ),
|
|
567
|
+
audioSource: joi.string().optional().description( 'Audio source filter' ),
|
|
555
568
|
isExport: joi.boolean().optional().description( 'Flag to export as CSV' ),
|
|
556
569
|
limit: joi.number().integer().min( 1 ).max( 1000 ).optional().default( 10 ).description( 'Pagination limit' ),
|
|
557
570
|
offset: joi.number().integer().min( 0 ).optional().default( 0 ).description( 'Pagination offset' ),
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import express from 'express';
|
|
3
3
|
import { validate } from 'tango-app-api-middleware';
|
|
4
4
|
import { createCohortValid, createBulkCohortValid, updateCohortValid, getCohortValid, listCohortsByClientValid, deleteCohortValid } from '../dtos/audioAnalytics.dtos.js';
|
|
5
|
-
import { cohortAnalysisCardValid, categoryAnalysisCardValid, conversationsListValid, conversationDetailsValid, chatHistoryListValid, getChatValid, getGeminiResponseValid, transcriptListValid } from '../dtos/audioAnalytics.dtos.js';
|
|
5
|
+
import { cohortAnalysisCardValid, cohortSummaryCardValid, categoryAnalysisCardValid, conversationsListValid, conversationDetailsValid, chatHistoryListValid, getChatValid, getGeminiResponseValid, transcriptListValid } from '../dtos/audioAnalytics.dtos.js';
|
|
6
6
|
import { createCohort, createBulkCohort, updateCohort, deleteCohort, getCohort, listCohortsByClient, chatHistoryList, getChat, getGeminiResponse, aiStreamResponse } from '../controllers/audioAnalytics.controller.js';
|
|
7
|
-
import { getCohortAnalysisCard } from '../controllers/cohortAnalytics.controller.js';
|
|
7
|
+
import { getCohortAnalysisCard, getCohortSummaryCard } from '../controllers/cohortAnalytics.controller.js';
|
|
8
8
|
import { getConversationsList, getTranscriptsList, getConversationDetails, getCategoryAnalysisCard } from '../controllers/conversationAnalytics.controller.js';
|
|
9
9
|
|
|
10
10
|
export const audioAnalyticsrouter = express.Router(); ;
|
|
@@ -27,6 +27,7 @@ audioAnalyticsrouter.post( '/chat-history-list', validate( chatHistoryListValid
|
|
|
27
27
|
audioAnalyticsrouter.post( '/get-chat', validate( getChatValid ), getChat );
|
|
28
28
|
// Cohort Analytics Routes
|
|
29
29
|
audioAnalyticsrouter.post( '/cohort-analysis-card', validate( cohortAnalysisCardValid ), getCohortAnalysisCard );
|
|
30
|
+
audioAnalyticsrouter.post( '/cohort-summary-card', validate( cohortSummaryCardValid ), getCohortSummaryCard );
|
|
30
31
|
audioAnalyticsrouter.post( '/category-analysis-card', validate( categoryAnalysisCardValid ), getCategoryAnalysisCard );
|
|
31
32
|
|
|
32
33
|
// Conversation Analytics Routes
|
|
@@ -77,10 +77,10 @@ export async function getConversationsListFromLambda( params ) {
|
|
|
77
77
|
isAI: params.isAI,
|
|
78
78
|
analyticsType: params.analyticsType,
|
|
79
79
|
searchValue: params.searchValue,
|
|
80
|
+
audioSource: params.audioSource,
|
|
80
81
|
limit: params.limit,
|
|
81
82
|
offset: params.offset,
|
|
82
83
|
};
|
|
83
|
-
console.log( payload );
|
|
84
84
|
const response = await axios.post( `${LAMBDA_ENDPOINT.cohortConversationList}/conversations/list`, payload, {
|
|
85
85
|
timeout: 30000,
|
|
86
86
|
} );
|
|
@@ -122,10 +122,10 @@ export async function getTranscriptListFromLambda( params ) {
|
|
|
122
122
|
isAI: params.isAI,
|
|
123
123
|
analyticsType: params.analyticsType,
|
|
124
124
|
searchValue: params.searchValue,
|
|
125
|
+
audioSource: params.audioSource,
|
|
125
126
|
limit: params.limit,
|
|
126
127
|
offset: params.offset,
|
|
127
128
|
};
|
|
128
|
-
console.log( LAMBDA_ENDPOINT.transcriptList, payload );
|
|
129
129
|
const response = await axios.post( `${LAMBDA_ENDPOINT.transcriptList}`, payload, {
|
|
130
130
|
timeout: 30000,
|
|
131
131
|
} );
|
|
@@ -338,6 +338,51 @@ export async function getCategoryAnalysisCardFromLambda( params ) {
|
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Call Lambda to get cohort summary card
|
|
343
|
+
* @param {Object} params - Request parameters
|
|
344
|
+
* @param {string} params.startDate - Start date (YYYY-MM-DD)
|
|
345
|
+
* @param {string} params.endDate - End date (YYYY-MM-DD)
|
|
346
|
+
* @param {string[]} params.storeId - Array of store IDs
|
|
347
|
+
* @param {string[]} params.clientId - Array of client IDs
|
|
348
|
+
* @param {string[]} params.cohortId - Array of cohort IDs
|
|
349
|
+
* @return {Promise<Object>} Response from Lambda
|
|
350
|
+
*/
|
|
351
|
+
export async function getCohortSummaryCardFromLambda( params ) {
|
|
352
|
+
try {
|
|
353
|
+
const LAMBDA_ENDPOINT = JSON.parse( process.env.URL ) || 'http://lambda-api:8000';
|
|
354
|
+
|
|
355
|
+
const payload = {
|
|
356
|
+
startDate: params.startDate,
|
|
357
|
+
endDate: params.endDate,
|
|
358
|
+
storeId: Array.isArray( params.storeId ) ? params.storeId : [ params.storeId ],
|
|
359
|
+
clientId: Array.isArray( params.clientId ) ? params.clientId : [ params.clientId ],
|
|
360
|
+
cohortId: Array.isArray( params.cohortId ) ? params.cohortId : [ params.cohortId ],
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
logger.info( { message: 'Calling Lambda for cohort summary card', url: LAMBDA_ENDPOINT.cohortSummaryCard, payload } );
|
|
364
|
+
|
|
365
|
+
const response = await axios.post( `${LAMBDA_ENDPOINT.cohortSummaryCard}`, payload, {
|
|
366
|
+
headers: {
|
|
367
|
+
'Content-Type': 'application/json',
|
|
368
|
+
},
|
|
369
|
+
timeout: 30000,
|
|
370
|
+
} );
|
|
371
|
+
|
|
372
|
+
logger.info( { message: 'Lambda response received for cohort summary card', status: response.status } );
|
|
373
|
+
return response.data;
|
|
374
|
+
} catch ( error ) {
|
|
375
|
+
logger.error( {
|
|
376
|
+
error: error.message,
|
|
377
|
+
status: error.response?.status,
|
|
378
|
+
data: error.response?.data,
|
|
379
|
+
message: 'Error calling Lambda for cohort summary card',
|
|
380
|
+
params,
|
|
381
|
+
} );
|
|
382
|
+
throw new Error( `Failed to fetch cohort summary card: ${error.message}` );
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
341
386
|
/**
|
|
342
387
|
* Process and filter conversations based on search criteria
|
|
343
388
|
* @param {Array} conversations - Array of conversation objects
|