Terms & Conditions AI Analyzer

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