- // ==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
-
- *
- *
- */