Files
DPM/backend/vendor/s2s-cloud/demo/ws/codec.js
T
Pine 7f25c8f6bb refactor(backend): 启动环境初始化与资源项目化(零跨项目依赖)
- main.py:uv run main.py 一键启动——读取 backend/.env、TORCH_HOME/NLTK_DATA 指向项目内缓存、certifi SSL + NO_PROXY 网络直连、默认开启 s2s,启动横幅
- vendor/:补丁后 s2s 云化栈移入项目(backend/vendor/s2s-cloud),pyproject sources 改相对路径
- .gitignore:忽略 .torch-cache / nltk_data 缓存
- AGENTS.md:进程管理铁律(AI 不启动/重启服务,由用户操作)
2026-08-18 01:37:57 +08:00

58 lines
1.8 KiB
JavaScript

// @ts-check
/**
* Pure, stateless helpers for the WebSocket realtime client: base64 <-> PCM
* conversion for the audio frames on the wire, transcript extraction from a
* `response.done` payload, and a tiny URL helper. Kept separate from the client
* so the protocol/state logic stays readable.
*/
/** @param {string} url */
export function trimTrailingSlash(url) {
return url.endsWith("/") ? url.slice(0, -1) : url;
}
/**
* Pull the assistant transcript out of a `response.done` payload. The text
* lives in `response.output[].content[].transcript` (audio) or `.text`. Used as
* the source of truth for interrupted replies, where the dedicated
* `*.transcript.done` event may never arrive.
* @param {any} response
* @returns {string}
*/
export function extractResponseTranscript(response) {
const output = response?.output;
if (!Array.isArray(output)) return "";
/** @type {string[]} */
const parts = [];
for (const item of output) {
for (const part of item?.content ?? []) {
const text = part?.transcript ?? part?.text;
if (typeof text === "string" && text.trim()) parts.push(text.trim());
}
}
return parts.join(" ").trim();
}
/** @param {ArrayBuffer} buf */
export function base64FromArrayBuffer(buf) {
const bytes = new Uint8Array(buf);
// Chunked encoding so we don't blow up the call stack on long buffers.
let binary = "";
const chunk = 0x8000;
for (let i = 0; i < bytes.length; i += chunk) {
binary += String.fromCharCode.apply(null, /** @type {number[]} */ (
/** @type {unknown} */ (bytes.subarray(i, i + chunk))
));
}
return btoa(binary);
}
/** @param {string} b64 */
export function base64ToBytes(b64) {
const binary = atob(b64);
const len = binary.length;
const out = new Uint8Array(len);
for (let i = 0; i < len; i++) out[i] = binary.charCodeAt(i);
return out;
}