Optimize syntax highlighting during chat streaming (#6655)

This commit is contained in:
oobabooga 2025-01-11 21:14:10 -03:00 committed by GitHub
parent f1797f4323
commit a0492ce325
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 44 additions and 53 deletions

View File

@ -19,5 +19,5 @@ function copyToClipboard(element) {
} }
function regenerateClick() { function regenerateClick() {
document.getElementById("Regenerate").click(); document.getElementById("Regenerate").click();
} }

View File

@ -177,47 +177,30 @@ function isElementVisibleOnScreen(element) {
); );
} }
function getVisibleMessagesIndexes() {
const elements = document.querySelectorAll(".message-body");
const visibleIndexes = [];
elements.forEach((element, index) => {
if (isElementVisibleOnScreen(element) && !element.hasAttribute("data-highlighted")) {
visibleIndexes.push(index);
}
});
return visibleIndexes;
}
function doSyntaxHighlighting() { function doSyntaxHighlighting() {
const indexes = getVisibleMessagesIndexes(); const messageBodies = document.querySelectorAll(".message-body");
const elements = document.querySelectorAll(".message-body");
if (indexes.length > 0) { if (messageBodies.length > 0) {
observer.disconnect(); observer.disconnect();
indexes.forEach((index) => { messageBodies.forEach((messageBody) => {
const element = elements[index]; if (isElementVisibleOnScreen(messageBody)) {
// Handle both code and math in a single pass through each message
const codeBlocks = messageBody.querySelectorAll("pre code:not([data-highlighted])");
codeBlocks.forEach((codeBlock) => {
hljs.highlightElement(codeBlock);
codeBlock.setAttribute("data-highlighted", "true");
});
// Tag this element to prevent it from being highlighted twice renderMathInElement(messageBody, {
element.setAttribute("data-highlighted", "true"); delimiters: [
{ left: "$$", right: "$$", display: true },
// Perform syntax highlighting { left: "$", right: "$", display: false },
const codeBlocks = element.querySelectorAll("pre code"); { left: "\\(", right: "\\)", display: false },
{ left: "\\[", right: "\\]", display: true },
codeBlocks.forEach((codeBlock) => { ],
hljs.highlightElement(codeBlock); });
}); }
renderMathInElement(element, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\\(", right: "\\)", display: false },
{ left: "\\[", right: "\\]", display: true },
],
});
}); });
observer.observe(targetElement, config); observer.observe(targetElement, config);

View File

@ -182,23 +182,31 @@ def create_event_handlers():
# Morph HTML updates instead of updating everything # Morph HTML updates instead of updating everything
shared.gradio['display'].change(None, gradio('display'), None, shared.gradio['display'].change(None, gradio('display'), None,
js=""" js="""
(text) => { (text) => {
morphdom( morphdom(
document.getElementById('chat').parentNode, document.getElementById('chat').parentNode,
'<div class="prose svelte-1ybaih5">' + text + '</div>', '<div class="prose svelte-1ybaih5">' + text + '</div>',
{ {
onBeforeElUpdated: function(fromEl, toEl) { onBeforeElUpdated: function(fromEl, toEl) {
if (fromEl.isEqualNode(toEl)) { if (fromEl.tagName === 'PRE' && fromEl.querySelector('code[data-highlighted]')) {
return false; // Skip identical nodes const fromCode = fromEl.querySelector('code');
} const toCode = toEl.querySelector('code');
return true; // Update only if nodes differ
} if (fromCode && toCode && fromCode.textContent === toCode.textContent) {
} // If the <code> content is the same, preserve the entire <pre> element
); toEl.className = fromEl.className;
toEl.innerHTML = fromEl.innerHTML;
return false; // Skip updating the <pre> element
}
}
return !fromEl.isEqualNode(toEl); // Update only if nodes differ
} }
""" }
) );
}
"""
);
shared.gradio['Generate'].click( shared.gradio['Generate'].click(
ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then( ui.gather_interface_values, gradio(shared.input_elements), gradio('interface_state')).then(