From d3be6caaa10ce4ab9250d92a74787c9f10411571 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:22:35 +0300 Subject: [PATCH 01/30] Create CONTRIBUTING.md --- CONTRIBUTING.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..84253f028 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# How to contribute to SillyTavern + +## Setting up the dev environment + +1. Required software: git and node. +2. Recommended editor: Visual Studio Code. +3. You can also use GitHub Codespaces which sets up everything for you. + +## Getting the code ready + +1. Register a GitHub account. +2. Fork this repository under your account. +3. Clone the fork onto your machine. +4. Open the cloned repository in the code editor. +5. Create a git branch (recommended). +6. Make your changes and test them locally. +7. Commit the changes and push the branch to the remote repo. +8. Go to GitHub, and open a pull request, targeting the upstream branch. + +## Contribution guidelines + +1. Our standards are pretty low, but make sure the code is not too ugly: + - Run VS Code's autoformat when you're done. + - Check with ESLint by running `npm run lint`, then fix the errors. + - Use common sense and follow existing naming conventions. +2. Create pull requests for the staging branch, 99% of contributions should go there. That way people could test your code before the next stable release. +3. You can still send a pull request for release in the following scenarios: + - Updating README. + - Updating GitHub Actions. + - Hotfixing a critical bug. +4. Project maintainers will test and can change your code before merging. +5. Mind the license. Your contributions will be licensed under the GNU Affero General Public License. If you don't know what that implies, consult your lawyer. From 62a14fb74b2acb6d03d434a4011cefdbf9da3706 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:22:29 +0300 Subject: [PATCH 02/30] Create PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..e8e292fef --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ +* **Please check if the PR fulfills these requirements** +- [ ] I have read the [contribution guidelines](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md) From c69c5e07e3b1fcdbbc14bf628e43d6a34ad3b18d Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:25:07 +0300 Subject: [PATCH 03/30] Update PULL_REQUEST_TEMPLATE.md --- .github/PULL_REQUEST_TEMPLATE.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e8e292fef..a8d364dc3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,2 +1,3 @@ -* **Please check if the PR fulfills these requirements** -- [ ] I have read the [contribution guidelines](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md) +## Checklist: + +- [ ] I have read the [Contributing guidelines](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md). From 0c129f6dbec09952a197364be1cb2f7a972b5641 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:31:16 +0300 Subject: [PATCH 04/30] Rename PULL_REQUEST_TEMPLATE.md to pull_request_template.md --- .github/{PULL_REQUEST_TEMPLATE.md => pull_request_template.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{PULL_REQUEST_TEMPLATE.md => pull_request_template.md} (100%) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/pull_request_template.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to .github/pull_request_template.md From 3077df40e082367952844734307cedbc0397e381 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:19:28 +0300 Subject: [PATCH 05/30] Update pull_request_template.md --- .github/pull_request_template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index a8d364dc3..608850799 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,5 @@ + + ## Checklist: - [ ] I have read the [Contributing guidelines](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md). From 39c97f9b8939ddb40edbdcc1e7fa3934c26e4a1a Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 00:16:46 +0300 Subject: [PATCH 06/30] Fix undefined reference --- public/scripts/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/utils.js b/public/scripts/utils.js index 1e140a6ae..9e437d30a 100644 --- a/public/scripts/utils.js +++ b/public/scripts/utils.js @@ -803,7 +803,7 @@ export function getImageSizeFromDataURL(dataUrl) { export function getCharaFilename(chid) { const context = getContext(); - const fileName = context.characters[chid ?? context.characterId].avatar; + const fileName = context.characters[chid ?? context.characterId]?.avatar; if (fileName) { return fileName.replace(/\.[^/.]+$/, ''); From c91e7dd948309bbebd0057c019c49a11b4ceaa2d Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 00:59:01 +0300 Subject: [PATCH 07/30] Add relative suffix to timediff macro output --- public/scripts/macros.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/macros.js b/public/scripts/macros.js index ecdb453c6..45ceec334 100644 --- a/public/scripts/macros.js +++ b/public/scripts/macros.js @@ -401,7 +401,7 @@ function timeDiffReplace(input) { const time2 = moment(matchPart2); const timeDifference = moment.duration(time1.diff(time2)); - return timeDifference.humanize(); + return timeDifference.humanize(true); }); return output; From 21c064fc5bc8b21416fe289ec9aee2fd8ce8be69 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 2 Jul 2024 01:28:52 +0200 Subject: [PATCH 08/30] Fix {{currentSwipeId}} not returning first swipe --- public/scripts/macros.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/macros.js b/public/scripts/macros.js index 45ceec334..4d201e3c9 100644 --- a/public/scripts/macros.js +++ b/public/scripts/macros.js @@ -254,7 +254,7 @@ function getCurrentSwipeId() { // For swipe macro, we are accepting using the message that is currently being swiped const mid = getLastMessageId({ exclude_swipe_in_propress: false }); const swipeId = chat[mid]?.swipe_id; - return swipeId ? swipeId + 1 : null; + return swipeId !== null ? swipeId + 1 : null; } /** From 52b64a823daf15a4003a106ec0802acfad979392 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 2 Jul 2024 02:00:39 +0200 Subject: [PATCH 09/30] validate group that all members exist --- public/scripts/group-chats.js | 36 ++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index 3027cb8a6..e85d302ba 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -178,8 +178,37 @@ async function loadGroupChat(chatId) { return []; } +async function validateGroup(group) { + if (!group) return; + + // Validate that all members exist as characters + let dirty = false; + group.members = group.members.filter(member => { + const character = characters.find(x => x.avatar === member || x.name === member); + if (!character) { + const msg = `Warning: Listed member ${member} does not exist as a character. It will be removed from the group.`; + toastr.warning(msg, 'Group Validation'); + console.warn(msg); + dirty = true; + } + return character; + }); + + if (dirty) { + await editGroup(group.id, true, false); + } +} + export async function getGroupChat(groupId, reload = false) { const group = groups.find((x) => x.id === groupId); + if (!group) { + console.warn(`Group not found`, groupId); + return; + } + + // Run validation before any loading + validateGroup(group); + const chat_id = group.chat_id; const data = await loadGroupChat(chat_id); let freshChat = false; @@ -197,7 +226,6 @@ export async function getGroupChat(groupId, reload = false) { if (group && Array.isArray(group.members)) { for (let member of group.members) { const character = characters.find(x => x.avatar === member || x.name === member); - if (!character) { continue; } @@ -219,10 +247,8 @@ export async function getGroupChat(groupId, reload = false) { freshChat = true; } - if (group) { - let metadata = group.chat_metadata ?? {}; - updateChatMetadata(metadata, true); - } + let metadata = group.chat_metadata ?? {}; + updateChatMetadata(metadata, true); if (reload) { select_group_chats(groupId, true); From 08d21e9b17f8291df4984a36c269b04c23dff029 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 2 Jul 2024 02:15:44 +0200 Subject: [PATCH 10/30] Fix warning on dynamic-styles init --- public/scripts/dynamic-styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/dynamic-styles.js b/public/scripts/dynamic-styles.js index b70c33e6b..dd5462501 100644 --- a/public/scripts/dynamic-styles.js +++ b/public/scripts/dynamic-styles.js @@ -154,7 +154,7 @@ export function initDynamicStyles() { // Process all stylesheets on initial load Array.from(document.styleSheets).forEach(sheet => { try { - applyDynamicFocusStyles(sheet, { fromExtension: sheet.href.toLowerCase().includes('scripts/extensions') }); + applyDynamicFocusStyles(sheet, { fromExtension: sheet.href?.toLowerCase().includes('scripts/extensions') == true }); } catch (e) { console.warn('Failed to process stylesheet on initial load:', e); } From b6de77935b3e145c8e55c7ae223e48dd1e46b04b Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 07:29:14 +0000 Subject: [PATCH 11/30] Fix quotes style --- public/scripts/group-chats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index e85d302ba..a9eaddd82 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -202,7 +202,7 @@ async function validateGroup(group) { export async function getGroupChat(groupId, reload = false) { const group = groups.find((x) => x.id === groupId); if (!group) { - console.warn(`Group not found`, groupId); + console.warn('Group not found', groupId); return; } From da11ffe874918c1309e8f6dcaf0d5c43392ac620 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 07:37:07 +0000 Subject: [PATCH 12/30] #2457 Remove screen size breakpoint from iOS cope styles --- public/css/popup-safari-fix.css | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/public/css/popup-safari-fix.css b/public/css/popup-safari-fix.css index 017486a22..db256ea24 100644 --- a/public/css/popup-safari-fix.css +++ b/public/css/popup-safari-fix.css @@ -1,8 +1,6 @@ /* iPhone copium land */ -@media screen and (max-width: 1000px) { - .ios .popup .popup-body { - height: fit-content; - max-height: 90vh; - max-height: 90svh; - } +.ios .popup .popup-body { + height: fit-content; + max-height: 90vh; + max-height: 90svh; } From 9f1a5f4606447fa835199c414ecdd13956582c04 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:51:14 +0300 Subject: [PATCH 13/30] Update bug-report.yml --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 53be9963f..92a02412a 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -1,5 +1,5 @@ name: Bug Report 🐛 -description: Report something that's not working the intended way. Support requests for external programs (reverse proxies, 3rd party servers, other peoples' forks) will be refused! +description: Report something that's not working the intended way. Support requests for external programs (reverse proxies, 3rd party servers, other peoples' forks) will be refused! Please use English only. title: '[BUG] ' labels: ['🐛 Bug'] body: From 303520be083388d5a2fbdebf5d1017dee33ef1d0 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:51:33 +0300 Subject: [PATCH 14/30] Update feature-request.yml --- .github/ISSUE_TEMPLATE/feature-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index bbb97465e..088a8acf3 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -1,5 +1,5 @@ name: Feature Request ✨ -description: Suggest an idea for future development of this project +description: Suggest an idea for future development of this project. Please use English only. title: '[FEATURE_REQUEST] <title>' labels: ['🦄 Feature Request'] From fde4995adeef4270ebe7cbf6dfee10e9134cfa9c Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:26:23 +0000 Subject: [PATCH 15/30] Add dotfolders to docker and npm ignores --- .dockerignore | 2 ++ .npmignore | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.dockerignore b/.dockerignore index 9f6dc7953..99976ae65 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,6 @@ .git +.github +.vscode node_modules npm-debug.log readme* diff --git a/.npmignore b/.npmignore index ccee41fb6..150ad23aa 100644 --- a/.npmignore +++ b/.npmignore @@ -8,3 +8,6 @@ secrets.json /data /cache access.log +.github +.vscode +.git From a3031d798686db92f7668b1bb5920db0fb52cc23 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:47:02 +0000 Subject: [PATCH 16/30] Reinforce iOS check --- public/scripts/RossAscends-mods.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index 4dc86c9d6..d06068c66 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -725,7 +725,9 @@ export function initRossMods() { RA_autoconnect(); } - if (getParsedUA()?.os?.name === 'iOS') { + const isAppleDevice = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); + + if (getParsedUA()?.os?.name === 'iOS' || isAppleDevice) { document.body.classList.add('ios'); } From b66e589b30b21ce973f9c10471b6a66c470798ab Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:17:10 +0000 Subject: [PATCH 17/30] Don't use dynatemp for unsupported backends --- public/scripts/textgen-settings.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/public/scripts/textgen-settings.js b/public/scripts/textgen-settings.js index 0187676a1..a38a63a1d 100644 --- a/public/scripts/textgen-settings.js +++ b/public/scripts/textgen-settings.js @@ -263,6 +263,8 @@ export const setting_names = [ 'bypass_status_check', ]; +const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba'); + export function validateTextGenUrl() { const selector = SERVER_INPUTS[settings.type]; @@ -1045,6 +1047,10 @@ export function isJsonSchemaSupported() { return [TABBY, LLAMACPP].includes(settings.type) && main_api === 'textgenerationwebui'; } +function isDynamicTemperatureSupported() { + return settings.dynatemp && DYNATEMP_BLOCK?.dataset?.tgType?.includes(settings.type); +} + function getLogprobsNumber() { if (settings.type === VLLM || settings.type === INFERMATICAI) { return 5; @@ -1055,6 +1061,7 @@ function getLogprobsNumber() { export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, isContinue, cfgValues, type) { const canMultiSwipe = !isContinue && !isImpersonate && type !== 'quiet'; + const dynatemp = isDynamicTemperatureSupported(); const { banned_tokens, banned_strings } = getCustomTokenBans(); let params = { @@ -1063,7 +1070,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, 'max_new_tokens': maxTokens, 'max_tokens': maxTokens, 'logprobs': power_user.request_token_probabilities ? getLogprobsNumber() : undefined, - 'temperature': settings.dynatemp ? (settings.min_temp + settings.max_temp) / 2 : settings.temp, + 'temperature': dynatemp ? (settings.min_temp + settings.max_temp) / 2 : settings.temp, 'top_p': settings.top_p, 'typical_p': settings.typical_p, 'typical': settings.typical_p, @@ -1081,11 +1088,11 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, 'length_penalty': settings.length_penalty, 'early_stopping': settings.early_stopping, 'add_bos_token': settings.add_bos_token, - 'dynamic_temperature': settings.dynatemp ? true : undefined, - 'dynatemp_low': settings.dynatemp ? settings.min_temp : undefined, - 'dynatemp_high': settings.dynatemp ? settings.max_temp : undefined, - 'dynatemp_range': settings.dynatemp ? (settings.max_temp - settings.min_temp) / 2 : undefined, - 'dynatemp_exponent': settings.dynatemp ? settings.dynatemp_exponent : undefined, + 'dynamic_temperature': dynatemp ? true : undefined, + 'dynatemp_low': dynatemp ? settings.min_temp : undefined, + 'dynatemp_high': dynatemp ? settings.max_temp : undefined, + 'dynatemp_range': dynatemp ? (settings.max_temp - settings.min_temp) / 2 : undefined, + 'dynatemp_exponent': dynatemp ? settings.dynatemp_exponent : undefined, 'smoothing_factor': settings.smoothing_factor, 'smoothing_curve': settings.smoothing_curve, 'dry_allowed_length': settings.dry_allowed_length, From 9eb404a2753ffe07a65a6502131dfb4ef3f0b07f Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 19:11:45 +0300 Subject: [PATCH 18/30] #2460 replaceAll for all workflow placeholders --- .../scripts/extensions/stable-diffusion/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index cfff05c8d..b7f0a6496 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -2916,25 +2916,25 @@ async function generateComfyImage(prompt, negativePrompt) { const text = await workflowResponse.text(); toastr.error(`Failed to load workflow.\n\n${text}`); } - let workflow = (await workflowResponse.json()).replace('"%prompt%"', JSON.stringify(prompt)); - workflow = workflow.replace('"%negative_prompt%"', JSON.stringify(negativePrompt)); + let workflow = (await workflowResponse.json()).replaceAll('"%prompt%"', JSON.stringify(prompt)); + workflow = workflow.replaceAll('"%negative_prompt%"', JSON.stringify(negativePrompt)); const seed = extension_settings.sd.seed >= 0 ? extension_settings.sd.seed : Math.round(Math.random() * Number.MAX_SAFE_INTEGER); workflow = workflow.replaceAll('"%seed%"', JSON.stringify(seed)); placeholders.forEach(ph => { - workflow = workflow.replace(`"%${ph}%"`, JSON.stringify(extension_settings.sd[ph])); + workflow = workflow.replaceAll(`"%${ph}%"`, JSON.stringify(extension_settings.sd[ph])); }); (extension_settings.sd.comfy_placeholders ?? []).forEach(ph => { - workflow = workflow.replace(`"%${ph.find}%"`, JSON.stringify(substituteParams(ph.replace))); + workflow = workflow.replaceAll(`"%${ph.find}%"`, JSON.stringify(substituteParams(ph.replace))); }); if (/%user_avatar%/gi.test(workflow)) { const response = await fetch(getUserAvatarUrl()); if (response.ok) { const avatarBlob = await response.blob(); const avatarBase64 = await getBase64Async(avatarBlob); - workflow = workflow.replace('"%user_avatar%"', JSON.stringify(avatarBase64)); + workflow = workflow.replaceAll('"%user_avatar%"', JSON.stringify(avatarBase64)); } else { - workflow = workflow.replace('"%user_avatar%"', JSON.stringify(PNG_PIXEL)); + workflow = workflow.replaceAll('"%user_avatar%"', JSON.stringify(PNG_PIXEL)); } } if (/%char_avatar%/gi.test(workflow)) { @@ -2942,9 +2942,9 @@ async function generateComfyImage(prompt, negativePrompt) { if (response.ok) { const avatarBlob = await response.blob(); const avatarBase64 = await getBase64Async(avatarBlob); - workflow = workflow.replace('"%char_avatar%"', JSON.stringify(avatarBase64)); + workflow = workflow.replaceAll('"%char_avatar%"', JSON.stringify(avatarBase64)); } else { - workflow = workflow.replace('"%char_avatar%"', JSON.stringify(PNG_PIXEL)); + workflow = workflow.replaceAll('"%char_avatar%"', JSON.stringify(PNG_PIXEL)); } } console.log(`{ From 0ca880bf605a636402ebe2e724f8ed6851a66be2 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:32:46 +0300 Subject: [PATCH 19/30] Check for whitespace-only WI format --- public/scripts/openai.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 9d3d13029..ee48db290 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -689,7 +689,7 @@ function formatWorldInfo(value) { return ''; } - if (!oai_settings.wi_format) { + if (!oai_settings.wi_format.trim()) { return value; } From 6e86ab07dde6fb663b50616ff84f7a54d1a3c186 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Wed, 3 Jul 2024 09:26:53 +0000 Subject: [PATCH 20/30] Bump package version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d1501827..ae2d0a3ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sillytavern", - "version": "1.12.2", + "version": "1.12.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sillytavern", - "version": "1.12.2", + "version": "1.12.3", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 774eee69b..3dd6007e7 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "type": "git", "url": "https://github.com/SillyTavern/SillyTavern.git" }, - "version": "1.12.2", + "version": "1.12.3", "scripts": { "start": "node server.js", "start:no-csrf": "node server.js --disableCsrf", From 7de43d3a9cdc2e27826577a2c373363c8fad8625 Mon Sep 17 00:00:00 2001 From: Wolfsblvt <wolfsblvt@gmail.com> Date: Wed, 3 Jul 2024 14:44:17 +0200 Subject: [PATCH 21/30] /stop slash command to stop generation --- public/script.js | 32 +++++++++++++++++++++++--------- public/scripts/slash-commands.js | 19 +++++++++++++++++++ 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/public/script.js b/public/script.js index 655feb483..0ffaf2b49 100644 --- a/public/script.js +++ b/public/script.js @@ -520,6 +520,7 @@ const chatElement = $('#chat'); let dialogueResolve = null; let dialogueCloseStop = false; export let chat_metadata = {}; +/** @type {StreamingProcessor} */ export let streamingProcessor = null; let crop_data = undefined; let is_delete_mode = false; @@ -837,6 +838,7 @@ export let main_api;// = "kobold"; //novel settings export let novelai_settings; export let novelai_setting_names; +/** @type {AbortController} */ let abortController; //css @@ -4380,6 +4382,25 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro } } +/** + * Stops the generation and any streaming if it is currently running. + */ +export function stopGeneration() { + let stopped = false; + if (streamingProcessor) { + streamingProcessor.onStopStreaming(); + streamingProcessor = null; + stopped = true; + } + if (abortController) { + abortController.abort('Clicked stop button'); + hideStopButton(); + stopped = true; + } + eventSource.emit(event_types.GENERATION_STOPPED); + return stopped; +} + /** * Injects extension prompts into chat messages. * @param {object[]} messages Array of chat messages @@ -10342,15 +10363,7 @@ jQuery(async function () { }); $(document).on('click', '.mes_stop', function () { - if (streamingProcessor) { - streamingProcessor.onStopStreaming(); - streamingProcessor = null; - } - if (abortController) { - abortController.abort('Clicked stop button'); - hideStopButton(); - } - eventSource.emit(event_types.GENERATION_STOPPED); + stopGeneration(); }); $(document).on('click', '#form_sheld .stscript_continue', function () { @@ -10839,3 +10852,4 @@ jQuery(async function () { initCustomSelectedSamplers(); }); + diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 0f7aeed5f..bbd8934ba 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -33,6 +33,7 @@ import { setCharacterName, setExtensionPrompt, setUserName, + stopGeneration, substituteParams, system_avatar, system_message_types, @@ -898,6 +899,24 @@ export function initDefaultSlashCommands() { ], helpString: 'Adds a swipe to the last chat message.', })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'stop', + callback: () => { + const stopped = stopGeneration(); + return String(stopped); + }, + returns: 'true/false, whether the generation was running and got stopped', + helpString: ` + <div> + Stops the generation and any streaming if it is currently running. + </div> + <div> + Note: This command cannot be executed from the chat input, as sending any message or script from there is blocked during generation. + But it can be executed via automations or QR scripts/buttons. + </div> + `, + aliases: ['generate-stop'], + })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'abort', callback: abortCallback, From c0436f4a321fc38ba94177f297608acb2a398136 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Wed, 3 Jul 2024 20:35:42 +0300 Subject: [PATCH 22/30] Extend getContext API --- public/script.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/public/script.js b/public/script.js index 0ffaf2b49..c657423d9 100644 --- a/public/script.js +++ b/public/script.js @@ -227,7 +227,7 @@ import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, de import { initPresetManager } from './scripts/preset-manager.js'; import { MacrosParser, evaluateMacros } from './scripts/macros.js'; import { currentUser, setUserControls } from './scripts/user.js'; -import { POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; +import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; import { renderTemplate, renderTemplateAsync } from './scripts/templates.js'; import { ScraperManager } from './scripts/scrapers.js'; import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js'; @@ -7184,7 +7184,8 @@ function onScenarioOverrideRemoveClick() { * @param {string} inputValue - Value to set the input to. * @param {PopupOptions} options - Options for the popup. * @typedef {{okButton?: string, rows?: number, wide?: boolean, wider?: boolean, large?: boolean, allowHorizontalScrolling?: boolean, allowVerticalScrolling?: boolean, cropAspect?: number }} PopupOptions - Options for the popup. - * @returns + * @returns {Promise<any>} A promise that resolves when the popup is closed. + * @deprecated Use `callGenericPopup` instead. */ export function callPopup(text, type, inputValue = '', { okButton, rows, wide, wider, large, allowHorizontalScrolling, allowVerticalScrolling, cropAspect } = {}) { function getOkButtonText() { @@ -7815,6 +7816,7 @@ window['SillyTavern'].getContext = function () { eventTypes: event_types, addOneMessage: addOneMessage, generate: Generate, + stopGeneration: stopGeneration, getTokenCount: getTokenCount, extensionPrompts: extension_prompts, setExtensionPrompt: setExtensionPrompt, @@ -7870,6 +7872,8 @@ window['SillyTavern'].getContext = function () { * @deprecated Legacy snake-case naming, compatibility with old extensions */ event_types: event_types, + POPUP_TYPE: POPUP_TYPE, + POPUP_RESULT: POPUP_RESULT, }; }; From fa983521c07839031c74e2719dab24cbdae63ca2 Mon Sep 17 00:00:00 2001 From: Risenafis <91325858+Risenafis@users.noreply.github.com> Date: Thu, 4 Jul 2024 02:39:57 +0900 Subject: [PATCH 23/30] Improve ja-jp translation (#2459) * improve ja-jp.json * addtional improve --- public/locales/ja-jp.json | 110 +++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/public/locales/ja-jp.json b/public/locales/ja-jp.json index 0af4081ee..cfb6f6c79 100644 --- a/public/locales/ja-jp.json +++ b/public/locales/ja-jp.json @@ -1,6 +1,6 @@ { "Favorite": "お気に入り", - "Tag": "鬼ごっこ", + "Tag": "タグ", "Duplicate": "重複", "Persona": "ペルソナ", "Delete": "削除", @@ -29,13 +29,13 @@ "Text Adventure": "テキストアドベンチャー", "response legth(tokens)": "応答の長さ(トークン数)", "Streaming": "ストリーミング", - "Streaming_desc": "生成された応答をビット単位で表示します。", + "Streaming_desc": "生成された応答を逐次表示します。", "context size(tokens)": "コンテキストのサイズ(トークン数)", "unlocked": "ロック解除", "Only enable this if your model supports context sizes greater than 4096 tokens": "モデルが4096トークンを超えるコンテキストサイズをサポートしている場合にのみ有効にします", "Max prompt cost:": "最大プロンプトコスト:", - "Display the response bit by bit as it is generated.": "生成されるたびに、応答をビットごとに表示します。", - "When this is off, responses will be displayed all at once when they are complete.": "この機能がオフの場合、応答は完全になるとすぐにすべて一度に表示されます。", + "Display the response bit by bit as it is generated.": "生成されるたびに、応答を逐次表示します。", + "When this is off, responses will be displayed all at once when they are complete.": "この機能がオフの場合、応答は完全に生成されたときに一度ですべて表示されます。", "Temperature": "温度", "rep.pen": "繰り返しペナルティ", "Rep. Pen. Range.": "繰り返しペナルティの範囲", @@ -46,10 +46,10 @@ "Phrase Repetition Penalty": "フレーズの繰り返しペナルティ", "Off": "オフ", "Very light": "非常に軽い", - "Light": "ライト", - "Medium": "ミディアム", - "Aggressive": "攻撃的", - "Very aggressive": "非常に攻撃的", + "Light": "軽め", + "Medium": "中程度", + "Aggressive": "強め", + "Very aggressive": "非常に強い", "Unlocked Context Size": "ロック解除されたコンテキストサイズ", "Unrestricted maximum value for the context slider": "コンテキストスライダーの制限なしの最大値", "Context Size (tokens)": "コンテキストサイズ(トークン数)", @@ -132,7 +132,7 @@ "CFG Scale": "CFGスケール", "Negative Prompt": "ネガティブプロンプト", "Add text here that would make the AI generate things you don't want in your outputs.": "出力に望ましくないものを生成させるAIを作成するテキストをここに追加します。", - "Used if CFG Scale is unset globally, per chat or character": "CFGスケールがグローバル、チャットごと、または文字ごとに設定されていない場合に使用されます", + "Used if CFG Scale is unset globally, per chat or character": "CFGスケールがグローバル、チャットごと、またはキャラクターごとに設定されていない場合に使用されます", "Mirostat Tau": "Mirostat Tau", "Mirostat LR": "ミロスタットLR", "Min Length": "最小長", @@ -214,7 +214,7 @@ "Sampler Priority": "サンプラー優先度", "Ooba only. Determines the order of samplers.": "Oobaのみ。サンプラーの順序を決定します。", "Character Names Behavior": "キャラクター名の動作", - "Helps the model to associate messages with characters.": "モデルがメッセージを文字に関連付けるのに役立ちます。", + "Helps the model to associate messages with characters.": "モデルがメッセージをキャラクターに関連付けるのに役立ちます。", "None": "なし", "character_names_none": "グループと過去のペルソナを除きます。それ以外の場合は、プロンプトに名前を必ず入力してください。", "Don't add character names.": "キャラクター名を追加しないでください。", @@ -222,7 +222,7 @@ "character_names_completion": "制限事項: ラテン英数字とアンダースコアのみ。すべてのソースで機能するわけではありません。特に、Claude、MistralAI、Google では機能しません。", "Add character names to completion objects.": "完了オブジェクトにキャラクター名を追加します。", "Message Content": "メッセージ内容", - "Prepend character names to message contents.": "メッセージの内容の先頭に文字名を追加します。", + "Prepend character names to message contents.": "メッセージの内容の先頭にキャラクター名を追加します。", "Continue Postfix": "ポストフィックスの継続", "The next chunk of the continued message will be appended using this as a separator.": "継続メッセージの次のチャンクは、これを区切り文字として使用して追加されます。", "Space": "空間", @@ -270,9 +270,9 @@ "Text Completion": "テキスト補完", "Chat Completion": "チャット完了", "NovelAI": "NovelAI", - "KoboldAI Horde": "KoboldAIホルド", + "KoboldAI Horde": "KoboldAI Horde", "KoboldAI": "KoboldAI", - "Avoid sending sensitive information to the Horde.": "ホルドに機密情報を送信しないでください。", + "Avoid sending sensitive information to the Horde.": "Hordeに機密情報を送信しないでください。", "Review the Privacy statement": "プライバシー声明を確認する", "Register a Horde account for faster queue times": "キュー待ち時間を短縮するためにHordeアカウントを登録する", "Learn how to contribute your idle GPU cycles to the Horde": "アイドルのGPUサイクルをホルドに貢献する方法を学びます", @@ -633,7 +633,7 @@ "Tags_as_Folders_desc": "最近の変更: タグは、タグ管理メニューでフォルダーとしてマークされて初めてフォルダーとして表示されます。ここをクリックして表示します。", "Character Handling": "キャラクター処理", "If set in the advanced character definitions, this field will be displayed in the characters list.": "高度なキャラクター定義で設定されている場合、このフィールドがキャラクターリストに表示されます。", - "Char List Subheader": "文字リストサブヘッダー", + "Char List Subheader": "キャラクターリストサブヘッダー", "Character Version": "キャラクターバージョン", "Created by": "作成者", "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "曖昧な一致を使用し、名前の部分文字列ではなく、すべてのデータフィールドでリスト内のキャラクターを検索する", @@ -729,8 +729,8 @@ "Automatically hide details": "詳細を自動的に非表示にする", "Determines how entries are found for autocomplete.": "オートコンプリートのエントリの検索方法を決定します。", "Autocomplete Matching": "マッチング", - "Starts with": "始まりは", - "Includes": "含まれるもの", + "Starts with": "前方一致", + "Includes": "部分一致", "Fuzzy": "ファジー", "Sets the style of the autocomplete.": "オートコンプリートのスタイルを設定します。", "Autocomplete Style": "スタイル", @@ -755,8 +755,8 @@ "Auto-select": "自動選択", "System Backgrounds": "システムの背景", "Chat Backgrounds": "チャットの背景", - "bg_chat_hint_1": "チャットの背景は、", - "bg_chat_hint_2": "拡張子がここに表示されます。", + "bg_chat_hint_1": "", + "bg_chat_hint_2": "拡張機能で生成したチャットの背景はここに表示されます。", "Extensions": "拡張機能", "Notify on extension updates": "拡張機能の更新時に通知", "Manage extensions": "拡張機能を管理", @@ -770,9 +770,9 @@ "How do I use this?": "これをどのように使用しますか?", "Click for stats!": "統計をクリック!", "Usage Stats": "使用状況統計", - "Backup your personas to a file": "キャラクタをファイルにバックアップします", + "Backup your personas to a file": "キャラクターをファイルにバックアップします", "Backup": "バックアップ", - "Restore your personas from a file": "ファイルからキャラクタを復元します", + "Restore your personas from a file": "ファイルからキャラクターを復元します", "Restore": "復元", "Create a dummy persona": "ダミーのペルソナを作成", "Create": "作成", @@ -839,7 +839,7 @@ "Describe your character's physical and mental traits here.": "ここにキャラクターの身体的および精神的特徴を説明します。", "First message": "最初のメッセージ", "Click to set additional greeting messages": "追加の挨拶メッセージを設定するにはクリック", - "Alt. Greetings": "挨拶", + "Alt. Greetings": "他の挨拶", "This will be the first message from the character that starts every chat.": "これはすべてのチャットを開始するキャラクターからの最初のメッセージになります。", "Group Controls": "グループコントロール", "Chat Name (Optional)": "チャット名(任意)", @@ -889,7 +889,7 @@ "popup-button-yes": "はい", "popup-button-no": "いいえ", "popup-button-cancel": "キャンセル", - "popup-button-import": "輸入", + "popup-button-import": "インポート", "Advanced Defininitions": "高度な定義", "Prompt Overrides": "プロンプトのオーバーライド", "(For Chat Completion and Instruct Mode)": "(チャット補完と指示モード用)", @@ -937,7 +937,7 @@ "Type here...": "ここに入力...", "Chat Lorebook": "チャットロアブック", "Chat Lorebook for": "チャットロアブック", - "chat_world_template_txt": "選択したワールド情報はこのチャットにバインドされます。AI の返信を生成する際、\nグローバルおよびキャラクターの伝承書のエントリと結合されます。", + "chat_world_template_txt": "選択したワールド情報はこのチャットにバインドされます。AI の返信を生成する際、\nグローバルおよびキャラクターのロアブックのエントリと結合されます。", "Select a World Info file for": "次のためにワールド情報ファイルを選択", "Primary Lorebook": "プライマリロアブック", "A selected World Info will be bound to this character as its own Lorebook.": "選択したワールド情報は、このキャラクターにその独自のロアブックとしてバインドされます。", @@ -1065,9 +1065,9 @@ "Change it later in the 'User Settings' panel.": "後で「ユーザー設定」パネルで変更します。", "Enable simple UI mode": "シンプルUIモードを有効にする", "Looking for AI characters?": "AIキャラクターをお探しですか?", - "onboarding_import": "輸入", + "onboarding_import": "インポート", "from supported sources or view": "サポートされているソースからまたは表示", - "Sample characters": "サンプル文字", + "Sample characters": "サンプルキャラクター", "Your Persona": "あなたのペルソナ", "Before you get started, you must select a persona name.": "始める前に、ペルソナ名を選択する必要があります。", "welcome_message_part_8": "これはいつでも変更可能です。", @@ -1081,7 +1081,7 @@ "View character card": "キャラクターカードを表示", "Remove from group": "グループから削除", "Add to group": "グループに追加", - "Alternate Greetings": "代わりの挨拶", + "Alternate Greetings": "挨拶のバリエーション", "Alternate_Greetings_desc": "これらは、新しいチャットを開始するときに最初のメッセージにスワイプとして表示されます。\nグループのメンバーは、そのうちの 1 つを選択して会話を開始できます。", "Alternate Greetings Hint": "ボタンをクリックして始めましょう!", "(This will be the first message from the character that starts every chat)": "(これはすべてのチャットを開始するキャラクターからの最初のメッセージになります)", @@ -1118,11 +1118,11 @@ "Will be used as the default CFG options for every chat unless overridden.": "上書きされない限り、すべてのチャットのデフォルトの CFG オプションとして使用されます。", "CFG Prompt Cascading": "CFG プロンプト カスケード", "Combine positive/negative prompts from other boxes.": "他のボックスからの肯定的/否定的なプロンプトを組み合わせます。", - "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "たとえば、チャット、グローバル、および文字のボックスにチェックを入れると、すべての否定プロンプトがコンマ区切りの文字列に結合されます。", + "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "たとえば、チャット、グローバル、およびキャラクターのボックスにチェックを入れると、すべてのネガティブプロンプトがコンマ区切りの文字列に結合されます。", "Always Include": "常に含めます", "Chat Negatives": "チャットのネガティブ", - "Character Negatives": "性格のマイナス面", - "Global Negatives": "世界的なマイナス", + "Character Negatives": "キャラクターのネガティブ", + "Global Negatives": "グローバルネガティブ", "Custom Separator:": "カスタムセパレーター:", "Insertion Depth:": "挿入深さ:", "Token Probabilities": "トークン確率", @@ -1236,7 +1236,7 @@ "ext_regex_title": "正規表現", "ext_regex_new_global_script": "+ グローバル", "ext_regex_new_scoped_script": "+ スコープ付き", - "ext_regex_import_script": "輸入", + "ext_regex_import_script": "インポート", "ext_regex_global_scripts": "グローバルスクリプト", "ext_regex_global_scripts_desc": "すべてのキャラクターで使用可能。ローカル設定に保存されます。", "ext_regex_scoped_scripts": "スコープ付きスクリプト", @@ -1301,8 +1301,8 @@ "Authentication (optional)": "認証(オプション)", "Example: username:password": "例: ユーザー名:パスワード", "Important:": "重要:", - "sd_auto_auth_warning_1": "SD Web UIを実行する", - "sd_auto_auth_warning_2": "フラグ! サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。", + "sd_auto_auth_warning_1": "SD Web UIを", + "sd_auto_auth_warning_2": "フラグを指定して実行してください! サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。", "sd_drawthings_url": "例: {{drawthings_url}}", "sd_drawthings_auth_txt": "UI で HTTP API スイッチを有効にして DrawThings アプリを実行します。サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。", "sd_vlad_url": "例: {{vlad_url}}", @@ -1326,36 +1326,36 @@ "Enhance": "強化する", "Refine": "リファイン", "Decrisper": "デクリスパー", - "Sampling steps": "サンプリング手順 ()", - "Width": "幅 ()", - "Height": "身長 ()", - "Resolution": "解決", + "Sampling steps": "サンプリングステップ数", + "Width": "幅", + "Height": "高さ", + "Resolution": "解像度", "Model": "モデル", "Sampling method": "サンプリング方法", "Karras (not all samplers supported)": "Karras (すべてのサンプラーがサポートされているわけではありません)", "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA バージョンのサンプラーは、高解像度でより優れたパフォーマンスを発揮するように変更されています。", - "SMEA": "中小企業庁", + "SMEA": "SMEA", "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA サンプラーの DYN バリアントは、多くの場合、より多様な出力をもたらしますが、非常に高い解像度では失敗する可能性があります。", "DYN": "ダイナミック", - "Scheduler": "スケジューラ", - "Restore Faces": "顔を復元する", - "Hires. Fix": "雇用。修正", + "Scheduler": "スケジューラー", + "Restore Faces": "顔の修復", + "Hires. Fix": "高解像度補助", "Upscaler": "アップスケーラー", - "Upscale by": "高級化", + "Upscale by": "アップスケール倍率", "Denoising strength": "ノイズ除去の強さ", - "Hires steps (2nd pass)": "採用手順(2回目のパス)", - "Preset for prompt prefix and negative prompt": "プロンプトプレフィックスと否定プロンプトのプリセット", + "Hires steps (2nd pass)": "高解像度でのステップ数", + "Preset for prompt prefix and negative prompt": "プロンプトプレフィックスとネガティブプロンプトのプリセット", "Style": "スタイル", "Save style": "スタイルを保存", "Delete style": "スタイルを削除", - "Common prompt prefix": "一般的なプロンプトプレフィックス", + "Common prompt prefix": "共通のプロンプトプレフィックス", "sd_prompt_prefix_placeholder": "生成されたプロンプトを挿入する場所を指定するには、{prompt}を使用します。", - "Negative common prompt prefix": "否定の共通プロンプト接頭辞", - "Character-specific prompt prefix": "文字固有のプロンプトプレフィックス", + "Negative common prompt prefix": "共通のネガティブプロンプトプレフィックス", + "Character-specific prompt prefix": "キャラクター固有のプロンプトプレフィックス", "Won't be used in groups.": "グループでは使用されません。", - "sd_character_prompt_placeholder": "現在選択されているキャラクターを説明する任意の特性。共通のプロンプト プレフィックスの後に追加されます。\n例: 女性、緑の目、茶色の髪、ピンクのシャツ", - "Character-specific negative prompt prefix": "文字固有の否定プロンプト接頭辞", - "sd_character_negative_prompt_placeholder": "選択したキャラクターに表示されるべきではない特性。否定の共通プロンプト接頭辞の後に追加されます。\n例: ジュエリー、靴、メガネ", + "sd_character_prompt_placeholder": "現在選択されているキャラクターを説明する特徴。共通のプロンプトプレフィックスの後に追加されます。\n例: 女性、緑の目、茶色の髪、ピンクのシャツ", + "Character-specific negative prompt prefix": "キャラクター固有のネガティブプロンプトプレフィックス", + "sd_character_negative_prompt_placeholder": "選択したキャラクターに表示されるべきではない特徴。共通のネガティブプロンプトプレフィックスの後に追加されます。\n例: ジュエリー、靴、メガネ", "Shareable": "共有可能", "Image Prompt Templates": "画像プロンプトテンプレート", "Vectors Model Warning": "チャットの途中でモデルを変更する場合は、ベクトルを消去することをお勧めします。そうしないと、標準以下の結果になります。", @@ -1380,22 +1380,22 @@ "Warning:": "警告:", "This action is irreversible.": "この操作は元に戻せません。", "Type the user's handle below to confirm:": "確認するには、以下のユーザーのハンドルを入力してください。", - "Import Characters": "文字をインポートする", + "Import Characters": "キャラクターをインポートする", "Enter the URL of the content to import": "インポートするコンテンツの URL を入力します", "Supported sources:": "サポートされているソース:", - "char_import_1": "チャブキャラクター(直接リンクまたはID)", + "char_import_1": "Chub キャラクター (直接リンクまたはID)", "char_import_example": "例:", - "char_import_2": "チャブの伝承集 (直接リンクまたは ID)", + "char_import_2": "Chub ロアブック (直接リンクまたは ID)", "char_import_3": "JanitorAI キャラクター (直接リンクまたは UUID)", "char_import_4": "Pygmalion.chat キャラクター (直接リンクまたは UUID)", "char_import_5": "AICharacterCard.com キャラクター (直接リンクまたは ID)", "char_import_6": "直接PNGリンク(参照", "char_import_7": "許可されたホストの場合)", "char_import_8": "RisuRealm キャラクター (直接リンク)", - "Supports importing multiple characters.": "複数の文字のインポートをサポートします。", + "Supports importing multiple characters.": "複数のキャラクターのインポートをサポートします。", "Write each URL or ID into a new line.": "各 URL または ID を新しい行に入力します。", - "Export for character": "文字のエクスポート", - "Export prompts for this character, including their order.": "この文字のプロンプトを順序も含めてエクスポートします。", + "Export for character": "キャラクターのエクスポート", + "Export prompts for this character, including their order.": "このキャラクターのプロンプトを順序も含めてエクスポートします。", "Export all": "すべてをエクスポート", "Export all your prompts to a file": "すべてのプロンプトをファイルにエクスポートする", "Insert prompt": "プロンプトを挿入", From 46c91bec679bba44a0593b6ea9649cf6bea97fd7 Mon Sep 17 00:00:00 2001 From: steve green <steve_green@qq.com> Date: Thu, 4 Jul 2024 02:24:03 +0800 Subject: [PATCH 24/30] Update server.js to trust UserAccounts securely (#2447) * Update server.js to trust UserAccounts securely * Update zh-cn.json btw * Clarify security logic * update logic * Fix filtering of enabled users. * Fix account name logging * More friendly log * Even friendlier message * Revert deleted keys --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com> --- public/locales/zh-cn.json | 17 +++++++++--- server.js | 57 +++++++++++++++++++++++++++++---------- src/users.js | 31 ++++++++++----------- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/public/locales/zh-cn.json b/public/locales/zh-cn.json index 9c7329712..759af7fc6 100644 --- a/public/locales/zh-cn.json +++ b/public/locales/zh-cn.json @@ -334,6 +334,9 @@ "vLLM API key": "vLLM API 密钥", "Example: 127.0.0.1:8000": "例如:http://127.0.0.1:8000", "vLLM Model": "vLLM 模型", + "HuggingFace Token": "HuggingFace 代币", + "Endpoint URL": "端点 URL", + "Example: https://****.endpoints.huggingface.cloud": "例如:https://****.endpoints.huggingface.cloud", "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine(用于OpenAI API的包装器)", "Aphrodite API key": "Aphrodite API 密钥", "Aphrodite Model": "Aphrodite 模型", @@ -419,6 +422,8 @@ "Prompt Post-Processing": "提示词后处理", "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。", "prompt_post_processing_none": "未选择", + "01.AI API Key": "01.AI API密钥", + "01.AI Model": "01.AI模型", "Additional Parameters": "附加参数", "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意,您将因此而消耗额度!", "Test Message": "发送测试消息", @@ -1033,6 +1038,8 @@ "Sticky": "粘性", "Entries with a cooldown can't be activated N messages after being triggered.": "具有冷却时间的条目在触发后 N 条消息内无法被激活。", "Cooldown": "冷却", + "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。", + "Delay": "延迟", "Filter to Character(s)": "应用到角色", "Character Exclusion": "反选角色", "-- Characters not found --": "-- 未找到角色 --", @@ -1077,6 +1084,7 @@ "Move message up": "将消息上移", "Move message down": "将消息下移", "Enlarge": "放大", + "Caption": "标题", "Welcome to SillyTavern!": "欢迎来到 SillyTavern!", "welcome_message_part_1": "阅读", "welcome_message_part_2": "官方文档", @@ -1113,10 +1121,6 @@ "alternate_greetings_hint_2": "按钮即可开始!", "Alternate Greeting #": "额外问候语 #", "(This will be the first message from the character that starts every chat)": "(这将是角色在每次聊天开始时发送的第一条消息)", - "Forbid Media Override explanation": "当前角色/群组在聊天中使用外部媒体的能力。", - "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。", - "Always forbidden": "始终禁止", - "Always allowed": "始终允许", "View contents": "查看内容", "Remove the file": "删除文件", "Unique to this chat": "此聊天独有", @@ -1240,6 +1244,7 @@ "Message Template": "消息模板", "(use _space": "(使用", "macro)": "宏指令)", + "Automatically caption images": "自动为图像添加标题", "Edit captions before saving": "保存前编辑标题", "Character Expressions": "角色表情", "Translate text to English before classification": "分类之前将文本翻译成英文", @@ -1579,6 +1584,10 @@ "Warning:": "警告:", "This action is irreversible.": "此操作不可逆。", "Type the user's handle below to confirm:": "在下面输入用户的名称以确认:", + "Forbid Media Override explanation": "当前角色/群组在聊天中使用外部媒体的能力。", + "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。", + "Always forbidden": "始终禁止", + "Always allowed": "始终允许", "help_format_1": "文本格式化命令:", "help_format_2": "*文本*", "help_format_3": "显示为", diff --git a/server.js b/server.js index 9f1bd81b4..eebd23c22 100644 --- a/server.js +++ b/server.js @@ -609,10 +609,6 @@ const postSetupTasks = async function () { console.warn(color.yellow('Basic Authentication is enabled, but username or password is not set or empty!')); } } - - if (listen && !basicAuthMode && enableAccounts) { - await userModule.checkAccountsProtection(); - } }; /** @@ -631,16 +627,6 @@ async function loadPlugins() { } } -if (listen && !enableWhitelist && !basicAuthMode) { - if (getConfigValue('securityOverride', false)) { - console.warn(color.red('Security has been overridden. If it\'s not a trusted network, change the settings.')); - } - else { - console.error(color.red('Your SillyTavern is currently unsecurely open to the public. Enable whitelisting or basic authentication.')); - process.exit(1); - } -} - /** * Set the title of the terminal window * @param {string} title Desired title for the window @@ -654,10 +640,53 @@ function setWindowTitle(title) { } } +/** + * Prints an error message and exits the process if necessary + * @param {string} message The error message to print + * @returns {void} + */ +function logSecurityAlert(message) { + if (basicAuthMode || enableWhitelist) return; // safe! + console.error(color.red(message)); + if (getConfigValue('securityOverride', false)) { + console.warn(color.red('Security has been overridden. If it\'s not a trusted network, change the settings.')); + return; + } + process.exit(1); +} + +async function verifySecuritySettings() { + // Skip all security checks as listen is set to false + if (!listen) { + return; + } + + if (!enableAccounts) { + logSecurityAlert('Your SillyTavern is currently insecurely open to the public. Enable whitelisting, basic authentication or user accounts.'); + } + + const users = await userModule.getAllEnabledUsers(); + const unprotectedUsers = users.filter(x => !x.password); + const unprotectedAdminUsers = unprotectedUsers.filter(x => x.admin); + + if (unprotectedUsers.length > 0) { + console.warn(color.blue('A friendly reminder that the following users are not password protected:')); + unprotectedUsers.map(x => `${color.yellow(x.handle)} ${color.red(x.admin ? '(admin)' : '')}`).forEach(x => console.warn(x)); + console.log(); + console.warn(`Consider setting a password in the admin panel or by using the ${color.blue('recover.js')} script.`); + console.log(); + + if (unprotectedAdminUsers.length > 0) { + logSecurityAlert('If you are not using basic authentication or whitelisting, you should set a password for all admin users.'); + } + } +} + // User storage module needs to be initialized before starting the server userModule.initUserStorage(dataRoot) .then(userModule.ensurePublicDirectoriesExist) .then(userModule.migrateUserData) + .then(verifySecuritySettings) .then(preSetupTasks) .finally(() => { if (cliArguments.ssl) { diff --git a/src/users.js b/src/users.js index d01419248..dcf3718a9 100644 --- a/src/users.js +++ b/src/users.js @@ -681,27 +681,27 @@ async function createBackupArchive(handle, response) { } /** - * Checks if any admin users are not password protected. If so, logs a warning. - * @returns {Promise<void>} + * Gets all of the users. + * @returns {Promise<User[]>} */ -async function checkAccountsProtection() { +async function getAllUsers() { if (!ENABLE_ACCOUNTS) { - return; + return []; } - /** * @type {User[]} */ const users = await storage.values(); - const unprotectedUsers = users.filter(x => x.enabled && x.admin && !x.password); - if (unprotectedUsers.length > 0) { - console.warn(color.red('The following admin users are not password protected:')); - unprotectedUsers.forEach(x => console.warn(color.yellow(x.handle))); - console.log(); - console.warn('Please disable them or set a password in the admin panel.'); - console.log(); - await delay(3000); - } + return users; +} + +/** + * Gets all of the enabled users. + * @returns {Promise<User[]>} + */ +async function getAllEnabledUsers() { + const users = await getAllUsers(); + return users.filter(x => x.enabled); } /** @@ -738,6 +738,7 @@ module.exports = { shouldRedirectToLogin, createBackupArchive, tryAutoLogin, - checkAccountsProtection, + getAllUsers, + getAllEnabledUsers, router, }; From 8159b7f5f44a33f9dde5666327561ba0062f3c88 Mon Sep 17 00:00:00 2001 From: Wolfsblvt <wolfsblvt@gmail.com> Date: Wed, 3 Jul 2024 20:32:05 +0200 Subject: [PATCH 25/30] Validate story string about missing fields (#2462) * Validate story string about missing fields * Update validation to only warn once * Improve story string validation log once --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com> --- public/scripts/power-user.js | 56 +++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 8751e2d2e..32deaaf09 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -40,7 +40,7 @@ import { tokenizers } from './tokenizers.js'; import { BIAS_CACHE } from './logit-bias.js'; import { renderTemplateAsync } from './templates.js'; -import { countOccurrences, debounce, delay, download, getFileText, isOdd, isTrueBoolean, onlyUnique, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js'; +import { countOccurrences, debounce, delay, download, getFileText, getStringHash, isOdd, isTrueBoolean, onlyUnique, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js'; import { FILTER_TYPES } from './filters.js'; import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { SlashCommand } from './slash-commands/SlashCommand.js'; @@ -335,6 +335,8 @@ const storage_keys = { compact_input_area: 'compact_input_area', auto_connect_legacy: 'AutoConnectEnabled', auto_load_chat_legacy: 'AutoLoadChatEnabled', + + storyStringValidationCache: 'StoryStringValidationCache', }; const contextControls = [ @@ -2105,6 +2107,9 @@ export function fuzzySearchGroups(searchValue) { */ export function renderStoryString(params) { try { + // Validate and log possible warnings/errors + validateStoryString(power_user.context.story_string, params); + // compile the story string template into a function, with no HTML escaping const compiledTemplate = Handlebars.compile(power_user.context.story_string, { noEscape: true }); @@ -2132,6 +2137,55 @@ export function renderStoryString(params) { } } +/** + * Validate the story string for possible warnings or issues + * + * @param {string} storyString - The story string + * @param {Object} params - The story string parameters + */ +function validateStoryString(storyString, params) { + /** @type {{hashCache: {[hash: string]: {fieldsWarned: {[key: string]: boolean}}}}} */ + const cache = JSON.parse(localStorage.getItem(storage_keys.storyStringValidationCache)) ?? { hashCache: {} }; + + const hash = getStringHash(storyString); + + // Initialize the cache for the current hash if it doesn't exist + if (!cache.hashCache[hash]) { + cache.hashCache[hash] = { fieldsWarned: {} }; + } + + const currentCache = cache.hashCache[hash]; + const fieldsToWarn = []; + + function validateMissingField(field, fallbackLegacyField = null) { + const contains = storyString.includes(`{{${field}}}`) || (!!fallbackLegacyField && storyString.includes(`{{${fallbackLegacyField}}}`)); + if (!contains && params[field]) { + const wasLogged = currentCache.fieldsWarned[field]; + if (!wasLogged) { + fieldsToWarn.push(field); + currentCache.fieldsWarned[field] = true; + } + console.warn(`The story string does not contain {{${field}}}, but it would contain content:\n`, params[field]); + } + } + + validateMissingField('description'); + validateMissingField('personality'); + validateMissingField('persona'); + validateMissingField('scenario'); + validateMissingField('system'); + validateMissingField('wiBefore', 'loreBefore'); + validateMissingField('wiAfter', 'loreAfter'); + + if (fieldsToWarn.length > 0) { + const fieldsList = fieldsToWarn.map(field => `{{${field}}}`).join(', '); + toastr.warning(`The story string does not contain the following fields, but they would contain content: ${fieldsList}`, 'Story String Validation'); + } + + localStorage.setItem(storage_keys.storyStringValidationCache, JSON.stringify(cache)); +} + + const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a); const compareFunc = (first, second) => { const a = first[power_user.sort_field]; From 542a13a01be8f803eb810826a608c856f81c09cd Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:28:42 +0300 Subject: [PATCH 26/30] More Safari weirdness cope --- public/css/popup-safari-fix.css | 6 +++++- public/scripts/RossAscends-mods.js | 10 +++++++--- public/scripts/chats.js | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/public/css/popup-safari-fix.css b/public/css/popup-safari-fix.css index db256ea24..4f916747e 100644 --- a/public/css/popup-safari-fix.css +++ b/public/css/popup-safari-fix.css @@ -1,5 +1,9 @@ /* iPhone copium land */ -.ios .popup .popup-body { +body.safari .popup .popup-body:has(.maximized_textarea) { + height: 100%; +} + +body.safari .popup .popup-body { height: fit-content; max-height: 90vh; max-height: 90svh; diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index d06068c66..dceba9063 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -725,10 +725,14 @@ export function initRossMods() { RA_autoconnect(); } - const isAppleDevice = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); + const userAgent = getParsedUA(); + console.debug('User Agent', userAgent); + const isMobileSafari = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1); + const isDesktopSafari = userAgent?.browser?.name === 'Safari' && userAgent?.platform?.type === 'desktop'; + const isIOS = userAgent?.os?.name === 'iOS'; - if (getParsedUA()?.os?.name === 'iOS' || isAppleDevice) { - document.body.classList.add('ios'); + if (isIOS || isMobileSafari || isDesktopSafari) { + document.body.classList.add('safari'); } $('#main_api').change(function () { diff --git a/public/scripts/chats.js b/public/scripts/chats.js index e605f02db..6d1e8d694 100644 --- a/public/scripts/chats.js +++ b/public/scripts/chats.js @@ -1430,7 +1430,7 @@ jQuery(function () { wrapper.classList.add('flexFlowColumn', 'justifyCenter', 'alignitemscenter'); const textarea = document.createElement('textarea'); textarea.value = String(bro.val()); - textarea.classList.add('height100p', 'wide100p'); + textarea.classList.add('height100p', 'wide100p', 'maximized_textarea'); bro.hasClass('monospace') && textarea.classList.add('monospace'); textarea.addEventListener('input', function () { bro.val(textarea.value).trigger('input'); From 09632fe5f80e8afad3a7a4a6ceb5425f5aa88901 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 4 Jul 2024 00:34:48 +0300 Subject: [PATCH 27/30] Reword KoboldCpp API hint --- public/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/index.html b/public/index.html index 61ce9e14d..851b54228 100644 --- a/public/index.html +++ b/public/index.html @@ -1969,7 +1969,7 @@ <small data-i18n="Example: http://127.0.0.1:5000/api ">Example: http://127.0.0.1:5000/api </small> <input id="api_url_text" name="api_url" class="text_pole" placeholder="http://127.0.0.1:5000/api" maxlength="500" value="" autocomplete="off" data-server-history="kobold"> <div id="koboldcpp_hint" class="neutral_warning displayNone"> - We have a dedicated KoboldCpp support under Text Completion ⇒ KoboldCpp. + KoboldCpp works better when you select the Text Completion API and then KoboldCpp as a type! </div> <div class="flex-container"> <div id="api_button" class="api_button menu_button" type="submit" data-i18n="Connect" data-server-connect="kobold">Connect</div> From ea768661e8ae5234a9c80f74c4480b49e942e7ef Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 4 Jul 2024 01:12:26 +0300 Subject: [PATCH 28/30] Add theme contest winner, pt.2 --- default/content/index.json | 4 ++++ default/content/themes/Azure.json | 35 +++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 default/content/themes/Azure.json diff --git a/default/content/index.json b/default/content/index.json index f467fc86e..6d4ca564b 100644 --- a/default/content/index.json +++ b/default/content/index.json @@ -19,6 +19,10 @@ "filename": "themes/Dark V 1.0.json", "type": "theme" }, + { + "filename": "themes/Azure.json", + "type": "theme" + }, { "filename": "backgrounds/__transparent.png", "type": "background" diff --git a/default/content/themes/Azure.json b/default/content/themes/Azure.json new file mode 100644 index 000000000..676ae668c --- /dev/null +++ b/default/content/themes/Azure.json @@ -0,0 +1,35 @@ +{ + "name": "Azure", + "blur_strength": 11, + "main_text_color": "rgba(171, 198, 223, 1)", + "italics_text_color": "rgba(255, 255, 255, 1)", + "underline_text_color": "rgba(188, 231, 207, 1)", + "quote_text_color": "rgba(111, 133, 253, 1)", + "blur_tint_color": "rgba(23, 30, 33, 0.61)", + "chat_tint_color": "rgba(23, 23, 23, 0)", + "user_mes_blur_tint_color": "rgba(0, 28, 174, 0.2)", + "bot_mes_blur_tint_color": "rgba(0, 13, 57, 0.22)", + "shadow_color": "rgba(0, 0, 0, 1)", + "shadow_width": 5, + "border_color": "rgba(0, 0, 0, 0.5)", + "font_scale": 1, + "fast_ui_mode": false, + "waifuMode": false, + "avatar_style": 1, + "chat_display": 1, + "noShadows": false, + "chat_width": 50, + "timer_enabled": true, + "timestamps_enabled": true, + "timestamp_model_icon": false, + "mesIDDisplay_enabled": true, + "message_token_count_enabled": false, + "expand_message_actions": false, + "enableZenSliders": false, + "enableLabMode": false, + "hotswap_enabled": true, + "custom_css": "", + "bogus_folders": false, + "reduced_motion": false, + "compact_input_area": false +} From aef879ced0b99ca363356aa0fa511f1eeba7b3a9 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 4 Jul 2024 01:41:21 +0300 Subject: [PATCH 29/30] Fix double blur on preloader --- public/css/loader.css | 2 -- public/scripts/loader.js | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/public/css/loader.css b/public/css/loader.css index 1c73c4e3f..6fe9812b6 100644 --- a/public/css/loader.css +++ b/public/css/loader.css @@ -10,8 +10,6 @@ width: 100svw; height: 100svh; background-color: var(--SmartThemeBlurTintColor); - /*for some reason the full screen blur does not work on iOS*/ - backdrop-filter: blur(30px); color: var(--SmartThemeBodyColor); opacity: 1; } diff --git a/public/scripts/loader.js b/public/scripts/loader.js index b991e1ee0..2df5f6edf 100644 --- a/public/scripts/loader.js +++ b/public/scripts/loader.js @@ -1,7 +1,5 @@ import { POPUP_RESULT, POPUP_TYPE, Popup } from './popup.js'; -const ELEMENT_ID = 'loader'; - /** @type {Popup} */ let loaderPopup; @@ -31,7 +29,7 @@ export async function hideLoader() { return new Promise((resolve) => { // Spinner blurs/fades out $('#load-spinner').on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () { - $(`#${ELEMENT_ID}`).remove(); + $('#loader').remove(); // Yoink preloader entirely; it only exists to cover up unstyled content while loading JS // If it's present, we remove it once and then it's gone. yoinkPreloader(); From 2cba5e3a450b548937c7af029605472515fdfdf9 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 4 Jul 2024 01:46:02 +0300 Subject: [PATCH 30/30] Revert blur removal --- public/css/loader.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/css/loader.css b/public/css/loader.css index 6fe9812b6..dea0eb5a3 100644 --- a/public/css/loader.css +++ b/public/css/loader.css @@ -11,6 +11,8 @@ height: 100svh; background-color: var(--SmartThemeBlurTintColor); color: var(--SmartThemeBodyColor); + /*for some reason the full screen blur does not work on iOS*/ + backdrop-filter: blur(30px); opacity: 1; }