npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

inter-eval

v1.4.0

Published

Interactive evaluation pipeline for AI-generated data visualization pages

Readme

inter-eval

交互式数据可视化页面自动化评测工具。基于 Playwright 对 AI 生成的单页 HTML 页面进行交互功能评测,覆盖按钮点击、滑块拖拽、下拉选择、Tab 切换、模态弹窗、Canvas/Three.js 3D 交互等 10 种交互类型,支持 SVG/CSS/JS 动画的时间序列截图评测,产出结构化评测报告。

快速开始

环境要求:Node.js >= 22

1. 安装

npm install -g inter-eval

2. 运行评测

inter-eval run dataset/query.csv

支持 CSV 和 JSONL 两种数据格式,通过文件扩展名自动识别。首次运行时会自动检测并安装 Chromium 浏览器引擎,无需手动操作。评测完成后打开 output/report.html 查看报告。

免安装使用

不想全局安装也可以通过 npx 直接运行:

npx inter-eval run dataset/query.csv

数据格式

支持 CSV 和 JSONL(每行一个 JSON 对象),通过文件扩展名自动识别。

| 字段 | 必须 | 说明 | |------|------|------| | task_id | | 任务唯一标识(数字或字符串,如 base64) | | result | 否* | Markdown 文本,包含 ```html 代码块,工具会自动提取其中的 HTML | | url | 否* | 外部页面 URL,当 result 无法提取有效 HTML 时自动回退使用 |

*resulturl 至少提供一个。优先使用 result 中提取的 HTML;提取失败时检查 url 字段,若为合法 http/https 地址则直接访问该 URL 进行评测。

最小可用示例(JSONL):

{"task_id": 14794, "result": "```html\n<div>hello</div>\n```"}
{"task_id": 14795, "url": "https://example.com/page"}

使用示例

# 评测指定任务
inter-eval run data.csv --task-id 14794,3035

# 使用 JSONL 格式数据
inter-eval run data.jsonl --task-id 14794

# 评测外部 URL(数据集中配置 url 字段)
inter-eval run urls.jsonl --headed

# 只处理前 100 条记录
inter-eval run data.jsonl --limit 100

# 从第 200 条开始,处理 50 条
inter-eval run data.jsonl --start 200 --limit 50

# 清理上次输出 + 重跑
inter-eval run data.csv --clean

# 断点续跑时复用已有的 test-pages(跳过 HTML 生成)
inter-eval run data.jsonl -o output_0615 --reuse-test-pages

# 有头模式(打开浏览器窗口,方便调试)
inter-eval run data.csv --headed

# 自定义输出目录和配置文件
inter-eval run data.csv -o ./results --config my-config.json

# 后台运行(nohup)
nohup inter-eval run data.jsonl --limit 500 > eval.log 2>&1 &

# 生成默认配置文件(可选)
inter-eval init

# 生成 3D 场景配置
inter-eval init 3d

# 生成游戏场景配置
inter-eval init game

# 生成动画评测配置(Timeline 模式)
inter-eval init timeline

# Timeline 模式:按时间序列截图评测 SVG/CSS/JS 动画
inter-eval run data.jsonl --timeline 0,500,1000,2000,3000

# Timeline + AI 动画判断
inter-eval run data.jsonl --timeline 0,500,1000,2000,3000 --ai

CLI 参考

| 命令 | 说明 | |------|------| | inter-eval run [dataset] [options] | 执行评测流水线 | | inter-eval retest [options] | 对已有结果进行复测 | | inter-eval report [options] | 从 results.jsonl 重新生成统计报告 | | inter-eval init [mode] | 在当前目录生成配置 .interevalrc.json(mode: website/3d/game/timeline,默认 website) | | inter-eval --version | 显示版本号(同时检查更新) | | inter-eval --help | 显示帮助信息 |

run 参数

| 参数 | 说明 | |------|------| | [dataset] | 数据文件路径,支持 CSV 和 JSONL(默认 ./dataset/query.csv)。当 result 无有效 HTML 时回退使用 url 字段 | | --task-id, -t | 逗号分隔的 task_id,只评测指定任务 | | --start | 起始记录位置(默认 0),跳过前 n 条有效记录 | | --limit | 最多处理的记录条数(大文件分批评测) | | --clean | 清理输出目录后重新运行 | | --reuse-test-pages | 复用已有的 test-pages/ 目录,跳过 HTML 文件生成(适合断点续跑、仅改配置重跑) | | --headed | 有头模式运行浏览器 | | --timeline | 启用 Timeline 模式,逗号分隔的毫秒时间点(如 0,500,1000,2000,3000)。动画按时间序列截图,而非交互驱动截图 | | --output-dir, -o | 输出目录(默认 ./output) | | --config | 配置文件路径(默认自动查找) |

report 参数

| 参数 | 说明 | |------|------| | --input, -i | 输入的 jsonl 文件路径(默认 ./output/results.jsonl) | | --output-dir, -o | 输出目录(默认 ./output) | | --config | 配置文件路径(影响评分权重和忽略规则) |

retest 参数

| 参数 | 说明 | |------|------| | --failed | 复测所有失败的任务(TIMEOUT / 加载失败 / 交互失败) | | --task-id, -t | 逗号分隔的 task_id,指定要复测的任务 | | --score-below | 复测总分低于指定值的任务 | | --append | 追加到已有 results-retest.jsonl(默认覆盖) | | --headed | 有头模式运行浏览器 | | --output-dir, -o | 输出目录(默认 ./output,test-pages 和 results.jsonl 从此目录读取) | | --config | 配置文件路径(默认自动查找) |

环境变量

| 变量 | 说明 | |------|------| | AISTUDIO_PROXY_ADDR | AIStudio 代理地址。设置后启用 AIStudio 模式:HTTP server 使用代理地址对外暴露、CDN 预热使用全并发(而非本地的 4 并发)、CDN 缓存走 route intercept 模式。本地运行时无需配置,仅在 AIStudio 环境中设置(如 http://proxy.aistudio:8080) | | HTTPS_PROXY / HTTP_PROXY | 标准代理环境变量,Playwright 浏览器实例会自动使用。AIStudio 环境通常已预设,本地无需配置 |

AI 增强配置

AI 功能需要通过 --ai 参数显式启用:

# 启用 AI 增强评测
inter-eval run data.jsonl --ai

# 不传 --ai 则使用规则评测(默认)
inter-eval run data.jsonl

AI 的 API 配置通过配置文件或环境变量提供(环境变量优先级高于配置文件):

配置文件方式.interevalrc.json):

{
  "ai": {
    "apiKey": "your-key",
    "endpoint": "",
    "apiPath": "/v1/chat/completions",
    "model": "deepseek-v4-pro",
    "visualJudgeMode": "all"
  }
}

环境变量方式(覆盖配置文件中的同名字段):

| 变量 | 配置字段 | 默认值 | 说明 | |------|----------|--------|------| | AI_API_KEY | ai.apiKey | — | API Key(必需) | | AI_API_ENDPOINT | ai.endpoint | https://api.deepseek.com | API 地址(兼容 OpenAI 协议的任意服务) | | AI_API_PATH | ai.apiPath | /v1/chat/completions | API 路径 | | AI_MODEL | ai.model | deepseek-v4-pro | 模型名称(如 qwen-vl-maxgpt-4o 等) | | AI_VISUAL_JUDGE_MODE | ai.visualJudgeMode | all | 视觉判定策略:all(全量 AI 判定)/ fail_only(仅复核 FAIL)/ none(禁用) |

AI 增强功能:

| 功能 | 触发条件 | 说明 | |------|----------|------| | 视觉变化判定 | 交互产生截图后 | AI 判断交互是否产生有意义的视觉变化,避免 pixelmatch 误判 | | 渲染质量评估 | baseline 截图完成后 | 检测白屏、布局错乱、CSS 丢失等渲染问题 | | 交互优先级选择 | 元素发现后 | AI 从候选池中选择最有价值的交互元素 | | 错误分类 | 检测到 JS 错误时 | 区分致命错误/警告/噪声,只有致命错误影响评分 | | 页面类型识别 | baseline 完成后 | 自动识别 website/3d/game |

# 示例:配置文件有 apiKey,通过 --ai 启用
inter-eval run data.jsonl --ai

# 示例:环境变量覆盖 + 启用 AI
AI_API_KEY="your-key" AI_API_ENDPOINT="https://antchat.alipay.com" \
inter-eval run data.jsonl --ai

# 对比跑法
inter-eval run data.jsonl -o output_rule
inter-eval run data.jsonl --ai -o output_ai

配置

配置文件查找顺序

未指定 --config 时,按以下顺序自动查找:

  1. 当前目录下的 .interevalrc.json
  2. 当前目录下的 config/thresholds.json
  3. 全部不存在则使用内置默认值

运行 inter-eval init 可生成完整默认配置,按需修改即可。

常用配置项

| 参数 | 默认值 | 说明 | |------|--------|------| | diffThreshold | 0.001 | 视觉变化阈值(0.1% 像素差异即认为有变化) | | threeJsDiffThreshold | 0.005 | Canvas/3D 放宽阈值(0.5%),仅用于 canvas_interact | | loadTimeoutMs | 15000 | 页面加载超时(ms) | | taskTimeoutMs | 60000 | 单任务总超时(ms) | | maxRetries | 2 | 超时任务的最大重试次数 | | batchSize | 0 | 分批大小(0 = 不分批)。每批完成后重启浏览器回收内存,大数据集建议设为 500 | | maxTopInteractions | 3 | 配额补充阶段的交互数上限 | | maxInteractionsPerTask | 30 | 单任务最大交互数(硬上限) | | concurrency | 0 | 并行数(0 = 自动取 CPU 核数 / 2) | | freezeAnimations | — | 截图前动画冻结策略:"full"(冻结 CSS + rAF + timers)/ "css_only"(仅冻结 CSS 动画)/ "none"(不冻结)。不设置时自动检测(有 Canvas 交互用 css_only,否则用 full) | | excludedTypes | [] | 排除的交互类型,如 ["range_sweep"] | | ignoredErrors | [] | 忽略的 JS 错误(匹配子串) | | ignoredCdnPatterns | ["cdn.tailwindcss.com"] | 忽略的 CDN 域名(不计入加载失败) | | screenshotFormat | "jpeg" | 截图格式:"jpeg"(体积更小,quality=80)或 "png"(无损) | | keepSuccessScreenshots | true | 是否保留成功任务的截图。设为 false 可在每批次完成后自动清理,节省 NAS 空间 |

完整配置项参见 inter-eval init 生成的默认文件,或查看 开发文档

交互覆盖配置

对特殊页面可通过 interactions 字段手动指定交互(与自动发现互补):

{
  "excludedTypes": ["range_sweep"],
  "concurrency": 3,
  "interactions": {
    "14794": {
      "threejs_orbit": {
        "type": "canvas_interact",
        "selector": "canvas",
        "actions": [
          { "type": "drag", "from": [500, 300], "to": [600, 400] }
        ]
      }
    }
  }
}

输出

| 文件 | 说明 | |------|------| | output/report.html | 评测概览页(评分分布、错误汇总) | | output/reports/task_{id}.html | 单任务详情页(交互明细、截图对比) | | output/results.json | 结构化评测结果 | | output/results.jsonl | 增量结果(支持断点续跑) | | output/results-retest.jsonl | 复测结果(由 retest 命令生成) | | output/errors.json | 异常详情 | | output/test-pages/ | 提取的 HTML 页面(URL 模式下不生成) | | output/screenshots/ | 交互前后截图 | | output/diffs/ | 视觉 diff 热力图 | | output/logs/ | 控制台日志 |

结果判断

判断任务是否完全通过

const isFullyPassed = r.baseline.loaded
  && r.baseline.issues.length === 0
  && (r.interactions.length === 0 || r.interactions.every(i => i.passed));

| 条件 | 含义 | |------|------| | baseline.loaded | 页面加载成功 | | baseline.issues.length === 0 | 无框架级异常(超时、加载失败等) | | interactions.every(i => i.passed) | 所有交互都有视觉反馈且无异常 |

如果还需排除伴随 console.error 的交互(更严格):

&& r.interactions.every(i => i.passed && !i.warning)

关键字段说明

| 字段 | 含义 | |------|------| | baseline.issues | 框架级问题(加载失败、超时、viewport 溢出) | | baseline.consoleEntries | 页面自身 JS 的 console 输出(不影响 loaded 判定) | | baseline.pageErrors | 页面未捕获异常(uncaught exception) |

评分规则

每个任务的总分 overall(0-100)由两个维度加权计算:

overall = (基础可用性 × W1 + 交互功能 × W2) × 100

默认权重:W1=0.5, W2=0.5,可通过 scoring 配置修改。

1. 基础可用性(basicAvailability,0-1)

四项检查,通过得对应权重,不通过得 0:

| 检查项 | 配置字段 | 默认权重 | 判定逻辑 | |--------|----------|----------|----------| | 页面加载成功 | loadedWeight | 0.4 | baseline.loaded === true | | 无 JS 错误 | noJsErrorsWeight | 0.35 | 页面无 uncaught exception 且无 console.error(过滤 ignoredErrors 后) | | 内容适配视口 | fitsViewportWeight | 0.1 | 页面内容未超出 viewport 边界 | | 关键资源无 404 | noResourceErrorsWeight | 0.15 | script/stylesheet 资源全部加载成功(过滤 ignoredCdnPatterns 后) |

四项权重之和应为 1.0。

2. 交互功能(interactionFunctionality,0-1)

交互功能 = 通过的交互数 / 已测试的交互总数
  • 跳过的交互(skipped)不计入分母
  • 无交互元素时为 0

判定标准:

| 结果 | 条件 | |------|------| | PASS | 交互产生了超过阈值的视觉变化(visualChangeRatio > diffThreshold)且无异常 | | WARN | 交互有视觉变化但伴随 console.error | | FAIL | 交互无视觉变化 / 触发 JS 异常 / 元素不可交互 |

评分配置示例

{
  "scoring": {
    "basicAvailabilityWeight": 0.5,
    "interactionFunctionalityWeight": 0.5,
    "loadedWeight": 0.4,
    "noJsErrorsWeight": 0.35,
    "fitsViewportWeight": 0.1,
    "noResourceErrorsWeight": 0.15
  }
}

report 命令会使用当前配置重新计算分数,因此修改权重后运行 inter-eval report 即可刷新报告,无需重跑评测。

断点续跑

评测中断后再次运行会自动跳过已完成的 task(通过 results.jsonl 识别)。超时(TIMEOUT)的任务不视为已完成,会在下次运行时重新评测。如需全新重跑,使用 --clean

复测

评测完成后,可使用 retest 命令对部分任务进行复测,无需重新解析原始 dataset,直接复用 test-pages/ 中已有的 HTML 文件。复测结果写入独立的 results-retest.jsonl,不影响原始 results.jsonl

# 复测所有失败的任务
inter-eval retest --failed

# 复测指定任务
inter-eval retest -t 14794,3035

# 复测总分低于 60 的任务
inter-eval retest --score-below 60

# 组合使用:失败 + 低分
inter-eval retest --failed --score-below 60

# 追加模式(多次复测结果累积)
inter-eval retest --failed --append

# 指定其他输出目录
inter-eval retest --failed -o ./my-output

默认覆盖模式下,复测使用临时文件写入,全部完成后原子替换 results-retest.jsonl。即使复测中途出错,旧的结果文件也不会丢失。

生成报告

无需重跑评测,直接从 results.jsonl 重新生成统计报告(report.htmlresults.jsonerrors.json 及 per-task 详情页)。适用于手动修改了 jsonl 数据后需要刷新报告的场景。

# 从默认 output/results.jsonl 生成
inter-eval report

# 从 retest 结果生成
inter-eval report -i output/results-retest.jsonl

# 指定输出目录和配置
inter-eval report -i data.jsonl -o ./reports --config my.json

超时自动重试

在代理网络环境下,外部 CDN 资源偶发不可达可能导致个别任务超时。Pipeline 会在所有任务完成后,自动串行重试超时的任务(最多 maxRetries 次,默认 2 次),避免因偶发网络问题导致评测结果缺失。

大数据集

处理万级数据集(如 2W 条)时,建议配置 batchSize 进行分批处理:

{
  "batchSize": 500,
  "concurrency": 4,
  "taskTimeoutMs": 120000
}

分批处理会在每批完成后重启浏览器实例回收内存,防止长时间运行导致内存泄漏。Pipeline 会在 HTML 文件写入磁盘后立即释放内存中的 HTML 内容,评测结果以增量方式写入 results.jsonl 而非在内存中累积。

降低磁盘占用

大数据集评测会产生大量截图和 diff 文件,NAS 等共享存储容易占满。可通过以下配置减少磁盘使用:

{
  "screenshotFormat": "jpeg",
  "keepSuccessScreenshots": false
}
  • screenshotFormat: "jpeg":截图改用 JPEG 格式(quality=80),单张体积比 PNG 小 5-10 倍,尤其适合不需要像素级精度的场景
  • keepSuccessScreenshots: false:每批次完成后自动删除已成功任务的 screenshots/diffs/ 目录,只保留失败/超时任务的截图用于排查

两个选项可组合使用,对 2W 条数据的评测任务预计可节省 90%+ 的存储空间。

Timeline 模式(动画评测)

对于自动播放的 SVG/CSS/JS 动画(无需点击即可运动),传统交互驱动截图无法捕获动画过程。Timeline 模式按配置的时间点拍摄帧序列,通过相邻帧像素差异和 VLM 语义判断来评估动画合理性。

快速开始

# CLI 方式:在 0ms、500ms、1s、2s、3s 时刻截图
inter-eval run data.jsonl --timeline 0,500,1000,2000,3000

# 配合 AI 进行动画整体合理性判断
inter-eval run data.jsonl --timeline 0,500,1000,2000,3000 --ai

# 生成 timeline 专用配置
inter-eval init timeline

配置方式

除 CLI --timeline 参数外,也可在配置文件中设置(两种方式等效,CLI 优先级更高):

{
  "timeline": {
    "timePointsMs": [0, 500, 1000, 2000, 3000],
    "minFrameChangeRatio": 0.001,
    "aiAnimationJudge": true
  }
}

| 字段 | 默认值 | 说明 | |------|--------|------| | timePointsMs | — | 页面加载后的截图时间点(ms),非空时启用 timeline 模式 | | minFrameChangeRatio | 0.001 | 相邻帧最小像素变化率,低于此值视为无动画(帧判定 FAIL) | | aiAnimationJudge | true | 启用 AI 时是否对帧序列做整体动画合理性判断 |

工作原理

  1. 页面正常加载并拍摄 baseline 截图
  2. 不冻结动画,按 timePointsMs 的时间点依次截图
  3. 每帧与前一帧做 pixelmatch 像素对比,生成 diff 热力图
  4. 若启用 AI(--ai),将所有帧截图送入 VLM 做整体动画合理性判断
  5. AI 判断 coherent 且有像素变化的帧标记为 PASS

与交互模式的关系

  • 同一任务中 timeline 模式和交互模式互斥:有 timeline 配置时跳过交互元素发现和执行
  • 若需要对部分任务用交互模式、部分用 timeline 模式,可在 interactions 覆盖配置中通过 "__timeline": { "skip": true } 让指定任务回退到交互模式

报告展示

Timeline 任务的详情页展示 filmstrip 视图:

  • 帧序列:横向排列所有帧缩略图,标注时间
  • Diff 热力图:相邻帧差异的红/绿可视化
  • 像素变化率柱状图:展示各帧间变化趋势
  • 动画整体评判(AI 模式):coherent/incoherent + 置信度 + 原因

Programmatic API

除 CLI 外,inter-eval 也可作为 Node.js 模块在代码中直接调用:

import { run } from 'inter-eval';

const { report, results, outputDir, durationMs } = await run({
  csvPath: './data.jsonl',
  taskIds: null,
  clean: false,
  headed: false,
  outputDir: './output',
  configPath: null,
});

// 聚合报告
console.log(`平均分: ${report.summary.averageOverallScore}`);
console.log(`通过率: ${report.summary.totalTasksClean} / ${report.totalTasks}`);

// 逐任务结果
for (const r of results) {
  if (r.scores.overall < 60) {
    console.log(`低分任务: ${r.taskId} (${r.scores.overall})`);
  }
}

返回值

run() 返回 RunResult 对象:

| 字段 | 类型 | 说明 | |------|------|------| | report | EvalReport | 聚合报告(平均分、通过率、错误统计等) | | results | TaskEvalResult[] | 每个任务的详细评测结果 | | outputDir | string | 输出目录绝对路径 | | durationMs | number | 评测总耗时(ms) |

retest() 同样返回 RunResult

导出的类型

import type {
  RunResult,          // run()/retest() 返回值
  RunOptions,         // run() 参数
  RetestOptions,      // retest() 参数
  TaskEvalResult,     // 单任务评测结果
  EvalReport,         // 聚合报告
  BaselineResult,     // 页面加载结果
  InteractionResult,  // 交互测试结果
  TaskScores,         // 评分明细
} from 'inter-eval';

开发

项目内开发参见 开发文档

git clone <repo-url> && cd inter-eval
pnpm install
npx playwright install chromium

pnpm start                    # 运行评测
pnpm test                     # 单元测试
pnpm build                    # 构建
pnpm serve                    # 查看报告