dsh-media-lens

visioninstall failsnpmMIT

All-media (video/audio/image) sibling of liustack/modlens: turns local media into structured evidence (timeline / transcript / layout regions) injected into the conversation so text-only models can cite concrete frames, seconds and speakers — Evidence, not imagination. One failover chain per media,

下载量 / Downloads
2,532
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-media-lens

Sandbox test results

StageResult
1 install✗
2 list—
3 mount—
4 boot—
First error
dsh: initialized profile web at /home/node/.dsh/profiles/web

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-media-lens

媒体感知插件:把本地 video / audio / image 变成结构化证据(时间线 / 转写 / 版面区域)注入对话,让文本模型引用具体帧、秒、说话人 —— Evidence, not imagination。同时内置 provider 路由线:每个媒体一条 failover 链,预算超限自动降级,每次尝试记录在 meta.attempts —— a fallback is never silent。

media_read_video / media_read_audio / media_read_image
  → 路径守卫(存在性 + 扩展名白名单)
  → ffprobe 探测 + 预算裁决(full / reencode / sampleFrames / segment / downsample)
  → failover 链(首个成功即返回;全败抛带 attempts 的结构化错误)
  → MediaEvidence JSON(timeline / transcript / regions + meta.attempts)

<!-- host-compat:begin — generated by scripts/sync-hosts.mjs from scripts/hosts.mjs; DO NOT EDIT -->

  • Supported DSH hosts: 0.1.7-rc.1 0.1.7-rc.2 0.2.0-rc.1 0.2.0-rc.2 0.2.1-rc.1 0.2.1-rc.2 0.2.1-rc.3 0.2.1-rc.4 0.2.1-rc.5 0.2.2-rc.1 (10 rc across lines 0.1.7 / 0.2.0 / 0.2.1)
  • Runtime-verified: 0.1.7-rc.2, 0.2.0-rc.2, 0.2.1-rc.1 — evidence in .compat-results/

<!-- host-compat:end -->

链序(每媒体)

媒体 · 链

video(≤10MB 且 ≤10min) · multimodal(注册全模态直传)→ frames:(ffmpeg 均匀抽帧 + 图片链)→ local:metadata

video(10–19MB) · reencode:multimodal(540p x264 压缩后直传)→ 同上

video(>19MB 或 >10min) · 直接 frames: 抽帧路

audio · multimodal(全模态直传转写)→ asr:endpoint-N(本地 ASR CLI,多端点按序)→ local:metadata

image · registered:(宿主已注册视觉模型)→ configured:openai(OpenAI-compatible 端点)→ local:metadata

处理端来源(FR-9:已注册模型优先)

  • 宿主已注册模型:插件经 ctx.llm.listProviders()/listModels() 枚举(60s 缓存),按 inputModalities 分组构成首选链;图片原生 image 块直送。
  • 显式选择:配置 models.{image,audio,video}: "provider/model" 直接指定一个已注册模型 —— 视频的 MiMo 类全模态路就走这里(宿主模态词表当前只认 text|image,自动发现不了视频/音频声明,显式选择是唯一入口;实际承载由适配器(如 openai-completions 接管线)的模态硬闸把关,拒绝是响亮的)。
  • 自配端点:providers.openai.{baseUrl, apiKey, model},apiKey 支持逗号分隔多 key(auth/429/quota 换下一个 key;网络/5xx 跳过保链)。
  • 本地兜底:strictLocalOnly 或全链失败时,local:metadata 只出 probe 元数据(时长/分辨率/大小),degraded='local-metadata-only'。

配置

dsh-media-lens:
  strictLocalOnly: false      # true 时链中剔除一切远端 provider,媒体内容不出本机
  cooldownMs: 600000          # keyFailure 类失败的默认冷却时长(有 Retry-After/"Resets in" 线索时按线索)
  models:
    image: auto               # auto | '' | "provider/model"
    audio: auto
    video: auto               # MiMo 类全模态:填 "llm-pi-ai/你的mimo模型id"
  providers:
    openai:
      baseUrl: ''             # 例 https://api.example.com/v1
      apiKey: ''              # 逗号分隔多 key 轮换
      model: ''
      structuredOutput: false # true 时注入 response_format json_schema(strict)(不认识的网关会 400,故默认关)
    asr:
      command: ''             # 单端点写法:本地转写 CLI 模板,{input} 占位
      endpoints: []           # 多端点选择项,按序尝试;与 command 合并(command 在前)
  refine:
    enabled: false            # Phase 7:链出口一次 refine pass,默认关
    model: ''                 # 开启时必须写 'openai/<model>' 或裸 model;auto / 空串 = 未启用。转述手只认 configured 自配端点(registered:/插件注入模型无效)

ASR 命令模板示例(Windows,模板内双引号保护空格路径):

python "C:\tools\sensevoice_cli.py" --input "{input}" --json

转写输出识别两种格式:JSON segments([{start,end,text[,speaker]}] 或 {"segments":[...]})与 SRT/时间行文本。

