Apex Learning Quiz Cheat

Highlights Correct Answers in Apex Learning Quiz Menus. Includes Image Support, AI Logic, Auto-Complete, and Keybind Controls

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Apex Learning Quiz Cheat
// @namespace    https://github.com/paysonism
// @version      8.3
// @description  Highlights Correct Answers in Apex Learning Quiz Menus. Includes Image Support, AI Logic, Auto-Complete, and Keybind Controls
// @author       paysonism
// @match        https://course.apexlearning.com/public/activity/*
// @match        https://*.apexvs.com/public/activity/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      generativelanguage.googleapis.com
// @run-at       document-end
// @license      MIT
// ==/UserScript==

//      ====================================================
//     |  Keybinds - MENU WILL SHOW FOR 1S ON CHANGE        |
//     |  Ctrl+Shift+E - Toggle Enable/Disable Script       |
//     |  Ctrl+Shift+A - Toggle Auto-Complete Mode          |
//     |  Ctrl+Shift+R - Manual Reprocess Current Question  |
//      ====================================================

(function() {
    'use strict';

    // CONFIGURATION - MUST ADD API KEY!
    // ============================================
    const GEMINI_API_KEY = 'YOUR_API_KEY_HERE'; // Get a free key from: https://aistudio.google.com/app/apikey
    const DEBUG_MODE = false; // Set to true for console logging

    const MAX_IMAGE_WIDTH = 800;
    const MAX_IMAGE_HEIGHT = 800;
    const IMAGE_QUALITY = 0.85;

    // Auto Complete Delay Settings
    const AUTO_SELECT_DELAY = 500; // Delay before auto-selecting answer (ms)
    const AUTO_SUBMIT_DELAY = 1000; // Delay before auto-submitting (ms)
    const NEXT_QUESTION_DELAY = 1000; // Delay before clicking next question (ms)
    const VIEW_SUMMARY_DELAY = 500; // Delay before clicking view summary (ms)

    let lastQuestionText = '';
    let isProcessing = false;
    let progressInterval = null;
    let isEnabled = GM_getValue('scriptEnabled', true);
    let autoCompleteEnabled = GM_getValue('autoCompleteEnabled', false);
    let notificationTimeout = null;

    function log(...args) {
        if (DEBUG_MODE) {
            console.log(...args);
        }
    }

    function logError(...args) {
        if (DEBUG_MODE) {
            console.error(...args);
        }
    }

    // Show glassmorphism notification
    function showNotification(message, duration = 2000) {
        // Remove existing notification
        const existing = document.getElementById('apex-notification');
        if (existing) {
            existing.remove();
        }

        const notification = document.createElement('div');
        notification.id = 'apex-notification';
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(255, 255, 255, 0.15);
            backdrop-filter: blur(20px);
            -webkit-backdrop-filter: blur(20px);
            border: 1px solid rgba(255, 255, 255, 0.25);
            color: white;
            padding: 20px 25px;
            border-radius: 16px;
            z-index: 999999;
            font-family: 'Bahnschrift', 'Segoe UI', Tahoma, sans-serif;
            font-size: 15px;
            font-weight: 300;
            letter-spacing: 0.5px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
            animation: slideIn 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
            min-width: 200px;
        `;

        notification.innerHTML = `
            <style>
                @keyframes slideIn {
                    from {
                        transform: translateX(400px) scale(0.8);
                        opacity: 0;
                    }
                    to {
                        transform: translateX(0) scale(1);
                        opacity: 1;
                    }
                }
                @keyframes slideOut {
                    from {
                        transform: translateX(0) scale(1);
                        opacity: 1;
                    }
                    to {
                        transform: translateX(400px) scale(0.8);
                        opacity: 0;
                    }
                }
            </style>
            <div style="text-shadow: 0 2px 4px rgba(0,0,0,0.3);">${message}</div>
        `;

        document.body.appendChild(notification);

        if (notificationTimeout) {
            clearTimeout(notificationTimeout);
        }

        notificationTimeout = setTimeout(() => {
            notification.style.animation = 'slideOut 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55)';
            setTimeout(() => {
                if (notification.parentNode) {
                    notification.remove();
                }
            }, 300);
        }, duration);
    }

    function hasQuizContent() {
        const hasStem = document.querySelector('.sia-question-stem') !== null;
        const hasQuestion = document.querySelector('kp-sia-question') !== null;
        const hasDistractors = document.querySelectorAll('.sia-distractor').length > 0;
        return hasStem || hasQuestion || hasDistractors;
    }

    function extractQuestion() {
        const siaQuestion = document.querySelector('kp-sia-question');
        if (siaQuestion) {
            const kpContent = siaQuestion.querySelector('kp-content');
            if (kpContent) {
                const generated = kpContent.querySelector('[class*="kp-generated"]');
                if (generated) {
                    return generated.textContent.trim();
                }
                const text = kpContent.textContent.trim();
                if (text) return text;
            }
        }

        const questionStem = document.querySelector('.sia-question-stem');
        if (questionStem) {
            const allElements = questionStem.querySelectorAll('*');
            for (let el of allElements) {
                if (el.className && el.className.includes('kp-generated')) {
                    const text = el.textContent.trim();
                    if (text) return text;
                }
            }
            const text = questionStem.textContent.trim();
            if (text) return text;
        }

        return null;
    }

    function resizeAndCompressImage(img) {
        return new Promise((resolve, reject) => {
            try {
                const canvas = document.createElement('canvas');
                const ctx = canvas.getContext('2d');

                let width = img.naturalWidth || img.width;
                let height = img.naturalHeight || img.height;

                log(`Original image size: ${width}x${height}`);

                if (width > MAX_IMAGE_WIDTH || height > MAX_IMAGE_HEIGHT) {
                    const ratio = Math.min(MAX_IMAGE_WIDTH / width, MAX_IMAGE_HEIGHT / height);
                    width = Math.floor(width * ratio);
                    height = Math.floor(height * ratio);
                }

                log(`Resized to: ${width}x${height}`);

                canvas.width = width;
                canvas.height = height;
                ctx.drawImage(img, 0, 0, width, height);

                canvas.toBlob((blob) => {
                    if (!blob) {
                        reject(new Error('Failed to create blob'));
                        return;
                    }

                    const reader = new FileReader();
                    reader.onloadend = function() {
                        const base64data = reader.result.split(',')[1];
                        const originalSize = (base64data.length * 0.75 / 1024).toFixed(2);
                        log(`Compressed image size: ${originalSize} KB`);

                        resolve({
                            data: base64data,
                            mimeType: 'image/jpeg'
                        });
                    };
                    reader.onerror = () => reject(new Error('Failed to read blob'));
                    reader.readAsDataURL(blob);
                }, 'image/jpeg', IMAGE_QUALITY);

            } catch (e) {
                reject(e);
            }
        });
    }

    async function extractImages() {
        const images = [];
        const questionArea = document.querySelector('kp-sia-question');
        if (!questionArea) return images;

        const imgElements = questionArea.querySelectorAll('img');
        log(`Found ${imgElements.length} images in question`);

        for (let imgEl of imgElements) {
            try {
                const img = new Image();
                img.crossOrigin = 'anonymous';

                const imageLoadPromise = new Promise((resolve, reject) => {
                    img.onload = () => resolve(img);
                    img.onerror = () => reject(new Error('Failed to load image'));

                    if (imgEl.src) {
                        img.src = imgEl.src;
                    } else if (imgEl.dataset.src) {
                        img.src = imgEl.dataset.src;
                    } else {
                        reject(new Error('No image source found'));
                    }
                });

                await imageLoadPromise;
                const compressedImage = await resizeAndCompressImage(img);
                images.push(compressedImage);
                log('Image processed and compressed');

            } catch (error) {
                logError('Error processing image:', error);

                try {
                    if (imgEl.src && imgEl.src.startsWith('data:')) {
                        const base64Data = imgEl.src.split(',')[1];
                        const mimeType = imgEl.src.split(';')[0].split(':')[1];
                        images.push({
                            data: base64Data,
                            mimeType: mimeType
                        });
                        log('Used original base64 image (compression failed)');
                    }
                } catch (fallbackError) {
                    logError('Fallback also failed:', fallbackError);
                }
            }
        }

        return images;
    }

    function extractAnswers() {
        const answers = [];
        const distractors = document.querySelectorAll('.sia-distractor');

        distractors.forEach((distractor, index) => {
            const choiceLetter = distractor.querySelector('.sia-choice-letter')?.textContent.trim();
            let answerText = null;

            const kpContent = distractor.querySelector('kp-content');
            if (kpContent) {
                const generated = kpContent.querySelector('[class*="kp-generated"]');
                if (generated) {
                    answerText = generated.textContent.trim();
                } else {
                    answerText = kpContent.textContent.trim();
                }
            }

            if (!answerText) {
                const labelDiv = distractor.querySelector('.label');
                if (labelDiv) {
                    answerText = labelDiv.textContent.replace(choiceLetter || '', '').trim();
                }
            }

            if (answerText) {
                answers.push({
                    letter: choiceLetter || String.fromCharCode(65 + index) + '.',
                    text: answerText,
                    element: distractor
                });
            }
        });

        return answers;
    }

    function createProgressBar() {
        let progressBar = document.getElementById('gemini-progress-bar');

        if (!progressBar) {
            progressBar = document.createElement('div');
            progressBar.id = 'gemini-progress-bar';
            progressBar.style.cssText = `
                position: fixed;
                bottom: 25px;
                right: 25px;
                width: 200px;
                height: 6px;
                background: #e0e0e0;
                border-radius: 2px;
                overflow: hidden;
                z-index: 999999;
                opacity: 0;
                transition: opacity 0.3s ease;
            `;

            const progressFill = document.createElement('div');
            progressFill.id = 'gemini-progress-fill';
            progressFill.style.cssText = `
                height: 100%;
                width: 0%;
                background: linear-gradient(90deg, #4285f4, #34a853);
                border-radius: 2px;
                transition: width 0.1s linear;
            `;

            progressBar.appendChild(progressFill);
            document.body.appendChild(progressBar);
        }

        return progressBar;
    }

    function showProgress() {
        const progressBar = createProgressBar();
        const progressFill = document.getElementById('gemini-progress-fill');

        progressBar.style.opacity = '0.75';
        progressFill.style.width = '0%';

        let progress = 0;
        const duration = 3000;
        const interval = 50;
        const increment = (interval / duration) * 100;

        if (progressInterval) {
            clearInterval(progressInterval);
        }

        progressInterval = setInterval(() => {
            progress += increment;
            if (progress >= 95) {
                progress = 95;
            }
            progressFill.style.width = progress + '%';
        }, interval);
    }

    function hideProgress(success = true) {
        if (progressInterval) {
            clearInterval(progressInterval);
            progressInterval = null;
        }

        const progressBar = document.getElementById('gemini-progress-bar');
        const progressFill = document.getElementById('gemini-progress-fill');

        if (progressBar && progressFill) {
            if (success) {
                progressFill.style.width = '100%';
                setTimeout(() => {
                    progressBar.style.opacity = '0';
                    setTimeout(() => {
                        progressFill.style.width = '0%';
                    }, 300);
                }, 300);
            } else {
                progressFill.style.background = '#ea4335';
                setTimeout(() => {
                    progressBar.style.opacity = '0';
                    setTimeout(() => {
                        progressFill.style.width = '0%';
                        progressFill.style.background = 'linear-gradient(90deg, #4285f4, #34a853)';
                    }, 300);
                }, 500);
            }
        }
    }

    function queryGemini(question, answers, images) {
        return new Promise((resolve, reject) => {
            if (!GEMINI_API_KEY || GEMINI_API_KEY === 'YOUR_API_KEY_HERE') {
                reject(new Error('No API key configured'));
                return;
            }

            const answerList = answers.map(a => `${a.letter} ${a.text}`).join('\n');

            let prompt = `You are a knowledgeable assistant operating at a high school level. `;

            if (images.length > 0) {
                prompt += `Analyze the question carefully INCLUDING the provided image(s). The images may contain diagrams, charts, molecular structures, or other visual information needed to answer correctly. `;
            }

            prompt += `Provide ONLY the letter (A, B, C, or D) of the correct answer. Do not include any explanation or additional text - just the single letter.

Question: ${question}

Answer Options:
${answerList}

Think through the question logically and select the most accurate answer based on high school official correct answer trends. This is for a high school level quiz so use appropriate reasoning for that level.

Correct answer letter (A, B, C, or D only):`;

            const parts = [];

            if (images.length > 0) {
                log(`Including ${images.length} optimized image(s) in request`);
                images.forEach((img) => {
                    parts.push({
                        inline_data: {
                            mime_type: img.mimeType,
                            data: img.data
                        }
                    });
                });
            }

            parts.push({ text: prompt });

            const requestData = {
                contents: [{
                    parts: parts
                }]
            };

            const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-flash-latest:generateContent?key=${GEMINI_API_KEY}`;

            log('Querying Gemini' + (images.length > 0 ? ' with vision' : ''));

            GM_xmlhttpRequest({
                method: 'POST',
                url: url,
                headers: {
                    'Content-Type': 'application/json'
                },
                data: JSON.stringify(requestData),
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);

                        if (data.error) {
                            logError('API Error:', data.error);
                            reject(new Error(data.error.message));
                            return;
                        }

                        if (data.candidates && data.candidates.length > 0) {
                            const candidate = data.candidates[0];
                            let answer = null;

                            if (candidate.content && candidate.content.parts) {
                                if (Array.isArray(candidate.content.parts) && candidate.content.parts.length > 0) {
                                    const part = candidate.content.parts[0];
                                    if (part && part.text) {
                                        answer = part.text;
                                    }
                                }
                            }

                            if (answer) {
                                log('Full response text:', answer);

                                const letterMatch = answer.match(/\b[A-D]\b/i);
                                if (letterMatch) {
                                    const finalAnswer = letterMatch[0].toUpperCase();
                                    log('Extracted answer:', finalAnswer);
                                    resolve(finalAnswer);
                                } else {
                                    const anyLetter = answer.match(/[A-D]/i);
                                    if (anyLetter) {
                                        const finalAnswer = anyLetter[0].toUpperCase();
                                        log('Using first A-D found:', finalAnswer);
                                        resolve(finalAnswer);
                                    } else {
                                        reject(new Error('No A-D letter in response'));
                                    }
                                }
                            } else {
                                logError('No text in response');

                                if (candidate.finishReason === 'SAFETY') {
                                    reject(new Error('Response blocked by safety filter'));
                                } else if (candidate.finishReason === 'MAX_TOKENS') {
                                    reject(new Error('MAX_TOKENS issue'));
                                } else {
                                    reject(new Error(`No text (finish: ${candidate.finishReason})`));
                                }
                            }
                        } else {
                            reject(new Error('No candidates'));
                        }
                    } catch (e) {
                        logError('Parse error:', e);
                        reject(e);
                    }
                },
                onerror: function(error) {
                    logError('Request error:', error);
                    reject(error);
                }
            });
        });
    }

    function removeHighlights() {
        document.querySelectorAll('.sia-distractor').forEach(el => {
            const labelDiv = el.querySelector('.label');
            if (labelDiv) {
                labelDiv.style.color = '';
                labelDiv.style.fontWeight = '';
                labelDiv.style.opacity = '';
            }
        });
    }

    function highlightAnswer(answers, correctLetter) {
        const normalizedCorrect = correctLetter.replace(/[^A-D]/gi, '').trim().toUpperCase();
        log('Highlighting answer:', normalizedCorrect);

        answers.forEach(answer => {
            const normalizedAnswerLetter = answer.letter.replace(/[^A-D]/gi, '').trim().toUpperCase();

            if (normalizedAnswerLetter === normalizedCorrect) {
                const labelDiv = answer.element.querySelector('.label');
                if (labelDiv) {
                    labelDiv.style.color = '#1e7e34';
                    labelDiv.style.fontWeight = '600';
                    labelDiv.style.opacity = '0.65';
                }

                log(`Highlighted answer ${answer.letter}`);
            }
        });
    }

    function selectAnswer(answers, correctLetter) {
        const normalizedCorrect = correctLetter.replace(/[^A-D]/gi, '').trim().toUpperCase();

        for (let answer of answers) {
            const normalizedAnswerLetter = answer.letter.replace(/[^A-D]/gi, '').trim().toUpperCase();

            if (normalizedAnswerLetter === normalizedCorrect) {
                log('Auto-selecting answer:', normalizedCorrect);

                const radioButton = answer.element.querySelector('input[type="radio"]');
                if (radioButton) {
                    radioButton.checked = true;
                    radioButton.dispatchEvent(new Event('change', { bubbles: true }));
                    radioButton.dispatchEvent(new Event('click', { bubbles: true }));
                    return true;
                }

                answer.element.click();
                return true;
            }
        }

        return false;
    }

    function submitAnswer() {
        log('Attempting to submit answer');
        const submitSelectors = [
            'button[type="submit"]',
            'button.submit',
            'button.submit-button',
            'input[type="submit"]',
            '.submit-button',
            '[class*="submit"]'
        ];

        for (let selector of submitSelectors) {
            const buttons = document.querySelectorAll(selector);
            for (let button of buttons) {
                if (button.offsetParent !== null) {
                    const buttonText = button.textContent.trim().toUpperCase();
                    if (buttonText.includes('SUBMIT') || buttonText.includes('CHECK') ||
                        (buttonText.includes('ANSWER') && !buttonText.includes('NEXT'))) {
                        log('Found submit button:', buttonText);
                        button.click();
                        return true;
                    }
                }
            }
        }

        log('Submit button not found');
        return false;
    }

    function clickNextQuestion() {
    log('Attempting to click next question button');

    const nextSelectors = [
        'button.submit-button', // apex uses this one
        'button.next',
        '[class*="next"]',
        '[class*="continue"]'
    ];

    for (let selector of nextSelectors) {
        const buttons = document.querySelectorAll(selector);
        for (let button of buttons) {
            if (button.offsetParent !== null) {
                const buttonText = button.textContent.trim().toUpperCase();
                log('Found button with text:', buttonText);

                if (buttonText.includes('VIEW SUMMARY')) {
                    log('Found VIEW SUMMARY button - clicking and disabling auto-complete');
                    button.click();

                    autoCompleteEnabled = false;
                    GM_setValue('autoCompleteEnabled', false);

                    const message = `
                        <div style="font-size: 15px; font-weight: 400;"><b>Quiz Complete!<b></div>
                        <div style="font-size: 12px; opacity: 0.8; margin-top: 5px;">Auto-Complete: <span style="color: #f87171"><b>Disabled<b></span></div>
                    `;
                    showNotification(message, 3000);

                    return true;
                }

                if (buttonText.includes('NEXT') || buttonText.includes('CONTINUE')) {
                    log('Clicking next question button');
                    button.click();

                    setTimeout(() => {
                        lastQuestionText = '';
                    }, 500);

                    return true;
                }
            }
        }
    }

    log('Next question button not found');
    return false;
}


    async function processQuiz() {
        if (!isEnabled || isProcessing) return;

        if (!hasQuizContent()) {
            return;
        }

        const question = extractQuestion();
        if (!question) {
            return;
        }

        if (question === lastQuestionText) {
            return;
        }

        log('New question detected');
        lastQuestionText = question;
        isProcessing = true;

        removeHighlights();
        showProgress();

        try {
            const answers = extractAnswers();
            if (answers.length === 0) {
                log('No answers found');
                hideProgress(false);
                isProcessing = false;
                return;
            }

            const images = await extractImages();
            if (images.length > 0) {
                log(`Processed ${images.length} optimized image(s)`);
            }

            const correctAnswer = await queryGemini(question, answers, images);
            highlightAnswer(answers, correctAnswer);
            hideProgress(true);

            if (autoCompleteEnabled) {
                setTimeout(() => {
                    const selected = selectAnswer(answers, correctAnswer);
                    if (selected) {
                        log('Answer selected, waiting before submit');

                        setTimeout(() => {
                            const submitted = submitAnswer();

                            if (submitted) {
                                log('Answer submitted, waiting before clicking next');

                                setTimeout(() => {
                                    clickNextQuestion();
                                }, NEXT_QUESTION_DELAY);
                            }
                        }, AUTO_SUBMIT_DELAY);
                    }
                }, AUTO_SELECT_DELAY);
            }

        } catch (error) {
            logError('Error:', error.message);
            hideProgress(false);
        } finally {
            isProcessing = false;
        }
    }

    function startMonitoring() {
        if (!GEMINI_API_KEY || GEMINI_API_KEY === 'YOUR_API_KEY_HERE') {
            console.error('Apex Quiz Auto-Answer: No API key configured. Get one from https://aistudio.google.com/app/apikey');
            return;
        }

        log('Apex Quiz Auto-Answer Active');
        log('Images will be resized to max 800x800');

        setTimeout(processQuiz, 2000);

        const observer = new MutationObserver((mutations) => {
            const relevantChange = mutations.some(mutation => {
                return Array.from(mutation.addedNodes).some(node => {
                    if (node.nodeType === 1) {
                        return node.classList?.contains('sia-distractor') ||
                               node.classList?.contains('sia-question-stem') ||
                               node.querySelector?.('.sia-distractor') ||
                               node.querySelector?.('.sia-question-stem');
                    }
                    return false;
                });
            });

            if (relevantChange) {
                setTimeout(processQuiz, 500);
            }
        });

        const mainContent = document.querySelector('kp-main, main, .sia-content');
        if (mainContent) {
            observer.observe(mainContent, {
                childList: true,
                subtree: true
            });
        }

        setInterval(processQuiz, 3000);
    }

    function init() {
        startMonitoring();

        const statusMessage = `
            <div style="font-size: 16px; margin-bottom: 8px; font-weight: 400;">Apex Quiz Helper</div>
            <div style="font-size: 13px; opacity: 0.9;">Script: <span style="color: ${isEnabled ? '#4ade80' : '#f87171'}"><b>${isEnabled ? 'Enabled' : 'Disabled'}</b></span></div>
            <div style="font-size: 13px; opacity: 0.9;">Auto-Complete: <span style="color: ${autoCompleteEnabled ? '#4ade80' : '#f87171'}"><b>${autoCompleteEnabled ? 'ON' : 'OFF'}</b></span></div>
        `;
        showNotification(statusMessage, 3000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    document.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.shiftKey && e.key === 'E') {
            e.preventDefault();
            isEnabled = !isEnabled;
            GM_setValue('scriptEnabled', isEnabled);
            const message = `
                <div style="font-size: 15px; font-weight: 400;">Script <b>${isEnabled ? 'Enabled' : 'Disabled'}</b></div>
                <div style="font-size: 12px; opacity: 0.8; margin-top: 5px;">Status: <span style="color: ${isEnabled ? '#4ade80' : '#f87171'}"><b>${isEnabled ? 'Active' : 'Inactive'}</b></span></div>
            `;
            showNotification(message);
            if (isEnabled) {
                processQuiz();
            } else {
                removeHighlights();
            }
        }

        if (e.ctrlKey && e.shiftKey && e.key === 'A') {
            e.preventDefault();
            autoCompleteEnabled = !autoCompleteEnabled;
            GM_setValue('autoCompleteEnabled', autoCompleteEnabled);
            const message = `
                <div style="font-size: 15px; font-weight: 400;">Auto-Complete <b>${autoCompleteEnabled ? 'Enabled' : 'Disabled'}</b></div>
                <div style="font-size: 12px; opacity: 0.8; margin-top: 5px;">Mode: <span style="color: ${autoCompleteEnabled ? '#4ade80' : '#f87171'}"><b>${autoCompleteEnabled ? 'Full Auto' : 'Highlight Only'}</b></span></div>
            `;
            showNotification(message);
        }

        if (e.ctrlKey && e.shiftKey && e.key === 'R') {
            e.preventDefault();
            lastQuestionText = '';
            isProcessing = false;
            removeHighlights();
            const message = `
                <div style="font-size: 15px; font-weight: 400;">Reprocessing Question</div>
                <div style="font-size: 12px; opacity: 0.8; margin-top: 5px;">Analyzing with Gemini...</div>
            `;
            showNotification(message, 1500);
            processQuiz();
        }
    });

})();