🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

语义表情 5101good/amoji

DeepSeek Harness
5101good43 天前有提交已提供中文文档扫描:含敏感能力

用带固定文字语义的表情,让人和 AI 自然表达情绪

29.5/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add 5101good/amoji
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · vision
装得上吗
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 43 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 119 处,展示前 106 条)
  • 读取本地文件
    apps/marketplace/build.mjs:15
    await readFile("../../docs/specs/amoji-0.1.schema.json", "utf8"),
  • 读取本地文件
    apps/marketplace/build.mjs:23
    const { code: css } = await transform(await readFile("web/style.css", "utf8"), {
  • 读取本地文件
    apps/marketplace/build.mjs:28
    const homepageTemplate = (await readFile("web/index.html", "utf8")).replace(
  • 写入本地文件
    apps/marketplace/build.mjs:56
    await copyFile("src/decoder.wasm", "dist/decoder.wasm").catch(async () => {
  • 写入本地文件
    apps/marketplace/build.mjs:57
    await mkdir("dist", { recursive: true });
  • 写入本地文件
    apps/marketplace/build.mjs:58
    await copyFile("src/decoder.wasm", "dist/decoder.wasm");
  • 写入本地文件
    apps/marketplace/build.mjs:60
    await mkdir("dist/public", { recursive: true });
  • 写入本地文件
    apps/marketplace/build.mjs:83
    await copyFile("web/style.css", "dist/public/style.css");
  • 读取本地文件
    apps/marketplace/build.mjs:87
    new Uint8Array(await readFile("../../assets/official-packs/classic.amoji")),
  • 写入本地文件
    apps/marketplace/build.mjs:90
    await mkdir("dist/public/art", { recursive: true });
  • 读取本地文件
    apps/marketplace/build.mjs:119
    (await readFile("web/_headers", "utf8")).replace(
  • 发起网络请求
    apps/marketplace/src/auth.ts:88
    const response = await env.FREE_RUNTIME.getByName("free-runtime-v1").fetch(
  • 发起网络请求
    apps/marketplace/src/free-runtime.ts:76
    async fetch(request: Request): Promise<Response> {
  • 发起网络请求
    apps/marketplace/src/free-runtime.ts:163
    return marketApi.fetch(request, {
  • 请求外部主机runtime
    apps/marketplace/src/maintenance.ts:7
    Promise.resolve().then(()=>runtime.getByName('free-runtime-v1').fetch('https://runtime/cleanup',{method:'POST'})),
  • 发起网络请求
    apps/marketplace/src/maintenance.ts:7
    Promise.resolve().then(()=>runtime.getByName('free-runtime-v1').fetch('https://runtime/cleanup',{method:'POST'})),
  • 请求外部主机runtime
    apps/marketplace/src/maintenance.ts:8
    Promise.resolve().then(()=>runtime.getByName('backup-v1').fetch('https://runtime/backup',{method:'POST'})),
  • 发起网络请求
    apps/marketplace/src/maintenance.ts:8
    Promise.resolve().then(()=>runtime.getByName('backup-v1').fetch('https://runtime/backup',{method:'POST'})),
  • 发起网络请求
    apps/marketplace/src/market-api.ts:144
    async fetch(request: Request, env: ApiEnv): Promise<Response> {
  • 发起网络请求
    apps/marketplace/src/market-api.ts:149
    ? env.ASSETS.fetch(request)
  • 请求外部主机runtime
    apps/marketplace/src/uploads.ts:215
    ).fetch("https://runtime/validate", {
  • 发起网络请求
    apps/marketplace/src/uploads.ts:215
    ).fetch("https://runtime/validate", {
  • 发起网络请求
    apps/marketplace/src/worker.ts:30
    async fetch(request: Request, env: Env): Promise<Response> {
  • 发起网络请求
    apps/marketplace/src/worker.ts:35
    ? env.ASSETS.fetch(request)
  • 发起网络请求
    apps/marketplace/src/worker.ts:57
    const catalog = await runtime.fetch(
  • 发起网络请求
    apps/marketplace/src/worker.ts:72
    response = await runtime.fetch(new Request(request, { headers }));
  • 读取本地文件
    src/adapter-runtime.ts:83
    async readBlob(digest: string) { return readFile(await this.client.blobPath(digest)); }
  • 读取本地文件
    src/claude-mods/bridge.ts:43
    async () => readFile(await client.blobPath(digest)), options.previewDirectory,
  • 删除本地文件
    src/claude-mods/files.ts:77
    await unlink(path).catch(() => {});
  • 读取本地文件
    src/claude-mods/market.ts:41
    try{images[e.revision_id]=await cachedThumbnailImage(blob.sha256,async()=>readFile(await client.blobPath(blob.sha256)),options.previewDirectory,'galle
  • 读取本地文件
    src/claude-mods/thumbnail.ts:47
    const cached = await readFile(join(source, filename));
  • 写入本地文件
    src/claude-mods/thumbnail.ts:60
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/claude-mods/thumbnail.ts:61
    await writeFile(temporary, pixels, { mode: 0o600, flag: "wx" });
  • 写入本地文件
    src/claude-mods/thumbnail.ts:62
    await rename(temporary, path);
  • 删除本地文件
    src/claude-mods/thumbnail.ts:64
    finally { await unlink(temporary).catch(() => {}); }
  • 写入本地文件
    src/dsh/profile-identity.ts:8
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 读取本地文件
    src/dsh/profile-identity.ts:9
    const info = await stat(directory, { bigint: true });
  • 写入本地文件
    src/dsh/profile-identity.ts:15
    await mkdir(lock, { mode: 0o700 });
  • 读取本地文件
    src/dsh/profile-identity.ts:20
    const value: unknown = JSON.parse(await readFile(path, 'utf8'));
  • 写入本地文件
    src/dsh/profile-identity.ts:26
    await writeFile(temporary, JSON.stringify({ id, fingerprint }) + '\n', { mode: 0o600, flag: 'wx' });
  • 写入本地文件
    src/dsh/profile-identity.ts:27
    await rename(temporary, path); temporary = undefined;
  • 删除本地文件递归
    src/dsh/profile-identity.ts:29
    } finally { if (temporary) await rm(temporary, { force: true }); await rm(lock, { recursive: true }); }
  • 写入本地文件
    src/library-store.ts:57
    await mkdir(join(directory, 'blobs'), { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/library-store.ts:64
    await chmod(database, 0o600);
  • 读取本地文件
    src/library-store.ts:84
    await withValidatedPack(createReadStream(seed), async pack => {
  • 写入本地文件
    src/library-store.ts:119
    try { await writeFile(temporary, await pack.readBlob(blob), { flag: 'wx', mode: 0o600 }); await rename(temporary, destination); }
  • 写入本地文件
    src/library-store.ts:119
    try { await writeFile(temporary, await pack.readBlob(blob), { flag: 'wx', mode: 0o600 }); await rename(temporary, destination); }
  • 删除本地文件
    src/library-store.ts:120
    finally { await rm(temporary, { force: true }); }
  • 读取本地文件
    src/library-store.ts:366
    if (await exists(destination)) { if (!(await readFile(destination)).equals(data)) fail('BLOB_INTEGRITY_FAILED', '已有素材损坏,不覆盖不可变素材'); }
  • 写入本地文件
    src/library-store.ts:367
    else { const temporary = `${destination}.${randomUUID()}.tmp`; await writeFile(temporary, data, { mode: 0o600 }); await rename(temporary, destination)
  • 写入本地文件
    src/library-store.ts:367
    else { const temporary = `${destination}.${randomUUID()}.tmp`; await writeFile(temporary, data, { mode: 0o600 }); await rename(temporary, destination)
  • 读取本地文件
    src/library-store.ts:765
    private async readBlob(blob: BlobRef): Promise<Buffer> { await this.verifyBlob(blob); return readFile(join(this.directory, 'blobs', blob.sha256)); }
  • 读取本地文件
    src/library-store.ts:776
    try { bytes = await readFile(join(this.directory, 'blobs', blob.sha256)); } catch { fail('BLOB_MISSING', '保留素材缺失'); }
  • 读取本地文件
    src/library-store.ts:792
    async function exists(path: string): Promise<boolean> { try { await access(path); return true; } catch (error) { if ((error as NodeJS.ErrnoException).
  • 发起网络请求
    src/local-acquisition.ts:50
    const value=JSON.parse((await this.request(path)).toString());const manifest=validatePackManifest(value.manifest);if(value.pack_id!==a.pack_id||manife
  • 发起网络请求
    src/local-acquisition.ts:55
    try{const data=JSON.parse((await this.request(path,512*1024)).toString());if(!Array.isArray(data.packs)||data.packs.length>50||!data.packs.every((p:an
  • 发起网络请求
    src/local-acquisition.ts:65
    const before=await this.detail({pack_id:identity.pack_id,release_id:identity.release_id});const bytes=await this.request(this.path(identity.pack_id,id
  • 发起网络请求
    src/local-acquisition.ts:76
    async visual(raw:unknown){const a=object(raw,['pack_id','release_id','digest']);if(!/^[a-f0-9]{64}$/.test(String(a.digest)))fail('INVALID_ARGUMENT','无
  • 读取本地文件
    src/marketplace-publisher.ts:18
    private async read<T>(name:string,fallback:T):Promise<T>{try{return JSON.parse(await readFile(join(this.directory,name),'utf8')) as T;}catch(e){if((e
  • 写入本地文件
    src/marketplace-publisher.ts:19
    private async write(name:string,value:unknown){const tmp=join(this.directory,'.'+randomUUID());try{await writeFile(tmp,JSON.stringify(value),{mode:0o6
  • 写入本地文件
    src/marketplace-publisher.ts:19
    private async write(name:string,value:unknown){const tmp=join(this.directory,'.'+randomUUID());try{await writeFile(tmp,JSON.stringify(value),{mode:0o6
  • 删除本地文件
    src/marketplace-publisher.ts:19
    private async write(name:string,value:unknown){const tmp=join(this.directory,'.'+randomUUID());try{await writeFile(tmp,JSON.stringify(value),{mode:0o6
  • 写入本地文件
    src/marketplace-publisher.ts:20
    private async init(){await mkdir(this.directory,{recursive:true,mode:0o700});if(!(await lstat(this.directory)).isDirectory())fail('PUBLISHER_STORAGE',
  • 写入本地文件
    src/marketplace-publisher.ts:20
    private async init(){await mkdir(this.directory,{recursive:true,mode:0o700});if(!(await lstat(this.directory)).isDirectory())fail('PUBLISHER_STORAGE',
  • 读取本地文件
    src/marketplace-publisher.ts:20
    private async init(){await mkdir(this.directory,{recursive:true,mode:0o700});if(!(await lstat(this.directory)).isDirectory())fail('PUBLISHER_STORAGE',
  • 发起网络请求
    src/marketplace-publisher.ts:30
    const value=await this.request('device-tokens/refresh',{refresh_token:old.refresh_token});c.tokens=this.tokens(value);await this.write('credentials.js
  • 发起网络请求
    src/marketplace-publisher.ts:37
    const c=await this.credentials();if(c.pair)await this.request(`device-authorizations/${c.pair.id}/cancel`,{device_secret:c.pair.device_secret});
  • 发起网络请求
    src/marketplace-publisher.ts:38
    const value=await this.request('device-authorizations',{device_name:nonempty(a.device_name)});c.pair={...value,next_poll:this.now()+5000};await this.w
  • 发起网络请求
    src/marketplace-publisher.ts:45
    try{const result=await this.request(`device-authorizations/${c.pair.id}/token`,{device_secret:c.pair.device_secret});if(result.state==='pending')retur
  • 发起网络请求
    src/marketplace-publisher.ts:50
    const c=await this.credentials();if(c.pair)await this.request(`device-authorizations/${c.pair.id}/cancel`,{device_secret:c.pair.device_secret});delete
  • 发起网络请求
    src/marketplace-publisher.ts:53
    const c=await this.credentials();if(c.tokens){try{await this.request('device-tokens/revoke',{refresh_token:c.tokens.refresh_token});}catch(e){if(!['PU
  • 读取本地文件
    src/marketplace-publisher.ts:90
    try{bytes=await readFile(path);}catch(e){if((e as NodeJS.ErrnoException).code!=='ENOENT')throw e;const m={...d.manifest,pack_id:u.pack_id,release_id:u
  • 写入本地文件
    src/marketplace-publisher.ts:90
    try{bytes=await readFile(path);}catch(e){if((e as NodeJS.ErrnoException).code!=='ENOENT')throw e;const m={...d.manifest,pack_id:u.pack_id,release_id:u
  • 写入本地文件
    src/packs.ts:47
    } }), createWriteStream(archive, { flags: 'wx', mode: 0o600 }));
  • 写入本地文件
    src/packs.ts:69
    } }), createWriteStream(path, { flags: 'wx', mode: 0o600 }));
  • 读取本地文件
    src/packs.ts:74
    try { value = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(await readFile(manifestPath))); }
  • 读取本地文件
    src/packs.ts:82
    return readFile(path);
  • 删除本地文件递归
    src/packs.ts:90
    } finally { zip?.close(); await rm(directory, { recursive: true, force: true }); }
  • 写入本地文件
    src/packs.ts:105
    await writeFile(path, bytes, { flag: 'wx', mode: 0o600 }); blobs.set(blob.sha256, path);
  • 写入本地文件
    src/packs.ts:110
    const done = pipeline(zip.outputStream, createWriteStream(path, { flags: 'wx', mode: 0o600 }));
  • 读取本地文件
    src/packs.ts:116
    limit((await stat(path)).size > PACK_LIMITS.archive, '压缩包超过 260 MiB');
  • 读取本地文件
    src/packs.ts:117
    return await readFile(path);
  • 删除本地文件递归
    src/packs.ts:118
    } finally { await rm(directory, { recursive: true, force: true }); }
  • 读取本地文件
    src/panel-server.ts:103
    const content = await readFile(new URL(name, this.webRoot));
  • 读取本地文件
    src/panel-server.ts:130
    const bytes = this.runtime.readBlob ? await this.runtime.readBlob(digest) : await readFile(new URL(`blobs/${digest}`, this.runtime.catalog.root));
  • 写入本地文件
    src/shared-client.ts:34
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 读取本地文件
    src/shared-client.ts:35
    directory = await realpath(directory);
  • 发起网络请求
    src/shared-client.ts:49
    const response = await fetch(`${descriptor.origin}/connect`, { headers: headers(descriptor), signal: client.lease.signal });
  • 发起网络请求
    src/shared-client.ts:103
    const response = await fetch(`${this.descriptor.origin}/rpc`, { method: 'POST', headers: { ...headers(this.descriptor), 'Content-Type': 'application/j
  • 发起网络请求
    src/shared-client.ts:130
    const response = await fetch(`${this.descriptor.origin}/packs/${path}`, { method: 'POST', headers: { ...headers(this.descriptor), 'Content-Type': cont
  • 读取本地文件
    src/shared-client.ts:221
    directory = await realpath(directory);
  • 发起网络请求
    src/shared-client.ts:226
    await decoded(await fetch(`${descriptor.origin}/stop`, { method: 'POST', headers: { ...headers(descriptor), 'Content-Type': 'application/json' }, body
  • 发起网络请求
    src/shared-client.ts:247
    const identity = await decoded(await fetch(`${descriptor.origin}/health`, { headers: { ...headers(descriptor), 'x-amoji-api-min': String(range.min), '
  • 读取本地文件
    src/shared-client.ts:255
    const metadata = await stat(path);
  • 读取本地文件
    src/shared-client.ts:257
    const d = JSON.parse(await readFile(path, 'utf8')) as ServiceDescriptor;
  • 执行外部命令来自配置/变量
    src/shared-client.ts:281
    const child = spawn(process.execPath, [...(source ? ['--import', 'tsx'] : []), entry], { env: { ...process.env, AMOJI_DATA_DIR: directory }, detached:
  • 写入本地文件
    src/shared-service.ts:24
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 读取本地文件
    src/shared-service.ts:25
    directory = await realpath(directory);
  • 写入本地文件
    src/shared-service.ts:26
    await chmod(directory, 0o700);
  • 读取本地文件
    src/shared-service.ts:36
    readBlob: async digest => readFile(await store.blobPath(digest)),
  • 读取本地文件
    src/shared-service.ts:74
    const current = JSON.parse(await readFile(join(directory, 'service.json'), 'utf8'));
  • 删除本地文件
    src/shared-service.ts:75
    if (current.serviceId === descriptor.serviceId) await rm(join(directory, 'service.json'));
  • 写入本地文件
    src/shared-service.ts:222
    await writeFile(temporary, JSON.stringify(descriptor), { mode: 0o600 });
  • 写入本地文件
    src/shared-service.ts:223
    await rename(temporary, join(directory, 'service.json'));
  • 发起网络请求
    web/panel.js:33
    const response = await fetch(`/api/${path}`, { headers, ...options, ...(body ? { method: 'POST', body: JSON.stringify(body) } : {}) });
  • 发起网络请求
    web/panel.js:50
    const response = await fetch(`/blobs/${blob.sha256}`, { headers, signal: controller.signal });
扫描于 2026/11/2(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库
涉及外部主机:runtime

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-api-session-controller@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-ui-chat@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-session@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-client-ui-tool@deepseek-ai/dsh-client-ui-workspace@deepseek-ai/dsh-llm@deepseek-ai/dsh-session
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 带固定文字语义的表情
  • 人和AI表达情绪

AI 原生表情 · dsh 的 AI 原生表情:给人看的图片,给 AI 用的固定文本语义。

README

由 DeepSeek 最新模型翻译生成
Amoji English · 开始使用 · 文档 · 下载 1.0 人机协作,也需要表情。 AI 原生表情:人看图,AI 读固定语义。让感谢、迟疑、鼓励与关怀,也能成为人和 AI 之间自然的表达。 为什么我们需要它 人与人交流时,一张表情可以让感谢更亲切,让困惑更容易说出口,也让一次提醒少一点生硬。当 AI 成为日常工作中的协作伙伴,人仍然需要这些表达:能轻松地说“我没看懂”,能为共同的进展高兴,也能在投入许多努力后,得到一句恰当的“辛苦了”。 我们相信:情感表达是人机协作的基本需求。它不应该因为模型只能处理文字,或识图成本太高,就从交互中消失。 Amoji 想让这种能力更普遍。你用一张图表达感受与意图,AI 通过随图附带的文字语义理解它;AI 也可以选择合适的表情回应你。理解一张表情的含义,可以直接走文字路径。 什么是 AI 原生表情 一张 AI 原生表情,同时面向两种阅读方式: | 面向谁 | 读到什么 | 用来做什么 | | 人 | 表情的图像、动作与神态 | 感受语气,快速表达 | | AI | 明确的含义、语气、适用与避免场景 | 理解意图,判断是否适合回应 | 传统表情主要依靠观看者理解画面。Amoji 在视觉内容之外,为每张图附上一份可以直接读取的语义约定。
展开完整文档(README 剩余 1 节)
Amoji

English · 开始使用 · 文档 · 下载 1.0

人机协作,也需要表情。

AI 原生表情:人看图,AI 读固定语义。让感谢、迟疑、鼓励与关怀,也能成为人和 AI 之间自然的表达。

为什么我们需要它

人与人交流时,一张表情可以让感谢更亲切,让困惑更容易说出口,也让一次提醒少一点生硬。当 AI 成为日常工作中的协作伙伴,人仍然需要这些表达:能轻松地说“我没看懂”,能为共同的进展高兴,也能在投入许多努力后,得到一句恰当的“辛苦了”。

我们相信:情感表达是人机协作的基本需求。它不应该因为模型只能处理文字,或识图成本太高,就从交互中消失。

Amoji 想让这种能力更普遍。你用一张图表达感受与意图,AI 通过随图附带的文字语义理解它;AI 也可以选择合适的表情回应你。理解一张表情的含义,可以直接走文字路径。

什么是 AI 原生表情

一张 AI 原生表情,同时面向两种阅读方式:

| 面向谁 | 读到什么 | 用来做什么 |
| 人 | 表情的图像、动作与神态 | 感受语气,快速表达 |
| AI | 明确的含义、语气、适用与避免场景 | 理解意图,判断是否适合回应 |

传统表情主要依靠观看者理解画面。Amoji 在视觉内容之外,为每张图附上一份可以直接读取的语义约定。例如,同样是“挠头”,它可以表达困惑、自嘲或尴尬;创作者可以明确这张表情想表达哪一种意思。

这些含义可以由用户编写,也可以先让 AI 提建议,再由用户修改、核对和确认。确认后的版本保留固定语义,历史消息始终引用发送时的版本。模型不必每次从像素重新猜测,也不能临时改写已发送表情的含义。

在协作中,它能表达什么

| 交流时刻 | 表情 | 希望传达的意思 |
| 解释太复杂,你还没理解 | 你 → AI:没看懂 | 请换一种更简单的说法,我们还没有达成理解上的一致。 |
| AI 的帮助确实有用 | 你 → AI:谢谢 | 我收到了你的帮助,也愿意表达感谢。 |
| 收到你的感谢 | AI → 你:不客气 | 你的感谢我收到了,能帮上忙就好。 |
| 现有证据还不足 | AI → 你:暂时没把握 | 目前还不能给出有把握的判断,需要进一步说明不确定在哪里。 |
| 你已经为这件事付出很多 | AI → 你:辛苦了 | 我注意到了你投入的时间与努力。 |

表情可以和解释、结果一起出现,让一句回应有更清楚的语气。你也可以选择更克制的办公画风,调整 AI 使用表情的频率,或暂停 AI 表情回应。

这带来了什么

- 让纯文本模型也能参与。 理解表情所需的信息以文字提供,无需为了这一张表情额外具备视觉能力。
- 把识图开销省在理解路径之外。 模型可以检索和读取简短语义,省去对表情图片的视觉推理;仍会产生正常的文字与工具调用开销。
- 让含义有据可查。 你能看到 AI 将读到什么,也能明确表达的语气和使用边界,减少双方对同一张图各自猜测。
- 让交流是双向的。 人可以表达反馈与情绪,AI 可以用合适的表情回应感谢、表达不确定或提供鼓励。
- 让表达由你定义。 自己创作、导入图片、确认语义,再通过 .amoji 文件分享;你可以拥有自己的表情体系。

从 dsh 开始

Amoji 的愿景,是让这套表达方式能够跨越模型与客户端。1.0 从 dsh 的原生交互开始,把选择、发送、理解和管理放进同一个工作流:

- 原生双向表情:输入区点选即发送,AI 通过文字工具检索和选用,图片直接显示在会话中。
- 经典与办公画风:相同的 24 种语义、共 48 个资产,覆盖人向 AI 表达和 AI 回应人的场景。
- 一个输入框辅助创作:描述想表达的意思,选择宿主模型生成文字建议;默认使用当前会话模型,由你采用、修改和确认。
- 本地个人表情库:草稿、版本、归档、个人副本、完整包导入导出,以及 AI 使用偏好。
- 中英界面:跟随 dsh 的语言设置。界面翻译不会改写表情本身的语义,内置语义目前为中文。

看看实际界面:经典画风、办公画风与固定语义

经典画风办公画风 AI 读取的固定语义

安装

已经在使用 dsh 的 web profile,可以直接安装公开发布包,然后重启该 profile:

dsh plugin --profile web add https://github.com/5101good/amoji/releases/download/v1.0.0/amoji-dsh-1.0.0.tgz --ignore-scripts

需要独立 profile 或先核验下载文件时:

1. 使用 Node.js 24 或更新版本。当前验证基线为 dsh 0.1.5-rc.2 / macOS arm64。
2. 从 GitHub Releases 下载 amoji-dsh-1.0.0.tgz,按同次发布的 SHA256SUMS 核对 SHA-256。
3. 安装到自己的 dsh profile,重启该 profile,选择工作区后打开输入区的“表情”。

第一条命令为新 profile 初始化 Web 模板并显示帮助;随后安装并启动。

npx @deepseek-ai/dsh@0.1.5-rc.2 --profile amoji --from-default-profile web --helpsh
npx @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile amoji add ./amoji-dsh-1.0.0.tgz --ignore-scripts
npx @deepseek-ai/dsh@0.1.5-rc.2 --profile amoji

amoji 是示例 profile 名称;使用已有 profile 时替换它。源码安装参见构建步骤。插件安装成功与运行激活是两项不同检查。

使用

在选择器中搜索并点选表情即可发送;详情按钮用于先阅读固定语义。在“管理表情”中切换画风、调整 AI 语气与频率、管理自己的素材。AI 表情可独立暂停。

创作时描述“谁对谁说、什么情境、想表达什么、什么语气”,选择模型后生成建议。Amoji 只向所选模型发送文字意图和生成指令,不发送图片或会话历史。生成按宿主所配置模型的规则计费;也可以完全手工填写。建议不会自动保存或入库。

完整使用指南涵盖草稿确认、编辑旧版本、导入导出、连接恢复及发送状态。

验证与边界

1.0 以 dsh 为主要支持宿主。已有 macOS arm64 的本地安装、实际浏览器使用及一次真实 Flash 文字建议成功记录;这些证据不代表所有模型、平台或宿主版本均通过。一次 AI 发送测试的表情已成功显示,但提供方工具续答因 reasoning_text 兼容问题返回 HTTP 400,不能算完整模型回合成功。

Linux、Windows 和其他 dsh 版本未完成真实宿主验收。Code Dispatch / PTC 嵌套工具不保证图片展示。Codex、Claude Code 实现作为 legacy 保留,暂不纳入 1.0 真机验证或兼容承诺。详见发布与已知限制。

一起丰富这套表达

我们希望通过开放的格式和开源实现,让更多人参与定义 AI 时代的表情:它们可以温暖、幽默,也可以严肃、克制。欢迎分享真实协作中的表达需求、创作新的画风与语义,或帮助我们改进交互和宿主适配。

你可以从试用 Amoji、提出建议或贡献代码与素材开始。

开发 sh
npm ci
npm run typecheck
npm test
npm run test:dsh

test:dsh 会构建插件并检查锁定的 dsh npm 合同。构建输出为 adapters/dsh。开发指南、架构与协议、贡献指南和安全政策说明开发、验证与报告问题的方法。

代码和技术文档使用 MIT;内置基础表情视觉、固定语义及生成提示使用 CC0-1.0。生成来源见基础库说明。第三方依赖、用户素材保留各自许可,见 NOTICE。
预览分享卡片长什么样 ↓5101good/amoji
分享 · DeepSeek Harness Hub
5101good/amoji

用带固定文字语义的表情,让人和 AI 自然表达情绪

这是你的仓库?认领条目

回到顶部