HongMing-Huang/dsh-file-upload ↗★ 3
dsh-file-upload
DeepSeek Harness dual-face plugin: Claude-style drag-and-drop / paperclip uploads, fully bundled document→Markdown (MarkItDown engine, 20+ formats, image OCR), text inlining, voice input, audio transcription (optional ASR), read_document tool.
AI Analysis
核心用途是增强 DSH 的文件上传与本地文档解析能力。适合需要处理 PDF、Office 文档、图片 OCR 或语音转文字的效率用户。无需安装 Python 或额外依赖,开箱即用。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:HongMing-Huang/dsh-file-uploadREADME
Read the full README ↗Usage
- Click the paperclip in the composer toolbar, or drag files anywhere over the window;
- Small text files land directly in the composer; documents appear as attachment cards and their path is sent with the message;
- The agent reads documents with
read_document— converted to Markdown on demand, pageable withoffset/limit.
MarkItDown (fully bundled — no downloads, no setup)
The MarkItDown capability ships inside the plugin. Works out of the box: no Python, no pip, no downloads, no build-script approval.
- Bundled engine — the Microsoft MarkItDown TypeScript port (
markitdown-node) is a regular dependency covering 20+ formats: PDF, DOCX, PPTX, XLSX, HTML, CSV, JSON, XML, RSS, Atom, ZIP, Jupyter notebooks, images (OCR via Tesseract, 110+ languages), and audio transcription (via LLM, needs model credentials). - Images — OCR to text by default through the bundled engine.
- Offline — all parsing runs locally, no network calls.
Optional upgrade: if an official MarkItDown CLI already exists on your machine (or is set via
markitdownBin), the plugin prefers it (adds EPUB and more); without one the bundled engine is always available.
- id: file-upload
config:
markitdownBin: /path/to/your/markitdown # optional; empty = bundled engine only
Startup log (bundled mode):
[dsh-file-upload] Document → Markdown ready: bundled MarkItDown engine (20+ formats, image OCR) — fully packaged, no downloads, no Python.
How images are handled (auto-adapted to your model)
The plugin detects your session's model capability at upload time and tells the agent the right way to read the image:
| Detected route | What happens |
|---|---|
Multimodal model (declares image input, e.g. GPT-4o / Qwen-VL / Claude / Gemini) | upload response carries imageMode: native; the message tells the agent to use the official read_image tool — the image enters model context directly |
| Text-only model (or unknown) | imageMode: ocr; the agent uses read_document on the image path — the bundled engine runs OCR (Tesseract, 110+ languages) and returns a text description |
The detection mirrors the official read_image route gate (ctx.llm.resolveModelInfo + inputModalities), so it never claims image support that the routed model does not declare.
Voice input (zero-config)
- Record — the mic button in the composer works immediately (browser Web Speech API, no setup); the transcript lands in the composer as editable text, review it before sending.
- Audio files — uploaded audio is transcribed automatically when an OpenAI-compatible ASR key is available: the plugin auto-detects the standard
OPENAI_API_KEYcredential (no configuration needed) and useshttps://api.openai.com/v1/audio/transcriptions; the transcript travels with the message. Without a key, audio uploads still work as regular file attachments. - Override the endpoint/model only if you need to (e.g. a self-hosted ASR):
- id: file-upload
config:
asrEndpoint: '' # empty = auto (standard OpenAI endpoint when a key is present)
asrApiKeyEnv: OPENAI_API_KEY # env var holding the ASR key
asrModel: whisper-1
Configuration
All fields have sensible defaults — you can install and use the plugin without touching any of them. Tune only what you need.
| Field | Default | Description |
|---|---|---|
uploadMaxBytes | 25165824 (24 MB) | Max bytes per uploaded file |
allowedExtensions | [] | Extension allowlist; empty = all allowed |
uploadTtlMs | 604800000 (7 days) | Unreferenced upload lifetime |
sweepIntervalMs | 3600000 (1 h) | Sweep period; 0 = disabled |
maxConcurrentUploads | 4 | Concurrent upload limit |
inlineTextLimit | 8192 (8 KB) | Text inlined into the composer up to this size |
previewTextLimit | 2048 (2 KB) | Preview length for larger text files |
maxFileBytes | 25165824 | Byte cap for one document read |
readLimit | 2000 | Max lines returned by one read_document call |
sheetRowLimit | 200 | Rows kept per XLSX sheet |
maxSheets | 5 | Sheets read per workbook |
cacheEntries | 16 | Parse-cache entry count |
cacheMaxBytes | 67108864 (64 MB) | Parse-cache byte budget |
markitdownBin | '' | Optional MarkItDown CLI path; empty = auto-detect PATH |
markitdownTimeoutMs | 120000 | Timeout for one CLI invocation |
maxRecordSec | 60 | Max voice recording length (seconds) |
asrEndpoint | '' | Optional OpenAI-compatible ASR endpoint for audio files |
asrApiKeyEnv | OPENAI_API_KEY | Env var holding the ASR API key |
asrModel | whisper-1 | ASR model name |