89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
import { spawn, execFile } from "node:child_process";
|
|
import { promisify } from "node:util";
|
|
import { readFile } from "node:fs/promises";
|
|
import path from "node:path";
|
|
import {
|
|
audioJobStatusSchema,
|
|
type AudioJobInput,
|
|
} from "../../lib/video-canvas/smart-edit/audio-contract";
|
|
const python = () => process.env.AUDIO_PYTHON || "python3";
|
|
export async function audioHealth() {
|
|
const { stdout } = await promisify(execFile)(
|
|
python(),
|
|
[path.join(__dirname, "run.py"), "--check"],
|
|
{ timeout: 30000, maxBuffer: 65536 }
|
|
);
|
|
const value = JSON.parse(stdout);
|
|
if (value.asr !== true || value.separation !== true)
|
|
throw Error("音频模型未准备就绪");
|
|
return { asr: true, separation: true };
|
|
}
|
|
export async function audioJob(
|
|
plan: AudioJobInput,
|
|
_tenant: string,
|
|
dir: string,
|
|
progress: (stage: string) => Promise<void>
|
|
) {
|
|
await progress(
|
|
plan.operation === "transcribe"
|
|
? "算力服务器正在自动转写"
|
|
: "算力服务器正在分离人声与背景声"
|
|
);
|
|
await new Promise<void>((resolve, reject) => {
|
|
const child = spawn(
|
|
python(),
|
|
[
|
|
path.join(__dirname, "run.py"),
|
|
plan.operation,
|
|
path.join(dir, "input.wav"),
|
|
dir,
|
|
],
|
|
{
|
|
stdio: ["ignore", "ignore", "pipe"],
|
|
detached: true,
|
|
env: { ...process.env, CUDA_VISIBLE_DEVICES: "", OMP_NUM_THREADS: "2" },
|
|
}
|
|
);
|
|
let tail = "",
|
|
timedOut = false;
|
|
const timer = setTimeout(() => {
|
|
timedOut = true;
|
|
try {
|
|
process.kill(-child.pid!, "SIGKILL");
|
|
} catch {}
|
|
}, 600000);
|
|
child.stderr.on("data", (b) => {
|
|
tail = (tail + b.toString()).slice(-2000);
|
|
});
|
|
child.once("error", () => {
|
|
clearTimeout(timer);
|
|
reject(Error("音频处理器无法启动"));
|
|
});
|
|
child.once("close", (code) => {
|
|
clearTimeout(timer);
|
|
if (code === 0) resolve();
|
|
else {
|
|
console.error(
|
|
JSON.stringify({
|
|
event: "audio-inference-failed",
|
|
code,
|
|
timedOut,
|
|
detail: tail.replace(/https?:\S+/g, "[url]"),
|
|
})
|
|
);
|
|
reject(
|
|
Error(
|
|
timedOut
|
|
? "音频处理超时,请缩短素材后重试"
|
|
: "音频模型处理失败,请检查素材或服务日志"
|
|
)
|
|
);
|
|
}
|
|
});
|
|
});
|
|
const result = JSON.parse(
|
|
await readFile(path.join(dir, "result.json"), "utf8")
|
|
);
|
|
return audioJobStatusSchema.shape.result.parse(result)!;
|
|
}
|