feat: 添加信息图插件,并更新相关插件模板和开发文档。

This commit is contained in:
fujie
2025-12-28 20:08:50 +08:00
parent 3ddddb69d7
commit 2f27267b42
20 changed files with 5020 additions and 49 deletions

View File

@@ -0,0 +1,67 @@
# 信息图 - OpenWebUI Action 插件
将文本内容智能转换为美观的信息图,基于蚂蚁集团 AntV Infographic 引擎。
## 功能特性
- 🤖 **AI 驱动**: 使用 LLM 自动分析文本内容并生成信息图语法
- 📊 **多种模板**: 支持列表、流程、层级等多种信息图类型
- 🎨 **自动图标**: 使用 `ref:search` 语法自动匹配高质量图标
- 💾 **多格式导出**: 支持下载 SVG、PNG 和独立 HTML 文件
- 🎯 **零配置**: 开箱即用,无需额外设置
## 安装
1.`信息图.py` 文件复制到 Open WebUI 的插件目录:
```
plugins/actions/infographic/
```
2. 重启 Open WebUI 或在管理界面重新加载插件
3. 在聊天界面的 Action 菜单中即可看到 "信息图" 选项
## 使用方法
1. 在聊天框输入需要可视化的文本内容(建议 100 字符以上)
2. 点击 "信息图" Action 按钮
3. AI 将自动分析文本并生成信息图
4. 可以下载 SVG、PNG 或 HTML 格式的文件
### 示例文本
```
我们的产品开发流程包括三个主要阶段:
1. 需求分析 - 收集和分析用户需求,确定产品方向
2. 设计开发 - 完成 UI/UX 设计和前后端开发
3. 测试上线 - 进行质量验证并正式发布
```
## 配置选项Valves
- **SHOW_STATUS**: 是否显示操作状态更新(默认: True
- **MODEL_ID**: 用于分析的 LLM 模型 ID默认: 使用当前对话模型)
- **MIN_TEXT_LENGTH**: 最小文本长度要求(默认: 100 字符)
- **CLEAR_PREVIOUS_HTML**: 是否清除之前的插件输出(默认: False
## 支持的信息图类型
插件会根据文本内容自动选择最合适的模板:
- **列表型**: `list-row-horizontal-icon-arrow`, `list-grid`
- **层级型**: `tree-vertical`, `tree-horizontal`
## 技术栈
- **后端**: Python, OpenWebUI Action API
- **前端**: AntV Infographic (CDN)
- **AI**: 自定义提示词工程
## 许可证
MIT License
## 致谢
- [AntV Infographic](https://infographic.antv.vision/) - 信息图渲染引擎
- [Open WebUI](https://github.com/open-webui/open-webui) - AI 聊天界面

View File

@@ -0,0 +1,43 @@
# AntV Infographic 智能信息图插件
将文本内容一键转换为精美的信息图。支持列表、层级、流程、关系、对比、分析、图表等多种可视化形式。
## 功能特性
- **智能分析**: 自动识别文本结构,选择最合适的图表模板。
- **丰富模板**: 支持 20+ 种 AntV 信息图模板涵盖列表、树图、思维导图、流程图、桑基图、SWOT、象限图、柱状图、饼图等。
- **自动配图**: 智能搜索并匹配合适的图标。
- **多格式导出**: 支持导出为 SVG, PNG, HTML 格式。
- **多语言支持**: 输出语言跟随用户设定。
## 使用方法
在 Open WebUI 聊天框中,直接输入文本或上传文档,然后启用该插件。插件会自动分析内容并生成信息图。
### 支持的图表类型
#### 1. 列表与层级
- **列表**: 网格卡片 (`list-grid`), 垂直列表 (`list-vertical`)
- **树图**: 垂直树 (`tree-vertical`), 水平树 (`tree-horizontal`)
- **思维导图**: `mindmap`
#### 2. 顺序与关系
- **流程**: 路线图 (`sequence-roadmap`), 之字形流程 (`sequence-zigzag`), 水平流程 (`sequence-horizontal`)
- **关系**: 桑基图 (`relation-sankey`), 循环关系 (`relation-circle`)
#### 3. 对比与分析
- **对比**: 二元对比 (`compare-binary`), 对比表 (`compare-table`)
- **分析**: SWOT 分析 (`compare-swot`), 象限图 (`quadrant-quarter`)
#### 4. 图表与数据
- **统计**: 统计卡片 (`statistic-card`)
- **图表**: 柱状图 (`chart-bar`), 条形图 (`chart-column`), 折线图 (`chart-line`), 饼图 (`chart-pie`), 环形图 (`chart-doughnut`)
## 安装
`infographic.py` (英文版) 或 `信息图.py` (中文版) 放入 Open WebUI 的插件目录即可。
## 依赖
- 插件依赖 `@antv/infographic` 库 (通过 CDN 加载)。
- 需要联网权限以加载 CDN 资源和图标。

View File

@@ -0,0 +1,43 @@
# AntV Infographic Plugin
Transform text content into beautiful infographics with a single click. Supports lists, hierarchies, processes, relationships, comparisons, analysis, charts, and more.
## Features
- **Smart Analysis**: Automatically identifies text structure and selects the best template.
- **Rich Templates**: Supports 20+ AntV infographic templates, including lists, trees, mind maps, roadmaps, Sankey diagrams, SWOT, quadrant charts, bar charts, pie charts, etc.
- **Auto Icons**: Intelligently searches and matches appropriate icons.
- **Multi-format Export**: Export as SVG, PNG, or HTML.
- **Multi-language**: Output language follows user settings.
## Usage
In the Open WebUI chat interface, simply input text or upload a document, then enable this plugin. The plugin will analyze the content and generate an infographic.
### Supported Chart Types
#### 1. List & Hierarchy
- **List**: Grid Cards (`list-grid`), Vertical List (`list-vertical`)
- **Tree**: Vertical Tree (`tree-vertical`), Horizontal Tree (`tree-horizontal`)
- **Mindmap**: `mindmap`
#### 2. Sequence & Relationship
- **Process**: Roadmap (`sequence-roadmap`), Zigzag Process (`sequence-zigzag`), Horizontal Process (`sequence-horizontal`)
- **Relationship**: Sankey Diagram (`relation-sankey`), Circular Relationship (`relation-circle`)
#### 3. Comparison & Analysis
- **Comparison**: Binary Comparison (`compare-binary`), Comparison Table (`compare-table`)
- **Analysis**: SWOT Analysis (`compare-swot`), Quadrant Chart (`quadrant-quarter`)
#### 4. Charts & Data
- **Statistics**: Statistic Cards (`statistic-card`)
- **Charts**: Bar Chart (`chart-bar`), Column Chart (`chart-column`), Line Chart (`chart-line`), Pie Chart (`chart-pie`), Doughnut Chart (`chart-doughnut`)
## Installation
Place `infographic.py` (English version) or `信息图.py` (Chinese version) into your Open WebUI plugins directory.
## Dependencies
- Depends on `@antv/infographic` library (loaded via CDN).
- Requires internet access to load CDN resources and icons.

View File

@@ -0,0 +1,277 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>卡片间距调试工具</title>
<script src="https://registry.npmmirror.com/@antv/infographic/0.2.1/files/dist/infographic.min.js"></script>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 20px;
background: #f0f0f0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.debug-container {
display: flex;
gap: 20px;
max-width: 1400px;
margin: 0 auto;
}
.controls {
width: 320px;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
height: fit-content;
position: sticky;
top: 20px;
}
.controls h2 {
margin-top: 0;
font-size: 16px;
color: #333;
}
.controls label {
display: block;
margin: 16px 0 6px;
font-size: 14px;
color: #666;
font-weight: 500;
}
.controls input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.controls button {
width: 100%;
padding: 10px;
margin-top: 16px;
background: #6366f1;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
}
.controls button:hover {
background: #4f46e5;
}
.controls .info {
margin-top: 20px;
padding: 12px;
background: #f1f5f9;
border-radius: 6px;
font-size: 13px;
color: #475569;
line-height: 1.6;
}
.preview {
flex: 1;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
#infographic-container {
min-height: 500px;
padding: 24px;
}
/* 基础样式 */
#infographic-container svg text {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif !important;
}
#infographic-container svg foreignObject {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif !important;
line-height: 1.4 !important;
}
/* 主标题样式 */
#infographic-container svg foreignObject[data-element-type="title"]>* {
font-size: 1.2em !important;
font-weight: bold !important;
line-height: 1.4 !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
/* 页面副标题样式 */
#infographic-container svg foreignObject[data-element-type="desc"]>* {
font-size: 0.6em !important;
line-height: 1.4 !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
/* 卡片标题和描述样式(这里是重点调试区域) */
#infographic-container svg foreignObject[data-element-type="item-label"]>* {
font-size: 0.6em !important;
line-height: 1.4 !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
#infographic-container svg foreignObject[data-element-type="item-desc"]>* {
line-height: 1.4 !important;
white-space: normal !important;
}
</style>
</head>
<body>
<div class="debug-container">
<div class="controls">
<h2>🔧 卡片间距调试面板</h2>
<label>卡片标题与描述间距 (margin-top)</label>
<input type="text" id="label-desc-gap" value="8px" placeholder="例如: 8px, 12px, 1em">
<label>卡片标题字体大小</label>
<input type="text" id="label-size" value="0.6em" placeholder="例如: 0.6em, 12px">
<label>卡片描述字体大小</label>
<input type="text" id="desc-size" value="0.5em" placeholder="例如: 0.5em, 10px">
<label>卡片内边距 (padding)</label>
<input type="text" id="card-padding" value="8px" placeholder="例如: 8px, 12px">
<button onclick="applyStyles()">应用样式</button>
<button onclick="reRender()" style="background: #10b981; margin-top: 8px;">重新渲染</button>
<div class="info">
<strong>说明:</strong><br>
• 标题与描述间距:控制标题和内容之间的垂直间距<br>
• 字体大小:分别控制标题和描述的文字大小<br>
• 内边距:控制整个卡片内的留白
</div>
</div>
<div class="preview">
<div id="infographic-container"></div>
</div>
</div>
<script>
function applyStyles() {
console.log('[Debug] 应用卡片样式...');
const labelDescGap = document.getElementById('label-desc-gap').value;
const labelSize = document.getElementById('label-size').value;
const descSize = document.getElementById('desc-size').value;
const cardPadding = document.getElementById('card-padding').value;
const container = document.getElementById('infographic-container');
// 卡片标题
const itemLabels = container.querySelectorAll('svg foreignObject[data-element-type="item-label"]');
itemLabels.forEach(fo => {
const firstChild = fo.querySelector(':scope > *');
if (firstChild) {
firstChild.style.setProperty('font-size', labelSize, 'important');
firstChild.style.setProperty('margin-bottom', labelDescGap, 'important');
}
});
// 卡片描述
const itemDescs = container.querySelectorAll('svg foreignObject[data-element-type="item-desc"]');
itemDescs.forEach(fo => {
const firstChild = fo.querySelector(':scope > *');
if (firstChild) {
firstChild.style.setProperty('font-size', descSize, 'important');
}
});
// 尝试调整卡片整体内边距(通过调整 g 元素的 padding
const cardGroups = container.querySelectorAll('svg g[data-element-type="items-group"] > g');
cardGroups.forEach(group => {
// 这里可能需要通过调整内部 g 的 transform 来实现
// AntV 的布局比较复杂padding 可能需要通过其他方式实现
});
console.log('[Debug] 卡片样式已应用:', {
labelDescGap,
labelSize,
descSize,
cardPadding
});
}
function reRender() {
const container = document.getElementById('infographic-container');
container.innerHTML = '';
const syntaxContent = `infographic list-grid-compact-card
data
title 🚀 功能亮点说明
desc 系统核心逻辑与交互视觉特性
items
- label 核心流程演示
icon mdi/database-cog
desc 包含4个数据源、4条分流管道运费/商品/退货以及UNION ALL与GROUP BY聚合节点
- label 灵动动画效果
icon mdi/motion-play
desc 支持5个订单多色并行流转、管道霓虹闪烁光晕、节点旋转及仪表盘数值跳动反馈
- label 极简交互控制
icon mdi/cursor-default-click
desc 内置开始/暂停/重置逻辑支持1x至4x倍速调整并集成实时仪表板与日志系统
- label 赛博朋克风格
icon mdi/palette
desc 采用深蓝紫色调、霓虹绿文字影、网格背景以及渐变发光边框,打造极客视觉体验`;
if (typeof AntVInfographic === 'undefined') {
container.innerHTML = '<div style="color: red; padding: 20px;">⚠️ AntV Infographic 库未加载</div>';
return;
}
try {
const { Infographic } = AntVInfographic;
const instance = new Infographic({
container: '#infographic-container',
padding: 24,
});
instance.render(syntaxContent);
console.log('[Debug] 渲染完成');
// 渲染完成后自动应用样式
setTimeout(() => {
applyStyles();
}, 300);
} catch (error) {
container.innerHTML = '<div style="color: red; padding: 20px;">⚠️ 渲染错误: ' + error.message + '</div>';
console.error(error);
}
}
// 页面加载后自动渲染
window.onload = function () {
setTimeout(reRender, 500);
};
</script>
</body>
</html>

