File size: 12,688 Bytes
2247396
 
 
 
 
0858d1b
2247396
 
 
 
 
 
 
 
 
 
0858d1b
2247396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0858d1b
 
 
2247396
 
 
 
 
 
787c151
 
 
0858d1b
787c151
2247396
 
 
0858d1b
 
 
 
 
 
 
2247396
 
 
 
 
 
 
 
 
 
 
0858d1b
2247396
 
 
 
0858d1b
926bd82
2247396
 
 
 
 
 
 
ecc5ae3
2247396
 
ecc5ae3
 
 
 
 
2247396
 
 
 
 
0858d1b
ecc5ae3
0858d1b
ecc5ae3
0858d1b
 
2247396
0858d1b
2247396
 
 
 
 
ecc5ae3
 
 
0858d1b
 
 
ecc5ae3
2247396
787c151
 
 
0858d1b
 
787c151
 
 
 
 
 
0858d1b
787c151
 
0858d1b
787c151
0858d1b
787c151
 
 
 
 
 
0858d1b
787c151
 
 
 
 
0858d1b
787c151
 
 
 
 
 
 
0858d1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926bd82
0858d1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926bd82
787c151
 
0858d1b
2247396
0858d1b
2247396
0858d1b
 
2247396
 
 
 
 
 
