FEAT: Add Vega Char Visualizer Renderer

### FEAT: Add Vega Char Visualizer Renderer

Feature required in https://github.com/open-webui/open-webui/discussions/18022

Added npm vega lib to package.json
Added function for visualization renderer to src/libs/utils/index.ts
Added logic to src/lib/components/chat/Messages/CodeBlock.svelte

The treatment is similar as for mermaid diagrams.

Reference: https://vega.github.io/vega/
This commit is contained in:
_00_ 2025-10-03 19:42:04 +02:00
parent 8334149cb2
commit 351ba167f5
3 changed files with 31 additions and 1 deletions

View File

@ -137,6 +137,7 @@
"turndown-plugin-gfm": "^1.0.2",
"undici": "^7.3.0",
"uuid": "^9.0.1",
"vega": "^6.2.0",
"vite-plugin-static-copy": "^2.2.0",
"y-prosemirror": "^1.3.7",
"yaml": "^2.7.1",

View File

@ -6,7 +6,7 @@
import PyodideWorker from '$lib/workers/pyodide.worker?worker';
import { executeCode } from '$lib/apis/utils';
import { copyToClipboard, renderMermaidDiagram } from '$lib/utils';
import { copyToClipboard, renderMermaidDiagram, renderVegaVisualization } from '$lib/utils';
import 'highlight.js/styles/github-dark.min.css';
@ -55,6 +55,7 @@
let _token = null;
let mermaidHtml = null;
let vegaHtml = null;
let highlightedCode = null;
let executing = false;
@ -326,6 +327,11 @@
onUpdate(token);
if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
mermaidHtml = await renderMermaidDiagram(code);
} else if (
(lang === 'vega' || lang === 'vega-lite') &&
(token?.raw ?? '').slice(-4).includes('```')
) {
vegaHtml = await renderVegaVisualization(code);
}
};
@ -397,6 +403,16 @@
{:else}
<pre class="mermaid">{code}</pre>
{/if}
{:else if lang === 'vega' || lang === 'vega-lite'}
{#if vegaHtml}
<SvgPanZoom
className="rounded-3xl max-h-fit overflow-hidden"
svg={vegaHtml}
content={_token.text}
/>
{:else}
<pre class="vega">{code}</pre>
{/if}
{:else}
<div
class="absolute left-0 right-0 py-2.5 pr-3 text-text-300 pl-4.5 text-xs font-medium dark:text-white"

View File

@ -1596,3 +1596,16 @@ export const renderMermaidDiagram = async (code: string) => {
return '';
}
};
export const renderVegaVisualization = async (spec: string) => {
try {
const vega = await import('vega');
const parsedSpec = JSON.parse(spec);
const view = new vega.View(vega.parse(parsedSpec), { renderer: 'none' });
const svg = await view.toSVG();
return svg;
} catch (error) {
console.log('Failed to render Vega visualization:', error);
return '';
}
};