From b856e2f566b6d37ddac64afe74a261cde57ac141 Mon Sep 17 00:00:00 2001 From: RossAsscends <124905043+RossAscends@users.noreply.github.com> Date: Fri, 3 Mar 2023 11:36:57 +0900 Subject: [PATCH 01/10] A little error-proofing to chat loading and history viewing 1. revised the new date format (reformatted to be a function so it would return new dates each time called) 2. re-added new date format functionality as I had previously rolled it back while debugging the avatar loading issues discovered in last push. 3. resolved some issues related to loading past chats for bots with no chat save files. Usually this wouldn't happen, as a new (or previous) chat is loaded each time the character is selected. But in cases where the files are deleted after being created, the chat history loading screen would remain in a 'loading.svg' loop. I added errorhandling to avoid this, and to kick GetAllCharaChats() from trying to read empty arrays. 4. increased potential size of past chats popup box --- public/index.html | 77 +++++++++++++++---------- public/style.css | 18 +++--- server.js | 139 ++++++++++++++++++++++++++-------------------- 3 files changed, 136 insertions(+), 98 deletions(-) diff --git a/public/index.html b/public/index.html index 8769e034b..52ce17239 100644 --- a/public/index.html +++ b/public/index.html @@ -61,15 +61,18 @@ //New chats made with characters will use this new formatting. //Useable variable is (( humanizedISO8601Datetime )) - var baseDate = new Date(Date.now()); - var humanYear = baseDate.getFullYear(); - var humanMonth = (baseDate.getMonth()+1); - var humanDate = baseDate.getDate(); - var humanHour = (baseDate.getHours() < 10? '0' : '') + baseDate.getHours(); - var humanMinute = (baseDate.getMinutes() < 10? '0' : '') + baseDate.getMinutes(); - var humanSecond = (baseDate.getSeconds() < 10? '0' : '') + baseDate.getSeconds(); - var humanMillisecond = (baseDate.getMilliseconds() < 10? '0' : '') + baseDate.getMilliseconds(); - var humanizedISO8601DateTime = (humanYear+"-"+humanMonth+"-"+humanDate+" @"+humanHour+"h "+humanMinute+"m "+humanSecond+"s "+humanMillisecond+"ms"); + function humanizedISO8601DateTime() { + let baseDate = new Date(Date.now()); + let humanYear = baseDate.getFullYear(); + let humanMonth = (baseDate.getMonth()+1); + let humanDate = baseDate.getDate(); + let humanHour = (baseDate.getHours() < 10? '0' : '') + baseDate.getHours(); + let humanMinute = (baseDate.getMinutes() < 10? '0' : '') + baseDate.getMinutes(); + let humanSecond = (baseDate.getSeconds() < 10? '0' : '') + baseDate.getSeconds(); + let humanMillisecond = (baseDate.getMilliseconds() < 10? '0' : '') + baseDate.getMilliseconds(); + let HumanizedDateTime = (humanYear+"-"+humanMonth+"-"+humanDate+" @"+humanHour+"h "+humanMinute+"m "+humanSecond+"s "+humanMillisecond+"ms"); + return HumanizedDateTime; + }; var default_ch_mes = "Hello"; @@ -673,7 +676,7 @@ chat[chat.length-1]['name'] = name1; chat[chat.length-1]['is_user'] = true; chat[chat.length-1]['is_name'] = true; - chat[chat.length-1]['send_date'] = Date.now(); + chat[chat.length-1]['send_date'] = humanizedISO8601DateTime(); chat[chat.length-1]['mes'] = textareaText; addOneMessage(chat[chat.length-1]); } @@ -1090,12 +1093,13 @@ chat[chat.length-1]['name'] = name2; chat[chat.length-1]['is_user'] = false; chat[chat.length-1]['is_name'] = this_mes_is_name; - chat[chat.length-1]['send_date'] = Date.now(); + chat[chat.length-1]['send_date'] = humanizedISO8601DateTime(); getMessage = $.trim(getMessage); chat[chat.length-1]['mes'] = getMessage; addOneMessage(chat[chat.length-1]); $( "#send_but" ).css("display", "inline"); $( "#loading_mes" ).css("display", "none"); +console.log('/savechat called by /Generate'); saveChat(); }else{ //console.log('run force_name2 protocol'); @@ -1157,6 +1161,7 @@ }); } async function getChat() { +console.log('/getChat entered'); //console.log(characters[this_chid].chat); jQuery.ajax({ type: 'POST', @@ -1177,13 +1182,16 @@ } //chat = data; chat_create_date = chat[0]['create_date']; +console.log('/getchat saw chat_create_date: '+chat_create_date); chat.shift(); }else{ - chat_create_date = Date.now(); + chat_create_date = humanizedISO8601DateTime(); } //console.log(chat); +console.log('getChatResults called by /getchat'); getChatResult(); +console.log('savechat called by /getchat'); saveChat(); }, error: function (jqXHR, exception) { @@ -1213,7 +1221,7 @@ chat[0]['name'] = name2; chat[0]['is_user'] = false; chat[0]['is_name'] = true; - chat[0]['send_date'] = Date.now(); + chat[0]['send_date'] = humanizedISO8601DateTime(); if(characters[this_chid].first_mes != ""){ chat[0]['mes'] = characters[this_chid].first_mes; }else{ @@ -1582,11 +1590,11 @@ } }); } + //Make a new chat for selected character if(popup_type == 'new_chat' && this_chid != undefined && menu_type != "create"){//Fix it; New chat doesn't create while open create character menu clearChat(); chat.length = 0; - characters[this_chid].chat = Date.now(); //RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedISO8601DateTime; - //characters[this_chid].chat = (name2 +' - '+ humanizedISO8601DateTime); //RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedISO8601DateTime; + characters[this_chid].chat = (name2 +' - '+ humanizedISO8601DateTime()); //RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedISO8601DateTime; $("#selected_chat_pole").val(characters[this_chid].chat); timerSaveEdit = setTimeout(() => {$("#create_button").click();},durationSaveEdit); getChat(); @@ -1720,7 +1728,8 @@ if($("#form_create").attr("actiontype") == "createcharacter"){ if($("#character_name_pole").val().length > 0){ - +console.log('/createcharacter entered'); +console.log('CharCreate formData: '+formData); jQuery.ajax({ type: 'POST', url: '/createcharacter', @@ -1763,7 +1772,7 @@ select_rm_info("Character created"); $('#rm_info_block').transition({ opacity: 1.0 ,duration: 2000}); - +console.log('/getcharacters called after /createchracter'); getCharacters(); }else{ $('#result_info').html(html); @@ -1777,7 +1786,7 @@ $('#result_info').html("Name not entered"); } }else{ - console.log($("#add_avatar_button").val()); +console.log('Avatar Button Value:'+$("#add_avatar_button").val()); jQuery.ajax({ type: 'POST', @@ -2576,6 +2585,7 @@ }); //Select chat async function getAllCharaChats() { + console.log('entered getAllCharaChats'); $('#select_chat_div').html(''); //console.log(characters[this_chid].chat); jQuery.ajax({ @@ -2591,20 +2601,24 @@ success: function(data){ $('#load_select_chat_div').css('display', 'none'); let dataArr = Object.values(data); + console.log('dataArr = '+ Object.values(data)); data = dataArr.sort((a, b) => a['file_name'].localeCompare(b['file_name'])); data = data.reverse(); + for (const key in data) { let strlen = 40; let mes = data[key]['mes']; - if(mes.length > strlen){ - mes = '...'+mes.substring(mes.length - strlen); - } - $('#select_chat_div').append('
'+data[key]['file_name']+'
'+mes+'
'); - if(characters[this_chid]['chat'] == data[key]['file_name'].replace('.jsonl', '')){ - //children().last() - $('#select_chat_div').children(':nth-last-child(1)').attr('highlight', true); - } - } + if(mes !== undefined){ + if(mes.length > strlen){ + mes = '...'+mes.substring(mes.length - strlen); + } + $('#select_chat_div').append('
'+data[key]['file_name']+'
'+mes+'
'); + if(characters[this_chid]['chat'] == data[key]['file_name'].replace('.jsonl', '')){ + //children().last() + $('#select_chat_div').children(':nth-last-child(1)').attr('highlight', true); + } + } + } //
//
@@ -2614,11 +2628,14 @@ //chat = data; //getChatResult(); //saveChat(); - }, + console.log('Finished getAllCharaChats successfully'); + }, error: function (jqXHR, exception) { //getChatResult(); - console.log(exception); + console.log('Failed to Finished getAllCharaChats'); + console.log(exception); console.log(jqXHR); + } }); } @@ -2816,7 +2833,7 @@ $("#chat_import_file_type").val(format); //console.log(format); var formData = new FormData($("#form_import_chat").get(0)); - +console.log('/importchat entered with: '+formData); jQuery.ajax({ type: 'POST', url: '/importchat', diff --git a/public/style.css b/public/style.css index fdca52129..8827130f6 100644 --- a/public/style.css +++ b/public/style.css @@ -1589,19 +1589,22 @@ label.checkbox :checked + span:after { #select_chat_popup{ display: block; grid-template-rows: 50px 100px 100px auto 45px; - max-width:800px; - height: 440px; + max-width: 800px; + max-height: 80vh; + height: min-content; position: absolute; z-index: 2066; margin-left: auto; margin-right: auto; left: 0; right: 0; - margin-top: 21vh; - box-shadow: 0 0 10px rgba(0,0,0,0.5); - padding: 4px; - background-color: rgba(0,0,0,0.7); + margin-top: 6vh; + box-shadow: 0 0 10px rgb(0 0 0 / 50%); + padding: 10px; + /* padding-top: 50px; */ + background-color: rgba(0,0,0,0.7); border-radius: 20px; + overflow-y: auto; } #select_chat_popup a{ color: #936f4a; @@ -1633,7 +1636,8 @@ label.checkbox :checked + span:after { overflow-x: hidden; overflow-y: scroll; - height: 350px; + height: min-content; + max-height:100%; } #select_chat_div hr{ margin:0; diff --git a/server.js b/server.js index cbf6caf0b..fdd37899c 100644 --- a/server.js +++ b/server.js @@ -58,16 +58,20 @@ var api_key_novel; //New chats made with characters will use this new formatting. //Useable variable is (( humanizedISO8601Datetime )) - var baseDate = new Date(Date.now()); - var humanYear = baseDate.getFullYear(); - var humanMonth = (baseDate.getMonth()+1); - var humanDate = baseDate.getDate(); - var humanHour = (baseDate.getHours() < 10? '0' : '') + baseDate.getHours(); - var humanMinute = (baseDate.getMinutes() < 10? '0' : '') + baseDate.getMinutes(); - var humanSecond = (baseDate.getSeconds() < 10? '0' : '') + baseDate.getSeconds(); - var humanMillisecond = (baseDate.getMilliseconds() < 10? '0' : '') + baseDate.getMilliseconds(); - var humanizedISO8601DateTime = (humanYear+"-"+humanMonth+"-"+humanDate+" @"+humanHour+"h "+humanMinute+"m "+humanSecond+"s "+humanMillisecond+"ms"); + + function humanizedISO8601DateTime() { + let baseDate = new Date(Date.now()); + let humanYear = baseDate.getFullYear(); + let humanMonth = (baseDate.getMonth()+1); + let humanDate = baseDate.getDate(); + let humanHour = (baseDate.getHours() < 10? '0' : '') + baseDate.getHours(); + let humanMinute = (baseDate.getMinutes() < 10? '0' : '') + baseDate.getMinutes(); + let humanSecond = (baseDate.getSeconds() < 10? '0' : '') + baseDate.getSeconds(); + let humanMillisecond = (baseDate.getMilliseconds() < 10? '0' : '') + baseDate.getMilliseconds(); + let HumanizedDateTime = (humanYear+"-"+humanMonth+"-"+humanDate+" @"+humanHour+"h "+humanMinute+"m "+humanSecond+"s "+humanMillisecond+"ms"); + return HumanizedDateTime; + }; var is_colab = false; var charactersPath = 'public/characters/'; @@ -281,7 +285,7 @@ app.post("/generate", jsonParser, function(request, response_generate = response }); }); app.post("/savechat", jsonParser, function(request, response){ - //console.log('/savechat/ entered'); +console.log(humanizedISO8601DateTime()+':/savechat/ entered'); //console.log(request.data); //console.log(request.body.bg); //const data = request.body; @@ -289,8 +293,10 @@ app.post("/savechat", jsonParser, function(request, response){ //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',''); +console.log(humanizedISO8601DateTime()+':/savechat sees '+dir_name+' as the character name (derived from avatar PNG filename)'); let chat_data = request.body.chat; let jsonlData = chat_data.map(JSON.stringify).join('\n'); +console.log(humanizedISO8601DateTime()+':/savechat saving a chat named '+request.body.file_name+'.jsonl'); fs.writeFile(chatsPath+dir_name+"/"+request.body.file_name+'.jsonl', jsonlData, 'utf8', function(err) { if(err) { response.send(err); @@ -310,7 +316,7 @@ app.post("/getchat", jsonParser, function(request, response){ //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+");}"; - //console.log('/getchat entered'); +console.log(humanizedISO8601DateTime()+':/getchat entered'); var dir_name = String(request.body.avatar_url).replace('.png',''); fs.stat(chatsPath+dir_name, function(err, stat) { @@ -327,7 +333,7 @@ app.post("/getchat", jsonParser, function(request, response){ fs.stat(chatsPath+dir_name+"/"+request.body.file_name+".jsonl", function(err, stat) { if (err === null) { //if no error (the file exists), read the file - +console.log(humanizedISO8601DateTime()+':/getchat tries to access: '+chatsPath+dir_name+'/'+request.body.file_name+'.jsonl'); if(stat !== undefined){ fs.readFile(chatsPath+dir_name+"/"+request.body.file_name+".jsonl", 'utf8', (err, data) => { if (err) { @@ -355,11 +361,8 @@ app.post("/getchat", jsonParser, function(request, response){ console.error(err); response.send({}); return; - } } - - }); @@ -415,7 +418,7 @@ function checkServer(){ //***************** 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()}; + var char = {"name": data.ch_name, "description": data.description, "personality": data.personality, "first_mes": data.first_mes, "avatar": 'none', "chat": data.ch_name+' - '+humanizedISO8601DateTime(), "mes_example": data.mes_example, "scenario": data.scenario, "create_date": humanizedISO8601DateTime}; return char; } app.post("/createcharacter", urlencodedParser, function(request, response){ @@ -911,12 +914,14 @@ app.post("/getallchatsofcharacter", jsonParser, function(request, response){ var char_dir = (request.body.avatar_url).replace('.png','') fs.readdir(chatsPath+char_dir, (err, files) => { if (err) { + console.log('found error in history loading'); console.error(err); response.send({error: true}); return; } // filter for JSON files + console.log('looking for JSONL files'); const jsonFiles = files.filter(file => path.extname(file) === '.jsonl'); // sort the files by name @@ -924,41 +929,46 @@ app.post("/getallchatsofcharacter", jsonParser, function(request, response){ // print the sorted file names var chatData = {}; let ii = jsonFiles.length; //this is the number of files belonging to the character - - for(let i = jsonFiles.length-1; i >= 0; i--){ - const file = jsonFiles[i]; + if (ii !== 0) { + console.log('found '+ii+' chat logs to load'); + for(let i = jsonFiles.length-1; i >= 0; i--){ + const file = jsonFiles[i]; + const fileStream = fs.createReadStream(chatsPath+char_dir+'/'+file); + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); - const fileStream = fs.createReadStream(chatsPath+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(); - }); - } - }); - -}); + 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){ + console.log('ii count went to zero, responding with chatData'); + response.send(chatData); + } + }else{ + console.log('just returning from getallchatsofcharacter'); + return; + } + } + console.log('successfully closing getallchatsofcharacter'); + rl.close(); + }); + }; + }else{ + console.log('Found No Chats. Exiting Load Routine.'); + response.send({error: true}); + }; + })}); function getPngName(file){ let i = 1; let base_name = file; @@ -969,6 +979,7 @@ function getPngName(file){ return file; } app.post("/importcharacter", urlencodedParser, function(request, response){ + if(!request.body) return response.sendStatus(400); let png_name = ''; @@ -987,12 +998,12 @@ app.post("/importcharacter", urlencodedParser, function(request, response){ if(jsonData.name !== undefined){ png_name = getPngName(jsonData.name); - let char = {"name": jsonData.name, "description": jsonData.description ?? '', "personality": jsonData.personality ?? '', "first_mes": jsonData.first_mes ?? '', "avatar": 'none', "chat": Date.now(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": Date.now()}; + 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}; char = JSON.stringify(char); charaWrite('./public/img/fluffy.png', char, png_name, response, {file_name: png_name}); }else if(jsonData.char_name !== undefined){//json Pygmalion notepad png_name = getPngName(jsonData.char_name); - let 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()}; + let char = {"name": jsonData.char_name, "description": jsonData.char_persona ?? '', "personality": '', "first_mes": jsonData.char_greeting ?? '', "avatar": 'none', "chat": humanizedISO8601DateTime(), "mes_example": jsonData.example_dialogue ?? '', "scenario": jsonData.world_scenario ?? '', "create_date": humanizedISO8601DateTime}; char = JSON.stringify(char); charaWrite('./public/img/fluffy.png', char, png_name, response, {file_name: png_name}); }else{ @@ -1008,7 +1019,7 @@ app.post("/importcharacter", urlencodedParser, function(request, response){ 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": Date.now(), "mes_example": jsonData.mes_example ?? '', "scenario": jsonData.scenario ?? '', "create_date": Date.now()}; + 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}; char = JSON.stringify(char); charaWrite('./uploads/'+filedata.filename, char, png_name, response, {file_name: png_name}); /* @@ -1040,6 +1051,7 @@ app.post("/importcharacter", urlencodedParser, function(request, response){ }); app.post("/importchat", urlencodedParser, function(request, response){ +console.log(humanizedISO8601DateTime()+':/importchat begun'); if(!request.body) return response.sendStatus(400); var format = request.body.file_type; @@ -1063,11 +1075,12 @@ app.post("/importchat", urlencodedParser, function(request, response){ const jsonData = JSON.parse(data); var new_chat = []; if(jsonData.histories !== undefined){ +console.log('/importchat confirms JSON histories are defined'); 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() //Date.now(); + new_chat[0]['create_date'] = humanizedISO8601DateTime() //Date.now(); i++; jsonData.histories.histories[0].msgs.forEach(function(item) { new_chat[i] = {}; @@ -1078,12 +1091,13 @@ app.post("/importchat", urlencodedParser, function(request, response){ } new_chat[i]['is_user'] = item.src.is_human; new_chat[i]['is_name'] = true; - new_chat[i]['send_date'] = Date.now() //Date.now(); + new_chat[i]['send_date'] = humanizedISO8601DateTime() //Date.now(); new_chat[i]['mes'] = item.text; i++; }); const chatJsonlData = new_chat.map(JSON.stringify).join('\n'); - fs.writeFile(chatsPath+avatar_url+'/'+ch_name+' - '+humanizedISO8601DateTime+' imported.jsonl', chatJsonlData, 'utf8', function(err) { //added ch_name and replaced Date.now() with humanizedISO8601DateTime +console.log('/importchat saving a file: '+ch_name+' - '+humanizedISO8601DateTime()+' imported.jsonl'); + fs.writeFile(chatsPath+avatar_url+'/'+ch_name+' - '+humanizedISO8601DateTime()+' imported.jsonl', chatJsonlData, 'utf8', function(err) { //added ch_name and replaced Date.now() with humanizedISO8601DateTime if(err) { response.send(err); @@ -1103,6 +1117,7 @@ app.post("/importchat", urlencodedParser, function(request, response){ }); } if(format === 'jsonl'){ +console.log(humanizedISO8601DateTime()+':imported chat format is JSONL'); const fileStream = fs.createReadStream('./uploads/'+filedata.filename); const rl = readline.createInterface({ input: fileStream, @@ -1113,7 +1128,8 @@ app.post("/importchat", urlencodedParser, function(request, response){ let jsonData = JSON.parse(line); if(jsonData.user_name !== undefined){ - fs.copyFile('./uploads/'+filedata.filename, chatsPath+avatar_url+'/'+ch_name+' - '+humanizedISO8601DateTime+'.jsonl', (err) => { //added character name and replaced Date.now() with humanizedISO8601DateTime +console.log(humanizedISO8601DateTime()+':/importchat copying chat as '+ch_name+' - '+humanizedISO8601DateTime()+'.jsonl'); + fs.copyFile('./uploads/'+filedata.filename, chatsPath+avatar_url+'/'+ch_name+' - '+humanizedISO8601DateTime()+'.jsonl', (err) => { //added character name and replaced Date.now() with humanizedISO8601DateTime if(err) { response.send({error:true}); return console.log(err); @@ -1192,7 +1208,7 @@ function convertStage2(){ //console.log(directoriesB[key]); var char = JSON.parse(charactersB[key]); - char.create_date = Date.now(); + char.create_date = humanizedISO8601DateTime(); charactersB[key] = JSON.stringify(char); var avatar = 'public/img/fluffy.png'; if(char.avatar !== 'none'){ @@ -1222,7 +1238,7 @@ function convertStage2(){ } let i = 0; let ii = 0; - new_chat_data[i] = {user_name:'You', character_name:char.name, create_date: Date.now()}; + new_chat_data[i] = {user_name:'You', character_name:char.name, create_date: humanizedISO8601DateTime()}; i++; ii++; chat_data.forEach(function(mes) { @@ -1238,14 +1254,14 @@ function convertStage2(){ 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(); //Date.now(); + new_chat_data[ii]['send_date'] = humanizedISO8601DateTime(); //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() //Date.now(); + new_chat_data[ii]['send_date'] = humanizedISO8601DateTime(); //Date.now(); } new_chat_data[ii]['mes'] = mes.trim(); @@ -1257,6 +1273,7 @@ function convertStage2(){ }); const jsonlData = new_chat_data.map(JSON.stringify).join('\n'); // Write the contents to the destination folder +console.log('convertstage2 writing a file: '+chatsPath+char.name+'/' + file+'l'); fs.writeFileSync(chatsPath+char.name+'/' + file+'l', jsonlData); }); //fs.rmSync('public/characters/'+directoriesB[key],{ recursive: true }); From eb30b84bff8fb3d6a4b3a81e1a51eacc482d3cb9 Mon Sep 17 00:00:00 2001 From: RossAsscends <124905043+RossAscends@users.noreply.github.com> Date: Fri, 3 Mar 2023 11:44:11 +0900 Subject: [PATCH 02/10] Update style.css --- public/style.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/style.css b/public/style.css index 8827130f6..d64b1d562 100644 --- a/public/style.css +++ b/public/style.css @@ -1590,8 +1590,8 @@ label.checkbox :checked + span:after { display: block; grid-template-rows: 50px 100px 100px auto 45px; max-width: 800px; - max-height: 80vh; - height: min-content; + max-height: 70vh; + min-height: 100px; position: absolute; z-index: 2066; margin-left: auto; @@ -1604,7 +1604,7 @@ label.checkbox :checked + span:after { /* padding-top: 50px; */ background-color: rgba(0,0,0,0.7); border-radius: 20px; - overflow-y: auto; + overflow-y: scroll; } #select_chat_popup a{ color: #936f4a; From 7ce52046fd076e22405d2e2893e8b5085cf3329d Mon Sep 17 00:00:00 2001 From: RossAsscends <124905043+RossAscends@users.noreply.github.com> Date: Sat, 4 Mar 2023 04:00:40 +0900 Subject: [PATCH 03/10] New toggle features: Auto-Connect & Auto-Load-Chat 1. new function - Auto-connect to API 2. new function - Auto-load last character/chat Both of these have toggles in the right menu at the bottom in a "Power user options" section. Both only load if settings.json has a pre-defined setting for them. (won't fire on first load after install) --- public/User Avatars/you1.png | Bin 2930 -> 0 bytes public/index.html | 159 +++++++++++++++++++++++++---------- public/style.css | 22 +++-- server.js | 26 +++--- 4 files changed, 142 insertions(+), 65 deletions(-) delete mode 100644 public/User Avatars/you1.png diff --git a/public/User Avatars/you1.png b/public/User Avatars/you1.png deleted file mode 100644 index e241153a433d82c49cb18450b0da1dbf89631fe0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2930 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 diff --git a/public/index.html b/public/index.html index 52ce17239..d76f7e2c3 100644 --- a/public/index.html +++ b/public/index.html @@ -81,6 +81,7 @@ var generatedPromtCache = ''; var characters = []; var this_chid; + var active_character; var backgrounds = []; var default_avatar = 'img/fluffy.png'; var is_colab = false; @@ -150,6 +151,8 @@ var anchor_order = 0; var style_anchor = true; var character_anchor = true; + var auto_connect = false; + var auto_load_chat = false; var main_api = 'kobold'; //novel settings @@ -201,18 +204,20 @@ $.get("/csrf-token") .then(data => { token = data.token; + getCharacters(); getSettings("def"); getLastVersion(); - getCharacters(); - + //getCharacters(); printMessages(); getBackgrounds(); getUserAvatars(); + }); + - $('#characloud_url').click(function(){ - window.open('https://boosty.to/tavernai', '_blank'); - }); + $('#characloud_url').click(function(){ + window.open('https://boosty.to/tavernai', '_blank'); + }); function checkOnlineStatus(){ //console.log(online_status); if(online_status == 'no_connection'){ @@ -341,7 +346,7 @@ this_avatar = "characters/"+item.avatar+"#"+Date.now(); } - $("#rm_print_characters_block").prepend('
'+item.name+'
'); + $("#rm_print_characters_block").prepend('
'+item.name+'
'); //console.log(item.name); }); @@ -1099,7 +1104,7 @@ addOneMessage(chat[chat.length-1]); $( "#send_but" ).css("display", "inline"); $( "#loading_mes" ).css("display", "none"); -console.log('/savechat called by /Generate'); +//console.log('/savechat called by /Generate'); saveChat(); }else{ //console.log('run force_name2 protocol'); @@ -1161,7 +1166,7 @@ console.log('/savechat called by /Generate'); }); } async function getChat() { -console.log('/getChat entered'); +//console.log('/getChat entered'); //console.log(characters[this_chid].chat); jQuery.ajax({ type: 'POST', @@ -1182,16 +1187,16 @@ console.log('/getChat entered'); } //chat = data; chat_create_date = chat[0]['create_date']; -console.log('/getchat saw chat_create_date: '+chat_create_date); +//console.log('/getchat saw chat_create_date: '+chat_create_date); chat.shift(); }else{ chat_create_date = humanizedISO8601DateTime(); } //console.log(chat); -console.log('getChatResults called by /getchat'); +//console.log('getChatResults called by /getchat'); getChatResult(); -console.log('savechat called by /getchat'); +//console.log('savechat called by /getchat'); saveChat(); }, error: function (jqXHR, exception) { @@ -1388,12 +1393,13 @@ console.log('savechat called by /getchat'); } function select_selected_character(chid){ //character select - + //console.log('select_selected_character() -- starting with input of -- '+chid+' (name:'+characters[chid].name+')'); select_rm_create(); menu_type = 'character_edit'; $( "#delete_button_div" ).css("display", "block"); $( "#rm_button_selected_ch" ).css("class","selected-right-tab"); var display_name = characters[chid].name; + $( "#rm_button_selected_ch" ).children("h2").text(display_name); @@ -1432,6 +1438,10 @@ console.log('savechat called by /getchat'); $("#name_div").css("display", "none"); $("#form_create").attr("actiontype", "editcharacter"); + active_character = chid; + //console.log('select_selected_character() -- active_character -- '+chid+'(ChID of '+display_name+')'); + saveSettings(); + //console.log('select_selected_character() -- called saveSettings() to save -- active_character -- '+active_character+'(ChID of '+display_name+')'); } $(document).on('click', '.character_select', function(){ if(this_chid !== $(this).attr("chid")){ @@ -1441,8 +1451,7 @@ console.log('savechat called by /getchat'); this_chid = $(this).attr("chid"); clearChat(); chat.length = 0; - getChat(); - + getChat(); } }else{ selected_button = 'character_edit'; @@ -1728,8 +1737,7 @@ console.log('savechat called by /getchat'); if($("#form_create").attr("actiontype") == "createcharacter"){ if($("#character_name_pole").val().length > 0){ -console.log('/createcharacter entered'); -console.log('CharCreate formData: '+formData); +//console.log('/createcharacter entered'); jQuery.ajax({ type: 'POST', url: '/createcharacter', @@ -1772,7 +1780,7 @@ console.log('CharCreate formData: '+formData); select_rm_info("Character created"); $('#rm_info_block').transition({ opacity: 1.0 ,duration: 2000}); -console.log('/getcharacters called after /createchracter'); +//console.log('/getcharacters called after /createchracter'); getCharacters(); }else{ $('#result_info').html(html); @@ -1786,7 +1794,7 @@ console.log('/getcharacters called after /createchracter'); $('#result_info').html("Name not entered"); } }else{ -console.log('Avatar Button Value:'+$("#add_avatar_button").val()); +//console.log('Avatar Button Value:'+$("#add_avatar_button").val()); jQuery.ajax({ type: 'POST', @@ -2191,6 +2199,16 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); character_anchor = !!$('#character_anchor').prop('checked'); saveSettings(); }); + + $('#auto-connect-checkbox').change(function() { + auto_connect = !!$('#auto-connect-checkbox').prop('checked'); + saveSettings(); + }); + $('#auto-load-chat-checkbox').change(function() { + auto_load_chat = !!$('#auto-load-chat-checkbox').prop('checked'); + saveSettings(); + }); + $(document).on('input', '#rep_pen', function() { rep_pen = $(this).val(); if(isInt(rep_pen)){ @@ -2235,7 +2253,7 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); /////////////////////////////////////////// async function getSettings(type){//timer - + //console.log('getSettings() pinging server for settings request'); jQuery.ajax({ type: 'POST', url: '/getsettings', @@ -2249,33 +2267,36 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); contentType: "application/json", //processData: false, success: function(data){ +// console.log('processing loaded settings'); if(data.result != 'file not find'){ +// console.log('getSettings() -- settings file found'); settings = JSON.parse(data.settings); if(settings.username !== undefined){ +// console.log('getSettings() -- Username -- '+settings.username); if(settings.username !== ''){ name1 = settings.username; $('#your_name').val(name1); } } - - - //Novel + + //Load which API we are using if(settings.main_api != undefined){ main_api = settings.main_api; $("#main_api option[value="+main_api+"]").attr('selected', 'true'); changeMainAPI(); } + //load Novel API KEY is exists if(settings.api_key_novel != undefined){ api_key_novel = settings.api_key_novel; $("#api_key_novel").val(api_key_novel); } + //load the rest of the Novel settings without any checks model_novel = settings.model_novel; $("#model_novel_select option[value="+model_novel+"]").attr('selected', 'true'); novelai_setting_names = data.novelai_setting_names; novelai_settings = data.novelai_settings; novelai_settings.forEach(function(item, i, arr) { - novelai_settings[i] = JSON.parse(item); }); var arr_holder = {}; @@ -2290,7 +2311,8 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); preset_settings_novel = settings.preset_settings_novel; $("#settings_perset_novel option[value="+novelai_setting_names[preset_settings_novel]+"]").attr('selected', 'true'); - //Kobold + + //Load KoboldAI settings koboldai_setting_names = data.koboldai_setting_names; koboldai_settings = data.koboldai_settings; koboldai_settings.forEach(function(item, i, arr) { @@ -2307,13 +2329,19 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); koboldai_setting_names = arr_holder; preset_settings = settings.preset_settings; - + + //Load AI model config settings (temp, context length, anchors, and anchor order) temp = settings.temp; amount_gen = settings.amount_gen; if(settings.max_context !== undefined) max_context = parseInt(settings.max_context); if(settings.anchor_order !== undefined) anchor_order = parseInt(settings.anchor_order); if(settings.style_anchor !== undefined) style_anchor = !!settings.style_anchor; if(settings.character_anchor !== undefined) character_anchor = !!settings.character_anchor; + + //load poweruser options + if(settings.auto_connect !== undefined) auto_connect = !!settings.auto_connect; + if(settings.auto_load_chat !== undefined) auto_load_chat = !!settings.auto_load_chat; + rep_pen = settings.rep_pen; rep_pen_size = settings.rep_pen_size; @@ -2327,6 +2355,9 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); $('#character_anchor').prop('checked', character_anchor); $("#anchor_order option[value="+anchor_order+"]").attr('selected', 'true'); + $('#auto-connect-checkbox').prop('checked', auto_connect); + $('#auto-load-chat-checkbox').prop('checked', auto_load_chat); + $('#max_context').val(max_context); $('#max_context_counter').html(max_context+' Tokens'); @@ -2360,7 +2391,7 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); $('#rep_pen_size_novel').val(rep_pen_size_novel); $('#rep_pen_size_counter_novel').html(rep_pen_size_novel+" Tokens"); - ////////////////////// + //Enable GUI deference settings if GUI is selected for Kobold if(preset_settings == 'gui'){ $("#settings_perset option[value=gui]").attr('selected', 'true'); $("#range_block").children().prop("disabled", true); @@ -2384,17 +2415,36 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); } - //User + //Load User's Name and Avatar user_avatar = settings.user_avatar; $('.mes').each(function(){ if($(this).attr('ch_name') == name1){ $(this).children('.avatar').children('img').attr('src', 'User Avatars/'+user_avatar); } }); - + + //Load the API server URL from settings api_server = settings.api_server; $('#api_url_text').val(api_server); + + //RossAscends: auto-connect to last API function (fires when API URL exists in settings and auto_connect is true) + if(api_server !== ''&& auto_connect == true){ + $('#api_button').click(); + } } + + //RossAscends: auto-load last character function (fires when active_character is defined and auto_load_chat is true) + if(settings.active_character !== undefined){ + //console.log('getSettings() -- active_character -- '+settings.active_character); + if(settings.active_character !== ''){ + active_character = settings.active_character; + //console.log('getSettings() -- auto_load_chat -- '+auto_load_chat); + if (auto_load_chat == true){ + //console.log('getSettings() - trying to click .character_select div with ID #CharID'+active_character); + $('#CharID'+active_character).click(); //will auto-select and load chat of last selected character is auto_load_chat is true + } + } + } if(!is_checked_colab) isColab(); }, @@ -2408,7 +2458,7 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); } async function saveSettings(type){ - +//console.log('saveSettings() -- pinging server to save settings.'); jQuery.ajax({ type: 'POST', url: '/savesettings', @@ -2424,6 +2474,8 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); anchor_order: anchor_order, style_anchor: style_anchor, character_anchor: character_anchor, + auto_connect: auto_connect, + auto_load_chat: auto_load_chat, main_api: main_api, api_key_novel: api_key_novel, rep_pen: rep_pen, @@ -2431,10 +2483,11 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); model_novel: model_novel, temp_novel: temp_novel, rep_pen_novel: rep_pen_novel, - rep_pen_size_novel: rep_pen_size_novel + rep_pen_size_novel: rep_pen_size_novel, + active_character: active_character                  }), beforeSend: function(){ - +//console.log('saveSettings() -- active_character -- '+active_character); }, cache: false, @@ -2578,14 +2631,14 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); if(!is_send_press){ name1 = $("#your_name").val(); if(name1 === undefined || name1 == '') name1 = default_user_name; - console.log(name1); + //console.log(name1); saveSettings('change_name'); } }); //Select chat async function getAllCharaChats() { - console.log('entered getAllCharaChats'); + //console.log('getAllCharaChats() pinging server for character chat history.'); $('#select_chat_div').html(''); //console.log(characters[this_chid].chat); jQuery.ajax({ @@ -2601,12 +2654,11 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); success: function(data){ $('#load_select_chat_div').css('display', 'none'); let dataArr = Object.values(data); - console.log('dataArr = '+ Object.values(data)); data = dataArr.sort((a, b) => a['file_name'].localeCompare(b['file_name'])); data = data.reverse(); for (const key in data) { - let strlen = 40; + let strlen = 300; let mes = data[key]['mes']; if(mes !== undefined){ if(mes.length > strlen){ @@ -2628,11 +2680,11 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); //chat = data; //getChatResult(); //saveChat(); - console.log('Finished getAllCharaChats successfully'); + //console.log('getAllCharaChats() -- Finished successfully'); }, error: function (jqXHR, exception) { //getChatResult(); - console.log('Failed to Finished getAllCharaChats'); + //console.log('getAllCharaChats() -- Failed'); console.log(exception); console.log(jqXHR); @@ -2833,7 +2885,7 @@ console.log('Avatar Button Value:'+$("#add_avatar_button").val()); $("#chat_import_file_type").val(format); //console.log(format); var formData = new FormData($("#form_import_chat").get(0)); -console.log('/importchat entered with: '+formData); +//console.log('/importchat entered with: '+formData); jQuery.ajax({ type: 'POST', url: '/importchat', @@ -3132,7 +3184,7 @@ console.log('/importchat entered with: '+formData);
-
+

