|
| 1 | +// ======================================== |
| 2 | +// VA Conversation Analyzer - Background Script |
| 3 | +// ======================================== |
| 4 | +// Purpose: On-demand analysis of Virtual Agent conversations |
| 5 | +// Usage: Run from Scripts - Background when you need immediate insights |
| 6 | +// Output: Detailed analytics report in system logs |
| 7 | +// ======================================== |
| 8 | + |
| 9 | +(function analyzeConversations() { |
| 10 | + |
| 11 | + // Configuration |
| 12 | + var config = { |
| 13 | + daysToAnalyze: 30, // Analyze last 30 days |
| 14 | + includeAbandoned: true, |
| 15 | + includeCompleted: true, |
| 16 | + minConversations: 5 // Minimum conversations to show in report |
| 17 | + }; |
| 18 | + |
| 19 | + gs.info('=== VA Conversation Analysis Report ==='); |
| 20 | + gs.info('Analyzing conversations from last ' + config.daysToAnalyze + ' days'); |
| 21 | + gs.info(''); |
| 22 | + |
| 23 | + // Get all conversations in time range |
| 24 | + var conversations = new GlideRecord('sys_cs_conversation'); |
| 25 | + conversations.addEncodedQuery('sys_created_on>=javascript:gs.daysAgoStart(' + config.daysToAnalyze + ')'); |
| 26 | + conversations.query(); |
| 27 | + |
| 28 | + var totalConversations = conversations.getRowCount(); |
| 29 | + gs.info('Total Conversations: ' + totalConversations); |
| 30 | + |
| 31 | + if (totalConversations == 0) { |
| 32 | + gs.info('No conversations found in the specified time period'); |
| 33 | + return; |
| 34 | + } |
| 35 | + |
| 36 | + // Analytics collections |
| 37 | + var topicStats = {}; |
| 38 | + var userStats = {}; |
| 39 | + var departmentStats = {}; |
| 40 | + var timeStats = { morning: 0, afternoon: 0, evening: 0, night: 0 }; |
| 41 | + var abandonmentReasons = {}; |
| 42 | + var totalAbandoned = 0; |
| 43 | + var totalCompleted = 0; |
| 44 | + |
| 45 | + // Process each conversation |
| 46 | + conversations.query(); |
| 47 | + while (conversations.next()) { |
| 48 | + var topicId = conversations.getValue('topic'); |
| 49 | + var topicName = conversations.topic.getDisplayValue() || 'Unknown Topic'; |
| 50 | + var userId = conversations.getValue('user'); |
| 51 | + var state = conversations.getValue('state'); |
| 52 | + var timestamp = conversations.getValue('sys_created_on'); |
| 53 | + |
| 54 | + // Topic statistics |
| 55 | + if (!topicStats[topicName]) { |
| 56 | + topicStats[topicName] = { |
| 57 | + total: 0, |
| 58 | + abandoned: 0, |
| 59 | + completed: 0, |
| 60 | + users: {} |
| 61 | + }; |
| 62 | + } |
| 63 | + topicStats[topicName].total++; |
| 64 | + topicStats[topicName].users[userId] = true; |
| 65 | + |
| 66 | + if (state == 'abandoned') { |
| 67 | + topicStats[topicName].abandoned++; |
| 68 | + totalAbandoned++; |
| 69 | + } else if (state == 'complete') { |
| 70 | + topicStats[topicName].completed++; |
| 71 | + totalCompleted++; |
| 72 | + } |
| 73 | + |
| 74 | + // User statistics |
| 75 | + if (!userStats[userId]) { |
| 76 | + userStats[userId] = 0; |
| 77 | + } |
| 78 | + userStats[userId]++; |
| 79 | + |
| 80 | + // Department statistics |
| 81 | + var department = getUserDepartment(userId); |
| 82 | + if (!departmentStats[department]) { |
| 83 | + departmentStats[department] = 0; |
| 84 | + } |
| 85 | + departmentStats[department]++; |
| 86 | + |
| 87 | + // Time of day statistics |
| 88 | + var timeSegment = getTimeSegment(timestamp); |
| 89 | + timeStats[timeSegment]++; |
| 90 | + } |
| 91 | + |
| 92 | + // Print Topic Statistics |
| 93 | + gs.info(''); |
| 94 | + gs.info('=== Topic Statistics ==='); |
| 95 | + gs.info(''); |
| 96 | + |
| 97 | + var topicArray = []; |
| 98 | + for (var topic in topicStats) { |
| 99 | + var stats = topicStats[topic]; |
| 100 | + topicArray.push({ |
| 101 | + name: topic, |
| 102 | + total: stats.total, |
| 103 | + abandoned: stats.abandoned, |
| 104 | + completed: stats.completed, |
| 105 | + uniqueUsers: Object.keys(stats.users).length, |
| 106 | + abandonRate: ((stats.abandoned / stats.total) * 100).toFixed(1) |
| 107 | + }); |
| 108 | + } |
| 109 | + |
| 110 | + // Sort by total conversations |
| 111 | + topicArray.sort(function(a, b) { |
| 112 | + return b.total - a.total; |
| 113 | + }); |
| 114 | + |
| 115 | + // Print top topics |
| 116 | + gs.info('Top Topics by Conversation Count:'); |
| 117 | + gs.info('-----------------------------------'); |
| 118 | + topicArray.forEach(function(topic) { |
| 119 | + if (topic.total >= config.minConversations) { |
| 120 | + gs.info(topic.name); |
| 121 | + gs.info(' Total: ' + topic.total + |
| 122 | + ' | Completed: ' + topic.completed + |
| 123 | + ' | Abandoned: ' + topic.abandoned + |
| 124 | + ' | Abandon Rate: ' + topic.abandonRate + '%' + |
| 125 | + ' | Unique Users: ' + topic.uniqueUsers); |
| 126 | + } |
| 127 | + }); |
| 128 | + |
| 129 | + // Print topics with high abandonment |
| 130 | + gs.info(''); |
| 131 | + gs.info('Topics with High Abandonment (>30%):'); |
| 132 | + gs.info('-------------------------------------'); |
| 133 | + var highAbandonmentFound = false; |
| 134 | + topicArray.forEach(function(topic) { |
| 135 | + if (parseFloat(topic.abandonRate) > 30 && topic.total >= config.minConversations) { |
| 136 | + gs.info('⚠️ ' + topic.name + ' - ' + topic.abandonRate + '% abandonment (' + topic.abandoned + '/' + topic.total + ')'); |
| 137 | + highAbandonmentFound = true; |
| 138 | + } |
| 139 | + }); |
| 140 | + if (!highAbandonmentFound) { |
| 141 | + gs.info('None - all topics performing well!'); |
| 142 | + } |
| 143 | + |
| 144 | + // Print Department Statistics |
| 145 | + gs.info(''); |
| 146 | + gs.info('=== Department Statistics ==='); |
| 147 | + gs.info(''); |
| 148 | + |
| 149 | + var deptArray = []; |
| 150 | + for (var dept in departmentStats) { |
| 151 | + deptArray.push({ |
| 152 | + name: dept, |
| 153 | + count: departmentStats[dept] |
| 154 | + }); |
| 155 | + } |
| 156 | + |
| 157 | + deptArray.sort(function(a, b) { |
| 158 | + return b.count - a.count; |
| 159 | + }); |
| 160 | + |
| 161 | + deptArray.forEach(function(dept) { |
| 162 | + var percentage = ((dept.count / totalConversations) * 100).toFixed(1); |
| 163 | + gs.info(dept.name + ': ' + dept.count + ' conversations (' + percentage + '%)'); |
| 164 | + }); |
| 165 | + |
| 166 | + // Print Time of Day Statistics |
| 167 | + gs.info(''); |
| 168 | + gs.info('=== Time of Day Statistics ==='); |
| 169 | + gs.info(''); |
| 170 | + gs.info('Morning (6am-12pm): ' + timeStats.morning + ' (' + ((timeStats.morning / totalConversations) * 100).toFixed(1) + '%)'); |
| 171 | + gs.info('Afternoon (12pm-5pm): ' + timeStats.afternoon + ' (' + ((timeStats.afternoon / totalConversations) * 100).toFixed(1) + '%)'); |
| 172 | + gs.info('Evening (5pm-10pm): ' + timeStats.evening + ' (' + ((timeStats.evening / totalConversations) * 100).toFixed(1) + '%)'); |
| 173 | + gs.info('Night (10pm-6am): ' + timeStats.night + ' (' + ((timeStats.night / totalConversations) * 100).toFixed(1) + '%)'); |
| 174 | + |
| 175 | + // Print User Engagement Statistics |
| 176 | + gs.info(''); |
| 177 | + gs.info('=== User Engagement Statistics ==='); |
| 178 | + gs.info(''); |
| 179 | + |
| 180 | + var totalUsers = Object.keys(userStats).length; |
| 181 | + var powerUsers = 0; |
| 182 | + var casualUsers = 0; |
| 183 | + |
| 184 | + for (var user in userStats) { |
| 185 | + if (userStats[user] >= 5) { |
| 186 | + powerUsers++; |
| 187 | + } else { |
| 188 | + casualUsers++; |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + gs.info('Total Unique Users: ' + totalUsers); |
| 193 | + gs.info('Power Users (5+ conversations): ' + powerUsers); |
| 194 | + gs.info('Casual Users (<5 conversations): ' + casualUsers); |
| 195 | + gs.info('Average Conversations per User: ' + (totalConversations / totalUsers).toFixed(1)); |
| 196 | + |
| 197 | + // Print Overall Statistics |
| 198 | + gs.info(''); |
| 199 | + gs.info('=== Overall Statistics ==='); |
| 200 | + gs.info(''); |
| 201 | + gs.info('Total Conversations: ' + totalConversations); |
| 202 | + gs.info('Completed: ' + totalCompleted + ' (' + ((totalCompleted / totalConversations) * 100).toFixed(1) + '%)'); |
| 203 | + gs.info('Abandoned: ' + totalAbandoned + ' (' + ((totalAbandoned / totalConversations) * 100).toFixed(1) + '%)'); |
| 204 | + gs.info('Average Daily Conversations: ' + (totalConversations / config.daysToAnalyze).toFixed(1)); |
| 205 | + |
| 206 | + // Recommendations |
| 207 | + gs.info(''); |
| 208 | + gs.info('=== Recommendations ==='); |
| 209 | + gs.info(''); |
| 210 | + |
| 211 | + var highAbandonTopics = topicArray.filter(function(t) { |
| 212 | + return parseFloat(t.abandonRate) > 30 && t.total >= config.minConversations; |
| 213 | + }); |
| 214 | + |
| 215 | + if (highAbandonTopics.length > 0) { |
| 216 | + gs.info('🔍 Review ' + highAbandonTopics.length + ' topic(s) with high abandonment rates'); |
| 217 | + } |
| 218 | + |
| 219 | + if (timeStats.night > (totalConversations * 0.1)) { |
| 220 | + gs.info('🌙 Significant night-time usage detected (' + timeStats.night + ' conversations) - consider 24/7 support topics'); |
| 221 | + } |
| 222 | + |
| 223 | + if (totalUsers > 0 && (totalConversations / totalUsers) < 2) { |
| 224 | + gs.info('📢 Low engagement (avg ' + (totalConversations / totalUsers).toFixed(1) + ' conversations/user) - consider promoting VA to increase awareness'); |
| 225 | + } |
| 226 | + |
| 227 | + if ((totalCompleted / totalConversations) > 0.85) { |
| 228 | + gs.info('✅ High completion rate (' + ((totalCompleted / totalConversations) * 100).toFixed(1) + '%) - VA is performing well!'); |
| 229 | + } |
| 230 | + |
| 231 | + gs.info(''); |
| 232 | + gs.info('=== Analysis Complete ==='); |
| 233 | + |
| 234 | + // Helper functions |
| 235 | + function getUserDepartment(userId) { |
| 236 | + var user = new GlideRecord('sys_user'); |
| 237 | + if (user.get(userId)) { |
| 238 | + return user.getDisplayValue('department') || 'Unknown'; |
| 239 | + } |
| 240 | + return 'Unknown'; |
| 241 | + } |
| 242 | + |
| 243 | + function getTimeSegment(timestamp) { |
| 244 | + var dt = new GlideDateTime(timestamp); |
| 245 | + var timeStr = dt.getDisplayValue(); |
| 246 | + var hour = parseInt(timeStr.split(' ')[1].split(':')[0]); |
| 247 | + |
| 248 | + if (hour >= 6 && hour < 12) return 'morning'; |
| 249 | + if (hour >= 12 && hour < 17) return 'afternoon'; |
| 250 | + if (hour >= 17 && hour < 22) return 'evening'; |
| 251 | + return 'night'; |
| 252 | + } |
| 253 | + |
| 254 | +})(); |
0 commit comments