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})();