import process from "node:process"; import { mkdir } from "node:fs/promises"; import path from "node:path"; import { spawn } from "node:child_process"; import { loadConfig } from "./config.js"; import { resolveDockerCommand } from "./docker-runtime.js"; import { Logger } from "./logger.js"; import { MeloTtsService } from "./services/melo-tts.js"; async function run(command: string, args: string[], cwd = process.cwd()): Promise { const env = { ...process.env }; if (path.isAbsolute(command)) { const dockerBinDir = path.dirname(command); const currentPath = env.PATH ?? env.Path ?? ""; env.PATH = `${dockerBinDir}${path.delimiter}${currentPath}`; } await new Promise((resolve, reject) => { const child = spawn(command, args, { cwd, stdio: "inherit", windowsHide: true, shell: process.platform === "win32" && !path.isAbsolute(command), env, }); child.on("error", (error) => { if ((error as NodeJS.ErrnoException).code === "ENOENT" && command === "docker") { reject(new Error("Docker를 찾지 못했습니다. Docker Desktop을 설치하고 실행한 뒤 다시 시도하세요.")); return; } reject(error); }); child.on("exit", (code) => { if (code === 0) { resolve(); return; } reject(new Error(`${command} ${args.join(" ")} exited with code ${code ?? "null"}`)); }); }); } export async function setupTts(): Promise { const config = loadConfig(); const logger = new Logger(config.DEBUG ? config.LOG_LEVEL : "error"); const docker = await resolveDockerCommand(config); const dockerContext = path.resolve(process.cwd(), "docker", "melotts"); const cacheDir = path.resolve(process.cwd(), config.TTS_CACHE_DIR); const outputDir = path.resolve(process.cwd(), config.TTS_OUTPUT_DIR); await mkdir(cacheDir, { recursive: true }); await mkdir(outputDir, { recursive: true }); console.log(`MeloTTS Docker 이미지 빌드: ${config.TTS_IMAGE}`); await run(docker, ["build", "-t", config.TTS_IMAGE, dockerContext]); const tts = new MeloTtsService(config, logger); console.log("MeloTTS 모델 워밍업..."); try { await tts.warmup(); } finally { await tts.destroy().catch(() => undefined); } console.log("로컬 TTS 환경 준비 완료"); } if (import.meta.main) { void setupTts().catch((error) => { console.error(error instanceof Error ? error.message : String(error)); process.exit(1); }); }