dsh-vision-router 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +268 -0
- package/README.zh.md +268 -0
- package/assets/dsh-conversation-image-qa-result.png +0 -0
- package/assets/dsh-conversation-image-qa.png +0 -0
- package/assets/hero-zh.svg +41 -0
- package/assets/hero.svg +122 -0
- package/assets/how-it-works-zh.svg +1 -0
- package/assets/how-it-works.svg +1 -0
- package/assets/pixel-loop-zh.png +0 -0
- package/assets/pixel-loop.png +0 -0
- package/assets/vision-demo.gif +0 -0
- package/assets/vision-settings.png +0 -0
- package/assets/vision-tools-zh.svg +4 -0
- package/assets/vision-tools.svg +4 -0
- package/cordis.patch.yml +25 -0
- package/docs/free-models.zh-CN.md +166 -0
- package/index.js +3201 -0
- package/lib/client.js +866 -0
- package/package.json +75 -0
- package/presets/README.md +33 -0
- package/presets/dashscope.yaml +18 -0
- package/presets/openrouter.yaml +17 -0
- package/presets/ovh.yaml +14 -0
- package/presets/siliconflow.yaml +18 -0
- package/presets/zhipu.yaml +18 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-vision-router contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/hero.svg" width="100%" alt="DSH Vision Router — eyes for text-only DeepSeek Harness agents" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">dsh-vision-router</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>Paste an image and it just works — eyes for text-only agents on DeepSeek Harness. Free out of the box, no key, no Python, one command.</strong></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">DeepSeek keeps thinking; the built-in free vision chain and ten pixel-level tools do the seeing. Image turns behave like ordinary tool-calling turns — grounded, measurable, repeatable.</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin" /></a>
|
|
13
|
+
<a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.0.0"><img src="https://img.shields.io/badge/release-v1.0.0-5B4CF0?style=flat-square" alt="Release v1.0.0" /></a>
|
|
14
|
+
<a href="tests"><img src="https://img.shields.io/badge/verified-86%20tests-2EA44F?style=flat-square" alt="Verified: 86 tests" /></a>
|
|
15
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
|
|
16
|
+
<a href="package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >=22" /></a>
|
|
17
|
+
<img src="https://img.shields.io/badge/runtime-no%20Python-8A2BE2?style=flat-square" alt="No Python" />
|
|
18
|
+
<a href="cordis.patch.yml"><img src="https://img.shields.io/badge/DSH-Web%20profile-5B4CF0?style=flat-square" alt="DSH Web profile" /></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">English · <a href="README.zh.md">中文</a></p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="assets/vision-demo.gif" width="640" alt="Demo: paste an image, the agent locates the send button with vision_ground / vision_crop / vision_pixel_diff and answers with coordinates" />
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
## Why this exists
|
|
28
|
+
|
|
29
|
+
Most DSH vision plugins bridge images to DeepSeek as *text descriptions* — lossy, one-shot, and blind to pixels. This plugin keeps the **original pixels on the vision model's side** and DeepSeek on the reasoning side, and makes looking at an image an **ordinary tool call**:
|
|
30
|
+
|
|
31
|
+
- **One command install.** The package ships its own composition patch (`dsh.bundle.patch`): `dsh plugin add` wires the row, the admission wrapper, the stealth takeover and the attachment limits automatically — zero manual file edits.
|
|
32
|
+
- **Free by default.** The vision chain starts with a built-in OVHcloud anonymous endpoint (`Qwen2.5-VL-72B-Instruct`, no account, no key, 2 req/min per IP). Paid chains (OpenRouter, Pi-AI providers, direct OpenAI-compatible endpoints) are optional upgrades.
|
|
33
|
+
- **No Python.** The whole pipeline — downscale, grounding, crop, pixel diff, palette, OCR, SVG trace, cutout, HTML screenshot — runs on sharp / potrace / tesseract / system Chrome.
|
|
34
|
+
- **Continuous multi-step image work.** An image turn is a text turn that calls tools: `vision_ground` → `vision_crop` → `vision_describe` → `vision_pixel_diff` → fix → screenshot again. The agent keeps iterating until the work is done.
|
|
35
|
+
- **DeepSeek stays the brain.** Text turns are untouched in model, cost and context. The vision model is only the eyes, called on demand; answers are cached by image content.
|
|
36
|
+
- **Transparent to the user.** Uploaded images keep rendering as images in the conversation UI; the rewrite that points the model at the vision tools happens only inside the model call, never in the session log.
|
|
37
|
+
|
|
38
|
+
## How it compares
|
|
39
|
+
|
|
40
|
+
The closest alternative is [@anionex/dsh-vision-toolkit](https://github.com/Anionex/dsh-vision-toolkit) (Anionex), a native DSH bundle of the well-known `agent-vision-toolkit` lineage. Both packages ship a `vision-tools` skill and a family of pixel-level tools; they differ in philosophy — **zero-config paste-and-go** versus **agent-driven visual engineering**:
|
|
41
|
+
|
|
42
|
+
| | dsh-vision-router | @anionex/dsh-vision-toolkit |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Image Q&A out of the box | ✅ Built-in free chain (anonymous OVHcloud endpoint) — no account, no key | Requires your own vision API key (local pixel tools work without one) |
|
|
45
|
+
| Runtime | ✅ Node only — no Python | Python 3.11+ managed runtime |
|
|
46
|
+
| Getting an image in | ✅ Paste it — the turn auto-routes to the vision chain and auto-mounts the tools | Workspace path + `/vision-tools` command, then explicit tool calls |
|
|
47
|
+
| Turn routing | ✅ Image turns switch to vision, text turns switch back to DeepSeek — stealth takeover, the model picker looks stock | Tool-driven; no whole-turn auto-routing |
|
|
48
|
+
| Profiles | Web | Web + Headless |
|
|
49
|
+
| Playbooks | The pixel loop: ground → crop → diff → fix → screenshot again | Richer case library (long-screenshot OCR, UI restoration, GUI automation) |
|
|
50
|
+
| Tests | 86 | 162 |
|
|
51
|
+
| Install | One command | One command (npm) |
|
|
52
|
+
|
|
53
|
+
Both are MIT-licensed and one command away. Pick this plugin when you want images to *just work* with zero setup; pick theirs when you need headless profiles or the extended playbook library. (Feature comparison reflects their README as of 2026-08.)
|
|
54
|
+
|
|
55
|
+
## Quick start
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
dsh plugin --profile web add github:ysr666/dsh-vision-router
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Restart `dsh web` — done. Zero configuration:
|
|
62
|
+
|
|
63
|
+
- the plugin's bundle patch mounts the row, takes over the official DeepSeek route (stealth mode — the model picker looks exactly like stock), and relaxes attachment limits to 20 MB / 100 MP;
|
|
64
|
+
- the default vision chain is the built-in free endpoint;
|
|
65
|
+
- every setting is editable live in **Settings → Plugins → Plugin config → 视觉路由(自动识图)**.
|
|
66
|
+
|
|
67
|
+
Then just paste an image into a conversation. The agent mounts the vision tools automatically and looks at it through `vision_describe` (and friends) — multi-step if needed.
|
|
68
|
+
|
|
69
|
+
### See it in action
|
|
70
|
+
|
|
71
|
+
*Left: an image turn — the user sends a picture, the agent calls `vision_describe` through the free chain and answers. Right: the finished structured answer.*
|
|
72
|
+
|
|
73
|
+
<p align="center">
|
|
74
|
+
<img src="assets/dsh-conversation-image-qa.png" width="49%" alt="A conversation turn in which the agent looks at an uploaded image through vision_describe." />
|
|
75
|
+
<img src="assets/dsh-conversation-image-qa-result.png" width="49%" alt="The agent's structured answer describing the image content." />
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
## Highlights
|
|
79
|
+
|
|
80
|
+
- **Original pixels, real answers.** The vision chain reads the image at original resolution (auto-downscaled only to protect latency/quota); the agent's question travels with the image, so answers are about *your* question, not a generic description.
|
|
81
|
+
- **Automatic failover with classified errors.** Region blocks, ToS filtering, 402 quota, 429 rate limits (with Retry-After backoff), context overflow, network failures — the chain walks providers one by one and only reports after all of them failed, with actionable advice.
|
|
82
|
+
- **Image memory.** Vision answers are cached by attachment content hash; later text turns substitute the recorded description (marked as untrusted evidence), so DeepSeek genuinely remembers earlier images without re-spending vision calls.
|
|
83
|
+
- **A verifiable pixel loop.** Reference → `vision_html_screenshot` → `vision_pixel_diff` (ratio + red heatmap + worst-region ranking) → fix → repeat until the mismatch converges. UI restoration becomes measurable instead of eyeballed.
|
|
84
|
+
- **Progressive schema exposure.** Only a zero-arg `vision_activate` bootstrap is always visible; image turns auto-mount all ten deep tools with a one-time usage note, and a `vision-tools` skill is registered for text-only turns.
|
|
85
|
+
- **Selective proxy.** Only the configured vision provider hosts go through your local proxy; DeepSeek stays direct.
|
|
86
|
+
|
|
87
|
+
### Pixel loop in practice
|
|
88
|
+
|
|
89
|
+
<p align="center">
|
|
90
|
+
<img src="assets/pixel-loop.png" width="100%" alt="Reference design and final agent rebuild, verified with vision_pixel_diff at 2.54% final difference." />
|
|
91
|
+
</p>
|
|
92
|
+
|
|
93
|
+
The agent rebuilt the UI from the reference image, then verified the final result with `vision_pixel_diff`: **2.54% final diff** (32,939 / 1,296,000 differing pixels, threshold 16/channel).
|
|
94
|
+
|
|
95
|
+
## How it works
|
|
96
|
+
|
|
97
|
+
<p align="center">
|
|
98
|
+
<img src="assets/how-it-works.svg" width="100%" alt="How DSH Vision Router keeps DeepSeek as the brain and vision tools as the eyes." />
|
|
99
|
+
</p>
|
|
100
|
+
|
|
101
|
+
The vision model is **only the eyes**; DeepSeek is **always the brain**. An image turn is never hijacked by a one-shot vision answer — the agent drives the tools itself and can keep operating on the image across as many steps as the task needs.
|
|
102
|
+
|
|
103
|
+
## Tools
|
|
104
|
+
|
|
105
|
+
All ten deep tools mount automatically on image turns (`autoActivateOnImage`); text turns can mount them via `vision_activate` or the `/vision-tools` skill. Built on sharp / potrace / tesseract / system Chrome — no Python:
|
|
106
|
+
|
|
107
|
+
<p align="center">
|
|
108
|
+
<img src="assets/vision-tools.svg" width="100%" alt="Nine vision tools available in DSH Vision Router." />
|
|
109
|
+
</p>
|
|
110
|
+
|
|
111
|
+
| Tool | What it does | Artifact |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `vision_describe` | Image Q&A / multi-image compare / structured-evidence JSON mode (summary + layout regions + entity inventory + verbatim transcription) | — |
|
|
114
|
+
| `vision_ground` | Locate a target → **original-pixel box x1/y1/x2/y2** | annotated PNG (optional) |
|
|
115
|
+
| `vision_detect` | Numbered inventory of every element of a kind (buttons/inputs/links…) with original-pixel boxes | annotated PNG with numbered boxes |
|
|
116
|
+
| `vision_crop` | Crop and zoom into a pixel box | PNG |
|
|
117
|
+
| `vision_pixel_diff` | Per-pixel comparison: diff ratio + worst 8×8-grid regions | red heatmap PNG + JSON report |
|
|
118
|
+
| `vision_colors` | Dominant colors (hex + share) | — |
|
|
119
|
+
| `vision_ocr` | Text transcription: local tesseract (chi_sim+eng) first, vision model fallback | — |
|
|
120
|
+
| `vision_trace` | SVG vectorization (potrace posterization; icons/logos) | SVG |
|
|
121
|
+
| `vision_extract_foreground` | Cutout via border flood fill (uniform backgrounds) | transparent PNG |
|
|
122
|
+
| `vision_html_screenshot` | Screenshot a local HTML file (headless system Chrome) | PNG |
|
|
123
|
+
|
|
124
|
+
Formats are sniffed from magic bytes, so extensionless content-addressed attachment files work everywhere (no `.png` renaming needed).
|
|
125
|
+
|
|
126
|
+
**Common workflows**
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
vision_ground image="ref.png" target="the send button"
|
|
130
|
+
vision_detect image="page.png" target="input fields"
|
|
131
|
+
vision_crop image="ref.png" region="1067,841,1108,881"
|
|
132
|
+
vision_describe paths=["ref.png","impl.png"] question="list the differences" json=true
|
|
133
|
+
vision_pixel_diff original="ref.png" rebuilt="screenshot.png"
|
|
134
|
+
vision_ocr image="screenshot.png"
|
|
135
|
+
vision_colors image="ref.png" top=8
|
|
136
|
+
vision_trace image="icon.png" steps=4
|
|
137
|
+
vision_extract_foreground image="logo.png"
|
|
138
|
+
vision_html_screenshot source="page.html" width=1200 height=720
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Provider fallback chain
|
|
142
|
+
|
|
143
|
+
The vision chain walks providers in order and only surfaces an error after every one failed:
|
|
144
|
+
|
|
145
|
+
1. the **built-in free endpoint** (`vision-http` → `ovh/Qwen2.5-VL-72B-Instruct`) — no key, best-effort, 2 req/min per IP;
|
|
146
|
+
2. configured `httpProviders` (direct OpenAI-compatible endpoints with optional `apiKeyEnv`);
|
|
147
|
+
3. configured `providers` / `provider` + `fallbacks` (any adapter-backed provider, e.g. a Pi-AI profile like OpenRouter or Zhipu).
|
|
148
|
+
|
|
149
|
+
> In the legacy `routing: true` mode, the whole-turn chain walks only `provider + fallbacks` — `httpProviders` (including the free fallback) do not participate there. The default `routing: false` (tools-first) tries everything.
|
|
150
|
+
|
|
151
|
+
Failures are classified (region / tos / quota / rate-limit / context / network) and the final error carries advice; `429` responses honor `Retry-After` once with a capped backoff. Oversized uploads are downscaled before the call (default budget 4 MP) to keep tool calls fast.
|
|
152
|
+
|
|
153
|
+
## Stealth mode
|
|
154
|
+
|
|
155
|
+
A default install takes over the official `deepseek-official` route: the model picker looks exactly like stock (same DeepSeek group, same model names), but each entry is the auto-vision wrapper that declares image input and delegates text turns to a rebuilt native DeepSeek adapter (same `llm-deepseek` settings section and credentials). Old sessions keep working through the hidden `deepseek-vision` alias.
|
|
156
|
+
|
|
157
|
+
To keep the stock row instead, override it in your profile patch layer (`~/.dsh/profiles/<profile>/cordis.patch.yml`):
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
- id: llm-deepseek
|
|
161
|
+
name: '@deepseek-ai/dsh-llm-deepseek'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
With the stock row present, the plugin falls back to the visible "DeepSeek + 自动识图" wrapper entry — pick it in the model picker for image turns. Recovery from a broken install is the same one-line override.
|
|
165
|
+
|
|
166
|
+
## Web settings
|
|
167
|
+
|
|
168
|
+
The Web profile registers a **视觉路由(自动识图)** card under **Settings → Plugins → Plugin config**, styled like the built-in cards. It live-edits:
|
|
169
|
+
|
|
170
|
+
- switches: whole-turn legacy routing, vision tools, image-block rewriting, stealth;
|
|
171
|
+
- vision request timeout, wrapper/chain route names;
|
|
172
|
+
- the **vision chain** (one `provider/model` per line, top-down fallback) and the text model;
|
|
173
|
+
- every field shows an "overridden" badge with a one-click reset to the composition default, plus discard/save.
|
|
174
|
+
|
|
175
|
+
<p align="center">
|
|
176
|
+
<img src="assets/vision-settings.png" width="72%" alt="The vision-router card in Settings > Plugins > Plugin config." />
|
|
177
|
+
</p>
|
|
178
|
+
|
|
179
|
+
> PR [#8](https://github.com/ysr666/dsh-vision-router/pull/8) upgrades the panel with catalog-driven model dropdowns, add/remove fallback rows, and proxy settings.
|
|
180
|
+
|
|
181
|
+
## Configuration
|
|
182
|
+
|
|
183
|
+
Everything is optional; defaults work out of the box. Edit via the Web card or a profile patch:
|
|
184
|
+
|
|
185
|
+
| Field | Default | Meaning |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| `provider` / `model` | `vision-http` / `ovh/Qwen2.5-VL-72B-Instruct` | shorthand chain (adapter-backed provider + model) |
|
|
188
|
+
| `fallbacks` | `[]` | backup models for the shorthand provider |
|
|
189
|
+
| `providers` | `[]` | multi-provider chain `{ provider, model, fallbacks[] }`, tried in order; wins over the shorthand |
|
|
190
|
+
| `httpProviders` | built-in OVH entry | direct OpenAI-compatible endpoints `{ name, baseURL, model, apiKeyEnv, maxTokens }` |
|
|
191
|
+
| `routing` | `false` | legacy whole-turn chain routing (one-shot answer). `false` = tools-first flow (recommended) |
|
|
192
|
+
| `reverseRouting` | `true` | with `routing: true`, route text turns back to `textProvider` |
|
|
193
|
+
| `wrapperRoute` / `chainRoute` | `deepseek-vision` / `vision-chain` | admission wrapper route name / fallback chain route name (empty disables) |
|
|
194
|
+
| `stealth` | `true` | take over the official `deepseek-official` route |
|
|
195
|
+
| `textProvider` | `deepseek-official` / `deepseek-v4-pro` | the model that reasons (your daily model) |
|
|
196
|
+
| `tool` / `progressiveTools` / `autoActivateOnImage` | `true` ×3 | vision tools on / progressive mounting / auto-mount on image turns |
|
|
197
|
+
| `rewriteImages` | `true` | rewrite image blocks in the model input (cached description or tool-hint marker); the UI log keeps images |
|
|
198
|
+
| `downscale` / `downscaleMaxPixels` | `true` / `4000000` | pre-call downscale and its pixel budget (latency guard) |
|
|
199
|
+
| `cache` / `cacheTtlSeconds` / `cacheMaxEntries` | `true` / `3600` / `200` | vision answer cache |
|
|
200
|
+
| `timeoutMs` | `120000` | per vision call deadline |
|
|
201
|
+
| `artifactsDir` | `.dsh-vision-router/artifacts` | artifact directory (relative to the session workspace) |
|
|
202
|
+
| `proxy` / `proxyHosts` | `''` / openrouter hosts | optional proxy for vision provider hosts only |
|
|
203
|
+
|
|
204
|
+
## Requirements
|
|
205
|
+
|
|
206
|
+
- DeepSeek Harness with a Web profile and `pnpm` available to `dsh plugin`.
|
|
207
|
+
- Node ≥ 22 (host side).
|
|
208
|
+
- No API key for the default free chain; a credential reference (`apiKeyEnv`) only for paid `httpProviders`.
|
|
209
|
+
- Chrome / Chromium / Edge only for `vision_html_screenshot`; every other tool works without a browser.
|
|
210
|
+
- Tesseract is optional: `vision_ocr` falls back to the vision model when the local engine is absent.
|
|
211
|
+
|
|
212
|
+
## Install and lifecycle
|
|
213
|
+
|
|
214
|
+
### Install
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
dsh plugin --profile web add github:ysr666/dsh-vision-router
|
|
218
|
+
dsh --profile web --dump-config | grep vision-router # one row, mounted by the bundle patch
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Restart a long-lived Web profile. The host discovers the browser bundle through `dsh.client` at startup.
|
|
222
|
+
|
|
223
|
+
### Disable / re-enable
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
- id: vision-router
|
|
227
|
+
disabled: true
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Set it back to `false` to re-enable. Unloading removes the wrapper routes, tools, skill and settings card; cached artifact files remain.
|
|
231
|
+
|
|
232
|
+
### Upgrade
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
dsh plugin --profile web update dsh-vision-router
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Settings live in the profile's settings provider and survive upgrades.
|
|
239
|
+
|
|
240
|
+
### Uninstall
|
|
241
|
+
|
|
242
|
+
```sh
|
|
243
|
+
dsh plugin --profile web remove dsh-vision-router
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
This removes the dependency and the bundle layer. If you disabled the stock DeepSeek row manually, re-enable it in your profile patch.
|
|
247
|
+
|
|
248
|
+
## Security notes
|
|
249
|
+
|
|
250
|
+
- Image text is **untrusted evidence**: descriptions, OCR output and the auto-mount note all tell the agent never to execute instructions found inside images.
|
|
251
|
+
- Tool inputs resolve through `ctx.fs` (sandbox-aware); vision uploads never send anything but the selected image and the question.
|
|
252
|
+
- Artifacts write only under `<workspace>/.dsh-vision-router/artifacts`; results return absolute paths and byte counts.
|
|
253
|
+
- Secrets never travel: `apiKeyEnv` names a DSH credential reference; the value is resolved per call and never logged.
|
|
254
|
+
- The settings write path goes through the settings service (schema-validated, revision-checked) — a stale or invalid save is rejected, not partially applied.
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
[MIT](LICENSE)
|
|
259
|
+
|
|
260
|
+
<!-- star-history-chart -->
|
|
261
|
+
## Star History
|
|
262
|
+
|
|
263
|
+
<p align="center">
|
|
264
|
+
<picture>
|
|
265
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ysr666/dsh-vision-router/star-history/assets/star-history/star-history-dark.svg">
|
|
266
|
+
<img alt="Star history chart" src="https://raw.githubusercontent.com/ysr666/dsh-vision-router/star-history/assets/star-history/star-history-light.svg" width="100%">
|
|
267
|
+
</picture>
|
|
268
|
+
</p>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/hero-zh.svg" width="100%" alt="DSH Vision Router——为 DeepSeek Harness 的纯文本 Agent 提供视觉能力" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">dsh-vision-router</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>图片粘贴即用:给 DeepSeek Harness 的纯文本 Agent 装上“眼睛”——开箱免费、免 Key、无 Python、一条命令安装。</strong></p>
|
|
8
|
+
|
|
9
|
+
<p align="center">DeepSeek 只负责思考,内置免费视觉链 + 10 个像素级工具负责“看”;图片轮次就像普通工具调用一样自然、可定位、可验证。</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin" /></a>
|
|
13
|
+
<a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.0.0"><img src="https://img.shields.io/badge/release-v1.0.0-5B4CF0?style=flat-square" alt="Release v1.0.0" /></a>
|
|
14
|
+
<a href="tests"><img src="https://img.shields.io/badge/verified-86%20tests-2EA44F?style=flat-square" alt="Verified: 86 tests" /></a>
|
|
15
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
|
|
16
|
+
<a href="package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >=22" /></a>
|
|
17
|
+
<img src="https://img.shields.io/badge/runtime-no%20Python-8A2BE2?style=flat-square" alt="No Python" />
|
|
18
|
+
<a href="cordis.patch.yml"><img src="https://img.shields.io/badge/DSH-Web%20profile-5B4CF0?style=flat-square" alt="DSH Web profile" /></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center"><a href="README.md">English</a> · 中文</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="assets/vision-demo.gif" width="640" alt="演示:粘贴图片,Agent 用 vision_ground / vision_crop / vision_pixel_diff 定位发送按钮并给出坐标" />
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
## 为什么做这个
|
|
28
|
+
|
|
29
|
+
大多数 DSH 视觉插件把图片“翻译”成一段文字描述再喂给 DeepSeek——有损、一次性、看不见像素。本插件把**原图像素留在视觉模型侧**、把推理留在 DeepSeek 侧,并把“看图”变成一次**普通的工具调用**:
|
|
30
|
+
|
|
31
|
+
- **一条命令安装。** 包自带组合补丁(`dsh.bundle.patch`):`dsh plugin add` 自动完成插件行挂载、准入包装、隐身接管与附件限制放宽——不用手改任何文件。
|
|
32
|
+
- **默认免费。** 视觉链内置 OVHcloud 匿名端点(`Qwen2.5-VL-72B-Instruct`,免注册、免 Key,每 IP 2 次/分钟)。付费链路(OpenRouter、Pi-AI 供应商、任意 OpenAI 兼容直连端点)是可选升级。
|
|
33
|
+
- **无 Python。** 整条管线——缩放、定位、裁剪、像素对比、取色、OCR、SVG 矢量化、抠图、HTML 截图——全部基于 sharp / potrace / tesseract / 系统 Chrome。
|
|
34
|
+
- **可连续多步看图。** 图片轮 = 调用工具的文本轮:`vision_ground` → `vision_crop` → `vision_describe` → `vision_pixel_diff` → 修复 → 再截图,Agent 可以一直迭代到任务完成。
|
|
35
|
+
- **DeepSeek 始终是大脑。** 文字轮在模型、成本、上下文上完全不动;视觉模型只当“眼睛”、按需调用,答案按图片内容缓存。
|
|
36
|
+
- **界面无感。** 上传的图片在会话界面里照常显示为图片;指向视觉工具的改写只发生在模型输入层,从不写入会话日志。
|
|
37
|
+
|
|
38
|
+
## 对比同类插件
|
|
39
|
+
|
|
40
|
+
最接近的同类是 [@anionex/dsh-vision-toolkit](https://github.com/Anionex/dsh-vision-toolkit)(Anionex),它是知名 `agent-vision-toolkit` 系列的 DSH 原生版。两者都提供 `vision-tools` 技能和一组像素级工具,区别在理念:**零配置粘贴即用** vs **Agent 主导的视觉工程**:
|
|
41
|
+
|
|
42
|
+
| | dsh-vision-router | @anionex/dsh-vision-toolkit |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| 开箱图片问答 | ✅ 内置免费视觉链(OVHcloud 匿名端点),免注册免 Key | 远程工具需自备视觉 API Key(本地像素工具免 Key) |
|
|
45
|
+
| 运行时 | ✅ 纯 Node,无需 Python | 需要 Python 3.11+ 受管运行时 |
|
|
46
|
+
| 图片怎么进来 | ✅ 直接粘贴——轮次自动切视觉链并自动挂载工具 | 工作区路径 + `/vision-tools` 命令,再显式调用工具 |
|
|
47
|
+
| 轮次路由 | ✅ 图片轮切视觉、文本轮切回 DeepSeek——隐身接管,模型选择器与官方一致 | 工具驱动,无整轮自动路由 |
|
|
48
|
+
| 支持 profile | Web | Web + Headless |
|
|
49
|
+
| 玩法库 | 像素循环:定位 → 裁剪 → 对比 → 修复 → 再截图 | 更丰富的案例库(长截图 OCR、UI 还原、GUI 自动化) |
|
|
50
|
+
| 测试 | 86 | 162 |
|
|
51
|
+
| 安装 | 一条命令 | 一条命令(npm) |
|
|
52
|
+
|
|
53
|
+
两者都是 MIT 许可、一条命令安装。想要图片**粘贴即用**、零配置就选本插件;需要 Headless 部署或更丰富的案例库,可以看 @anionex/dsh-vision-toolkit。(功能对比以其 README 2026-08 状态为准。)
|
|
54
|
+
|
|
55
|
+
## 快速开始
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
dsh plugin --profile web add github:ysr666/dsh-vision-router
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
重启 `dsh web`——完成,零配置:
|
|
62
|
+
|
|
63
|
+
- 插件的 bundle 补丁自动挂载插件行、接管官方 DeepSeek 路由(隐身模式——模型选择器看起来和原版一模一样)、放宽附件限制到 20MB / 1 亿像素;
|
|
64
|
+
- 默认视觉链就是内置免费端点;
|
|
65
|
+
- 全部配置可在 **设置 → 插件 → 插件配置 → 视觉路由(自动识图)** 实时修改。
|
|
66
|
+
|
|
67
|
+
然后直接往对话里贴一张图。Agent 自动挂载视觉工具,通过 `vision_describe`(以及其余 8 个工具)看图,需要时连续多步。
|
|
68
|
+
|
|
69
|
+
### 实际效果
|
|
70
|
+
|
|
71
|
+
*左:一次图片轮——用户发图,Agent 通过免费链路调用 `vision_describe` 并作答。右:最终的结构化解读。*
|
|
72
|
+
|
|
73
|
+
<p align="center">
|
|
74
|
+
<img src="assets/dsh-conversation-image-qa.png" width="49%" alt="Agent 通过 vision_describe 查看上传图片的对话轮次。" />
|
|
75
|
+
<img src="assets/dsh-conversation-image-qa-result.png" width="49%" alt="Agent 对图片内容的结构化解读。" />
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
## 亮点
|
|
79
|
+
|
|
80
|
+
- **原图像素,真实答案。** 视觉链按原始分辨率读图(仅为保护延迟/额度自动缩放);你的问题随图一起发送,答案围绕*你的问题*,而不是一段泛泛的描述。
|
|
81
|
+
- **自动降级 + 分类报错。** 地区限制、ToS 风控、402 额度、429 限流(尊重 Retry-After 退避重试)、上下文超长、网络故障——链路逐供应商尝试,全部失败才报错并给出可操作的建议。
|
|
82
|
+
- **图片记忆。** 视觉答案按附件内容哈希缓存;后续文字轮用记录的描述替换历史图片(标注为不可信证据),DeepSeek 真正“记得”之前发过的图,且不重复消耗视觉调用。
|
|
83
|
+
- **可验证的像素闭环。** 参照图 → `vision_html_screenshot` → `vision_pixel_diff`(差异率 + 红色热力图 + 最差区域排行)→ 修复 → 再对比,直到差异收敛。UI 还原从“目测”变成“实测”。
|
|
84
|
+
- **渐进式 schema 暴露。** 平时只有一个零参引导工具 `vision_activate`;图片轮自动挂载全部 10 个深看工具(附一次性使用提示),并为纯文字轮注册 `vision-tools` 技能。
|
|
85
|
+
- **选择性代理。** 只有配置的视觉供应商域名走本地代理;DeepSeek 保持直连。
|
|
86
|
+
|
|
87
|
+
### 像素闭环实测
|
|
88
|
+
|
|
89
|
+
<p align="center">
|
|
90
|
+
<img src="assets/pixel-loop-zh.png" width="100%" alt="参考设计与 Agent 最终复刻,通过 vision_pixel_diff 实测最终差异为 2.54%。" />
|
|
91
|
+
</p>
|
|
92
|
+
|
|
93
|
+
Agent 仅根据参考图复刻 UI,再用 `vision_pixel_diff` 验证最终结果:**最终差异 2.54%**(32,939 / 1,296,000 个差异像素,threshold 16/channel)。
|
|
94
|
+
|
|
95
|
+
## 工作原理
|
|
96
|
+
|
|
97
|
+
<p align="center">
|
|
98
|
+
<img src="assets/how-it-works-zh.svg" width="100%" alt="DSH Vision Router 的工作原理:DeepSeek 作为大脑,视觉工具作为眼睛。" />
|
|
99
|
+
</p>
|
|
100
|
+
|
|
101
|
+
视觉模型**只当眼睛**,DeepSeek **始终是大脑**。图片轮永远不会被一次性视觉答案“劫持”——Agent 自己驱动工具,可以跨多个步骤持续对同一张图操作。
|
|
102
|
+
|
|
103
|
+
## 工具
|
|
104
|
+
|
|
105
|
+
10 个深看工具在图片轮自动挂载(`autoActivateOnImage`);文字轮可通过 `vision_activate` 或 `/vision-tools` 技能挂载。全部基于 sharp / potrace / tesseract / 系统 Chrome——无 Python:
|
|
106
|
+
|
|
107
|
+
<p align="center">
|
|
108
|
+
<img src="assets/vision-tools-zh.svg" width="100%" alt="DSH Vision Router 的 10 个视觉工具。" />
|
|
109
|
+
</p>
|
|
110
|
+
|
|
111
|
+
| 工具 | 作用 | 产物 |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `vision_describe` | 看图问答 / 多图对比 / 结构化证据 JSON 模式(摘要 + 布局区域 + 实体清单 + 原文转写) | — |
|
|
114
|
+
| `vision_ground` | 定位目标 → **原图像素框 x1/y1/x2/y2** | 标注 PNG(可选) |
|
|
115
|
+
| `vision_detect` | 盘点某类元素(按钮/输入框/链接…)→ 编号清单 + 原图像素框 | 编号标注 PNG |
|
|
116
|
+
| `vision_crop` | 按像素框裁剪放大 | PNG |
|
|
117
|
+
| `vision_pixel_diff` | 逐像素对比:差异率 + 最差 8×8 网格区域 | 红色热力图 PNG + JSON 报告 |
|
|
118
|
+
| `vision_colors` | 主色提取(十六进制 + 占比) | — |
|
|
119
|
+
| `vision_ocr` | 文字转写:本地 tesseract(中英)优先,视觉模型兜底 | — |
|
|
120
|
+
| `vision_trace` | SVG 矢量化(potrace 分色;图标/logo) | SVG |
|
|
121
|
+
| `vision_extract_foreground` | 边界洪泛抠图(纯色背景) | 透明 PNG |
|
|
122
|
+
| `vision_html_screenshot` | 给本地 HTML 文件截图(无头系统 Chrome) | PNG |
|
|
123
|
+
|
|
124
|
+
图片格式按**魔数识别**,无扩展名的内容寻址附件文件也能直接用(不用再复制成 `.png`)。
|
|
125
|
+
|
|
126
|
+
**常用流程**
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
vision_ground image="ref.png" target="发送按钮"
|
|
130
|
+
vision_detect image="page.png" target="输入框"
|
|
131
|
+
vision_crop image="ref.png" region="1067,841,1108,881"
|
|
132
|
+
vision_describe paths=["ref.png","impl.png"] question="列出两图的差异" json=true
|
|
133
|
+
vision_pixel_diff original="ref.png" rebuilt="screenshot.png"
|
|
134
|
+
vision_ocr image="screenshot.png"
|
|
135
|
+
vision_colors image="ref.png" top=8
|
|
136
|
+
vision_trace image="icon.png" steps=4
|
|
137
|
+
vision_extract_foreground image="logo.png"
|
|
138
|
+
vision_html_screenshot source="page.html" width=1200 height=720
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 供应商降级链
|
|
142
|
+
|
|
143
|
+
视觉链按顺序逐个尝试,全部失败才报错:
|
|
144
|
+
|
|
145
|
+
1. **内置免费端点**(`vision-http` → `ovh/Qwen2.5-VL-72B-Instruct`)——免 Key、尽力而为、每 IP 2 次/分钟;
|
|
146
|
+
2. 配置的 `httpProviders`(OpenAI 兼容直连端点,可选 `apiKeyEnv`);
|
|
147
|
+
3. 配置的 `providers` / `provider` + `fallbacks`(任何有适配器的供应商,例如 Pi-AI 配置的 OpenRouter 或智谱)。
|
|
148
|
+
|
|
149
|
+
> 在旧版 `routing: true` 模式下,整轮链只走 `provider + fallbacks`——`httpProviders`(含免费兜底)不参与。默认的 `routing: false`(工具优先)会尝试全部。
|
|
150
|
+
|
|
151
|
+
失败会分类(地区 / 风控 / 额度 / 限流 / 上下文 / 网络),最终报错附带建议;`429` 会尊重 `Retry-After` 做一次有上限的退避重试。超大上传图在调用前自动压缩(默认预算 400 万像素),保证工具调用不卡。
|
|
152
|
+
|
|
153
|
+
## 隐身模式
|
|
154
|
+
|
|
155
|
+
默认安装即接管官方 `deepseek-official` 路由:模型选择器看起来和原版完全一样(同一个 DeepSeek 组、同样的模型名),但每个条目背后都是声明了图片输入的自动识图包装;文字轮交给插件重建的原生 DeepSeek 适配器(读取同一个 `llm-deepseek` 设置段与凭据)。老会话通过隐藏的 `deepseek-vision` 别名继续工作。
|
|
156
|
+
|
|
157
|
+
想保留官方行,在你的 profile 补丁层(`~/.dsh/profiles/<profile>/cordis.patch.yml`)覆写即可:
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
- id: llm-deepseek
|
|
161
|
+
name: '@deepseek-ai/dsh-llm-deepseek'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
官方行在场时,插件回退为选择器里可见的「DeepSeek + 自动识图」包装入口——发图前选它即可。安装出问题时同样用这一行恢复。
|
|
165
|
+
|
|
166
|
+
## Web 设置
|
|
167
|
+
|
|
168
|
+
Web 配置页在 **设置 → 插件 → 插件配置** 下注册「视觉路由(自动识图)」卡片,样式与内置卡片一致,可实时修改:
|
|
169
|
+
|
|
170
|
+
- 开关:整轮自动路由(旧模式)、识图工具、图片块改写、隐身模式;
|
|
171
|
+
- 视觉请求超时、包装/链路由名;
|
|
172
|
+
- **视觉模型链**(每行一个 `provider/model`,自上而下降级)与文本模型;
|
|
173
|
+
- 每个字段都有「已覆盖」徽标与一键恢复组合默认,以及放弃/保存。
|
|
174
|
+
|
|
175
|
+
<p align="center">
|
|
176
|
+
<img src="assets/vision-settings.png" width="72%" alt="设置 → 插件 → 插件配置 里的视觉路由卡片。" />
|
|
177
|
+
</p>
|
|
178
|
+
|
|
179
|
+
> PR [#8](https://github.com/ysr666/dsh-vision-router/pull/8) 会把面板升级为目录驱动的模型下拉框、可增删的备用模型行与代理设置。
|
|
180
|
+
|
|
181
|
+
## 配置项
|
|
182
|
+
|
|
183
|
+
全部可选,默认即可用。通过 Web 卡片或 profile 补丁修改:
|
|
184
|
+
|
|
185
|
+
| 字段 | 默认值 | 含义 |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| `provider` / `model` | `vision-http` / `ovh/Qwen2.5-VL-72B-Instruct` | 简写链路(有适配器的供应商 + 模型) |
|
|
188
|
+
| `fallbacks` | `[]` | 简写供应商的备用模型 |
|
|
189
|
+
| `providers` | `[]` | 多供应商链路 `{ provider, model, fallbacks[] }`,按序尝试;优先于简写形式 |
|
|
190
|
+
| `httpProviders` | 内置 OVH 条目 | OpenAI 兼容直连端点 `{ name, baseURL, model, apiKeyEnv, maxTokens }` |
|
|
191
|
+
| `routing` | `false` | 旧版整轮链路由(一次性整轮回答)。`false` = 工具优先流程(推荐) |
|
|
192
|
+
| `reverseRouting` | `true` | 开启 `routing` 时,文字轮路由回 `textProvider` |
|
|
193
|
+
| `wrapperRoute` / `chainRoute` | `deepseek-vision` / `vision-chain` | 准入包装路由名 / 降级链路由名(置空关闭) |
|
|
194
|
+
| `stealth` | `true` | 接管官方 `deepseek-official` 路由 |
|
|
195
|
+
| `textProvider` | `deepseek-official` / `deepseek-v4-pro` | 负责思考的模型(你的日常模型) |
|
|
196
|
+
| `tool` / `progressiveTools` / `autoActivateOnImage` | `true` ×3 | 视觉工具开关 / 渐进式挂载 / 图片轮自动挂载 |
|
|
197
|
+
| `rewriteImages` | `true` | 模型输入层改写图片块(缓存描述或工具提示标记);界面日志保留图片 |
|
|
198
|
+
| `downscale` / `downscaleMaxPixels` | `true` / `4000000` | 调用前压缩及其像素预算(延迟保护) |
|
|
199
|
+
| `cache` / `cacheTtlSeconds` / `cacheMaxEntries` | `true` / `3600` / `200` | 视觉答案缓存 |
|
|
200
|
+
| `timeoutMs` | `120000` | 单次视觉调用超时 |
|
|
201
|
+
| `artifactsDir` | `.dsh-vision-router/artifacts` | 产物目录(相对会话工作区) |
|
|
202
|
+
| `proxy` / `proxyHosts` | `''` / openrouter 域名 | 仅视觉供应商域名可选的本地代理 |
|
|
203
|
+
|
|
204
|
+
## 环境要求
|
|
205
|
+
|
|
206
|
+
- DeepSeek Harness 的 Web profile,且 `dsh plugin` 可用 `pnpm`。
|
|
207
|
+
- Node ≥ 22(宿主侧)。
|
|
208
|
+
- 默认免费链路无需 API Key;付费 `httpProviders` 只需一个凭据引用(`apiKeyEnv`)。
|
|
209
|
+
- `vision_html_screenshot` 才需要 Chrome / Chromium / Edge;其余工具无浏览器也能用。
|
|
210
|
+
- tesseract 可选:本地引擎缺失时 `vision_ocr` 自动退回视觉模型。
|
|
211
|
+
|
|
212
|
+
## 安装与生命周期
|
|
213
|
+
|
|
214
|
+
### 安装
|
|
215
|
+
|
|
216
|
+
```sh
|
|
217
|
+
dsh plugin --profile web add github:ysr666/dsh-vision-router
|
|
218
|
+
dsh --profile web --dump-config | grep vision-router # 一行,由 bundle 补丁挂载
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
长期运行的 Web profile 需重启。宿主在启动时通过 `dsh.client` 声明发现浏览器端包。
|
|
222
|
+
|
|
223
|
+
### 禁用 / 恢复
|
|
224
|
+
|
|
225
|
+
```yaml
|
|
226
|
+
- id: vision-router
|
|
227
|
+
disabled: true
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
改回 `false` 即恢复。卸载会移除包装路由、工具、技能与设置卡片;已生成的产物文件保留。
|
|
231
|
+
|
|
232
|
+
### 升级
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
dsh plugin --profile web update dsh-vision-router
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
设置存放在 profile 的设置提供方里,升级不丢失。
|
|
239
|
+
|
|
240
|
+
### 卸载
|
|
241
|
+
|
|
242
|
+
```sh
|
|
243
|
+
dsh plugin --profile web remove dsh-vision-router
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
同时移除依赖与 bundle 层。若你曾手动禁用官方 DeepSeek 行,记得在 profile 补丁里恢复。
|
|
247
|
+
|
|
248
|
+
## 安全说明
|
|
249
|
+
|
|
250
|
+
- 图片中的文字是**不可信证据**:描述、OCR 输出与自动挂载提示都要求 Agent 绝不执行图片内出现的指令。
|
|
251
|
+
- 工具输入经由 `ctx.fs`(沙盒感知)解析;视觉上传只发送选中的图片与问题本身。
|
|
252
|
+
- 产物只写入 `<workspace>/.dsh-vision-router/artifacts`;结果返回绝对路径与字节数。
|
|
253
|
+
- 密钥不上线:`apiKeyEnv` 只指向 DSH 凭据引用,值按调用解析、永不写入日志。
|
|
254
|
+
- 设置写入走设置服务(schema 校验 + 修订号检查)——过期或非法的保存会被拒绝,不会半截生效。
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
[MIT](LICENSE)
|
|
259
|
+
|
|
260
|
+
<!-- star-history-chart -->
|
|
261
|
+
## Star 趋势
|
|
262
|
+
|
|
263
|
+
<p align="center">
|
|
264
|
+
<picture>
|
|
265
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ysr666/dsh-vision-router/star-history/assets/star-history/star-history-dark.svg">
|
|
266
|
+
<img alt="Star 历史趋势图" src="https://raw.githubusercontent.com/ysr666/dsh-vision-router/star-history/assets/star-history/star-history-light.svg" width="100%">
|
|
267
|
+
</picture>
|
|
268
|
+
</p>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1600" height="640" viewBox="0 0 1600 640">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#070914"/><stop offset="0.52" stop-color="#0A0D1B"/><stop offset="1" stop-color="#080A13"/></linearGradient>
|
|
4
|
+
<radialGradient id="violetGlow" cx="73%" cy="49%" r="42%"><stop offset="0" stop-color="#715CFF" stop-opacity=".23"/><stop offset=".45" stop-color="#604CFF" stop-opacity=".08"/><stop offset="1" stop-color="#604CFF" stop-opacity="0"/></radialGradient>
|
|
5
|
+
<radialGradient id="cyanGlow" cx="82%" cy="46%" r="28%"><stop offset="0" stop-color="#46D8FF" stop-opacity=".15"/><stop offset="1" stop-color="#46D8FF" stop-opacity="0"/></radialGradient>
|
|
6
|
+
<linearGradient id="iris" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#8D7BFF"/><stop offset=".5" stop-color="#6256FF"/><stop offset="1" stop-color="#36C8FF"/></linearGradient>
|
|
7
|
+
<linearGradient id="route" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#695BFF"/><stop offset=".55" stop-color="#7B6DFF"/><stop offset="1" stop-color="#42D8FF"/></linearGradient>
|
|
8
|
+
<linearGradient id="chip" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#171B2C" stop-opacity=".95"/><stop offset="1" stop-color="#0D1020" stop-opacity=".95"/></linearGradient>
|
|
9
|
+
<filter id="glow"><feGaussianBlur stdDeviation="5" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
|
|
10
|
+
<filter id="softGlow"><feGaussianBlur stdDeviation="12" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
|
|
11
|
+
<pattern id="dots" width="34" height="34" patternUnits="userSpaceOnUse"><circle cx="1.4" cy="1.4" r="1.35" fill="#65708A" opacity=".12"/></pattern>
|
|
12
|
+
</defs>
|
|
13
|
+
<rect width="1600" height="640" rx="32" fill="url(#bg)"/><rect width="1600" height="640" rx="32" fill="url(#dots)" opacity=".45"/><rect width="1600" height="640" rx="32" fill="url(#violetGlow)"/><rect width="1600" height="640" rx="32" fill="url(#cyanGlow)"/>
|
|
14
|
+
<path d="M790 70 C980 15 1240 42 1515 180" fill="none" stroke="#8D7BFF" stroke-opacity=".08"/><path d="M780 575 C1020 620 1300 585 1510 425" fill="none" stroke="#47CFFF" stroke-opacity=".08"/><path d="M925 36 C1120 160 1380 132 1565 250" fill="none" stroke="#FFFFFF" stroke-opacity=".035"/>
|
|
15
|
+
<g transform="translate(92,86)">
|
|
16
|
+
<g><rect x="0" y="0" width="224" height="34" rx="17" fill="#111528" stroke="#7568FF" stroke-opacity=".42"/><circle cx="19" cy="17" r="4" fill="#6A5BFF" filter="url(#glow)"/><text x="33" y="22" fill="#BFB8FF" font-family="Inter, Arial, sans-serif" font-size="14" font-weight="700" letter-spacing="1.7">DEEPSEEK HARNESS</text></g>
|
|
17
|
+
<text x="0" y="101" fill="#F7F8FF" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="68" font-weight="800" letter-spacing="-2.2">DSH 视觉</text>
|
|
18
|
+
<text x="0" y="176" fill="url(#iris)" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="70" font-weight="800" letter-spacing="-2.2">路由器</text>
|
|
19
|
+
<text x="2" y="228" fill="#C7CCDB" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="24">给 DeepSeek 一双眼,而不是换一个大脑。</text>
|
|
20
|
+
<text x="2" y="277" fill="#7F889F" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="16.5">内置免费视觉链 · 自动故障切换 · 像素级工具</text>
|
|
21
|
+
<text x="2" y="306" fill="#7F889F" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="16.5">一条命令安装 · 无需注册 · 无需 API Key · 无需 Python</text>
|
|
22
|
+
<g transform="translate(0,355)" fill="#CFD5E6" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="14" font-weight="650">
|
|
23
|
+
<g><rect width="132" height="39" rx="12" fill="#111526" stroke="#252B42"/><circle cx="18" cy="19.5" r="4" fill="#50D890"/><text x="31" y="25">免费链路</text></g>
|
|
24
|
+
<g transform="translate(145,0)"><rect width="132" height="39" rx="12" fill="#111526" stroke="#252B42"/><circle cx="18" cy="19.5" r="4" fill="#7B6DFF"/><text x="31" y="25">自动路由</text></g>
|
|
25
|
+
<g transform="translate(290,0)"><rect width="132" height="39" rx="12" fill="#111526" stroke="#252B42"/><circle cx="18" cy="19.5" r="4" fill="#4CD5FF"/><text x="31" y="25">像素循环</text></g>
|
|
26
|
+
</g>
|
|
27
|
+
<g transform="translate(2,438)"><path d="M0 0 H422" stroke="#252A3C"/><text x="0" y="38" fill="#666F85" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="14">github.com/ysr666/dsh-vision-router</text></g>
|
|
28
|
+
</g>
|
|
29
|
+
<g>
|
|
30
|
+
<rect x="760" y="64" width="760" height="510" rx="34" fill="#0C0F1C" fill-opacity=".45" stroke="#252B40" stroke-opacity=".72"/><rect x="780" y="84" width="720" height="470" rx="26" fill="none" stroke="#FFFFFF" stroke-opacity=".035"/>
|
|
31
|
+
<g transform="translate(815,248)"><rect width="116" height="142" rx="20" fill="url(#chip)" stroke="#2B3148"/><rect x="16" y="17" width="84" height="82" rx="13" fill="#0A0D17" stroke="#2D3550"/><rect x="28" y="31" width="23" height="23" rx="5" fill="#5C51E8"/><rect x="55" y="31" width="33" height="23" rx="5" fill="#183C58"/><rect x="28" y="58" width="38" height="28" rx="5" fill="#154A63"/><rect x="70" y="58" width="18" height="28" rx="5" fill="#7F6FFF"/><text x="58" y="121" text-anchor="middle" fill="#AEB6CC" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="13" font-weight="700">图像</text></g>
|
|
32
|
+
<path d="M931 319 C978 319 995 319 1032 319" fill="none" stroke="url(#route)" stroke-width="2.7" stroke-linecap="round" filter="url(#glow)"/><circle cx="974" cy="319" r="4" fill="#7668FF"/><circle cx="1004" cy="319" r="3" fill="#7668FF" opacity=".65"/>
|
|
33
|
+
<g transform="translate(1111,319)"><circle r="102" fill="#0D1020" stroke="#2B314B" stroke-width="1.4"/><circle r="87" fill="none" stroke="#6659FF" stroke-opacity=".18"/><circle r="68" fill="none" stroke="#46D7FF" stroke-opacity=".10"/><path d="M-64 0 C-35 -38 35 -38 64 0 C35 38 -35 38 -64 0Z" fill="#11162A" stroke="url(#iris)" stroke-width="2.5" filter="url(#glow)"/><circle r="28" fill="url(#iris)" opacity=".92" filter="url(#softGlow)"/><circle r="12" fill="#080B14"/><circle cx="7" cy="-8" r="4.5" fill="#DDF8FF"/><circle cx="-91" r="4" fill="#7568FF"/><circle cx="91" cy="-49" r="4" fill="#49D5FF"/><circle cx="101" r="4" fill="#49D5FF"/><circle cx="91" cy="49" r="4" fill="#49D5FF"/><text x="0" y="132" text-anchor="middle" fill="#7A839A" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="13" font-weight="700">视觉路由核心</text></g>
|
|
34
|
+
<path d="M1212 270 C1258 270 1260 183 1308 183" fill="none" stroke="url(#route)" stroke-width="2.2"/><path d="M1214 319 C1264 319 1266 319 1308 319" fill="none" stroke="url(#route)" stroke-width="2.2"/><path d="M1212 368 C1258 368 1260 455 1308 455" fill="none" stroke="url(#route)" stroke-width="2.2"/><circle cx="1268" cy="213" r="4" fill="#65D9FF"/><circle cx="1262" cy="319" r="4" fill="#7B6DFF"/><circle cx="1268" cy="425" r="4" fill="#65D9FF"/>
|
|
35
|
+
<g transform="translate(1308,137)"><rect width="164" height="92" rx="17" fill="url(#chip)" stroke="#2C334B"/><circle cx="24" cy="26" r="8" fill="#2ED887" fill-opacity=".14" stroke="#4BDB96"/><path d="M20 26 l3 3 l6 -7" fill="none" stroke="#60E6A5" stroke-width="2"/><text x="43" y="31" fill="#E0E5F2" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="14" font-weight="700">免费视觉</text><text x="22" y="61" fill="#737D94" font-family="monospace" font-size="11.5">Qwen2.5-VL</text><text x="22" y="78" fill="#535D74" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="10.5">内置 · 无需 Key</text></g>
|
|
36
|
+
<g transform="translate(1308,273)"><rect width="164" height="92" rx="17" fill="url(#chip)" stroke="#403772"/><circle cx="24" cy="26" r="8" fill="#7A6BFF" fill-opacity=".15" stroke="#7A6BFF"/><path d="M20 26 h8 M24 22 v8" stroke="#A79DFF" stroke-width="1.7"/><text x="43" y="31" fill="#E7E4FF" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="14" font-weight="700">故障切换</text><text x="22" y="61" fill="#8E86C9" font-family="monospace" font-size="11.5">provider chain</text><text x="22" y="78" fill="#615B83" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="10.5">配额 · 区域 · 429</text></g>
|
|
37
|
+
<g transform="translate(1308,409)"><rect width="164" height="92" rx="17" fill="url(#chip)" stroke="#263D52"/><circle cx="24" cy="26" r="8" fill="#43D6FF" fill-opacity=".13" stroke="#44D6FF"/><path d="M19 26 h10 M24 21 v10" stroke="#7AE3FF" stroke-width="1.7"/><text x="43" y="31" fill="#DDF7FF" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="14" font-weight="700">像素工具</text><text x="22" y="61" fill="#7DB5C6" font-family="monospace" font-size="11.5">crop · diff · OCR</text><text x="22" y="78" fill="#52707D" font-family="monospace" font-size="10.5">ground · trace · color</text></g>
|
|
38
|
+
<g transform="translate(982,106)"><rect width="316" height="40" rx="20" fill="#101526" stroke="#2D3450"/><circle cx="21" cy="20" r="4" fill="#A092FF"/><text x="36" y="25" fill="#BAC1D2" font-family="PingFang SC, Noto Sans CJK SC, Microsoft YaHei, Inter, Arial, sans-serif" font-size="13" font-weight="650">DEEPSEEK 仍是大脑</text><path d="M239 20 h46" stroke="#343C59" stroke-width="1.5"/><circle cx="291" cy="20" r="4" fill="#4BD5FF"/></g>
|
|
39
|
+
</g>
|
|
40
|
+
<rect x=".75" y=".75" width="1598.5" height="638.5" rx="31.25" fill="none" stroke="#FFFFFF" stroke-opacity=".08" stroke-width="1.5"/>
|
|
41
|
+
</svg>
|