Size
23.5 KB
Version
1.0.1
Created
Oct 30, 2025
Updated
15 days ago
1// ==UserScript==
2// @name Slack NPS Chat Summarizer
3// @description Summarizes all NPS chats from the NPS channel using AI
4// @version 1.0.1
5// @match https://*.app.slack.com/*
6// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAACxLAAAsSwGlPZapAAAFGmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDIgNzkuMTY0NDg4LCAyMDIwLzA3LzEwLTIyOjA2OjUzICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjIuMCAoTWFjaW50b3NoKSIgeG1wOkNyZWF0ZURhdGU9IjIwMjAtMTItMTBUMTA6MzI6MzEtMDg6MDAiIHhtcDpNb2RpZnlEYXRlPSIyMDIwLTEyLTEwVDEwOjMzOjM2LTA4OjAwIiB4bXA6TWV0YWRhdGFEYXRlPSIyMDIwLTEyLTEwVDEwOjMzOjM2LTA4OjAwIiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOmExODkyZGRmLTQ4ZDIt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
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('NPS Chat Summarizer extension loaded');
12
13 // Debounce function to prevent excessive calls
14 function debounce(func, wait) {
15 let timeout;
16 return function executedFunction(...args) {
17 const later = () => {
18 clearTimeout(timeout);
19 func(...args);
20 };
21 clearTimeout(timeout);
22 timeout = setTimeout(later, wait);
23 };
24 }
25
26 // Extract all messages from the current Slack channel
27 function extractMessages() {
28 console.log('Extracting messages from Slack channel...');
29 const messages = [];
30
31 // Find all message elements in Slack
32 const messageElements = document.querySelectorAll('[data-qa="virtual-list-item"]');
33
34 console.log(`Found ${messageElements.length} message elements`);
35
36 messageElements.forEach((element, index) => {
37 try {
38 // Extract sender name
39 const senderElement = element.querySelector('[data-qa="message_sender_name"]') ||
40 element.querySelector('.c-message__sender_button') ||
41 element.querySelector('.c-message__sender');
42 const sender = senderElement ? senderElement.textContent.trim() : 'Unknown';
43
44 // Extract message text
45 const messageTextElement = element.querySelector('[data-qa="message-text"]') ||
46 element.querySelector('.c-message_kit__text') ||
47 element.querySelector('.p-rich_text_section');
48 const text = messageTextElement ? messageTextElement.textContent.trim() : '';
49
50 // Extract timestamp
51 const timestampElement = element.querySelector('[data-qa="message_timestamp"]') ||
52 element.querySelector('.c-timestamp');
53 const timestamp = timestampElement ? timestampElement.textContent.trim() : '';
54
55 if (text && text.length > 0) {
56 messages.push({
57 sender: sender,
58 text: text,
59 timestamp: timestamp
60 });
61 }
62 } catch (error) {
63 console.error(`Error extracting message ${index}:`, error);
64 }
65 });
66
67 console.log(`Successfully extracted ${messages.length} messages`);
68 return messages;
69 }
70
71 // Create and show loading indicator
72 function showLoadingIndicator() {
73 const existingLoader = document.getElementById('nps-summarizer-loader');
74 if (existingLoader) return;
75
76 const loader = document.createElement('div');
77 loader.id = 'nps-summarizer-loader';
78 loader.innerHTML = `
79 <div style="display: flex; align-items: center; gap: 10px;">
80 <div class="spinner"></div>
81 <span>AI is analyzing NPS chats...</span>
82 </div>
83 `;
84 loader.style.cssText = `
85 position: fixed;
86 top: 20px;
87 right: 20px;
88 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
89 color: white;
90 padding: 15px 20px;
91 border-radius: 8px;
92 box-shadow: 0 4px 12px rgba(0,0,0,0.3);
93 z-index: 10000;
94 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
95 font-size: 14px;
96 `;
97
98 document.body.appendChild(loader);
99
100 // Add spinner animation
101 const style = document.createElement('style');
102 style.textContent = `
103 #nps-summarizer-loader .spinner {
104 width: 20px;
105 height: 20px;
106 border: 3px solid rgba(255,255,255,0.3);
107 border-top-color: white;
108 border-radius: 50%;
109 animation: spin 1s linear infinite;
110 }
111 @keyframes spin {
112 to { transform: rotate(360deg); }
113 }
114 `;
115 document.head.appendChild(style);
116 }
117
118 // Hide loading indicator
119 function hideLoadingIndicator() {
120 const loader = document.getElementById('nps-summarizer-loader');
121 if (loader) loader.remove();
122 }
123
124 // Display summary in a modal
125 function displaySummary(summary) {
126 console.log('Displaying summary modal');
127
128 // Remove existing modal if any
129 const existingModal = document.getElementById('nps-summary-modal');
130 if (existingModal) existingModal.remove();
131
132 const modal = document.createElement('div');
133 modal.id = 'nps-summary-modal';
134 modal.innerHTML = `
135 <div class="modal-overlay">
136 <div class="modal-content">
137 <div class="modal-header">
138 <h2>📊 NPS Chat Summary</h2>
139 <button class="close-btn" id="close-summary-modal">✕</button>
140 </div>
141 <div class="modal-body">
142 <div class="summary-section">
143 <h3>🎯 Key Themes</h3>
144 <ul>
145 ${summary.keyThemes.map(theme => `<li>${theme}</li>`).join('')}
146 </ul>
147 </div>
148
149 <div class="summary-section">
150 <h3>😊 Positive Feedback</h3>
151 <ul>
152 ${summary.positiveFeedback.map(item => `<li>${item}</li>`).join('')}
153 </ul>
154 </div>
155
156 <div class="summary-section">
157 <h3>⚠️ Issues & Concerns</h3>
158 <ul>
159 ${summary.issues.map(item => `<li>${item}</li>`).join('')}
160 </ul>
161 </div>
162
163 <div class="summary-section">
164 <h3>💡 Recommendations</h3>
165 <ul>
166 ${summary.recommendations.map(item => `<li>${item}</li>`).join('')}
167 </ul>
168 </div>
169
170 <div class="summary-section">
171 <h3>📈 Overall Sentiment</h3>
172 <p class="sentiment-text">${summary.overallSentiment}</p>
173 </div>
174 </div>
175 </div>
176 </div>
177 `;
178
179 // Add styles
180 const style = document.createElement('style');
181 style.textContent = `
182 #nps-summary-modal .modal-overlay {
183 position: fixed;
184 top: 0;
185 left: 0;
186 right: 0;
187 bottom: 0;
188 background: rgba(0, 0, 0, 0.7);
189 display: flex;
190 align-items: center;
191 justify-content: center;
192 z-index: 10001;
193 animation: fadeIn 0.3s ease;
194 }
195
196 #nps-summary-modal .modal-content {
197 background: white;
198 border-radius: 12px;
199 max-width: 800px;
200 max-height: 90vh;
201 width: 90%;
202 overflow: hidden;
203 box-shadow: 0 20px 60px rgba(0,0,0,0.3);
204 animation: slideUp 0.3s ease;
205 }
206
207 #nps-summary-modal .modal-header {
208 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
209 color: white;
210 padding: 20px 30px;
211 display: flex;
212 justify-content: space-between;
213 align-items: center;
214 }
215
216 #nps-summary-modal .modal-header h2 {
217 margin: 0;
218 font-size: 24px;
219 font-weight: 600;
220 }
221
222 #nps-summary-modal .close-btn {
223 background: rgba(255,255,255,0.2);
224 border: none;
225 color: white;
226 font-size: 24px;
227 width: 36px;
228 height: 36px;
229 border-radius: 50%;
230 cursor: pointer;
231 display: flex;
232 align-items: center;
233 justify-content: center;
234 transition: background 0.2s;
235 }
236
237 #nps-summary-modal .close-btn:hover {
238 background: rgba(255,255,255,0.3);
239 }
240
241 #nps-summary-modal .modal-body {
242 padding: 30px;
243 overflow-y: auto;
244 max-height: calc(90vh - 80px);
245 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
246 }
247
248 #nps-summary-modal .summary-section {
249 margin-bottom: 30px;
250 }
251
252 #nps-summary-modal .summary-section h3 {
253 color: #333;
254 font-size: 18px;
255 margin-bottom: 12px;
256 font-weight: 600;
257 }
258
259 #nps-summary-modal .summary-section ul {
260 list-style: none;
261 padding: 0;
262 margin: 0;
263 }
264
265 #nps-summary-modal .summary-section li {
266 background: #f8f9fa;
267 padding: 12px 16px;
268 margin-bottom: 8px;
269 border-radius: 6px;
270 border-left: 3px solid #667eea;
271 color: #333;
272 line-height: 1.5;
273 }
274
275 #nps-summary-modal .sentiment-text {
276 background: #f8f9fa;
277 padding: 16px;
278 border-radius: 6px;
279 color: #333;
280 line-height: 1.6;
281 margin: 0;
282 }
283
284 @keyframes fadeIn {
285 from { opacity: 0; }
286 to { opacity: 1; }
287 }
288
289 @keyframes slideUp {
290 from { transform: translateY(30px); opacity: 0; }
291 to { transform: translateY(0); opacity: 1; }
292 }
293 `;
294 document.head.appendChild(style);
295
296 document.body.appendChild(modal);
297
298 // Close modal handlers
299 document.getElementById('close-summary-modal').addEventListener('click', () => {
300 modal.remove();
301 });
302
303 modal.querySelector('.modal-overlay').addEventListener('click', (e) => {
304 if (e.target.classList.contains('modal-overlay')) {
305 modal.remove();
306 }
307 });
308 }
309
310 // Main function to summarize NPS chats
311 async function summarizeNPSChats() {
312 console.log('Starting NPS chat summarization...');
313
314 try {
315 showLoadingIndicator();
316
317 // Extract messages
318 const messages = extractMessages();
319
320 if (messages.length === 0) {
321 alert('No messages found in the current channel. Please make sure you are in the NPS channel.');
322 hideLoadingIndicator();
323 return;
324 }
325
326 console.log(`Analyzing ${messages.length} messages with AI...`);
327
328 // Prepare messages for AI analysis
329 const messagesText = messages.map((msg, idx) =>
330 `[${idx + 1}] ${msg.sender} (${msg.timestamp}): ${msg.text}`
331 ).join('\n\n');
332
333 // Call AI to analyze and summarize
334 const prompt = `You are analyzing NPS (Net Promoter Score) feedback from a Slack channel. Below are all the messages from the NPS channel. Please analyze them and provide a comprehensive summary.
335
336Messages:
337${messagesText}
338
339Please analyze these NPS chats and provide:
3401. Key themes that emerge from the feedback
3412. Positive feedback and what customers appreciate
3423. Issues and concerns raised by customers
3434. Actionable recommendations for improvement
3445. Overall sentiment analysis
345
346Focus on extracting actionable insights that can help improve the product/service.`;
347
348 const summary = await RM.aiCall(prompt, {
349 type: "json_schema",
350 json_schema: {
351 name: "nps_summary",
352 schema: {
353 type: "object",
354 properties: {
355 keyThemes: {
356 type: "array",
357 items: { type: "string" },
358 description: "Main themes identified in the NPS feedback"
359 },
360 positiveFeedback: {
361 type: "array",
362 items: { type: "string" },
363 description: "Positive aspects mentioned by customers"
364 },
365 issues: {
366 type: "array",
367 items: { type: "string" },
368 description: "Problems and concerns raised"
369 },
370 recommendations: {
371 type: "array",
372 items: { type: "string" },
373 description: "Actionable recommendations for improvement"
374 },
375 overallSentiment: {
376 type: "string",
377 description: "Overall sentiment analysis of the feedback"
378 }
379 },
380 required: ["keyThemes", "positiveFeedback", "issues", "recommendations", "overallSentiment"]
381 }
382 }
383 });
384
385 console.log('AI analysis complete:', summary);
386
387 hideLoadingIndicator();
388
389 // Display the summary
390 displaySummary(summary);
391
392 // Store the summary for future reference
393 await GM.setValue('last_nps_summary', JSON.stringify({
394 summary: summary,
395 timestamp: new Date().toISOString(),
396 messageCount: messages.length
397 }));
398
399 } catch (error) {
400 console.error('Error summarizing NPS chats:', error);
401 hideLoadingIndicator();
402 alert('Failed to summarize NPS chats. Error: ' + error.message);
403 }
404 }
405
406 // Create the summarize button
407 function createSummarizeButton() {
408 console.log('Creating summarize button...');
409
410 // Remove existing button if any
411 const existingButton = document.getElementById('nps-summarize-btn');
412 if (existingButton) {
413 existingButton.remove();
414 }
415
416 // Find the channel header to place the button
417 const channelHeader = document.querySelector('[data-qa="channel_header"]') ||
418 document.querySelector('.p-ia__view_header') ||
419 document.querySelector('.p-view_header');
420
421 if (!channelHeader) {
422 console.log('Channel header not found, will retry...');
423 return false;
424 }
425
426 const button = document.createElement('button');
427 button.id = 'nps-summarize-btn';
428 button.innerHTML = '📊 Summarize NPS Chats';
429 button.style.cssText = `
430 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
431 color: white;
432 border: none;
433 padding: 8px 16px;
434 border-radius: 6px;
435 font-size: 14px;
436 font-weight: 600;
437 cursor: pointer;
438 margin-left: 12px;
439 transition: transform 0.2s, box-shadow 0.2s;
440 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
441 box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
442 `;
443
444 button.addEventListener('mouseenter', () => {
445 button.style.transform = 'translateY(-2px)';
446 button.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.4)';
447 });
448
449 button.addEventListener('mouseleave', () => {
450 button.style.transform = 'translateY(0)';
451 button.style.boxShadow = '0 2px 8px rgba(102, 126, 234, 0.3)';
452 });
453
454 button.addEventListener('click', summarizeNPSChats);
455
456 // Insert the button into the header
457 const headerActions = channelHeader.querySelector('.p-ia__view_header__actions') ||
458 channelHeader.querySelector('[data-qa="channel_header_actions"]') ||
459 channelHeader;
460
461 headerActions.appendChild(button);
462 console.log('Summarize button created successfully');
463 return true;
464 }
465
466 // Initialize the extension
467 function init() {
468 console.log('Initializing NPS Chat Summarizer...');
469
470 // Wait for the page to be fully loaded
471 if (document.readyState === 'loading') {
472 document.addEventListener('DOMContentLoaded', init);
473 return;
474 }
475
476 // Try to create the button
477 const buttonCreated = createSummarizeButton();
478
479 if (!buttonCreated) {
480 // If button creation failed, retry after a delay
481 setTimeout(init, 2000);
482 return;
483 }
484
485 // Watch for navigation changes in Slack (SPA)
486 const observer = new MutationObserver(debounce(() => {
487 const existingButton = document.getElementById('nps-summarize-btn');
488 if (!existingButton) {
489 console.log('Button disappeared, recreating...');
490 createSummarizeButton();
491 }
492 }, 1000));
493
494 observer.observe(document.body, {
495 childList: true,
496 subtree: true
497 });
498
499 console.log('NPS Chat Summarizer initialized successfully');
500 }
501
502 // Start the extension
503 init();
504})();