mcpField
S
sn-da-image-caption

sn-da-image-caption

github.com/opensensenova数据与数据库6.0k139 次安装2 天前更新
代码仓库

关于 sn-da-image-caption

sn-da-image-caption 是用于图像描述和数据提取的技能,适合需要把图片内容转为文本或结构化数据的场景。它可识别图表、表格、界面和示意图类型,并支持批处理与缓存。

主要功能

  1. 01生成图像文本描述
  2. 02自动识别图表、表格及界面类型
  3. 03自定义提示词引导提取
  4. 04批量处理目录中的图像
  5. 05JSON 输出与结果缓存

适用场景

  1. 01从图表图片提取数值
  2. 02将表格截图转换为 Markdown 表格
  3. 03批量整理图片描述结果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/opensensenova/sensenova-skills --skill sn-da-image-caption

安装后在 Claude Code 中输入/sn-da-image-caption确认已加载。

附带文件scripts/caption.py

详细介绍

图像描述分析——图像描述与数据提取

概述

分析、提取图像文件(.png、.jpg、.jpeg、.gif、.webp、.bmp)中的数据,或理解图像内容。核心工作流:

  1. 运行 scripts/caption.py 获取图像的文本描述
  2. 将描述解析为结构化数据(DataFrame 等)
  3. 分析、可视化或导出

scripts/caption.py — 图像描述

此脚本通过视觉模型将图像转换为文本描述。配置 SN_API_KEY(最低要求),或使用 SN_VISION_API_KEY / SN_VISION_BASE_URL / SN_VISION_MODEL 进行精细控制。完整的回退链请参阅项目环境变量规范。

用法
# Basic — get text description
python3 scripts/caption.py /mnt/data/image.png

# Custom prompt — guide what to extract
python3 scripts/caption.py /mnt/data/chart.png --prompt "提取所有数值,Markdown 表格格式"

# JSON output — includes detected type, usage stats, cache info
python3 scripts/caption.py /mnt/data/image.png --json

# Batch — process all images in a directory
python3 scripts/caption.py /mnt/data/images/ --batch --output /mnt/data/captions.json

# Override model (optional)
python3 scripts/caption.py /mnt/data/image.png --model gemini-3.1-flash-lite-preview
选项
选项描述
--prompt, -p自定义提示词(覆盖自动检测)
--model, -m视觉模型(默认:sensenova-6.8-flash-lite)
--json输出结构化 JSON,而非纯文本
--batch处理目录中的所有图像
--output, -o批处理结果的输出文件
--no-cache跳过 MD5 缓存
自动执行的操作
  • 类型检测:根据文件名检测图像类型(图表/表格/UI/示意图/通用),并选择最佳提示词
  • 压缩:发送前压缩大于 5MB 或大于 2048px 的图像
  • 缓存:相同图像 + 相同提示词 → 立即返回缓存结果,不产生 API 费用
  • 错误处理:失败时重试,永久失败时返回错误消息
JSON 输出格式
{
  "file": "/mnt/data/image.png",
  "type": "chart",
  "description": "这是一张柱状图...",
  "usage": {"prompt_tokens": 1100, "completion_tokens": 400},
  "cached": false
}

从 Python 调用

import subprocess, json

CAPTION = "/path/to/skills/sn-da-image-caption/scripts/caption.py"

# Single image
result = subprocess.run(
    ["python3", CAPTION, "/mnt/data/chart.png", "--json",
     "--prompt", "提取图表数据,Markdown 表格输出"],
    capture_output=True, text=True, timeout=60
)
data = json.loads(result.stdout)
description = data["description"]

# Batch
result = subprocess.run(
    ["python3", CAPTION, "/mnt/data/images/", "--batch",
     "--output", "/mnt/data/captions.json"],
    capture_output=True, text=True, timeout=300
)
with open("/mnt/data/captions.json") as f:
    all_captions = json.load(f)

提示词策略

不同图像类型需要不同的提示词。脚本会自动检测,但指定 --prompt 可获得更好的结果。

