Replace ElevenLabs with local STT and TTS

This commit is contained in:
2026-04-30 03:21:30 +09:00
parent 5d636e8619
commit 73546c15b9
24 changed files with 943 additions and 326 deletions

88
src/setup-local-ai.ts Normal file
View File

@@ -0,0 +1,88 @@
import { existsSync } from "node:fs";
import { mkdir } from "node:fs/promises";
import { spawn } from "node:child_process";
import path from "node:path";
import { loadConfig } from "./config.js";
import { resolveLocalAiCachePath, resolveLocalAiVenvPath, resolvePythonLaunch, resolveVenvPythonPath } from "./python-runtime.js";
async function run(command: string, args: string[], extraEnv?: NodeJS.ProcessEnv): Promise<void> {
await new Promise<void>((resolve, reject) => {
const child = spawn(command, args, {
stdio: "inherit",
env: {
...process.env,
...extraEnv,
},
});
child.on("exit", (code) => {
if (code === 0) {
resolve();
return;
}
reject(new Error(`${command} ${args.join(" ")} exited with code ${code ?? "null"}`));
});
child.on("error", reject);
});
}
async function ensurePip(pythonBin: string, env: NodeJS.ProcessEnv): Promise<void> {
await new Promise<void>((resolve, reject) => {
const child = spawn(pythonBin, ["-m", "pip", "--version"], {
stdio: "ignore",
env,
});
child.on("exit", (code) => {
if (code === 0) {
resolve();
return;
}
reject(new Error("pip missing"));
});
child.on("error", reject);
}).catch(async () => {
await run(pythonBin, ["-m", "ensurepip", "--upgrade"], env);
});
}
async function main(): Promise<void> {
const config = loadConfig();
const venvPath = resolveLocalAiVenvPath(config);
const venvPython = resolveVenvPythonPath(config);
const cachePath = resolveLocalAiCachePath(config);
const requirementsPath = path.resolve(process.cwd(), "python", "requirements.txt");
const baseEnv = {
HF_HOME: cachePath,
TRANSFORMERS_CACHE: cachePath,
PYTHONIOENCODING: "utf-8",
};
await mkdir(cachePath, { recursive: true });
if (!existsSync(venvPython)) {
const launch = resolvePythonLaunch(config, { preferVenv: false });
console.log(`기본 Python 확인: ${launch.command} ${launch.args.join(" ")}`.trim());
console.log(`가상환경 생성: ${venvPath}`);
await run(launch.command, [...launch.args, "-m", "venv", venvPath], baseEnv);
}
await ensurePip(venvPython, {
...process.env,
...baseEnv,
});
console.log("로컬 AI 의존성 설치를 시작합니다.");
await run(venvPython, ["-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"], baseEnv);
await run(venvPython, ["-m", "pip", "install", "-r", requirementsPath], baseEnv);
console.log("설치가 끝났습니다.");
console.log("다음 순서:");
console.log("1. bun run devices");
console.log("2. bun run start:local");
}
void main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
});