fix latex rendering
This commit is contained in:
parent
10aa898c83
commit
bb4e17fc70
6 changed files with 80 additions and 4 deletions
Binary file not shown.
1
examples/server/webui/package-lock.json
generated
1
examples/server/webui/package-lock.json
generated
|
@ -12,6 +12,7 @@
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"daisyui": "^4.12.14",
|
"daisyui": "^4.12.14",
|
||||||
"highlight.js": "^11.10.0",
|
"highlight.js": "^11.10.0",
|
||||||
|
"katex": "^0.16.15",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"tailwindcss": "^3.4.15",
|
"tailwindcss": "^3.4.15",
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"daisyui": "^4.12.14",
|
"daisyui": "^4.12.14",
|
||||||
"highlight.js": "^11.10.0",
|
"highlight.js": "^11.10.0",
|
||||||
|
"katex": "^0.16.15",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"postcss": "^8.4.49",
|
"postcss": "^8.4.49",
|
||||||
"tailwindcss": "^3.4.15",
|
"tailwindcss": "^3.4.15",
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
{
|
{
|
||||||
"id": 1734087548327,
|
"id": 1734087548327,
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
"content": "This is the formula:\n$\\frac{e^{x_i}}{\\sum_{j=1}^{n}e^{x_j}}$\n\nGiven an input vector \\(\\mathbf{x} = [x_1, x_2, \\ldots, x_n]\\)\n\n\\[\ny_i = \\frac{e^{x_i}}{\\sum_{j=1}^n e^{x_j}}\n\\]\n\nCode block latex:\n```latex\n\\frac{e^{x_i}}{\\sum_{j=1}^{n}e^{x_j}}\n```",
|
"content": "This is the formula:\n$\\frac{e^{x_i}}{\\sum_{j=1}^{n}e^{x_j}}$\n\nGiven an input vector \\(\\mathbf{x} = [x_1, x_2, \\ldots, x_n]\\)\n\n\\[\ny_i = \\frac{e^{x_i}}{\\sum_{j=1}^n e^{x_j}}\n\\]\n\nCode block latex:\n```latex\n\\frac{e^{x_i}}{\\sum_{j=1}^{n}e^{x_j}}\n```\n\nTest dollar sign: $1234 $4567\n\nInvalid latex syntax: $E = mc^$ and $$E = mc^$$",
|
||||||
"timings": {
|
"timings": {
|
||||||
"prompt_n": 1,
|
"prompt_n": 1,
|
||||||
"prompt_ms": 28.923,
|
"prompt_ms": 28.923,
|
||||||
|
|
66
examples/server/webui/src/katex-gpt.js
Normal file
66
examples/server/webui/src/katex-gpt.js
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import katex from 'katex';
|
||||||
|
|
||||||
|
// Adapted from https://github.com/SchneeHertz/markdown-it-katex-gpt
|
||||||
|
// MIT license
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
delimiters: [
|
||||||
|
{ left: '\\[', right: '\\]', display: true },
|
||||||
|
{ left: '\\(', right: '\\)', display: false },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export function renderLatexHTML(content, display = false) {
|
||||||
|
return katex.renderToString(content, {
|
||||||
|
throwOnError: false,
|
||||||
|
output: 'mathml',
|
||||||
|
displayMode: display,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapedBracketRule(options) {
|
||||||
|
return (state, silent) => {
|
||||||
|
const max = state.posMax;
|
||||||
|
const start = state.pos;
|
||||||
|
|
||||||
|
for (const { left, right, display } of options.delimiters) {
|
||||||
|
|
||||||
|
// Check if it starts with the left delimiter
|
||||||
|
if (!state.src.slice(start).startsWith(left)) continue;
|
||||||
|
|
||||||
|
// Skip the length of the left delimiter
|
||||||
|
let pos = start + left.length;
|
||||||
|
|
||||||
|
// Find the matching right delimiter
|
||||||
|
while (pos < max) {
|
||||||
|
if (state.src.slice(pos).startsWith(right)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No matching right delimiter found, skip to the next match
|
||||||
|
if (pos >= max) continue;
|
||||||
|
|
||||||
|
// If not in silent mode, convert LaTeX formula to MathML
|
||||||
|
if (!silent) {
|
||||||
|
const content = state.src.slice(start + left.length, pos);
|
||||||
|
try {
|
||||||
|
const renderedContent = renderLatexHTML(content, display);
|
||||||
|
const token = state.push('html_inline', '', 0);
|
||||||
|
token.content = renderedContent;
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update position, skip the length of the right delimiter
|
||||||
|
state.pos = pos + right.length;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function (md, options = defaultOptions) {
|
||||||
|
md.inline.ruler.after('text', 'escaped_bracket', escapedBracketRule(options));
|
||||||
|
}
|
|
@ -5,7 +5,8 @@ import TextLineStream from 'textlinestream';
|
||||||
|
|
||||||
// math formula rendering
|
// math formula rendering
|
||||||
import 'katex/dist/katex.min.css';
|
import 'katex/dist/katex.min.css';
|
||||||
import markdownItKatex from '@vscode/markdown-it-katex';
|
import markdownItKatexGpt, { renderLatexHTML } from './katex-gpt';
|
||||||
|
import markdownItKatexNormal from '@vscode/markdown-it-katex';
|
||||||
|
|
||||||
// code highlighting
|
// code highlighting
|
||||||
import hljs from './highlight-config';
|
import hljs from './highlight-config';
|
||||||
|
@ -90,6 +91,9 @@ const VueMarkdown = defineComponent(
|
||||||
const md = shallowRef(new MarkdownIt({
|
const md = shallowRef(new MarkdownIt({
|
||||||
breaks: true,
|
breaks: true,
|
||||||
highlight: function (str, lang) { // Add highlight.js
|
highlight: function (str, lang) { // Add highlight.js
|
||||||
|
if (lang === 'latex') {
|
||||||
|
return renderLatexHTML(str, true);
|
||||||
|
}
|
||||||
if (lang && hljs.getLanguage(lang)) {
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
try {
|
try {
|
||||||
return '<pre><code class="hljs">' +
|
return '<pre><code class="hljs">' +
|
||||||
|
@ -100,7 +104,8 @@ const VueMarkdown = defineComponent(
|
||||||
return '<pre><code class="hljs">' + md.value.utils.escapeHtml(str) + '</code></pre>';
|
return '<pre><code class="hljs">' + md.value.utils.escapeHtml(str) + '</code></pre>';
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
md.value.use(markdownItKatex, {
|
// support latex with double dollar sign and square brackets
|
||||||
|
md.value.use(markdownItKatexGpt, {
|
||||||
delimiters: [
|
delimiters: [
|
||||||
{ left: '\\[', right: '\\]', display: true },
|
{ left: '\\[', right: '\\]', display: true },
|
||||||
{ left: '\\(', right: '\\)', display: false },
|
{ left: '\\(', right: '\\)', display: false },
|
||||||
|
@ -108,6 +113,9 @@ const VueMarkdown = defineComponent(
|
||||||
],
|
],
|
||||||
throwOnError: false,
|
throwOnError: false,
|
||||||
});
|
});
|
||||||
|
// support latex with single dollar sign
|
||||||
|
md.value.use(markdownItKatexNormal, { throwOnError: false });
|
||||||
|
// add copy button to code blocks
|
||||||
const origFenchRenderer = md.value.renderer.rules.fence;
|
const origFenchRenderer = md.value.renderer.rules.fence;
|
||||||
md.value.renderer.rules.fence = (tokens, idx, ...args) => {
|
md.value.renderer.rules.fence = (tokens, idx, ...args) => {
|
||||||
const content = tokens[idx].content;
|
const content = tokens[idx].content;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue