// ==UserScript==
// @name ChatGPT Model Switcher: Toggle on/off 4o-mini
// @namespace http://tampermonkey.net/
// @version 0.21
// @description Injects a button allowing you to switch on/off 4o-mini during the chat
// @match *://chatgpt.com/*
// @author d0gkiller87
// @license MIT
// @grant unsafeWindow
// @grant GM.setValue
// @grant GM.getValue
// @run-at document-end
// @downloadURL none
// ==/UserScript==
(async function() {
'use strict';
class ModelSwitcher {
constructor( useMini = true ) {
this.useMini = useMini;
}
hookFetch() {
const originalFetch = unsafeWindow.fetch;
unsafeWindow.fetch = async ( resource, config = {} ) => {
if (
this.useMini &&
resource === 'https://chatgpt.com/backend-api/conversation' &&
config.method === 'POST' &&
config.headers &&
config.headers['Content-Type'] === 'application/json' &&
config.body
) {
const body = JSON.parse( config.body );
body.model = 'gpt-4o-mini';
config.body = JSON.stringify( body );
}
return originalFetch( resource, config );
};
}
injectToggleButton() {
// Credit: https://webdevworkshop.io/code/css-toggle-button/
if ( !document.getElementById( 'toggleCss' ) ) {
const styleNode = document.createElement( 'style' );
styleNode.id = 'toggleCss';
styleNode.type = 'text/css';
styleNode.textContent = `.toggle {
position: relative;
display: inline-block;
width: 2.5rem;
height: 1.5rem;
background-color: hsl(0deg 0% 40%);
border-radius: 25px;
cursor: pointer;
transition: background-color 0.25s ease-in;
}
.toggle::after {
content: '';
position: absolute;
width: 1.4rem;
left: 0.1rem;
height: calc(1.5rem - 2px);
top: 1px;
background-color: white;
border-radius: 50%;
transition: all 0.25s ease-out;
}
#cb-toggle:checked + .toggle {
background-color: hsl(102, 58%, 39%);
}
#cb-toggle:checked + .toggle::after {
transform: translateX(1rem);
}
.hide-me {
opacity: 0;
height: 0;
width: 0;
}`;
document.head.appendChild( styleNode );
}
const container = document.querySelector( '#composer-background div:nth-of-type(2) div:first-child' );
if ( container ) {
container.classList.add( 'items-center' );
const observer = new MutationObserver( mutationsList => {
for ( const mutation of mutationsList ) {
if ( mutation.type !== 'childList' ) continue;
if ( !mutation.addedNodes ) continue;
observer.disconnect();
setTimeout(() => {
//
const checkbox = document.createElement( 'input' );
checkbox.id = 'cb-toggle';
checkbox.type = 'checkbox';
checkbox.className = 'hide-me';
checkbox.checked = this.useMini;
//
const label = document.createElement( 'label' );
label.htmlFor = 'cb-toggle';
label.className = 'toggle';
label.title = `Using model: ${ this.useMini ? 'GPT-4o mini' : 'original' }`;
container.appendChild( checkbox );
container.appendChild( label );
const cb = document.querySelector( '#cb-toggle' );
cb.addEventListener(
'click', async () => {
this.useMini = cb.checked;
await GM.setValue( 'useMini', this.useMini );
label.title = `Using model: ${ this.useMini ? 'GPT-4o mini' : 'original' }`;
},
false
);
}, 1000 );
break;
}
});
observer.observe( container, { childList: true } );
} else {
console.error( 'container not found!' );
}
}
}
const useMini = await GM.getValue( 'useMini', true );
const switcher = new ModelSwitcher( useMini );
switcher.hookFetch();
switcher.injectToggleButton();
})();