图像类型场景推荐的 --prompt
数据图表柱状图/折线图/饼图"提取图表标题、坐标轴、每个数据点数值、图例。Markdown 表格输出。"
表格截图表格截图"提取表格所有内容,Markdown 表格格式,保持行列结构,数值不四舍五入。"
UI 截图界面截图"以前端开发者视角描述:布局、组件、文字、颜色。"
示意图流程图/架构图"描述所有节点、连接关系(A→B)、分支条件。"
通用照片、其他不传 --prompt,使用默认值

解析描述结果

描述结果通常以 Markdown 表格形式返回,可解析为 DataFrame:

import pandas as pd

def parse_markdown_table(text):
    lines = text.strip().split('\n')
    table_lines = []
    in_table = False
    for line in lines:
        stripped = line.strip()
        if '|' in stripped:
            in_table = True
            table_lines.append(stripped)
        elif in_table:
            break

    data_lines = []
    for l in table_lines:
        cells = [c.strip() for c in l.split('|') if c.strip()]
        if cells and not all(set(c) <= set('-: ') for c in cells):
            data_lines.append(cells)

    if len(data_lines) < 2:
        return None

    header = data_lines[0]
    rows = [r for r in data_lines[1:] if len(r) == len(header)]
    df = pd.DataFrame(rows, columns=header)

    # Auto numeric conversion
    for col in df.columns:
        try:
            cleaned = df[col].str.replace(',', '').str.strip()
            if cleaned.str.endswith('%').any():
                df[col] = pd.to_numeric(cleaned.str.rstrip('%'), errors='coerce')
            else:
                converted = pd.to_numeric(cleaned, errors='coerce')
                if converted.notna().sum() > len(df) * 0.5:
                    df[col] = converted
        except Exception:
            pass
    return df

可视化

中文字体设置(必需)
import matplotlib.pyplot as plt
import matplotlib
import os

font_path = '/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc'
if os.path.exists(font_path):
    matplotlib.rcParams['font.family'] = 'WenQuanYi Zen Hei'
matplotlib.rcParams['axes.unicode_minus'] = False
调色板
COLORS = ['#4C72B0', '#55A868', '#C44E52', '#8172B2', '#CCB974', '#64B5CD']
保存与显示
plt.savefig('/mnt/data/chart.png', dpi=150, bbox_inches='tight')
plt.show()
print("![图表](sandbox:/mnt/data/chart.png)")

导出到 Excel

from openpyxl.styles import Font, PatternFill, Alignment

output_path = "/mnt/data/result.xlsx"
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
    df.to_excel(writer, index=False, sheet_name='提取数据')
    ws = writer.sheets['提取数据']
    fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
    for cell in ws[1]:
        cell.font = Font(bold=True, color='FFFFFF')
        cell.fill = fill
        cell.alignment = Alignment(horizontal='center')
    for i, col in enumerate(df.columns, 1):
        w = max(df[col].astype(str).str.len().max(), len(str(col))) + 2
        ws.column_dimensions[chr(64 + i)].width = min(w * 1.2, 40)

print(f"[下载](sandbox:{output_path})")

多图像处理

import glob

image_files = sorted(glob.glob("/mnt/data/*.png"))
all_dfs = []

for img in image_files:
    r = subprocess.run(
        ["python3", CAPTION, img, "--json", "--prompt", "提取数据,Markdown 表格"],
        capture_output=True, text=True, timeout=60
    )
    desc = json.loads(r.stdout)["description"]
    df = parse_markdown_table(desc)
    if df is not None:
        all_dfs.append(df)

combined = pd.concat(all_dfs, ignore_index=True) if all_dfs else None

或使用批处理模式:

python3 scripts/caption.py /mnt/data/images/ --batch --output /mnt/data/captions.json

常见问题

  • 始终先生成图像描述——不要根据文件名猜测图像内容
  • 使用 --prompt 提高精度——自动检测可以满足基本需求,明确指定提示词效果更好
  • 核验提取的数据——解析后检查总和、百分比和行数
  • 大型表格会被截断——分两次生成描述:“提取前半部分” + “提取后半部分”
  • 中文字体——必须在调用任何 matplotlib 函数前设置,否则输出会乱码
  • 超时——处理单张图像约需 10–30 秒,批处理时应相应设置超时时间

评论

支持 Markdown