Move Kobold Classic settings into related module (#4234) * Move Kobold Classic settings into related module * Update public/scripts/kai-settings.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

e0469b48087ae402ddbc2f9ac248dcab0cc80264

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

Signed
6 files changed, +175 -180Ignore whitespace
public/script.js+16 -165
@@ -17,10 +17,11 @@ import {
1717 generateKoboldWithStreaming,
1818 kai_settings,
1919 loadKoboldSettings,
20- formatKoboldUrl,
2120 getKoboldGenerationData,
2221 kai_flags,
2322 setKoboldFlagskoboldai_settings,
23+ koboldai_setting_names,
24+ initKoboldSettings,
2425} from './scripts/kai-settings.js';
2526
2627import {
@@ -303,9 +304,6 @@ globalThis.SillyTavern = {
303304 getContext,
304305};
305306
306-/**
307- * Exports that were once part of this module. For backwards compatibility.
308- */
309307export {
310308 user_avatar,
311309 setUserAvatar,
@@ -324,6 +322,8 @@ export {
324322 replaceItemizedPromptText,
325323 deleteItemizedPrompts,
326324 findItemizedPromptSet,
325+ koboldai_settings,
326+ koboldai_setting_names,
327327};
328328
329329/**
@@ -900,8 +900,6 @@ let popup_type = '';
900900let chat_file_for_del = '';
901901export let online_status = 'no_connection';
902902
903-export let api_server = '';
904-
905903export let is_send_press = false; //Send generation
906904
907905let this_del_mes = -1;
@@ -912,9 +910,6 @@ var this_edit_mes_id;
912910
913911//settings
914912export let settings;
915-export let koboldai_settings;
916-export let koboldai_setting_names;
917-var preset_settings = 'gui';
918913export let amount_gen = 80; //default max length of AI generated responses
919914export let max_context = 2048;
920915
@@ -1009,6 +1004,7 @@ async function firstLoadInit() {
10091004 initDefaultSlashCommands();
10101005 initTextGenModels();
10111006 initOpenAI();
1007+ initKoboldSettings();
10121008 initSystemPrompts();
10131009 initExtensions();
10141010 initExtensionSlashCommands();
@@ -1120,52 +1116,6 @@ async function getStatusHorde() {
11201116 return resultCheckStatus();
11211117}
11221118
1123-async function getStatusKobold() {
1124- let endpoint = api_server;
1125-
1126- if (!endpoint) {
1127- console.warn('No endpoint for status check');
1128- setOnlineStatus('no_connection');
1129- return resultCheckStatus();
1130- }
1131-
1132- try {
1133- const response = await fetch('/api/backends/kobold/status', {
1134- method: 'POST',
1135- headers: getRequestHeaders(),
1136- body: JSON.stringify({
1137- main_api,
1138- api_server: endpoint,
1139- }),
1140- signal: abortStatusCheck.signal,
1141- });
1142-
1143- const data = await response.json();
1144-
1145- setOnlineStatus(data?.model ?? 'no_connection');
1146-
1147- if (!data.koboldUnitedVersion) {
1148- throw new Error('Missing mandatory Kobold version in data:', data);
1149- }
1150-
1151- // Determine instruct mode preset
1152- autoSelectInstructPreset(online_status);
1153-
1154- // determine if we can use stop sequence and streaming
1155- setKoboldFlags(data.koboldUnitedVersion, data.koboldCppVersion);
1156-
1157- // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress.
1158- if (online_status === 'no_connection' && data.response) {
1159- toastr.error(data.response, t`API Error`, { timeOut: 5000, preventDuplicates: true });
1160- }
1161- } catch (err) {
1162- console.error('Error getting status', err);
1163- setOnlineStatus('no_connection');
1164- }
1165-
1166- return resultCheckStatus();
1167-}
1168-
11691119async function getStatusTextgen() {
11701120 const url = '/api/backends/text-completions/status';
11711121
@@ -3716,11 +3666,11 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
37163666 switch (api) {
37173667 case 'kobold':
37183668 case 'koboldhorde':
37193669 if (kai_settings.preset_settings === 'gui') {
37203670 generateData = { prompt: prompt, gui_settings: true, max_length: amount_gen, max_context_length: max_context, api_server: kai_settings.api_server };
37213671 } else {
37223672 const isHorde = api === 'koboldhorde';
37233673 const koboldSettings = koboldai_settings[koboldai_setting_names[kai_settings.preset_settings]];
37243674 generateData = getKoboldGenerationData(prompt, koboldSettings, amount_gen, max_context, isHorde, 'quiet');
37253675 }
37263676 TempResponseLength.restore(api);
@@ -4871,12 +4821,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
48714821 gui_settings: true,
48724822 max_length: maxLength,
48734823 max_context_length: max_context,
48744824 api_server: kai_settings.api_server,
48754825 };
48764826
48774827 if (kai_settings.preset_settings != 'gui') {
48784828 const isHorde = main_api == 'koboldhorde';
48794829 const presetSettings = koboldai_settings[koboldai_setting_names[kai_settings.preset_settings]];
48804830 const maxContext = (adjustedParams && horde_settings.auto_adjust_context_length) ? adjustedParams.maxContextLength : max_context;
48814831 generate_data = getKoboldGenerationData(finalPrompt, presetSettings, maxLength, maxContext, isHorde, type);
48824832 }
@@ -7329,47 +7279,12 @@ export async function getSettings() {
73297279 // Allow subscribers to mutate settings
73307280 await eventSource.emit(event_types.SETTINGS_LOADED_BEFORE, settings);
73317281
7332- //Load KoboldAI settings
7333- koboldai_setting_names = data.koboldai_setting_names;
7334- koboldai_settings = data.koboldai_settings;
7335- koboldai_settings.forEach(function (item, i, arr) {
7336- koboldai_settings[i] = JSON.parse(item);
7337- });
7338-
7339- let arr_holder = {};
7340-
7341- $('#settings_preset').empty();
7342- $('#settings_preset').append(
7343- '<option value="gui">GUI KoboldAI Settings</option>',
7344- ); //adding in the GUI settings, since it is not loaded dynamically
7345-
7346- koboldai_setting_names.forEach(function (item, i, arr) {
7347- arr_holder[item] = i;
7348- $('#settings_preset').append(`<option value=${i}>${item}</option>`);
7349- //console.log('loading preset #'+i+' -- '+item);
7350- });
7351- koboldai_setting_names = {};
7352- koboldai_setting_names = arr_holder;
7353- preset_settings = settings.preset_settings;
7354-
7355- if (preset_settings == 'gui') {
7356- selectKoboldGuiPreset();
7357- } else {
7358- if (typeof koboldai_setting_names[preset_settings] !== 'undefined') {
7359- $(`#settings_preset option[value=${koboldai_setting_names[preset_settings]}]`)
7360- .attr('selected', 'true');
7361- } else {
7362- preset_settings = 'gui';
7363- selectKoboldGuiPreset();
7364- }
7365- }
7366-
73677282 novelai_setting_names = data.novelai_setting_names;
73687283 novelai_settings = data.novelai_settings;
73697284 novelai_settings.forEach(function (item, i, arr) {
73707285 novelai_settings[i] = JSON.parse(item);
73717286 });
73727287 const arr_holder = {};
73737288
73747289 $('#settings_preset_novel').empty();
73757290
@@ -7381,7 +7296,6 @@ export async function getSettings() {
73817296 novelai_setting_names = arr_holder;
73827297
73837298 //Load AI model config settings
7384-
73857299 amount_gen = settings.amount_gen;
73867300 if (settings.max_context !== undefined)
73877301 max_context = parseInt(settings.max_context);
@@ -7392,7 +7306,7 @@ export async function getSettings() {
73927306 showSwipeButtons();
73937307
73947308 // Kobold
73957309 loadKoboldSettings(data, settings.kai_settings ?? settings, settings);
73967310
73977311 // Novel
73987312 loadNovelSettings(settings.nai_settings ?? settings);
@@ -7401,7 +7315,6 @@ export async function getSettings() {
74017315 // TextGen
74027316 loadTextGenSettings(data, settings);
74037317
7404-
74057318 // OpenAI
74067319 loadOpenAISettings(data, settings.oai_settings ?? settings);
74077320
@@ -7444,13 +7357,9 @@ export async function getSettings() {
74447357
74457358 main_api = settings.main_api;
74467359 $('#main_api').val(main_api);
74477360 $('`#main_api option[value=' + ${main_api + '}]'`).attr('selected', 'true');
7448- 'selected',
7449- 'true',
7450- );
74517361 changeMainAPI();
74527362
7453-
74547363 //Load User's Name and Avatar
74557364 initUserAvatar(settings.user_avatar);
74567365 setPersonaDescription();
@@ -7459,10 +7368,6 @@ export async function getSettings() {
74597368 active_character = settings.active_character;
74607369 active_group = settings.active_group;
74617370
7462- //Load the API server URL from settings
7463- api_server = settings.api_server;
7464- $('#api_url_text').val(api_server);
7465-
74667371 setWorldInfoSettings(settings.world_info_settings ?? settings, data);
74677372
74687373 selected_button = settings.selected_button;
@@ -7487,12 +7392,6 @@ export async function getSettings() {
74877392 await eventSource.emit(event_types.SETTINGS_LOADED);
74887393}
74897394
7490-function selectKoboldGuiPreset() {
7491- $('#settings_preset option[value=gui]')
7492- .attr('selected', 'true')
7493- .trigger('change');
7494-}
7495-
74967395//MARK: saveSettings()
74977396export async function saveSettings(loopCounter = 0) {
74987397 if (!settingsReady) {
@@ -7523,8 +7422,6 @@ export async function saveSettings(loopCounter = 0) {
75237422 username: name1,
75247423 active_character: active_character,
75257424 active_group: active_group,
7526- api_server: api_server,
7527- preset_settings: preset_settings,
75287425 user_avatar: user_avatar,
75297426 amount_gen: amount_gen,
75307427 max_context: max_context,
@@ -8609,7 +8506,7 @@ export function setGenerationProgress(progress) {
86098506}
86108507
86118508function isHordeGenerationNotAllowed() {
86128509 if (main_api == 'koboldhorde' && kai_settings.preset_settings == 'gui') {
86138510 toastr.error(t`GUI Settings preset is not supported for Horde. Please select another preset.`);
86148511 return true;
86158512 }
@@ -10893,27 +10790,6 @@ jQuery(async function () {
1089310790 }
1089410791 });
1089510792
10896- ///////////////////////////////////////////////////////////////////////////////////
10897-
10898- $('#api_button').on('click', function (e) {
10899- if ($('#api_url_text').val() != '') {
10900- let value = formatKoboldUrl(String($('#api_url_text').val()).trim());
10901-
10902- if (!value) {
10903- toastr.error('Please enter a valid URL.');
10904- return;
10905- }
10906-
10907- $('#api_url_text').val(value);
10908- api_server = value;
10909- startStatusLoading();
10910-
10911- main_api = 'kobold';
10912- saveSettingsDebounced();
10913- getStatusKobold();
10914- }
10915- });
10916-
1091710793 $('#api_button_textgenerationwebui').on('click', async function (e) {
1091810794 const keys = [
1091910795 { id: 'api_key_mancer', secret: SECRET_KEYS.MANCER },
@@ -11184,31 +11060,6 @@ jQuery(async function () {
1118411060 is_delete_mode = false;
1118511061 });
1118611062
11187- $('#settings_preset').on('change', function () {
11188- if ($('#settings_preset').find(':selected').val() != 'gui') {
11189- preset_settings = $('#settings_preset').find(':selected').text();
11190- const preset = koboldai_settings[koboldai_setting_names[preset_settings]];
11191- loadKoboldSettings(preset);
11192- setGenerationParamsFromPreset(preset);
11193- $('#kobold_api-settings').find('input').prop('disabled', false);
11194- $('#kobold_api-settings').css('opacity', 1.0);
11195- $('#kobold_order')
11196- .css('opacity', 1)
11197- .sortable('enable');
11198- } else {
11199- //$('.button').disableSelection();
11200- preset_settings = 'gui';
11201-
11202- $('#kobold_api-settings').find('input').prop('disabled', true);
11203- $('#kobold_api-settings').css('opacity', 0.5);
11204-
11205- $('#kobold_order')
11206- .css('opacity', 0.5)
11207- .sortable('disable');
11208- }
11209- saveSettingsDebounced();
11210- });
11211-
1121211063 $('#settings_preset_novel').on('change', function () {
1121311064 nai_settings.preset_settings_novel = $('#settings_preset_novel')
1121411065 .find(':selected')
public/scripts/RossAscends-mods.js+2 -2
@@ -4,7 +4,6 @@ import {
44 characters,
55 online_status,
66 main_api,
7- api_server,
87 is_send_press,
98 max_context,
109 saveSettingsDebounced,
@@ -42,6 +41,7 @@ import { debounce_timeout } from './constants.js';
4241import { Popup } from './popup.js';
4342import { accountStorage } from './util/AccountStorage.js';
4443import { getCurrentUserHandle } from './user.js';
44+import { kai_settings } from './kai-settings.js';
4545
4646var RPanelPin = document.getElementById('rm_button_panel_pin');
4747var LPanelPin = document.getElementById('lm_button_panel_pin');
@@ -371,7 +371,7 @@ function RA_autoconnect(PrevApi) {
371371 if (online_status === 'no_connection' && power_user.auto_connect) {
372372 switch (main_api) {
373373 case 'kobold':
374374 if (kai_settings.api_server && isValidUrl(kai_settings.api_server)) {
375375 $('#api_button').trigger('click');
376376 }
377377 break;
public/scripts/kai-settings.js+148 -6
@@ -3,8 +3,16 @@ import {
33 saveSettingsDebounced,
44 getStoppingStrings,
55 substituteParams,
66 api_serversetOnlineStatus,
7+ resultCheckStatus,
8+ main_api,
9+ online_status,
10+ abortStatusCheck,
11+ startStatusLoading,
12+ setGenerationParamsFromPreset,
713} from '../script.js';
14+import { t } from './i18n.js';
15+import { autoSelectInstructPreset } from './instruct-mode.js';
816
917import {
1018 power_user,
@@ -12,6 +20,9 @@ import {
1220import { getEventSourceStream } from './sse-stream.js';
1321import { getSortableDelay } from './utils.js';
1422
23+export let koboldai_settings;
24+export let koboldai_setting_names;
25+
1526export const kai_settings = {
1627 temp: 1,
1728 rep_pen: 1,
@@ -31,6 +42,8 @@ export const kai_settings = {
3142 use_default_badwordsids: false,
3243 grammar: '',
3344 seed: -1,
45+ api_server: '',
46+ preset_settings: 'gui',
3447};
3548
3649/**
@@ -72,7 +85,50 @@ export function formatKoboldUrl(value) {
7285 return null;
7386}
7487
7588export function loadKoboldSettingsselectKoboldGuiPreset(preset) {
89+ $('#settings_preset option[value=gui]')
90+ .attr('selected', 'true')
91+ .trigger('change');
92+}
93+
94+export function loadKoboldSettings(data, preset, settings) {
95+ koboldai_setting_names = data.koboldai_setting_names;
96+ koboldai_settings = data.koboldai_settings;
97+ koboldai_settings.forEach(function (item, i, arr) {
98+ koboldai_settings[i] = JSON.parse(item);
99+ });
100+
101+ $('#settings_preset').empty();
102+ $('#settings_preset').append('<option value="gui">GUI KoboldAI Settings</option>');
103+ const names = {};
104+ koboldai_setting_names.forEach(function (item, i, arr) {
105+ names[item] = i;
106+ $('#settings_preset').append(`<option value=${i}>${item}</option>`);
107+ });
108+ koboldai_setting_names = names;
109+
110+ kai_settings.preset_settings = preset.preset_settings ?? settings.preset_settings;
111+ kai_settings.api_server = preset.api_server ?? settings.api_server;
112+
113+ if (kai_settings.preset_settings == 'gui') {
114+ selectKoboldGuiPreset();
115+ } else {
116+ if (typeof koboldai_setting_names[kai_settings.preset_settings] !== 'undefined') {
117+ $(`#settings_preset option[value=${koboldai_setting_names[kai_settings.preset_settings]}]`)
118+ .attr('selected', 'true');
119+ } else {
120+ kai_settings.preset_settings = 'gui';
121+ selectKoboldGuiPreset();
122+ }
123+ }
124+
125+ loadKoboldSettingsFromPreset(preset);
126+
127+ //Load the API server URL from settings
128+ $('#api_url_text').val(kai_settings.api_server);
129+}
130+
131+function loadKoboldSettingsFromPreset(preset) {
76132 for (const name of Object.keys(kai_settings)) {
77133 const value = preset[name] ?? defaultValues[name];
78134 const slider = sliders.find(x => x.name === name);
@@ -139,8 +195,7 @@ export function getKoboldGenerationData(finalPrompt, settings, maxLength, maxCon
139195 use_default_badwordsids: (kai_flags.can_use_default_badwordsids || isHorde) ? kai_settings.use_default_badwordsids : undefined,
140196 grammar: (kai_flags.can_use_grammar || isHorde) ? substituteParams(kai_settings.grammar) : undefined,
141197 sampler_seed: kai_settings.seed >= 0 ? kai_settings.seed : undefined,
142-
198+ api_server: kai_settings.api_server,
143- api_server,
144199 };
145200 return generate_data;
146201}
@@ -350,7 +405,53 @@ function sortItemsByOrder(orderArray) {
350405 }
351406}
352407
353408jQuery(export async function getStatusKobold() {
409+ let endpoint = kai_settings.api_server;
410+
411+ if (!endpoint) {
412+ console.warn('No endpoint for status check');
413+ setOnlineStatus('no_connection');
414+ return resultCheckStatus();
415+ }
416+
417+ try {
418+ const response = await fetch('/api/backends/kobold/status', {
419+ method: 'POST',
420+ headers: getRequestHeaders(),
421+ body: JSON.stringify({
422+ main_api,
423+ api_server: endpoint,
424+ }),
425+ signal: abortStatusCheck.signal,
426+ });
427+
428+ const data = await response.json();
429+
430+ setOnlineStatus(data?.model ?? 'no_connection');
431+
432+ if (!data.koboldUnitedVersion) {
433+ throw new Error(`Missing mandatory Kobold version in data: ${JSON.stringify(data)}`);
434+ }
435+
436+ // Determine instruct mode preset
437+ autoSelectInstructPreset(online_status);
438+
439+ // determine if we can use stop sequence and streaming
440+ setKoboldFlags(data.koboldUnitedVersion, data.koboldCppVersion);
441+
442+ // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress.
443+ if (online_status === 'no_connection' && data.response) {
444+ toastr.error(data.response, t`API Error`, { timeOut: 5000, preventDuplicates: true });
445+ }
446+ } catch (err) {
447+ console.error('Error getting status', err);
448+ setOnlineStatus('no_connection');
449+ }
450+
451+ return resultCheckStatus();
452+}
453+
454+export function initKoboldSettings() {
354455 sliders.forEach(slider => {
355456 $(document).on('input', slider.sliderId, function () {
356457 const value = $(this).val();
@@ -361,6 +462,23 @@ jQuery(function () {
361462 });
362463 });
363464
465+ $('#api_button').on('click', function (e) {
466+ if ($('#api_url_text').val() != '') {
467+ const value = formatKoboldUrl(String($('#api_url_text').val()).trim());
468+
469+ if (!value) {
470+ toastr.error('Please enter a valid URL.');
471+ return;
472+ }
473+
474+ $('#api_url_text').val(value);
475+ kai_settings.api_server = value;
476+ startStatusLoading();
477+ saveSettingsDebounced();
478+ getStatusKobold();
479+ }
480+ });
481+
364482 $('#streaming_kobold').on('input', function () {
365483 const value = !!$(this).prop('checked');
366484 kai_settings.streaming_kobold = value;
@@ -391,4 +509,28 @@ jQuery(function () {
391509 sortItemsByOrder(kai_settings.sampler_order);
392510 saveSettingsDebounced();
393511 });
394-});
512+
513+ $('#settings_preset').on('change', function () {
514+ if ($('#settings_preset').find(':selected').val() != 'gui') {
515+ kai_settings.preset_settings = $('#settings_preset').find(':selected').text();
516+ const preset = koboldai_settings[koboldai_setting_names[kai_settings.preset_settings]];
517+ loadKoboldSettingsFromPreset(preset);
518+ setGenerationParamsFromPreset(preset);
519+ $('#kobold_api-settings').find('input').prop('disabled', false);
520+ $('#kobold_api-settings').css('opacity', 1.0);
521+ $('#kobold_order')
522+ .css('opacity', 1)
523+ .sortable('enable');
524+ } else {
525+ kai_settings.preset_settings = 'gui';
526+
527+ $('#kobold_api-settings').find('input').prop('disabled', true);
528+ $('#kobold_api-settings').css('opacity', 0.5);
529+
530+ $('#kobold_order')
531+ .css('opacity', 0.5)
532+ .sortable('disable');
533+ }
534+ saveSettingsDebounced();
535+ });
536+}
public/scripts/preset-manager.js+2 -0
@@ -598,6 +598,7 @@ class PresetManager {
598598 }
599599
600600 const filteredKeys = [
601+ 'api_server',
601602 'preset',
602603 'streaming',
603604 'truncation_length',
@@ -607,6 +608,7 @@ class PresetManager {
607608 'can_use_tokenization',
608609 'can_use_streaming',
609610 'preset_settings_novel',
611+ 'preset_settings',
610612 'streaming_novel',
611613 'nai_preamble',
612614 'model_novel',
public/scripts/slash-commands.js+3 -3
@@ -6,7 +6,6 @@ import {
66 UNIQUE_APIS,
77 activateSendButtons,
88 addOneMessage,
9- api_server,
109 characters,
1110 chat,
1211 chat_metadata,
@@ -80,6 +79,7 @@ import { accountStorage } from './util/AccountStorage.js';
8079import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js';
8180import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
8281import { t } from './i18n.js';
82+import { kai_settings } from './kai-settings.js';
8383export {
8484 executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
8585};
@@ -4555,7 +4555,7 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
45554555 const isCurrentlyKoboldClassic = main_api === 'kobold';
45564556 if (api === 'kobold' || (!api && isCurrentlyKoboldClassic)) {
45574557 if (!url) {
45584558 return kai_settings.api_server ?? '';
45594559 }
45604560
45614561 if (!isCurrentlyKoboldClassic && autoConnect) {
@@ -4571,7 +4571,7 @@ async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false'
45714571 $('#api_button').trigger('click');
45724572 }
45734573
45744574 return kai_settings.api_server ?? '';
45754575 }
45764576
45774577 // Do some checks and get the api type we are targeting with this command
public/scripts/tokenizers.js+4 -4
@@ -1,10 +1,10 @@
11import { localforage } from '../lib.js';
22import { characters, main_api, api_server, nai_settings, online_status, this_chid } from '../script.js';
33import { power_user, registerDebugFunction } from './power-user.js';
44import { chat_completion_sources, model_list, oai_settings } from './openai.js';
55import { groups, selected_group } from './group-chats.js';
66import { getStringHash } from './utils.js';
77import { kai_flags, kai_settings } from './kai-settings.js';
88import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer, getTextGenModel } from './textgen-settings.js';
99import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, openRouterModels } from './textgen-models.js';
1010
@@ -911,7 +911,7 @@ function countTokensFromKoboldAPI(str, resolve) {
911911 url: TOKENIZER_URLS[tokenizers.API_KOBOLD].count,
912912 data: JSON.stringify({
913913 text: str,
914914 url: kai_settings.api_server,
915915 }),
916916 dataType: 'json',
917917 contentType: 'application/json',
@@ -1062,7 +1062,7 @@ function getTextTokensFromKoboldAPI(str, resolve) {
10621062 url: TOKENIZER_URLS[tokenizers.API_KOBOLD].encode,
10631063 data: JSON.stringify({
10641064 text: str,
10651065 url: kai_settings.api_server,
10661066 }),
10671067 dataType: 'json',
10681068 contentType: 'application/json',