您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Select Reason Option Automatically in ChatGPT
// ==UserScript== // @name ChatGPT Auto‑Select Reason // @namespace https://github.com/ayoubdya/ChatGPT-Auto-Select-Reason // @version 1.0.6 // @description Select Reason Option Automatically in ChatGPT // @author ayoubdya // @license MIT // @match *://*.chatgpt.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=chatgpt.com // @grant none // @run-at document-idle // ==/UserScript== (function () { 'use strict'; const CONFIG = { selectors: { toolsButton: "button[data-testid=composer-plus-btn]", reasonOption: "div[role='menuitemradio']", reasonOptionText: "Think longer", reasonOptionTextDisabled: "more available on", selectedOption: "button[data-is-selected='true']", selectedOptionText: "Think" }, timeouts: { waitForElement: 5000, apiDelay: 500, retryDelay: 1000 }, maxRetries: 3, debug: false }; const logger = { log: (msg) => CONFIG.debug && console.log(`[Auto-Select Reason] ${msg}`), error: (msg, err) => console.error(`[Auto-Select Reason] ${msg}`, err), warn: (msg) => console.warn(`[Auto-Select Reason] ${msg}`) }; function simulateClick(element) { if (!element) { logger.warn('Attempted to click null element'); return false; } try { const events = ['pointerdown', 'pointerup', 'click']; events.forEach(eventType => { const EventConstructor = eventType.startsWith('pointer') ? PointerEvent : MouseEvent; const eventOptions = { bubbles: true, cancelable: true, }; const event = new EventConstructor(eventType, eventOptions); element.dispatchEvent(event); }); logger.log(`Successfully clicked element: ${element.tagName}`); return true; } catch (error) { logger.error('Failed to simulate click', error); return false; } } function waitForElement(selector, timeout = CONFIG.timeouts.waitForElement) { return new Promise((resolve, reject) => { let existingElement; if (selector === CONFIG.selectors.reasonOption) { try { existingElement = getReasonElement() } catch (err) { if (err instanceof DisabledReasonError) { reject(err); } } } else { existingElement = document.querySelector(selector); } if (existingElement) { logger.log(`Element found immediately: ${selector}`); return resolve(existingElement); } let timeoutId; const observer = new MutationObserver(() => { let element; if (selector === CONFIG.selectors.reasonOption) { try { element = getReasonElement(); } catch (err) { if (err instanceof DisabledReasonError) { clearTimeout(timeoutId); observer.disconnect(); reject(err); } } } else { element = document.querySelector(selector); } if (element) { clearTimeout(timeoutId); observer.disconnect(); logger.log(`Element found after waiting: ${selector}`); resolve(element); } }); observer.observe(document, { childList: true, subtree: true, }); timeoutId = setTimeout(() => { observer.disconnect(); const error = new Error(`Timeout waiting for element: ${selector}`); logger.error('Element wait timeout', error); reject(error); }, timeout); }); } class DisabledReasonError extends Error { constructor(message) { super(message); this.name = 'DisabledReasonError'; } } function getReasonElement() { const els = document.querySelectorAll(CONFIG.selectors.reasonOption); const validTexts = [CONFIG.selectors.reasonOptionText, CONFIG.selectors.reasonOptionTextDisabled].map(text => text.toLowerCase()); const el = Array.from(els).find(el => validTexts.some(text => { return el.textContent.trim().toLowerCase().includes(text); })); if (el?.textContent?.trim().toLowerCase().includes(CONFIG.selectors.reasonOptionTextDisabled)) { throw new DisabledReasonError('Reason option is disabled, cannot select'); } return el; } function isReasonSelected() { try { const selectedElement = document.querySelector(CONFIG.selectors.selectedOption); const isSelected = selectedElement?.textContent?.trim() === CONFIG.selectors.selectedOptionText; logger.log(`Reason selected status: ${isSelected}`); return isSelected; } catch (error) { logger.error('Error checking if Reason is selected', error); return false; } } async function enableReason({ retryCount = 0, initialCall = false } = {}) { try { logger.log(`Attempting to enable Reason (attempt ${retryCount + 1}/${CONFIG.maxRetries + 1})`); if (isReasonSelected()) { logger.log('Reason is already selected'); return true; } const toolsButton = await waitForElement(CONFIG.selectors.toolsButton); // Wait for API response from: chatgpt.com/backend-api/system_hints if (initialCall) { await new Promise(resolve => setTimeout(resolve, CONFIG.timeouts.apiDelay)); } if (!simulateClick(toolsButton)) { throw new Error('Failed to click tools button'); } const reasonOption = await waitForElement(CONFIG.selectors.reasonOption); if (!simulateClick(reasonOption)) { throw new Error('Failed to click reason option'); } // await new Promise(resolve => setTimeout(resolve, 200)); if (isReasonSelected()) { logger.log('Successfully enabled Reason'); return true; } else { throw new Error('Reason was not properly selected'); } } catch (error) { if (error instanceof DisabledReasonError) { logger.warn(error.message); const toolsButton = document.querySelector(CONFIG.selectors.toolsButton); simulateClick(toolsButton); return false; } logger.error(`Failed to enable Reason (attempt ${retryCount + 1})`, error); if (retryCount < CONFIG.maxRetries) { logger.log(`Retrying in ${CONFIG.timeouts.retryDelay}ms...`); await new Promise(resolve => setTimeout(resolve, CONFIG.timeouts.retryDelay)); return enableReason({ retryCount: retryCount + 1 }); } else { logger.error('Max retries exceeded, giving up'); return false; } } } function initialize() { logger.log('Initializing Auto-Select Reason script'); enableReason({ initialCall: true }).catch(error => { logger.error('Initial enableReason failed', error); }); const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (!(node instanceof HTMLElement)) continue; if (node.matches?.(CONFIG.selectors.toolsButton) || node.querySelector?.(CONFIG.selectors.toolsButton)) { logger.log('Tools button detected, attempting to enable Reason'); enableReason().catch(error => { logger.error('Dynamic enableReason failed', error); }); return; } } } }); observer.observe(document.body, { childList: true, subtree: true }); logger.log('Script initialized successfully'); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();