Merge branch 'staging' into connection-manager
| @@ -1916,17 +1916,26 @@ | |||
| 1916 | <form action="javascript:void(null);" method="post" enctype="multipart/form-data"> | 1916 | <form action="javascript:void(null);" method="post" enctype="multipart/form-data"> |
| 1917 | <div id="kobold_horde_block"> | 1917 | <div id="kobold_horde_block"> |
| 1918 | <ul> | 1918 | <ul> |
| 1919 | <li data-i18n="Avoid sending sensitive information to the Horde."> | 1919 | <li> |
| 1920 | Avoid sending sensitive information to the Horde. | 1920 | <a target="_blank" href="https://aihorde.net/" data-i18n="KoboldAI Horde Website"> |
| 1921 | <a target="_blank" href="https://docs.sillytavern.app/usage/api-connections/horde/" data-i18n="Review the Privacy statement">Review the Privacy statement</a> | 1921 | KoboldAI Horde Website |
| 1922 | </a> | ||
| 1923 | </li> | ||
| 1924 | <li> | ||
| 1925 | <span data-i18n="Avoid sending sensitive information to the Horde.">Avoid sending sensitive information to the Horde.</span> | ||
| 1926 | <a target="_blank" href="https://docs.sillytavern.app/usage/api-connections/horde/" data-i18n="Review the Privacy statement"> | ||
| 1927 | Review the Privacy statement | ||
| 1928 | </a> | ||
| 1922 | </li> | 1929 | </li> |
| 1923 | <li> | 1930 | <li> |
| 1924 | <a target="_blank" href="https://horde.koboldai.net/register" data-i18n="Register a Horde account for faster queue times">Register a Horde | 1931 | <a target="_blank" href="https://aihorde.net/register" data-i18n="Register a Horde account for faster queue times"> |
| 1925 | account for faster queue times</a> | 1932 | Register a Horde account for faster queue times |
| 1933 | </a> | ||
| 1926 | </li> | 1934 | </li> |
| 1927 | <li> | 1935 | <li> |
| 1928 | <a target="_blank" href="https://github.com/Haidra-Org/horde-worker-reGen?tab=readme-ov-file#ai-horde-worker-regen" data-i18n="Learn how to contribute your idle GPU cycles to the Horde">Learn | 1936 | <a target="_blank" href="https://github.com/Haidra-Org/horde-worker-reGen?tab=readme-ov-file#ai-horde-worker-regen" data-i18n="Learn how to contribute your idle GPU cycles to the Horde"> |
| 1929 | how to contribute your idle GPU cycles to the Horde</a> | 1937 | Learn how to contribute your idle GPU cycles to the Horde |
| 1938 | </a> | ||
| 1930 | </li> | 1939 | </li> |
| 1931 | </ul> | 1940 | </ul> |
| 1932 | <label for="horde_auto_adjust_context_length" class="checkbox_label"> | 1941 | <label for="horde_auto_adjust_context_length" class="checkbox_label"> |
| @@ -1944,12 +1953,9 @@ | |||
| 1944 | <small id="adjustedHordeParams">Context: --, Response: --</small> | 1953 | <small id="adjustedHordeParams">Context: --, Response: --</small> |
| 1945 | <h4 data-i18n="API key">API key</h4> | 1954 | <h4 data-i18n="API key">API key</h4> |
| 1946 | <small> | 1955 | <small> |
| 1947 | <span data-i18n="Get it here:">Get it here: </span> <a target="_blank" href="https://horde.koboldai.net/register" data-i18n="Register">Register</a> (<a id="horde_kudos" href="javascript:void(0);" data-i18n="View my Kudos">View my Kudos</a>)<br> | 1956 | <span data-i18n="Get it here:">Get it here: </span> <a target="_blank" href="https://aihorde.net/register" data-i18n="Register">Register</a> (<a id="horde_kudos" href="javascript:void(0);" data-i18n="View my Kudos">View my Kudos</a>)<br> |
| 1948 | <span data-i18n="Enter">Enter </span> <span class="monospace">0000000000</span> <span data-i18n="to use anonymous mode.">to use anonymous mode. </span> | 1957 | <span data-i18n="Enter">Enter </span> <span class="monospace">0000000000</span> <span data-i18n="to use anonymous mode.">to use anonymous mode. </span> |
| 1949 | </small> | 1958 | </small> |
| 1950 | <!-- <div> | ||
| 1951 | <a id="horde_kudos" href="javascript:void(0);">View my Kudos</a> | ||
| 1952 | </div> --> | ||
| 1953 | <div class="flex-container"> | 1959 | <div class="flex-container"> |
| 1954 | <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" type="text" placeholder="0000000000" autocomplete="off"> | 1960 | <input id="horde_api_key" name="horde_api_key" class="text_pole flex1" type="text" placeholder="0000000000" autocomplete="off"> |
| 1955 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div> | 1961 | <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_horde"></div> |
| @@ -4333,7 +4339,10 @@ | |||
| 4333 | </div> | 4339 | </div> |
| 4334 | <div id="Backgrounds" class="drawer-content closedDrawer"> | 4340 | <div id="Backgrounds" class="drawer-content closedDrawer"> |
| 4335 | <div class="flex-container"> | 4341 | <div class="flex-container"> |
| 4336 | <div class="flex-container wide100p"> | 4342 | <div class="flex-container alignItemsBaseline wide100p"> |
| 4343 | <h3 class="margin0 flex2" data-i18n="Background Image"> | ||
| 4344 | Background Image | ||
| 4345 | </h3> | ||
| 4337 | <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" /> | 4346 | <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" /> |
| 4338 | <div id="auto_background" class="menu_button menu_button_icon" data-i18n="[title]Automatically select a background based on the chat context" title="Automatically select a background based on the chat context."> | 4347 | <div id="auto_background" class="menu_button menu_button_icon" data-i18n="[title]Automatically select a background based on the chat context" title="Automatically select a background based on the chat context."> |
| 4339 | <i class="fa-solid fa-wand-magic"></i> | 4348 | <i class="fa-solid fa-wand-magic"></i> |
| @@ -92,7 +92,7 @@ const showPopupHelper = { | |||
| 92 | * @param {string?} header - The header text for the popup. | 92 | * @param {string?} header - The header text for the popup. |
| 93 | * @param {string?} text - The main text for the popup. | 93 | * @param {string?} text - The main text for the popup. |
| 94 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. | 94 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. |
| 95 | * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction. | 95 | * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction. |
| 96 | */ | 96 | */ |
| 97 | confirm: async (header, text, popupOptions = {}) => { | 97 | confirm: async (header, text, popupOptions = {}) => { |
| 98 | const content = PopupUtils.BuildTextWithHeader(header, text); | 98 | const content = PopupUtils.BuildTextWithHeader(header, text); |
| @@ -107,7 +107,7 @@ const showPopupHelper = { | |||
| 107 | * @param {string?} header - The header text for the popup. | 107 | * @param {string?} header - The header text for the popup. |
| 108 | * @param {string?} text - The main text for the popup. | 108 | * @param {string?} text - The main text for the popup. |
| 109 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. | 109 | * @param {PopupOptions} [popupOptions={}] - Options for the popup. |
| 110 | * @return {Promise<POPUP_RESULT>} A Promise that resolves with the result of the user's interaction. | 110 | * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction. |
| 111 | */ | 111 | */ |
| 112 | text: async (header, text, popupOptions = {}) => { | 112 | text: async (header, text, popupOptions = {}) => { |
| 113 | const content = PopupUtils.BuildTextWithHeader(header, text); | 113 | const content = PopupUtils.BuildTextWithHeader(header, text); |
| @@ -1267,20 +1267,59 @@ export function initDefaultSlashCommands() { | |||
| 1267 | callback: popupCallback, | 1267 | callback: popupCallback, |
| 1268 | returns: 'popup text', | 1268 | returns: 'popup text', |
| 1269 | namedArgumentList: [ | 1269 | namedArgumentList: [ |
| 1270 | new SlashCommandNamedArgument( | 1270 | SlashCommandNamedArgument.fromProps({ |
| 1271 | 'large', 'show large popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(), | 1271 | name: 'large', |
| 1272 | ), | 1272 | description: 'show large popup', |
| 1273 | new SlashCommandNamedArgument( | 1273 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1274 | 'wide', 'show wide popup', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(), | 1274 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1275 | ), | 1275 | defaultValue: 'false', |
| 1276 | new SlashCommandNamedArgument( | 1276 | }), |
| 1277 | 'okButton', 'text for the OK button', [ARGUMENT_TYPE.STRING], false, | 1277 | SlashCommandNamedArgument.fromProps({ |
| 1278 | ), | 1278 | name: 'wide', |
| 1279 | description: 'show wide popup', | ||
| 1280 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1281 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1282 | defaultValue: 'false', | ||
| 1283 | }), | ||
| 1284 | SlashCommandNamedArgument.fromProps({ | ||
| 1285 | name: 'wider', | ||
| 1286 | description: 'show wider popup', | ||
| 1287 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1288 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1289 | defaultValue: 'false', | ||
| 1290 | }), | ||
| 1291 | SlashCommandNamedArgument.fromProps({ | ||
| 1292 | name: 'transparent', | ||
| 1293 | description: 'show transparent popup', | ||
| 1294 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1295 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1296 | defaultValue: 'false', | ||
| 1297 | }), | ||
| 1298 | SlashCommandNamedArgument.fromProps({ | ||
| 1299 | name: 'okButton', | ||
| 1300 | description: 'text for the OK button', | ||
| 1301 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 1302 | defaultValue: 'OK', | ||
| 1303 | }), | ||
| 1304 | SlashCommandNamedArgument.fromProps({ | ||
| 1305 | name: 'cancelButton', | ||
| 1306 | description: 'text for the Cancel button', | ||
| 1307 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 1308 | }), | ||
| 1309 | SlashCommandNamedArgument.fromProps({ | ||
| 1310 | name: 'result', | ||
| 1311 | description: 'if enabled, returns the popup result (as an integer) instead of the popup text. Resolves to 1 for OK and 0 cancel button, empty string for exiting out.', | ||
| 1312 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1313 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1314 | defaultValue: 'false', | ||
| 1315 | }), | ||
| 1279 | ], | 1316 | ], |
| 1280 | unnamedArgumentList: [ | 1317 | unnamedArgumentList: [ |
| 1281 | new SlashCommandArgument( | 1318 | SlashCommandArgument.fromProps({ |
| 1282 | 'text', [ARGUMENT_TYPE.STRING], true, | 1319 | description: 'popup text', |
| 1283 | ), | 1320 | typeList: [ARGUMENT_TYPE.STRING], |
| 1321 | isRequired: true, | ||
| 1322 | }), | ||
| 1284 | ], | 1323 | ], |
| 1285 | helpString: ` | 1324 | helpString: ` |
| 1286 | <div> | 1325 | <div> |
| @@ -1291,7 +1330,10 @@ export function initDefaultSlashCommands() { | |||
| 1291 | <strong>Example:</strong> | 1330 | <strong>Example:</strong> |
| 1292 | <ul> | 1331 | <ul> |
| 1293 | <li> | 1332 | <li> |
| 1294 | <pre><code>/popup large=on wide=on okButton="Submit" Enter some text:</code></pre> | 1333 | <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre> |
| 1334 | </li> | ||
| 1335 | <li> | ||
| 1336 | <pre><code>/popup okButton="Left" cancelButton="Right" result=true Do you want to go left or right? | /echo 0 means right, 1 means left. Choice: {{pipe}}</code></pre> | ||
| 1295 | </li> | 1337 | </li> |
| 1296 | </ul> | 1338 | </ul> |
| 1297 | </div> | 1339 | </div> |
| @@ -1574,6 +1616,13 @@ export function initDefaultSlashCommands() { | |||
| 1574 | defaultValue: 'true', | 1616 | defaultValue: 'true', |
| 1575 | enumList: commonEnumProviders.boolean('trueFalse')(), | 1617 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1576 | }), | 1618 | }), |
| 1619 | SlashCommandNamedArgument.fromProps({ | ||
| 1620 | name: 'quiet', | ||
| 1621 | description: 'suppress the toast message on API change', | ||
| 1622 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 1623 | defaultValue: 'false', | ||
| 1624 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 1625 | }), | ||
| 1577 | ], | 1626 | ], |
| 1578 | unnamedArgumentList: [ | 1627 | unnamedArgumentList: [ |
| 1579 | SlashCommandArgument.fromProps({ | 1628 | SlashCommandArgument.fromProps({ |
| @@ -1882,16 +1931,21 @@ async function buttonsCallback(args, text) { | |||
| 1882 | } | 1931 | } |
| 1883 | 1932 | ||
| 1884 | async function popupCallback(args, value) { | 1933 | async function popupCallback(args, value) { |
| 1885 | const safeValue = DOMPurify.sanitize(value || ''); | 1934 | const safeBody = DOMPurify.sanitize(value || ''); |
| 1935 | const safeHeader = args?.header && typeof args?.header === 'string' ? DOMPurify.sanitize(args.header) : null; | ||
| 1936 | const requestedResult = isTrueBoolean(args?.result); | ||
| 1937 | |||
| 1938 | /** @type {import('./popup.js').PopupOptions} */ | ||
| 1886 | const popupOptions = { | 1939 | const popupOptions = { |
| 1887 | large: isTrueBoolean(args?.large), | 1940 | large: isTrueBoolean(args?.large), |
| 1888 | wide: isTrueBoolean(args?.wide), | 1941 | wide: isTrueBoolean(args?.wide), |
| 1942 | wider: isTrueBoolean(args?.wider), | ||
| 1943 | transparent: isTrueBoolean(args?.transparent), | ||
| 1889 | okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok', | 1944 | okButton: args?.okButton !== undefined && typeof args?.okButton === 'string' ? args.okButton : 'Ok', |
| 1945 | cancelButton: args?.cancelButton !== undefined && typeof args?.cancelButton === 'string' ? args.cancelButton : null, | ||
| 1890 | }; | 1946 | }; |
| 1891 | await delay(1); | 1947 | const result = await Popup.show.text(safeHeader, safeBody, popupOptions); |
| 1892 | await callGenericPopup(safeValue, POPUP_TYPE.TEXT, '', popupOptions); | 1948 | return String(requestedResult ? result ?? '' : value); |
| 1893 | await delay(1); | ||
| 1894 | return String(value); | ||
| 1895 | } | 1949 | } |
| 1896 | 1950 | ||
| 1897 | async function getMessagesCallback(args, value) { | 1951 | async function getMessagesCallback(args, value) { |
| @@ -3530,10 +3584,12 @@ function setPromptEntryCallback(args, targetState) { | |||
| 3530 | * @param {object} args - named args | 3584 | * @param {object} args - named args |
| 3531 | * @param {string?} [args.api=null] - the API name to set/get the URL for | 3585 | * @param {string?} [args.api=null] - the API name to set/get the URL for |
| 3532 | * @param {string?} [args.connect=true] - whether to connect to the API after setting | 3586 | * @param {string?} [args.connect=true] - whether to connect to the API after setting |
| 3587 | * @param {string?} [args.quiet=false] - whether to suppress toasts | ||
| 3533 | * @param {string} url - the API URL to set | 3588 | * @param {string} url - the API URL to set |
| 3534 | * @returns {Promise<string>} | 3589 | * @returns {Promise<string>} |
| 3535 | */ | 3590 | */ |
| 3536 | async function setApiUrlCallback({ api = null, connect = 'true' }, url) { | 3591 | async function setApiUrlCallback({ api = null, connect = 'true', quiet = 'false' }, url) { |
| 3592 | const isQuiet = isTrueBoolean(quiet); | ||
| 3537 | const autoConnect = isTrueBoolean(connect); | 3593 | const autoConnect = isTrueBoolean(connect); |
| 3538 | 3594 | ||
| 3539 | // Special handling for Chat Completion Custom OpenAI compatible, that one can also support API url handling | 3595 | // Special handling for Chat Completion Custom OpenAI compatible, that one can also support API url handling |
| @@ -3582,22 +3638,26 @@ async function setApiUrlCallback({ api = null, connect = 'true' }, url) { | |||
| 3582 | 3638 | ||
| 3583 | // Do some checks and get the api type we are targeting with this command | 3639 | // Do some checks and get the api type we are targeting with this command |
| 3584 | if (api && !Object.values(textgen_types).includes(api)) { | 3640 | if (api && !Object.values(textgen_types).includes(api)) { |
| 3585 | toastr.warning(`API '${api}' is not a valid text_gen API.`); | 3641 | !isQuiet && toastr.warning(`API '${api}' is not a valid text_gen API.`); |
| 3586 | return ''; | 3642 | return ''; |
| 3587 | } | 3643 | } |
| 3588 | if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) { | 3644 | if (!api && !Object.values(textgen_types).includes(textgenerationwebui_settings.type)) { |
| 3589 | toastr.warning(`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`); | 3645 | !isQuiet && toastr.warning(`API '${textgenerationwebui_settings.type}' is not a valid text_gen API.`); |
| 3646 | return ''; | ||
| 3647 | } | ||
| 3648 | if (!api && main_api !== 'textgenerationwebui') { | ||
| 3649 | !isQuiet && toastr.warning(`API type '${main_api}' does not support setting the server URL.`); | ||
| 3590 | return ''; | 3650 | return ''; |
| 3591 | } | 3651 | } |
| 3592 | if (api && url && autoConnect && api !== textgenerationwebui_settings.type) { | 3652 | if (api && url && autoConnect && api !== textgenerationwebui_settings.type) { |
| 3593 | toastr.warning(`API '${api}' is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.`); | 3653 | !isQuiet && toastr.warning(`API '${api}' is not the currently selected API, so we cannot do an auto-connect. Consider switching to it via /api beforehand.`); |
| 3594 | return ''; | 3654 | return ''; |
| 3595 | } | 3655 | } |
| 3596 | const type = api || textgenerationwebui_settings.type; | 3656 | const type = api || textgenerationwebui_settings.type; |
| 3597 | 3657 | ||
| 3598 | const inputSelector = SERVER_INPUTS[type]; | 3658 | const inputSelector = SERVER_INPUTS[type]; |
| 3599 | if (!inputSelector) { | 3659 | if (!inputSelector) { |
| 3600 | toastr.warning(`API '${type}' does not have a server url input.`); | 3660 | !isQuiet && toastr.warning(`API '${type}' does not have a server url input.`); |
| 3601 | return ''; | 3661 | return ''; |
| 3602 | } | 3662 | } |
| 3603 | 3663 | ||