webp import

This commit is contained in:
SillyLossy
2023-04-08 13:19:02 +03:00
parent 342d83c334
commit 0ca66ee471
6 changed files with 166 additions and 77 deletions

80
package-lock.json generated
View File

@ -14,9 +14,11 @@
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"csrf-csrf": "^2.2.3",
"exifreader": "^4.12.0",
"express": "^4.18.2",
"ipaddr.js": "^2.0.1",
"jimp": "^0.22.7",
"json5": "^2.2.3",
"mime-types": "^2.1.35",
"multer": "^1.4.5-lts.1",
"node-rest-client": "^3.1.1",
@ -26,6 +28,7 @@
"png-chunks-extract": "^1.0.0",
"rimraf": "^3.0.2",
"sanitize-filename": "^1.6.3",
"webp-converter": "^2.3.3",
"ws": "^8.13.0"
},
"bin": {
@ -450,6 +453,15 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="
},
"node_modules/@xmldom/xmldom": {
"version": "0.7.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.10.tgz",
"integrity": "sha512-hb9QhOg5MGmpVkFcoZ9XJMe1em5gd0e2eqqjK87O1dwULedXsnY/Zg/Ju6lcohA+t6jVkmKpe7I1etqhvdRdrQ==",
"optional": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -887,6 +899,15 @@
"resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
"integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="
},
"node_modules/exifreader": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.12.0.tgz",
"integrity": "sha512-aRSmNyw2c6f6qPK4jmC56W/5XePDN7LVwt8tQjgMchxoY3MCxqEToegirKdS7A3CYCWAOPehfypMZWGWxtLhzw==",
"hasInstallScript": true,
"optionalDependencies": {
"@xmldom/xmldom": "^0.7.8"
}
},
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
@ -1252,6 +1273,17 @@
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/load-bmfont": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz",
@ -1996,6 +2028,14 @@
"node": ">= 0.4.0"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -2009,6 +2049,14 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/webp-converter": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/webp-converter/-/webp-converter-2.3.3.tgz",
"integrity": "sha512-2p4XvPCIQ/CbUztEFA9vdkILVrRTdMtMxFpQTxlnPc3qx14MV5wnpVvK7m6pG70QdeL+Ser0+Tp843ONwh8VbQ==",
"dependencies": {
"uuid": "^8.3.2"
}
},
"node_modules/whatwg-fetch": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
@ -2405,6 +2453,12 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="
},
"@xmldom/xmldom": {
"version": "0.7.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.10.tgz",
"integrity": "sha512-hb9QhOg5MGmpVkFcoZ9XJMe1em5gd0e2eqqjK87O1dwULedXsnY/Zg/Ju6lcohA+t6jVkmKpe7I1etqhvdRdrQ==",
"optional": true
},
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -2738,6 +2792,14 @@
"resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
"integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="
},
"exifreader": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.12.0.tgz",
"integrity": "sha512-aRSmNyw2c6f6qPK4jmC56W/5XePDN7LVwt8tQjgMchxoY3MCxqEToegirKdS7A3CYCWAOPehfypMZWGWxtLhzw==",
"requires": {
"@xmldom/xmldom": "^0.7.8"
}
},
"express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
@ -3019,6 +3081,11 @@
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="
},
"json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
},
"load-bmfont": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz",
@ -3598,6 +3665,11 @@
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -3608,6 +3680,14 @@
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"webp-converter": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/webp-converter/-/webp-converter-2.3.3.tgz",
"integrity": "sha512-2p4XvPCIQ/CbUztEFA9vdkILVrRTdMtMxFpQTxlnPc3qx14MV5wnpVvK7m6pG70QdeL+Ser0+Tp843ONwh8VbQ==",
"requires": {
"uuid": "^8.3.2"
}
},
"whatwg-fetch": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",

View File

@ -2,13 +2,15 @@
"dependencies": {
"@dqbd/tiktoken": "^1.0.2",
"axios": "^1.3.4",
"compression": "^1",
"cookie-parser": "^1.4.6",
"compression":"^1",
"cors": "^2.8.5",
"csrf-csrf": "^2.2.3",
"exifreader": "^4.12.0",
"express": "^4.18.2",
"ipaddr.js": "^2.0.1",
"jimp": "^0.22.7",
"json5": "^2.2.3",
"mime-types": "^2.1.35",
"multer": "^1.4.5-lts.1",
"node-rest-client": "^3.1.1",
@ -18,6 +20,7 @@
"png-chunks-extract": "^1.0.0",
"rimraf": "^3.0.2",
"sanitize-filename": "^1.6.3",
"webp-converter": "^2.3.3",
"ws": "^8.13.0"
},
"name": "TavernAI",

