Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/chenoneto_sensenova-infographic-skill.json

1 line
25 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "chenoneto/sensenova-infographic-skill", "files": {"scripts/generate_infographic.py": {"19c711520a22c2531c58b802db474d38a0335c9d": {"t": 1785768242.805694, "n": 11446, "h": "f681c85c77745bce", "c": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n\"\"\"\nSenseNova U1 Fast 信息图生成脚本(纯标准库,零第三方依赖,跨平台)。\n\n用途:调用商汤 sensenova-u1-fast 图像生成接口,把一段结构化中文\nPrompt 渲染成信息图,并把返回的签名 URL 下载保存到本地。\n\n接口:POST https://token.sensenova.cn/v1/images/generations (OpenAI images 兼容)\n鉴权:Authorization: Bearer $SENSENOVA_API_KEY\n\n示例:\n python generate_infographic.py \\\n --prompt-file prompt.txt \\\n --size 2752x1536 \\\n --output ./out/infographic.png\n\n # 按宽高比快速选尺寸(16:9 自动映射到 2752x1536)\n python generate_infographic.py --prompt-file prompt.txt --aspect-ratio 16:9\n\n # 干运行:只校验 Prompt,不烧 Token\n python generate_infographic.py --prompt-file prompt.txt --dry-run --show-prompt\n\n # JSON 输出(便于自动化流程解析)\n python generate_infographic.py --prompt-file prompt.txt --json --output ./out.png\n\"\"\"\nimport argparse\nimport json\nimport os\nimport re\nimport sys\nimport time\nimport urllib.error\nimport urllib.request\n\n# Windows GBK 控制台下强制 UTF-8 输出,避免中文/emoji 报错\ntry:\n sys.stdout.reconfigure(encoding=\"utf-8\")\n sys.stderr.reconfigure(encoding=\"utf-8\")\nexcept Exception:\n pass\n\nBASE_URL = \"https://token.sensenova.cn/v1\"\nENDPOINT = BASE_URL + \"/images/generations\"\nMODEL = \"sensenova-u1-fast\"\n\n# 11 种官方白名单分辨率(传其它值会 400)\nVALID_SIZES = {\n \"2048x2048\", \"2752x1536\", \"1536x2752\", \"2496x1664\", \"1664x2496\",\n \"2368x1760\", \"1760x2368\", \"2272x1824\", \"1824x2272\", \"3072x1376\",\n \"1344x3136\",\n}\nDEFAULT_SIZE = \"2752x1536\"\n\n# 常用宽高比 → 官方白名单分辨率(对外友好,对内精确)\nASPECT_RATIOS = {\n \"16:9\": \"2752x1536\",\n \"9:16\": \"1536x2752\",\n \"1:1\": \"2048x2048\",\n \"3:2\": \"2496x1664\",\n \"2:3\": \"1664x2496\",\n \"4:3\": \"2368x1760\",\n \"3:4\": \"1760x2368\",\n \"5:4\": \"2272x1824\",\n \"4:5\": \"1824x2272\",\n \"21:9\": \"3072x1376\",\n \"9:21\": \"1344x3136\",\n}\n\nMAX_RETRIES = 3\nRETRY_BACKOFF = [5, 15, 30] # 秒\n\n\ndef log(msg, force_stdout=False):\n \"\"\"默认输出到 stderr,方便 --json 模式把 stdout 留给机器解析。\"\"\"\n if force_stdout:\n print(msg, flush=True)\n else:\n print(msg, file=sys.stderr, flush=True)\n\n\ndef approx_tokens(prompt):\n \"\"\"粗略估算:1 token ≈ 1.5 中文字符。\"\"\"\n return int(len(prompt) / 1.5)\n\n\ndef lint_prompt(prompt):\n \"\"\"对 Prompt 做静态检查,返回警告列表。\"\"\"\n warnings = []\n # HEX 色值容易让 U1 当成可见文字渲染\n hex_codes = re.findall(r\"#[0-9A-Fa-f]{6}\\b\", prompt)\n if hex_codes:\n warnings.append(\n \"Prompt 中检测到 HEX 色值 %s,可能会被 U1 渲染为可见文字。\"\n \"建议只在设计描述里用颜色名称(如'青色霓虹'),不要写 HEX 代码。\" % hex_codes\n )\n # 过长的提示词\n tokens = approx_tokens(prompt)\n if tokens > 4096:\n warnings.append(\"Prompt 约 %d tokens,超过 4096 上限,建议精简或拆图。\" % tokens)\n elif tokens > 3000:\n warnings.append(\"Prompt 约 %d tokens,接近上限,建议检查是否冗余。\" % tokens)\n # 缺少关键结构标记\n for marker in [\"【整体风格】\", \"【整体布局】\", \"【标题区】\"]:\n if marker not in prompt:\n warnings.append(\"未检测到 %s,结构化程度不足可能导致 U1 跑偏。\" % marker)\n # 约束词不足\n if \"溢出\" not in prompt and \"安全间距\" not in prompt:\n warnings.append(\"建议增加'元素与边框保持安全间距,严禁溢出'等约束,减少排版翻车。\")\n return warnings\n\n\ndef build_request(prompt, size, n):\n payload = {\n \"model\": MODEL,\n \"prompt\": prompt,\n \"size\": size,\n \"n\": n,\n }\n return json.dumps(payload, ensure_ascii=False).encode(\"utf-8\")\n\n\ndef call_api(api_key, body, timeout):\n req = urllib.request.Request(\n ENDPOINT,\n data=body,\n method=\"POST\",\n headers={\n \"Authorization\": \"Bearer \" + api_key,\n \"Content-Type\": \"application/json\",\n },\n )\n with urllib.request.urlopen(req, timeout=timeout) as resp:\n return json.loads(resp.read().decode(\"utf-8\"))\n\n\ndef download(url, dest, timeout):\n req = urllib.request.Request(url, headers={\"User-Agent\": \"sensenova-infographic/1.1\"})\n with urllib.request.urlopen(req, timeout=timeout) as resp:\n data = resp.read()\n os.makedirs(os.path.dirname(os.path.abspath(dest)), exist_ok=True)\n with open(dest, \"wb\") as f:\n f.write(data)\n return len(data)\n\n\ndef parse_error_body(e):\n try:\n return e.read().decode(\"utf-8\", errors=\"replace\")\n except Exception:\n return \"\"\n\n\ndef output_json(result, exit_code=0):\n \"\"\"输出 JSON 并退出。\"\"\"\n result[\"exit_code\"] = exit_code\n print(json.dumps(result, ensure_ascii=False), flush=True)\n sys.exit(exit_code)\n\n\ndef main():\n ap = argparse.ArgumentParser(description=\"Generate infographic via SenseNova U1 Fast\")\n g = ap.add_mutually_exclusive_group(required=True)\n g.add_argument(\"--prompt\", help=\"信息图 Prompt 文本(结构化中文)\")\n g.add_argument(\"--prompt-file\", help=\"包含 Prompt 的文本文件路径(UTF-8)\")\n ap.add_argument(\"--size\", default=DEFAULT_SIZE, help=\"分辨率,默认 %s\" % DEFAULT_SIZE)\n ap.add_argument(\"--aspect-ratio\", help=\"按宽高比选尺寸(16:9, 9:16, 1:1, 4:5 ...),自动映射到白名单\")\n ap.add_argument(\"--n\", type=int, default=1, help=\"生成张数,默认 1\")\n ap.add_argument(\"--output\", default=\"./infographic.png\", help=\"输出文件路径(多张时自动加序号)\")\n ap.add_argument(\"--api-key\", default=os.environ.get(\"SENSENOVA_API_KEY\", \"\"),\n help=\"API Key,默认读环境变量 SENSENOVA_API_KEY\")\n ap.add_argument(\"--timeout\", type=int, default=180, help=\"超时秒数,默认 180\")\n ap.add_argument(\"--dry-run\", action=\"store_true\", help=\"不调用 API,只校验并打印请求体\")\n ap.add_argument(\"--show-prompt\", action=\"store_true\", help=\"打印最终使用的 Prompt\")\n ap.add_argument(\"--json\", action=\"store_true\", help=\"最终输出 JSON 格式,便于脚本解析\")\n args = ap.parse_args()\n\n # 尺寸解析:--aspect-ratio 优先级高于 --size\n if args.aspect_ratio:\n ar = args.aspect_ratio.strip()\n if ar not in ASPECT_RATIOS:\n log(\"[错误] 不支持的宽高比 '%s'。仅支持:%s\" % (ar, \", \".join(sorted(ASPECT_RATIOS.keys()))))\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"unsupported aspect ratio\", \"aspect_ratio\": ar}, 2)\n return 2\n args.size = ASPECT_RATIOS[ar]\n log(\"[信息] 宽高比 %s 已映射为分辨率 %s\" % (ar, args.size))\n\n if args.size not in VALID_SIZES:\n log(\"[错误] 非法分辨率 '%s'。仅支持以下 11 种:\" % args.size)\n log(\" \" + \", \".join(sorted(VALID_SIZES)))\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"invalid size\", \"size\": args.size}, 2)\n return 2\n\n # 读取 Prompt\n if args.prompt_file:\n try:\n with open(args.prompt_file, \"r\", encoding=\"utf-8\") as f:\n prompt = f.read().strip()\n except OSError as e:\n log(\"[错误] 读取 prompt 文件失败:%s\" % e)\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"failed to read prompt file\", \"error\": str(e)}, 2)\n return 2\n else:\n prompt = args.prompt.strip()\n\n if not prompt:\n log(\"[错误] Prompt 为空。\")\n return 2\n\n tokens = approx_tokens(prompt)\n if args.show_prompt:\n log(\"=\" * 60)\n log(\"[最终 Prompt](约 %d tokens):\" % tokens)\n log(prompt)\n log(\"=\" * 60)\n\n # 静态检查\n for w in lint_prompt(prompt):\n log(\"[提示] %s\" % w)\n\n body = build_request(prompt, args.size, args.n)\n\n if args.dry_run:\n log(\"[信息] 干运行模式,不调用 API,已校验通过。\")\n log(\"[信息] 请求体:\")\n log(body.decode(\"utf-8\"))\n if args.json:\n output_json({\n \"status\": \"dry_run\",\n \"model\": MODEL,\n \"size\": args.size,\n \"n\": args.n,\n \"tokens\": tokens,\n \"prompt\": prompt,\n }, 0)\n return 0\n\n # 前置检查:API Key\n if not args.api_key:\n log(\"[错误] 未提供 API Key。请设置环境变量 SENSENOVA_API_KEY,或用 --api-key 传入。\")\n log(\" 获取地址:https://platform.sensenova.cn/console → API Keys(sk- 开头)\")\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"missing API key\"}, 2)\n return 2\n\n log(\"[信息] 模型 %s | 尺寸 %s | 张数 %d | Prompt 约 %d tokens\"\n % (MODEL, args.size, args.n, tokens))\n\n # 带重试的 API 调用\n result = None\n error_detail = None\n for attempt in range(1, MAX_RETRIES + 1):\n try:\n log(\"[信息] 正在请求生成(第 %d/%d 次尝试)...\" % (attempt, MAX_RETRIES))\n result = call_api(args.api_key, body, args.timeout)\n break\n except urllib.error.HTTPError as e:\n detail = parse_error_body(e)\n error_detail = detail\n log(\"[错误] HTTP %s:%s\" % (e.code, detail[:500]))\n if e.code in (401, 403):\n log(\" → API Key 无效/无权限,请检查后重试,不再自动重试。\")\n if args.json:\n output_json({\"status\": \"error\", \"http_code\": e.code, \"message\": \"invalid API key\", \"detail\": detail}, 1)\n return 1\n if e.code == 400:\n log(\" → 请求参数错误,请检查 size 是否为白名单、prompt 是否合法。\")\n if args.json:\n output_json({\"status\": \"error\", \"http_code\": e.code, \"message\": \"bad request\", \"detail\": detail}, 1)\n return 1\n if e.code in (429, 500, 502, 503, 504) and attempt < MAX_RETRIES:\n wait = RETRY_BACKOFF[attempt - 1]\n log(\" → 可重试错误,%d 秒后重试。\" % wait)\n time.sleep(wait)\n continue\n if args.json:\n output_json({\"status\": \"error\", \"http_code\": e.code, \"message\": \"http error\", \"detail\": detail}, 1)\n return 1\n except (urllib.error.URLError, TimeoutError) as e:\n error_detail = str(e)\n log(\"[错误] 网络/超时:%s\" % e)\n if attempt < MAX_RETRIES:\n wait = RETRY_BACKOFF[attempt - 1]\n log(\" → %d 秒后重试。\" % wait)\n time.sleep(wait)\n continue\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"network/timeout\", \"detail\": str(e)}, 1)\n return 1\n\n if not result:\n log(\"[错误] 多次尝试后仍未获得结果。\")\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"no result after retries\"}, 1)\n return 1\n\n data = result.get(\"data\") or []\n if not data:\n log(\"[错误] 返回结果无 data 字段:%s\" % json.dumps(result, ensure_ascii=False)[:500])\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"no data field in response\", \"response\": result}, 1)\n return 1\n\n # 下载保存\n base, ext = os.path.splitext(args.output)\n if not ext:\n ext = \".png\"\n saved = []\n for i, item in enumerate(data):\n url = item.get(\"url\")\n if not url:\n log(\"[警告] 第 %d 张无 url,跳过。\" % (i + 1))\n continue\n dest = args.output if len(data) == 1 else \"%s_%d%s\" % (base, i + 1, ext)\n try:\n size_bytes = download(url, dest, args.timeout)\n saved.append({\"path\": dest, \"bytes\": size_bytes, \"url\": url})\n log(\"[成功] 已保存:%s(%.1f KB)\" % (dest, size_bytes / 1024.0))\n except Exception as e:\n log(\"[警告] 下载第 %d 张失败:%s\" % (i + 1, e))\n log(\" 原始 URL(1 小时内有效):%s\" % url)\n\n if not saved:\n log(\"[错误] 没有任何图片保存成功。\")\n if args.json:\n output_json({\"status\": \"error\", \"message\": \"no images saved\"}, 1)\n return 1\n\n log(\"[完成] 共保存 %d 张信息图。\" % len(saved))\n\n if args.json:\n output_json({\n \"status\": \"success\",\n \"model\": MODEL,\n \"size\": args.size,\n \"n_requested\": args.n,\n \"n_saved\": len(saved),\n \"tokens\": tokens,\n \"saved\": saved,\n }, 0)\n else:\n # 机器可读输出,方便上层解析\n print(\"SAVED_FILES=\" + json.dumps([s[\"path\"] for s in saved], ensure_ascii=False))\n\n return 0\n\n\nif __name__ == \"__main__\":\n sys.exit(main())\n"}}, "SKILL.md": {"19c711520a22c2531c58b802db474d38a0335c9d": {"t": 1785768263.426032, "n": 6343, "h": "128b46b7fa57de82", "c": "---\nname: sensenova-infographic\ndescription: >\n 用商汤 SenseNova U1 Fast(sensenova-u1-fast)生成中文信息图 / 海报 / 知识卡片。\n 该模型是专精信息图的原生图像生成模型,文字渲染达商业级精度、排版规整。\n 内置针对中文场景优化的结构化提示词模板库(对比图/流程图/数据图/知识卡片/清单/海报)。\n Use when the user wants to make an infographic, poster, knowledge card, data\n visualization image, or 信息图 with SenseNova / 商汤 / U1.\n 触发词:信息图, 生成信息图, 商汤信息图, SenseNova, sensenova-u1-fast, U1, 海报,\n 知识卡片, 数据可视化图, infographic, 科普图, 流程图海报, 清单图。\nagent_created: true\n---\n\n# SenseNova U1 Fast — 中文信息图生成\n\n## Overview\n\n`sensenova-u1-fast` 是商汤 SenseNova U1(NEO-Unify 理解生成统一架构)的加速版,**专精信息图**:\n文字渲染达商业级精度、能精准控制多栏边界、排版规整。本 skill 把「用户内容 → 结构化中文\nPrompt → 调 API 生图 → 下载保存」串成稳定流程,并内置一套**中文优化提示词模板库**。\n\n- 接口:`POST https://token.sensenova.cn/v1/images/generations`(OpenAI images 兼容)\n- 模型:`sensenova-u1-fast`(固定)| Prompt 上限 **4096 tokens** | 11 种固定分辨率\n- 生图脚本:`scripts/generate_infographic.py`(纯标准库,零依赖,自动下载+重试)\n- 提示词模板:`references/prompt-guide.md` | 接口细节:`references/api.md`\n\n> ⚠️ **U1 Fast 不是万能模型**:它只擅长**信息图/海报/排版类图像生成**。不要用它做:\n> - 通用写实照片(人物/风景)\n> - 图像理解/识图/问答\n> - 纯艺术创作(它会被强制结构化,反而受约束)\n> 对话/识图请走 `/v1/chat/completions` + `sensenova-6.7-flash-lite`。\n\n\n---\n\n## Prerequisites\n\n🔴 **CHECKPOINT — 生图前必须确认 API Key,否则调用必失败:**\n\n1. 访问 https://platform.sensenova.cn/console → API Keys,创建 sk- 开头的密钥(公测免费)。\n2. 设置环境变量(**每次调用脚本都必须带**,Windows 还要带 UTF-8):\n - Windows(bash):`export SENSENOVA_API_KEY=sk-xxx`\n - 或调用脚本时用 `--api-key sk-xxx` 传入\n3. **确认 Key 就绪后再进入下面的流程。** 未就绪 → 停下,先引导用户去控制台创建。\n\n⚠️ API Key 是敏感凭据:**绝不硬编码进代码或提交到仓库**,只走环境变量 / `--api-key`。\n\n---\n\n## Workflow(5 步,逐步执行)\n\n### Step 1 · 明确需求(输入 → 输出)\n问清并锁定 4 件事,缺则用合理默认并**明确告知用户**:\n- **主题内容**:要表达什么?把关键文字/数据尽量拿全(U1 渲染的就是你给的字)。\n- **信息图类型**:对比 / 流程 / 数据 / 知识卡片 / 清单 / 海报(决定套哪个模板)。\n- **风格**:扁平商务 / 可爱卡通 / 国风 / 科技 / 手账 / 波普 / 数据仪表(见 prompt-guide 风格库)。\n- **尺寸**:默认横版 `2752x1536`;竖屏 `1536x2752`;小红书 `1824x2272`(见 api.md 尺寸表)。\n\n### Step 2 · 选模板(读 prompt-guide.md)\n按类型从 `references/prompt-guide.md` 的模板库选一个骨架(A 对比 / B 流程 / C 数据 / D 知识卡片 / E 清单 / F 海报)。**必须实际读取该文件**,不要凭记忆。\n\n### Step 3 · 组装结构化中文 Prompt(核心,决定成败)\n按黄金 5 段填满模板:【整体风格】【配色方案】【整体布局】【标题区】【各区块内容+底部】。\n遵守五条铁律:① 文字写原文 ② 图标描述造型 ③ 布局用几何词 ④ 配色先定死 ⑤ 加防溢出约束。\nPrompt 尽量写详细(上限 4096 tokens,用满更稳)。把最终 Prompt 存成 UTF-8 文件,例如\n`<工作目录>/_sensenova_prompt.txt`,避免命令行超长/转义问题。\n\n🔴 **CHECKPOINT**:把组装好的 Prompt 先展示给用户确认(尤其文字/数据/配色),确认后再生图。\n\n### Step 4 · 调用脚本生图\n\n```bash\n# 基础调用\nPYTHONIOENCODING=utf-8 python \"C:/Users/MSI/.workbuddy/skills/sensenova-infographic/scripts/generate_infographic.py\" \\\n --prompt-file \"<工作目录>/_sensenova_prompt.txt\" \\\n --size 2752x1536 \\\n --output \"<工作目录>/信息图_主题.png\"\n\n# 按宽高比快速选尺寸(16:9 / 9:16 / 1:1 / 4:5 ...)\nPYTHONIOENCODING=utf-8 python scripts/generate_infographic.py \\\n --prompt-file prompt.txt --aspect-ratio 16:9 --output out.png\n\n# 干运行:不烧 Token,先校验 Prompt / 请求体\nPYTHONIOENCODING=utf-8 python scripts/generate_infographic.py \\\n --prompt-file prompt.txt --dry-run --show-prompt\n\n# JSON 输出,方便自动化流程解析\nPYTHONIOENCODING=utf-8 python scripts/generate_infographic.py \\\n --prompt-file prompt.txt --json --output out.png\n```\n\n- 脚本自动:校验 size 白名单 → Prompt 静态检查(HEX 色值、token 超限、结构缺失) → 调 API(401/400 不重试,429/5xx/超时退避重试 3 次) → 下载签名 URL 保存。\n- 多张时(`--n>1`)自动加序号。成功后:默认输出 `SAVED_FILES=[...]`;`--json` 模式输出完整 JSON 结果。\n\n\n### Step 5 · 展示结果\n用 present_files 展示保存的 PNG。若用户要微调,回 Step 3 改 Prompt 局部再生成(不要从头重写)。\n\n---\n\n## 内置提示词模板速查(详见 references/prompt-guide.md)\n\n| 模板 | 用途 | 默认尺寸 |\n|------|------|---------|\n| A 三栏对比/并列要点 | 优缺点、方案对比、三大功能 | 2752x1536 |\n| B 流程步骤图 | 操作步骤、工作流、时间线 | 2752x1536 / 竖版 |\n| C 数据可视化 | 报告、统计、KPI 大数字 | 2752x1536 / 2496x1664 |\n| D 知识卡片/九宫格 | 科普、教程、小红书 | 1536x2752 / 2048x2048 |\n| E 清单 Checklist | 待办、要点、攻略 | 1536x2752 / 1344x3136 |\n| F 单页海报/封面 | 活动、公告、封面 | 1664x2496 / 1536x2752 |\n\n**黄金结构**(任何图都套):【整体风格】+【配色方案】+【整体布局】+【标题区】+【各区块精确文字与图标】+【底部】。\n\n---\n\n## 失败模式与回退(if-then)\n\n### 阶段一 · 生图前检查\n| 检查项 | 失败 → 处理 |\n|--------|-----------|\n| API Key 是否就绪 | → **立即停止**,引导去 https://platform.sensenova.cn/console 创建 |\n| size 是否在 11 白名单内 | → 脚本直接报错并列出白名单;换合法值;或用 `--aspect-ratio` 映射 |\n| Prompt 是否 ≤4096 tokens | → 脚本打印约算 token 警告;精简文字或拆两张图 |\n| Prompt 是否结构化 | → 若是\"意识流\"一句话,先按黄金 5 段重写再生图 |\n| 脚本静态检查是否有警告(HEX色值/缺结构/缺约束) | → 按提示修复后再生图;可用 `--dry-run` 先不烧 Token 校验 |\n\n### 阶段二 · API 调用失败\n| 错误 | 含义 | 一线修复 | 仍失败 → 兜底 |\n|------|------|---------|-------------|\n| **401/403** | Key 无效/无权限 | 去控制台确认 Key 有效、未注销 | 让用户重建 Key;不自动重试 |\n| **400** | 参数错误 | 检查 model=`sensenova-u1-fast`、size 白名单 | 回退最小参数(model+prompt+默认 size)重试 |\n| **404** | 接口用错 | 确认走 `/v1/images/generations` 而非 chat | 核对 Base URL 子域名是 `token.sensenova.cn` |\n| **429** | 频率超限(1500次/5h) | 等待 Retry-After | 退避 5→15→30s 重试,最多 3 次 |\n| **5xx/超时** | 服务端/网络 | 退避重试 | 3 次失败告知用户稍后再试 |\n| **URL 下载失败** | 签名 URL 过期(>1h) | 立即重跑生图拿新 URL | 脚本会打印原始 URL 供手动下载 |\n\n### 阶段三 · 出图质量不达标(实测高频)\n| 症状 | 修复(改 Prompt 后重生) |\n|------|------------------------|\n| 文字模糊/错字 | 加「标题粗体、小字边缘锐利」+ 简化背景;文字过多则拆图 |\n| 布局混乱 | 换几何布局词 + 强调\"区块外观完全统一\";区块数降到 ≤4 |\n| 内容溢出边框 | 加「元素与边框保持安全间距,严禁溢出」;缩短单块文字 |\n| 配色杂乱 | 先定死主/辅/背景/文字四色;必要时降到双色 |\n\n---\n\n## 反例黑名单(不要做的事)\n\n| # | 禁止行为 | 为什么 | 正确做法 |\n|---|---------|--------|---------|\n| 1 | **硬编码 API Key 到代码/仓库** | 泄露凭据 | 只用 `$SENSENOVA_API_KEY` 或 `--api-key` |\n| 2 | **写\"意识流\" Prompt**(如\"画个好看的海报字大点\")| U1 会跑偏、抽卡 | 按黄金 5 段结构化,文字写原文 |\n| 3 | **只说\"配几个图标\"不描述造型** | 图标随机、不符主题 | 明确图标位置/造型/颜色 |\n| 4 | **传非白名单分辨率**(如 `1920x1080`)| 直接 400 | 只用 11 种官方尺寸 |\n| 5 | **用生图接口去做问答/识图** | 404 | 对话/识图走 `/v1/chat/completions` + `sensenova-6.7-flash-lite` |\n| 6 | **Prompt 里只写\"介绍三点\"不给原文** | 模型自己编字,不可控 | 把三点的完整文字逐字写进 Prompt |\n| 7 | **一次塞太多区块(>4-5块)+ 海量文字** | 排版必乱、文字糊 | 精简或拆成多张图 |\n| 8 | **Windows 下不设 UTF-8 就跑脚本** | 中文/emoji 可能 GBK 报错 | 命令前加 `PYTHONIOENCODING=utf-8` |\n| 9 | **签名 URL 拿到手不及时下载** | URL 约 1 小时失效 | 立即下载保存(脚本已自动做) |\n\n---\n\n## Runtime 适配性声明\n\n本 skill 遵循 Agent Skills Standard,可在 Claude Code、Codex、Cursor、WorkBuddy、Hermes、\nOpenClaw、Gemini CLI 等任何 skills-compatible runtime 运行。生图通过标准 HTTP(Python 标准库)\n执行,无 runtime 特定依赖;脚本路径按各 runtime 的 skills 目录自行替换即可。\n\n---\n\n## 资源速查\n\n| 路径 | 用途 |\n|------|------|\n| `scripts/generate_infographic.py` | 生图脚本:校验/调用/重试/下载,零依赖 |\n| `references/prompt-guide.md` | 中文提示词工程指南 + 6 套模板库 + 风格库 |\n| `references/api.md` | 接口规格 + 11 种分辨率 + 错误码 |\n\n## 版本记录\n\n| 版本 | 日期 | 变更 |\n|------|------|------|\n| 1.1 | 2026-07-20 | 脚本增强:支持 `--aspect-ratio`、`--dry-run`、`--show-prompt`、`--json`;新增 Prompt 静态检查(HEX色值/token/结构/约束);prompt-guide 补充配色写法指南与完整示例;SKILL.md 补充 U1 不适用场景 |\n| 1.0 | 2026-07-17 | 初始版本:U1 Fast 信息图生成 + 中文优化提示词模板库 + 失败模式/黑名单/检查点 |\n"}}}}