infographic-gen 1.0.2 → 1.0.5
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/README.md +83 -27
- package/README.zh-CN.md +122 -38
- package/dist/index.js +224 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
<img src="https://gw.alipayobjects.com/zos/antfincdn/R8sN%24GNdh6/language.svg" width="18"> [简体中文](./README.zh-CN.md) | English
|
|
2
|
+
|
|
1
3
|
# infographic-gen
|
|
2
4
|
|
|
3
5
|
AI-powered CLI tool to generate [AntV Infographic](https://infographic.antv.vision/) SVGs from natural language prompts.
|
|
@@ -12,6 +14,8 @@ Transform your ideas into beautiful, data-driven infographics in seconds using t
|
|
|
12
14
|
- **AI-Powered Generation** — Uses OpenAI, DeepSeek, or other LLM providers via OpenAI SDK
|
|
13
15
|
- **Professional Templates** — 60+ pre-designed AntV Infographic templates (lists, sequences, hierarchies, comparisons, charts, relations, etc.)
|
|
14
16
|
- **Self-Correcting** — Automatically retries with error feedback if generation fails (up to 3 attempts)
|
|
17
|
+
- **DSL Export** — Optional `--dsl` flag to save raw syntax for debugging and fine-tuning
|
|
18
|
+
- **Error Auto-Dump** — Automatically saves problematic DSL to `error-dump.txt` when rendering fails
|
|
15
19
|
- **Persistent Config** — Save API keys and settings locally for repeat use
|
|
16
20
|
- **Automated Sync** — Weekly checks for upstream Infographic updates via GitHub Actions
|
|
17
21
|
- **Fully Tested** — 131 comprehensive tests covering all features
|
|
@@ -47,12 +51,25 @@ npm start # Run built CLI
|
|
|
47
51
|
|
|
48
52
|
## 🚀 Quick Start
|
|
49
53
|
|
|
54
|
+
### Command Aliases
|
|
55
|
+
|
|
56
|
+
For convenience, the CLI supports multiple shortcuts:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
infographic-gen # Full command
|
|
60
|
+
info-gen # Short alias
|
|
61
|
+
ig-gen # Shortest alias (recommended)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
All examples below use `ig-gen` (can be replaced with any alias above).
|
|
65
|
+
|
|
50
66
|
### 1. Configure Your LLM Provider
|
|
51
67
|
|
|
52
68
|
```bash
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
ig-gen config set apiKey sk-xxxx123
|
|
70
|
+
ig-gen config set baseUrl https://api.openai.com/v1 # Optional
|
|
71
|
+
ig-gen config set modelName gpt-4o # Optional
|
|
72
|
+
ig-gen config set defaultOutputDir ~/my-infographics # Optional: default output directory
|
|
56
73
|
```
|
|
57
74
|
|
|
58
75
|
**Supported Providers:**
|
|
@@ -65,30 +82,53 @@ infographic-gen config set modelName gpt-4o # Optional
|
|
|
65
82
|
View your config:
|
|
66
83
|
|
|
67
84
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
85
|
+
ig-gen config list
|
|
86
|
+
ig-gen config path # Show config file location
|
|
70
87
|
```
|
|
71
88
|
|
|
72
89
|
### 2. Generate an Infographic
|
|
73
90
|
|
|
74
91
|
```bash
|
|
75
|
-
|
|
92
|
+
# generate is the default command, so these are equivalent:
|
|
93
|
+
ig-gen "A comparison of frontend frameworks"
|
|
94
|
+
ig-gen generate "A comparison of frontend frameworks"
|
|
95
|
+
ig-gen g "A comparison of frontend frameworks" # Using 'g' alias
|
|
76
96
|
```
|
|
77
97
|
|
|
78
|
-
Output: `infographic-output.svg` (in current directory)
|
|
98
|
+
Output: `infographic-output.svg` (in default output directory or current directory)
|
|
79
99
|
|
|
80
100
|
Specify output path:
|
|
81
101
|
|
|
82
102
|
```bash
|
|
83
|
-
|
|
103
|
+
ig-gen "Data visualization trends" --output my-chart.svg
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. Save DSL Syntax (Optional)
|
|
107
|
+
|
|
108
|
+
The `--dsl` option allows you to save the raw DSL syntax generated by the AI to a text file. This is useful for:
|
|
109
|
+
|
|
110
|
+
- **Debugging** — Inspect what the LLM generated if rendering fails
|
|
111
|
+
- **Fine-tuning** — Manually edit the DSL to adjust the infographic
|
|
112
|
+
- **Learning** — Understand the DSL syntax for future manual creation
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Generate SVG and save DSL syntax
|
|
116
|
+
ig-gen "Compare React vs Vue" -o frameworks.svg --dsl frameworks.txt
|
|
117
|
+
|
|
118
|
+
# The command will create:
|
|
119
|
+
# - frameworks.svg (rendered infographic)
|
|
120
|
+
# - frameworks.txt (raw DSL syntax)
|
|
84
121
|
```
|
|
85
122
|
|
|
86
|
-
|
|
123
|
+
**Error Auto-Dump:**
|
|
124
|
+
If rendering fails after 3 self-correction attempts, the problematic DSL is automatically saved to `error-dump.txt` for debugging.
|
|
125
|
+
|
|
126
|
+
### 4. Get Help
|
|
87
127
|
|
|
88
128
|
```bash
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
129
|
+
ig-gen --help
|
|
130
|
+
ig-gen config --help
|
|
131
|
+
ig-gen --version
|
|
92
132
|
```
|
|
93
133
|
|
|
94
134
|
---
|
|
@@ -98,7 +138,7 @@ infographic-gen generate --help
|
|
|
98
138
|
### Example 1: Technology Timeline
|
|
99
139
|
|
|
100
140
|
```bash
|
|
101
|
-
|
|
141
|
+
ig-gen "A timeline showing the evolution of web technologies from HTTP/1.0 to HTTP/3"
|
|
102
142
|
```
|
|
103
143
|
|
|
104
144
|
Will generate a timeline with key milestones, automatically selecting an appropriate template.
|
|
@@ -106,7 +146,7 @@ Will generate a timeline with key milestones, automatically selecting an appropr
|
|
|
106
146
|
### Example 2: Comparison Matrix
|
|
107
147
|
|
|
108
148
|
```bash
|
|
109
|
-
|
|
149
|
+
ig-gen "Compare the pros and cons of monolithic vs microservices architecture"
|
|
110
150
|
```
|
|
111
151
|
|
|
112
152
|
Generates a comparison infographic with Strengths and Weaknesses categories.
|
|
@@ -114,11 +154,24 @@ Generates a comparison infographic with Strengths and Weaknesses categories.
|
|
|
114
154
|
### Example 3: Data Chart
|
|
115
155
|
|
|
116
156
|
```bash
|
|
117
|
-
|
|
157
|
+
ig-gen "Show the distribution of programming languages by usage: Python 35%, JavaScript 28%, Java 20%, C++ 12%, Other 5%"
|
|
118
158
|
```
|
|
119
159
|
|
|
120
160
|
Creates a pie/bar chart with the provided data.
|
|
121
161
|
|
|
162
|
+
### Example 4: Debug with DSL Export
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
ig-gen "Compare React, Vue, and Angular pros and cons" -o frameworks.svg --dsl frameworks-dsl.txt
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
This will generate:
|
|
169
|
+
|
|
170
|
+
- `frameworks.svg` — The rendered infographic
|
|
171
|
+
- `frameworks-dsl.txt` — The raw DSL syntax
|
|
172
|
+
|
|
173
|
+
You can then inspect or manually edit the DSL file to fine-tune the output. If rendering fails, check `error-dump.txt` for the problematic syntax.
|
|
174
|
+
|
|
122
175
|
---
|
|
123
176
|
|
|
124
177
|
## 🛠️ Development
|
|
@@ -189,31 +242,34 @@ Config is stored in:
|
|
|
189
242
|
|
|
190
243
|
### Configurable Keys
|
|
191
244
|
|
|
192
|
-
| Key
|
|
193
|
-
|
|
|
194
|
-
| `apiKey`
|
|
195
|
-
| `baseUrl`
|
|
196
|
-
| `modelName`
|
|
197
|
-
| `
|
|
245
|
+
| Key | Type | Example | Notes |
|
|
246
|
+
| ------------------ | ------ | --------------------------- | ---------------------------------------------------- |
|
|
247
|
+
| `apiKey` | string | `sk-...` | Your LLM API key |
|
|
248
|
+
| `baseUrl` | string | `https://api.openai.com/v1` | LLM endpoint (optional) |
|
|
249
|
+
| `modelName` | string | `gpt-4o` | Model to use (optional, defaults to gpt-4o) |
|
|
250
|
+
| `defaultOutputDir` | string | `~/infographics` or `.` | Default output directory (optional, defaults to `.`) |
|
|
198
251
|
|
|
199
252
|
Manage config via CLI:
|
|
200
253
|
|
|
201
254
|
```bash
|
|
202
255
|
# Set
|
|
203
|
-
|
|
204
|
-
|
|
256
|
+
ig-gen config set apiKey sk-...
|
|
257
|
+
ig-gen config set baseUrl https://api.deepseek.com
|
|
258
|
+
ig-gen config set defaultOutputDir ~/my-infographics
|
|
205
259
|
|
|
206
260
|
# Get
|
|
207
|
-
|
|
261
|
+
ig-gen config get apiKey
|
|
262
|
+
ig-gen c get defaultOutputDir # Using 'c' alias
|
|
208
263
|
|
|
209
264
|
# List all
|
|
210
|
-
|
|
265
|
+
ig-gen config list
|
|
266
|
+
ig-gen c list # Using 'c' alias
|
|
211
267
|
|
|
212
268
|
# Delete
|
|
213
|
-
|
|
269
|
+
ig-gen config delete baseUrl
|
|
214
270
|
|
|
215
271
|
# Show config file path
|
|
216
|
-
|
|
272
|
+
ig-gen config path
|
|
217
273
|
```
|
|
218
274
|
|
|
219
275
|
---
|
package/README.zh-CN.md
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
- **AI 驱动生成** — 支持 OpenAI、DeepSeek 或其他兼容 OpenAI SDK 的 LLM 服务
|
|
13
13
|
- **专业模板库** — 60+ 预设设计的 AntV Infographic 模板(列表、流程、层级、对比、图表、关系等)
|
|
14
14
|
- **自动纠错** — 生成失败时自动重试并反馈错误信息(最多 3 次尝试)
|
|
15
|
+
- **DSL 导出** — 可选的 `--dsl` 参数保存原始语法,用于调试和微调
|
|
16
|
+
- **错误自动转储** — 渲染失败时自动保存有问题的 DSL 到 `error-dump.txt`
|
|
17
|
+
- **多语言支持** — CLI 输出支持英文/中文切换(默认英文)
|
|
15
18
|
- **本地配置存储** — API Key 和设置永久保存,无需重复输入
|
|
16
19
|
- **上游自动同步** — 每周自动检测 @antv/infographic 更新,通过 GitHub Actions 创建 PR
|
|
17
20
|
- **全面的测试覆盖** — 131 个综合测试,覆盖所有功能
|
|
@@ -47,44 +50,100 @@ npm start # 运行构建后的 CLI
|
|
|
47
50
|
|
|
48
51
|
## 🚀 快速开始
|
|
49
52
|
|
|
50
|
-
###
|
|
53
|
+
### 命令别名
|
|
54
|
+
|
|
55
|
+
为了方便使用,CLI 提供了多个快捷别名:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
infographic-gen # 完整命令
|
|
59
|
+
info-gen # 短别名
|
|
60
|
+
ig-gen # 最短别名(推荐)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
下面的所有示例均使用 `ig-gen`(可替换为任何上述别名)。
|
|
64
|
+
|
|
65
|
+
### 1. 配置 LLM 服务和语言
|
|
51
66
|
|
|
52
67
|
```bash
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
ig-gen config set apiKey sk-xxxx123
|
|
69
|
+
ig-gen config set baseUrl https://api.openai.com/v1 # 可选
|
|
70
|
+
ig-gen config set modelName gpt-4o # 可选
|
|
71
|
+
ig-gen config set defaultOutputDir ~/my-infographics # 可选
|
|
72
|
+
ig-gen config set locale zh-CN # 可选:切换界面语言为中文
|
|
56
73
|
```
|
|
57
74
|
|
|
58
75
|
**支持的服务提供商:**
|
|
76
|
+
|
|
59
77
|
- **OpenAI** ← 默认
|
|
60
78
|
- **DeepSeek** — 设置 `baseUrl` 为 `https://api.deepseek.com`
|
|
61
79
|
- **阿里云 DashScope** — 设置对应的端点
|
|
62
80
|
- 任何兼容 OpenAI API 的服务
|
|
63
81
|
|
|
64
82
|
查看配置:
|
|
83
|
+
|
|
65
84
|
```bash
|
|
66
|
-
|
|
67
|
-
|
|
85
|
+
ig-gen config list
|
|
86
|
+
ig-gen config path # 显示配置文件位置
|
|
68
87
|
```
|
|
69
88
|
|
|
70
89
|
### 2. 生成信息图
|
|
71
90
|
|
|
72
91
|
```bash
|
|
73
|
-
|
|
92
|
+
# generate 是默认命令,所以这些都是等效的:
|
|
93
|
+
ig-gen "对比前端框架的优缺点"
|
|
94
|
+
ig-gen generate "对比前端框架的优缺点"
|
|
95
|
+
ig-gen g "对比前端框架的优缺点" # 使用 g 别名
|
|
74
96
|
```
|
|
75
97
|
|
|
76
|
-
输出:`infographic-output.svg
|
|
98
|
+
输出:`infographic-output.svg`(在默认输出目录或当前目录)
|
|
77
99
|
|
|
78
100
|
指定输出路径:
|
|
101
|
+
|
|
79
102
|
```bash
|
|
80
|
-
|
|
103
|
+
ig-gen "数据可视化趋势分析" --output my-chart.svg
|
|
81
104
|
```
|
|
82
105
|
|
|
83
|
-
### 3.
|
|
106
|
+
### 3. 保存 DSL 语法(可选)
|
|
107
|
+
|
|
108
|
+
`--dsl` 选项允许你将 AI 生成的原始 DSL 语法保存到文本文件。适用于:
|
|
109
|
+
|
|
110
|
+
- **调试** — 检查 LLM 生成的内容,排查渲染失败原因
|
|
111
|
+
- **微调** — 手动编辑 DSL 以调整信息图细节
|
|
112
|
+
- **学习** — 了解 DSL 语法,为未来手动创建做准备
|
|
84
113
|
|
|
85
114
|
```bash
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
# 同时生成 SVG 和保存 DSL 语法
|
|
116
|
+
ig-gen "对比 React 和 Vue" -o frameworks.svg --dsl frameworks.txt
|
|
117
|
+
|
|
118
|
+
# 该命令会创建:
|
|
119
|
+
# - frameworks.svg (渲染后的信息图)
|
|
120
|
+
# - frameworks.txt (原始 DSL 语法)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**错误自动保存:**
|
|
124
|
+
如果经过 3 次自我修正后渲染仍然失败,有问题的 DSL 会自动保存到 `error-dump.txt` 以便调试。
|
|
125
|
+
|
|
126
|
+
### 4. 切换界面语言
|
|
127
|
+
|
|
128
|
+
默认情况下,CLI 输出为英文。如需切换为中文:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# 切换为中文
|
|
132
|
+
ig-gen config set locale zh-CN
|
|
133
|
+
|
|
134
|
+
# 切换回英文
|
|
135
|
+
ig-gen config set locale en
|
|
136
|
+
|
|
137
|
+
# 查看当前语言设置
|
|
138
|
+
ig-gen config get locale
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 5. 获取帮助
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
ig-gen --help
|
|
145
|
+
ig-gen config --help
|
|
146
|
+
ig-gen --version
|
|
88
147
|
infographic-gen generate --help
|
|
89
148
|
infographic-gen gen -h # gen 是 generate 的别名
|
|
90
149
|
```
|
|
@@ -96,7 +155,7 @@ infographic-gen gen -h # gen 是 generate 的别名
|
|
|
96
155
|
### 示例 1:技术演进时间线
|
|
97
156
|
|
|
98
157
|
```bash
|
|
99
|
-
|
|
158
|
+
ig-gen "展示 Web 技术演进:从 HTTP/1.0 到 HTTP/3"
|
|
100
159
|
```
|
|
101
160
|
|
|
102
161
|
自动生成时间线,展示关键里程碑。
|
|
@@ -104,7 +163,7 @@ infographic-gen gen "展示 Web 技术演进:从 HTTP/1.0 到 HTTP/3"
|
|
|
104
163
|
### 示例 2:对比矩阵
|
|
105
164
|
|
|
106
165
|
```bash
|
|
107
|
-
|
|
166
|
+
ig-gen "对比单体架构和微服务架构的优缺点"
|
|
108
167
|
```
|
|
109
168
|
|
|
110
169
|
生成包含优势和劣势的对比信息图。
|
|
@@ -112,11 +171,24 @@ infographic-gen gen "对比单体架构和微服务架构的优缺点"
|
|
|
112
171
|
### 示例 3:数据图表
|
|
113
172
|
|
|
114
173
|
```bash
|
|
115
|
-
|
|
174
|
+
ig-gen "编程语言使用分布:Python 35%、JavaScript 28%、Java 20%、C++ 12%、其他 5%"
|
|
116
175
|
```
|
|
117
176
|
|
|
118
177
|
自动创建饼图或柱状图。
|
|
119
178
|
|
|
179
|
+
### 示例 4:导出 DSL 用于调试
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
ig-gen "对比 React、Vue 和 Angular 的优缺点" -o frameworks.svg --dsl frameworks-dsl.txt
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
该命令会生成:
|
|
186
|
+
|
|
187
|
+
- `frameworks.svg` — 渲染后的信息图
|
|
188
|
+
- `frameworks-dsl.txt` — 原始 DSL 语法
|
|
189
|
+
|
|
190
|
+
你可以检查或手动编辑 DSL 文件来微调输出结果。如果渲染失败,可以检查 `error-dump.txt` 中的问题语法。
|
|
191
|
+
|
|
120
192
|
---
|
|
121
193
|
|
|
122
194
|
## 🛠️ 开发
|
|
@@ -131,15 +203,15 @@ npm install
|
|
|
131
203
|
|
|
132
204
|
### 常用命令
|
|
133
205
|
|
|
134
|
-
| 命令
|
|
135
|
-
|
|
136
|
-
| `npm run build`
|
|
137
|
-
| `npm run dev`
|
|
138
|
-
| `npm start`
|
|
139
|
-
| `npm test`
|
|
140
|
-
| `npm run test:watch` | Watch 模式测试
|
|
141
|
-
| `npm run sync`
|
|
142
|
-
| `npm run sync:check` | 仅检测,不更新(干运行)
|
|
206
|
+
| 命令 | 说明 |
|
|
207
|
+
| -------------------- | -------------------------------- |
|
|
208
|
+
| `npm run build` | 构建 CLI 到 `dist/index.js` |
|
|
209
|
+
| `npm run dev` | Watch 模式(文件变化自动重建) |
|
|
210
|
+
| `npm start` | 运行已构建的 CLI |
|
|
211
|
+
| `npm test` | 运行全部测试 (vitest) |
|
|
212
|
+
| `npm run test:watch` | Watch 模式测试 |
|
|
213
|
+
| `npm run sync` | 检查并更新上游 @antv/infographic |
|
|
214
|
+
| `npm run sync:check` | 仅检测,不更新(干运行) |
|
|
143
215
|
|
|
144
216
|
### 项目结构
|
|
145
217
|
|
|
@@ -177,36 +249,43 @@ infographic-gen/
|
|
|
177
249
|
## 📋 配置管理
|
|
178
250
|
|
|
179
251
|
配置文件存储位置:
|
|
252
|
+
|
|
180
253
|
- **macOS/Linux** — `~/.config/infographic-gen/config.json`
|
|
181
254
|
- **Windows** — `%APPDATA%\infographic-gen\config.json`
|
|
182
255
|
|
|
183
256
|
### 可配置的字段
|
|
184
257
|
|
|
185
|
-
| 字段
|
|
186
|
-
|
|
187
|
-
| `apiKey`
|
|
188
|
-
| `baseUrl`
|
|
189
|
-
| `modelName`
|
|
190
|
-
| `
|
|
258
|
+
| 字段 | 类型 | 示例 | 说明 |
|
|
259
|
+
| ------------------ | ------ | --------------------------- | ---------------------------------- |
|
|
260
|
+
| `apiKey` | string | `sk-...` | LLM API 密钥 |
|
|
261
|
+
| `baseUrl` | string | `https://api.openai.com/v1` | LLM 服务端点(可选) |
|
|
262
|
+
| `modelName` | string | `gpt-4o` | 使用的模型(可选,默认 gpt-4o) |
|
|
263
|
+
| `defaultOutputDir` | string | `~/infographics` 或 `.` | 默认输出目录(可选,默认当前目录) |
|
|
264
|
+
| `locale` | string | `en` 或 `zh-CN` | CLI 界面语言(可选,默认 `en`) |
|
|
191
265
|
|
|
192
266
|
### 通过 CLI 管理配置
|
|
193
267
|
|
|
194
268
|
```bash
|
|
195
269
|
# 设置
|
|
196
|
-
|
|
197
|
-
|
|
270
|
+
ig-gen config set apiKey sk-...
|
|
271
|
+
ig-gen config set baseUrl https://api.deepseek.com
|
|
272
|
+
ig-gen config set defaultOutputDir ~/my-infographics
|
|
273
|
+
ig-gen config set locale zh-CN # 切换界面语言为中文
|
|
198
274
|
|
|
199
275
|
# 读取
|
|
200
|
-
|
|
276
|
+
ig-gen config get apiKey
|
|
277
|
+
ig-gen config get locale # 查看当前语言设置
|
|
278
|
+
ig-gen c get defaultOutputDir # 使用 c 别名
|
|
201
279
|
|
|
202
280
|
# 列出所有配置
|
|
203
|
-
|
|
281
|
+
ig-gen config list
|
|
282
|
+
ig-gen c list # 使用 c 别名
|
|
204
283
|
|
|
205
284
|
# 删除
|
|
206
|
-
|
|
285
|
+
ig-gen config delete baseUrl
|
|
207
286
|
|
|
208
287
|
# 显示配置文件路径
|
|
209
|
-
|
|
288
|
+
ig-gen config path
|
|
210
289
|
```
|
|
211
290
|
|
|
212
291
|
---
|
|
@@ -247,6 +326,7 @@ npm run sync
|
|
|
247
326
|
推送 git tag 后,GitHub Actions 会自动发布到 npm:
|
|
248
327
|
|
|
249
328
|
1. **创建版本 tag**(遵循语义化版本):
|
|
329
|
+
|
|
250
330
|
```bash
|
|
251
331
|
npm version patch # 1.0.0 → 1.0.1 (bug 修复)
|
|
252
332
|
npm version minor # 1.0.0 → 1.1.0 (新功能)
|
|
@@ -296,6 +376,7 @@ npm publish # 需要先运行 npm login
|
|
|
296
376
|
```
|
|
297
377
|
|
|
298
378
|
发布时:
|
|
379
|
+
|
|
299
380
|
- 仅包含 `dist/` 文件夹(通过 `"files"` 字段)
|
|
300
381
|
- 创建全局 `infographic-gen` 命令
|
|
301
382
|
- 仅支持 ESM,需要 Node.js 18+
|
|
@@ -307,13 +388,15 @@ npm publish # 需要先运行 npm login
|
|
|
307
388
|
已配置两个自动化工作流:
|
|
308
389
|
|
|
309
390
|
### 1. `sync-upstream.yml` — 上游变更检测
|
|
391
|
+
|
|
310
392
|
- 每周运行(周一 08:00 UTC)
|
|
311
393
|
- 检测 `@antv/infographic` 版本更新
|
|
312
394
|
- 检查 SKILL.md 变更
|
|
313
395
|
- 有变更时自动创建 PR
|
|
314
396
|
|
|
315
397
|
### 2. `publish.yml` — 发布到 npm
|
|
316
|
-
|
|
398
|
+
|
|
399
|
+
- 当推送 git tag 时触发(格式:v*.*.\*)
|
|
317
400
|
- 自动构建和测试
|
|
318
401
|
- 发布到 npm
|
|
319
402
|
- 创建 GitHub Release
|
|
@@ -330,6 +413,7 @@ npm run test:watch # Watch 模式
|
|
|
330
413
|
```
|
|
331
414
|
|
|
332
415
|
测试覆盖:
|
|
416
|
+
|
|
333
417
|
- **131 个测试**分布在 7 个测试文件
|
|
334
418
|
- 配置管理(持久化存储)
|
|
335
419
|
- 日志和加载动画工具
|
|
@@ -413,7 +497,7 @@ LLM 可能建议了你的 @antv/infographic 版本中不存在的模板。尝试
|
|
|
413
497
|
---
|
|
414
498
|
|
|
415
499
|
更多信息请查看:
|
|
500
|
+
|
|
416
501
|
- [README.md](README.md) — 英文版本
|
|
417
502
|
- [PUBLISHING.md](PUBLISHING.md) — 详细发布指南
|
|
418
503
|
- [QUICK_START.md](QUICK_START.md) — 快速参考卡片
|
|
419
|
-
|
package/dist/index.js
CHANGED
|
@@ -125,19 +125,25 @@ var CONFIG_KEYS = [
|
|
|
125
125
|
"apiKey",
|
|
126
126
|
"baseUrl",
|
|
127
127
|
"provider",
|
|
128
|
-
"modelName"
|
|
128
|
+
"modelName",
|
|
129
|
+
"defaultOutputDir",
|
|
130
|
+
"locale"
|
|
129
131
|
];
|
|
130
132
|
var CONFIG_LABELS = {
|
|
131
133
|
apiKey: "API Key",
|
|
132
134
|
baseUrl: "Base URL",
|
|
133
135
|
provider: "Provider",
|
|
134
|
-
modelName: "Model Name"
|
|
136
|
+
modelName: "Model Name",
|
|
137
|
+
defaultOutputDir: "Default Output Directory",
|
|
138
|
+
locale: "Language"
|
|
135
139
|
};
|
|
136
140
|
var DEFAULTS = {
|
|
137
141
|
apiKey: "",
|
|
138
142
|
baseUrl: "https://api.openai.com/v1",
|
|
139
143
|
provider: "openai",
|
|
140
|
-
modelName: "gpt-4o"
|
|
144
|
+
modelName: "gpt-4o",
|
|
145
|
+
defaultOutputDir: ".",
|
|
146
|
+
locale: "en"
|
|
141
147
|
};
|
|
142
148
|
var store = new Conf({
|
|
143
149
|
projectName: "infographic-gen",
|
|
@@ -165,7 +171,9 @@ function getAllConfig() {
|
|
|
165
171
|
apiKey: getConfig("apiKey"),
|
|
166
172
|
baseUrl: getConfig("baseUrl"),
|
|
167
173
|
provider: getConfig("provider"),
|
|
168
|
-
modelName: getConfig("modelName")
|
|
174
|
+
modelName: getConfig("modelName"),
|
|
175
|
+
defaultOutputDir: getConfig("defaultOutputDir"),
|
|
176
|
+
locale: getConfig("locale")
|
|
169
177
|
};
|
|
170
178
|
}
|
|
171
179
|
function isValidConfigKey(key) {
|
|
@@ -197,49 +205,168 @@ function label(key, value) {
|
|
|
197
205
|
console.error(` ${import_picocolors.default.cyan(key)}: ${value}`);
|
|
198
206
|
}
|
|
199
207
|
|
|
208
|
+
// src/utils/i18n.ts
|
|
209
|
+
init_esm_shims();
|
|
210
|
+
var translations = {
|
|
211
|
+
en: {
|
|
212
|
+
// Main program
|
|
213
|
+
programDesc: "AI-powered CLI to generate AntV Infographic SVGs from natural language prompts",
|
|
214
|
+
versionFlag: "Display version number",
|
|
215
|
+
// Config command
|
|
216
|
+
configDesc: "Manage configuration (API Key, Base URL, Provider, Model, Output Directory)",
|
|
217
|
+
configSetDesc: "Set a configuration value",
|
|
218
|
+
configGetDesc: "Get a single configuration value",
|
|
219
|
+
configListDesc: "List all configuration values",
|
|
220
|
+
configDeleteDesc: "Delete a configuration value (reset to default)",
|
|
221
|
+
configPathDesc: "Show configuration file path",
|
|
222
|
+
configInvalidKey: 'Invalid config key "{key}". Available: {keys}',
|
|
223
|
+
configSetSuccess: "{label} set successfully",
|
|
224
|
+
configNotSet: "{label} not set",
|
|
225
|
+
configCurrent: "Current configuration:",
|
|
226
|
+
configFileLocation: " Config file location: {path}",
|
|
227
|
+
configResetSuccess: "{label} reset to default",
|
|
228
|
+
configNotSetValue: "(not set)",
|
|
229
|
+
// Generate command
|
|
230
|
+
generateDesc: "Generate an SVG infographic from natural language (default command)",
|
|
231
|
+
generatePromptArg: "Describe the infographic you want to create",
|
|
232
|
+
generateOutputOpt: "Output SVG file path (default: infographic-output.svg in default output directory)",
|
|
233
|
+
generateDslOpt: "Save raw DSL syntax to a text file (optional, for debugging or fine-tuning)",
|
|
234
|
+
outputTarget: "Output target: {path}",
|
|
235
|
+
callingAI: "Calling AI to generate infographic syntax...",
|
|
236
|
+
renderingSVG: "Rendering SVG...",
|
|
237
|
+
reRenderingSVG: "Re-rendering SVG...",
|
|
238
|
+
aiCallFailed: "AI call failed",
|
|
239
|
+
renderingFailed: "Rendering failed",
|
|
240
|
+
renderFailedAfterRetries: "Failed to generate renderable infographic after {retries} self-correction attempts.",
|
|
241
|
+
lastError: "Last error: {error}",
|
|
242
|
+
dslAutoSaved: "\u274C Problematic DSL syntax auto-saved to: {path}",
|
|
243
|
+
dslAutoSaveHint: "You can inspect this file to debug the LLM output or refine your prompt.",
|
|
244
|
+
dslForDebug: "Generated DSL syntax (for debugging reference):",
|
|
245
|
+
fileWriteFailed: "File write failed",
|
|
246
|
+
dslSaved: "DSL syntax saved to: {path}",
|
|
247
|
+
dslWriteFailed: "DSL file write failed (does not affect main functionality):",
|
|
248
|
+
infographicGenerated: "Infographic generated!",
|
|
249
|
+
svgSaved: "SVG saved to: {path}",
|
|
250
|
+
openInBrowser: "You can open the SVG file directly in a browser to view it.",
|
|
251
|
+
selfCorrecting: "AI self-correcting (attempt {attempt}/{max})...",
|
|
252
|
+
selfCorrectionFailed: "Self-correction failed",
|
|
253
|
+
renderFailedRetrying: "Render failed, auto-correcting (attempt {attempt}/{max})...",
|
|
254
|
+
// AI errors
|
|
255
|
+
apiKeyNotConfigured: "API Key not configured. Please run: infographic-gen config set apiKey <YOUR_KEY>",
|
|
256
|
+
llmEmptyContent: "LLM returned empty content",
|
|
257
|
+
failedAfterRetries: "Failed to generate renderable infographic after {retries} retries. Last error: {error}"
|
|
258
|
+
},
|
|
259
|
+
"zh-CN": {
|
|
260
|
+
// Main program
|
|
261
|
+
programDesc: "AI \u9A71\u52A8\u7684\u4FE1\u606F\u56FE\u751F\u6210 CLI \u2014\u2014 \u8F93\u5165\u81EA\u7136\u8BED\u8A00\uFF0C\u8F93\u51FA\u7CBE\u7F8E SVG \u4FE1\u606F\u56FE",
|
|
262
|
+
versionFlag: "\u663E\u793A\u7248\u672C\u53F7",
|
|
263
|
+
// Config command
|
|
264
|
+
configDesc: "\u7BA1\u7406\u914D\u7F6E\uFF08API Key\u3001Base URL\u3001Provider\u3001Model\u3001\u8F93\u51FA\u76EE\u5F55\uFF09",
|
|
265
|
+
configSetDesc: "\u8BBE\u7F6E\u914D\u7F6E\u9879",
|
|
266
|
+
configGetDesc: "\u67E5\u770B\u5355\u4E2A\u914D\u7F6E\u9879",
|
|
267
|
+
configListDesc: "\u5217\u51FA\u6240\u6709\u914D\u7F6E\u9879",
|
|
268
|
+
configDeleteDesc: "\u5220\u9664\u914D\u7F6E\u9879\uFF08\u6062\u590D\u9ED8\u8BA4\u503C\uFF09",
|
|
269
|
+
configPathDesc: "\u663E\u793A\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84",
|
|
270
|
+
configInvalidKey: '\u65E0\u6548\u7684\u914D\u7F6E\u9879 "{key}"\uFF0C\u53EF\u9009\u9879\uFF1A{keys}',
|
|
271
|
+
configSetSuccess: "{label} \u5DF2\u8BBE\u7F6E",
|
|
272
|
+
configNotSet: "{label} \u5C1A\u672A\u8BBE\u7F6E",
|
|
273
|
+
configCurrent: "\u5F53\u524D\u914D\u7F6E\uFF1A",
|
|
274
|
+
configFileLocation: " \u914D\u7F6E\u6587\u4EF6\u4F4D\u7F6E: {path}",
|
|
275
|
+
configResetSuccess: "{label} \u5DF2\u91CD\u7F6E\u4E3A\u9ED8\u8BA4\u503C",
|
|
276
|
+
configNotSetValue: "(\u672A\u8BBE\u7F6E)",
|
|
277
|
+
// Generate command
|
|
278
|
+
generateDesc: "\u6839\u636E\u81EA\u7136\u8BED\u8A00\u63CF\u8FF0\u751F\u6210 SVG \u4FE1\u606F\u56FE\uFF08\u9ED8\u8BA4\u547D\u4EE4\uFF09",
|
|
279
|
+
generatePromptArg: "\u63CF\u8FF0\u4F60\u60F3\u8981\u751F\u6210\u7684\u4FE1\u606F\u56FE\u5185\u5BB9",
|
|
280
|
+
generateOutputOpt: "\u8F93\u51FA SVG \u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4\uFF1A\u9ED8\u8BA4\u8F93\u51FA\u76EE\u5F55\u4E2D\u7684 infographic-output.svg\uFF09",
|
|
281
|
+
generateDslOpt: "\u5C06\u539F\u59CB DSL \u8BED\u6CD5\u4FDD\u5B58\u5230\u6307\u5B9A\u6587\u672C\u6587\u4EF6\uFF08\u53EF\u9009\uFF0C\u7528\u4E8E\u8C03\u8BD5\u6216\u5FAE\u8C03\uFF09",
|
|
282
|
+
outputTarget: "\u76EE\u6807\u8F93\u51FA\uFF1A{path}",
|
|
283
|
+
callingAI: "\u6B63\u5728\u8C03\u7528 AI \u751F\u6210\u4FE1\u606F\u56FE\u8BED\u6CD5...",
|
|
284
|
+
renderingSVG: "\u6B63\u5728\u6E32\u67D3 SVG...",
|
|
285
|
+
reRenderingSVG: "\u6B63\u5728\u91CD\u65B0\u6E32\u67D3 SVG...",
|
|
286
|
+
aiCallFailed: "AI \u8C03\u7528\u5931\u8D25",
|
|
287
|
+
renderingFailed: "\u6E32\u67D3\u6700\u7EC8\u5931\u8D25",
|
|
288
|
+
renderFailedAfterRetries: "\u7ECF\u8FC7 {retries} \u6B21\u81EA\u6211\u4FEE\u6B63\u4ECD\u65E0\u6CD5\u751F\u6210\u53EF\u6E32\u67D3\u7684\u4FE1\u606F\u56FE\u3002",
|
|
289
|
+
lastError: "\u6700\u540E\u4E00\u6B21\u9519\u8BEF\uFF1A{error}",
|
|
290
|
+
dslAutoSaved: "\u274C \u6709\u95EE\u9898\u7684 DSL \u8BED\u6CD5\u5DF2\u81EA\u52A8\u4FDD\u5B58\u81F3\uFF1A{path}",
|
|
291
|
+
dslAutoSaveHint: "\u4F60\u53EF\u4EE5\u68C0\u67E5\u6B64\u6587\u4EF6\u4EE5\u6392\u67E5\u5927\u6A21\u578B\u751F\u6210\u7684\u95EE\u9898\uFF0C\u6216\u7528\u4E8E\u8C03\u8BD5 Prompt\u3002",
|
|
292
|
+
dslForDebug: "\u751F\u6210\u7684 DSL \u8BED\u6CD5\u5982\u4E0B\uFF08\u4F9B debug \u53C2\u8003\uFF09\uFF1A",
|
|
293
|
+
fileWriteFailed: "\u6587\u4EF6\u5199\u5165\u5931\u8D25",
|
|
294
|
+
dslSaved: "DSL \u8BED\u6CD5\u5DF2\u4FDD\u5B58\u81F3\uFF1A{path}",
|
|
295
|
+
dslWriteFailed: "DSL \u6587\u4EF6\u5199\u5165\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u4E3B\u8981\u529F\u80FD\uFF09\uFF1A",
|
|
296
|
+
infographicGenerated: "\u4FE1\u606F\u56FE\u5DF2\u751F\u6210\uFF01",
|
|
297
|
+
svgSaved: "SVG \u5DF2\u4FDD\u5B58\u81F3\uFF1A{path}",
|
|
298
|
+
openInBrowser: "\u53EF\u76F4\u63A5\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00 SVG \u6587\u4EF6\u67E5\u770B\u6548\u679C\u3002",
|
|
299
|
+
selfCorrecting: "AI \u6B63\u5728\u81EA\u6211\u4FEE\u6B63\uFF08\u7B2C {attempt}/{max} \u6B21\uFF09...",
|
|
300
|
+
selfCorrectionFailed: "\u81EA\u6211\u4FEE\u6B63\u5931\u8D25",
|
|
301
|
+
renderFailedRetrying: "\u6E32\u67D3\u5931\u8D25\uFF0C\u6B63\u5728\u81EA\u52A8\u4FEE\u6B63\uFF08\u7B2C {attempt}/{max} \u6B21\uFF09...",
|
|
302
|
+
// AI errors
|
|
303
|
+
apiKeyNotConfigured: "\u5C1A\u672A\u914D\u7F6E API Key\u3002\u8BF7\u5148\u8FD0\u884C\uFF1Ainfographic-gen config set apiKey <YOUR_KEY>",
|
|
304
|
+
llmEmptyContent: "LLM \u8FD4\u56DE\u4E86\u7A7A\u5185\u5BB9",
|
|
305
|
+
failedAfterRetries: "\u5DF2\u91CD\u8BD5 {retries} \u6B21\u4ECD\u7136\u65E0\u6CD5\u751F\u6210\u53EF\u6E32\u67D3\u7684\u4FE1\u606F\u56FE\u3002\u6700\u540E\u4E00\u6B21\u9519\u8BEF\uFF1A{error}"
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
function getLocale() {
|
|
309
|
+
const locale = getConfig("locale");
|
|
310
|
+
return locale === "zh-CN" ? "zh-CN" : "en";
|
|
311
|
+
}
|
|
312
|
+
function t(key, params) {
|
|
313
|
+
const locale = getLocale();
|
|
314
|
+
let text = translations[locale][key];
|
|
315
|
+
if (params) {
|
|
316
|
+
Object.entries(params).forEach(([paramKey, value]) => {
|
|
317
|
+
text = text.replace(`{${paramKey}}`, String(value));
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
return text;
|
|
321
|
+
}
|
|
322
|
+
|
|
200
323
|
// src/commands/config.ts
|
|
201
324
|
function registerConfigCommand(program2) {
|
|
202
|
-
const configCmd = program2.command("config").
|
|
203
|
-
|
|
325
|
+
const configCmd = program2.command("config").alias("c").description(
|
|
326
|
+
"Manage configuration (API Key, Base URL, Provider, Model, Output Directory)"
|
|
327
|
+
);
|
|
328
|
+
configCmd.command("set <key> <value>").description(t("configSetDesc")).action((key, value) => {
|
|
204
329
|
if (!isValidConfigKey(key)) {
|
|
205
|
-
error(
|
|
330
|
+
error(t("configInvalidKey", { key, keys: CONFIG_KEYS.join(", ") }));
|
|
206
331
|
process.exit(1);
|
|
207
332
|
}
|
|
208
333
|
setConfig(key, value);
|
|
209
|
-
success(
|
|
334
|
+
success(t("configSetSuccess", { label: CONFIG_LABELS[key] }));
|
|
210
335
|
});
|
|
211
|
-
configCmd.command("get <key>").description("
|
|
336
|
+
configCmd.command("get <key>").description(t("configGetDesc")).action((key) => {
|
|
212
337
|
if (!isValidConfigKey(key)) {
|
|
213
|
-
error(
|
|
338
|
+
error(t("configInvalidKey", { key, keys: CONFIG_KEYS.join(", ") }));
|
|
214
339
|
process.exit(1);
|
|
215
340
|
}
|
|
216
341
|
const val = getConfig(key);
|
|
217
342
|
if (!val) {
|
|
218
|
-
warn(
|
|
343
|
+
warn(t("configNotSet", { label: CONFIG_LABELS[key] }));
|
|
219
344
|
} else {
|
|
220
345
|
const display = key === "apiKey" ? maskApiKey(val) : val;
|
|
221
346
|
label(CONFIG_LABELS[key], display);
|
|
222
347
|
}
|
|
223
348
|
});
|
|
224
|
-
configCmd.command("list").description("
|
|
349
|
+
configCmd.command("list").description(t("configListDesc")).action(() => {
|
|
225
350
|
const all = getAllConfig();
|
|
226
|
-
info("
|
|
351
|
+
info(t("configCurrent"));
|
|
227
352
|
for (const k of CONFIG_KEYS) {
|
|
228
353
|
const val = all[k];
|
|
229
|
-
const display = k === "apiKey" && val ? maskApiKey(val) : val || "
|
|
354
|
+
const display = k === "apiKey" && val ? maskApiKey(val) : val || t("configNotSetValue");
|
|
230
355
|
label(CONFIG_LABELS[k], display);
|
|
231
356
|
}
|
|
232
|
-
dim(
|
|
357
|
+
dim(t("configFileLocation", { path: getConfigPath() }));
|
|
233
358
|
});
|
|
234
|
-
configCmd.command("delete <key>").description("
|
|
359
|
+
configCmd.command("delete <key>").description(t("configDeleteDesc")).action((key) => {
|
|
235
360
|
if (!isValidConfigKey(key)) {
|
|
236
|
-
error(
|
|
361
|
+
error(t("configInvalidKey", { key, keys: CONFIG_KEYS.join(", ") }));
|
|
237
362
|
process.exit(1);
|
|
238
363
|
}
|
|
239
364
|
deleteConfig(key);
|
|
240
|
-
success(
|
|
365
|
+
success(
|
|
366
|
+
t("configResetSuccess", { label: CONFIG_LABELS[key] })
|
|
367
|
+
);
|
|
241
368
|
});
|
|
242
|
-
configCmd.command("path").description("
|
|
369
|
+
configCmd.command("path").description(t("configPathDesc")).action(() => {
|
|
243
370
|
console.log(getConfigPath());
|
|
244
371
|
});
|
|
245
372
|
}
|
|
@@ -622,9 +749,7 @@ var MAX_RETRIES = 3;
|
|
|
622
749
|
function createClient() {
|
|
623
750
|
const { apiKey, baseUrl } = getLLMConfig();
|
|
624
751
|
if (!apiKey) {
|
|
625
|
-
throw new Error(
|
|
626
|
-
"\u5C1A\u672A\u914D\u7F6E API Key\u3002\u8BF7\u5148\u8FD0\u884C\uFF1Ainfographic-gen config set apiKey <YOUR_KEY>"
|
|
627
|
-
);
|
|
752
|
+
throw new Error(t("apiKeyNotConfigured"));
|
|
628
753
|
}
|
|
629
754
|
return new OpenAI({
|
|
630
755
|
apiKey,
|
|
@@ -640,7 +765,7 @@ async function callLLM(client, model, messages) {
|
|
|
640
765
|
});
|
|
641
766
|
const content = response.choices[0]?.message?.content;
|
|
642
767
|
if (!content) {
|
|
643
|
-
throw new Error("
|
|
768
|
+
throw new Error(t("llmEmptyContent"));
|
|
644
769
|
}
|
|
645
770
|
return cleanDSL(content);
|
|
646
771
|
}
|
|
@@ -668,11 +793,21 @@ async function generateInfographicDSL(userPrompt) {
|
|
|
668
793
|
async function retryWithCorrection(originalSyntax, errorMessage, userPrompt, attempt) {
|
|
669
794
|
if (attempt > MAX_RETRIES) {
|
|
670
795
|
throw new Error(
|
|
671
|
-
|
|
796
|
+
t("failedAfterRetries", {
|
|
797
|
+
retries: String(MAX_RETRIES),
|
|
798
|
+
error: errorMessage
|
|
799
|
+
})
|
|
672
800
|
);
|
|
673
801
|
}
|
|
674
|
-
updateSpinner(
|
|
675
|
-
|
|
802
|
+
updateSpinner(
|
|
803
|
+
t("selfCorrecting", { attempt: String(attempt), max: String(MAX_RETRIES) })
|
|
804
|
+
);
|
|
805
|
+
warn(
|
|
806
|
+
t("renderFailedRetrying", {
|
|
807
|
+
attempt: String(attempt),
|
|
808
|
+
max: String(MAX_RETRIES)
|
|
809
|
+
})
|
|
810
|
+
);
|
|
676
811
|
const client = createClient();
|
|
677
812
|
const { modelName } = getLLMConfig();
|
|
678
813
|
const correctionMessage = SELF_CORRECTION_PROMPT_TEMPLATE.replace(
|
|
@@ -711,35 +846,43 @@ async function writeSVGFile(outputPath, svgContent) {
|
|
|
711
846
|
await fs.mkdir(dir, { recursive: true });
|
|
712
847
|
await fs.writeFile(absolutePath, svgContent, "utf-8");
|
|
713
848
|
}
|
|
849
|
+
async function writeDSLFile(outputPath, dslContent) {
|
|
850
|
+
const absolutePath = path2.resolve(outputPath);
|
|
851
|
+
const dir = path2.dirname(absolutePath);
|
|
852
|
+
await fs.mkdir(dir, { recursive: true });
|
|
853
|
+
await fs.writeFile(absolutePath, dslContent, "utf-8");
|
|
854
|
+
}
|
|
714
855
|
function resolveOutputPath(userOutput) {
|
|
856
|
+
const defaultDir = getConfig("defaultOutputDir") || ".";
|
|
715
857
|
if (userOutput) {
|
|
716
|
-
|
|
717
|
-
|
|
858
|
+
const withExt = userOutput.endsWith(".svg") ? userOutput : userOutput + ".svg";
|
|
859
|
+
if (path2.isAbsolute(withExt)) {
|
|
860
|
+
return withExt;
|
|
718
861
|
}
|
|
719
|
-
return
|
|
862
|
+
return path2.resolve(defaultDir, withExt);
|
|
720
863
|
}
|
|
721
|
-
return path2.resolve(
|
|
864
|
+
return path2.resolve(defaultDir, "infographic-output.svg");
|
|
722
865
|
}
|
|
723
866
|
|
|
724
867
|
// src/commands/generate.ts
|
|
725
868
|
function registerGenerateCommand(program2) {
|
|
726
|
-
program2.command("generate").alias("
|
|
727
|
-
await handleGenerate(prompt, opts.output);
|
|
869
|
+
program2.command("generate", { isDefault: true }).alias("g").description(t("generateDesc")).argument("<prompt>", t("generatePromptArg")).option("-o, --output <path>", t("generateOutputOpt")).option("--dsl <path>", t("generateDslOpt")).action(async (prompt, opts) => {
|
|
870
|
+
await handleGenerate(prompt, opts.output, opts.dsl);
|
|
728
871
|
});
|
|
729
872
|
}
|
|
730
|
-
async function handleGenerate(prompt, outputOption) {
|
|
873
|
+
async function handleGenerate(prompt, outputOption, dslOption) {
|
|
731
874
|
const outputPath = resolveOutputPath(outputOption);
|
|
732
|
-
info(
|
|
733
|
-
startSpinner("
|
|
875
|
+
info(t("outputTarget", { path: path3.resolve(outputPath) }));
|
|
876
|
+
startSpinner(t("callingAI"));
|
|
734
877
|
let syntax;
|
|
735
878
|
try {
|
|
736
879
|
syntax = await generateInfographicDSL(prompt);
|
|
737
880
|
} catch (err) {
|
|
738
|
-
failSpinner("
|
|
881
|
+
failSpinner(t("aiCallFailed"));
|
|
739
882
|
error(err instanceof Error ? err.message : String(err));
|
|
740
883
|
process.exit(1);
|
|
741
884
|
}
|
|
742
|
-
updateSpinner("
|
|
885
|
+
updateSpinner(t("renderingSVG"));
|
|
743
886
|
let svgContent = null;
|
|
744
887
|
let lastError = "";
|
|
745
888
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -750,40 +893,69 @@ async function handleGenerate(prompt, outputOption) {
|
|
|
750
893
|
lastError = err instanceof Error ? err.message : String(err);
|
|
751
894
|
if (attempt < MAX_RETRIES) {
|
|
752
895
|
try {
|
|
753
|
-
syntax = await retryWithCorrection(
|
|
754
|
-
|
|
896
|
+
syntax = await retryWithCorrection(
|
|
897
|
+
syntax,
|
|
898
|
+
lastError,
|
|
899
|
+
prompt,
|
|
900
|
+
attempt + 1
|
|
901
|
+
);
|
|
902
|
+
updateSpinner(t("reRenderingSVG"));
|
|
755
903
|
} catch (retryErr) {
|
|
756
|
-
failSpinner("
|
|
757
|
-
error(
|
|
904
|
+
failSpinner(t("selfCorrectionFailed"));
|
|
905
|
+
error(
|
|
906
|
+
retryErr instanceof Error ? retryErr.message : String(retryErr)
|
|
907
|
+
);
|
|
758
908
|
process.exit(1);
|
|
759
909
|
}
|
|
760
910
|
}
|
|
761
911
|
}
|
|
762
912
|
}
|
|
763
913
|
if (!svgContent) {
|
|
764
|
-
failSpinner("
|
|
765
|
-
error(
|
|
766
|
-
error(
|
|
767
|
-
|
|
768
|
-
|
|
914
|
+
failSpinner(t("renderingFailed"));
|
|
915
|
+
error(t("renderFailedAfterRetries", { retries: String(MAX_RETRIES) }));
|
|
916
|
+
error(t("lastError", { error: lastError }));
|
|
917
|
+
const errorDumpPath = "error-dump.txt";
|
|
918
|
+
try {
|
|
919
|
+
await writeDSLFile(errorDumpPath, syntax);
|
|
920
|
+
warn(t("dslAutoSaved", { path: path3.resolve(errorDumpPath) }));
|
|
921
|
+
dim(t("dslAutoSaveHint"));
|
|
922
|
+
} catch (writeErr) {
|
|
923
|
+
dim(t("dslForDebug"));
|
|
924
|
+
console.error(syntax);
|
|
925
|
+
}
|
|
769
926
|
process.exit(1);
|
|
770
927
|
}
|
|
771
928
|
try {
|
|
772
929
|
await writeSVGFile(outputPath, svgContent);
|
|
773
930
|
} catch (err) {
|
|
774
|
-
failSpinner("
|
|
931
|
+
failSpinner(t("fileWriteFailed"));
|
|
775
932
|
error(err instanceof Error ? err.message : String(err));
|
|
776
933
|
process.exit(1);
|
|
777
934
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
935
|
+
if (dslOption) {
|
|
936
|
+
try {
|
|
937
|
+
await writeDSLFile(dslOption, syntax);
|
|
938
|
+
success(t("dslSaved", { path: path3.resolve(dslOption) }));
|
|
939
|
+
} catch (err) {
|
|
940
|
+
warn(t("dslWriteFailed"));
|
|
941
|
+
warn(err instanceof Error ? err.message : String(err));
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
succeedSpinner(t("infographicGenerated"));
|
|
945
|
+
success(t("svgSaved", { path: path3.resolve(outputPath) }));
|
|
946
|
+
dim(t("openInBrowser"));
|
|
781
947
|
}
|
|
782
948
|
|
|
783
949
|
// src/index.ts
|
|
784
|
-
|
|
950
|
+
import { readFileSync } from "fs";
|
|
951
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
952
|
+
import { dirname, join } from "path";
|
|
953
|
+
var __dirname2 = dirname(fileURLToPath2(import.meta.url));
|
|
954
|
+
var packageJsonPath = join(__dirname2, "../package.json");
|
|
955
|
+
var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
956
|
+
var VERSION = packageJson.version;
|
|
785
957
|
var program = new Command();
|
|
786
|
-
program.name("infographic-gen").description("
|
|
958
|
+
program.name("infographic-gen").description(t("programDesc")).version(VERSION, "-v, --version", t("versionFlag"));
|
|
787
959
|
registerConfigCommand(program);
|
|
788
960
|
registerGenerateCommand(program);
|
|
789
961
|
program.parse(process.argv);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../node_modules/picocolors/picocolors.js","../src/index.ts","../src/commands/config.ts","../src/config/index.ts","../src/utils/logger.ts","../src/commands/generate.ts","../src/core/ai.ts","../src/core/prompts.ts","../src/utils/spinner.ts","../src/core/render.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","let p = process || {}, argv = p.argv || [], env = p.env || {}\nlet isColorSupported =\n\t!(!!env.NO_COLOR || argv.includes(\"--no-color\")) &&\n\t(!!env.FORCE_COLOR || argv.includes(\"--color\") || p.platform === \"win32\" || ((p.stdout || {}).isTTY && env.TERM !== \"dumb\") || !!env.CI)\n\nlet formatter = (open, close, replace = open) =>\n\tinput => {\n\t\tlet string = \"\" + input, index = string.indexOf(close, open.length)\n\t\treturn ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close\n\t}\n\nlet replaceClose = (string, close, replace, index) => {\n\tlet result = \"\", cursor = 0\n\tdo {\n\t\tresult += string.substring(cursor, index) + replace\n\t\tcursor = index + close.length\n\t\tindex = string.indexOf(close, cursor)\n\t} while (~index)\n\treturn result + string.substring(cursor)\n}\n\nlet createColors = (enabled = isColorSupported) => {\n\tlet f = enabled ? formatter : () => String\n\treturn {\n\t\tisColorSupported: enabled,\n\t\treset: f(\"\\x1b[0m\", \"\\x1b[0m\"),\n\t\tbold: f(\"\\x1b[1m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[1m\"),\n\t\tdim: f(\"\\x1b[2m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[2m\"),\n\t\titalic: f(\"\\x1b[3m\", \"\\x1b[23m\"),\n\t\tunderline: f(\"\\x1b[4m\", \"\\x1b[24m\"),\n\t\tinverse: f(\"\\x1b[7m\", \"\\x1b[27m\"),\n\t\thidden: f(\"\\x1b[8m\", \"\\x1b[28m\"),\n\t\tstrikethrough: f(\"\\x1b[9m\", \"\\x1b[29m\"),\n\n\t\tblack: f(\"\\x1b[30m\", \"\\x1b[39m\"),\n\t\tred: f(\"\\x1b[31m\", \"\\x1b[39m\"),\n\t\tgreen: f(\"\\x1b[32m\", \"\\x1b[39m\"),\n\t\tyellow: f(\"\\x1b[33m\", \"\\x1b[39m\"),\n\t\tblue: f(\"\\x1b[34m\", \"\\x1b[39m\"),\n\t\tmagenta: f(\"\\x1b[35m\", \"\\x1b[39m\"),\n\t\tcyan: f(\"\\x1b[36m\", \"\\x1b[39m\"),\n\t\twhite: f(\"\\x1b[37m\", \"\\x1b[39m\"),\n\t\tgray: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\n\t\tbgBlack: f(\"\\x1b[40m\", \"\\x1b[49m\"),\n\t\tbgRed: f(\"\\x1b[41m\", \"\\x1b[49m\"),\n\t\tbgGreen: f(\"\\x1b[42m\", \"\\x1b[49m\"),\n\t\tbgYellow: f(\"\\x1b[43m\", \"\\x1b[49m\"),\n\t\tbgBlue: f(\"\\x1b[44m\", \"\\x1b[49m\"),\n\t\tbgMagenta: f(\"\\x1b[45m\", \"\\x1b[49m\"),\n\t\tbgCyan: f(\"\\x1b[46m\", \"\\x1b[49m\"),\n\t\tbgWhite: f(\"\\x1b[47m\", \"\\x1b[49m\"),\n\n\t\tblackBright: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\t\tredBright: f(\"\\x1b[91m\", \"\\x1b[39m\"),\n\t\tgreenBright: f(\"\\x1b[92m\", \"\\x1b[39m\"),\n\t\tyellowBright: f(\"\\x1b[93m\", \"\\x1b[39m\"),\n\t\tblueBright: f(\"\\x1b[94m\", \"\\x1b[39m\"),\n\t\tmagentaBright: f(\"\\x1b[95m\", \"\\x1b[39m\"),\n\t\tcyanBright: f(\"\\x1b[96m\", \"\\x1b[39m\"),\n\t\twhiteBright: f(\"\\x1b[97m\", \"\\x1b[39m\"),\n\n\t\tbgBlackBright: f(\"\\x1b[100m\", \"\\x1b[49m\"),\n\t\tbgRedBright: f(\"\\x1b[101m\", \"\\x1b[49m\"),\n\t\tbgGreenBright: f(\"\\x1b[102m\", \"\\x1b[49m\"),\n\t\tbgYellowBright: f(\"\\x1b[103m\", \"\\x1b[49m\"),\n\t\tbgBlueBright: f(\"\\x1b[104m\", \"\\x1b[49m\"),\n\t\tbgMagentaBright: f(\"\\x1b[105m\", \"\\x1b[49m\"),\n\t\tbgCyanBright: f(\"\\x1b[106m\", \"\\x1b[49m\"),\n\t\tbgWhiteBright: f(\"\\x1b[107m\", \"\\x1b[49m\"),\n\t}\n}\n\nmodule.exports = createColors()\nmodule.exports.createColors = createColors\n","import { Command } from \"commander\";\nimport { registerConfigCommand } from \"./commands/config.js\";\nimport { registerGenerateCommand } from \"./commands/generate.js\";\n\nconst VERSION = \"1.0.0\";\n\nconst program = new Command();\n\nprogram\n .name(\"infographic-gen\")\n .description(\"AI 驱动的信息图生成 CLI —— 输入自然语言,输出精美 SVG 信息图\")\n .version(VERSION, \"-v, --version\", \"显示版本号\");\n\n// 注册子命令\nregisterConfigCommand(program);\nregisterGenerateCommand(program);\n\n// 解析命令行参数\nprogram.parse(process.argv);\n","import { Command } from \"commander\";\nimport {\n getAllConfig,\n getConfig,\n setConfig,\n deleteConfig,\n isValidConfigKey,\n getConfigPath,\n CONFIG_KEYS,\n CONFIG_LABELS,\n type ConfigKey,\n} from \"../config/index.js\";\nimport * as log from \"../utils/logger.js\";\n\n/**\n * 注册 `config` 子命令,支持以下操作:\n * config set <key> <value> — 设置配置项\n * config get <key> — 查看单个配置项\n * config list — 列出所有配置\n * config delete <key> — 删除(重置)配置项\n * config path — 打印配置文件路径\n */\nexport function registerConfigCommand(program: Command): void {\n const configCmd = program\n .command(\"config\")\n .description(\"管理 LLM 配置(API Key、Base URL、Provider、Model)\");\n\n // ---------- config set ----------\n configCmd\n .command(\"set <key> <value>\")\n .description(\"设置配置项\")\n .action((key: string, value: string) => {\n if (!isValidConfigKey(key)) {\n log.error(`无效的配置项 \"${key}\",可选项:${CONFIG_KEYS.join(\", \")}`);\n process.exit(1);\n }\n setConfig(key, value);\n log.success(`${CONFIG_LABELS[key]} 已设置`);\n });\n\n // ---------- config get ----------\n configCmd\n .command(\"get <key>\")\n .description(\"查看单个配置项\")\n .action((key: string) => {\n if (!isValidConfigKey(key)) {\n log.error(`无效的配置项 \"${key}\",可选项:${CONFIG_KEYS.join(\", \")}`);\n process.exit(1);\n }\n const val = getConfig(key);\n if (!val) {\n log.warn(`${CONFIG_LABELS[key]} 尚未设置`);\n } else {\n // 对 apiKey 做脱敏显示\n const display = key === \"apiKey\" ? maskApiKey(val) : val;\n log.label(CONFIG_LABELS[key], display);\n }\n });\n\n // ---------- config list ----------\n configCmd\n .command(\"list\")\n .description(\"列出所有配置项\")\n .action(() => {\n const all = getAllConfig();\n log.info(\"当前配置:\");\n for (const k of CONFIG_KEYS) {\n const val = all[k];\n const display =\n k === \"apiKey\" && val ? maskApiKey(val) : val || \"(未设置)\";\n log.label(CONFIG_LABELS[k], display);\n }\n log.dim(` 配置文件位置: ${getConfigPath()}`);\n });\n\n // ---------- config delete ----------\n configCmd\n .command(\"delete <key>\")\n .description(\"删除配置项(恢复默认值)\")\n .action((key: string) => {\n if (!isValidConfigKey(key)) {\n log.error(`无效的配置项 \"${key}\",可选项:${CONFIG_KEYS.join(\", \")}`);\n process.exit(1);\n }\n deleteConfig(key as ConfigKey);\n log.success(`${CONFIG_LABELS[key as ConfigKey]} 已重置为默认值`);\n });\n\n // ---------- config path ----------\n configCmd\n .command(\"path\")\n .description(\"显示配置文件路径\")\n .action(() => {\n console.log(getConfigPath());\n });\n}\n\n// ---- helpers ----\n\n/** 对 API Key 做脱敏处理:只显示前 4 位和后 4 位 */\nfunction maskApiKey(key: string): string {\n if (key.length <= 8) return \"****\";\n return key.slice(0, 4) + \"****\" + key.slice(-4);\n}\n","import Conf from \"conf\";\n\n/**\n * 用户可配置的 LLM 字段\n */\nexport interface LLMConfig {\n apiKey: string;\n baseUrl: string;\n provider: string;\n modelName: string;\n}\n\n/**\n * 配置 schema 的完整类型\n */\ninterface ConfigSchema {\n apiKey: string;\n baseUrl: string;\n provider: string;\n modelName: string;\n}\n\n/** 所有可配置的 key */\nexport const CONFIG_KEYS = [\n \"apiKey\",\n \"baseUrl\",\n \"provider\",\n \"modelName\",\n] as const;\nexport type ConfigKey = (typeof CONFIG_KEYS)[number];\n\n/** 配置项的人类可读标签 */\nexport const CONFIG_LABELS: Record<ConfigKey, string> = {\n apiKey: \"API Key\",\n baseUrl: \"Base URL\",\n provider: \"Provider\",\n modelName: \"Model Name\",\n};\n\n/** 默认值 */\nconst DEFAULTS: ConfigSchema = {\n apiKey: \"\",\n baseUrl: \"https://api.openai.com/v1\",\n provider: \"openai\",\n modelName: \"gpt-4o\",\n};\n\n/**\n * 基于 conf 的本地持久化配置管理器(单例)\n */\nconst store = new Conf<ConfigSchema>({\n projectName: \"infographic-gen\",\n defaults: DEFAULTS,\n});\n\n/** 读取单个配置值 */\nexport function getConfig<K extends ConfigKey>(key: K): string {\n return store.get(key) as string;\n}\n\n/** 写入单个配置值 */\nexport function setConfig<K extends ConfigKey>(key: K, value: string): void {\n store.set(key, value);\n}\n\n/** 删除单个配置值(恢复为默认) */\nexport function deleteConfig<K extends ConfigKey>(key: K): void {\n store.delete(key);\n}\n\n/** 读取完整 LLM 配置(用于创建 OpenAI 客户端) */\nexport function getLLMConfig(): LLMConfig {\n return {\n apiKey: getConfig(\"apiKey\"),\n baseUrl: getConfig(\"baseUrl\"),\n provider: getConfig(\"provider\"),\n modelName: getConfig(\"modelName\"),\n };\n}\n\n/** 返回所有配置项的 KV 对象(用于 `config list`) */\nexport function getAllConfig(): Record<ConfigKey, string> {\n return {\n apiKey: getConfig(\"apiKey\"),\n baseUrl: getConfig(\"baseUrl\"),\n provider: getConfig(\"provider\"),\n modelName: getConfig(\"modelName\"),\n };\n}\n\n/** 判断某个 key 是否为合法配置项 */\nexport function isValidConfigKey(key: string): key is ConfigKey {\n return CONFIG_KEYS.includes(key as ConfigKey);\n}\n\n/** 返回配置文件在磁盘上的路径(用于 debug) */\nexport function getConfigPath(): string {\n return store.path;\n}\n","import pc from \"picocolors\";\n\n/**\n * 统一的控制台日志工具,基于 picocolors 着色。\n * 所有输出走 stderr,stdout 留给管道场景。\n */\n\nexport function info(msg: string): void {\n console.error(pc.blue(\"ℹ\") + \" \" + msg);\n}\n\nexport function success(msg: string): void {\n console.error(pc.green(\"✔\") + \" \" + msg);\n}\n\nexport function warn(msg: string): void {\n console.error(pc.yellow(\"⚠\") + \" \" + pc.yellow(msg));\n}\n\nexport function error(msg: string): void {\n console.error(pc.red(\"✖\") + \" \" + pc.red(msg));\n}\n\nexport function dim(msg: string): void {\n console.error(pc.dim(msg));\n}\n\nexport function bold(msg: string): string {\n return pc.bold(msg);\n}\n\nexport function label(key: string, value: string): void {\n console.error(` ${pc.cyan(key)}: ${value}`);\n}\n","import path from 'node:path';\nimport { Command } from 'commander';\nimport { generateInfographicDSL, retryWithCorrection, MAX_RETRIES } from '../core/ai.js';\nimport { renderDSLToSVG, writeSVGFile, resolveOutputPath } from '../core/render.js';\nimport * as log from '../utils/logger.js';\nimport {\n startSpinner,\n succeedSpinner,\n failSpinner,\n updateSpinner,\n} from '../utils/spinner.js';\n\n/**\n * 注册 `generate` 子命令。\n *\n * 用法示例:\n * infographic-gen generate \"帮我画一个软件开发流程图\" -o result.svg\n */\nexport function registerGenerateCommand(program: Command): void {\n program\n .command('generate')\n .alias('gen')\n .description('根据自然语言描述生成 SVG 信息图')\n .argument('<prompt>', '描述你想要生成的信息图内容')\n .option('-o, --output <path>', '输出 SVG 文件路径', 'infographic-output.svg')\n .action(async (prompt: string, opts: { output: string }) => {\n await handleGenerate(prompt, opts.output);\n });\n}\n\n/**\n * 生成命令的核心处理逻辑。\n *\n * 流程:\n * 1. 调用 LLM 生成 DSL\n * 2. 调用 SSR 渲染为 SVG\n * 3. 如果渲染失败,自动进入自我修正循环(最多 MAX_RETRIES 次)\n * 4. 写入 SVG 文件\n */\nasync function handleGenerate(prompt: string, outputOption: string): Promise<void> {\n const outputPath = resolveOutputPath(outputOption);\n\n log.info(`目标输出:${path.resolve(outputPath)}`);\n startSpinner('正在调用 AI 生成信息图语法...');\n\n let syntax: string;\n try {\n syntax = await generateInfographicDSL(prompt);\n } catch (err) {\n failSpinner('AI 调用失败');\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n updateSpinner('正在渲染 SVG...');\n\n // ─── 渲染 + 自我修正循环 ───────────────────────────────────────────\n let svgContent: string | null = null;\n let lastError = '';\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n svgContent = await renderDSLToSVG(syntax);\n break; // 渲染成功,跳出循环\n } catch (err) {\n lastError = err instanceof Error ? err.message : String(err);\n\n if (attempt < MAX_RETRIES) {\n // 还有重试机会 → 自我修正\n try {\n syntax = await retryWithCorrection(syntax, lastError, prompt, attempt + 1);\n updateSpinner('正在重新渲染 SVG...');\n } catch (retryErr) {\n failSpinner('自我修正失败');\n log.error(retryErr instanceof Error ? retryErr.message : String(retryErr));\n process.exit(1);\n }\n }\n }\n }\n\n if (!svgContent) {\n failSpinner('渲染最终失败');\n log.error(`经过 ${MAX_RETRIES} 次自我修正仍无法生成可渲染的信息图。`);\n log.error(`最后一次错误:${lastError}`);\n log.dim('生成的 DSL 语法如下(供 debug 参考):');\n console.error(syntax);\n process.exit(1);\n }\n\n // ─── 渲染成功,写入文件 ─────────────────────────────────────────────\n try {\n await writeSVGFile(outputPath, svgContent);\n } catch (err) {\n failSpinner('文件写入失败');\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n succeedSpinner(`信息图已生成!`);\n log.success(`SVG 已保存至:${path.resolve(outputPath)}`);\n log.dim('可直接在浏览器中打开 SVG 文件查看效果。');\n}\n","import OpenAI from \"openai\";\nimport { getLLMConfig } from \"../config/index.js\";\nimport {\n INFOGRAPHIC_CREATOR_SYSTEM_PROMPT,\n SELF_CORRECTION_PROMPT_TEMPLATE,\n} from \"./prompts.js\";\nimport * as log from \"../utils/logger.js\";\nimport { updateSpinner } from \"../utils/spinner.js\";\n\n/** LLM 请求返回的结果 */\nexport interface LLMResult {\n /** 生成的 DSL 语法文本 */\n syntax: string;\n /** 总共重试了几次(0 = 一次成功) */\n attempts: number;\n}\n\n/** 最大自我修正重试次数 */\nconst MAX_RETRIES = 3;\n\n/**\n * 创建一个懒初始化的 OpenAI 客户端。\n * 通过覆盖 baseURL / apiKey 兼容 DeepSeek、阿里云百炼等平台。\n */\nfunction createClient(): OpenAI {\n const { apiKey, baseUrl } = getLLMConfig();\n\n if (!apiKey) {\n throw new Error(\n \"尚未配置 API Key。请先运行:infographic-gen config set apiKey <YOUR_KEY>\",\n );\n }\n\n return new OpenAI({\n apiKey,\n baseURL: baseUrl,\n });\n}\n\n/**\n * 向 LLM 发送请求,获取信息图 DSL。\n *\n * @param userPrompt 用户的自然语言描述\n * @returns LLM 返回的纯 DSL 文本\n */\nasync function callLLM(\n client: OpenAI,\n model: string,\n messages: OpenAI.ChatCompletionMessageParam[],\n): Promise<string> {\n const response = await client.chat.completions.create({\n model,\n messages,\n temperature: 0.7,\n max_tokens: 4096,\n });\n\n const content = response.choices[0]?.message?.content;\n if (!content) {\n throw new Error(\"LLM 返回了空内容\");\n }\n\n return cleanDSL(content);\n}\n\n/**\n * 清理 LLM 返回的文本,去除可能的 Markdown 代码块标记等噪声。\n */\nfunction cleanDSL(raw: string): string {\n let cleaned = raw.trim();\n\n // 去掉可能包裹的 ```xxx ... ``` 代码块\n const codeBlockMatch = cleaned.match(/^```[\\w]*\\n?([\\s\\S]*?)```$/);\n if (codeBlockMatch) {\n cleaned = codeBlockMatch[1].trim();\n }\n\n // 确保以 infographic 开头\n const infographicIndex = cleaned.indexOf(\"infographic \");\n if (infographicIndex > 0) {\n cleaned = cleaned.slice(infographicIndex);\n }\n\n return cleaned;\n}\n\n/**\n * 带自我修正机制的 AI 生成入口。\n *\n * 流程:\n * 1. 将用户 Prompt + 系统提示词发给 LLM,获取 DSL。\n * 2. 调用方(generate 命令)会尝试渲染。如果渲染失败,调用 retryWithCorrection。\n * 3. 最多重试 MAX_RETRIES 次。\n *\n * @param userPrompt 用户输入的自然语言\n * @returns 生成的 DSL 语法\n */\nexport async function generateInfographicDSL(\n userPrompt: string,\n): Promise<string> {\n const client = createClient();\n const { modelName } = getLLMConfig();\n\n const messages: OpenAI.ChatCompletionMessageParam[] = [\n { role: \"system\", content: INFOGRAPHIC_CREATOR_SYSTEM_PROMPT },\n { role: \"user\", content: userPrompt },\n ];\n\n return callLLM(client, modelName, messages);\n}\n\n/**\n * 自我修正:当 DSL 渲染失败时,把错误信息反馈给 LLM 要求修正。\n *\n * @param originalSyntax 上一次生成的 DSL\n * @param errorMessage 渲染报错信息\n * @param userPrompt 用户原始需求\n * @param attempt 当前第几次重试(从 1 开始)\n * @returns 修正后的 DSL\n */\nexport async function retryWithCorrection(\n originalSyntax: string,\n errorMessage: string,\n userPrompt: string,\n attempt: number,\n): Promise<string> {\n if (attempt > MAX_RETRIES) {\n throw new Error(\n `已重试 ${MAX_RETRIES} 次仍然无法生成可渲染的信息图。最后一次错误:${errorMessage}`,\n );\n }\n\n updateSpinner(`AI 正在自我修正(第 ${attempt}/${MAX_RETRIES} 次)...`);\n log.warn(`渲染失败,正在自动修正(第 ${attempt}/${MAX_RETRIES} 次)...`);\n\n const client = createClient();\n const { modelName } = getLLMConfig();\n\n const correctionMessage = SELF_CORRECTION_PROMPT_TEMPLATE.replace(\n \"{error}\",\n errorMessage,\n ).replace(\"{syntax}\", originalSyntax);\n\n const messages: OpenAI.ChatCompletionMessageParam[] = [\n { role: \"system\", content: INFOGRAPHIC_CREATOR_SYSTEM_PROMPT },\n { role: \"user\", content: userPrompt },\n { role: \"assistant\", content: originalSyntax },\n { role: \"user\", content: correctionMessage },\n ];\n\n return callLLM(client, modelName, messages);\n}\n\n/** 导出最大重试次数常量供外部使用 */\nexport { MAX_RETRIES };\n","/**\n * ⭐ 硬编码的系统提示词常量。\n *\n * 直接内嵌在代码中,确保 CLI 开箱即用,无需读取本地磁盘文件。\n * 内容基于 @antv/infographic 的 .skills/infographic-creator/SKILL.md 整理。\n */\n\n// ─── 公共:AntV Infographic 语法规范 ────────────────────────────────\n\nconst SYNTAX_SPEC = `\n## AntV Infographic 语法\n\nAntV Infographic 语法是一种自定义的 DSL,用于描述信息图渲染配置。它使用缩进描述信息,具有较强鲁棒性,便于 AI 流式输出并渲染信息图。主要包含以下信息:\n\n1. template:用模板表达文字信息结构。\n2. data:信息图数据,包含 title、desc、数据项等。数据项通常包含 label、desc、icon 等字段。\n3. theme:主题包含 palette、font 等样式配置。\n\n例如:\n\\`\\`\\`\ninfographic list-row-horizontal-icon-arrow\ndata\n title Title\n desc Description\n lists\n - label Label\n value 12.5\n desc Explanation\n icon document text\ntheme\n palette #3b82f6 #8b5cf6 #f97316\n\\`\\`\\`\n\n### 语法规范\n\n• 第一行必须是 \\`infographic <template-name>\\`,模板从下方可用模板列表中选择。\n• 使用 \\`data\\` / \\`theme\\` 块,块内用两个空格缩进。\n• 键值对使用「键 空格 值」;数组使用 \\`-\\` 作为条目前缀。\n• icon 使用图标关键词(如 \\`star fill\\`)。\n• \\`data\\` 应包含 title/desc + 模板对应的主数据字段(不一定是 \\`items\\`)。\n• 主数据字段选择(只用一个,避免混用):\n - \\`list-*\\` → \\`lists\\`\n - \\`sequence-*\\` → \\`sequences\\`(可选 \\`order asc|desc\\`)\n - \\`compare-*\\` → \\`compares\\`(支持 \\`children\\` 分组对比),可包含多个对比项\n - \\`hierarchy-structure\\` → \\`items\\`(每一项对应一个独立层级,每一层级可以包含子项,最多可嵌套 3 层)\n - \\`hierarchy-*\\` → 单一 \\`root\\`(树结构,通过 \\`children\\` 嵌套)\n - \\`relation-*\\` → \\`nodes\\` + \\`relations\\`;简单关系图可省略 \\`nodes\\`,在 relations 中用箭头语法\n - \\`chart-*\\` → \\`values\\`(数值统计,可选 \\`category\\`)\n - 不确定时再用 \\`items\\` 兜底\n\n• \\`compare-binary-*\\` / \\`compare-hierarchy-left-right-*\\` 二元模板:必须两个根节点,所有对比项挂在这两个根节点的 children\n• \\`hierarchy-*\\`:使用单一 \\`root\\`,通过 \\`children\\` 嵌套(不要重复 \\`root\\`)\n• \\`theme\\` 用于自定义主题(palette、font 等)\n\n例如:暗色主题 + 自定义配色\n\\`\\`\\`\ninfographic list-row-simple-horizontal-arrow\ntheme dark\n palette\n - #61DDAA\n - #F6BD16\n - #F08BB4\n\\`\\`\\`\n\n• 使用 \\`theme.base.text.font-family\\` 指定字体,如手写风格 \\`851tegakizatsu\\`\n• 使用 \\`theme.stylize\\` 选择内置风格并传参。常见风格:\n - \\`rough\\`:手绘效果\n - \\`pattern\\`:图案填充\n - \\`linear-gradient\\` / \\`radial-gradient\\`:线性/径向渐变\n\n例如:手绘风格(rough)\n\\`\\`\\`\ninfographic list-row-simple-horizontal-arrow\ntheme\n stylize rough\n base\n text\n font-family 851tegakizatsu\n\\`\\`\\`\n`.trim();\n\n// ─── 数据语法示例 ───────────────────────────────────────────────────\n\nconst DATA_EXAMPLES = `\n### 数据语法示例\n\n• list-* 模版\n\\`\\`\\`\ninfographic list-grid-badge-card\ndata\n title Feature List\n lists\n - label Fast\n icon flash fast\n - label Secure\n icon secure shield check\n\\`\\`\\`\n\n• sequence-* 模版\n\\`\\`\\`\ninfographic sequence-steps-simple\ndata\n sequences\n - label Step 1\n - label Step 2\n - label Step 3\n order asc\n\\`\\`\\`\n\n• hierarchy-* 模版\n\\`\\`\\`\ninfographic hierarchy-structure\ndata\n root\n label Company\n children\n - label Dept A\n - label Dept B\n\\`\\`\\`\n\n• compare-* 模版\n\\`\\`\\`\ninfographic compare-swot\ndata\n compares\n - label Strengths\n children\n - label Strong brand\n - label Loyal users\n - label Weaknesses\n children\n - label High cost\n - label Slow release\n\\`\\`\\`\n\n四象限图\n\\`\\`\\`\ninfographic compare-quadrant-quarter-simple-card\ndata\n compares\n - label High Impact & Low Effort\n - label High Impact & High Effort\n - label Low Impact & Low Effort\n - label Low Impact & High Effort\n\\`\\`\\`\n\n• chart-* 模版\n\\`\\`\\`\ninfographic chart-column-simple\ndata\n values\n - label Visits\n value 1280\n - label Conversion\n value 12.4\n\\`\\`\\`\n\n• relation-* 模版\n边标签写法:A -label-> B 或 A -->|label| B\n\\`\\`\\`\ninfographic relation-dagre-flow-tb-simple-circle-node\ndata\n nodes\n - id A\n label Node A\n - id B\n label Node B\n relations\n A - approves -> B\n A -->|blocks| B\n\\`\\`\\`\n\n• 兜底 items 示例\n\\`\\`\\`\ninfographic list-row-horizontal-icon-arrow\ndata\n items\n - label Item A\n desc Description\n icon sun\n - label Item B\n desc Description\n icon moon\n\\`\\`\\`\n`.trim();\n\n// ─── 可用模板列表 ───────────────────────────────────────────────────\n\nconst AVAILABLE_TEMPLATES = `\n### 可用模板\n\n• chart-bar-plain-text\n• chart-column-simple\n• chart-line-plain-text\n• chart-pie-compact-card\n• chart-pie-donut-pill-badge\n• chart-pie-donut-plain-text\n• chart-pie-plain-text\n• chart-wordcloud\n• compare-binary-horizontal-badge-card-arrow\n• compare-binary-horizontal-simple-fold\n• compare-binary-horizontal-underline-text-vs\n• compare-hierarchy-left-right-circle-node-pill-badge\n• compare-quadrant-quarter-circular\n• compare-quadrant-quarter-simple-card\n• compare-swot\n• hierarchy-mindmap-branch-gradient-capsule-item\n• hierarchy-mindmap-level-gradient-compact-card\n• hierarchy-structure\n• hierarchy-tree-curved-line-rounded-rect-node\n• hierarchy-tree-tech-style-badge-card\n• hierarchy-tree-tech-style-capsule-item\n• list-column-done-list\n• list-column-simple-vertical-arrow\n• list-column-vertical-icon-arrow\n• list-grid-badge-card\n• list-grid-candy-card-lite\n• list-grid-ribbon-card\n• list-row-horizontal-icon-arrow\n• list-sector-plain-text\n• list-waterfall-badge-card\n• list-waterfall-compact-card\n• list-zigzag-down-compact-card\n• list-zigzag-down-simple\n• list-zigzag-up-compact-card\n• list-zigzag-up-simple\n• relation-dagre-flow-tb-animated-badge-card\n• relation-dagre-flow-tb-animated-simple-circle-node\n• relation-dagre-flow-tb-badge-card\n• relation-dagre-flow-tb-simple-circle-node\n• sequence-ascending-stairs-3d-underline-text\n• sequence-ascending-steps\n• sequence-circular-simple\n• sequence-color-snake-steps-horizontal-icon-line\n• sequence-cylinders-3d-simple\n• sequence-filter-mesh-simple\n• sequence-funnel-simple\n• sequence-horizontal-zigzag-underline-text\n• sequence-mountain-underline-text\n• sequence-pyramid-simple\n• sequence-roadmap-vertical-plain-text\n• sequence-roadmap-vertical-simple\n• sequence-snake-steps-compact-card\n• sequence-snake-steps-simple\n• sequence-snake-steps-underline-text\n• sequence-stairs-front-compact-card\n• sequence-stairs-front-pill-badge\n• sequence-timeline-rounded-rect-node\n• sequence-timeline-simple\n• sequence-zigzag-pucks-3d-simple\n• sequence-zigzag-steps-underline-text\n\n模板选择建议:\n• 严格顺序(流程/步骤/发展趋势)→ sequence-*\n - 时间线 → sequence-timeline-*\n - 阶梯图 → sequence-stairs-*\n - 路线图 → sequence-roadmap-vertical-*\n - 折线路径 → sequence-zigzag-*\n - 环形进度 → sequence-circular-simple\n - 彩色蛇形步骤 → sequence-color-snake-steps-*\n - 金字塔 → sequence-pyramid-simple\n• 观点列举 → list-row-* 或 list-column-*\n• 二元对比(利弊)→ compare-binary-*\n• SWOT → compare-swot\n• 层级结构(树图)→ hierarchy-tree-*\n• 数据图表 → chart-*\n• 象限分析 → quadrant-*\n• 网格列表(要点)→ list-grid-*\n• 关系展示 → relation-*\n• 词云 → chart-wordcloud\n• 思维导图 → hierarchy-mindmap-*\n`.trim();\n\n// ─── 完整示例 ───────────────────────────────────────────────────────\n\nconst FULL_EXAMPLE = `\n### 完整示例\n\n绘制互联网技术演进信息图:\n\\`\\`\\`\ninfographic list-row-horizontal-icon-arrow\ndata\n title Internet Technology Evolution\n desc From Web 1.0 to AI era, key milestones\n lists\n - time 1991\n label Web 1.0\n desc Tim Berners-Lee published the first website, opening the Internet era\n icon web\n - time 2004\n label Web 2.0\n desc Social media and user-generated content become mainstream\n icon account multiple\n - time 2007\n label Mobile\n desc iPhone released, smartphone changes the world\n icon cellphone\n - time 2015\n label Cloud Native\n desc Containerization and microservices architecture are widely used\n icon cloud\n - time 2020\n label Low Code\n desc Visual development lowers the technology threshold\n icon application brackets\n - time 2023\n label AI Large Model\n desc ChatGPT ignites the generative AI revolution\n icon brain\n\\`\\`\\`\n`.trim();\n\n// ─── 导出:信息图创建者系统提示词 ───────────────────────────────────\n\n/**\n * 信息图创建者的完整 System Prompt。\n * 用于指导 LLM 根据用户自然语言需求,生成合法的 AntV Infographic DSL 语法。\n */\nexport const INFOGRAPHIC_CREATOR_SYSTEM_PROMPT = `\n你是一位专业的信息图设计专家。你的任务是根据用户的需求,生成 AntV Infographic DSL 语法来创建精美的信息图。\n\n信息图(Infographic)将数据、信息与知识转化为可感知的视觉语言。它结合视觉设计与数据可视化,用直观符号压缩复杂信息,帮助受众快速理解并记住要点。\n\nInfographic = Information Structure + Visual Expression\n\n你需要严格遵守以下规范来生成 AntV Infographic 语法:\n\n${SYNTAX_SPEC}\n\n${DATA_EXAMPLES}\n\n${AVAILABLE_TEMPLATES}\n\n${FULL_EXAMPLE}\n\n## 重要约束\n\n1. **只输出纯 DSL 语法**:不要输出任何 Markdown 代码块标记(如 \\\\\\`\\\\\\`\\\\\\`)、解释性文字、JSON 或其他格式。直接输出以 \\`infographic <template-name>\\` 开头的 DSL 文本。\n2. **必须尊重用户输入语言**:如果用户使用中文描述需求,DSL 中所有文本内容(title、desc、label 等)也必须使用中文。\n3. **选择最合适的模板**:根据用户需求的信息结构(列表、流程、对比、层级等)选择最匹配的模板。\n4. **数据完整性**:确保生成的数据结构完整,包含 title、desc 以及与模板匹配的主数据字段。\n5. **配色和主题**:除非用户特别要求,否则使用一组美观且协调的默认配色。\n`.trim();\n\n/**\n * 自我修正提示词模板。\n * 当 SSR 渲染失败时,将报错信息注入后发给 LLM 进行修正。\n */\nexport const SELF_CORRECTION_PROMPT_TEMPLATE = `\n之前你生成的 AntV Infographic DSL 语法在渲染时出错了。\n\n报错信息:\n{error}\n\n之前生成的语法:\n{syntax}\n\n请修正语法并重新输出。要求:\n1. 只输出修正后的纯 DSL 语法,不要添加任何解释或 Markdown 格式。\n2. 确保第一行是 \\`infographic <template-name>\\`。\n3. 确保数据结构符合所选模板的规范。\n4. 修复导致错误的具体问题。\n`.trim();\n","import ora, { type Ora } from \"ora\";\n\n/**\n * 终端 Loading 动画封装。\n * 提供 start / succeed / fail / update 等便捷方法。\n */\n\nlet currentSpinner: Ora | null = null;\n\nexport function startSpinner(text: string): Ora {\n // 如果之前有未关闭的 spinner,先停掉\n if (currentSpinner?.isSpinning) {\n currentSpinner.stop();\n }\n currentSpinner = ora({ text, stream: process.stderr }).start();\n return currentSpinner;\n}\n\nexport function succeedSpinner(text?: string): void {\n currentSpinner?.succeed(text);\n currentSpinner = null;\n}\n\nexport function failSpinner(text?: string): void {\n currentSpinner?.fail(text);\n currentSpinner = null;\n}\n\nexport function updateSpinner(text: string): void {\n if (currentSpinner) {\n currentSpinner.text = text;\n }\n}\n\nexport function stopSpinner(): void {\n currentSpinner?.stop();\n currentSpinner = null;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { renderToString } from \"@antv/infographic/ssr\";\n\n/**\n * 渲染结果\n */\nexport interface RenderResult {\n /** 生成的 SVG 字符串 */\n svg: string;\n}\n\n/**\n * 使用 @antv/infographic SSR 将 DSL 语法渲染为 SVG 字符串。\n *\n * @param syntax AntV Infographic DSL 语法文本\n * @returns SVG 字符串\n * @throws 渲染失败时抛出带有详细错误信息的 Error\n */\nexport async function renderDSLToSVG(syntax: string): Promise<string> {\n try {\n const svgString = await renderToString(syntax);\n if (!svgString || svgString.trim().length === 0) {\n throw new Error(\"renderToString 返回了空的 SVG 内容\");\n }\n return svgString;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`SSR 渲染失败: ${message}`);\n }\n}\n\n/**\n * 将 SVG 字符串写入指定路径。\n * 自动创建所需的中间目录。\n *\n * @param outputPath 输出文件路径\n * @param svgContent SVG 字符串内容\n */\nexport async function writeSVGFile(\n outputPath: string,\n svgContent: string,\n): Promise<void> {\n const absolutePath = path.resolve(outputPath);\n const dir = path.dirname(absolutePath);\n\n // 确保输出目录存在\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(absolutePath, svgContent, \"utf-8\");\n}\n\n/**\n * 根据用户输入的输出路径,补全默认值。\n * 如果用户未指定,默认为当前目录下的 infographic-output.svg。\n */\nexport function resolveOutputPath(userOutput?: string): string {\n if (userOutput) {\n // 确保扩展名是 .svg\n if (!userOutput.endsWith(\".svg\")) {\n return userOutput + \".svg\";\n }\n return userOutput;\n }\n return path.resolve(process.cwd(), \"infographic-output.svg\");\n}\n"],"mappings":"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","names":["pc","pc","program","path","path","program","path"]}
|
|
1
|
+
{"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../node_modules/picocolors/picocolors.js","../src/index.ts","../src/commands/config.ts","../src/config/index.ts","../src/utils/logger.ts","../src/utils/i18n.ts","../src/commands/generate.ts","../src/core/ai.ts","../src/core/prompts.ts","../src/utils/spinner.ts","../src/core/render.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","let p = process || {}, argv = p.argv || [], env = p.env || {}\nlet isColorSupported =\n\t!(!!env.NO_COLOR || argv.includes(\"--no-color\")) &&\n\t(!!env.FORCE_COLOR || argv.includes(\"--color\") || p.platform === \"win32\" || ((p.stdout || {}).isTTY && env.TERM !== \"dumb\") || !!env.CI)\n\nlet formatter = (open, close, replace = open) =>\n\tinput => {\n\t\tlet string = \"\" + input, index = string.indexOf(close, open.length)\n\t\treturn ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close\n\t}\n\nlet replaceClose = (string, close, replace, index) => {\n\tlet result = \"\", cursor = 0\n\tdo {\n\t\tresult += string.substring(cursor, index) + replace\n\t\tcursor = index + close.length\n\t\tindex = string.indexOf(close, cursor)\n\t} while (~index)\n\treturn result + string.substring(cursor)\n}\n\nlet createColors = (enabled = isColorSupported) => {\n\tlet f = enabled ? formatter : () => String\n\treturn {\n\t\tisColorSupported: enabled,\n\t\treset: f(\"\\x1b[0m\", \"\\x1b[0m\"),\n\t\tbold: f(\"\\x1b[1m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[1m\"),\n\t\tdim: f(\"\\x1b[2m\", \"\\x1b[22m\", \"\\x1b[22m\\x1b[2m\"),\n\t\titalic: f(\"\\x1b[3m\", \"\\x1b[23m\"),\n\t\tunderline: f(\"\\x1b[4m\", \"\\x1b[24m\"),\n\t\tinverse: f(\"\\x1b[7m\", \"\\x1b[27m\"),\n\t\thidden: f(\"\\x1b[8m\", \"\\x1b[28m\"),\n\t\tstrikethrough: f(\"\\x1b[9m\", \"\\x1b[29m\"),\n\n\t\tblack: f(\"\\x1b[30m\", \"\\x1b[39m\"),\n\t\tred: f(\"\\x1b[31m\", \"\\x1b[39m\"),\n\t\tgreen: f(\"\\x1b[32m\", \"\\x1b[39m\"),\n\t\tyellow: f(\"\\x1b[33m\", \"\\x1b[39m\"),\n\t\tblue: f(\"\\x1b[34m\", \"\\x1b[39m\"),\n\t\tmagenta: f(\"\\x1b[35m\", \"\\x1b[39m\"),\n\t\tcyan: f(\"\\x1b[36m\", \"\\x1b[39m\"),\n\t\twhite: f(\"\\x1b[37m\", \"\\x1b[39m\"),\n\t\tgray: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\n\t\tbgBlack: f(\"\\x1b[40m\", \"\\x1b[49m\"),\n\t\tbgRed: f(\"\\x1b[41m\", \"\\x1b[49m\"),\n\t\tbgGreen: f(\"\\x1b[42m\", \"\\x1b[49m\"),\n\t\tbgYellow: f(\"\\x1b[43m\", \"\\x1b[49m\"),\n\t\tbgBlue: f(\"\\x1b[44m\", \"\\x1b[49m\"),\n\t\tbgMagenta: f(\"\\x1b[45m\", \"\\x1b[49m\"),\n\t\tbgCyan: f(\"\\x1b[46m\", \"\\x1b[49m\"),\n\t\tbgWhite: f(\"\\x1b[47m\", \"\\x1b[49m\"),\n\n\t\tblackBright: f(\"\\x1b[90m\", \"\\x1b[39m\"),\n\t\tredBright: f(\"\\x1b[91m\", \"\\x1b[39m\"),\n\t\tgreenBright: f(\"\\x1b[92m\", \"\\x1b[39m\"),\n\t\tyellowBright: f(\"\\x1b[93m\", \"\\x1b[39m\"),\n\t\tblueBright: f(\"\\x1b[94m\", \"\\x1b[39m\"),\n\t\tmagentaBright: f(\"\\x1b[95m\", \"\\x1b[39m\"),\n\t\tcyanBright: f(\"\\x1b[96m\", \"\\x1b[39m\"),\n\t\twhiteBright: f(\"\\x1b[97m\", \"\\x1b[39m\"),\n\n\t\tbgBlackBright: f(\"\\x1b[100m\", \"\\x1b[49m\"),\n\t\tbgRedBright: f(\"\\x1b[101m\", \"\\x1b[49m\"),\n\t\tbgGreenBright: f(\"\\x1b[102m\", \"\\x1b[49m\"),\n\t\tbgYellowBright: f(\"\\x1b[103m\", \"\\x1b[49m\"),\n\t\tbgBlueBright: f(\"\\x1b[104m\", \"\\x1b[49m\"),\n\t\tbgMagentaBright: f(\"\\x1b[105m\", \"\\x1b[49m\"),\n\t\tbgCyanBright: f(\"\\x1b[106m\", \"\\x1b[49m\"),\n\t\tbgWhiteBright: f(\"\\x1b[107m\", \"\\x1b[49m\"),\n\t}\n}\n\nmodule.exports = createColors()\nmodule.exports.createColors = createColors\n","import { Command } from \"commander\";\nimport { registerConfigCommand } from \"./commands/config.js\";\nimport { registerGenerateCommand } from \"./commands/generate.js\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport { t } from \"./utils/i18n.js\";\n\n// 从 package.json 中读取版本号\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst packageJsonPath = join(__dirname, \"../package.json\");\nconst packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\nconst VERSION = packageJson.version;\n\nconst program = new Command();\n\nprogram\n .name(\"infographic-gen\")\n .description(t(\"programDesc\"))\n .version(VERSION, \"-v, --version\", t(\"versionFlag\"));\n\n// 注册子命令\nregisterConfigCommand(program);\nregisterGenerateCommand(program);\n\n// 解析命令行参数\nprogram.parse(process.argv);\n","import { Command } from \"commander\";\nimport {\n getAllConfig,\n getConfig,\n setConfig,\n deleteConfig,\n isValidConfigKey,\n getConfigPath,\n CONFIG_KEYS,\n CONFIG_LABELS,\n type ConfigKey,\n} from \"../config/index.js\";\nimport * as log from \"../utils/logger.js\";\nimport { t } from \"../utils/i18n.js\";\n\n/**\n * 注册 `config` 子命令,支持以下操作:\n * config set <key> <value> — 设置配置项\n * config get <key> — 查看单个配置项\n * config list — 列出所有配置\n * config delete <key> — 删除(重置)配置项\n * config path — 打印配置文件路径\n */\nexport function registerConfigCommand(program: Command): void {\n const configCmd = program\n .command(\"config\")\n .alias(\"c\")\n .description(\n \"Manage configuration (API Key, Base URL, Provider, Model, Output Directory)\",\n );\n\n // ---------- config set ----------\n configCmd\n .command(\"set <key> <value>\")\n .description(t(\"configSetDesc\"))\n .action((key: string, value: string) => {\n if (!isValidConfigKey(key)) {\n log.error(t(\"configInvalidKey\", { key, keys: CONFIG_KEYS.join(\", \") }));\n process.exit(1);\n }\n setConfig(key, value);\n log.success(t(\"configSetSuccess\", { label: CONFIG_LABELS[key] }));\n });\n\n // ---------- config get ----------\n configCmd\n .command(\"get <key>\")\n .description(t(\"configGetDesc\"))\n .action((key: string) => {\n if (!isValidConfigKey(key)) {\n log.error(t(\"configInvalidKey\", { key, keys: CONFIG_KEYS.join(\", \") }));\n process.exit(1);\n }\n const val = getConfig(key);\n if (!val) {\n log.warn(t(\"configNotSet\", { label: CONFIG_LABELS[key] }));\n } else {\n // Mask apiKey for security\n const display = key === \"apiKey\" ? maskApiKey(val) : val;\n log.label(CONFIG_LABELS[key], display);\n }\n });\n\n // ---------- config list ----------\n configCmd\n .command(\"list\")\n .description(t(\"configListDesc\"))\n .action(() => {\n const all = getAllConfig();\n log.info(t(\"configCurrent\"));\n for (const k of CONFIG_KEYS) {\n const val = all[k];\n const display =\n k === \"apiKey\" && val\n ? maskApiKey(val)\n : val || t(\"configNotSetValue\");\n log.label(CONFIG_LABELS[k], display);\n }\n log.dim(t(\"configFileLocation\", { path: getConfigPath() }));\n });\n\n // ---------- config delete ----------\n configCmd\n .command(\"delete <key>\")\n .description(t(\"configDeleteDesc\"))\n .action((key: string) => {\n if (!isValidConfigKey(key)) {\n log.error(t(\"configInvalidKey\", { key, keys: CONFIG_KEYS.join(\", \") }));\n process.exit(1);\n }\n deleteConfig(key as ConfigKey);\n log.success(\n t(\"configResetSuccess\", { label: CONFIG_LABELS[key as ConfigKey] }),\n );\n });\n\n // ---------- config path ----------\n configCmd\n .command(\"path\")\n .description(t(\"configPathDesc\"))\n .action(() => {\n console.log(getConfigPath());\n });\n}\n\n// ---- helpers ----\n\n/** 对 API Key 做脱敏处理:只显示前 4 位和后 4 位 */\nfunction maskApiKey(key: string): string {\n if (key.length <= 8) return \"****\";\n return key.slice(0, 4) + \"****\" + key.slice(-4);\n}\n","import Conf from \"conf\";\n\n/**\n * 用户可配置的 LLM 字段\n */\nexport interface LLMConfig {\n apiKey: string;\n baseUrl: string;\n provider: string;\n modelName: string;\n}\n\n/**\n * 配置 schema 的完整类型\n */\ninterface ConfigSchema {\n apiKey: string;\n baseUrl: string;\n provider: string;\n modelName: string;\n defaultOutputDir: string;\n locale: string;\n}\n\n/** 所有可配置的 key */\nexport const CONFIG_KEYS = [\n \"apiKey\",\n \"baseUrl\",\n \"provider\",\n \"modelName\",\n \"defaultOutputDir\",\n \"locale\",\n] as const;\nexport type ConfigKey = (typeof CONFIG_KEYS)[number];\n\n/** 配置项的人类可读标签 */\nexport const CONFIG_LABELS: Record<ConfigKey, string> = {\n apiKey: \"API Key\",\n baseUrl: \"Base URL\",\n provider: \"Provider\",\n modelName: \"Model Name\",\n defaultOutputDir: \"Default Output Directory\",\n locale: \"Language\",\n};\n\n/** 默认值 */\nconst DEFAULTS: ConfigSchema = {\n apiKey: \"\",\n baseUrl: \"https://api.openai.com/v1\",\n provider: \"openai\",\n modelName: \"gpt-4o\",\n defaultOutputDir: \".\",\n locale: \"en\",\n};\n\n/**\n * 基于 conf 的本地持久化配置管理器(单例)\n */\nconst store = new Conf<ConfigSchema>({\n projectName: \"infographic-gen\",\n defaults: DEFAULTS,\n});\n\n/** 读取单个配置值 */\nexport function getConfig<K extends ConfigKey>(key: K): string {\n return store.get(key) as string;\n}\n\n/** 写入单个配置值 */\nexport function setConfig<K extends ConfigKey>(key: K, value: string): void {\n store.set(key, value);\n}\n\n/** 删除单个配置值(恢复为默认) */\nexport function deleteConfig<K extends ConfigKey>(key: K): void {\n store.delete(key);\n}\n\n/** 读取完整 LLM 配置(用于创建 OpenAI 客户端) */\nexport function getLLMConfig(): LLMConfig {\n return {\n apiKey: getConfig(\"apiKey\"),\n baseUrl: getConfig(\"baseUrl\"),\n provider: getConfig(\"provider\"),\n modelName: getConfig(\"modelName\"),\n };\n}\n\n/** 返回所有配置项的 KV 对象(用于 `config list`) */\nexport function getAllConfig(): Record<ConfigKey, string> {\n return {\n apiKey: getConfig(\"apiKey\"),\n baseUrl: getConfig(\"baseUrl\"),\n provider: getConfig(\"provider\"),\n modelName: getConfig(\"modelName\"),\n defaultOutputDir: getConfig(\"defaultOutputDir\"),\n locale: getConfig(\"locale\"),\n };\n}\n\n/** 判断某个 key 是否为合法配置项 */\nexport function isValidConfigKey(key: string): key is ConfigKey {\n return CONFIG_KEYS.includes(key as ConfigKey);\n}\n\n/** 返回配置文件在磁盘上的路径(用于 debug) */\nexport function getConfigPath(): string {\n return store.path;\n}\n","import pc from \"picocolors\";\n\n/**\n * 统一的控制台日志工具,基于 picocolors 着色。\n * 所有输出走 stderr,stdout 留给管道场景。\n */\n\nexport function info(msg: string): void {\n console.error(pc.blue(\"ℹ\") + \" \" + msg);\n}\n\nexport function success(msg: string): void {\n console.error(pc.green(\"✔\") + \" \" + msg);\n}\n\nexport function warn(msg: string): void {\n console.error(pc.yellow(\"⚠\") + \" \" + pc.yellow(msg));\n}\n\nexport function error(msg: string): void {\n console.error(pc.red(\"✖\") + \" \" + pc.red(msg));\n}\n\nexport function dim(msg: string): void {\n console.error(pc.dim(msg));\n}\n\nexport function bold(msg: string): string {\n return pc.bold(msg);\n}\n\nexport function label(key: string, value: string): void {\n console.error(` ${pc.cyan(key)}: ${value}`);\n}\n","import { getConfig } from \"../config/index.js\";\n\nexport type Locale = \"en\" | \"zh-CN\";\n\n/**\n * 所有翻译文本的定义\n */\nconst translations = {\n en: {\n // Main program\n programDesc:\n \"AI-powered CLI to generate AntV Infographic SVGs from natural language prompts\",\n versionFlag: \"Display version number\",\n\n // Config command\n configDesc:\n \"Manage configuration (API Key, Base URL, Provider, Model, Output Directory)\",\n configSetDesc: \"Set a configuration value\",\n configGetDesc: \"Get a single configuration value\",\n configListDesc: \"List all configuration values\",\n configDeleteDesc: \"Delete a configuration value (reset to default)\",\n configPathDesc: \"Show configuration file path\",\n configInvalidKey: 'Invalid config key \"{key}\". Available: {keys}',\n configSetSuccess: \"{label} set successfully\",\n configNotSet: \"{label} not set\",\n configCurrent: \"Current configuration:\",\n configFileLocation: \" Config file location: {path}\",\n configResetSuccess: \"{label} reset to default\",\n configNotSetValue: \"(not set)\",\n\n // Generate command\n generateDesc:\n \"Generate an SVG infographic from natural language (default command)\",\n generatePromptArg: \"Describe the infographic you want to create\",\n generateOutputOpt:\n \"Output SVG file path (default: infographic-output.svg in default output directory)\",\n generateDslOpt:\n \"Save raw DSL syntax to a text file (optional, for debugging or fine-tuning)\",\n outputTarget: \"Output target: {path}\",\n callingAI: \"Calling AI to generate infographic syntax...\",\n renderingSVG: \"Rendering SVG...\",\n reRenderingSVG: \"Re-rendering SVG...\",\n aiCallFailed: \"AI call failed\",\n renderingFailed: \"Rendering failed\",\n renderFailedAfterRetries:\n \"Failed to generate renderable infographic after {retries} self-correction attempts.\",\n lastError: \"Last error: {error}\",\n dslAutoSaved: \"❌ Problematic DSL syntax auto-saved to: {path}\",\n dslAutoSaveHint:\n \"You can inspect this file to debug the LLM output or refine your prompt.\",\n dslForDebug: \"Generated DSL syntax (for debugging reference):\",\n fileWriteFailed: \"File write failed\",\n dslSaved: \"DSL syntax saved to: {path}\",\n dslWriteFailed:\n \"DSL file write failed (does not affect main functionality):\",\n infographicGenerated: \"Infographic generated!\",\n svgSaved: \"SVG saved to: {path}\",\n openInBrowser:\n \"You can open the SVG file directly in a browser to view it.\",\n selfCorrecting: \"AI self-correcting (attempt {attempt}/{max})...\",\n selfCorrectionFailed: \"Self-correction failed\",\n renderFailedRetrying:\n \"Render failed, auto-correcting (attempt {attempt}/{max})...\",\n\n // AI errors\n apiKeyNotConfigured:\n \"API Key not configured. Please run: infographic-gen config set apiKey <YOUR_KEY>\",\n llmEmptyContent: \"LLM returned empty content\",\n failedAfterRetries:\n \"Failed to generate renderable infographic after {retries} retries. Last error: {error}\",\n },\n \"zh-CN\": {\n // Main program\n programDesc: \"AI 驱动的信息图生成 CLI —— 输入自然语言,输出精美 SVG 信息图\",\n versionFlag: \"显示版本号\",\n\n // Config command\n configDesc: \"管理配置(API Key、Base URL、Provider、Model、输出目录)\",\n configSetDesc: \"设置配置项\",\n configGetDesc: \"查看单个配置项\",\n configListDesc: \"列出所有配置项\",\n configDeleteDesc: \"删除配置项(恢复默认值)\",\n configPathDesc: \"显示配置文件路径\",\n configInvalidKey: '无效的配置项 \"{key}\",可选项:{keys}',\n configSetSuccess: \"{label} 已设置\",\n configNotSet: \"{label} 尚未设置\",\n configCurrent: \"当前配置:\",\n configFileLocation: \" 配置文件位置: {path}\",\n configResetSuccess: \"{label} 已重置为默认值\",\n configNotSetValue: \"(未设置)\",\n\n // Generate command\n generateDesc: \"根据自然语言描述生成 SVG 信息图(默认命令)\",\n generatePromptArg: \"描述你想要生成的信息图内容\",\n generateOutputOpt:\n \"输出 SVG 文件路径(默认:默认输出目录中的 infographic-output.svg)\",\n generateDslOpt: \"将原始 DSL 语法保存到指定文本文件(可选,用于调试或微调)\",\n outputTarget: \"目标输出:{path}\",\n callingAI: \"正在调用 AI 生成信息图语法...\",\n renderingSVG: \"正在渲染 SVG...\",\n reRenderingSVG: \"正在重新渲染 SVG...\",\n aiCallFailed: \"AI 调用失败\",\n renderingFailed: \"渲染最终失败\",\n renderFailedAfterRetries:\n \"经过 {retries} 次自我修正仍无法生成可渲染的信息图。\",\n lastError: \"最后一次错误:{error}\",\n dslAutoSaved: \"❌ 有问题的 DSL 语法已自动保存至:{path}\",\n dslAutoSaveHint:\n \"你可以检查此文件以排查大模型生成的问题,或用于调试 Prompt。\",\n dslForDebug: \"生成的 DSL 语法如下(供 debug 参考):\",\n fileWriteFailed: \"文件写入失败\",\n dslSaved: \"DSL 语法已保存至:{path}\",\n dslWriteFailed: \"DSL 文件写入失败(不影响主要功能):\",\n infographicGenerated: \"信息图已生成!\",\n svgSaved: \"SVG 已保存至:{path}\",\n openInBrowser: \"可直接在浏览器中打开 SVG 文件查看效果。\",\n selfCorrecting: \"AI 正在自我修正(第 {attempt}/{max} 次)...\",\n selfCorrectionFailed: \"自我修正失败\",\n renderFailedRetrying: \"渲染失败,正在自动修正(第 {attempt}/{max} 次)...\",\n\n // AI errors\n apiKeyNotConfigured:\n \"尚未配置 API Key。请先运行:infographic-gen config set apiKey <YOUR_KEY>\",\n llmEmptyContent: \"LLM 返回了空内容\",\n failedAfterRetries:\n \"已重试 {retries} 次仍然无法生成可渲染的信息图。最后一次错误:{error}\",\n },\n} as const;\n\n/**\n * 获取当前配置的语言\n */\nexport function getLocale(): Locale {\n const locale = getConfig(\"locale\");\n return (locale === \"zh-CN\" ? \"zh-CN\" : \"en\") as Locale;\n}\n\n/**\n * 获取翻译文本\n * @param key 翻译键\n * @param params 插值参数\n */\nexport function t(\n key: keyof (typeof translations)[\"en\"],\n params?: Record<string, string | number>,\n): string {\n const locale = getLocale();\n let text: string = translations[locale][key];\n\n if (params) {\n Object.entries(params).forEach(([paramKey, value]) => {\n text = text.replace(`{${paramKey}}`, String(value));\n });\n }\n\n return text;\n}\n","import path from \"node:path\";\nimport { Command } from \"commander\";\nimport {\n generateInfographicDSL,\n retryWithCorrection,\n MAX_RETRIES,\n} from \"../core/ai.js\";\nimport {\n renderDSLToSVG,\n writeSVGFile,\n writeDSLFile,\n resolveOutputPath,\n} from \"../core/render.js\";\nimport * as log from \"../utils/logger.js\";\nimport {\n startSpinner,\n succeedSpinner,\n failSpinner,\n updateSpinner,\n} from \"../utils/spinner.js\";\nimport { t } from \"../utils/i18n.js\";\n\n/**\n * 注册 `generate` 子命令。\n *\n * 用法示例:\n * infographic-gen generate \"帮我画一个软件开发流程图\" -o result.svg\n * infographic-gen generate \"帮我画一个饼图\" -o chart.svg --dsl chart-syntax.txt\n */\nexport function registerGenerateCommand(program: Command): void {\n program\n .command(\"generate\", { isDefault: true })\n .alias(\"g\")\n .description(t(\"generateDesc\"))\n .argument(\"<prompt>\", t(\"generatePromptArg\"))\n .option(\"-o, --output <path>\", t(\"generateOutputOpt\"))\n .option(\"--dsl <path>\", t(\"generateDslOpt\"))\n .action(async (prompt: string, opts: { output?: string; dsl?: string }) => {\n await handleGenerate(prompt, opts.output, opts.dsl);\n });\n}\n\n/**\n * 生成命令的核心处理逻辑。\n *\n * 流程:\n * 1. 调用 LLM 生成 DSL\n * 2. 调用 SSR 渲染为 SVG\n * 3. 如果渲染失败,自动进入自我修正循环(最多 MAX_RETRIES 次)\n * 4. 写入 SVG 文件\n * 5. 如果用户指定了 --dsl,保存原始 DSL 语法\n */\nasync function handleGenerate(\n prompt: string,\n outputOption?: string,\n dslOption?: string,\n): Promise<void> {\n const outputPath = resolveOutputPath(outputOption);\n\n log.info(t(\"outputTarget\", { path: path.resolve(outputPath) }));\n startSpinner(t(\"callingAI\"));\n\n let syntax: string;\n try {\n syntax = await generateInfographicDSL(prompt);\n } catch (err) {\n failSpinner(t(\"aiCallFailed\"));\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n updateSpinner(t(\"renderingSVG\"));\n\n // ─── 渲染 + 自我修正循环 ───────────────────────────────────────────\n let svgContent: string | null = null;\n let lastError = \"\";\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n svgContent = await renderDSLToSVG(syntax);\n break; // Render successful, exit loop\n } catch (err) {\n lastError = err instanceof Error ? err.message : String(err);\n\n if (attempt < MAX_RETRIES) {\n // Retry available → self-correction\n try {\n syntax = await retryWithCorrection(\n syntax,\n lastError,\n prompt,\n attempt + 1,\n );\n updateSpinner(t(\"reRenderingSVG\"));\n } catch (retryErr) {\n failSpinner(t(\"selfCorrectionFailed\"));\n log.error(\n retryErr instanceof Error ? retryErr.message : String(retryErr),\n );\n process.exit(1);\n }\n }\n }\n }\n\n if (!svgContent) {\n failSpinner(t(\"renderingFailed\"));\n log.error(t(\"renderFailedAfterRetries\", { retries: String(MAX_RETRIES) }));\n log.error(t(\"lastError\", { error: lastError }));\n\n // Auto-save problematic DSL to error-dump.txt\n const errorDumpPath = \"error-dump.txt\";\n try {\n await writeDSLFile(errorDumpPath, syntax);\n log.warn(t(\"dslAutoSaved\", { path: path.resolve(errorDumpPath) }));\n log.dim(t(\"dslAutoSaveHint\"));\n } catch (writeErr) {\n log.dim(t(\"dslForDebug\"));\n console.error(syntax);\n }\n\n process.exit(1);\n }\n\n // ─── Render successful, write file ─────────────────────────────────────────────\n try {\n await writeSVGFile(outputPath, svgContent);\n } catch (err) {\n failSpinner(t(\"fileWriteFailed\"));\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n\n // ─── If user specified --dsl, save raw DSL syntax ───────────────────────\n if (dslOption) {\n try {\n await writeDSLFile(dslOption, syntax);\n log.success(t(\"dslSaved\", { path: path.resolve(dslOption) }));\n } catch (err) {\n log.warn(t(\"dslWriteFailed\"));\n log.warn(err instanceof Error ? err.message : String(err));\n }\n }\n\n succeedSpinner(t(\"infographicGenerated\"));\n log.success(t(\"svgSaved\", { path: path.resolve(outputPath) }));\n log.dim(t(\"openInBrowser\"));\n}\n","import OpenAI from \"openai\";\nimport { getLLMConfig } from \"../config/index.js\";\nimport {\n INFOGRAPHIC_CREATOR_SYSTEM_PROMPT,\n SELF_CORRECTION_PROMPT_TEMPLATE,\n} from \"./prompts.js\";\nimport * as log from \"../utils/logger.js\";\nimport { updateSpinner } from \"../utils/spinner.js\";\nimport { t } from \"../utils/i18n.js\";\n\n/** LLM 请求返回的结果 */\nexport interface LLMResult {\n /** 生成的 DSL 语法文本 */\n syntax: string;\n /** 总共重试了几次(0 = 一次成功) */\n attempts: number;\n}\n\n/** 最大自我修正重试次数 */\nconst MAX_RETRIES = 3;\n\n/**\n * 创建一个懒初始化的 OpenAI 客户端。\n * 通过覆盖 baseURL / apiKey 兼容 DeepSeek、阿里云百炼等平台。\n */\nfunction createClient(): OpenAI {\n const { apiKey, baseUrl } = getLLMConfig();\n\n if (!apiKey) {\n throw new Error(t(\"apiKeyNotConfigured\"));\n }\n\n return new OpenAI({\n apiKey,\n baseURL: baseUrl,\n });\n}\n\n/**\n * 向 LLM 发送请求,获取信息图 DSL。\n *\n * @param userPrompt 用户的自然语言描述\n * @returns LLM 返回的纯 DSL 文本\n */\nasync function callLLM(\n client: OpenAI,\n model: string,\n messages: OpenAI.ChatCompletionMessageParam[],\n): Promise<string> {\n const response = await client.chat.completions.create({\n model,\n messages,\n temperature: 0.7,\n max_tokens: 4096,\n });\n\n const content = response.choices[0]?.message?.content;\n if (!content) {\n throw new Error(t(\"llmEmptyContent\"));\n }\n\n return cleanDSL(content);\n}\n\n/**\n * 清理 LLM 返回的文本,去除可能的 Markdown 代码块标记等噪声。\n */\nfunction cleanDSL(raw: string): string {\n let cleaned = raw.trim();\n\n // 去掉可能包裹的 ```xxx ... ``` 代码块\n const codeBlockMatch = cleaned.match(/^```[\\w]*\\n?([\\s\\S]*?)```$/);\n if (codeBlockMatch) {\n cleaned = codeBlockMatch[1].trim();\n }\n\n // 确保以 infographic 开头\n const infographicIndex = cleaned.indexOf(\"infographic \");\n if (infographicIndex > 0) {\n cleaned = cleaned.slice(infographicIndex);\n }\n\n return cleaned;\n}\n\n/**\n * 带自我修正机制的 AI 生成入口。\n *\n * 流程:\n * 1. 将用户 Prompt + 系统提示词发给 LLM,获取 DSL。\n * 2. 调用方(generate 命令)会尝试渲染。如果渲染失败,调用 retryWithCorrection。\n * 3. 最多重试 MAX_RETRIES 次。\n *\n * @param userPrompt 用户输入的自然语言\n * @returns 生成的 DSL 语法\n */\nexport async function generateInfographicDSL(\n userPrompt: string,\n): Promise<string> {\n const client = createClient();\n const { modelName } = getLLMConfig();\n\n const messages: OpenAI.ChatCompletionMessageParam[] = [\n { role: \"system\", content: INFOGRAPHIC_CREATOR_SYSTEM_PROMPT },\n { role: \"user\", content: userPrompt },\n ];\n\n return callLLM(client, modelName, messages);\n}\n\n/**\n * 自我修正:当 DSL 渲染失败时,把错误信息反馈给 LLM 要求修正。\n *\n * @param originalSyntax 上一次生成的 DSL\n * @param errorMessage 渲染报错信息\n * @param userPrompt 用户原始需求\n * @param attempt 当前第几次重试(从 1 开始)\n * @returns 修正后的 DSL\n */\nexport async function retryWithCorrection(\n originalSyntax: string,\n errorMessage: string,\n userPrompt: string,\n attempt: number,\n): Promise<string> {\n if (attempt > MAX_RETRIES) {\n throw new Error(\n t(\"failedAfterRetries\", {\n retries: String(MAX_RETRIES),\n error: errorMessage,\n }),\n );\n }\n\n updateSpinner(\n t(\"selfCorrecting\", { attempt: String(attempt), max: String(MAX_RETRIES) }),\n );\n log.warn(\n t(\"renderFailedRetrying\", {\n attempt: String(attempt),\n max: String(MAX_RETRIES),\n }),\n );\n\n const client = createClient();\n const { modelName } = getLLMConfig();\n\n const correctionMessage = SELF_CORRECTION_PROMPT_TEMPLATE.replace(\n \"{error}\",\n errorMessage,\n ).replace(\"{syntax}\", originalSyntax);\n\n const messages: OpenAI.ChatCompletionMessageParam[] = [\n { role: \"system\", content: INFOGRAPHIC_CREATOR_SYSTEM_PROMPT },\n { role: \"user\", content: userPrompt },\n { role: \"assistant\", content: originalSyntax },\n { role: \"user\", content: correctionMessage },\n ];\n\n return callLLM(client, modelName, messages);\n}\n\n/** 导出最大重试次数常量供外部使用 */\nexport { MAX_RETRIES };\n","/**\n * ⭐ 硬编码的系统提示词常量。\n *\n * 直接内嵌在代码中,确保 CLI 开箱即用,无需读取本地磁盘文件。\n * 内容基于 @antv/infographic 的 .skills/infographic-creator/SKILL.md 整理。\n */\n\n// ─── 公共:AntV Infographic 语法规范 ────────────────────────────────\n\nconst SYNTAX_SPEC = `\n## AntV Infographic 语法\n\nAntV Infographic 语法是一种自定义的 DSL,用于描述信息图渲染配置。它使用缩进描述信息,具有较强鲁棒性,便于 AI 流式输出并渲染信息图。主要包含以下信息:\n\n1. template:用模板表达文字信息结构。\n2. data:信息图数据,包含 title、desc、数据项等。数据项通常包含 label、desc、icon 等字段。\n3. theme:主题包含 palette、font 等样式配置。\n\n例如:\n\\`\\`\\`\ninfographic list-row-horizontal-icon-arrow\ndata\n title Title\n desc Description\n lists\n - label Label\n value 12.5\n desc Explanation\n icon document text\ntheme\n palette #3b82f6 #8b5cf6 #f97316\n\\`\\`\\`\n\n### 语法规范\n\n• 第一行必须是 \\`infographic <template-name>\\`,模板从下方可用模板列表中选择。\n• 使用 \\`data\\` / \\`theme\\` 块,块内用两个空格缩进。\n• 键值对使用「键 空格 值」;数组使用 \\`-\\` 作为条目前缀。\n• icon 使用图标关键词(如 \\`star fill\\`)。\n• \\`data\\` 应包含 title/desc + 模板对应的主数据字段(不一定是 \\`items\\`)。\n• 主数据字段选择(只用一个,避免混用):\n - \\`list-*\\` → \\`lists\\`\n - \\`sequence-*\\` → \\`sequences\\`(可选 \\`order asc|desc\\`)\n - \\`compare-*\\` → \\`compares\\`(支持 \\`children\\` 分组对比),可包含多个对比项\n - \\`hierarchy-structure\\` → \\`items\\`(每一项对应一个独立层级,每一层级可以包含子项,最多可嵌套 3 层)\n - \\`hierarchy-*\\` → 单一 \\`root\\`(树结构,通过 \\`children\\` 嵌套)\n - \\`relation-*\\` → \\`nodes\\` + \\`relations\\`;简单关系图可省略 \\`nodes\\`,在 relations 中用箭头语法\n - \\`chart-*\\` → \\`values\\`(数值统计,可选 \\`category\\`)\n - 不确定时再用 \\`items\\` 兜底\n\n• \\`compare-binary-*\\` / \\`compare-hierarchy-left-right-*\\` 二元模板:必须两个根节点,所有对比项挂在这两个根节点的 children\n• \\`hierarchy-*\\`:使用单一 \\`root\\`,通过 \\`children\\` 嵌套(不要重复 \\`root\\`)\n• \\`theme\\` 用于自定义主题(palette、font 等)\n\n例如:暗色主题 + 自定义配色\n\\`\\`\\`\ninfographic list-row-simple-horizontal-arrow\ntheme dark\n palette\n - #61DDAA\n - #F6BD16\n - #F08BB4\n\\`\\`\\`\n\n• 使用 \\`theme.base.text.font-family\\` 指定字体,如手写风格 \\`851tegakizatsu\\`\n• 使用 \\`theme.stylize\\` 选择内置风格并传参。常见风格:\n - \\`rough\\`:手绘效果\n - \\`pattern\\`:图案填充\n - \\`linear-gradient\\` / \\`radial-gradient\\`:线性/径向渐变\n\n例如:手绘风格(rough)\n\\`\\`\\`\ninfographic list-row-simple-horizontal-arrow\ntheme\n stylize rough\n base\n text\n font-family 851tegakizatsu\n\\`\\`\\`\n`.trim();\n\n// ─── 数据语法示例 ───────────────────────────────────────────────────\n\nconst DATA_EXAMPLES = `\n### 数据语法示例\n\n• list-* 模版\n\\`\\`\\`\ninfographic list-grid-badge-card\ndata\n title Feature List\n lists\n - label Fast\n icon flash fast\n - label Secure\n icon secure shield check\n\\`\\`\\`\n\n• sequence-* 模版\n\\`\\`\\`\ninfographic sequence-steps-simple\ndata\n sequences\n - label Step 1\n - label Step 2\n - label Step 3\n order asc\n\\`\\`\\`\n\n• hierarchy-* 模版\n\\`\\`\\`\ninfographic hierarchy-structure\ndata\n root\n label Company\n children\n - label Dept A\n - label Dept B\n\\`\\`\\`\n\n• compare-* 模版\n\\`\\`\\`\ninfographic compare-swot\ndata\n compares\n - label Strengths\n children\n - label Strong brand\n - label Loyal users\n - label Weaknesses\n children\n - label High cost\n - label Slow release\n\\`\\`\\`\n\n四象限图\n\\`\\`\\`\ninfographic compare-quadrant-quarter-simple-card\ndata\n compares\n - label High Impact & Low Effort\n - label High Impact & High Effort\n - label Low Impact & Low Effort\n - label Low Impact & High Effort\n\\`\\`\\`\n\n• chart-* 模版\n\\`\\`\\`\ninfographic chart-column-simple\ndata\n values\n - label Visits\n value 1280\n - label Conversion\n value 12.4\n\\`\\`\\`\n\n• relation-* 模版\n边标签写法:A -label-> B 或 A -->|label| B\n\\`\\`\\`\ninfographic relation-dagre-flow-tb-simple-circle-node\ndata\n nodes\n - id A\n label Node A\n - id B\n label Node B\n relations\n A - approves -> B\n A -->|blocks| B\n\\`\\`\\`\n\n• 兜底 items 示例\n\\`\\`\\`\ninfographic list-row-horizontal-icon-arrow\ndata\n items\n - label Item A\n desc Description\n icon sun\n - label Item B\n desc Description\n icon moon\n\\`\\`\\`\n`.trim();\n\n// ─── 可用模板列表 ───────────────────────────────────────────────────\n\nconst AVAILABLE_TEMPLATES = `\n### 可用模板\n\n• chart-bar-plain-text\n• chart-column-simple\n• chart-line-plain-text\n• chart-pie-compact-card\n• chart-pie-donut-pill-badge\n• chart-pie-donut-plain-text\n• chart-pie-plain-text\n• chart-wordcloud\n• compare-binary-horizontal-badge-card-arrow\n• compare-binary-horizontal-simple-fold\n• compare-binary-horizontal-underline-text-vs\n• compare-hierarchy-left-right-circle-node-pill-badge\n• compare-quadrant-quarter-circular\n• compare-quadrant-quarter-simple-card\n• compare-swot\n• hierarchy-mindmap-branch-gradient-capsule-item\n• hierarchy-mindmap-level-gradient-compact-card\n• hierarchy-structure\n• hierarchy-tree-curved-line-rounded-rect-node\n• hierarchy-tree-tech-style-badge-card\n• hierarchy-tree-tech-style-capsule-item\n• list-column-done-list\n• list-column-simple-vertical-arrow\n• list-column-vertical-icon-arrow\n• list-grid-badge-card\n• list-grid-candy-card-lite\n• list-grid-ribbon-card\n• list-row-horizontal-icon-arrow\n• list-sector-plain-text\n• list-waterfall-badge-card\n• list-waterfall-compact-card\n• list-zigzag-down-compact-card\n• list-zigzag-down-simple\n• list-zigzag-up-compact-card\n• list-zigzag-up-simple\n• relation-dagre-flow-tb-animated-badge-card\n• relation-dagre-flow-tb-animated-simple-circle-node\n• relation-dagre-flow-tb-badge-card\n• relation-dagre-flow-tb-simple-circle-node\n• sequence-ascending-stairs-3d-underline-text\n• sequence-ascending-steps\n• sequence-circular-simple\n• sequence-color-snake-steps-horizontal-icon-line\n• sequence-cylinders-3d-simple\n• sequence-filter-mesh-simple\n• sequence-funnel-simple\n• sequence-horizontal-zigzag-underline-text\n• sequence-mountain-underline-text\n• sequence-pyramid-simple\n• sequence-roadmap-vertical-plain-text\n• sequence-roadmap-vertical-simple\n• sequence-snake-steps-compact-card\n• sequence-snake-steps-simple\n• sequence-snake-steps-underline-text\n• sequence-stairs-front-compact-card\n• sequence-stairs-front-pill-badge\n• sequence-timeline-rounded-rect-node\n• sequence-timeline-simple\n• sequence-zigzag-pucks-3d-simple\n• sequence-zigzag-steps-underline-text\n\n模板选择建议:\n• 严格顺序(流程/步骤/发展趋势)→ sequence-*\n - 时间线 → sequence-timeline-*\n - 阶梯图 → sequence-stairs-*\n - 路线图 → sequence-roadmap-vertical-*\n - 折线路径 → sequence-zigzag-*\n - 环形进度 → sequence-circular-simple\n - 彩色蛇形步骤 → sequence-color-snake-steps-*\n - 金字塔 → sequence-pyramid-simple\n• 观点列举 → list-row-* 或 list-column-*\n• 二元对比(利弊)→ compare-binary-*\n• SWOT → compare-swot\n• 层级结构(树图)→ hierarchy-tree-*\n• 数据图表 → chart-*\n• 象限分析 → quadrant-*\n• 网格列表(要点)→ list-grid-*\n• 关系展示 → relation-*\n• 词云 → chart-wordcloud\n• 思维导图 → hierarchy-mindmap-*\n`.trim();\n\n// ─── 完整示例 ───────────────────────────────────────────────────────\n\nconst FULL_EXAMPLE = `\n### 完整示例\n\n绘制互联网技术演进信息图:\n\\`\\`\\`\ninfographic list-row-horizontal-icon-arrow\ndata\n title Internet Technology Evolution\n desc From Web 1.0 to AI era, key milestones\n lists\n - time 1991\n label Web 1.0\n desc Tim Berners-Lee published the first website, opening the Internet era\n icon web\n - time 2004\n label Web 2.0\n desc Social media and user-generated content become mainstream\n icon account multiple\n - time 2007\n label Mobile\n desc iPhone released, smartphone changes the world\n icon cellphone\n - time 2015\n label Cloud Native\n desc Containerization and microservices architecture are widely used\n icon cloud\n - time 2020\n label Low Code\n desc Visual development lowers the technology threshold\n icon application brackets\n - time 2023\n label AI Large Model\n desc ChatGPT ignites the generative AI revolution\n icon brain\n\\`\\`\\`\n`.trim();\n\n// ─── 导出:信息图创建者系统提示词 ───────────────────────────────────\n\n/**\n * 信息图创建者的完整 System Prompt。\n * 用于指导 LLM 根据用户自然语言需求,生成合法的 AntV Infographic DSL 语法。\n */\nexport const INFOGRAPHIC_CREATOR_SYSTEM_PROMPT = `\n你是一位专业的信息图设计专家。你的任务是根据用户的需求,生成 AntV Infographic DSL 语法来创建精美的信息图。\n\n信息图(Infographic)将数据、信息与知识转化为可感知的视觉语言。它结合视觉设计与数据可视化,用直观符号压缩复杂信息,帮助受众快速理解并记住要点。\n\nInfographic = Information Structure + Visual Expression\n\n你需要严格遵守以下规范来生成 AntV Infographic 语法:\n\n${SYNTAX_SPEC}\n\n${DATA_EXAMPLES}\n\n${AVAILABLE_TEMPLATES}\n\n${FULL_EXAMPLE}\n\n## 重要约束\n\n1. **只输出纯 DSL 语法**:不要输出任何 Markdown 代码块标记(如 \\\\\\`\\\\\\`\\\\\\`)、解释性文字、JSON 或其他格式。直接输出以 \\`infographic <template-name>\\` 开头的 DSL 文本。\n2. **必须尊重用户输入语言**:如果用户使用中文描述需求,DSL 中所有文本内容(title、desc、label 等)也必须使用中文。\n3. **选择最合适的模板**:根据用户需求的信息结构(列表、流程、对比、层级等)选择最匹配的模板。\n4. **数据完整性**:确保生成的数据结构完整,包含 title、desc 以及与模板匹配的主数据字段。\n5. **配色和主题**:除非用户特别要求,否则使用一组美观且协调的默认配色。\n`.trim();\n\n/**\n * 自我修正提示词模板。\n * 当 SSR 渲染失败时,将报错信息注入后发给 LLM 进行修正。\n */\nexport const SELF_CORRECTION_PROMPT_TEMPLATE = `\n之前你生成的 AntV Infographic DSL 语法在渲染时出错了。\n\n报错信息:\n{error}\n\n之前生成的语法:\n{syntax}\n\n请修正语法并重新输出。要求:\n1. 只输出修正后的纯 DSL 语法,不要添加任何解释或 Markdown 格式。\n2. 确保第一行是 \\`infographic <template-name>\\`。\n3. 确保数据结构符合所选模板的规范。\n4. 修复导致错误的具体问题。\n`.trim();\n","import ora, { type Ora } from \"ora\";\n\n/**\n * 终端 Loading 动画封装。\n * 提供 start / succeed / fail / update 等便捷方法。\n */\n\nlet currentSpinner: Ora | null = null;\n\nexport function startSpinner(text: string): Ora {\n // 如果之前有未关闭的 spinner,先停掉\n if (currentSpinner?.isSpinning) {\n currentSpinner.stop();\n }\n currentSpinner = ora({ text, stream: process.stderr }).start();\n return currentSpinner;\n}\n\nexport function succeedSpinner(text?: string): void {\n currentSpinner?.succeed(text);\n currentSpinner = null;\n}\n\nexport function failSpinner(text?: string): void {\n currentSpinner?.fail(text);\n currentSpinner = null;\n}\n\nexport function updateSpinner(text: string): void {\n if (currentSpinner) {\n currentSpinner.text = text;\n }\n}\n\nexport function stopSpinner(): void {\n currentSpinner?.stop();\n currentSpinner = null;\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { renderToString } from \"@antv/infographic/ssr\";\nimport { getConfig } from \"../config/index.js\";\n\n/**\n * 渲染结果\n */\nexport interface RenderResult {\n /** 生成的 SVG 字符串 */\n svg: string;\n}\n\n/**\n * 使用 @antv/infographic SSR 将 DSL 语法渲染为 SVG 字符串。\n *\n * @param syntax AntV Infographic DSL 语法文本\n * @returns SVG 字符串\n * @throws 渲染失败时抛出带有详细错误信息的 Error\n */\nexport async function renderDSLToSVG(syntax: string): Promise<string> {\n try {\n const svgString = await renderToString(syntax);\n if (!svgString || svgString.trim().length === 0) {\n throw new Error(\"renderToString 返回了空的 SVG 内容\");\n }\n return svgString;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`SSR 渲染失败: ${message}`);\n }\n}\n\n/**\n * 将 SVG 字符串写入指定路径。\n * 自动创建所需的中间目录。\n *\n * @param outputPath 输出文件路径\n * @param svgContent SVG 字符串内容\n */\nexport async function writeSVGFile(\n outputPath: string,\n svgContent: string,\n): Promise<void> {\n const absolutePath = path.resolve(outputPath);\n const dir = path.dirname(absolutePath);\n\n // 确保输出目录存在\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(absolutePath, svgContent, \"utf-8\");\n}\n\n/**\n * 将 DSL 语法文本写入指定路径。\n * 自动创建所需的中间目录。\n *\n * @param outputPath 输出文件路径\n * @param dslContent DSL 语法字符串\n */\nexport async function writeDSLFile(\n outputPath: string,\n dslContent: string,\n): Promise<void> {\n const absolutePath = path.resolve(outputPath);\n const dir = path.dirname(absolutePath);\n\n // 确保输出目录存在\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(absolutePath, dslContent, \"utf-8\");\n}\n\n/**\n * 根据用户输入的输出路径,补全默认值。\n * 支持配置默认输出目录,如果用户未指定,默认为 defaultOutputDir 下的 infographic-output.svg。\n *\n * @param userOutput 用户指定的输出路径(可选)\n * @returns 完整的输出路径(绝对路径或相对路径)\n */\nexport function resolveOutputPath(userOutput?: string): string {\n const defaultDir = getConfig(\"defaultOutputDir\") || \".\";\n\n if (userOutput) {\n // 用户指定了输出路径\n // 确保扩展名是 .svg\n const withExt = userOutput.endsWith(\".svg\")\n ? userOutput\n : userOutput + \".svg\";\n\n // 如果是绝对路径,直接返回;否则相对于默认目录\n if (path.isAbsolute(withExt)) {\n return withExt;\n }\n return path.resolve(defaultDir, withExt);\n }\n\n // 用户未指定,使用默认输出目录 + 默认文件名\n return path.resolve(defaultDir, \"infographic-output.svg\");\n}\n"],"mappings":"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","names":["pc","pc","program","path","path","path","program","path","fileURLToPath","__dirname","fileURLToPath"]}
|
package/package.json
CHANGED