dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
A DeepSeek Harness plugin that adds a translation workspace to the Web GUI: translate text, an image, or a whole file, compare source and translation segment by segment, edit the output, switch the model per session, and keep every document on this device.
A DeepSeek Harness plugin that turns the Web GUI into a translation workspace: paste text, drop a file, or paste a screenshot, read the source and the translation side by side, edit the output, and let a second model review what a first one drafted. Everything stays on this device, and the model can be switched per request.
It targets DeepSeek Harness 0.2.x (the desktop app or dsh web, verified on 0.2.1). The plugin is published to npm as dsh-translation-assistant; pick whichever of the four fits. It ships no model of its own, so select a default model under Settings → Models before you start.
dsh-translation-assistant in Package name or address, press Install, then Enable now.Best if you intend to keep working on the code: edits to client.js are swapped into the open page by the artifact watcher, and Host changes apply after a restart.
git clone https://github.com/coldgust/dsh-translation-assistant.git ~/code/dsh-translationpackage.json, for example /Users/you/code/dsh-translation.This records a link: dependency: the profile points at that directory instead of copying it. Do not move or rename the directory afterwards — the plugin will fail to load and has to be installed again.
For when you do not want a local copy. Enter https://github.com/coldgust/dsh-translation-assistant.git where method 2 asks for the path and keep the rest. The code lands in the profile's node_modules, so edits never reach your repository and upgrading means uninstalling and reinstalling.
If you prefer files or want to script the setup, edit the profile's package.json (~/.dsh/profiles/desktop/package.json on the desktop app). Only the two places below concern this plugin; keep the profile's existing bundles and dependencies. Using the published package:
{
"dsh": {
"profile": {
"bundles": ["dsh-translation-assistant"]
}
},
"dependencies": {
"dsh-translation-assistant": "^1.11.1"
}
}Use "link:/Users/you/code/dsh-translation" instead to point at a local checkout.
Then run pnpm install in that directory and restart Harness. Keep the profile's existing entries in the bundles array and append this one at the end. The profile's cordis.patch.yml stays untouched: the plugin row comes from the patch this package ships (dsh.bundle.patch in package.json → cordis.patch.yml).
translation-assistant row it contributes.Installed as · Upgrade · Uninstall npm package · Uninstall it first, then install again with method 1 · Uninstall on the bundle's page Local directory · git pull, then reload; Host changes need a restart · Same as above Git address · Uninstall, then install again with method 3 · Same as above By hand · Change the version and pnpm install; for a link, git pull and restart · Delete the bundles entry and the dependency, then pnpm install
By paragraph is the default; By sentence switches granularity. A single request returns both, so switching costs nothing..txt, .md, .log, .html, .htm, or .docx. Word files are unpacked in the browser (no library, and the original never leaves the machine); HTML loses scripts, styles, and the head first, so only visible prose reaches the model.Translation (editable), Source, or Compare (side by side, stacked on narrow screens). Edits are split on blank lines and written back onto the matching segments; copying and document-level scoring live here.AI retranslate redoes one segment; Retranslate with prompt adds an instruction such as "more colloquial" or "keep the legal terms".Apply suggestion under a score sends that score and its comment back as the instruction for a fresh pass; Apply all does the same for every scored segment in the view, three at a time. While scores are hidden, no suggestion button is shown.Restore puts one back — the text it replaces is snapshotted too, so a rollback can itself be undone.Follow default keeps tracking the profile; any other entry pins that route for translation, retranslation, scoring, and OCR, and the choice is remembered on this device. A model that has since disappeared falls back to the default with a notice instead of failing every request. The appendix shows how to register an outside endpoint.translation_assistant (action: translate | retranslate | score | score_document), so the assistant can translate or review text in chat.Quality comes from separating the two jobs: draft cheap and fast, then judge and rewrite with the strongest model you can reach. The pick applies to translation, retranslation, scoring, and OCR, so the two halves of the job can even come from different providers.
Index-Translate-9B, or Index-Translate-2B when there is a lot of text — and press Translate, or drop the file in.deepseek-reasoner, GPT-5, or Index-Translate-35B-A3B.Show scores, then Score all. Each segment comes back with a 0–100 score and one sentence of feedback.Apply all, or Apply suggestion on a single segment. The rewrite is sent together with the score and its comment as the instruction, so the strong model fixes exactly what it criticised.Revisions to compare the passes. Every AI rewrite left a snapshot, and restoring one is undoable in turn.Scores are cached with the text: a rewrite drops the stale score, and editing a translation clears the score it invalidated, so step 3 only has to be repeated when the text actually changed.
Drop a .docx, .md, or .html file and it is translated in one request. The file name stays on the document, and Download translation writes the result back in the same shape: .md for Markdown, an HTML document for HTML, .txt for everything else. Blank-line structure survives, so the output opens the way the input did.
File · Role host/index.js · Host half: registers the /dsh-translation/api JSON route and the translation_assistant Agent tool, validates requests, resolves the model route. host/engine.js · Prompt construction, streaming completion wrapper, retries, batched translation with per-segment fallback, retranslation, segment/document scoring, image OCR. No Harness imports, so it is unit-testable with a fake LLM stream. client.js · Browser half: the main page, the sidebar panel icon, all interaction state and rendering. package.json · Bundle declaration: dsh.bundle.patch points at the shipped cordis.patch.yml, dsh.client names the browser entry and the sidebar package it injects into. cordis.patch.yml · Inserts the Host plugin row. locale/en.json, locale/zh.json · Plugin Manager title and description, in English and Chinese.
The page talks to the Host through same-origin calls:
Endpoint · Purpose GET /dsh-translation/api/health · Service state, the resolved model label, the profile default, the switchable model list (grouped by provider), and per-provider listing failures. POST …/translate · Translate a sentences / paragraphs array in one request. POST …/retranslate · Redo one segment, optionally with extraPrompt. POST …/score · Score one segment (0–100 plus a one-sentence comment). POST …/score-document · Score a whole source/translation pair. POST …/ocr · Transcribe an image (image as base64 + media type).
POSTs are rejected when the Origin header names a different origin, and the request body is capped at 24 MiB. Every POST accepts an optional route: { provider, model }; omitting it follows the configured or profile-default route. A route that is not in the advertised catalog is rejected with HTTP 400 before any model call, unless the catalog itself is empty (discovery failed), in which case the model service has the final say.
All fields are optional and live in the plugin row (cordis.patch.yml or Plugin Manager):
Field · Default · Meaning provider, model · current default selection · Exact model route for all calls. reasoningEffort · unset · Optional reasoning effort passed to the route. models · unset (discovery) · Extra routes for the header picker, for example [{ provider: deepseek-account, model: deepseek-pro, label: Pro }]. Merged with what the Host's LLM registry advertises; the routes in use are always listed. targetLanguage · Chinese · Default target language. sourceLanguage · unset (auto-detect) · Default source language; the page can override it. maxTokens · 8192 · Output limit for translation calls. retranslateMaxTokens · 4096 · Output limit for retranslation. scoreMaxTokens · 4096 · Output limit for scoring. ocrMaxTokens · 4096 · Output limit for image transcription. maxRetries · 1 · Retries for transient provider failures. scoreRetries · 1 · Retries when a scoring reply cannot be parsed. sentenceChunk, paragraphChunk · 16, 6 · Segments per translation batch. concurrency · 3 · Batches in flight at once. tool · true · Set false to hide the Agent tool.
Key · Content dsh-translation-assistant:history:v1 · Up to 200 entries (~2 M characters), pinned first and then most recently used. Each entry carries its own revision snapshots (up to 20, 200,000 characters per document). dsh-translation-assistant:session:v1 · The id of the document that was open last. dsh-translation-assistant:prefs:v2 · Source/target language, comparison view, full-text display mode, and the picked model route (or null to follow the default). dsh-translation-assistant:document:v1 · Legacy single-document key from 1.1.x: adopted into history on first boot, then cleared.
History, edits, and preferences never leave the browser; only the text being translated, retranslated, scored, or read from an image is sent to the model route. Clearing site data for the Harness origin erases the history — there is no server-side copy.
.docx unpacking needs the browser's DecompressionStream (Chrome 80+, Firefox 113+, Safari 16.4+); elsewhere the page asks for .txt, .md, or .html instead.SCORE: / COMMENT: pair, falls back to JSON, and retries once when the model breaks that shape. A score is a model judgement, not a certified metric.This directory is the installed bundle (the profile links it), so client.js is picked up by the artifact watcher and swapped into the open page; Host changes (host/index.js, host/engine.js) apply after the next Harness restart.
# 86 unit/integration tests: engine (translation/retranslation/scoring/OCR),
# the HTTP handler, model-catalog discovery and route overrides, and the page
# rendered through a minimal React harness (no browser needed).
node --test 'test/*.test.mjs'Notes for maintainers:
@deepseek-ai/dsh-llm registry: listProviders() names the registered routes, then listModels(providerId) asks each adapter what it serves. listModels takes a provider id — calling it with no argument throws NO_ADAPTER, which is why a generic "call every list-like method" probe finds nothing on a current Host. One provider whose listing fails is reported in modelFailures and does not hide the others. The result is cached for 60 seconds and dropped on llm/adapters-updated, so adding a provider in Settings → Models shows up without a restart. Requests only pay for discovery when they carry a route.optgroup) once more than one provider is visible, and the default entry is labelled from the profile selection rather than from the route in use, so it keeps naming the real default after a switch..docx reading is a small ZIP walker (central directory → local header → DecompressionStream('deflate-raw')) plus a tag stripper for word/document.xml; it deliberately ignores headers, footers, and comments. HTML reading is regex-based so it also runs in the Node test harness, where no DOM exists.docs/screenshots/ are the real page rendered against mocked Host data at 1280 px CSS width (2x, downscaled to 1600 px). Retake them the same way when a layout change makes them lie.{ / } totals catches it.Symptom · Cause and fix Installation says the package is not a bundle · The path points at a subdirectory. Enter the repository root — the directory with package.json and its dsh.bundle.patch. The bundle reports an error after the folder moved · A local install is a link: dependency, so moving or renaming the directory breaks it. Put it back, or uninstall and install again from the new path. No sidebar entry after installing · Restart Harness on the desktop app, or reload the page under dsh web. If it is still missing, check that the bundle is switched on in Plugins. Header shows “Translation service not ready” · No default model is selected in Settings, or the provider is unreachable. Pick a default model and reload. The header shows no model picker · Only one route was discovered, so there is nothing to switch to. The notice above the editor names the provider whose listing failed; a models list in the plugin config is the manual fallback. “The selected model cannot read images” (HTTP 422) · The routed model cannot read images. Choose a vision-capable model. Importing a .docx says the browser cannot unpack it · DecompressionStream is unavailable in that browser. Save the file as .txt, .md, or .html and import that. The downloaded HTML has no styling or links · Expected: the page translates text, so the export keeps paragraphs only. Keep the original file if you need the markup. New translation seems to have deleted the document · It does not: the document stays in history and the page opens a blank form. Open the header chip to switch back. A rollback lost the newer wording · It does not: the text you left is stored as a Before rollback revision. Open Revisions again and restore it. Edits disappeared after clearing browser data · History and edits live in localStorage only; there is no cloud copy.
Index-Translate is Bilibili's open machine-translation model family, and that page is its online demo. It runs on vLLM and speaks standard OpenAI Chat Completions, so it can be registered as an ordinary custom provider; once it is, this plugin's header picker can select it directly.
Index-Translate-35B-A3B — the flagship: a mixture-of-experts model (35B total parameters, 3B active) that translates between many languages and can also read text straight out of an image, which in this plugin means translation, retranslation, scoring, and OCR all work.Index-Translate-9B / Index-Translate-2B — smaller, faster text-only models for high volume.The demo needs no API key and comes with no SLA, so treat it as a playground route.
The most direct way, and what most users want.
dsh web and open the interface.bilibili-translate — a lowercase identifier you choose, used internally to recognise the providerhttps://index-translate.bilibili.com/v1OpenAI Completions (openai-completions)indexIndex-Translate-35B-A3B. If that fails, add the model id by hand.For people who prefer files or want to script the setup. Edit $DSH_HOME/settings.yaml (usually ~/.dsh/settings.yaml; on the desktop app the live file is ~/.dsh/profiles/desktop/cordis.patch.yml) and add an entry under providers inside the llm-pi-ai section:
llm-pi-ai:
providers:
bilibili-translate: # Provider ID
apiKeyEnv: BILIBILI_TRANSLATE_API_KEY # names an environment variable
api: openai-completions
baseURL: https://index-translate.bilibili.com/v1
models:
- id: Index-Translate-35B-A3BNote that apiKeyEnv is a *reference*, not a value: the Harness process has to be able to read that variable. The endpoint ignores the key, so any non-empty value works. A Harness launched from Finder or the Dock does not inherit your shell environment, so if the variable cannot resolve, send the placeholder as a header instead:
headers:
Authorization: Bearer indexRestart Harness — providers are registered at boot. This plugin's header picker then gains a bilibili-translate group, and picking Index-Translate-35B-A3B pins it for translation, retranslation, scoring, and OCR. You can also check the endpoint directly:
curl http://127.0.0.1:<port>/dsh-translation/api/healthEntries under models with provider: bilibili-translate mean the route is live.
concurrency to 2 for the demo endpoint.