mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
button to duplicate solo characters
This commit is contained in:
@ -989,48 +989,48 @@
|
||||
</div>
|
||||
<div id="kobold_horde" style="position: relative;"> <!-- shows the kobold settings -->
|
||||
<form action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
<div id="kobold_horde_block">
|
||||
<ul>
|
||||
<li>
|
||||
<a target="_blank" href="https://horde.koboldai.net/register">Register a Horde account for faster queue times</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/db0/AI-Horde-Worker#readme">Learn how to contribute your idle GPU cycles to the Horde</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="kobold_horde_block">
|
||||
<ul>
|
||||
<li>
|
||||
<a target="_blank" href="https://horde.koboldai.net/register">Register a Horde account for faster queue times</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://github.com/db0/AI-Horde-Worker#readme">Learn how to contribute your idle GPU cycles to the Horde</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<label for="horde_auto_adjust_context_length" class="checkbox_label">
|
||||
<input id="horde_auto_adjust_context_length" type="checkbox" />
|
||||
Adjust context size to worker capabilities
|
||||
</label>
|
||||
<label for="horde_auto_adjust_context_length" class="checkbox_label">
|
||||
<input id="horde_auto_adjust_context_length" type="checkbox" />
|
||||
Adjust context size to worker capabilities
|
||||
</label>
|
||||
|
||||
<label for="horde_auto_adjust_response_length" class="checkbox_label">
|
||||
<input id="horde_auto_adjust_response_length" type="checkbox" />
|
||||
Adjust response length to worker capabilities
|
||||
</label>
|
||||
<h4>API key</h4>
|
||||
<h5>Get it here: <a target="_blank" href="https://horde.koboldai.net/register">Register</a><br>
|
||||
Enter <span class="monospace">0000000000</span> to use anonymous mode.
|
||||
</h5>
|
||||
<div>
|
||||
<a id="horde_kudos" href="javascript:void(0);">View my Kudos</a>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<input id="horde_api_key" name="horde_api_key" class="text_pole flex1" maxlength="500" type="text" placeholder="0000000000" autocomplete="off">
|
||||
<div title="Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div>
|
||||
</div>
|
||||
<div class="neutral_warning">For privacy reasons, your API key will be hidden after you reload the page.</div>
|
||||
<h4 class="horde_model_title">
|
||||
Model
|
||||
<div id="horde_refresh" title="Refresh models" class="right_menu_button">
|
||||
<div class="fa-solid fa-repeat "></div>
|
||||
<label for="horde_auto_adjust_response_length" class="checkbox_label">
|
||||
<input id="horde_auto_adjust_response_length" type="checkbox" />
|
||||
Adjust response length to worker capabilities
|
||||
</label>
|
||||
<h4>API key</h4>
|
||||
<h5>Get it here: <a target="_blank" href="https://horde.koboldai.net/register">Register</a><br>
|
||||
Enter <span class="monospace">0000000000</span> to use anonymous mode.
|
||||
</h5>
|
||||
<div>
|
||||
<a id="horde_kudos" href="javascript:void(0);">View my Kudos</a>
|
||||
</div>
|
||||
</h4>
|
||||
<small class="horde_multiple_hint">Hold Control / Command key to select multiple models.</small>
|
||||
<select id="horde_model" multiple>
|
||||
<option>-- Horde models not loaded --</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<input id="horde_api_key" name="horde_api_key" class="text_pole flex1" maxlength="500" type="text" placeholder="0000000000" autocomplete="off">
|
||||
<div title="Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div>
|
||||
</div>
|
||||
<div class="neutral_warning">For privacy reasons, your API key will be hidden after you reload the page.</div>
|
||||
<h4 class="horde_model_title">
|
||||
Model
|
||||
<div id="horde_refresh" title="Refresh models" class="right_menu_button">
|
||||
<div class="fa-solid fa-repeat "></div>
|
||||
</div>
|
||||
</h4>
|
||||
<small class="horde_multiple_hint">Hold Control / Command key to select multiple models.</small>
|
||||
<select id="horde_model" multiple>
|
||||
<option>-- Horde models not loaded --</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="online_status_horde">
|
||||
<div id="online_status_indicator_horde"></div>
|
||||
<div id="online_status_text_horde">Not connected</div>
|
||||
@ -1931,6 +1931,7 @@
|
||||
<input type="hidden" id="fav_checkbox" name="fav" />
|
||||
<div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions"></div>
|
||||
<div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download"></div>
|
||||
<div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character"></div>
|
||||
<label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character">
|
||||
<input type="submit" id="create_button" name="create_button">
|
||||
</label>
|
||||
@ -2221,7 +2222,7 @@
|
||||
<div id="context_editor_template" class="template_element">
|
||||
<div class="context_editor">
|
||||
<h3>Context Template Editor</h3>
|
||||
<h4 class="template_name"></h4>
|
||||
<h4 class="template_name"></h4>
|
||||
|
||||
<div class="inline-drawer wide100p">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
|
@ -4258,30 +4258,38 @@ function select_rm_info(type, charId, previousCharId = null) {
|
||||
toastr.error(`Invalid process (no 'type')`);
|
||||
return;
|
||||
}
|
||||
if (type !== 'group_create') {
|
||||
var displayName = String(charId).replace('.png', '');
|
||||
}
|
||||
|
||||
if (type === 'char_delete') {
|
||||
toastr.warning(`Character Deleted: ${charId}`);
|
||||
toastr.warning(`Character Deleted: ${displayName}`);
|
||||
}
|
||||
if (type === 'char_create') {
|
||||
toastr.success(`Character Created: ${charId}`);
|
||||
toastr.success(`Character Created: ${displayName}`);
|
||||
}
|
||||
if (type === 'group_create') {
|
||||
toastr.success(`Group Created`);
|
||||
}
|
||||
if (type === 'char_import') {
|
||||
toastr.success(`Character Imported: ${charId}`);
|
||||
if (type === 'group_delete') {
|
||||
toastr.warning(`Group Deleted`);
|
||||
}
|
||||
|
||||
if (type === 'char_import') {
|
||||
toastr.success(`Character Imported: ${displayName}`);
|
||||
}
|
||||
|
||||
getCharacters();
|
||||
selectRightMenuWithAnimation('rm_characters_block');
|
||||
|
||||
if (type === 'char_import' || type === 'char_create') {
|
||||
|
||||
//$(`#rm_characters_block [title="${charId + '.png'}"]`).scrollIntoView({ behavior: "smooth", block: "end" });
|
||||
const element = $(`#rm_characters_block [title="${charId + '.png'}"]`).get(0);
|
||||
const element = $(`#rm_characters_block [title="${charId}"]`).get(0);
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'end' });
|
||||
|
||||
$(`#rm_characters_block [title="${charId + '.png'}"]`).parent().addClass('flash animated');
|
||||
$(`#rm_characters_block [title="${charId}"]`).parent().addClass('flash animated');
|
||||
setTimeout(function () {
|
||||
$(`#rm_characters_block [title="${charId + '.png'}"]`).parent().removeClass('flash animated');
|
||||
$(`#rm_characters_block [title="${charId}"]`).parent().removeClass('flash animated');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
@ -4319,7 +4327,8 @@ export function select_selected_character(chid) {
|
||||
$("#rm_button_back").css("display", "none");
|
||||
//$("#character_import_button").css("display", "none");
|
||||
$("#create_button").attr("value", "Save"); // what is the use case for this?
|
||||
$("#create_button_label").css("display", "none");
|
||||
$("#dupe_button").show();
|
||||
//$("#create_button_label").css("display", "none");
|
||||
|
||||
// Don't update the navbar name if we're peeking the group member defs
|
||||
if (!selected_group) {
|
||||
@ -4376,8 +4385,7 @@ function select_rm_create() {
|
||||
$("#export_button").css("display", "none");
|
||||
$("#create_button_label").css("display", "");
|
||||
$("#create_button").attr("value", "Create");
|
||||
//RossAscends: commented this out as part of the auto-loading token counter
|
||||
//$('#result_info').html(' ');
|
||||
$("#dupe_button").hide();
|
||||
|
||||
//create text poles
|
||||
$("#rm_button_back").css("display", "");
|
||||
@ -4511,7 +4519,7 @@ function read_bg_load(input) {
|
||||
url: "/downloadbackground",
|
||||
data: formData,
|
||||
beforeSend: function () {
|
||||
//$('#create_button').attr('value','Creating...');
|
||||
|
||||
},
|
||||
cache: false,
|
||||
contentType: false,
|
||||
@ -5412,7 +5420,6 @@ $(document).ready(function () {
|
||||
url: "/deletecharacter",
|
||||
beforeSend: function () {
|
||||
select_rm_info("char_delete", characters[this_chid].name);
|
||||
//$('#create_button').attr('value','Deleting...');
|
||||
},
|
||||
data: msg,
|
||||
cache: false,
|
||||
@ -5593,7 +5600,7 @@ $(document).ready(function () {
|
||||
$("#rm_info_block").transition({ opacity: 0, duration: 0 });
|
||||
var $prev_img = $("#avatar_div_div").clone();
|
||||
$("#rm_info_avatar").append($prev_img);
|
||||
select_rm_info(`char_create`, save_name, oldSelectedChar);
|
||||
select_rm_info(`char_create`, html, oldSelectedChar);
|
||||
|
||||
$("#rm_info_block").transition({ opacity: 1.0, duration: 2000 });
|
||||
crop_data = undefined;
|
||||
@ -5617,7 +5624,7 @@ $(document).ready(function () {
|
||||
url: url,
|
||||
data: formData,
|
||||
beforeSend: function () {
|
||||
//$("#create_button").attr("disabled", true);
|
||||
$("#create_button").attr("disabled", true);
|
||||
$("#create_button").attr("value", "Save");
|
||||
},
|
||||
cache: false,
|
||||
@ -6548,6 +6555,20 @@ $(document).ready(function () {
|
||||
select_rm_characters();
|
||||
});
|
||||
|
||||
$("#dupe_button").click(async function () {
|
||||
|
||||
const body = { avatar_url: characters[this_chid].avatar };
|
||||
const response = await fetch('/dupecharacter', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (response.ok) {
|
||||
toastr.success("Character Duplicated");
|
||||
getCharacters();
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", ".select_chat_block, .bookmark_link, .mes_bookmark", async function () {
|
||||
let file_name = $(this).hasClass('mes_bookmark')
|
||||
? $(this).closest('.mes').attr('bookmark_link')
|
||||
|
@ -762,7 +762,7 @@ async function deleteGroup(id) {
|
||||
|
||||
$("#rm_info_avatar").html("");
|
||||
$("#rm_info_block").transition({ opacity: 0, duration: 0 });
|
||||
select_rm_info("Group deleted!");
|
||||
select_rm_info("group_delete", id);
|
||||
$("#rm_info_block").transition({ opacity: 1.0, duration: 2000 });
|
||||
|
||||
$("#rm_button_selected_ch").children("h2").text('');
|
||||
|
33
server.js
33
server.js
@ -1545,6 +1545,39 @@ app.post("/importcharacter", urlencodedParser, async function (request, response
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/dupecharacter", jsonParser, async function (request, response) {
|
||||
try {
|
||||
if (!request.body.avatar_url) {
|
||||
console.log("avatar URL not found in request body");
|
||||
console.log(request.body);
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
let filename = path.join(directories.characters, sanitize(request.body.avatar_url));
|
||||
if (!fs.existsSync(filename)) {
|
||||
console.log('file for dupe not found');
|
||||
console.log(filename);
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
let suffix = 1;
|
||||
let newFilename = filename;
|
||||
while (fs.existsSync(newFilename)) {
|
||||
let suffixStr = "_" + suffix;
|
||||
let ext = path.extname(filename);
|
||||
newFilename = filename.slice(0, -ext.length) + suffixStr + ext;
|
||||
suffix++;
|
||||
}
|
||||
fs.copyFile(filename, newFilename, (err) => {
|
||||
if (err) throw err;
|
||||
console.log(`${filename} was copied to ${newFilename}`);
|
||||
response.sendStatus(200);
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return response.send({ error: true });
|
||||
}
|
||||
});
|
||||
|
||||
app.post("/exportcharacter", jsonParser, async function (request, response) {
|
||||
if (!request.body.format || !request.body.avatar_url) {
|
||||
return response.sendStatus(400);
|
||||
|
Reference in New Issue
Block a user