Merge pull request #2834 from SillyTavern/replace-ajax Replace ajax with fetch in character create/edit

7c383e32182c9f0ac0fb2fe8cf9ff878086ee084

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
1 files changed, +124 -127Ignore whitespace
public/script.js+124 -127
@@ -7892,13 +7892,19 @@ async function createOrEditCharacter(e) {
78927892 formData.set('avatar', convertedFile);
78937893 }
78947894
7895- if ($('#form_create').attr('actiontype') == 'createcharacter') {
7895+ const headers = getRequestHeaders();
7896- if (String($('#character_name_pole').val()).length > 0) {
7896+ delete headers['Content-Type'];
7897- if (is_group_generating || is_send_press) {
7898- toastr.error('Cannot create characters while generating. Stop the request and try again.', 'Creation aborted');
7899- throw new Error('Cannot import character while generating');
7900- }
79017897
7898+ if ($('#form_create').attr('actiontype') == 'createcharacter') {
7899+ if (String($('#character_name_pole').val()).length === 0) {
7900+ toastr.error('Name is required');
7901+ return;
7902+ }
7903+ if (is_group_generating || is_send_press) {
7904+ toastr.error('Cannot create characters while generating. Stop the request and try again.', 'Creation aborted');
7905+ return;
7906+ }
7907+ try {
79027908 //if the character name text area isn't empty (only posible when creating a new character)
79037909 let url = '/api/characters/create';
79047910
@@ -7913,142 +7919,133 @@ async function createOrEditCharacter(e) {
79137919
79147920 formData.append('extensions', JSON.stringify(create_save.extensions));
79157921
7916- await jQuery.ajax({
7922+ const fetchResult = await fetch(url, {
79177923 typemethod: 'POST',
79187924 urlheaders: urlheaders,
79197925 databody: formData,
7920- beforeSend: function () {
7926+ cache: 'no-cache',
7921- $('#create_button').attr('disabled', String(true));
7927+ });
7922- $('#create_button').attr('value', '⏳');
7923- },
7924- cache: false,
7925- contentType: false,
7926- processData: false,
7927- success: async function (html) {
7928- $('#character_cross').trigger('click'); //closes the advanced character editing popup
7929- const fields = [
7930- { id: '#character_name_pole', callback: value => create_save.name = value },
7931- { id: '#description_textarea', callback: value => create_save.description = value },
7932- { id: '#creator_notes_textarea', callback: value => create_save.creator_notes = value },
7933- { id: '#character_version_textarea', callback: value => create_save.character_version = value },
7934- { id: '#post_history_instructions_textarea', callback: value => create_save.post_history_instructions = value },
7935- { id: '#system_prompt_textarea', callback: value => create_save.system_prompt = value },
7936- { id: '#tags_textarea', callback: value => create_save.tags = value },
7937- { id: '#creator_textarea', callback: value => create_save.creator = value },
7938- { id: '#personality_textarea', callback: value => create_save.personality = value },
7939- { id: '#firstmessage_textarea', callback: value => create_save.first_message = value },
7940- { id: '#talkativeness_slider', callback: value => create_save.talkativeness = value, defaultValue: talkativeness_default },
7941- { id: '#scenario_pole', callback: value => create_save.scenario = value },
7942- { id: '#depth_prompt_prompt', callback: value => create_save.depth_prompt_prompt = value },
7943- { id: '#depth_prompt_depth', callback: value => create_save.depth_prompt_depth = value, defaultValue: depth_prompt_depth_default },
7944- { id: '#depth_prompt_role', callback: value => create_save.depth_prompt_role = value, defaultValue: depth_prompt_role_default },
7945- { id: '#mes_example_textarea', callback: value => create_save.mes_example = value },
7946- { id: '#character_json_data', callback: () => { } },
7947- { id: '#alternate_greetings_template', callback: value => create_save.alternate_greetings = value, defaultValue: [] },
7948- { id: '#character_world', callback: value => create_save.world = value },
7949- { id: '#_character_extensions_fake', callback: value => create_save.extensions = {} },
7950- ];
7951-
7952- fields.forEach(field => {
7953- const fieldValue = field.defaultValue !== undefined ? field.defaultValue : '';
7954- $(field.id).val(fieldValue);
7955- field.callback && field.callback(fieldValue);
7956- });
79577928
7958- $('#character_popup-button-h3').text('Create character');
7929+ if (!fetchResult.ok) {
7930+ throw new Error('Fetch result is not ok');
7931+ }
7932+
7933+ const avatarId = await fetchResult.text();
7934+
7935+ $('#character_cross').trigger('click'); //closes the advanced character editing popup
7936+ const fields = [
7937+ { id: '#character_name_pole', callback: value => create_save.name = value },
7938+ { id: '#description_textarea', callback: value => create_save.description = value },
7939+ { id: '#creator_notes_textarea', callback: value => create_save.creator_notes = value },
7940+ { id: '#character_version_textarea', callback: value => create_save.character_version = value },
7941+ { id: '#post_history_instructions_textarea', callback: value => create_save.post_history_instructions = value },
7942+ { id: '#system_prompt_textarea', callback: value => create_save.system_prompt = value },
7943+ { id: '#tags_textarea', callback: value => create_save.tags = value },
7944+ { id: '#creator_textarea', callback: value => create_save.creator = value },
7945+ { id: '#personality_textarea', callback: value => create_save.personality = value },
7946+ { id: '#firstmessage_textarea', callback: value => create_save.first_message = value },
7947+ { id: '#talkativeness_slider', callback: value => create_save.talkativeness = value, defaultValue: talkativeness_default },
7948+ { id: '#scenario_pole', callback: value => create_save.scenario = value },
7949+ { id: '#depth_prompt_prompt', callback: value => create_save.depth_prompt_prompt = value },
7950+ { id: '#depth_prompt_depth', callback: value => create_save.depth_prompt_depth = value, defaultValue: depth_prompt_depth_default },
7951+ { id: '#depth_prompt_role', callback: value => create_save.depth_prompt_role = value, defaultValue: depth_prompt_role_default },
7952+ { id: '#mes_example_textarea', callback: value => create_save.mes_example = value },
7953+ { id: '#character_json_data', callback: () => { } },
7954+ { id: '#alternate_greetings_template', callback: value => create_save.alternate_greetings = value, defaultValue: [] },
7955+ { id: '#character_world', callback: value => create_save.world = value },
7956+ { id: '#_character_extensions_fake', callback: value => create_save.extensions = {} },
7957+ ];
7958+
7959+ fields.forEach(field => {
7960+ const fieldValue = field.defaultValue !== undefined ? field.defaultValue : '';
7961+ $(field.id).val(fieldValue);
7962+ field.callback && field.callback(fieldValue);
7963+ });
79597964
7960- create_save.avatar = '';
7965+ $('#character_popup-button-h3').text('Create character');
79617966
7962- $('#create_button').removeAttr('disabled');
7967+ create_save.avatar = '';
7963- $('#add_avatar_button').replaceWith(
7964- $('#add_avatar_button').val('').clone(true),
7965- );
79667968
79677969 $('#create_buttonadd_avatar_button').attrreplaceWith('value', '✅');
7968- let oldSelectedChar = null;
7970+ $('#add_avatar_button').val('').clone(true),
7969- if (this_chid !== undefined) {
7971+ );
7970- oldSelectedChar = characters[this_chid].avatar;
7971- }
79727972
7973- console.log(`new avatar id: ${html}`);
7973+ let oldSelectedChar = null;
7974- createTagMapFromList('#tagList', html);
7974+ if (this_chid !== undefined) {
7975- await getCharacters();
7975+ oldSelectedChar = characters[this_chid].avatar;
7976+ }
79767977
7977- select_rm_info('char_create', html, oldSelectedChar);
7978+ console.log(`new avatar id: ${avatarId}`);
7979+ createTagMapFromList('#tagList', avatarId);
7980+ await getCharacters();
79787981
7979- crop_data = undefined;
7982+ select_rm_info('char_create', avatarId, oldSelectedChar);
7980- },
7983+
7981- error: function (jqXHR, exception) {
7984+ crop_data = undefined;
7982- $('#create_button').removeAttr('disabled');
7985+
7983- },
7986+ } catch (error) {
7984- });
7987+ console.error('Error creating character', error);
7985- } else {
7988+ toastr.error('Failed to create character');
7986- toastr.error('Name is required');
79877989 }
79887990 } else {
7989- let url = '/api/characters/edit';
7991+ try {
7992+ let url = '/api/characters/edit';
79907993
79917994 if (crop_data != undefined) {
79927995 url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
79937996 }
79947997
79957998 formData.delete('alternate_greetings');
79967999 const chid = $('.open_alternate_greetings').data('chid');
79978000 if (chid && Array.isArray(characters[chid]?.data?.alternate_greetings)) {
79988001 for (const value of characters[chid].data.alternate_greetings) {
79998002 formData.append('alternate_greetings', value);
8003+ }
80008004 }
8001- }
80028005
8003- await jQuery.ajax({
8006+ const fetchResult = await fetch(url, {
80048007 type method: 'POST',
80058008 url headers: urlheaders,
80068009 data body: formData,
8007- beforeSend: function () {
8010+ cache: 'no-cache',
8008- $('#create_button').attr('disabled', String(true));
8011+ });
8009- $('#create_button').attr('value', 'Save');
8010- },
8011- cache: false,
8012- contentType: false,
8013- processData: false,
8014- success: async function (html) {
8015- $('#create_button').removeAttr('disabled');
80168012
8017- await getOneCharacter(formData.get('avatar_url'));
8013+ if (!fetchResult.ok) {
8018- favsToHotswap(); // Update fav state
8014+ throw new Error('Fetch result is not ok');
8015+ }
80198016
8020- $('#add_avatar_button').replaceWith(
8017+ await getOneCharacter(formData.get('avatar_url'));
8021- $('#add_avatar_button').val('').clone(true),
8018+ favsToHotswap(); // Update fav state
8022- );
8019+
80238020 $('#create_buttonadd_avatar_button').attrreplaceWith('value', 'Save');
8024- crop_data = undefined;
8021+ $('#add_avatar_button').val('').clone(true),
8025- eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });
8022+ );
8026-
8023+ $('#create_button').attr('value', 'Save');
8027- // Recreate the chat if it hasn't been used at least once (i.e. with continue).
8024+ crop_data = undefined;
8028- const message = getFirstMessage();
8025+ await eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });
8029- const shouldRegenerateMessage =
8026+
8030- !isNewChat &&
8027+ // Recreate the chat if it hasn't been used at least once (i.e. with continue).
8031- message.mes &&
8028+ const message = getFirstMessage();
8032- !selected_group &&
8029+ const shouldRegenerateMessage =
8033- !chat_metadata['tainted'] &&
8030+ !isNewChat &&
8034- (chat.length === 0 || (chat.length === 1 && !chat[0].is_user && !chat[0].is_system));
8031+ message.mes &&
8035-
8032+ !selected_group &&
8036- if (shouldRegenerateMessage) {
8033+ !chat_metadata['tainted'] &&
8037- chat.splice(0, chat.length, message);
8034+ (chat.length === 0 || (chat.length === 1 && !chat[0].is_user && !chat[0].is_system));
8038- const messageId = (chat.length - 1);
8035+
8039- await eventSource.emit(event_types.MESSAGE_RECEIVED, messageId);
8036+ if (shouldRegenerateMessage) {
8040- await clearChat();
8037+ chat.splice(0, chat.length, message);
8041- await printMessages();
8038+ const messageId = (chat.length - 1);
80428039 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDEREDMESSAGE_RECEIVED, messageId);
80438040 await saveChatConditionalclearChat();
8044- }
8041+ await printMessages();
8045- },
8042+ await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId);
8046- error: function (jqXHR, exception) {
8043+ await saveChatConditional();
8047- $('#create_button').removeAttr('disabled');
8044+ }
8048- console.log('Error! Either a file with the same name already existed, or the image file provided was in an invalid format. Double check that the image is not a webp.');
8045+ } catch (error) {
8049- toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.');
8046+ console.log(error);
8050- },
8047+ toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.');
80518048 });
80528049 }
80538050}
80548051