mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
1294 lines
46 KiB
JavaScript
1294 lines
46 KiB
JavaScript
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("<h1>Главная страница</h1>");
|
||
});
|
||
app.get("/notes/*", function(request, response){
|
||
response.sendFile(__dirname + "/public"+request.url+".html");
|
||
//response.send("<h1>Главная страница</h1>");
|
||
});
|
||
//**************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('');
|
||
//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(170, 234).toFormat('png').toBuffer();
|
||
// 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]['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('TavernAI started: http://127.0.0.1:'+server_port);
|
||
open('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('<username-holder>') !== -1){
|
||
this_chat_user_name = chat_data[0].substr('<username-holder>'.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('<username-holder>') === -1 && mes.indexOf('<username-idkey>') === -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}`);
|
||
});
|
||
*/
|
||
|