您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Bug Team —— 好用、爱用 ♥
当前为
// ==UserScript== // @name Switch Bug Team Model // @namespace http://tampermonkey.net/ // @version 1.0 // @description Bug Team —— 好用、爱用 ♥ // @author wandouyu // @match *://chatgpt.com/* // @match *://chat.openai.com/* // @match *://chat.voct.dev/* // @grant GM_addStyle // @license MIT // ==/UserScript== (function() { 'use strict'; const modelMap = { "o3 ": "o3", "o4-mini-high": "o4-mini-high", "o4-mini": "o4-mini", "gpt-4.5 (preview)": "gpt-4-5", "gpt-4o": "gpt-4o", "gpt-4o-mini": "gpt-4o-mini", "gpt-4o (tasks)": "gpt-4o-jawbone", "gpt-4": "gpt-4" }; const modelDisplayNames = Object.keys(modelMap); const modelIds = Object.values(modelMap); let dropdownElement = null; let isDropdownVisible = false; GM_addStyle(` .model-switcher-container { position: relative; display: inline-block; margin-left: 4px; margin-right: 4px; align-self: center; } #model-switcher-button { display: inline-flex; align-items: center; justify-content: center; height: 36px; min-width: 36px; padding: 0 12px; border-radius: 9999px; border: 1px solid var(--token-border-light, #E5E5E5); font-size: 14px; font-weight: 500; color: var(--token-text-secondary, #666666); background-color: var(--token-main-surface-primary, #FFFFFF); cursor: pointer; white-space: nowrap; transition: background-color 0.2s ease; box-sizing: border-box; } #model-switcher-button:hover { background-color: var(--token-main-surface-secondary, #F7F7F8); } #model-switcher-dropdown { position: fixed; display: block; background-color: var(--token-main-surface-primary, white); border: 1px solid var(--token-border-medium, #E5E5E5); border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); z-index: 1050; min-width: 180px; overflow-y: auto; padding: 4px 0; } .model-switcher-item { display: block; padding: 8px 16px; color: var(--token-text-primary, #171717); text-decoration: none; white-space: nowrap; cursor: pointer; font-size: 14px; } .model-switcher-item:hover { background-color: var(--token-main-surface-secondary, #F7F7F8); } .model-switcher-item.active { font-weight: bold; } `); function getCurrentModelInfo() { const params = new URLSearchParams(window.location.search); const currentModelId = params.get('model'); let currentDisplayName = "Select Model"; let currentIndex = -1; if (currentModelId) { const index = modelIds.indexOf(currentModelId); if (index !== -1) { currentIndex = index; currentDisplayName = modelDisplayNames[index]; } else { currentDisplayName = `Model: ${currentModelId.substring(0, 10)}${currentModelId.length > 10 ? '...' : ''}`; currentIndex = -1; } } else { if (modelDisplayNames.length > 0) { currentDisplayName = modelDisplayNames[0]; currentIndex = 0; } } return { currentId: currentModelId, displayName: currentDisplayName, index: currentIndex }; } function createModelSwitcher() { if (modelDisplayNames.length === 0) { console.warn("Model Switcher: modelMap is empty. Cannot create switcher."); return null; } const container = document.createElement('div'); container.className = 'model-switcher-container'; container.id = 'model-switcher-container'; const button = document.createElement('button'); button.id = 'model-switcher-button'; button.type = 'button'; const dropdown = document.createElement('div'); dropdown.className = 'model-switcher-dropdown'; dropdown.id = 'model-switcher-dropdown'; const currentInfo = getCurrentModelInfo(); button.textContent = currentInfo.displayName; modelDisplayNames.forEach((name, index) => { const modelId = modelIds[index]; const item = document.createElement('a'); item.className = 'model-switcher-item'; item.textContent = name; item.dataset.modelId = modelId; item.href = '#'; if ((currentInfo.currentId && currentInfo.currentId === modelId) || (!currentInfo.currentId && index === 0)) { item.classList.add('active'); } item.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); const selectedModelId = e.target.dataset.modelId; if (selectedModelId) { const url = new URL(window.location.href); url.searchParams.set('model', selectedModelId); if (getCurrentModelInfo().currentId !== selectedModelId) { window.location.href = url.toString(); } else { hideDropdown(); } } else { hideDropdown(); } }); dropdown.appendChild(item); }); button.addEventListener('click', (e) => { e.stopPropagation(); toggleDropdown(); }); container.appendChild(button); dropdownElement = dropdown; return container; } function showDropdown() { if (!dropdownElement || isDropdownVisible) return; const button = document.getElementById('model-switcher-button'); if (!button) return; const buttonRect = button.getBoundingClientRect(); const scrollX = window.scrollX || window.pageXOffset; const scrollY = window.scrollY || window.pageYOffset; document.body.appendChild(dropdownElement); isDropdownVisible = true; const dropdownHeight = dropdownElement.offsetHeight; const spaceAbove = buttonRect.top; const spaceBelow = window.innerHeight - buttonRect.bottom; const margin = 5; let top, left = buttonRect.left + scrollX; if (spaceBelow >= dropdownHeight + margin || spaceBelow >= spaceAbove) { top = buttonRect.bottom + scrollY + margin; } else { top = buttonRect.top + scrollY - dropdownHeight - margin; } if (top < scrollY + margin) top = scrollY + margin; if (left < scrollX + margin) left = scrollX + margin; const dropdownWidth = dropdownElement.offsetWidth; if (left + dropdownWidth > window.innerWidth + scrollX - margin) { left = window.innerWidth + scrollX - dropdownWidth - margin; } dropdownElement.style.top = `${top}px`; dropdownElement.style.left = `${left}px`; document.addEventListener('click', handleClickOutside, true); window.addEventListener('resize', hideDropdown); window.addEventListener('scroll', hideDropdown, true); } function hideDropdown() { if (!dropdownElement || !isDropdownVisible) return; if (dropdownElement.parentNode === document.body) { document.body.removeChild(dropdownElement); } isDropdownVisible = false; document.removeEventListener('click', handleClickOutside, true); window.removeEventListener('resize', hideDropdown); window.removeEventListener('scroll', hideDropdown, true); } function toggleDropdown() { if (isDropdownVisible) { hideDropdown(); } else { showDropdown(); } } function handleClickOutside(event) { const button = document.getElementById('model-switcher-button'); if (dropdownElement && dropdownElement.parentNode === document.body && button && !button.contains(event.target) && !dropdownElement.contains(event.target)) { hideDropdown(); } } function insertSwitcherButton() { const existingContainer = document.getElementById('model-switcher-container'); if (existingContainer) { const button = document.getElementById('model-switcher-button'); const currentInfo = getCurrentModelInfo(); if(button && button.textContent !== currentInfo.displayName) { button.textContent = currentInfo.displayName; if (dropdownElement) { const items = dropdownElement.querySelectorAll('.model-switcher-item'); items.forEach((item, index) => { item.classList.remove('active'); const modelId = item.dataset.modelId; if ((currentInfo.currentId && currentInfo.currentId === modelId) || (!currentInfo.currentId && index === 0)) { item.classList.add('active'); } }); } } return true; } const attachmentButton = document.querySelector('button[aria-label="Upload files and more"]'); if (!attachmentButton) { return false; } const targetContainer = attachmentButton.closest('div[style*="--vt-composer-attach-file-action"]'); if (!targetContainer) { console.warn('Model Switcher: Could not find the target container (div with view-transition-name) for the attachment button.'); const directParent = attachmentButton.parentElement; if (directParent && directParent.parentElement) { const switcherContainer = createModelSwitcher(); if (!switcherContainer) return false; directParent.parentElement.insertBefore(switcherContainer, directParent.nextSibling); console.log('Model Switcher: Inserted after attachment button\'s direct parent (fallback).'); return true; } console.error('Model Switcher: Fallback insertion also failed.'); return false; } const switcherContainer = createModelSwitcher(); if (!switcherContainer) return false; targetContainer.insertAdjacentElement('afterend', switcherContainer); console.log('Model Switcher: Button inserted after the attachment button container.'); return true; } let insertionAttempted = false; const observer = new MutationObserver((mutationsList, obs) => { const targetButtonExists = document.querySelector('button[aria-label="Upload files and more"]'); if (targetButtonExists) { if (!document.getElementById('model-switcher-container')) { if (insertSwitcherButton()) { insertionAttempted = true; } else if (!insertionAttempted) { console.error('Model Switcher: Found attachment button, but failed to insert switcher next to it.'); insertionAttempted = true; } } else { insertSwitcherButton(); insertionAttempted = true; } } if (insertionAttempted && !document.getElementById('model-switcher-container')) { console.log("Model Switcher: Button container removed (UI update?), resetting for re-insertion attempt..."); insertionAttempted = false; hideDropdown(); } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(insertSwitcherButton, 1500); })();