0858d1b
2247396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0858d1b
2247396
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>录匣 Offlisten · 离线会议转写</title>
<style>
  :root {
    --bg: #23272c;
    --panel: #1b1e22;
    --line: #343a41;
    --fg: #e8eaed;
    --dim: #9aa4ae;
    --accent: #f5c542;
  }
  * { box-sizing: border-box; }
  html { background: var(--bg); }
  body {
    margin: 0;
    background: var(--bg);
    color: var(--fg);
    font: 16px/1.7 -apple-system, "Segoe UI", "Helvetica Neue", "PingFang SC", "Microsoft YaHei", sans-serif;
    -webkit-font-smoothing: antialiased;
  }
  main { max-width: 760px; margin: 0 auto; padding: 64px 24px 96px; }
  header { border-bottom: 1px solid var(--line); padding-bottom: 28px; margin-bottom: 36px; }
  h1 { font-size: 30px; line-height: 1.25; margin: 0 0 6px; letter-spacing: -0.01em; }
  .en { color: var(--dim); font-size: 15px; margin: 0; }
  h2 { font-size: 17px; margin: 44px 0 12px; font-weight: 600; }
  p { margin: 0 0 14px; }
  .lead { font-size: 18px; line-height: 1.65; }
  .lead strong { color: var(--accent); font-weight: 600; }
  .note { color: var(--dim); font-size: 14px; }
  a { color: var(--accent); text-decoration: none; border-bottom: 1px solid rgba(245,197,66,.35); }
  a:hover { border-bottom-color: var(--accent); }
  .tablewrap { overflow-x: auto; border: 1px solid var(--line); border-radius: 8px; }
  table { border-collapse: collapse; width: 100%; font-size: 14px; }
  th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
  th { background: var(--panel); font-weight: 600; color: var(--dim); white-space: nowrap; }
  tr:last-child td { border-bottom: 0; }
  td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
  td.out { font-size: 13px; }
  th .thsub { font-weight: 400; font-size: 13px; color: var(--dim); }
  td .rng { font-size: 13px; color: var(--dim); }
  video { width: 100%; border: 1px solid var(--line); border-radius: 8px; background: #000; display: block; }
  .videohint {
    border: 1px dashed var(--line); border-radius: 8px; padding: 28px 20px;
    text-align: center; color: var(--dim); font-size: 14px;
  }
  code { background: var(--panel); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; font-size: 13px; }
  h3 { font-size: 15px; margin: 26px 0 10px; font-weight: 600; color: var(--dim); }
  blockquote {
    margin: 0 0 14px; padding: 10px 14px; border-left: 2px solid var(--accent);
    background: var(--panel); font-size: 14px; line-height: 1.7;
  }
  footer { margin-top: 56px; padding-top: 20px; border-top: 1px solid var(--line); color: var(--dim); font-size: 13px; }
  ul { padding-left: 20px; margin: 0 0 14px; }
  li { margin-bottom: 6px; }
  figure { margin: 0 0 10px; background: #fff; border-radius: 8px; padding: 10px; }
  figure img { display: block; width: 100%; height: auto; }
  figure a { display: block; border-bottom: 0; }
  /* 矩阵图是 1000px 宽的信息图,正文栏只有 712px:宽屏时让它出血,字才看得清 */
  @media (min-width: 960px) {
    figure { margin-left: -90px; margin-right: -90px; }
  }
</style>
</head>
<body>
<main>

<header>
  <h1>录匣 Offlisten</h1>
  <p class="en">100% offline speech-to-text for meetings and lectures.</p>
</header>

<p class="lead">
录匣把你电脑上的声音转成文字,全部在本机完成。
<strong>没有账号,没有云端,拔掉网线它还在写。</strong>
</p>

<p>
下面是同一份模型(SenseVoice int8,2 个 CPU 线程)在五段公开音频上的真实输出,看完再决定要不要装。
这个页面不放可交互 demo:转写要在服务端加载 229 MiB 的模型,而它的主场是你自己的电脑。
</p>

<h2>五个语种,同一份模型</h2>

<div class="tablewrap">
<table>
  <thead>
    <tr><th>音频</th><th>时长</th><th>耗时</th><th>RTF<br><span class="thsub">5 轮中位数</span></th><th>输出</th></tr>
  </thead>
  <tbody>
    <tr><td><a href="https://huggingface.co/ToothpasteLake/offlisten-models/resolve/main/test_wavs/zh.wav">中</a></td><td class="num">5.6 s</td><td class="num">0.56 s</td><td class="num">0.100<br><span class="rng">0.087–0.117</span></td><td class="out">开饭时间早上9点至下午5点。</td></tr>
    <tr><td><a href="https://huggingface.co/ToothpasteLake/offlisten-models/resolve/main/test_wavs/en.wav">英</a></td><td class="num">7.2 s</td><td class="num">0.59 s</td><td class="num">0.083<br><span class="rng">0.077–0.090</span></td><td class="out">The tribal chieftain called for the boy and presented him with 50 pieces of code.</td></tr>
    <tr><td><a href="https://huggingface.co/ToothpasteLake/offlisten-models/resolve/main/test_wavs/ja.wav">日</a></td><td class="num">7.2 s</td><td class="num">0.65 s</td><td class="num">0.090<br><span class="rng">0.080–0.108</span></td><td class="out">うちの中学は弁当制で持っていきない場合は、50円の学校販売のパンを買う。</td></tr>
    <tr><td><a href="https://huggingface.co/ToothpasteLake/offlisten-models/resolve/main/test_wavs/ko.wav">韩</a></td><td class="num">4.6 s</td><td class="num">0.38 s</td><td class="num">0.082<br><span class="rng">0.080–0.087</span></td><td class="out">조금만 생각을 하면서 살면 훨씬 편할 거야.</td></tr>
    <tr><td><a href="https://huggingface.co/ToothpasteLake/offlisten-models/resolve/main/test_wavs/yue.wav">粤</a></td><td class="num">5.1 s</td><td class="num">0.42 s</td><td class="num">0.081<br><span class="rng">0.078–0.099</span></td><td class="out">呢几个字都表达唔到我想讲嘅意思。</td></tr>
  </tbody>
</table>
</div>

<p class="note" style="margin-top:12px">
点语种名可以听那段音频。五段都在
<a href="https://huggingface.co/ToothpasteLake/offlisten-models/tree/main/test_wavs">模型仓库的 test_wavs/</a>,
和模型一样可下载,可自己复跑。耗时是 2 个 CPU 线程跑五轮的中位数,括号里是极值。
<br>
同一段音频连跑五次,RTF 能落在 0.077–0.117 之间,所以这张表只支撑一个结论:速度大概是实时的十倍。
要当 benchmark 用,得固定机器、关掉后台、多跑几轮看分布。
<br>
中文那句在官方示例里是「开放时间」,int8 量化后这里是「开饭时间」。我们没有换成好看的那条。
</p>

<h2>演示</h2>

<video id="demo" controls preload="metadata" src="./demo.mp4" hidden></video>
<p class="videohint" id="demo-hint">演示视频加载中;若浏览器不支持 mp4,可直接<a href="./demo.mp4">下载观看</a>。</p>

<p class="note">
这 42 秒是按真实时钟跑出来的:五段音频先被模型听完,字幕才依次出现,切段方式和产品里一样靠停顿。
界面是产品的本地文本页,以只读回放模式启动,所以控制区写着「只读文本页」;正常桌面运行时那里是开始/暂停。
视频里的数据只走过 <code>127.0.0.1</code>。
</p>

<h2>接上本地的 AI</h2>

<p>
录匣只把声音变成文字。总结、追问、翻译交给谁写由你决定,前提是那个模型也在这台机器上。
下面这段 46 秒没有音轨,因为它要证明的不是听感。
</p>

<video controls preload="metadata" src="./use-with-browser-ai.mp4"></video>

<p class="note" style="margin-top:12px">
左边是录匣的本地文本页,右边是浏览器里的 Page Assist,接着一个跑在 Ollama 上的 <code>qwen2.5:0.5b</code>。
勾选 <b>Chat with current page</b> 之后,插件读的是这个页面本身,走的不是云端接口,也不经过复制粘贴。
</p>

<h3>本地文本页本来就留了这个出口</h3>

<p>页面上那行提示是为这件事写的:</p>

<blockquote>
文本来自本机离线 ASR,只在 127.0.0.1 上传输。本页不调用任何模型,也不持有 apikey。
要交给 AI 处理,就复制全文,或让你浏览器里已有的 AI 插件读取本页。
</blockquote>

<p>视频里三个部件都在同一台机器上,链路没有一处出网:</p>

<div class="tablewrap">
<table>
  <thead><tr><th>部件</th><th>作用</th><th>跑在哪</th></tr></thead>
  <tbody>
    <tr><td>SenseVoice int8</td><td>声音转成带标点的文字</td><td class="out">本机进程,229 MiB 随安装包落盘</td></tr>
    <tr><td>Page Assist</td><td>把当前页内容放进提示词</td><td class="out">浏览器扩展</td></tr>
    <tr><td>Ollama + qwen2.5:0.5b</td><td>读文字,给回答</td><td class="out">本机进程,监听 127.0.0.1:11434</td></tr>
  </tbody>
</table>
</div>

<p class="note" style="margin-top:12px">
两点说明。一是 <code>0.5b</code> 只有五亿参数,回答质量按小模型的标准看,别拿它和云端大模型比。
二是视频里它用英文作答,因为页面上并排摆着中文原文和 Argos 译文,模型看到的是双语文本;
想让回答更稳,可以在插件里限定「只依据中文原文回答」。
</p>

<h2>造轮子之前,先看这 12 格</h2>

<p>
上面演示的是产品选中的那一格。选之前量过 4 个运行时 × 3 个平台,
能同时满足「CPU 能跑、流式、能装进别人的机器」的只有 2 格,其中 1 格有本机实测。
</p>

<figure>
  <a href="./matrix-zh.png" title="点开看原尺寸 1000×780"><img src="./matrix-zh.png" alt="端侧 ASR 运行时可用性矩阵:4 个运行时 × 3 个平台,12 格里只有 2 格通过"></a>
</figure>

<p class="note">
颜色越深越可用。斜纹表示这一格不存在:不是慢,是没有这个选项。
英文版:<a href="./matrix-en.png">matrix-en.png</a>。
</p>

<p>
图上只放结论,依据分四级:5 格来自官方文档或包矩阵,1 格是本机实测(就是上面那张表),
1 格只验过模型、没跑过运行时,5 格是推断。推断的那 5 格标了 L3,只能当「值得试」,不能当结论引用。
</p>

<h3>依据都能点开核</h3>

<ul>
  <li><a href="https://arxiv.org/abs/2407.04051">FunAudioLLM 论文(arXiv:2407.04051)</a>:SenseVoice-Small 的结构、5 语言支持与低延迟声明。</li>
  <li><a href="https://k2-fsa.github.io/sherpa/onnx/">sherpa-onnx 文档</a>:ONNX Runtime 下的 SenseVoice 用法与流式示例,产品走的就是这条。</li>
  <li><a href="https://k2-fsa.github.io/sherpa/ncnn/sense-voice/">sherpa-ncnn 的 SenseVoice 章</a>:ncnn 侧有现成预训练包,也有麦克风实时识别一节。</li>
  <li><a href="https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/backend/docs/backend_platform_support_matrix.html">Triton 后端支持矩阵</a>:TensorRT 在 x86 与 ARM-SBSA 上都是 GPU ✓ / CPU ✗。</li>
  <li><a href="https://pypi.org/project/sherpa-ncnn/#files">PyPI 上 sherpa-ncnn 的 wheel 列表</a>:只有 win32 与 win_amd64,没有 win_arm64。</li>
  <li><a href="https://huggingface.co/FunAudioLLM/SenseVoiceSmall-GGUF">SenseVoiceSmall-GGUF 模型卡</a>:q8 体积,8 线程 8.01% CER(184 条普通话)。</li>
</ul>

<p class="note">
逐格原因、证据分级和「补一格」用的模板在仓库的 <code>docs/bench/README.md</code>。
这 12 格里我们只量过 1 格,剩下 11 格要等有机器的人把数补上。
</p>

<h2>和云端转写比</h2>
<ul>
  <li><b>不上传</b>:音频不出本机。没有隐私政策需要读,因为没有服务器收它。</li>
  <li><b>不用登录</b>:没有账号体系,也就没有订阅和额度。</li>
  <li><b>断网可用</b>:模型随安装包落盘,拔掉网线照常写。</li>
  <li><b>能抓桌面客户端</b>:系统级音频采集,不只限于浏览器标签页。</li>
</ul>

<h2>模型</h2>
<p>
本页数字对应的权重公开在
<a href="https://huggingface.co/ToothpasteLake/offlisten-models">ToothpasteLake/offlisten-models</a>,
6 个文件共 229.07 MiB,逐文件 sha256 登记在发行清单里。换成自己的机器复跑时,先核对哈希,再比数字。
</p>

<!-- 主仓库公开后取消注释:
<p>源码、契约文档与负结果册:<a href="https://github.com/peaceaddpaasion/Offlisten">github.com/peaceaddpaasion/Offlisten</a></p>
-->

<footer>
录匣 Offlisten · 本地运行,不上传,不联网
</footer>

</main>
<script>
(function () {
  var v = document.getElementById('demo');
  var hint = document.getElementById('demo-hint');
  v.addEventListener('loadedmetadata', function () {
    v.hidden = false;
    hint.hidden = true;
  });
  v.addEventListener('error', function () {
    hint.innerHTML = '演示视频加载失败,可直接<a href="./demo.mp4">下载观看</a>。';
  });
})();
</script>
</body>
</html>