Files
Timothy Jaeryang Baek 2547992b8a refac
2026-11-12 13:39:35 +09:00

67 lines
3.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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'}