var express = require('express');
var app = express();
var fs = require('fs');
const readline = require('readline');
const open = require('open');
var rimraf = require("rimraf");
const multer = require("multer");
const https = require('https');
//const PNG = require('pngjs').PNG;
const extract = require('png-chunks-extract');
const encode = require('png-chunks-encode');
const PNGtext = require('png-chunk-text');
const sharp = require('sharp');
sharp.cache(false);
const path = require('path');
var Client = require('node-rest-client').Client;
var client = new Client();
var api_server = "";//"http://127.0.0.1:5000";
var server_port = 8000;
var api_novelai = "https://api.novelai.net";
var response_get_story;
var response_generate;
var response_generate_novel;
var request_promt;
var response_promt;
var characters = {};
var character_i = 0;
var response_create;
var response_edit;
var response_dw_bg;
var response_getstatus;
var response_getstatus_novel;
var response_getlastversion;
var api_key_novel;
var is_colab = false;
const jsonParser = express.json();
const urlencodedParser = express.urlencoded({extended: false});
app.post("/getlastversion", jsonParser, function(request, response_getlastversion = response){
if(!request.body) return response_getlastversion.sendStatus(400);
const repo = 'TavernAI/TavernAI';
https.request({
hostname: 'github.com',
path: `/${repo}/releases/latest`,
method: 'HEAD'
}, (res) => {
if(res.statusCode === 302) {
const glocation = res.headers.location;
const versionStartIndex = glocation.lastIndexOf('@')+1;
const version = glocation.substring(versionStartIndex);
//console.log(version);
response_getlastversion.send({version: version});
}else{
response_getlastversion.send({version: 'error'});
}
}).end();
});
app.use(express.static(__dirname + "/public"));
app.use(multer({dest:"uploads"}).single("avatar"));
app.get("/", function(request, response){
response.sendFile(__dirname + "/public/index.html");
//response.send("
Главная страница
");
});
app.get("/notes/*", function(request, response){
response.sendFile(__dirname + "/public"+request.url+".html");
//response.send("Главная страница
");
});
//**************Kobold api
app.post("/generate", jsonParser, function(request, response_generate = response){
if(!request.body) return response_generate.sendStatus(400);
//console.log(request.body.prompt);
//const dataJson = JSON.parse(request.body);
request_promt = request.body.prompt;
//console.log(request.body);
var this_settings = { prompt: request_promt,
use_story:false,
use_memory:false,
use_authors_note:false,
use_world_info:false,
max_context_length: request.body.max_context_length
//temperature: request.body.temperature,
//max_length: request.body.max_length
};
if(request.body.gui_settings == false){
var sampler_order = [request.body.s1,request.body.s2,request.body.s3,request.body.s4,request.body.s5,request.body.s6,request.body.s7];
this_settings = { prompt: request_promt,
use_story:false,
use_memory:false,
use_authors_note:false,
use_world_info:false,
max_context_length: request.body.max_context_length,
max_length: request.body.max_length,
rep_pen: request.body.rep_pen,
rep_pen_range: request.body.rep_pen_range,
rep_pen_slope: request.body.rep_pen_slope,
temperature: request.body.temperature,
tfs: request.body.tfs,
top_a: request.body.top_a,
top_k: request.body.top_k,
top_p: request.body.top_p,
typical: request.body.typical,
sampler_order: sampler_order
};
}
console.log(this_settings);
var args = {
data: this_settings,
headers: { "Content-Type": "application/json" }
};
client.post(api_server+"/v1/generate",args, function (data, response) {
if(response.statusCode == 200){
console.log(data);
response_generate.send(data);
}
if(response.statusCode == 422){
console.log('Validation error');
response_generate.send({error: true});
}
if(response.statusCode == 501 || response.statusCode == 503 || response.statusCode == 507){
console.log(data);
response_generate.send({error: true});
}
}).on('error', function (err) {
console.log(err);
//console.log('something went wrong on the request', err.request.options);
response_generate.send({error: true});
});
});
app.post("/savechat", jsonParser, function(request, response){
//console.log(request.data);
//console.log(request.body.bg);
//const data = request.body;
//console.log(request);
//console.log(request.body.chat);
//var bg = "body {background-image: linear-gradient(rgba(19,21,44,0.75), rgba(19,21,44,0.75)), url(../backgrounds/"+request.body.bg+");}";
var dir_name = String(request.body.avatar_url).replace('.png','');
let chat_data = request.body.chat;
let jsonlData = chat_data.map(JSON.stringify).join('\n');
fs.writeFile('public/chats/'+dir_name+"/"+request.body.file_name+'.jsonl', jsonlData, 'utf8', function(err) {
if(err) {
response.send(err);
return console.log(err);
//response.send(err);
}else{
//response.redirect("/");
response.send({result: "ok"});
}
});
});
app.post("/getchat", jsonParser, function(request, response){
//console.log(request.data);
//console.log(request.body.bg);
//const data = request.body;
//console.log(request);
//console.log(request.body.chat);
//var bg = "body {background-image: linear-gradient(rgba(19,21,44,0.75), rgba(19,21,44,0.75)), url(../backgrounds/"+request.body.bg+");}";
var dir_name = String(request.body.avatar_url).replace('.png','');
fs.stat('public/chats/'+dir_name, function(err, stat) {
if(stat === undefined){
fs.mkdirSync('public/chats/'+dir_name);
response.send({});
return;
}else{
if(err === null){
fs.stat('public/chats/'+dir_name+"/"+request.body.file_name+".jsonl", function(err, stat) {
if (err === null) {
if(stat !== undefined){
fs.readFile('public/chats/'+dir_name+"/"+request.body.file_name+".jsonl", 'utf8', (err, data) => {
if (err) {
console.error(err);
response.send(err);
return;
}
//console.log(data);
const lines = data.split('\n');
// Iterate through the array of strings and parse each line as JSON
const jsonData = lines.map(JSON.parse);
response.send(jsonData);
});
}
}else{
response.send({});
//return console.log(err);
return;
}
});
}else{
console.error(err);
response.send({});
return;
}
}
});
});
app.post("/getstatus", jsonParser, function(request, response_getstatus = response){
if(!request.body) return response_getstatus.sendStatus(400);
if(is_colab === true){
api_server = '127.0.0.1:5000';
}else{
api_server = request.body.api_server;
}
if(api_server.indexOf('localhost') != -1){
api_server = api_server.replace('localhost','127.0.0.1');
}
var args = {
headers: { "Content-Type": "application/json" }
};
client.get(api_server+"/v1/model",args, function (data, response) {
if(response.statusCode == 200){
if(data.result != "ReadOnly"){
//response_getstatus.send(data.result);
}else{
data.result = "no_connection";
}
}else{
data.result = "no_connection";
}
response_getstatus.send(data);
//console.log(response.statusCode);
//console.log(data);
//response_getstatus.send(data);
//data.results[0].text
}).on('error', function (err) {
//console.log('');
//console.log('something went wrong on the request', err.request.options);
response_getstatus.send({result: "no_connection"});
});
});
function checkServer(){
//console.log('Check run###################################################');
api_server = 'http://127.0.0.1:5000';
var args = {
headers: { "Content-Type": "application/json" }
};
client.get(api_server+"/v1/model",args, function (data, response) {
console.log(data.result);
//console.log('###################################################');
console.log(data);
}).on('error', function (err) {
console.log(err);
//console.log('');
//console.log('something went wrong on the request', err.request.options);
//console.log('errorrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr');
});
}
//***************** Main functions
function charaFormatData(data){
var char = {"name": data.ch_name, "description": data.description, "personality": data.personality, "first_mes": data.first_mes, "avatar": 'none', "chat": Date.now(), "mes_example": data.mes_example, "scenario": data.scenario, "create_date": Date.now()};
return char;
}
app.post("/createcharacter", urlencodedParser, function(request, response){
if(!request.body) return response.sendStatus(400);
if (!fs.existsSync('public/characters/'+request.body.ch_name+'.png')){
if(!fs.existsSync('public/chats/'+request.body.ch_name) )fs.mkdirSync('public/chats/'+request.body.ch_name);
//if(!fs.existsSync('public/characters/'+request.body.ch_name+'/chats')) fs.mkdirSync('public/characters/'+request.body.ch_name+'/chats');
//if(!fs.existsSync('public/characters/'+request.body.ch_name+'/avatars')) fs.mkdirSync('public/characters/'+request.body.ch_name+'/avatars');
let filedata = request.file;
//console.log(filedata.mimetype);
var fileType = ".png";
var img_file = "ai";
var img_path = "public/img/";
var char = charaFormatData(request.body);//{"name": request.body.ch_name, "description": request.body.description, "personality": request.body.personality, "first_mes": request.body.first_mes, "avatar": 'none', "chat": Date.now(), "last_mes": '', "mes_example": ''};
char = JSON.stringify(char);
if(!filedata){
charaWrite('./public/img/fluffy.png', char, request.body.ch_name, response);
//fs.writeFile('public/characters/'+request.body.ch_name+"/"+request.body.ch_name+".json", char, 'utf8', function(err) {
//if(err) {
//response.send(err);
//return console.log(err);
//}else{
//}
//});
}else{
img_path = "./uploads/";
img_file = filedata.filename
if (filedata.mimetype == "image/jpeg") fileType = ".jpeg";
if (filedata.mimetype == "image/png") fileType = ".png";
if (filedata.mimetype == "image/gif") fileType = ".gif";
if (filedata.mimetype == "image/bmp") fileType = ".bmp";
charaWrite(img_path+img_file, char, request.body.ch_name, response);
}
//console.log("The file was saved.");
}else{
response.send("Error: A character with that name already exists.");
}
//console.log(request.body);
//response.send(request.body.ch_name);
//response.redirect("https://metanit.com")
});
app.post("/editcharacter", urlencodedParser, function(request, response){
if(!request.body) return response.sendStatus(400);
let filedata = request.file;
//console.log(filedata.mimetype);
var fileType = ".png";
var img_file = "ai";
var img_path = "./public/characters/";
var char = charaFormatData(request.body);//{"name": request.body.ch_name, "description": request.body.description, "personality": request.body.personality, "first_mes": request.body.first_mes, "avatar": request.body.avatar_url, "chat": request.body.chat, "last_mes": request.body.last_mes, "mes_example": ''};
char.chat = request.body.chat;
char.create_date = request.body.create_date;
char = JSON.stringify(char);
if(!filedata){
charaWrite(img_path+request.body.avatar_url, char, request.body.ch_name, response, 'Character saved');
}else{
//console.log(filedata.filename);
img_path = "uploads/";
img_file = filedata.filename;
charaWrite(img_path+img_file, char, request.body.ch_name, response, 'Character saved');
//response.send('Character saved');
}
});
app.post("/deletecharacter", urlencodedParser, function(request, response){
if(!request.body) return response.sendStatus(400);
rimraf('public/characters/'+request.body.avatar_url, (err) => {
if(err) {
response.send(err);
return console.log(err);
}else{
//response.redirect("/");
let dir_name = request.body.avatar_url;
rimraf('public/chats/'+dir_name.replace('.png',''), (err) => {
if(err) {
response.send(err);
return console.log(err);
}else{
//response.redirect("/");
response.send('ok');
}
});
}
});
});
async function charaWrite(img_url, data, name, response = undefined, mes = 'ok'){
try {
// Load the image in any format
sharp.cache(false);
var image = await sharp(img_url).resize(400, 600).toFormat('png').toBuffer();// old 170 234
// Convert the image to PNG format
//const pngImage = image.toFormat('png');
// Resize the image to 100x100
//const resizedImage = pngImage.resize(100, 100);
// Get the chunks
var chunks = extract(image);
var tEXtChunks = chunks.filter(chunk => chunk.name === 'tEXt');
// Remove all existing tEXt chunks
for (var tEXtChunk of tEXtChunks) {
chunks.splice(chunks.indexOf(tEXtChunk), 1);
}
// Add new chunks before the IEND chunk
var base64EncodedData = Buffer.from(data, 'utf8').toString('base64');
chunks.splice(-1, 0, PNGtext.encode('chara', base64EncodedData));
//chunks.splice(-1, 0, text.encode('lorem', 'ipsum'));
fs.writeFileSync('public/characters/'+name+'.png', new Buffer.from(encode(chunks)));
if(response !== undefined) response.send(mes);
} catch (err) {
console.log(err);
if(response !== undefined) response.send(err);
}
}
function charaRead(img_url){
sharp.cache(false);
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'
}
app.post("/getcharacters", jsonParser, function(request, response){
fs.readdir("public/characters", (err, files) => {
if (err) {
console.error(err);
return;
}
const pngFiles = files.filter(file => file.endsWith('.png'));
//console.log(pngFiles);
characters = {};
var i = 0;
pngFiles.forEach(item => {
//console.log(item);
var img_data = charaRead('./public/characters/'+item);
try {
let jsonObject = JSON.parse(img_data);
jsonObject.avatar = item;
//console.log(jsonObject);
characters[i] = {};
characters[i] = jsonObject;
i++;
} catch (error) {
if (error instanceof SyntaxError) {
console.log("String [" + (i) + "] is not valid JSON!");
} else {
console.log("An unexpected error occurred: ", error);
}
}
});
//console.log(characters);
response.send(JSON.stringify(characters));
});
//var directories = getDirectories("public/characters");
//console.log(directories[0]);
//characters = {};
//character_i = 0;
//getCharaterFile(directories, response,0);
});
app.post("/getbackgrounds", jsonParser, function(request, response){
var images = getImages("public/backgrounds");
if(is_colab === true){
images = ['tavern.png'];
}
response.send(JSON.stringify(images));
});
app.post("/iscolab", jsonParser, function(request, response){
response.send({is_colab:is_colab});
});
app.post("/getuseravatars", jsonParser, function(request, response){
var images = getImages("public/User Avatars");
response.send(JSON.stringify(images));
});
app.post("/setbackground", jsonParser, function(request, response){
//console.log(request.data);
//console.log(request.body.bg);
//const data = request.body;
//console.log(request);
//console.log(1);
var bg = "#bg1 {background-image: linear-gradient(rgba(19,21,44,0.75), rgba(19,21,44,0.75)), url(../backgrounds/"+request.body.bg+");}";
fs.writeFile('public/css/bg_load.css', bg, 'utf8', function(err) {
if(err) {
response.send(err);
return console.log(err);
}else{
//response.redirect("/");
response.send({result:'ok'});
}
});
});
app.post("/delbackground", jsonParser, function(request, response){
if(!request.body) return response.sendStatus(400);
rimraf('public/backgrounds/'+request.body.bg, (err) => {
if(err) {
response.send(err);
return console.log(err);
}else{
//response.redirect("/");
response.send('ok');
}
});
});
app.post("/downloadbackground", urlencodedParser, function(request, response){
response_dw_bg = response;
if(!request.body) return response.sendStatus(400);
let filedata = request.file;
//console.log(filedata.mimetype);
var fileType = ".png";
var img_file = "ai";
var img_path = "public/img/";
img_path = "uploads/";
img_file = filedata.filename;
if (filedata.mimetype == "image/jpeg") fileType = ".jpeg";
if (filedata.mimetype == "image/png") fileType = ".png";
if (filedata.mimetype == "image/gif") fileType = ".gif";
if (filedata.mimetype == "image/bmp") fileType = ".bmp";
fs.copyFile(img_path+img_file, 'public/backgrounds/'+img_file+fileType, (err) => {
if(err) {
return console.log(err);
}else{
//console.log(img_file+fileType);
response_dw_bg.send(img_file+fileType);
}
//console.log('The image was copied from temp directory.');
});
});
app.post("/savesettings", jsonParser, function(request, response){
fs.writeFile('public/settings.json', JSON.stringify(request.body), 'utf8', function(err) {
if(err) {
response.send(err);
return console.log(err);
//response.send(err);
}else{
//response.redirect("/");
response.send({result: "ok"});
}
});
});
app.post('/getsettings', jsonParser, (request, response) => { //Wintermute's code
const koboldai_settings = [];
const koboldai_setting_names = [];
const novelai_settings = [];
const novelai_setting_names = [];
const settings = fs.readFileSync('public/settings.json', 'utf8', (err, data) => {
if (err) return response.sendStatus(500);
return data;
});
//Kobold
const files = fs
.readdirSync('public/KoboldAI Settings')
.sort(
(a, b) =>
new Date(fs.statSync(`public/KoboldAI Settings/${b}`).mtime) -
new Date(fs.statSync(`public/KoboldAI Settings/${a}`).mtime)
);
files.forEach(item => {
const file = fs.readFileSync(
`public/KoboldAI Settings/${item}`,
'utf8',
(err, data) => {
if (err) return response.sendStatus(500)
return data;
}
);
koboldai_settings.push(file);
koboldai_setting_names.push(item.replace(/\.[^/.]+$/, ''));
});
//Novel
const files2 = fs
.readdirSync('public/NovelAI Settings')
.sort(
(a, b) =>
new Date(fs.statSync(`public/NovelAI Settings/${b}`).mtime) -
new Date(fs.statSync(`public/NovelAI Settings/${a}`).mtime)
);
files2.forEach(item => {
const file2 = fs.readFileSync(
`public/NovelAI Settings/${item}`,
'utf8',
(err, data) => {
if (err) return response.sendStatus(500);
return data;
}
);
novelai_settings.push(file2);
novelai_setting_names.push(item.replace(/\.[^/.]+$/, ''));
});
response.send({
settings,
koboldai_settings,
koboldai_setting_names,
novelai_settings,
novelai_setting_names
});
});
function getCharaterFile(directories,response,i){ //old need del
if(directories.length > i){
fs.stat('public/characters/'+directories[i]+'/'+directories[i]+".json", function(err, stat) {
if (err == null) {
fs.readFile('public/characters/'+directories[i]+'/'+directories[i]+".json", 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
//console.log(data);
characters[character_i] = {};
characters[character_i] = data;
i++;
character_i++;
getCharaterFile(directories,response,i);
});
}else{
i++;
getCharaterFile(directories,response,i);
}
});
}else{
response.send(JSON.stringify(characters));
}
}
function getImages(path) {
return fs.readdirSync(path).sort(function (a, b) {
return new Date(fs.statSync(path + '/' + a).mtime) - new Date(fs.statSync(path + '/' + b).mtime);
}).reverse();
}
function getKoboldSettingFiles(path) {
return fs.readdirSync(path).sort(function (a, b) {
return new Date(fs.statSync(path + '/' + a).mtime) - new Date(fs.statSync(path + '/' + b).mtime);
}).reverse();
}
function getDirectories(path) {
return fs.readdirSync(path).sort(function (a, b) {
return new Date(fs.statSync(path + '/' + a).mtime) - new Date(fs.statSync(path + '/' + b).mtime);
}).reverse();
}
//***********Novel.ai API
app.post("/getstatus_novelai", jsonParser, function(request, response_getstatus_novel =response){
if(!request.body) return response_getstatus_novel.sendStatus(400);
api_key_novel = request.body.key;
var data = {};
var args = {
data: data,
headers: { "Content-Type": "application/json", "Authorization": "Bearer "+api_key_novel}
};
client.get(api_novelai+"/user/subscription",args, function (data, response) {
if(response.statusCode == 200){
//console.log(data);
response_getstatus_novel.send(data);//data);
}
if(response.statusCode == 401){
console.log('Access Token is incorrect.');
response_getstatus_novel.send({error: true});
}
if(response.statusCode == 500 || response.statusCode == 501 || response.statusCode == 501 || response.statusCode == 503 || response.statusCode == 507){
console.log(data);
response_getstatus_novel.send({error: true});
}
}).on('error', function (err) {
//console.log('');
//console.log('something went wrong on the request', err.request.options);
response_getstatus_novel.send({error: true});
});
});
app.post("/generate_novelai", jsonParser, function(request, response_generate_novel = response){
if(!request.body) return response_generate_novel.sendStatus(400);
console.log(request.body);
var data = {
"input": request.body.input,
"model": request.body.model,
"parameters": {
"use_string": request.body.use_string,
"temperature": request.body.temperature,
"max_length": request.body.max_length,
"min_length": request.body.min_length,
"tail_free_sampling": request.body.tail_free_sampling,
"repetition_penalty": request.body.repetition_penalty,
"repetition_penalty_range": request.body.repetition_penalty_range,
"repetition_penalty_frequency": request.body.repetition_penalty_frequency,
"repetition_penalty_presence": request.body.repetition_penalty_presence,
//"stop_sequences": {{187}},
//bad_words_ids = {{50256}, {0}, {1}};
//generate_until_sentence = true;
"use_cache": request.body.use_cache,
//use_string = true;
"return_full_text": request.body.return_full_text,
"prefix": request.body.prefix,
"order": request.body.order
}
};
var args = {
data: data,
headers: { "Content-Type": "application/json", "Authorization": "Bearer "+api_key_novel}
};
client.post(api_novelai+"/ai/generate",args, function (data, response) {
if(response.statusCode == 201){
console.log(data);
response_generate_novel.send(data);
}
if(response.statusCode == 400){
console.log('Validation error');
response_generate_novel.send({error: true});
}
if(response.statusCode == 401){
console.log('Access Token is incorrect');
response_generate_novel.send({error: true});
}
if(response.statusCode == 402){
console.log('An active subscription is required to access this endpoint');
response_generate_novel.send({error: true});
}
if(response.statusCode == 500 || response.statusCode == 409){
console.log(data);
response_generate_novel.send({error: true});
}
}).on('error', function (err) {
//console.log('');
//console.log('something went wrong on the request', err.request.options);
response_getstatus.send({error: true});
});
});
app.post("/getallchatsofchatacter", jsonParser, function(request, response){
if(!request.body) return response.sendStatus(400);
var char_dir = (request.body.avatar_url).replace('.png','')
fs.readdir('public/chats/'+char_dir, (err, files) => {
if (err) {
console.error(err);
response.send({error: true});
return;
}
// filter for JSON files
const jsonFiles = files.filter(file => path.extname(file) === '.jsonl');
// sort the files by name
//jsonFiles.sort().reverse();
// print the sorted file names
var chatData = {};
let ii = jsonFiles.length;
for(let i = jsonFiles.length-1; i >= 0; i--){
const file = jsonFiles[i];
const fileStream = fs.createReadStream('public/chats/'+char_dir+'/'+file);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
let lastLine;
rl.on('line', (line) => {
lastLine = line;
});
rl.on('close', () => {
if(lastLine){
let jsonData = JSON.parse(lastLine);
if(jsonData.name !== undefined){
chatData[i] = {};
chatData[i]['file_name'] = file;
chatData[i]['mes'] = jsonData['mes'];
ii--;
if(ii === 0){
response.send(chatData);
}
}else{
return;
}
}
rl.close();
});
}
});
});
function getPngName(file){
if (fs.existsSync('./public/characters/'+file+'.png')) {
file = file+'1';
}
return file;
}
app.post("/importcharacter", urlencodedParser, function(request, response){
if(!request.body) return response.sendStatus(400);
let png_name = '';
let filedata = request.file;
//console.log(filedata.filename);
var format = request.body.file_type;
//console.log(format);
if(filedata){
if(format == 'json'){
fs.readFile('./uploads/'+filedata.filename, 'utf8', (err, data) => {
if (err){
console.log(err);
response.send({error:true});
}
const jsonData = JSON.parse(data);
if(jsonData.char_name !== undefined){//json Pygmalion notepad
png_name = getPngName(jsonData.char_name);
var char = {"name": jsonData.char_name, "description": jsonData.char_persona, "personality": '', "first_mes": jsonData.char_greeting, "avatar": 'none', "chat": Date.now(), "mes_example": jsonData.example_dialogue, "scenario": jsonData.world_scenario, "create_date": Date.now()};
char = JSON.stringify(char);
charaWrite('./public/img/fluffy.png', char, png_name, response, {file_name: png_name});
}else if(jsonData.name !== undefined){
png_name = getPngName(jsonData.name);
var char = {"name": jsonData.name, "description": jsonData.description, "personality": jsonData.personality, "first_mes": jsonData.first_mes, "avatar": 'none', "chat": Date.now(), "mes_example": '', "scenario": '', "create_date": Date.now()};
char = JSON.stringify(char);
charaWrite('./public/img/fluffy.png', char, png_name, response, {file_name: png_name});
}else{
console.log('Incorrect character format .json');
response.send({error:true});
}
});
}else{
try{
var img_data = charaRead('./uploads/'+filedata.filename);
let jsonObject = JSON.parse(img_data);
png_name = getPngName(jsonObject.name);
if(jsonObject.name !== undefined){
fs.copyFile('./uploads/'+filedata.filename, 'public/characters/'+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.');
});
}
}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){
if(!request.body) return response.sendStatus(400);
var format = request.body.file_type;
let filedata = request.file;
let avatar_url = (request.body.avatar_url).replace('.png', '');
let ch_name = request.body.character_name;
//console.log(filedata.filename);
//var format = request.body.file_type;
//console.log(format);
//console.log(1);
if(filedata){
if(format === 'json'){
fs.readFile('./uploads/'+filedata.filename, 'utf8', (err, data) => {
if (err){
console.log(err);
response.send({error:true});
}
const jsonData = JSON.parse(data);
var new_chat = [];
if(jsonData.histories !== undefined){
let i = 0;
new_chat[i] = {};
new_chat[0]['user_name'] = 'You';
new_chat[0]['character_name'] = ch_name;
new_chat[0]['create_date'] = Date.now();
i++;
jsonData.histories.histories[0].msgs.forEach(function(item) {
new_chat[i] = {};
if(item.src.is_human == true){
new_chat[i]['name'] = 'You';
}else{
new_chat[i]['name'] = ch_name;
}
new_chat[i]['is_user'] = item.src.is_human;
new_chat[i]['is_name'] = true;
new_chat[i]['send_date'] = Date.now();
new_chat[i]['mes'] = item.text;
i++;
});
const chatJsonlData = new_chat.map(JSON.stringify).join('\n');
fs.writeFile('public/chats/'+avatar_url+'/'+Date.now()+'.jsonl', chatJsonlData, 'utf8', function(err) {
if(err) {
response.send(err);
return console.log(err);
//response.send(err);
}else{
//response.redirect("/");
response.send({res:true});
}
});
}else{
response.send({error:true});
return;
}
});
}
if(format === 'jsonl'){
const fileStream = fs.createReadStream('./uploads/'+filedata.filename);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
});
rl.once('line', (line) => {
let jsonData = JSON.parse(line);
if(jsonData.user_name !== undefined){
fs.copyFile('./uploads/'+filedata.filename, 'public/chats/'+avatar_url+'/'+Date.now()+'.jsonl', (err) => {
if(err) {
response.send({error:true});
return console.log(err);
}else{
response.send({res:true});
return;
}
});
}else{
//response.send({error:true});
return;
}
rl.close();
});
}
}
});
app.listen(server_port, function() {
if(process.env.colab !== undefined){
if(process.env.colab == 2){
is_colab = true;
}
}
console.log('Launching...');
open('http:127.0.0.1:'+server_port);
console.log('TavernAI started: http://127.0.0.1:'+server_port);
if (fs.existsSync('public/characters/update.txt')) { //&& !is_colab <- this need to put again
convertStage1();
}
});
//#####################CONVERTING IN NEW FORMAT########################
var charactersB = {};//B - Backup
var character_ib = 0;
var directoriesB = {};
function convertStage1(){
//if (!fs.existsSync('public/charactersBackup')) {
//fs.mkdirSync('public/charactersBackup');
//copyFolder('public/characters/', 'public/charactersBackup');
//}
var directories = getDirectories2("public/characters");
//console.log(directories[0]);
charactersB = {};
character_ib = 0;
var folderForDel = {};
getCharaterFile2(directories, 0);
}
function convertStage2(){
//directoriesB = JSON.parse(directoriesB);
//console.log(directoriesB);
var mes = true;
for (const key in directoriesB) {
if(mes){
console.log('***');
console.log('The update of the character format has begun...');
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 = Date.now();
charactersB[key] = JSON.stringify(char);
var avatar = 'public/img/fluffy.png';
if(char.avatar !== 'none'){
avatar = 'public/characters/'+char.name+'/avatars/'+char.avatar;
}
charaWrite(avatar, charactersB[key], directoriesB[key]);
const files = fs.readdirSync('public/characters/'+directoriesB[key]+'/chats');
if (!fs.existsSync('public/chats/'+char.name)) {
fs.mkdirSync('public/chats/'+char.name);
}
files.forEach(function(file) {
// Read the contents of the file
const fileContents = fs.readFileSync('public/characters/'+directoriesB[key]+'/chats/' + file, 'utf8');
// Iterate through the array of strings and parse each line as JSON
let chat_data = JSON.parse(fileContents);
let new_chat_data = [];
let this_chat_user_name = 'You';
let is_pass_0 = false;
if(chat_data[0].indexOf('') !== -1){
this_chat_user_name = chat_data[0].substr(''.length, chat_data[0].length);
is_pass_0 = true;
}
let i = 0;
let ii = 0;
new_chat_data[i] = {user_name:'You', character_name:char.name, create_date: Date.now()};
i++;
ii++;
chat_data.forEach(function(mes) {
if(!(i === 1 && is_pass_0)){
if(mes.indexOf('') === -1 && mes.indexOf('') === -1){
new_chat_data[ii] = {};
let is_name = false;
if(mes.trim().indexOf(this_chat_user_name+':') !== 0){
if(mes.trim().indexOf(char.name+':') === 0){
mes = mes.replace(char.name+':','');
is_name = true;
}
new_chat_data[ii]['name'] = char.name;
new_chat_data[ii]['is_user'] = false;
new_chat_data[ii]['is_name'] = is_name;
new_chat_data[ii]['send_date'] = Date.now();
}else{
mes = mes.replace(this_chat_user_name+':','');
new_chat_data[ii]['name'] = 'You';
new_chat_data[ii]['is_user'] = true;
new_chat_data[ii]['is_name'] = true;
new_chat_data[ii]['send_date'] = Date.now();
}
new_chat_data[ii]['mes'] = mes.trim();
ii++;
}
}
i++;
});
const jsonlData = new_chat_data.map(JSON.stringify).join('\n');
// Write the contents to the destination folder
fs.writeFileSync('public/chats/'+char.name+'/' + file+'l', jsonlData);
});
//fs.rmSync('public/characters/'+directoriesB[key],{ recursive: true });
console.log(char.name+' update!');
}
//removeFolders('public/characters');
fs.unlinkSync('public/characters/update.txt');
if(mes == false){
console.log('***');
console.log('Сharacter format update completed successfully!');
console.log('***');
console.log('Now you can delete these folders, they are no longer used by TavernAI:');
}
for (const key in directoriesB) {
console.log('public/characters/'+directoriesB[key]);
}
}
function removeFolders(folder) {
const files = fs.readdirSync(folder);
files.forEach(function(file) {
const filePath = folder + '/' + file;
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
removeFolders(filePath);
fs.rmdirSync(filePath);
}
});
}
function copyFolder(src, dest) {
const files = fs.readdirSync(src);
files.forEach(function(file) {
const filePath = src + '/' + file;
const stat = fs.statSync(filePath);
if (stat.isFile()) {
fs.copyFileSync(filePath, dest + '/' + file);
} else if (stat.isDirectory()) {
fs.mkdirSync(dest + '/' + file);
copyFolder(filePath, dest + '/' + file);
}
});
}
function getDirectories2(path) {
return fs.readdirSync(path)
.filter(function (file) {
return fs.statSync(path + '/' + file).isDirectory();
})
.sort(function (a, b) {
return new Date(fs.statSync(path + '/' + a).mtime) - new Date(fs.statSync(path + '/' + b).mtime);
})
.reverse();
}
function getCharaterFile2(directories,i){
if(directories.length > i){
fs.stat('public/characters/'+directories[i]+'/'+directories[i]+".json", function(err, stat) {
if (err == null) {
fs.readFile('public/characters/'+directories[i]+'/'+directories[i]+".json", 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
//console.log(data);
if (!fs.existsSync('public/characters/'+directories[i]+'.png')) {
charactersB[character_ib] = {};
charactersB[character_ib] = data;
directoriesB[character_ib] = directories[i];
character_ib++;
}
i++;
getCharaterFile2(directories,i);
});
}else{
i++;
getCharaterFile2(directories,i);
}
});
}else{
convertStage2();
}
}
/*
* async function aaa2(){
try {
// Load the image in any format
const image = await sharp('./original.jpg').resize(100, 100).toFormat('png');
image.metadata((err, metadata) => {
if (err) throw err;
if (!metadata.chunks) {
metadata.chunks = [];
}
const textData = text.encode('hello', 'world');
const textBuffer = Buffer.from(`${textData.keyword}\0${textData.text}`);
metadata.chunks.push({
type: 'tEXt',
data: textBuffer
});
return metadata;
})
.toFile('test-out.png')
.then(() => {
console.log('PNG image with tEXt chunks has been saved.');
})
.catch((err) => {
console.log(err);
});
} catch (err) {
console.log(err);
}
}
* function writePNG(){
const buffer = fs.readFileSync('test-out.png');
const chunks = extract(buffer);
const tEXtChunks = chunks.filter(chunk => chunk.name === 'tEXt');
// Remove all existing tEXt chunks
for (const tEXtChunk of tEXtChunks) {
chunks.splice(chunks.indexOf(tEXtChunk), 1);
}
// Add new chunks before the IEND chunk
chunks.splice(-1, 0, text.encode('hello', 'world'));
chunks.splice(-1, 0, text.encode('lorem', 'ipsum'));
fs.writeFileSync(
'test-out.png',
new Buffer.from(encode(chunks))
);
}
* function readPNG2(){
sharp('./test-out.png')
.metadata()
.then((metadata) => {
console.log(metadata);
if (!metadata.chunks) {
console.log("No tEXt chunks found in the image file");
}
const textChunks = metadata.chunks.filter((chunk) => chunk.type === 'tEXt');
textChunks.forEach((textChunk) => {
const textData = JSON.parse(textChunk.data.toString());
console.log(textData);
});
})
.catch((err) => {
console.log(err);
});
}
const requestListener = function (req, res) {
fs.readFile(__dirname + "/index.html")
.then(contents => {
res.setHeader("Content-Type", "text/html");
res.writeHead(200);
res.end(contents);
})
.catch(err => {
res.writeHead(500);
res.end(err);
return;
});
};
const server = http.createServer(requestListener);
server.listen(port, host, () => {
console.log(`Server is running on http://${host}:${port}`);
});
*/