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:
parent
8334149cb2
commit
351ba167f5
|
@ -137,6 +137,7 @@
|
||||||
"turndown-plugin-gfm": "^1.0.2",
|
"turndown-plugin-gfm": "^1.0.2",
|
||||||
"undici": "^7.3.0",
|
"undici": "^7.3.0",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
|
"vega": "^6.2.0",
|
||||||
"vite-plugin-static-copy": "^2.2.0",
|
"vite-plugin-static-copy": "^2.2.0",
|
||||||
"y-prosemirror": "^1.3.7",
|
"y-prosemirror": "^1.3.7",
|
||||||
"yaml": "^2.7.1",
|
"yaml": "^2.7.1",
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import PyodideWorker from '$lib/workers/pyodide.worker?worker';
|
import PyodideWorker from '$lib/workers/pyodide.worker?worker';
|
||||||
import { executeCode } from '$lib/apis/utils';
|
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';
|
import 'highlight.js/styles/github-dark.min.css';
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@
|
||||||
let _token = null;
|
let _token = null;
|
||||||
|
|
||||||
let mermaidHtml = null;
|
let mermaidHtml = null;
|
||||||
|
let vegaHtml = null;
|
||||||
|
|
||||||
let highlightedCode = null;
|
let highlightedCode = null;
|
||||||
let executing = false;
|
let executing = false;
|
||||||
|
@ -326,6 +327,11 @@
|
||||||
onUpdate(token);
|
onUpdate(token);
|
||||||
if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
|
if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
|
||||||
mermaidHtml = await renderMermaidDiagram(code);
|
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}
|
{:else}
|
||||||
<pre class="mermaid">{code}</pre>
|
<pre class="mermaid">{code}</pre>
|
||||||
{/if}
|
{/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}
|
{:else}
|
||||||
<div
|
<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"
|
class="absolute left-0 right-0 py-2.5 pr-3 text-text-300 pl-4.5 text-xs font-medium dark:text-white"
|
||||||
|
|
|
@ -1596,3 +1596,16 @@ export const renderMermaidDiagram = async (code: string) => {
|
||||||
return '';
|
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 '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue