tango-app-api-audio-analytics 1.0.31 → 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/COHORT_API_EXAMPLES.sh +235 -235
- package/package.json +2 -2
- package/src/controllers/audioAnalytics.controller.js +0 -1
- package/src/controllers/cohortAnalytics.controller.js +69 -1
- package/src/controllers/conversationAnalytics.controller.js +80 -0
- package/src/dtos/audioAnalytics.dtos.js +26 -0
- package/src/routes/audioAnalytics.routes.js +5 -3
- package/src/services/conversation.service.js +96 -2
package/COHORT_API_EXAMPLES.sh
CHANGED
|
@@ -1,235 +1,235 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Cohort API Test Examples
|
|
4
|
-
# This file contains curl commands to test all cohort API endpoints
|
|
5
|
-
|
|
6
|
-
BASE_URL="https://testtangoretail-api.tangoeye.ai/v3/audio-analitics"
|
|
7
|
-
COHORT_ID="cohort_photochromatic_001"
|
|
8
|
-
CLIENT_ID="11"
|
|
9
|
-
|
|
10
|
-
# ==================== Helper Function ====================
|
|
11
|
-
print_section() {
|
|
12
|
-
echo ""
|
|
13
|
-
echo "=================================="
|
|
14
|
-
echo "$1"
|
|
15
|
-
echo "=================================="
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
# ==================== 1. CREATE COHORT ====================
|
|
19
|
-
print_section "1. CREATE COHORT"
|
|
20
|
-
|
|
21
|
-
curl -X POST "$BASE_URL/cohorts" \
|
|
22
|
-
-H "Content-Type: application/json" \
|
|
23
|
-
-d '{
|
|
24
|
-
"clientId": "11",
|
|
25
|
-
"cohortId": "cohort_photochromatic_001",
|
|
26
|
-
"cohortName": "Photochromatic",
|
|
27
|
-
"cohortDescription": "A strict evaluation of the photochromatic sales journey, focusing on pitch quality, technical accuracy, and customer sentiment",
|
|
28
|
-
"metrics": [
|
|
29
|
-
{
|
|
30
|
-
"metricId": "pitch_quality_001",
|
|
31
|
-
"metricName": "Standard Pitch Quality",
|
|
32
|
-
"metricDescription": "Identify which specific value propositions were explicitly used by the staff",
|
|
33
|
-
"hasContext": true,
|
|
34
|
-
"isNumneric": false,
|
|
35
|
-
"contexts": [
|
|
36
|
-
{
|
|
37
|
-
"contextName": "ONE_GLASS_ALL_NEEDS",
|
|
38
|
-
"priority": 2,
|
|
39
|
-
"description": "Convenience of one pair for all lighting"
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"contextName": "TRAVEL_CONVENIENCE",
|
|
43
|
-
"priority": 2,
|
|
44
|
-
"description": "Specific benefits for bikers/commuters"
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
"contextName": "LIGHT_ADAPTATION",
|
|
48
|
-
"priority": 2,
|
|
49
|
-
"description": "Technical explanation of UV reaction"
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
"contextName": "REDUCES_EYE_STRAIN",
|
|
53
|
-
"priority": 2,
|
|
54
|
-
"description": "Glare and fatigue protection"
|
|
55
|
-
}
|
|
56
|
-
]
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
"metricId": "technical_depth_score_001",
|
|
60
|
-
"metricName": "Technical Depth Score",
|
|
61
|
-
"metricDescription": "A numeric evaluation of the staff'\''s product knowledge during the pitch",
|
|
62
|
-
"hasContext": true,
|
|
63
|
-
"isNumneric": true,
|
|
64
|
-
"contexts": [
|
|
65
|
-
{
|
|
66
|
-
"minValue": 0,
|
|
67
|
-
"maxValue": 100
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"metricId": "customer_sentiment_001",
|
|
73
|
-
"metricName": "Initial Customer Sentiment",
|
|
74
|
-
"metricDescription": "The immediate reaction of the customer when the lens was introduced",
|
|
75
|
-
"hasContext": true,
|
|
76
|
-
"isNumneric": false,
|
|
77
|
-
"contexts": [
|
|
78
|
-
{
|
|
79
|
-
"contextName": "POSITIVE",
|
|
80
|
-
"priority": 2,
|
|
81
|
-
"description": "High interest or curiosity"
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"contextName": "NEUTRAL",
|
|
85
|
-
"priority": 1,
|
|
86
|
-
"description": "Acknowledgment or price-focused only"
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
"contextName": "NEGATIVE",
|
|
90
|
-
"priority": 0,
|
|
91
|
-
"description": "Dismissive or disinterested"
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
"metricId": "staff_responsiveness_001",
|
|
97
|
-
"metricName": "Staff Responsiveness",
|
|
98
|
-
"metricDescription": "How effectively were customer doubts addressed?",
|
|
99
|
-
"hasContext": true,
|
|
100
|
-
"isNumneric": false,
|
|
101
|
-
"contexts": [
|
|
102
|
-
{
|
|
103
|
-
"contextName": "FULLY_RESPONSIVE",
|
|
104
|
-
"priority": 2,
|
|
105
|
-
"description": "All doubts cleared with evidence"
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
"contextName": "PARTIALLY_RESPONSIVE",
|
|
109
|
-
"priority": 1,
|
|
110
|
-
"description": "Some doubts addressed, others ignored"
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"contextName": "UNRESPONSIVE",
|
|
114
|
-
"priority": 0,
|
|
115
|
-
"description": "Customer doubts were dismissed"
|
|
116
|
-
}
|
|
117
|
-
]
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
"metricId": "sales_outcome_001",
|
|
121
|
-
"metricName": "Final Sales Outcome",
|
|
122
|
-
"metricDescription": "The final commitment level reached at the end of the conversation",
|
|
123
|
-
"hasContext": true,
|
|
124
|
-
"isNumneric": false,
|
|
125
|
-
"contexts": [
|
|
126
|
-
{
|
|
127
|
-
"contextName": "BOUGHT_PHOTOCHROMATIC",
|
|
128
|
-
"priority": 2,
|
|
129
|
-
"description": "Customer agreed to the upgrade"
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
"contextName": "BOUGHT_SOMETHING_ELSE",
|
|
133
|
-
"priority": 0,
|
|
134
|
-
"description": "Bought standard lenses/frames only"
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
"contextName": "NO_SALE",
|
|
138
|
-
"priority": 0,
|
|
139
|
-
"description": "No purchase commitment"
|
|
140
|
-
}
|
|
141
|
-
]
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
"metricId": "pitch_timing_summary_001",
|
|
145
|
-
"metricName": "Pitch Timing & Context",
|
|
146
|
-
"metricDescription": "Narrative summary of when and how the pitch was introduced",
|
|
147
|
-
"hasContext": false,
|
|
148
|
-
"isNumneric": false
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
}'
|
|
152
|
-
|
|
153
|
-
# ==================== 2. GET COHORT BY ID ====================
|
|
154
|
-
print_section "2. GET COHORT BY ID"
|
|
155
|
-
|
|
156
|
-
curl -X GET "$BASE_URL/cohorts/$COHORT_ID" \
|
|
157
|
-
-H "Content-Type: application/json"
|
|
158
|
-
|
|
159
|
-
# ==================== 3. GET COHORTS BY CLIENT ====================
|
|
160
|
-
print_section "3. GET COHORTS BY CLIENT"
|
|
161
|
-
|
|
162
|
-
curl -X GET "$BASE_URL/cohorts/client/$CLIENT_ID?limit=10&offset=0" \
|
|
163
|
-
-H "Content-Type: application/json"
|
|
164
|
-
|
|
165
|
-
# ==================== 4. SEARCH COHORTS ====================
|
|
166
|
-
print_section "4. SEARCH COHORTS"
|
|
167
|
-
|
|
168
|
-
curl -X POST "$BASE_URL/cohorts/search" \
|
|
169
|
-
-H "Content-Type: application/json" \
|
|
170
|
-
-d '{
|
|
171
|
-
"clientId": "11",
|
|
172
|
-
"cohortName": "Photochrom",
|
|
173
|
-
"limit": 10,
|
|
174
|
-
"offset": 0
|
|
175
|
-
}'
|
|
176
|
-
|
|
177
|
-
# ==================== 5. UPDATE COHORT ====================
|
|
178
|
-
print_section "5. UPDATE COHORT"
|
|
179
|
-
|
|
180
|
-
# Note: Replace DOCUMENT_ID with actual ID returned from create
|
|
181
|
-
DOCUMENT_ID="550e8400-e29b-41d4-a716-446655440000"
|
|
182
|
-
|
|
183
|
-
curl -X PUT "$BASE_URL/cohorts/$DOCUMENT_ID" \
|
|
184
|
-
-H "Content-Type: application/json" \
|
|
185
|
-
-d '{
|
|
186
|
-
"cohortName": "Updated Photochromatic",
|
|
187
|
-
"cohortDescription": "Updated description for photochromatic cohort"
|
|
188
|
-
}'
|
|
189
|
-
|
|
190
|
-
# ==================== 6. GET COHORT ANALYTICS ====================
|
|
191
|
-
print_section "6. GET COHORT ANALYTICS"
|
|
192
|
-
|
|
193
|
-
curl -X GET "$BASE_URL/cohorts/$COHORT_ID/analytics" \
|
|
194
|
-
-H "Content-Type: application/json"
|
|
195
|
-
|
|
196
|
-
# ==================== 7. DELETE COHORT ====================
|
|
197
|
-
print_section "7. DELETE COHORT"
|
|
198
|
-
|
|
199
|
-
# Note: Replace DOCUMENT_ID with actual ID
|
|
200
|
-
curl -X DELETE "$BASE_URL/cohorts/$DOCUMENT_ID" \
|
|
201
|
-
-H "Content-Type: application/json"
|
|
202
|
-
|
|
203
|
-
# ==================== VALIDATION TESTS ====================
|
|
204
|
-
print_section "VALIDATION TESTS"
|
|
205
|
-
|
|
206
|
-
echo "Testing invalid cohort name (too short):"
|
|
207
|
-
curl -X POST "$BASE_URL/cohorts" \
|
|
208
|
-
-H "Content-Type: application/json" \
|
|
209
|
-
-d '{
|
|
210
|
-
"clientId": "11",
|
|
211
|
-
"cohortId": "invalid_test",
|
|
212
|
-
"cohortName": "AB",
|
|
213
|
-
"cohortDescription": "This should fail because name is too short"
|
|
214
|
-
}'
|
|
215
|
-
|
|
216
|
-
echo ""
|
|
217
|
-
echo "Testing missing required field:"
|
|
218
|
-
curl -X POST "$BASE_URL/cohorts" \
|
|
219
|
-
-H "Content-Type: application/json" \
|
|
220
|
-
-d '{
|
|
221
|
-
"clientId": "11",
|
|
222
|
-
"cohortId": "invalid_test",
|
|
223
|
-
"cohortName": "Valid Name"
|
|
224
|
-
}'
|
|
225
|
-
|
|
226
|
-
echo ""
|
|
227
|
-
echo "Testing invalid cohortId (special characters):"
|
|
228
|
-
curl -X POST "$BASE_URL/cohorts" \
|
|
229
|
-
-H "Content-Type: application/json" \
|
|
230
|
-
-d '{
|
|
231
|
-
"clientId": "11",
|
|
232
|
-
"cohortId": "invalid@test",
|
|
233
|
-
"cohortName": "Valid Name",
|
|
234
|
-
"cohortDescription": "This should fail because cohortId has invalid characters"
|
|
235
|
-
}'
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Cohort API Test Examples
|
|
4
|
+
# This file contains curl commands to test all cohort API endpoints
|
|
5
|
+
|
|
6
|
+
BASE_URL="https://testtangoretail-api.tangoeye.ai/v3/audio-analitics"
|
|
7
|
+
COHORT_ID="cohort_photochromatic_001"
|
|
8
|
+
CLIENT_ID="11"
|
|
9
|
+
|
|
10
|
+
# ==================== Helper Function ====================
|
|
11
|
+
print_section() {
|
|
12
|
+
echo ""
|
|
13
|
+
echo "=================================="
|
|
14
|
+
echo "$1"
|
|
15
|
+
echo "=================================="
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
# ==================== 1. CREATE COHORT ====================
|
|
19
|
+
print_section "1. CREATE COHORT"
|
|
20
|
+
|
|
21
|
+
curl -X POST "$BASE_URL/cohorts" \
|
|
22
|
+
-H "Content-Type: application/json" \
|
|
23
|
+
-d '{
|
|
24
|
+
"clientId": "11",
|
|
25
|
+
"cohortId": "cohort_photochromatic_001",
|
|
26
|
+
"cohortName": "Photochromatic",
|
|
27
|
+
"cohortDescription": "A strict evaluation of the photochromatic sales journey, focusing on pitch quality, technical accuracy, and customer sentiment",
|
|
28
|
+
"metrics": [
|
|
29
|
+
{
|
|
30
|
+
"metricId": "pitch_quality_001",
|
|
31
|
+
"metricName": "Standard Pitch Quality",
|
|
32
|
+
"metricDescription": "Identify which specific value propositions were explicitly used by the staff",
|
|
33
|
+
"hasContext": true,
|
|
34
|
+
"isNumneric": false,
|
|
35
|
+
"contexts": [
|
|
36
|
+
{
|
|
37
|
+
"contextName": "ONE_GLASS_ALL_NEEDS",
|
|
38
|
+
"priority": 2,
|
|
39
|
+
"description": "Convenience of one pair for all lighting"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"contextName": "TRAVEL_CONVENIENCE",
|
|
43
|
+
"priority": 2,
|
|
44
|
+
"description": "Specific benefits for bikers/commuters"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"contextName": "LIGHT_ADAPTATION",
|
|
48
|
+
"priority": 2,
|
|
49
|
+
"description": "Technical explanation of UV reaction"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"contextName": "REDUCES_EYE_STRAIN",
|
|
53
|
+
"priority": 2,
|
|
54
|
+
"description": "Glare and fatigue protection"
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"metricId": "technical_depth_score_001",
|
|
60
|
+
"metricName": "Technical Depth Score",
|
|
61
|
+
"metricDescription": "A numeric evaluation of the staff'\''s product knowledge during the pitch",
|
|
62
|
+
"hasContext": true,
|
|
63
|
+
"isNumneric": true,
|
|
64
|
+
"contexts": [
|
|
65
|
+
{
|
|
66
|
+
"minValue": 0,
|
|
67
|
+
"maxValue": 100
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"metricId": "customer_sentiment_001",
|
|
73
|
+
"metricName": "Initial Customer Sentiment",
|
|
74
|
+
"metricDescription": "The immediate reaction of the customer when the lens was introduced",
|
|
75
|
+
"hasContext": true,
|
|
76
|
+
"isNumneric": false,
|
|
77
|
+
"contexts": [
|
|
78
|
+
{
|
|
79
|
+
"contextName": "POSITIVE",
|
|
80
|
+
"priority": 2,
|
|
81
|
+
"description": "High interest or curiosity"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"contextName": "NEUTRAL",
|
|
85
|
+
"priority": 1,
|
|
86
|
+
"description": "Acknowledgment or price-focused only"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"contextName": "NEGATIVE",
|
|
90
|
+
"priority": 0,
|
|
91
|
+
"description": "Dismissive or disinterested"
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"metricId": "staff_responsiveness_001",
|
|
97
|
+
"metricName": "Staff Responsiveness",
|
|
98
|
+
"metricDescription": "How effectively were customer doubts addressed?",
|
|
99
|
+
"hasContext": true,
|
|
100
|
+
"isNumneric": false,
|
|
101
|
+
"contexts": [
|
|
102
|
+
{
|
|
103
|
+
"contextName": "FULLY_RESPONSIVE",
|
|
104
|
+
"priority": 2,
|
|
105
|
+
"description": "All doubts cleared with evidence"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"contextName": "PARTIALLY_RESPONSIVE",
|
|
109
|
+
"priority": 1,
|
|
110
|
+
"description": "Some doubts addressed, others ignored"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"contextName": "UNRESPONSIVE",
|
|
114
|
+
"priority": 0,
|
|
115
|
+
"description": "Customer doubts were dismissed"
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"metricId": "sales_outcome_001",
|
|
121
|
+
"metricName": "Final Sales Outcome",
|
|
122
|
+
"metricDescription": "The final commitment level reached at the end of the conversation",
|
|
123
|
+
"hasContext": true,
|
|
124
|
+
"isNumneric": false,
|
|
125
|
+
"contexts": [
|
|
126
|
+
{
|
|
127
|
+
"contextName": "BOUGHT_PHOTOCHROMATIC",
|
|
128
|
+
"priority": 2,
|
|
129
|
+
"description": "Customer agreed to the upgrade"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"contextName": "BOUGHT_SOMETHING_ELSE",
|
|
133
|
+
"priority": 0,
|
|
134
|
+
"description": "Bought standard lenses/frames only"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"contextName": "NO_SALE",
|
|
138
|
+
"priority": 0,
|
|
139
|
+
"description": "No purchase commitment"
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"metricId": "pitch_timing_summary_001",
|
|
145
|
+
"metricName": "Pitch Timing & Context",
|
|
146
|
+
"metricDescription": "Narrative summary of when and how the pitch was introduced",
|
|
147
|
+
"hasContext": false,
|
|
148
|
+
"isNumneric": false
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}'
|
|
152
|
+
|
|
153
|
+
# ==================== 2. GET COHORT BY ID ====================
|
|
154
|
+
print_section "2. GET COHORT BY ID"
|
|
155
|
+
|
|
156
|
+
curl -X GET "$BASE_URL/cohorts/$COHORT_ID" \
|
|
157
|
+
-H "Content-Type: application/json"
|
|
158
|
+
|
|
159
|
+
# ==================== 3. GET COHORTS BY CLIENT ====================
|
|
160
|
+
print_section "3. GET COHORTS BY CLIENT"
|
|
161
|
+
|
|
162
|
+
curl -X GET "$BASE_URL/cohorts/client/$CLIENT_ID?limit=10&offset=0" \
|
|
163
|
+
-H "Content-Type: application/json"
|
|
164
|
+
|
|
165
|
+
# ==================== 4. SEARCH COHORTS ====================
|
|
166
|
+
print_section "4. SEARCH COHORTS"
|
|
167
|
+
|
|
168
|
+
curl -X POST "$BASE_URL/cohorts/search" \
|
|
169
|
+
-H "Content-Type: application/json" \
|
|
170
|
+
-d '{
|
|
171
|
+
"clientId": "11",
|
|
172
|
+
"cohortName": "Photochrom",
|
|
173
|
+
"limit": 10,
|
|
174
|
+
"offset": 0
|
|
175
|
+
}'
|
|
176
|
+
|
|
177
|
+
# ==================== 5. UPDATE COHORT ====================
|
|
178
|
+
print_section "5. UPDATE COHORT"
|
|
179
|
+
|
|
180
|
+
# Note: Replace DOCUMENT_ID with actual ID returned from create
|
|
181
|
+
DOCUMENT_ID="550e8400-e29b-41d4-a716-446655440000"
|
|
182
|
+
|
|
183
|
+
curl -X PUT "$BASE_URL/cohorts/$DOCUMENT_ID" \
|
|
184
|
+
-H "Content-Type: application/json" \
|
|
185
|
+
-d '{
|
|
186
|
+
"cohortName": "Updated Photochromatic",
|
|
187
|
+
"cohortDescription": "Updated description for photochromatic cohort"
|
|
188
|
+
}'
|
|
189
|
+
|
|
190
|
+
# ==================== 6. GET COHORT ANALYTICS ====================
|
|
191
|
+
print_section "6. GET COHORT ANALYTICS"
|
|
192
|
+
|
|
193
|
+
curl -X GET "$BASE_URL/cohorts/$COHORT_ID/analytics" \
|
|
194
|
+
-H "Content-Type: application/json"
|
|
195
|
+
|
|
196
|
+
# ==================== 7. DELETE COHORT ====================
|
|
197
|
+
print_section "7. DELETE COHORT"
|
|
198
|
+
|
|
199
|
+
# Note: Replace DOCUMENT_ID with actual ID
|
|
200
|
+
curl -X DELETE "$BASE_URL/cohorts/$DOCUMENT_ID" \
|
|
201
|
+
-H "Content-Type: application/json"
|
|
202
|
+
|
|
203
|
+
# ==================== VALIDATION TESTS ====================
|
|
204
|
+
print_section "VALIDATION TESTS"
|
|
205
|
+
|
|
206
|
+
echo "Testing invalid cohort name (too short):"
|
|
207
|
+
curl -X POST "$BASE_URL/cohorts" \
|
|
208
|
+
-H "Content-Type: application/json" \
|
|
209
|
+
-d '{
|
|
210
|
+
"clientId": "11",
|
|
211
|
+
"cohortId": "invalid_test",
|
|
212
|
+
"cohortName": "AB",
|
|
213
|
+
"cohortDescription": "This should fail because name is too short"
|
|
214
|
+
}'
|
|
215
|
+
|
|
216
|
+
echo ""
|
|
217
|
+
echo "Testing missing required field:"
|
|
218
|
+
curl -X POST "$BASE_URL/cohorts" \
|
|
219
|
+
-H "Content-Type: application/json" \
|
|
220
|
+
-d '{
|
|
221
|
+
"clientId": "11",
|
|
222
|
+
"cohortId": "invalid_test",
|
|
223
|
+
"cohortName": "Valid Name"
|
|
224
|
+
}'
|
|
225
|
+
|
|
226
|
+
echo ""
|
|
227
|
+
echo "Testing invalid cohortId (special characters):"
|
|
228
|
+
curl -X POST "$BASE_URL/cohorts" \
|
|
229
|
+
-H "Content-Type: application/json" \
|
|
230
|
+
-d '{
|
|
231
|
+
"clientId": "11",
|
|
232
|
+
"cohortId": "invalid@test",
|
|
233
|
+
"cohortName": "Valid Name",
|
|
234
|
+
"cohortDescription": "This should fail because cohortId has invalid characters"
|
|
235
|
+
}'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tango-app-api-audio-analytics",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.33",
|
|
4
4
|
"description": "audioAnalytics",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"start": "nodemon --exec \"eslint --fix . && node app.js\""
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
|
-
"node": ">=18.10.0"
|
|
11
|
+
"node": ">=18.10.0 <25"
|
|
12
12
|
},
|
|
13
13
|
"author": "praveenraj",
|
|
14
14
|
"license": "ISC",
|
|
@@ -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
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
exportConversationsFromLambda,
|
|
6
6
|
getConversationDetailsFromLambda,
|
|
7
7
|
getTranscriptListFromLambda,
|
|
8
|
+
getCategoryAnalysisCardFromLambda,
|
|
8
9
|
// filterConversationsBySearch,
|
|
9
10
|
// sortConversations,
|
|
10
11
|
} from '../services/conversation.service.js';
|
|
@@ -38,6 +39,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
38
39
|
isAI,
|
|
39
40
|
analyticsType,
|
|
40
41
|
searchValue,
|
|
42
|
+
audioSource,
|
|
41
43
|
limit,
|
|
42
44
|
offset,
|
|
43
45
|
isExport,
|
|
@@ -80,6 +82,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
80
82
|
offset,
|
|
81
83
|
_id,
|
|
82
84
|
name,
|
|
85
|
+
audioSource,
|
|
83
86
|
} );
|
|
84
87
|
|
|
85
88
|
// conversations = exportResponse.conversations || [];
|
|
@@ -118,6 +121,7 @@ export const getConversationsList = async ( req, res ) => {
|
|
|
118
121
|
isAI,
|
|
119
122
|
analyticsType,
|
|
120
123
|
searchValue,
|
|
124
|
+
audioSource,
|
|
121
125
|
limit,
|
|
122
126
|
offset,
|
|
123
127
|
_id,
|
|
@@ -188,6 +192,7 @@ export const getTranscriptsList = async ( req, res ) => {
|
|
|
188
192
|
isAI,
|
|
189
193
|
analyticsType,
|
|
190
194
|
searchValue,
|
|
195
|
+
audioSource,
|
|
191
196
|
limit,
|
|
192
197
|
offset,
|
|
193
198
|
isExport,
|
|
@@ -227,6 +232,7 @@ export const getTranscriptsList = async ( req, res ) => {
|
|
|
227
232
|
isAI,
|
|
228
233
|
analyticsType,
|
|
229
234
|
searchValue,
|
|
235
|
+
audioSource,
|
|
230
236
|
limit,
|
|
231
237
|
offset,
|
|
232
238
|
_id,
|
|
@@ -334,3 +340,77 @@ export const getConversationDetails = async ( req, res ) => {
|
|
|
334
340
|
}
|
|
335
341
|
};
|
|
336
342
|
|
|
343
|
+
/**
|
|
344
|
+
* Get Category Analysis Card
|
|
345
|
+
* POST /category-analysis-card
|
|
346
|
+
* @param {Object} req - Express request object
|
|
347
|
+
* @param {Object} req.body - Request body
|
|
348
|
+
* @param {string} req.body.startDate - Start date (YYYY-MM-DD)
|
|
349
|
+
* @param {string} req.body.endDate - End date (YYYY-MM-DD)
|
|
350
|
+
* @param {string[]} req.body.storeId - Array of store IDs
|
|
351
|
+
* @param {string} req.body.cohortId - Cohort ID
|
|
352
|
+
* @param {string} req.body.clientId - Client ID
|
|
353
|
+
* @param {number} req.body.id - Category numeric ID
|
|
354
|
+
* @param {string} req.body.category - Category name
|
|
355
|
+
* @param {Object} res - Express response object
|
|
356
|
+
* @return {void} Returns JSON response with category analysis card data
|
|
357
|
+
*/
|
|
358
|
+
export const getCategoryAnalysisCard = async ( req, res ) => {
|
|
359
|
+
try {
|
|
360
|
+
const { startDate, endDate, storeId, cohortId, clientId, id, category } = req.body;
|
|
361
|
+
|
|
362
|
+
if ( !startDate || !endDate || !storeId || !cohortId || !clientId || id === undefined || !category ) {
|
|
363
|
+
return res.status( 400 ).json( {
|
|
364
|
+
status: 'error',
|
|
365
|
+
message: 'Missing required parameters: startDate, endDate, storeId, cohortId, clientId, id, category',
|
|
366
|
+
code: 'MISSING_PARAMETERS',
|
|
367
|
+
timestamp: new Date().toISOString(),
|
|
368
|
+
} );
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
logger.info( {
|
|
372
|
+
message: 'Fetching category analysis card',
|
|
373
|
+
startDate,
|
|
374
|
+
endDate,
|
|
375
|
+
storeId,
|
|
376
|
+
cohortId,
|
|
377
|
+
clientId,
|
|
378
|
+
id,
|
|
379
|
+
category,
|
|
380
|
+
} );
|
|
381
|
+
|
|
382
|
+
const lambdaResponse = await getCategoryAnalysisCardFromLambda( {
|
|
383
|
+
startDate,
|
|
384
|
+
endDate,
|
|
385
|
+
storeId,
|
|
386
|
+
cohortId,
|
|
387
|
+
clientId,
|
|
388
|
+
id,
|
|
389
|
+
category,
|
|
390
|
+
} );
|
|
391
|
+
|
|
392
|
+
if ( !lambdaResponse ) {
|
|
393
|
+
return res.status( 204 ).json( {
|
|
394
|
+
status: 'error',
|
|
395
|
+
message: 'No data found for the given parameters',
|
|
396
|
+
code: 'DATA_NOT_FOUND',
|
|
397
|
+
timestamp: new Date().toISOString(),
|
|
398
|
+
} );
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return res.status( 200 ).json( {
|
|
402
|
+
status: lambdaResponse?.status || 'success',
|
|
403
|
+
data: lambdaResponse?.data ?? lambdaResponse,
|
|
404
|
+
timestamp: new Date().toISOString(),
|
|
405
|
+
} );
|
|
406
|
+
} catch ( error ) {
|
|
407
|
+
logger.error( { error, message: 'Error fetching category analysis card', body: req.body } );
|
|
408
|
+
return res.status( 500 ).json( {
|
|
409
|
+
status: 'error',
|
|
410
|
+
message: error.message || 'Internal server error',
|
|
411
|
+
code: 'INTERNAL_ERROR',
|
|
412
|
+
timestamp: new Date().toISOString(),
|
|
413
|
+
} );
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
@@ -510,6 +510,30 @@ 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
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Category Analysis Card Schema
|
|
526
|
+
*/
|
|
527
|
+
export const categoryAnalysisCardValid = joi.object( {
|
|
528
|
+
startDate: joi.string().required().pattern( /^\d{4}-\d{2}-\d{2}$/ ).description( 'Start date in YYYY-MM-DD format' ),
|
|
529
|
+
endDate: joi.string().required().pattern( /^\d{4}-\d{2}-\d{2}$/ ).description( 'End date in YYYY-MM-DD format' ),
|
|
530
|
+
storeId: joi.array().items( joi.string() ).required().min( 1 ).description( 'Array of store IDs' ),
|
|
531
|
+
cohortId: joi.string().required().description( 'Cohort ID' ),
|
|
532
|
+
clientId: joi.string().required().description( 'Client ID' ),
|
|
533
|
+
id: joi.number().integer().required().description( 'Category numeric ID' ),
|
|
534
|
+
category: joi.string().required().description( 'Category name' ),
|
|
535
|
+
} ).strict();
|
|
536
|
+
|
|
513
537
|
/**
|
|
514
538
|
* Conversations List Schema
|
|
515
539
|
*/
|
|
@@ -522,6 +546,7 @@ export const conversationsListValid = joi.object( {
|
|
|
522
546
|
isAI: joi.boolean().optional().description( 'Filter for AI-generated conversations' ),
|
|
523
547
|
analyticsType: joi.string().optional().valid( 'audio', 'text', 'all' ).description( 'Type of analytics' ),
|
|
524
548
|
searchValue: joi.string().optional().description( 'Search term' ),
|
|
549
|
+
audioSource: joi.string().optional().description( 'Audio source filter' ),
|
|
525
550
|
isExport: joi.boolean().optional().description( 'Flag to export as CSV' ),
|
|
526
551
|
limit: joi.number().integer().min( 1 ).max( 1000 ).optional().default( 10 ).description( 'Pagination limit' ),
|
|
527
552
|
offset: joi.number().integer().min( 0 ).optional().default( 0 ).description( 'Pagination offset' ),
|
|
@@ -539,6 +564,7 @@ export const transcriptListValid = joi.object( {
|
|
|
539
564
|
isAI: joi.boolean().optional().description( 'Filter for AI-generated conversations' ),
|
|
540
565
|
analyticsType: joi.string().optional().valid( 'audio', 'text', 'all' ).description( 'Type of analytics' ),
|
|
541
566
|
searchValue: joi.string().optional().description( 'Search term' ),
|
|
567
|
+
audioSource: joi.string().optional().description( 'Audio source filter' ),
|
|
542
568
|
isExport: joi.boolean().optional().description( 'Flag to export as CSV' ),
|
|
543
569
|
limit: joi.number().integer().min( 1 ).max( 1000 ).optional().default( 10 ).description( 'Pagination limit' ),
|
|
544
570
|
offset: joi.number().integer().min( 0 ).optional().default( 0 ).description( 'Pagination offset' ),
|
|
@@ -2,10 +2,10 @@
|
|
|
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, 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';
|
|
8
|
-
import { getConversationsList, getTranscriptsList, getConversationDetails } from '../controllers/conversationAnalytics.controller.js';
|
|
7
|
+
import { getCohortAnalysisCard, getCohortSummaryCard } from '../controllers/cohortAnalytics.controller.js';
|
|
8
|
+
import { getConversationsList, getTranscriptsList, getConversationDetails, getCategoryAnalysisCard } from '../controllers/conversationAnalytics.controller.js';
|
|
9
9
|
|
|
10
10
|
export const audioAnalyticsrouter = express.Router(); ;
|
|
11
11
|
|
|
@@ -27,6 +27,8 @@ 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 );
|
|
31
|
+
audioAnalyticsrouter.post( '/category-analysis-card', validate( categoryAnalysisCardValid ), getCategoryAnalysisCard );
|
|
30
32
|
|
|
31
33
|
// Conversation Analytics Routes
|
|
32
34
|
audioAnalyticsrouter.post( '/conversations/list', validate( conversationsListValid ), getConversationsList );
|
|
@@ -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
|
} );
|
|
@@ -289,6 +289,100 @@ export async function getCohortAnalysisSummaryCard( params ) {
|
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
/**
|
|
293
|
+
* Call Lambda to get category analysis card
|
|
294
|
+
* @param {Object} params - Request parameters
|
|
295
|
+
* @param {string} params.startDate - Start date (YYYY-MM-DD)
|
|
296
|
+
* @param {string} params.endDate - End date (YYYY-MM-DD)
|
|
297
|
+
* @param {string[]} params.storeId - Array of store IDs
|
|
298
|
+
* @param {string} params.cohortId - Cohort ID
|
|
299
|
+
* @param {string} params.clientId - Client ID
|
|
300
|
+
* @param {number} params.id - Category numeric ID
|
|
301
|
+
* @param {string} params.category - Category name
|
|
302
|
+
* @return {Promise<Object>} Response from Lambda
|
|
303
|
+
*/
|
|
304
|
+
export async function getCategoryAnalysisCardFromLambda( params ) {
|
|
305
|
+
try {
|
|
306
|
+
const LAMBDA_ENDPOINT = JSON.parse( process.env.URL ) || 'http://lambda-api:8000';
|
|
307
|
+
|
|
308
|
+
const payload = {
|
|
309
|
+
startDate: params.startDate,
|
|
310
|
+
endDate: params.endDate,
|
|
311
|
+
storeId: Array.isArray( params.storeId ) ? params.storeId : [ params.storeId ],
|
|
312
|
+
cohortId: params.cohortId,
|
|
313
|
+
clientId: params.clientId,
|
|
314
|
+
id: params.id,
|
|
315
|
+
category: params.category,
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
logger.info( { message: 'Calling Lambda for category analysis card', url: LAMBDA_ENDPOINT.categoryAnalysisCard, payload } );
|
|
319
|
+
|
|
320
|
+
const response = await axios.post( `${LAMBDA_ENDPOINT.categoryAnalysisCard}`, payload, {
|
|
321
|
+
headers: {
|
|
322
|
+
'Content-Type': 'application/json',
|
|
323
|
+
},
|
|
324
|
+
timeout: 30000,
|
|
325
|
+
} );
|
|
326
|
+
|
|
327
|
+
logger.info( { message: 'Lambda response received for category analysis card', status: response.status } );
|
|
328
|
+
return response.data;
|
|
329
|
+
} catch ( error ) {
|
|
330
|
+
logger.error( {
|
|
331
|
+
error: error.message,
|
|
332
|
+
status: error.response?.status,
|
|
333
|
+
data: error.response?.data,
|
|
334
|
+
message: 'Error calling Lambda for category analysis card',
|
|
335
|
+
params,
|
|
336
|
+
} );
|
|
337
|
+
throw new Error( `Failed to fetch category analysis card: ${error.message}` );
|
|
338
|
+
}
|
|
339
|
+
}
|
|
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
|
+
|
|
292
386
|
/**
|
|
293
387
|
* Process and filter conversations based on search criteria
|
|
294
388
|
* @param {Array} conversations - Array of conversation objects
|