const sqlite3 = require("sqlite3").verbose(); const path = require("path"); const { app } = require("electron"); const { spawn, exec } = require("child_process"); // 进程引用管理 const processes = { LiveTalkingProcess: null, gptsovitsProcess: null, chatProcess: null }; // 获取数据库路径 function getDatabasePath() { if (process.env.NODE_ENV === "development") { const dbPath = path.join(__dirname, "..", "..", "live_chat.db"); return dbPath; } else { const exePath = app.getPath("exe"); // 获取win-unpacked文件夹路径 const winUnpackedDir = path.dirname(exePath); // 获取win-unpacked的上级目录(与win-unpacked同级的目录) const parentDir = path.dirname(winUnpackedDir); // 构建live_chat.db的完整路径 const dbPath = path.join(parentDir, "live_chat.db"); console.log("dbPath", dbPath); return dbPath; } } // 更新配置值 function updateConfig(tableName, key, value) { return new Promise((resolve, reject) => { const db = new sqlite3.Database(getDatabasePath(), err => { if (err) { console.error("数据库连接错误:", err.message); return reject(err); } }); // 先尝试更新,如果影响行数为0则插入新记录 db.run( `UPDATE ${tableName} SET value = ? WHERE key = ?`, [value, key], function (err) { if (err) { db.close(); return reject(err); } // 如果没有匹配的记录则插入 if (this.changes === 0) { db.run( `INSERT INTO ${tableName} (key, value) VALUES (?, ?)`, [key, value], function (err) { db.close(); if (err) return reject(err); resolve({ success: true, action: "insert", changes: this.changes }); } ); } else { db.close(); resolve({ success: true, action: "update", changes: this.changes }); } } ); }); } // 获取配置值 function getConfigValue(tableName, key) { return new Promise((resolve, reject) => { const db = new sqlite3.Database(getDatabasePath(), err => { if (err) { return reject(err); } }); db.get( `SELECT value FROM ${tableName} WHERE key = ?`, [key], (err, row) => { db.close(); if (err) return reject(err); resolve(row ? row.value : null); } ); }); } // 批量插入系统消息 const bulkInsertSystemMessages = messages => { console.log("系统消息:", messages); return new Promise((resolve, reject) => { if (!Array.isArray(messages) || messages.length === 0) { reject(new Error("请提供有效的消息数组")); return; } try { const db = new sqlite3.Database(getDatabasePath(), err => { if (err) { reject(err); return; } // 使用事务进行批量插入,提高性能 db.run("BEGIN TRANSACTION", err => { if (err) { reject(err); db.close(); return; } const stmt = db.prepare( "INSERT INTO system_message (message) VALUES (?)" ); let completed = 0; let errorOccurred = null; messages.forEach(message => { stmt.run(message, function (err) { if (err && !errorOccurred) { errorOccurred = err; } completed++; // 所有消息都处理完毕 if (completed === messages.length) { stmt.finalize(); if (errorOccurred) { db.run("ROLLBACK", () => { reject(errorOccurred); db.close(); }); } else { db.run("COMMIT", err => { if (err) { reject(err); } else { resolve({ success: true, count: messages.length }); } db.close(); }); } } }); }); }); }); } catch (error) { reject(error); } }); }; // 清空系统消息表 const clearSystemMessages = () => { return new Promise((resolve, reject) => { const db = new sqlite3.Database(getDatabasePath(), err => { if (err) { reject(err); return; } // 使用TRUNCATE-like操作清空表,同时重置自增ID db.run("DELETE FROM system_message", err => { if (err) { reject(err); db.close(); return; } // 重置自增计数器(SQLite特定) db.run( "DELETE FROM sqlite_sequence WHERE name = 'system_message'", err => { if (err) { reject(err); } else { resolve({ success: true }); } db.close(); } ); }); }); }); }; function getProcessExePath(fileName, exeName) { let exePath; let exeFolder; // 判断是否为开发环境 if (process.env.NODE_ENV === "development") { // process.cwd() 通常指向项目根目录 const projectRoot = process.cwd(); const parentDir = path.dirname(projectRoot); exePath = path.join(parentDir, fileName, exeName); exeFolder = path.join(parentDir, fileName); } else { // 生产环境: 与win-unpacked同级目录下的LiveTalking文件夹 exePath = app.getPath("exe"); // 获取win-unpacked文件夹路径 const winUnpackedDir = path.dirname(exePath); // 获取win-unpacked的上级目录 const parentDir = path.dirname(winUnpackedDir); exePath = path.join(parentDir, fileName, exeName); exeFolder = path.join(parentDir, fileName); } console.log("exePath", exePath); console.log("exeFolder", exeFolder); // 标准化路径格式 return { exePath, exeFolder }; } /** * 启动LiveTalking.exe */ async function startProcess(fileName, exeName) { return new Promise(async (resolve, reject) => { const processKey = `${fileName}Process`; if (processes[processKey]) { reject(`${fileName} is already running`); return; } // 获取程序路径 const obj = getProcessExePath(fileName, exeName); try { // 启动进程时,通过wmic获取详细信息(仅Windows) const newProcess = spawn("cmd.exe", ["/c", obj.exePath], { // 直接运行bat,不使用start命令 cwd: obj.exeFolder, windowsVerbatimArguments: true, windowsHide: false, detached: false // 不分离,便于跟踪子进程 }); // 记录进程ID(关键:保存实际PID) processes[processKey] = { process: newProcess, pid: newProcess.pid // 保存PID用于后续终止 }; newProcess.on("error", err => { processes[processKey] = null; reject(`启动失败: ${err.message}`); }); console.log(`spawned with PID ${newProcess.pid}`); resolve(`${fileName} 启动成功 (PID: ${newProcess.pid})`); } catch (err) { reject(`启动异常: ${err.message}`); } }); } // 停止所有进程 async function stopAllProcesses() { try { // 清空所有属性,变成空对象 for (const key in processes) { if (processes[key]) { delete processes[key]; } } const projectRoot = process.cwd(); const parentDir = path.dirname(projectRoot); const exPath = path.join(parentDir, "kill-live.bat"); const child = spawn("cmd.exe", ["/c", "start", '""', `"${exPath}"`], { cwd: parentDir, windowsVerbatimArguments: true, windowsHide: false, detached: true }); child.unref(); } catch (err) { console.error(err); } } module.exports = { updateConfig, getConfigValue, bulkInsertSystemMessages, clearSystemMessages, startProcess, stopAllProcesses };