Files
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

160 lines
6.0 KiB
TypeScript

#!/usr/bin/env bun
/**
* Mixed local + cloud voice round-trip — REAL services, measured (#8785).
*
* Answers "can we mix local STT with the really fast cloud LLM?" with real
* numbers. One utterance flows through:
*
* cloud TTS (ElevenLabs, to make the question audio)
* → LOCAL STT (eliza-1-asr via the fused libelizainference + Metal)
* → cloud LLM (Cerebras — the fast inference)
* → cloud TTS (ElevenLabs — spoken reply)
*
* and prints the per-stage latency + the hybrid time-to-first-audio. This is the
* production "local STT + fast cloud LLM + cloud TTS" topology.
*
* Inputs (env): ELIZA_INFERENCE_LIBRARY (fused dylib), ELIZA_ASR_BUNDLE
* (asr/eliza-1-asr.gguf), ELEVENLABS_API_KEY, CEREBRAS_API_KEY. Exits 2 (skip)
* when an artifact/key is missing; 1 on failure; 0 on a clean round-trip.
*/
import { existsSync, readFileSync } from "node:fs";
import { decodeMonoPcm16Wav } from "../src/services/voice/engine-bridge";
import { loadElizaInferenceFfi } from "../src/services/voice/ffi-bindings";
const EL_VOICE = "21m00Tcm4TlvDq8ikWAM"; // a standard ElevenLabs voice
const QUESTION = "What time is it right now in San Francisco";
function skip(m: string): never {
console.log(`[mixed-roundtrip] SKIP: ${m}`);
process.exit(2);
}
function fail(m: string): never {
console.error(`[mixed-roundtrip] FAIL: ${m}`);
process.exit(1);
}
const lib = process.env.ELIZA_INFERENCE_LIBRARY?.trim();
const bundle = process.env.ELIZA_ASR_BUNDLE?.trim();
const elKey = process.env.ELEVENLABS_API_KEY?.trim();
const cbKey = process.env.CEREBRAS_API_KEY?.trim();
if (!lib || !existsSync(lib)) skip("set ELIZA_INFERENCE_LIBRARY to the fused dylib");
if (!bundle || !existsSync(`${bundle}/asr`)) skip("set ELIZA_ASR_BUNDLE");
if (!elKey) skip("set ELEVENLABS_API_KEY");
if (!cbKey) skip("set CEREBRAS_API_KEY");
/** Wrap raw mono PCM16LE @ sampleRate in a 44-byte WAV header. */
function wavFromPcm16(pcm: Uint8Array, sampleRate: number): Uint8Array {
const header = new ArrayBuffer(44);
const v = new DataView(header);
const w = (off: number, s: string) => {
for (let i = 0; i < s.length; i++) v.setUint8(off + i, s.charCodeAt(i));
};
const byteRate = sampleRate * 2;
w(0, "RIFF");
v.setUint32(4, 36 + pcm.length, true);
w(8, "WAVE");
w(12, "fmt ");
v.setUint32(16, 16, true);
v.setUint16(20, 1, true);
v.setUint16(22, 1, true);
v.setUint32(24, sampleRate, true);
v.setUint32(28, byteRate, true);
v.setUint16(32, 2, true);
v.setUint16(34, 16, true);
w(36, "data");
v.setUint32(40, pcm.length, true);
const out = new Uint8Array(44 + pcm.length);
out.set(new Uint8Array(header), 0);
out.set(pcm, 44);
return out;
}
async function elevenTts(text: string, fmt: string): Promise<Uint8Array> {
const r = await fetch(
`https://api.elevenlabs.io/v1/text-to-speech/${EL_VOICE}?output_format=${fmt}`,
{
method: "POST",
headers: { "xi-api-key": elKey!, "content-type": "application/json" },
body: JSON.stringify({ text, model_id: "eleven_turbo_v2_5" }),
},
);
if (!r.ok) fail(`ElevenLabs TTS ${r.status}: ${(await r.text()).slice(0, 200)}`);
return new Uint8Array(await r.arrayBuffer());
}
async function cerebras(userText: string): Promise<string> {
const r = await fetch("https://api.cerebras.ai/v1/chat/completions", {
method: "POST",
headers: { authorization: `Bearer ${cbKey}`, "content-type": "application/json" },
body: JSON.stringify({
model: process.env.CEREBRAS_MODEL?.trim() || "gpt-oss-120b",
// gpt-oss is a reasoning model — leave room for reasoning + the reply.
max_tokens: 400,
messages: [
{
role: "system",
content: "You are a concise voice assistant. Reply in one short sentence.",
},
{ role: "user", content: userText },
],
}),
});
if (!r.ok) fail(`Cerebras ${r.status}: ${(await r.text()).slice(0, 200)}`);
const j = (await r.json()) as {
choices?: Array<{ message?: { content?: string } }>;
};
return (j.choices?.[0]?.message?.content ?? "").trim();
}
console.log(`[mixed-roundtrip] question: "${QUESTION}"`);
// 1) cloud TTS → raw 16 kHz PCM (the spoken question)
const t0 = performance.now();
const pcm16 = await elevenTts(QUESTION, "pcm_16000");
const tQ = Math.round(performance.now() - t0);
console.log(`[mixed-roundtrip] (cloud TTS question) ${tQ}ms, ${pcm16.length} bytes pcm`);
// 2) LOCAL STT via the fused engine + Metal
const ffi = loadElizaInferenceFfi(lib);
const ctx = ffi.create(bundle);
ffi.mmapAcquire(ctx, "asr");
let transcript = "";
let asrMs = 0;
try {
const { pcm, sampleRate } = decodeMonoPcm16Wav(wavFromPcm16(pcm16, 16000));
const a0 = performance.now();
const res = ffi.asrTranscribeTimed({ ctx, pcm, sampleRateHz: sampleRate });
asrMs = Math.round(performance.now() - a0);
transcript = (res.text ?? "").trim();
} finally {
ffi.mmapEvict(ctx, "asr");
ffi.destroy(ctx);
ffi.close();
}
console.log(`[mixed-roundtrip] (LOCAL STT, eliza-1-asr) ${asrMs}ms → "${transcript}"`);
if (!transcript) fail("local STT produced an empty transcript");
// 3) cloud LLM (Cerebras — fast)
const l0 = performance.now();
const reply = await cerebras(transcript);
const llmMs = Math.round(performance.now() - l0);
const cbModel = process.env.CEREBRAS_MODEL?.trim() || "gpt-oss-120b";
console.log(`[mixed-roundtrip] (cloud LLM, Cerebras ${cbModel}) ${llmMs}ms → "${reply}"`);
if (!reply) fail("LLM produced an empty reply");
// 4) cloud TTS (spoken reply) — measure to first audio bytes
const r0 = performance.now();
const replyAudio = await elevenTts(reply, "mp3_44100_128");
const ttsMs = Math.round(performance.now() - r0);
console.log(`[mixed-roundtrip] (cloud TTS reply) ${ttsMs}ms, ${replyAudio.length} bytes mp3`);
const hybridTtfa = asrMs + llmMs + ttsMs;
console.log("");
console.log("[mixed-roundtrip] ── latency breakdown (real services) ──");
console.log(` local STT (eliza-1-asr + Metal): ${asrMs} ms`);
console.log(` cloud LLM (Cerebras): ${llmMs} ms`);
console.log(` cloud TTS (ElevenLabs first audio):${ttsMs} ms`);
console.log(` ── hybrid round-trip (STT+LLM+TTS): ${hybridTtfa} ms`);
console.log("[mixed-roundtrip] PASS");