ChatGPTNextWeb / ChatGPTNextWeb/NextChat
[Feature Request] 在对话中直接渲染 AI 生成的数据图表(vis 代码块)
- Dominant language
- TypeScript
- Stars
- 88.8k
- Forks
- 59.1k
- PR merge metrics
- No merged PRs in 30d
Description
### 🥰 需求描述
### 痛点
NextChat 已经很好地支持了 ` ```mermaid ` 代码块渲染为流程图。但当 LLM 需要展示**数据**时——销售趋势、用户分析、调查结果——只能输出 Markdown 表格或纯文本,用户需要把数据复制到别处才能可视化。
这是真实的需求。[#5707](https://github.com/ChatGPTNextWeb/NextChat/issues/5707) 明确提出了数据可视化需求——"利用本地搭建的大模型做数据分析,并进行可视化展示",并提到希望使用 echarts 等可视化库。
缺少的是一个对 LLM 友好、像 mermaid 一样易生成的图表格式——不过 mermaid 画的是流程图,而用户需要的是数据图表。
### 为什么适合 NextChat
1. **和 mermaid 一样的模式**——用户已经理解"代码块语言 = 渲染的可视化结果"。`vis` 对数据图表来说是完全相同的思维模型,零学习成本。
2. **响应真实需求**——[#5707](https://github.com/ChatGPTNextWeb/NextChat/issues/5707) 以及类似请求表明,用户希望在对话中通过自然语言驱动数据可视化。GPT-Vis 是这个等式的渲染端。
3. **26 种图表,一种语法**——统计图(折线/柱状/饼图/散点/雷达/漏斗等)+ 关系图(思维导图/流程图/网络图/组织架构图)+ 文本可视化(词云/表格)。
4. **零破坏性变更**——vis 检测与 mermaid/HTML 检测并存在 `PreCode` 中。没有 `vis` 代码块时静默跳过。
5. **包体积可控**——`@antv/gpt-vis` UMD 约 1MB gzipped,可通过动态 `import()` 加载,不阻塞首屏。
6. **暗色模式兼容**——内置 `dark` 主题,与 NextChat 暗色模式匹配。通过 `new GPTVis({ container: el, theme: 'dark' })` 切换。
### 🧐 解决方案
### 方案
**[GPT-Vis](https://github.com/antvis/GPT-Vis)**(`@antv/gpt-vis`,MIT 协议,AntV 出品)是专为 LLM 输出设计的可视化库。LLM 只需输出类 Markdown 的 `vis` 语法——就像输出 mermaid 一样简单:
````markdown
```vis
vis line
title 月度销售额
axisXTitle 月份
axisYTitle 营收(万元)
data
- month 1月
value 120
- month 2月
value 200
- month 3月
value 150
```
````
这段 Markdown 直接渲染为一张可交互折线图。LLM 只写 Markdown,不需要 JavaScript、不需要 JSON、不需要 API 调用。
**提案:在现有 mermaid 支持旁边增加 `vis` 代码块支持**(约 40 行代码),完全复用已有的渲染模式。
### 概念验证
NextChat 已经有完美的集成模式。在 `app/components/markdown.tsx` 中,`PreCode` 组件检测 `code.language-mermaid` 并用 `` 渲染。`vis` 可以用完全一样的方式:
```tsx
// app/components/markdown.tsx — 在现有 Mermaid 组件旁边添加
import { GPTVis, isVisSyntax } from '@antv/gpt-vis';
function VisChart(props: { code: string }) {
const ref = useRef(null);
const visRef = useRef(null);
useEffect(() => {
if (!ref.current) return;
visRef.current = new GPTVis({ container: ref.current });
return () => visRef.current?.destroy();
}, []);
useEffect(() => {
if (visRef.current && isVisSyntax(props.code)) {
visRef.current.render(props.code);
}
}, [props.code]);
return
}
// 在 PreCode 组件中,在 mermaid 检测旁边添加:
export function PreCode(props: { children: any }) {
// ... 现有 state ...
const [mermaidCode, setMermaidCode] = useState('');
const [visCode, setVisCode] = useState(''); // 新增
const renderArtifacts = useDebouncedCallback(() => {
if (!ref.current) return;
// ... 现有 mermaid 检测 ...
const visDom = ref.current.querySelector('code.language-vis'); // 新增
if (visDom) {
setVisCode((visDom as HTMLElement).innerText); // 新增
}
// ... 其余不变 ...
}, 600);
return (
<>
{/* ... 现有 pre + 复制按钮 ... */}
{mermaidCode.length > 0 && }
{visCode.length > 0 && ( // 新增
// 新增
)}
);
}
```
集成方式完全复制 mermaid 的现有模式——同样的检测逻辑、同样的组件结构、同样的生命周期。
### 流式渲染(附赠能力)
GPT-Vis 为流式输出而设计。在 LLM 逐 token 输出时,图表可以增量渲染:
```tsx
// 流式场景:每次更新只渲染到最后一个完整行
useEffect(() => {
if (!visRef.current || !isVisSyntax(code)) return;
if (streaming) {
const lastNewline = code.lastIndexOf('\n');
if (lastNewline > 0) {
try {
visRef.current.render(code.slice(0, lastNewline));
} catch {}
}
} else {
visRef.current.render(code);
}
}, [code, streaming]);
```
图表随 LLM token 实时生长,和文本、代码块的流式体验一致。这是 echarts、recharts、chart.js 完全不具备的能力。
### 📝 补充信息
### 相关资源
- GitHub:https://github.com/antvis/GPT-Vis
- 文档站:https://gpt-vis.antv.vision
- npm:https://www.npmjs.com/package/@antv/gpt-vis
- CDN:`https://unpkg.com/@antv/gpt-vis/dist/umd/index.min.js`
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.