您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Remind you how many quota you left
// ==UserScript== // @name ChatGPT: Message Records // @namespace UserScripts // @match https://chatgpt.com/* // @match https://chat.openai.com/* // @grant GM.getValue // @grant GM.setValue // @grant GM.deleteValue // @grant GM_addValueChangeListener // @grant unsafeWindow // @version 1.2.2 // @author CY Fung // @license MIT // @description Remind you how many quota you left // @run-at document-start // @inject-into page // ==/UserScript== const __errorCode21167__ = (() => { try { Promise.resolve('\u{1F4D9}', ((async () => { })()).constructor); } catch (e) { console.log('%cUnsupported Browser', 'background-color: #FAD02E; color: #333; padding: 4px 8px; font-weight: bold; border-radius: 4px;'); return 0x3041; } if (typeof GM_addValueChangeListener !== 'function' || typeof GM !== 'object' || typeof (GM || 0).setValue !== 'function') { console.log('%cUnsupported UserScript Manager', 'background-color: #FAD02E; color: #333; padding: 4px 8px; font-weight: bold; border-radius: 4px;'); return 0x3042; } return 0; })(); __errorCode21167__ || (() => { /** @type {Window} */ const uWin = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window; /** @type {{ globalThis.PromiseConstructor}} */ const Promise = ((async () => { })()).constructor; let __recordId_new = 1; let abortCounter = 0; let userOpenAction = null; const kPattern = (num) => { const letters = 'abcdefghijklmnopqrstuvwxyz'; const k = num % 9; const j = Math.floor(num / 9); const letter = letters[j]; return `${letter}${k + 1}`; } const kHash = (n) => { if (n < 0 || n > 54755) { throw new Error('Number out of range'); } const nValue = 9 * 26; // precompute this value since it's constant // Simplified equation, combined terms let hashBase = (n * 9173) % 54756; // ((54756 - n) * 9173 + (n) * 7919 + (n) * 5119) % 54756;` let hash = ''; for (let i = 0; i < 2; i++) { const t = hashBase % nValue; hash = kPattern(t) + hash; hashBase = Math.floor(hashBase / nValue); } return hash; } const cleanContext = async (win, gmWindow) => { /** @param {Window} fc */ const sanitize = (fc) => { const { setTimeout, clearTimeout, setInterval, clearInterval, requestAnimationFrame, cancelAnimationFrame } = fc; const res = { setTimeout, clearTimeout, setInterval, clearInterval, requestAnimationFrame, cancelAnimationFrame }; for (let k in res) res[k] = res[k].bind(win); // necessary return res; } if (gmWindow && typeof gmWindow === 'object' && gmWindow.GM_info && gmWindow.GM) { let isIsolatedContext = ( (gmWindow.requestAnimationFrame !== win.requestAnimationFrame) && (gmWindow.cancelAnimationFrame !== win.cancelAnimationFrame) && (gmWindow.setTimeout !== win.setTimeout) && (gmWindow.setInterval !== win.setInterval) && (gmWindow.clearTimeout !== win.clearTimeout) && (gmWindow.clearInterval !== win.clearInterval) ); if (isIsolatedContext) { return sanitize(gmWindow); } } const waitFn = requestAnimationFrame; // shall have been binded to window try { let mx = 16; // MAX TRIAL const frameId = 'vanillajs-iframe-v1' let frame = document.getElementById(frameId); let removeIframeFn = null; if (!frame) { frame = document.createElement('iframe'); frame.id = frameId; const blobURL = typeof webkitCancelAnimationFrame === 'function' && typeof kagi === 'undefined' ? (frame.src = URL.createObjectURL(new Blob([], { type: 'text/html' }))) : null; // avoid Brave Crash frame.sandbox = 'allow-same-origin'; // script cannot be run inside iframe but API can be obtained from iframe let n = document.createElement('noscript'); // wrap into NOSCRPIT to avoid reflow (layouting) n.appendChild(frame); while (!document.documentElement && mx-- > 0) await new Promise(waitFn); // requestAnimationFrame here could get modified by YouTube engine const root = document.documentElement; root.appendChild(n); // throw error if root is null due to exceeding MAX TRIAL if (blobURL) Promise.resolve().then(() => URL.revokeObjectURL(blobURL)); removeIframeFn = (setTimeout) => { const removeIframeOnDocumentReady = (e) => { e && win.removeEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false); e = n; n = win = removeIframeFn = 0; setTimeout ? setTimeout(() => e.remove(), 200) : e.remove(); } if (!setTimeout || document.readyState !== 'loading') { removeIframeOnDocumentReady(); } else { win.addEventListener("DOMContentLoaded", removeIframeOnDocumentReady, false); } } } while (!frame.contentWindow && mx-- > 0) await new Promise(waitFn); const fc = frame.contentWindow; if (!fc) throw "window is not found."; // throw error if root is null due to exceeding MAX TRIAL try { const res = sanitize(fc); if (removeIframeFn) Promise.resolve(res.setTimeout).then(removeIframeFn); return res; } catch (e) { if (removeIframeFn) removeIframeFn(); return null; } } catch (e) { console.warn(e); return null; } }; const observablePromise = (proc, timeoutPromise) => { let promise = null; return { obtain() { if (!promise) { promise = new Promise(resolve => { let mo = null; const f = () => { let t = proc(); if (t) { mo.disconnect(); mo.takeRecords(); mo = null; resolve(t); } } mo = new MutationObserver(f); mo.observe(document, { subtree: true, childList: true }) f(); timeoutPromise && timeoutPromise.then(() => { resolve(null) }); }); } return promise } } } cleanContext(uWin, window).then((__CONTEXT__) => { const { setTimeout, clearTimeout, setInterval, clearInterval, requestAnimationFrame, cancelAnimationFrame } = __CONTEXT__; const console = Object.assign({}, window.console); /** @type {JSON.parse} */ const jParse = window.JSON.parse.bind(window.JSON); const jParseCatched = (val) => { let res = null; try { res = jParse(val); } catch (e) { } return res; } const jStringify = window.JSON.stringify.bind(window.JSON); const GM_RECORD_KEY = 'TOTAL_MESSAGE_RECORDS'; let __foregroundActivityMeasure = 0; let __totalActivityMeasure = 0; const foregroundActivityMeasureInterval = 500; const amiUL = foregroundActivityMeasureInterval * 1.1; const amiLL = foregroundActivityMeasureInterval * 0.9; const activityMeasure = { get foreground() { return __foregroundActivityMeasure; }, get background() { return activityMeasure.total - activityMeasure.foreground; }, get total() { return Math.round(__totalActivityMeasure) } } let __uid = 0; let message_cap = null; let message_cap_window = null; let categories = null; let models = null; let currentAccount = null; let currentUser = null; const getUserId = () => currentAccount && currentUser ? `${currentAccount}.${currentUser}` : ''; const dummyObject = {}; for (const [key, value] of Object.entries(console)) { if (typeof value === 'function' && typeof dummyObject[key] !== 'function') { console[key] = value.bind(window.console); } } const messageRecords = []; let messageRecordsOnCurrentAccount = null; let rafPromise = null; const getRafPromise = () => rafPromise || (rafPromise = new Promise(resolve => { requestAnimationFrame(hRes => { rafPromise = null; resolve(hRes); }); })); const foregroundWrap = (cb) => { let wait = false; return () => { if (wait) return; wait = true; requestAnimationFrame(function () { wait = false; cb(); }); } } const findRecordIndexByRId = (rid) => { if (!rid) return null; for (let i = 0; i < messageRecords.length; i++) { const record = messageRecords[i]; if (record.$recordId && rid === record.$recordId) { return i; } } return -1; } const cssStyleText = () => ` :root { --mr-background-color: #2a5c47; --mr-font-stack: "Ubuntu-Italic", "Lucida Sans", helvetica, sans; --mr-target-width: 30px; --mr-target-height: 30px; --mr-target-bottom: 90px; --mr-target-right: 50px; /* 8-0.5*x+0.25*x*x */ --mr-tb-radius: calc(2.42 * var(--mr-border-width)); /* 20 -> 8px. 14 -> 6px 4px. 10px */ --mr-message-bubble-width: 200px; --mr-message-bubble-margin: 0; --mr-border-width: 2px; --mr-triangle-border-width: var(--mr-tb-radius); --mr-message-bubble-opacity: 0; --mr-message-bubble-scale: 0.5; --mr-message-bubble-transform-origin: bottom right; --mr-message-bubble-transition: opacity 0.3s, transform 0.3s, visibility 0s 0.3s; --mr-border-color: #666; --mr-tb-btm: calc(var(--mr-tb-radius) * 1.72); } html { --mr-message-bubble-bg-color: #ecf3e7; --mr-message-bubble-text-color: #414351; --progress-color: #807e1e; } html.dark{ --mr-message-bubble-bg-color: #40414f; --mr-message-bubble-text-color: #ececf1; } html[mr-request-model="gpt-4"]{ --progress-color: #ac68ff; } html[mr-request-model="gpt-3"] { --progress-color: #19c37d; } html[mr-request-state="request"] { --progress-percent: 25%; --progress-rr: 9px; } html[mr-request-state="response"] { --progress-percent: 75%; --progress-rr: 9px; } html[mr-request-state=""] { --progress-percent: 100%; --progress-rr: 20px; } html[mr-request-state=""] .mr-progress-bar::before { --mr-animate-background-image: none; } .mr-progress-bar.mr-progress-bar-show { visibility:visible; } .mr-progress-bar { display: inline-block; width: 200px; --progress-height: 16px; --progress-padding: 4px; /* --progress-percent: 50%; */ /* --progress-color: #2bc253; */ --progress-stripe-color: rgba(255, 255, 255, 0.2); --progress-shadow1: rgba(255, 255, 255, 0.3); --progress-shadow2: rgba(0, 0, 0, 0.4); --progress-rl: 20px; /* --progress-rr: 9px; */ width: 100%; /* --progress-percent: 100%; --progress-rr: 20px;*/ visibility: collapse; } @keyframes mr-progress-bar-move { 0% { background-position: 0 0; } 100% { background-position: 50px 50px; } } .mr-progress-bar { box-sizing: border-box; height: var(--progress-height); position: relative; background: #555; border-radius: 25px; box-shadow: inset 0 -1px 1px var(--progress-shadow1); display: inline-block; } .mr-progress-bar::before { box-sizing: border-box; content: ""; display: block; margin: var(--progress-padding); border-top-right-radius: var(--progress-rr); border-bottom-right-radius: var(--progress-rr); border-top-left-radius: var(--progress-rl); border-bottom-left-radius: var(--progress-rl); background-color: var(--progress-color); box-shadow: inset 0 2px 9px var(--progress-shadow1), inset 0 -2px 6px var(--progress-shadow2); position: absolute; top: 0; left: 0; right: calc(100% - var(--progress-percent)); transition: right 300ms, background-color 300ms; bottom: 0; --mr-animate-background-image: linear-gradient(-45deg, var(--progress-stripe-color) 25%, transparent 25%, transparent 50%, var(--progress-stripe-color) 50%, var(--progress-stripe-color) 75%, transparent 75%, transparent); background-image: var(--mr-animate-background-image); background-size: 50px 50px; animation: mr-progress-bar-move 2s linear infinite; } .mr-nostripes::before { --mr-animate-background-image: none; } #mr-msg-l { text-align: center; font-size: .875rem; color: var(--tw-prose-code); font-size: .875em; font-weight: 600; } #mr-msg-p { text-align: center; font-size: 1rem; } #mr-msg-p1{ display: block; } #mr-msg-p2{ display: block; font-size: .75rem; } .mr-message-bubble { margin: 0; display: inline-block; position: absolute; width: var(--mr-message-bubble-width); height: auto; background-color: var(--mr-message-bubble-bg-color); opacity: var(--mr-message-bubble-opacity); transform: scale(var(--mr-message-bubble-scale)); transform-origin: var(--mr-message-bubble-transform-origin); transition: var(--mr-message-bubble-transition); visibility: hidden; margin-bottom: var(--mr-tb-btm); bottom:0; right:0; color: var(--mr-message-bubble-text-color); --mr-user-select: auto-user-select; } .mr-border { border: var(--mr-border-width) solid var(--mr-border-color); } .mr-round { border-radius: var(--mr-tb-radius); } .mr-tri-right.mr-border.mr-btm-right:before { content: ' '; position: absolute; width: 0; height: 0; left: auto; right: calc(var(--mr-border-width) * -1); bottom: calc(var(--mr-tb-radius) * -2); border: calc(var(--mr-border-width) * 4) solid; border-color: transparent var(--mr-border-color) transparent transparent; } .mr-tri-right.mr-btm-right:after { content: ' '; position: absolute; width: 0; height: 0; left: auto; right: 0px; bottom: calc(var(--mr-tb-radius) * -1); border: var(--mr-triangle-border-width) solid; border-color: var(--mr-message-bubble-bg-color) var(--mr-message-bubble-bg-color) transparent transparent; } .mr-msg-text { padding: 1em; text-align: left; line-height: 1.5em; } .mr-message-bubble.mr-open { opacity: 1; transform: scale(1); visibility: visible; transition-delay: 0s; } .mr-msg-text p { margin: 0; } .mr-a33 { position: absolute; top: auto; left: auto; bottom: 0px; right: 0px; } .mr-k33 { position: absolute; contain: size layout style; width: 100%; height: 100%; transform: translate(-50%, -100%); } .mr-button-container[class] button[class] { opacity: 0.8; } .mr-button-container[class] button[class]:hover { opacity: 1; } .mr-button-container.mr-clicked[class] button[class], .mr-button-container.mr-clicked[class] button[class]:hover { background-color: #616a8a; opacity:1; } .mr-button-container[class], .mr-button-container[class] button[class] { --mr-user-select: none; user-select: var(--mr-user-select); } .mr-offset-book-btn { margin-right: 28px; } .flex.w-full.flex-col[class*="rounded-"][class*="bg-"]:hover { z-index: 999; } `; const addCssText = () => { if (document.querySelector('#mr-style811')) return; const style = document.createElement('style'); style.id = 'mr-style811'; style.textContent = cssStyleText(); document.head.appendChild(style); } const updateGMRecord = () => { Promise.resolve().then(() => { GM.setValue(GM_RECORD_KEY, jStringify({ version: 1, records: messageRecords })); }); } const updateMessageRecordsOnCurrentAccount = () => { messageRecordsOnCurrentAccount = messageRecords.filter(entry => entry.$account_uid === `${currentAccount}.${currentUser}`); } const fixOverRecords = () => { messageRecords.splice(0, Math.floor(messageRecords.length / 2)); let rid = 1; for (const record of messageRecords) { record.$recordId = rid; messageRecords.push(record); rid++; } __recordId_new = rid; keep.length = 0; keep = null; updateMessageRecordsOnCurrentAccount(); updateGMRecord(); } const addRecord = (record) => { if (!currentAccount || !currentUser || !record || record.$account_uid) { console.log('addRecord aborted'); return; } record.$account_uid = getUserId(); const recordId = __recordId_new; record.$recordId = recordId; record.$recorded_at = Date.now(); // Local Time messageRecords.push(record); __recordId_new++; messageRecordsOnCurrentAccount.push(record); if (messageRecords.length > 3600 || __recordId_new > 3600) { // around 4MB Promise.resolve().then(fixOverRecords); } return recordId; } Object.assign(uWin, { $$mr$$getMessageRecords() { return messageRecords; }, $$mr$$getMessageRecordsFromGM() { return GM.getValue(GM_RECORD_KEY); }, $$mr$$clearMessageRecords() { return GM.deleteValue(GM_RECORD_KEY); }, $$mr$$getUserId() { const r = getUserId(); if (!r) console.log(`!! ${currentAccount}.${currentUser} !!`) return r; }, $$mr$$activityMeasure() { return Object.assign({}, activityMeasure) } }); const setRecordsByJSONString = (newValue, initial) => { let tObj = jParseCatched(newValue || '{}'); if (!tObj || !tObj.version || !tObj.records) tObj = { version: 1, records: [] }; if (tObj.version !== 1) { if (initial) { GM.deleteValue(GM_RECORD_KEY); // and wait change confirmed by listener } else { console.warn('record version is incorrect. please reload the page.'); } return; } if (messageRecords.length > 0) messageRecords.length = 0; __recordId_new = 1; let rid = 1; for (const record of tObj.records) { if (record.$recordId >= rid) rid = record.$recordId + 1; messageRecords.push(record); __recordId_new++; } __recordId_new = rid; updateMessageRecordsOnCurrentAccount(); } const onAccountDetectedOrChanged = () => { updateMessageRecordsOnCurrentAccount(); } let last_GM_RECORD_KEY_newValue = null; const setRecordsByJSONStringX = () => { setRecordsByJSONString(last_GM_RECORD_KEY_newValue); } const setRecordsByJSONStringForegroundWrapped = foregroundWrap(setRecordsByJSONStringX); let gmValueListenerId = GM_addValueChangeListener(GM_RECORD_KEY, (key, oldValue, newValue, remote) => { last_GM_RECORD_KEY_newValue = newValue; setRecordsByJSONStringForegroundWrapped(); }); Promise.resolve().then(() => GM.getValue(GM_RECORD_KEY)).then(result => { // result = result || '{}'; if (typeof result !== 'string') { console.log('GM.getValue aborted') return; } GM.setValue() setRecordsByJSONString(result, true) }) const arrayTypeFix = (a) => { return a === null || a === undefined ? [] : a; } const getRequestQuotaString = () => { let num = null; if (document.documentElement.getAttribute('mr-request-model') === 'gpt-4') { num = messageRecordsOnCurrentAccount.filter(entry => { return typeof entry.model === 'string' && entry.model.startsWith('gpt-4') && (entry.$recorded_at || entry.$record_time_ms || 0) > (Date.now() - (6 * 1000 * 60) - message_cap_window * 60 * 1000) }).length; + ' out of ' + message_cap; let p1 = document.querySelector('#mr-msg-p1') let p2 = document.querySelector('#mr-msg-p2') if (p1 && p2) { p1.textContent = `${num}` p2.textContent = ' out of ' + message_cap; } } else if (document.documentElement.getAttribute('mr-request-model') === 'gpt-3') { num = messageRecordsOnCurrentAccount.filter(entry => { return typeof entry.model === 'string' && entry.model.startsWith('text-davinci-002-render-sha') && (entry.$recorded_at || entry.$record_time_ms || 0) > (Date.now() - (6 * 1000 * 60) - 24 * 60 * 60 * 1000) }).length; let p1 = document.querySelector('#mr-msg-p1') let p2 = document.querySelector('#mr-msg-p2') if (p1 && p2) { p1.textContent = `${num}` p2.textContent = ` in past 24 hours`; } } else { let p1 = document.querySelector('#mr-msg-p1') let p2 = document.querySelector('#mr-msg-p2') if (p1 && p2) { p1.textContent = ''; p2.textContent = ''; } // return ''; } } function onRequest(_body) { const body = _body; const bodyObject = jParseCatched(body); if (!bodyObject) { console.log('invalid JSON object'); return; } if (!('messages' in bodyObject)) { console.log('invalid format of JSON body') return; } const model = typeof bodyObject.model === 'string' ? bodyObject.model : null; const messages = arrayTypeFix(bodyObject.messages); if (!model || !messages || typeof (messages || 0).length !== 'number') { console.log('invalid format of JSON body') return; } if (!currentAccount) { console.log('No account information is found. Message Record aborted.') return; } let conversation_id = bodyObject.conversation_id; if (!conversation_id) conversation_id = "***" let recordIds = null; let request_model = ''; if (typeof model === 'string' && (model === 'text-davinci-002-render-sha' || model.startsWith('text-davinci-002-render-sha'))) { request_model = 'gpt-3'; } else if (typeof model === 'string' && (model === 'gpt-4' || model.startsWith('gpt-4'))) { request_model = 'gpt-4'; } if (request_model) { try { document.documentElement.setAttribute('mr-request-model', request_model); getRequestQuotaString(); document.documentElement.setAttribute('mr-request-state', 'request'); document.querySelector('.mr-progress-bar').classList.add('mr-progress-bar-show'); } catch (e) { } if (userOpenAction === null && attachedGroup && attachedGroup.isConnected === true && isChatBubbleOpened() === false) { const myGroup = attachedGroup; myGroupClicked(myGroup); } } else { try { document.documentElement.setAttribute('mr-request-model', '') getRequestQuotaString(); document.querySelector('.mr-progress-bar').classList.remove('mr-progress-bar-show'); } catch (e) { } } const onAbort = (evt, signal, newChatId) => { if (typeof newChatId === 'string' && newChatId) { const cd002 = !!recordIds && recordIds.length === 1 && recordIds[0] > 0; console.log('condition 002', cd002); if (cd002) { const rid = recordIds[0]; const idx = findRecordIndexByRId(rid); if (idx === null || idx < 0 || !messageRecords[idx] || messageRecords[idx].conversation_id !== '***') { console.warn('error found in onAbort'); } else { messageRecords[idx].conversation_id = newChatId console.log(`record#${rid} is updated with conversation_id = "${newChatId}"`) } } } if (recordIds && recordIds.length >= 1) { const completionTime = evt.__aborted_at__ > 0 ? evt.__aborted_at__ : 0; if (completionTime) { for (const rid of recordIds) { const idx = findRecordIndexByRId(rid); if (idx === null || idx < 0 || !messageRecords[idx]) { console.warn('completionTime found in onAbort'); } else if (messageRecords[idx].conversation_id === '***') { // TBC } else { messageRecords[idx].$completed_at = completionTime; } } } } updateGMRecord(); if (document.documentElement.getAttribute('mr-request-state') === 'response') document.documentElement.setAttribute('mr-request-state', '') console.log('messageHandler: onAbort', evt, signal, newChatId); }; const uid = ++__uid; const onResponse = (response, info) => { const { requestTime, responseTime } = info; // response.lockedBodyStream.then((body) => { // // console.log(13, body) // }) if (!currentAccount) { console.log('No account information is found. Message Record aborted.') return; } if (recordIds !== null) { console.warn('recordIds !== null'); } recordIds = []; for (const message of messages) { const rid = addRecord({ model, conversation_id, message, $requested_at: requestTime, $responsed_at: responseTime }); recordIds.push(rid); } updateGMRecord(); if (document.documentElement.getAttribute('mr-request-state') === 'request') document.documentElement.setAttribute('mr-request-state', 'response') try { getRequestQuotaString(); } catch (e) { } // console.log(bodyObject) // console.log(response, info) // console.log({ // message_cap, message_cap_window, // categories, // models // }) } return { uid, model, conversation_id, message_cap, message_cap_window, categories, bodyObject, messages, onAbort, onResponse, } } uWin.__fetch247__ = uWin.fetch; let onceRgStr = false; let __newChatIdResolveFn__ = null; const authJsonPn = function () { const target = this['$a039$'] || this; return new Promise((resolve, reject) => { // console.log(112) target.json().then((result) => { const __jsonRes__ = result; if (typeof (__jsonRes__ || 0).user === 'object' && (__jsonRes__.user || 0).id) { currentUser = `${(__jsonRes__.user || 0).id}`; // console.log('user??', currentUser) // __NEXT_DATA__.props.pageProps.user.id // document.cookie.__puid } // console.log(566, result) resolve(result) }).catch(reject) }) } const jsonPnForGetRequest = function () { const target = this['$a039$'] || this; return new Promise((resolve, reject) => { target.json().then((result) => { const __jsonRes__ = result; if (typeof (__jsonRes__ || 0).accounts === 'object') { const tmpSet = new Set(); if (((__jsonRes__ || 0).accounts || 0).length > 0) { for (const account of __jsonRes__.accounts) { tmpSet.add(`${account.account_id}.${account.account_user_id}`); } } else { for (let [key, account] of Object.entries(__jsonRes__.accounts)) { account = account.account || account; tmpSet.add(`${account.account_id}.${account.account_user_id}`); } } if (tmpSet.size !== 1) { console.log('account detection failed') } else { let acc = [...tmpSet.keys()][0]; if (acc !== currentAccount) { currentAccount = acc; onAccountDetectedOrChanged(); } } } else if (((__jsonRes__ || 0).categories || 0).length >= 1 && ((__jsonRes__ || 0).models || 0).length >= 1) { const jsonRes = __jsonRes__; try { categories = [...jsonRes.categories]; } catch (e) { } try { models = [...jsonRes.models]; } catch (e) { } // console.log(233, categories, models) } // console.log(544, result) resolve(result) }).catch(reject) }) }; const message_limit_jsonPn = function () { const target = this['$a039$'] || this; return new Promise((resolve, reject) => { // console.log(114) target.clone().text().then(r => { // console.log(r) let jr = jParseCatched(r); if (jr) { if (jr.message_cap > 0 && jr.message_cap_window > 0) { message_cap = +jr.message_cap; message_cap_window = +jr.message_cap_window; } } }) target.json().then((result) => { // console.log(result) resolve(result) }).catch(reject) }) }; uWin.fetch = function (a) { const args = arguments; return new Promise((resolve, reject) => { let doCatch = false; let body = null; let _onAbort = null; if (typeof a === 'string' && a.endsWith('/backend-api/conversation')) { const b = args[1] || 0; if (b.method === "POST" && typeof b.body === 'string' && ((b.headers || 0)['Content-Type'] || '').includes('application/json')) { doCatch = true; body = b.body; } if (b && b.signal) { const signal = b.signal; const tid = ++abortCounter; signal.addEventListener('abort', (evt) => { evt.__aborted_at__ = Date.now(); const aid = abortCounter; ++abortCounter; console.log('onabort', aid, tid, evt, signal) if (aid === tid && _onAbort) { _onAbort(evt, signal); } }); } } else if (typeof a === 'string' && a.startsWith('https://events.statsigapi.net/v1/rgstr')) { if (onceRgStr) { resolve = null; reject = null; return; // no resolve or reject for subsequent requests } onceRgStr = true; // no resolve or reject for next request } else if (__newChatIdResolveFn__ && typeof a === 'string' && a.startsWith('https://chat.openai.com/backend-api/conversation/gen_title/')) { let m = /gen_title\/([-0-9a-z]+)(\/|$)/.exec(a); if (m && m[1]) { __newChatIdResolveFn__(m[1]); } } const unprocessedFetch = () => { const actualRequest = uWin.__fetch247__.apply(this, args); // console.log(269, false, args[0], Object.assign({}, args[1] || {})) let rType = 0; if (typeof args[0] === 'string' && args[0].includes('/') && args[1] && args[1].method === 'GET') { rType = 1; } else if (args[0].includes('/api/auth/session')) { rType = 2; } actualRequest.then((result) => { if (rType > 0) { result = new Proxy(result, { get(target, key, receiver) { if (key === '$a039$') return target; const r = target[key]; if (key === 'json' && key in target) { if (typeof r === 'function') { if (rType === 1) { if (typeof args[0] === 'string' && args[0].includes('/conversation_limit') && args[1] && args[1].method === 'GET') { return message_limit_jsonPn; } else { return jsonPnForGetRequest; } } else if (rType === 2) { return authJsonPn; } } } if (typeof r === 'function') { return (receiver['$b031$' + key] || (receiver['$b031$' + key] = ((r) => (function () { return r.apply(this['$a039$'] || this, arguments) }))(r))); } return r; } }); } // console.log(result) resolve(result); }).catch((error) => { reject(error); }); } const messageHandler = doCatch ? onRequest(body) : false; if (!messageHandler) { unprocessedFetch(); return; } const requireNewChatId = (messageHandler.conversation_id === '***'); _onAbort = (evt, signal) => { __newChatIdResolveFn__ = null; if (requireNewChatId) { let resolveFn = null; let promise = new Promise(resolve => { resolveFn = resolve; }) __newChatIdResolveFn__ = (x) => { resolveFn && resolveFn(x); resolveFn = null; }; setTimeout(() => { resolveFn && resolveFn(); resolveFn = null; }, 16); // 777ms -> 781ms => 16ms shall be sufficient promise.then((newChatId) => { if (__newChatIdResolveFn__ === null) { console.warn('unexpected error'); return; } __newChatIdResolveFn__ = null; newChatId = newChatId || null; console.log(`newChatId: ${newChatId}`); messageHandler.onAbort(evt, signal, newChatId); }) } else { messageHandler.onAbort(evt, signal, false); } } const requestTime1 = Date.now(); const actualRequest = uWin.__fetch247__.apply(this, args); const requestTime2 = Date.now(); const requestTime = Math.round((requestTime1 + requestTime2) / 2); // console.log(269, true, args[0], Object.assign({}, args[1] || {})) actualRequest.then((result) => { const responseTime = Date.now(); let mBodyResolve = null; const mBody = new Promise(r => { mBodyResolve = r; }); const pRes = new Proxy(result, { get(target, property, receiver) { if (property === '$a039$') return target; const r = target[property]; /** * * property's get order * * then * status * then * * ---- * * type * status * clone * headers * headers * ok * body * * */ if (property === 'body') { mBodyResolve && mBodyResolve(r); // console.log(667, r); } else if (typeof r === 'function') { return (receiver['$b031$' + property] || (receiver['$b031$' + property] = ((r) => (function () { return r.apply(this['$a039$'] || this, arguments) }))(r))); } return r; } }); const mResult = { headers: result.headers, ok: result.ok, redirected: result.redirected, status: result.status, statusText: result.statusText, type: result.type, url: result.url, get lockedBodyStream() { return mBody }, }; resolve(pRes); Promise.resolve().then(() => { messageHandler.onResponse(mResult, { requestTime, responseTime }); }).catch(console.warn); }).catch((error) => { reject(error); }) }); } const findButtonByExpression = (()=>{ const xpathExpressionV1 = '//button[normalize-space(text())="?"][contains(@class, "h-") and contains(@class, "w-")]'; const xpathExpressionV0 = '//div[normalize-space(text())="?"][contains(@class, "h-") and contains(@class, "w-")]'; return (contextNode) => { let w = document.evaluate(xpathExpressionV1, contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (!w || !w.singleNodeValue) { w = document.evaluate(xpathExpressionV0, contextNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); if (!w || !w.singleNodeValue) { w = null; } } return w; } })(); let observer = null; let mct = 0; let wType = 0; let attachedGroup = null; function openChatBubble() { const chatBubble = document.querySelector(".mr-message-bubble"); if (!chatBubble) return; chatBubble.classList.add('mr-open'); } function isChatBubbleOpened() { const chatBubble = document.querySelector(".mr-message-bubble"); if (!chatBubble) return null; return chatBubble.classList.contains('mr-open'); } function closeChatBubble() { const chatBubble = document.querySelector(".mr-message-bubble"); if (!chatBubble) return; chatBubble.classList.remove('mr-open'); } const myGroupClicked = (myGroup) => { const chatBubble = document.querySelector(".mr-message-bubble"); if (!chatBubble) return null; const msgP = document.querySelector("#mr-msg-p1"); if (!msgP || msgP.firstChild === null) return null; if (!chatBubble.classList.contains('mr-open')) { myGroup.classList.add('mr-clicked'); openChatBubble() return true; } else { myGroup.classList.remove('mr-clicked'); closeChatBubble(); return false; } return null; } /** @param {HTMLElement} myGroup */ const setupMyGroup = (myGroup) => { addCssText(); const buttonText = findButtonByExpression(myGroup).singleNodeValue; buttonText.textContent = '\u{1F4D9}'; const placeholder = document.createElement('div'); placeholder.classList.add('mr-k33'); placeholder.innerHTML = ` <div class="mr-message-bubble mr-tri-right mr-round mr-border mr-btm-right"> <div class="mr-msg-text"> <p id="mr-msg-l">count(messages)</p> <p id="mr-msg-p"><span id="mr-msg-p1"></span><span id="mr-msg-p2"></span></p> <p class="mr-progress-bar"></p> </div> </div> `; myGroup.classList.add('mr-button-container'); myGroup.insertBefore(placeholder, myGroup.firstChild); myGroup.addEventListener('click', function (evt) { if (!evt || !evt.target) return; if (evt.target.closest('.mr-k33')) return; const myGroup = this; const chatBubble = document.querySelector(".mr-message-bubble"); if (!chatBubble) return; let clickedResult = myGroupClicked(myGroup); if (typeof clickedResult === 'boolean') { if (evt.isTrusted === true) { if (clickedResult) { userOpenAction = true; } else { userOpenAction = false; } } } }) } const onElementFound = (matchedElement) => { console.log('onElementFound', matchedElement) let group = matchedElement.closest('.group'); if (!group) { console.log('The group parent of Question Mark Button cannot be found.') return; } let groupParent = group; let level = 0; while (groupParent && groupParent.nextSibling === null && groupParent.previousSibling === null && (groupParent.parentNode instanceof HTMLElement)) { groupParent = groupParent.parentNode; if (++level === 1) { groupParent.style.columnGap = '6px'; } groupParent.classList.remove('flex-col'); groupParent.classList.add('flex-row'); groupParent.style.display = 'inline-flex' } if (!attachedGroup) { let myGroup = group.cloneNode(true); // if (/\bright-\d+\b/.test(myGroup.className)) { myGroup.classList.add('mr-offset-book-btn'); // } group.parentNode.insertBefore(myGroup, group); setupMyGroup(myGroup); attachedGroup = myGroup; } else { group.parentNode.insertBefore(attachedGroup, group); } } const setupMRAM = () => { const mram = document.createElement('mr-activity-measure'); mram.setAttribute('m', ''); document.head.appendChild(document.createElement('style')).textContent = ` mr-activity-measure[m] { visibility: collapse !important; width: 1px !important; height: 1px !important; display: block !important; z-index: -1 !important; contain: strict !important; box-sizing: border-box !important; position: fixed !important; top: -1000px !important; left: -1000px !important; animation: ${foregroundActivityMeasureInterval}ms ease-in 500ms infinite alternate forwards running mrActivityMeasure !important; } @keyframes mrActivityMeasure{ 0%{ order: 0; } 100%{ order: 1; } } `; let lastEt = 0; mram.onanimationiteration = function (evt) { const et = evt.elapsedTime * 1000; if (__totalActivityMeasure > et) { this.onanimationiteration = null; return; } const wt = lastEt; lastEt = et; const dt = et - wt; if (dt < amiUL && dt > amiLL) __foregroundActivityMeasure += foregroundActivityMeasureInterval; __totalActivityMeasure = et; // console.log(evt) } document.documentElement.appendChild(mram); } const findAndHandleElement = () => { if (!observer) return; if (wType !== 0) { if (!attachedGroup) return; if (attachedGroup.isConnected) return; } const result = findButtonByExpression( document); if(!result) return; const matchedElement = result.singleNodeValue; if (!matchedElement) return; console.log('findAndHandleElement OK'); const cb = wType === 0 ? setupMRAM : () => { }; if (wType === 0) { wType = 1; } Promise.resolve(matchedElement).then(onElementFound).then(cb).catch(console.warn); } const findAndHandleElementForegroundWrapped = foregroundWrap(findAndHandleElement); observer = new MutationObserver(function (mutationsList) { if (!observer) return; findAndHandleElementForegroundWrapped(); }); observer.observe(document, { childList: true, subtree: true }); (async function (){ if (document.readyState === 'loading') { await new Promise(resolve=>window.addEventListener('load', resolve, false)); } if (!observer) return; if (wType > 0) return; const main = await observablePromise(() => document.querySelector('main')).obtain(); if (!main) return; await getRafPromise(); setTimeout(function () { if (!observer) return; if (wType > 0) return; console.log('The Question Mark Button cannot be found.') observer.disconnect(); observer.takeRecords(); observer = null; }, 1200); })(); console.log('script loaded') }) })(); /** * $record_time_ms: 1692831419486 $requested_at: 1692831418865 $responsed_at: 1692831419485 create_time: 1692831782.061773 server time is now() + 6 minutes * * */