Chuyển đến nội dung chính

dsh-meme-gen

Đã xác minh

@liaozhi/dsh-meme-gen · v0.9.2 · MIT · Giao diện web

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

Cài đặt

dsh plugin add @liaozhi/dsh-meme-gen

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.

Thẻ

Tác giả

Readme

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          # 风格压缩包格式说明