@ai-gui/plugin-chart 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/index.cjs +122 -0
- package/dist/index.d.cts +30 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +97 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Liang Li
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @ai-gui/plugin-chart
|
|
2
|
+
|
|
3
|
+
Chart plugin for [AIGUI](../../README.md), powered by [ECharts](https://echarts.apache.org). The model emits a ` ```chart ` fenced block containing an ECharts option JSON. Charts are complete-gated: a skeleton shows while the option streams, then the full chart renders (never partial-drawn).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pnpm add @ai-gui/plugin-chart
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { chart } from "@ai-gui/plugin-chart"
|
|
15
|
+
import { AIRenderer } from "@ai-gui/react"
|
|
16
|
+
|
|
17
|
+
<AIRenderer plugins={[chart({ interactive: true })]} />
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The model emits, e.g.:
|
|
21
|
+
|
|
22
|
+
```chart {"xAxis":{"type":"category","data":["A","B"]},"yAxis":{"type":"value"},"series":[{"type":"bar","data":[1,2]}]}```
|
|
23
|
+
|
|
24
|
+
## Options
|
|
25
|
+
|
|
26
|
+
- `interactive?: boolean` — when true, complete options render a **live** ECharts instance (tooltip / dataZoom / click) via a `mount` output. When false/omitted, they render a static SSR SVG.
|
|
27
|
+
- `gl?: boolean` — when true, render 3D charts via `echarts-gl` (WebGL, live-only; implies interactive). Enables 3D series like `bar3D`, `scatter3D`, `surface`, `line3D`, `globe`, `map3D`.
|
|
28
|
+
- `width?: number` / `height?: number` — chart dimensions (default 600 × 400).
|
|
29
|
+
|
|
30
|
+
## Exports
|
|
31
|
+
|
|
32
|
+
- `chart(options)` — the plugin.
|
|
33
|
+
- `chartPromptSpec()` — the prompt-spec string (also folded in automatically by `buildSystemPrompt` when the plugin is passed).
|
|
34
|
+
|
|
35
|
+
See the [root README](../../README.md) for the full plugin list.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//#region rolldown:runtime
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
const echarts = __toESM(require("echarts"));
|
|
26
|
+
const __ai_gui_core = __toESM(require("@ai-gui/core"));
|
|
27
|
+
|
|
28
|
+
//#region src/index.ts
|
|
29
|
+
/** Memoized `echarts-gl` side-effect import, shared across all mounts. */
|
|
30
|
+
let glReady = null;
|
|
31
|
+
const loadGl = () => glReady ??= import("echarts-gl");
|
|
32
|
+
/** Prompt spec describing the ```chart``` fence for LLM system prompts. */
|
|
33
|
+
function chartPromptSpec() {
|
|
34
|
+
return [
|
|
35
|
+
"Charts (fenced): ```chart <ECharts option JSON>```.",
|
|
36
|
+
"Example: ```chart {\"xAxis\":{\"type\":\"category\",\"data\":[\"A\",\"B\"]},\"yAxis\":{\"type\":\"value\"},\"series\":[{\"type\":\"bar\",\"data\":[1,2]}]}```",
|
|
37
|
+
"When gl mode is enabled, 3D types are available: bar3D, scatter3D, surface, line3D, globe, map3D (WebGL, live-only)."
|
|
38
|
+
].join("\n");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Chart plugin: claims the `chart` node type and renders an ECharts option JSON
|
|
42
|
+
* to a framework-neutral SVG string via ECharts SSR. Sync, never throws.
|
|
43
|
+
*/
|
|
44
|
+
function chart(opts = {}) {
|
|
45
|
+
const width = opts.width ?? 600;
|
|
46
|
+
const height = opts.height ?? 400;
|
|
47
|
+
const gl = opts.gl ?? false;
|
|
48
|
+
const interactive = gl || (opts.interactive ?? false);
|
|
49
|
+
const render = (node) => {
|
|
50
|
+
const { data: option, complete } = (0, __ai_gui_core.parsePartialJSON)(node.content ?? "");
|
|
51
|
+
if (!complete || option == null || typeof option !== "object") return {
|
|
52
|
+
kind: "html",
|
|
53
|
+
html: `<div data-aigui-chart-loading></div>`
|
|
54
|
+
};
|
|
55
|
+
if (gl) {
|
|
56
|
+
const opt = option;
|
|
57
|
+
return {
|
|
58
|
+
kind: "mount",
|
|
59
|
+
mount: (el) => {
|
|
60
|
+
let inst;
|
|
61
|
+
let disposed = false;
|
|
62
|
+
loadGl().then(() => {
|
|
63
|
+
if (disposed) return;
|
|
64
|
+
inst = echarts.init(el, void 0, {
|
|
65
|
+
width,
|
|
66
|
+
height
|
|
67
|
+
});
|
|
68
|
+
inst.setOption(opt);
|
|
69
|
+
}).catch(() => {});
|
|
70
|
+
return () => {
|
|
71
|
+
disposed = true;
|
|
72
|
+
inst?.dispose();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (interactive) {
|
|
78
|
+
const opt = option;
|
|
79
|
+
return {
|
|
80
|
+
kind: "mount",
|
|
81
|
+
mount: (el) => {
|
|
82
|
+
const inst = echarts.init(el, void 0, {
|
|
83
|
+
renderer: "svg",
|
|
84
|
+
width,
|
|
85
|
+
height
|
|
86
|
+
});
|
|
87
|
+
inst.setOption(opt);
|
|
88
|
+
return () => inst.dispose();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const inst = echarts.init(null, null, {
|
|
94
|
+
renderer: "svg",
|
|
95
|
+
ssr: true,
|
|
96
|
+
width,
|
|
97
|
+
height
|
|
98
|
+
});
|
|
99
|
+
inst.setOption(option);
|
|
100
|
+
const svg = inst.renderToSVGString();
|
|
101
|
+
inst.dispose();
|
|
102
|
+
return {
|
|
103
|
+
kind: "html",
|
|
104
|
+
html: svg
|
|
105
|
+
};
|
|
106
|
+
} catch (e) {
|
|
107
|
+
return {
|
|
108
|
+
kind: "html",
|
|
109
|
+
html: `<pre data-aigui-chart-error>${String(e?.message ?? e)}</pre>`
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
name: "chart",
|
|
115
|
+
nodeRenderers: { chart: render },
|
|
116
|
+
promptSpec: chartPromptSpec()
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
exports.chart = chart
|
|
122
|
+
exports.chartPromptSpec = chartPromptSpec
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AIGuiPlugin } from "@ai-gui/core";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
interface ChartOptions {
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
/**
|
|
8
|
+
* When true, complete options render a LIVE ECharts instance via the `mount`
|
|
9
|
+
* RenderOutput (enabling tooltip/dataZoom/click). When false/omitted, complete
|
|
10
|
+
* options render a static SSR SVG. Incomplete options always render the loading
|
|
11
|
+
* placeholder regardless of this flag.
|
|
12
|
+
*/
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* When true, complete options render a LIVE ECharts instance using the
|
|
16
|
+
* `echarts-gl` extension and the canvas renderer (required by WebGL) via the
|
|
17
|
+
* `mount` RenderOutput. This enables 3D chart types (bar3D/scatter3D/surface/
|
|
18
|
+
* line3D/globe/map3D), which have no static SSR form. `gl` implies interactive.
|
|
19
|
+
* The `echarts-gl` module is lazily imported and memoized across mounts.
|
|
20
|
+
*/
|
|
21
|
+
gl?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Prompt spec describing the ```chart``` fence for LLM system prompts. */
|
|
24
|
+
declare function chartPromptSpec(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Chart plugin: claims the `chart` node type and renders an ECharts option JSON
|
|
27
|
+
* to a framework-neutral SVG string via ECharts SSR. Sync, never throws.
|
|
28
|
+
*/
|
|
29
|
+
declare function chart(opts?: ChartOptions): AIGuiPlugin; //#endregion
|
|
30
|
+
export { ChartOptions, chart, chartPromptSpec };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AIGuiPlugin } from "@ai-gui/core";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
interface ChartOptions {
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
/**
|
|
8
|
+
* When true, complete options render a LIVE ECharts instance via the `mount`
|
|
9
|
+
* RenderOutput (enabling tooltip/dataZoom/click). When false/omitted, complete
|
|
10
|
+
* options render a static SSR SVG. Incomplete options always render the loading
|
|
11
|
+
* placeholder regardless of this flag.
|
|
12
|
+
*/
|
|
13
|
+
interactive?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* When true, complete options render a LIVE ECharts instance using the
|
|
16
|
+
* `echarts-gl` extension and the canvas renderer (required by WebGL) via the
|
|
17
|
+
* `mount` RenderOutput. This enables 3D chart types (bar3D/scatter3D/surface/
|
|
18
|
+
* line3D/globe/map3D), which have no static SSR form. `gl` implies interactive.
|
|
19
|
+
* The `echarts-gl` module is lazily imported and memoized across mounts.
|
|
20
|
+
*/
|
|
21
|
+
gl?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Prompt spec describing the ```chart``` fence for LLM system prompts. */
|
|
24
|
+
declare function chartPromptSpec(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Chart plugin: claims the `chart` node type and renders an ECharts option JSON
|
|
27
|
+
* to a framework-neutral SVG string via ECharts SSR. Sync, never throws.
|
|
28
|
+
*/
|
|
29
|
+
declare function chart(opts?: ChartOptions): AIGuiPlugin; //#endregion
|
|
30
|
+
export { ChartOptions, chart, chartPromptSpec };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as echarts from "echarts";
|
|
2
|
+
import { parsePartialJSON } from "@ai-gui/core";
|
|
3
|
+
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
/** Memoized `echarts-gl` side-effect import, shared across all mounts. */
|
|
6
|
+
let glReady = null;
|
|
7
|
+
const loadGl = () => glReady ??= import("echarts-gl");
|
|
8
|
+
/** Prompt spec describing the ```chart``` fence for LLM system prompts. */
|
|
9
|
+
function chartPromptSpec() {
|
|
10
|
+
return [
|
|
11
|
+
"Charts (fenced): ```chart <ECharts option JSON>```.",
|
|
12
|
+
"Example: ```chart {\"xAxis\":{\"type\":\"category\",\"data\":[\"A\",\"B\"]},\"yAxis\":{\"type\":\"value\"},\"series\":[{\"type\":\"bar\",\"data\":[1,2]}]}```",
|
|
13
|
+
"When gl mode is enabled, 3D types are available: bar3D, scatter3D, surface, line3D, globe, map3D (WebGL, live-only)."
|
|
14
|
+
].join("\n");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Chart plugin: claims the `chart` node type and renders an ECharts option JSON
|
|
18
|
+
* to a framework-neutral SVG string via ECharts SSR. Sync, never throws.
|
|
19
|
+
*/
|
|
20
|
+
function chart(opts = {}) {
|
|
21
|
+
const width = opts.width ?? 600;
|
|
22
|
+
const height = opts.height ?? 400;
|
|
23
|
+
const gl = opts.gl ?? false;
|
|
24
|
+
const interactive = gl || (opts.interactive ?? false);
|
|
25
|
+
const render = (node) => {
|
|
26
|
+
const { data: option, complete } = parsePartialJSON(node.content ?? "");
|
|
27
|
+
if (!complete || option == null || typeof option !== "object") return {
|
|
28
|
+
kind: "html",
|
|
29
|
+
html: `<div data-aigui-chart-loading></div>`
|
|
30
|
+
};
|
|
31
|
+
if (gl) {
|
|
32
|
+
const opt = option;
|
|
33
|
+
return {
|
|
34
|
+
kind: "mount",
|
|
35
|
+
mount: (el) => {
|
|
36
|
+
let inst;
|
|
37
|
+
let disposed = false;
|
|
38
|
+
loadGl().then(() => {
|
|
39
|
+
if (disposed) return;
|
|
40
|
+
inst = echarts.init(el, void 0, {
|
|
41
|
+
width,
|
|
42
|
+
height
|
|
43
|
+
});
|
|
44
|
+
inst.setOption(opt);
|
|
45
|
+
}).catch(() => {});
|
|
46
|
+
return () => {
|
|
47
|
+
disposed = true;
|
|
48
|
+
inst?.dispose();
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (interactive) {
|
|
54
|
+
const opt = option;
|
|
55
|
+
return {
|
|
56
|
+
kind: "mount",
|
|
57
|
+
mount: (el) => {
|
|
58
|
+
const inst = echarts.init(el, void 0, {
|
|
59
|
+
renderer: "svg",
|
|
60
|
+
width,
|
|
61
|
+
height
|
|
62
|
+
});
|
|
63
|
+
inst.setOption(opt);
|
|
64
|
+
return () => inst.dispose();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const inst = echarts.init(null, null, {
|
|
70
|
+
renderer: "svg",
|
|
71
|
+
ssr: true,
|
|
72
|
+
width,
|
|
73
|
+
height
|
|
74
|
+
});
|
|
75
|
+
inst.setOption(option);
|
|
76
|
+
const svg = inst.renderToSVGString();
|
|
77
|
+
inst.dispose();
|
|
78
|
+
return {
|
|
79
|
+
kind: "html",
|
|
80
|
+
html: svg
|
|
81
|
+
};
|
|
82
|
+
} catch (e) {
|
|
83
|
+
return {
|
|
84
|
+
kind: "html",
|
|
85
|
+
html: `<pre data-aigui-chart-error>${String(e?.message ?? e)}</pre>`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
name: "chart",
|
|
91
|
+
nodeRenderers: { chart: render },
|
|
92
|
+
promptSpec: chartPromptSpec()
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
export { chart, chartPromptSpec };
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ai-gui/plugin-chart",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ECharts chart plugin for AIGUI — static SVG, interactive, and 3D (echarts-gl).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"llm",
|
|
7
|
+
"ai",
|
|
8
|
+
"streaming",
|
|
9
|
+
"markdown",
|
|
10
|
+
"echarts",
|
|
11
|
+
"chart",
|
|
12
|
+
"visualization",
|
|
13
|
+
"3d",
|
|
14
|
+
"plugin",
|
|
15
|
+
"aigui"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "Liang Li <ll_faw@hotmail.com>",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/liliang-cn/aigui.git",
|
|
22
|
+
"directory": "packages/plugin-chart"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/liliang-cn/aigui#readme",
|
|
25
|
+
"bugs": "https://github.com/liliang-cn/aigui/issues",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js",
|
|
34
|
+
"require": "./dist/index.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"README.md",
|
|
40
|
+
"LICENSE"
|
|
41
|
+
],
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"echarts": "^5.5.1",
|
|
47
|
+
"echarts-gl": "^2.0.9",
|
|
48
|
+
"@ai-gui/core": "0.1.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsdown",
|
|
52
|
+
"typecheck": "tsc --noEmit"
|
|
53
|
+
}
|
|
54
|
+
}
|