View File

@@ -0,0 +1,342 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>信息图样式调试</title>
<script src="https://registry.npmmirror.com/@antv/infographic/0.2.1/files/dist/infographic.min.js"></script>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 20px;
background: #f0f0f0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.debug-container {
display: flex;
gap: 20px;
max-width: 1400px;
margin: 0 auto;
}
.controls {
width: 300px;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
height: fit-content;
position: sticky;
top: 20px;
}
.controls h2 {
margin-top: 0;
font-size: 16px;
}
.controls label {
display: block;
margin: 12px 0 4px;
font-size: 14px;
color: #666;
}
.controls input,
.controls select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.controls button {
width: 100%;
padding: 10px;
margin-top: 16px;
background: #6366f1;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
.controls button:hover {
background: #4f46e5;
}
.preview {
flex: 1;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
#infographic-container {
min-height: 500px;
padding: 24px;
}
/* ========== 可调试的样式 ========== */
/* 这些样式可以直接在这里修改,刷新页面即可看到效果 */
/* 基础字体 */
#infographic-container svg text {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif !important;
}
#infographic-container svg foreignObject {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif !important;
line-height: 1.4 !important;
}
/* 标题样式 - 根据需要调整 */
#infographic-container svg foreignObject h1,
#infographic-container svg foreignObject [class*="title"] {
font-size: 0.8em !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
#infographic-container svg foreignObject h2,
#infographic-container svg foreignObject [class*="subtitle"] {
font-size: 0.85em !important;
white-space: nowrap !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
/* ========== 调试样式结束 ========== */
</style>
</head>
<body>
<div class="debug-container">
<div class="controls">
<h2>🔧 样式调试面板</h2>
<label>一级标题字体大小</label>
<input type="text" id="h1-size" value="1.2em" placeholder="例如: 1.2em, 20px">
<label>二级标题字体大小</label>
<input type="text" id="h2-size" value="0.6em" placeholder="例如: 0.6em, 12px">
<label>标题换行设置</label>
<select id="title-wrap">
<option value="nowrap">不换行 (nowrap)</option>
<option value="normal">自动换行 (normal)</option>
</select>
<label>行高</label>
<input type="text" id="line-height" value="1.4" placeholder="例如: 1.4, 1.6">
<button onclick="applyStyles()">应用样式</button>
<button onclick="reRender()" style="background: #10b981; margin-top: 8px;">重新渲染</button>
<hr style="margin: 20px 0; border: none; border-top: 1px solid #eee;">
<label>自定义语法内容</label>
<textarea id="syntax-input" rows="10" style="width: 100%; font-size: 12px; font-family: monospace;">infographic list-grid
data
title 2025职业足球运动员成功要素解析
desc 在高度竞争的现代足球体系下,从天赋到职业的进化路径
items
- label 核心入场券:天赋与身体
desc 速度、爆发力及极佳的球感是底线。基本功必须化为肌肉记忆。
icon mdi/lightning-bolt
- label 决定上限:极度自律
desc 包含严苛的饮食、睡眠管理及强大的抗压心态。
icon mdi/shield-star
- label 现代智慧:球商 (IQ)
desc 复杂的战术理解力与阅读比赛能力。
icon mdi/brain
- label 隐形推手:机遇与平台
desc 专业的青训体系、能发掘你的伯乐。
icon mdi/star-shooting</textarea>
</div>
<div class="preview">
<div id="infographic-container"></div>
</div>
</div>
<script>
function applyStyles() {
console.log('[Debug] 应用样式到已渲染的元素...');
const h1Size = document.getElementById('h1-size').value;
const h2Size = document.getElementById('h2-size').value;
const titleWrap = document.getElementById('title-wrap').value;
const lineHeight = document.getElementById('line-height').value;
const container = document.getElementById('infographic-container');
// 直接操作 SVG 内的所有文本元素
const allTexts = container.querySelectorAll('svg text');
allTexts.forEach(text => {
text.style.setProperty('font-size', h1Size, 'important');
});
// 操作 foreignObject 内的所有元素
const foreignObjects = container.querySelectorAll('svg foreignObject');
let mainTitleCount = 0;
let itemLabelCount = 0;
let itemDescCount = 0;
let otherCount = 0;
foreignObjects.forEach(fo => {
// 检查 foreignObject 自身的 data-element-type 属性
const elementType = fo.getAttribute('data-element-type');
// 设置 foreignObject 本身的行高
fo.style.setProperty('line-height', lineHeight, 'important');
// 获取内部的第一个元素(通常是 span
const firstChild = fo.querySelector(':scope > *');
if (!firstChild) return;
// 根据 foreignObject 的类型设置样式
if (elementType === 'title') {
// 主标题
mainTitleCount++;
firstChild.style.setProperty('font-size', h1Size, 'important');
firstChild.style.setProperty('font-weight', 'bold', 'important');
firstChild.style.setProperty('line-height', lineHeight, 'important');
if (titleWrap === 'nowrap') {
firstChild.style.setProperty('white-space', 'nowrap', 'important');
firstChild.style.setProperty('overflow', 'hidden', 'important');
firstChild.style.setProperty('text-overflow', 'ellipsis', 'important');
} else {
firstChild.style.setProperty('white-space', 'normal', 'important');
firstChild.style.setProperty('overflow', 'visible', 'important');
firstChild.style.setProperty('text-overflow', 'clip', 'important');
}
} else if (elementType === 'desc') {
// 页面副标题(主标题下方的描述)
itemLabelCount++; // 归入副标题计数
firstChild.style.setProperty('font-size', h2Size, 'important');
firstChild.style.setProperty('line-height', lineHeight, 'important');
if (titleWrap === 'nowrap') {
firstChild.style.setProperty('white-space', 'nowrap', 'important');
firstChild.style.setProperty('overflow', 'hidden', 'important');
firstChild.style.setProperty('text-overflow', 'ellipsis', 'important');
} else {
firstChild.style.setProperty('white-space', 'normal', 'important');
firstChild.style.setProperty('overflow', 'visible', 'important');
firstChild.style.setProperty('text-overflow', 'clip', 'important');
}
} else if (elementType === 'item-label') {
// 卡片标题
itemLabelCount++;
firstChild.style.setProperty('font-size', h2Size, 'important');
firstChild.style.setProperty('line-height', lineHeight, 'important');
if (titleWrap === 'nowrap') {
firstChild.style.setProperty('white-space', 'nowrap', 'important');
firstChild.style.setProperty('overflow', 'hidden', 'important');
firstChild.style.setProperty('text-overflow', 'ellipsis', 'important');
} else {
firstChild.style.setProperty('white-space', 'normal', 'important');
firstChild.style.setProperty('overflow', 'visible', 'important');
firstChild.style.setProperty('text-overflow', 'clip', 'important');
}
} else if (elementType === 'item-desc') {
// 卡片描述
itemDescCount++;
firstChild.style.setProperty('line-height', lineHeight, 'important');
firstChild.style.setProperty('white-space', 'normal', 'important');
} else {
// 其他元素
otherCount++;
firstChild.style.setProperty('line-height', lineHeight, 'important');
firstChild.style.setProperty('white-space', 'normal', 'important');
}
});
console.log('[Debug] foreignObject 处理:', '主标题:', mainTitleCount, '卡片标题:', itemLabelCount, '卡片描述:', itemDescCount, '其他:', otherCount);
console.log('[Debug] 样式已应用到', allTexts.length, '个文本元素和', foreignObjects.length, '个 foreignObject');
}
function reRender() {
const container = document.getElementById('infographic-container');
container.innerHTML = '';
let syntaxContent = document.getElementById('syntax-input').value.trim();
if (typeof AntVInfographic === 'undefined') {
container.innerHTML = '<div style="color: red; padding: 20px;">⚠️ AntV Infographic 库未加载</div>';
return;
}
// 应用模板映射(与插件保持一致)
const TEMPLATE_MAPPING = {
'list-grid': 'list-grid-compact-card',
'list-vertical': 'list-column-simple-vertical-arrow',
'tree-vertical': 'hierarchy-tree-tech-style-capsule-item',
'tree-horizontal': 'hierarchy-tree-lr-tech-style-capsule-item',
'mindmap': 'hierarchy-mindmap-branch-gradient-capsule-item',
'sequence-roadmap': 'sequence-roadmap-vertical-simple',
'sequence-zigzag': 'sequence-horizontal-zigzag-simple',
'sequence-horizontal': 'sequence-horizontal-zigzag-simple',
'relation-sankey': 'relation-sankey-simple',
'relation-circle': 'relation-circle-icon-badge',
'compare-binary': 'compare-binary-horizontal-simple-vs',
'compare-swot': 'compare-swot',
'compare-table': 'compare-table-simple',
'quadrant-quarter': 'quadrant-quarter-simple-card',
'statistic-card': 'list-grid-compact-card',
'chart-bar': 'chart-bar-plain-text',
'chart-column': 'chart-column-simple',
'chart-line': 'chart-line-plain-text',
'chart-area': 'chart-area-simple',
'chart-pie': 'chart-pie-plain-text',
'chart-doughnut': 'chart-pie-donut-plain-text'
};
for (const [key, value] of Object.entries(TEMPLATE_MAPPING)) {
const regex = new RegExp(`infographic\\s+${key}(?=\\s|$)`, 'i');
if (regex.test(syntaxContent)) {
console.log(`[Debug] 模板映射: ${key} -> ${value}`);
syntaxContent = syntaxContent.replace(regex, `infographic ${value}`);
break;
}
}
try {
const { Infographic } = AntVInfographic;
const instance = new Infographic({
container: '#infographic-container',
padding: 24,
});
instance.render(syntaxContent);
console.log('[Debug] 渲染完成');
// 渲染完成后应用样式
setTimeout(() => {
applyStyles();
}, 300);
} catch (error) {
container.innerHTML = '<div style="color: red; padding: 20px;">⚠️ 渲染错误: ' + error.message + '</div>';
console.error(error);
}
}
// 页面加载后自动渲染
window.onload = function () {
setTimeout(reRender, 500);
};
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,194 @@
{
"templates": [
"chart-bar-basic-bar",
"chart-bar-basic-column",
"chart-bar-grouped-bar",
"chart-bar-grouped-column",
"chart-bar-percent-stacked-bar",
"chart-bar-percent-stacked-column",
"chart-bar-stacked-bar",
"chart-bar-stacked-column",
"chart-line-basic-line",
"chart-line-curved-line",
"chart-line-multi-line",
"chart-line-step-line",
"chart-pie-basic-donut",
"chart-pie-basic-pie",
"chart-pie-compact-card",
"chart-pie-donut-compact-card",
"chart-wordcloud-basic",
"compare-binary-circle-progress",
"compare-binary-compact-card",
"compare-binary-dashed-arrow-compact-card",
"compare-binary-dashed-line-compact-card",
"compare-binary-horizontal-icon-arrow",
"compare-binary-simple-horizontal-arrow",
"compare-binary-simple-vertical-arrow",
"compare-binary-tech-style-compact-card",
"compare-hierarchy-compact-card",
"compare-hierarchy-dashed-arrow-compact-card",
"compare-hierarchy-dashed-line-compact-card",
"compare-hierarchy-horizontal-icon-arrow",
"compare-hierarchy-simple-horizontal-arrow",
"compare-hierarchy-simple-vertical-arrow",
"compare-hierarchy-tech-style-compact-card",
"compare-swot-compact-card",
"compare-swot-dashed-arrow-compact-card",
"compare-swot-dashed-line-compact-card",
"compare-swot-horizontal-icon-arrow",
"compare-swot-simple-horizontal-arrow",
"compare-swot-simple-vertical-arrow",
"compare-swot-tech-style-compact-card",
"hierarchy-mindmap-branch-gradient-capsule-item",
"hierarchy-mindmap-branch-gradient-circle-progress",
"hierarchy-mindmap-branch-gradient-compact-card",
"hierarchy-mindmap-branch-gradient-lined-palette",
"hierarchy-mindmap-branch-gradient-rounded-rect",
"hierarchy-mindmap-level-gradient-capsule-item",
"hierarchy-mindmap-level-gradient-circle-progress",
"hierarchy-mindmap-level-gradient-compact-card",
"hierarchy-mindmap-level-gradient-lined-palette",
"hierarchy-mindmap-level-gradient-rounded-rect",
"hierarchy-tree-bt-curved-line-badge-card",
"hierarchy-tree-bt-curved-line-capsule-item",
"hierarchy-tree-bt-curved-line-compact-card",
"hierarchy-tree-bt-curved-line-ribbon-card",
"hierarchy-tree-bt-curved-line-rounded-rect-node",
"hierarchy-tree-bt-dashed-arrow-badge-card",
"hierarchy-tree-bt-dashed-arrow-capsule-item",
"hierarchy-tree-bt-dashed-arrow-compact-card",
"hierarchy-tree-bt-dashed-arrow-ribbon-card",
"hierarchy-tree-bt-dashed-arrow-rounded-rect-node",
"hierarchy-tree-bt-dashed-line-badge-card",
"hierarchy-tree-bt-dashed-line-capsule-item",
"hierarchy-tree-bt-dashed-line-compact-card",
"hierarchy-tree-bt-dashed-line-ribbon-card",
"hierarchy-tree-bt-dashed-line-rounded-rect-node",
"hierarchy-tree-bt-distributed-origin-badge-card",
"hierarchy-tree-bt-distributed-origin-capsule-item",
"hierarchy-tree-bt-distributed-origin-compact-card",
"hierarchy-tree-bt-distributed-origin-ribbon-card",
"hierarchy-tree-bt-distributed-origin-rounded-rect-node",
"hierarchy-tree-bt-tech-style-badge-card",
"hierarchy-tree-bt-tech-style-capsule-item",
"hierarchy-tree-bt-tech-style-compact-card",
"hierarchy-tree-bt-tech-style-ribbon-card",
"hierarchy-tree-bt-tech-style-rounded-rect-node",
"hierarchy-tree-curved-line-badge-card",
"hierarchy-tree-curved-line-capsule-item",
"hierarchy-tree-curved-line-compact-card",
"hierarchy-tree-curved-line-ribbon-card",
"hierarchy-tree-curved-line-rounded-rect-node",
"hierarchy-tree-dashed-arrow-badge-card",
"hierarchy-tree-dashed-arrow-capsule-item",
"hierarchy-tree-dashed-arrow-compact-card",
"hierarchy-tree-dashed-arrow-ribbon-card",
"hierarchy-tree-dashed-arrow-rounded-rect-node",
"hierarchy-tree-dashed-line-badge-card",
"hierarchy-tree-dashed-line-capsule-item",
"hierarchy-tree-dashed-line-compact-card",
"hierarchy-tree-dashed-line-ribbon-card",
"hierarchy-tree-dashed-line-rounded-rect-node",
"hierarchy-tree-distributed-origin-badge-card",
"hierarchy-tree-distributed-origin-capsule-item",
"hierarchy-tree-distributed-origin-compact-card",
"hierarchy-tree-distributed-origin-ribbon-card",
"hierarchy-tree-distributed-origin-rounded-rect-node",
"hierarchy-tree-lr-curved-line-badge-card",
"hierarchy-tree-lr-curved-line-capsule-item",
"hierarchy-tree-lr-curved-line-compact-card",
"hierarchy-tree-lr-curved-line-ribbon-card",
"hierarchy-tree-lr-curved-line-rounded-rect-node",
"hierarchy-tree-lr-dashed-arrow-badge-card",
"hierarchy-tree-lr-dashed-arrow-capsule-item",
"hierarchy-tree-lr-dashed-arrow-compact-card",
"hierarchy-tree-lr-dashed-arrow-ribbon-card",
"hierarchy-tree-lr-dashed-arrow-rounded-rect-node",
"hierarchy-tree-lr-dashed-line-badge-card",
"hierarchy-tree-lr-dashed-line-capsule-item",
"hierarchy-tree-lr-dashed-line-compact-card",
"hierarchy-tree-lr-dashed-line-ribbon-card",
"hierarchy-tree-lr-dashed-line-rounded-rect-node",
"hierarchy-tree-lr-distributed-origin-badge-card",
"hierarchy-tree-lr-distributed-origin-capsule-item",
"hierarchy-tree-lr-distributed-origin-compact-card",
"hierarchy-tree-lr-distributed-origin-ribbon-card",
"hierarchy-tree-lr-distributed-origin-rounded-rect-node",
"hierarchy-tree-lr-tech-style-badge-card",
"hierarchy-tree-lr-tech-style-capsule-item",
"hierarchy-tree-lr-tech-style-compact-card",
"hierarchy-tree-lr-tech-style-ribbon-card",
"hierarchy-tree-lr-tech-style-rounded-rect-node",
"hierarchy-tree-rl-curved-line-badge-card",
"hierarchy-tree-rl-curved-line-capsule-item",
"hierarchy-tree-rl-curved-line-compact-card",
"hierarchy-tree-rl-curved-line-ribbon-card",
"hierarchy-tree-rl-curved-line-rounded-rect-node",
"hierarchy-tree-rl-dashed-arrow-badge-card",
"hierarchy-tree-rl-dashed-arrow-capsule-item",
"hierarchy-tree-rl-dashed-arrow-compact-card",
"hierarchy-tree-rl-dashed-arrow-ribbon-card",
"hierarchy-tree-rl-dashed-arrow-rounded-rect-node",
"hierarchy-tree-rl-dashed-line-badge-card",
"hierarchy-tree-rl-dashed-line-capsule-item",
"hierarchy-tree-rl-dashed-line-compact-card",
"hierarchy-tree-rl-dashed-line-ribbon-card",
"hierarchy-tree-rl-dashed-line-rounded-rect-node",
"hierarchy-tree-rl-distributed-origin-badge-card",
"hierarchy-tree-rl-distributed-origin-capsule-item",
"hierarchy-tree-rl-distributed-origin-compact-card",
"hierarchy-tree-rl-distributed-origin-ribbon-card",
"hierarchy-tree-rl-distributed-origin-rounded-rect-node",
"hierarchy-tree-rl-tech-style-badge-card",
"hierarchy-tree-rl-tech-style-capsule-item",
"hierarchy-tree-rl-tech-style-compact-card",
"hierarchy-tree-rl-tech-style-ribbon-card",
"hierarchy-tree-rl-tech-style-rounded-rect-node",
"hierarchy-tree-tech-style-badge-card",
"hierarchy-tree-tech-style-capsule-item",
"hierarchy-tree-tech-style-compact-card",
"hierarchy-tree-tech-style-ribbon-card",
"hierarchy-tree-tech-style-rounded-rect-node",
"list-column-done-list",
"list-column-simple-vertical-arrow",
"list-column-vertical-icon-arrow",
"list-grid-badge-card",
"list-grid-candy-card-lite",
"list-grid-circular-progress",
"list-grid-compact-card",
"list-grid-done-list",
"list-grid-horizontal-icon-arrow",
"list-grid-progress-card",
"list-grid-ribbon-card",
"list-grid-simple",
"list-pyramid-badge-card",
"list-pyramid-compact-card",
"list-pyramid-rounded-rect-node",
"list-row-circular-progress",
"list-row-horizontal-icon-arrow",
"list-row-horizontal-icon-line",
"list-row-simple-horizontal-arrow",
"list-row-simple-illus",
"list-sector-half-plain-text",
"list-sector-plain-text",
"list-sector-simple",
"quadrant-scatter-basic",
"quadrant-scatter-compact-card",
"quadrant-scatter-dashed-arrow-compact-card",
"quadrant-scatter-dashed-line-compact-card",
"quadrant-scatter-horizontal-icon-arrow",
"quadrant-scatter-simple-horizontal-arrow",
"quadrant-scatter-simple-vertical-arrow",
"quadrant-scatter-tech-style-compact-card",
"relation-graph-circular-layout",
"relation-graph-force-directed",
"sequence-circular-basic",
"sequence-roadmap-vertical-simple",
"sequence-snake-basic",
"sequence-stairs-basic",
"sequence-steps-basic",
"sequence-timeline-basic",
"sequence-timeline-done-list",
"sequence-zigzag-basic"
]
}

