Analyzes terms and conditions with AI to highlight important clauses and potential concerns
Size
16.2 KB
Version
1.0.1
Created
Feb 18, 2026
Updated
19 days ago
1// ==UserScript==
2// @name Terms & Conditions AI Analyzer
3// @description Analyzes terms and conditions with AI to highlight important clauses and potential concerns
4// @version 1.0.1
5// @match https://*.robomonkey.io/*
6// @icon https://robomonkey.io/favicon.ico
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Terms & Conditions AI Analyzer loaded');
12
13 // Debounce function for performance
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 // Create the analyze button
27 function createAnalyzeButton() {
28 const button = document.createElement('button');
29 button.id = 'tc-analyzer-button';
30 button.innerHTML = '🔍 Analyze T&C';
31 button.style.cssText = `
32 position: fixed;
33 bottom: 20px;
34 right: 20px;
35 z-index: 999999;
36 padding: 12px 20px;
37 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38 color: white;
39 border: none;
40 border-radius: 25px;
41 font-size: 14px;
42 font-weight: 600;
43 cursor: pointer;
44 box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
45 transition: all 0.3s ease;
46 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
47 `;
48
49 button.addEventListener('mouseenter', () => {
50 button.style.transform = 'translateY(-2px)';
51 button.style.boxShadow = '0 6px 20px rgba(102, 126, 234, 0.6)';
52 });
53
54 button.addEventListener('mouseleave', () => {
55 button.style.transform = 'translateY(0)';
56 button.style.boxShadow = '0 4px 15px rgba(102, 126, 234, 0.4)';
57 });
58
59 button.addEventListener('click', handleAnalyzeClick);
60 document.body.appendChild(button);
61 console.log('Analyze button created');
62 }
63
64 // Extract text content from the page
65 function extractPageContent() {
66 console.log('Extracting page content...');
67
68 // Try to find common T&C containers
69 const selectors = [
70 'article',
71 '[class*="terms"]',
72 '[class*="conditions"]',
73 '[class*="legal"]',
74 '[class*="policy"]',
75 '[id*="terms"]',
76 '[id*="conditions"]',
77 'main',
78 '.content',
79 '#content'
80 ];
81
82 let content = '';
83
84 for (const selector of selectors) {
85 const element = document.querySelector(selector);
86 if (element && element.textContent.length > 500) {
87 content = element.textContent;
88 console.log(`Found content using selector: ${selector}`);
89 break;
90 }
91 }
92
93 // Fallback to body content
94 if (!content || content.length < 500) {
95 content = document.body.textContent;
96 console.log('Using body content as fallback');
97 }
98
99 // Clean up the content
100 content = content
101 .replace(/\s+/g, ' ')
102 .replace(/\n+/g, '\n')
103 .trim();
104
105 // Limit content length to avoid token limits (approximately 15000 characters)
106 if (content.length > 15000) {
107 content = content.substring(0, 15000) + '...';
108 console.log('Content truncated to 15000 characters');
109 }
110
111 console.log(`Extracted ${content.length} characters`);
112 return content;
113 }
114
115 // Show loading indicator
116 function showLoadingIndicator() {
117 const loader = document.createElement('div');
118 loader.id = 'tc-analyzer-loader';
119 loader.innerHTML = `
120 <div style="display: flex; flex-direction: column; align-items: center; gap: 15px;">
121 <div class="spinner"></div>
122 <div style="font-size: 16px; font-weight: 500;">Analyzing Terms & Conditions...</div>
123 <div style="font-size: 13px; color: #888;">This may take a moment</div>
124 </div>
125 `;
126 loader.style.cssText = `
127 position: fixed;
128 top: 50%;
129 left: 50%;
130 transform: translate(-50%, -50%);
131 background: white;
132 padding: 40px;
133 border-radius: 15px;
134 box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
135 z-index: 1000000;
136 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
137 text-align: center;
138 `;
139
140 document.body.appendChild(loader);
141
142 // Add spinner styles
143 const style = document.createElement('style');
144 style.textContent = `
145 .spinner {
146 width: 50px;
147 height: 50px;
148 border: 4px solid #f3f3f3;
149 border-top: 4px solid #667eea;
150 border-radius: 50%;
151 animation: spin 1s linear infinite;
152 }
153
154 @keyframes spin {
155 0% { transform: rotate(0deg); }
156 100% { transform: rotate(360deg); }
157 }
158 `;
159 document.head.appendChild(style);
160 }
161
162 // Hide loading indicator
163 function hideLoadingIndicator() {
164 const loader = document.getElementById('tc-analyzer-loader');
165 if (loader) {
166 loader.remove();
167 }
168 }
169
170 // Analyze content with AI
171 async function analyzeWithAI(content) {
172 console.log('Sending content to AI for analysis...');
173
174 const prompt = `Analyze the following terms and conditions text and identify the most important points users should be aware of. Focus on:
1751. Data collection and privacy concerns
1762. User rights and restrictions
1773. Payment and refund policies
1784. Liability limitations
1795. Account termination clauses
1806. Any unusual or concerning clauses
181
182Terms and Conditions Text:
183${content}
184
185Please provide a comprehensive analysis.`;
186
187 try {
188 const analysis = await RM.aiCall(prompt, {
189 type: "json_schema",
190 json_schema: {
191 name: "tc_analysis",
192 schema: {
193 type: "object",
194 properties: {
195 summary: {
196 type: "string",
197 description: "Brief overall summary of the T&C"
198 },
199 keyPoints: {
200 type: "array",
201 items: {
202 type: "object",
203 properties: {
204 category: {
205 type: "string",
206 enum: ["Privacy", "Rights", "Payment", "Liability", "Termination", "Other"]
207 },
208 title: {
209 type: "string"
210 },
211 description: {
212 type: "string"
213 },
214 severity: {
215 type: "string",
216 enum: ["high", "medium", "low"]
217 }
218 },
219 required: ["category", "title", "description", "severity"]
220 }
221 },
222 redFlags: {
223 type: "array",
224 items: {
225 type: "string"
226 }
227 },
228 recommendation: {
229 type: "string",
230 description: "Overall recommendation (accept, review carefully, or avoid)"
231 }
232 },
233 required: ["summary", "keyPoints", "redFlags", "recommendation"]
234 }
235 }
236 });
237
238 console.log('AI analysis completed successfully');
239 return analysis;
240 } catch (error) {
241 console.error('AI analysis failed:', error);
242 throw error;
243 }
244 }
245
246 // Display analysis results
247 function displayResults(analysis) {
248 console.log('Displaying analysis results');
249
250 // Remove existing panel if any
251 const existingPanel = document.getElementById('tc-analyzer-panel');
252 if (existingPanel) {
253 existingPanel.remove();
254 }
255
256 const panel = document.createElement('div');
257 panel.id = 'tc-analyzer-panel';
258 panel.style.cssText = `
259 position: fixed;
260 top: 50%;
261 left: 50%;
262 transform: translate(-50%, -50%);
263 width: 90%;
264 max-width: 700px;
265 max-height: 85vh;
266 background: white;
267 border-radius: 15px;
268 box-shadow: 0 10px 50px rgba(0, 0, 0, 0.3);
269 z-index: 1000001;
270 overflow: hidden;
271 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
272 display: flex;
273 flex-direction: column;
274 `;
275
276 // Create overlay
277 const overlay = document.createElement('div');
278 overlay.id = 'tc-analyzer-overlay';
279 overlay.style.cssText = `
280 position: fixed;
281 top: 0;
282 left: 0;
283 width: 100%;
284 height: 100%;
285 background: rgba(0, 0, 0, 0.5);
286 z-index: 1000000;
287 `;
288 overlay.addEventListener('click', () => {
289 panel.remove();
290 overlay.remove();
291 });
292
293 // Severity colors
294 const severityColors = {
295 high: '#ef4444',
296 medium: '#f59e0b',
297 low: '#10b981'
298 };
299
300 // Build content
301 let keyPointsHTML = '';
302 analysis.keyPoints.forEach(point => {
303 const color = severityColors[point.severity];
304 keyPointsHTML += `
305 <div style="background: #f9fafb; padding: 15px; border-radius: 10px; margin-bottom: 12px; border-left: 4px solid ${color};">
306 <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 8px;">
307 <div style="font-weight: 600; font-size: 15px; color: #111;">${point.title}</div>
308 <span style="background: ${color}; color: white; padding: 3px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; text-transform: uppercase;">${point.category}</span>
309 </div>
310 <div style="color: #555; font-size: 14px; line-height: 1.5;">${point.description}</div>
311 </div>
312 `;
313 });
314
315 let redFlagsHTML = '';
316 if (analysis.redFlags && analysis.redFlags.length > 0) {
317 redFlagsHTML = `
318 <div style="background: #fef2f2; padding: 15px; border-radius: 10px; border-left: 4px solid #ef4444; margin-bottom: 20px;">
319 <div style="font-weight: 600; font-size: 15px; color: #dc2626; margin-bottom: 10px;">⚠️ Red Flags</div>
320 <ul style="margin: 0; padding-left: 20px; color: #555;">
321 ${analysis.redFlags.map(flag => `<li style="margin-bottom: 5px;">${flag}</li>`).join('')}
322 </ul>
323 </div>
324 `;
325 }
326
327 panel.innerHTML = `
328 <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; color: white;">
329 <div style="display: flex; justify-content: space-between; align-items: center;">
330 <h2 style="margin: 0; font-size: 22px; font-weight: 700;">T&C Analysis Results</h2>
331 <button id="tc-close-btn" style="background: rgba(255,255,255,0.2); border: none; color: white; width: 32px; height: 32px; border-radius: 50%; cursor: pointer; font-size: 20px; display: flex; align-items: center; justify-content: center; transition: background 0.2s;">×</button>
332 </div>
333 </div>
334
335 <div style="padding: 25px; overflow-y: auto; flex: 1;">
336 <div style="background: #f0f9ff; padding: 15px; border-radius: 10px; margin-bottom: 20px; border-left: 4px solid #3b82f6;">
337 <div style="font-weight: 600; font-size: 15px; color: #1e40af; margin-bottom: 8px;">Summary</div>
338 <div style="color: #555; font-size: 14px; line-height: 1.6;">${analysis.summary}</div>
339 </div>
340
341 ${redFlagsHTML}
342
343 <div style="margin-bottom: 15px;">
344 <h3 style="font-size: 17px; font-weight: 600; color: #111; margin-bottom: 15px;">Key Points to Review</h3>
345 ${keyPointsHTML}
346 </div>
347
348 <div style="background: #f9fafb; padding: 15px; border-radius: 10px; border-left: 4px solid #8b5cf6;">
349 <div style="font-weight: 600; font-size: 15px; color: #6d28d9; margin-bottom: 8px;">💡 Recommendation</div>
350 <div style="color: #555; font-size: 14px; line-height: 1.6;">${analysis.recommendation}</div>
351 </div>
352 </div>
353 `;
354
355 document.body.appendChild(overlay);
356 document.body.appendChild(panel);
357
358 // Close button handler
359 document.getElementById('tc-close-btn').addEventListener('click', () => {
360 panel.remove();
361 overlay.remove();
362 });
363
364 // Hover effect for close button
365 const closeBtn = document.getElementById('tc-close-btn');
366 closeBtn.addEventListener('mouseenter', () => {
367 closeBtn.style.background = 'rgba(255,255,255,0.3)';
368 });
369 closeBtn.addEventListener('mouseleave', () => {
370 closeBtn.style.background = 'rgba(255,255,255,0.2)';
371 });
372 }
373
374 // Handle analyze button click
375 async function handleAnalyzeClick() {
376 console.log('Analyze button clicked');
377
378 try {
379 showLoadingIndicator();
380
381 // Extract content
382 const content = extractPageContent();
383
384 if (!content || content.length < 100) {
385 hideLoadingIndicator();
386 alert('Could not find enough text content to analyze. Please make sure you are on a page with terms and conditions.');
387 return;
388 }
389
390 // Analyze with AI
391 const analysis = await analyzeWithAI(content);
392
393 hideLoadingIndicator();
394
395 // Display results
396 displayResults(analysis);
397
398 } catch (error) {
399 console.error('Error during analysis:', error);
400 hideLoadingIndicator();
401 alert('An error occurred while analyzing the terms and conditions. Please try again.');
402 }
403 }
404
405 // Initialize the extension
406 function init() {
407 console.log('Initializing Terms & Conditions AI Analyzer');
408
409 // Wait for body to be ready
410 if (document.body) {
411 createAnalyzeButton();
412 } else {
413 const observer = new MutationObserver((mutations, obs) => {
414 if (document.body) {
415 createAnalyzeButton();
416 obs.disconnect();
417 }
418 });
419 observer.observe(document.documentElement, { childList: true, subtree: true });
420 }
421 }
422
423 // Start the extension
424 if (document.readyState === 'loading') {
425 document.addEventListener('DOMContentLoaded', init);
426 } else {
427 init();
428 }
429
430})();