Files
atomk-hermes-skills/skills/cross-border-ecommerce/flairgs-vision-api/SKILL.md
T

12 KiB
Raw Blame History

name, title, description, category, tags
name title description category tags
flairgs-vision-api FlairGS 视觉分析 API Self-hosted VL (qwen3-vl:8b) + image processing API for 9Webs cross-border ecommerce — OCR, captcha, product analysis, IP screening, white-bg, txt2img. 关键:字段名是 base64 不是 image_base64。 cross-border-ecommerce
flairgs
vision
vl
ocr
captcha
qwen-vl
image-processing
cdp-bridge

FlairGS 视觉分析 API

自建 VL (Vision-Language) + 图像处理 API。GS3 运行 qwen3-vl:8b,通过 frp 隧道暴露给 SG5。

速查表

项目
LAN URL (优先) http://192.168.9.105:7870
FRP URL (新) http://43.160.244.125:17870 (2026-07 上线)
FRP URL (旧/回退) http://frp.9webs.online:17870
AtomK 工具箱 http://192.168.9.105:20261 (Desktop CDP 可访问)
连接策略 FRP 直连优先(10s 超时),headless browser 可能不通需走 cron
共享客户端 ~/.hermes/scripts/flairgs_client.py
Auth Header X-API-Key: 8Ax4TyZc66qrZgXK
源码 GS3: /home/admin9webs/flairgs_v3_server.py
VL 模型 GS3: qwen3-vl:8b (127.0.0.1:11434) + GS4: qwen3-vl:8b (192.168.9.129:11434)
Chat 模型 GS1-35B + 本机 4B
典型延迟 ~7.5s (VL analyze)

端点

GET /health

curl -H "X-API-Key: 8Ax4TyZc66qrZgXK" http://frp.9webs.online:17870/health

返回: {"status": "ready", ...}

POST /api/analyze — VL 图像分析(最常用)

OCR、视觉问答、场景理解。这是最主要端点。

⚠️ 致命陷阱:JSON 字段是 "base64",不是 "image_base64"image_base64 会静默失败——HTTP 200 但返回 "No image data"

POST /api/analyze
Content-Type: application/json
X-API-Key: 8Ax4TyZc66qrZgXK

{
  "base64": "<纯base64,不带 data:image/png;base64, 前缀>",
  "prompt": "可选,引导分析的文本提示",
  "filename": "可选,默认 image.jpg"
}

返回:

{
  "description": "分析结果(中文/英文)...",
  "model": "GS3/qwen3-vl:8b",
  "elapsed": 7.8
}

常用 prompt 模板:

  • OCR: "只输出图片中的文字,不要任何其他内容。"
  • 验证码: "只输出验证码中的4个字符,不要任何其他内容。区分大小写。"
  • UI 分析: "Describe all visible buttons and their positions."
  • 产品分析: "描述这个商品图片。类目?材质?风格?"
  • IP 筛查: "图中是否包含卡通/动漫/品牌角色?列出所有 IP 风险。"

POST /api/resize — 图片缩放

{"base64": "...", "width": 800, "height": 600}

POST /api/txt2img — 文生图

{"base64": "...", "prompt": "生成提示词"}

POST /api/white-bg — 白底处理(商品图标准化)

{"base64": "..."}

POST /api/chat — LLM 对话

GS1-35B + 本机 4B 混合推理。

共享客户端 (推荐)

所有脚本统一用 ~/.hermes/scripts/flairgs_client.py,自动实现 LAN 优先 + FRP 回退:

from flairgs_client import analyze, health_check, get_active_url

# 自动 LAN → FRP 回退
result = analyze(b64, "描述这张图片")
print(result)

# 健康检查
for url, info in health_check().items():
    print(f"{url}{info['status']}")

# 获取当前活跃 URL
active = get_active_url()

连接策略:

  1. 先尝试 http://192.168.9.105:7870LAN 直连,3s 超时)
  2. 失败自动回退 http://43.160.244.125:17870FRP 隧道)
  3. 局域网用户享受低延迟直连,外网用户无缝 FRP

便捷封装也内置了:

  • ocr_captcha(b64) — 验证码 OCR
  • describe_product(b64) — 商品描述
  • check_ip_risk(b64) — IP 风险筛查

📖 实现细节、超时策略、扩展现有脚本的侵入模式:references/client-internals.md

标准集成模式:CDP 截图 → FlairGS 分析

最常见的组合:Cloud Bridge CDP 截图 + FlairGS VL 分析。使用共享客户端,自动 LAN/FRP 回退。

import json, urllib.request
from flairgs_client import analyze as flairgs_analyze

