🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

视频网格理解 yangjili6/video-understanding-kit

DeepSeek Harness
yangjili65 天前有提交已提供中文文档扫描:含敏感能力

把视频切成带时间戳的网格图,让 AI 省 token 看懂画面

30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add yangjili6/video-understanding-kit
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么[目录]—
dsh 原生插件 · market
暂无时间戳·判据 →
装得上吗[实装验证]—
本站尚未做安装检查
暂无时间戳·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/03·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 5 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 99 处,展示前 62 条)
  • 写入本地文件
    asr.mjs:52
    mkdirSync(join(outWav, '..'), { recursive: true })
  • 执行外部命令固定命令
    asr.mjs:53
    execFileSync('ffmpeg', ['-hide_banner', '-loglevel', 'error', '-i', video, '-vn', '-ac', '1', '-ar', '16000', '-c:a', 'pcm_s16le', outWav, '-y'])
  • 执行外部命令固定命令
    asr.mjs:65
    const r = spawnSync('ffmpeg', ['-hide_banner', '-i', wav, '-af', filter, '-f', 'null', '-'], { encoding: 'utf8' })
  • 写入本地文件
    download-models.mjs:10
    mkdirSync(MODEL_DIR, { recursive: true })
  • 读取本地文件
    download-models.mjs:21
    if (existsSync(dest) && statSync(dest).size === f.size) {
  • 读取本地文件
    download-models.mjs:21
    if (existsSync(dest) && statSync(dest).size === f.size) {
  • 发起网络请求
    download-models.mjs:26
    const res = await fetch(f.url)
  • 写入本地文件
    download-models.mjs:28
    await pipeline(res.body, createWriteStream(dest))
  • 读取本地文件
    download-models.mjs:29
    const actual = statSync(dest).size
  • 发起网络请求
    dsh-plugin/client.js:87
    const res = await fetch(API + path, {
  • 读取本地文件
    dsh-plugin/index.js:74
    for (const c of candidates) if (existsSync(c)) return c
  • 执行外部命令来自配置/变量
    dsh-plugin/index.js:179
    const res = spawnSync(cmd, ['--version'], {
  • 读取本地文件
    dsh-plugin/index.js:210
    ok = existsSync(p) && statSync(p).size === f.size
  • 读取本地文件
    dsh-plugin/index.js:210
    ok = existsSync(p) && statSync(p).size === f.size
  • 写入本地文件
    dsh-plugin/index.js:242
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    dsh-plugin/index.js:246
    if (!existsSync(pkgFile)) {
  • 写入本地文件
    dsh-plugin/index.js:247
    writeFileSync(
  • 执行外部命令来自配置/变量
    dsh-plugin/index.js:268
    const child = spawn(pm, installArgs, {
  • 写入本地文件
    dsh-plugin/index.js:299
    const ws = createWriteStream(dest)
  • 写入本地文件
    dsh-plugin/index.js:325
    const ws = createWriteStream(dest)
  • 写入本地文件
    dsh-plugin/index.js:376
    const ws = createWriteStream(dest)
  • 读取本地文件
    dsh-plugin/index.js:377
    for (const p of parts) await pipeline(createReadStream(p.file), ws, { end: false })
  • 删除本地文件
    dsh-plugin/index.js:379
    for (const p of parts) rmSync(p.file, { force: true })
  • 删除本地文件
    dsh-plugin/index.js:382
    for (const p of parts) rmSync(p.file, { force: true })
  • 删除本地文件
    dsh-plugin/index.js:383
    rmSync(dest, { force: true })
  • 写入本地文件
    dsh-plugin/index.js:401
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    dsh-plugin/index.js:411
    have = existsSync(dest) && statSync(dest).size === f.size
  • 删除本地文件
    dsh-plugin/index.js:454
    rmSync(tmp, { force: true })
  • 删除本地文件递归
    dsh-plugin/index.js:472
    rmSync(dir, { recursive: true, force: true })
  • 删除本地文件
    dsh-plugin/index.js:475
    for (const f of assetFiles(target)) rmSync(join(dir, f.name), { force: true })
  • 发起网络请求
    dsh-plugin/index.js:612
    return await fetch(url, { ...options, signal: AbortSignal.timeout(timeoutMs) })
  • 执行外部命令来自配置/变量
    dsh-plugin/index.js:803
    const child = spawn(process.execPath, args, {
  • 执行外部命令来自配置/变量
    dsh-plugin/index.js:1073
    const c = spawn(ffmpegBin, ffArgs, { stdio: ['ignore', 'ignore', 'pipe'] })
  • 读取本地文件
    lib/ocr-pp.mjs:20
    const dictText = readFileSync(join(APP_DIR, 'models/ppocr_keys_v1.txt'), 'utf8')
  • 读取本地文件
    lib/ocr-pp.mjs:28
    const detModel = readFileSync(join(APP_DIR, 'models/ch_PP-OCRv4_det_infer.onnx'))
  • 读取本地文件
    lib/ocr-pp.mjs:30
    const recModel = readFileSync(join(APP_DIR, 'models/ch_PP-OCRv4_rec_infer.onnx'))
  • 执行外部命令固定命令
    lib/ocr-pp.mjs:38
    const buf = execFileSync('convert', [path, '-resize', `${outW}x${outH}!`, '-depth', '8', 'rgb:-'], { maxBuffer: 128 * 1024 * 1024 })
  • 执行外部命令固定命令
    lib/ocr-pp.mjs:43
    const out = execFileSync('identify', ['-format', '%w %h', path], { encoding: 'utf8' })
  • 执行外部命令固定命令
    lib/ocr-pp.mjs:174
    const buf = execFileSync('convert', [path, '-crop', `${box.x1 - box.x0 + 1}x${box.y1 - box.y0 + 1}+${box.x0}+${box.y0}`, '+repage', '-resize', `${w}x$
  • 执行外部命令来自配置/变量
    lib/transnet-lib.mjs:13
    const run = (c, a, o = {}) => execFileSync(c, a, { encoding: 'utf8', maxBuffer: 512 * 1024 * 1024, stdio: ['ignore', 'pipe', 'pipe'], ...o })
  • 读取本地文件
    lib/transnet-lib.mjs:19
    if (!session) session = await ort.InferenceSession.create(readFileSync(join(APP, 'models/transnetv2.onnx')), { executionProviders: ['wasm'] })
  • 读取本地文件
    pipeline.mjs:37
    if (!VIDEO || !existsSync(VIDEO)) {
  • 执行外部命令来自配置/变量
    pipeline.mjs:58
    execFileSync(cmd, argv, { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, stdio: ['ignore', 'pipe', 'pipe'], ...opts })
  • 写入本地文件
    pipeline.mjs:79
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    pipeline.mjs:84
    return readdirSync(dir).filter((f) => f.endsWith('.jpg')).sort().map((f, i) => {
  • 执行外部命令固定命令
    pipeline.mjs:101
    const child = spawn('ffmpeg', args, { stdio: ['ignore', 'pipe', 'pipe'] })
  • 读取本地文件
    pipeline.mjs:191
    const raw = JSON.parse(readFileSync(CUES_FILE, 'utf8'))
  • 写入本地文件
    pipeline.mjs:209
    mkdirSync(dir, { recursive: true })
  • 执行外部命令固定命令
    pipeline.mjs:301
    const r = spawnSync('compare', ['-metric', 'RMSE', a.file, b.file, 'null:'], { encoding: 'utf8' })
  • 写入本地文件
    pipeline.mjs:424
    mkdirSync(join(OUT, 'grids'), { recursive: true })
  • 读取本地文件
    pipeline.mjs:491
    if (existsSync(OUT)) {
  • 读取本地文件
    pipeline.mjs:492
    const st = lstatSync(OUT)
  • 删除本地文件递归
    pipeline.mjs:495
    rmSync(OUT, { recursive: true, force: true })
  • 读取本地文件
    pipeline.mjs:496
    } else if (readdirSync(OUT).length > 0) {
  • 写入本地文件
    pipeline.mjs:500
    mkdirSync(join(OUT, 'grids'), { recursive: true })
  • 写入本地文件
    pipeline.mjs:621
    writeFileSync(join(OUT, 'index.json'), JSON.stringify(index, null, 2))
  • 读取本地文件
    serve-preview.mjs:27
    const idx = JSON.parse(readFileSync(join(ROOT, 'index.json'), 'utf8'))
  • 读取本地文件
    serve-preview.mjs:104
    if (!isInside(rootReal, fileReal) || !statSync(fileReal).isFile()) return sendNotFound(res)
  • 读取本地文件
    serve-preview.mjs:108
    const body = readFileSync(fileReal)
  • 执行外部命令来自配置/变量
    subs.mjs:7
    const run = (c, a, o = {}) => execFileSync(c, a, { encoding: 'utf8', maxBuffer: 256 * 1024 * 1024, stdio: ['ignore', 'pipe', 'pipe'], ...o })
  • 写入本地文件
    subs.mjs:62
    mkdirSync(frameDir, { recursive: true })
  • 读取本地文件
    subs.mjs:70
    const files = readdirSync(frameDir).filter((f) => f.endsWith('.jpg')).sort()
扫描于 2026/11/3(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
展开完整介绍(270 字)↓

目前是手机DSH专用,如果效果好的话未来会考虑多端;这个工具不同于传统的AI理解视频流程(定时切帧-切出的帧猜测上下文),而是以5FPS一帧来尽可能获取视频的完全内容,再以网格的形式存入每一帧;网格使用预训练模型进行分组(相同的场景/内容会尽可能在一个网格大组中),这样你的AI在使用了这个插件/工具后能够更好的形容看到的视频,并且不会花什么token;不过由于技术原因,我目前还无法优化完成这个流程所需要的时长(中端手机在OCR与ASR全开启的情况下让AI完成一个这样的工作流时长需要原视频的1.5倍~3倍左右),这是这个工具最大的痛点。

README

由 DeepSeek 最新模型翻译生成
Video Understanding Kit 面向 DSH 手机版的网格法视频理解工具包。 它把视频整理成带时间戳的采样帧、镜头分组、网格图,以及可选的字幕和语音转写,方便 AI 先快速浏览,再按时间回查证据。 本项目依赖 DSH 手机版的工具链与目录约定。桌面、服务器和其他 Android 环境尚未验证。使用它的 AI 助手需要支持图像输入。 设计与实验记录(ADR、对照实验数据、复现命令)在 docx/。 工作流程 Video Understanding Kit 工作流程 网格适合快速浏览和定位;需要确认小字、细节动作或不确定内容时,再打开对应页面或原始帧。镜头边界与画面变化用于时间导航,不代表语义场景或完整事件划分。 能力一览 - 镜头分组与网格:抽取带时间戳的基础帧,检测镜头边界,生成网格页和组级导航图。 - 字幕识别(可选):PP-OCRv4 提取画面文字,输出带时间的候选文本和疑点标记。 - 语音识别(可选):使用 sherpa-onnx 本地识别语音,生成带时间戳的转写候选。 - 证据回查:通过 index.json 中的时间戳、帧 ID 和页面关联,定位网格页或原始帧。 - DSH 插件(可选):dsh-plugin/ 提供 video_analyze 和 video_frame 两个工具,详见 插件说明。
展开完整文档(README 剩余 1 节)
Video Understanding Kit

面向 DSH 手机版的网格法视频理解工具包。 它把视频整理成带时间戳的采样帧、镜头分组、网格图,以及可选的字幕和语音转写,方便 AI 先快速浏览,再按时间回查证据。

本项目依赖 DSH 手机版的工具链与目录约定。桌面、服务器和其他 Android 环境尚未验证。使用它的 AI 助手需要支持图像输入。

设计与实验记录(ADR、对照实验数据、复现命令)在 docx/。

工作流程

Video Understanding Kit 工作流程

网格适合快速浏览和定位;需要确认小字、细节动作或不确定内容时,再打开对应页面或原始帧。镜头边界与画面变化用于时间导航,不代表语义场景或完整事件划分。

能力一览

- 镜头分组与网格:抽取带时间戳的基础帧,检测镜头边界,生成网格页和组级导航图。
- 字幕识别(可选):PP-OCRv4 提取画面文字,输出带时间的候选文本和疑点标记。
- 语音识别(可选):使用 sherpa-onnx 本地识别语音,生成带时间戳的转写候选。
- 证据回查:通过 index.json 中的时间戳、帧 ID 和页面关联,定位网格页或原始帧。
- DSH 插件(可选):dsh-plugin/ 提供 video_analyze 和 video_frame 两个工具,详见 插件说明。

安装

运行环境:DSH 手机版、Node.js 20 或更新版本、ffmpeg、ImageMagick。

在项目目录安装依赖并下载模型:

pnpm install
node download-models.mjs

模型下载脚本获取 TransNetV2 与 PP-OCRv4 模型,约 47 MB。OCR 和镜头检测通过 onnxruntime-web 运行。

可选:语音识别

--asr 需要 sherpa-onnx 运行时和中文 Paraformer 模型,模型约 217 MB,不包含在上述 47 MB 中。安装方法见 sherpa-onnx 和 asr.mjs 顶部说明。未安装时请不要传入 --asr;基础分组、网格和字幕功能不受影响。

使用

镜头分组与网格
node pipeline.mjs --video video.mp4 --out out

同时提取画面字幕
node pipeline.mjs --video video.mp4 --out out --subs

同时进行语音识别(需安装 sherpa-onnx 和模型)
node pipeline.mjs --video video.mp4 --out out --asr

按需同时启用字幕提取和语音识别
node pipeline.mjs --video video.mp4 --out out --subs --asr

启动本地预览服务
node serve-preview.mjs out # 默认读取 ./out;也可传入其他输出目录
浏览器打开 http://127.0.0.1:3329

输出文件

out/
├── index.json # 分组、网格页、OCR/ASR 候选与镜头边界索引 ├── base/ # 基础采样帧 ├── extra/ # 候选窗口的补充回看帧 ├── grids/ # 网格页与组级导航图 ├── subs/ # OCR 中间帧(启用 --subs 时) └── audio/ # ASR 音频(启用 --asr 时)

index.json 常用字段:

| 字段 | 内容 |
| groups[] | 内容组的起止时间、网格页和导航图 |
| groups[].pages[].frames[] | 每个网格格子的时间戳、源帧 ID 与提取 ID |
| subs[] | OCR 字幕候选;review 用于标记建议核验的条目 |
| candidates[] | cues/ASR 候选及回看状态 |
| boundaries[] | 分组边界类型及左右组、边界帧关系 |

OCR 与 ASR 的结果都是识别候选,不应直接视为准确字幕或完整语音记录。关键文字、数字和台词请结合原帧或音频核验。

参数

| 参数 | 默认值 | 说明 |
| --video | — | 输入视频路径 |
| --out | — | 输出目录 |
| --subs | 关闭 | 提取画面字幕(PP-OCRv4) |
| --asr | 关闭 | 识别语音(sherpa-onnx) |
| --base-fps | 5 | 基础采样帧率 |
| --diff-threshold | 8 | 补帧用的帧差阈值 |
| --page-scale | 1.8 | 网格页面缩放比例 |
| --force | 关闭 | 允许清空并覆盖已有输出目录 |

环境变量:SUBS_SKIP_TH 控制字幕跳帧阈值(默认 3.0);DET_MAX_SIDE 控制 OCR 检测图像长边上限(默认 720)。

模型与许可

| 模型 | 来源 | 许可 |
| TransNetV2 | soCzech/TransNetV2,ONNX 转换版来自 elya5/transnetv2 | MIT |
| PP-OCRv4 检测与识别模型 | PaddleOCR,ONNX 模型由 RapidOCR 提供 | Apache-2.0 |
| PP-OCR 字典 | PaddleOCR | Apache-2.0 |
| sherpa-onnx(可选 ASR) | k2-fsa/sherpa-onnx | Apache-2.0 |

使用前请核对各模型及其权重在目标场景下的许可条款。

已知限制

- 采样可能漏掉极短的动作、镜头或字幕。
- OCR 可能误识艺术字、生僻字或低清文字;高置信度结果也需要核验。
- ASR 可能误识同音词和专名,也不能可靠判断说话人归属。
- 处理耗时会随设备性能、视频分辨率和启用的 OCR/ASR 选项明显变化;单次测试数据见 插件实测记录,不应视为普遍性能保证。

给 AI 助手的使用提示

请参阅 PROMPT.md。核心原则是:先读索引、按网格浏览;遇到不确定内容时回查对应帧或音频,并区分观察结果与推测。
预览分享卡片长什么样 ↓yangjili6/video-understanding-kit
分享 · DeepSeek Harness Hub
yangjili6/video-understanding-kit

把视频切成带时间戳的网格图,让 AI 省 token 看懂画面

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部