跳到主要内容

dsh-meme-gen

已验证

@liaozhi/dsh-meme-gen · v0.9.2 · MIT · Web 界面

DeepSeek Harness plugin: 把一个图/照片变成一套 12 张聊天表情包(表情包风格库 + 贴纸生产工作流 + 确定性后处理,生图依赖 dsh-qw-tool)。

安装

dsh plugin add @liaozhi/dsh-meme-gen

用 dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南。

源码

发布到 npm 但没有公开仓库。安装前请检查包内容。

标签

作者

说明文档

dsh-meme-gen

支持范围:本插件仅适配 DeepSeek 桌面版(desktop profile)的 Harness runtime。 当前支持的 DeepSeek 桌面版版本:0.2.0-rc.1 ~ 0.2.0-rc.2(版本门禁 [MIN_HARNESS_VERSION, MAX_HARNESS_VERSION] = [0.2.0-rc.1, 0.2.0-rc.2], 见 src/version-gate.ts;桌面版应用与 runtime 锁步同版发版, 插件 peer 声明 ^0.2.0-rc.1)——桌面版版本不匹配时插件启动即软禁用, 「插件」页的组合包详情页出现「已停用」说明面板并给出版本指引,不影响 DSH 启动与其他插件。 dsh web、自定义 profile、SDK/headless 等形态一律不支持——启动时 profile 门禁 (src/profile-gate.ts)会自动软禁用本插件。下文沿用的 dsh web 开发流示例是 插件模板的历史写法,实际部署与运行请以桌面版为准。

DeepSeek Harness 插件:表情包风格库 + 贴纸生产工作流——把用户的一张图/照片变成一套 12 张聊天表情包。

  • 表情包风格库(本插件核心,范式对齐 dsh-post-gen 的海报风格库):磁盘文件夹存储 + zip 安装 + 内置风格首启播种,模型经原语工具查库/点选/点名取模板;
  • 确定性后处理(meme_gen_postprocess_sheets):sharp + 像素算法把两张 3×2 贴纸 sheet 切分、去 key 背景、归一化成透明表情包 + 预览图;
  • 生图/编辑/多模态依赖 dsh-qw-tool:qw_gen_image / qw_edit_image / qw_multimodal_chat(千问 API Key 在那个插件里配置),本插件不自带任何千问调用;dsh-comfyui-based-tools 的 Qwen Image 2.1 图像工具(comfyui_gen_image_qwen_21_t2i / comfyui_gen_image_qwen_21_edit)只作 qw 侧不可用时的回退。

工具面

工具 职责
meme_gen_get_all_meme_skills 实时扫库,返回风格库轻量目录(frontmatter 元数据,不含模板正文)
meme_gen_pick_meme_skill 固定 3 个候选风格(库内/自定义可混合)渲染成交互卡片,用户点选后返回该风格的 sheet 生图提示词模板
meme_gen_use_meme_skill 用户点名风格时按 name 直取模板(插件页配置页的详情弹窗可复制"使用这个风格"提示词)
meme_gen_postprocess_sheets 两张 sheet(各 6 贴纸、纯色 key 背景)→ 12 张透明表情包 + 1 张预览图(attachment ID 供飞书等工具复用)

门控:「插件」页表情包配置页打开「启用表情包工作流」且风格库里至少有一个合法风格时,上述工具与系统提示词工作流剧本才注册进会话;任一条件变化自动重估。

表情包风格

一个风格 = 一个文件夹(SKILL.md + previews/ 预览图,可打 zip 在面板上传安装):

  • frontmatter:name / title / description / whenToUse / styleTags / previews;
  • 正文 = 该风格的贴纸 sheet 生图提示词模板,唯一占位符 {{brief}}(创作简报:主体特征 + 风格融合 + 12 个反应清单 + 约束)。固定 sheet 生成契约(3×2、key 背景、gutter、die-cut 描边)不在模板里,由插件统一承载——风格模板只写画风。

完整格式说明(校验规则、安全上限、内置风格语义)见 docs/meme-skill-format.md。

插件自带 2 个内置风格(assets/skills/,SVG 占位预览图),首启自动播种进库,不可删除但可同名覆盖:

name 风格
meme-clay-sculpture 软陶泥塑:黏土捏塑立体小雕塑、哑光颗粒、Q 版大头身
meme-oil-painting 古典油画:厚涂笔触、明暗对照、庄重画风 × 夸张情绪的反差

配置页(「插件」页内)

侧边栏「插件」→ 点开 @liaozhi/dsh-meme-gen 卡片,配置区渲染在组合包详情页的描述与「包含的组件」之间(ui-plugin-manager 声明的 plugins.bundle.config 槽位,key = 组合包名;设置页不再有本插件的分区):

  • 风格库:卡片网格(预览图 + 内置徽标)、模糊搜索、zip 上传安装、详情弹窗(轮播预览/元信息/「使用这个风格」复制)、卸载(内置风格锁定);
  • 总开关:风格库为空时不允许打开;开关状态与门控真实状态分开展示;
  • 插件自更新:标题行更新条(检查更新 / 经官方 pluginManager 服务通道安装新版,安装中可取消、pnpm 输出实时可见)。

