diff --git a/crates/openfang-api/src/webchat.rs b/crates/openfang-api/src/webchat.rs index ec8ada30e..d37e014c9 100644 --- a/crates/openfang-api/src/webchat.rs +++ b/crates/openfang-api/src/webchat.rs @@ -127,6 +127,8 @@ const WEBCHAT_HTML: &str = concat!( "\n", include_str!("../static/js/pages/overview.js"), "\n", + include_str!("../static/js/katex.js"), + "\n", include_str!("../static/js/pages/chat.js"), "\n", include_str!("../static/js/pages/agents.js"), diff --git a/crates/openfang-api/static/index_head.html b/crates/openfang-api/static/index_head.html index e052c081e..7bea95786 100644 --- a/crates/openfang-api/static/index_head.html +++ b/crates/openfang-api/static/index_head.html @@ -11,7 +11,4 @@ - - - diff --git a/crates/openfang-api/static/js/app.js b/crates/openfang-api/static/js/app.js index 6e1132c32..e30a80b41 100644 --- a/crates/openfang-api/static/js/app.js +++ b/crates/openfang-api/static/js/app.js @@ -66,26 +66,6 @@ function renderMarkdown(text) { return escapeHtml(text); } -// Render LaTeX math in the chat message container using KaTeX auto-render. -// Call this after new messages are inserted into the DOM. -function renderLatex(el) { - if (typeof renderMathInElement !== 'function') return; - var target = el || document.getElementById('messages'); - if (!target) return; - try { - renderMathInElement(target, { - delimiters: [ - { left: '$$', right: '$$', display: true }, - { left: '\\[', right: '\\]', display: true }, - { left: '$', right: '$', display: false }, - { left: '\\(', right: '\\)', display: false } - ], - throwOnError: false, - trust: false - }); - } catch(e) { /* KaTeX render error — ignore gracefully */ } -} - function copyCode(btn) { var code = btn.nextElementSibling; if (code) { diff --git a/crates/openfang-api/static/js/katex.js b/crates/openfang-api/static/js/katex.js new file mode 100644 index 000000000..8a704ade8 --- /dev/null +++ b/crates/openfang-api/static/js/katex.js @@ -0,0 +1,84 @@ +// On-demand KaTeX loader and renderer for chat messages. + +var KATEX_VERSION = '0.16.21'; +var KATEX_CSS_URL = 'https://cdn.jsdelivr.net/npm/katex@' + KATEX_VERSION + '/dist/katex.min.css'; +var KATEX_JS_URL = 'https://cdn.jsdelivr.net/npm/katex@' + KATEX_VERSION + '/dist/katex.min.js'; +var KATEX_AUTORENDER_URL = + 'https://cdn.jsdelivr.net/npm/katex@' + KATEX_VERSION + '/dist/contrib/auto-render.min.js'; +var katexLoadPromise = null; + +function hasLatexDelimiters(text) { + if (!text) return false; + return /\$\$|\\\[|\\\(|\$(?=\S)[^$\n]+\$/.test(text); +} + +function loadScript(url) { + return new Promise(function (resolve, reject) { + var script = document.createElement('script'); + script.src = url; + script.async = true; + script.onload = function () { + resolve(); + }; + script.onerror = function () { + reject(new Error('Failed to load script: ' + url)); + }; + document.head.appendChild(script); + }); +} + +function ensureKatexLoaded() { + if (typeof renderMathInElement === 'function') return Promise.resolve(true); + if (katexLoadPromise) return katexLoadPromise; + + katexLoadPromise = new Promise(function (resolve) { + var cssId = 'openfang-katex-css'; + if (!document.getElementById(cssId)) { + var link = document.createElement('link'); + link.id = cssId; + link.rel = 'stylesheet'; + link.href = KATEX_CSS_URL; + document.head.appendChild(link); + } + + loadScript(KATEX_JS_URL) + .then(function () { + return loadScript(KATEX_AUTORENDER_URL); + }) + .then(function () { + resolve(typeof renderMathInElement === 'function'); + }) + .catch(function () { + katexLoadPromise = null; + resolve(false); + }); + }); + + return katexLoadPromise; +} + +// Render LaTeX math in the chat message container using KaTeX auto-render. +// Call this after new messages are inserted into the DOM. +function renderLatex(el) { + var target = el || document.getElementById('messages'); + if (!target) return; + if (!hasLatexDelimiters(target.textContent || '')) return; + + ensureKatexLoaded().then(function (ok) { + if (!ok || typeof renderMathInElement !== 'function') return; + try { + renderMathInElement(target, { + delimiters: [ + { left: '$$', right: '$$', display: true }, + { left: '\\[', right: '\\]', display: true }, + { left: '$', right: '$', display: false }, + { left: '\\(', right: '\\)', display: false }, + ], + throwOnError: false, + trust: false, + }); + } catch (e) { + /* KaTeX render error — ignore gracefully */ + } + }); +}