Files
Fam Zheng 9328c01c1b
deploy write / build-and-deploy (push) Failing after 4s
write: 进 cube 仓库 + 接 gitea CI 自动部署
- 整 apps/write/ 进 git(含 frontend 源码 + Makefile + systemd unit + k8s service/ingress)
- .gitea/workflows/deploy-write.yml: act_runner fam 用户跑 host shell
    cargo build → npm build → install 到 ~/.local/bin/share/config →
    systemctl --user daemon-reload + restart → kubectl apply svc/ingress
- 前端 3 处"麻薯"字样去掉(思考中 / placeholder × 2)

注意 ~/.config/write/env 已有 passphrase,CI placeholder 逻辑会跳过不覆盖。
2026-05-24 17:16:44 +01:00

46 lines
1.4 KiB
JavaScript

// AudioWorkletProcessor: downsample mic input to 16 kHz mono **Int16 LE** PCM.
// Qwen3-ASR streaming server (mochi-asr on i7:9000) expects Int16 LE.
//
// Browsers run AudioContext at 44.1k or 48k. We linear-resample to 16k.
const TARGET_RATE = 16000;
const CHUNK_SAMPLES = 1600; // 100 ms at 16 kHz
class AsrWorklet extends AudioWorkletProcessor {
constructor() {
super();
this._ratio = sampleRate / TARGET_RATE;
this._tail = [];
}
process(inputs) {
const input = inputs[0];
if (!input || input.length === 0 || !input[0]) return true;
const channel = input[0];
const outLen = Math.floor(channel.length / this._ratio);
for (let i = 0; i < outLen; i++) {
const srcIdx = i * this._ratio;
const i0 = srcIdx | 0;
const i1 = i0 + 1 < channel.length ? i0 + 1 : channel.length - 1;
const t = srcIdx - i0;
this._tail.push(channel[i0] * (1 - t) + channel[i1] * t);
}
while (this._tail.length >= CHUNK_SAMPLES) {
const samples = this._tail.splice(0, CHUNK_SAMPLES);
const i16 = new Int16Array(CHUNK_SAMPLES);
for (let i = 0; i < CHUNK_SAMPLES; i++) {
let s = samples[i];
if (s < -1) s = -1;
else if (s > 1) s = 1;
i16[i] = s < 0 ? Math.round(s * 32768) : Math.round(s * 32767);
}
this.port.postMessage(i16.buffer, [i16.buffer]);
}
return true;
}
}
registerProcessor('asr-worklet', AsrWorklet);