Преглед на файлове

skill-image v2.0: 架构图+场景图双模式,自动读Key,发布使用

liuyuyang преди 10 часа
ревизия
53dbf5d246
променени са 2 файла, в които са добавени 224 реда и са изтрити 0 реда
  1. 124 0
      SKILL.md
  2. 100 0
      scripts/gen.py

+ 124 - 0
SKILL.md

@@ -0,0 +1,124 @@
+---
+name: skill-image
+description: "触发词:生成架构图/场景图/插图。走API出白底PNG,自动读Key,¥0.3-0.5/张。"
+version: 2.0.0
+author: Yuyang001 (FmodeAgent)
+license: MIT
+platforms: [linux]
+tags: [architecture, image, harness, diagram]
+---
+
+# skill-image v2 — 架构图 + 场景插图双模式
+
+## 凭据自动获取
+自动读取(按优先级):
+1. 环境变量 `FMODE_API_KEY`
+2. `~/.fmode/config.json` api_key
+3. `~/.fmode/config.yaml`
+4. 容器内 `.env` 文件
+
+自带 `scripts/gen.py` 可独立运行,不依赖 Hermes。
+
+## 模式A:架构图 (--arch)
+- **尺寸**:1792×1024(PPT横版)
+- **成本**:≈¥0.5/张
+- **用途**:Harness五层、数据本体、Loop闭环、系统架构
+- **风格**:纯白底、扁平、简洁、商务
+- **输出**:白底PNG,直接拖入PPT
+
+示例 prompt:
+```
+纯白背景扁平风格架构图。标题"内容营销超级预审Agent Harness架构"。
+从上到下五层:L1宣称定级→L2规则匹配→L3案例类比→L4决策门→L5风险评级。
+右侧三个数据卡片。底部三大本体模块。右下Loop闭环。
+简洁扁平商务风格。纯白背景适合PPT。
+```
+
+### 架构图色彩规范
+- 背景:纯白 #FFFFFF
+- Harness层标题:金色 #D5B254
+- 本体层标题:紫色 #AF8AE8
+- Loop闭环:青色 #7FD1A0
+- 数据指标:金色亮 #FFC000
+- 文字主:#1a1a2e 文字次:#666666
+
+### 架构图布局(1792×1024)
+1. 顶部标题区
+2. 右上指标卡片(3-4个)
+3. 中部Harness引擎(五层竖向/横向)
+4. 底部本体层(三大模块)
+5. 右侧Loop闭环
+
+## 模式B:场景/插图 (--scene)
+- **尺寸**:1024×1024(方形)
+- **成本**:≈¥0.3/张(省40%)
+- **用途**:照片替代、示意图、人物场景、故事板
+- **风格**:扁平插画、清新明亮
+- **适用**:案例故事配图、痛点可视化、前后对比
+
+示例 prompt:
+```
+扁平插画场景。一个法务团队围坐在堆满文件的办公桌前,
+桌上电脑显示67%退审率。人物表情焦虑。
+清新明亮风格。
+```
+
+### 常见场景类型
+- **痛点场景**:人物+问题+数据,传达紧迫感
+- **对比场景**:Before/After分屏对比
+- **应用场景**:人物使用产品示意
+- **数据场景**:以人物为中心+数据上下文
+- **未来场景**:愿景描绘,科技感
+
+### 场景图Prompt技巧
+1. 指定人物、表情、动作
+2. 指定环境/背景
+3. 指定色彩倾向(清新明亮/柔和暖色/专业商务)
+4. 避免过多文字(AI不擅长文字生成)
+5. 用"扁平插画"保持风格一致
+
+## 尺寸选择建议
+| 用途 | 尺寸 | 成本 |
+|------|------|------|
+| PPT大图/架构 | 1792×1024 | ¥0.5 |
+| PPT小图/插画 | 1024×1024 | ¥0.3 |
+| 卡片/图标 | 1024×1024 | ¥0.3 |
+| 封面/海报 | 1792×1024 | ¥0.5 |
+
+## 成本参考
+| 模式 | 尺寸 | Token | 单价 | 8张总价 |
+|------|------|-------|-----|--------|
+| 架构图 | 1792×1024 | ~3,500 | ¥0.5 | ¥4.0 |
+| 场景图 | 1024×1024 | ~2,000 | ¥0.3 | ¥2.4 |
+
+## 用法
+
+### Hermes 内调用
+```python
+from hermes_tools import terminal
+terminal('python3 skills/skill-image/scripts/gen.py --arch "内容营销预审Agent Harness架构" case01')
+terminal('python3 skills/skill-image/scripts/gen.py --scene "法务团队被海量稿件淹没" legal-scene')
+```
+
+### 命令行独立使用
+```bash
+python3 /path/to/skill-image/scripts/gen.py --arch "内容营销预审Agent Harness架构" my-arch
+python3 /path/to/skill-image/scripts/gen.py --scene "营销团队在开会" team-meeting
+export SKILL_IMAGE_OUTPUT=/my/project/images
+python3 gen.py --arch "..." out
+```
+
+### Python 编程调用
+```python
+from scripts.gen import gen_arch, gen_scene, batch_arch
+# 单张
+path = gen_arch('内容营销预审Agent Harness架构...', 'case01')
+# 场景
+path = gen_scene('医生在电脑前分析健康数据的场景', 'doctor-scene')
+# 批量
+batch_arch([('case01','prompt1'), ('case02','prompt2')])
+```
+
+## 仓库
+- Gogs: https://git.fmode.cn/fmode/skill-image
+- GitHub: https://github.com/fmodecn/skill-image

