# dsh-web-ui

> Adds image understanding to text-only models: automatically calls a vision model to describe dropped images, with only text entering the conversation.

## Metadata

- Author: [@zhu1090093659](https://github.com/zhu1090093659)
- Repo: <https://github.com/zhu1090093659/dsh-web-ui.git>
- GitHub: [zhu1090093659/dsh-web-ui](https://github.com/zhu1090093659/dsh-web-ui)
- Stars: 5,125
- Language: TypeScript
- License: [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)
- Homepage: <https://gallery.dsh-market.com>
- Topics: `deepseek-harness`, `dsh`, `dsh-plugin`, `web-ui`
- Forks: 310
- Open Issues: 49
- Last push: 2026-08-20T14:37:38.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:zhu1090093659/dsh-web-ui/packages/dsh-tool-describe-image
```

## Wiki

## 一句话定位
为 DSH Web GUI 增加模型侧的 `describe_image` 工具：让纯文本模型（DeepSeek V4 等）也能读懂图片——会话里拖入或粘贴一张图，插件自动把图片发给视觉模型（Qwen-VL、GLM-4V、GPT-4o、Claude 风格、本地 Ollama 等），只把返回的文字送回对话，图片本身不进入会话日志。

## 核心能力
- 提供 `describe_image` 模型工具：模型可调用它让视觉模型描述任意图片（本地绝对路径、http(s) URL、附件引用、自描述 Markdown 引用），返回结构化结果 `{ text, model, image, mimeType, bytes }`，模型侧只看到 `text`（src/index.ts:189-232）。
- 拖拽 / 粘贴图片自动改写：在纯文本会话里把图片块改写成 `![图片](/describe-image/raw/sha256:...?ref=...)` 引用，图片字节通过 `/describe-image/attach` 路由上传（校验 base64、magic bytes 与字节上限），持久化到附件存储，只有引用文本进入会话（src/attach-routes.ts:1-13）。
- 模型能力自适应：每次发送前通过 `/describe-image/capability` 探测当前会话模型是否声明 image 输入；声明了直接把原图交给模型原生视觉并隐藏 `describe_image` 工具（包括 run_code 嵌套调用），未声明则走改写路径（src/model-capability.ts:1-22 / src/client/send-hook.ts:97-103）。
- 实时配置卡：「设置 → 插件配置 → Web UI 插件 → Image understanding」卡可改 `baseURL` / `apiStyle` / `model` / API key / 默认指令 / 各项上限（走设置服务），即时生效无需重启（README.md:23）。
- 端点连通与模型枚举：「获取模型」控件调 `/describe-image/models` 列出端点可用模型 id（解析草稿值以验证未保存的连接），列表切换为下拉选择；「测试连通性」控件以 `max_tokens=1` 最小补全测模型往返延迟（README.md:24 / src/model-probe.ts）。
- 多协议视觉端点：内置 `chat-completions`（默认 `/chat/completions`）、`responses`（OpenAI Responses API 的 `/responses`）、`anthropic-messages`（Claude 风格 `/v1/messages` + `x-api-key`），适配 OpenAI、Qwen、GLM、Kimi、OpenCode Go 等不同厂商（src/config-resolve.ts:29-32 / README.md:75）。

## 技术实现
- **语言**: TypeScript（host 半区 + 浏览器半区双 program，参照 packages/AGENTS.md:16-19）
- **关键依赖**: @deepseek-ai/dsh-tools（注册 describe_image 工具）/ @deepseek-ai/dsh-settings（设置区与命名空间）/ @deepseek-ai/dsh-credentials（凭证解析）/ @deepseek-ai/dsh-llm（模型路由解析）/ schemastery（配置 schema）
- **架构模式**: cordis bundle 双半区包——host 半区（src/index.ts，注册工具、注册 attach/raw/capability/native-images/models 路由、安装设置区）；浏览器半区（src/client/，挂载发送钩子、能力探测、缩略图预览、设置卡 React 组件）；两端通过官方 NPM SDK 解耦（package.json:28-42 / cordis.patch.yml:13-15）
- **入口文件**: host 入口 src/index.ts（apply 函数 137-233 行）；浏览器入口 src/client/index.ts（apply 函数 72-148 行）

## 适用场景
用户日常用 DeepSeek V4 这类纯文本模型与 DSH 对话时，遇到需要读图的任务——截屏报错、UI 截图诊断、拍照发图、扫描件 OCR——直接拖入输入框即可。模型看不到图片字节本身，而是收到一段引用与上下文，再调用 `describe_image` 把图片发给视觉模型，让模型侧既能聊纯文本又能像多模态模型一样读图。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DeepSeek Harness (DSH) | 0.1.0-rc.8 | 所有 @deepseek-ai/* 依赖锁定 ^0.1.0-rc.8（package.json:61-73） |
| Node.js | ^22.19.0 或 >=24.0.0 | package.json#engines（package.json:7-9） |
| 平台 | 跨平台 | 仅使用 Node 内置模块（node:fs/promises、node:crypto、node:http），无原生模块依赖 |
| 原生模块 | 无 | — |

## 安装方式
```bash
dsh plugin --profile web add github:zhu1090093659/dsh-web-ui/packages/dsh-tool-describe-image
```

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `baseURL` | 字符串（必填） | 视觉模型端点根地址，按协议自动追加 `/chat/completions` / `/responses` 或归一化为 `/v1/messages`；末尾斜杠自动去除；仅接受 `http(s)` | — |
| `model` | 字符串（必填） | 视觉模型 id，可带思考控制后缀：`:off` 显式关闭思考，`:low` `:medium` `:high` 开启思考，不带后缀则不发送思考控制字段 | — |
| `apiStyle` | 枚举 | 视觉端点协议：`chat-completions`（默认，OpenAI 兼容）、`responses`（OpenAI Responses API）、`anthropic-messages`（Claude 风格，x-api-key 鉴权） | `chat-completions` |
| `apiKey` | 字符串（密钥） | 内联 API key，本地调试用，建议用环境变量而非明文 | — |
| `apiKeyEnv` | 环境变量名 | 凭证引用：先看 dsh-credentials 服务，再回退到启动环境 | `VISION_API_KEY` |
| `defaultPrompt` | 字符串 | 模型未传 `prompt` 参数时的兜底指令（OCR、UI 评审、翻译等场景可按需调优） | 一段描述图片客观内容并转录可见文字的指令 |
| `maxBytes` | 整数 | 图片字节上限（本地文件与下载 URL 一致） | `10485760`（10 MiB） |
| `maxOutputTokens` | 整数 | 单次输出 token 上限 | `1024` |
| `timeoutMs` | 整数 | 单次视觉请求超时 | `120000`（120 秒） |
| `renderImagePreview` | 布尔 | 把会话里图片引用原地升级为缩略图（点击看大图）；仅影响本地显示 | `true` |
| `interceptImageSend` | 布尔 | 发送时改写图片块为 describe-image 引用；关掉可让其他视觉插件接收原图 | `true` |

## 常见问题

**Q: 模型本身已经支持图片输入，还需要装这个插件吗？**

A: 不需要。插件会在每次发送时通过 `/describe-image/capability` 探测当前会话模型是否声明 image 输入；声明了就把原图直接交给模型原生视觉能力，并自动隐藏 `describe_image` 工具，避免重复。

**Q: 安装后一定要立即配置 endpoint 吗？**

A: 不强制。全家桶聚合包默认无配置挂载，加载不受影响；首次调用会以 `describe-image: baseURL must be an absolute http(s) URL` 错误退出，到「设置 → 插件配置 → Image understanding」卡填好端点、模型、密钥即可使用，无需重启。

**Q: 怎么切换视觉模型协议（OpenAI 风格、Anthropic 风格）？**

A: 设置卡的「API style」字段控制：`chat-completions`（默认）请求 `/chat/completions`；`responses` 适配 OpenAI Responses API；`anthropic-messages` 用于 Claude 风格端点（OpenCode Go、智谱 GLM、月之暗面 Kimi 等），走 `/v1/messages` 并使用 `x-api-key` 鉴权。

**Q: 模型 id 后面的 :off / :low / :medium / :high 是什么意思？**

A: 思考控制后缀。`:off` 显式关闭思考，`:low` `:medium` `:high` 开启思考（chat-completions 协议三档都映射为 enabled，因为该协议没有 effort 档）；不带后缀则不发送控制字段，沿用端点默认。仅这四个已知后缀会被剥离，其他冒号变体（如 OpenRouter 的 `:free`）会原样转发。

**Q: API key 应该怎么放？**

A: 推荐走环境变量：把密钥放到环境变量 `VISION_API_KEY`（或 `apiKeyEnv` 自定义名），用 `!!js process.env.VISION_API_KEY` 注入到 cordis 配置；插件在每次调用时按「内联 apiKey → 凭证服务（dsh-credentials）→ 启动环境」三级回退解析，密钥不会出现在请求体里，也不会进入日志。

**Q: 「会话内渲染图片预览」开关要不要开？**

A: 默认开（renderImagePreview: true）。开启后客户端会把发送的 describe-image 引用原地升级为缩略图，点击查看大图；关闭则保留原始引用文本。两者都只是显示层差异，对消息文本与模型分析没有影响。如果反向代理没转发 `/describe-image/raw` 路由，缩略图会加载失败，文本仍按原样保留。

**Q: 怎么让其他视觉插件接管图片处理？**

A: 关闭设置卡的「发送时改写图片为 describe-image 引用」开关（interceptImageSend: false）。关闭后带图片的发送原样放行，由同会话的其他视觉插件接收原始图片块；此时纯文本模型的改写需要由它们自己负责。

**Q: 一个调用能传多张图或获取结构化结果吗？**

A: 不支持。插件只支持单图单答：不接受多图输入、不能追问上一张图、不输出坐标或框选这类结构化字段；纯 OCR 场景可以把 `baseURL` 指向更便宜的 OCR 模型降低单次成本。

## 上手难度
进阶 — 多数场景安装即用，但要发挥多协议 / 思考控制 / 原生图片切换这些能力需要理解视觉模型协议差异与会话模型能力，零基础用户可能需要先读 README 才能用对设置项。

## 已知问题与限制
- 仅 magic-byte 门校验类型、不解码图片：头合法但内容损坏的文件会在视觉端点才报错（README.md:177-178）。
- 单图单答：不支持多图输入、追问上一张图、结构化输出（坐标 / 框）（README.md:179-180）。
- 三种协议固定：仅支持 Chat Completions、Responses、Anthropic Messages——其他请求 / 响应形态的厂商需要新增适配器（README.md:182-184）。
- 思考后缀是插件简写，会向请求注入厂商专用字段（`thinking.type` / `reasoning.effort`）；不接受这些字段的端点（如普通 OpenAI 视觉模型）应使用不带后缀的模型 id（README.md:185-191）。
- 模型能力探测保守失败：探测失败时一律按「不接受图片」处理，沿用改写路径，避免误判导致原图被送给纯文本模型后被宿主拒绝（`MODEL_DOES_NOT_SUPPORT_IMAGES`）（src/model-capability.ts:18-22）。

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-web-ui](https://deepseek-plugin.org/plugins/zhu1090093659/dsh-web-ui/packages/dsh-tool-describe-image)
Wiki generated by AI (model: `MiniMax-M3`)
