QPS Content Summarizer

Summarize QPS page content with AI-powered analysis

Size

12.2 KB

Version

1.0.1

Created

Oct 23, 2025

Updated

22 days ago

1// ==UserScript==
2// @name		QPS Content Summarizer
3// @description		Summarize QPS page content with AI-powered analysis
4// @version		1.0.1
5// @match		https://*.webcms.qps.cnhind.com/*
6// @icon		https://webcms.qps.cnhind.com/PublishingImages/favicon.ico
7// @grant		GM.getValue
8// @grant		GM.setValue
9// @grant		GM.xmlhttpRequest
10// ==/UserScript==
11(function() {
12    'use strict';
13
14    console.log('QPS Content Summarizer initialized');
15
16    // Debounce function to prevent multiple rapid calls
17    function debounce(func, wait) {
18        let timeout;
19        return function executedFunction(...args) {
20            const later = () => {
21                clearTimeout(timeout);
22                func(...args);
23            };
24            clearTimeout(timeout);
25            timeout = setTimeout(later, wait);
26        };
27    }
28
29    // Create the summarizer button
30    function createSummarizerButton() {
31        const button = document.createElement('button');
32        button.id = 'qps-summarizer-btn';
33        button.innerHTML = `
34            <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" style="margin-right: 5px;">
35                <path d="M2 3h12v2H2V3zm0 4h12v2H2V7zm0 4h8v2H2v-2z"/>
36            </svg>
37            Summarize Page
38        `;
39        button.style.cssText = `
40            position: fixed;
41            top: 80px;
42            right: 20px;
43            z-index: 10000;
44            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
45            color: white;
46            border: none;
47            padding: 12px 20px;
48            border-radius: 8px;
49            cursor: pointer;
50            font-size: 14px;
51            font-weight: 600;
52            box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
53            display: flex;
54            align-items: center;
55            transition: all 0.3s ease;
56            font-family: Arial, sans-serif;
57        `;
58
59        button.addEventListener('mouseenter', () => {
60            button.style.transform = 'translateY(-2px)';
61            button.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
62        });
63
64        button.addEventListener('mouseleave', () => {
65            button.style.transform = 'translateY(0)';
66            button.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)';
67        });
68
69        button.addEventListener('click', handleSummarize);
70        document.body.appendChild(button);
71        console.log('Summarizer button created');
72    }
73
74    // Extract page content
75    function extractPageContent() {
76        console.log('Extracting page content...');
77        
78        const content = {
79            title: document.title,
80            url: window.location.href,
81            mainContent: ''
82        };
83
84        // Extract main content from various sections
85        const contentSelectors = [
86            '#page-content',
87            'article.block-news',
88            '.block-content',
89            '.text',
90            'section.row p',
91            'section.row h1',
92            'section.row h2',
93            'section.row h3',
94            '.news-content'
95        ];
96
97        let extractedText = '';
98        contentSelectors.forEach(selector => {
99            const elements = document.querySelectorAll(selector);
100            elements.forEach(el => {
101                const text = el.textContent.trim();
102                if (text && text.length > 20) {
103                    extractedText += text + '\n\n';
104                }
105            });
106        });
107
108        // If no content found, get all visible text
109        if (extractedText.length < 100) {
110            const bodyText = document.body.innerText;
111            extractedText = bodyText.substring(0, 5000);
112        }
113
114        content.mainContent = extractedText.substring(0, 8000); // Limit content size
115        console.log('Content extracted, length:', content.mainContent.length);
116        return content;
117    }
118
119    // Show loading indicator
120    function showLoadingIndicator() {
121        const existing = document.getElementById('qps-summarizer-loading');
122        if (existing) existing.remove();
123
124        const loader = document.createElement('div');
125        loader.id = 'qps-summarizer-loading';
126        loader.innerHTML = `
127            <div style="display: flex; align-items: center; gap: 10px;">
128                <div class="spinner"></div>
129                <span>AI is analyzing the page...</span>
130            </div>
131        `;
132        loader.style.cssText = `
133            position: fixed;
134            top: 140px;
135            right: 20px;
136            z-index: 10001;
137            background: white;
138            color: #333;
139            padding: 15px 20px;
140            border-radius: 8px;
141            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
142            font-size: 14px;
143            font-family: Arial, sans-serif;
144        `;
145
146        // Add spinner styles
147        const style = document.createElement('style');
148        style.textContent = `
149            .spinner {
150                width: 20px;
151                height: 20px;
152                border: 3px solid #f3f3f3;
153                border-top: 3px solid #667eea;
154                border-radius: 50%;
155                animation: spin 1s linear infinite;
156            }
157            @keyframes spin {
158                0% { transform: rotate(0deg); }
159                100% { transform: rotate(360deg); }
160            }
161        `;
162        document.head.appendChild(style);
163
164        document.body.appendChild(loader);
165        console.log('Loading indicator shown');
166    }
167
168    // Hide loading indicator
169    function hideLoadingIndicator() {
170        const loader = document.getElementById('qps-summarizer-loading');
171        if (loader) {
172            loader.remove();
173            console.log('Loading indicator hidden');
174        }
175    }
176
177    // Display summary
178    function displaySummary(summary) {
179        console.log('Displaying summary...');
180        
181        // Remove existing summary
182        const existing = document.getElementById('qps-summary-panel');
183        if (existing) existing.remove();
184
185        const panel = document.createElement('div');
186        panel.id = 'qps-summary-panel';
187        panel.innerHTML = `
188            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
189                <h3 style="margin: 0; color: #667eea; font-size: 18px; font-weight: 600;">
190                    📝 Page Summary
191                </h3>
192                <button id="qps-summary-close" style="background: none; border: none; font-size: 24px; cursor: pointer; color: #999; padding: 0; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;">×</button>
193            </div>
194            <div style="color: #333; line-height: 1.6; font-size: 14px;">
195                ${summary.summary ? `<div style="margin-bottom: 15px;"><strong style="color: #667eea;">Overview:</strong><br>${summary.summary}</div>` : ''}
196                ${summary.keyPoints && summary.keyPoints.length > 0 ? `
197                    <div style="margin-bottom: 15px;">
198                        <strong style="color: #667eea;">Key Points:</strong>
199                        <ul style="margin: 8px 0; padding-left: 20px;">
200                            ${summary.keyPoints.map(point => `<li style="margin: 5px 0;">${point}</li>`).join('')}
201                        </ul>
202                    </div>
203                ` : ''}
204                ${summary.actionItems && summary.actionItems.length > 0 ? `
205                    <div>
206                        <strong style="color: #667eea;">Action Items:</strong>
207                        <ul style="margin: 8px 0; padding-left: 20px;">
208                            ${summary.actionItems.map(item => `<li style="margin: 5px 0;">${item}</li>`).join('')}
209                        </ul>
210                    </div>
211                ` : ''}
212            </div>
213        `;
214        panel.style.cssText = `
215            position: fixed;
216            top: 140px;
217            right: 20px;
218            z-index: 10001;
219            background: white;
220            padding: 20px;
221            border-radius: 12px;
222            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
223            max-width: 450px;
224            max-height: 70vh;
225            overflow-y: auto;
226            font-family: Arial, sans-serif;
227            border: 2px solid #667eea;
228        `;
229
230        document.body.appendChild(panel);
231
232        // Add close button handler
233        document.getElementById('qps-summary-close').addEventListener('click', () => {
234            panel.remove();
235        });
236
237        console.log('Summary panel displayed');
238    }
239
240    // Handle summarize action
241    async function handleSummarize() {
242        console.log('Summarize button clicked');
243        
244        try {
245            showLoadingIndicator();
246
247            // Extract content
248            const pageContent = extractPageContent();
249            console.log('Page content:', pageContent);
250
251            // Check cache
252            const cacheKey = 'qps_summary_' + btoa(window.location.href).slice(0, 30);
253            let summary = await GM.getValue(cacheKey);
254
255            if (summary) {
256                console.log('Using cached summary');
257                summary = JSON.parse(summary);
258            } else {
259                console.log('Calling AI for new summary');
260                
261                // Call AI API
262                const prompt = `Analyze and summarize the following QPS (Quality Process System) page content. Provide a clear, concise summary with key points and any action items.
263
264Page Title: ${pageContent.title}
265URL: ${pageContent.url}
266
267Content:
268${pageContent.mainContent}
269
270Please provide a structured summary.`;
271
272                summary = await RM.aiCall(prompt, {
273                    type: "json_schema",
274                    json_schema: {
275                        name: "page_summary",
276                        schema: {
277                            type: "object",
278                            properties: {
279                                summary: { 
280                                    type: "string",
281                                    description: "A brief 2-3 sentence overview of the page content"
282                                },
283                                keyPoints: { 
284                                    type: "array",
285                                    items: { type: "string" },
286                                    description: "3-5 key points or important information from the page"
287                                },
288                                actionItems: { 
289                                    type: "array",
290                                    items: { type: "string" },
291                                    description: "Any action items, tasks, or next steps mentioned"
292                                }
293                            },
294                            required: ["summary", "keyPoints"]
295                        }
296                    }
297                });
298
299                console.log('AI response received:', summary);
300
301                // Cache the summary for 1 hour
302                await GM.setValue(cacheKey, JSON.stringify(summary));
303            }
304
305            hideLoadingIndicator();
306            displaySummary(summary);
307
308        } catch (error) {
309            console.error('Error generating summary:', error);
310            hideLoadingIndicator();
311            
312            // Show error message
313            const errorPanel = document.createElement('div');
314            errorPanel.style.cssText = `
315                position: fixed;
316                top: 140px;
317                right: 20px;
318                z-index: 10001;
319                background: #ff4444;
320                color: white;
321                padding: 15px 20px;
322                border-radius: 8px;
323                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
324                font-size: 14px;
325                font-family: Arial, sans-serif;
326            `;
327            errorPanel.textContent = 'Failed to generate summary. Please try again.';
328            document.body.appendChild(errorPanel);
329            
330            setTimeout(() => errorPanel.remove(), 5000);
331        }
332    }
333
334    // Initialize the extension
335    function init() {
336        console.log('Initializing QPS Content Summarizer...');
337        
338        // Wait for page to be fully loaded
339        if (document.readyState === 'loading') {
340            document.addEventListener('DOMContentLoaded', createSummarizerButton);
341        } else {
342            createSummarizerButton();
343        }
344    }
345
346    // Start the extension
347    init();
348
349})();
QPS Content Summarizer | Robomonkey