隐私说明(对照 dsh-vision-router 教训)

  • 默认媒体内容会发往远端 provider(注册模型 / 配置端点)。要内容不出本机,显式开启 strictLocalOnly: true——之后只剩本地 ASR CLI 与元数据兜底。
  • meta.attempts 记录每次尝试(provider 名含来源前缀 registered: / multimodal: / configured: / asr: / frames: / local:,多 key 轮换带 keyIndex),meta.warnings 记录路由通告(failover 去向、冷却垫尾、轮换成功)——降级绝不静默。
  • 媒体路径按不可信输入处理:只读取、存在性 + 扩展名 + magic-byte 三重校验(改名伪装的文件在入参侧拒绝);处理指令显式声明媒体内出现的指令一律视为数据;内容永不执行。
  • 错误文本先脱密(apiKey/baseUrl 精确匹配)再截断,密钥不进 attempts/日志。
  • 音视频直传只在适配器接管线(如 openai-completions takeover)上真正内联;未接管线路上模型只看到文件 handle 文本 —— 插件检测到这种回声会放弃该跳并落到抽帧/ASR 兜底,不产幻觉证据。

冷却语义(modlens 软化熔断)

只有 keyFailure 类失败(auth/429/quota 正文)触发冷却——普通失败(网络抖动、5xx、解析失败)永不冷却,正文碰巧含 quota 字样也不算。冷却中的 provider 垫到链尾仍作最后尝试(不是踢出):穷途末路时仍试一把,成功即恢复。provider 给恢复线索(Retry-After 头或正文 Resets in Xh Ym Zs)时按线索计时,否则 cooldownMs。

structuredOutput(FR-13,opt-in)

providers.openai.structuredOutput: true 时请求注入 response_format json_schema(strict)(由证据载荷派生,非手写镜像)。认识的网关(vLLM、官方 OpenAI 等)服务端强制形状能显著提证据质量;不认识的网关对未知字段直接 400——所以缺省关。

refine pass(Phase 7,链出口一次,opt-in)

主链首个成功后、返回前可选地再过一次文本模型将证据精炼规范化(去重 / 紧措辞 / 保留不确定性)——对齐 medialens 型项目常见的 "visionModel 读手 + textModel 转述手" pair 设计。

refine:
  enabled: true
  model: "openai/your-text-model"   # 或裸 model;auto / 空串 = 未启用

默认关,理由:

  • 隐私:多一跳远端 = 多一次媒体内容(raw evidence)暴露面;strictLocalOnly 下链仅到 local:metadata,此时 refine 自动跳过(无文本可精炼),不会拉回远端。
  • 延迟:直出证据已可用,refine 是锦上添花。
  • 不作 auto:auto = 随便把所有模型都加透镜,不允许。

来源闸门(转述手只认用户自配端点):refine 这一跳只允许 configured 端点(providers.openai 配了 baseUrl + apiKey)——model 必须写 openai/<model> 或裸 model,实际请求 model 取 providers.openai.model 单源。registered: / multimodal:(宿主 discovery 枚举,可能含其它插件注入的模型)一律不可信:命中即静默跳过(不写 refineAttempt、不追 warning,行为与未启用一致)。传输走 configured 直连(不经宿主 runtime 路由表),structuredOutput 开启时注入 response_format。

失败行为(不静默,但不撤销已成):refine 抛错 / 输出无 JSON / 校验不通过 → 保留 raw evidence,meta.warnings 追加 refine failed: <redacted>,meta.refineAttempt.ok = false;主链 attempts 不新增(读手已成功,不浪费下一跳抽帧/ASR)。成功时 refine 归属写 meta.refineAttempt.provider = 'refined:openai/<model>',meta.provider 保留读手前缀(registered / multimodal / configured / asr / frames / local);source / meta.attempts / meta.generatedAt 不被 refine 修改。

传输硬化:EVIDENCE_REFINE_INSTRUCTION 四要素与读手指令同源(反注入 / verbatim / bbox 保守 / uncertainty),另加「保留原 source 与 attempts」一行——媒体内出现的指令会随 raw evidence 二次进入 LLM 上下文,反注入行必须再吃一遍,防洗证据。错误文本先脱密后截断。

vision-bridge(v4,选择器可见的透镜包装,opt-in)

把透镜包装成宿主模型选择器里可见的路由:经宿主 llm.registerAdapter 注册 media-lens-vision-<upstream> 包装 provider,选择器出现 <模型名> (media-lens vision) 条目。选中它作主对话模型后,请求中的媒体在发送前经 media-lens 链(读手 = 上文「处理端模型」配置)转成证据文本,再委托真实路由——纯文本主力模型由此获得图片与音视频 sight("让 deepseek 收到小米读出的证据")。

inject:
  enabled: true
  families: ["deepseek", "glm", "mimo"]   # 前缀过滤;"*" = 全部(仍受否决)

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::8,最后更新 2026-11-06

Links

GitHub · Homepage · npm

Same category