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

本地音视频观察 ck99998888/dsh-video-reader

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

让智能体看视频听音频并观察实时桌面

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

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

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

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · desktop
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 10 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 85 处,展示前 69 条)
  • 读取本地文件
    index.js:281
    const data = new Uint8Array(await readFile(entry.path))
  • 写入本地文件
    index.js:329
    await mkdir(framesDir, { recursive: true })
  • 写入本地文件
    index.js:478
    await writeFile(srtPath, srtText, 'utf8')
  • 写入本地文件
    index.js:479
    await writeFile(path.join(dir, 'transcript.txt'), speakerLines.join('\n'), 'utf8')
  • 写入本地文件
    index.js:549
    await mkdir(framesDir, { recursive: true })
  • 写入本地文件
    index.js:609
    await mkdir(dir, { recursive: true })
  • 写入本地文件
    index.js:624
    await writeFile(manifestPath, `${JSON.stringify({ createdAt: Date.now(), fps, seconds, region: plan.label, width, frames: framePaths }, null, 2)}\n`,
  • 读取本地文件
    index.js:669
    const raw = await readFile(manifestPath, 'utf8').catch(() => undefined)
  • 读取本地文件
    index.js:1378
    const data = await readFile(target)
  • 发起网络请求
    client.js:314
    fetch(`${API}/settings`, { headers: { accept: 'application/json' } })
  • 发起网络请求
    client.js:327
    fetch(`${API}/deps/status`, { cache: 'no-store' })
  • 发起网络请求
    client.js:340
    const response = await fetch(`${API}/deps/install`, {
  • 发起网络请求
    client.js:376
    const response = await fetch(`${API}/settings`, {
  • 发起网络请求
    client.js:397
    const response = await fetch(`${API}/preview?t=${Date.now()}`, { cache: 'no-store' })
  • 发起网络请求
    client.js:415
    fetch(`${API}/watch/status`).then((response) => response.json())
  • 读取本地文件
    lib/ffmpeg.js:37
    await access(candidate, constants.X_OK)
  • 执行外部命令来自配置/变量
    lib/ffmpeg.js:78
    child = spawn(command, args, { windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] })
  • 读取本地文件
    lib/video.js:64
    const info = await stat(absolute).catch(() => undefined)
  • 读取本地文件
    lib/video.js:232
    const info = await stat(outPath).catch(() => undefined)
  • 写入本地文件
    lib/video.js:280
    await copyFile(source, pattern.replace('%03d', String(index + 1).padStart(3, '0')))
  • 读取本地文件
    lib/video.js:292
    const info = await stat(outPath).catch(() => undefined)
  • 读取本地文件
    lib/video.js:360
    const decoded = decodeText(await readFile(outPath))
  • 读取本地文件
    lib/video.js:378
    entries = await readdir(dir, { withFileTypes: true })
  • 读取本地文件
    lib/video.js:395
    const decoded = decodeText(await readFile(full))
  • 写入本地文件
    lib/video.js:432
    await mkdir(dir, { recursive: true })
  • 删除本地文件递归
    lib/video.js:458
    await rm(stale.full, { recursive: true, force: true }).catch(() => {})
  • 读取本地文件
    lib/asr.js:34
    await access(candidate, constants.R_OK)
  • 读取本地文件
    lib/asr.js:69
    stat(source).catch(() => undefined),
  • 读取本地文件
    lib/asr.js:70
    stat(destination).catch(() => undefined),
  • 写入本地文件
    lib/asr.js:73
    await mkdir(path.dirname(destination), { recursive: true })
  • 写入本地文件
    lib/asr.js:74
    await copyFile(source, destination)
  • 读取本地文件
    lib/asr.js:102
    const entries = (await readdir(dir)).filter((name) => /^ggml-.*\.bin$/i.test(name))
  • 读取本地文件
    lib/asr.js:164
    .update(`${wavPath}|${(await stat(wavPath).catch(() => ({ size: 0 }))).size}`)
  • 删除本地文件
    lib/asr.js:184
    await rm(srtPath, { force: true }).catch(() => {})
  • 读取本地文件
    lib/asr.js:193
    const srt = await readFile(srtPath, 'utf8').catch(() => undefined)
  • 写入本地文件
    lib/asr.js:200
    await writeFile(saveSrt, srt, 'utf8').catch(() => undefined)
  • 删除本地文件
    lib/asr.js:210
    if (stagedAudio) await rm(stagedAudio, { force: true }).catch(() => {})
  • 读取本地文件
    lib/diarize.js:35
    await access(candidate, constants.R_OK)
  • 读取本地文件
    lib/diarize.js:54
    const entries = (await readdir(dir)).filter((name) => /\.onnx$/i.test(name))
  • 读取本地文件
    lib/settings.js:87
    const raw = await readFile(settingsPath(), 'utf8')
  • 写入本地文件
    lib/settings.js:102
    await mkdir(path.dirname(settingsPath()), { recursive: true })
  • 写入本地文件
    lib/settings.js:103
    await writeFile(settingsPath(), `${JSON.stringify(next, null, 2)}\n`, 'utf8')
  • 读取本地文件
    lib/capture.js:108
    const info = await stat(outPath).catch(() => undefined)
  • 写入本地文件
    lib/capture.js:125
    await mkdir(outDir, { recursive: true })
  • 读取本地文件
    lib/capture.js:131
    const entries = await readdir(outDir).catch(() => [])
  • 执行外部命令固定命令
    lib/windows.js:69
    const child = spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script], {
  • 执行外部命令来自配置/变量
    lib/record.js:33
    const child = spawn(ffmpeg, args, { windowsHide: true, stdio: ['pipe', 'ignore', 'pipe'] })
  • 读取本地文件
    lib/record.js:85
    const info = await stat(session.outPath).catch(() => undefined)
  • 读取本地文件
    lib/record.js:106
    const info = await stat(session.outPath).catch(() => undefined)
  • 读取本地文件
    lib/deps.js:204
    const input = createReadStream(file)
  • 读取本地文件
    lib/deps.js:212
    try { return (await stat(file)).size } catch { return -1 }
  • 读取本地文件
    lib/deps.js:216
    try { await access(file); return true } catch { return false }
  • 读取本地文件
    lib/deps.js:222
    const entries = await readdir(dir, { recursive: true, withFileTypes: true })
  • 执行外部命令固定命令
    lib/deps.js:234
    const child = spawn('tar', ['-xf', archive, '-C', destination], { windowsHide: true })
  • 执行外部命令固定命令
    lib/deps.js:249
    const child = spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script], { windowsHide: true })
  • 写入本地文件
    lib/deps.js:261
    await mkdir(destination, { recursive: true })
  • 发起网络请求
    lib/deps.js:276
    const response = await fetch(url, {
  • 写入本地文件
    lib/deps.js:283
    await mkdir(path.dirname(destination), { recursive: true })
  • 写入本地文件
    lib/deps.js:284
    const stream = createWriteStream(destination)
  • 写入本地文件
    lib/deps.js:329
    await mkdir(path.dirname(finalPath), { recursive: true })
  • 写入本地文件
    lib/deps.js:331
    await copyFile(source, temp)
  • 删除本地文件
    lib/deps.js:339
    await rm(finalPath, { force: true })
  • 写入本地文件
    lib/deps.js:340
    await rename(temp, finalPath)
  • 删除本地文件
    lib/deps.js:342
    await rm(temp, { force: true }).catch(() => {})
  • 删除本地文件
    lib/deps.js:384
    return async () => { await unlink(lockPath).catch(() => {}) }
  • 读取本地文件
    lib/deps.js:387
    const info = await readFile(lockPath, 'utf8').then((text) => JSON.parse(text)).catch(() => ({}))
  • 删除本地文件
    lib/deps.js:391
    await unlink(lockPath).catch(() => {})
  • 删除本地文件
    lib/deps.js:448
    await rm(target, { force: true }).catch(() => {})
  • 删除本地文件递归
    lib/deps.js:481
    await rm(staging, { recursive: true, force: true }).catch(() => {})
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DeepSeek Harness 插件:观看、收听并查看视频/音频文件和实时桌面,全程本地运行(whisper.cpp + sherpa-onnx + ffmpeg)。

README

由 DeepSeek 最新模型翻译生成
Video Reader English · 中文 一个 DeepSeek Harness 插件,让智能体看、听、观察这些东西:磁盘上的视频/音频文件,以及实时桌面。全部在本地运行——不上传,不调用云端 API。 - video_read —— 元数据、帧、字幕、多语种带说话人标注的转写 - video_frames —— 在精确时刻截取全宽静帧 - screen_capture —— 观察屏幕;每一帧捕获结果都会返回,分页给出 - screen_frames_read —— 继续读取一次捕获,直到没有未读帧 - screen_watch —— 持续采样,只在画面变化时唤醒智能体 - screen_record —— 长时间捕获录成视频(30 fps 录 1 小时约 350 MB) - video_reader_setup —— 检查或安装外部工具链(首次使用时自动安装) 安装 git clone https://github.com/ck99998888/dsh-video-reader $env:USERPROFILE\dsh-video-reader pwsh -File $env:USERPROFILE\dsh-video-reader\scripts\setup.ps1 # optional; -Mirror if GitHub is slow
展开完整文档(README 剩余 1 节)
Video Reader

English · 中文

一个 DeepSeek Harness 插件,让智能体看、听、观察这些东西:磁盘上的视频/音频文件,以及实时桌面。全部在本地运行——不上传,不调用云端 API。

- video_read —— 元数据、帧、字幕、多语种带说话人标注的转写
- video_frames —— 在精确时刻截取全宽静帧
- screen_capture —— 观察屏幕;每一帧捕获结果都会返回,分页给出
- screen_frames_read —— 继续读取一次捕获,直到没有未读帧
- screen_watch —— 持续采样,只在画面变化时唤醒智能体
- screen_record —— 长时间捕获录成视频(30 fps 录 1 小时约 350 MB)
- video_reader_setup —— 检查或安装外部工具链(首次使用时自动安装)

安装

git clone https://github.com/ck99998888/dsh-video-reader $env:USERPROFILE\dsh-video-reader
pwsh -File $env:USERPROFILE\dsh-video-reader\scripts\setup.ps1 # optional; -Mirror if GitHub is slow

或者从仓库把它作为 DSH bundle 安装:

dsh plugin --profile web add github:ck99998888/dsh-video-reader

然后在 DSH 里把这个文件夹作为 bundle 安装(插件管理器 → 从文件夹安装,或用该路径执行 plugin_manager install_bundle),并重启 DSH 一次:bundle 的 Client 部分在页面启动时组装。

依赖会自动安装。 首次调用 video_read/video_frames/screen_capture 时,会把缺失的东西下载到 %LOCALAPPDATA%\dsh-video-reader\bin 和 …\models(先下 ffmpeg),然后重试该调用。每个下载都锁定版本,并按 lib/deps.js 里的清单做 sha256 校验;校验不通过的文件会被删除,绝不会安装。scripts/setup.ps1 现在只是提前预置全部依赖的一种方式。
用插件 Config(autoSetup、autoSetupModels、 dependencyMirror)或从 设置 → Video Reader → Dependencies 控制这一行为。

| 组件 | 大小 | 为什么不提交进仓库 |
| ffmpeg + ffprobe(essentials 9.0.2) | ~200 MB | GitHub 单文件上限 100 MB |
| whisper.cpp CLI + DLLs(b5454) | ~10 MB | 随其余依赖一起下载 |
| sherpa-onnx 说话人分离运行时(v2.0.0) | ~17 MB | 随其余依赖一起下载 |
| ggml-medium-q5_0.bin 语音模型 | 514 MB | 远超上限 |
| pyannote 分割 + 3D-Speaker 嵌入 | ~33 MB | 随其余依赖一起下载 |

值得了解的设计取舍

- 长时间捕获是录像,不是一堆帧:30 fps 录一小时就是 108,000 帧,只有当成视频、让读取方事后采样才说得通。
- screen_capture 绝不做降采样。它保留每一帧,写出 manifest.json,附带一个批次,并明确告诉你还有多少帧未读。
- 窗口捕获按窗口边界裁剪合成后的桌面:GDI 读不了硬件合成窗口的 D3D 表面,所以 gdigrab -i title= 返回的是黑帧。
- screen_watch 对比 64×40 灰度采样(2,560 字节),只有变化超过阈值时,才消耗一张全尺寸帧并唤醒。

License MIT。

让智能体真正「看」和「听」视频:一次调用就能拿到容器与流信息、可直观看清的关键帧拼版、逐帧大图路径、内嵌或同名字幕,以及带说话人标签的多语种转写(S1/S2/… 谁在第几秒说了什么)。

全部在本机处理:视频不上传、不联网、不依赖云服务。插件 = Harness Host 插件 + ffmpeg / whisper.cpp / sherpa-onnx 与模型(由插件自动下载,不入库)。

依赖:首次使用自动补齐(1.8 起)

tools/、models/ 不入库,插件会自己补齐:

- 首次需要时(video_read / video_frames / screen_capture)自动把缺的组件下到 %LOCALAPPDATA%\dsh-video-reader\{bin,models},装好再继续本次调用;
- 每个文件都按 lib/deps.js 里钉死的版本与 sha256 校验,校验失败的文件直接丢弃、不会安装;
- GitHub 域名不可达时默认走 gh-proxy.com 镜像(dependencyMirror);
- 设置页「依赖组件」可看状态、手动安装、关掉自动安装;
- 也可以用工具 video_reader_setup 显式检查/安装,或提前跑 scripts/setup.ps1。

工具

video_reader_setup

| 参数 | 说明 |
| action | status(只读报告)或 install(下载缺失组件) |
| components | ffmpeg whisper whisper-model sherpa diarization-models,或简写 models / binaries / all(默认) |
| mirror | GitHub 下载是否优先走 gh-proxy 镜像;默认取设置页 |

返回每一项的就绪状态、安装位置、版本,以及安装耗时/体积。视频类工具在缺依赖时会先自动安装再继续,所以这个工具主要用于提前体检或重试失败的下载。

video_read

| 参数 | 说明 |
| path | 视频/音频路径,绝对或相对会话工作目录 |
| frames | 抽帧数量,默认 12,0–40,0 只要元数据/转写 |
| mode | even(默认)或 scenes(按镜头切换) |
| start / end | 只看某段,支持 90、1:30、00:01:30 |
| transcript | 是否转写,默认 true |
| language | 强制语种,如 zh en de ja ko fr ru;默认 auto 自动识别 |
| speakers | 已知说话人数(0 = 自动推断);给出时聚类更稳 |
| diarize | 是否标说话人,默认 true |
| subtitles | 是否提取内嵌/同名字幕,默认 true |
| width | 单帧宽度,默认 960,0 = 原尺寸 |

输出现场:

Speech transcript (auto-detected, 6 turns, 2 speakers: S1/S2)
talk time: S1 0:10 · S2 0:07 [S1] 0:00–0:05 大家好,今天我们讨论视频阅读器的测试结果。
[S2] 0:06–0:09 我觉得识别准确率比之前好多了。
...
full timestamped SRT: …\transcript.srt

拼版图片会作为图片内容直接进模型上下文(每格左上角烧入时间码),同时给出每帧全尺寸图路径。

video_frames

按时间点抓全宽大图,一次最多 8 张,用于复查细节。

screen_capture

看一眼当前桌面(实时屏幕),不是磁盘上的文件。

| 参数 | 说明 |
| seconds | 抓取窗口秒数,0 = 单张截图,最大 30 |
| fps | 采样帧率 1–30(默认取自设置页)。实测 2560×1600 下 gdigrab 能稳定跑到 ~28 fps、上限 ~56 fps;单次抓取总帧数封顶 240 |
| region | full / window:<标题片段> / x,y,w,h;不传则用设置页的默认值 |
| frames | 拼版最多保留几帧(默认 12) |
| width | 每帧宽度 |
| mouse | 是否把鼠标指针画进去 |

返回同样是一张可直接看的拼版 + 每帧路径。抓取是采样:模型看到的是这 N 秒内实际存在的若干帧,不是持续视频流——所谓「实时看视频」,就是「按 2–5 fps 采样一段时间」。

屏幕捕获设置页

Web UI 里 设置 → 视频阅读器 提供图形化配置:允许/禁止抓屏、整屏 / 指定窗口 / 自定义区域、帧率、默认时长、每帧宽度、是否包含鼠标指针,并带「抓一帧预览」按钮直接确认范围。

设置在保存后立即生效(工具每次调用都会重新读取),也可以直接改 %LOCALAPPDATA%\dsh-video-reader\screen-settings.json。

抓取方式的实现要点:

- 整屏:gdigrab -i desktop,对 GPU 合成的浏览器、播放器同样有效
- 窗口:先枚举窗口拿到坐标,再按该矩形裁剪桌面。不能直接用 gdigrab -i title=,因为 GDI 读不到 D3D 合成窗口,会得到黑帧
- 区域:-offset_x/-offset_y/-video_size
- 窗口标题是子串匹配,填稳定片段(如 Microsoft Edge),因为播放页的完整标题会随页面变化

实测帧率(2560×1600 桌面,JPEG 落盘)

| 目标 fps | 实际产出 | 说明 |
| 10 | 9.1 fps | |
| 20 | 18.8 fps | |
| 30 | 28.5 fps | 插件上限,够覆盖 24–30fps 的视频 |
| 40 | 37.9 fps | |
| 60 | 56.6 fps | 受 JPEG 编码/写盘限制,不是采集 API 的瓶颈 |

单张全屏截图(含进程启动)约 173 ms。ddagrab(Desktop Duplication)同分辨率下 60 目标也只有 55.5 fps,与 gdigrab 基本持平,因此插件统一用 gdigrab,避免给窗口/区域模式再分一套实现。

看视频场景建议 15–24 fps;看游戏或快速动画再上 30。总帧数封顶 240(seconds × fps ≤ 240),超了会自动降 fps 并在结果里注明。

语种与识别

单个多语种模型(whisper medium-q5_0,99 种语言),不需要按语种换模型。

本机实测:

| 语种 | 素材 | 结果 |
| 中文 | Windows 原生 TTS 双人对话 | 逐句全对,两名说话人分对 |
| 英文 | 原生 TTS + espeak | 全对 |
| 德文 | espeak | “Das Wetter ist heute schön. Wir gehen im Park spazieren.” 全对 |
| 法文 | espeak | “Le temps est bon aujourd'hui, nous allons nous promener dans le parc.” 仅一处冠词差异 |
| 俄/日/韩 | — | 模型原生支持(99 语种),本机没有可用素材,未实测 |

说话人分离

sherpa-onnx 离线分离:pyannote 分段模型(5.7MB)+ 3D-Speaker 声纹嵌入(27MB)+ 聚类,不联网、CPU 即可。57 秒 4 人素材实测分离正确(S1–S4),速度约为实时 20 倍。

- 每句转写按时间重叠度归到说话人,连续同人语句合并成一 "turn"
- 输出附带各说话人发言总时长
- 已知人数时传 speakers 会显著更稳(尤其 3 人以上)

配置

- insert:
- id: video-reader
name: '@local/dsh-video-reader'
config:
frames: 12
columns: 4
frameWidth: 960
tileWidth: 320
maxTextChars: 12000
maxTranscriptSeconds: 900
languages: auto
cacheDir: .dsh-video-cache
diarize: true
speakers: 0 # 0 = 自动 diarizationThreshold: 0.5 依赖自动安装(1.8 起) autoSetup: true # 首次使用时自动下载缺失的 ffmpeg / 运行时 autoSetupModels: true # 连语音与分离模型(~547 MB)也自动下载 dependencyMirror: true # GitHub 域名不通时走 gh-proxy.com 镜像路径覆盖(留空则用随包二进制) ffmpegPath: '' ffprobePath: '' whisperPath: '' whisperModel: '' diarizationPath: '' segmentationModel: '' embeddingModel: ''

体积

| 组成 | 大小 |
| ffmpeg + ffprobe(essentials 构建) | 201 MB |
| whisper.cpp + sherpa-onnx 运行时 | 27 MB |
| 识别模型 medium-q5_0 | 514 MB |
| 分离模型(分段 + 声纹) | 33 MB |
| 代码/资源 | < 0.1 MB |
| 合计 | 约 778 MB |

想更准可以换 ggml-large-v3-q5_0.bin(1031 MB,俄/日/韩明显更好)放进 models/ 即可,代码会自动优先选它。想更小可以换 ggml-small.bin(465 MB),代价是德/俄/日/韩准确率下降。

ggml-large-v3-turbo-q5_0.bin 经实测在本机两个 whisper.cpp 构建上都无法加载(unknown tensor ''),文件 sha256 与官方一致,属模型与构建的格式兼容问题,故默认不采用。

screen_record

长时采集走录制而不是堆截图:1 小时 × 30fps = 108,000 帧,只有视频形态才合理。

| 参数 | 说明 |
| action | start / stop / status |
| id | stop 时指定要停的录制 id |
| seconds | 最长时长,默认 3600(1 小时),上限 7200 |
| fps | 1–30,默认 30 |
| region | 同 screen_capture,默认用设置页的选择 |
| maxMB | 文件大小上限,默认 2000MB,到顶自动停 |
| width | 编码前缩放宽度,默认 1280 |

录制在后台跑(不阻塞对话),返回 id 和 .mkv 路径;stop 后直接用 video_read 采样任意片段。

实测码率(2560×1600 桌面,30fps):

| 编码参数 | 码率 | 1 小时 |
| 原生尺寸 · crf26 · ultrafast | 7.7 GB/h | 太大 |
| 原生尺寸 · crf30 · veryfast | 1.05 GB/h | 偏大 |
| 1280 宽 · crf30 · veryfast(默认) | 354 MB/h | 1 小时约 0.35 GB |

选择要抓的软件界面

设置页的「指定窗口」是一个自动列出当前所有可见窗口的下拉框(进程名 + 标题 + 分辨率),带「刷新窗口列表」按钮,不用手打标题。
选中的窗口会同时保存 windowTitle 与 windowProcess;抓取时按 精确标题 → 标题子串 → 进程名 的顺序解析,所以浏览器换页面、标题变了也能命中同一个进程。窗口不在了会直接报错,并列出当前可选的窗口,而不是给一张黑图。

抓窗口的实现是「先取窗口坐标,再裁剪合成后的桌面」——因为 GDI 读不到 GPU 合成窗口的 D3D 表面,gdigrab -i title= 对浏览器/播放器只会得到黑帧。

缓存

帧、拼版、字幕、wav、SRT 写在 <会话工作目录>/.dsh-video-cache/<文件名>-<内容哈希>/,保留最近 20 个媒体目录,可整删。

边界

- 位图字幕(PGS/VobSub)无法转文字,会标注跳过
- 转写同步执行:turbo/medium 在 CPU 上约实时 1–3 倍;超过 maxTranscriptSeconds 需自己传 start/end 分段
- 说话人分离是聚类结果,人数未知且音色接近时可能多分/少分;给 speakers 可缓解
- whisper 系模型对纯合成音(如 espeak)不代表真实口语表现
- 抓屏会包含屏幕上一切可见内容(聊天、验证码、密码框),默认整屏;需要隔离就用窗口/区域模式
- DRM、受保护视频、部分全屏独占的游戏在 GDI 下可能黑屏;独显直连/多显示器时坐标要按实际桌面
- 抓屏是采样而非录制:seconds × fps 决定能看清多少变化,动作太快(如 60fps 游戏)需要调高 fps 或缩短窗口

两条读取路径(1.6 起)

1. 全帧读取:不抽样

screen_capture 保留每一帧、写入 manifest.json,并把帧按批(默认 20 张/次)作为图片返回:

- 返回里带 totalFrames / readFrames / remainingFrames
- remainingFrames > 0 时结果明确写出下一步:screen_frames_read {manifest, offset, count}
- 拼版只在 sheet: true 时生成,且仅作总览,不再替代逐帧阅读

算一下就知道为何要分批:30 秒 × 30fps = 900 帧,每帧约 800 token,全读约 72 万 token,单轮装不下。插件保证“一帧不少地落盘、可按批读完”,同时保留 240 帧采集预算(fps 会被压到 240/seconds)。

2. 实时通道:screen_watch

| 参数 | 说明 |
| action | start / stop / status |
| intervalMs | 采样间隔,默认 2000ms |
| threshold | 判定“变了”的归一化差异,默认 0.02 |
| maxMinutes | 自动停止,默认 30 分钟 |

每次抓一张 64×40 灰度小图(2560 字节)算平均绝对差;超过阈值才抓全尺寸帧存盘,并主动唤醒模型(agent.inject + agent.followup)。唤醒失败时事件留在队列,用 action:"status" 抽取,不丢观察。

实测:3 秒内壁纸变化一次,检测 1 次、唤醒 1 次、误报 0。
预览分享卡片长什么样 ↓ck99998888/dsh-video-reader
分享 · DeepSeek Harness Hub
ck99998888/dsh-video-reader

让智能体看视频听音频并观察实时桌面

这是你的仓库?认领条目

回到顶部