ChatGPT LaTeX Auto Render (OpenAI, you, bing, etc.)

Auto typeset LaTeX math formulas on ChatGPT pages (OpenAI, new bing, you, etc.).

Από την 24/02/2023. Δείτε την τελευταία έκδοση.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name               ChatGPT LaTeX Auto Render (OpenAI, you, bing, etc.)
// @namespace          http://tampermonkey.net/
// @version            0.4.4
// @author             Scruel
// @homepage           https://github.com/scruel/tampermonkey-scripts
// @description        Auto typeset LaTeX math formulas on ChatGPT pages (OpenAI, new bing, you, etc.).
// @description:zh-CN  自动渲染 ChatGPT 页面 (OpenAI, new bing, you 等) 上的 LaTeX 数学公式。
// @match              https://chat.openai.com/*
// @match              https://you.com/search?*&tbm=youchat*
// @match              https://www.bing.com/search?*
// @grant              none
// ==/UserScript==

'use strict';

const _parsed_mark = '_sc_parsed';

function queryAddNoParsed(query) {
    return query + ":not([" + _parsed_mark + "])";
}

function prepareScript() {
    window._sc_afterTypesetElement = (element) => {};
    window._sc_typeset = () => {
        if (window._sc_typesetting) {
            return;
        }
        window._sc_typesetting = true;
        try {
            const messages = window._sc_getMessages();
            messages.forEach((element) => {
                element.setAttribute(_parsed_mark,'');
                MathJax.typesetPromise([element]);
                window._sc_afterTypesetElement(element);
            });
        } catch (ignore) {
        }
        window._sc_typesetting = false;
    }

    const commonCheck = (query) => {
        const submitButton = document.querySelector(query);
        return submitButton && !submitButton.disabled;
    }

    if (window.location.host == "www.bing.com") {
        window._sc_getMessages = () => {
            const elements = [];
            const allChatTurn = document.querySelector("#b_sydConvCont > cib-serp").shadowRoot.querySelector("#cib-conversation-main").shadowRoot.querySelectorAll("#cib-chat-main > cib-chat-turn");
            if (allChatTurn.length == 0) {
                return;
            }
            const allCibMeg = allChatTurn[allChatTurn.length - 1].shadowRoot.querySelector("cib-message-group.response-message-group").shadowRoot.querySelectorAll("cib-message");
            allCibMeg.forEach((cibMeg) => {
                const element = cibMeg.shadowRoot.querySelector(queryAddNoParsed("cib-shared"));
                if (element) {
                    elements.append(element);
                }
            });
            return elements;
        }
        window._sc_isAnswerPrepared = () => {
            const actionBarParent = document.querySelector("#b_sydConvCont > cib-serp");
            if (!actionBarParent) {
                return false;
            }
            const actionBar = actionBarParent.shadowRoot.querySelector("#cib-action-bar-main");
            return actionBar && !actionBar.hasAttribute('cancelable');
        }
    }
    else if (window.location.host == "you.com") {
        window._sc_getMessages = () => {
            return document.querySelectorAll(queryAddNoParsed('#chatHistory div[data-testid="youchat-answer"]'));
        }
        window._sc_isAnswerPrepared = () => {
            return commonCheck('main div[data-testid="youchat-input"] textarea+button');
        }
    }
    else if (window.location.host == "chat.openai.com") {
        window._sc_getMessages = () => {
            return document.querySelectorAll(queryAddNoParsed("div.w-full div.text-base div.items-start"));
        }
        window._sc_afterTypesetElement = (element) => { element.style.display = 'unset';}
        window._sc_isAnswerPrepared = () => {
            return commonCheck('main form textarea+button');
        }
    }
}

function renderTrigger() {
    setTimeout(renderLatex, window.renderDelay);
}

function renderLatex() {
    if (window._sc_isAnswerPrepared()) {
        // console.log("Rendering...")
        window._sc_typeset();
    }
    renderTrigger();
}

async function addScript(url) {
    const scriptElement = document.createElement('script');
    const headElement = document.getElementsByTagName('head')[0] || document.documentElement;
    if (!headElement.appendChild(scriptElement)) {
        // Prevent appendChild overwritten problem.
        headElement.append(scriptElement);
    }
    scriptElement.src = url;

    await waitScriptLoaded();
}

function waitScriptLoaded() {
  return new Promise(async (resolve, reject) => {
      const resolver = () => {
          if (MathJax.hasOwnProperty('typeset')) {
              resolve();
              return;
          }
          if (window._sc_ChatLatex.loadCount > 100) {
              setTipsElementText("Failed to load MathJax, try refresh.");
              reject("Failed to load MathJax, try refresh.");
              return;
          }
          window._sc_ChatLatex.loadCount += 1;
          window.setTimeout(resolver, 200);
      }
      resolver();
  });
}

function setTipsElementText(text) {
    window._sc_ChatLatex.tipsElement.innerHTML = text;
}

function showTipsElement() {
    const tipsElement = window._sc_ChatLatex.tipsElement;
    tipsElement.style.position = "fixed";
    tipsElement.style.left = "10px";
    tipsElement.style.bottom = "10px";
    tipsElement.style.background = '#333';
    tipsElement.style.color = '#fff';
    document.body.appendChild(tipsElement);
}

function hideTipsElement(timeout=3) {
    window.setTimeout(() => {window._sc_ChatLatex.tipsElement.hidden=true}, 3000);
}

(async function() {
    window._sc_ChatLatex = {
        tipsElement: document.createElement("div"),
        loadCount: 0
    }
    window.MathJax = {
        tex: {
            inlineMath: [['$', '$'], ['\\(', '\\)']],
            displayMath  : [['$$', '$$']]
        }
    };

    showTipsElement();
    setTipsElementText("Loading MathJax...");
    await addScript('https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js');
    setTipsElementText("MathJax Loaded.");
    hideTipsElement();

    prepareScript();
    window.renderDelay = 1000;
    renderTrigger();
})();