dsh-pet-plugin
DSH 桌宠插件:四只超写实立绘(表情 + 动作序列)、主动说话与神经音色、小输入框单聊(一次性模型调用,不进会话)。
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:zuoyunlai/dsh-pet-plugin说明文档
阅读完整 README ↗dsh-pet
A little companion that lives in the bottom-right corner of the DSH web UI: it stays around or drops in at random, talks (with voice), walks, dances, gets shy or annoyed, and carries a tiny input box you can chat with. Four photo-realistic personas, each with its own temper.
Scope: the pet only lives inside the DSH window (it mounts into the framework's overlay slot). It cannot float above other applications — that would need a separate Electron shell rather than a plugin.
At a glance
-
Languages: UI chrome, persona taglines and the chat system prompt follow the browser interface language — shipped for
en / zh / es / pt / hi(locale/*.json, namespacepet; slots register withlocale: 'pet'per the DSH slot contract). Each persona also ships an English line pack, so a non-Chinese UI hears English lines. -
Mount points:
shell.overlay(the pet itself, a click-through layer) andconversation.input.right(the entry button next to the composer). -
Private chat: what you type in the small box never enters your session. The host half exposes
POST /dsh-pet/chatand answers with a one-shotctx.llm.stream()call (no session, no session log). Defaults:deepseek-account/deepseek-flash; provider, model, maxTokens and temperature are plugin config. -
Icon:
icon.svg(the rose silhouette) and the composer button share the same path. -
Settings panel: grouped (look / voice / display / actions / effects), custom dropdowns (native `` popups are system-white and unreadable in dark themes) and custom switches; it is pinned to the viewport and does not follow the pet.
-
Four personas (photo-realistic, same lighting, 5 expressions each: default / happy / shy / angry / sleepy): 薇 (violet), 绯 (crimson), 靛 (indigo), 雪 (silver). Expression changes cross-fade (240 ms) instead of hard-cutting.
-
Action sequences: a persona may declare
actions: { dance: [...], hair: [...], walk: [...] }; each set is 3 frames played as a 340 ms flip-book. All four have dance / hair-flip / walk, each stylised to the character. -
Adding artwork: drop transparent PNGs into
assets/and reference them fromPERSONAS(image, orimages: { mood: 'file.png' }). Served by/dsh-pet/assets/(image extensions only, basename only).tools/make-pet-image.pyremoves a green-screen background (preferred) and falls back to a gradient key.
Behavior
| Capability | How |
|---|---|
| Always-on / random | Toggle in the panel; random mode rolls a per-hour probability inside the active window |
| Active hours | Start/end time, supports crossing midnight (22:00 → 03:00) |
| Proactive lines | Per-mood line packs, bubble + speech |
| Voice | Optional: if the host has any python with edge-tts, /dsh-pet/tts synthesises (cached) and /dsh-pet/tts/status probes it; otherwise it falls back to the system speechSynthesis. The plugin itself has zero runtime dependencies |
| Small input box | Chat with the pet only; one-shot model call, nothing is written to any DSH session |
| Moods | idle / walk / dance / shy / angry / sleep / talk / happy |
| Gaze | Pupils follow the mouse (CSS variables only, no re-render) |
| Effects | Ink / confetti / cloud / fog (wipable) / bomb + cracked screen |
| Event hooks | Confetti after a turn longer than 4 s; a cloud appears after a failed tool call |
| Temper | Per-persona weight table decides what it does more of |
| Hide | "Hide for 1 h" in the panel |
Install (local, no registry)
Published as dsh-pet-plugin on npm; it also installs straight from a folder.
# from the registry (after publish)
dsh plugin --profile desktop add dsh-pet-plugin
# from a local checkout: quit DSH first, then
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 # or double-click install.cmd
Quit DSH first (the profile's package.json is HMR-watched). The script adds
"@local/dsh-pet": "file:" to the profile, registers the bundle, runs
pnpm install, then reads back all four facts. update.cmd only refreshes files and is
safe while DSH is running. For the sweeter neural voice:
pip install edge-tts # any python the host can find
export DSH_PET_PYTHON=/path/to/python # only if auto-discovery misses it
Verify
node --check client.js
node tests/smoke.mjs # fake window + React stub, renders every persona/mood
# host routes need the harness packages, so run them from the installed copy:
cd
/node_modules/@local/dsh-pet && node --test tests/host.test.mjs
node /bin/dsh-plugin-dev.js check --cwd . --strict
node /bin/dsh-plugin-dev.js verify --cwd .
Customize
- The client bundle is generated: edit
src/*.jsand runnode build.mjs, which concatenates the parts intoclient.js(the only file DSH loads). Never editclient.jsby hand —npm testrebuilds and then runs the smoke test. - Personas, lines and tempers:
pets//pack.json—images(five expressions),actions(dance / hair / walk, three frames each),voice,temper, andlines/linesEnline packs. - UI strings: edit the
petnamespace inlocale/*.json, thennode build.mjs— the dictionaries are injected at build time, so the locale files are the single source of truth. New language: runnode tools/gen-locales.cjsfor a skeleton, then translate. - Moods and animations: add keyframes in
src/70-style.jsand map the class bymoodinsrc/96-overlay.js. - Artwork: drop transparent WebPs into
assets/and reference them frompets//pack.json, thennode build.mjs(it regeneratessrc/30-personas.js). The/dsh-pet/assets/route only serves image extensions.
Security model
- The host routes are gated three ways, none of them tied to a fixed port or domain:
Hostmust be a loopback address, the host's own origin, or listed in theallowedHostsplugin config (for reverse-proxy / LAN deployments); a presentOriginmust be same-origin with thatHostor the desktop shell (dsh-app://app,dsh-app://shell); andSec-Fetch-Site, when present, must besame-originornone. Non-browser clients that send none of these are allowed — that is the deliberate limit of a local HTTP endpoint, see below. - Speech synthesis is a
POSTendpoint that returns the audio bytes; there is no GET URL to feed to an ``, so a page (or another local process) cannot make the host synthesise anything by pointing an element at it. - Synthesised speech is cached in the OS temp dir with a size cap that is re-checked after every synthesis, and writes go through a random temp name + rename so a pre-planted symlink cannot redirect them.
- Anything the page sends (settings, chat history, persona id) is treated as data: validated, length-capped, and never interpolated as instructions or markup.
- Neural voice sends the spoken text to Microsoft's edge-tts endpoint. Turn it off
(or never install
edge-tts) to keep everything local; the panel says so.
Known limits
-
Host version: built and tested against dsh
0.2.1-alpha.2. It needs thewebServerservice and theshell.overlay/conversation.input.rightslots, which are 0.2-generation APIs — on a 0.1.x host it installs but never mounts (one console line says so).engines.dshinpackage.jsonis a declaration only: the installer does not enforce it, and the plugin declares no@deepseek-ai/dsh-*peer ranges on purpose, so a version mismatch never blocks installation. -
Neural voice needs a host python with
edge_tts; otherwise the system SAPI voice is used. -
Browsers block autoplay before the first user gesture — click the page once.
-
Settings live in
localStorage. The debug handle (globalThis.__dshPet) stays off unless you setdsh-pet.debug=1inlocalStorageor append?petdebug=1. -
The pet cannot float above other applications (overlay slot only).