# === Bridge 认证 ===
BRIDGE_KEY = "Bing2026Cao$$$"
BRIDGE_URL = "http://127.0.0.1:9228"
SLOT = "desktop-mqjqto79"
BH = {
    "Authorization": f"Bearer {BRIDGE_KEY}",
    "Content-Type": "application/json",
    "X-Desktop-Id": SLOT,
}

def bridge_req(path, data=None):
    url = f"{BRIDGE_URL}{path}"
    body = json.dumps(data).encode() if data else None
    r = urllib.request.Request(url, data=body, method="POST")
    for k, v in BH.items(): r.add_header(k, v)
    return json.loads(urllib.request.urlopen(r, timeout=60).read())

# 1. Attach CDP
att = bridge_req("/cdp/attach", {})
tid = att["targetId"]
att2 = bridge_req("/cdp/send", {
    "method": "Target.attachToTarget",
    "params": {"targetId": tid, "flatten": True}
})
sid = att2["result"]["sessionId"]

# 2. 截图
ss = bridge_req("/cdp/send", {
    "method": "Page.captureScreenshot",
    "params": {"format": "png"},
    "sessionId": sid
})
b64 = ss["result"]["data"]

# 3. FlairGS 分析 (LAN → FRP 自动回退)
desc = flairgs_analyze(b64, "描述这个页面上的所有按钮和功能")
print(desc)

Desktop CDP 内网工具箱模式(2026-07 新增)

Bridge headless 浏览器到不了 192.168.9.x,但 Desktop CDP Chrome 可以(同内网):

# 1. Attach to Desktop CDP target
att = bridge_req("/cdp/attach", {})  # X-Desktop-Id header

# 2. 交互工具箱页面 (evaluate 可用)
ev("document.querySelector('textarea')['value']='prompt here'")
ev("document.querySelectorAll('button')[7].click()")  # "🎨 生成"

# 3. 提取生成的图片
ev("var img=document.querySelectorAll('img')[1]; var c=document.createElement('canvas'); c.width=img.naturalWidth; c.height=img.naturalHeight; c.getContext('2d').drawImage(img,0,0); window.__CAPTURED_IMG=c.toDataURL('image/jpeg',0.9).split(',')[1]")

# 4. 图片在本地磁盘: /home/ubuntu/output/text2img_*.jpg

关键发现:工具箱生成的图片存在 Bridge 服务器的 /home/ubuntu/output/ 目录下,说明工具箱和 Bridge 共享文件系统。可直接用 Python 读取本地文件后调用 VL API。

(async function(){
  var urls = ["http://192.168.9.105:7870", "http://43.160.244.125:17870"];
  var key = "8Ax4TyZc66qrZgXK";
  var b64 = "iVBORw0KGgo...";  // 纯 base64
  // LAN first, FRP fallback
  for (var url of urls) {
    try {
      var r = await fetch(url + "/api/analyze", {
        method: "POST",
        headers: {"X-API-Key": key, "Content-Type": "application/json"},
        body: JSON.stringify({base64: b64, prompt: "你的问题"}),
        signal: AbortSignal.timeout(url.includes("105") ? 3000 : 120000)
      });
      return await r.text();
    } catch(e) { continue; }
  }
  return "All URLs failed";
})()

Desktop CDP 交互模式(2026-07 实测)

Desktop CDP Chrome 在用户 Windows 机器上(192.168.9.x 内网),可直接操控工具箱 Web UI:

// 获取按钮列表(while 循环兼容 CDP 表达式过滤器)
var b=document.querySelectorAll('button'); var i=b.length; var r=[];
while(i--) { r.push(i+':'+b[i].innerText.substring(0,30)); }
JSON.stringify(r)
// → ["15:确认转换","14:取消",...,"7:🎨 生成",...,"1:🔍 一键分析","0:加载"]

// 填 textarea + 生成图
var ta=document.querySelector('textarea');
ta.value='prompt'; ta.dispatchEvent(new Event("input",{bubbles:true}));
document.querySelectorAll('button')[7].click();  // 🎨 生成

// 一键 VL 分析
document.querySelectorAll('button')[1].click();  // 🔍 一键分析

// 提取生成的图片为 base64
var img=document.querySelectorAll('img')[1];  // 索引依页面而定
var c=document.createElement('canvas');
c.width=img.naturalWidth; c.height=img.naturalHeight;
c.getContext('2d').drawImage(img,0,0);
window.__CAPTURED_IMG=c.toDataURL('image/jpeg',0.9).split(',')[1];

限制: CDP 仅支持 sync XHRXMLHttpRequest,不可设 timeout),不支持 fetch()。VL API 跨域调用会失败(NetworkError),但工具箱页面内 /api/analyze 同源调用可用——lastDescription 全局变量存储分析结果。

