2023-07-20 19:32:15 +02:00
import {
characters ,
saveChat ,
system _messages ,
system _message _types ,
this _chid ,
openCharacterChat ,
chat _metadata ,
callPopup ,
getRequestHeaders ,
getThumbnailUrl ,
getCharacters ,
chat ,
saveChatConditional ,
2024-05-24 23:07:36 +02:00
saveItemizedPrompts ,
2023-12-02 19:04:51 +01:00
} from '../script.js' ;
import { humanizedDateTime } from './RossAscends-mods.js' ;
2023-07-20 19:32:15 +02:00
import {
getGroupPastChats ,
group _activation _strategy ,
groups ,
2023-08-19 20:44:15 +02:00
openGroupById ,
2023-07-20 19:32:15 +02:00
openGroupChat ,
saveGroupBookmarkChat ,
selected _group ,
2023-12-02 19:04:51 +01:00
} from './group-chats.js' ;
2024-06-27 01:01:43 +02:00
import { Popup } from './popup.js' ;
2023-12-02 19:04:51 +01:00
import { createTagMapFromList } from './tags.js' ;
2023-07-20 19:32:15 +02:00
import {
delay ,
getUniqueName ,
2023-12-02 19:04:51 +01:00
} from './utils.js' ;
2023-07-20 19:32:15 +02:00
export {
createNewBookmark ,
showBookmarksButtons ,
2023-12-02 20:11:06 +01:00
} ;
2023-07-20 19:32:15 +02:00
2023-12-03 02:11:14 +01:00
const bookmarkNameToken = 'Checkpoint #' ;
2023-07-20 19:32:15 +02:00
async function getExistingChatNames ( ) {
if ( selected _group ) {
const data = await getGroupPastChats ( selected _group ) ;
return data . map ( x => x . file _name ) ;
} else {
2023-12-04 12:51:45 +01:00
const response = await fetch ( '/api/characters/chats' , {
2023-07-20 19:32:15 +02:00
method : 'POST' ,
headers : getRequestHeaders ( ) ,
2023-12-02 21:06:57 +01:00
body : JSON . stringify ( { avatar _url : characters [ this _chid ] . avatar } ) ,
2023-07-20 19:32:15 +02:00
} ) ;
if ( response . ok ) {
const data = await response . json ( ) ;
return Object . values ( data ) . map ( x => x . file _name . replace ( '.jsonl' , '' ) ) ;
}
}
}
async function getBookmarkName ( ) {
const chatNames = await getExistingChatNames ( ) ;
2023-12-03 02:11:14 +01:00
const popupText = ` <h3>Enter the checkpoint name:<h3>
2023-07-20 19:32:15 +02:00
< small > Leave empty to auto - generate . < / s m a l l > ` ;
let name = await callPopup ( popupText , 'input' ) ;
if ( name === false ) {
return null ;
}
else if ( name === '' ) {
for ( let i = chatNames . length ; i < 1000 ; i ++ ) {
name = bookmarkNameToken + i ;
if ( ! chatNames . includes ( name ) ) {
break ;
}
}
}
return ` ${ name } - ${ humanizedDateTime ( ) } ` ;
}
function getMainChatName ( ) {
if ( chat _metadata ) {
if ( chat _metadata [ 'main_chat' ] ) {
return chat _metadata [ 'main_chat' ] ;
}
// groups didn't support bookmarks before chat metadata was introduced
else if ( selected _group ) {
return null ;
}
else if ( characters [ this _chid ] . chat && characters [ this _chid ] . chat . includes ( bookmarkNameToken ) ) {
const tokenIndex = characters [ this _chid ] . chat . lastIndexOf ( bookmarkNameToken ) ;
chat _metadata [ 'main_chat' ] = characters [ this _chid ] . chat . substring ( 0 , tokenIndex ) . trim ( ) ;
return chat _metadata [ 'main_chat' ] ;
}
}
return null ;
}
function showBookmarksButtons ( ) {
try {
if ( selected _group ) {
2023-12-02 19:04:51 +01:00
$ ( '#option_convert_to_group' ) . hide ( ) ;
2023-07-20 19:32:15 +02:00
} else {
2023-12-02 19:04:51 +01:00
$ ( '#option_convert_to_group' ) . show ( ) ;
2023-07-20 19:32:15 +02:00
}
if ( chat _metadata [ 'main_chat' ] ) {
// In bookmark chat
2023-12-02 19:04:51 +01:00
$ ( '#option_back_to_main' ) . show ( ) ;
$ ( '#option_new_bookmark' ) . show ( ) ;
2023-07-20 19:32:15 +02:00
} else if ( ! selected _group && ! characters [ this _chid ] . chat ) {
// No chat recorded on character
2023-12-02 19:04:51 +01:00
$ ( '#option_back_to_main' ) . hide ( ) ;
$ ( '#option_new_bookmark' ) . hide ( ) ;
2023-07-20 19:32:15 +02:00
} else {
// In main chat
2023-12-02 19:04:51 +01:00
$ ( '#option_back_to_main' ) . hide ( ) ;
$ ( '#option_new_bookmark' ) . show ( ) ;
2023-07-20 19:32:15 +02:00
}
}
catch {
2023-12-02 19:04:51 +01:00
$ ( '#option_back_to_main' ) . hide ( ) ;
$ ( '#option_new_bookmark' ) . hide ( ) ;
$ ( '#option_convert_to_group' ) . hide ( ) ;
2023-07-20 19:32:15 +02:00
}
}
async function saveBookmarkMenu ( ) {
if ( ! chat . length ) {
2023-12-03 02:11:14 +01:00
toastr . warning ( 'The chat is empty.' , 'Checkpoint creation failed' ) ;
2023-07-20 19:32:15 +02:00
return ;
}
return createNewBookmark ( chat . length - 1 ) ;
}
2023-09-21 04:48:05 +02:00
export async function createBranch ( mesId ) {
if ( ! chat . length ) {
2023-09-21 06:40:38 +02:00
toastr . warning ( 'The chat is empty.' , 'Branch creation failed' ) ;
2023-09-21 04:48:05 +02:00
return ;
}
if ( mesId < 0 || mesId >= chat . length ) {
2023-09-21 06:40:38 +02:00
toastr . warning ( 'Invalid message ID.' , 'Branch creation failed' ) ;
2023-09-21 04:48:05 +02:00
return ;
}
const lastMes = chat [ mesId ] ;
const mainChat = selected _group ? groups ? . find ( x => x . id == selected _group ) ? . chat _id : characters [ this _chid ] . chat ;
const newMetadata = { main _chat : mainChat } ;
2023-12-02 20:11:06 +01:00
let name = ` Branch # ${ mesId } - ${ humanizedDateTime ( ) } ` ;
2023-09-21 04:48:05 +02:00
if ( selected _group ) {
await saveGroupBookmarkChat ( selected _group , name , newMetadata , mesId ) ;
} else {
await saveChat ( name , newMetadata , mesId ) ;
}
// append to branches list if it exists
// otherwise create it
if ( typeof lastMes . extra !== 'object' ) {
lastMes . extra = { } ;
}
if ( typeof lastMes . extra [ 'branches' ] !== 'object' ) {
lastMes . extra [ 'branches' ] = [ ] ;
}
lastMes . extra [ 'branches' ] . push ( name ) ;
return name ;
}
2023-07-20 19:32:15 +02:00
async function createNewBookmark ( mesId ) {
if ( ! chat . length ) {
2023-12-03 02:11:14 +01:00
toastr . warning ( 'The chat is empty.' , 'Checkpoint creation failed' ) ;
2023-07-20 19:32:15 +02:00
return ;
}
if ( mesId < 0 || mesId >= chat . length ) {
2023-12-03 02:11:14 +01:00
toastr . warning ( 'Invalid message ID.' , 'Checkpoint creation failed' ) ;
2023-07-20 19:32:15 +02:00
return ;
}
const lastMes = chat [ mesId ] ;
if ( typeof lastMes . extra !== 'object' ) {
lastMes . extra = { } ;
}
if ( lastMes . extra . bookmark _link ) {
2023-12-03 02:11:14 +01:00
const confirm = await callPopup ( 'Checkpoint for the last message already exists. Would you like to replace it?' , 'confirm' ) ;
2023-07-20 19:32:15 +02:00
if ( ! confirm ) {
return ;
}
}
await delay ( 250 ) ;
let name = await getBookmarkName ( ) ;
if ( ! name ) {
return ;
}
const mainChat = selected _group ? groups ? . find ( x => x . id == selected _group ) ? . chat _id : characters [ this _chid ] . chat ;
const newMetadata = { main _chat : mainChat } ;
2024-05-24 23:07:36 +02:00
await saveItemizedPrompts ( name ) ;
2023-07-20 19:32:15 +02:00
if ( selected _group ) {
await saveGroupBookmarkChat ( selected _group , name , newMetadata , mesId ) ;
} else {
await saveChat ( name , newMetadata , mesId ) ;
}
lastMes . extra [ 'bookmark_link' ] = name ;
$ ( ` .mes[mesid=" ${ mesId } "] ` ) . attr ( 'bookmark_link' , name ) ;
await saveChatConditional ( ) ;
2023-12-03 02:11:14 +01:00
toastr . success ( 'Click the flag icon in the last message to open the checkpoint chat.' , 'Checkpoint created' , { timeOut : 10000 } ) ;
2023-07-20 19:32:15 +02:00
}
async function backToMainChat ( ) {
const mainChatName = getMainChatName ( ) ;
const allChats = await getExistingChatNames ( ) ;
if ( allChats . includes ( mainChatName ) ) {
if ( selected _group ) {
await openGroupChat ( selected _group , mainChatName ) ;
} else {
await openCharacterChat ( mainChatName ) ;
}
}
}
async function convertSoloToGroupChat ( ) {
if ( selected _group ) {
console . log ( 'Already in group. No need for conversion' ) ;
return ;
}
if ( this _chid === undefined ) {
console . log ( 'Need to have a character selected' ) ;
return ;
}
2024-06-27 01:01:43 +02:00
const confirm = await Popup . show . confirm ( 'Convert to group chat' , 'Are you sure you want to convert this chat to a group chat?<br />This cannot be reverted.' ) ;
2023-12-17 20:14:16 +01:00
if ( ! confirm ) {
return ;
}
2023-07-20 19:32:15 +02:00
const character = characters [ this _chid ] ;
// Populate group required fields
const name = getUniqueName ( ` Group: ${ character . name } ` , y => groups . findIndex ( x => x . name === y ) !== - 1 ) ;
const avatar = getThumbnailUrl ( 'avatar' , character . avatar ) ;
const chatName = humanizedDateTime ( ) ;
const chats = [ chatName ] ;
const members = [ character . avatar ] ;
const activationStrategy = group _activation _strategy . NATURAL ;
const allowSelfResponses = false ;
const favChecked = character . fav || character . fav == 'true' ;
const metadata = Object . assign ( { } , chat _metadata ) ;
delete metadata . main _chat ;
2023-12-06 18:40:58 +01:00
const createGroupResponse = await fetch ( '/api/groups/create' , {
2023-12-02 19:04:51 +01:00
method : 'POST' ,
2023-07-20 19:32:15 +02:00
headers : getRequestHeaders ( ) ,
body : JSON . stringify ( {
name : name ,
members : members ,
avatar _url : avatar ,
allow _self _responses : activationStrategy ,
activation _strategy : allowSelfResponses ,
disabled _members : [ ] ,
chat _metadata : metadata ,
fav : favChecked ,
chat _id : chatName ,
chats : chats ,
} ) ,
} ) ;
if ( ! createGroupResponse . ok ) {
console . error ( 'Group creation unsuccessful' ) ;
return ;
}
const group = await createGroupResponse . json ( ) ;
// Convert tags list and assign to group
2023-12-02 19:04:51 +01:00
createTagMapFromList ( '#tagList' , group . id ) ;
2023-07-20 19:32:15 +02:00
// Update chars list
await getCharacters ( ) ;
// Convert chat to group format
const groupChat = chat . slice ( ) ;
const genIdFirst = Date . now ( ) ;
// Add something if the chat is empty
if ( groupChat . length === 0 ) {
const newMessage = {
... system _messages [ system _message _types . GROUP ] ,
send _date : humanizedDateTime ( ) ,
2023-12-02 21:06:57 +01:00
extra : { type : system _message _types . GROUP } ,
2023-07-20 19:32:15 +02:00
} ;
groupChat . push ( newMessage ) ;
}
for ( let index = 0 ; index < groupChat . length ; index ++ ) {
const message = groupChat [ index ] ;
// Save group-chat marker
if ( index == 0 ) {
message . is _group = true ;
}
// Skip messages we don't care about
if ( message . is _user || message . is _system || message . extra ? . type === system _message _types . NARRATOR || message . force _avatar !== undefined ) {
continue ;
}
// Set force fields for solo character
message . name = character . name ;
message . original _avatar = character . avatar ;
message . force _avatar = getThumbnailUrl ( 'avatar' , character . avatar ) ;
// Allow regens of a single message in group
if ( typeof message . extra !== 'object' ) {
message . extra = { gen _id : genIdFirst + index } ;
}
}
// Save group chat
2023-12-06 04:34:52 +01:00
const createChatResponse = await fetch ( '/api/chats/group/save' , {
2023-12-02 19:04:51 +01:00
method : 'POST' ,
2023-07-20 19:32:15 +02:00
headers : getRequestHeaders ( ) ,
body : JSON . stringify ( { id : chatName , chat : groupChat } ) ,
} ) ;
if ( ! createChatResponse . ok ) {
console . error ( 'Group chat creation unsuccessful' ) ;
2024-06-28 03:28:16 +02:00
toastr . error ( 'Group chat creation unsuccessful' ) ;
2023-07-20 19:32:15 +02:00
return ;
}
// Click on the freshly selected group to open it
2023-08-19 20:44:15 +02:00
await openGroupById ( group . id ) ;
2023-07-20 19:32:15 +02:00
toastr . success ( 'The chat has been successfully converted!' ) ;
}
2023-08-19 20:44:15 +02:00
jQuery ( function ( ) {
2023-07-20 19:32:15 +02:00
$ ( '#option_new_bookmark' ) . on ( 'click' , saveBookmarkMenu ) ;
$ ( '#option_back_to_main' ) . on ( 'click' , backToMainChat ) ;
$ ( '#option_convert_to_group' ) . on ( 'click' , convertSoloToGroupChat ) ;
} ) ;