634 lines
21 KiB
JavaScript
634 lines
21 KiB
JavaScript
const path = require('path');
|
|
const express = require('express');
|
|
const args = process.argv.slice(2);
|
|
const fs = require('fs');
|
|
const fsp = require('fs/promises')
|
|
const qrcode = require('qrcode');
|
|
const { Client, LocalAuth, MessageMedia } = require('whatsapp-web.js');
|
|
|
|
let CONFIG = {
|
|
PORT: 4000,
|
|
BROWSER_DIRECTORY: path.join(__dirname, 'user'),
|
|
MODELS_DIRECTORY: path.join(__dirname, 'models'),
|
|
TEMP_DIRECTORY: path.join(__dirname, 'temp'),
|
|
OUTPUT_DIRECTORY: path.join(__dirname, 'output'),
|
|
WEB_DIRECTORY: path.join(__dirname, 'website'),
|
|
API_URL: 'http://127.0.0.1:8188',
|
|
CHROME: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
MODE: null,
|
|
ADMIN: null,
|
|
EXPRESS: express(),
|
|
WA: null,
|
|
QRCODE: null,
|
|
READY: false,
|
|
KSAMPLER_SEED_CHANGE: 1,
|
|
MODELS: {},
|
|
PROMPT: {
|
|
MODEL: {},
|
|
NODES: {}
|
|
},
|
|
WATCHER: {}
|
|
}
|
|
|
|
const deleteContentsInsideDirectory = async (dirPath) => {
|
|
try {
|
|
const files = await fsp.readdir(dirPath);
|
|
await Promise.all(files.map(async (file) => {
|
|
const filePath = path.join(dirPath, file);
|
|
const stats = await fsp.stat(filePath);
|
|
if (stats.isDirectory()) {
|
|
await deleteContentsInsideDirectory(filePath);
|
|
await fsp.rmdir(filePath);
|
|
} else {
|
|
await fsp.unlink(filePath);
|
|
}
|
|
}));
|
|
|
|
console.log(`Successfully deleted contents inside ${dirPath}`);
|
|
} catch (error) {
|
|
console.error(`Error deleting contents inside ${dirPath}:`, error);
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
function readJsonFile(filePath) {
|
|
try {
|
|
const data = fs.readFileSync(filePath, 'utf8');
|
|
const jsonData = JSON.parse(data);
|
|
return jsonData;
|
|
} catch (err) {
|
|
console.error(`Error reading or parsing file: ${err}`);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function addDirectories() {
|
|
|
|
CONFIG.BROWSER_DIRECTORY = path.join(CONFIG.MAIN_DIRECTORY, 'user')
|
|
CONFIG.MODELS_DIRECTORY = path.join(CONFIG.MAIN_DIRECTORY, 'workflows')
|
|
CONFIG.TEMP_DIRECTORY = path.join(CONFIG.MAIN_DIRECTORY, 'temp')
|
|
CONFIG.OUTPUT_DIRECTORY = path.join(CONFIG.MAIN_DIRECTORY, 'output')
|
|
|
|
WA_CONFIG = readJsonFile(path.join(CONFIG.MAIN_DIRECTORY, 'whatsapp.json'))
|
|
|
|
CONFIG.MODE = parseInt(WA_CONFIG.mode);
|
|
CONFIG.ADMIN = `${WA_CONFIG.phone_code}${WA_CONFIG.phone}@c.us`
|
|
|
|
CONFIG.CHROME = WA_CONFIG.chrome
|
|
CONFIG.API_URL = WA_CONFIG.comfy_url;
|
|
|
|
}
|
|
|
|
args.forEach(arg => {
|
|
const [key, value] = arg.split('=');
|
|
if (key === '--mode') {
|
|
CONFIG.MODE = parseInt(value);
|
|
} else if (key === '--admin') {
|
|
CONFIG.ADMIN = `${value}@c.us`;
|
|
} else if (key === '--api') {
|
|
CONFIG.API_URL = value
|
|
} else if (key === '--pd') {
|
|
CONFIG.MAIN_DIRECTORY = value
|
|
addDirectories()
|
|
}
|
|
});
|
|
|
|
function createDirectories(config) {
|
|
for (let key in config) {
|
|
if (key.endsWith('_DIRECTORY')) {
|
|
const dir = config[key];
|
|
if (!fs.existsSync(dir)) {
|
|
fs.mkdirSync(dir, { recursive: true });
|
|
console.log(`Directory created: ${dir}`);
|
|
} else {
|
|
console.log(`Directory already exists: ${dir}`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function botMediaMessage(to, message, media) {
|
|
CONFIG.WA.sendMessage(to, "🤖\n\n" + message, { media })
|
|
}
|
|
|
|
function botTextMessage(to, message) {
|
|
CONFIG.WA.sendMessage(to, "🤖\n\n" + message)
|
|
}
|
|
|
|
function botTextMessagReply(message_object, message) {
|
|
message_object.reply("🤖\n\n" + message)
|
|
}
|
|
|
|
function isAdmin(user) {
|
|
return CONFIG.ADMIN == user
|
|
}
|
|
|
|
function allCommands() {
|
|
let rules = ''
|
|
rules += 'Write */wfs* to get a numbered list of uploaded workflows.\n\n'
|
|
rules += 'Write */wf id* to select the workflow.\n\n'
|
|
rules += 'Write */wns* to get numbered list of selected workflow nodes.\n\n'
|
|
rules += 'Write */wn id* to get numbered list of inputs available.\n\n'
|
|
rules += 'Write */s node_id input_id value* to set value for input selected.\n\n'
|
|
rules += 'Write */sce* enable auto ksampler seed change.\n\n'
|
|
rules += 'Write */scd* disable auto ksampler seed change.\n\n'
|
|
rules += 'Write */r* to reset all to default settings.\n\n'
|
|
rules += 'Write */q* to queue.\n\n'
|
|
rules += 'Write */i* to interrupt queue.\n\n'
|
|
rules += 'Write */m number* to set bot usage mode. *1*: Single User, *2*: Multi User.\n\n'
|
|
return rules
|
|
}
|
|
|
|
function readModels(folderPath) {
|
|
return fs.readdirSync(folderPath);
|
|
}
|
|
|
|
function formatModelObject(models) {
|
|
return Object.entries(models).map(([key, value]) => `*${key}* | ${value}`).join("\n");
|
|
}
|
|
|
|
function containsIndex(arr, index) {
|
|
return index >= 0 && index < arr.length && arr[index] !== undefined;
|
|
}
|
|
|
|
function containsValue(arr, value) {
|
|
return arr.includes(value);
|
|
}
|
|
|
|
function containsValueAtIndex(arr, index, value) {
|
|
return index >= 0 && index < arr.length && arr[index] === value;
|
|
}
|
|
|
|
function readJSONFile(file) {
|
|
try {
|
|
let file_path = path.join(CONFIG.MODELS_DIRECTORY, file)
|
|
const data = fs.readFileSync(file_path, 'utf8');
|
|
const jsonData = JSON.parse(data);
|
|
return jsonData;
|
|
} catch (err) {
|
|
console.error("Error reading file:", err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function extractTitleFromModel(data) {
|
|
const titles = {};
|
|
if (data) {
|
|
for (const key in data) {
|
|
if (data.hasOwnProperty(key)) {
|
|
titles[key] = data[key]._meta.title;
|
|
}
|
|
}
|
|
}
|
|
return titles;
|
|
}
|
|
|
|
function formatOutput(titles) {
|
|
let output = '*ID* | Node Name\n';
|
|
for (const key in titles) {
|
|
if (titles.hasOwnProperty(key)) {
|
|
output += `*${key}* | ${titles[key]}\n`;
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function formatInputsIgnoreArray(number, data) {
|
|
const inputs = data[number].inputs;
|
|
let formattedInputs = `ID | Input Name | Input Value\n`;
|
|
let counter = 0
|
|
for (const inputName in inputs) {
|
|
if (inputs.hasOwnProperty(inputName) && !Array.isArray(inputs[inputName])) {
|
|
formattedInputs += `*${counter++}* | *${inputName}* | *${inputs[inputName]}*\n`;
|
|
}
|
|
}
|
|
return formattedInputs.trim();
|
|
}
|
|
|
|
function containsSettings(number, setting_number, data) {
|
|
if (data[number] && data[number].inputs) {
|
|
const inputs = data[number].inputs;
|
|
let counter = 0
|
|
for (const inputName in inputs) {
|
|
if (inputs.hasOwnProperty(inputName) && !Array.isArray(inputs[inputName])) {
|
|
if (counter == setting_number) {
|
|
break;
|
|
}
|
|
counter++
|
|
}
|
|
}
|
|
return (counter == setting_number)
|
|
}
|
|
}
|
|
|
|
function getSettingName(number, setting_number, data) {
|
|
if (data[number] && data[number].inputs) {
|
|
const inputs = data[number].inputs;
|
|
let counter = 0
|
|
let name = ""
|
|
for (const inputName in inputs) {
|
|
if (inputs.hasOwnProperty(inputName) && !Array.isArray(inputs[inputName])) {
|
|
if (counter == setting_number) {
|
|
name = inputName
|
|
break;
|
|
}
|
|
counter++
|
|
}
|
|
}
|
|
return name
|
|
}
|
|
}
|
|
|
|
function editInputs(jsonObj, title, inputName, value) {
|
|
for (let key in jsonObj) {
|
|
if (jsonObj[key]._meta && jsonObj[key]._meta.title === title) {
|
|
if (jsonObj[key].inputs) {
|
|
jsonObj[key].inputs[inputName] = value;
|
|
} else {
|
|
jsonObj[key].inputs = { [inputName]: value };
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function getNodeID(jsonObj, title) {
|
|
let id = -1
|
|
for (let key in jsonObj) {
|
|
if (jsonObj[key]._meta && jsonObj[key]._meta.title === title) {
|
|
id = key
|
|
break
|
|
}
|
|
}
|
|
return id
|
|
}
|
|
|
|
function editJSON(number, inputName, inputValue, data) {
|
|
if (data[number] && data[number].inputs) {
|
|
const existingValue = data[number].inputs[inputName];
|
|
if (existingValue !== undefined) {
|
|
const existingValueType = typeof existingValue;
|
|
let convertedValue;
|
|
if (existingValueType === 'number' && Number.isInteger(existingValue)) {
|
|
convertedValue = parseInt(inputValue);
|
|
} else if (existingValueType === 'number' && !Number.isInteger(existingValue)) {
|
|
convertedValue = parseFloat(inputValue);
|
|
} else if (existingValueType === 'boolean') {
|
|
convertedValue = (inputValue.toLowerCase() === 'true');
|
|
} else {
|
|
convertedValue = inputValue
|
|
}
|
|
data[number].inputs[inputName] = convertedValue;
|
|
return data;
|
|
} else {
|
|
console.log("Invalid input name.");
|
|
return null;
|
|
}
|
|
} else {
|
|
console.log("Invalid number.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function extractPhoneNumber(inputString) {
|
|
const parts = inputString.split('@');
|
|
const firstPart = parts[0];
|
|
const phoneNumber = firstPart.slice(-10);
|
|
return phoneNumber;
|
|
}
|
|
|
|
async function sendResultToUser(user, images) {
|
|
|
|
if (images.length > 0) {
|
|
|
|
images.forEach(async (image) => {
|
|
let file_path = path.join(image.subfolder, image.filename)
|
|
const media = await MessageMedia.fromFilePath(file_path);
|
|
botMediaMessage(user, "Here is your image", media)
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
async function watch(user, data) {
|
|
try {
|
|
if (!CONFIG.WATCHER[user]) {
|
|
CONFIG.WATCHER[user] = {
|
|
count: 0,
|
|
}
|
|
}
|
|
let id = data.prompt_id
|
|
let res = await fetch(`${CONFIG.API_URL}/history/${id}`).then(response => response.json())
|
|
if (res && res[id]) {
|
|
let status = res[id].status
|
|
if (status.completed && status.status_str === "success") {
|
|
let nodeid = getNodeID(CONFIG.PROMPT.NODES[user], "WA_ImageSaver")
|
|
if (nodeid != -1) {
|
|
let images = res[id].outputs[nodeid].images || []
|
|
sendResultToUser(user, images)
|
|
}
|
|
}
|
|
else {
|
|
botTextMessage(user, "Workflow failed/interrupted to generate result. Please try again!")
|
|
}
|
|
}
|
|
else {
|
|
setTimeout(watch, 1000, user, data)
|
|
}
|
|
} catch (error) {
|
|
console.log(error)
|
|
botTextMessage(user, "Workflow failed/interrupted to generate result. Please try again!")
|
|
}
|
|
}
|
|
|
|
function setCommand(message) {
|
|
|
|
let sliced = message.body.split(" ")
|
|
let command = sliced[0]
|
|
|
|
switch (command) {
|
|
case '/c':
|
|
botTextMessagReply(message, allCommands())
|
|
break;
|
|
case '/wfs':
|
|
CONFIG.MODELS[message.from] = readModels(CONFIG.MODELS_DIRECTORY)
|
|
let models = formatModelObject(CONFIG.MODELS[message.from])
|
|
botTextMessagReply(message, "Here are your workflows:\n\n" + "*ID* | Model Name\n\n" + models + "\n\nTo select workfloe write /wf id")
|
|
break;
|
|
case '/wf':
|
|
if (!CONFIG.MODELS[message.from]) {
|
|
CONFIG.MODELS[message.from] = readModels(CONFIG.MODELS_DIRECTORY)
|
|
}
|
|
let index = parseInt(sliced[1])
|
|
if (!containsIndex(CONFIG.MODELS[message.from], index)) {
|
|
botTextMessagReply(message, "Workflows does not exists!")
|
|
}
|
|
else {
|
|
CONFIG.PROMPT.MODEL[message.from] = CONFIG.MODELS[message.from][index]
|
|
if (!CONFIG.PROMPT.NODES[message.from]) {
|
|
CONFIG.PROMPT.NODES[message.from] = readJSONFile(CONFIG.PROMPT.MODEL[message.from])
|
|
}
|
|
botTextMessagReply(message, `Workflow *${CONFIG.PROMPT.MODEL[message.from]}* selected!`)
|
|
}
|
|
break;
|
|
case '/wns':
|
|
if (!CONFIG.MODELS[message.from]) {
|
|
botTextMessagReply(message, "Workflow not selected!")
|
|
}
|
|
else {
|
|
CONFIG.PROMPT.NODES[message.from] = readJSONFile(CONFIG.PROMPT.MODEL[message.from])
|
|
let nodes = formatOutput(extractTitleFromModel(CONFIG.PROMPT.NODES[message.from]))
|
|
botTextMessagReply(message, "Here are your workflow nodes:\n\n" + nodes + "\n\nTo get the datail of a particular node write /wn id")
|
|
}
|
|
break;
|
|
case '/wn':
|
|
if (!CONFIG.MODELS[message.from]) {
|
|
botTextMessagReply(message, "Workflow not selected!")
|
|
}
|
|
else {
|
|
if (!CONFIG.PROMPT.NODES[message.from]) {
|
|
CONFIG.PROMPT.NODES[message.from] = readJSONFile(CONFIG.PROMPT.MODEL[message.from])
|
|
}
|
|
let index = sliced[1]
|
|
|
|
if (!containsValue(Object.keys(CONFIG.PROMPT.NODES[message.from]), index)) {
|
|
botTextMessagReply(message, "Node does not exists!")
|
|
}
|
|
else {
|
|
let nodes = formatInputsIgnoreArray(index, CONFIG.PROMPT.NODES[message.from])
|
|
botTextMessagReply(message, "Here are your node inputs:\n\n" + nodes + "\n\nTo edit a particular input write /s wns_id wn_id value")
|
|
}
|
|
}
|
|
break;
|
|
case '/sce':
|
|
CONFIG.KSAMPLER_SEED_CHANGE = 1
|
|
botTextMessagReply(message, `KSampler Seed Change: *Enabled*`)
|
|
break;
|
|
case '/scd':
|
|
CONFIG.KSAMPLER_SEED_CHANGE = 0
|
|
botTextMessagReply(message, `KSampler Seed Change: *Disabled*`)
|
|
break;
|
|
case '/s':
|
|
if (!CONFIG.MODELS[message.from]) {
|
|
botTextMessagReply(message, "Workflow not selected!")
|
|
}
|
|
else {
|
|
if (!CONFIG.PROMPT.NODES[message.from]) {
|
|
CONFIG.PROMPT.NODES[message.from] = readJSONFile(CONFIG.PROMPT.MODEL[message.from])
|
|
}
|
|
|
|
let node_number = sliced[1]
|
|
let setting_number = sliced[2]
|
|
let value = sliced[3]
|
|
|
|
if (sliced.length > 4) {
|
|
for (let index = 4; index < sliced.length; index++) {
|
|
const element = sliced[index];
|
|
value += " " + element
|
|
}
|
|
}
|
|
|
|
if (!containsValue(Object.keys(CONFIG.PROMPT.NODES[message.from]), node_number)) {
|
|
botTextMessagReply(message, "Node does not exists.")
|
|
}
|
|
else if (!containsSettings(node_number, setting_number, CONFIG.PROMPT.NODES[message.from])) {
|
|
botTextMessagReply(message, "Node setting does not exists.")
|
|
}
|
|
else {
|
|
let setting_name = getSettingName(node_number, setting_number, CONFIG.PROMPT.NODES[message.from])
|
|
editJSON(node_number, setting_name, value, CONFIG.PROMPT.NODES[message.from])
|
|
let nodes = formatInputsIgnoreArray(node_number, CONFIG.PROMPT.NODES[message.from])
|
|
botTextMessagReply(message, "Node setting changed.\n\n" + nodes)
|
|
}
|
|
}
|
|
break;
|
|
case '/r':
|
|
CONFIG.MODELS[message.from] = null
|
|
CONFIG.PROMPT.MODEL[message.from] = null
|
|
CONFIG.PROMPT.NODES[message.from] = null
|
|
botTextMessagReply(message, "Reset Done.\n")
|
|
break;
|
|
case '/q':
|
|
if(CONFIG.KSAMPLER_SEED_CHANGE) {
|
|
editInputs(CONFIG.PROMPT.NODES[message.from], "KSampler", "seed", Date.now())
|
|
}
|
|
editInputs(CONFIG.PROMPT.NODES[message.from], "WA_ImageSaver", "Path", path.join(CONFIG.OUTPUT_DIRECTORY, extractPhoneNumber(message.from)))
|
|
let requestOptions = {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ "prompt": CONFIG.PROMPT.NODES[message.from] })
|
|
};
|
|
fetch(CONFIG.API_URL + "/prompt", requestOptions)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
botTextMessagReply(message, "Promt Submitted.\n")
|
|
watch(message.from, data)
|
|
})
|
|
.catch(error => console.error('Error:', error));
|
|
break;
|
|
case '/m':
|
|
if (!isAdmin(message.from)) {
|
|
botTextMessagReply(message, `You are not Admin.`)
|
|
return
|
|
}
|
|
let mode = parseInt(sliced[1])
|
|
if (mode == 1) {
|
|
CONFIG.MODE = 1
|
|
botTextMessagReply(message, `Usage Mode changed to: *${CONFIG.MODE == 1 ? 'Single User' : 'Multi User'}*`)
|
|
}
|
|
else if (mode == 2) {
|
|
CONFIG.MODE = 2
|
|
botTextMessagReply(message, `Usage Mode changed to: *${CONFIG.MODE == 1 ? 'Single User' : 'Multi User'}*`)
|
|
}
|
|
else {
|
|
botTextMessagReply(message, `Invalid Mode.`)
|
|
}
|
|
break;
|
|
case '/i':
|
|
fetch(CONFIG.API_URL + "/interrupt", {
|
|
method: 'POST',
|
|
})
|
|
.then(data => { botTextMessagReply(message, "Promt Interrupted.\n\n") })
|
|
.catch(error => console.error('Error:', error));
|
|
break;
|
|
default:
|
|
if (mode == 2) {
|
|
botTextMessagReply(message, `Invalid command. Message */c*`)
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//==================================== WA ======================================================
|
|
|
|
let options = {
|
|
executablePath: CONFIG.CHROME,
|
|
headless: true
|
|
}
|
|
|
|
if (!CONFIG.CHROME && CONFIG.CHROME.length == 0) {
|
|
delete options.executablePath
|
|
}
|
|
|
|
CONFIG.WA = new Client({ authStrategy: new LocalAuth({ dataPath: CONFIG.BROWSER_DIRECTORY }), puppeteer: options })
|
|
|
|
CONFIG.WA.on('qr', (qr) => {
|
|
CONFIG.QRCODE = qr
|
|
qrcode.toFile(path.join(CONFIG.TEMP_DIRECTORY, 'qr.png'), qr, {
|
|
color: {
|
|
dark: '#000',
|
|
light: '#fff'
|
|
}
|
|
}, (err) => {
|
|
if (err) throw err;
|
|
console.log('QR code generated successfully!');
|
|
});
|
|
});
|
|
|
|
CONFIG.WA.on('ready', () => {
|
|
CONFIG.READY = true
|
|
if (CONFIG.ADMIN)
|
|
botTextMessage(CONFIG.ADMIN, `ComfyUI Bot is *Online*.\n\nMessage */c* to start.\n\nUsage Mode: *${CONFIG.MODE == 1 ? 'Single User' : 'Multi User'}*`)
|
|
});
|
|
|
|
CONFIG.WA.on('message_create', message => {
|
|
|
|
if (message.body.includes('🤖')) {
|
|
return
|
|
}
|
|
|
|
if (CONFIG.MODE == 1 && message.id.fromMe == true) {
|
|
setCommand(message)
|
|
} else if (CONFIG.MODE == 1 && message.id.fromMe == false) {
|
|
botTextMessagReply("I can't fulfill your request sorry 😅.")
|
|
} else if (CONFIG.MODE == 2) {
|
|
setCommand(message)
|
|
}
|
|
|
|
});
|
|
|
|
// =================================== EXPRESS ========================================
|
|
|
|
CONFIG.EXPRESS.use(express.static(CONFIG.WEB_DIRECTORY))
|
|
CONFIG.EXPRESS.use(express.json());
|
|
|
|
CONFIG.EXPRESS.get('/ping', (req, res) => {
|
|
return res.json({ TIME: +new Date() })
|
|
});
|
|
|
|
CONFIG.EXPRESS.get('/qr', (req, res) => {
|
|
const qrImagePath = path.join(CONFIG.TEMP_DIRECTORY, 'qr.png');
|
|
if (fs.existsSync(qrImagePath)) {
|
|
return res.sendFile(path.resolve(qrImagePath));
|
|
} else {
|
|
return res.status(404).send("QR code image not found");
|
|
}
|
|
});
|
|
|
|
CONFIG.EXPRESS.get('/ready', (req, res) => {
|
|
return res.json({ ready: CONFIG.READY })
|
|
});
|
|
|
|
CONFIG.EXPRESS.post('/model', async (req, res) => {
|
|
try {
|
|
const data = req.body;
|
|
const filename = data.name
|
|
const filePath = path.join(CONFIG.MODELS_DIRECTORY, filename);
|
|
await fsp.mkdir(CONFIG.MODELS_DIRECTORY, { recursive: true });
|
|
await fsp.writeFile(filePath, JSON.stringify(data.data, null, 2), 'utf8');
|
|
res.status(200).json({ success: true, message: 'Model data saved successfully' });
|
|
} catch (error) {
|
|
console.error('Error saving model data:', error);
|
|
res.status(500).json({ success: false, message: 'Failed to save model data' });
|
|
}
|
|
});
|
|
|
|
CONFIG.EXPRESS.get('/models', async (req, res) => {
|
|
try {
|
|
const files = await fsp.readdir(CONFIG.MODELS_DIRECTORY);
|
|
const models = await Promise.all(files.map(async (file) => {
|
|
const filePath = path.join(CONFIG.MODELS_DIRECTORY, file);
|
|
const stats = await fsp.stat(filePath);
|
|
return {
|
|
name: file.split('.')[0],
|
|
dateCreated: stats.mtime.toISOString()
|
|
};
|
|
}));
|
|
res.status(200).json(models);
|
|
} catch (error) {
|
|
console.error('Error retrieving models:', error);
|
|
res.status(500).json({ success: false, message: 'Failed to retrieve models' });
|
|
}
|
|
});
|
|
|
|
CONFIG.EXPRESS.delete('/model/:name', async (req, res) => {
|
|
try {
|
|
const { name } = req.params;
|
|
const filePath = path.join(CONFIG.MODELS_DIRECTORY, name + '.json');
|
|
await fsp.unlink(filePath);
|
|
res.status(200).json({ success: true, message: 'Model deleted successfully' });
|
|
} catch (error) {
|
|
console.error('Error deleting model:', error);
|
|
res.status(500).json({ success: false, message: 'Failed to delete model' });
|
|
}
|
|
});
|
|
|
|
CONFIG.EXPRESS.get('/', (req, res) => {
|
|
return res.sendFile(path.join(__dirname, 'website', 'index.html'))
|
|
})
|
|
|
|
//==============================================INIT============================
|
|
|
|
let ON = true
|
|
|
|
if (ON) {
|
|
createDirectories(CONFIG);
|
|
CONFIG.WA.initialize()
|
|
|
|
CONFIG.EXPRESS.listen(CONFIG.PORT, () => {
|
|
console.log(`Server running at http://localhost:${CONFIG.PORT}`);
|
|
});
|
|
}
|