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) {
7892 formData.set('avatar', convertedFile);7892 formData.set('avatar', convertedFile);
7893 }7893 }
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 {
7902 //if the character name text area isn't empty (only posible when creating a new character)7908 //if the character name text area isn't empty (only posible when creating a new character)
7903 let url = '/api/characters/create';7909 let url = '/api/characters/create';
79047910
@@ -7913,142 +7919,133 @@ async function createOrEditCharacter(e) {
79137919
7914 formData.append('extensions', JSON.stringify(create_save.extensions));7920 formData.append('extensions', JSON.stringify(create_save.extensions));
79157921
7916 await jQuery.ajax({7922 const fetchResult = await fetch(url, {
7917 type: 'POST',7923 method: 'POST',
7918 url: url,7924 headers: headers,
7919 data: formData,7925 body: 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
7967 $('#create_button').attr('value', '✅');7969 $('#add_avatar_button').replaceWith(
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');
7987 }7989 }
7988 } else {7990 } else {
7989 let url = '/api/characters/edit';7991 try {
7992 let url = '/api/characters/edit';
79907993
7991 if (crop_data != undefined) {7994 if (crop_data != undefined) {
7992 url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;7995 url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
7993 }7996 }
79947997
7995 formData.delete('alternate_greetings');7998 formData.delete('alternate_greetings');
7996 const chid = $('.open_alternate_greetings').data('chid');7999 const chid = $('.open_alternate_greetings').data('chid');
7997 if (chid && Array.isArray(characters[chid]?.data?.alternate_greetings)) {8000 if (chid && Array.isArray(characters[chid]?.data?.alternate_greetings)) {
7998 for (const value of characters[chid].data.alternate_greetings) {8001 for (const value of characters[chid].data.alternate_greetings) {
7999 formData.append('alternate_greetings', value);8002 formData.append('alternate_greetings', value);
8003 }
8000 }8004 }
8001 }
80028005
8003 await jQuery.ajax({8006 const fetchResult = await fetch(url, {
8004 type: 'POST',8007 method: 'POST',
8005 url: url,8008 headers: headers,
8006 data: formData,8009 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 state8014 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
8023 $('#create_button').attr('value', 'Save');8020 $('#add_avatar_button').replaceWith(
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 );
80268023 $('#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 &&
80358032 !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);
8042 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId);8039 await eventSource.emit(event_types.MESSAGE_RECEIVED, messageId);
8043 await saveChatConditional();8040 await clearChat();
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.');
8051 });8048 }
8052 }8049 }
8053}8050}
80548051