From d70a44a1b938c5823ff59d1decb78984a9e2c2ee Mon Sep 17 00:00:00 2001 From: Dustin Miller <1342542+spdustin@users.noreply.github.com> Date: Wed, 22 Nov 2023 02:02:43 -0600 Subject: [PATCH] Adds TamperMonkey UserScript for debug use --- autoExpertChatGPTDebugHelper.user.js | 351 +++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) create mode 100644 autoExpertChatGPTDebugHelper.user.js diff --git a/autoExpertChatGPTDebugHelper.user.js b/autoExpertChatGPTDebugHelper.user.js new file mode 100644 index 0000000..a5215b9 --- /dev/null +++ b/autoExpertChatGPTDebugHelper.user.js @@ -0,0 +1,351 @@ +// ==UserScript== +// @name AutoExpert ChatGPT Debug Helper 1.0 +// @author Dustin Miller +// @namespace https://spdustin.substack.com +// @version 1.0 +// @description Adds some helpful debugging tools to the ChatGPT UI +// @run-at document-idle +// @match https://chat.openai.com/* +// @grant none +// ==/UserScript== + +(function () { + + class AEDataService { + constructor(baseUrl) { + this.baseUrl = baseUrl; + this.cachedToken = null; + this.tokenExpiration = Date.now(); + } + + async fetchToken() { + const MAX_RETRIES = 3; + const RETRY_DELAY = 2000; + let retries = 0; + + if (Date.now() < this.tokenExpiration) return this.cachedToken; + + while (retries < MAX_RETRIES) { + try { + const response = await fetch(`${this.baseUrl}/api/auth/session`); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + let tokenData; + try { + tokenData = await response.json(); + } catch (err) { + throw new Error("Failed to parse token data as JSON"); + } + if (tokenData && tokenData.accessToken && typeof tokenData.expires === "string") { + this.cachedToken = tokenData.accessToken; + this.tokenExpiration = new Date(tokenData.expires).getTime(); + return this.cachedToken; + } else { + throw new Error("Token data is missing the accessToken property"); + } + } catch (err) { + handleError("fetchToken", err); + retries++; + if (retries < MAX_RETRIES) { + await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY)); + } else { + return null; + } + } + } + } + + async fetchData(url, options = {}, needsAuth = false) { + if (needsAuth) { + await this.fetchToken(); + options.headers = { + Authorization: `Bearer ${this.cachedToken}`, + ...options.headers, + }; + } + const response = await fetch(`${this.baseUrl}/${url}`, options); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + const contentType = response.headers.get("Content-Type"); + if (contentType && contentType.includes("application/json")) { + return response.json(); + } else { + return response.text(); + } + } + + async updateCustomInstructions(data) { + try { + const response = await this.fetchData( + `backend-api/user_system_messages`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }, + true + ); + + if (response.error) { + throw new Error(`Failed to update custom instructions: ${response.error}`); + } + + return response; + } catch (error) { + handleError("updateCustomInstructions", error); + } + } + } + + const BASE_URL = "https://chat.openai.com"; + const CI_MODAL_TRIGGER = new KeyboardEvent("keydown", { + key: "I", + keyCode: 73, + metaKey: true, + shiftKey: true, + altKey: false, + ctrlKey: false, + bubbles: true, + }); + const DEBUGGER_SKIP_KEYS = ["id", "error", "create_time", "update_time", "parent_id", "conversation_id"]; + + const aeDataService = new AEDataService(BASE_URL); + + let messages = []; + + async function setup() { + const fetchedData = await aeDataService.fetchData("backend-api/user_system_messages", {}, true); + const buttonBar = createFloatingButtonContainer(); + const buttons = [{ + title: "Show custom instructions dialog", + id: "ae_CustomInstModal", + emoji: "📝", + handler: () => document.dispatchEvent(CI_MODAL_TRIGGER) + }, { + title: "Toggle Custom Instructions", + id: "ae_toggle", + emoji: fetchedData.enabled ? "✅" : "❌", + handler: handleToggleClick + }, { + title: "Download Data", + id: "ae_downloadData", + emoji: "📥", + handler: handleDownloadDataClick + }, { + title: "Download Message Log", + id: "ae_DownloadLog", + emoji: "🕵️", + handler: () => downloadJson(messages) + }, { + title: "Show debug panel", + id: "ae_debug", + emoji: "🕷️", + handler: () => panelDebug.style.display = (panelDebug.style.display === "none") ? "block" : "none" + }]; + for (let i in buttons) { + const _button = createButton(buttons[i]); + buttonBar.appendChild(_button); + } + + const panelDebug = createDomElementFromHTML( + '