Automatically force GPT-4o, even if switched back to GPT-5
// ==UserScript==
// @name Auto-gpt4o
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Automatically force GPT-4o, even if switched back to GPT-5
// @author Prof_Bum
// @match https://chatgpt.com/*
// @grant none
// @icon https://www.google.com/s2/favicons?sz=64&domain=chatgpt.com
// ==/UserScript==
(function () {
'use strict';
const preferredModelName = "GPT-4o";
let menuAlreadyOpened = false;
let legacyMenuOpened = false;
let gpt4oSelected = false;
let lastModel = null;
const TOGGLE_ID = "gpt4o-toggle";
const TOGGLE_STATE_KEY = "gpt4o-toggle-enabled";
function getToggleState() {
return JSON.parse(localStorage.getItem(TOGGLE_STATE_KEY) || "true");
}
function createToggleButton(enabled) {
const btn = document.createElement("button");
btn.id = TOGGLE_ID;
btn.textContent = enabled ? "Auto 4o: ON" : "Auto 4o: OFF";
btn.style = `
margin-left: 8px;
padding: 4px 10px;
font-size: 12px;
border-radius: 6px;
border: 1px solid #888;
background-color: ${enabled ? "#4caf50" : "#aaa"};
color: white;
cursor: pointer;
`;
btn.onclick = () => {
const newState = !getToggleState();
localStorage.setItem(TOGGLE_STATE_KEY, JSON.stringify(newState));
btn.textContent = newState ? "Auto 4o: ON" : "Auto 4o: OFF";
btn.style.backgroundColor = newState ? "#4caf50" : "#aaa";
console.log(`[GPT4o Toggle] Switched to ${newState ? "ENABLED" : "DISABLED"}`);
};
return btn;
}
function isInsideMain(el) {
let node = el;
while (node) {
if (node.tagName === "MAIN") return true;
node = node.parentElement;
}
return false;
}
function injectToggleIntoModelSwitcher() {
const switchers = document.querySelectorAll('[data-testid="model-switcher-dropdown-button"]');
for (const btn of switchers) {
if (isInsideMain(btn)) {
const parentFlex = btn.parentElement;
if (!parentFlex || document.getElementById(TOGGLE_ID)) return;
// Hydrated check: must include readable model label
if (!btn.innerText.includes("ChatGPT")) return;
const toggle = createToggleButton(getToggleState());
parentFlex.appendChild(toggle);
console.log("[GPT4o Toggle] Toggle injected into hydrated model switcher inside <main>");
return;
}
}
}
function simulateClick(el) {
el.dispatchEvent(new PointerEvent("pointerdown", { bubbles: true }));
el.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
el.dispatchEvent(new MouseEvent("mouseup", { bubbles: true }));
el.dispatchEvent(new MouseEvent("click", { bubbles: true }));
}
let lastCheckTime = 0;
const CHECK_COOLDOWN = 200; // ms
const checkAndSwitchModel = () => {
if (!getToggleState()) {
return; // Toggle disabled, do nothing
}
const now = Date.now();
const button = document.querySelector('button[aria-label^="Model selector"]');
if (!button) return;
const label = button.getAttribute("aria-label") || "";
const currentModel = label.split("current model is")[1]?.trim();
if (!currentModel) return;
// Always detect model change instantly
if (currentModel !== lastModel) {
lastModel = currentModel;
lastCheckTime = now; // reset cooldown window
menuAlreadyOpened = false;
legacyMenuOpened = false;
gpt4oSelected = false;
console.log(`[Model Switcher] Detected model change → ${currentModel}`);
} else {
// Only cooldown if no model change
if (now - lastCheckTime < CHECK_COOLDOWN) return;
lastCheckTime = now; // Update time so future calls can continue
}
if (currentModel !== preferredModelName && !menuAlreadyOpened) {
console.log(`[Model Switcher] Model is "${currentModel}", switching to "${preferredModelName}"`);
setTimeout(() => simulateClick(button), 100); // Open dropdown
menuAlreadyOpened = true;
}
if (currentModel === preferredModelName && !gpt4oSelected) {
console.log(`[Model Switcher] Already on preferred model: "${preferredModelName}"`);
gpt4oSelected = true;
}
};
const tryClickLegacyMenu = () => {
if (legacyMenuOpened) return;
const legacyItem = [...document.querySelectorAll('[role="menuitem"]')]
.find(el => el.textContent.trim().includes("Legacy models"));
if (legacyItem) {
simulateClick(legacyItem);
legacyMenuOpened = true;
console.log("[Model Switcher] Clicked Legacy models submenu");
}
};
const trySelectGPT4o = () => {
if (gpt4oSelected) return;
const gpt4oItem = [...document.querySelectorAll('[role="menuitem"]')]
.find(el => el.textContent.trim() === "GPT-4o");
if (gpt4oItem) {
simulateClick(gpt4oItem);
gpt4oSelected = true;
console.log("[Model Switcher] Switched to GPT-4o");
document.body.click();
}
};
function injectToggleIfReady() {
const modelButton = document.querySelector('[data-testid="model-switcher-dropdown-button"]');
const parentFlex = modelButton?.parentElement;
if (!modelButton || !parentFlex || document.getElementById("gpt4o-toggle")) return;
// ONLY inject if we're inside <main>
if (!isInsideMain(modelButton)) {
console.log("[GPT4o Toggle] Model button not inside <main>, skipping injection");
return;
}
const label = modelButton.innerText.trim();
if (!label.includes("ChatGPT")) {
console.log("[GPT4o Toggle] Waiting for hydration...");
return;
}
const toggleBtn = createToggleButton(getToggleState());
parentFlex.appendChild(toggleBtn);
console.log("[GPT4o Toggle] Injected toggle inside hydrated <main>");
}
const observer = new MutationObserver(() => {
checkAndSwitchModel();
tryClickLegacyMenu();
trySelectGPT4o();
injectToggleIntoModelSwitcher();
});
observer.observe(document.body, { childList: true, subtree: true });
})();