View File

@@ -0,0 +1,688 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AntV Infographic Debug Test</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 1000px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.infographic-render-container {
height: 800px;
border: 1px dashed #ccc;
border-radius: 4px;
margin-top: 20px;
overflow: auto;
}
h1 {
margin-top: 0;
}
.status {
margin-top: 10px;
padding: 10px;
background: #e0f2fe;
border-radius: 4px;
font-family: monospace;
white-space: pre-wrap;
/* 保留换行符 */
}
</style>
</head>
<body>
<div class="container">
<h1>AntV Infographic 综合测试台</h1>
<div class="controls">
<label>选择测试用例:</label>
<select id="case-selector">
<option value="case-list-basic">Case A: List Basic (Standard)</option>
<option value="case-tree-vertical">Case B: Tree Vertical (Hierarchy)</option>
<option value="case-theme-extended">Case C: Theme Extended (Bg/Text Color)</option>
<option value="case-tree-horizontal">Case D: Tree Horizontal</option>
<option value="case-list-children">Case E: List with Children</option>
<option value="case-tree-indented">Case F: Indented Tree</option>
<option value="case-mindmap">Case G: Mindmap</option>
<option value="case-l">Case L: List Grid (MiniMax)</option>
<option value="case-list-vertical">Case H: List Vertical</option>
<option value="case-statistic-card">Case I: Statistic Card</option>
<option value="case-k">Case K: 柠檬霜 Controversy (Roadmap)</option>
<option value="case-l">Case L: List Grid (MiniMax)</option>
<option value="case-llm-list-grid">LLM: List Grid (Features)</option>
<option value="case-llm-tree-vertical">LLM: Tree Vertical (Hierarchy)</option>
<option value="case-llm-statistic-card">LLM: Statistic Card (Metrics)</option>
<option value="case-llm-mindmap">LLM: Mindmap (Brainstorming)</option>
<option value="case-chart-bar">Case M: Chart Bar</option>
<option value="case-compare-swot">Case N: Comparison SWOT</option>
<option value="case-relation-sankey">Case O: Relationship Sankey</option>
<option value="case-quadrant-quarter">Case P: Quadrant Analysis</option>
</select>
<button onclick="runTest()">运行测试</button>
</div>
<div class="status" id="status-log">准备就绪...</div>
<div id="infographic-container-test" class="infographic-render-container"></div>
</div>
<!-- Case A: 基础列表 -->
<script type="text/template" id="case-list-basic">
infographic list-row-simple-horizontal-arrow
data
title 基础列表测试
items
- label 步骤一
icon ref:search:one
- label 步骤二
icon ref:search:two
theme
colorPrimary #3b82f6
palette #3b82f6 #8b5cf6
</script>
<!-- Case B: 垂直树 (尝试添加 ID) -->
<script type="text/template" id="case-tree-vertical">
infographic tree-vertical
data
title 垂直树测试
items
- label 根节点
id root
icon ref:search:root
children
- label 子节点 A
id child-a
- label 子节点 B
id child-b
theme
colorPrimary #10b981
palette #10b981 #34d399
</script>
<!-- Case C: 扩展主题 (测试清理逻辑) -->
<script type="text/template" id="case-theme-extended">
infographic list-row-simple-horizontal-arrow
data
title 扩展主题测试
items
- label 暗色模式
icon ref:search:moon
theme
colorPrimary #6366f1
palette #6366f1 #8b5cf6
backgroundColor #1e293b
textColor #f8fafc
roughness 0.5
</script>
<!-- Case D: 水平树 -->
<script type="text/template" id="case-tree-horizontal">
infographic tree-horizontal
data
title 水平树测试
items
- label 根节点
id root-h
children
- label 子节点 1
id child-1
- label 子节点 2
id child-2
theme
colorPrimary #f59e0b
</script>
<!-- Case E: 列表带子节点 (测试兼容性) -->
<script type="text/template" id="case-list-children">
infographic list-row-simple-horizontal-arrow
data
title 列表带子节点
items
- label 父项 1
children
- label 子项 1.1
- label 父项 2
theme
colorPrimary #ec4899
</script>
<!-- Case F: Indented Tree (缩进树) -->
<script type="text/template" id="case-tree-indented">
infographic tree-indented
data
title 缩进树测试
items
- label 根节点
id root-i
children
- label 子节点 1
id child-i-1
- label 子节点 2
id child-i-2
theme
colorPrimary #8b5cf6
</script>
<!-- Case G: Mindmap -->
<script type="text/template" id="case-mindmap">
infographic mindmap
data
title 脑图测试
items
- label 中心主题
children
- label 主题 A
children
- label 子主题 A1
- label 子主题 A2
- label 主题 B
theme
colorPrimary #06b6d4
</script>
<!-- Case H: List Vertical (垂直列表) -->
<script type="text/template" id="case-list-vertical">
infographic list-vertical
data
title 垂直列表测试
items
- label 第一项
desc 描述文本 1
icon ref:search:one
- label 第二项
desc 描述文本 2
icon ref:search:two
theme
colorPrimary #8b5cf6
</script>
<!-- Case I: Statistic Card (统计卡片) -->
<script type="text/template" id="case-statistic-card">
infographic statistic-card
data
title 核心指标
items
- label 总用户数
value 1,234
icon ref:search:users
- label 日活
value 89%
icon ref:search:activity
theme
colorPrimary #10b981
</script>
<!-- Case J: Official Tree Example -->
<script type="text/template" id="case-official-tree">
infographic hierarchy-tree-tech-style-capsule-item
data
title 官方树形示例
items
- label 根节点
icon ref:search:root
children
- label 子节点 A
icon ref:search:a
children
- label 叶子 A1
- label 叶子 A2
- label 子节点 B
icon ref:search:b
theme
colorPrimary #1677ff
</script>
<!-- Case K: User Fail Case (Lemon Frost) -->
<script type="text/template" id="case-user-fail">
infographic list-vertical
data
title 柠檬霜豹纹守宫美丽的诅咒
desc 揭露极端审美背后的遗传缺陷伦理代价与商业真相
items
- label 审美霸权与病态追求
desc 追求极致黄色而筛选出致癌基因让生命背负终身癌症风险是伦理上的霸权行为
icon mdi/eye-off-outline
- label 致命的基因多效性
desc 品系不同柠檬霜导致的是实体肿瘤溃烂致癌机制与颜色性状不可剥离
icon mdi/dna
- label 商业层面的误导欺诈
desc 所谓低肿瘤率改良版多为营销谎言只要表现出性状就注定携带致癌机制
icon mdi/alert-octagon
- label 科学研究与宠物价值
desc 其价值应仅限于作为黑色素瘤的医学研究模型而非在宠物交易市场中流通
icon mdi/microscope
- label 行动呼吁坚决拒绝
desc 拒绝购买与繁育将柠檬霜留在教科书中作为警示而非留在饲养箱中承受痛苦
icon mdi/cancel
theme
colorPrimary #FFD700
colorBg #1A1A1A
textColor #FFFFFF
palette #FFD700 #FF4D4F #E6E6E6
stylize rough
roughness 0.2
</script>
<!-- Case L: List Grid (MiniMax) -->
<script type="text/template" id="case-l">
list-grid
data
title MiniMax 2025 模型矩阵全解析
desc abab 7 为核心的国产顶尖大模型
items
- label 极致 MoE 架构优化
desc 国内首批 MoE 路线坚定者
icon mdi/cpu-64-bit
- label Video-01 视频生成
desc 杀手锏级多模态能力
icon mdi/movie-filter
- label 情感陪伴与角色扮演
desc 源自星野基因
icon mdi/emoticon-heart
- label 超长上下文与精准召回
desc 支持 128k+ 窗口
icon mdi/database-search
theme
colorPrimary #6366f1
colorBg #ffffff
textColor #1f2937
</script>
<!-- LLM Generated Cases for Verification -->
<script type="text/template" id="case-llm-list-grid">
infographic list-grid
data
title MiniMax 2025 模型矩阵全解析
desc 极致架构与多模态能力的全面进阶
items
- label 极致 MoE 架构优化
desc 国内首批 MoE 路线坚定者兼顾模型性能与推理效率
icon mdi/layers-triple
- label Video-01 视频生成
desc 杀手锏级多模态能力支持高品质视频内容创作
icon mdi/video-vintage
- label 情感陪伴与角色扮演
desc 源自星野基因提供深度的情感连接与人格化交互
icon mdi/robot-happy
- label 超长上下文与精准召回
desc 支持 128k+ 超长窗口实现海量信息的精准处理
icon mdi/file-find
theme
colorPrimary #0052D9
colorBg #F2F3F5
palette #0052D9 #2BA471 #E37318 #D54941
stylize flat
</script>
<script type="text/template" id="case-llm-tree-vertical">
infographic tree-vertical
data
title 公司组织架构
desc 2025年度企业内部编制示意图
items
- label 研发部
icon mdi/xml
children
- label 后端组
icon mdi/server
- label 前端组
icon mdi/language-javascript
- label 市场部
icon mdi/chart-bell-curve
children
- label 销售组
icon mdi/account-cash
- label 推广组
icon mdi/bullhorn
</script>
<script type="text/template" id="case-llm-statistic-card">
infographic statistic-card
data
title 2024年Q4 核心指标
desc 统计日期2024年第四季度
items
- label 总用户数
value 1,234,567
icon mdi/account-group
- label 日活跃用户
value 89%
icon mdi/chart-line
- label 营收增长
value +45%
icon mdi/trending-up
</script>
<script type="text/template" id="case-llm-mindmap">
infographic mindmap
data
title 人工智能应用领域
desc 核心应用场景分类与展示
items
- label 生成式 AI
icon mdi/brain
children
- label 文本生成
icon mdi/text-recognition
- label 图像生成
icon mdi/image-multiple
- label 视频生成
icon mdi/video-input-component
- label 预测性 AI
icon mdi/chart-line
children
- label 股市预测
icon mdi/finance
- label 天气预报
icon mdi/weather-partly-cloudy
- label 决策 AI
icon mdi/robot
children
- label 自动驾驶
icon mdi/car-autonomous
- label 游戏博弈
icon mdi/controller-classic
theme
colorPrimary #2F54EB
colorBg #FFFFFF
</script>
<!-- New Styles Test Cases -->
<script type="text/template" id="case-chart-bar">
infographic chart-bar
data
title 2023年季度营收分析
desc 单位亿元
items
- label 第一季度
value 12.5
- label 第二季度
value 15.8
- label 第三季度
value 14.2
- label 第四季度
value 18.9
</script>
<script type="text/template" id="case-relation-circle">
infographic relation-circle
data
title 生态循环
items
- label 生产者
- label 消费者
- label 分解者
</script>
<script type="text/template" id="case-compare-swot">
infographic compare-swot
data
title 某初创咖啡品牌 SWOT 分析
items
- label 优势
children
- label 产品口味独特
- label 选址精准
- label 劣势
children
- label 品牌知名度低
- label 资金压力大
- label 机会
children
- label 线上外卖市场增长
- label 年轻人对精品咖啡需求增加
- label 威胁
children
- label 行业巨头价格战
- label 原材料成本上涨
</script>
<script type="text/template" id="case-relation-sankey">
infographic relation-sankey
data
title 家庭月度开支流向
desc 2025年12月家庭总收入 10000 元分配明细
items
- label 总收入
value 10000
children
- label 房贷
value 4000
- label 日常消费
value 3000
children
- label 餐饮
value 2000
- label 交通
value 1000
- label 教育培训
value 2000
- label 存入银行
value 1000
</script>
<script type="text/template" id="case-quadrant-quarter">
infographic quadrant-quarter
data
title 个人任务象限分析
desc 2025年12月28日 任务优先级管理
items
- label 修复线上紧急 Bug
desc 紧急且重要立即优先处理
illus mdi/bug
- label 准备下午的客户会议
desc 紧急且重要核心商务产出
illus mdi/account-group
- label 制定年度学习计划
desc 重要不紧急长期价值积累
illus mdi/calendar-check
- label 健身锻炼
desc 重要不紧急身体健康投资
illus mdi/dumbbell
- label 回复琐碎的邮件
desc 紧急不重要低价值干扰
illus mdi/email-outline
- label 接听推销电话
desc 紧急不重要时间黑洞
illus mdi/phone-cancel
- label 刷社交媒体
desc 不紧急不重要消遣娱乐
illus mdi/instagram
- label 看无聊的综艺
desc 不紧急不重要无谓消耗
illus mdi/television-classic
</script>
<script type="text/template" id="case-compare-binary">
infographic compare-binary
data
title IDE vs Open WebUI
desc 核心差异对比
items
- label IDE
desc 代码工程中心
children
- label 深度上下文
- label 实时补全
- label Open WebUI
desc 对话交互中心
children
- label 模型管理
- label 知识库 RAG
</script>
<script src="https://unpkg.com/@antv/infographic@latest/dist/infographic.min.js"></script>
<script>
function log(msg) {
console.log(msg);
const el = document.getElementById('status-log');
el.textContent += '\n' + msg;
}
function logError(err) {
console.error('Detailed Error:', err);
let msg = `❌ 内部错误: ${err.message}`;
if (err.stack) msg += `\nStack: ${err.stack}`;
for (const key in err) {
if (key !== 'message' && key !== 'stack') {
msg += `\n${key}: ${JSON.stringify(err[key])}`;
}
}
log(msg);
}
function clearLog() {
document.getElementById('status-log').textContent = '准备就绪...';
}
window.listTemplates = () => {
clearLog();
log('[Explore] 正在获取模版列表...');
if (typeof AntVInfographic !== 'undefined') {
if (typeof AntVInfographic.getTemplates === 'function') {
const templates = AntVInfographic.getTemplates();
log(`[Explore] getTemplates() result (${templates.length}):\n${JSON.stringify(templates, null, 2)}`);
console.log(templates);
} else {
log('❌ AntVInfographic.getTemplates is not a function.');
log('Available keys: ' + Object.keys(AntVInfographic).join(', '));
}
} else {
log('❌ AntVInfographic is undefined.');
}
};
window.runTest = () => {
clearLog();
const selector = document.getElementById('case-selector');
const caseId = selector.value;
const sourceEl = document.getElementById(caseId);
const containerEl = document.getElementById('infographic-container-test');
if (!sourceEl) return log('❌ 未找到测试用例');
// 重置容器
containerEl.innerHTML = '';
containerEl.style = '';
let syntaxContent = sourceEl.textContent.trim();
log(`[Test] 运行用例: ${caseId} (${selector.options[selector.selectedIndex].text})`);
log(`[Step 1] 原始内容:\n${syntaxContent}`);
// --- 模拟插件的清理逻辑 ---
const bgMatch = syntaxContent.match(/backgroundColor\s+(#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|[a-zA-Z]+)/);
if (bgMatch && bgMatch[1]) {
containerEl.style.backgroundColor = bgMatch[1];
}
const textMatch = syntaxContent.match(/textColor\s+(#[0-9a-fA-F]{6}|#[0-9a-fA-F]{3}|[a-zA-Z]+)/);
if (textMatch && textMatch[1]) {
containerEl.style.color = textMatch[1];
}
// 使用更强的正则:匹配 stylize 及其后续缩进的行
const nl = String.fromCharCode(10);
const cleanRegex = new RegExp('^\\s*(roughness|stylize|backgroundColor|textColor|colorBg).*(' + nl + '\\s+.*)*', 'gm');
if (cleanRegex.test(syntaxContent)) {
log('[Fix] 移除扩展 Theme 属性...');
syntaxContent = syntaxContent.replace(cleanRegex, '');
}
// 2. 模板映射配置
const TEMPLATE_MAPPING = {
// 列表与层级
'list-grid': 'list-grid-compact-card',
'list-vertical': 'list-column-simple-vertical-arrow',
'tree-vertical': 'hierarchy-tree-tech-style-capsule-item',
'tree-horizontal': 'hierarchy-tree-lr-tech-style-capsule-item',
'mindmap': 'hierarchy-mindmap-branch-gradient-capsule-item',
// 顺序与关系
'sequence-roadmap': 'sequence-roadmap-vertical-simple',
'sequence-zigzag': 'sequence-horizontal-zigzag-simple',
'sequence-horizontal': 'sequence-horizontal-zigzag-simple',
'relation-sankey': 'relation-sankey-simple', // 暂无直接对应,保留原值或需移除
'relation-circle': 'relation-circle-icon-badge',
// 对比与分析
'compare-binary': 'compare-binary-horizontal-simple-vs',
'compare-swot': 'compare-swot',
'compare-table': 'compare-table-simple', // 暂无直接对应
'quadrant-quarter': 'quadrant-quarter-simple-card',
// 图表与数据
'statistic-card': 'list-grid-compact-card',
'chart-bar': 'chart-bar-plain-text',
'chart-column': 'chart-column-simple',
'chart-line': 'chart-line-plain-text',
'chart-area': 'chart-area-simple', // 暂无直接对应
'chart-pie': 'chart-pie-plain-text',
'chart-doughnut': 'chart-pie-donut-plain-text'
};
// 3. 应用映射策略
for (const [key, value] of Object.entries(TEMPLATE_MAPPING)) {
const regex = new RegExp(`infographic\\s+${key}(?=\\s|$)`, 'i');
if (regex.test(syntaxContent)) {
log(`[Fix] 自动映射模板: ${key} -> ${value}`);
syntaxContent = syntaxContent.replace(regex, `infographic ${value}`);
break; // 找到一个匹配后即停止
}
}
// 兜底检查:确保以 infographic 开头
if (!syntaxContent.trim().toLowerCase().startsWith('infographic')) {
const firstWord = syntaxContent.trim().split(/\s+/)[0].toLowerCase();
if (!['data', 'theme', 'design', 'items'].includes(firstWord)) {
log('[Fix] 检测到缺失 infographic 前缀,自动补全');
syntaxContent = 'infographic ' + syntaxContent;
}
}
syntaxContent = syntaxContent.trim();
log(`[Step 2] 清理后内容:\n${syntaxContent}`);
try {
const { Infographic } = AntVInfographic;
const instance = new Infographic({
container: '#infographic-container-test',
padding: 24,
});
instance.on('error', (err) => {
logError(err);
});
instance.render(syntaxContent);
if (instance.node) {
log('✅ 渲染成功 (instance.node 存在)');
if (!containerEl.querySelector('svg')) {
log('⚠️ 自动挂载失败,手动挂载...');
containerEl.appendChild(instance.node);
}
} else {
log('❌ 渲染失败 (instance.node 为空)');
}
} catch (e) {
logError(e);
}
};
</script>
</body>
</html>

View File

@@ -0,0 +1,395 @@
import os
import sys
import json
import requests
from datetime import datetime
from dotenv import load_dotenv
import pathlib
# Load .env from the same directory as this script
env_path = pathlib.Path(__file__).parent / ".env"
load_dotenv(dotenv_path=env_path)
# =================================================================
# Configuration
# =================================================================
API_KEY = os.getenv("OPENAI_API_KEY")
BASE_URL = os.getenv("OPENAI_BASE_URL")
MODEL = os.getenv("OPENAI_MODEL", "gpt-4o") # Default to gpt-4o if not set
if not API_KEY or not BASE_URL:
print(
"Error: OPENAI_API_KEY and OPENAI_BASE_URL environment variables must be set."
)
sys.exit(1)
# =================================================================
# Prompts (Extracted from 信息图.py)
# =================================================================
SYSTEM_PROMPT_INFOGRAPHIC_ASSISTANT = """
You are a professional infographic design expert who can analyze user-provided text content and convert it into AntV Infographic syntax format.
## Infographic Syntax Specification
Infographic syntax is a Mermaid-like declarative syntax for describing infographic templates, data, and themes.
### Syntax Rules
- Entry uses `infographic <template-name>`
- Key-value pairs are separated by spaces, **absolutely NO colons allowed**
- Use two spaces for indentation
- Object arrays use `-` with line breaks
⚠️ **IMPORTANT WARNING: This is NOT YAML format!**
- ❌ Wrong: `children:` `items:` `data:` (with colons)
- ✅ Correct: `children` `items` `data` (without colons)
### Template Library & Selection Guide
#### 1. List & Hierarchy (Text-heavy)
- **Linear & Short (Steps/Phases)** -> `list-row-horizontal-icon-arrow`
- **Linear & Long (Rankings/Details)** -> `list-vertical`
- **Grouped / Parallel (Features/Catalog)** -> `list-grid`
- **Hierarchical (Org Chart/Taxonomy)** -> `tree-vertical` or `tree-horizontal`
- **Central Idea (Brainstorming)** -> `mindmap`
#### 2. Sequence & Relationship (Flow-based)
- **Time-based (History/Plan)** -> `sequence-roadmap-vertical-simple`
- **Process Flow (Complex)** -> `sequence-zigzag` or `sequence-horizontal`
- **Resource Flow / Distribution** -> `relation-sankey`
- **Circular Relationship** -> `relation-circle`
#### 3. Comparison & Analysis
- **Binary Comparison (A vs B)** -> `compare-binary`
- **SWOT Analysis** -> `compare-swot`
- **Multi-item Comparison Table** -> `compare-table`
- **Quadrant Analysis (Importance vs Urgency)** -> `quadrant-quarter`
#### 4. Charts & Data (Metric-heavy)
- **Key Metrics / Data Cards** -> `statistic-card`
- **Distribution / Comparison** -> `chart-bar` or `chart-column`
- **Trend over Time** -> `chart-line` or `chart-area`
- **Proportion / Part-to-Whole** -> `chart-pie` or `chart-doughnut`
### Infographic Syntax Guide
#### 1. Structure
- **Entry**: `infographic <template-name>`
- **Blocks**: `data`, `theme`, `design` (optional)
- **Format**: Key-value pairs separated by spaces, 2-space indentation.
- **Arrays**: Object arrays use `-` (newline), simple arrays use inline values.
#### 2. Data Block (`data`)
- `title`: Main title
- `desc`: Subtitle or description
- `items`: List of data items
- - `label`: Item title
- - `value`: Numerical value (required for Charts/Stats)
- - `desc`: Item description (optional)
- - `icon`: Icon name (e.g., `mdi/rocket-launch`)
- - `time`: Time label (Optional, for Roadmap/Sequence)
- - `children`: Nested items (ONLY for Tree/Mindmap/Sankey/SWOT)
- - `illus`: Illustration name (ONLY for Quadrant)
#### 3. Theme Block (`theme`)
- `colorPrimary`: Main color (Hex)
- `colorBg`: Background color (Hex)
- `palette`: Color list (Space separated)
- `textColor`: Text color (Hex)
- `stylize`: Style effect (e.g., `rough`, `flat`)
### Examples
#### Chart (Bar Chart)
infographic chart-bar
data
title Revenue Growth
desc Monthly revenue in 2024
items
- label Jan
value 1200
- label Feb
value 1500
- label Mar
value 1800
#### Comparison (SWOT)
infographic compare-swot
data
title Project SWOT
items
- label Strengths
children
- label Strong team
- label Innovative tech
- label Weaknesses
children
- label Limited budget
- label Opportunities
children
- label Emerging market
- label Threats
children
- label High competition
#### Relationship (Sankey)
infographic relation-sankey
data
title Energy Flow
items
- label Solar
value 100
children
- label Grid
value 60
- label Battery
value 40
- label Wind
value 80
children
- label Grid
value 80
#### Quadrant (Importance vs Urgency)
infographic quadrant-quarter
data
title Task Management
items
- label Critical Bug
desc Fix immediately
illus mdi/bug
- label Feature Request
desc Plan for next sprint
illus mdi/star
### Output Rules
1. **Strict Syntax**: Follow the indentation and formatting rules exactly.
2. **No Explanations**: Output ONLY the syntax code block.
3. **Language**: Use the user's requested language for content.
"""
USER_PROMPT_GENERATE_INFOGRAPHIC = """
请分析以下文本内容,将其核心信息转换为 AntV Infographic 语法格式。
---
**用户上下文信息:**
用户姓名: {user_name}
当前日期时间: {current_date_time_str}
用户语言: {user_language}
---
**文本内容:**
{long_text_content}
请根据文本特点选择最合适的信息图模板,并输出规范的 infographic 语法。注意保持正确的缩进格式(两个空格)。
"""
# =================================================================
# Test Cases
# =================================================================
TEST_CASES = [
{
"name": "List Grid (Features)",
"content": """
MiniMax 2025 模型矩阵全解析:
1. 极致 MoE 架构优化:国内首批 MoE 路线坚定者。
2. Video-01 视频生成:杀手锏级多模态能力。
3. 情感陪伴与角色扮演:源自星野基因。
4. 超长上下文与精准召回:支持 128k+ 窗口。
""",
},
{
"name": "Tree Vertical (Hierarchy)",
"content": """
公司组织架构:
- 研发部
- 后端组
- 前端组
- 市场部
- 销售组
- 推广组
""",
},
{
"name": "Statistic Card (Metrics)",
"content": """
2024年Q4 核心指标:
- 总用户数1,234,567
- 日活跃用户89%
- 营收增长:+45%
""",
},
{
"name": "Mindmap (Brainstorming)",
"content": """
人工智能的应用领域:
- 生成式 AI文本生成、图像生成、视频生成
- 预测性 AI股市预测、天气预报
- 决策 AI自动驾驶、游戏博弈
""",
},
{
"name": "SWOT Analysis",
"content": """
某初创咖啡品牌的 SWOT 分析:
优势:产品口味独特,选址精准。
劣势:品牌知名度低,资金压力大。
机会:线上外卖市场增长,年轻人对精品咖啡需求增加。
威胁:行业巨头价格战,原材料成本上涨。
""",
},
{
"name": "Sankey (Relationship)",
"content": """
家庭月度开支流向:
总收入 10000 元。
其中 4000 元用于房贷。
3000 元用于日常消费(包括 2000 元餐饮1000 元交通)。
2000 元用于教育培训。
1000 元存入银行。
""",
},
{
"name": "Quadrant (Analysis)",
"content": """
个人任务象限分析:
- 紧急且重要:修复线上紧急 Bug准备下午的客户会议。
- 重要不紧急:制定年度学习计划,健身锻炼。
- 紧急不重要:回复琐碎的邮件,接听推销电话。
- 不紧急不重要:刷社交媒体,看无聊的综艺。
""",
},
{
"name": "Chart Bar (Data)",
"content": """
2023年各季度营收情况亿元
第一季度12.5
第二季度15.8
第三季度14.2
第四季度18.9
""",
},
]
# =================================================================
# Helper Functions
# =================================================================
def generate_infographic(content):
now = datetime.now()
current_date_time_str = now.strftime("%Y年%m月%d%H:%M:%S")
formatted_user_prompt = USER_PROMPT_GENERATE_INFOGRAPHIC.format(
user_name="TestUser",
current_date_time_str=current_date_time_str,
user_language="zh-CN",
long_text_content=content,
)
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
payload = {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM_PROMPT_INFOGRAPHIC_ASSISTANT},
{"role": "user", "content": formatted_user_prompt},
],
"stream": False,
}
try:
response = requests.post(
f"{BASE_URL}/chat/completions", headers=headers, json=payload
)
response.raise_for_status()
return response.json()["choices"][0]["message"]["content"]
except Exception as e:
print(f"API Request Failed: {e}")
return None
def validate_syntax(syntax):
if not syntax:
return False, "Empty output"
# Basic checks
if "infographic" not in syntax.lower():
return False, "Missing 'infographic' keyword"
if "data" not in syntax.lower() and "items" not in syntax.lower():
return False, "Missing 'data' or 'items' block"
# Check for colons in keys (simple heuristic)
lines = syntax.split("\n")
for line in lines:
stripped = line.strip()
if not stripped:
continue
# Ignore lines that are likely values or descriptions containing colons
first_word = stripped.split()[0]
if first_word in ["title", "desc", "label", "value", "time", "icon"]:
continue # These can have colons in value
# Check for key: pattern at start of line
if re.match(r"^\w+:", stripped):
return False, f"Found colon in key: {stripped}"
return True, "Syntax looks valid"
# =================================================================
# Main Execution
# =================================================================
import re
def main():
print(f"Starting Infographic Generation Verification...")
print(f"API: {BASE_URL}")
print(f"Model: {MODEL}")
print("-" * 50)
results = []
for case in TEST_CASES:
print(f"\nTesting Case: {case['name']}")
print("Generating...")
output = generate_infographic(case["content"])
if output:
# Clean output (remove markdown code blocks if present)
clean_output = output
if "```" in output:
match = re.search(
r"```(?:infographic|mermaid)?\s*(.*?)\s*```", output, re.DOTALL
)
if match:
clean_output = match.group(1).strip()
print(f"Output Preview:\n{clean_output[:200]}...")
is_valid, message = validate_syntax(clean_output)
if is_valid:
print(f"✅ Validation Passed: {message}")
results.append({"name": case["name"], "status": "PASS"})
else:
print(f"❌ Validation Failed: {message}")
print(f"Full Output:\n{output}")
results.append({"name": case["name"], "status": "FAIL"})
else:
print("❌ Generation Failed")
results.append({"name": case["name"], "status": "ERROR"})
print("\n" + "=" * 50)
print("Summary")
print("=" * 50)
for res in results:
print(f"{res['name']}: {res['status']}")
if __name__ == "__main__":
main()

File diff suppressed because one or more lines are too long