tango-app-api-audio-analytics 1.0.0

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.
@@ -0,0 +1,387 @@
1
+ # Cohort API - Quick Start Guide
2
+
3
+ ## Project Structure
4
+ ```
5
+ src/
6
+ ├── controllers/
7
+ │ ├── cohortAnalytics.controller.js ✅ (7 endpoints)
8
+ │ └── conversationAnalytics.controller.js
9
+ ├── services/
10
+ │ └── cohort.service.js ✅ (7 CRUD operations)
11
+ ├── models/
12
+ │ └── (ready for database models)
13
+ ├── routes/
14
+ │ └── audioAnalytics.routes.js ✅ (updated with 7 cohort routes)
15
+ ├── middlewares/
16
+ │ └── validation.middleware.js ✅ (3 cohort validators added)
17
+ ├── dtos/
18
+ │ └── audioAnalytics.dtos.js ✅ (17 DTO classes)
19
+ ├── validations/
20
+ │ └── cohort.validation.js ✅ (Joi schemas)
21
+ └── utils/
22
+ ```
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ # Required dependency (if not already installed)
28
+ npm install joi
29
+
30
+ # The tango-app-api-middleware is already available
31
+ const { insert, search, update, delete } = require('tango-app-api-middleware');
32
+ ```
33
+
34
+ ## Quick Integration
35
+
36
+ ### 1. Import Cohort Endpoints
37
+ Already integrated in `src/routes/audioAnalytics.routes.js`:
38
+ ```javascript
39
+ const {
40
+ createCohort,
41
+ getCohort,
42
+ getCohortsByClient,
43
+ searchCohortsEndpoint,
44
+ updateCohort,
45
+ deleteCohort,
46
+ getCohortAnalyticsEndpoint
47
+ } = require('../controllers/cohort.controller');
48
+
49
+ const {
50
+ validateCohortCreation,
51
+ validateCohortUpdate,
52
+ validateCohortQuery
53
+ } = require('../middlewares/validation.middleware');
54
+ ```
55
+
56
+ ### 2. Available Routes
57
+ ```javascript
58
+ // READ
59
+ GET /cohorts/:cohortId // Get single cohort
60
+ GET /cohorts/client/:clientId // Get by client (paginated)
61
+ GET /cohorts/:cohortId/analytics // Get analytics
62
+
63
+ // CREATE
64
+ POST /cohorts // Create new cohort
65
+
66
+ // SEARCH
67
+ POST /cohorts/search // Search with filters
68
+
69
+ // UPDATE
70
+ PUT /cohorts/:documentId // Update cohort
71
+
72
+ // DELETE
73
+ DELETE /cohorts/:documentId // Delete cohort
74
+ ```
75
+
76
+ ## Common Tasks
77
+
78
+ ### Create a Cohort
79
+ ```javascript
80
+ // Request
81
+ POST /cohorts
82
+ {
83
+ "clientId": "11",
84
+ "cohortId": "cohort_example_001",
85
+ "cohortName": "Example Cohort",
86
+ "cohortDescription": "A test cohort with metrics",
87
+ "metrics": [
88
+ {
89
+ "metricId": "metric_1",
90
+ "metricName": "Engagement",
91
+ "metricDescription": "Customer engagement level",
92
+ "hasContext": true,
93
+ "isNumneric": true,
94
+ "contexts": [
95
+ {
96
+ "contextName": "HIGH",
97
+ "priority": 2,
98
+ "description": "High engagement",
99
+ "minValue": 80,
100
+ "maxValue": 100
101
+ }
102
+ ]
103
+ }
104
+ ]
105
+ }
106
+
107
+ // Response (201 Created)
108
+ {
109
+ "status": "success",
110
+ "data": {
111
+ "documentId": "550e8400-e29b-41d4-a716-446655440000",
112
+ "clientId": "11",
113
+ "cohortId": "cohort_example_001",
114
+ ...
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### Get a Cohort
120
+ ```javascript
121
+ GET /cohorts/cohort_example_001
122
+
123
+ // Response (200 OK)
124
+ {
125
+ "status": "success",
126
+ "data": { ...cohort document... }
127
+ }
128
+ ```
129
+
130
+ ### Search Cohorts
131
+ ```javascript
132
+ POST /cohorts/search
133
+ {
134
+ "clientId": "11",
135
+ "cohortName": "Example",
136
+ "limit": 10,
137
+ "offset": 0
138
+ }
139
+
140
+ // Response (200 OK)
141
+ {
142
+ "status": "success",
143
+ "data": {
144
+ "cohorts": [...],
145
+ "total": 5,
146
+ "limit": 10,
147
+ "offset": 0
148
+ }
149
+ }
150
+ ```
151
+
152
+ ### Update a Cohort
153
+ ```javascript
154
+ PUT /cohorts/550e8400-e29b-41d4-a716-446655440000
155
+ {
156
+ "cohortName": "Updated Cohort Name",
157
+ "metrics": [...]
158
+ }
159
+
160
+ // Response (200 OK)
161
+ {
162
+ "status": "success",
163
+ "data": { ...updated cohort... }
164
+ }
165
+ ```
166
+
167
+ ### Delete a Cohort
168
+ ```javascript
169
+ DELETE /cohorts/550e8400-e29b-41d4-a716-446655440000
170
+
171
+ // Response (200 OK)
172
+ {
173
+ "status": "success",
174
+ "message": "Cohort deleted successfully"
175
+ }
176
+ ```
177
+
178
+ ### Get Analytics
179
+ ```javascript
180
+ GET /cohorts/cohort_example_001/analytics
181
+
182
+ // Response (200 OK)
183
+ {
184
+ "status": "success",
185
+ "data": {
186
+ "cohortId": "cohort_example_001",
187
+ "metricsCount": 6,
188
+ "metrics": [
189
+ {
190
+ "metricId": "metric_1",
191
+ "metricName": "Engagement",
192
+ "contextsCount": 3
193
+ }
194
+ ]
195
+ }
196
+ }
197
+ ```
198
+
199
+ ## Validation Reference
200
+
201
+ ### Cohort ID Format
202
+ - Must be alphanumeric with hyphens and underscores
203
+ - Examples: `cohort_001`, `cohort-test`, `test123`
204
+ - Invalid: `cohort@001`, `cohort.test`, `Cohort_001` (uppercase)
205
+
206
+ ### Cohort Name
207
+ - Minimum 3 characters, maximum 100 characters
208
+ - Any UTF-8 characters allowed
209
+ - Required field
210
+
211
+ ### Cohort Description
212
+ - Minimum 10 characters, maximum 500 characters
213
+ - Any UTF-8 characters allowed
214
+ - Required field
215
+
216
+ ### Metrics Array
217
+ - Minimum 1 metric, maximum 50 metrics
218
+ - Each metric requires: metricId, metricName, metricDescription, hasContext, isNumneric
219
+ - If hasContext is true, contexts array is required with at least 1 context
220
+
221
+ ### Contexts
222
+ - contextName (required)
223
+ - priority: 0, 1, or 2 (required)
224
+ - description (required, any length)
225
+ - minValue, maxValue (optional, for numeric metrics)
226
+
227
+ ## Error Handling
228
+
229
+ ### Common Error Responses
230
+
231
+ **400 - Validation Error**
232
+ ```json
233
+ {
234
+ "status": "error",
235
+ "message": "Validation failed",
236
+ "code": "VALIDATION_ERROR",
237
+ "details": [
238
+ "cohortName must be at least 3 characters",
239
+ "clientId is required"
240
+ ],
241
+ "timestamp": "2024-01-15T10:30:00.000Z"
242
+ }
243
+ ```
244
+
245
+ **409 - Cohort Exists**
246
+ ```json
247
+ {
248
+ "status": "error",
249
+ "message": "Cohort with ID 'cohort_001' already exists",
250
+ "code": "COHORT_EXISTS",
251
+ "timestamp": "2024-01-15T10:30:00.000Z"
252
+ }
253
+ ```
254
+
255
+ **404 - Not Found**
256
+ ```json
257
+ {
258
+ "status": "error",
259
+ "message": "Cohort not found",
260
+ "code": "COHORT_NOT_FOUND",
261
+ "timestamp": "2024-01-15T10:30:00.000Z"
262
+ }
263
+ ```
264
+
265
+ ## Testing
266
+
267
+ ### Using curl
268
+ ```bash
269
+ # Create
270
+ curl -X POST http://localhost:3000/v3/audio-analitics/cohorts \
271
+ -H "Content-Type: application/json" \
272
+ -d @cohort_payload.json
273
+
274
+ # Get
275
+ curl http://localhost:3000/v3/audio-analitics/cohorts/cohort_001
276
+
277
+ # Search
278
+ curl -X POST http://localhost:3000/v3/audio-analitics/cohorts/search \
279
+ -H "Content-Type: application/json" \
280
+ -d '{"clientId":"11","limit":10}'
281
+
282
+ # Update
283
+ curl -X PUT http://localhost:3000/v3/audio-analitics/cohorts/DOC_ID \
284
+ -H "Content-Type: application/json" \
285
+ -d @update_payload.json
286
+
287
+ # Delete
288
+ curl -X DELETE http://localhost:3000/v3/audio-analitics/cohorts/DOC_ID
289
+
290
+ # Analytics
291
+ curl http://localhost:3000/v3/audio-analitics/cohorts/cohort_001/analytics
292
+ ```
293
+
294
+ ### Using Test Script
295
+ ```bash
296
+ bash COHORT_API_EXAMPLES.sh
297
+ ```
298
+
299
+ ## File Dependencies
300
+
301
+ | File | Depends On | Used By |
302
+ |------|-----------|---------|
303
+ | cohort.validation.js | joi | validation.middleware.js |
304
+ | cohort.service.js | tango-app-api-middleware | cohort.controller.js |
305
+ | cohort.controller.js | cohort.service.js, audioAnalytics.dtos.js | audioAnalytics.routes.js |
306
+ | validation.middleware.js | cohort.validation.js | audioAnalytics.routes.js |
307
+ | audioAnalytics.routes.js | cohort.controller.js, validation.middleware.js | app.js |
308
+
309
+ ## Environmental Setup
310
+
311
+ ### Required Environment Variables
312
+ ```env
313
+ # Database (OpenSearch)
314
+ OPENSEARCH_HOST=localhost
315
+ OPENSEARCH_PORT=9200
316
+ OPENSEARCH_INDEX=tango-audio-cohort
317
+
318
+ # API
319
+ API_PORT=3000
320
+ NODE_ENV=development
321
+
322
+ # Logger
323
+ LOG_LEVEL=info
324
+ ```
325
+
326
+ ## Key Constants
327
+
328
+ ```javascript
329
+ // Database
330
+ OPENSEARCH_INDEX = 'tango-audio-cohort'
331
+
332
+ // API Status Codes
333
+ 201 = Created
334
+ 200 = OK
335
+ 400 = Bad Request
336
+ 404 = Not Found
337
+ 409 = Conflict
338
+ 500 = Internal Server Error
339
+
340
+ // Error Codes
341
+ VALIDATION_ERROR // 400
342
+ COHORT_EXISTS // 409
343
+ COHORT_NOT_FOUND // 404
344
+ COHORT_CREATE_ERROR // 500
345
+ COHORT_SEARCH_ERROR // 500
346
+ INTERNAL_ERROR // 500
347
+ ```
348
+
349
+ ## Performance Considerations
350
+
351
+ ### Pagination
352
+ - Default limit: 10 items
353
+ - Maximum items: 50
354
+ - Offset-based pagination supported
355
+ - Use for `/cohorts/client/:clientId` endpoint
356
+
357
+ ### Search Optimization
358
+ - Fuzzy search enabled on cohortName (AUTO fuzziness)
359
+ - Bool query for multiple criteria
360
+ - Indexed by: clientId, cohortId, cohortName
361
+
362
+ ### Caching Recommendations
363
+ - Cache GET /cohorts/:cohortId for 5 minutes
364
+ - Invalidate cache on PUT/DELETE
365
+ - Analytics endpoint can be cached for 1 hour
366
+
367
+ ## Security Notes
368
+
369
+ - All inputs validated via Joi
370
+ - SQL injection not applicable (OpenSearch)
371
+ - Validate clientId against user permissions
372
+ - Use UUID for document IDs (not sequential)
373
+ - Hash sensitive data in metrics if needed
374
+
375
+ ## Support Files
376
+
377
+ - **COHORT_API.md** - Full API documentation
378
+ - **COHORT_API_EXAMPLES.sh** - Bash testing script
379
+ - **COHORT_API_IMPLEMENTATION.md** - Implementation details
380
+
381
+ ## Next Steps
382
+
383
+ 1. ✅ Install dependencies (`npm install joi`)
384
+ 2. ✅ Review COHORT_API.md for complete documentation
385
+ 3. ✅ Run COHORT_API_EXAMPLES.sh to test endpoints
386
+ 4. ✅ Integrate with conversation analytics
387
+ 5. ✅ Deploy to production with proper environment configuration
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+
2
+
3
+ import { audioAnalyticsrouter } from './src/routes/audioAnalytics.routes.js';
4
+
5
+ export { audioAnalyticsrouter };
6
+
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "tango-app-api-audio-analytics",
3
+ "version": "1.0.0",
4
+ "description": "audioAnalytics",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "nodemon --exec \"eslint --fix . && node app.js\""
9
+ },
10
+ "engines": {
11
+ "node": ">=18.10.0"
12
+ },
13
+ "author": "praveenraj",
14
+ "license": "ISC",
15
+ "dependencies": {
16
+ "aws-sdk": "^2.1693.0",
17
+ "body-parser": "^2.2.2",
18
+ "cors": "^2.8.6",
19
+ "dotenv": "^17.3.1",
20
+ "express": "^5.2.1",
21
+ "mongodb": "^6.21.0",
22
+ "nodemon": "^3.1.14",
23
+ "tango-api-schema": "^2.5.62",
24
+ "tango-app-api-middleware": "^3.6.18",
25
+ "winston": "^3.19.0",
26
+ "winston-daily-rotate-file": "^5.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "eslint": "^8.57.1",
30
+ "eslint-config-google": "^0.14.0",
31
+ "eslint-config-semistandard": "^17.0.0",
32
+ "eslint-config-standard": "^17.1.0",
33
+ "eslint-plugin-import": "^2.32.0",
34
+ "eslint-plugin-promise": "^6.6.0"
35
+ }
36
+ }
@@ -0,0 +1,116 @@
1
+ import { insertWithId, logger } from 'tango-app-api-middleware';
2
+ import { randomUUID } from 'crypto';
3
+
4
+ const EXTERNAL_STREAM_API = 'http://172.236.179.51:8000/stream';
5
+
6
+ export async function createCohort( req, res ) {
7
+ try {
8
+ const inputData = req.body;
9
+
10
+ const cohortId = `cohort_${inputData.clientId}_${randomUUID()}`;
11
+
12
+ const metrics = ( inputData.metrics || [] ).map( ( metric ) => {
13
+ const hasContext = Array.isArray( metric.contexts ) && metric.contexts.length > 0;
14
+ return {
15
+ ...metric,
16
+ metricId: randomUUID(),
17
+ hasContext,
18
+ isNumeric: metric.isNumeric ?? false,
19
+ };
20
+ } );
21
+
22
+ const cohortData = {
23
+ clientId: inputData.clientId,
24
+ cohortId,
25
+ cohortName: inputData.cohortName,
26
+ cohortDescription: inputData.cohortDescription,
27
+ metrics,
28
+ createdAt: new Date().toISOString(),
29
+ updatedAt: new Date().toISOString(),
30
+ };
31
+
32
+ const result = await insertWithId( 'tango-audio-config', cohortId, cohortData );
33
+ logger.info( { result } );
34
+
35
+ if ( result && result.body && result.body.result === 'created' ) {
36
+ return res.sendSuccess( { result: 'Cohort created successfully', cohortId } );
37
+ } else {
38
+ return res.sendError( 'Failed to create cohort', 500 );
39
+ }
40
+ } catch ( error ) {
41
+ const err = error.message || 'Internal Server Error';
42
+ logger.error( { error: error, message: req.body, function: 'createCohort' } );
43
+ return res.sendError( err, 500 );
44
+ }
45
+ }
46
+
47
+ export const callExternalStreamAPI = async ( req, res ) => {
48
+ try {
49
+ const { prompt, storeId, productModule, country, region, fromDate, toDate, clusters } = req.body;
50
+ console.log( 'Received request for external stream API with parameters:', req.body );
51
+ // Validation for required parameters
52
+ if ( !prompt ) {
53
+ logger.warn( 'Stream API call attempted without prompt' );
54
+ return res.status( 400 ).json( {
55
+ status: 'error',
56
+ message: 'Missing required parameter: prompt',
57
+ code: 'MISSING_PROMPT',
58
+ timestamp: new Date().toISOString(),
59
+ } );
60
+ }
61
+
62
+ // Build query parameters
63
+ const queryParams = new URLSearchParams();
64
+ queryParams.append( 'prompt', prompt );
65
+
66
+ if ( storeId ) queryParams.append( 'storeId', storeId );
67
+ if ( productModule ) queryParams.append( 'productModule', productModule );
68
+ if ( country ) queryParams.append( 'country', country );
69
+ if ( region ) queryParams.append( 'region', region );
70
+ if ( fromDate ) queryParams.append( 'fromDate', fromDate );
71
+ if ( toDate ) queryParams.append( 'toDate', toDate );
72
+ if ( clusters ) queryParams.append( 'clusters', clusters );
73
+
74
+ const url = `${EXTERNAL_STREAM_API}?${queryParams.toString()}`;
75
+
76
+ logger.info( `Calling external stream API with URL: ${url}` );
77
+
78
+ // Make the external API call
79
+ const response = await fetch( url, {
80
+ method: 'GET',
81
+ headers: {
82
+ 'Content-Type': 'application/json',
83
+ 'Accept': 'application/json',
84
+ },
85
+ } );
86
+
87
+ if ( !response.ok ) {
88
+ logger.error( `External API error: ${response.status} ${response.statusText}` );
89
+ return res.status( response.status ).json( {
90
+ status: 'error',
91
+ message: `External API error: ${response.statusText}`,
92
+ code: 'EXTERNAL_API_ERROR',
93
+ timestamp: new Date().toISOString(),
94
+ } );
95
+ }
96
+
97
+ const data = await response.json();
98
+
99
+ logger.info( `Successfully called external stream API` );
100
+
101
+ return res.status( 200 ).json( {
102
+ status: 'success',
103
+ data: data,
104
+ timestamp: new Date().toISOString(),
105
+ } );
106
+ } catch ( error ) {
107
+ logger.error( `Error calling external stream API: ${error.message}` );
108
+ return res.status( 500 ).json( {
109
+ status: 'error',
110
+ message: 'Internal server error while calling external API',
111
+ code: 'INTERNAL_ERROR',
112
+ error: error.message,
113
+ timestamp: new Date().toISOString(),
114
+ } );
115
+ }
116
+ };