button to duplicate solo characters

This commit is contained in:
RossAscends
2023-05-27 21:00:46 +09:00
parent d18105b31c
commit 41251937b3
4 changed files with 112 additions and 57 deletions

View File

@ -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">

View File

@ -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('&nbsp;');
$("#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')

View File

@ -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('');

View File

@ -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);