+ 100 - 0
scripts/gen.py

@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+"""skill-image: 架构图 + 场景插图生成器
+用法:
+  python3 gen.py --arch "prompt" [name]     # 架构图 1792x1024 ¥0.5/张
+  python3 gen.py --scene "prompt" [name]    # 场景图 1024x1024 ¥0.3/张
+  python3 gen.py --batch-arch <json_file>   # 批量架构图
+
+凭据: 自动读取 FMODE_API_KEY (env/config)
+"""
+import json, base64, urllib.request, os, sys
+
+API = 'https://api.fmode.cn/v1/images/generations'
+
+def _get_key():
+    for src_name, src_val in [
+        ('FMODE_API_KEY env', os.environ.get('FMODE_API_KEY', '')),
+        ('ANTHROPIC_AUTH_TOKEN env', os.environ.get('ANTHROPIC_AUTH_TOKEN', '')),
+    ]:
+        if src_val and '***' not in src_val and len(src_val) > 10:
+            return src_val
+    try:
+        with open(os.path.expanduser('~/.fmode/config.json')) as f:
+            c = json.load(f)
+            for k in ('api_key', 'FMODE_API_KEY'):
+                if c.get(k): return c[k]
+    except: pass
+    try:
+        with open(os.path.expanduser('~/.fmode/config.yaml')) as f:
+            for l in f:
+                for kw in ('api_key', 'FMODE_API_KEY'):
+                    if kw in l:
+                        v = l.split(':')[1].strip().strip('"\'')
+                        if v and v != '${FMODE_API_KEY}': return v
+    except: pass
+    for p in ['/opt/data/.env', '.env']:
+        try:
+            with open(p) as f:
+                for l in f:
+                    if 'FMODE_API_KEY' in l:
+                        v = l.split('=')[1].strip().strip('"\'')
+                        if v and '***' not in v and len(v) > 10: return v
+        except: pass
+    print('❌ 未找到 API Key。设置环境变量 FMODE_API_KEY 或 ~/.fmode/config.json')
+    sys.exit(1)
+
+API_KEY = _get_key()
+
+def _call_api(prompt, size):
+    body = json.dumps({"model": "gpt-image-2.5-sunburst", "prompt": prompt, "n": 1, "size": size}).encode()
+    req = urllib.request.Request(API, data=body,
+        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
+        method='POST')
+    resp = urllib.request.urlopen(req, timeout=300)
+    data = json.loads(resp.read())
+    if 'b64_json' in data['data'][0]:
+        return base64.b64decode(data['data'][0]['b64_json'])
+    if 'url' in data['data'][0]:
+        return urllib.request.urlopen(data['data'][0]['url'], timeout=60).read()
+    raise Exception('No image data')
+
+def gen_arch(prompt, name='arch'):
+    """架构图: 1792x1024 ¥0.5/张,纯白底PPT用"""
+    full = f'纯白背景扁平风格架构图。{prompt} 简洁扁平商务风格,纯白背景适合PPT。'
+    out = _gen(full, '1792x1024', name)
+    return out
+
+def gen_scene(prompt, name='scene'):
+    """场景/插图: 1024x1024 ¥0.3/张,照片/示意图/画面"""
+    full = f'扁平插画场景。{prompt} 清新明亮风格。'
+    out = _gen(full, '1024x1024', name)
+    return out
+
+def _gen(prompt, size, name):
+    outdir = os.environ.get('SKILL_IMAGE_OUTPUT', '.')
+    os.makedirs(outdir, exist_ok=True)
+    path = f'{outdir}/{name}.png'
+    data = _call_api(prompt, size)
+    with open(path, 'wb') as f:
+        f.write(data)
+    sz = os.path.getsize(path)//1024
+    print(f'✅ {sz}KB -> {path}')
+    return path
+
+def batch_arch(items):
+    """items: [(name, prompt), ...]"""
+    for name, prompt in items:
+        print(f'{name}:', end=' ', flush=True)
+        try:
+            gen_arch(prompt, name)
+        except Exception as e:
+            print(f'❌ {e}')
+
+if __name__ == '__main__':
+    if len(sys.argv) < 3:
+        print(__doc__)
+        sys.exit(1)
+    mode, content = sys.argv[1], sys.argv[2]
+    name = sys.argv[3] if len(sys.argv) > 3 else 'output'
+    {'--arch': lambda: gen_arch(content, name),
+     '--scene': lambda: gen_scene(content, name)}.get(mode, lambda: print(f'Unknown mode {mode}'))()