/** * AI 어시스턴트 서비스를 자식 프로세스로 기동 * - backend-node 서버 기동 시 함께 띄우고, 종료 시 함께 종료 (한 번에 킬) */ import path from "path"; import { spawn, ChildProcess } from "child_process"; import { logger } from "./logger"; const AI_PORT = process.env.AI_ASSISTANT_SERVICE_PORT || "3100"; let aiAssistantProcess: ChildProcess | null = null; /** ERP-node/ai-assistant 경로 (backend-node 기준 상대) */ function getAiAssistantDir(): string { return path.resolve(process.cwd(), "..", "ai-assistant"); } /** * AI 어시스턴트 서비스 기동 (있으면 띄움, 실패해도 backend는 계속 동작) */ export function startAiAssistant(): void { const aiDir = getAiAssistantDir(); const appPath = path.join(aiDir, "src", "app.js"); try { const fs = require("fs"); if (!fs.existsSync(appPath)) { logger.info(`⏭️ AI 어시스턴트 스킵 (경로 없음: ${appPath})`); return; } } catch { return; } aiAssistantProcess = spawn("node", ["src/app.js"], { cwd: aiDir, stdio: "inherit", env: { ...process.env, PORT: AI_PORT }, shell: true, // Windows에서 node 경로 인식 }); aiAssistantProcess.on("error", (err) => { logger.warn(`⚠️ AI 어시스턴트 프로세스 에러: ${err.message}`); }); aiAssistantProcess.on("exit", (code, signal) => { aiAssistantProcess = null; if (code != null && code !== 0) { logger.warn(`⚠️ AI 어시스턴트 종료 (code=${code}, signal=${signal})`); } }); logger.info(`🤖 AI 어시스턴트 서비스 기동 (포트 ${AI_PORT}, cwd: ${aiDir})`); } /** * AI 어시스턴트 프로세스 종료 (SIGTERM/SIGINT 시 호출) */ export function stopAiAssistant(): void { if (aiAssistantProcess && aiAssistantProcess.kill) { aiAssistantProcess.kill("SIGTERM"); aiAssistantProcess = null; logger.info("🤖 AI 어시스턴트 프로세스 종료"); } }