mirror of
https://github.com/open-webui/open-webui.git
synced 2026-11-15 18:55:07 +03:00
67 lines
3.6 KiB
Python
67 lines
3.6 KiB
Python
"""The visualization tool validates source; only the isolated browser frame executes it."""
|
||
|
||
from typing import Literal
|
||
|
||
MAX_HTML_BYTES = 256 * 1024
|
||
|
||
DEFAULT_VISUALIZATION_PROMPT_TEMPLATE = """\
|
||
Render an interactive chart, SVG diagram, calculator, or explainer inline in chat.
|
||
|
||
Use proactively when a visual helps the user understand or explore the answer,
|
||
even when they have not explicitly asked for a visualization. Good uses include
|
||
comparisons, trends, mechanisms, and exploring how inputs change an outcome.
|
||
Prefer plain text for simple facts or short answers. Put the entire visualization
|
||
in html; write explanation in normal messages. HTML/SVG previews
|
||
appear progressively. Scripts run once, after the complete call is accepted.
|
||
Default to a lean, compact, flat inline design: concise labels, restrained spacing,
|
||
readable text, and only useful controls. Use regular font weight almost everywhere;
|
||
use medium (500) sparingly and never heavier weights. Prefer flat layouts to cards.
|
||
Inherit the default body text size (0.90625rem, matching chat) for normal text
|
||
and labels; do not shrink body text to make a layout compact.
|
||
Use rem for CSS typography, spacing, radii, and dimensions; use responsive widths.
|
||
Prefer 0.25–0.5rem gaps and padding, with 0.75rem only between distinct sections.
|
||
Keep labels close to controls and trim heading, paragraph, and list margins.
|
||
Avoid fixed-pixel styling and empty space.
|
||
The chat displays title above the visual; avoid repeating it in html. Avoid hero
|
||
headers, introductory copy, decorative gradients/shadows, oversized typography,
|
||
and nested cards unless requested.
|
||
Let content determine height; use the chat's scrolling, not internal scroll areas.
|
||
Emit a fragment: styles first, visible content next, classic inline scripts last.
|
||
Use addEventListener, not onclick attributes or DOMContentLoaded. No external
|
||
scripts, imports, fetch, frames, or parent-page access are available.
|
||
Request libraries=["chartjs"] to get window.Chart (no script URL needed).
|
||
Wrap each canvas in .chart-container; use responsive:true, maintainAspectRatio:false.
|
||
Buttons, inputs, tables, and details have built-in styling. Use CSS variables
|
||
--owui-background, --owui-surface, --owui-text, --owui-muted, --owui-border,
|
||
--owui-accent. Include accessible labels and responsive layouts; avoid vh heights.
|
||
window.openwebui.context supplies theme, language, direction, reducedMotion.
|
||
Listen for openwebui:contextchange for custom canvas theme updates.
|
||
await openwebui.sendMessage(text) requests a user-confirmed follow-up and returns
|
||
{sent:boolean}. Never assume access to chat history, credentials, or storage."""
|
||
|
||
|
||
async def render_visualization(
|
||
title: str,
|
||
html: str,
|
||
libraries: list[Literal['chartjs']] | None = None,
|
||
) -> dict:
|
||
"""Render an interactive visualization inline in chat.
|
||
|
||
:param title: Short accessible title, 1–160 characters.
|
||
:param html: Self-contained HTML/SVG/CSS/JavaScript fragment, at most 256 KiB UTF-8.
|
||
:param libraries: Omit or use [] for native HTML/SVG, or ["chartjs"] for charts.
|
||
"""
|
||
if not isinstance(title, str) or not 1 <= len(title.strip()) <= 160:
|
||
return {'error': 'title must contain 1–160 characters'}
|
||
if not isinstance(html, str) or not html.strip():
|
||
return {'error': 'html must be a nonempty string'}
|
||
try:
|
||
size = len(html.encode('utf-8'))
|
||
except UnicodeEncodeError:
|
||
return {'error': 'html must contain valid Unicode'}
|
||
if size > MAX_HTML_BYTES:
|
||
return {'error': 'html exceeds the 256 KiB limit'}
|
||
if libraries is not None and libraries not in ([], ['chartjs']):
|
||
return {'error': 'libraries must be [] or ["chartjs"]'}
|
||
return {'status': 'accepted'}
|