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

自动渲染 ChatGPT 页面 (OpenAI, you, bing 等) 上的 LaTeX 数学公式。

当前为 2023-02-16 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name ChatGPT LaTeX Auto Render (OpenAI, you, bing, etc.)
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3.4
  5. // @author Scruel
  6. // @homepage https://github.com/scruel/tampermonkey-scripts
  7. // @description Auto typeset LaTeX math formulas on ChatGPT pages (OpenAI, you, bing, etc.).
  8. // @description:zh-CN 自动渲染 ChatGPT 页面 (OpenAI, you, bing 等) 上的 LaTeX 数学公式。
  9. // @match https://chat.openai.com/chat/*
  10. // @match https://you.com/search?q=chatgpt*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. 'use strict';
  15.  
  16. async function addScript(url) {
  17. const scriptElement = document.createElement('script');
  18. scriptElement.src = url;
  19. scriptElement.async = true;
  20.  
  21. const headElement = document.getElementsByTagName('head')[0] || document.documentElement;
  22. headElement.appendChild(scriptElement);
  23. await waitScriptLoaded();
  24. }
  25.  
  26. function waitScriptLoaded() {
  27. return new Promise(async (resolve, reject) => {
  28. const resolver = () => {
  29. if (MathJax.hasOwnProperty('Hub')) {
  30. resolve();
  31. return;
  32. }
  33. if (window.ChatLatex.loadCount > 100) {
  34. setTipsElementText("Failed to load MathJax, try refresh.");
  35. reject("Failed to load MathJax, try refresh.");
  36. return;
  37. }
  38. window.ChatLatex.loadCount += 1;
  39. window.setTimeout(resolver, 200);
  40. }
  41. resolver();
  42. });
  43. }
  44.  
  45. function renderTrigger() {
  46. setTimeout(renderLatex, window.renderDelay);
  47. }
  48.  
  49. function loadingCheckFn() {
  50. const commonCheck = (query) => {
  51. const submitButton = document.querySelector(query);
  52. return submitButton && !submitButton.disabled;
  53. }
  54. if (window.location.host == 'you.com') {
  55. window.isChatLoading = () => {
  56. return commonCheck('main div[data-testid="youchat-input"] textarea+button');
  57. }
  58. }
  59. if (window.location.host == 'openai.com') {
  60. window.isChatLoading = () => {
  61. return commonCheck('main form textarea+button');
  62. }
  63. }
  64. }
  65.  
  66. function renderLatex() {
  67. if (window.isChatLoading()) {
  68. console.log("Rendering...")
  69. MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
  70. }
  71. renderTrigger();
  72. }
  73.  
  74. function showTipsElement() {
  75. const tipsElement = window.ChatLatex.tipsElement;
  76. tipsElement.style.position = "fixed";
  77. tipsElement.style.left = "10px";
  78. tipsElement.style.bottom = "10px";
  79. tipsElement.style.background = '#333';
  80. tipsElement.style.color = '#fff';
  81. document.body.appendChild(tipsElement);
  82. }
  83.  
  84. function setTipsElementText(text) {
  85. window.ChatLatex.tipsElement.innerHTML = text;
  86. }
  87.  
  88. function hideTipsElement(timeout=3) {
  89. window.setTimeout(() => {window.ChatLatex.tipsElement.hidden=true}, 3000);
  90. }
  91.  
  92. (async function() {
  93. window.ChatLatex = {
  94. tipsElement: document.createElement("div"),
  95. loadCount: 0
  96. }
  97. window.MathJax = {
  98. tex2jax: {
  99. inlineMath: [['$', '$']],
  100. displayMath : [['$$', '$$']]
  101. },
  102. CommonHTML: { linebreaks: { automatic: true } },
  103. "HTML-CSS": { linebreaks: { automatic: true } },
  104. SVG: { linebreaks: { automatic: true } },
  105. };
  106.  
  107. showTipsElement();
  108. setTipsElementText("Loading MathJax...");
  109. await addScript('https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS_CHTML');
  110. setTipsElementText("MathJax Loaded.");
  111. hideTipsElement();
  112.  
  113. loadingCheckFn();
  114. window.renderDelay = 1000;
  115. renderTrigger();
  116. })();