AI Content Detector for Google Docs

Detects and highlights AI-generated phrases in Google Docs

Size

10.7 KB

Version

1.0.1

Created

Dec 16, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		AI Content Detector for Google Docs
3// @description		Detects and highlights AI-generated phrases in Google Docs
4// @version		1.0.1
5// @match		https://*.docs.google.com/*
6// @icon		https://ssl.gstatic.com/docs/documents/images/kix-favicon-2023q4.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    // Common AI-generated phrases to detect
12    const AI_PHRASES = [
13        // Common AI transitions and connectors
14        'in conclusion',
15        'in summary',
16        'to summarize',
17        'it is important to note',
18        'it is worth noting',
19        'it should be noted',
20        'it is essential to',
21        'it is crucial to',
22        'it is vital to',
23        'furthermore',
24        'moreover',
25        'additionally',
26        'consequently',
27        'therefore',
28        'thus',
29        'hence',
30        'accordingly',
31        'as a result',
32        'in light of',
33        'with that being said',
34        'that being said',
35        'having said that',
36        
37        // AI-style qualifiers
38        'delve into',
39        'delve deeper',
40        'dive into',
41        'dive deeper',
42        'explore the nuances',
43        'multifaceted',
44        'intricate',
45        'complex interplay',
46        'myriad of',
47        'plethora of',
48        'a testament to',
49        'underscores the importance',
50        'underscores the need',
51        'paramount importance',
52        'of utmost importance',
53        
54        // Formal/robotic phrases
55        'in today\'s digital age',
56        'in today\'s world',
57        'in the modern era',
58        'in this day and age',
59        'it goes without saying',
60        'needless to say',
61        'suffice it to say',
62        'rest assured',
63        'bear in mind',
64        'take into consideration',
65        'take into account',
66        
67        // AI hedging language
68        'it can be argued',
69        'one could argue',
70        'some may argue',
71        'arguably',
72        'to a certain extent',
73        'to some degree',
74        'in many ways',
75        'in various ways',
76        'in numerous ways',
77        
78        // Overly formal conclusions
79        'in the final analysis',
80        'all things considered',
81        'when all is said and done',
82        'at the end of the day',
83        'in the grand scheme',
84        'on a broader scale',
85        
86        // AI enthusiasm markers
87        'exciting opportunity',
88        'exciting possibilities',
89        'game-changing',
90        'revolutionary approach',
91        'cutting-edge',
92        'state-of-the-art',
93        'ever-evolving',
94        'ever-changing',
95        'rapidly evolving',
96        'constantly evolving',
97        
98        // Redundant AI phrases
99        'absolutely essential',
100        'completely unique',
101        'very unique',
102        'quite literally',
103        'literally speaking',
104        'basically',
105        'essentially',
106        'fundamentally',
107        
108        // AI list starters
109        'first and foremost',
110        'last but not least',
111        'it\'s important to remember',
112        'keep in mind that',
113        'don\'t forget that',
114        
115        // Overly descriptive
116        'comprehensive guide',
117        'ultimate guide',
118        'complete guide',
119        'in-depth analysis',
120        'thorough examination',
121        'detailed exploration',
122        
123        // AI empathy attempts
124        'it\'s understandable',
125        'understandably so',
126        'it makes sense',
127        'rightfully so',
128        
129        // Generic AI conclusions
130        'the bottom line',
131        'the key takeaway',
132        'the main point',
133        'what this means',
134        'what this tells us'
135    ];
136
137    // Debounce function to avoid excessive processing
138    function debounce(func, wait) {
139        let timeout;
140        return function executedFunction(...args) {
141            const later = () => {
142                clearTimeout(timeout);
143                func(...args);
144            };
145            clearTimeout(timeout);
146            timeout = setTimeout(later, wait);
147        };
148    }
149
150    // Function to detect AI phrases in text
151    function detectAIPhrases(text) {
152        const detectedPhrases = [];
153        const lowerText = text.toLowerCase();
154        
155        AI_PHRASES.forEach(phrase => {
156            const regex = new RegExp('\\b' + phrase.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\b', 'gi');
157            let match;
158            while ((match = regex.exec(text)) !== null) {
159                detectedPhrases.push({
160                    phrase: match[0],
161                    index: match.index,
162                    length: match[0].length
163                });
164            }
165        });
166        
167        return detectedPhrases;
168    }
169
170    // Function to highlight AI phrases in Google Docs
171    function highlightAIPhrases() {
172        console.log('AI Content Detector: Scanning document for AI phrases...');
173        
174        // Get the document canvas
175        const canvas = document.querySelector('.kix-canvas-tile-content');
176        if (!canvas) {
177            console.log('AI Content Detector: Document canvas not found yet');
178            return;
179        }
180
181        // Get all text spans in the document
182        const textSpans = document.querySelectorAll('.kix-wordhtmlgenerator-word-node, span[role="presentation"]');
183        
184        if (textSpans.length === 0) {
185            console.log('AI Content Detector: No text spans found in document');
186            return;
187        }
188
189        let detectedCount = 0;
190        
191        // Process each text span
192        textSpans.forEach(span => {
193            const text = span.textContent;
194            if (!text || text.trim().length === 0) return;
195            
196            const detectedPhrases = detectAIPhrases(text);
197            
198            if (detectedPhrases.length > 0) {
199                detectedCount += detectedPhrases.length;
200                
201                // Add visual indicator (background highlight)
202                if (!span.classList.contains('ai-phrase-detected')) {
203                    span.classList.add('ai-phrase-detected');
204                    span.style.backgroundColor = '#ffeb3b';
205                    span.style.borderBottom = '2px solid #ff9800';
206                    span.title = `AI phrase detected: "${detectedPhrases[0].phrase}"`;
207                    
208                    console.log(`AI Content Detector: Found "${detectedPhrases[0].phrase}" in text`);
209                }
210            }
211        });
212
213        if (detectedCount > 0) {
214            console.log(`AI Content Detector: Found ${detectedCount} AI phrases in document`);
215            showDetectionSummary(detectedCount);
216        } else {
217            console.log('AI Content Detector: No AI phrases detected');
218        }
219    }
220
221    // Show detection summary banner
222    function showDetectionSummary(count) {
223        // Remove existing banner if present
224        const existingBanner = document.getElementById('ai-detector-banner');
225        if (existingBanner) {
226            existingBanner.remove();
227        }
228
229        // Create banner
230        const banner = document.createElement('div');
231        banner.id = 'ai-detector-banner';
232        banner.style.cssText = `
233            position: fixed;
234            top: 60px;
235            right: 20px;
236            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
237            color: white;
238            padding: 15px 20px;
239            border-radius: 8px;
240            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
241            z-index: 10000;
242            font-family: 'Google Sans', Arial, sans-serif;
243            font-size: 14px;
244            font-weight: 500;
245            display: flex;
246            align-items: center;
247            gap: 10px;
248            animation: slideIn 0.3s ease-out;
249        `;
250        
251        banner.innerHTML = `
252            <span style="font-size: 20px;">⚠️</span>
253            <span><strong>${count}</strong> AI phrase${count > 1 ? 's' : ''} detected</span>
254            <button id="ai-detector-close" style="
255                background: rgba(255,255,255,0.2);
256                border: none;
257                color: white;
258                padding: 5px 10px;
259                border-radius: 4px;
260                cursor: pointer;
261                margin-left: 10px;
262                font-size: 12px;
263            "></button>
264        `;
265        
266        document.body.appendChild(banner);
267        
268        // Add close button functionality
269        document.getElementById('ai-detector-close').addEventListener('click', () => {
270            banner.remove();
271        });
272        
273        // Auto-hide after 10 seconds
274        setTimeout(() => {
275            if (banner.parentElement) {
276                banner.style.animation = 'slideOut 0.3s ease-out';
277                setTimeout(() => banner.remove(), 300);
278            }
279        }, 10000);
280    }
281
282    // Add CSS animations
283    TM_addStyle(`
284        @keyframes slideIn {
285            from {
286                transform: translateX(400px);
287                opacity: 0;
288            }
289            to {
290                transform: translateX(0);
291                opacity: 1;
292            }
293        }
294        
295        @keyframes slideOut {
296            from {
297                transform: translateX(0);
298                opacity: 1;
299            }
300            to {
301                transform: translateX(400px);
302                opacity: 0;
303            }
304        }
305        
306        .ai-phrase-detected {
307            position: relative;
308            transition: all 0.2s ease;
309        }
310        
311        .ai-phrase-detected:hover {
312            background-color: #ffd54f !important;
313        }
314    `);
315
316    // Debounced version of highlight function
317    const debouncedHighlight = debounce(highlightAIPhrases, 1000);
318
319    // Initialize the detector
320    function init() {
321        console.log('AI Content Detector: Extension loaded');
322        
323        // Wait for document to be ready
324        TM_runBody(() => {
325            console.log('AI Content Detector: Document body ready');
326            
327            // Initial scan after a delay to ensure content is loaded
328            setTimeout(highlightAIPhrases, 3000);
329            
330            // Watch for changes in the document
331            const observer = new MutationObserver(debouncedHighlight);
332            
333            // Observe the document editor
334            const editorContainer = document.querySelector('#docs-editor');
335            if (editorContainer) {
336                observer.observe(editorContainer, {
337                    childList: true,
338                    subtree: true,
339                    characterData: true
340                });
341                console.log('AI Content Detector: Monitoring document for changes');
342            } else {
343                console.log('AI Content Detector: Editor container not found, will retry');
344                // Retry after a delay
345                setTimeout(init, 2000);
346            }
347        });
348    }
349
350    // Start the extension
351    init();
352})();
AI Content Detector for Google Docs | Robomonkey