Back to home

Ghz114514

dsh-refpics

Pinterest-style reference image search for the dsh web GUI: search_refs tool, masonry wall, sidebar board, downloads, and save-to-Eagle

Stars
0
Language
JavaScript
Created
Aug 15, 2026
Updated
Aug 15, 2026

Introduction

dsh-refpics — Reference Image Search Plugin

English | 中文

Model-facing search_refs tool for the dsh web GUI: turns a natural-language description ("minimalist living room", "brutalist poster layout", "cyberpunk neon street at night"...) into a board of matching reference images from stock design platforms, rendered inside the conversation as a Pinterest-style masonry wall with hover credits and a keyboard-friendly lightbox.

One package, both halves. The node half (host process) registers the search_refs tool plus the "Reference pictures" settings section; the browser half (Web GUI) registers a keyed tool.call.toolview entry that owns how every search_refs call renders, so the wall appears inline in the chat — no separate panel or page.

Capabilities

CapabilityDescription
Natural-language searchOne call takes the user's raw description as query — no manual keyword translation needed
Four providersOpenverse (keyless, always available), Pexels, Pixabay, Unsplash (free API keys); provider: auto prefers the first configured keyed provider and falls back to Openverse
Pinterest-style wallResponsive multi-column masonry inside the chat turn; lazy thumbnails, hover overlay with title and author
LightboxClick any card for the full image with title, author, source links, prev/next and Esc/arrow keyboard control
换一批 / 翻页Header buttons on every wall: 换一批 queues a prompt asking the agent for a fresh batch, 翻页 queues the same query's next page — the new result renders as a normal chat wall
Sidebar board (dsh-better-sidebar)Registers a single-instance "参考图" tab in the right sidebar: mirrors the latest chat search for the session and can run its own searches directly (instant 换一批/翻页, no agent round trip); "在侧边栏打开" on the wall jumps there
DownloadOne click downloads the image through a host proxy route (bounded, image-type gated, sanitized file name)
Save to EagleOne click sends the image URL to the local Eagle app (/api/item/addFromURLs), with website/tags metadata; Eagle port and optional token are configurable
Attribution preservedEvery result carries author, author URL, source page and license; the wall and the model-facing text both surface them
Orientation and pagingorientation: any/landscape/portrait/square filters; page fetches more of the same query
Bounded resultsCount clamped to 1-30 per call; per-request 20 s timeout; short-lived in-memory cache (TTL 10 min) dedupes repeat queries
Safe degradationRunning calls show a shimmer skeleton; failed calls show the error; a malformed payload falls back to a plain text card — a bad result can never break the chat row
No scrapingThe tool talks only to official, documented APIs. It deliberately does not scrape Pinterest (no public API, ToS-hostile); Openverse/Pexels/Pixabay/Unsplash are the legal substitutes

Installation

# From GitHub — the repo ships prebuilt bundles, so no build step is needed
dsh plugin --profile web add github:Ghz114514/dsh-refpics

Restart the dsh web host (or the GUI) once so the profile picks up the new bundle; afterwards a page refresh is enough for client-side updates. The tool mounts without configuration: auto falls back to Openverse immediately, and the first keyed-provider call fails with a clear message until its key is filled in.

Local development (this repo):

pnpm install          # node >= 22.19
pnpm build            # lib/index.js (host) + lib/client.js (browser)
dsh plugin --profile web add file:<repo>     # install the local build
# After any rebuild, refresh the installed copy the same way

Configuration

Settings → Plugins → Reference pictures (the ref-pics settings section; effective immediately):

KeyDefaultMeaning
pexelsKeyemptyPexels API key (free at pexels.com/api); empty disables the provider
pixabayKeyemptyPixabay API key (free at pixabay.com/api/docs); empty disables the provider
unsplashKeyemptyUnsplash access key (free at unsplash.com/developers); empty disables the provider
defaultProviderautoProvider preferred when a call passes auto
defaultCount12Image count used when a call omits count (1-30)
eaglePort41595Eagle local API port; 0 disables the save-to-Eagle routes
eagleTokenemptyOptional Eagle API token (only when Eagle requires one)

Keys and the Eagle token are marked secret in the settings schema (masked in the card) and are never included in logs, tool output, or model-facing text.

The browser half exposes four same-origin host routes: GET /refpics/search (direct board search), GET /refpics/download (proxied attachment download, 30 MiB cap, image content types only), POST /refpics/eagle (add one image to the local Eagle app), and GET /refpics/eagle/status (Eagle health). The Eagle routes only ever talk to 127.0.0.1:<eaglePort>.

Tool usage

The model calls search_refs when the user asks for reference pictures, moodboards, or visual inspiration. Arguments:

ArgumentTypeDefaultMeaning
querystringrequiredNatural-language description (style, subject, mood, colors, medium)
countinteger12Images per page (1-30)
providerenumautoauto | openverse | pexels | pixabay | unsplash
orientationenumanyany | landscape | portrait | square
pageinteger1Page of the same query (more results)

Example prompts that trigger it: "帮我找几张极简客厅的参考图", "show me reference images of brutalist poster layouts", "做一个赛博朋克风格的 moodboard".

Security model

  • Only official, documented provider APIs are called over HTTPS; no scraping, no cookies, no login.
  • API keys live in the settings section (role: secret), resolve per call, and are never logged or returned to the model; HTTP failure excerpts are truncated to 200 characters.
  • Requests are bounded: 20 s per provider call (plus a 30 s tool-level cooperative timeout) and the abort signal is forwarded on cancellation.
  • Results are provider-hosted image URLs with attribution metadata; the plugin stores nothing.

Development

pnpm install          # dependencies (node >= 22.19)
pnpm build            # tsc -b && tsdown -> lib/index.js (host) + lib/client.js (browser)
pnpm typecheck        # host + client programs + tests
pnpm test             # node --test tests/ (31 tests, in-process)
node scripts/smoke-host.mjs    # live end-to-end: registers the tool and runs one real Openverse search
node scripts/smoke-client.mjs  # simulated-browser smoke of the client bundle and its wiring

Layout follows the dsh-web-ui family conventions (adapted to a standalone package): src/index.ts host half, src/client/ browser half, src/core/ shared pure logic, cordis.patch.yml profile patch, dsh.client declaration for the browser bundle. The browser half uses the keyed tool.call.toolview slot (key: search_refs) with a generic-card fallback for UIs that do not know the plugin.

Credits