陷阱大全

  1. ⚠️ 字段名是 base64,不是 image_base64 — 用错静默返回 "No image data" HTTP 200。~/.hermes/scripts/ 里多个脚本仍有此 bug。

  2. Base64 必须纯的 — 去掉 data:image/png;base64, 前缀。用 dataUrl.split(",")[1] 剥离。

  3. Multipart/form-data 会导致 500 crash — 必须用 Content-Type: application/json + JSON body。

  4. /api/load-url 不可靠 — 可能超时。推荐本地下载后传 base64。

  5. frp 隧道可能截断大 payload — 如果 SG5 突然报错但 GS3 本地正常,检查 frp。

  6. timeout — 默认 60s 足够(VL ~7.5s)。大图或复杂 prompt 设 timeout=120。

  7. CORS — 浏览器跨域会阻止。用服务端 Python 调用。

  8. 🔴 图片最小 32×32 像素 — qwen3-vl:8b 要求图片 ≥ 32×32,否则 Ollama 直接 500 panic。调用前校验尺寸!典型错误日志:height:1 or width:1 < factor:32

  9. 🔴 VL 后端 5032026-07 — FRP 转发成功但 127.0.0.1:7870/api/analyze 返回 503 Service Unavailable。表示 VL 服务器进程挂了或端口未监听。检查 192.168.9.105 上 systemctl --user status flairgs.service

  10. 🔴 alicdn 图片需 PIL convert('RGB')2026-07 — 从 alicdn 下载的产品图片(800x800 WebP/JPEG)直接传 base64 会导致 qwen3-vl 返回空描述。必须先用 Image.open().convert('RGB') 转换再 save(format='JPEG')。小 PNG 测试图不受影响。

  11. **get_active_url() 每次调用都做 health check`

  12. get_active_url() 每次调用都做 health check — 开销小(3s 超时),但不要在热循环里调用。脚本里一般只在构造 URL 时调用一次。缓存策略见 references/client-internals.md

服务器管理

  • API 端口: 192.168.9.105: 7870LAN: 192.168.9.105:7870, FRP: 43.160.244.125:17870
  • 重启: GS3 上 systemctl --user restart flairgs.service
  • 日志: journalctl --user -u flairgs.service -f
  • 本地测试GS3 绕过 frp:
    curl -X POST http://localhost:7870/api/analyze \
      -H "Content-Type: application/json" \
      -H "X-API-Key: 8Ax4TyZc66qrZgXK" \
      -d '{"base64":"你的base64"}'
    
  • LAN 测试(局域网内其他机器):
    curl -X POST http://192.168.9.105:7870/api/analyze \
      -H "Content-Type: application/json" \
      -H "X-API-Key: 8Ax4TyZc66qrZgXK" \
      -d '{"base64":"你的base64"}'
    

已有脚本参考

~/.hermes/scripts/ 中的参考脚本(全部已升级 LAN 优先路由:

脚本 用途 字段名 路由 状态
dxm_try2.py 验证码 OCR + CDP 登录 base64 _fga_url()
dxm_captcha.py 验证码提取 + OCR base64 _fga_url()
dxm_ss.py CDP 截图 + 分析 base64 _fga_url()
flairgs_client.py 共享客户端(本模块) base64 内置 LAN/FRP
flairgs_v2.py CDP 截图 + VL 分析 + 重试 base64 _fga_url()
flairgs_full.py 163 邮箱截图 + 分析 base64 _fga_url()
flairgs_analyze.py 独立 FlairGS 分析 base64 _fga_url()
flairgs_163.py 163 工具栏分析 base64 _fga_url()
flairgs_test.py 多格式探测 base64 _fga_url()
flairgs_img.py 直接图片分析 base64 _fga_url()
flairgs_diag.py 诊断探测 base64 _fga_url()
flairgs_raw.py 多格式实验 base64 _fga_url()
flairgs_multi.py 多格式提交 base64 _fga_url()
flairgs_inbox.py 收件箱截图分析 base64 _fga_url()
flairgs_inbox2.py 收件箱截图分析 v2 base64 _fga_url()
flairgs_prompt.py Prompt 变体测试 base64 _fga_url()
flairgs_final.py 最终集成方案 base64 _fga_url()
flairgs_form.py 多表单格式 base64 _fga_url()
flairgs_go.py 快速调用 base64 _fga_url()
flairgs_oa.py OA 集成 base64 _fga_url()
flairgs_q.py 快速分析 base64 _fga_url()
flairgs_ollama.py Ollama 直连测试 base64 _fga_url()

Legacy 模式说明: 现有脚本使用 from flairgs_client import get_active_url as _fga_url + _fga_url() + "/api/analyze" 模式——这是最小侵入式改动,保留了原有请求构建逻辑。新脚本推荐直接用 analyze(b64, prompt)