View File

@ -258,7 +258,7 @@
<div class="avatar_upload">+</div>
</div>
<form id="form_upload_avatar" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<input type="file" id="avatar_upload_file" accept="image/png" name="avatar">
<input type="file" id="avatar_upload_file" accept="image/*" name="avatar">
</form>
<form id='form_change_name' action="javascript:void(null);" method="post" enctype="multipart/form-data">
<h4>Name</h4>
@ -1297,7 +1297,7 @@
<div id="rm_character_import" class="right_menu" style="display: none;">
<form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<input type="file" id="character_import_file" accept=".json, image/png" name="avatar">
<input type="file" id="character_import_file" accept=".json, image/png, image/webp" name="avatar">
<input id="character_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off">
</form>
</div>

View File

@ -4437,7 +4437,7 @@ $(document).ready(function () {
var ext = file.name.match(/\.(\w+)$/);
if (
!ext ||
(ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png")
(ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png" && ext[1] != "webp")
) {
return;
}

View File

@ -222,7 +222,11 @@ function RA_checkOnlineStatus() {
//Auto-connect to API (when set to kobold, API URL exists, and auto_connect is true)
function RA_autoconnect(PrevApi) {
if ((online_status === undefined || online_status === "no_connection") && LoadLocalBool('AutoConnectEnabled')) {
if (online_status === undefined) {
setTimeout(RA_autoconnect, 100);
return;
}
if (online_status === "no_connection" && LoadLocalBool('AutoConnectEnabled')) {
switch (main_api) {
case 'kobold':
if (api_server && isUrlOrAPIKey(api_server)) {

146
server.js
View File

@ -23,6 +23,10 @@ const mime = require('mime-types');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');
const ipaddr = require('ipaddr.js');
const json5 = require('json5');
const ExifReader = require('exifreader');
const webp = require('webp-converter');
const config = require(path.join(process.cwd(), './config.conf'));
const server_port = process.env.SILLY_TAVERN_PORT || config.port;
@ -395,7 +399,7 @@ app.post("/getchat", jsonParser, function (request, response) {
const lines = data.split('\n');
// Iterate through the array of strings and parse each line as JSON
const jsonData = lines.map(JSON.parse);
const jsonData = lines.map(json5.parse);
response.send(jsonData);
//console.log('read the requested file')
@ -441,7 +445,7 @@ app.post("/getstatus", jsonParser, function (request, response_getstatus = respo
var response = body.match(/gradio_config[ =]*(\{.*\});/)[1];
if (!response)
throw "no_connection";
let model = JSON.parse(response).components.filter((x) => x.props.label == "Model" && x.type == "dropdown")[0].props.value;
let model = json5.parse(response).components.filter((x) => x.props.label == "Model" && x.type == "dropdown")[0].props.value;
data = { result: model };
if (!data)
throw "no_connection";
@ -678,28 +682,44 @@ async function charaWrite(img_url, data, target_img, response = undefined, mes =
}
}
async function charaRead(img_url, input_format) {
let format;
if (input_format === undefined) {
if (img_url.indexOf('.webp') !== -1) {
format = 'webp';
} else {
format = 'png';
}
} else {
format = input_format;
}
switch (format) {
case 'webp':
const exif_data = await ExifReader.load(fs.readFileSync(img_url));
const char_data = exif_data['UserComment']['description'];
if (char_data === 'Undefined' && exif_data['UserComment'].value && exif_data['UserComment'].value.length === 1) {
return exif_data['UserComment'].value[0];
}
return char_data;
case 'png':
const buffer = fs.readFileSync(img_url);
const chunks = extract(buffer);
function charaRead(img_url) {
const buffer = fs.readFileSync(img_url);
const chunks = extract(buffer);
const textChunks = chunks.filter(function (chunk) {
return chunk.name === 'tEXt';
}).map(function (chunk) {
//console.log(text.decode(chunk.data));
return PNGtext.decode(chunk.data);
});
var base64DecodedData = Buffer.from(textChunks[0].text, 'base64').toString('utf8');
return base64DecodedData;//textChunks[0].text;
//console.log(textChunks[0].keyword); // 'hello'
//console.log(textChunks[0].text);    // 'world'
const textChunks = chunks.filter(function (chunk) {
return chunk.name === 'tEXt';
}).map(function (chunk) {
return PNGtext.decode(chunk.data);
});
var base64DecodedData = Buffer.from(textChunks[0].text, 'base64').toString('utf8');
return base64DecodedData;//textChunks[0].text;
default:
break;
}
}
app.post("/getcharacters", jsonParser, function (request, response) {
fs.readdir(charactersPath, (err, files) => {
fs.readdir(charactersPath, async (err, files) => {
if (err) {
console.error(err);
return;
@ -710,11 +730,10 @@ app.post("/getcharacters", jsonParser, function (request, response) {
//console.log(pngFiles);
characters = {};
var i = 0;
pngFiles.forEach(item => {
//console.log(item);
var img_data = charaRead(charactersPath + item);
for (const item of pngFiles) {
try {
let jsonObject = JSON.parse(img_data);
var img_data = await charaRead(charactersPath + item);
let jsonObject = json5.parse(img_data);
jsonObject.avatar = item;
//console.log(jsonObject);
characters[i] = {};
@ -727,7 +746,7 @@ app.post("/getcharacters", jsonParser, function (request, response) {
console.log("An unexpected error occurred: ", error);
}
}
});
};
//console.log(characters);
response.send(JSON.stringify(characters));
});
@ -746,7 +765,7 @@ app.post("/getbackgrounds", jsonParser, function (request, response) {
app.post("/iscolab", jsonParser, function (request, response) {
let send_data = false;
if (is_colab) {
send_data = String(process.env.colaburl).trim();
send_data = String(process.env.colaburl).trim();
}
response.send({ colaburl: send_data });
@ -1036,7 +1055,7 @@ function readWorldInfoFile(worldInfoName) {
}
const worldInfoText = fs.readFileSync(pathToWorldInfo, 'utf8');
const worldInfo = JSON.parse(worldInfoText);
const worldInfo = json5.parse(worldInfoText);
return worldInfo;
}
@ -1222,7 +1241,7 @@ app.post("/getallchatsofcharacter", jsonParser, function (request, response) {
});
rl.on('close', () => {
if (lastLine) {
let jsonData = JSON.parse(lastLine);
let jsonData = json5.parse(lastLine);
if (jsonData.name !== undefined) {
chatData[i] = {};
chatData[i]['file_name'] = file;
@ -1247,6 +1266,7 @@ app.post("/getallchatsofcharacter", jsonParser, function (request, response) {
};
})
});
function getPngName(file) {
let i = 1;
let base_name = file;
@ -1256,23 +1276,24 @@ function getPngName(file) {
}
return file;
}
app.post("/importcharacter", urlencodedParser, async function (request, response) {
if (!request.body) return response.sendStatus(400);
let png_name = '';
let filedata = request.file;
//console.log(filedata.filename);
let uploadPath = path.join('./uploads', filedata.filename);
var format = request.body.file_type;
//console.log(format);
if (filedata) {
if (format == 'json') {
fs.readFile('./uploads/' + filedata.filename, 'utf8', async (err, data) => {
fs.readFile(uploadPath, 'utf8', async (err, data) => {
if (err) {
console.log(err);
response.send({ error: true });
}
const jsonData = JSON.parse(data);
const jsonData = json5.parse(data);
if (jsonData.name !== undefined) {
jsonData.name = sanitize(jsonData.name);
@ -1295,43 +1316,29 @@ app.post("/importcharacter", urlencodedParser, async function (request, response
});
} else {
try {
var img_data = charaRead('./uploads/' + filedata.filename);
let jsonData = JSON.parse(img_data);
var img_data = await charaRead(uploadPath, format);
let jsonData = json5.parse(img_data);
jsonData.name = sanitize(jsonData.name);
if (format == 'webp') {
let convertedPath = path.join('./uploads', path.basename(uploadPath, ".webp") + ".png")
await webp.dwebp(uploadPath, convertedPath, "-o");
uploadPath = convertedPath;
}
png_name = getPngName(jsonData.name);
if (jsonData.name !== undefined) {
let char = { "name": jsonData.name, "description": jsonData.description ?? '', "personality": jsonData.personality ?? '', "first_mes": jsonData.first_mes ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": humanizedISO8601DateTime(), "talkativeness": jsonData.talkativeness ?? 0.5 };
char = JSON.stringify(char);
await charaWrite('./uploads/' + filedata.filename, char, png_name, response, { file_name: png_name });
/*
fs.copyFile('./uploads/'+filedata.filename, charactersPath+png_name+'.png', (err) => {
if(err) {
response.send({error:true});
return console.log(err);
}else{
//console.log(img_file+fileType);
response.send({file_name: png_name});
}
//console.log('The image was copied from temp directory.');
});*/
await charaWrite(uploadPath, char, png_name, response, { file_name: png_name });
}
} catch (err) {
console.log(err);
response.send({ error: true });
}
}
//charaWrite(img_path+img_file, char, request.body.ch_name, response);
}
//console.log("The file was saved.");
//console.log(request.body);
//response.send(request.body.ch_name);
//response.redirect("https://metanit.com")
});
app.post("/importchat", urlencodedParser, function (request, response) {
@ -1356,7 +1363,7 @@ app.post("/importchat", urlencodedParser, function (request, response) {
response.send({ error: true });
}
const jsonData = JSON.parse(data);
const jsonData = json5.parse(data);
var new_chat = [];
if (jsonData.histories !== undefined) {
//console.log('/importchat confirms JSON histories are defined');
@ -1409,7 +1416,7 @@ app.post("/importchat", urlencodedParser, function (request, response) {
});
rl.once('line', (line) => {
let jsonData = JSON.parse(line);
let jsonData = json5.parse(line);
if (jsonData.user_name !== undefined) {
//console.log(humanizedISO8601DateTime()+':/importchat copying chat as '+ch_name+' - '+humanizedISO8601DateTime()+'.jsonl');
@ -1447,7 +1454,7 @@ app.post('/importworldinfo', urlencodedParser, (request, response) => {
const fileContents = fs.readFileSync(pathToUpload, 'utf8');
try {
const worldContent = JSON.parse(fileContents);
const worldContent = json5.parse(fileContents);
if (!('entries' in worldContent)) {
throw new Error('File must contain a world info entries list');
}
@ -1519,7 +1526,7 @@ app.post('/getgroups', jsonParser, (_, response) => {
const files = fs.readdirSync(directories.groups);
files.forEach(function (file) {
const fileContents = fs.readFileSync(path.join(directories.groups, file), 'utf8');
const group = JSON.parse(fileContents);
const group = json5.parse(fileContents);
groups.push(group);
});
@ -1578,7 +1585,7 @@ app.post('/getgroupchat', jsonParser, (request, response) => {
const lines = data.split('\n');
// Iterate through the array of strings and parse each line as JSON
const jsonData = lines.map(JSON.parse);
const jsonData = lines.map(json5.parse);
return response.send(jsonData);
} else {
return response.send([]);
@ -1641,7 +1648,7 @@ app.post('/status_poe', jsonParser, async (request, response) => {
const botNames = client.get_bot_names();
client.disconnect_ws();
return response.send({'bot_names': botNames});
return response.send({ 'bot_names': botNames });
}
catch {
return response.sendStatus(401);
@ -1661,8 +1668,8 @@ app.post('/purge_poe', jsonParser, async (request, response) => {
const client = await getPoeClient(token);
await client.purge_conversation(bot, count);
client.disconnect_ws();
return response.send({"ok" : true});
return response.send({ "ok": true });
}
catch {
return response.sendStatus(500);
@ -1673,24 +1680,24 @@ app.post('/generate_poe', jsonParser, async (request, response) => {
if (!request.body.token || !request.body.prompt) {
return response.sendStatus(400);
}
const token = request.body.token;
const prompt = request.body.prompt;
const bot = request.body.bot ?? POE_DEFAULT_BOT;
try {
const client = await getPoeClient(token);
let reply;
for await (const mes of client.send_message(bot, prompt)) {
reply = mes.text;
}
console.log(reply);
client.disconnect_ws();
return response.send({'reply': reply});
return response.send({ 'reply': reply });
}
catch {
return response.sendStatus(500);
@ -2034,8 +2041,6 @@ function convertStage1() {
getCharacterFile2(directories, 0);
}
function convertStage2() {
//directoriesB = JSON.parse(directoriesB);
//console.log(directoriesB);
var mes = true;
for (const key in directoriesB) {
if (mes) {
@ -2044,9 +2049,6 @@ function convertStage2() {
console.log('***');
mes = false;
}
//console.log(`${key}: ${directoriesB[key]}`);
//console.log(JSON.parse(charactersB[key]));
//console.log(directoriesB[key]);
var char = JSON.parse(charactersB[key]);
char.create_date = humanizedISO8601DateTime();