开发(HMR)

一次安装进 profile(client half 的发现依赖包名解析,必须安装而非 --patch 插路径):

dsh plugin --profile web add <本插件目录的绝对路径>

每个开发会话两个终端:

# 终端 1:构建监视器(tsc --watch + tsdown --watch,持续重写 lib/)
pnpm dev

# 终端 2:harness(叠加开发 overlay,重新启用 HMR 并监听 lib/)
dsh web --patch <本插件目录>/cordis.dev.yml --no-open
  • 改 host 半(src/) → tsc 重写 lib/index.js → cordis-plugin-hmr 重载插件 → 终端打印新的 host half loaded 日志;
  • 改 client 半(src/client/) → tsdown 重写 lib/client.js → host 的 client-hmr 轮询发现 → SSE 广播 → 浏览器不刷新页面就地更新。

安装版 dsh 注意:cordis-plugin-hmr 需要读 Node 内部模块加载器。若启动报 --expose-internals is required for HMR,用 NODE_OPTIONS=--expose-internals dsh web ... 启动即可。

npm/git 安装进 profile 的实体副本不参与热重载(HMR 沿 Node 模块图追踪时排除 /node_modules/ 路径);dsh plugin add <本地目录> 是符号链接,realpath 后跳出 node_modules 才能被追踪。改完源码想让安装副本生效,重新执行 dsh plugin add 后重启 harness。

自更新测试桩(verdaccio 本地 registry)

