Files
memind/asr-proxy.mjs
T
John 2e14873f2d Initial commit: Memind H5 portal with MindSpace, Plaza, and agent jobs.
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 15:04:43 -07:00

67 lines
2.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import express from 'express';
import { fetch } from 'undici';
const ASR_TARGET = process.env.H5_ASR_TARGET ?? 'https://asr.tkmind.cn';
const ASR_MAX_BYTES = Number(process.env.H5_ASR_MAX_BYTES ?? 5 * 1024 * 1024);
const ASR_TIMEOUT_MS = Number(process.env.H5_ASR_TIMEOUT_MS ?? 45_000);
export function attachAsrRoutes(api, deps) {
const multipartRaw = express.raw({
type: (req) => (req.headers['content-type'] ?? '').includes('multipart/form-data'),
limit: ASR_MAX_BYTES,
});
// 登录校验由 api 全局中间件负责(req.currentUser)
api.post('/asr/oneshot', multipartRaw, async (req, res) => {
const contentType = req.headers['content-type'] ?? '';
if (!contentType.includes('multipart/form-data')) {
return deps.sendError(res, req, 400, 'invalid_request', 'Content-Type 必须为 multipart/form-data');
}
if (!req.body?.length) {
return deps.sendError(res, req, 400, 'invalid_request', '音频内容为空');
}
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ASR_TIMEOUT_MS);
try {
const upstream = await fetch(`${ASR_TARGET}/asr/oneshot`, {
method: 'POST',
headers: { 'content-type': contentType },
body: req.body,
signal: controller.signal,
});
const text = await upstream.text();
let payload = null;
try {
payload = JSON.parse(text);
} catch {
payload = null;
}
if (!upstream.ok) {
return deps.sendError(
res,
req,
upstream.status,
'asr_failed',
payload?.message ?? text ?? 'ASR 请求失败',
);
}
if (payload?.code !== 200) {
return deps.sendError(res, req, 502, 'asr_failed', payload?.message ?? '识别失败');
}
return deps.sendData(res, req, { text: payload?.data?.text ?? '' });
} catch (err) {
const message =
err instanceof Error && err.name === 'AbortError'
? '识别超时,请重试'
: err instanceof Error
? err.message
: 'ASR 请求失败';
return deps.sendError(res, req, 502, 'asr_failed', message);
} finally {
clearTimeout(timer);
}
});
}