infographic-gen 1.0.2 → 1.0.3

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/dist/index.js CHANGED
@@ -781,7 +781,13 @@ async function handleGenerate(prompt, outputOption) {
781
781
  }
782
782
 
783
783
  // src/index.ts
784
- var VERSION = "1.0.0";
784
+ import { readFileSync } from "fs";
785
+ import { fileURLToPath as fileURLToPath2 } from "url";
786
+ import { dirname, join } from "path";
787
+ var __dirname2 = dirname(fileURLToPath2(import.meta.url));
788
+ var packageJsonPath = join(__dirname2, "../package.json");
789
+ var packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
790
+ var VERSION = packageJson.version;
785
791
  var program = new Command();
786
792
  program.name("infographic-gen").description("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").version(VERSION, "-v, --version", "\u663E\u793A\u7248\u672C\u53F7");
787
793
  registerConfigCommand(program);
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/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\";\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(\"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","fileURLToPath","__dirname"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infographic-gen",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "AI-powered CLI tool to generate AntV Infographic SVGs from natural language prompts",
5
5
  "license": "MIT",
6
6
  "author": "Your Name <your.email@example.com>",