不碰真实 npm registry 测自更新全链路(npm 没有测试端点,版本号一次性,测试版本不能真发)。verdaccio = npm 官方文档推荐的本地测试 registry:匿名 publish + npmmirror 代理(被测包的常规依赖自动走代理),被测 scope @liaozhi/* 不设 proxy——完全本地化,上游真版本不干扰 dist-tags。

# 终端 1:起服务(仓库根目录运行)
npx --yes verdaccio@6 --config scripts/verdaccio.config.yaml

# 终端 2:发布测试版本(临时改 version → pnpm pack → npm publish --tag latest → 恢复 version,自动注册测试用户)
node scripts/update-stub.mjs publish 0.7.2-test.1

插件侧(PowerShell;$env: 只对当前终端会话生效,dsh web 从同一终端启动才继承):

$env:DSH_MEME_UPDATE_REGISTRY = "http://127.0.0.1:4873"
dsh web
# 取消覆盖:Remove-Item Env:DSH_MEME_UPDATE_REGISTRY(sh 等价:unset DSH_MEME_UPDATE_REGISTRY)

面板「检查更新」应报 0.7.2-test.1 → 「立即更新」→ 重启 harness 生效(回退:dsh plugin --profile <name> add @liaozhi/[email protected])。数据都在 .update-stub/(已 gitignore);npm 版本号一次性,同版本重复 publish 会被拒——每次测试换新版本号。测完切回 link 开发模式:先 remove 再 add(dsh plugin --profile <name> remove @liaozhi/dsh-meme-gen 后重新 add <目录>)——更新成功后 manifest 钉着只有桩里才有的测试版本,直接 add <目录> 会因 pnpm 先解析旧版本而报 NO_MATCHING_VERSION。

前提:DSH_MEME_UPDATE_REGISTRY 只被本仓库源码里的新版 self-update 读取——profile 里若还是旧版 registry 安装副本(≤0.7.1,走 dsh plugin 子进程且硬编码官方 registry),检查永远不会看到测试桩。先让 profile 跑本仓库源码(dsh web --patch <本插件目录>/cordis.dev.yml 开发 overlay,或 dsh plugin --profile web add <本插件目录> link)再测。测完「立即更新」会把 link 换成 registry 实体副本,想继续开发热重载要重新执行 link 安装。

依赖版本与追新

harness 处于 0.2.0 rc 快速迭代期,要点:

  • peer 与 dev 同一下限:dev = 编译所用版本,peer = 运行时最低兼容声明。官方规则:every peer has a matching development range。
  • 范围写法:用 ^0.1.5-rc.1(下限 = 已验证版本)。不要用 latest/*,也不要精确钉死。
  • 当前支持窗口:main 分支(0.2.0 线活跃分支;compat/0.2.0-rc.1 冻结 于 0.8.0 发布点)为 [0.2.0-rc.1, 0.2.0-rc.2]——0.2.0-rc.1 跨 minor 线 迁移落点(窗口单点钉死,硬约束 = harness 内建 peer 预检的 caret 无法 横跨 minor 线)+ 0.2.0-rc.2 同线追新(默认只抬 MAX:MIN 已实测且仍是 可安装的发布版本,dist-tag 被 rc.2 接任不构成 MIN 上移理由),依赖 caret ^0.2.0-rc.1 不动;0.1.7 及更早线宿主一律软禁用。跨线取证见 docs/compat-plan-0.2.0-rc.1.md;同线追新取证见 docs/compat-plan-0.2.0-rc.2.md。窗口语义:MIN = 已实测最低版本、 MAX = 已追新验证的目标 tag——同线内 rc 追新若 MIN 不动则「只抬 MAX、 依赖字段不变」(预发布 caret 恰好覆盖同线全部预发布号,semver 排序上 正式版反而满足 caret,见 docs/compat-plan-0.1.5-rc.3.md §7);MIN 上移 (目标版本已不可安装 / 从未实测)时依赖 caret 下限才同步改写——任何时候 都不要把依赖下限写成高于 MIN 的版本,那会与 MIN 承诺冲突。
  • harness 版本门禁:src/version-gate.ts 要求 harness 版本落在 [MIN_HARNESS_VERSION, MAX_HARNESS_VERSION] 窗口内;窗口外默认软禁用(醒目错误日志 + 不注册任何业务能力,不影响 dsh web 启动);DSH_MEME_GEN_STRICT=1 恢复抛错 fail-loud。软禁用时 host 半经 webserver/index-inject 向页面注入 __DSH_MEME_GEN_DISABLED__ 标记,client 半读到后改挂"已停用"说明面板。

追新流程:

# 跨 minor 线 / MIN 上移的迁移:
pnpm bump:deps                      # ① 查最新 ② 抬 peer/dev 下限 ③ pnpm install
pnpm typecheck && pnpm build        # 红 = 上游破坏性变更,按报错修
# 同线 rc 追新(MIN 不动)不走本流程:只抬 src/version-gate.ts 的 MAX +
# 文档同步(按 docs/compat-plan-*.md 范式留执行记录),依赖 caret 不动

发布到 npm

npm login          # 首次
pnpm publish       # prepack 会自动完成构建

files 白名单带运行必需的产物(lib/、assets/、cordis.patch.yml),发布前建议 pnpm pack 检查内容。用户安装:

dsh plugin --profile web add @liaozhi/dsh-meme-gen

硬约定(开发时必读)

  • 自更新只走官方 pluginManager 服务通道(0.1.7-rc.2 起):self-update.ts 调 ctx.pluginManager.installBundle(<pkg>@<version>)——与 dsh plugin CLI / Web「插件」页同一服务实例(同 pnpm 通道、同 profile manifest 写锁、装后 reconcile),registry 回退(npm → npmmirror)与失败/取消自动还原 package.json/pnpm-lock.yaml 由服务承担;版本检查同样多源降级——候选取自服务 registries() 的计划,registry 类失败逐源转问;profile 不需要定位(服务持有当前 profileContext);结论完全以服务返回为准,不回读磁盘——installBundle 成功前已读取安装后的 bundle manifest 做存在性/合法性检查(失败即抛错还原),版本真实性由 pnpm 的 tarball integrity 校验兜底,updatedTo = 请求的目标版本。对已安装包做版本更新返回 application: 'restart-required'(不热重载),与旧 CLI 通道 restartRequired: true 同语义。取消 = 协作式标志(预取阶段检查点)+ 服务 cancelInstall(requestId),相位迁移由安装 Promise 落点单一承担(update-state.ts)。注意 pluginManager 服务在 0.1.5 线不存在(回流 main 需恢复 CLI 通道);不要绕过服务直接调 pnpm,也不要用 pnpm update(会剥 rc 包的 ^);link 开发副本仍要先清残留 junction 再安装。
  • 后处理参数是常量不是设置:画布边长/内容比例/预览列数一旦暴露给用户改,前端点击定位(依赖 make_preview 网格)就会错位——保持 src/spec.ts 的 DEFAULT_*。

文件清单(业务部分)

├── src/index.ts                       # host half 入口(settings + 风格库 + 播种 + Typert + 门控)
├── src/gate.ts                        # 门控 + MEME_GUIDANCE 工作流剧本(工作流 A-D + 单占位符纪律)
├── src/skills/store.ts                # MemeSkillStore(scan/installZip/uninstall/seedBundled/onDidChange)
├── src/shared/skill-format.ts         # 风格文件夹格式约定(frontmatter + {{brief}} + zip 上限)
├── src/shared/meme-contract.ts        # host↔client RPC 契约(配置/风格库/trace/点选/自更新)
├── src/shared/meme-trace.ts           # 工具 trace 类型 + 宽容解析(postprocess/skills/pick)
├── src/tools/get-all-skills.ts        # meme_gen_get_all_meme_skills
├── src/tools/pick-skill.ts            # meme_gen_pick_meme_skill(候选卡片点选)
├── src/tools/use-skill.ts             # meme_gen_use_meme_skill(点名直取)
├── src/tools/postprocess-sheets.ts    # meme_gen_postprocess_sheets(确定性后处理)
├── src/previews-route.ts              # 风格预览图静态路由
├── src/sticker-service.ts             # StickerBackend(Typert RPC 面)
├── src/img/sticker-extract.ts         # sharp 切分/去背景/归一化/预览图
├── src/client/                        # 插件页配置页(风格库 + 总开关)+ 工具渲染节点 + locale/css
├── assets/skills/                     # 内置风格(首启播种;泥塑 / 油画)
└── docs/meme-skill-format.md          # 风格压缩包格式说明