Your Avatar

@@ -3143,17 +3195,23 @@ console.log('/importchat entered with: '+formData);
-
-

Pro Settings

+ +
+

Pro Settings

+
-

Amount generation

select
- +

Amount generation

+
select
+
-

Context Size

select
+

Context Size

+
select
-

Anchors Order

Helps to increase the length of messages (?)
+ +

Anchors Order

+
Helps to increase the length of messages (?)

Character Anchor

Style Anchor

+
+
+ +
+

Power User Options

+
+

Auto-connects Last Server

+

Auto-load Last Chat

+
+ + - + +
@@ -3291,5 +3326,8 @@
+ + + diff --git a/public/style.css b/public/style.css index 932b67c0d..7235f562d 100644 --- a/public/style.css +++ b/public/style.css @@ -4,7 +4,7 @@ box-sizing: border-box; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - -moz-appearance:initial + -moz-appearance:initial; } body { From 6793db967fa1b0e5b20ddb094d23ba776df204f5 Mon Sep 17 00:00:00 2001 From: RossAsscends <124905043+RossAscends@users.noreply.github.com> Date: Sat, 4 Mar 2023 17:26:20 +0900 Subject: [PATCH 07/10] fixed advanced_div and styled notes links advanced div changed to grid layout notes links "?" styled as circles --- public/index.html | 63 +++--- public/style.css | 495 +++++++++++++++++++++------------------------- 2 files changed, 254 insertions(+), 304 deletions(-) diff --git a/public/index.html b/public/index.html index 7b4dec924..c4fd362de 100644 --- a/public/index.html +++ b/public/index.html @@ -2979,32 +2979,34 @@
- - -

Create character

- +
+ +
+ +
+

Create character

+
- +
-

Personality summary

A brief description of the personality (?)
+

Personality summary

A brief description of the personality ?

Scenario

-
Circumstances and context of the dialogue (?)
+
Circumstances and context of the dialogue ?
-

Examples of dialogue

-
Forms a personality more clearly (?)
-
- - - +
+

Examples of dialogue

+
Forms a personality more clearly ?
+
+ +
-
@@ -3013,15 +3015,18 @@
-
+
-
(?)
- + +
+ ? +
+
@@ -3107,11 +3112,11 @@
-

Description

Description of personality and other characteristics (?)
+

Description

Description of personality and other characteristics ?
-

First message

First message from the character (?)
+

First message

First message from the character ?
@@ -3165,7 +3170,7 @@
Not connected
-

Preset settings

Selecting settings (?)
+

Preset settings

Selecting settings ?
@@ -3184,7 +3189,7 @@
-

API key

Where to get (?)
+

API key

Where to get ?

@@ -3193,12 +3198,12 @@
No connection...
-

Model

Selecting NovelAI model (?)
+

Model

Selecting NovelAI model ?
-

Preset settings

Selecting settings (?)
+

Preset settings

Selecting settings ?
@@ -3240,7 +3245,7 @@

Anchors Order

-
Helps to increase the length of messages (?)
+
Helps to increase the length of messages ?
+
?
@@ -3040,7 +3086,7 @@
-
+
@@ -3084,43 +3130,33 @@