ChatGPT Model Switcher: Toggle on/off 4o-mini

Injects a button allowing you to toggle on/off 4o-mini during the chat

  1. // ==UserScript==
  2. // @name ChatGPT Model Switcher: Toggle on/off 4o-mini
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.40
  5. // @description Injects a button allowing you to toggle on/off 4o-mini during the chat
  6. // @match *://chatgpt.com/*
  7. // @author d0gkiller87
  8. // @license MIT
  9. // @grant unsafeWindow
  10. // @grant GM.setValue
  11. // @grant GM.getValue
  12. // @grant GM_addStyle
  13. // @run-at document-idle
  14. // @icon https://www.google.com/s2/favicons?sz=64&domain=chatgpt.com
  15. // ==/UserScript==
  16.  
  17. (async function() {
  18. 'use strict';
  19.  
  20. class ModelSwitcher {
  21. constructor( useMini = true ) {
  22. this.useMini = useMini;
  23. this.buttons = {};
  24. }
  25.  
  26. hookFetch() {
  27. const originalFetch = unsafeWindow.fetch;
  28. unsafeWindow.fetch = async ( resource, config = {} ) => {
  29. if (
  30. resource === 'https://chatgpt.com/backend-api/conversation' &&
  31. config.method === 'POST' &&
  32. config.headers &&
  33. config.headers['Content-Type'] === 'application/json' &&
  34. config.body
  35. ) {
  36. if ( this.useMini ) {
  37. const body = JSON.parse( config.body );
  38. body.model = 'gpt-4o-mini';
  39. config.body = JSON.stringify( body );
  40. }
  41. }
  42. return originalFetch( resource, config );
  43. };
  44. }
  45.  
  46. injectToggleButtonStyle() {
  47. GM_addStyle(`
  48. #model-selector {
  49. position: fixed;
  50. bottom: 35px;
  51. right: 20px;
  52. background-color: rgba(0, 0, 0, 0.1);
  53. color: white;
  54. padding: 10px;
  55. border-radius: 10px;
  56. display: flex;
  57. flex-direction: column;
  58. gap: 6px;
  59. z-index: 9999;
  60. }
  61. #model-selector button {
  62. background: none;
  63. border: 1px solid white;
  64. color: white;
  65. padding: 6px;
  66. cursor: pointer;
  67. font-size: 0.9rem;
  68. }
  69. #model-selector button.btn-4o-mini {
  70. background-color: #43a25a;
  71. }
  72. #model-selector button.btn-default {
  73. background-color: #83838b;
  74. }
  75. `);
  76. }
  77.  
  78. refreshButtons() {
  79. for ( const [ model, button ] of Object.entries( this.buttons ) ) {
  80. if ( this.useMini ) {
  81. button.classList.toggle( model, model === 'btn-4o-mini' );
  82. } else {
  83. button.classList.toggle( model, model !== 'btn-4o-mini' );
  84. }
  85. }
  86. }
  87.  
  88. createModelSelectorMenu() {
  89. this.modelSelector = document.createElement( 'div' );
  90. this.modelSelector.id = 'model-selector';
  91.  
  92. [ '4o-mini', 'default' ].forEach(
  93. model => {
  94. const button = document.createElement( 'button' );
  95. button.textContent = model;//model.charAt(0).toUpperCase() + model.slice(1);
  96. button.onclick = async () => {
  97. this.useMini = !this.useMini;
  98. await GM.setValue( 'useMini', this.useMini );
  99. this.refreshButtons();
  100. }
  101. this.modelSelector.appendChild( button );
  102. this.buttons[`btn-${ model }`] = button;
  103. }
  104. );
  105. }
  106.  
  107. monitorBodyChanges() {
  108. const observer = new MutationObserver( mutationsList => {
  109. for ( const mutation of mutationsList ) {
  110. if ( document.body.querySelector( '#model-selector' ) ) continue;
  111. document.body.appendChild( this.modelSelector );
  112. break;
  113. }
  114. });
  115. observer.observe( document.body, { childList: true } );
  116. }
  117. }
  118.  
  119. const useMini = await GM.getValue( 'useMini', true );
  120. const switcher = new ModelSwitcher( useMini );
  121. switcher.hookFetch();
  122. switcher.injectToggleButtonStyle();
  123. switcher.createModelSelectorMenu();
  124. switcher.refreshButtons();
  125. switcher.monitorBodyChanges();
  126. document.body.appendChild( switcher.modelSelector );
  127. })();