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

本地会议转写 huliux/dsh-asr-plugin

DeepSeek Harnessv0.1.4
huliux1 天前有提交已提供中文文档扫描:含敏感能力

面向 Apple Silicon macOS 的 DeepSeek HarnessDSH非官方本地会议转写插件。

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

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

自动兼容检查未通过:engines.node 要求 >=24.0.0 <25,不满足 Node 22.19.0;仓库 package.json 标记 private,未发布到 npm,需从源码安装。以下命令仍可尝试,但可能失败。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add huliux/dsh-asr-plugin
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

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

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

engines.node 要求 >=24.0.0 <25,不满足 Node 22.19.0;仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@huliux/dsh-asr-plugin @ 0.1.4
✗Node 引擎要求 >=24.0.0 <25 · 基线 Node 22.19 不满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/29 11:39:02

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件写入剪贴板(不计风险)
查看扫描证据(共 96 处,展示前 83 条)
  • 写入剪贴板
    site/copy.js:6
    await navigator.clipboard.writeText(text);
  • 读取本地文件
    src/audio/closed-recording-chunks.ts:77
    const canonical = await realpath(path);
  • 读取本地文件
    src/audio/closed-recording-chunks.ts:79
    const info = await stat(canonical);
  • 读取本地文件
    src/audio/closed-recording-chunks.ts:133
    const info = await stat(known.id);
  • 读取本地文件
    src/audio/closed-recording-chunks.ts:148
    const entries = await readdir(root, { withFileTypes: true });
  • 读取本地文件
    src/audio/closed-recording-chunks.ts:155
    const path = await realpath(join(root, entry.name));
  • 读取本地文件
    src/audio/closed-recording-chunks.ts:169
    const recordingRoot = await realpath(recordingDirectory);
  • 读取本地文件
    src/audio/managed-audio-normalizer.ts:113
    stats = await lstat(filePath);
  • 写入本地文件
    src/audio/managed-audio-normalizer.ts:201
    await chmod(input.audioTemporaryPath, 0o600);
  • 写入本地文件
    src/audio/managed-audio-normalizer.ts:203
    await rename(input.audioTemporaryPath, input.audioPath);
  • 删除本地文件
    src/audio/managed-audio-normalizer.ts:216
    await rm(input.audioTemporaryPath, { force: true }).catch((error: unknown) => {
  • 写入本地文件
    src/audio/managed-audio-normalizer.ts:226
    await copyFile(input.sourcePath, input.audioTemporaryPath, constants.COPYFILE_EXCL);
  • 删除本地文件
    src/audio/managed-audio-normalizer.ts:236
    await rm(input.audioTemporaryPath, { force: true }).catch(() => undefined);
  • 删除本地文件
    src/audio/recording-audio-candidate.ts:121
    await rm(path, { force: true });
  • 删除本地文件
    src/audio/recording-audio-candidate.ts:131
    await rm(path, { force: true }).catch(() => undefined);
  • 读取本地文件
    src/audio/recording-audio-candidate.ts:144
    for await (const chunk of createReadStream(path)) {
  • 删除本地文件
    src/audio/recording-audio-candidate.ts:161
    await rm(destination, { force: true });
  • 写入本地文件
    src/audio/recording-audio-candidate.ts:162
    await copyFile(source, destination, constants.COPYFILE_FICLONE);
  • 写入本地文件
    src/audio/recording-audio-candidate.ts:163
    await chmod(destination, 0o600);
  • 删除本地文件
    src/audio/recording-audio-candidate.ts:180
    await Promise.all(CANDIDATE_FILES.map((name) => rm(join(directory, name), { force: true })));
  • 删除本地文件
    src/audio/recording-audio-candidate.ts:187
    await Promise.all(tracks.map(async (track) => rm(
  • 写入本地文件
    src/audio/recording-audio-candidate.ts:201
    await mkdir(paths.workRecordingDirectory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/audio/recording-audio-candidate.ts:202
    await chmod(paths.workRecordingDirectory, 0o700);
  • 读取本地文件
    src/audio/recording-audio-candidate.ts:230
    const sourceSizeBytes = (await stat(audioPath)).size;
  • 读取本地文件
    src/audio/recording-audio-candidate.ts:262
    const canonicalDirectory = await realpath(directory);
  • 读取本地文件
    src/audio/recording-audio-candidate.ts:264
    const info = await lstat(path);
  • 读取本地文件
    src/audio/recording-audio-candidate.ts:265
    if (!info.isFile() || await realpath(path) !== path) {
  • 读取本地文件
    src/audio/recording-audio-candidate.ts:278
    await lstat(path);
  • 写入本地文件
    src/audio/recording-audio-candidate.ts:342
    await rename(inspected[index + 1]!.canonical, join(paths.recordingDirectory, `${track}.wav`));
  • 写入本地文件
    src/audio/recording-audio-candidate.ts:345
    await rename(audio.canonical, sourcePath);
  • 写入本地文件
    src/index.ts:93
    await mkdir(databaseDirectory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/index.ts:94
    await chmod(databaseDirectory, 0o700);
  • 读取本地文件
    src/recording/final-cache.ts:94
    const info = await lstat(path);
  • 读取本地文件
    src/recording/final-cache.ts:96
    return await readFile(path);
  • 删除本地文件
    src/recording/final-cache.ts:104
    await rm(temporary, { force: true });
  • 写入本地文件
    src/recording/final-cache.ts:106
    await writeFile(temporary, bytes, { flag: "wx", mode: 0o600 });
  • 写入本地文件
    src/recording/final-cache.ts:107
    await rename(temporary, path);
  • 删除本地文件
    src/recording/final-cache.ts:109
    await rm(temporary, { force: true }).catch(() => undefined);
  • 写入本地文件
    src/recording/final-cache.ts:179
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/recording/final-cache.ts:180
    await chmod(directory, 0o700);
  • 写入本地文件
    src/recording/helper-client.ts:108
    await mkdir(directory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/recording/helper-client.ts:118
    await rename(temporary, path);
  • 删除本地文件
    src/recording/helper-client.ts:122
    await unlink(temporary).catch(() => undefined);
  • 读取本地文件
    src/recording/permissions.ts:71
    parent = await realpath(await mkdtemp(join(tmpdir(), "dsh-asr-permission-")));
  • 写入本地文件
    src/recording/permissions.ts:74
    await mkdir(root, { mode: 0o700 });
  • 删除本地文件递归
    src/recording/permissions.ts:77
    try { if (parent !== undefined) await rm(parent, { recursive: true, force: true }); }
  • 写入本地文件
    src/recording/permissions.ts:89
    const cancel = () => { void writeFile(join(root, "cancel"), "", { mode: 0o600 }).catch(() => undefined); };
  • 读取本地文件
    src/recording/permissions.ts:98
    const raw = await readFile(join(root, "permissions.json"), "utf8");
  • 写入本地文件
    src/recording/permissions.ts:107
    await writeFile(join(root, "cancel"), "", { mode: 0o600 }).catch(() => undefined);
  • 读取本地文件
    src/recording/worker-runtime.ts:141
    const child = await realpath(join(root, ...parts));
  • 读取本地文件
    src/recording/worker-runtime.ts:143
    if (!(await stat(child)).isDirectory()) throw new Error("not a directory");
  • 写入本地文件
    src/storage/data-root-lease.ts:12
    await mkdir(dataRoot, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/storage/data-root-lease.ts:13
    await chmod(dataRoot, 0o700);
  • 写入本地文件
    src/storage/database.ts:139
    chmodSync(filename, 0o600);
  • 读取本地文件
    src/storage/managed-audio-store.ts:178
    const stats = await lstat(sourcePath);
  • 读取本地文件
    src/storage/managed-audio-store.ts:187
    const stats = await lstat(sourcePath);
  • 写入本地文件
    src/storage/managed-audio-store.ts:234
    await mkdir(paths.meetingDirectory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/storage/managed-audio-store.ts:235
    await mkdir(paths.workDirectory, { recursive: true, mode: 0o700 });
  • 写入本地文件
    src/storage/managed-audio-store.ts:236
    await chmod(paths.meetingDirectory, 0o700);
  • 写入本地文件
    src/storage/managed-audio-store.ts:237
    await chmod(paths.workDirectory, 0o700);
  • 删除本地文件
    src/storage/managed-audio-store.ts:238
    await rm(paths.sourceTemporaryPath, { force: true });
  • 写入本地文件
    src/storage/managed-audio-store.ts:251
    await rename(paths.sourceTemporaryPath, paths.sourcePath);
  • 删除本地文件
    src/storage/managed-audio-store.ts:262
    await rm(paths.sourceTemporaryPath, { force: true }).catch(() => undefined);
  • 删除本地文件递归
    src/storage/managed-audio-store.ts:289
    await rm(workRoot, { force: true, recursive: true });
  • 写入本地文件
    src/storage/managed-audio-store.ts:290
    await mkdir(workRoot, { recursive: true, mode: 0o700 });
  • 删除本地文件递归
    src/storage/managed-audio-store.ts:300
    await rm(workDirectory, { force: true, recursive: true });
  • 删除本地文件递归
    src/storage/managed-audio-store.ts:310
    await rm(paths.meetingDirectory, { force: true, recursive: true });
  • 删除本地文件递归
    src/storage/managed-audio-store.ts:311
    await rm(paths.workDirectory, { force: true, recursive: true });
  • 读取本地文件
    src/storage/managed-audio-store.ts:466
    const dataRoot = await realpath(options.dataRoot);
  • 读取本地文件
    src/storage/managed-file-tree.ts:7
    stats = await lstat(path);
  • 读取本地文件
    src/storage/managed-file-tree.ts:14
    const entries = await readdir(path);
  • 写入本地文件
    src/storage/sqlite-exclusive-lease.ts:45
    await chmod(path, 0o600);
  • 读取本地文件
    src/transcript-projection/transcript-export-publisher.ts:57
    realpath(input.dataRoot),
  • 读取本地文件
    src/transcript-projection/transcript-export-publisher.ts:58
    realpath(dirname(input.outputPath)),
  • 读取本地文件
    src/transcript-projection/transcript-export-publisher.ts:60
    if (!(await stat(parent)).isDirectory()) {
  • 读取本地文件
    src/transcript-projection/transcript-export-publisher.ts:75
    const value = await lstat(outputPath);
  • 写入本地文件
    src/transcript-projection/transcript-export-publisher.ts:158
    if (input.overwrite) await rename(temporaryPath, outputPath);
  • 删除本地文件
    src/transcript-projection/transcript-export-publisher.ts:161
    await unlink(temporaryPath);
  • 删除本地文件
    src/transcript-projection/transcript-export-publisher.ts:173
    if (temporaryPath !== undefined) await unlink(temporaryPath).catch(() => undefined);
  • 读取本地文件
    src/worker/managed-audio.ts:15
    const canonical = await realpath(directory);
  • 读取本地文件
    src/worker/managed-audio.ts:16
    if (!(await stat(canonical)).isDirectory()) throw new Error("not a directory");
  • 读取本地文件
    src/worker/managed-audio.ts:42
    canonical = await realpath(audioPath);
  • 执行外部命令来自配置/变量
    src/worker/node-spawner.ts:49
    const child = spawn(command, args, {
扫描于 2026/11/1(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库

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

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-home-paths@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/cordis-plugin-group@deepseek-ai/cordis-plugin-include@deepseek-ai/cordis-plugin-loader@deepseek-ai/dsh-agent@deepseek-ai/dsh-api-session-controller@deepseek-ai/dsh-api-workspace-controller@deepseek-ai/dsh-app-boot@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-locale
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

界面预览

4 张 · 点击查看大图

功能亮点

  • 本地会议转录

非官方本地会议转录,为 Apple Silicon macOS 上的 DeepSeek Harness 打造

README

由 DeepSeek 最新模型翻译生成
dsh-asr-plugin 项目网站 ·快速开始 面向 Apple Silicon macOS 的 DeepSeek Harness(DSH)非官方本地会议转写插件。 支持导入 WAV、M4A、MP3 文件,录制麦克风与系统音频,生成包含时间戳和说话人标签的转写文本。会议可在 DSH 消息中显式引用,用于阅读与导出。 录音继续进行时引用当前会议生成阶段性总结 示例使用语音合成的虚构会议。在录音继续进行时,通过 @ 引用当前会议,让配置的 DeepSeek 模型读取实时草稿并生成阶段性总结。总结是用户主动请求的当前快照,后续可能随草稿变化。完整案例与环境信息见案例截图。 官方社区展示帖。 兼容性 | 组件 | 要求 | | 宿主 | DSH 0.2.0-rc.2、0.2.1-rc.2、0.2.1-rc.3 或 0.2.1-rc.5 | | 运行时 | Node.js 24 | | 平台 | macOS、Apple Silicon(darwin / arm64) | | 麦克风 API | macOS 13.5 或更高版本 | | 系统音频与双轨 API | macOS 14.2 或更高版本 | 上述 macOS 版本表示 API 可用下限,不代表完整的操作系统测试矩阵。 DSH 桌面版和 Web 模式均在运行 DSH 的 Mac 上处理音频。
展开完整文档(README 剩余 1 节)
dsh-asr-plugin

项目网站 ·快速开始

面向 Apple Silicon macOS 的 DeepSeek Harness(DSH)非官方本地会议转写插件。
支持导入 WAV、M4A、MP3 文件,录制麦克风与系统音频,生成包含时间戳和说话人标签的转写文本。会议可在 DSH 消息中显式引用,用于阅读与导出。

录音继续进行时引用当前会议生成阶段性总结

示例使用语音合成的虚构会议。在录音继续进行时,通过 @ 引用当前会议,让配置的 DeepSeek 模型读取实时草稿并生成阶段性总结。总结是用户主动请求的当前快照,后续可能随草稿变化。完整案例与环境信息见案例截图。
官方社区展示帖。

兼容性

| 组件 | 要求 |
| 宿主 | DSH 0.2.0-rc.2、0.2.1-rc.2、0.2.1-rc.3 或 0.2.1-rc.5 |
| 运行时 | Node.js 24 |
| 平台 | macOS、Apple Silicon(darwin / arm64) |
| 麦克风 API | macOS 13.5 或更高版本 |
| 系统音频与双轨 API | macOS 14.2 或更高版本 |

上述 macOS 版本表示 API 可用下限,不代表完整的操作系统测试矩阵。
DSH 桌面版和 Web 模式均在运行 DSH 的 Mac 上处理音频。
Windows、Linux 和 Intel Mac 不受支持。

安装

在 DSH 插件页安装 @huliux/dsh-asr-plugin。Web 配置也支持命令行安装:

dsh plugin --profile web add --ignore-scripts @huliux/dsh-asr-plugin@0.1.5

使用 DSH 0.2.1-rc.5 时,请升级至插件 0.1.5。桌面版在插件页选择 添加插件,输入 @huliux/dsh-asr-plugin@0.1.5;Web 用户可再次运行上面的命令。若宿主提示,请重启 DSH。支持的宿主版本无需添加兼容性豁免。
若桌面安装器提示“该插件已安装”,请从 GitHub Release 下载对应版本的 .tgz 和 SHA256SUMS,校验后在添加插件中输入安装包的绝对路径。此更新方式保留现有插件配置和会议数据。

安装包包含原生模块和采用 ad-hoc 签名的录音 Helper。Helper 未经过 Apple 公证;安装和更新后,macOS 可能要求权限或安全确认。请保持系统安全保护开启。

桌面与 Web 配置共用默认会议库。每个数据目录同时运行一个插件宿主;更换安装包时保留会议与模型数据。

安装包校验、本地归档安装与版本渠道见 分发说明。
源码下载后需要完成 源码构建 才能录音。
安装问题请通过 GitHub Issues 反馈,并附插件、DSH、Node.js 和 macOS 版本;请勿附会议数据或凭据。

模型准备

在插件设置中下载基础模型,约 278 MiB。可选标点模型约 274 MiB,通过校验并安装后自动用于新录音、导入与重新转写。活动任务和已有转写保留原处理模式。已安装的标点包损坏时,须修复后才能启动新任务。

模型来自固定的上游版本,安装前校验文件大小和 SHA-256。
权重不包含在 Git、npm 或 GitHub Release 中。启用插件不会触发下载。
下载可取消和重试;失败后可复用已完整下载并通过校验的文件。
来源、代理行为与离线导入方法见 模型资源。

录音与会议访问

通过插件设置中的“录音权限”检查麦克风与系统音频访问。
每次开始录音都会重新检查。系统音频检查失败可能与权限、输出音量或设备路由有关;录音期间的静音不能证明权限被拒绝。

展开录音助手会准备模型,但不采集音频。连续录音可复用已加载的模型资源,闲置五分钟后释放。每场会议的音频、草稿和说话人状态保持独立。

选择 DSH 会话后录音,或要求 DSH Agent 导入本机音频的绝对路径。
通过 @ 选择会议并请求阅读或导出;文件写入使用 DSH 审批。
会议独立于 DSH 会话和工作区保存。

紧凑录音条显示正在采集时的控制项:

正在录音的紧凑组件

展开后可以查看录音计时、音轨状态和实时转写草稿:

展开录音组件查看实时草稿

导入音频或录音结束后,可引用会议的正式转写,提炼决策与行动项:

引用演示会议后提炼决策与行动项

模型准备后,音频推理在本机运行。使用大模型阅读转写时,内容可能发送给 DSH 配置的服务提供方;该操作受宿主配置和提供方条款约束。

限制

- 说话人标签用于区分同一会议中的声音,不构成个人身份识别。
识别与说话人区分效果取决于输入条件;本项目未报告通用准确率基准。
- 三个固定模型权重目前只有一个已验证的提供方。上游故障可能阻止安装;不能用同名但不同字节的模型替代。
- 发送后的消息历史可能显示会议引用的内部链接,选择器与输入框仍显示会议标题。

开发与许可

源码构建和验证见 开发参考,贡献要求见 CONTRIBUTING.md,安装包准备见发布参考。

项目自有源码使用 Apache-2.0。第三方源码与模型保留各自条款;许可和署名见 THIRD_PARTY_NOTICES.md、 third_party/ 与原生模块的 vendored 目录。

支持与联系

- 使用问题、Bug 和功能建议: GitHub Issues。
需要提供的诊断信息见 支持说明。
- 合作与私下联系: dasenrising@gmail.com。
- 安全漏洞:请按 安全报告说明 私下反馈。
预览分享卡片长什么样 ↓huliux/dsh-asr-plugin
分享 · DeepSeek Harness Hub
huliux/dsh-asr-plugin

面向 Apple Silicon macOS 的 DeepSeek HarnessDSH非官方本地会议转写插件。

回到顶部