yauntyour
DSH-Multimodal
DSH 多模态输入插件:为不同类型的文件(图片 / 视频 / 音频 / 文本)配置独立的处理模型链,在文件进入会话模型之前,先用预设模型把它处理成 Prompt Tokens(文本),再交给会话模型。插件在 DSH 设置中新增独立的 Multimodal 页面。
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 15, 2026
- Updated
- Aug 15, 2026
Introduction
DSH-Multimodal
DSH 多模态输入插件:为不同类型的文件(图片 / 视频 / 音频 / 文本)配置独立的处理模型链,在文件进入会话模型之前,先用预设模型把它处理成 Prompt Tokens(文本),再交给会话模型。插件在 DSH 设置中新增独立的 Multimodal 页面。
解决的问题
DeepSeek 等会话模型只接受文本输入(inputModalities 为 text)。DSH 原生行为是:向这类模型附加图片时直接拒绝(Model does not support image input),视频 / 音频 / 普通文件则根本无法附加。本插件在发送路径上拦截文件输入:先调用你配置的多模态模型(如视觉模型)把文件转成描述文本,再把文本作为 Prompt Tokens 发给会话模型。
特性
- 设置页:DSH 设置中新增「Multimodal」菜单页,按通配符为不同文件格式配置预设;
- 预设可增删改:自带一个合并默认预设「多媒体(默认)」——内置 DSH 支持的全部非文本输入类型后缀(png/jpg/jpeg/webp/gif、mp4/webm/mov/mkv/avi/flv/wmv/m4v/mpg/mpeg/ts/3gp、mp3/wav/flac/aac/ogg/opus/m4a/wma/mid/midi),可自由编辑后缀通配符;可创建多个预设为不同文件类型配置不同模型(按配置顺序首个匹配生效);模型链为空时自动使用当前默认模型(即"匹配其多模态输入模型");
- 文本原生直通:文本类型没有预设(所有 LLM 都原生支持文本输入),文本文件永远不做 Multimodal 转换;
- 模型链回退:每个预设可配置多个模型,按顺序尝试,第一个成功者胜出(如视觉模型失败自动回退到下一个);链为空时自动回退到当前默认模型(内置预设即如此,开箱即可用);
- 提示词留空 = 使用类型默认:预设的处理提示词留空时,按文件实际类型自动使用默认提示词(图片为「请仔细分析这张图片的内容,并将其转化为详细的文字描述…」,视频/音频为元数据说明);custom 预设匹配到图片时同样以真实图片块传入处理模型(custom 只决定匹配方式,不改变传入格式);
- 模型需声明图片能力:处理模型的 Provider 适配器按模型声明的 input 模态决定是否接收图片(pi-ai 本地模型未声明会直接拒绝:
model does not support image input)。在 DSH 设置 → 模型 中把本地视觉模型(如 Ollama 的 uGemma4)的 input 配置为[text, image]; - 图片默认不自动处理:设置页开关「发送时自动处理图片」默认关闭——输入里的图片完全按原生行为处理(多模态会话模型直通、纯文本模型按原生规则拒绝);开启后,存在匹配预设时自动调用预设模型链转为文本;
- 原生多模态模型直通:即使开关开启,会话模型本身支持图片输入时图片仍原样传递(文本类文件始终不转换);
- 大小限制:默认 10 MB,每个预设可单独覆盖;
- 两条处理路径:
- 发送路径(图片):粘贴 / 拖拽的图片经
multimodal/send接管——消息立即入日志(用户消息含图片 + 文字原样显示,输入栏立即清空),描述在首个模型调用时由 llm/stream 瀑布惰性解析并注入上下文(日志永不被修改,同一图片+提问只跑一次链);你输入的文字会一并注入处理提示词; - 附件按钮(任意文件):输入框工具行的 ➕ 按钮选择文件,立即处理并把结果插入草稿;
- 发送路径(图片):粘贴 / 拖拽的图片经
- 兜底重写:llm/stream 瀑布钩子会把仍然到达模型调用的图片块(如 read_image 工具结果)改写为处理文本;
- 失败策略:每预设可选「原样传递」或「替换为失败说明」,默认替换为失败说明(新预设的默认值)。
安装
# 在 DSH 中挂载(web profile)
dsh plugin --profile web add <本插件路径或 tgz>
# headless profile 也会用到设置时同样挂载
dsh plugin --profile headless add <本插件路径或 tgz>
浏览器硬刷新(Ctrl+Shift+R)后,设置中会出现「Multimodal」页。
客户端改动热加载,无需重启 dsh web;host 半改动需要重启。
使用
- 打开 设置 → Multimodal;
- 打开「启用 Multimodal 处理」开关;
- 为预设配置模型链(Provider + 模型,可多行,顺序即回退顺序;用「测试」按钮验证连通性);
- 回到会话:粘贴/拖入图片,或点击输入框 ➕ 附加任意文件。
示例:给图片预设配置一个视觉模型 → 发送图片时自动生成描述文本再进入文本会话模型;配置了原生多模态会话模型时,图片则原样交给会话模型。
配置(cordis.yml / settings.yaml)
plugins:
multimodal:
enabled: true
presets:
- id: image
name: 图片
kind: image
patterns: [] # 空 = 匹配该类型所有文件;如 [*.png, *.jpg]
prompt: 请详细描述这张图片…
maxBytes: 10485760 # 覆盖大小上限(字节,默认 10MB)
onError: note # 默认 note(替换为失败说明);或 pass-through
models:
- provider: deepseek-official
model: deepseek-chat
- provider: openai
model: gpt-4o
限制
- 视频 / 音频:当前适配层只支持文本与图片内容块,视频/音频文件发送给处理模型的是元数据简报(文件名/类型/大小/MIME),无法直接转写;需要转录请在会话中使用相应工具;
- 图片格式:仅支持 DSH 附件服务接受的 png / jpeg / webp / gif;
- 远程浏览器:/multimodal 通道为 loopback 授权,远程浏览器不生效;
- 处理失败且策略为 pass-through:恢复 DSH 原生行为(文本模型会拒绝图片)。
- 默认行为 = 原生行为:未配置任何预设、或未开启「发送时自动处理图片」时,图片按会话模型能力处理,文本/视频/音频不附加。
开发
npm install
npm run typecheck # 类型检查
npm test # vitest
npm run build # tsc 类型 + tsdown 打包(lib/index.js + lib/client.js)
npm pack # 发布包
架构
- host 半(Node):设置命名空间 multimodal(schemastery schema + cordis.yml 作为 base 层);/multimodal loopback RPC 通道(presets.get / process / send / chain.test / settings.get / settings.save / settings.reset —— 设置页通过本通道读写命名空间,因为 DSH 的 settings RPC 域不为第三方命名空间提供服务);模型链执行器(prepareCall + 流式收集,失败回退,空链回退默认模型);send 端点(发送路径接管:复刻准入的持久化转换与上限校验,原始消息经
agent.followup立即入日志,端点即时返回;多模态会话模型直接返回 native 直通);描述缓存(attachmentId + preset + 提示词 + 用户文字为键,Promise 共享在途调用,一次链调用、全程复用);llm/stream 瀑布重写(WeakSet 标记防递归;图片块在模型调用层替换为描述文本,按 onError 处理失败;目标模型原生支持图片时跳过)。 - client 半(浏览器):settings.section「Multimodal」设置页;api.sessions.prompt 包装(仅把带图片的 queue 发送路由到
multimodal/send,从不修改消息内容,失败回退原生发送);conversation.input.left 附件按钮 + conversation.input.dock 状态行。 - 两端共享同一处理管线(src/process.ts + src/describe.ts);客户端只做 advisory 匹配,host 端权威校验大小与格式。
License
MIT