dsh-model-logos
> English: README.md
为你真正在用的模型配上品牌标记 —— 内置图形、你自己的图片,以及动态图标 —— 一个为 DeepSeek Harness(DSH)Web 界面写的小插件。
为什么需要图标?
模型列表曾经很短。如今它是一片人海:DeepSeek、GPT、Claude、Gemini、Qwen、GLM、Kimi、豆包、Llama、Mistral……全都显示成同样的灰色文字。逐个读名字,是找到想要那个的办法;认出一枚标记,是不用读就能找到的办法。这就是图标成立的全部理由:它把选择从「回忆」变成「识别」。
最需要它的地方是输入区的模型按钮 —— 你发送消息前最后会看一眼的控件。界面用一串文字回答「这是哪个模型?」;而一枚标记能一眼回答,就像手机桌面不会只是一列应用名称。名字只差一个后缀的模型也很容易点错,标记能在发送前拦住这个错误。
这是那个按钮和它打开的菜单,按实际尺寸做出的静态预览 —— 13 px 标签旁 20 px 的标记,浅色与深色背景:
「设置 → 模型」把这一点体现得更直白:提供商行显示的是路由 id(例如 anthropic)或显示名,添加提供商下拉框又是一串 id,模型编辑器则是一格格文本输入框。一枚 Logo 让每一行有了凭形状就能找到的轮廓,也让选择通道可以靠看,而不是靠拼写。
插件里还有第二个更安静的想法:一个模型可以有两个品牌。 厂商(vendor)是提供它的通道 —— OpenRouter、火山引擎、一个本地中转。模型(model)是你在对话的对象 —— Claude、Qwen、DeepSeek。在聚合器的一行里,这是两个不同的答案,所以它们得到两枚不同的标记,插件也谨慎地不让其中一个冒充另一个。
它长什么样
「设置 → 模型」,加载插件后:每一行官方提供商和每个编辑器标题左侧都预留 22 px 的标记位(官方通道填入厂商标记,手写提供商留空占位),点一下这个图标位即可为提供方选择图标;每个模型行开头都有预留 22 px 的图标位(模型标记,或一键可点的虚线占位);添加提供商的原生 `` 换成带 Logo 的自定义下拉框;插件自己的入口也在设置导航里。
这张装饰后的页面由校验脚本用同一份页面标记渲染 —— 通道是靠 Logo 选的,不是靠路由 id。
你得到什么
- 输入区和模型选择器 —— 模型按钮上是当前模型的标记,选择器顶部是当前模型,每个选项行也有标记。点击、搜索、勾选状态和推理强度标签仍归内置选择器所有。标签本身是重绘而非包裹(同一个位置只能容纳一个标签),因此这个组件会复现模型名和内置标签上的发布徽标。这是插件唯一一处「替换」。
- 设置 → 模型 —— 每个提供商行和提供商编辑器标题左侧都保留 22 px 的标记位:官方通道填入厂商 Logo,手写提供商留空占位;每个模型行开头有预留 22 px 的图标位(还没有把握时在图标位里显示虚线占位,标记出现时文字不会挪动);盖在原生提供商 `` 上的自定义下拉框带 Logo(原生 select 仍留在下面作为状态来源)。两处标记位都在弹窗第一帧绘制之前就位 —— 装饰在 DOM 监视回调里同步执行(早于布局),而不是等定时器 —— 所以再次打开设置时不会先露出没有标记位的行、再横向跳一下。
- 「模型图标」页面 —— 插件自己的设置页会先列出你的提供商及其当前厂商标记,可以在这里选择或恢复;随后列出这些提供商下的模型、它们当前的标记,并可以从这里修改。列表还会并入宿主机当前实际可路由的模型:只在运行时目录里、不写进设置文档的模型同样有一行。最典型的是已登录的 DeepSeek 账号路由 —— 它的模型来自账号列表 —— 所以每个账号模型也能单独设置图标。
- 随时可用的选择器 —— 在「设置 → 模型」里点模型的图标,或点提供方的图标位(以提供方模式打开),或在「模型图标」页面按行选择,就能打开它;改掉一次误判只需要一次点击,不用编辑配置文件。自定义图标的创建、重命名与删除也在这个弹窗里完成。
- 动态自定义图标 —— 自定义图标可以循环播放:编辑器把 GIF、WebP、APNG、AVIF 动图或短视频采样成 sprite atlas,并在你选择的分面上播放,海报帧始终兜底。见动态图标。
除此之外都是围绕现有界面添加的;禁用插件会移除这些装饰,让页面恢复原样。
选择图标
插件会先自动匹配 —— 根据模型 id 和名称、再根据提供商给出一个「初始」图标。这是有用的默认值,不是规则,每个模型都可以覆盖:
- 自动识别 —— 回到自动匹配的结果;
- 不使用图标 —— 这个模型不显示品牌标记;
- 首字母图标 —— 用名称生成一个确定性的色块,适合那些既不想冒充品牌、又希望看起来像有意为之的本地或小众模型;
- 厂商图标 —— 公司或渠道的标记(Anthropic、Google、Alibaba、ByteDance、OpenRouter、火山引擎、LM Studio 等);
- 模型图标 —— 模型产品的标记(Claude、Gemini、Qwen、豆包、Kimi 等)。
提供方的图标同样可以配置。 在「设置 → 模型」里点击提供方名称左侧的图标位,或在「模型图标」页面的提供方行上点选择按钮,就会以「提供方模式」打开同一个选择器:挑一枚厂商标记、首字母图标,或不使用图标,也可以恢复自动。手写提供方(中转、本地服务)也可以在这里挑内置标记;如果要的是自己的图形,用下面的自定义图标。
自定义图标。 选择器最上面是「自定义图标」分类,格子里的「+ 新建」打开编辑器:起一个名字,选一张本地图片,在方形取景框里拖动、缩放,保存时裁成 128×128 的方形图标。图标以裁剪后的 PNG(超过体积预算时转 WebP)存进 DSH 用户设置文档的 customIcons 字段,覆盖值记录为 custom: —— 和 modelIcons / providerIcons 是同一份文档,随配置走,不依赖浏览器 localStorage,也不产生网络请求。图标沿用品牌标记的圆角方形外观:按图标的 6/24 比例裁剪圆角(20px 时 5px、22px 时 5.5px、36px 时 9px,随尺寸等比缩放),所以它在任何一行里都和品牌标记一致。自定义图标可以像品牌标记一样用于任意模型或提供方;卡片右上角的铅笔可以重命名,编辑器里的删除会先确认,并在同一次写入中清掉引用它的所有覆盖,让这些行回到自动识别。
编辑器顶部的第二个类型 tab「动态」会把动图或短视频变成循环图标 —— 那套流程单独写在动态图标里。
图片裁剪与取景使用 MIT 许可的 react-easy-crop,不是手写的拖拽框。上限:40 枚自定义图标、名称 24 个字符、静态图片 12 MB;整个自定义图标文档不超过 3 MiB。
提供方覆盖存在 providerIcons,模型覆盖存在 modelIcons,自定义图标存在 customIcons,三者互不冲突;提供方覆盖优先于官方渠道表,未知渠道仍回退为确定性的字母色块。
选择器先放你自己的图标,再上下排布厂商与模型两组,并同时搜索这些分类。有些公司和模型共用一枚图形(DeepSeek、Mistral、MiniMax),这些标记放在模型组,官方渠道行复用同一枚 artwork;当两者确实不同时 —— Anthropic≠Claude、Google≠Gemini、Alibaba≠Qwen、ByteDance≠豆包 —— 选择器会同时提供两枚标记,而不是让其中一枚冒充另一枚。
组内按可量化的网络知名度排序,而不是按字母:一份可复现的快照综合 GitHub、npm、Wikipedia、Hugging Face 与 B 站信号,让真正会被找的标记排在前面。方法与原始数据见 docs/rankings.md。
模型覆盖项绑定在 provider + model 这一对上,所以两个提供商服务同名模型时可以显示不同标记;提供方覆盖则只按路由 id 记录。它们保存在 DSH 用户设置文档里(配置档的 cordis.patch.yml)—— modelIcons、providerIcons、自定义图标的 customIcons(含每枚图标可选的 motion 采样记录),以及 playback 播放策略 —— 和其他偏好放在一起,不用 localStorage,也不产生任何网络请求。
动态图标
自定义图标不必是静止的。在编辑器里切到「动态」,插件就接受 GIF、WebP、APNG、AVIF 动图,或 MP4 / WebM 短视频:在本地解码,把最多两秒采样成 4–24 帧,并在首帧海报旁保存一条横向的 sprite atlas。整个过程不上传,运行时也不拉取任何东西;它和别的标记一样,仍随设置文档一起走。
下面的示例是一枚真实的 9 帧 GIF。导演台会在当前帧上框取方形裁剪,实时预览线上真正使用的四种尺寸(20 / 22 / 36 / 64 px),并随帧数、单帧边长与画质调整显示 atlas 相对 128 KiB 预算的体积。超出预算时,「自动瘦身」会按固定的「画质 → 帧数 → 边长」阶梯逐项尝试,逐条列出改动,并支持一键恢复 —— 截图就是走完这一步后的结果。
播放策略按界面分面配置,位于「模型图标」页面底部:会话输入框默认 始终播放,设置 → 模型、模型图标页与图标选择器默认 仅交互播放,每一项也都可以关闭。所有分面都尊重系统的「减少动态效果」设置;选择器里的动态图标还带一枚小小的「动」角标,不播放时也能认出来。分面播放设置:
海报永远是兜底:旧版客户端、损坏的 atlas 或开启减少动态效果的系统会画首帧,而不是丢掉图标,所以动态图标永远不会比静态图标更差。素材上限:动图 24 MB、视频 64 MB;单枚图标的 atlas 不超过 128 KiB。
诚实面对的情况
- 厂商 Logo 只属于官方通道。 中转、自建服务器或本地 URL 背后没有厂商品牌,所以没有厂商 Logo —— 编造一个出来就是在撒谎。名称左侧的标记位仍然保留(留空)让各行对齐;每个官方通道都有标记,冷门通道回退为确定性的字母色块。这个空的图标位是可以点的:插件不会替你编造品牌,但会让你自己选一个。
- 没把握的模型不会被留白。 设置里的那一行会保留 22 px 的图标位并显示虚线占位,一点就能打开选择器 —— 真正的标记出现时名称不会跳动。
- 名称始终都在。 每个按钮、每个菜单行仍然带着名字,即使不认识标记,界面也照样可用。
安装
从 npm 安装已发布的包到 DSH 配置档。npm 包内已带预构建的 client.js / index.js,
无需本机构建、Node.js 工具链或构建授权:
dsh plugin --profile web add dsh-model-logos
插件要求 DSH 0.2.2-alpha.3 或更高(低于 0.3.0):设置页装饰依赖这条版本线引入的弹窗结构,package.json 里的 engines.dsh 范围会让 DSH 在加载插件前拒绝更旧的宿主。
也可以直接添加公开仓库。源码安装会在本机构建插件 —— 仓库的 prepare 脚本会执行
pnpm run build —— 因此需要 Node.js ≥ 24.22.2 与 pnpm,市场上首次安装时也会请求一次构建授权:
dsh plugin --profile web add github:Altermoe/dsh-model-logos
不用 npm 又想跳过构建,可以从
最新发布 下载
dsh-model-logos.tgz,直接安装这个文件:
dsh plugin --profile web add ./dsh-model-logos.tgz
本地检出也可以走插件管理器安装:
plugin_manager action=install_bundle target=<指向本目录的绝对路径>
然后刷新 Web 界面。插件在「插件」里显示为 Model Logos / 模型 Logo;禁用它就会移除装饰,恢复原本的界面。
关于这些图标
每一枚标记都是自包含的 24×24 SVG 方块 —— 品牌色的圆角方块,加上在实际使用尺寸(输入区模型按钮旁的 20 px,设置行旁的 22 px,图标选择器预览里的 36 px)下仍然清晰可辨的图形。运行时不拉取任何东西,所以这些图标不需要网络,也不依赖外部资源。
图形不是靠肉眼重画的,而是来自固定版本的官方矢量集 —— @lobehub/icons-static-svg 1.102.0(MIT),加上 Simple Icons(CC0)的 Xiaomi,以及取自本应用 Web 前端的 DeepSeek 官方鲸鱼 —— 由入库的导入脚本统一收进同样的方块。构建检查会把生成的路径数据与已提交的上游文件逐条比对,所以想改一枚标记,只能改它的来源。少数例外在源码里注明:Radius 没有官方图形;AWS 保留官方 smile 符号,因为完整字标在图标尺寸下不可读;Xiaomi 保留 Simple Icons 的「mi」。其中两枚标记不是从该包导入,而是由各自的固定来源重建:智谱的 Z 取自 zai-org/GLM-5 官方 logo(Apache-2.0,GLM 共用),Gemini 的极光配色取自 Lobe 的彩色标记。两者都提交在 reference/derived/ 下并有离线重建校验,所以同样只能通过改来源来改图。
原先偏差最明显的标记从来源层修正:Claude 换成官方不规则实心放射状、Ollama 换成正面看镜头的羊驼、豆包换成官方女性形象,替换掉旧的齿轮、侧脸剪影和聊天气泡。MiniMax 2025 年的波形与 Mistral 的像素方块 M 保留此前校正过的形状。品牌 Logo 是其所有者的商标,在此仅用于标识实际使用的提供商或模型。
开发
工具链要求 Node.js ≥ 24.22.2 与 pnpm(确切版本由 packageManager 固定)。client.js 与 index.js 是生成的构建产物 —— 不要手工编辑。
pnpm install # 安装依赖;prepare 脚本同时构建两个产物
pnpm run build # 修改 src/** 后重新生成 client.js + index.js
pnpm run verify # 完整门禁:类型检查、lint、格式化、测试、图标/排序校验、构建、产物一致性
pnpm run verify:dom # 在无头 Edge 中用真实 bundle 驱动 Settings 测试页面
pnpm run preview # 生成图标设计总览到 .preview/
pnpm run logo:check # 校验入库图标与固定版本官方矢量一致
pnpm run rank:check # 校验选择器顺序与提交的热度快照一致
发布(维护者)
npm 包是非 scoped 的公开包。pnpm publish 会先执行 prepublishOnly(完整 verify
门禁),再把生成的 client.js / index.js 打进包。一次发布是一个只改 version、
docs/engineering.md 验证日志与 docs/awesome-plugin.md §8 发布记录的提交;npm 版本、
tag 与 release 资产必须指向同一个提交。
scripts/ 下的两个交互式脚本会跑完整流程。它们不会保存或打印凭证:npm 认证用 pnpm
自己已登录的凭证(或你导出的 NPM_TOKEN),GitHub 认证用 gh 登录、GH_TOKEN /
GITHUB_TOKEN,或本次临时输入的 token。
pnpm run release:dry-run # 预演:检查仓库状态、凭证、打包,不发布任何东西
pnpm run release # 门禁、发布提交、推送、tag、npm 发布、资产、GitHub release
release:dry-run 只验证不发布;它会校验凭证、试打包并打印完整计划(加 --gates
还会跑完整门禁)。release 在每个破坏性步骤前询问,npm 双因素授权要求交互式终端
(脚本会打印授权链接,授权后继续),失败后可用 --from 从指定步骤续跑。
两者都尊重环境里的 EDGE、DSH_WEB_URL 与常规代理变量。
手动执行时等价于:
pnpm run verify
git commit -am "chore: bump the version to X" # 版本 + 发布记录
git push origin main
git tag -a vX -m "dsh-model-logos X" && git push origin vX
pnpm publish --access public # prepublishOnly 会再跑一次 verify
pnpm pack # 同一棵树 → dsh-model-logos-X.tgz
gh release create vX dsh-model-logos.tgz --title "dsh-model-logos X" --notes-file notes.md
pnpm pack 产出的文件名带版本号,附到 release 前改名为版本无关的
dsh-model-logos.tgz;latest/download/ 按字面文件名匹配,带版本号会在下次发布时 404。
发布记录里同时记下它的 SHA-256。
发布新版本前先提升 version,并建立对应的附注 v tag 与 release(v0.6.0、0.7.0……);tag 必须与 package.json 的版本一致,否则商店与 dshmarket 会显示一个 npm 上并不存在的版本。发布后用
pnpm view dsh-model-logos version 确认版本,再用
dsh plugin --profile web add dsh-model-logos 在干净配置档里验证安装。
模块图、贡献规则与验证日志在 docs/engineering.md;运行时契约与设计决策在 docs/architecture.md。
相关文档
docs/prior-art.md· 中文版 —— 这个插件与其他 DSH 图标插件的关系。docs/awesome-plugin.md—— 上架元数据与提交清单。