Merge pull request #3248 from SillyTavern/staging Staging

f246bc5ac6eeff65de0e482bc88f22e9b55a8eac

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

Signed
110 files changed, +3818 -1822Ignore whitespace
.dockerignore+1 -0
@@ -12,3 +12,4 @@ access.log
12/data12/data
13/cache13/cache
14.DS_Store14.DS_Store
15/public/scripts/extensions/third-party
.eslintrc.cjs+2 -0
@@ -91,6 +91,8 @@ module.exports = {
91 'space-infix-ops': 'error',91 'space-infix-ops': 'error',
92 'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],92 'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
93 'no-cond-assign': 'error',93 'no-cond-assign': 'error',
94 'no-unneeded-ternary': 'error',
95 'no-irregular-whitespace': ['error', { skipStrings: true, skipTemplates: true }],
9496
95 // These rules should eventually be enabled.97 // These rules should eventually be enabled.
96 'no-async-promise-executor': 'off',98 'no-async-promise-executor': 'off',
.gitignore+2 -0
@@ -50,3 +50,5 @@ public/css/user.css
50/default/scaffold50/default/scaffold
51public/scripts/extensions/third-party51public/scripts/extensions/third-party
52/certs52/certs
53.aider*
54.env
.npmignore+1 -0
@@ -11,3 +11,4 @@ access.log
11.github11.github
12.vscode12.vscode
13.git13.git
14/public/scripts/extensions/third-party
Dockerfile+2 -4
@@ -6,9 +6,6 @@ ARG APP_HOME=/home/node/app
6# Install system dependencies6# Install system dependencies
7RUN apk add gcompat tini git7RUN apk add gcompat tini git
88
9# Ensure proper handling of kernel signals
10ENTRYPOINT [ "tini", "--" ]
11
12# Create app directory9# Create app directory
13WORKDIR ${APP_HOME}10WORKDIR ${APP_HOME}
1411
@@ -42,4 +39,5 @@ RUN \
4239
43EXPOSE 800040EXPOSE 8000
4441
45CMD [ "./docker-entrypoint.sh" ]42# Ensure proper handling of kernel signals
43ENTRYPOINT ["tini", "--", "./docker-entrypoint.sh"]
default/config.yaml+2 -0
@@ -98,6 +98,8 @@ skipContentCheck: false
98disableChatBackup: false98disableChatBackup: false
99# Number of backups to keep for each chat and settings file99# Number of backups to keep for each chat and settings file
100numberOfBackups: 50100numberOfBackups: 50
101# Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups.
102maxTotalChatBackups: -1
101# Interval in milliseconds to throttle chat backups per user103# Interval in milliseconds to throttle chat backups per user
102chatBackupThrottleInterval: 10000104chatBackupThrottleInterval: 10000
103# Allowed hosts for card downloads105# Allowed hosts for card downloads
default/content/presets/instruct/ChatML-Names.json+2 -2
@@ -1,6 +1,6 @@
1{1{
2 "input_sequence": "<|im_start|>[{{name}}]",2 "input_sequence": "<|im_start|>{{name}}",
3 "output_sequence": "<|im_start|>[{{name}}]",3 "output_sequence": "<|im_start|>{{name}}",
4 "last_output_sequence": "",4 "last_output_sequence": "",
5 "system_sequence": "<|im_start|>system",5 "system_sequence": "<|im_start|>system",
6 "stop_sequence": "<|im_end|>",6 "stop_sequence": "<|im_end|>",
default/content/presets/instruct/Llama-3-Instruct-Names.json+2 -2
@@ -1,6 +1,6 @@
1{1{
2 "input_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n",2 "input_sequence": "<|start_header_id|>{{name}}<|end_header_id|>\n\n",
3 "output_sequence": "<|start_header_id|>[{{name}}]<|end_header_id|>\n\n",3 "output_sequence": "<|start_header_id|>{{name}}<|end_header_id|>\n\n",
4 "last_output_sequence": "",4 "last_output_sequence": "",
5 "system_sequence": "<|start_header_id|>system<|end_header_id|>\n\n",5 "system_sequence": "<|start_header_id|>system<|end_header_id|>\n\n",
6 "stop_sequence": "<|eot_id|>",6 "stop_sequence": "<|eot_id|>",
default/content/presets/openai/Default.json+2 -2
@@ -39,8 +39,8 @@
39 "proxy_password": "",39 "proxy_password": "",
40 "max_context_unlocked": false,40 "max_context_unlocked": false,
41 "wi_format": "{0}",41 "wi_format": "{0}",
42 "scenario_format": "[Circumstances and context of the dialogue: {{scenario}}]",42 "scenario_format": "{{scenario}}",
43 "personality_format": "[{{char}}'s personality: {{personality}}]",43 "personality_format": "{{personality}}",
44 "group_nudge_prompt": "[Write the next reply only as {{char}}.]",44 "group_nudge_prompt": "[Write the next reply only as {{char}}.]",
45 "stream_openai": true,45 "stream_openai": true,
46 "prompts": [46 "prompts": [
default/content/settings.json+4 -0
@@ -599,18 +599,22 @@
599 "Default (none)": [],599 "Default (none)": [],
600 "Anti-bond": [600 "Anti-bond": [
601 {601 {
602 "id": "22154f79-dd98-41bc-8e34-87015d6a0eaf",
602 "text": " bond",603 "text": " bond",
603 "value": -50604 "value": -50
604 },605 },
605 {606 {
607 "id": "8ad2d5c4-d8ef-49e4-bc5e-13e7f4690e0f",
606 "text": " future",608 "text": " future",
607 "value": -50609 "value": -50
608 },610 },
609 {611 {
612 "id": "52a4b280-0956-4940-ac52-4111f83e4046",
610 "text": " bonding",613 "text": " bonding",
611 "value": -50614 "value": -50
612 },615 },
613 {616 {
617 "id": "e63037c7-c9d1-4724-ab2d-7756008b433b",
614 "text": " connection",618 "text": " connection",
615 "value": -25619 "value": -25
616 }620 }
docker/docker-entrypoint.sh+1 -1
@@ -6,4 +6,4 @@ if [ ! -e "config/config.yaml" ]; then
6fi6fi
77
8# Start the server8# Start the server
9exec node server.js --listen9exec node server.js --listen "$@"
package-lock.json+67 -6
@@ -1,12 +1,12 @@
1{1{
2 "name": "sillytavern",2 "name": "sillytavern",
3 "version": "1.12.9",3 "version": "1.12.10",
4 "lockfileVersion": 3,4 "lockfileVersion": 3,
5 "requires": true,5 "requires": true,
6 "packages": {6 "packages": {
7 "": {7 "": {
8 "name": "sillytavern",8 "name": "sillytavern",
9 "version": "1.12.9",9 "version": "1.12.10",
10 "hasInstallScript": true,10 "hasInstallScript": true,
11 "license": "AGPL-3.0",11 "license": "AGPL-3.0",
12 "dependencies": {12 "dependencies": {
@@ -18,7 +18,7 @@
18 "@popperjs/core": "^2.11.8",18 "@popperjs/core": "^2.11.8",
19 "@zeldafan0225/ai_horde": "^5.1.0",19 "@zeldafan0225/ai_horde": "^5.1.0",
20 "archiver": "^7.0.1",20 "archiver": "^7.0.1",
21 "bing-translate-api": "^2.9.1",21 "bing-translate-api": "^4.0.2",
22 "body-parser": "^1.20.2",22 "body-parser": "^1.20.2",
23 "bowser": "^2.11.0",23 "bowser": "^2.11.0",
24 "command-exists": "^1.2.9",24 "command-exists": "^1.2.9",
@@ -63,7 +63,9 @@
63 "showdown": "^2.1.0",63 "showdown": "^2.1.0",
64 "sillytavern-transformers": "2.14.6",64 "sillytavern-transformers": "2.14.6",
65 "simple-git": "^3.19.1",65 "simple-git": "^3.19.1",
66 "slidetoggle": "^4.0.0",
66 "tiktoken": "^1.0.16",67 "tiktoken": "^1.0.16",
68 "url-join": "^5.0.0",
67 "vectra": "^0.2.2",69 "vectra": "^0.2.2",
68 "wavefile": "^11.0.0",70 "wavefile": "^11.0.0",
69 "webpack": "^5.95.0",71 "webpack": "^5.95.0",
@@ -86,6 +88,9 @@
86 "@types/deno": "^2.0.0",88 "@types/deno": "^2.0.0",
87 "@types/express": "^4.17.21",89 "@types/express": "^4.17.21",
88 "@types/jquery": "^3.5.29",90 "@types/jquery": "^3.5.29",
91 "@types/jquery-cropper": "^1.0.4",
92 "@types/jquery.transit": "^0.9.33",
93 "@types/jqueryui": "^1.12.23",
89 "@types/lodash": "^4.17.10",94 "@types/lodash": "^4.17.10",
90 "@types/mime-types": "^2.1.4",95 "@types/mime-types": "^2.1.4",
91 "@types/multer": "^1.4.12",96 "@types/multer": "^1.4.12",
@@ -95,6 +100,7 @@
95 "@types/png-chunks-encode": "^1.0.2",100 "@types/png-chunks-encode": "^1.0.2",
96 "@types/png-chunks-extract": "^1.0.2",101 "@types/png-chunks-extract": "^1.0.2",
97 "@types/response-time": "^2.3.8",102 "@types/response-time": "^2.3.8",
103 "@types/select2": "^4.0.63",
98 "@types/toastr": "^2.1.43",104 "@types/toastr": "^2.1.43",
99 "@types/write-file-atomic": "^4.0.3",105 "@types/write-file-atomic": "^4.0.3",
100 "@types/yargs": "^17.0.33",106 "@types/yargs": "^17.0.33",
@@ -1226,6 +1232,36 @@
1226 "@types/sizzle": "*"1232 "@types/sizzle": "*"
1227 }1233 }
1228 },1234 },
1235 "node_modules/@types/jquery-cropper": {
1236 "version": "1.0.4",
1237 "resolved": "https://registry.npmjs.org/@types/jquery-cropper/-/jquery-cropper-1.0.4.tgz",
1238 "integrity": "sha512-YMyUoY+rhB8yc3xM1B/daNaSq5+q93rzvRx6HP8K9mmvXEviTH3/rldlYNCGd0TmE/kLlZYJsruYhu9wY350PA==",
1239 "dev": true,
1240 "license": "MIT",
1241 "dependencies": {
1242 "@types/jquery": "*"
1243 }
1244 },
1245 "node_modules/@types/jquery.transit": {
1246 "version": "0.9.33",
1247 "resolved": "https://registry.npmjs.org/@types/jquery.transit/-/jquery.transit-0.9.33.tgz",
1248 "integrity": "sha512-gEDi1Lw7qfHFxtcnm2dg0F3Z5yG+84Sn0gDpGbd+u+r2RxsCcdQzfUmFKzHGBjWflZ9CXOZiAkenKOSvwLITrg==",
1249 "dev": true,
1250 "license": "MIT",
1251 "dependencies": {
1252 "@types/jquery": "*"
1253 }
1254 },
1255 "node_modules/@types/jqueryui": {
1256 "version": "1.12.23",
1257 "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.23.tgz",
1258 "integrity": "sha512-pm1yVNVI29B9IGw41anCEzA5eR2r1pYc7flqD471ZT7B0yUXIY7YNe/zq7LGpihIGXNzWyG+Q4YQSzv2AF3fNA==",
1259 "dev": true,
1260 "license": "MIT",
1261 "dependencies": {
1262 "@types/jquery": "*"
1263 }
1264 },
1229 "node_modules/@types/json-schema": {1265 "node_modules/@types/json-schema": {
1230 "version": "7.0.15",1266 "version": "7.0.15",
1231 "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",1267 "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1377,6 +1413,16 @@
1377 "@types/node": "*"1413 "@types/node": "*"
1378 }1414 }
1379 },1415 },
1416 "node_modules/@types/select2": {
1417 "version": "4.0.63",
1418 "resolved": "https://registry.npmjs.org/@types/select2/-/select2-4.0.63.tgz",
1419 "integrity": "sha512-/DXUfPSj3iVTGlRYRYPCFKKSogAGP/j+Z0fIMXbBiBtmmZj0WH7vnfNuckafq9C43KnqPPQW2TI/Rj/vTSGnQQ==",
1420 "dev": true,
1421 "license": "MIT",
1422 "dependencies": {
1423 "@types/jquery": "*"
1424 }
1425 },
1380 "node_modules/@types/send": {1426 "node_modules/@types/send": {
1381 "version": "0.17.4",1427 "version": "0.17.4",
1382 "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",1428 "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
@@ -2115,9 +2161,9 @@
2115 }2161 }
2116 },2162 },
2117 "node_modules/bing-translate-api": {2163 "node_modules/bing-translate-api": {
2118 "version": "2.9.1",2164 "version": "4.0.2",
2119 "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-2.9.1.tgz",2165 "resolved": "https://registry.npmjs.org/bing-translate-api/-/bing-translate-api-4.0.2.tgz",
2120 "integrity": "sha512-DaYqa7iupfj+fj/KeaeZSp5FUY/ZR4sZ6jqoTP0RHkYOUfo7wwoxlhYDkh4VcvBBzuVORnBEgdXBVQrfM4kk7g==",2166 "integrity": "sha512-JJ8XUehnxzOhHU91oy86xEtp8OOMjVEjCZJX042fKxoO19NNvxJ5omeCcxQNFoPbDqVpBJwqiGVquL0oPdQm1Q==",
2121 "license": "MIT",2167 "license": "MIT",
2122 "dependencies": {2168 "dependencies": {
2123 "got": "^11.8.6"2169 "got": "^11.8.6"
@@ -6531,6 +6577,12 @@
6531 "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==",6577 "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==",
6532 "license": "MIT"6578 "license": "MIT"
6533 },6579 },
6580 "node_modules/slidetoggle": {
6581 "version": "4.0.0",
6582 "resolved": "https://registry.npmjs.org/slidetoggle/-/slidetoggle-4.0.0.tgz",
6583 "integrity": "sha512-6qvrOS1dnDFEr41UEEFFRQE8nswaAFIYZAHer6dVlznRIjHyCISjNJoxIn5U5QlAbZfBBxTELQk4jS7miHto1A==",
6584 "license": "MIT"
6585 },
6534 "node_modules/smart-buffer": {6586 "node_modules/smart-buffer": {
6535 "version": "4.2.0",6587 "version": "4.2.0",
6536 "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",6588 "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@@ -7046,6 +7098,15 @@
7046 "punycode": "^2.1.0"7098 "punycode": "^2.1.0"
7047 }7099 }
7048 },7100 },
7101 "node_modules/url-join": {
7102 "version": "5.0.0",
7103 "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz",
7104 "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==",
7105 "license": "MIT",
7106 "engines": {
7107 "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
7108 }
7109 },
7049 "node_modules/utf8-byte-length": {7110 "node_modules/utf8-byte-length": {
7050 "version": "1.0.4",7111 "version": "1.0.4",
7051 "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",7112 "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
package.json+8 -2
@@ -8,7 +8,7 @@
8 "@popperjs/core": "^2.11.8",8 "@popperjs/core": "^2.11.8",
9 "@zeldafan0225/ai_horde": "^5.1.0",9 "@zeldafan0225/ai_horde": "^5.1.0",
10 "archiver": "^7.0.1",10 "archiver": "^7.0.1",
11 "bing-translate-api": "^2.9.1",11 "bing-translate-api": "^4.0.2",
12 "body-parser": "^1.20.2",12 "body-parser": "^1.20.2",
13 "bowser": "^2.11.0",13 "bowser": "^2.11.0",
14 "command-exists": "^1.2.9",14 "command-exists": "^1.2.9",
@@ -53,7 +53,9 @@
53 "showdown": "^2.1.0",53 "showdown": "^2.1.0",
54 "sillytavern-transformers": "2.14.6",54 "sillytavern-transformers": "2.14.6",
55 "simple-git": "^3.19.1",55 "simple-git": "^3.19.1",
56 "slidetoggle": "^4.0.0",
56 "tiktoken": "^1.0.16",57 "tiktoken": "^1.0.16",
58 "url-join": "^5.0.0",
57 "vectra": "^0.2.2",59 "vectra": "^0.2.2",
58 "wavefile": "^11.0.0",60 "wavefile": "^11.0.0",
59 "webpack": "^5.95.0",61 "webpack": "^5.95.0",
@@ -84,7 +86,7 @@
84 "type": "git",86 "type": "git",
85 "url": "https://github.com/SillyTavern/SillyTavern.git"87 "url": "https://github.com/SillyTavern/SillyTavern.git"
86 },88 },
87 "version": "1.12.9",89 "version": "1.12.10",
88 "scripts": {90 "scripts": {
89 "start": "node server.js",91 "start": "node server.js",
90 "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",92 "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
@@ -114,6 +116,9 @@
114 "@types/deno": "^2.0.0",116 "@types/deno": "^2.0.0",
115 "@types/express": "^4.17.21",117 "@types/express": "^4.17.21",
116 "@types/jquery": "^3.5.29",118 "@types/jquery": "^3.5.29",
119 "@types/jquery-cropper": "^1.0.4",
120 "@types/jquery.transit": "^0.9.33",
121 "@types/jqueryui": "^1.12.23",
117 "@types/lodash": "^4.17.10",122 "@types/lodash": "^4.17.10",
118 "@types/mime-types": "^2.1.4",123 "@types/mime-types": "^2.1.4",
119 "@types/multer": "^1.4.12",124 "@types/multer": "^1.4.12",
@@ -123,6 +128,7 @@
123 "@types/png-chunks-encode": "^1.0.2",128 "@types/png-chunks-encode": "^1.0.2",
124 "@types/png-chunks-extract": "^1.0.2",129 "@types/png-chunks-extract": "^1.0.2",
125 "@types/response-time": "^2.3.8",130 "@types/response-time": "^2.3.8",
131 "@types/select2": "^4.0.63",
126 "@types/toastr": "^2.1.43",132 "@types/toastr": "^2.1.43",
127 "@types/write-file-atomic": "^4.0.3",133 "@types/write-file-atomic": "^4.0.3",
128 "@types/yargs": "^17.0.33",134 "@types/yargs": "^17.0.33",
public/css/extensions-panel.css+47 -6
@@ -65,7 +65,7 @@ label[for="extensions_autoconnect"] {
65}65}
6666
67.extensions_info .extension_enabled {67.extensions_info .extension_enabled {
68 color: green;68 font-weight: bold;
69}69}
7070
71.extensions_info .extension_disabled {71.extensions_info .extension_disabled {
@@ -76,13 +76,44 @@ label[for="extensions_autoconnect"] {
76 color: gray;76 color: gray;
77}77}
7878
79input.extension_missing[type="checkbox"] {79.extensions_info .extension_modules {
80 opacity: 0.5;80 font-size: 0.8em;
81 font-weight: normal;
81}82}
8283
83#extensions_list .disabled {84.extensions_info .extension_block {
84 text-decoration: line-through;85 display: flex;
85 color: lightgray;86 flex-wrap: nowrap;
87 padding: 5px;
88 margin-bottom: 5px;
89 border: 1px solid var(--SmartThemeBorderColor);
90 border-radius: 10px;
91 align-items: baseline;
92 justify-content: space-between;
93 gap: 5px;
94}
95
96.extensions_info .extension_name {
97 font-size: 1.05em;
98}
99
100.extensions_info .extension_version {
101 opacity: 0.8;
102 font-size: 0.8em;
103 font-weight: normal;
104 margin-left: 2px;
105}
106
107.extensions_info .extension_block a {
108 color: var(--SmartThemeBodyColor);
109}
110
111.extensions_info .extension_name.update_available {
112 color: limegreen;
113}
114
115input.extension_missing[type="checkbox"] {
116 opacity: 0.5;
86}117}
87118
88.update-button {119.update-button {
@@ -105,3 +136,13 @@ input.extension_missing[type="checkbox"] {
105#extensionsMenu>div.extension_container:empty {136#extensionsMenu>div.extension_container:empty {
106 display: none;137 display: none;
107}138}
139
140.extensions_info .extension_text_block {
141 white-space: nowrap;
142 overflow: hidden;
143 text-overflow: ellipsis;
144}
145
146.extensions_info .extension_actions {
147 flex-wrap: nowrap;
148}
public/css/promptmanager.css+6 -1
@@ -28,6 +28,11 @@
28 color: var(--white50a);28 color: var(--white50a);
29}29}
3030
31#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .completion_prompt_manager_prompt_name .fa-solid[data-role] {
32 vertical-align: unset;
33 margin-left: 3px;
34}
35
31#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_invisible {36#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt_invisible {
32 display: none;37 display: none;
33}38}
@@ -260,7 +265,7 @@
260}265}
261266
262#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .completion_prompt_manager_prompt_name .fa-solid.prompt-manager-overridden {267#completion_prompt_manager #completion_prompt_manager_list .completion_prompt_manager_prompt .completion_prompt_manager_prompt_name .fa-solid.prompt-manager-overridden {
263 margin-left: 5px;268 margin-left: 3px;
264 color: var(--SmartThemeQuoteColor);269 color: var(--SmartThemeQuoteColor);
265 cursor: pointer;270 cursor: pointer;
266 opacity: 0.8;271 opacity: 0.8;
public/global.d.ts+17 -393
@@ -20,400 +20,24 @@ declare global {
20 pagination(method: 'getCurrentPageNum'): number;20 pagination(method: 'getCurrentPageNum'): number;
21 pagination(method: string, options?: any): JQuery;21 pagination(method: string, options?: any): JQuery;
22 pagination(options?: any): JQuery;22 pagination(options?: any): JQuery;
23 transition(options?: any, complete?: function): JQuery;
24 autocomplete(options?: any): JQuery;
25 autocomplete(method: string, options?: any): JQuery;
26 slider(options?: any): JQuery;
27 slider(method: string, func: string, options?: any): JQuery;
28 cropper(options?: any): JQuery;
29 izoomify(options?: any): JQuery;23 izoomify(options?: any): JQuery;
30
31 //#region select2
32
33 /**
34 * Initializes or modifies a select2 instance with provided options
35 *
36 * @param options - Configuration options for the select2 instance
37 * @returns The jQuery object for chaining
38 */
39 select2(options?: Select2Options): JQuery;
40
41 /**
42 * Retrieves data currently selected in the select2 instance
43 *
44 * @param field - A string specifying the 'data' method
45 * @returns An array of selected items
46 */
47 select2(field: 'data'): any[];
48
49 /**
50 * Calls the specified select2 method
51 *
52 * @param method - The name of the select2 method to invoke
53 * @returns The jQuery object for chaining
54 */
55 select2(method: 'open' | 'close' | 'destroy' | 'focus' | 'val', value?: any): JQuery;
56
57 //#endregion
58
59 //#region sortable
60
61 /**
62 * Initializes or updates a sortable instance with the provided options
63 *
64 * @param options - Configuration options for the sortable instance
65 * @returns The jQuery object for chaining
66 */
67 sortable(options?: SortableOptions): JQuery;
68
69 /**
70 * Calls a sortable method to perform actions on the instance
71 *
72 * @param method - The name of the sortable method to invoke
73 * @returns The jQuery object for chaining
74 */
75 sortable(method: 'destroy' | 'disable' | 'enable' | 'refresh' | 'toArray'): JQuery;
76
77 /**
78 * Retrieves the sortable's instance object. If the element does not have an associated instance, undefined is returned.
79 *
80 * @returns The instance of the sortable object
81 */
82 sortable(method: 'instance'): object;
83
84 /**
85 * Retrieves the current option value for the specified option
86 *
87 * @param method - The string 'option' to retrieve an option value
88 * @param optionName - The name of the option to retrieve
89 * @returns The value of the specified option
90 */
91 sortable(method: 'option', optionName: string): any;
92
93 /**
94 * Sets the value of the specified option
95 *
96 * @param method - The string 'option' to set an option value
97 * @param optionName - The name of the option to set
98 * @param value - The value to assign to the option
99 * @returns The jQuery object for chaining
100 */
101 sortable(method: 'option', optionName: string, value: any): JQuery;
102
103 /**
104 * Sets multiple options using an object
105 *
106 * @param method - The string 'option' to set options
107 * @param options - An object containing multiple option key-value pairs
108 * @returns The jQuery object for chaining
109 */
110 sortable(method: 'option', options: SortableOptions): JQuery;
111
112 //#endregion
113 }24 }
114}
115
116//#region select2
117
118/** Options for configuring a select2 instance */
119interface Select2Options {
120 /**
121 * Provides support for ajax data sources
122 * @param params - Parameters including the search term
123 * @param callback - A callback function to handle the results
124 * @default null
125 */
126 ajax?: {
127 url: string;
128 dataType?: string;
129 delay?: number;
130 data?: (params: any) => any;
131 processResults?: (data: any, params: any) => any;
132 } | { transport: (params, success, failure) => any };
133
134 /**
135 * Provides support for clearable selections
136 * @default false
137 */
138 allowClear?: boolean;
139
140 /**
141 * See Using Select2 with AMD or CommonJS loaders
142 * @default './i18n/'
143 */
144 amdLanguageBase?: string;
145
146 /**
147 * Controls whether the dropdown is closed after a selection is made
148 * @default true
149 */
150 closeOnSelect?: boolean;
151
152 /**
153 * Allows rendering dropdown options from an array
154 * @default null
155 */
156 data?: object[];
157
158 /**
159 * Used to override the built-in DataAdapter
160 * @default SelectAdapter
161 */
162 dataAdapter?: SelectAdapter;
163
164 /**
165 * Enable debugging messages in the browser console
166 * @default false
167 */
168 debug?: boolean;
169
170 /**
171 * Sets the dir attribute on the selection and dropdown containers to indicate the direction of the text
172 * @default 'ltr'
173 */
174 dir?: string;
175
176 /**
177 * When set to true, the select control will be disabled
178 * @default false
179 */
180 disabled?: boolean;
181
182 /**
183 * Used to override the built-in DropdownAdapter
184 * @default DropdownAdapter
185 */
186 dropdownAdapter?: DropdownAdapter;
187
188 /**
189 * @default false
190 */
191 dropdownAutoWidth?: boolean;
192
193 /**
194 * Adds additional CSS classes to the dropdown container. The helper :all: can be used to add all CSS classes present on the original <select> element.
195 * @default ''
196 */
197 dropdownCssClass?: string;
198
199 /**
200 * Allows you to customize placement of the dropdown
201 * @default $(document.body)
202 */
203 dropdownParent?: JQuery | HTMLElement;
204
205 /**
206 * Handles automatic escaping of content rendered by custom templates
207 * @default Utils.escapeMarkup
208 */
209 escapeMarkup?: function;
210
211 /**
212 * Specify the language used for Select2 messages
213 * @default EnglishTranslation
214 */
215 language?: string | object;
216
217 /**
218 * Handles custom search matching
219 * @default null
220 */
221 matcher?: (searchParams: object, data: object) => boolean;
222
223 /**
224 * Maximum number of characters that may be provided for a search term
225 * @default 0
226 */
227 maximumInputLength?: number;
228
229 /**
230 * The maximum number of items that may be selected in a multi-select control. If the value of this option is less than 1, the number of selected items will not be limited.
231 * @default 0
232 */
233 maximumSelectionLength?: number;
23425
235 /**26 namespace Select2 {
236 * Minimum number of characters required to start a search27 interface Options<Result = DataFormat | GroupedDataFormat, RemoteResult = any> {
237 * @default 028 /**
238 */29 * Extends Select2 v4 plugin by adding an option to set a placeholder for the 'search' input field
239 minimumInputLength?: number;30 * [Custom Field]
24031 * @default ''
241 /**32 */
242 * The minimum number of results required to display the search box33 searchInputPlaceholder?: string;
243 * @default 034
244 */35 /**
245 minimumResultsForSearch?: number;36 * Extends select2 plugin by adding a custom css class for the 'search' input field
24637 * [Custom Field]
247 /**38 * @default ''
248 * This option enables multi-select (pillbox) mode. Select2 will automatically map the value of the multiple HTML attribute to this option during initialization.39 */
249 * @default false40 searchInputCssClass?: string;
250 */41 }
251 multiple?: boolean;42 }
252
253 /**
254 * Specifies the placeholder for the control
255 * @default null
256 */
257 placeholder?: string;
258
259 /**
260 * Used to override the built-in ResultsAdapter
261 * @default ResultsAdapter
262 */
263 resultsAdapter?: ResultsAdapter;
264
265 /**
266 * Used to override the built-in SelectionAdapter
267 * @default SingleSelection | MultipleSelection
268 */
269 selectionAdapter?: SingleSelection | MultipleSelection;
270
271 /**
272 * Adds additional CSS classes to the selection container. The helper :all: can be used to add all CSS classes present on the original <select> element
273 * @default ''
274 */
275 selectionCssClass?: string;
276
277 /**
278 * Implements automatic selection when the dropdown is closed
279 * @default false
280 */
281 selectOnClose?: boolean;
282
283 sorter?: function;
284
285 /**
286 * When set to `true`, allows the user to create new tags that aren't pre-populated
287 * Used to enable free text responses
288 * @default false
289 */
290 tags?: boolean | object[];
291
292 /**
293 * Customizes the way that search results are rendered
294 * @param item - The item object to format
295 * @returns The formatted representation
296 * @default null
297 */
298 templateResult?: (item: any) => JQuery | string;
299
300 /**
301 * Customizes the way that selections are rendered
302 * @param item - The selected item object to format
303 * @returns The formatted representation
304 * @default null
305 */
306 templateSelection?: (item: any) => JQuery | string;
307
308 /**
309 * Allows you to set the theme
310 * @default 'default'
311 */
312 theme?: string;
313
314 /**
315 * A callback that handles automatic tokenization of free-text entry
316 * @default null
317 */
318 tokenizer?: (input: { _type: string, term: string }, selection: { options: object }, callback: (Select2Option) => any) => { term: string };
319
320 /**
321 * The list of characters that should be used as token separators
322 * @default null
323 */
324 tokenSeparators?: string[];
325
326 /**
327 * Supports customization of the container width
328 * @default 'resolve'
329 */
330 width?: string;
331
332 /**
333 * If true, resolves issue for multiselects using closeOnSelect: false that caused the list of results to scroll to the first selection after each select/unselect
334 * @default false
335 */
336 scrollAfterSelect?: boolean;
337
338 /**
339 * Extends Select2 v4 plugin by adding an option to set a placeholder for the 'search' input field
340 * [Custom Field]
341 * @default ''
342 */
343 searchInputPlaceholder?: string;
344
345 /**
346 * Extends select2 plugin by adding a custom css class for the 'searcH' input field
347 * [Custom Field]
348 * @default ''
349 */
350 searchInputCssClass?: string;
351}
352
353//#endregion
354
355//#region sortable
356
357/** Options for configuring a sortable instance */
358interface SortableOptions {
359 /**
360 * When set, prevents the sortable items from being dragged unless clicked with a delay
361 * @default 0
362 */
363 delay?: number;
364
365 /**
366 * Class name for elements to handle sorting. Elements with this class can be dragged to sort.
367 * @default ''
368 */
369 handle?: string;
370
371 /**
372 * Whether to allow sorting between different connected lists
373 * @default false
374 */
375 connectWith?: string | boolean;
376
377 /**
378 * Function called when sorting starts
379 * @param event - The event object
380 * @param ui - The UI object containing the helper and position information
381 */
382 start?: (event: Event, ui: SortableUI) => void;
383
384 /**
385 * Function called when sorting stops
386 * @param event - The event object
387 * @param ui - The UI object containing the helper and position information
388 */
389 stop?: (event: Event, ui: SortableUI) => void;
390
391 /**
392 * Function called when sorting updates
393 * @param event - The event object
394 * @param ui - The UI object containing the helper and position information
395 */
396 update?: (event: Event, ui: SortableUI) => void;
397
398 /**
399 * Specifies which items inside the element should be sortable
400 * @default '> *'
401 */
402 items?: string;
403}
404
405/** UI object passed to sortable event handlers */
406interface SortableUI {
407 /** jQuery object representing the helper element */
408 helper: JQuery;
409 /** The current position of the helper element */
410 position: { top: number; left: number };
411 /** Original position of the helper element */
412 originalPosition: { top: number; left: number };
413 /** jQuery object representing the item being sorted */
414 item: JQuery;
415 /** The placeholder element used during sorting */
416 placeholder: JQuery;
417}43}
418
419//#endregion
public/img/deepseek.svg+6 -0
@@ -0,0 +1,6 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128px" height="128px" viewBox="0 0 128 128" version="1.1">
3<g id="surface1">
4<path d="M 126.65625 23.902344 C 125.300781 23.242188 124.714844 24.507812 123.925781 25.152344 C 123.652344 25.359375 123.425781 25.632812 123.195312 25.878906 C 121.210938 27.996094 118.894531 29.382812 115.871094 29.214844 C 111.449219 28.96875 107.675781 30.355469 104.335938 33.738281 C 103.625 29.566406 101.269531 27.082031 97.683594 25.484375 C 95.808594 24.652344 93.910156 23.824219 92.59375 22.015625 C 91.675781 20.730469 91.425781 19.296875 90.964844 17.886719 C 90.671875 17.035156 90.378906 16.164062 89.402344 16.019531 C 88.335938 15.855469 87.921875 16.746094 87.503906 17.492188 C 85.835938 20.542969 85.1875 23.902344 85.253906 27.308594 C 85.398438 34.964844 88.628906 41.066406 95.054688 45.402344 C 95.785156 45.898438 95.972656 46.398438 95.742188 47.125 C 95.308594 48.617188 94.785156 50.070312 94.324219 51.566406 C 94.03125 52.523438 93.59375 52.726562 92.570312 52.316406 C 89.109375 50.828125 85.96875 48.691406 83.3125 46.019531 C 78.742188 41.605469 74.613281 36.730469 69.460938 32.910156 C 68.269531 32.03125 67.042969 31.191406 65.785156 30.398438 C 60.535156 25.296875 66.480469 21.105469 67.855469 20.609375 C 69.296875 20.085938 68.351562 18.304688 63.703125 18.324219 C 59.050781 18.347656 54.792969 19.898438 49.371094 21.972656 C 48.566406 22.28125 47.734375 22.527344 46.890625 22.703125 C 41.820312 21.75 36.636719 21.566406 31.515625 22.160156 C 21.460938 23.28125 13.433594 28.039062 7.53125 36.148438 C 0.4375 45.898438 -1.230469 56.980469 0.8125 68.535156 C 2.960938 80.714844 9.179688 90.800781 18.730469 98.683594 C 28.640625 106.859375 40.046875 110.863281 53.066406 110.097656 C 60.96875 109.644531 69.777344 108.582031 79.703125 100.175781 C 82.207031 101.425781 84.832031 101.921875 89.195312 102.292969 C 92.554688 102.609375 95.785156 102.132812 98.289062 101.609375 C 102.207031 100.777344 101.9375 97.148438 100.523438 96.484375 C 89.03125 91.128906 91.550781 93.3125 89.253906 91.546875 C 95.097656 84.632812 103.898438 77.457031 107.34375 54.199219 C 107.609375 52.347656 107.382812 51.183594 107.34375 49.691406 C 107.324219 48.785156 107.53125 48.425781 108.570312 48.324219 C 111.457031 48.027344 114.253906 47.164062 116.8125 45.792969 C 124.257812 41.722656 127.265625 35.046875 127.972656 27.035156 C 128.078125 25.808594 127.953125 24.542969 126.65625 23.898438 Z M 61.765625 96 C 50.625 87.242188 45.222656 84.355469 42.992188 84.480469 C 40.902344 84.609375 41.28125 86.992188 41.738281 88.550781 C 42.21875 90.085938 42.84375 91.140625 43.71875 92.492188 C 44.324219 93.382812 44.742188 94.710938 43.113281 95.707031 C 39.523438 97.925781 33.289062 94.960938 32.996094 94.816406 C 25.738281 90.539062 19.664062 84.894531 15.390625 77.179688 C 11.265625 69.75 8.863281 61.78125 8.46875 53.273438 C 8.363281 51.214844 8.964844 50.492188 11.011719 50.117188 C 13.703125 49.601562 16.457031 49.53125 19.167969 49.910156 C 30.539062 51.574219 40.214844 56.65625 48.332031 64.703125 C 52.960938 69.289062 56.464844 74.769531 60.074219 80.121094 C 63.914062 85.808594 68.042969 91.226562 73.300781 95.664062 C 75.15625 97.222656 76.632812 98.40625 78.054688 99.273438 C 73.777344 99.753906 66.640625 99.863281 61.765625 96 Z M 67.097656 61.652344 C 67.097656 61.117188 67.359375 60.609375 67.800781 60.304688 C 68.246094 60 68.808594 59.929688 69.3125 60.121094 C 70.378906 62.097656 70.207031 62.515625 69.894531 62.824219 C 69.585938 63.132812 69.164062 63.300781 68.726562 63.296875 C 68.292969 63.296875 67.875 63.125 67.570312 62.816406 C 67.265625 62.507812 67.097656 62.085938 67.105469 61.652344 Z M 83.683594 70.164062 C 82.617188 70.597656 81.558594 70.96875 80.539062 71.019531 C 79.007812 71.070312 77.503906 70.59375 76.28125 69.664062 C 74.820312 68.4375 73.777344 67.753906 73.339844 65.621094 C 73.1875 64.578125 73.214844 63.519531 73.425781 62.484375 C 73.796875 60.742188 73.382812 59.621094 72.148438 58.609375 C 71.152344 57.777344 69.878906 57.546875 68.480469 57.546875 C 68 57.519531 67.535156 57.375 67.125 57.128906 C 66.539062 56.84375 66.058594 56.117188 66.515625 55.222656 C 66.667969 54.933594 67.371094 54.230469 67.542969 54.101562 C 69.441406 53.023438 71.632812 53.375 73.652344 54.1875 C 75.53125 54.953125 76.949219 56.363281 78.992188 58.355469 C 81.078125 60.761719 81.457031 61.429688 82.644531 63.230469 C 83.585938 64.644531 84.4375 66.097656 85.019531 67.753906 C 85.375 68.792969 84.917969 69.644531 83.683594 70.164062 Z M 83.683594 70.164062 "/>
5</g>
6</svg>
public/img/generic.svg+15 -0
@@ -0,0 +1,15 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg
3 width="616.86328"
4 height="616.86328"
5 viewBox="0 0 77.10791 77.10791"
6 version="1.1"
7 id="svg4"
8 xmlns="http://www.w3.org/2000/svg"
9 xmlns:svg="http://www.w3.org/2000/svg">
10 <defs
11 id="defs4" />
12 <path
13 id="circle1"
14 d="M 38.553955,0 A 38.554,38.554 0 0 0 0,38.553955 38.554,38.554 0 0 0 38.553955,77.107911 38.554,38.554 0 0 0 77.107911,38.553955 38.554,38.554 0 0 0 38.553955,0 Z m -3.125976,13.545898 h 6.251953 v 19.593751 l 16.968751,-9.796875 3.125974,5.414306 -16.968506,9.796875 16.968506,9.796877 -3.125974,5.414305 -16.968751,-9.796874 V 63.56201 H 35.427979 V 43.968263 l -16.968506,9.796874 -3.125977,-5.414305 16.96875,-9.796877 -16.96875,-9.796875 3.125977,-5.414306 16.968506,9.796875 z" />
15</svg>
public/index.html+153 -61
@@ -651,6 +651,19 @@
651 <input type="number" id="n_openai" name="n_openai" class="text_pole" min="1" value="1">651 <input type="number" id="n_openai" name="n_openai" class="text_pole" min="1" value="1">
652 </div>652 </div>
653 </div>653 </div>
654 <div data-source="openrouter" class="range-block">
655 <div class="range-block-title" title="Allow compressing requests by removing messages from the middle of the prompt.">
656 <span data-i18n="Middle-out Transform">Middle-out Transform</span>
657 <a href="https://openrouter.ai/docs/transforms" target="_blank" rel="noreferrer noopener" class="note-link-span fa-solid fa-circle-question"></a>
658 </div>
659 <div class="wide100p">
660 <select id="openrouter_middleout" class="text_pole">
661 <option value="auto" data-i18n="Auto">Auto</option>
662 <option value="on" data-i18n="Allow">Allow</option>
663 <option value="off" data-i18n="Forbid">Forbid</option>
664 </select>
665 </div>
666 </div>
654 <div data-source="openrouter">667 <div data-source="openrouter">
655 Max prompt cost: <span id="openrouter_max_prompt_cost">Unknown</span>668 Max prompt cost: <span id="openrouter_max_prompt_cost">Unknown</span>
656 </div>669 </div>
@@ -669,7 +682,7 @@
669 </span>682 </span>
670 </div>683 </div>
671 </div>684 </div>
672 <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt">685 <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek">
673 <div class="range-block-title" data-i18n="Temperature">686 <div class="range-block-title" data-i18n="Temperature">
674 Temperature687 Temperature
675 </div>688 </div>
@@ -682,7 +695,7 @@
682 </div>695 </div>
683 </div>696 </div>
684 </div>697 </div>
685 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt">698 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek">
686 <div class="range-block-title" data-i18n="Frequency Penalty">699 <div class="range-block-title" data-i18n="Frequency Penalty">
687 Frequency Penalty700 Frequency Penalty
688 </div>701 </div>
@@ -695,7 +708,7 @@
695 </div>708 </div>
696 </div>709 </div>
697 </div>710 </div>
698 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt">711 <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek">
699 <div class="range-block-title" data-i18n="Presence Penalty">712 <div class="range-block-title" data-i18n="Presence Penalty">
700 Presence Penalty713 Presence Penalty
701 </div>714 </div>
@@ -721,7 +734,7 @@
721 </div>734 </div>
722 </div>735 </div>
723 </div>736 </div>
724 <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt">737 <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek">
725 <div class="range-block-title" data-i18n="Top P">738 <div class="range-block-title" data-i18n="Top P">
726 Top P739 Top P
727 </div>740 </div>
@@ -1235,7 +1248,8 @@
1235 <input class="neo-range-slider" type="range" id="temp_textgenerationwebui" name="volume" min="0.0" max="5.0" step="0.01" x-setting-id="temp">1248 <input class="neo-range-slider" type="range" id="temp_textgenerationwebui" name="volume" min="0.0" max="5.0" step="0.01" x-setting-id="temp">
1236 <input class="neo-range-input" type="number" min="0.0" max="5.0" step="0.01" data-for="temp_textgenerationwebui" id="temp_counter_textgenerationwebui">1249 <input class="neo-range-input" type="number" min="0.0" max="5.0" step="0.01" data-for="temp_textgenerationwebui" id="temp_counter_textgenerationwebui">
1237 </div>1250 </div>
1238 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1251 <!-- Note: "except" mode = show for all BUT types in data-tg-type -->
1252 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1239 <small>1253 <small>
1240 <span data-i18n="Top K">Top K</span>1254 <span data-i18n="Top K">Top K</span>
1241 <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from.&#13;E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited).&#13;Set to 0 (or -1, depending on your backend) to disable." data-i18n="[title]Top_K_desc"></div>1255 <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from.&#13;E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited).&#13;Set to 0 (or -1, depending on your backend) to disable." data-i18n="[title]Top_K_desc"></div>
@@ -1251,7 +1265,7 @@
1251 <input class="neo-range-slider" type="range" id="top_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1265 <input class="neo-range-slider" type="range" id="top_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1252 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p_textgenerationwebui" id="top_p_counter_textgenerationwebui">1266 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p_textgenerationwebui" id="top_p_counter_textgenerationwebui">
1253 </div>1267 </div>
1254 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1268 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1255 <small>1269 <small>
1256 <span data-i18n="Typical P">Typical P</span>1270 <span data-i18n="Typical P">Typical P</span>
1257 <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set.&#13;It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content.&#13;Set to 1.0 to disable." data-i18n="[title]Typical_P_desc"></div>1271 <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set.&#13;It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content.&#13;Set to 1.0 to disable." data-i18n="[title]Typical_P_desc"></div>
@@ -1259,7 +1273,7 @@
1259 <input class="neo-range-slider" type="range" id="typical_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1273 <input class="neo-range-slider" type="range" id="typical_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1260 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="typical_p_textgenerationwebui" id="typical_p_counter_textgenerationwebui">1274 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="typical_p_textgenerationwebui" id="typical_p_counter_textgenerationwebui">
1261 </div>1275 </div>
1262 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1276 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1263 <small>1277 <small>
1264 <span data-i18n="Min P">Min P</span>1278 <span data-i18n="Min P">Min P</span>
1265 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min_P_desc" title="Min P sets a base minimum probability. This is scaled according to the top token's probability.&#13;E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered.&#13;Set to 0 to disable."></div>1279 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min_P_desc" title="Min P sets a base minimum probability. This is scaled according to the top token's probability.&#13;E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered.&#13;Set to 0 to disable."></div>
@@ -1267,7 +1281,7 @@
1267 <input class="neo-range-slider" type="range" id="min_p_textgenerationwebui" name="volume" min="0" max="1" step="0.001">1281 <input class="neo-range-slider" type="range" id="min_p_textgenerationwebui" name="volume" min="0" max="1" step="0.001">
1268 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p_textgenerationwebui" id="min_p_counter_textgenerationwebui">1282 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p_textgenerationwebui" id="min_p_counter_textgenerationwebui">
1269 </div>1283 </div>
1270 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1284 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1271 <small>1285 <small>
1272 <span data-i18n="Top A">Top A</span>1286 <span data-i18n="Top A">Top A</span>
1273 <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability.&#13;E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded.&#13;Set to 0 to disable." data-i18n="[title]Top_A_desc"></div>1287 <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability.&#13;E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded.&#13;Set to 0 to disable." data-i18n="[title]Top_A_desc"></div>
@@ -1275,7 +1289,7 @@
1275 <input class="neo-range-slider" type="range" id="top_a_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1289 <input class="neo-range-slider" type="range" id="top_a_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1276 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_a_textgenerationwebui" id="top_a_counter_textgenerationwebui">1290 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_a_textgenerationwebui" id="top_a_counter_textgenerationwebui">
1277 </div>1291 </div>
1278 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1292 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1279 <small>1293 <small>
1280 <span data-i18n="TFS">TFS</span>1294 <span data-i18n="TFS">TFS</span>
1281 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>1295 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>
@@ -1307,7 +1321,7 @@
1307 <input class="neo-range-slider" type="range" id="eta_cutoff_textgenerationwebui" name="volume" min="0" max="20" step="0.01">1321 <input class="neo-range-slider" type="range" id="eta_cutoff_textgenerationwebui" name="volume" min="0" max="20" step="0.01">
1308 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="eta_cutoff_textgenerationwebui" id="eta_cutoff_counter_textgenerationwebui">1322 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="eta_cutoff_textgenerationwebui" id="eta_cutoff_counter_textgenerationwebui">
1309 </div>1323 </div>
1310 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1324 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1311 <small data-i18n="rep.pen">Repetition Penalty</small>1325 <small data-i18n="rep.pen">Repetition Penalty</small>
1312 <input class="neo-range-slider" type="range" id="rep_pen_textgenerationwebui" name="volume" min="1" max="3" step="0.01">1326 <input class="neo-range-slider" type="range" id="rep_pen_textgenerationwebui" name="volume" min="1" max="3" step="0.01">
1313 <input class="neo-range-input" type="number" min="1" max="3" step="0.01" data-for="rep_pen_textgenerationwebui" id="rep_pen_counter_textgenerationwebui">1327 <input class="neo-range-input" type="number" min="1" max="3" step="0.01" data-for="rep_pen_textgenerationwebui" id="rep_pen_counter_textgenerationwebui">
@@ -1569,7 +1583,7 @@
1569 <small data-i18n="Ignore EOS Token">Ignore EOS Token</small>1583 <small data-i18n="Ignore EOS Token">Ignore EOS Token</small>
1570 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ignore the EOS Token even if it generates." title="Ignore the EOS Token even if it generates."></div>1584 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ignore the EOS Token even if it generates." title="Ignore the EOS Token even if it generates."></div>
1571 </label>1585 </label>
1572 <label class="checkbox_label flexGrow flexShrink" for="skip_special_tokens_textgenerationwebui">1586 <label data-tg-type-mode="except" data-tg-type="generic" class="checkbox_label flexGrow flexShrink" for="skip_special_tokens_textgenerationwebui">
1573 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />1587 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />
1574 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>1588 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>
1575 </label>1589 </label>
@@ -1594,14 +1608,14 @@
1594 </label>1608 </label>
1595 </div>1609 </div>
1596 </div>1610 </div>
1597 <div data-tg-type="mancer, ooba, koboldcpp, vllm, aphrodite, llamacpp, ollama, infermaticai, huggingface" class="flex-container flexFlowColumn alignitemscenter flexBasis48p flexGrow flexShrink gap0">1611 <div data-tg-type="mancer, ooba, koboldcpp, vllm, aphrodite, llamacpp, ollama, infermaticai, huggingface, generic" class="flex-container flexFlowColumn alignitemscenter flexBasis48p flexGrow flexShrink gap0">
1598 <label>1612 <label>
1599 <small data-i18n="Seed">Seed</small>1613 <small data-i18n="Seed">Seed</small>
1600 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Seed_desc" title="A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed."></div>1614 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Seed_desc" title="A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed."></div>
1601 </label>1615 </label>
1602 <input type="number" id="seed_textgenerationwebui" class="text_pole textAlignCenter" min="-1" value="-1" />1616 <input type="number" id="seed_textgenerationwebui" class="text_pole textAlignCenter" min="-1" value="-1" />
1603 </div>1617 </div>
1604 <div id="banned_tokens_block_ooba" class="wide100p">1618 <div data-tg-type-mode="except" data-tg-type="generic" id="banned_tokens_block_ooba" class="wide100p">
1605 <hr class="width100p">1619 <hr class="width100p">
1606 <h4 class="range-block-title justifyCenter">1620 <h4 class="range-block-title justifyCenter">
1607 <span data-i18n="Banned Tokens">Banned Tokens/Strings</span>1621 <span data-i18n="Banned Tokens">Banned Tokens/Strings</span>
@@ -1735,6 +1749,7 @@
1735 <div data-name="tfs_z" draggable="true"><span>Tail Free Sampling</span><small></small></div>1749 <div data-name="tfs_z" draggable="true"><span>Tail Free Sampling</span><small></small></div>
1736 <div data-name="min_p" draggable="true"><span>Min P</span><small></small></div>1750 <div data-name="min_p" draggable="true"><span>Min P</span><small></small></div>
1737 <div data-name="xtc" draggable="true"><span>Exclude Top Choices</span><small></small></div>1751 <div data-name="xtc" draggable="true"><span>Exclude Top Choices</span><small></small></div>
1752 <div data-name="dry" draggable="true"><span>DRY</span><small></small></div>
1738 </div>1753 </div>
1739 <div id="llamacpp_samplers_default_order" class="menu_button menu_button_icon">1754 <div id="llamacpp_samplers_default_order" class="menu_button menu_button_icon">
1740 <span data-i18n="Load default order">Load default order</span>1755 <span data-i18n="Load default order">Load default order</span>
@@ -1774,6 +1789,35 @@
1774 <span data-i18n="Load default order">Load default order</span>1789 <span data-i18n="Load default order">Load default order</span>
1775 </div>1790 </div>
1776 </div>1791 </div>
1792 <div id="sampler_priority_block_aphrodite" data-tg-type="aphrodite" class="range-block flexFlowColumn wide100p">
1793 <hr class="wide100p">
1794 <h4 class="range-block-title justifyCenter">
1795 <span data-i18n="Sampler Order">Sampler Order</span>
1796 <div class="margin5 fa-solid fa-circle-info opacity50p" title="Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here." data-i18n="[title]Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here."></div>
1797 </h4>
1798 <div class="toggle-description widthUnset" data-i18n="Aphrodite only. Determines the order of samplers.">
1799 Aphrodite only. Determines the order of samplers.
1800 </div>
1801 <div id="sampler_priority_container_aphrodite" class="prompt_order">
1802 <div data-name="dry" draggable="true"><span>DRY</span><small></small></div>
1803 <div data-name="penalties" draggable="true"><span>Penalties</span><small></small></div>
1804 <div data-name="no_repeat_ngram" draggable="true"><span>No Repeat Ngram</span><small></small></div>
1805 <div data-name="temperature" draggable="true"><span>Dynatemp & Temperature</span><small></small></div>
1806 <div data-name="top_nsigma" draggable="true"><span>Top Nsigma</span><small></small></div>
1807 <div data-name="top_p_top_k" draggable="true"><span>Top P & Top K</span><small></small></div>
1808 <div data-name="top_a" draggable="true"><span>Top A</span><small></small></div>
1809 <div data-name="min_p" draggable="true"><span>Min P</span><small></small></div>
1810 <div data-name="tfs" draggable="true"><span>Tail-Free Sampling</span><small></small></div>
1811 <div data-name="eta_cutoff" draggable="true"><span>Eta Cutoff</span><small></small></div>
1812 <div data-name="epsilon_cutoff" draggable="true"><span>Epsilon Cutoff</span><small></small></div>
1813 <div data-name="typical_p" draggable="true"><span>Typical P</span><small></small></div>
1814 <div data-name="quadratic" draggable="true"><span>Cubic and Quadratic Sampling</span><small></small></div>
1815 <div data-name="xtc" draggable="true"><span>XTC</span><small></small></div>
1816 </div>
1817 <div id="aphrodite_default_order" class="menu_button menu_button_icon">
1818 <span data-i18n="Load default order">Load default order</span>
1819 </div>
1820 </div>
1777 </div>1821 </div>
1778 </div><!-- end of textgen settings-->1822 </div><!-- end of textgen settings-->
1779 <div id="openai_settings">1823 <div id="openai_settings">
@@ -1921,8 +1965,8 @@
1921 <label for="use_makersuite_sysprompt" class="checkbox_label widthFreeExpand">1965 <label for="use_makersuite_sysprompt" class="checkbox_label widthFreeExpand">
1922 <input id="use_makersuite_sysprompt" type="checkbox" />1966 <input id="use_makersuite_sysprompt" type="checkbox" />
1923 <span>1967 <span>
1924 <span data-i18n="Use system prompt">Use system prompt</span><br>1968 <span data-i18n="Use system prompt">Use system prompt</span>
1925 <small data-i18n="(Gemini 1.5 Pro/Flash only)">(Gemini 1.5 Pro/Flash only)</small>1969 <i class="opacity50p fa-solid fa-circle-info" title="Gemini 1.5/2.0 Pro/Flash"></i>
1926 </span>1970 </span>
1927 </label>1971 </label>
1928 <div class="toggle-description justifyLeft marginBot5">1972 <div class="toggle-description justifyLeft marginBot5">
@@ -1931,6 +1975,20 @@
1931 </span>1975 </span>
1932 </div>1976 </div>
1933 </div>1977 </div>
1978 <div class="range-block" data-source="makersuite">
1979 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
1980 <input id="openai_show_thoughts" type="checkbox" />
1981 <span>
1982 <span data-i18n="Show model thoughts">Show model thoughts</span>
1983 <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking"></i>
1984 </span>
1985 </label>
1986 <div class="toggle-description justifyLeft marginBot5">
1987 <span data-i18n="Display the model's internal thoughts in the response.">
1988 Display the model's internal thoughts in the response.
1989 </span>
1990 </div>
1991 </div>
1934 <div class="range-block" data-source="claude">1992 <div class="range-block" data-source="claude">
1935 <div class="wide100p">1993 <div class="wide100p">
1936 <div class="flex-container alignItemsCenter">1994 <div class="flex-container alignItemsCenter">
@@ -2022,7 +2080,7 @@
2022 <option value="textgenerationwebui" data-i18n="Text Completion">Text Completion</option>2080 <option value="textgenerationwebui" data-i18n="Text Completion">Text Completion</option>
2023 <option value="openai" data-i18n="Chat Completion">Chat Completion</option>2081 <option value="openai" data-i18n="Chat Completion">Chat Completion</option>
2024 <option value="novel" data-i18n="NovelAI">NovelAI</option>2082 <option value="novel" data-i18n="NovelAI">NovelAI</option>
2025 <option value="koboldhorde" data-i18n="KoboldAI Horde">KoboldAI Horde</option>2083 <option value="koboldhorde" data-i18n="AI Horde">AI Horde</option>
2026 <option value="kobold" data-i18n="KoboldAI">KoboldAI Classic</option>2084 <option value="kobold" data-i18n="KoboldAI">KoboldAI Classic</option>
2027 </select>2085 </select>
2028 </div>2086 </div>
@@ -2031,8 +2089,8 @@
2031 <div id="kobold_horde_block">2089 <div id="kobold_horde_block">
2032 <ul>2090 <ul>
2033 <li>2091 <li>
2034 <a target="_blank" href="https://aihorde.net/" data-i18n="KoboldAI Horde Website">2092 <a target="_blank" href="https://aihorde.net/" data-i18n="AI Horde Website">
2035 KoboldAI Horde Website2093 AI Horde Website
2036 </a>2094 </a>
2037 </li>2095 </li>
2038 <li>2096 <li>
@@ -2158,10 +2216,10 @@
2158 <div>2216 <div>
2159 <h4 data-i18n="API Type">API Type</h4>2217 <h4 data-i18n="API Type">API Type</h4>
2160 <select id="textgen_type">2218 <select id="textgen_type">
2161 <option value="ooba" data-i18n="Default (completions compatible)">Default [OpenAI /completions compatible: oobabooga, LM Studio, etc.]</option>
2162 <option value="aphrodite">Aphrodite</option>2219 <option value="aphrodite">Aphrodite</option>
2163 <option value="dreamgen">DreamGen</option>2220 <option value="dreamgen">DreamGen</option>
2164 <option value="featherless">Featherless</option>2221 <option value="featherless">Featherless</option>
2222 <option value="generic" data-i18n="Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]">Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]</option>
2165 <option value="huggingface">HuggingFace (Inference Endpoint)</option>2223 <option value="huggingface">HuggingFace (Inference Endpoint)</option>
2166 <option value="infermaticai">InfermaticAI</option>2224 <option value="infermaticai">InfermaticAI</option>
2167 <option value="koboldcpp">KoboldCpp</option>2225 <option value="koboldcpp">KoboldCpp</option>
@@ -2170,6 +2228,7 @@
2170 <option value="ollama">Ollama</option>2228 <option value="ollama">Ollama</option>
2171 <option value="openrouter">OpenRouter</option>2229 <option value="openrouter">OpenRouter</option>
2172 <option value="tabby">TabbyAPI</option>2230 <option value="tabby">TabbyAPI</option>
2231 <option value="ooba">Text Generation WebUI (oobabooga)</option>
2173 <option value="togetherai">TogetherAI</option>2232 <option value="togetherai">TogetherAI</option>
2174 <option value="vllm">vLLM</option>2233 <option value="vllm">vLLM</option>
2175 </select>2234 </select>
@@ -2292,6 +2351,24 @@
2292 </select>2351 </select>
2293 </div>2352 </div>
2294 </div>2353 </div>
2354 <div data-tg-type="generic" class="flex-container flexFlowColumn">
2355 <h4 data-i18n="API key (optional)">API key (optional)</h4>
2356 <div class="flex-container">
2357 <input id="api_key_generic" name="api_key_generic" class="text_pole flex1 wide100p" type="text" autocomplete="off">
2358 <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_generic">
2359 </div>
2360 </div>
2361 <div data-for="api_key_generic" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page.">
2362 For privacy reasons, your API key will be hidden after you reload the page.
2363 </div>
2364 <div class="flex1">
2365 <h4 data-i18n="Server url">Server URL</h4>
2366 <small data-i18n="Example: 127.0.0.1:5000">Example: http://127.0.0.1:5000</small>
2367 <input id="generic_api_url_text" name="generic_api_url" class="text_pole wide100p" value="" autocomplete="off" data-server-history="generic">
2368 </div>
2369 <datalist id="generic_model_fill"></datalist>
2370 <input id="generic_model_textgenerationwebui" list="generic_model_fill" class="text_pole wide100p" placeholder="Model ID (optional)" data-i18n="[placeholder]Model ID (optional)" type="text">
2371 </div>
2295 <div data-tg-type="ooba" class="flex-container flexFlowColumn">2372 <div data-tg-type="ooba" class="flex-container flexFlowColumn">
2296 <div class="flex-container flexFlowColumn">2373 <div class="flex-container flexFlowColumn">
2297 <a href="https://github.com/oobabooga/text-generation-webui" target="_blank">2374 <a href="https://github.com/oobabooga/text-generation-webui" target="_blank">
@@ -2567,7 +2644,7 @@
2567 </div>2644 </div>
2568 </div>2645 </div>
2569 <div class="flex-container flexFlowColumn marginTopBot5">2646 <div class="flex-container flexFlowColumn marginTopBot5">
2570 <label data-tg-type="ooba" class="checkbox_label" for="bypass_status_check_textgenerationwebui">2647 <label data-tg-type="ooba, generic" class="checkbox_label" for="bypass_status_check_textgenerationwebui">
2571 <input type="checkbox" id="bypass_status_check_textgenerationwebui" />2648 <input type="checkbox" id="bypass_status_check_textgenerationwebui" />
2572 <span data-i18n="Bypass status check">Bypass status check</span>2649 <span data-i18n="Bypass status check">Bypass status check</span>
2573 </label>2650 </label>
@@ -2602,6 +2679,7 @@
2602 <option value="blockentropy">Block Entropy</option>2679 <option value="blockentropy">Block Entropy</option>
2603 <option value="claude">Claude</option>2680 <option value="claude">Claude</option>
2604 <option value="cohere">Cohere</option>2681 <option value="cohere">Cohere</option>
2682 <option value="deepseek">DeepSeek</option>
2605 <option value="groq">Groq</option>2683 <option value="groq">Groq</option>
2606 <option value="makersuite">Google AI Studio</option>2684 <option value="makersuite">Google AI Studio</option>
2607 <option value="mistralai">MistralAI</option>2685 <option value="mistralai">MistralAI</option>
@@ -2976,33 +3054,31 @@
2976 <optgroup label="Primary">3054 <optgroup label="Primary">
2977 <option value="gemini-1.5-pro">Gemini 1.5 Pro</option>3055 <option value="gemini-1.5-pro">Gemini 1.5 Pro</option>
2978 <option value="gemini-1.5-flash">Gemini 1.5 Flash</option>3056 <option value="gemini-1.5-flash">Gemini 1.5 Flash</option>
2979 <option value="gemini-1.0-pro">Gemini 1.0 Pro</option>3057 <option value="gemini-1.0-pro">Gemini 1.0 Pro (Deprecated)</option>
2980 <option value="gemini-pro">Gemini Pro (1.0)</option>3058 <option value="gemini-pro">Gemini Pro (1.0) (Deprecated)</option>
2981 <option value="gemini-pro-vision">Gemini Pro Vision (1.0)</option>
2982 <option value="gemini-ultra">Gemini Ultra (1.0)</option>3059 <option value="gemini-ultra">Gemini Ultra (1.0)</option>
2983 <option value="gemini-1.0-ultra-latest">Gemini 1.0 Ultra</option>3060 <option value="gemini-1.0-ultra-latest">Gemini 1.0 Ultra</option>
2984 <option value="text-bison-001">PaLM 2 (Legacy)</option>
2985 <option value="chat-bison-001">PaLM 2 Chat (Legacy)</option>
2986 </optgroup>3061 </optgroup>
2987 <optgroup label="Subversions">3062 <optgroup label="Subversions">
2988 <option value="gemini-exp-1121">Gemini Experimental 2024-11-21</option>3063 <option value="gemini-2.0-flash-thinking-exp-1219">Gemini 2.0 Flash Thinking Experimental</option>
3064 <option value="gemini-2.0-flash-exp">Gemini 2.0 Flash Experimental</option>
2989 <option value="gemini-exp-1114">Gemini Experimental 2024-11-14</option>3065 <option value="gemini-exp-1114">Gemini Experimental 2024-11-14</option>
3066 <option value="gemini-exp-1121">Gemini Experimental 2024-11-21</option>
2990 <option value="gemini-exp-1206">Gemini Experimental 2024-12-06</option>3067 <option value="gemini-exp-1206">Gemini Experimental 2024-12-06</option>
2991 <option value="gemini-1.5-pro-exp-0801">Gemini 1.5 Pro Experiment 2024-08-01</option>3068 <option value="gemini-1.5-pro-exp-0801">Gemini 1.5 Pro Experimental 2024-08-01</option>
2992 <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option>3069 <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experimental 2024-08-27</option>
2993 <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option>3070 <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option>
2994 <option value="gemini-1.5-pro-001">Gemini 1.5 Pro [001]</option>3071 <option value="gemini-1.5-pro-001">Gemini 1.5 Pro [001]</option>
2995 <option value="gemini-1.5-pro-002">Gemini 1.5 Pro [002]</option>3072 <option value="gemini-1.5-pro-002">Gemini 1.5 Pro [002]</option>
2996 <option value="gemini-1.5-flash-8b">Gemini 1.5 Flash 8B</option>3073 <option value="gemini-1.5-flash-8b">Gemini 1.5 Flash 8B</option>
2997 <option value="gemini-1.5-flash-exp-0827">Gemini 1.5 Flash Experiment 2024-08-27</option>3074 <option value="gemini-1.5-flash-exp-0827">Gemini 1.5 Flash Experimental 2024-08-27</option>
2998 <option value="gemini-1.5-flash-8b-exp-0827">Gemini 1.5 Flash 8B Experiment 2024-08-27</option>3075 <option value="gemini-1.5-flash-8b-exp-0827">Gemini 1.5 Flash 8B Experimental 2024-08-27</option>
2999 <option value="gemini-1.5-flash-8b-exp-0924">Gemini 1.5 Flash 8B Experiment 2024-09-24</option>3076 <option value="gemini-1.5-flash-8b-exp-0924">Gemini 1.5 Flash 8B Experimental 2024-09-24</option>
3000 <option value="gemini-1.5-flash-latest">Gemini 1.5 Flash [latest]</option>3077 <option value="gemini-1.5-flash-latest">Gemini 1.5 Flash [latest]</option>
3001 <option value="gemini-1.5-flash-001">Gemini 1.5 Flash [001]</option>3078 <option value="gemini-1.5-flash-001">Gemini 1.5 Flash [001]</option>
3002 <option value="gemini-1.5-flash-002">Gemini 1.5 Flash [002]</option>3079 <option value="gemini-1.5-flash-002">Gemini 1.5 Flash [002]</option>
3003 <option value="gemini-1.0-pro-latest">Gemini 1.0 Pro [latest]</option>3080 <option value="gemini-1.0-pro-latest">Gemini 1.0 Pro [latest] (Deprecated)</option>
3004 <option value="gemini-1.0-pro-001">Gemini 1.0 Pro (Tuning) [001]</option>3081 <option value="gemini-1.0-pro-001">Gemini 1.0 Pro (Tuning) [001] (Deprecated)</option>
3005 <option value="gemini-1.0-pro-vision-latest">Gemini 1.0 Pro Vision [latest]</option>
3006 </optgroup>3082 </optgroup>
3007 </select>3083 </select>
3008 </div>3084 </div>
@@ -3071,6 +3147,9 @@
3071 </div>3147 </div>
3072 <h4 data-i18n="Groq Model">Groq Model</h4>3148 <h4 data-i18n="Groq Model">Groq Model</h4>
3073 <select id="model_groq_select">3149 <select id="model_groq_select">
3150 <optgroup label="Llama 3.3">
3151 <option value="llama-3.3-70b-versatile">llama-3.3-70b-versatile</option>
3152 </optgroup>
3074 <optgroup label="Llama 3.2">3153 <optgroup label="Llama 3.2">
3075 <option value="llama-3.2-1b-preview">llama-3.2-1b-preview</option>3154 <option value="llama-3.2-1b-preview">llama-3.2-1b-preview</option>
3076 <option value="llama-3.2-3b-preview">llama-3.2-3b-preview</option>3155 <option value="llama-3.2-3b-preview">llama-3.2-3b-preview</option>
@@ -3114,6 +3193,23 @@
3114 </select>3193 </select>
3115 </div>3194 </div>
3116 </div>3195 </div>
3196 <div id="deepseek_form" data-source="deepseek">
3197 <h4 data-i18n="DeepSeek API Key">DeepSeek API Key</h4>
3198 <div class="flex-container">
3199 <input id="api_key_deepseek" name="api_key_deepseek" class="text_pole flex1" value="" type="text" autocomplete="off">
3200 <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_deepseek"></div>
3201 </div>
3202 <div data-for="api_key_deepseek" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page.">
3203 For privacy reasons, your API key will be hidden after you reload the page.
3204 </div>
3205 <div>
3206 <h4 data-i18n="DeepSeek Model">DeepSeek Model</h4>
3207 <select id="model_deepseek_select">
3208 <option value="deepseek-chat">deepseek-chat</option>
3209 <option value="deepseek-coder">deepseek-coder</option>
3210 </select>
3211 </div>
3212 </div>
3117 <div id="perplexity_form" data-source="perplexity">3213 <div id="perplexity_form" data-source="perplexity">
3118 <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4>3214 <h4 data-i18n="Perplexity API Key">Perplexity API Key</h4>
3119 <div class="flex-container">3215 <div class="flex-container">
@@ -3167,16 +3263,17 @@
3167 <h4 data-i18n="Cohere Model">Cohere Model</h4>3263 <h4 data-i18n="Cohere Model">Cohere Model</h4>
3168 <select id="model_cohere_select">3264 <select id="model_cohere_select">
3169 <optgroup label="Stable">3265 <optgroup label="Stable">
3170 <option value="c4ai-aya-expanse-32b">c4ai-aya-expanse-32b</option>
3171 <option value="c4ai-aya-expanse-8b">c4ai-aya-expanse-8b</option>
3172 <option value="c4ai-aya-23-35b">c4ai-aya-23-35b</option>
3173 <option value="c4ai-aya-23-8b">c4ai-aya-23-8b</option>3266 <option value="c4ai-aya-23-8b">c4ai-aya-23-8b</option>
3267 <option value="c4ai-aya-23">c4ai-aya-23</option>
3268 <option value="c4ai-aya-expanse-8b">c4ai-aya-expanse-8b</option>
3269 <option value="c4ai-aya-expanse-32b">c4ai-aya-expanse-32b</option>
3174 <option value="command-light">command-light</option>3270 <option value="command-light">command-light</option>
3175 <option value="command">command</option>3271 <option value="command">command</option>
3176 <option value="command-r">command-r</option>3272 <option value="command-r">command-r</option>
3177 <option value="command-r-plus">command-r-plus</option>3273 <option value="command-r-plus">command-r-plus</option>
3178 <option value="command-r-08-2024">command-r-08-2024</option>3274 <option value="command-r-08-2024">command-r-08-2024</option>
3179 <option value="command-r-plus-08-2024">command-r-plus-08-2024</option>3275 <option value="command-r-plus-08-2024">command-r-plus-08-2024</option>
3276 <option value="command-r7b-12-2024">command-r7b-12-2024</option>
3180 </optgroup>3277 </optgroup>
3181 <optgroup label="Nightly">3278 <optgroup label="Nightly">
3182 <option value="command-light-nightly">command-light-nightly</option>3279 <option value="command-light-nightly">command-light-nightly</option>
@@ -3232,8 +3329,9 @@
3232 <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4>3329 <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4>
3233 <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API.">3330 <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API.">
3234 <option data-i18n="prompt_post_processing_none" value="">None</option>3331 <option data-i18n="prompt_post_processing_none" value="">None</option>
3235 <option value="merge">Merge consecutive roles</option>3332 <option data-i18n="prompt_post_processing_merge" value="merge">Merge consecutive roles</option>
3236 <option value="strict">Strict (user first, alternating roles)</option>3333 <option data-i18n="prompt_post_processing_semi" value="semi">Semi-strict (alternating roles)</option>
3334 <option data-i18n="prompt_post_processing_strict" value="strict">Strict (user first, alternating roles)</option>
3237 </select>3335 </select>
3238 </form>3336 </form>
3239 <div id="01ai_form" data-source="01ai">3337 <div id="01ai_form" data-source="01ai">
@@ -3683,6 +3781,7 @@
3683 <option value="17">Mistral Nemo</option>3781 <option value="17">Mistral Nemo</option>
3684 <option value="8">Yi</option>3782 <option value="8">Yi</option>
3685 <option value="11">Claude 1/2</option>3783 <option value="11">Claude 1/2</option>
3784 <option value="18">DeepSeek V3</option>
3686 <option value="6">API (WebUI / koboldcpp)</option>3785 <option value="6">API (WebUI / koboldcpp)</option>
3687 </select>3786 </select>
3688 </div>3787 </div>
@@ -4649,6 +4748,13 @@
4649 Background Image4748 Background Image
4650 </h3>4749 </h3>
4651 <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" />4750 <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" />
4751 <select id="background_fitting" class="text_pole" data-i18n="[title]Background Fitting" title="Background Fitting">
4752 <option value="classic" data-i18n="Classic">Classic</option>
4753 <option value="cover" data-i18n="Cover">Cover</option>
4754 <option value="contain" data-i18n="Contain">Contain</option>
4755 <option value="stretch" data-i18n="Stretch">Stretch</option>
4756 <option value="center" data-i18n="Center">Center</option>
4757 </select>
4652 <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.">4758 <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.">
4653 <i class="fa-solid fa-wand-magic"></i>4759 <i class="fa-solid fa-wand-magic"></i>
4654 <span data-i18n="Auto-select">Auto-select</span>4760 <span data-i18n="Auto-select">Auto-select</span>
@@ -4814,6 +4920,8 @@
4814 </div>4920 </div>
4815 <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages" data-i18n="[title]Click to set user name for all messages">4921 <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages" data-i18n="[title]Click to set user name for all messages">
4816 </div>4922 </div>
4923 <div id="persona_lore_button" class="menu_button fa-solid fa-globe" title="Persona Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Persona Lore Alt+Click to open the lorebook">
4924 </div>
4817 </div>4925 </div>
4818 <div>4926 <div>
4819 <h4 data-i18n="Persona Description">Persona Description</h4>4927 <h4 data-i18n="Persona Description">Persona Description</h4>
@@ -4930,7 +5038,7 @@
4930 <input type="hidden" id="fav_checkbox" name="fav" />5038 <input type="hidden" id="fav_checkbox" name="fav" />
4931 <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div>5039 <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div>
4932 <div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore&#10;&#10;Click to load&#10;Shift-click to open 'Link to World Info' popup" data-i18n="[title]world_button_title"></div>5040 <div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore&#10;&#10;Click to load&#10;Shift-click to open 'Link to World Info' popup" data-i18n="[title]world_button_title"></div>
4933 <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore" data-i18n="[title]Chat Lore"></div>5041 <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div>
4934 <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>5042 <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>
4935 <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->5043 <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->
4936 <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->5044 <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->
@@ -5540,26 +5648,6 @@
5540 </div>5648 </div>
5541 </div>5649 </div>
5542 <!-- templates for JS to reuse when needed -->5650 <!-- templates for JS to reuse when needed -->
5543 <div id="chat_world_template" class="template_element">
5544 <div class="chat_world range-block flexFlowColumn flex-container">
5545 <div class="range-block-title">
5546 <h4 data-i18n="Chat Lorebook"><!-- This data-i18n attribute is kept for backward compatibility, use the ones below when translating -->
5547 <span data-i18n="Chat Lorebook for">Chat Lorebook for</span> <span class="chat_name"></span>
5548 </h4>
5549 </div>
5550 <div class="range-block-counter justifyLeft flex-container flexFlowColumn margin-bot-10px">
5551 <span data-i18n="chat_world_template_txt">
5552 A selected World Info will be bound to this chat. When generating an AI reply,
5553 it will be combined with the entries from global and character lorebooks.
5554 </span>
5555 </div>
5556 <div class="range-block-range wide100p">
5557 <select class="chat_world_info_selector wide100p">
5558 <option value="">--- None ---</option>
5559 </select>
5560 </div>
5561 </div>
5562 </div>
5563 <div id="character_world_template" class="template_element">5651 <div id="character_world_template" class="template_element">
5564 <div class="character_world range-block flexFlowColumn flex-container">5652 <div class="character_world range-block flexFlowColumn flex-container">
5565 <div class="range-block-title">5653 <div class="range-block-title">
@@ -5977,6 +6065,7 @@
5977 </div>6065 </div>
5978 <div id="openai_logit_bias_template" class="template_element">6066 <div id="openai_logit_bias_template" class="template_element">
5979 <div class="openai_logit_bias_form">6067 <div class="openai_logit_bias_form">
6068 <span class="drag-handle">☰</span>
5980 <input class="openai_logit_bias_text text_pole" data-i18n="[placeholder]Text or token ids" placeholder="Text or [token ids]" />6069 <input class="openai_logit_bias_text text_pole" data-i18n="[placeholder]Text or token ids" placeholder="Text or [token ids]" />
5981 <input class="openai_logit_bias_value text_pole" type="number" min="-100" value="0" max="100" />6070 <input class="openai_logit_bias_value text_pole" type="number" min="-100" value="0" max="100" />
5982 <i class="menu_button fa-solid fa-xmark openai_logit_bias_remove"></i>6071 <i class="menu_button fa-solid fa-xmark openai_logit_bias_remove"></i>
@@ -5984,6 +6073,7 @@
5984 </div>6073 </div>
5985 <div id="logit_bias_template" class="template_element">6074 <div id="logit_bias_template" class="template_element">
5986 <div class="logit_bias_form">6075 <div class="logit_bias_form">
6076 <span class="drag-handle">☰</span>
5987 <input class="logit_bias_text text_pole" data-i18n="[placeholder]Type here..." placeholder="type here..." />6077 <input class="logit_bias_text text_pole" data-i18n="[placeholder]Type here..." placeholder="type here..." />
5988 <input class="logit_bias_value text_pole" type="number" min="-100" value="0" max="100" step="0.01" />6078 <input class="logit_bias_value text_pole" type="number" min="-100" value="0" max="100" step="0.01" />
5989 <i class="menu_button fa-solid fa-xmark logit_bias_remove"></i>6079 <i class="menu_button fa-solid fa-xmark logit_bias_remove"></i>
@@ -6023,7 +6113,9 @@
6023 <label for="completion_prompt_manager_popup_entry_form_role">6113 <label for="completion_prompt_manager_popup_entry_form_role">
6024 <span data-i18n="Role">Role</span>6114 <span data-i18n="Role">Role</span>
6025 </label>6115 </label>
6026 <div class="text_muted" data-i18n="To whom this message will be attributed.">To whom this message will be attributed.</div>6116 <div class="text_muted">
6117 <span data-i18n="To whom this message will be attributed.">To whom this message will be attributed.</span>
6118 </div>
6027 <select id="completion_prompt_manager_popup_entry_form_role" class="text_pole" name="role">6119 <select id="completion_prompt_manager_popup_entry_form_role" class="text_pole" name="role">
6028 <option data-i18n="System" value="system">System</option>6120 <option data-i18n="System" value="system">System</option>
6029 <option data-i18n="User" value="user">User</option>6121 <option data-i18n="User" value="user">User</option>
public/lib.js+3 -0
@@ -19,6 +19,7 @@ import seedrandom from 'seedrandom';
19import * as Popper from '@popperjs/core';19import * as Popper from '@popperjs/core';
20import droll from 'droll';20import droll from 'droll';
21import morphdom from 'morphdom';21import morphdom from 'morphdom';
22import { toggle as slideToggle } from 'slidetoggle';
2223
23/**24/**
24 * Expose the libraries to the 'window' object.25 * Expose the libraries to the 'window' object.
@@ -94,6 +95,7 @@ export default {
94 Popper,95 Popper,
95 droll,96 droll,
96 morphdom,97 morphdom,
98 slideToggle,
97};99};
98100
99export {101export {
@@ -115,4 +117,5 @@ export {
115 Popper,117 Popper,
116 droll,118 droll,
117 morphdom,119 morphdom,
120 slideToggle,
118};121};
public/lib/eventemitter.js+4 -2
@@ -95,13 +95,14 @@ EventEmitter.prototype.removeListener = function (event, listener) {
95};95};
9696
97EventEmitter.prototype.emit = async function (event) {97EventEmitter.prototype.emit = async function (event) {
98 let args = [].slice.call(arguments, 1);
98 if (localStorage.getItem('eventTracing') === 'true') {99 if (localStorage.getItem('eventTracing') === 'true') {
99 console.trace('Event emitted: ' + event, args);100 console.trace('Event emitted: ' + event, args);
100 } else {101 } else {
101 console.debug('Event emitted: ' + event);102 console.debug('Event emitted: ' + event);
102 }103 }
103104
104 var i, listeners, length, args = [].slice.call(arguments, 1);105 let i, listeners, length;
105106
106 if (typeof this.events[event] === 'object') {107 if (typeof this.events[event] === 'object') {
107 listeners = this.events[event].slice();108 listeners = this.events[event].slice();
@@ -120,13 +121,14 @@ EventEmitter.prototype.emit = async function (event) {
120};121};
121122
122EventEmitter.prototype.emitAndWait = function (event) {123EventEmitter.prototype.emitAndWait = function (event) {
124 let args = [].slice.call(arguments, 1);
123 if (localStorage.getItem('eventTracing') === 'true') {125 if (localStorage.getItem('eventTracing') === 'true') {
124 console.trace('Event emitted: ' + event, args);126 console.trace('Event emitted: ' + event, args);
125 } else {127 } else {
126 console.debug('Event emitted: ' + event);128 console.debug('Event emitted: ' + event);
127 }129 }
128130
129 var i, listeners, length, args = [].slice.call(arguments, 1);131 let i, listeners, length;
130132
131 if (typeof this.events[event] === 'object') {133 if (typeof this.events[event] === 'object') {
132 listeners = this.events[event].slice();134 listeners = this.events[event].slice();
public/locales/ar-sa.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "اكتمال النص",267 "Text Completion": "اكتمال النص",
268 "Chat Completion": "إكمال الدردشة",268 "Chat Completion": "إكمال الدردشة",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "جماعة KoboldAI",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "تجنب إرسال معلومات حساسة إلى الجماعة.",272 "Avoid sending sensitive information to the Horde.": "تجنب إرسال معلومات حساسة إلى الجماعة.",
273 "Review the Privacy statement": "مراجعة بيان الخصوصية",273 "Review the Privacy statement": "مراجعة بيان الخصوصية",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "قم بتشغيل تطبيق DrawThings مع تمكين مفتاح HTTP API في واجهة المستخدم! يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.",1295 "sd_drawthings_auth_txt": "قم بتشغيل تطبيق DrawThings مع تمكين مفتاح HTTP API في واجهة المستخدم! يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.",
1296 "sd_vlad_url": "مثال: {{vlad_url}}",1296 "sd_vlad_url": "مثال: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "يجب أن يكون الخادم قابلاً للوصول من الجهاز المضيف SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "تلميح: احفظ مفتاح API في إعدادات Horde KoboldAI API لاستخدامه هنا.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "تلميح: احفظ مفتاح API في إعدادات AI Horde API لاستخدامه هنا.",
1299 "Allow NSFW images from Horde": "السماح بصور NSFW من Horde",1299 "Allow NSFW images from Horde": "السماح بصور NSFW من Horde",
1300 "Sanitize prompts (recommended)": "مطالبات التعقيم (مستحسن)",1300 "Sanitize prompts (recommended)": "مطالبات التعقيم (مستحسن)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "قم بضبط معلمات الإنشاء تلقائيًا لضمان إنشاء صور مجانية.",1301 "Automatically adjust generation parameters to ensure free image generations.": "قم بضبط معلمات الإنشاء تلقائيًا لضمان إنشاء صور مجانية.",
public/locales/de-de.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Textvervollständigung",267 "Text Completion": "Textvervollständigung",
268 "Chat Completion": "Chat-Abschluss",268 "Chat Completion": "Chat-Abschluss",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "KoboldAI Horde",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Vermeide das Senden sensibler Informationen an die Horde.",272 "Avoid sending sensitive information to the Horde.": "Vermeide das Senden sensibler Informationen an die Horde.",
273 "Review the Privacy statement": "Überprüfe die Datenschutzerklärung",273 "Review the Privacy statement": "Überprüfe die Datenschutzerklärung",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "Führen Sie die DrawThings-App mit aktiviertem HTTP-API-Schalter in der Benutzeroberfläche aus! Der Server muss vom SillyTavern-Hostcomputer aus zugänglich sein.",1295 "sd_drawthings_auth_txt": "Führen Sie die DrawThings-App mit aktiviertem HTTP-API-Schalter in der Benutzeroberfläche aus! Der Server muss vom SillyTavern-Hostcomputer aus zugänglich sein.",
1296 "sd_vlad_url": "Beispiel: {{vlad_url}}",1296 "sd_vlad_url": "Beispiel: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Der Server muss vom SillyTavern-Hostcomputer aus zugänglich sein.",1297 "The server must be accessible from the SillyTavern host machine.": "Der Server muss vom SillyTavern-Hostcomputer aus zugänglich sein.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Tipp: Speichern Sie einen API-Schlüssel in den Horde KoboldAI API-Einstellungen, um ihn hier zu verwenden.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Tipp: Speichern Sie einen API-Schlüssel in den AI Horde API-Einstellungen, um ihn hier zu verwenden.",
1299 "Allow NSFW images from Horde": "NSFW-Bilder von Horde zulassen",1299 "Allow NSFW images from Horde": "NSFW-Bilder von Horde zulassen",
1300 "Sanitize prompts (recommended)": "Eingabeaufforderungen bereinigen (empfohlen)",1300 "Sanitize prompts (recommended)": "Eingabeaufforderungen bereinigen (empfohlen)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Passen Sie die Generierungsparameter automatisch an, um eine freie Bildgenerierung zu gewährleisten.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Passen Sie die Generierungsparameter automatisch an, um eine freie Bildgenerierung zu gewährleisten.",
public/locales/es-es.json+4 -4
@@ -267,7 +267,7 @@
267 "Text Completion": "Completar texto",267 "Text Completion": "Completar texto",
268 "Chat Completion": "Finalización del chat",268 "Chat Completion": "Finalización del chat",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "Horde de KoboldAI",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Evite enviar información sensible a Horde.",272 "Avoid sending sensitive information to the Horde.": "Evite enviar información sensible a Horde.",
273 "Review the Privacy statement": "Revise la declaración de privacidad",273 "Review the Privacy statement": "Revise la declaración de privacidad",
@@ -874,7 +874,7 @@
874 "Bulk_edit_characters": "Editar personajes masivamente",874 "Bulk_edit_characters": "Editar personajes masivamente",
875 "Bulk select all characters": "Seleccionar de forma masiva todos los personajes",875 "Bulk select all characters": "Seleccionar de forma masiva todos los personajes",
876 "Bulk delete characters": "Eliminar personajes masivamente",876 "Bulk delete characters": "Eliminar personajes masivamente",
877 "popup-button-save": "Ahorrar",877 "popup-button-save": "Guardar",
878 "popup-button-yes": "Sí",878 "popup-button-yes": "Sí",
879 "popup-button-no": "No",879 "popup-button-no": "No",
880 "popup-button-cancel": "Cancelar",880 "popup-button-cancel": "Cancelar",
@@ -1019,7 +1019,7 @@
1019 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Este mensaje no puede ser anulado por tarjetas de personaje, incluso si se prefieren las anulaciones.",1019 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Este mensaje no puede ser anulado por tarjetas de personaje, incluso si se prefieren las anulaciones.",
1020 "prompt_manager_forbid_overrides": "Prohibir anulaciones",1020 "prompt_manager_forbid_overrides": "Prohibir anulaciones",
1021 "reset": "reiniciar",1021 "reset": "reiniciar",
1022 "save": "ahorrar",1022 "save": "guardar",
1023 "This message is invisible for the AI": "Este mensaje es invisible para la IA",1023 "This message is invisible for the AI": "Este mensaje es invisible para la IA",
1024 "Message Actions": "Acciones de mensajes",1024 "Message Actions": "Acciones de mensajes",
1025 "Translate message": "Traducir mensaje",1025 "Translate message": "Traducir mensaje",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "¡Ejecute la aplicación DrawThings con el interruptor API HTTP habilitado en la interfaz de usuario! Se debe poder acceder al servidor desde la máquina host de SillyTavern.",1295 "sd_drawthings_auth_txt": "¡Ejecute la aplicación DrawThings con el interruptor API HTTP habilitado en la interfaz de usuario! Se debe poder acceder al servidor desde la máquina host de SillyTavern.",
1296 "sd_vlad_url": "Ejemplo: {{vlad_url}}",1296 "sd_vlad_url": "Ejemplo: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Se debe poder acceder al servidor desde la máquina host de SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "Se debe poder acceder al servidor desde la máquina host de SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Sugerencia: guarde una clave API en la configuración de API de Horde KoboldAI para usarla aquí.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Sugerencia: guarde una clave API en la configuración de API de AI Horde para usarla aquí.",
1299 "Allow NSFW images from Horde": "Permitir imágenes NSFW de Horda",1299 "Allow NSFW images from Horde": "Permitir imágenes NSFW de Horda",
1300 "Sanitize prompts (recommended)": "Indicaciones para desinfectar (recomendado)",1300 "Sanitize prompts (recommended)": "Indicaciones para desinfectar (recomendado)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Ajuste automáticamente los parámetros de generación para garantizar generaciones de imágenes gratuitas.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Ajuste automáticamente los parámetros de generación para garantizar generaciones de imágenes gratuitas.",
public/locales/fr-fr.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Achèvement du texte",267 "Text Completion": "Achèvement du texte",
268 "Chat Completion": "Achèvement du chat",268 "Chat Completion": "Achèvement du chat",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "Horde KoboldAI",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Évitez d'envoyer des informations sensibles à la Horde.",272 "Avoid sending sensitive information to the Horde.": "Évitez d'envoyer des informations sensibles à la Horde.",
273 "Review the Privacy statement": "Examiner la déclaration de confidentialité",273 "Review the Privacy statement": "Examiner la déclaration de confidentialité",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "exécutez l'application DrawThings avec le commutateur API HTTP activé dans l'interface utilisateur ! Le serveur doit être accessible depuis la machine hôte de SillyTavern.",1295 "sd_drawthings_auth_txt": "exécutez l'application DrawThings avec le commutateur API HTTP activé dans l'interface utilisateur ! Le serveur doit être accessible depuis la machine hôte de SillyTavern.",
1296 "sd_vlad_url": "Exemple : {{vlad_url}}",1296 "sd_vlad_url": "Exemple : {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Le serveur doit être accessible depuis la machine hôte de SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "Le serveur doit être accessible depuis la machine hôte de SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Astuce : enregistrez une clé API dans les paramètres de l'API Horde KoboldAI pour l'utiliser ici.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Astuce : enregistrez une clé API dans les paramètres de l'API AI Horde pour l'utiliser ici.",
1299 "Allow NSFW images from Horde": "Autoriser les images NSFW de la Horde",1299 "Allow NSFW images from Horde": "Autoriser les images NSFW de la Horde",
1300 "Sanitize prompts (recommended)": "Désinfecter les invites (recommandé)",1300 "Sanitize prompts (recommended)": "Désinfecter les invites (recommandé)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Ajustez automatiquement les paramètres de génération pour garantir des générations d’images gratuites.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Ajustez automatiquement les paramètres de génération pour garantir des générations d’images gratuites.",
public/locales/is-is.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Textaútfylling",267 "Text Completion": "Textaútfylling",
268 "Chat Completion": "Spjalllokun",268 "Chat Completion": "Spjalllokun",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "KoboldAI Hópur",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Forðastu að senda viðkvæm gögn til Hórdans.",272 "Avoid sending sensitive information to the Horde.": "Forðastu að senda viðkvæm gögn til Hórdans.",
273 "Review the Privacy statement": "Farið yfir Persónuverndarskýrsluna",273 "Review the Privacy statement": "Farið yfir Persónuverndarskýrsluna",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "keyrðu DrawThings app með HTTP API rofi virkt í notendaviðmótinu! Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.",1295 "sd_drawthings_auth_txt": "keyrðu DrawThings app með HTTP API rofi virkt í notendaviðmótinu! Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.",
1296 "sd_vlad_url": "Dæmi: {{vlad_url}}",1296 "sd_vlad_url": "Dæmi: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.",1297 "The server must be accessible from the SillyTavern host machine.": "Miðlarinn verður að vera aðgengilegur frá SillyTavern hýsingarvélinni.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Ábending: Vistaðu API lykil í Horde KoboldAI API stillingum til að nota hann hér.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Ábending: Vistaðu API lykil í AI Horde API stillingum til að nota hann hér.",
1299 "Allow NSFW images from Horde": "Leyfa NSFW myndir frá Horde",1299 "Allow NSFW images from Horde": "Leyfa NSFW myndir frá Horde",
1300 "Sanitize prompts (recommended)": "Hreinsunarleiðbeiningar (ráðlagt)",1300 "Sanitize prompts (recommended)": "Hreinsunarleiðbeiningar (ráðlagt)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Stilltu kynslóðarbreytur sjálfkrafa til að tryggja ókeypis myndmyndun.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Stilltu kynslóðarbreytur sjálfkrafa til að tryggja ókeypis myndmyndun.",
public/locales/it-it.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Completamento del testo",267 "Text Completion": "Completamento del testo",
268 "Chat Completion": "Completamento della chat",268 "Chat Completion": "Completamento della chat",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "Orda di KoboldAI",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Evita di inviare informazioni sensibili all'Orda.",272 "Avoid sending sensitive information to the Horde.": "Evita di inviare informazioni sensibili all'Orda.",
273 "Review the Privacy statement": "Revisione della dichiarazione sulla privacy",273 "Review the Privacy statement": "Revisione della dichiarazione sulla privacy",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "esegui l'app DrawThings con lo switch API HTTP abilitato nell'interfaccia utente! Il server deve essere accessibile dalla macchina host SillyTavern.",1295 "sd_drawthings_auth_txt": "esegui l'app DrawThings con lo switch API HTTP abilitato nell'interfaccia utente! Il server deve essere accessibile dalla macchina host SillyTavern.",
1296 "sd_vlad_url": "Esempio: {{vlad_url}}",1296 "sd_vlad_url": "Esempio: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Il server deve essere accessibile dalla macchina host SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "Il server deve essere accessibile dalla macchina host SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Suggerimento: salva una chiave API nelle impostazioni API Horde KoboldAI per usarla qui.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Suggerimento: salva una chiave API nelle impostazioni API AI Horde per usarla qui.",
1299 "Allow NSFW images from Horde": "Consenti immagini NSFW da Horde",1299 "Allow NSFW images from Horde": "Consenti immagini NSFW da Horde",
1300 "Sanitize prompts (recommended)": "Messaggi di disinfezione (consigliato)",1300 "Sanitize prompts (recommended)": "Messaggi di disinfezione (consigliato)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Regola automaticamente i parametri di generazione per garantire generazioni di immagini gratuite.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Regola automaticamente i parametri di generazione per garantire generazioni di immagini gratuite.",
public/locales/ja-jp.json+8 -3
@@ -267,7 +267,7 @@
267 "Text Completion": "テキスト補完",267 "Text Completion": "テキスト補完",
268 "Chat Completion": "チャット完了",268 "Chat Completion": "チャット完了",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "KoboldAI Horde",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Hordeに機密情報を送信しないでください。",272 "Avoid sending sensitive information to the Horde.": "Hordeに機密情報を送信しないでください。",
273 "Review the Privacy statement": "プライバシー声明を確認する",273 "Review the Privacy statement": "プライバシー声明を確認する",
@@ -1274,6 +1274,8 @@
1274 "sd_Raw_Last_Message": "生の最後のメッセージ",1274 "sd_Raw_Last_Message": "生の最後のメッセージ",
1275 "sd_Background": "背景",1275 "sd_Background": "背景",
1276 "Image Generation": "画像生成",1276 "Image Generation": "画像生成",
1277 "Stop Image Generation": "画像生成を停止",
1278 "Generate Caption": "画像説明を生成",
1277 "sd_refine_mode": "プロンプトを生成 API に送信する前に手動で編集できるようにする",1279 "sd_refine_mode": "プロンプトを生成 API に送信する前に手動で編集できるようにする",
1278 "sd_refine_mode_txt": "生成前にプロンプ​​トを編集する",1280 "sd_refine_mode_txt": "生成前にプロンプ​​トを編集する",
1279 "sd_interactive_mode": "「猫の写真を送ってください」のようなメッセージを送信するときに、画像を自動的に生成します。",1281 "sd_interactive_mode": "「猫の写真を送ってください」のようなメッセージを送信するときに、画像を自動的に生成します。",
@@ -1295,7 +1297,7 @@
1295 "sd_drawthings_auth_txt": "UI で HTTP API スイッチを有効にして DrawThings アプリを実行します。サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。",1297 "sd_drawthings_auth_txt": "UI で HTTP API スイッチを有効にして DrawThings アプリを実行します。サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。",
1296 "sd_vlad_url": "例: {{vlad_url}}",1298 "sd_vlad_url": "例: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。",1299 "The server must be accessible from the SillyTavern host machine.": "サーバーは SillyTavern ホスト マシンからアクセスできる必要があります。",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "ヒント: ここで使用するには、Horde KoboldAI API 設定に API キーを保存してください。",1300 "Hint: Save an API key in AI Horde API settings to use it here.": "ヒント: ここで使用するには、AI Horde API 設定に API キーを保存してください。",
1299 "Allow NSFW images from Horde": "HordeからのNSFW画像を許可する",1301 "Allow NSFW images from Horde": "HordeからのNSFW画像を許可する",
1300 "Sanitize prompts (recommended)": "サニタイズプロンプト(推奨)",1302 "Sanitize prompts (recommended)": "サニタイズプロンプト(推奨)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "生成パラメータを自動的に調整して、自由な画像生成を保証します。",1303 "Automatically adjust generation parameters to ensure free image generations.": "生成パラメータを自動的に調整して、自由な画像生成を保証します。",
@@ -1439,5 +1441,8 @@
1439 "Still have questions?": "まだ質問がありますか?",1441 "Still have questions?": "まだ質問がありますか?",
1440 "Join the SillyTavern Discord": "SillyTavernのDiscordに参加",1442 "Join the SillyTavern Discord": "SillyTavernのDiscordに参加",
1441 "Post a GitHub issue": "GitHubの問題を投稿",1443 "Post a GitHub issue": "GitHubの問題を投稿",
1442 "Contact the developers": "開発者に連絡"1444 "Contact the developers": "開発者に連絡",
1445 "Stop Inspecting": "検査を停止",
1446 "Inspect Prompts": "プロンプトを検査",
1447 "Toggle prompt inspection": "プロンプト検査の切り替え"
1443}1448}
public/locales/ko-kr.json+3 -3
@@ -269,7 +269,7 @@
269 "Text Completion": "Text Completion",269 "Text Completion": "Text Completion",
270 "Chat Completion": "Chat Completion",270 "Chat Completion": "Chat Completion",
271 "NovelAI": "NovelAI",271 "NovelAI": "NovelAI",
272 "KoboldAI Horde": "KoboldAI Horde",272 "AI Horde": "AI Horde",
273 "KoboldAI": "KoboldAI",273 "KoboldAI": "KoboldAI",
274 "Avoid sending sensitive information to the Horde.": "민감한 정보를 Horde에 보내지 않도록 합니다.",274 "Avoid sending sensitive information to the Horde.": "민감한 정보를 Horde에 보내지 않도록 합니다.",
275 "Review the Privacy statement": "개인 정보 보호 정책 검토",275 "Review the Privacy statement": "개인 정보 보호 정책 검토",
@@ -1312,7 +1312,7 @@
1312 "sd_drawthings_auth_txt": "UI에서 HTTP API 스위치가 활성화된 상태에서 DrawThings 앱을 실행하세요! SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.",1312 "sd_drawthings_auth_txt": "UI에서 HTTP API 스위치가 활성화된 상태에서 DrawThings 앱을 실행하세요! SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.",
1313 "sd_vlad_url": "예: {{vlad_url}}",1313 "sd_vlad_url": "예: {{vlad_url}}",
1314 "The server must be accessible from the SillyTavern host machine.": "SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.",1314 "The server must be accessible from the SillyTavern host machine.": "SillyTavern 호스트 시스템에서 서버에 액세스할 수 있어야 합니다.",
1315 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "힌트: 여기에서 사용하려면 Horde KoboldAI API 설정에 API 키를 저장하세요.",1315 "Hint: Save an API key in AI Horde API settings to use it here.": "힌트: 여기에서 사용하려면 AI Horde API 설정에 API 키를 저장하세요.",
1316 "Allow NSFW images from Horde": "Horde의 NSFW 이미지 허용",1316 "Allow NSFW images from Horde": "Horde의 NSFW 이미지 허용",
1317 "Sanitize prompts (recommended)": "프롬프트 삭제(권장)",1317 "Sanitize prompts (recommended)": "프롬프트 삭제(권장)",
1318 "Automatically adjust generation parameters to ensure free image generations.": "무료 이미지 생성을 보장하기 위해 생성 매개변수를 자동으로 조정합니다.",1318 "Automatically adjust generation parameters to ensure free image generations.": "무료 이미지 생성을 보장하기 위해 생성 매개변수를 자동으로 조정합니다.",
@@ -1623,4 +1623,4 @@
1623 "Master Import": "마스터 불러오기",1623 "Master Import": "마스터 불러오기",
1624 "Master Export": "마스터 내보내기",1624 "Master Export": "마스터 내보내기",
1625 "Chat Quick Reply Sets": "채팅 빠른 답장 세트들"1625 "Chat Quick Reply Sets": "채팅 빠른 답장 세트들"
1626}
1626 \ No newline at end of file \ No newline at end of file
1626}
public/locales/nl-nl.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Tekstvoltooiing",267 "Text Completion": "Tekstvoltooiing",
268 "Chat Completion": "Chat-voltooiing",268 "Chat Completion": "Chat-voltooiing",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "KoboldAI Horde",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Vermijd het verzenden van gevoelige informatie naar de Horde.",272 "Avoid sending sensitive information to the Horde.": "Vermijd het verzenden van gevoelige informatie naar de Horde.",
273 "Review the Privacy statement": "Bekijk de privacyverklaring",273 "Review the Privacy statement": "Bekijk de privacyverklaring",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "voer de DrawThings-app uit met HTTP API-switch ingeschakeld in de gebruikersinterface! De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.",1295 "sd_drawthings_auth_txt": "voer de DrawThings-app uit met HTTP API-switch ingeschakeld in de gebruikersinterface! De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.",
1296 "sd_vlad_url": "Voorbeeld: {{vlad_url}}",1296 "sd_vlad_url": "Voorbeeld: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.",1297 "The server must be accessible from the SillyTavern host machine.": "De server moet toegankelijk zijn vanaf de SillyTavern-hostmachine.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Tip: sla een API-sleutel op in de Horde KoboldAI API-instellingen om deze hier te gebruiken.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Tip: sla een API-sleutel op in de AI Horde API-instellingen om deze hier te gebruiken.",
1299 "Allow NSFW images from Horde": "Sta NSFW-afbeeldingen van Horde toe",1299 "Allow NSFW images from Horde": "Sta NSFW-afbeeldingen van Horde toe",
1300 "Sanitize prompts (recommended)": "Ontsmettingsmeldingen (aanbevolen)",1300 "Sanitize prompts (recommended)": "Ontsmettingsmeldingen (aanbevolen)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Pas de generatieparameters automatisch aan om vrije beeldgeneraties te garanderen.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Pas de generatieparameters automatisch aan om vrije beeldgeneraties te garanderen.",
public/locales/pt-pt.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Conclusão de texto",267 "Text Completion": "Conclusão de texto",
268 "Chat Completion": "Conclusão do bate-papo",268 "Chat Completion": "Conclusão do bate-papo",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "Horda KoboldAI",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Evite enviar informações sensíveis para a Horda.",272 "Avoid sending sensitive information to the Horde.": "Evite enviar informações sensíveis para a Horda.",
273 "Review the Privacy statement": "Reveja a declaração de privacidade",273 "Review the Privacy statement": "Reveja a declaração de privacidade",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "execute o aplicativo DrawThings com a opção HTTP API habilitada na IU! O servidor deve estar acessível a partir da máquina host SillyTavern.",1295 "sd_drawthings_auth_txt": "execute o aplicativo DrawThings com a opção HTTP API habilitada na IU! O servidor deve estar acessível a partir da máquina host SillyTavern.",
1296 "sd_vlad_url": "Exemplo: {{vlad_url}}",1296 "sd_vlad_url": "Exemplo: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "O servidor deve estar acessível a partir da máquina host SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "O servidor deve estar acessível a partir da máquina host SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Dica: salve uma chave de API nas configurações da API Horde KoboldAI para usá-la aqui.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Dica: salve uma chave de API nas configurações da API AI Horde para usá-la aqui.",
1299 "Allow NSFW images from Horde": "Permitir imagens NSFW da Horda",1299 "Allow NSFW images from Horde": "Permitir imagens NSFW da Horda",
1300 "Sanitize prompts (recommended)": "Solicitações de higienização (recomendado)",1300 "Sanitize prompts (recommended)": "Solicitações de higienização (recomendado)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Ajuste automaticamente os parâmetros de geração para garantir gerações de imagens livres.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Ajuste automaticamente os parâmetros de geração para garantir gerações de imagens livres.",
public/locales/ru-ru.json+2 -2
@@ -299,7 +299,7 @@
299 "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api",299 "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api",
300 "No connection...": "Нет соединения...",300 "No connection...": "Нет соединения...",
301 "Get your NovelAI API Key": "Получите свой API-ключ для NovelAI",301 "Get your NovelAI API Key": "Получите свой API-ключ для NovelAI",
302 "KoboldAI Horde": "KoboldAI Horde",302 "AI Horde": "AI Horde",
303 "NovelAI": "NovelAI",303 "NovelAI": "NovelAI",
304 "OpenAI API key": "Ключ для API OpenAI",304 "OpenAI API key": "Ключ для API OpenAI",
305 "Trim spaces": "Обрезать пробелы",305 "Trim spaces": "Обрезать пробелы",
@@ -1461,7 +1461,7 @@
1461 "sd_drawthings_auth_txt": "run DrawThings app with HTTP API switch enabled in the UI! The server must be accessible from the SillyTavern host machine.",1461 "sd_drawthings_auth_txt": "run DrawThings app with HTTP API switch enabled in the UI! The server must be accessible from the SillyTavern host machine.",
1462 "sd_vlad_url": "Example: {{vlad_url}}",1462 "sd_vlad_url": "Example: {{vlad_url}}",
1463 "The server must be accessible from the SillyTavern host machine.": "The server must be accessible from the SillyTavern host machine.",1463 "The server must be accessible from the SillyTavern host machine.": "The server must be accessible from the SillyTavern host machine.",
1464 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Hint: Save an API key in Horde KoboldAI API settings to use it here.",1464 "Hint: Save an API key in AI Horde API settings to use it here.": "Hint: Save an API key in AI Horde API settings to use it here.",
1465 "Allow NSFW images from Horde": "Разрешить NSFW-картинки в Horde",1465 "Allow NSFW images from Horde": "Разрешить NSFW-картинки в Horde",
1466 "Sanitize prompts (recommended)": "Sanitize prompts (recommended)",1466 "Sanitize prompts (recommended)": "Sanitize prompts (recommended)",
1467 "Automatically adjust generation parameters to ensure free image generations.": "Automatically adjust generation parameters to ensure free image generations.",1467 "Automatically adjust generation parameters to ensure free image generations.": "Automatically adjust generation parameters to ensure free image generations.",
public/locales/uk-ua.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Завершення тексту",267 "Text Completion": "Завершення тексту",
268 "Chat Completion": "Завершення чату",268 "Chat Completion": "Завершення чату",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "KoboldAI Horde",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Уникайте надсилання чутливої інформації в Horde.",272 "Avoid sending sensitive information to the Horde.": "Уникайте надсилання чутливої інформації в Horde.",
273 "Review the Privacy statement": "Перегляньте заяву про конфіденційність",273 "Review the Privacy statement": "Перегляньте заяву про конфіденційність",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "запустіть програму DrawThings із увімкненим перемикачем HTTP API в інтерфейсі користувача! Сервер має бути доступним із хост-машини SillyTavern.",1295 "sd_drawthings_auth_txt": "запустіть програму DrawThings із увімкненим перемикачем HTTP API в інтерфейсі користувача! Сервер має бути доступним із хост-машини SillyTavern.",
1296 "sd_vlad_url": "Приклад: {{vlad_url}}",1296 "sd_vlad_url": "Приклад: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Сервер має бути доступним із хост-машини SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "Сервер має бути доступним із хост-машини SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Підказка: збережіть ключ API в налаштуваннях Horde KoboldAI API, щоб використовувати його тут.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Підказка: збережіть ключ API в налаштуваннях AI Horde API, щоб використовувати його тут.",
1299 "Allow NSFW images from Horde": "Дозволити зображення NSFW від Horde",1299 "Allow NSFW images from Horde": "Дозволити зображення NSFW від Horde",
1300 "Sanitize prompts (recommended)": "Очистити підказки (рекомендовано)",1300 "Sanitize prompts (recommended)": "Очистити підказки (рекомендовано)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Автоматично налаштовуйте параметри генерації, щоб забезпечити вільне створення зображень.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Автоматично налаштовуйте параметри генерації, щоб забезпечити вільне створення зображень.",
public/locales/vi-vn.json+2 -2
@@ -267,7 +267,7 @@
267 "Text Completion": "Text Completion",267 "Text Completion": "Text Completion",
268 "Chat Completion": "Chat Completion",268 "Chat Completion": "Chat Completion",
269 "NovelAI": "NovelAI",269 "NovelAI": "NovelAI",
270 "KoboldAI Horde": "KoboldAI Horde",270 "AI Horde": "AI Horde",
271 "KoboldAI": "KoboldAI",271 "KoboldAI": "KoboldAI",
272 "Avoid sending sensitive information to the Horde.": "Tránh gửi thông tin nhạy cảm cho Horde.",272 "Avoid sending sensitive information to the Horde.": "Tránh gửi thông tin nhạy cảm cho Horde.",
273 "Review the Privacy statement": "Xem lại Chính sách bảo mật",273 "Review the Privacy statement": "Xem lại Chính sách bảo mật",
@@ -1295,7 +1295,7 @@
1295 "sd_drawthings_auth_txt": "chạy ứng dụng DrawThings với tính năng chuyển đổi API HTTP được bật trong giao diện người dùng! Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.",1295 "sd_drawthings_auth_txt": "chạy ứng dụng DrawThings với tính năng chuyển đổi API HTTP được bật trong giao diện người dùng! Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.",
1296 "sd_vlad_url": "Ví dụ: {{vlad_url}}",1296 "sd_vlad_url": "Ví dụ: {{vlad_url}}",
1297 "The server must be accessible from the SillyTavern host machine.": "Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.",1297 "The server must be accessible from the SillyTavern host machine.": "Máy chủ phải có thể truy cập được từ máy chủ SillyTavern.",
1298 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "Gợi ý: Lưu khóa API trong cài đặt API Horde KoboldAI để sử dụng tại đây.",1298 "Hint: Save an API key in AI Horde API settings to use it here.": "Gợi ý: Lưu khóa API trong cài đặt API AI Horde để sử dụng tại đây.",
1299 "Allow NSFW images from Horde": "Cho phép hình ảnh NSFW từ Horde",1299 "Allow NSFW images from Horde": "Cho phép hình ảnh NSFW từ Horde",
1300 "Sanitize prompts (recommended)": "Nhắc nhở vệ sinh (khuyến nghị)",1300 "Sanitize prompts (recommended)": "Nhắc nhở vệ sinh (khuyến nghị)",
1301 "Automatically adjust generation parameters to ensure free image generations.": "Tự động điều chỉnh các thông số tạo để đảm bảo tạo ra hình ảnh miễn phí.",1301 "Automatically adjust generation parameters to ensure free image generations.": "Tự động điều chỉnh các thông số tạo để đảm bảo tạo ra hình ảnh miễn phí.",
public/locales/zh-cn.json+409 -264
@@ -10,39 +10,49 @@
10 "MAD LAB MODE ON": "疯狂实验室模式开启",10 "MAD LAB MODE ON": "疯狂实验室模式开启",
11 "Documentation on sampling parameters": "有关采样参数的文档",11 "Documentation on sampling parameters": "有关采样参数的文档",
12 "kobldpresets": "Kobold 预设",12 "kobldpresets": "Kobold 预设",
13 "Import preset": "导入预设",
14 "Export preset": "导出预设",
15 "Delete the preset": "删除预设",
13 "guikoboldaisettings": "KoboldAI 用户界面设置",16 "guikoboldaisettings": "KoboldAI 用户界面设置",
14 "Update current preset": "更新当前预设",17 "Update current preset": "更新当前预设",
18 "Rename current preset": "重命名当前预设",
15 "Save preset as": "另存预设为",19 "Save preset as": "另存预设为",
16 "Import preset": "导入预设",
17 "Export preset": "导出预设",
18 "Restore current preset": "恢复当前预设",20 "Restore current preset": "恢复当前预设",
19 "Delete the preset": "删除预设",
20 "novelaipresets": "NovelAI 预设",21 "novelaipresets": "NovelAI 预设",
21 "Default": "默认",22 "Default": "默认",
22 "openaipresets": "对话补全预设",23 "openaipresets": "对话补全预设",
23 "Text Completion presets": "文本补全预设",24 "Text Completion presets": "文本补全预设",
24 "AI Module": "AI 模块",
25 "Changes the style of the generated text.": "更改生成文本的样式。",
26 "No Module": "无模块",
27 "Instruct": "指导",
28 "Prose Augmenter": "散文增强器",
29 "Text Adventure": "文字冒险",
30 "response legth(tokens)": "回复长度(以词符数计)",25 "response legth(tokens)": "回复长度(以词符数计)",
31 "Streaming": "流式传输",26 "Streaming": "流式传输",
32 "Streaming_desc": "逐位显示生成的回复",27 "Streaming_desc": "逐位显示生成的回复",
33 "context size(tokens)": "上下文长度(以词符数计)",28 "context size(tokens)": "上下文长度(以词符数计)",
34 "unlocked": "解锁",29 "unlocked": "解锁",
35 "Only enable this if your model supports context sizes greater than 8192 tokens": "仅在您的模型支持大于8192个词符的上下文大小时启用此选项",30 "Only enable this if your model supports context sizes greater than 8192 tokens": "仅在您的模型支持大于8192个词符的上下文长度时启用此选项",
36 "Max prompt cost:": "最大提示词费用:",31 "Max prompt cost:": "最大提示词费用:",
37 "Display the response bit by bit as it is generated.": "随着回复的生成,逐位显示结果。",32 "AI Module": "AI 模块",
38 "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。",33 "Changes the style of the generated text.": "更改生成文本的样式。",
34 "No Module": "无模块",
35 "Instruct": "指导",
36 "Prose Augmenter": "散文增强器",
37 "Text Adventure": "文字冒险",
39 "Temperature": "温度",38 "Temperature": "温度",
40 "rep.pen": "重复惩罚",39 "rep.pen": "重复惩罚",
41 "Rep. Pen. Range.": "重复惩罚范围。",40 "Rep. Pen. Range.": "重复惩罚范围。",
42 "Rep. Pen. Slope": "重复惩罚斜率",41 "Rep. Pen. Slope": "重复惩罚斜率",
43 "Rep. Pen. Freq.": "频率重复惩罚",42 "Rep. Pen. Freq.": "频率重复惩罚",
44 "Rep. Pen. Presence": "存在重复惩罚",43 "Rep. Pen. Presence": "存在重复惩罚",
44 "Min P": "Min P",
45 "TFS": "无尾采样",45 "TFS": "无尾采样",
46 "Top P": "Top P",
47 "Top A": "Top A",
48 "Top K": "Top K",
49 "Mirostat Tau": "Mirostat τ",
50 "Mirostat LR": "Mirostat 学习率",
51 "Typical P": "典型P",
52 "Linear": "Linear",
53 "Quad": "Quad",
54 "Conf": "Conf",
55 "Min Length": "最小长度",
46 "Phrase Repetition Penalty": "短语重复惩罚",56 "Phrase Repetition Penalty": "短语重复惩罚",
47 "Off": "关闭",57 "Off": "关闭",
48 "Very light": "非常轻",58 "Very light": "非常轻",
@@ -50,27 +60,35 @@
50 "Medium": "中",60 "Medium": "中",
51 "Aggressive": "激进",61 "Aggressive": "激进",
52 "Very aggressive": "非常激进",62 "Very aggressive": "非常激进",
63 "Preamble": "序文",
64 "Restore default prompt": "恢复默认提示词",
65 "Use style tags to modify the writing style of the output.": "使用样式标签修改输出的写作风格。",
66 "Banned Tokens": "禁用的词符",
67 "Sequences you don't want to appear in the output. One per line.": "您不希望出现在输出中的字符串。 每行一个。",
68 "Logit Bias": "Logit 偏置",
69 "Add": "添加",
70 "Helps to ban or reenforce the usage of certain words": "有助于禁止或加强某些单词的使用",
53 "Unlocked Context Size": "解锁上下文长度",71 "Unlocked Context Size": "解锁上下文长度",
54 "Unrestricted maximum value for the context slider": "AI可见的最大上下文长度",72 "Unrestricted maximum value for the context slider": "AI可见的最大上下文长度",
55 "Context Size (tokens)": "上下文长度(以词符数计)",73 "Context Size (tokens)": "上下文长度(以词符数计)",
56 "Max Response Length (tokens)": "最大回复长度(以词符数计)",74 "Max Response Length (tokens)": "最大回复长度(以词符数计)",
57 "Multiple swipes per generation": "每次生成多个备选回复",75 "Multiple swipes per generation": "每次生成多个备选回复",
76 "Middle-out Transform": "Middle-out Transform",
77 "Auto": "Auto",
78 "Allow": "Allow",
79 "Forbid": "Forbid",
58 "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输",80 "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输",
81 "Display the response bit by bit as it is generated.": "随着回复的生成,逐位显示结果。",
82 "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。",
59 "Frequency Penalty": "频率惩罚",83 "Frequency Penalty": "频率惩罚",
60 "Presence Penalty": "存在惩罚",84 "Presence Penalty": "存在惩罚",
61 "Count Penalty": "计数惩罚",
62 "Top K": "Top K",
63 "Top P": "Top P",
64 "Repetition Penalty": "重复惩罚",85 "Repetition Penalty": "重复惩罚",
65 "Min P": "Min P",
66 "Top A": "Top A",
67 "Quick Prompts Edit": "快速提示词编辑",86 "Quick Prompts Edit": "快速提示词编辑",
68 "Main": "主要",87 "Main": "主要",
69 "Auxiliary": "辅助的",88 "Auxiliary": "辅助的",
70 "Post-History Instructions": "后续历史指令",89 "Post-History Instructions": "后续历史指令",
71 "Utility Prompts": "实用提示词",90 "Utility Prompts": "实用提示词",
72 "Impersonation prompt": "AI帮答提示词",91 "Impersonation prompt": "AI帮答提示词",
73 "Restore default prompt": "恢复默认提示词",
74 "Prompt that is used for Impersonation function": "用于AI帮答功能的提示词",92 "Prompt that is used for Impersonation function": "用于AI帮答功能的提示词",
75 "World Info Format Template": "世界信息格式模板",93 "World Info Format Template": "世界信息格式模板",
76 "Restore default format": "恢复默认格式",94 "Restore default format": "恢复默认格式",
@@ -79,7 +97,7 @@
79 "scenario_format_template_part_2": "标记插入内容的位置。",97 "scenario_format_template_part_2": "标记插入内容的位置。",
80 "Scenario Format Template": "场景格式模板",98 "Scenario Format Template": "场景格式模板",
81 "Personality Format Template": "角色设定格式模板",99 "Personality Format Template": "角色设定格式模板",
82 "Group Nudge Prompt Template": "群组推进提示词模板",100 "Group Nudge Prompt Template": "群聊推进提示词模板",
83 "Sent at the end of the group chat history to force reply from a specific character.": "在群聊记录的末尾发送,以强制特定角色回复。",101 "Sent at the end of the group chat history to force reply from a specific character.": "在群聊记录的末尾发送,以强制特定角色回复。",
84 "New Chat": "新聊天",102 "New Chat": "新聊天",
85 "Restore new chat prompt": "恢复新的聊天提示词",103 "Restore new chat prompt": "恢复新的聊天提示词",
@@ -98,7 +116,6 @@
98 "Temperature controls the randomness in token selection": "温度控制词符选择中的随机性:\n- 低温(<1.0)导致更可预测的文本,优先选择高概率的词符。\n- 高温(>1.0)鼓励创造性和输出的多样性,更多地选择低概率的词符。\n将值设置为 1.0 以使用原始概率。",116 "Temperature controls the randomness in token selection": "温度控制词符选择中的随机性:\n- 低温(<1.0)导致更可预测的文本,优先选择高概率的词符。\n- 高温(>1.0)鼓励创造性和输出的多样性,更多地选择低概率的词符。\n将值设置为 1.0 以使用原始概率。",
99 "Top_K_desc": "Top K 设定了可以选择的最高概率词符的最大数量。",117 "Top_K_desc": "Top K 设定了可以选择的最高概率词符的最大数量。",
100 "Top_P_desc": "Top P(又称核采样)将所有高概率词符聚集在一起,直到达到特定的百分比。\n换句话说,如果前两个词符分别都有 25% 的概率,而 Top-P 为 0.50,那么只有这两个词符会被考虑。\n将这个值设置为 1.0 就相当于关闭了这个功能。",118 "Top_P_desc": "Top P(又称核采样)将所有高概率词符聚集在一起,直到达到特定的百分比。\n换句话说,如果前两个词符分别都有 25% 的概率,而 Top-P 为 0.50,那么只有这两个词符会被考虑。\n将这个值设置为 1.0 就相当于关闭了这个功能。",
101 "Typical P": "典型P",
102 "Typical_P_desc": "典型P采样会根据词符与整体熵的平均差异来优先选择词符。\n那些累积概率接近特定阈值(比如 0.5)的词符会被保留,这样就能区分出那些含有平均信息量的词符。\n将这个值设置为 1.0 就相当于关闭了这个功能。",119 "Typical_P_desc": "典型P采样会根据词符与整体熵的平均差异来优先选择词符。\n那些累积概率接近特定阈值(比如 0.5)的词符会被保留,这样就能区分出那些含有平均信息量的词符。\n将这个值设置为 1.0 就相当于关闭了这个功能。",
103 "Min_P_desc": "Min P 设定了一个基础的最小概率,它会根据最高词符概率来进行优化。\n如果最高词符概率是 80%,而Min P设定为 0.1,那么只有那些概率高于8%的词符会被考虑。\n将这个值设置为 0 就相当于关闭了这个功能。",120 "Min_P_desc": "Min P 设定了一个基础的最小概率,它会根据最高词符概率来进行优化。\n如果最高词符概率是 80%,而Min P设定为 0.1,那么只有那些概率高于8%的词符会被考虑。\n将这个值设置为 0 就相当于关闭了这个功能。",
104 "Top_A_desc": "Top A 设定了一个阈值,用于根据最高词符概率的平方来选择词符。\n如果 Top A 设定为 0.2,而最高词符概率是 50%,那么概率低于 5% 的词符会被排除(0.2 * 0.5^2)。\n将这个值设置为 0 就相当于关闭了这个功能。",121 "Top_A_desc": "Top A 设定了一个阈值,用于根据最高词符概率的平方来选择词符。\n如果 Top A 设定为 0.2,而最高词符概率是 50%,那么概率低于 5% 的词符会被排除(0.2 * 0.5^2)。\n将这个值设置为 0 就相当于关闭了这个功能。",
@@ -119,30 +136,17 @@
119 "Samplers will be applied in a top-down order. Use with caution.": "采样器将按自上而下的顺序应用。请谨慎使用。",136 "Samplers will be applied in a top-down order. Use with caution.": "采样器将按自上而下的顺序应用。请谨慎使用。",
120 "Tail Free Sampling": "无尾采样",137 "Tail Free Sampling": "无尾采样",
121 "Load koboldcpp order": "加载koboldcpp顺序",138 "Load koboldcpp order": "加载koboldcpp顺序",
122 "Preamble": "序文",
123 "Use style tags to modify the writing style of the output.": "使用样式标签修改输出的写作风格。",
124 "Banned Tokens": "禁用的词符",
125 "Sequences you don't want to appear in the output. One per line.": "您不希望出现在输出中的字符串。 每行一个。",
126 "Logit Bias": "Logit 偏置",
127 "Add": "添加",
128 "Helps to ban or reenforce the usage of certain words": "有助于禁止或加强某些单词的使用",
129 "CFG Scale": "CFG缩放",
130 "Negative Prompt": "负面提示词",
131 "Add text here that would make the AI generate things you don't want in your outputs.": "请在此处添加文本,以避免生成您不希望出现在输出中的内容。",
132 "Used if CFG Scale is unset globally, per chat or character": "如果无分类器指导(CFG)缩放比例未在全局设置,它将作用于每个聊天或每个角色",
133 "Mirostat Tau": "Mirostat τ",
134 "Mirostat LR": "Mirostat 学习率",
135 "Min Length": "最小长度",
136 "Top K Sampling": "Top K 采样",139 "Top K Sampling": "Top K 采样",
137 "Nucleus Sampling": "核采样",140 "Nucleus Sampling": "核采样",
138 "Top A Sampling": "Top A 采样",141 "Top A Sampling": "Top A 采样",
139 "CFG": "CFG",142 "Unified Sampling": "Unified Sampling",
140 "Neutralize Samplers": "置采样器参数为失效值",143 "Neutralize Samplers": "置采样器参数为失效值",
141 "Set all samplers to their neutral/disabled state.": "将所有采样器设置为失效/禁用状态。",144 "Set all samplers to their neutral/disabled state.": "将所有采样器设置为失效/禁用状态。",
142 "Sampler Select": "采样器选择",145 "Sampler Select": "采样器选择",
143 "Customize displayed samplers or add custom samplers.": "自定义显示的采样器或添加自定义采样器。",146 "Customize displayed samplers or add custom samplers.": "自定义显示的采样器或添加自定义采样器。",
144 "Epsilon Cutoff": "ε 截断",147 "Epsilon Cutoff": "ε 截断",
145 "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "ε 截断设置了一个概率下限,低于该下限的词符将被排除在采样之外。\n以 1e-4 单位;合适的值为 3。将其设置为 0 以禁用。",148 "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "ε 截断设置了一个概率下限,低于该下限的词符将被排除在采样之外。\n以 1e-4 单位;合适的值为 3。将其设置为 0 以禁用。",
149 "Top nsigma": "Top nsigma",
146 "Eta Cutoff": "η 截断",150 "Eta Cutoff": "η 截断",
147 "Eta_Cutoff_desc": "η截断是特殊η采样技术的主要参数。&#13;以1e-4为单位;合理的值为3。&#13;设置为0以禁用。&#13;有关详细信息,请参阅Hewitt等人的论文《Truncation Sampling as Language Model Desmoothing》(2022年)。",151 "Eta_Cutoff_desc": "η截断是特殊η采样技术的主要参数。&#13;以1e-4为单位;合理的值为3。&#13;设置为0以禁用。&#13;有关详细信息,请参阅Hewitt等人的论文《Truncation Sampling as Language Model Desmoothing》(2022年)。",
148 "rep.pen decay": "重复惩罚衰减",152 "rep.pen decay": "重复惩罚衰减",
@@ -154,6 +158,9 @@
154 "Smooth_Sampling_desc": "允许您使用二次/三次变换来调整分布。较低的平滑因子值将更具创造性,通常在 0.2-0.3 之间是最佳点(假设曲线 = 1)。较高的平滑曲线值将使曲线更陡峭,这将更积极地惩罚低概率选择。1.0 曲线相当于仅使用平滑因子。",158 "Smooth_Sampling_desc": "允许您使用二次/三次变换来调整分布。较低的平滑因子值将更具创造性,通常在 0.2-0.3 之间是最佳点(假设曲线 = 1)。较高的平滑曲线值将使曲线更陡峭,这将更积极地惩罚低概率选择。1.0 曲线相当于仅使用平滑因子。",
155 "Smoothing Factor": "平滑系数",159 "Smoothing Factor": "平滑系数",
156 "Smoothing Curve": "平滑曲线",160 "Smoothing Curve": "平滑曲线",
161 "Exclude Top Choices (XTC)": "Exclude Top Choices (XTC)",
162 "Threshold": "阈值",
163 "Probability": "可能性",
157 "DRY_Repetition_Penalty_desc": "DRY 会对那些会将输入末尾扩展为输入中之前出现过的序列的词符进行惩罚。将乘数设置为 0 以禁用。",164 "DRY_Repetition_Penalty_desc": "DRY 会对那些会将输入末尾扩展为输入中之前出现过的序列的词符进行惩罚。将乘数设置为 0 以禁用。",
158 "DRY Repetition Penalty": "DRY 重复惩罚",165 "DRY Repetition Penalty": "DRY 重复惩罚",
159 "DRY_Multiplier_desc": "将值设置为 > 0 以启用 DRY。控制最短惩罚序列的惩罚幅度。",166 "DRY_Multiplier_desc": "将值设置为 > 0 以启用 DRY。控制最短惩罚序列的惩罚幅度。",
@@ -178,10 +185,13 @@
178 "Mirostat Eta": "Mirostat η",185 "Mirostat Eta": "Mirostat η",
179 "Learning rate of Mirostat": "Mirostat 的学习率。",186 "Learning rate of Mirostat": "Mirostat 的学习率。",
180 "Beam search": "束搜索",187 "Beam search": "束搜索",
181 "Helpful tip coming soon.": "有用的提示即将发布。",188 "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.",
182 "Number of Beams": "束数量",189 "# of Beams": "# of Beams",
190 "The number of sequences generated at each step with Beam Search.": "The number of sequences generated at each step with Beam Search.",
183 "Length Penalty": "长度惩罚",191 "Length Penalty": "长度惩罚",
192 "Penalize sequences based on their length.": "Penalize sequences based on their length.",
184 "Early Stopping": "提前停止",193 "Early Stopping": "提前停止",
194 "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.",
185 "Contrastive search": "对比搜索",195 "Contrastive search": "对比搜索",
186 "Contrastive_search_txt": "通过利用大多数 LLM 表示空间的各向同性以鼓励多样性同时保持一致性的采样器。详见 Su 等人在 2022 年发表的论文 《A Contrastive Framework for Neural Text Generation》。",196 "Contrastive_search_txt": "通过利用大多数 LLM 表示空间的各向同性以鼓励多样性同时保持一致性的采样器。详见 Su 等人在 2022 年发表的论文 《A Contrastive Framework for Neural Text Generation》。",
187 "Penalty Alpha": "惩罚系数 α",197 "Penalty Alpha": "惩罚系数 α",
@@ -198,30 +208,34 @@
198 "Speculative Ngram": "推测性 Ngram",208 "Speculative Ngram": "推测性 Ngram",
199 "Use a different speculative decoding method without a draft model": "使用不同的推测解码方法(不采用草稿模型)。最好使用草稿模型。推测性 Ngram 的效果不太好。",209 "Use a different speculative decoding method without a draft model": "使用不同的推测解码方法(不采用草稿模型)。最好使用草稿模型。推测性 Ngram 的效果不太好。",
200 "Spaces Between Special Tokens": "特殊词符之间的空格",210 "Spaces Between Special Tokens": "特殊词符之间的空格",
211 "Seed_desc": "A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed.",
201 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",212 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",
202 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",213 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",
214 "CFG": "CFG",
203 "Classifier Free Guidance. More helpful tip coming soon": "无分类器指导(CFG)。更多有用的提示敬请期待。",215 "Classifier Free Guidance. More helpful tip coming soon": "无分类器指导(CFG)。更多有用的提示敬请期待。",
204 "Scale": "缩放比例",216 "Scale": "缩放比例",
205 "JSON Schema": "JSON 结构",217 "Negative Prompt": "负面提示词",
206 "Type in the desired JSON schema": "输入所需的 JSON 结构",218 "Used if CFG Scale is unset globally, per chat or character": "如果无分类器指导(CFG)缩放比例未在全局设置,它将作用于每个聊天或每个角色",
219 "Add text here that would make the AI generate things you don't want in your outputs.": "请在此处添加文本,以避免生成您不希望出现在输出中的内容。",
207 "Grammar String": "语法字符串",220 "Grammar String": "语法字符串",
208 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。",221 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF 或 EBNF,取决于使用的后端。如果您使用这个,您应该知道该用哪一个。",
222 "JSON Schema": "JSON 结构",
223 "Type in the desired JSON schema": "输入所需的 JSON 结构",
209 "Top P & Min P": "Top P 和 Min P",224 "Top P & Min P": "Top P 和 Min P",
210 "Load default order": "加载默认顺序",225 "Load default order": "加载默认顺序",
211 "Sampler Order": "取样器顺序",226 "Sampler Order": "取样器顺序",
212 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",227 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "仅限 llama.cpp。确定采样器的顺序。如果 Mirostat 模式不为 0,则忽略采样器顺序。",
213 "Sampler Priority": "采样器优先级",228 "Sampler Priority": "采样器优先级",
214 "Ooba only. Determines the order of samplers.": "确定采样器的顺序(仅适用于Ooba)",229 "Ooba only. Determines the order of samplers.": "确定采样器的顺序(仅适用于Ooba)",
230 "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.",
231 "Aphrodite only. Determines the order of samplers.": "Aphrodite only. Determines the order of samplers.",
215 "Character Names Behavior": "角色名称行为",232 "Character Names Behavior": "角色名称行为",
216 "Helps the model to associate messages with characters.": "有助于模型将消息与角色关联起来。",233 "Helps the model to associate messages with characters.": "有助于模型将消息与角色关联起来。",
217 "None": "无",234 "None": "无",
218 "character_names_none": "不添加角色名称前缀。在群聊中可能导致错误行为,谨慎勾选。",235 "character_names_none": "不添加角色名称前缀。在群聊中可能导致错误行为,谨慎勾选。",
219 "Never add character names.": "不添加角色名称。",
220 "character_names_default": "群聊和过去的角色除外。否则,请确保在提示词中提供了姓名。",236 "character_names_default": "群聊和过去的角色除外。否则,请确保在提示词中提供了姓名。",
221 "Don't add character names unless necessary.": "如非必要,否则不添加角色名称。",
222 "Completion Object": "补全对象",237 "Completion Object": "补全对象",
223 "character_names_completion": "适用限制:仅限拉丁字母数字和下划线。不适用于所有补全源,尤其是:Claude、MistralAI、Google。",238 "character_names_completion": "适用限制:仅限拉丁字母数字和下划线。不适用于所有补全源,尤其是:Claude、MistralAI、Google。",
224 "Add character names to completion objects.": "在补全对象中添加角色名称。",
225 "Message Content": "消息内容",239 "Message Content": "消息内容",
226 "Prepend character names to message contents.": "在消息内容中添加角色名称。",240 "Prepend character names to message contents.": "在消息内容中添加角色名称。",
227 "Continue Postfix": "继续后缀",241 "Continue Postfix": "继续后缀",
@@ -249,22 +263,17 @@
249 "openai_inline_image_quality_auto": "自动",263 "openai_inline_image_quality_auto": "自动",
250 "openai_inline_image_quality_low": "低",264 "openai_inline_image_quality_low": "低",
251 "openai_inline_image_quality_high": "高",265 "openai_inline_image_quality_high": "高",
252 "Use AI21 Tokenizer": "使用 AI21 词符化器",
253 "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "对Jurassic模型使用适当的词符化器,它比 GPT 的更高效。",
254 "Use Google Tokenizer": "使用Google词符化器",
255 "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "通过其API为Google模型使用适当的词符化器。处理速度较慢,但提供更准确的词符计数。",
256 "Use system prompt": "使用系统提示词",266 "Use system prompt": "使用系统提示词",
257 "(Gemini 1.5 Pro/Flash only)": "(仅限 Gemini 1.5 Pro/Flash)",
258 "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过",267 "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过",
259 "Merges_all_system_messages_desc_2": "字段发送。",268 "Merges_all_system_messages_desc_2": "字段发送。",
260 "Assistant Prefill": "AI预填",269 "Assistant Prefill": "AI预填",
270 "Expand the editor": "展开编辑器",
261 "Start Claude's answer with...": "以如下内容开始Claude的回答...",271 "Start Claude's answer with...": "以如下内容开始Claude的回答...",
262 "Assistant Impersonation Prefill": "AI帮答预填",272 "Assistant Impersonation Prefill": "AI帮答预填",
263 "Use system prompt (Claude 2.1+ only)": "使用系统提示词(仅适用于Claude 2.1+)",273 "Use system prompt (Claude 2.1+ only)": "使用系统提示词(仅适用于Claude 2.1+)",
264 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。",274 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。",
265 "User first message": "用户第一条消息",275 "Confirm token parsing with": "Confirm token parsing with",
266 "Restore User first message": "恢复用户第一条消息",276 "Tokenizer": "词符化器",
267 "Human message": "人性化消息、说明等。\n为空时不添加任何内容,即需要具有“用户”角色的新提示词。",
268 "New preset": "新预设",277 "New preset": "新预设",
269 "Delete preset": "删除预设",278 "Delete preset": "删除预设",
270 "View / Edit bias preset": "查看/编辑偏置预设",279 "View / Edit bias preset": "查看/编辑偏置预设",
@@ -276,13 +285,14 @@
276 "Text Completion": "文本补全",285 "Text Completion": "文本补全",
277 "Chat Completion": "聊天补全",286 "Chat Completion": "聊天补全",
278 "NovelAI": "NovelAI",287 "NovelAI": "NovelAI",
279 "KoboldAI Horde": "KoboldAI Horde",288 "AI Horde": "AI Horde",
280 "KoboldAI": "KoboldAI",289 "KoboldAI": "KoboldAI",
290 "AI Horde Website": "AI Horde 网站",
281 "Avoid sending sensitive information to the Horde.": "避免向 Horde 发送敏感信息。",291 "Avoid sending sensitive information to the Horde.": "避免向 Horde 发送敏感信息。",
282 "Review the Privacy statement": "查看隐私声明",292 "Review the Privacy statement": "查看隐私声明",
283 "Register a Horde account for faster queue times": "注册Horde帐户以加快排队时间",293 "Register a Horde account for faster queue times": "注册 Horde 帐户以加快排队时间",
284 "Learn how to contribute your idle GPU cycles to the Horde": "了解如何将您的空闲GPU时钟周期共享给Horde",294 "Learn how to contribute your idle GPU cycles to the Horde": "了解如何将您的空闲GPU时钟周期共享给 Horde",
285 "Adjust context size to worker capabilities": "根据工作单元能力调整上下文大小",295 "Adjust context size to worker capabilities": "根据工作单元能力调整上下文长度",
286 "Adjust response length to worker capabilities": "根据工作单元能力调整响应长度",296 "Adjust response length to worker capabilities": "根据工作单元能力调整响应长度",
287 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "可以通过仅排队认证的工作单元来帮助处理不良回复。这可能会减慢回复速度。",297 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "可以通过仅排队认证的工作单元来帮助处理不良回复。这可能会减慢回复速度。",
288 "Trusted workers only": "仅信任的工作单元",298 "Trusted workers only": "仅信任的工作单元",
@@ -308,7 +318,7 @@
308 "Novel AI Model": "Novel AI 模型",318 "Novel AI Model": "Novel AI 模型",
309 "No connection...": "没有连接...",319 "No connection...": "没有连接...",
310 "API Type": "API 类型",320 "API Type": "API 类型",
311 "Default (completions compatible)": "默认 [OpenAI/completions 兼容:oobabooga、LM Studio 等]",321 "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]",
312 "TogetherAI API Key": "TogetherAI API 密钥",322 "TogetherAI API Key": "TogetherAI API 密钥",
313 "TogetherAI Model": "TogetherAI 模型",323 "TogetherAI Model": "TogetherAI 模型",
314 "-- Connect to the API --": "-- 连接到API --",324 "-- Connect to the API --": "-- 连接到API --",
@@ -324,15 +334,26 @@
324 "DreamGen Model": "DreamGen 模型",334 "DreamGen Model": "DreamGen 模型",
325 "Mancer API key": "Mancer API 密钥",335 "Mancer API key": "Mancer API 密钥",
326 "Mancer Model": "Mancer 模型",336 "Mancer Model": "Mancer 模型",
327 "Make sure you run it with": "确保您在运行时加上",
328 "flag": "标志",
329 "API key (optional)": "API密钥(可选)",337 "API key (optional)": "API密钥(可选)",
330 "Server url": "服务器URL",338 "Server url": "服务器URL",
331 "Example: 127.0.0.1:5000": "示例:127.0.0.1:5000",339 "Example: 127.0.0.1:5000": "示例:127.0.0.1:5000",
340 "Model ID (optional)": "模型 ID(可选)",
341 "Make sure you run it with": "确保您在运行时加上",
342 "flag": "标志",
332 "Custom model (optional)": "自定义模型(可选)",343 "Custom model (optional)": "自定义模型(可选)",
344 "Featherless Model Selection": "Featherless Model Selection",
345 "Search...": "搜索...",
346 "Search": "搜索",
347 "category": "分类",
348 "Top": "Top",
349 "New": "新建",
350 "All": "All",
351 "class": "All Classes",
352 "Toggle grid view": "切换网格视图",
353 "No model description": "[No description]",
333 "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)",354 "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)",
334 "vLLM API key": "vLLM API 密钥",355 "vLLM API key": "vLLM API 密钥",
335 "Example: 127.0.0.1:8000": "例如:http://127.0.0.1:8000",356 "Example: 127.0.0.1:8000": "示例:http://127.0.0.1:8000",
336 "vLLM Model": "vLLM 模型",357 "vLLM Model": "vLLM 模型",
337 "HuggingFace Token": "HuggingFace 代币",358 "HuggingFace Token": "HuggingFace 代币",
338 "Endpoint URL": "端点 URL",359 "Endpoint URL": "端点 URL",
@@ -347,11 +368,14 @@
347 "Download": "下载",368 "Download": "下载",
348 "Tabby API key": "Tabby API 密钥",369 "Tabby API key": "Tabby API 密钥",
349 "Tabby Model": "Tabby 模型",370 "Tabby Model": "Tabby 模型",
371 "must be set in Tabby's config.yml to switch models.": "必须在Tabby的config.yml内设置以切换模型",
372 "Use an admin API key.": "使用管理员API密钥。",
350 "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)",373 "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)",
351 "Example: 127.0.0.1:5001": "示例:127.0.0.1:5001",374 "Example: 127.0.0.1:5001": "示例:127.0.0.1:5001",
375 "Bypass status check": "绕过状态检查",
376 "Derive context size from backend": "从后端获取上下文长度",
352 "Authorize": "授权",377 "Authorize": "授权",
353 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用OAuth流程获取您的OpenRouter API令牌。您将被重定向到openrouter.ai",378 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用OAuth流程获取您的OpenRouter API令牌。您将被重定向到openrouter.ai",
354 "Bypass status check": "绕过状态检查",
355 "Chat Completion Source": "聊天补全来源",379 "Chat Completion Source": "聊天补全来源",
356 "Custom (OpenAI-compatible)": "自定义(兼容 OpenAI)",380 "Custom (OpenAI-compatible)": "自定义(兼容 OpenAI)",
357 "Reverse Proxy": "反向代理",381 "Reverse Proxy": "反向代理",
@@ -363,7 +387,7 @@
363 "This will show up as your saved preset.": "这将显示为您保存的预设。",387 "This will show up as your saved preset.": "这将显示为您保存的预设。",
364 "Proxy Server URL": "代理服务器 URL",388 "Proxy Server URL": "代理服务器 URL",
365 "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。",389 "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。",
366 "Doesn't work? Try adding": "不起作用?尝试在最后添加",390 "Doesn't work? Try adding": "不起作用?尝试添加",
367 "at the end!": "!",391 "at the end!": "!",
368 "Proxy Password": "代理密码",392 "Proxy Password": "代理密码",
369 "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。",393 "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。",
@@ -373,15 +397,16 @@
373 "Do not proceed if you do not agree to this!": "如果您不同意,请不要继续!",397 "Do not proceed if you do not agree to this!": "如果您不同意,请不要继续!",
374 "OpenAI API key": "OpenAI API 密钥",398 "OpenAI API key": "OpenAI API 密钥",
375 "View API Usage Metrics": "查看API使用情况",399 "View API Usage Metrics": "查看API使用情况",
376 "Follow": "跟随",400 "Follow": "按照",
377 "these directions": "这些说明",401 "these directions": "这些步骤",
378 "to get your OpenAI API key.": "以获取您的OpenAI API密钥。",402 "to get your OpenAI API key.": "获取您的OpenAI API密钥。",
379 "Use Proxy password field instead. This input will be ignored.": "请使用“代理密码”字段。此输入将被忽略。",403 "Use Proxy password field instead. This input will be ignored.": "请使用“代理密码”字段。此输入将被忽略。",
380 "OpenAI Model": "OpenAI 模型",404 "OpenAI Model": "OpenAI 模型",
381 "Bypass API status check": "绕过API状态检查",405 "Bypass API status check": "绕过API状态检查",
382 "Show External models (provided by API)": "显示外部模型(由API提供)",406 "Show External models (provided by API)": "显示外部模型(由API提供)",
407 "Claude API Key": "Claude API Key",
383 "Get your key from": "从以下位置获取您的密钥",408 "Get your key from": "从以下位置获取您的密钥",
384 "Anthropic's developer console": "Anthropic的开发者控制台",409 "Anthropic's developer console": "Anthropic 开发者控制台",
385 "Claude Model": "Claude 模型",410 "Claude Model": "Claude 模型",
386 "Window AI Model": "Window AI 模型",411 "Window AI Model": "Window AI 模型",
387 "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。",412 "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。",
@@ -389,8 +414,8 @@
389 "Model Order": "OpenRouter 模型顺序",414 "Model Order": "OpenRouter 模型顺序",
390 "Alphabetically": "按字母顺序",415 "Alphabetically": "按字母顺序",
391 "Price": "价格(最便宜)",416 "Price": "价格(最便宜)",
392 "Context Size": "上下文大小",417 "Context Size": "上下文长度",
393 "Group by vendors": "按供应商分组",418 "Group by vendors": "按厂商分组",
394 "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。",419 "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。",
395 "Scale API Key": "Scale API密钥",420 "Scale API Key": "Scale API密钥",
396 "Clear your cookie": "清除你的 Cookie",421 "Clear your cookie": "清除你的 Cookie",
@@ -403,15 +428,19 @@
403 "MistralAI Model": "MistralAI 模型",428 "MistralAI Model": "MistralAI 模型",
404 "Groq API Key": "Groq API 密钥",429 "Groq API Key": "Groq API 密钥",
405 "Groq Model": "Groq 模型",430 "Groq Model": "Groq 模型",
431 "NanoGPT API Key": "NanoGPT API Key",
432 "NanoGPT Model": "NanoGPT Model",
406 "Perplexity API Key": "Perplexity API 密钥",433 "Perplexity API Key": "Perplexity API 密钥",
407 "Perplexity Model": "Perplexity 模型",434 "Perplexity Model": "Perplexity 模型",
408 "Cohere API Key": "Cohere API 密钥",435 "Cohere API Key": "Cohere API 密钥",
409 "Cohere Model": "Cohere 模型",436 "Cohere Model": "Cohere 模型",
437 "Block Entropy API Key": "Block Entropy API Key",
438 "Select a Model": "Select a Model",
410 "Custom Endpoint (Base URL)": "自定义端点(基本 URL)",439 "Custom Endpoint (Base URL)": "自定义端点(基本 URL)",
411 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",440 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
412 "at the end of the URL!": "在 URL 的末尾!",441 "at the end of the URL!": "到 URL 的末尾!",
413 "Custom API Key": "自定义 API 密钥",442 "Custom API Key": "自定义 API 密钥",
414 "(Optional)": "(可选的)",443 "(Optional)": "(可选)",
415 "Enter a Model ID": "输入模型名",444 "Enter a Model ID": "输入模型名",
416 "Example: gpt-3.5-turbo": "例如:gpt-3.5-turbo",445 "Example: gpt-3.5-turbo": "例如:gpt-3.5-turbo",
417 "Available Models": "可用模型",446 "Available Models": "可用模型",
@@ -419,9 +448,9 @@
419 "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。",448 "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。",
420 "prompt_post_processing_none": "未选择",449 "prompt_post_processing_none": "未选择",
421 "01.AI API Key": "01.AI API密钥",450 "01.AI API Key": "01.AI API密钥",
422 "01.AI Model": "01.AI模型",451 "01.AI Model": "01.AI 模型",
423 "Additional Parameters": "附加参数",452 "Additional Parameters": "附加参数",
424 "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意,您将因此而消耗额度!",453 "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意,您将因此消耗额度!",
425 "Test Message": "发送测试消息",454 "Test Message": "发送测试消息",
426 "Auto-connect to Last Server": "自动连接到上次的服务器",455 "Auto-connect to Last Server": "自动连接到上次的服务器",
427 "Missing key": "❌ 缺少密钥",456 "Missing key": "❌ 缺少密钥",
@@ -429,57 +458,74 @@
429 "View hidden API keys": "查看隐藏的API密钥",458 "View hidden API keys": "查看隐藏的API密钥",
430 "AI Response Formatting": "AI回复格式化",459 "AI Response Formatting": "AI回复格式化",
431 "Advanced Formatting": "高级格式化设置",460 "Advanced Formatting": "高级格式化设置",
461 "Import Advanced Formatting settings": "导入高级格式化设置\n\n对于指导和上下文模板,你也可以提供旧版文件。",
462 "Master Import": "Master Import",
463 "Export Advanced Formatting settings": "导出高级格式化设置",
464 "Master Export": "Master Export",
432 "Context Template": "上下文模板",465 "Context Template": "上下文模板",
433 "Auto-select this preset for Instruct Mode": "在指示模式下自动选择此预设",466 "context_derived": "若可能,从模型的元数据获取。",
467 "Select your current Context Template": "选择你当前的上下文模板",
468 "Update current template": "更新当前模板",
469 "Rename current template": "重命名当前模板",
470 "Save template as": "将模板另存为",
471 "Import template": "导入模板",
472 "Export template": "导出模板",
473 "Restore current template": "还原当前模板",
474 "Delete the template": "删除模板",
434 "Story String": "故事字符串",475 "Story String": "故事字符串",
435 "Example Separator": "示例分隔符",476 "Example Separator": "示例分隔符",
436 "Chat Start": "聊天开始",477 "Chat Start": "聊天开始",
478 "Context Formatting": "上下文格式",
479 "Always add character's name to prompt": "始终将角色名称添加到提示词",
480 "Generate only one line per request": "每次请求只生成一行",
481 "Collapse Consecutive Newlines": "折叠连续的换行符",
482 "Trim spaces": "修剪空格",
483 "Disabling is not recommended.": "不建议关闭。",
484 "Trim Incomplete Sentences": "修剪不完整的句子",
437 "Add Chat Start and Example Separator to a list of stopping strings.": "将聊天开始和示例分隔符添加到停止字符串列表中。",485 "Add Chat Start and Example Separator to a list of stopping strings.": "将聊天开始和示例分隔符添加到停止字符串列表中。",
438 "Separators as Stop Strings": "分隔符作为终止字符串",486 "Separators as Stop Strings": "分隔符作为终止字符串",
439 "Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。",487 "Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。",
440 "Names as Stop Strings": "名称作为终止字符串",488 "Names as Stop Strings": "名称作为终止字符串",
441 "context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。",489 "context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。",
442 "Allow Post-History Instructions": "允许后历史说明",490 "Allow Post-History Instructions": "允许后历史说明",
443 "Context Order": "上下文顺序",491 "Instruct Template": "指导模板",
444 "Summary": "总结",492 "instruct_derived": "如果可能,从模型元数据中获取",
445 "Author's Note": "作者注释",
446 "Example Dialogues": "对话范例",
447 "Hint": "提示:",
448 "In-Chat Position not affected": "仅当摘要和作者注释订单未设置聊天内位置时,它们才会受到影响。",
449 "Instruct Mode": "指示模式",
450 "Enabled": "已启用",
451 "instruct_bind_to_context": "如果启用,上下文模板将根据所选的指导模板名称或偏好自动选择。",493 "instruct_bind_to_context": "如果启用,上下文模板将根据所选的指导模板名称或偏好自动选择。",
452 "Bind to Context": "绑定到上下文",494 "instruct_enabled": "启用指导模板",
453 "Presets": "预设",495 "Select your current Instruct Template": "选择你当前的指导模板",
454 "Auto-select this preset on API connection": "在API连接时自动选择此预设",496 "Delete template": "删除模板",
455 "Activation Regex": "激活正则表达式",497 "Activation Regex": "激活正则表达式",
498 "instruct_template_activation_regex_desc": "当连接到API或选择模型时,若模型名称与给定的正则表达式匹配,自动启用此指导模板。",
456 "Wrap Sequences with Newline": "用换行符包裹序列",499 "Wrap Sequences with Newline": "用换行符包裹序列",
457 "Replace Macro in Sequences": "替换序列中的宏",500 "Replace Macro in Sequences": "替换序列中的宏",
458 "Skip Example Dialogues Formatting": "跳过示例对话格式化",501 "Skip Example Dialogues Formatting": "跳过示例对话格式化",
459 "Include Names": "包括名称",502 "Include Names": "包括名称",
460 "Force for Groups and Personas": "强制适用于群聊和我的角色",503 "Never": "永不",
461 "System Prompt": "系统提示词",504 "Groups and Past Personas": "Groups and Past Personas",
462 "Instruct Mode Sequences": "指示模式序列",505 "Always": "永远",
463 "System Prompt Wrapping": "系统提示词换行",506 "Instruct Sequences": "Instruct Sequences",
464 "Inserted before a System prompt.": "插入到系统提示词之前。",507 "User Message Sequences": "User Message Sequences",
465 "System Prompt Prefix": "系统提示词前缀",
466 "Inserted after a System prompt.": "在系统提示词后插入。",
467 "System Prompt Suffix": "系统提示词后缀",
468 "Chat Messages Wrapping": "聊天消息换行",
469 "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。",508 "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。",
470 "User Message Prefix": "用户消息前缀",509 "User Prefix": "用户消息前缀",
471 "Inserted after a User message.": "插入到用户消息之后。",510 "Inserted after a User message.": "插入到用户消息之后。",
472 "User Message Suffix": "用户消息后缀",511 "User Suffix": "用户消息后缀",
512 "Assistant Message Sequences": "Assistant Message Sequences",
473 "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入到助手消息之前并作为生成 AI 回复时的最后一行提示词。",513 "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "插入到助手消息之前并作为生成 AI 回复时的最后一行提示词。",
474 "Assistant Message Prefix": "助理消息前缀",514 "Assistant Prefix": "助手消息前缀",
475 "Inserted after an Assistant message.": "插入于助手消息之后。",515 "Inserted after an Assistant message.": "插入于助手消息之后。",
476 "Assistant Message Suffix": "助理消息后缀",516 "Assistant Suffix": "助手消息后缀",
517 "System Message Sequences": "System Message Sequences",
477 "Inserted before a System (added by slash commands or extensions) message.": "插入到系统(由快捷命令或扩展添加)消息之前。",518 "Inserted before a System (added by slash commands or extensions) message.": "插入到系统(由快捷命令或扩展添加)消息之前。",
478 "System Message Prefix": "系统消息前缀",519 "System Prefix": "System Message Prefix",
479 "Inserted after a System message.": "插入到系统消息之后。",520 "Inserted after a System message.": "插入到系统消息之后。",
480 "System Message Suffix": "系统消息后缀",521 "System Suffix": "System Message Suffix",
481 "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。",522 "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。",
482 "System same as User": "系统与用户相同",523 "System same as User": "系统与用户相同",
524 "System Prompt Sequences": "System Prompt Sequences",
525 "Inserted before a System prompt.": "插入到系统提示词之前。",
526 "System Prompt Prefix": "系统提示词前缀",
527 "Inserted after a System prompt.": "在系统提示词后插入。",
528 "System Prompt Suffix": "系统提示词后缀",
483 "Misc. Sequences": "杂项序列",529 "Misc. Sequences": "杂项序列",
484 "Inserted before the first Assistant's message.": "插入到第一个助理的消息之前。",530 "Inserted before the first Assistant's message.": "插入到第一个助理的消息之前。",
485 "First Assistant Prefix": "第一个助理前缀",531 "First Assistant Prefix": "第一个助理前缀",
@@ -495,28 +541,24 @@
495 "Stop Sequence": "停止序列",541 "Stop Sequence": "停止序列",
496 "Will be inserted at the start of the chat history if it doesn't start with a User message.": "如果聊天记录不是以用户消息开头,则会插入到聊天记录的开头。",542 "Will be inserted at the start of the chat history if it doesn't start with a User message.": "如果聊天记录不是以用户消息开头,则会插入到聊天记录的开头。",
497 "User Filler Message": "用户填写信息",543 "User Filler Message": "用户填写信息",
498 "Context Formatting": "上下文格式",544 "System Prompt": "系统提示词",
499 "(Saved to Context Template)": "(已保存到上下文模板)",545 "sysprompt_enabled": "启用系统提示词",
500 "Always add character's name to prompt": "始终将角色名称添加到提示词",546 "Select your current System Prompt": "选择当前的系统提示词",
501 "Generate only one line per request": "每次请求只生成一行",547 "Update current prompt": "更新当前提示词",
502 "Trim Incomplete Sentences": "修剪不完整的句子",548 "Rename current prompt": "重命名当前提示词",
503 "Include Newline": "包括换行符",549 "Save prompt as": "将提示词另存为",
504 "Misc. Settings": "其他设置",550 "Restore current prompt": "还原当前提示词",
505 "Collapse Consecutive Newlines": "折叠连续的换行符",551 "Delete prompt": "删除提示词",
506 "Trim spaces": "修剪空格",552 "Prompt Content": "提示词内容",
507 "Tokenizer": "词符化器",
508 "Token Padding": "词符填充",
509 "Start Reply With": "以...开始回复",
510 "AI reply prefix": "AI回复前缀",
511 "Show reply prefix in chat": "在聊天中显示回复前缀",
512 "Non-markdown strings": "非 Markdown 字符串",
513 "separate with commas w/o space between": "用逗号分隔,不要空格",
514 "Custom Stopping Strings": "自定义停止字符串",553 "Custom Stopping Strings": "自定义停止字符串",
515 "JSON serialized array of strings": "JSON序列化的字符串数组",554 "JSON serialized array of strings": "JSON序列化的字符串数组",
516 "Replace Macro in Custom Stopping Strings": "替换自定义停止字符串中的宏",555 "Replace Macro in Custom Stopping Strings": "替换自定义停止字符串中的宏",
517 "Auto-Continue": "自动继续",556 "Token Padding": "词符填充",
518 "Allow for Chat Completion APIs": "允许使用聊天补全API",557 "Miscellaneous": "杂项",
519 "Target length (tokens)": "目标长度(以词符数计)",558 "Non-markdown strings": "非 Markdown 字符串",
559 "comma delimited,no spaces between": "comma delimited,no spaces between",
560 "Start Reply With": "以...开始回复",
561 "Show reply prefix in chat": "在聊天中显示回复前缀",
520 "World Info": "世界信息",562 "World Info": "世界信息",
521 "Locked = World Editor will stay open": "锁定 = 世界编辑器将保持打开状态",563 "Locked = World Editor will stay open": "锁定 = 世界编辑器将保持打开状态",
522 "Worlds/Lorebooks": "世界/知识书",564 "Worlds/Lorebooks": "世界/知识书",
@@ -527,11 +569,15 @@
527 "Scan Depth": "扫描深度",569 "Scan Depth": "扫描深度",
528 "Context %": "上下文百分比",570 "Context %": "上下文百分比",
529 "Budget Cap": "Token预算上限",571 "Budget Cap": "Token预算上限",
530 "(0 = disabled)": "(0 = 禁用)",572 "(0 = disabled)": "(“0”为禁用)",
531 "Scan chronologically until reached min entries or token budget.": "按时间顺序扫描直到达到最少条目或词符预算。",573 "Scan chronologically until reached min entries or token budget.": "按时间顺序扫描直到达到最少条目或词符预算。",
532 "Min Activations": "最小激活数",574 "Min Activations": "最小激活数",
575 "(disabled when max recursion steps are used)": "(当使用最大递归步数时禁用)",
533 "Max Depth": "最大深度",576 "Max Depth": "最大深度",
534 "(0 = unlimited, use budget)": "(0 = 无限制,使用预算)",577 "(0 = unlimited, use budget)": "(“0”为无限制,使用预算)",
578 "Cap the number of entry activation recursions": "限制条目激活递归的次数",
579 "Max Recursion Steps": "最大递归深度",
580 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\\n(disabled when min activations are used)": "“0”为无限制,“1”为扫描一次且不递归,“2”为扫描一次且递归一次,依此类推\n(当使用最小激活次数时,此功能被禁用)",
535 "Insertion Strategy": "插入策略",581 "Insertion Strategy": "插入策略",
536 "Sorted Evenly": "均匀排序",582 "Sorted Evenly": "均匀排序",
537 "Character Lore First": "角色世界书优先",583 "Character Lore First": "角色世界书优先",
@@ -539,7 +585,7 @@
539 "Include names with each message into the context for scanning": "将每条消息的名称纳入上下文中以供扫描",585 "Include names with each message into the context for scanning": "将每条消息的名称纳入上下文中以供扫描",
540 "Entries can activate other entries by mentioning their keywords": "条目可以通过提及它们的关键字来激活其他条目",586 "Entries can activate other entries by mentioning their keywords": "条目可以通过提及它们的关键字来激活其他条目",
541 "Recursive Scan": "递归扫描",587 "Recursive Scan": "递归扫描",
542 "Lookup for the entry keys in the context will respect the case": "在上下文中查找条目键将保持大小写敏感",588 "Lookup for the entry keys in the context will respect the case": "在上下文中查找条目键将继续区分大小写",
543 "Case Sensitive": "区分大小写",589 "Case Sensitive": "区分大小写",
544 "If the entry key consists of only one word, it would not be matched as part of other words": "如果条目键只由一个单词组成,则不会作为其他单词的一部分匹配",590 "If the entry key consists of only one word, it would not be matched as part of other words": "如果条目键只由一个单词组成,则不会作为其他单词的一部分匹配",
545 "Match Whole Words": "匹配整个单词",591 "Match Whole Words": "匹配整个单词",
@@ -547,7 +593,6 @@
547 "Use Group Scoring": "使用群组评分",593 "Use Group Scoring": "使用群组评分",
548 "Alert if your world info is greater than the allocated budget.": "如果您的世界信息大于分配的预算,则会发出警报。",594 "Alert if your world info is greater than the allocated budget.": "如果您的世界信息大于分配的预算,则会发出警报。",
549 "Alert On Overflow": "溢出警报",595 "Alert On Overflow": "溢出警报",
550 "New": "新建",
551 "or": "或",596 "or": "或",
552 "--- Pick to Edit ---": "--- 选择以编辑 ---",597 "--- Pick to Edit ---": "--- 选择以编辑 ---",
553 "Rename World Info": "重命名世界书",598 "Rename World Info": "重命名世界书",
@@ -560,8 +605,6 @@
560 "Export World Info": "导出世界书",605 "Export World Info": "导出世界书",
561 "Duplicate World Info": "复制世界书",606 "Duplicate World Info": "复制世界书",
562 "Delete World Info": "删除世界书",607 "Delete World Info": "删除世界书",
563 "Search...": "搜索...",
564 "Search": "搜索",
565 "Priority": "优先级",608 "Priority": "优先级",
566 "Custom": "自定义",609 "Custom": "自定义",
567 "Title A-Z": "标题 A-Z",610 "Title A-Z": "标题 A-Z",
@@ -578,12 +621,10 @@
578 "Trigger% ↘": "触发频率% ↘",621 "Trigger% ↘": "触发频率% ↘",
579 "Refresh": "刷新",622 "Refresh": "刷新",
580 "User Settings": "用户设置",623 "User Settings": "用户设置",
581 "Simple": "简单",
582 "Advanced": "高级",
583 "UI Language": "语言",624 "UI Language": "语言",
584 "Account": "帐户",625 "Account": "帐户",
585 "Admin Panel": "管理员面板",626 "Admin Panel": "管理员面板",
586 "Logout": "注销",627 "Logout": "登出",
587 "Search Settings": "搜索设置",628 "Search Settings": "搜索设置",
588 "UI Theme": "UI主题",629 "UI Theme": "UI主题",
589 "Import a theme file": "导入主题文件",630 "Import a theme file": "导入主题文件",
@@ -611,7 +652,7 @@
611 "UI Border": "UI 边框",652 "UI Border": "UI 边框",
612 "User Message Blur Tint": "用户消息模糊色调",653 "User Message Blur Tint": "用户消息模糊色调",
613 "AI Message Blur Tint": "AI 消息模糊色调",654 "AI Message Blur Tint": "AI 消息模糊色调",
614 "Chat Width": "聊天宽度",655 "Chat Width": "页面宽度",
615 "Width of the main chat window in % of screen width": "主聊天窗口的宽度为屏幕宽度的 %",656 "Width of the main chat window in % of screen width": "主聊天窗口的宽度为屏幕宽度的 %",
616 "Font Scale": "字体比例",657 "Font Scale": "字体比例",
617 "Font size": "字体大小",658 "Font size": "字体大小",
@@ -633,22 +674,24 @@
633 "Zen Sliders": "禅意滑块",674 "Zen Sliders": "禅意滑块",
634 "Entirely unrestrict all numeric sampling parameters": "完全解除所有数字采样参数的限制",675 "Entirely unrestrict all numeric sampling parameters": "完全解除所有数字采样参数的限制",
635 "Mad Lab Mode": "疯狂实验室模式",676 "Mad Lab Mode": "疯狂实验室模式",
636 "Time the AI's message generation, and show the duration in the chat log": "对 AI 生成消息的时间进行计时,并在聊天记录中显示持续时间。",677 "Time the AI's message generation, and show the duration in the chat log": "对 AI 生成消息的时间进行计时,并在聊天记录中显示。",
637 "Message Timer": "AI回复计时器",678 "Message Timer": "AI回复计时器",
638 "Show a timestamp for each message in the chat log": "在聊天日志中为每条消息显示时间戳",679 "Show a timestamp for each message in the chat log": "在聊天日志中显示每条消息的时间戳",
639 "Chat Timestamps": "聊天时间戳",680 "Chat Timestamps": "聊天时间戳",
640 "Show an icon for the API that generated the message": "为生成消息的API显示图标",681 "Show an icon for the API that generated the message": "显示此消息所用API的图标",
641 "Model Icon": "模型图标",682 "Model Icon": "模型图标",
642 "Show sequential message numbers in the chat log": "在聊天日志中显示连续的消息编号",683 "Show sequential message numbers in the chat log": "在聊天记录中显示消息楼层",
643 "Message IDs": "显示消息编号",684 "Message IDs": "显示消息楼层",
644 "Hide avatars in chat messages.": "在聊天信息中隐藏头像。",685 "Hide avatars in chat messages.": "在聊天记录中隐藏头像。",
645 "Hide Chat Avatars": "隐藏聊天头像",686 "Hide Chat Avatars": "隐藏头像",
646 "Show the number of tokens in each message in the chat log": "在聊天日志中显示每条消息中的词符数",687 "Show the number of tokens in each message in the chat log": "在聊天记录中显示每条消息的词符数",
647 "Show Message Token Count": "显示消息词符数",688 "Show Message Token Count": "显示消息词符数",
648 "Single-row message input area. Mobile only, no effect on PC": "单行消息输入区域。仅适用于移动设备,对PC无影响",689 "Single-row message input area. Mobile only, no effect on PC": "将输入框限制为一行。仅适用于移动设备,对PC无影响",
649 "Compact Input Area (Mobile)": "紧凑输入区域(移动端)",690 "Compact Input Area (Mobile)": "紧凑输入区域(移动端)",
691 "Display swipe numbers for all messages, not just the last.": "Display swipe numbers for all messages, not just the last.",
692 "Swipe # for All Messages": "Swipe # for All Messages",
650 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,显示快速选择按钮以选择收藏的角色",693 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,显示快速选择按钮以选择收藏的角色",
651 "Characters Hotswap": "角色卡快速热切换",694 "Characters Hotswap": "角色卡热切换",
652 "Enable magnification for zoomed avatar display.": "启用放大功能以放大头像显示。",695 "Enable magnification for zoomed avatar display.": "启用放大功能以放大头像显示。",
653 "Avatar Hover Magnification": "头像悬停放大",696 "Avatar Hover Magnification": "头像悬停放大",
654 "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "启用在聊天中点击头像图像后显示放大的头像时的放大效果。",697 "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "启用在聊天中点击头像图像后显示放大的头像时的放大效果。",
@@ -668,56 +711,60 @@
668 "Existing": "现存的",711 "Existing": "现存的",
669 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊匹配,在列表中通过所有数据字段搜索角色,而不仅仅是名称子字符串",712 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊匹配,在列表中通过所有数据字段搜索角色,而不仅仅是名称子字符串",
670 "Advanced Character Search": "高级角色搜索",713 "Advanced Character Search": "高级角色搜索",
671 "If checked and the character card contains a prompt override (System Prompt), use that instead": "如果角色卡包含提示词,则使用它替代系统提示词",714 "If checked and the character card contains a prompt override (System Prompt), use that instead": "开启后,如果角色卡已包含系统提示词,则覆盖当前的系统提示词。",
672 "Prefer Character Card Prompt": "角色卡提示词优先",715 "Prefer Character Card Prompt": "角色卡提示词优先",
673 "If checked and the character card contains a Post-History Instructions override, use that instead": "如果选中并且角色卡包含后历史指令覆盖,则使用它。",716 "If checked and the character card contains a Post-History Instructions override, use that instead": "开启后,如果角色卡包含后历史指令覆盖,则使用它。",
674 "Prefer Character Card Instructions": "首选角色卡说明",717 "Prefer Character Card Instructions": "首选角色卡说明",
675 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。",718 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。",
676 "Never resize avatars": "永不调整头像大小",719 "Never resize avatars": "永不调整头像大小",
677 "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。",720 "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。",
678 "Show avatar filenames": "显示头像文件名",721 "Show avatar filenames": "显示头像文件名",
679 "Hide character definitions from the editor panel behind a spoiler button": "在编辑器面板中,将角色定义隐藏在一个剧透按钮后面。",722 "Hide character definitions from the editor panel behind a spoiler button": "在编辑器面板中,将角色定义隐藏在一个剧透按钮后面。",
680 "Spoiler Free Mode": "隐藏角色卡信息",723 "Spoiler Free Mode": "防剧透模式",
681 "Miscellaneous": "杂项",
682 "Reload and redraw the currently open chat": "重新加载并重新渲染当前打开的聊天",724 "Reload and redraw the currently open chat": "重新加载并重新渲染当前打开的聊天",
683 "Reload Chat": "重新加载聊天",725 "Reload Chat": "重新加载聊天",
684 "Debug Menu": "调试菜单",726 "Debug Menu": "调试菜单",
685 "Smooth Streaming": "平滑流式传输",727 "Smooth Streaming": "平滑流式传输",
686 "Experimental feature. May not work for all backends.": "实验性功能。可能不适用于所有后端。",728 "Experimental feature. May not work for all backends.": "实验性功能。可能不适用于所有后端。",
687 "Slow": "慢",729 "Slow": "慢",
688 "Fast": "快速",730 "Fast": "快",
689 "Play a sound when a message generation finishes": "当消息生成完成时播放声音",731 "Play a sound when a message generation finishes": "当消息生成完毕时播放声音",
690 "Message Sound": "消息声音",732 "Message Sound": "消息声音",
691 "Only play a sound when ST's browser tab is unfocused": "仅在ST的浏览器选项卡未聚焦时播放声音",733 "Only play a sound when ST's browser tab is unfocused": "仅在ST的浏览器标签页未被打开时播放声音",
692 "Background Sound Only": "仅背景声音",734 "Background Sound Only": "仅背景声音",
693 "Reduce the formatting requirements on API URLs": "减少API URL的格式化要求",735 "Reduce the formatting requirements on API URLs": "减少API URL的格式化要求",
694 "Relaxed API URLS": "宽松的API URL",736 "Relaxed API URLS": "宽松的API URL",
695 "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "询问是否为每个具有嵌入的知识书的新角色导入世界信息/知识书。如果未选中,则会显示简短的消息",737 "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "询问是否为每个具有嵌入的知识书的新角色导入世界信息/知识书。如果未选中,则会显示简短的消息",
696 "Lorebook Import Dialog": "知识书导入对话框",738 "Lorebook Import Dialog": "知识书导入对话框",
739 "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "启用在某些文本字段中单击/选择时自动选中文本的功能。适用于弹出输入框以及可能的其他自定义输入字段。",
740 "Auto-select Input Text": "自动选择输入文本",
741 "markdown_hotkeys_desc": "在特定文本输入框中,启用插入 Markdown 格式的快捷键。详情输入:“/help hotkeys”。",
742 "Markdown Hotkeys": "Markdown 快捷键",
697 "Restore unsaved user input on page refresh": "在页面刷新时恢复未保存的用户输入",743 "Restore unsaved user input on page refresh": "在页面刷新时恢复未保存的用户输入",
698 "Restore User Input": "恢复用户输入",744 "Restore User Input": "恢复用户输入",
699 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允许通过拖动重新定位某些UI元素。仅适用于PC,对移动设备无影响",745 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允许通过拖动重新定位某些UI元素。仅适用于PC,对移动设备无影响",
700 "Movable UI Panels": "可移动 UI 面板",746 "Movable UI Panels": "可移动 UI 面板",
701 "Reset MovingUI panel sizes/locations.": "重置 MovingUI 面板大小/位置。",747 "Reset MovingUI panel sizes/locations.": "重置 MovingUI 面板大小/位置。",
748 "mui_reset": "Reset",
702 "MovingUI preset. Predefined/saved draggable positions": "可移动UI预设。预定义/保存的可拖动位置",749 "MovingUI preset. Predefined/saved draggable positions": "可移动UI预设。预定义/保存的可拖动位置",
703 "MUI Preset": "可移动 UI 预设",750 "MUI Preset": "可移动 UI 预设",
704 "Save movingUI changes to a new file": "将可移动UI更改保存到新文件中",751 "Save movingUI changes to a new file": "将可移动UI更改保存到新文件中",
705 "Apply a custom CSS style to all of the ST GUI": "将自定义CSS样式应用于所有ST GUI",752 "Apply a custom CSS style to all of the ST GUI": "将自定义CSS样式应用于所有ST GUI",
706 "Custom CSS": "自定义 CSS",753 "Custom CSS": "自定义 CSS",
707 "Expand the editor": "展开编辑器",
708 "Chat/Message Handling": "聊天/消息处理",754 "Chat/Message Handling": "聊天/消息处理",
709 "# Messages to Load": "# 要加载的消息",755 "# Messages to Load": "# 要加载的消息",
710 "The number of chat history messages to load before pagination.": "分页前要加载的聊天历史消息数。",756 "The number of chat history messages to load before pagination.": "分页前要加载的聊天历史消息数。",
711 "(0 = All)": "(0 = 全部)",757 "(0 = All)": "(“0”为全部)",
712 "Streaming FPS": "流式传输帧速率",758 "Streaming FPS": "流式传输帧速率",
713 "Update speed of streamed text.": "文本流的更新速度。",759 "Update speed of streamed text.": "文本流的更新速度。",
714 "Example Messages Behavior": "示例消息行为",760 "Example Messages Behavior": "示例消息行为",
715 "Gradual push-out": "逐渐推出",761 "Gradual push-out": "逐渐推出",
716 "Always include examples": "始终包含示例",762 "Always include examples": "始终包含示例",
717 "Never include examples": "永远不包含示例",763 "Never include examples": "永不包含示例",
718 "Send on Enter": "按 Enter 发送",764 "Send on Enter": "按 Enter 发送",
719 "Disabled": "已禁用",765 "Disabled": "已禁用",
720 "Automatic (PC)": "自动(PC)",766 "Automatic (PC)": "自动(PC)",
767 "Enabled": "已启用",
721 "Press Send to continue": "按发送键以继续",768 "Press Send to continue": "按发送键以继续",
722 "Show a button in the input area to ask the AI to continue (extend) its last message": "在输入区域中显示一个按钮,要求AI继续(延长)其上一条消息",769 "Show a button in the input area to ask the AI to continue (extend) its last message": "在输入区域中显示一个按钮,要求AI继续(延长)其上一条消息",
723 "Quick 'Continue' button": "快速“继续”按钮",770 "Quick 'Continue' button": "快速“继续”按钮",
@@ -739,9 +786,9 @@
739 "Allow {{user}}: in bot messages": "在机器人消息中允许 {{user}}: ",786 "Allow {{user}}: in bot messages": "在机器人消息中允许 {{user}}: ",
740 "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "跳过消息文本中的编码和字符,允许一部分HTML标记以及Markdown",787 "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "跳过消息文本中的编码和字符,允许一部分HTML标记以及Markdown",
741 "Show tags in responses": "在响应中显示标签",788 "Show tags in responses": "在响应中显示标签",
742 "Allow AI messages in groups to contain lines spoken by other group members": "允许群组中的AI消息包含其他组成员说的话",789 "Allow AI messages in groups to contain lines spoken by other group members": "允许群聊中的AI输出群中其他成员说的话",
743 "Relax message trim in Groups": "放松群组中的消息修剪",790 "Relax message trim in Groups": "减轻群聊中的消息修剪",
744 "Log prompts to console": "将提示词记录到控制台",791 "Log prompts to console": "将提示词输出到控制台",
745 "Requests logprobs from the API for the Token Probabilities feature": "从API请求对数概率数据,用于实现词符概率功能。",792 "Requests logprobs from the API for the Token Probabilities feature": "从API请求对数概率数据,用于实现词符概率功能。",
746 "Request token probabilities": "请求词符概率",793 "Request token probabilities": "请求词符概率",
747 "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群聊中,突出显示当前排队等待生成响应的角色以及他们响应的顺序。",794 "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群聊中,突出显示当前排队等待生成响应的角色以及他们响应的顺序。",
@@ -751,10 +798,13 @@
751 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效",798 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效",
752 "Minimum generated message length": "生成的消息的最小长度",799 "Minimum generated message length": "生成的消息的最小长度",
753 "If the generated message is shorter than this, trigger an auto-swipe": "如果生成的消息短于此长度,则触发自动滑动",800 "If the generated message is shorter than this, trigger an auto-swipe": "如果生成的消息短于此长度,则触发自动滑动",
754 "Blacklisted words": "黑名单词语",801 "Blacklisted words": "屏蔽词",
755 "words you dont want generated separated by comma ','": "不想生成的词语,用逗号','分隔",802 "words you dont want generated separated by comma ','": "不想生成的词语,用半角逗号“,”分隔",
756 "Blacklisted word count to swipe": "触发滑动的黑名单词语数量",803 "Blacklisted word count to swipe": "触发滑动的黑名单词语数量",
757 "Minimum number of blacklisted words detected to trigger an auto-swipe": "触发自动滑动刷新回复所需检测到的最少违禁词数量。",804 "Minimum number of blacklisted words detected to trigger an auto-swipe": "触发自动滑动刷新回复所需检测到的最少违禁词数量。",
805 "Auto-Continue": "自动继续",
806 "Allow for Chat Completion APIs": "允许使用聊天补全API",
807 "Target length (tokens)": "目标长度(以词符数计)",
758 "AutoComplete Settings": "自动补全设置",808 "AutoComplete Settings": "自动补全设置",
759 "Automatically hide details": "自动隐藏详细信息",809 "Automatically hide details": "自动隐藏详细信息",
760 "Determines how entries are found for autocomplete.": "确定如何找到自动补全的条目。",810 "Determines how entries are found for autocomplete.": "确定如何找到自动补全的条目。",
@@ -784,7 +834,14 @@
784 "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} {{getglobalvar::}} 宏具有自动评估的文字宏类值。\n例如,“{{newline}}”保留为文字字符串“{{newline}}”\n\n(这是通过在内部用范围变量替换 {{getvar::}} {{getglobalvar::}} 宏来实现的。)",834 "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} {{getglobalvar::}} 宏具有自动评估的文字宏类值。\n例如,“{{newline}}”保留为文字字符串“{{newline}}”\n\n(这是通过在内部用范围变量替换 {{getvar::}} {{getglobalvar::}} 宏来实现的。)",
785 "REPLACE_GETVAR": "替换GETVAR",835 "REPLACE_GETVAR": "替换GETVAR",
786 "Change Background Image": "更改背景图片",836 "Change Background Image": "更改背景图片",
837 "Background Image": "背景图片",
787 "Filter": "搜索",838 "Filter": "搜索",
839 "Background Fitting": "Background Fitting",
840 "Classic": "Classic",
841 "Cover": "Cover",
842 "Contain": "Contain",
843 "Stretch": "Stretch",
844 "Center": "Center",
788 "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景",845 "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景",
789 "Auto-select": "自动选择",846 "Auto-select": "自动选择",
790 "System Backgrounds": "系统背景",847 "System Backgrounds": "系统背景",
@@ -801,7 +858,6 @@
801 "Extras API URL": "附加 API URL",858 "Extras API URL": "附加 API URL",
802 "Extras API key (optional)": "扩展API密钥(可选)",859 "Extras API key (optional)": "扩展API密钥(可选)",
803 "Persona Management": "用户角色管理",860 "Persona Management": "用户角色管理",
804 "How do I use this?": "怎样使用?",
805 "Click for stats!": "点击查看统计!",861 "Click for stats!": "点击查看统计!",
806 "Usage Stats": "使用统计",862 "Usage Stats": "使用统计",
807 "Backup your personas to a file": "将用户角色备份到文件中",863 "Backup your personas to a file": "将用户角色备份到文件中",
@@ -810,17 +866,18 @@
810 "Restore": "恢复",866 "Restore": "恢复",
811 "Create a dummy persona": "创建空白用户角色",867 "Create a dummy persona": "创建空白用户角色",
812 "Create": "创建",868 "Create": "创建",
813 "Toggle grid view": "切换网格视图",
814 "No persona description": "[没有描述]",869 "No persona description": "[没有描述]",
815 "Name": "名称",870 "Name": "名称",
816 "Enter your name": "输入您的名字",871 "Enter your name": "输入您的名字",
817 "Click to set a new User Name": "点击设置新的用户名",872 "Click to set a new User Name": "点击设置新的用户名",
818 "Click to lock your selected persona to the current chat. Click again to remove the lock.": "单击以将您选择的用户角色锁定到当前聊天。再次单击以移除锁定。",873 "Click to lock your selected persona to the current chat. Click again to remove the lock.": "单击以将您选择的用户角色锁定到当前聊天。再次单击以移除锁定。",
819 "Click to set user name for all messages": "点击为所有消息设置用户名",874 "Click to set user name for all messages": "点击为所有消息设置用户名",
875 "Persona Lore Alt+Click to open the lorebook": "Persona Lore\nAlt+Click to open the lorebook",
820 "Persona Description": "用户角色描述",876 "Persona Description": "用户角色描述",
821 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "示例:[{{user}}是一个28岁的罗马尼亚猫娘。]",877 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "示例:[{{user}}是一个28岁的罗马尼亚猫娘。]",
822 "Tokens persona description": "用户角色描述词符数",878 "Tokens persona description": "用户角色描述词符数",
823 "Position:": "位置:",879 "Position:": "位置:",
880 "None (disabled)": "无(已禁用)",
824 "In Story String / Prompt Manager": "在故事字符串/提示词管理器中",881 "In Story String / Prompt Manager": "在故事字符串/提示词管理器中",
825 "Top of Author's Note": "作者注的顶部",882 "Top of Author's Note": "作者注的顶部",
826 "Bottom of Author's Note": "作者注的底部",883 "Bottom of Author's Note": "作者注的底部",
@@ -848,8 +905,8 @@
848 "Click to select a new avatar for this character": "单击以为此角色选择新的头像",905 "Click to select a new avatar for this character": "单击以为此角色选择新的头像",
849 "Add to Favorites": "添加到收藏夹",906 "Add to Favorites": "添加到收藏夹",
850 "Advanced Definition": "高级定义",907 "Advanced Definition": "高级定义",
851 "Character Lore": "角色世界书",908 "world_button_title": "Character Lore\n\nClick to load\nShift-click to open 'Link to World Info' popup",
852 "Chat Lore": "聊天知识",909 "Chat Lore Alt+Click to open the lorebook": "Chat Lore\nAlt+Click to open the lorebook",
853 "Export and Download": "导出并下载",910 "Export and Download": "导出并下载",
854 "Duplicate Character": "复制角色",911 "Duplicate Character": "复制角色",
855 "Create Character": "创建角色",912 "Create Character": "创建角色",
@@ -877,10 +934,12 @@
877 "This will be the first message from the character that starts every chat.": "这将是角色在每次聊天开始时发送的第一条消息。",934 "This will be the first message from the character that starts every chat.": "这将是角色在每次聊天开始时发送的第一条消息。",
878 "Group Controls": "群聊控制",935 "Group Controls": "群聊控制",
879 "Chat Name (Optional)": "聊天名称(可选)",936 "Chat Name (Optional)": "聊天名称(可选)",
880 "Click to select a new avatar for this group": "单击以为该群组选择新的头像",937 "Chat Lore": "聊天知识",
938 "Click to select a new avatar for this group": "单击选择该群聊的新头像",
881 "Group reply strategy": "群聊回复策略",939 "Group reply strategy": "群聊回复策略",
940 "Manual": "手动",
882 "Natural order": "自然顺序",941 "Natural order": "自然顺序",
883 "List order": "列表顺序",942 "List order": "上下顺序",
884 "Group generation handling mode": "群组生成处理模式",943 "Group generation handling mode": "群组生成处理模式",
885 "Swap character cards": "交换角色卡",944 "Swap character cards": "交换角色卡",
886 "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)",945 "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)",
@@ -890,7 +949,7 @@
890 "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)": "当选择“合并角色卡”时,角色的所有相应字段将被合并在一起。这意味着在故事字符串中,例如,所有角色描述都将合并为一个大文本。如果您希望将这些字段分开,可以在此处定义前缀或后缀。此值支持普通宏,还会将 {{char}} 替换为相关角色的名称,将 <FIELDNAME> 替换为部分的名称(例如:描述、个性、场景等)",949 "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)": "当选择“合并角色卡”时,角色的所有相应字段将被合并在一起。这意味着在故事字符串中,例如,所有角色描述都将合并为一个大文本。如果您希望将这些字段分开,可以在此处定义前缀或后缀。此值支持普通宏,还会将 {{char}} 替换为相关角色的名称,将 <FIELDNAME> 替换为部分的名称(例如:描述、个性、场景等)",
891 "Inserted after each part of the joined fields.": "插入到加入字段的每个部分之后。",950 "Inserted after each part of the joined fields.": "插入到加入字段的每个部分之后。",
892 "Join Suffix": "加入后缀",951 "Join Suffix": "加入后缀",
893 "Set a group chat scenario": "设置群组聊天场景",952 "Set a group chat scenario": "设置群聊背景",
894 "Click to allow/forbid the use of external media for this group.": "单击以允许/禁止该组使用外部媒体。",953 "Click to allow/forbid the use of external media for this group.": "单击以允许/禁止该组使用外部媒体。",
895 "Restore collage avatar": "恢复拼贴头像",954 "Restore collage avatar": "恢复拼贴头像",
896 "Allow self responses": "允许自我回复",955 "Allow self responses": "允许自我回复",
@@ -902,7 +961,7 @@
902 "Create New Character": "新建角色",961 "Create New Character": "新建角色",
903 "Import Character from File": "从文件导入角色",962 "Import Character from File": "从文件导入角色",
904 "Import content from external URL": "从外部URL导入内容",963 "Import content from external URL": "从外部URL导入内容",
905 "Create New Chat Group": "创建新的聊天群组",964 "Create New Chat Group": "创建新的群聊",
906 "Characters sorting order": "角色排序顺序",965 "Characters sorting order": "角色排序顺序",
907 "A-Z": "A-Z",966 "A-Z": "A-Z",
908 "Z-A": "Z-A",967 "Z-A": "Z-A",
@@ -919,6 +978,11 @@
919 "Bulk_edit_characters": "批量编辑角色",978 "Bulk_edit_characters": "批量编辑角色",
920 "Bulk select all characters": "批量选择所有角色",979 "Bulk select all characters": "批量选择所有角色",
921 "Bulk delete characters": "批量删除角色",980 "Bulk delete characters": "批量删除角色",
981 "Bind user name to that avatar": "将用户名称绑定到该头像",
982 "Change persona image": "更改用户角色头像",
983 "Select this as default persona for the new chats.": "选择此项作为新聊天的默认用户角色。",
984 "Duplicate persona": "复制用户角色",
985 "Delete persona": "删除用户角色",
922 "popup-button-save": "保存",986 "popup-button-save": "保存",
923 "popup-button-yes": "是",987 "popup-button-yes": "是",
924 "popup-button-no": "否",988 "popup-button-no": "否",
@@ -937,26 +1001,26 @@
937 "Creator's Metadata": "创作者的元数据",1001 "Creator's Metadata": "创作者的元数据",
938 "(Not sent with the AI Prompt)": "(不随 AI 提示词发送)",1002 "(Not sent with the AI Prompt)": "(不随 AI 提示词发送)",
939 "Everything here is optional": "这里的一切都是可选的",1003 "Everything here is optional": "这里的一切都是可选的",
940 "(Botmaker's name / Contact Info)": "(角色制作者的姓名/联系信息)",1004 "(Botmaker's name / Contact Info)": "(角色制作者的姓名/联系信息)",
941 "(If you want to track character versions)": "(如果您想跟踪角色版本)",1005 "(If you want to track character versions)": "(如果您想跟踪角色版本)",
942 "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(描述角色,提供使用技巧,或列出已经测试过的聊天模型。这将显示在角色列表中。)",1006 "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(描述角色,提供使用技巧,或列出已经测试过的聊天模型。这将显示在角色列表中。)",
943 "Tags to Embed": "嵌入的标签",1007 "Tags to Embed": "嵌入的标签",
944 "(Write a comma-separated list of tags)": "(编写一个以逗号分隔的标签列表。)",1008 "(Write a comma-separated list of tags)": "(编写一个以逗号分隔的标签列表。)",
945 "Personality summary": "角色设定摘要",1009 "Personality summary": "角色设定摘要",
946 "(A brief description of the personality)": "(角色设定的简要描述)",1010 "(A brief description of the personality)": "(角色设定的简要描述)",
947 "Scenario": "情景",1011 "Scenario": "情景",
948 "(Circumstances and context of the interaction)": "(交互的情况和背景)",1012 "(Circumstances and context of the interaction)": "(交互的情况和背景)",
949 "Character's Note": "角色备注",1013 "Character's Note": "角色备注",
950 "(Text to be inserted in-chat @ designated depth and role)": "(文本将插入聊天中指定的深度和角色)",1014 "(Text to be inserted in-chat @ designated depth and role)": "(文本将插入聊天中指定的深度和角色)",
951 "@ Depth": "@ 深度",1015 "@ Depth": "@ 深度",
952 "Role": "角色",1016 "Role": "角色",
953 "Talkativeness": "健谈度",1017 "Talkativeness": "发言频率",
954 "How often the character speaks in group chats!": "角色在群聊中说话的频率!",1018 "How often the character speaks in group chats!": "角色在群聊中发言的频率!",
955 "How often the character speaks in": "角色说话的频率",1019 "How often the character speaks in": "角色发言的频率",
956 "group chats!": "群聊中!",1020 "group chats!": "群聊中!",
957 "Shy": "害羞",1021 "Shy": "低",
958 "Normal": "普通",1022 "Normal": "正常",
959 "Chatty": "话多",1023 "Chatty": "高",
960 "Examples of dialogue": "对话示例",1024 "Examples of dialogue": "对话示例",
961 "Important to set the character's writing style.": "设置角色的写作风格,很重要!",1025 "Important to set the character's writing style.": "设置角色的写作风格,很重要!",
962 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天对话的示例,每个示例都另起一行以<START>开头。)",1026 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天对话的示例,每个示例都另起一行以<START>开头。)",
@@ -965,12 +1029,9 @@
965 "Import Chat": "导入聊天",1029 "Import Chat": "导入聊天",
966 "Copy to system backgrounds": "复制到系统背景",1030 "Copy to system backgrounds": "复制到系统背景",
967 "Rename background": "重命名背景",1031 "Rename background": "重命名背景",
968 "Lock": "加锁",1032 "Lock": "锁定",
969 "Unlock": "解锁",1033 "Unlock": "解锁",
970 "Delete background": "删除背景",1034 "Delete background": "删除背景",
971 "Chat Lorebook": "聊天知识书",
972 "Chat Lorebook for": "聊天知识书",
973 "chat_world_template_txt": "选定的世界信息将绑定到此聊天。生成 AI 回复时,\n它将与全球和角色传说书中的条目相结合。",
974 "Select a World Info file for": "选择一个世界书文件给",1035 "Select a World Info file for": "选择一个世界书文件给",
975 "Primary Lorebook": "主要知识书",1036 "Primary Lorebook": "主要知识书",
976 "A selected World Info will be bound to this character as its own Lorebook.": "所选的世界信息将会于该角色绑定,作为该角色自己的知识书",1037 "A selected World Info will be bound to this character as its own Lorebook.": "所选的世界信息将会于该角色绑定,作为该角色自己的知识书",
@@ -980,18 +1041,17 @@
980 "Associate one or more auxillary Lorebooks with this character.": "将一个或多个辅助知识书与此角色关联。",1041 "Associate one or more auxillary Lorebooks with this character.": "将一个或多个辅助知识书与此角色关联。",
981 "NOTE: These choices are optional and won't be preserved on character export!": "注意:这些选项是可选的,并且不会在角色导出时被一并导出!",1042 "NOTE: These choices are optional and won't be preserved on character export!": "注意:这些选项是可选的,并且不会在角色导出时被一并导出!",
982 "Rename chat file": "重命名聊天文件",1043 "Rename chat file": "重命名聊天文件",
983 "Export JSONL chat file": "导出JSONL聊天文件",1044 "Export JSONL chat file": "导出 .JSONL 聊天文件",
984 "Download chat as plain text document": "将聊天下载为纯文本文档",1045 "Download chat as plain text document": "将聊天下载为纯文本文档",
985 "Delete chat file": "删除聊天文件",1046 "Delete chat file": "删除聊天文件",
986 "Drag to reorder tag": "拖动以排序",1047 "Drag to reorder tag": "拖动以排序",
987 "Use tag as folder": "标记为文件夹",1048 "Use tag as folder": "标记为文件夹",
988 "Delete tag": "删除标签",1049 "Delete tag": "删除标签",
989 "Entry Title/Memo": "条目标题/备忘录",1050 "Entry Title/Memo": "条目标题/备忘录",
990 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "世界信息条目状态:🔵 常量 🟢 正常 🔗 矢量化 ❌ 已禁用",1051 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界书条目状态:\r🔵 永久\r🟢 关键词\r🔗 向量化",
991 "WI_Entry_Status_Constant": "常量",1052 "WI_Entry_Status_Constant": "永久",
992 "WI_Entry_Status_Normal": "普通",1053 "WI_Entry_Status_Normal": "关键词",
993 "WI_Entry_Status_Vectorized": "矢量化",1054 "WI_Entry_Status_Vectorized": "向量化",
994 "WI_Entry_Status_Disabled": "禁用",
995 "T_Position": "↑Char:在角色定义之前\n↓Char:在角色定义之后\n↑AN:在作者注释之前\n↓AN:在作者注释之后\n@D:在深度D处",1055 "T_Position": "↑Char:在角色定义之前\n↓Char:在角色定义之后\n↑AN:在作者注释之前\n↓AN:在作者注释之后\n@D:在深度D处",
996 "Before Char Defs": "角色定义之前",1056 "Before Char Defs": "角色定义之前",
997 "After Char Defs": "角色定义之后",1057 "After Char Defs": "角色定义之后",
@@ -1006,7 +1066,6 @@
1006 "Order:": "顺序:",1066 "Order:": "顺序:",
1007 "Order": "顺序",1067 "Order": "顺序",
1008 "Trigger %:": "触发 %:",1068 "Trigger %:": "触发 %:",
1009 "Probability": "可能性",
1010 "Duplicate world info entry": "重复的世界信息条目",1069 "Duplicate world info entry": "重复的世界信息条目",
1011 "Delete world info entry": "删除世界信息条目",1070 "Delete world info entry": "删除世界信息条目",
1012 "Comma separated (required)": "逗号分隔(必填)",1071 "Comma separated (required)": "逗号分隔(必填)",
@@ -1025,15 +1084,20 @@
1025 "Comma separated list (ignored if empty)": "逗号分隔列表(如果为空则忽略)",1084 "Comma separated list (ignored if empty)": "逗号分隔列表(如果为空则忽略)",
1026 "Use global setting": "使用全局设置",1085 "Use global setting": "使用全局设置",
1027 "Case-Sensitive": "区分大小写",1086 "Case-Sensitive": "区分大小写",
1087 "Use global": "使用全局",
1028 "Yes": "是",1088 "Yes": "是",
1029 "No": "否",1089 "No": "否",
1090 "Whole Words": "Whole Words",
1091 "Group Scoring": "Group Scoring",
1030 "Can be used to automatically activate Quick Replies": "可用于自动激活快速回复",1092 "Can be used to automatically activate Quick Replies": "可用于自动激活快速回复",
1031 "Automation ID": "自动化ID",1093 "Automation ID": "自动化ID",
1032 "( None )": "( 没有任何 )",1094 "( None )": "(没有任何)",
1095 "delay_until_recursion_level": "Defines delay levels for recursive scans.\r\rInitially, only the first level (smallest number) will match.\rOnce no matches are found, the next level becomes eligible for matching.\rThis repeats until all levels are checked.\r\rTied to the \"Delay until recursion\" setting.",
1096 "Recursion Level": "递归等级",
1033 "Content": "内容",1097 "Content": "内容",
1034 "Exclude from recursion": "从递归中排除",1098 "Non-recursable (will not be activated by another)": "不可递归(不会被其他条目激活)",
1035 "Prevent further recursion (this entry will not activate others)": "防止进一步递归(本条目将不会激活其他条目)",1099 "Prevent further recursion (this entry will not activate others)": "防止进一步递归(本条目将不会激活其他条目)",
1036 "Delay until recursion (this entry can only be activated on recursive checking)": "延迟到递归(本条目只能在递归检查时激活)",1100 "Delay until recursion (can only be activated on recursive checking)": "延迟到递归(本条目只能在递归检查时激活)",
1037 "What this keyword should mean to the AI, sent verbatim": "这个关键词对AI的含义,逐字发送",1101 "What this keyword should mean to the AI, sent verbatim": "这个关键词对AI的含义,逐字发送",
1038 "Inclusion Group": "包含组",1102 "Inclusion Group": "包含组",
1039 "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "包含组可确保每次仅激活组中的一项(如果触发了多项)。支持多个逗号分隔的组。文档:世界信息 - 包含组",1103 "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "包含组可确保每次仅激活组中的一项(如果触发了多项)。支持多个逗号分隔的组。文档:世界信息 - 包含组",
@@ -1048,8 +1112,9 @@
1048 "Cooldown": "冷却",1112 "Cooldown": "冷却",
1049 "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。",1113 "Entries with a delay can't be activated until there are N messages present in the chat.": "直到聊天中出现 N 条消息时,延迟的条目才能被激活。",
1050 "Delay": "延迟",1114 "Delay": "延迟",
1051 "Filter to Character(s)": "应用到角色",1115 "Filter to Characters or Tags": "应用到角色或标签",
1052 "Character Exclusion": "反选角色",1116 "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外",
1117 "Exclude": "排除",
1053 "-- Characters not found --": "-- 未找到角色 --",1118 "-- Characters not found --": "-- 未找到角色 --",
1054 "Selective": "选择性",1119 "Selective": "选择性",
1055 "Use Probability": "使用概率",1120 "Use Probability": "使用概率",
@@ -1068,6 +1133,7 @@
1068 "prompt_manager_in_chat": "聊天中",1133 "prompt_manager_in_chat": "聊天中",
1069 "prompt_manager_depth": "深度",1134 "prompt_manager_depth": "深度",
1070 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最后一条消息之后,1 = 在最后一条消息之前,等等。",1135 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最后一条消息之后,1 = 在最后一条消息之前,等等。",
1136 "The content of this prompt is pulled from elsewhere and cannot be edited here.": "The content of this prompt is pulled from elsewhere and cannot be edited here.",
1071 "Prompt": "提示词",1137 "Prompt": "提示词",
1072 "The prompt to be sent.": "要发送的提示词。",1138 "The prompt to be sent.": "要发送的提示词。",
1073 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。",1139 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。",
@@ -1085,7 +1151,7 @@
1085 "Create checkpoint": "创建检查点",1151 "Create checkpoint": "创建检查点",
1086 "Create Branch": "创建分支",1152 "Create Branch": "创建分支",
1087 "Copy": "复制",1153 "Copy": "复制",
1088 "Open checkpoint chat": "打开检查点聊天",1154 "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "点击打开检查点聊天\nShift+单击来覆盖已有检查点",
1089 "Edit": "编辑",1155 "Edit": "编辑",
1090 "Confirm": "确认",1156 "Confirm": "确认",
1091 "Copy this message": "复制此消息",1157 "Copy this message": "复制此消息",
@@ -1094,7 +1160,10 @@
1094 "Move message down": "将消息下移",1160 "Move message down": "将消息下移",
1095 "Enlarge": "放大",1161 "Enlarge": "放大",
1096 "Caption": "标题",1162 "Caption": "标题",
1163 "Swipe left": "Swipe left",
1164 "Swipe right": "Swipe right",
1097 "Welcome to SillyTavern!": "欢迎来到 SillyTavern!",1165 "Welcome to SillyTavern!": "欢迎来到 SillyTavern!",
1166 "SillyTavern is aimed at advanced users.": "SillyTavern 面向高级用户。",
1098 "welcome_message_part_1": "阅读",1167 "welcome_message_part_1": "阅读",
1099 "welcome_message_part_2": "官方文档",1168 "welcome_message_part_2": "官方文档",
1100 "welcome_message_part_3": "。",1169 "welcome_message_part_3": "。",
@@ -1103,10 +1172,6 @@
1103 "welcome_message_part_6": "加入",1172 "welcome_message_part_6": "加入",
1104 "Discord server": "Discord 服务器",1173 "Discord server": "Discord 服务器",
1105 "welcome_message_part_7": "了解信息和公告。",1174 "welcome_message_part_7": "了解信息和公告。",
1106 "SillyTavern is aimed at advanced users.": "SillyTavern 面向高级用户。",
1107 "If you're new to this, enable the simplified UI mode below.": "如果您是新手,请启用下面的简化 UI 模式。",
1108 "Change it later in the 'User Settings' panel.": "稍后在“用户设置”面板中更改它。",
1109 "Enable simple UI mode": "启用简单 UI 模式",
1110 "Looking for AI characters?": "正在寻找 AI 角色?",1175 "Looking for AI characters?": "正在寻找 AI 角色?",
1111 "onboarding_import": "导入",1176 "onboarding_import": "导入",
1112 "from supported sources or view": "来自受支持的来源或查看",1177 "from supported sources or view": "来自受支持的来源或查看",
@@ -1122,16 +1187,17 @@
1122 "Move up": "向上移动",1187 "Move up": "向上移动",
1123 "Move down": "向下移动",1188 "Move down": "向下移动",
1124 "View character card": "查看角色卡片",1189 "View character card": "查看角色卡片",
1125 "Remove from group": "从群组中移除",1190 "Remove from group": "踢出群聊",
1126 "Add to group": "添加到群组中",1191 "Add to group": "拉入群聊",
1127 "Alternate Greetings": "额外问候语",1192 "Alternate Greetings": "额外问候语",
1128 "Alternate_Greetings_desc": "开始新聊天时,这些按钮将显示为第一条消息的滑动选项。\n群组成员可以选择其中之一来发起对话。",1193 "Alternate_Greetings_desc": "开始新聊天时,这些按钮将显示为第一条消息的滑动选项。\n群成员可以选择其中之一来发起对话。",
1129 "alternate_greetings_hint_1": "点击",1194 "alternate_greetings_hint_1": "点击",
1130 "alternate_greetings_hint_2": "按钮即可开始!",1195 "alternate_greetings_hint_2": "按钮即可开始!",
1131 "Alternate Greeting #": "额外问候语 #",1196 "Alternate Greeting #": "额外问候语 #",
1132 "(This will be the first message from the character that starts every chat)": "(这将是角色在每次聊天开始时发送的第一条消息)",1197 "(This will be the first message from the character that starts every chat)": "(这是每次聊天开始时角色的第一条消息)",
1133 "View contents": "查看内容",1198 "View contents": "查看内容",
1134 "Remove the file": "删除文件",1199 "Remove the file": "删除文件",
1200 "Author's Note": "作者注释",
1135 "Unique to this chat": "此聊天独有",1201 "Unique to this chat": "此聊天独有",
1136 "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "检查点从其父级继承注释,之后可以单独更改。",1202 "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "检查点从其父级继承注释,之后可以单独更改。",
1137 "Include in World Info Scanning": "纳入世界信息扫描",1203 "Include in World Info Scanning": "纳入世界信息扫描",
@@ -1139,7 +1205,7 @@
1139 "After Main Prompt / Story String": "主提示词/故事线之后",1205 "After Main Prompt / Story String": "主提示词/故事线之后",
1140 "as": "作为",1206 "as": "作为",
1141 "Insertion Frequency": "插入频率",1207 "Insertion Frequency": "插入频率",
1142 "(0 = Disable, 1 = Always)": "(0 = 禁用,1 = 始终)",1208 "(0 = Disable, 1 = Always)": "(“0”为禁用,“1”为始终)",
1143 "User inputs until next insertion:": "用户输入直到下一次插入:",1209 "User inputs until next insertion:": "用户输入直到下一次插入:",
1144 "Character Author's Note (Private)": "人物作者注(私有)",1210 "Character Author's Note (Private)": "人物作者注(私有)",
1145 "Won't be shared with the character card on export.": "导出时不会与角色卡共享。",1211 "Won't be shared with the character card on export.": "导出时不会与角色卡共享。",
@@ -1149,7 +1215,7 @@
1149 "Default Author's Note": "默认作者注",1215 "Default Author's Note": "默认作者注",
1150 "Will be automatically added as the Author's Note for all new chats.": "将自动添加为所有新聊天的作者注释。",1216 "Will be automatically added as the Author's Note for all new chats.": "将自动添加为所有新聊天的作者注释。",
1151 "Chat CFG": "聊天CFG",1217 "Chat CFG": "聊天CFG",
1152 "1 = disabled": "1 = 已禁用",1218 "1 = disabled": "“1”为已禁用",
1153 "write short replies, write replies using past tense": "写简短的回复,用过去时写回复",1219 "write short replies, write replies using past tense": "写简短的回复,用过去时写回复",
1154 "Positive Prompt": "正面提示词",1220 "Positive Prompt": "正面提示词",
1155 "Use character CFG scales": "单独为各个角色设置CFG缩放",1221 "Use character CFG scales": "单独为各个角色设置CFG缩放",
@@ -1168,6 +1234,7 @@
1168 "Insertion Depth:": "插入深度:",1234 "Insertion Depth:": "插入深度:",
1169 "Token Probabilities": "词符概率",1235 "Token Probabilities": "词符概率",
1170 "Select a token to see alternatives considered by the AI.": "选择一个词符来查看 AI 考虑的替代方案。",1236 "Select a token to see alternatives considered by the AI.": "选择一个词符来查看 AI 考虑的替代方案。",
1237 "Reroll with the entire prefix": "Reroll with the entire prefix",
1171 "Not connected to API!": "未连接到API!",1238 "Not connected to API!": "未连接到API!",
1172 "Type a message, or /? for help": "键入消息,或 /? 获取帮助",1239 "Type a message, or /? for help": "键入消息,或 /? 获取帮助",
1173 "Continue script execution": "继续执行脚本",1240 "Continue script execution": "继续执行脚本",
@@ -1179,6 +1246,7 @@
1179 "Send a message": "发送消息",1246 "Send a message": "发送消息",
1180 "Close chat": "关闭聊天",1247 "Close chat": "关闭聊天",
1181 "Toggle Panels": "切换面板",1248 "Toggle Panels": "切换面板",
1249 "CFG Scale": "CFG缩放",
1182 "Back to parent chat": "返回到父级聊天",1250 "Back to parent chat": "返回到父级聊天",
1183 "Save checkpoint": "保存检查点",1251 "Save checkpoint": "保存检查点",
1184 "Convert to group": "转换为群聊",1252 "Convert to group": "转换为群聊",
@@ -1188,11 +1256,6 @@
1188 "Regenerate": "重新生成",1256 "Regenerate": "重新生成",
1189 "Impersonate": "AI 帮答",1257 "Impersonate": "AI 帮答",
1190 "Continue": "继续",1258 "Continue": "继续",
1191 "Bind user name to that avatar": "将用户名称绑定到该头像",
1192 "Change persona image": "更改用户角色头像",
1193 "Select this as default persona for the new chats.": "选择此项作为新聊天的默认用户角色。",
1194 "Duplicate persona": "复制用户角色",
1195 "Delete persona": "删除用户角色",
1196 "These characters are the winners of character design contests and have outstandable quality.": "这些角色都是角色设计大赛的获奖者,品质非常出色。",1259 "These characters are the winners of character design contests and have outstandable quality.": "这些角色都是角色设计大赛的获奖者,品质非常出色。",
1197 "Contest Winners": "比赛获胜者",1260 "Contest Winners": "比赛获胜者",
1198 "These characters are the finalists of character design contests and have remarkable quality.": "这些角色都是角色设计大赛的入围作品,品质十分出色。",1261 "These characters are the finalists of character design contests and have remarkable quality.": "这些角色都是角色设计大赛的入围作品,品质十分出色。",
@@ -1261,18 +1324,30 @@
1261 "macro)": "宏指令)",1324 "macro)": "宏指令)",
1262 "Automatically caption images": "自动为图像添加标题",1325 "Automatically caption images": "自动为图像添加标题",
1263 "Edit captions before saving": "保存前编辑标题",1326 "Edit captions before saving": "保存前编辑标题",
1327 "Profile name:": "配置名称:",
1328 "Creating a Connection Profile": "新建API连接配置",
1329 "{{@key}}": "{{@key}}:",
1330 "Enter a name:": "输入名字:",
1331 "Connection Profile": "API连接配置",
1332 "View connection profile details": "查看API连接配置详情",
1333 "Create a new connection profile": "新建一个API连接配置",
1334 "Update a connection profile": "更新API连接配置",
1335 "Edit a connection profile": "编辑API连接配置",
1336 "Reload a connection profile": "重载API连接配置",
1337 "Delete a connection profile": "删除API连接配置",
1338 "Omitted Settings:": "Omitted Settings:",
1264 "Character Expressions": "角色表情",1339 "Character Expressions": "角色表情",
1265 "Translate text to English before classification": "分类之前将文本翻译成英文",1340 "Translate text to English before classification": "分类之前将文本翻译成英文",
1266 "Show default images (emojis) if sprite missing": "如果表情包缺失,则显示默认图像(表情符号)",1341 "Show default images (emojis) if sprite missing": "如果表情包缺失,则显示默认图像(表情符号)",
1267 "Image Type - talkinghead (extras)": "图像类型 - 说话头像(附加内容)",1342 "Image Type - talkinghead (extras)": "图像类型 - 说话头像(附加内容)",
1268 "Classifier API": "分类器 API",1343 "Classifier API": "分类器 API",
1269 "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。",1344 "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。",
1270 "LLM": "大语言模型",1345 "Main API": "主要 API",
1346 "WebLLM Extension": "WebLLM Extension",
1271 "LLM Prompt": "大语言模型提示词",1347 "LLM Prompt": "大语言模型提示词",
1272 "Will be used if the API doesn't support JSON schemas or function calling.": "如果 API 不支持 JSON 模式或函数调用,则会使用它。",1348 "Will be used if the API doesn't support JSON schemas or function calling.": "如果 API 不支持 JSON 模式或函数调用,则会使用它。",
1273 "Default / Fallback Expression": "默认/后备表达式",1349 "Default / Fallback Expression": "默认/后备表达式",
1274 "Set the default and fallback expression being used when no matching expression is found.": "设置在未找到匹配表达式时使用的默认表达式和后备表达式。",1350 "Set the default and fallback expression being used when no matching expression is found.": "设置在未找到匹配表达式时使用的默认表达式和后备表达式。",
1275 "Fallback Expression": "后备表达式",
1276 "Custom Expressions": "自定义表达式",1351 "Custom Expressions": "自定义表达式",
1277 "Can be set manually or with an _space": "可以手动设置或使用",1352 "Can be set manually or with an _space": "可以手动设置或使用",
1278 "space_ slash command.": "快捷命令来设置。",1353 "space_ slash command.": "快捷命令来设置。",
@@ -1291,10 +1366,11 @@
1291 "ext_sum_title": "总结",1366 "ext_sum_title": "总结",
1292 "ext_sum_with": "总结如下:",1367 "ext_sum_with": "总结如下:",
1293 "ext_sum_main_api": "主要 API",1368 "ext_sum_main_api": "主要 API",
1369 "ext_sum_webllm": "WebLLM 扩展",
1294 "ext_sum_current_summary": "当前摘要:",1370 "ext_sum_current_summary": "当前摘要:",
1371 "ext_sum_restore_tip": "恢复先前的摘要;重复使用以清除此聊天的摘要状态",
1295 "ext_sum_restore_previous": "恢复上一个",1372 "ext_sum_restore_previous": "恢复上一个",
1296 "ext_sum_memory_placeholder": "摘要将在这里生成...",1373 "ext_sum_memory_placeholder": "摘要将在这里生成...",
1297 "ext_sum_restore_tip": "恢复先前的摘要;重复使用以清除此聊天的摘要状态",
1298 "ext_sum_force_tip": "立即触发摘要更新。",1374 "ext_sum_force_tip": "立即触发摘要更新。",
1299 "ext_sum_force_text": "现在总结",1375 "ext_sum_force_text": "现在总结",
1300 "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "禁用自动摘要更新。暂停时,摘要保持原样。您仍然可以通过按“立即汇总”按钮(仅适用于主 API)强制更新。",1376 "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "禁用自动摘要更新。暂停时,摘要保持原样。您仍然可以通过按“立即汇总”按钮(仅适用于主 API)强制更新。",
@@ -1319,13 +1395,13 @@
1319 "ext_sum_api_response_length_1": "API 响应长度",1395 "ext_sum_api_response_length_1": "API 响应长度",
1320 "ext_sum_api_response_length_2": "(",1396 "ext_sum_api_response_length_2": "(",
1321 "ext_sum_api_response_length_3": "个词符)",1397 "ext_sum_api_response_length_3": "个词符)",
1322 "ext_sum_0_default": "0 = 默认",1398 "ext_sum_0_default": "“0”为默认",
1323 "ext_sum_raw_max_msg": "[原始] 每个请求的最大消息数",1399 "ext_sum_raw_max_msg": "[原始] 每个请求的最大消息数",
1324 "ext_sum_0_unlimited": "0 = 无限制",1400 "ext_sum_0_unlimited": "“0”为无限制",
1325 "Update frequency": "更新频率",1401 "Update frequency": "更新频率",
1326 "ext_sum_update_every_messages_1": "更新间隔",1402 "ext_sum_update_every_messages_1": "更新间隔",
1327 "ext_sum_update_every_messages_2": "消息",1403 "ext_sum_update_every_messages_2": "消息",
1328 "ext_sum_0_disable": "0 = 禁用",1404 "ext_sum_0_disable": "“0”为禁用",
1329 "ext_sum_auto_adjust_desc": "尝试根据聊天指标自动调整间隔。",1405 "ext_sum_auto_adjust_desc": "尝试根据聊天指标自动调整间隔。",
1330 "ext_sum_update_every_words_1": "更新间隔(",1406 "ext_sum_update_every_words_1": "更新间隔(",
1331 "ext_sum_update_every_words_2": "字)",1407 "ext_sum_update_every_words_2": "字)",
@@ -1346,7 +1422,7 @@
1346 "Message / Command:": "消息/命令:",1422 "Message / Command:": "消息/命令:",
1347 "Word wrap": "自动换行",1423 "Word wrap": "自动换行",
1348 "Tab size:": "标签大小:",1424 "Tab size:": "标签大小:",
1349 "Ctrl+Enter to execute": "Ctrl+Enter 执行",1425 "Ctrl+Enter to execute": "使用 Ctrl+Enter 来执行",
1350 "Context Menu": "上下文菜单",1426 "Context Menu": "上下文菜单",
1351 "Chaining:": "链接:",1427 "Chaining:": "链接:",
1352 "Auto-Execute": "自动执行",1428 "Auto-Execute": "自动执行",
@@ -1356,6 +1432,7 @@
1356 "Execute on user message": "根据用户消息执行",1432 "Execute on user message": "根据用户消息执行",
1357 "Execute on AI message": "根据 AI 消息执行",1433 "Execute on AI message": "根据 AI 消息执行",
1358 "Execute on chat change": "聊天内容改变时执行",1434 "Execute on chat change": "聊天内容改变时执行",
1435 "Execute on new chat": "在新聊天中执行",
1359 "Execute on group member draft": "起草群组成员时执行",1436 "Execute on group member draft": "起草群组成员时执行",
1360 "Automation ID:": "自动化标识",1437 "Automation ID:": "自动化标识",
1361 "Testing": "测试",1438 "Testing": "测试",
@@ -1363,6 +1440,7 @@
1363 "Quick Reply": "快速回复",1440 "Quick Reply": "快速回复",
1364 "Enable Quick Replies": "启用快速回复",1441 "Enable Quick Replies": "启用快速回复",
1365 "Combine Quick Replies": "合并快速回复",1442 "Combine Quick Replies": "合并快速回复",
1443 "Show Popout Button": "(在电脑上)展示弹出式按钮",
1366 "Global Quick Reply Sets": "全局快速回复集",1444 "Global Quick Reply Sets": "全局快速回复集",
1367 "Chat Quick Reply Sets": "聊天快速回复集",1445 "Chat Quick Reply Sets": "聊天快速回复集",
1368 "Edit Quick Replies": "编辑快速回复",1446 "Edit Quick Replies": "编辑快速回复",
@@ -1382,6 +1460,7 @@
1382 "ext_regex_global_scripts": "全局正则脚本",1460 "ext_regex_global_scripts": "全局正则脚本",
1383 "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中",1461 "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中",
1384 "ext_regex_scoped_scripts": "局部正则脚本",1462 "ext_regex_scoped_scripts": "局部正则脚本",
1463 "ext_regex_disallow_scoped": "Disallow using scoped regex",
1385 "ext_regex_allow_scoped": "允许使用范围正则表达式",1464 "ext_regex_allow_scoped": "允许使用范围正则表达式",
1386 "ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中",1465 "ext_regex_scoped_scripts_desc": "只影响当前角色,保存在角色卡片中",
1387 "Regex Editor": "正则表达式编辑器",1466 "Regex Editor": "正则表达式编辑器",
@@ -1398,20 +1477,30 @@
1398 "Trim Out": "修剪掉",1477 "Trim Out": "修剪掉",
1399 "ext_regex_trim_placeholder": "在替换之前全局修剪正则表达式匹配中任何不需要的部分。用回车键分隔每个元素。",1478 "ext_regex_trim_placeholder": "在替换之前全局修剪正则表达式匹配中任何不需要的部分。用回车键分隔每个元素。",
1400 "ext_regex_affects": "影响",1479 "ext_regex_affects": "影响",
1480 "ext_regex_user_input_desc": "用户发送的消息",
1401 "ext_regex_user_input": "用户输入",1481 "ext_regex_user_input": "用户输入",
1482 "ext_regex_ai_input_desc": "从生成式API中获取的信息。",
1402 "ext_regex_ai_output": "AI输出",1483 "ext_regex_ai_output": "AI输出",
1484 "ext_regex_slash_desc": "通过 STscript 命令发送的消息。",
1403 "Slash Commands": "快捷命令",1485 "Slash Commands": "快捷命令",
1404 "ext_regex_min_depth_desc": "当应用于提示或显示时,仅影响深度至少为 N 级的消息。0 = 最后一条消息,1 = 倒数第二条消息等。仅计算 WI 条目 @Depth 和可用消息,即非隐藏或系统消息。",1486 "ext_regex_wi_desc": "知识书/世界书 条目的内容。需要勾选“仅格式提示词”!",
1487 "ext_regex_min_depth_desc": "当应用于提示或显示时,仅影响深度至少为 N 级的消息。“0”为最后一条消息,“1”为倒数第二条消息等。仅计算 WI 条目 @Depth 和可用消息,即非隐藏或系统消息。",
1405 "Min Depth": "最小深度",1488 "Min Depth": "最小深度",
1406 "ext_regex_min_depth_placeholder": "无限",1489 "ext_regex_min_depth_placeholder": "无限",
1407 "ext_regex_max_depth_desc": "当应用于提示词或显示时,仅影响深度不超过 N 级的消息。0 = 最后一条消息,1 = 倒数第二条消息等。仅计算世界信息条目 @Depth 和可用消息,即非隐藏或系统消息。",1490 "ext_regex_max_depth_desc": "当应用于提示词或显示时,仅影响深度不超过 N 级的消息。“0”为最后一条消息,“1”为倒数第二条消息等。仅计算世界信息条目 @Depth 和可用消息,即非隐藏或系统消息。",
1408 "ext_regex_other_options": "其他选项",1491 "ext_regex_other_options": "其他选项",
1492 "ext_regex_run_on_edit_desc": "当指定角色的消息被编辑时运行正则脚本。",
1493 "Run On Edit": "在编辑时运行",
1494 "ext_regex_substitute_regex_desc": "在运行正则表达式查找之前,替换 {{macros}}",
1495 "Macro in Find Regex": "正则表达式查找时的宏",
1496 "Don't substitute": "不替换",
1497 "Substitute (raw)": "替换(原始)",
1498 "Substitute (escaped)": "替换(转义)",
1499 "Ephemerality": "短暂",
1500 "ext_regex_only_format_visual_desc": "正则仅在聊天页面生效,聊天文件内的内容不会被改变。",
1409 "Only Format Display": "仅格式显示",1501 "Only Format Display": "仅格式显示",
1410 "ext_regex_only_format_prompt_desc": "聊天记录不会改变,只有在请求发送时(生成时)才会出现提示词。",1502 "ext_regex_only_format_prompt_desc": "聊天记录不会改变,只有在请求发送时(生成时)才会出现提示词。",
1411 "Only Format Prompt (?)": "仅格式提示词",1503 "Only Format Prompt (?)": "仅格式提示词",
1412 "Run On Edit": "在编辑时运行",
1413 "ext_regex_substitute_regex_desc": "在运行正则表达式查找之前,替换 {{macros}}",
1414 "Substitute Regex": "替代正则表达式",
1415 "ext_regex_import_target": "导入至:",1504 "ext_regex_import_target": "导入至:",
1416 "ext_regex_disable_script": "禁用脚本",1505 "ext_regex_disable_script": "禁用脚本",
1417 "ext_regex_enable_script": "启用脚本",1506 "ext_regex_enable_script": "启用脚本",
@@ -1422,6 +1511,7 @@
1422 "ext_regex_delete_script": "删除脚本",1511 "ext_regex_delete_script": "删除脚本",
1423 "Trigger Stable Diffusion": "触发Stable Diffusion",1512 "Trigger Stable Diffusion": "触发Stable Diffusion",
1424 "Abort current image generation task": "中止当前图像生成",1513 "Abort current image generation task": "中止当前图像生成",
1514 "Stop Image Generation": "停止图像生成",
1425 "sd_Yourself": "你自己",1515 "sd_Yourself": "你自己",
1426 "sd_Your_Face": "你的脸",1516 "sd_Your_Face": "你的脸",
1427 "sd_Me": "我",1517 "sd_Me": "我",
@@ -1432,6 +1522,8 @@
1432 "Image Generation": "图像生成",1522 "Image Generation": "图像生成",
1433 "sd_refine_mode": "允许在将提示词发送到生成 API 之前手动编辑提示词",1523 "sd_refine_mode": "允许在将提示词发送到生成 API 之前手动编辑提示词",
1434 "sd_refine_mode_txt": "生成之前编辑提示词",1524 "sd_refine_mode_txt": "生成之前编辑提示词",
1525 "sd_function_tool": "Use the function tool to automatically detect intents to generate images.",
1526 "sd_function_tool_txt": "Use function tool",
1435 "sd_interactive_mode": "发送消息时自动生成图像,例如“给我发一张猫的照片”。",1527 "sd_interactive_mode": "发送消息时自动生成图像,例如“给我发一张猫的照片”。",
1436 "sd_interactive_mode_txt": "交互模式",1528 "sd_interactive_mode_txt": "交互模式",
1437 "sd_multimodal_captioning": "使用多模式字幕根据用户和角色的头像生成提示词。",1529 "sd_multimodal_captioning": "使用多模式字幕根据用户和角色的头像生成提示词。",
@@ -1439,8 +1531,6 @@
1439 "sd_free_extend": "使用当前选择的 LLM 自动扩展自由模式主题提示(不是肖像或背景)。",1531 "sd_free_extend": "使用当前选择的 LLM 自动扩展自由模式主题提示(不是肖像或背景)。",
1440 "sd_free_extend_txt": "延长自由模式提示",1532 "sd_free_extend_txt": "延长自由模式提示",
1441 "sd_free_extend_small": "(交互/命令)",1533 "sd_free_extend_small": "(交互/命令)",
1442 "sd_expand": "使用文本生成模型自动扩展提示词",
1443 "sd_expand_txt": "自动增强提示词",
1444 "sd_snap": "快照生成请求具有强制纵横比(肖像、背景)到最接近已知分辨率,同时尝试保留绝对像素数(推荐用于 SDXL)。",1534 "sd_snap": "快照生成请求具有强制纵横比(肖像、背景)到最接近已知分辨率,同时尝试保留绝对像素数(推荐用于 SDXL)。",
1445 "sd_snap_txt": "自动调整分辨率",1535 "sd_snap_txt": "自动调整分辨率",
1446 "sd_auto_url": "例如:{{auto_url}}",1536 "sd_auto_url": "例如:{{auto_url}}",
@@ -1451,10 +1541,12 @@
1451 "sd_auto_auth_warning_2": "注意!服务器必须可从 SillyTavern 主机访问。",1541 "sd_auto_auth_warning_2": "注意!服务器必须可从 SillyTavern 主机访问。",
1452 "sd_drawthings_url": "例如:{{drawthings_url}}",1542 "sd_drawthings_url": "例如:{{drawthings_url}}",
1453 "sd_drawthings_auth_txt": "运行 DrawThings 应用程序并在 UI 中启用 HTTP API 开关!必须可以从 SillyTavern 主机访问服务器。",1543 "sd_drawthings_auth_txt": "运行 DrawThings 应用程序并在 UI 中启用 HTTP API 开关!必须可以从 SillyTavern 主机访问服务器。",
1544 "Model ID": "Model ID",
1545 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",
1454 "sd_vlad_url": "例如:{{vlad_url}}",1546 "sd_vlad_url": "例如:{{vlad_url}}",
1455 "The server must be accessible from the SillyTavern host machine.": "必须能够从 SillyTavern 主机访问该服务器。",1547 "The server must be accessible from the SillyTavern host machine.": "必须能够从 SillyTavern 主机访问该服务器。",
1456 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "提示:在 Horde KoboldAI API 设置中保存一个 API 密钥以便在此处使用它。",1548 "Hint: Save an API key in AI Horde API settings to use it here.": "提示:在 Horde AI API 设置中保存一个 API 密钥以便在此处使用它。",
1457 "Allow NSFW images from Horde": "允许 Horde 的 NSFW 图片",1549 "Allow NSFW images from Horde": "允许来自 Horde 的 NSFW 图片",
1458 "Sanitize prompts (recommended)": "净化提示词(推荐)",1550 "Sanitize prompts (recommended)": "净化提示词(推荐)",
1459 "Automatically adjust generation parameters to ensure free image generations.": "自动调整生成参数,确保图像生成自由。",1551 "Automatically adjust generation parameters to ensure free image generations.": "自动调整生成参数,确保图像生成自由。",
1460 "Avoid spending Anlas": "避免花费 Anlas",1552 "Avoid spending Anlas": "避免花费 Anlas",
@@ -1470,18 +1562,18 @@
1470 "Create new workflow": "创建新的工作流",1562 "Create new workflow": "创建新的工作流",
1471 "Delete workflow": "删除工作流",1563 "Delete workflow": "删除工作流",
1472 "Enhance": "提高",1564 "Enhance": "提高",
1473 "Refine": "优化",
1474 "API Key": "API 密钥",1565 "API Key": "API 密钥",
1475 "Click to set": "点击设置",1566 "Click to set": "点击设置",
1476 "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。",1567 "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。",
1477 "Style Preset": "风格预设",1568 "Style Preset": "风格预设",
1569 "Prompt Upsampling": "Prompt Upsampling",
1478 "Sampling method": "采样方法",1570 "Sampling method": "采样方法",
1479 "Scheduler": "调度器",1571 "Scheduler": "调度器",
1480 "Resolution": "分辨率",1572 "Resolution": "分辨率",
1481 "Upscaler": "图像扩大器",1573 "Upscaler": "图像扩大器",
1482 "Sampling steps": "采样步数()",1574 "Sampling steps": "采样步数",
1483 "Width": "宽度()",1575 "Width": "宽度",
1484 "Height": "高度()",1576 "Height": "高度",
1485 "Swap width and height": "交换宽度和高度",1577 "Swap width and height": "交换宽度和高度",
1486 "Upscale by": "扩大倍数",1578 "Upscale by": "扩大倍数",
1487 "Denoising strength": "去噪强度",1579 "Denoising strength": "去噪强度",
@@ -1491,12 +1583,14 @@
1491 "Hires. Fix": "高清修复",1583 "Hires. Fix": "高清修复",
1492 "Karras": "Karras",1584 "Karras": "Karras",
1493 "Not all samplers supported.": "并非所有采样器都受支持。",1585 "Not all samplers supported.": "并非所有采样器都受支持。",
1586 "sd_adetailer_face": "Use ADetailer with face model during the generation. The ADetailer extension must be installed on the backend.",
1587 "Use ADetailer (Face)": "使用 ADetailer (Face)",
1494 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的采样器经过修改,在高分辨率下性能更佳。",1588 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的采样器经过修改,在高分辨率下性能更佳。",
1495 "SMEA": "中小企业协会",1589 "SMEA": "中小企业协会",
1496 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。",1590 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。",
1497 "DYN": "动态",1591 "DYN": "动态",
1498 "Decrisper": "去伪器",1592 "Decrisper": "去伪器",
1499 "(-1 for random)": "(-1 为随机)",1593 "(-1 for random)": "(“-1”为随机)",
1500 "Preset for prompt prefix and negative prompt": "提示词前缀和负面提示词的预设",1594 "Preset for prompt prefix and negative prompt": "提示词前缀和负面提示词的预设",
1501 "Style": "风格",1595 "Style": "风格",
1502 "Save style": "保存风格",1596 "Save style": "保存风格",
@@ -1515,6 +1609,7 @@
1515 "Extensions Menu": "扩展菜单",1609 "Extensions Menu": "扩展菜单",
1516 "Slash Command": "快捷命令",1610 "Slash Command": "快捷命令",
1517 "Interactive Mode": "交互模式",1611 "Interactive Mode": "交互模式",
1612 "Function Tool": "Function Tool",
1518 "Image Prompt Templates": "图像提示模板",1613 "Image Prompt Templates": "图像提示模板",
1519 "ext_translate_btn_chat": "翻译聊天",1614 "ext_translate_btn_chat": "翻译聊天",
1520 "ext_translate_btn_input": "翻译输入",1615 "ext_translate_btn_input": "翻译输入",
@@ -1529,6 +1624,18 @@
1529 "ext_translate_mode_provider": "提供者",1624 "ext_translate_mode_provider": "提供者",
1530 "ext_translate_target_lang": "目标语言",1625 "ext_translate_target_lang": "目标语言",
1531 "ext_translate_clear": "清空设置",1626 "ext_translate_clear": "清空设置",
1627 "Select TTS Provider": "选择 文本转语音 的服务提供商",
1628 "tts_enabled": "已启用",
1629 "Narrate user messages": "朗读用户消息",
1630 "Auto Generation": "Auto Generation",
1631 "Requires auto generation to be enabled.": "Requires auto generation to be enabled.",
1632 "Narrate by paragraphs (when streaming)": "Narrate by paragraphs (when streaming)",
1633 "Only narrate quotes": "只朗读引号内文本",
1634 "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹",
1635 "Narrate only the translated text": "只朗读翻译后文本",
1636 "Skip codeblocks": "跳过代码块",
1637 "Skip tagged blocks": "跳过标签化的块(<tagged>)",
1638 "Pass Asterisks to TTS Engine": "将星号传递给文本转语音服务",
1532 "Audio Playback Speed": "音频播放速度",1639 "Audio Playback Speed": "音频播放速度",
1533 "Vector Storage": "向量存储",1640 "Vector Storage": "向量存储",
1534 "Vectorization Source": "向量化源",1641 "Vectorization Source": "向量化源",
@@ -1537,7 +1644,6 @@
1537 "Keep model in memory": "将模型保存在内存中",1644 "Keep model in memory": "将模型保存在内存中",
1538 "Hint: Set the URL in the API connection settings.": "提示:在 API 连接设置中设置 URL。",1645 "Hint: Set the URL in the API connection settings.": "提示:在 API 连接设置中设置 URL。",
1539 "The server MUST be started with the --embedding flag to use this feature!": "服务器必须使用 --embedding 标志启动才能使用此功能!",1646 "The server MUST be started with the --embedding flag to use this feature!": "服务器必须使用 --embedding 标志启动才能使用此功能!",
1540 "Vectors Model Warning": "建议在聊天过程中更改模型时清除向量。否则会导致结果不理想。",
1541 "NomicAI API Key": "NomicAI API 密钥",1647 "NomicAI API Key": "NomicAI API 密钥",
1542 "Query messages": "查询消息",1648 "Query messages": "查询消息",
1543 "Score threshold": "分数阈值",1649 "Score threshold": "分数阈值",
@@ -1559,9 +1665,9 @@
1559 "Data Bank files": "数据库文件",1665 "Data Bank files": "数据库文件",
1560 "Injection Template": "注入模板",1666 "Injection Template": "注入模板",
1561 "Injection Position": "注射位置",1667 "Injection Position": "注射位置",
1562 "Vectorize All": "全部矢量化",1668 "Vectorize All": "全部向量化",
1563 "Purge Vectors": "清除向量",1669 "Purge Vectors": "清除向量",
1564 "Chat vectorization settings": "聊天矢量化设置",1670 "Chat vectorization settings": "聊天向量化设置",
1565 "Enabled for chat messages": "已启用聊天消息",1671 "Enabled for chat messages": "已启用聊天消息",
1566 "Retain#": "保持#",1672 "Retain#": "保持#",
1567 "Insert#": "插入#",1673 "Insert#": "插入#",
@@ -1570,15 +1676,10 @@
1570 "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:这将大大减慢向量生成速度,因为必须先汇总所有消息。",1676 "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:这将大大减慢向量生成速度,因为必须先汇总所有消息。",
1571 "Summarize chat messages when sending": "发送时总结聊天消息",1677 "Summarize chat messages when sending": "发送时总结聊天消息",
1572 "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:这可能会导致您发送的消息需要一点时间来处理并减慢响应时间。",1678 "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:这可能会导致您发送的消息需要一点时间来处理并减慢响应时间。",
1573 "Main API": "主要 API",
1574 "Extras API": "附加 API",1679 "Extras API": "附加 API",
1575 "Only used when Main API is selected.": "仅在选择主 API 时使用。",1680 "Only used when Main API or WebLLM Extension is selected.": "仅在 Main API 或 WebLLM 扩展被选中时使用。",
1576 "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "随着您聊天,旧消息会逐渐矢量化。\n要处理所有以前的消息,请单击下面的按钮。",1681 "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "随着您聊天,旧消息会逐渐向量化。\n要处理所有以前的消息,请单击下面的按钮。",
1577 "View Stats": "查看统计数据",1682 "View Stats": "查看统计数据",
1578 "Title/Memo": "标题/备忘录",
1579 "Status": "状态",
1580 "Position": "位置",
1581 "Trigger %": "触发率 %",
1582 "Manager Users": "管理用户",1683 "Manager Users": "管理用户",
1583 "New User": "新用户",1684 "New User": "新用户",
1584 "Status:": "地位:",1685 "Status:": "地位:",
@@ -1588,6 +1689,8 @@
1588 "Password:": "密码:",1689 "Password:": "密码:",
1589 "Confirm Password:": "确认密码:",1690 "Confirm Password:": "确认密码:",
1590 "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。",1691 "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。",
1692 "Note:": "提示:",
1693 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。",
1591 "Current Password:": "当前密码:",1694 "Current Password:": "当前密码:",
1592 "New Password:": "新密码:",1695 "New Password:": "新密码:",
1593 "Confirm New Password:": "确认新密码:",1696 "Confirm New Password:": "确认新密码:",
@@ -1602,6 +1705,13 @@
1602 "Import All": "全部导入",1705 "Import All": "全部导入",
1603 "Import Existing": "导入现有",1706 "Import Existing": "导入现有",
1604 "Import": "导入",1707 "Import": "导入",
1708 "Chat Lorebook": "聊天知识书",
1709 "Chat Lorebook for": "聊天知识书",
1710 "chat_world_template_txt": "选定的世界信息将绑定到此聊天。生成 AI 回复时,\n它将与全球和角色传说书中的条目相结合。",
1711 "chat_rename_1": "输入聊天的新名称:",
1712 "chat_rename_2": "注意!!使用已有文件名会导致错误!!",
1713 "chat_rename_3": "此举会将次聊天与标记为“检查点”的聊天解绑。",
1714 "chat_rename_4": "不需要在结尾添加 '.jsonl'",
1605 "Include Body Parameters": "包括主体参数",1715 "Include Body Parameters": "包括主体参数",
1606 "custom_include_body_desc": "聊天完成请求主体中要包含的参数(YAML 对象)\n\n示例:\n- top_k:20\n- repetition_penalty:1.1",1716 "custom_include_body_desc": "聊天完成请求主体中要包含的参数(YAML 对象)\n\n示例:\n- top_k:20\n- repetition_penalty:1.1",
1607 "Exclude Body Parameters": "排除主体参数",1717 "Exclude Body Parameters": "排除主体参数",
@@ -1609,14 +1719,20 @@
1609 "Include Request Headers": "包含请求标头",1719 "Include Request Headers": "包含请求标头",
1610 "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\n- CustomHeader:自定义值\n- AnotherHeader:自定义值",1720 "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\n- CustomHeader:自定义值\n- AnotherHeader:自定义值",
1611 "Debug Warning": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。",1721 "Debug Warning": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。",
1722 "THIS IS PERMANENT!": "此操作不可逆!",
1723 "Also delete the chat files": "同时删除聊天文件",
1612 "Are you sure you want to delete this user?": "您确定要删除该用户吗?",1724 "Are you sure you want to delete this user?": "您确定要删除该用户吗?",
1613 "Deleting:": "删除:",1725 "Deleting:": "删除:",
1614 "Also wipe user data.": "也清空用户数据。",1726 "Also wipe user data.": "也清空用户数据。",
1615 "Warning:": "警告:",1727 "Warning:": "警告:",
1616 "This action is irreversible.": "此操作不可逆。",1728 "This action is irreversible.": "此操作不可逆。",
1617 "Type the user's handle below to confirm:": "在下面输入用户的名称以确认:",1729 "Type the user's handle below to confirm:": "在下面输入用户的名称以确认:",
1618 "Forbid Media Override explanation": "当前角色/群组在聊天中使用外部媒体的能力。",1730 "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?",
1731 "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。",
1732 "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。",
1619 "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。",1733 "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。",
1734 "forbid_media_global_state_forbidden": "(禁止)",
1735 "forbid_media_global_state_allowed": "(允许)",
1620 "Always forbidden": "始终禁止",1736 "Always forbidden": "始终禁止",
1621 "Always allowed": "始终允许",1737 "Always allowed": "始终允许",
1622 "help_format_1": "文本格式化命令:",1738 "help_format_1": "文本格式化命令:",
@@ -1654,10 +1770,6 @@
1654 "help_format_33": "显示为中等标题(注意空格)",1770 "help_format_33": "显示为中等标题(注意空格)",
1655 "help_format_35": "### 文本",1771 "help_format_35": "### 文本",
1656 "help_format_36": "显示为小标题(注意空格)",1772 "help_format_36": "显示为小标题(注意空格)",
1657 "help_format_38": "$$ 文本 $$",
1658 "help_format_39": "呈现 LaTeX 公式(如果启用)",
1659 "help_format_40": "$文本$",
1660 "help_format_41": "呈现 AsciiMath 公式(如果启用)",
1661 "help_1": "您好!请选择您想要详细了解的帮助主题:",1773 "help_1": "您好!请选择您想要详细了解的帮助主题:",
1662 "help_2": "斜线命令",1774 "help_2": "斜线命令",
1663 "help_or": "或者",1775 "help_or": "或者",
@@ -1668,27 +1780,33 @@
1668 "help_7": "SillyTavern 官方文档网站",1780 "help_7": "SillyTavern 官方文档网站",
1669 "help_8": "有更多信息!",1781 "help_8": "有更多信息!",
1670 "help_hotkeys_0": "热键/按键绑定",1782 "help_hotkeys_0": "热键/按键绑定",
1671 "help_hotkeys_1": "向上",1783 "help_hotkeys_1": "上",
1672 "help_hotkeys_2": "编辑聊天中的最后一条消息",1784 "help_hotkeys_2": "编辑聊天中的最后一条消息",
1673 "help_hotkeys_3": "Ctrl+向上",1785 "help_hotkeys_3": "Ctrl+上",
1674 "help_hotkeys_4": "编辑聊天中的最后一条用户消息",1786 "help_hotkeys_4": "编辑聊天中的最后一条用户消息",
1675 "help_hotkeys_5": "左边",1787 "help_hotkeys_5": "左",
1676 "help_hotkeys_6": "向左滑动",1788 "help_hotkeys_6": "向左滑动",
1677 "help_hotkeys_7": "正确的",1789 "help_hotkeys_7": "右",
1678 "help_hotkeys_8": "向右滑动(注意:当聊天栏中输入内容时,滑动热键将被禁用)",1790 "help_hotkeys_8": "向右滑动(注意:当聊天栏中输入内容时,滑动热键将被禁用)",
1679 "help_hotkeys_9": "进入",1791 "help_hotkeys_9": "Enter",
1680 "help_hotkeys_10": "(选中聊天栏)",1792 "help_hotkeys_10": "(选中聊天栏)",
1681 "help_hotkeys_10_1": "向 AI 发送消息",1793 "help_hotkeys_10_1": "向 AI 发送消息",
1682 "help_hotkeys_11": "Ctrl+Enter",1794 "help_hotkeys_11": "Ctrl+Enter",
1683 "help_hotkeys_12": "重新生成最后的 AI 响应",1795 "help_hotkeys_12": "重新生成最后的 AI 响应",
1684 "help_hotkeys_13": "Alt+Enter",1796 "help_hotkeys_13": "Alt+Enter",
1685 "help_hotkeys_14": "继续上一次AI响应",1797 "help_hotkeys_14": "继续上一次AI响应",
1686 "help_hotkeys_15": "逃脱",1798 "help_hotkeys_15": "Esc",
1687 "help_hotkeys_16": "停止 AI 响应生成、关闭 UI 面板、取消消息编辑",1799 "help_hotkeys_16": "停止 AI 响应生成、关闭 UI 面板、取消消息编辑",
1688 "help_hotkeys_17": "Ctrl+Shift+向上",1800 "help_hotkeys_17": "Ctrl+Shift+上",
1689 "help_hotkeys_18": "滚动到上下文行",1801 "help_hotkeys_18": "滚动到上下文行",
1690 "help_hotkeys_19": "Ctrl+Shift+向下",1802 "help_hotkeys_19": "Ctrl+Shift+下",
1691 "help_hotkeys_20": "滚动聊天到底部",1803 "help_hotkeys_20": "滚动聊天到底部",
1804 "help_hotkeys_21": "在输入框中生效,由这个图标标记:",
1805 "help_hotkeys_22": "**加粗**",
1806 "help_hotkeys_23": "*斜体*",
1807 "help_hotkeys_24": "__下划线__",
1808 "help_hotkeys_25": "`行内代码`",
1809 "help_hotkeys_26": "~~删除线~~",
1692 "Import Characters": "导入角色",1810 "Import Characters": "导入角色",
1693 "Enter the URL of the content to import": "输入要导入的内容的URL",1811 "Enter the URL of the content to import": "输入要导入的内容的URL",
1694 "Supported sources:": "支持的来源:",1812 "Supported sources:": "支持的来源:",
@@ -1726,7 +1844,8 @@
1726 "help_macros_15": "您当前的 Persona 用户名",1844 "help_macros_15": "您当前的 Persona 用户名",
1727 "help_macros_16": "角色的名字",1845 "help_macros_16": "角色的名字",
1728 "help_macros_17": "角色的版本号",1846 "help_macros_17": "角色的版本号",
1729 "help_macros_18": "以逗号分隔的群组成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}",1847 "help_macros_18": "以逗号分隔的群成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}",
1848 "help_groupNotMuted": "与 {{group}} 相同,但排除被禁言的成员",
1730 "help_macros_19": "当前选定的 API 的文本生成模型名称。",1849 "help_macros_19": "当前选定的 API 的文本生成模型名称。",
1731 "Can be inaccurate!": "可能不准确!",1850 "Can be inaccurate!": "可能不准确!",
1732 "help_macros_20": "最新聊天消息的文本。",1851 "help_macros_20": "最新聊天消息的文本。",
@@ -1755,9 +1874,10 @@
1755 "help_macros_38": "随机的替代语法允许在列表项中使用逗号。",1874 "help_macros_38": "随机的替代语法允许在列表项中使用逗号。",
1756 "help_macros_39": "从列表中随机挑选一项。工作原理与 {{random}} 相同,具有相同的语法选项,但一旦挑选,挑选将一直持续到本次聊天,不会在连续消息和提示处理中重新滚动。",1875 "help_macros_39": "从列表中随机挑选一项。工作原理与 {{random}} 相同,具有相同的语法选项,但一旦挑选,挑选将一直持续到本次聊天,不会在连续消息和提示处理中重新滚动。",
1757 "help_macros_40": "如果使用文本生成 WebUI 后端,则动态地将引号中的文本添加到禁用单词序列中。对其他后端不执行任何操作。可以在任何地方使用(角色描述、WI、AN 等)。文本周围的引号很重要。",1876 "help_macros_40": "如果使用文本生成 WebUI 后端,则动态地将引号中的文本添加到禁用单词序列中。对其他后端不执行任何操作。可以在任何地方使用(角色描述、WI、AN 等)。文本周围的引号很重要。",
1877 "help_macros_isMobile": "当为移动端时为\"true\",反之为\"false\"",
1758 "Instruct Mode and Context Template Macros:": "指导模式和上下文模板宏:",1878 "Instruct Mode and Context Template Macros:": "指导模式和上下文模板宏:",
1759 "(enabled in the Advanced Formatting settings)": "(在高级格式设置中启用)",1879 "(enabled in the Advanced Formatting settings)": "(在高级格式设置中启用)",
1760 "help_macros_41": "令牌中允许的最大提示长度 = (上下文大小 - 响应长度)",1880 "help_macros_41": "令牌中允许的最大提示长度 = (上下文长度 - 响应长度)",
1761 "help_macros_42": "上下文模板示例对话分隔符",1881 "help_macros_42": "上下文模板示例对话分隔符",
1762 "help_macros_43": "上下文模板聊天开始行",1882 "help_macros_43": "上下文模板聊天开始行",
1763 "help_macros_44": "主系统提示(如果选择,则覆盖字符提示,或 instructSystemPrompt)",1883 "help_macros_44": "主系统提示(如果选择,则覆盖字符提示,或 instructSystemPrompt)",
@@ -1793,12 +1913,16 @@
1793 "help_macros_68": "替换为全局变量“name”的值减 1 的结果",1913 "help_macros_68": "替换为全局变量“name”的值减 1 的结果",
1794 "help_macros_69": "替换为范围变量“name”的值",1914 "help_macros_69": "替换为范围变量“name”的值",
1795 "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换",1915 "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换",
1916 "{{name}}": "{{name}}",
1917 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。",
1918 "Also delete the current chat file": "同时删除当前聊天文件",
1919 "Persona Lorebook for": "Persona Lorebook for",
1920 "persona_world_template_txt": "A selected World Info will be bound to this persona. When generating an AI reply,\n it will be combined with the entries from global, character and chat lorebooks.",
1796 "Export for character": "导出角色",1921 "Export for character": "导出角色",
1797 "Export prompts for this character, including their order.": "导出此角色的提示词,包括其顺序。",1922 "Export prompts for this character, including their order.": "导出此角色的提示词,包括其顺序。",
1798 "Export all": "全部导出",1923 "Export all": "全部导出",
1799 "Export all your prompts to a file": "将所有提示词导出到文件",1924 "Export all your prompts to a file": "将所有提示词导出到文件",
1800 "Insert prompt": "插入提示词",1925 "Insert prompt": "插入提示词",
1801 "Delete prompt": "删除提示词",
1802 "Import a prompt list": "导入提示词列表",1926 "Import a prompt list": "导入提示词列表",
1803 "Export this prompt list": "导出此提示词列表",1927 "Export this prompt list": "导出此提示词列表",
1804 "Reset current character": "重置当前角色",1928 "Reset current character": "重置当前角色",
@@ -1806,7 +1930,13 @@
1806 "Prompts": "提示词",1930 "Prompts": "提示词",
1807 "Total Tokens:": "总词符数:",1931 "Total Tokens:": "总词符数:",
1808 "prompt_manager_tokens": "词符",1932 "prompt_manager_tokens": "词符",
1809 "Are you sure you want to reset your settings to factory defaults?": "您确定要将设置重置为出厂默认设置吗?",1933 "Are you sure you want to connect to the following proxy URL?": "你确定要连接到下面的代理URL吗?",
1934 "Encountered an error while processing your request.": "处理请求时遇到了问题。",
1935 "Check you have credits available on your": "检查您的 ",
1936 "OpenAI account quora_error": "OpenAI 账号余额是否充足",
1937 "dot quota_error": "。",
1938 "If you have sufficient credits, please try again later.": "若您有足够的余额,请稍后再试。",
1939 "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?",
1810 "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。",1940 "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。",
1811 "Chat Scenario Override": "聊天场景覆盖",1941 "Chat Scenario Override": "聊天场景覆盖",
1812 "Remove": "移除",1942 "Remove": "移除",
@@ -1824,7 +1954,15 @@
1824 "Glob patterns of files to include in the download.": "要包含在下载中的文件的全局模式。每个模式用换行符分隔。",1954 "Glob patterns of files to include in the download.": "要包含在下载中的文件的全局模式。每个模式用换行符分隔。",
1825 "Exclude Patterns": "排除模式",1955 "Exclude Patterns": "排除模式",
1826 "Glob patterns of files to exclude in the download.": "下载中要排除的文件的 Glob 模式。每个模式用换行符分隔。",1956 "Glob patterns of files to exclude in the download.": "下载中要排除的文件的 Glob 模式。每个模式用换行符分隔。",
1827 "Hi,": "嘿,",1957 "Tag Management": "标签管理",
1958 "Save your tags to a file": "将标签保存为文件",
1959 "Restore tags from a file": "从文件中恢复标签",
1960 "Create a new tag": "新建一个标签",
1961 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖拽左侧三条横线以排序,点击名字以重命名,点击调色盘以切换颜色。",
1962 "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。",
1963 "Use alphabetical sorting": "按字母顺序排列",
1964 "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。",
1965 "Hi,": "嗨,",
1828 "To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器",1966 "To enable multi-account features, restart the SillyTavern server with": "要启用多帐户功能,请使用以下命令重新启动 SillyTavern 服务器",
1829 "set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。",1967 "set to true in the config.yaml file.": "在 config.yaml 文件中设置为 true。",
1830 "Account Info": "帐户信息",1968 "Account Info": "帐户信息",
@@ -1848,18 +1986,25 @@
1848 "Want to update?": "获取最新版本",1986 "Want to update?": "获取最新版本",
1849 "How to start chatting?": "如何快速开始聊天?",1987 "How to start chatting?": "如何快速开始聊天?",
1850 "Click _space": "点击",1988 "Click _space": "点击",
1851 "and select a": "并选择一个",1989 "and connect to an": "并连接一个",
1852 "Chat API": "聊天API",
1853 "and pick a character.": "并选择一个角色。",1990 "and pick a character.": "并选择一个角色。",
1854 "You can browse a list of bundled characters in the": "您可以在",1991 "You can add more": "你可以点击右侧添加更多",
1855 "menu within": "中浏览角色包列表",1992 "or_welcome": "或从其他网站中",
1856 "Confused or lost?": "获取更多帮助?",1993 "from other websites": "。",
1857 "click these icons!": "点击这些图标!",1994 "Go to the": "您可前往此处",
1858 "in the chat bar": "到聊天框里",1995 "menu within": "(在这里:",
1859 "SillyTavern Documentation Site": "SillyTavern帮助文档",1996 "to install additional features.": ")以安装拓展功能。",
1860 "Extras Installation Guide": "扩展安装指南",1997 "Confused or lost?": "遇到了不懂的内容?",
1998 "click these icons!": "点击左侧这种图标!",
1999 "in the chat bar": "至聊天框",
2000 "SillyTavern Documentation Site": "访问 SillyTavern 帮助文档",
1861 "Still have questions?": "仍有疑问?",2001 "Still have questions?": "仍有疑问?",
1862 "Join the SillyTavern Discord": "加入SillyTavern Discord",2002 "Join the SillyTavern Discord": "加入 SillyTavern Discord群组",
1863 "Post a GitHub issue": "发布GitHub问题",2003 "Post a GitHub issue": "在 GitHub 发布问题",
1864 "Contact the developers": "联系开发人员"2004 "Contact the developers": "联系开发者",
2005 "If you're connected to an API, try asking me something!": "若您已经配置好API,尝试发送些什么吧!",
2006 "Title/Memo": "标题/备忘录",
2007 "Strategy": "Strategy",
2008 "Position": "位置",
2009 "Trigger %": "触发率 %"
1865}2010}
public/locales/zh-tw.json+1312 -452
@@ -2,9 +2,9 @@
2 "Favorite": "我的最愛",2 "Favorite": "我的最愛",
3 "Tag": "標籤",3 "Tag": "標籤",
4 "Duplicate": "複製",4 "Duplicate": "複製",
5 "Persona": "玩家角色人物",5 "Persona": "使用者角色",
6 "Delete": "刪除",6 "Delete": "刪除",
7 "AI Response Configuration": "AI 回應配置",7 "AI Response Configuration": "設定 AI 回應",
8 "AI Configuration panel will stay open": "上鎖 = AI 設定面板將保持開啟",8 "AI Configuration panel will stay open": "上鎖 = AI 設定面板將保持開啟",
9 "clickslidertips": "點選滑桿下的數字可手動輸入。",9 "clickslidertips": "點選滑桿下的數字可手動輸入。",
10 "MAD LAB MODE ON": "瘋狂實驗室模式",10 "MAD LAB MODE ON": "瘋狂實驗室模式",
@@ -20,20 +20,20 @@
20 "novelaipresets": "NovelAI 預設設定檔",20 "novelaipresets": "NovelAI 預設設定檔",
21 "Default": "預設",21 "Default": "預設",
22 "openaipresets": "OpenAI 預設設定檔",22 "openaipresets": "OpenAI 預設設定檔",
23 "Text Completion presets": "文字補充預設",23 "Text Completion presets": "文本補全預設",
24 "AI Module": "AI 模組",24 "AI Module": "AI 模組",
25 "Changes the style of the generated text.": "變更生成文字的樣式。",25 "Changes the style of the generated text.": "變更生成文字的樣式。",
26 "No Module": "無模組",26 "No Module": "無模組",
27 "Instruct": "指示",27 "Instruct": "指示",
28 "Prose Augmenter": "散文增強器",28 "Prose Augmenter": "散文增強器",
29 "Text Adventure": "文字冒險",29 "Text Adventure": "文字冒險",
30 "response legth(tokens)": "回應長度(符記數)",30 "response legth(tokens)": "回應長度(符元數)",
31 "Streaming": "串流",31 "Streaming": "串流",
32 "Streaming_desc": "生成時逐位顯示回應。當此功能關閉時,回應將在完成後一次顯示。",32 "Streaming_desc": "生成時逐位顯示回應。當此功能關閉時,回應將在完成後一次顯示。",
33 "context size(tokens)": "上下文大小(符記數)",33 "context size(tokens)": "上下文長度(符元數)",
34 "unlocked": "解鎖",34 "unlocked": "解鎖",
35 "Only enable this if your model supports context sizes greater than 8192 tokens": "僅在您的模型支援超過8192個符記的上下文大小時啟用此功能",35 "Only enable this if your model supports context sizes greater than 8192 tokens": "僅在您的模型支援超過 8192 個符元的上下文長度時啟用此功能",
36 "Max prompt cost:": "最多提示詞費用",36 "Max prompt cost:": "最大提示詞費用",
37 "Display the response bit by bit as it is generated.": "生成時逐位顯示回應。",37 "Display the response bit by bit as it is generated.": "生成時逐位顯示回應。",
38 "When this is off, responses will be displayed all at once when they are complete.": "關閉時,回應將在完成後一次性顯示。",38 "When this is off, responses will be displayed all at once when they are complete.": "關閉時,回應將在完成後一次性顯示。",
39 "Temperature": "溫度",39 "Temperature": "溫度",
@@ -50,12 +50,12 @@
50 "Medium": "中等",50 "Medium": "中等",
51 "Aggressive": "積極",51 "Aggressive": "積極",
52 "Very aggressive": "非常積極",52 "Very aggressive": "非常積極",
53 "Unlocked Context Size": "解鎖的上下文大小",53 "Unlocked Context Size": "解鎖上下文長度",
54 "Unrestricted maximum value for the context slider": "上下文滑桿的無限制最大值",54 "Unrestricted maximum value for the context slider": "上下文滑桿的無限制最大值",
55 "Context Size (tokens)": "上下文大小(符記數)",55 "Context Size (tokens)": "上下文長度(符元數)",
56 "Max Response Length (tokens)": "最大回應長度(符記數)",56 "Max Response Length (tokens)": "最大回應長度(符元數)",
57 "Multiple swipes per generation": "每次生成多次滑動",57 "Multiple swipes per generation": "每次生成多次滑動",
58 "Enable OpenAI completion streaming": "啟用 OpenAI 補充串流",58 "Enable OpenAI completion streaming": "啟用 OpenAI 補全串流",
59 "Frequency Penalty": "頻率懲罰",59 "Frequency Penalty": "頻率懲罰",
60 "Presence Penalty": "存在懲罰",60 "Presence Penalty": "存在懲罰",
61 "Count Penalty": "計數懲罰",61 "Count Penalty": "計數懲罰",
@@ -65,22 +65,22 @@
65 "Min P": "Min P",65 "Min P": "Min P",
66 "Top A": "Top A",66 "Top A": "Top A",
67 "Quick Prompts Edit": "快速提示詞編輯",67 "Quick Prompts Edit": "快速提示詞編輯",
68 "Main": "主要",68 "Main": "主要提示詞",
69 "NSFW": "NSFW",69 "NSFW": "NSFW",
70 "Jailbreak": "越獄",70 "Jailbreak": "越獄",
71 "Utility Prompts": "實用提示詞",71 "Utility Prompts": "實用提示詞",
72 "Impersonation prompt": "AI 扮演提示詞",72 "Impersonation prompt": "AI 扮演提示詞",
73 "Restore default prompt": "還原預設提示詞",73 "Restore default prompt": "還原預設提示詞",
74 "Prompt that is used for Impersonation function": "用於 AI 模仿功能的提示詞",74 "Prompt that is used for Impersonation function": "用於 AI 模仿功能的提示詞",
75 "World Info Format Template": "世界資訊格式範本",75 "World Info Format Template": "世界資訊格式",
76 "Restore default format": "還原預設格式",76 "Restore default format": "還原預設格式",
77 "Wraps activated World Info entries before inserting into the prompt.": "在插入提示詞前包裝已啟用的世界資訊條目。",77 "Wraps activated World Info entries before inserting into the prompt.": "在插入提示詞前包裝已啟用的世界資訊條目。",
78 "scenario_format_template_part_1": "使用",78 "scenario_format_template_part_1": "使用",
79 "scenario_format_template_part_2": "來標示要插入內容的位置。",79 "scenario_format_template_part_2": "來標示要插入內容的位置。",
80 "Scenario Format Template": "情境格式範本",80 "Scenario Format Template": "場景格式",
81 "Personality Format Template": "個性格式範本",81 "Personality Format Template": "個性格式",
82 "Group Nudge Prompt Template": "群組推動提示詞範本",82 "Group Nudge Prompt Template": "群組推動提示詞範本",
83 "Sent at the end of the group chat history to force reply from a specific character.": "在群組聊天歷史結束時發送以強制特定角色人物回覆",83 "Sent at the end of the group chat history to force reply from a specific character.": "在群組聊天歷史結束時發送以強制特定角色回覆",
84 "New Chat": "新聊天",84 "New Chat": "新聊天",
85 "Restore new chat prompt": "還原新聊天的提示詞",85 "Restore new chat prompt": "還原新聊天的提示詞",
86 "Set at the beginning of the chat history to indicate that a new chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的聊天",86 "Set at the beginning of the chat history to indicate that a new chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的聊天",
@@ -91,18 +91,18 @@
91 "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "設定在對話範例的開頭以表明即將開始新的範例聊天",91 "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "設定在對話範例的開頭以表明即將開始新的範例聊天",
92 "Continue nudge": "繼續輔助提示詞",92 "Continue nudge": "繼續輔助提示詞",
93 "Set at the end of the chat history when the continue button is pressed.": "按下繼續按鈕時設定在聊天歷史的末尾",93 "Set at the end of the chat history when the continue button is pressed.": "按下繼續按鈕時設定在聊天歷史的末尾",
94 "Replace empty message": "取代空訊息",94 "Replace empty message": "取代空白訊息",
95 "Send this text instead of nothing when the text box is empty.": "當文字方塊為空時,發送此字串而不是空白。",95 "Send this text instead of nothing when the text box is empty.": "當文字方塊為空時,發送此字串而不是空白。",
96 "Seed": "種子",96 "Seed": "種子",
97 "Set to get deterministic results. Use -1 for random seed.": "設置以獲取確定性結果。使用 -1 作為隨機種子",97 "Set to get deterministic results. Use -1 for random seed.": "設定以獲取確定性結果。使用 -1 作為隨機種子",
98 "Temperature controls the randomness in token selection": "溫度控制符記選擇中的隨機性",98 "Temperature controls the randomness in token selection": "溫度控制符元選擇中的隨機性",
99 "Top_K_desc": "Top K 設定可以選擇的最高符記數量。\n例如,Top K 為 20,這意味著只保留排名前 20 的符記(無論它們的機率是多樣還是有限的)。\n設定為 0 以停用。",99 "Top_K_desc": "Top K 設定可以選擇的最高符元數量。\n例如,Top K 為 20,這意味著只保留排名前 20 的符元(無論它們的機率是多樣還是有限的)。\n設定為 0 以停用。",
100 "Top_P_desc": "Top P(又名核心取樣)會將所有頂級符記加總,直到達到目標百分比。\n例如,如果前兩個符記都是 25%,而 Top P 設為 0.5,那麼只有前兩個符記會被考慮。\n設定為 1.0 以停用。",100 "Top_P_desc": "Top P(又名核心取樣)會將所有頂級符元加總,直到達到目標百分比。\n例如,如果前兩個符元都是 25%,而 Top P 設為 0.5,那麼只有前兩個符元會被考慮。\n設定為 1.0 以停用。",
101 "Typical P": "Typical P",101 "Typical P": "Typical P",
102 "Typical_P_desc": "Typical P 取樣根據符記偏離集合平均熵的程度進行優先排序。\n它會保留累積機率接近預設閾值(例如0.5)的符記,強調那些具有平均信息量的符記。\n設定為 1.0 以停用。",102 "Typical_P_desc": "Typical P 取樣根據符元偏離集合平均熵的程度進行優先排序。\n它會保留累積機率接近預設閾值(例如0.5)的符元,強調那些具有平均信息量的符元。\n設定為 1.0 以停用。",
103 "Min_P_desc": "Min P 設定基本最小機率。\n這個值會根據最高符記的機率進行調整。例如,如果最高符記機率為 80%,而 Min P 設為 0.1 ,那麼只有機率高於 8% 的符記會被考慮。\n設定為 0 以停用。",103 "Min_P_desc": "Min P 設定基本最小機率。\n這個值會根據最高符元的機率進行調整。例如,如果最高符元機率為 80%,而 Min P 設為 0.1 ,那麼只有機率高於 8% 的符元會被考慮。\n設定為 0 以停用。",
104 "Top_A_desc": "Top A 根據最高符記機率的平方設定符記選擇的門檻。\n例如,如果 Top A 值為 0.2,而最高符記機率為 50%,那麼低於 5%(0.2 * 0.5^2) 的符記機率就會被排除。\n設定為 0 以停用。",104 "Top_A_desc": "Top A 根據最高符元機率的平方設定符元選擇的門檻。\n例如,如果 Top A 值為 0.2,而最高符元機率為 50%,那麼低於 5%(0.2 * 0.5^2) 的符元機率就會被排除。\n設定為 0 以停用。",
105 "Tail_Free_Sampling_desc": "無尾取樣(Tail-Free Sampling, TFS)會透過分析符記機率的變化率(使用導數)來尋找分佈中的低機率符記尾部。\n它會根據標準化的二階導數,保留直到某個閾值(例如0.3)的符記。\n數值越接近 0 ,表示會棄去越多符記。設定為 1.0 以停用。",105 "Tail_Free_Sampling_desc": "無尾取樣(Tail-Free Sampling, TFS)會透過分析符元機率的變化率(使用導數)來尋找分佈中的低機率符元尾部。\n它會根據標準化的二階導數,保留直到某個閾值(例如0.3)的符元。\n數值越接近 0 ,表示會棄去越多符元。設定為 1.0 以停用。",
106 "rep.pen range": "重複懲罰範圍",106 "rep.pen range": "重複懲罰範圍",
107 "Mirostat": "Mirostat",107 "Mirostat": "Mirostat",
108 "Mode": "模式",108 "Mode": "模式",
@@ -111,8 +111,8 @@
111 "Mirostat_Tau_desc": "這個設定控制了 Mirostat 輸出的可變性。",111 "Mirostat_Tau_desc": "這個設定控制了 Mirostat 輸出的可變性。",
112 "Eta": "Eta",112 "Eta": "Eta",
113 "Mirostat_Eta_desc": "這個設定控制 Mirostat 的學習率。",113 "Mirostat_Eta_desc": "這個設定控制 Mirostat 的學習率。",
114 "Ban EOS Token": "禁止 EOS 符記",114 "Ban EOS Token": "禁止 EOS 符元",
115 "Ban_EOS_Token_desc": "對於 KoboldCpp (以及可能也適用於 KoboldAI 的其他符記),禁止使用序列結束 (End-of-Sequence, EOS) 符記。這個設定對於故事創作很有幫助,但不應該在聊天和指令模式中使用。",115 "Ban_EOS_Token_desc": "對於 KoboldCpp(以及可能也適用於 KoboldAI 的其他符元),禁止使用序列結束 (End-of-Sequence, EOS) 符元。這個設定對於故事創作很有幫助,但不應該在聊天和指令模式中使用。",
116 "GBNF Grammar": "GBNF 語法",116 "GBNF Grammar": "GBNF 語法",
117 "Type in the desired custom grammar": "輸入所需的自定義語法",117 "Type in the desired custom grammar": "輸入所需的自定義語法",
118 "Samplers Order": "取樣器順序",118 "Samplers Order": "取樣器順序",
@@ -121,15 +121,15 @@
121 "Load koboldcpp order": "載入 koboldcpp 順序",121 "Load koboldcpp order": "載入 koboldcpp 順序",
122 "Preamble": "前言",122 "Preamble": "前言",
123 "Use style tags to modify the writing style of the output.": "使用樣式標籤修改輸出的寫作樣式。",123 "Use style tags to modify the writing style of the output.": "使用樣式標籤修改輸出的寫作樣式。",
124 "Banned Tokens": "禁止的符記",124 "Banned Tokens": "禁止的符元",
125 "Sequences you don't want to appear in the output. One per line.": "您不希望在輸出中出現的序列。每行一個,使用文字或符記 ID。",125 "Sequences you don't want to appear in the output. One per line.": "您不希望在輸出中出現的序列。每行一個,使用文字或符元 ID。",
126 "Logit Bias": "Logit 偏差",126 "Logit Bias": "Logit 偏差",
127 "Add": "新增",127 "Add": "新增",
128 "Helps to ban or reenforce the usage of certain words": "有助於禁止或強化某些符記的使用",128 "Helps to ban or reenforce the usage of certain words": "有助於禁止或強化某些符元的使用",
129 "CFG Scale": "CFG 比例",129 "CFG Scale": "CFG 比例",
130 "Negative Prompt": "負面提示詞",130 "Negative Prompt": "負面提示詞",
131 "Add text here that would make the AI generate things you don't want in your outputs.": "在這裡新增文字,使 AI 生成您不希望在輸出中出現的內容。",131 "Add text here that would make the AI generate things you don't want in your outputs.": "在這裡新增文字,使 AI 生成您不希望在輸出中出現的內容。",
132 "Used if CFG Scale is unset globally, per chat or character": "如果CFG Scale未在全域、每個聊天或角色人物中設定,則使用",132 "Used if CFG Scale is unset globally, per chat or character": "如果CFG Scale未在全域、每個聊天或角色中設定,則使用",
133 "Mirostat Tau": "Tau",133 "Mirostat Tau": "Tau",
134 "Mirostat LR": "Mirostat 學習率",134 "Mirostat LR": "Mirostat 學習率",
135 "Min Length": "最小長度",135 "Min Length": "最小長度",
@@ -138,23 +138,23 @@
138 "Top A Sampling": "Top A 取樣",138 "Top A Sampling": "Top A 取樣",
139 "CFG": "CFG",139 "CFG": "CFG",
140 "Neutralize Samplers": "中和取樣器",140 "Neutralize Samplers": "中和取樣器",
141 "Set all samplers to their neutral/disabled state.": "將所有取樣器設定為中性/停用狀態。",141 "Set all samplers to their neutral/disabled state.": "將所有取樣器設定為中性/停用狀態。",
142 "Sampler Select": "選擇取樣器",142 "Sampler Select": "選擇取樣器",
143 "Customize displayed samplers or add custom samplers.": "自訂顯示的取樣器或新增自訂取樣器。",143 "Customize displayed samplers or add custom samplers.": "自訂顯示的取樣器或新增自訂取樣器。",
144 "Epsilon Cutoff": "Epsilon 截斷",144 "Epsilon Cutoff": "Epsilon 截斷",
145 "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon 截斷設定排除符記的機率下限",145 "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon 截斷設定排除符元的機率下限",
146 "Eta Cutoff": "Eta 截斷",146 "Eta Cutoff": "Eta 截斷",
147 "Eta_Cutoff_desc": "Eta 截斷是特殊 Eta 取樣技術的主要參數。\n單位為 1e-4;合理值為 3。\n設為 0 以停用。\n詳情請參見 Hewitt 等人(2022)撰寫的論文《Truncation Sampling as Language Model Desmoothing》。",147 "Eta_Cutoff_desc": "Eta 截斷是特殊 Eta 取樣技術的主要參數。\n單位為 1e-4;合理值為 3。\n設為 0 以停用。\n詳情請參見 Hewitt 等人於 2022 年撰寫的論文《Truncation Sampling as Language Model Desmoothing》。",
148 "rep.pen decay": "重複懲罰衰減",148 "rep.pen decay": "重複懲罰衰減",
149 "Encoder Rep. Pen.": "編碼器重複懲罰",149 "Encoder Rep. Pen.": "編碼器重複懲罰",
150 "No Repeat Ngram Size": "無重複Ngram大小",150 "No Repeat Ngram Size": "無重複 Ngram 大小",
151 "Skew": "Skew",151 "Skew": "Skew",
152 "Max Tokens Second": "最大符記/秒",152 "Max Tokens Second": "最大符元/秒",
153 "Smooth Sampling": "平滑取樣",153 "Smooth Sampling": "平滑取樣",
154 "Smooth_Sampling_desc": "允許您使用二次/三次變換來調整分佈。較低的平滑因子值將更具創造性,通常在 0.2-0.3 之間是最佳點(假設曲線=1)。較高的平滑曲線值會使曲線更陡峭,這將更加激烈地懲罰低概率選擇。1.0 的曲線值相當於僅使用平滑因子。",154 "Smooth_Sampling_desc": "允許您使用二次/三次變換來調整分佈。較低的平滑因子值將更具創造性,通常在 0.2-0.3 之間是最佳點(假設曲線=1)。較高的平滑曲線值會使曲線更陡峭,這將更加激烈地懲罰低概率選擇。1.0 的曲線值相當於僅使用平滑因子。",
155 "Smoothing Factor": "平滑因子",155 "Smoothing Factor": "平滑因子",
156 "Smoothing Curve": "平滑曲線",156 "Smoothing Curve": "平滑曲線",
157 "DRY_Repetition_Penalty_desc": "DRY 會懲罰那些將輸入的結尾擴充為已在先前輸入中出現過序列的符記。將乘法器設為 0 以停用。",157 "DRY_Repetition_Penalty_desc": "DRY 會懲罰那些將輸入的結尾擴充為已在先前輸入中出現過序列的符元。將乘法器設為 0 以停用。",
158 "DRY Repetition Penalty": "DRY 重複懲罰",158 "DRY Repetition Penalty": "DRY 重複懲罰",
159 "DRY_Multiplier_desc": "將值設為大於 0 來啟用 DRY。控制對最短受懲罰序列的懲罰幅度。",159 "DRY_Multiplier_desc": "將值設為大於 0 來啟用 DRY。控制對最短受懲罰序列的懲罰幅度。",
160 "Multiplier": "乘法器",160 "Multiplier": "乘法器",
@@ -163,42 +163,42 @@
163 "DRY_Allowed_Length_desc": "可以重複而不受懲罰的最長序列長度。",163 "DRY_Allowed_Length_desc": "可以重複而不受懲罰的最長序列長度。",
164 "Allowed Length": "允許長度",164 "Allowed Length": "允許長度",
165 "Penalty Range": "懲罰範圍",165 "Penalty Range": "懲罰範圍",
166 "DRY_Sequence_Breakers_desc": "序列停止繼續配對的符記,使用引號包裹字串並以逗號分隔清單。",166 "DRY_Sequence_Breakers_desc": "序列停止繼續配對的符元,使用引號包裹字串並以逗號分隔清單。",
167 "Sequence Breakers": "序列中斷器",167 "Sequence Breakers": "序列中斷器",
168 "JSON-serialized array of strings.": "序列化JSON的字串陣列。",168 "JSON-serialized array of strings.": "序列化 JSON 的字串陣列。",
169 "Dynamic Temperature": "動態溫度",169 "Dynamic Temperature": "動態溫度",
170 "Scale Temperature dynamically per token, based on the variation of probabilities": "根據機率變化,動態調整每個符記的溫度",170 "Scale Temperature dynamically per token, based on the variation of probabilities": "根據機率變化,動態調整每個符元的溫度",
171 "Minimum Temp": "最低溫度",171 "Minimum Temp": "最低溫度",
172 "Maximum Temp": "最高溫度",172 "Maximum Temp": "最高溫度",
173 "Exponent": "指數",173 "Exponent": "指數",
174 "Mirostat (mode=1 is only for llama.cpp)": "Mirostat(mode=1僅適用於llama.cpp)",174 "Mirostat (mode=1 is only for llama.cpp)": "Mirostat(mode=1 僅適用於 llama.cpp)",
175 "Mirostat_desc": "Mirostat 是輸出困惑度的恆溫器。\nMirostat 會將輸出的困惑度與輸入的困惑度相配對,\n從而避免了重複陷阱(在這個陷阱中,隨著自回歸推理產生字串,輸出的困惑度趨於零)和混亂陷阱(困惑度發散)。\n有關詳細資訊,請參閱 Basu 等人於 2020 年發表的論文《A Neural Text Decoding Algorithm that Directly Controls Perplexity》。\n模式選擇 Mirostat 版本。0=停用,1=Mirostat 1.0(僅限 llama.cpp),2=Mirostat 2.0。",175 "Mirostat_desc": "Mirostat 是輸出困惑度的恆溫器。\nMirostat 會將輸出的困惑度與輸入的困惑度相配對,\n從而避免了重複陷阱(在這個陷阱中,隨著自回歸推理產生字串,輸出的困惑度趨於零)和混亂陷阱(困惑度發散)。\n有關詳細資訊,請參閱 Basu 等人於 2020 年發表的論文《A Neural Text Decoding Algorithm that Directly Controls Perplexity》。\n模式選擇 Mirostat 版本。0=停用,1=Mirostat 1.0(僅限 llama.cpp),2=Mirostat 2.0。",
176 "Mirostat Mode": "Mode",176 "Mirostat Mode": "Mode",
177 "Variability parameter for Mirostat outputs": "Mirostat 輸出的變異性參數",177 "Variability parameter for Mirostat outputs": "Mirostat 輸出的變異性參數",
178 "Mirostat Eta": "Eta",178 "Mirostat Eta": "Eta",
179 "Learning rate of Mirostat": "Mirostat 的學習率",179 "Learning rate of Mirostat": "Mirostat 的學習率",
180 "Beam search": "波束搜尋",180 "Beam search": "Beam search(波束搜尋)",
181 "Helpful tip coming soon.": "更多有用提示訊息即將推出。",181 "Helpful tip coming soon.": "更多有用提示訊息即將推出。",
182 "Number of Beams": "波束數量",182 "Number of Beams": "波束數量",
183 "Length Penalty": "長度懲罰",183 "Length Penalty": "長度懲罰",
184 "Early Stopping": "提前停止",184 "Early Stopping": "提前停止",
185 "Contrastive search": "對比搜尋",185 "Contrastive search": "對比搜尋",
186 "Contrastive_search_txt": "一種取樣器,通過利用大多數 LLM 的表示空間的等向性,鼓勵多樣性的同時保持一致性。詳情請參閱 Su 等人於2022年發表的論文《A Contrastive Framework for Neural Text Generation》。",186 "Contrastive_search_txt": "一種取樣器,通過利用大多數 LLM 的表示空間的等向性,鼓勵多樣性的同時保持一致性。詳情請參閱 Su 等人於 2022 年發表的論文《A Contrastive Framework for Neural Text Generation》。",
187 "Penalty Alpha": "懲罰 Alpha",187 "Penalty Alpha": "懲罰 Alpha",
188 "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "對比搜尋正則化項的強度。設定為0以停用CS",188 "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "對比搜尋正則化項的強度。設定為 0 以停用 CS",
189 "Do Sample": "進行取樣",189 "Do Sample": "進行取樣",
190 "Add BOS Token": "新增 BOS 符記",190 "Add BOS Token": "新增 BOS 符元",
191 "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "在提示詞的開頭新增 bos_token。停用此功能可以使回應更具創造性",191 "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "在提示詞的開頭新增 bos_token。停用此功能可以使回應更具創造性",
192 "Ban the eos_token. This forces the model to never end the generation prematurely": "禁止 eos_token。這迫使模型不會提前結束生成",192 "Ban the eos_token. This forces the model to never end the generation prematurely": "禁止 eos_token。這迫使模型不會提前結束生成",
193 "Ignore EOS Token": "忽略 EOS 符記",193 "Ignore EOS Token": "忽略 EOS 符元",
194 "Ignore the EOS Token even if it generates.": "即使生成也忽略 EOS 符記",194 "Ignore the EOS Token even if it generates.": "即使生成也忽略 EOS 符元",
195 "Skip Special Tokens": "跳過特殊符記",195 "Skip Special Tokens": "跳過特殊符元",
196 "Temperature Last": "最後的溫度",196 "Temperature Last": "最後的溫度",
197 "Temperature_Last_desc": "使用最後應用溫度取樣器。這幾乎總是明智的做法。\n啟用時:首先取樣一組合理的符記,然後應用溫度來調整它們的相對機率(技術上講,是 logits)。\n停用時:首先應用溫度調整所有符記的相對機率,然後從中取樣合理的符記。\n停用「最後應用溫度取樣」會增加分佈尾部的概率,這傾向於放大獲得不連貫回應的機會。",197 "Temperature_Last_desc": "使用最後應用溫度取樣器。這幾乎總是明智的做法。\n啟用時:首先取樣一組合理的符元,然後應用溫度來調整它們的相對機率(技術上講,是 logits)。\n停用時:首先應用溫度調整所有符元的相對機率,然後從中取樣合理的符元。\n停用「最後應用溫度取樣」會增加分佈尾部的概率,這傾向於放大獲得不連貫回應的機會。",
198 "Speculative Ngram": "推測性 Ngram",198 "Speculative Ngram": "推測性 Ngram",
199 "Use a different speculative decoding method without a draft model": "使用不含草稿模型的不同推測性解碼方法。",199 "Use a different speculative decoding method without a draft model": "使用不含草稿模型的不同推測性解碼方法。",
200 "Spaces Between Special Tokens": "特殊符記之間的空格",200 "Spaces Between Special Tokens": "特殊符元之間的空格",
201 "LLaMA / Mistral / Yi models only": "僅限 LLaMA / Mistral / Yi 模型",201 "LLaMA / Mistral / Yi models only": "僅限 LLaMA/Mistral/Yi 模型",
202 "Example: some text [42, 69, 1337]": "範例:\n一些文字 [42, 69, 1337]",202 "Example: some text [42, 69, 1337]": "範例:\n一些文字 [42, 69, 1337]",
203 "Classifier Free Guidance. More helpful tip coming soon": "無分類器導引。更多有用提示訊息即將推出",203 "Classifier Free Guidance. More helpful tip coming soon": "無分類器導引。更多有用提示訊息即將推出",
204 "Scale": "比例",204 "Scale": "比例",
@@ -211,16 +211,16 @@
211 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "僅適用於 llama.cpp。決定取樣器的順序。如果 Mirostat 模式不為 0,則忽略取樣器順序。",211 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "僅適用於 llama.cpp。決定取樣器的順序。如果 Mirostat 模式不為 0,則忽略取樣器順序。",
212 "Sampler Priority": "取樣器優先順序",212 "Sampler Priority": "取樣器優先順序",
213 "Ooba only. Determines the order of samplers.": "僅適用於 Ooba。決定取樣器的順序。",213 "Ooba only. Determines the order of samplers.": "僅適用於 Ooba。決定取樣器的順序。",
214 "Character Names Behavior": "角色人物名稱行為",214 "Character Names Behavior": "角色名稱行為",
215 "Helps the model to associate messages with characters.": "幫助模型將訊息與角色人物關聯起來。",215 "Helps the model to associate messages with characters.": "幫助模型將訊息與角色關聯起來。",
216 "None": "無",216 "None": "無",
217 "character_names_default": "除了團體和過去的玩家角色人物外。否則,請確保在提示中提供名字。",217 "character_names_default": "除了團體和過去的使用者角色外。否則,請確保在提示中提供名字。",
218 "Don't add character names.": "不要新增角色人物名稱",218 "Don't add character names.": "不要新增角色名稱",
219 "Completion": "補充",219 "Completion": "補全",
220 "character_names_completion": "字元限制:僅限拉丁字母數字和底線。不適用於所有來源,特別是:Claude、MistralAI、Google。",220 "character_names_completion": "字元限制:僅限拉丁字母數字和底線。不適用於所有來源,特別是:Claude、MistralAI、Google。",
221 "Add character names to completion objects.": "新增角色人物名稱來補充物件",221 "Add character names to completion objects.": "新增角色名稱來補充物件",
222 "Message Content": "訊息內容",222 "Message Content": "訊息內容",
223 "Prepend character names to message contents.": "在訊息內容前新增角色人物名稱",223 "Prepend character names to message contents.": "在訊息內容前新增角色名稱",
224 "Continue Postfix": "繼續後綴",224 "Continue Postfix": "繼續後綴",
225 "The next chunk of the continued message will be appended using this as a separator.": "繼續訊息的下一塊將使用此作為分隔符附加",225 "The next chunk of the continued message will be appended using this as a separator.": "繼續訊息的下一塊將使用此作為分隔符附加",
226 "Space": "空格",226 "Space": "空格",
@@ -233,55 +233,55 @@
233 "Continue prefill": "繼續預先填充",233 "Continue prefill": "繼續預先填充",
234 "Continue sends the last message as assistant role instead of system message with instruction.": "繼續將最後的訊息作為助理角色發送,而不是帶有指令的系統訊息。",234 "Continue sends the last message as assistant role instead of system message with instruction.": "繼續將最後的訊息作為助理角色發送,而不是帶有指令的系統訊息。",
235 "Squash system messages": "合併系統訊息",235 "Squash system messages": "合併系統訊息",
236 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括範例對話)。可能會提高某些模型的一致性。",236 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括對話範例)。可能會提高某些模型的一致性。",
237 "Enable function calling": "啟用函數調用",237 "Enable function calling": "啟用函數調用",
238 "Send inline images": "發送內嵌圖片",238 "Send inline images": "發送內嵌圖片",
239 "image_inlining_hint_1": "如果模型支援(例如: GPT-4V、Claude 3 或 Llava 13B),則在提示詞中發送圖片。\n使用任何訊息上的",239 "image_inlining_hint_1": "如果模型支援(例如:GPT-4V、Claude 3 或 Llava 13B),則在提示詞中發送圖片。\n使用任何訊息上的",
240 "image_inlining_hint_2": "動作或",240 "image_inlining_hint_2": "動作或",
241 "image_inlining_hint_3": "選單來附加圖片文件到聊天中。",241 "image_inlining_hint_3": "選單來附加圖片文件到聊天中。",
242 "Inline Image Quality": "內嵌圖片品質",242 "Inline Image Quality": "內嵌圖片品質",
243 "openai_inline_image_quality_auto": "自動",243 "openai_inline_image_quality_auto": "自動",
244 "openai_inline_image_quality_low": "低",244 "openai_inline_image_quality_low": "低",
245 "openai_inline_image_quality_high": "高",245 "openai_inline_image_quality_high": "高",
246 "Use AI21 Tokenizer": "使用 AI21 符記器",246 "Use AI21 Tokenizer": "使用 AI21 分詞器",
247 "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "對於 Jurassic 模型使用適當的符記器,比 GPT 的更高效",247 "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "對於 Jurassic 模型使用適當的分詞器,比 GPT 的更高效",
248 "Use Google Tokenizer": "使用 Google 符記器",248 "Use Google Tokenizer": "使用 Google 分詞器",
249 "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "通過 Google 模型的 API 使用適當的符記器。提示詞處理速度較慢,但提供更準確的符記計數。",249 "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "通過 Google 模型的 API 使用適當的分詞器。提示詞處理速度較慢,但提供更準確的符元計數。",
250 "Use system prompt": "使用系統提示詞",250 "Use system prompt": "使用系統提示詞",
251 "(Gemini 1.5 Pro/Flash only)": "(僅限於 Gemini 1.5 Pro/Flash)",251 "(Gemini 1.5 Pro/Flash only)": "(僅限於 Gemini 1.5 Pro/Flash)",
252 "Merges_all_system_messages_desc_1": "合併所有系統訊息,直到第一條非系統角色的訊息,並通過 google 的",252 "Merges_all_system_messages_desc_1": "合併所有系統訊息,直到第一則非系統角色的訊息,並通過 google 的",
253 "Merges_all_system_messages_desc_2": "字段發送,而不是與其餘提示詞內容一起發送。",253 "Merges_all_system_messages_desc_2": "字段發送,而不是與其餘提示詞內容一起發送。",
254 "Assistant Prefill": "預先填充助理訊息",254 "Assistant Prefill": "預先填充助理訊息",
255 "Start Claude's answer with...": "開始 Claude 的回答...",255 "Start Claude's answer with...": "開始 Claude 的回答⋯",
256 "Assistant Impersonation Prefill": "助理扮演時的預先填充",256 "Assistant Impersonation Prefill": "助理扮演時的預先填充",
257 "Use system prompt (Claude 2.1+ only)": "使用系統提示詞(僅限 Claude 2.1+)",257 "Use system prompt (Claude 2.1+ only)": "使用系統提示詞(僅限 Claude 2.1+)",
258 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "為支援的模型發送系統提示詞。停用時,使用者訊息將新增到提示詞的開頭。",258 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "為支援的模型發送系統提示詞。停用時,使用者訊息將新增到提示詞的開頭。",
259 "User first message": "使用者第一條訊息",259 "User first message": "使用者第一則訊息",
260 "Restore User first message": "還原使用者第一個訊息",260 "Restore User first message": "還原使用者第一則訊息",
261 "Human message": "人類訊息、指令等。\n當空白時不加入任何內容,也就是需要一個帶有使用者角色的新提示詞。",261 "Human message": "人類訊息、指令等。\n當空白時不加入任何內容,也就是需要一個帶有使用者角色的新提示詞。",
262 "New preset": "新預設",262 "New preset": "新預設",
263 "Delete preset": "刪除預設",263 "Delete preset": "刪除預設",
264 "View / Edit bias preset": "查看/編輯偏見預設",264 "View / Edit bias preset": "查看/編輯 Bias 預設",
265 "Add bias entry": "新增偏見條目",265 "Add bias entry": "新增 Bias 條目",
266 "Most tokens have a leading space.": "大多數符記有前導空格",266 "Most tokens have a leading space.": "大多數符元有前導空格",
267 "API Connections": "API 連線",267 "API Connections": "API 連線",
268 "Text Completion": "文字補充",268 "Text Completion": "文本補全",
269 "Chat Completion": "聊天補充",269 "Chat Completion": "聊天補全",
270 "NovelAI": "NovelAI",270 "NovelAI": "NovelAI",
271 "KoboldAI Horde": "KoboldAI Horde",271 "AI Horde": "AI Horde",
272 "KoboldAI": "KoboldAI",272 "KoboldAI": "KoboldAI",
273 "Avoid sending sensitive information to the Horde.": "避免發送敏感資訊到 Horde。",273 "Avoid sending sensitive information to the Horde.": "避免發送敏感資訊到 Horde。",
274 "Review the Privacy statement": "檢視隱私聲明",274 "Review the Privacy statement": "檢視隱私聲明",
275 "Register a Horde account for faster queue times": "註冊Horde帳號以縮短排隊時間",275 "Register a Horde account for faster queue times": "註冊 Horde 帳號以縮短等待時間",
276 "Learn how to contribute your idle GPU cycles to the Horde": "了解如何將閒置的 GPU 週期貢獻給 Horde",276 "Learn how to contribute your idle GPU cycles to the Horde": "了解如何將閒置的 GPU 週期貢獻給 Horde",
277 "Adjust context size to worker capabilities": "根據 worker 的能力調整上下文大小",277 "Adjust context size to worker capabilities": "根據 worker 的能力調整上下文長度",
278 "Adjust response length to worker capabilities": "根據 worker 的能力調整回應長度",278 "Adjust response length to worker capabilities": "根據 worker 的能力調整回應長度",
279 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "僅將已批准的 worker 排隊,可以幫助處理不良回應。可能會延長回應時間。",279 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "僅將已批准的 worker 排隊,可以幫助處理不良回應。可能會延長回應時間。",
280 "Trusted workers only": "僅限受信任的 worker",280 "Trusted workers only": "僅限受信任的 worker",
281 "API key": "API 金鑰",281 "API key": "API 金鑰",
282 "Get it here:": "在這裡獲取:",282 "Get it here:": "在這裡獲取:",
283 "Register": "登記",283 "Register": "註冊",
284 "View my Kudos": "查看我的稱讚",284 "View my Kudos": "瀏覽我的讚賞記錄",
285 "Enter": "輸入",285 "Enter": "輸入",
286 "to use anonymous mode.": "以使用匿名模式。",286 "to use anonymous mode.": "以使用匿名模式。",
287 "Clear your API key": "清除您的 API 金鑰",287 "Clear your API key": "清除您的 API 金鑰",
@@ -289,7 +289,7 @@
289 "Models": "模型",289 "Models": "模型",
290 "Refresh models": "重新整理模型",290 "Refresh models": "重新整理模型",
291 "-- Horde models not loaded --": "-- Horde 模型未載入 --",291 "-- Horde models not loaded --": "-- Horde 模型未載入 --",
292 "Not connected...": "尚未連線...",292 "Not connected...": "尚未連線⋯",
293 "API url": "API URL",293 "API url": "API URL",
294 "Example: http://127.0.0.1:5000/api ": "範例:http://127.0.0.1:5000/api ",294 "Example: http://127.0.0.1:5000/api ": "範例:http://127.0.0.1:5000/api ",
295 "Connect": "連線",295 "Connect": "連線",
@@ -298,9 +298,9 @@
298 "Get your NovelAI API Key": "取得您的 NovelAI API 金鑰",298 "Get your NovelAI API Key": "取得您的 NovelAI API 金鑰",
299 "Enter it in the box below": "請在下面的框中輸入",299 "Enter it in the box below": "請在下面的框中輸入",
300 "Novel AI Model": "NovelAI 模型",300 "Novel AI Model": "NovelAI 模型",
301 "No connection...": "沒有連線...",301 "No connection...": "沒有連線⋯",
302 "API Type": "API 類型",302 "API Type": "API 類型",
303 "Default (completions compatible)": "預設(相容補充)",303 "Default (completions compatible)": "預設(相容補全)",
304 "TogetherAI API Key": "TogetherAI API 金鑰",304 "TogetherAI API Key": "TogetherAI API 金鑰",
305 "TogetherAI Model": "TogetherAI 模型",305 "TogetherAI Model": "TogetherAI 模型",
306 "-- Connect to the API --": "-- 連線到 API --",306 "-- Connect to the API --": "-- 連線到 API --",
@@ -317,10 +317,10 @@
317 "Mancer Model": "Mancer 模型",317 "Mancer Model": "Mancer 模型",
318 "Make sure you run it with": "確保您使用以下方式執行它",318 "Make sure you run it with": "確保您使用以下方式執行它",
319 "flag": "旗標",319 "flag": "旗標",
320 "API key (optional)": "API 金鑰(可選)",320 "API key (optional)": "API 金鑰(可選)",
321 "Server url": "伺服器 URL",321 "Server url": "伺服器 URL",
322 "Example: 127.0.0.1:5000": "範例:127.0.0.1:5000",322 "Example: 127.0.0.1:5000": "範例:127.0.0.1:5000",
323 "Custom model (optional)": "自訂模型(選填)",323 "Custom model (optional)": "自訂模型(選填)",
324 "vllm-project/vllm": "vllm-project/vllm",324 "vllm-project/vllm": "vllm-project/vllm",
325 "vLLM API key": "vLLM API 金鑰",325 "vLLM API key": "vLLM API 金鑰",
326 "Example: 127.0.0.1:8000": "範例:127.0.0.1:8000",326 "Example: 127.0.0.1:8000": "範例:127.0.0.1:8000",
@@ -334,12 +334,12 @@
334 "Ollama Model": "Ollama 模型",334 "Ollama Model": "Ollama 模型",
335 "Download": "下載",335 "Download": "下載",
336 "Tabby API key": "Tabby API 金鑰",336 "Tabby API key": "Tabby API 金鑰",
337 "koboldcpp API key (optional)": "KoboldCpp API 金鑰(可選)",337 "koboldcpp API key (optional)": "KoboldCpp API 金鑰(可選)",
338 "Example: 127.0.0.1:5001": "範例:127.0.0.1:5001",338 "Example: 127.0.0.1:5001": "範例:127.0.0.1:5001",
339 "Authorize": "授權",339 "Authorize": "授權",
340 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用 OAuth 流程取得您的 OpenRouter API 符記。您將被重新導向到 openrouter.ai",340 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用 OAuth 流程取得您的 OpenRouter API 符元。您將被重新導向到 openrouter.ai",
341 "Bypass status check": "繞過狀態檢查",341 "Bypass status check": "繞過狀態檢查",
342 "Chat Completion Source": "聊天補充來源",342 "Chat Completion Source": "聊天補全來源",
343 "Reverse Proxy": "反向代理伺服器",343 "Reverse Proxy": "反向代理伺服器",
344 "Proxy Presets": "代理伺服器預設設定檔",344 "Proxy Presets": "代理伺服器預設設定檔",
345 "Saved addresses and passwords.": "已儲存的地址和密碼",345 "Saved addresses and passwords.": "已儲存的地址和密碼",
@@ -348,11 +348,11 @@
348 "Proxy Name": "代理伺服器名稱",348 "Proxy Name": "代理伺服器名稱",
349 "This will show up as your saved preset.": "這將顯示為您儲存的預設",349 "This will show up as your saved preset.": "這將顯示為您儲存的預設",
350 "Proxy Server URL": "代理伺服器 URL",350 "Proxy Server URL": "代理伺服器 URL",
351 "Alternative server URL (leave empty to use the default value).": "替代伺服器 URL(留空以使用預設值)。",351 "Alternative server URL (leave empty to use the default value).": "替代伺服器 URL(留空以使用預設值)。",
352 "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "在此框中輸入任何內容之前,從API面板中刪除您的實際OAI API金鑰",352 "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "在此框中輸入任何內容之前,從 API 面板中刪除您的實際 OAI API 金鑰",
353 "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "我們無法為使用非官方 OpenAI 代理伺服器時遇到的問題提供支援",353 "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "我們無法為使用非官方 OpenAI 代理伺服器時遇到的問題提供支援",
354 "Doesn't work? Try adding": "不起作用?嘗試新增",354 "Doesn't work? Try adding": "不起作用?嘗試新增",
355 "at the end!": "在最後!",355 "at the end!": "在最後!",
356 "Proxy Password": "代理伺服器密碼",356 "Proxy Password": "代理伺服器密碼",
357 "Will be used as a password for the proxy instead of API key.": "將用作代理的密碼,而不是 API 金鑰",357 "Will be used as a password for the proxy instead of API key.": "將用作代理的密碼,而不是 API 金鑰",
358 "Peek a password": "顯示密碼",358 "Peek a password": "顯示密碼",
@@ -364,17 +364,17 @@
364 "Use Proxy password field instead. This input will be ignored.": "請改用代理密碼欄位。此輸入將被忽略",364 "Use Proxy password field instead. This input will be ignored.": "請改用代理密碼欄位。此輸入將被忽略",
365 "OpenAI Model": "OpenAI 模型",365 "OpenAI Model": "OpenAI 模型",
366 "Bypass API status check": "繞過 API 狀態檢查",366 "Bypass API status check": "繞過 API 狀態檢查",
367 "Show External models (provided by API)": "顯示外部模型(由 API 提供)",367 "Show External models (provided by API)": "顯示外部模型(由 API 提供)",
368 "Get your key from": "取得您的鑰匙",368 "Get your key from": "取得您的鑰匙",
369 "Anthropic's developer console": "Anthropic 的開發者控制台",369 "Anthropic's developer console": "Anthropic 的開發者控制台",
370 "Claude Model": "Claude 模型",370 "Claude Model": "Claude 模型",
371 "Window AI Model": "Window AI 模型",371 "Window AI Model": "Window AI 模型",
372 "Model Order": "模型順序",372 "Model Order": "模型順序",
373 "Alphabetically": "按字母順序",373 "Alphabetically": "按字母順序",
374 "Price": "價格(最便宜的)",374 "Price": "價格(最便宜的)",
375 "Context Size": "上下文大小",375 "Context Size": "上下文長度",
376 "Group by vendors": "按供應商分組",376 "Group by vendors": "按供應商分組",
377 "Group by vendors Description": "將 OpenAI 、 Anthropic 等等的模型放各自供應商的群組中。可以與排序功能結合使用。",377 "Group by vendors Description": "將 OpenAI、Anthropic 等模型放各自供應商的群組中。可以與排序功能結合使用。",
378 "Allow fallback routes": "允許備援路徑",378 "Allow fallback routes": "允許備援路徑",
379 "Allow fallback routes Description": "如果選擇的模型無法滿足要求,會自動選擇替代模型。",379 "Allow fallback routes Description": "如果選擇的模型無法滿足要求,會自動選擇替代模型。",
380 "Scale API Key": "Scale API 金鑰",380 "Scale API Key": "Scale API 金鑰",
@@ -392,7 +392,7 @@
392 "Perplexity Model": "Perplexity 模型",392 "Perplexity Model": "Perplexity 模型",
393 "Cohere API Key": "Cohere API 金鑰",393 "Cohere API Key": "Cohere API 金鑰",
394 "Cohere Model": "Cohere 模型",394 "Cohere Model": "Cohere 模型",
395 "Custom Endpoint (Base URL)": "自訂端點(Base URL)",395 "Custom Endpoint (Base URL)": "自訂端點(Base URL)",
396 "Custom API Key": "自訂 API 金鑰",396 "Custom API Key": "自訂 API 金鑰",
397 "Available Models": "可用模型",397 "Available Models": "可用模型",
398 "Prompt Post-Processing": "提示詞後處理",398 "Prompt Post-Processing": "提示詞後處理",
@@ -403,7 +403,7 @@
403 "Missing key": "❌ 鑰匙遺失",403 "Missing key": "❌ 鑰匙遺失",
404 "Key saved": "✔️ 金鑰已儲存",404 "Key saved": "✔️ 金鑰已儲存",
405 "View hidden API keys": "查看隱藏的 API 金鑰",405 "View hidden API keys": "查看隱藏的 API 金鑰",
406 "AI Response Formatting": "AI 回應格式化",406 "AI Response Formatting": "AI 回應進階格式化",
407 "Advanced Formatting": "進階格式化",407 "Advanced Formatting": "進階格式化",
408 "Context Template": "上下文範本",408 "Context Template": "上下文範本",
409 "Auto-select this preset for Instruct Mode": "自動選擇此預設用於指令模式",409 "Auto-select this preset for Instruct Mode": "自動選擇此預設用於指令模式",
@@ -412,7 +412,7 @@
412 "Chat Start": "聊天開始符號",412 "Chat Start": "聊天開始符號",
413 "Add Chat Start and Example Separator to a list of stopping strings.": "將聊天開始和範例分隔符號加入終止字串中。",413 "Add Chat Start and Example Separator to a list of stopping strings.": "將聊天開始和範例分隔符號加入終止字串中。",
414 "Use as Stop Strings": "用作停止字串",414 "Use as Stop Strings": "用作停止字串",
415 "context_allow_jailbreak": "如果在角色人物卡中定義了越獄,且啟用了「偏好角色人物卡越獄」,則會在提示詞的結尾加入越獄內容。\n這不建議用於文字完成模型,因為可能導致不良的輸出結果。",415 "context_allow_jailbreak": "如果在角色卡中定義了越獄,且啟用了「角色卡越獄優先」,則會在提示詞的結尾加入越獄內容。\n這不建議用於文字完成模型,因為可能導致不良的輸出結果。",
416 "Allow Jailbreak": "允許越獄",416 "Allow Jailbreak": "允許越獄",
417 "Context Order": "上下文順序",417 "Context Order": "上下文順序",
418 "Summary": "摘要",418 "Summary": "摘要",
@@ -422,16 +422,16 @@
422 "In-Chat Position not affected": "摘要和作者的注釋順序僅在未設定聊天中位置時受影響。",422 "In-Chat Position not affected": "摘要和作者的注釋順序僅在未設定聊天中位置時受影響。",
423 "Instruct Mode": "指示模式",423 "Instruct Mode": "指示模式",
424 "Enabled": "啟用",424 "Enabled": "啟用",
425 "instruct_bind_to_context": "如果啟用此選項,系統會根據所選擇的指令範本名稱或偏好,自動選取對應的上下文範本。",425 "instruct_bind_to_context": "啟用後,系統將根據所選擇的指令範本名稱或偏好,自動選取對應的上下文範本。",
426 "Bind to Context": "附加到上下文",426 "Bind to Context": "附加到上下文",
427 "Presets": "預設設定檔",427 "Presets": "預設設定檔",
428 "Auto-select this preset on API connection": "在 API 連線時自動選擇此預設",428 "Auto-select this preset on API connection": "在 API 連線時自動選擇此預設",
429 "Activation Regex": "啟用正規表示式",429 "Activation Regex": "啟用正規表示式",
430 "Wrap Sequences with Newline": "用換行符包裹序列",430 "Wrap Sequences with Newline": "用換行符包裹序列",
431 "Replace Macro in Sequences": "取代序列中的巨集",431 "Replace Macro in Sequences": "取代序列中的巨集",
432 "Skip Example Dialogues Formatting": "跳過範例對話的格式設定",432 "Skip Example Dialogues Formatting": "跳過對話範例的格式設定",
433 "Include Names": "包含名稱",433 "Include Names": "包含名稱",
434 "Force for Groups and Personas": "強制用於群組和玩家角色人物",434 "Force for Groups and Personas": "強制用於群組和使用者角色",
435 "System Prompt": "系統提示詞",435 "System Prompt": "系統提示詞",
436 "Instruct Mode Sequences": "指示模式序列",436 "Instruct Mode Sequences": "指示模式序列",
437 "System Prompt Wrapping": "系統提示詞換行",437 "System Prompt Wrapping": "系統提示詞換行",
@@ -448,34 +448,34 @@
448 "Assistant Message Prefix": "助理訊息前綴",448 "Assistant Message Prefix": "助理訊息前綴",
449 "Inserted after an Assistant message.": "插入在助理訊息之後。",449 "Inserted after an Assistant message.": "插入在助理訊息之後。",
450 "Assistant Message Suffix": "助理訊息後綴",450 "Assistant Message Suffix": "助理訊息後綴",
451 "Inserted before a System (added by slash commands or extensions) message.": "插入在系統(透過斜線命令或擴充套件增加)訊息之前。",451 "Inserted before a System (added by slash commands or extensions) message.": "插入在系統(透過斜線命令或擴充功能增加)訊息之前。",
452 "System Message Prefix": "系統訊息前綴",452 "System Message Prefix": "系統訊息前綴",
453 "Inserted after a System message.": "插入在系統訊息之後",453 "Inserted after a System message.": "插入在系統訊息之後",
454 "System Message Suffix": "系統訊息後綴",454 "System Message Suffix": "系統訊息後綴",
455 "If enabled, System Sequences will be the same as User Sequences.": "如果啟用,系統序列將與使用者序列相同。",455 "If enabled, System Sequences will be the same as User Sequences.": "啟用後,系統序列將與使用者序列相同。",
456 "System same as User": "系統與使用者相同",456 "System same as User": "系統與使用者相同",
457 "Misc. Sequences": "其他序列",457 "Misc. Sequences": "其他序列",
458 "Inserted before the first Assistant's message.": "插入在第一個助理的訊息之前。",458 "Inserted before the first Assistant's message.": "插入在第一則助理訊息之前。",
459 "First Assistant Prefix": "首個助理前綴",459 "First Assistant Prefix": "開頭助理前綴",
460 "instruct_last_output_sequence": "插入在最後一個助理的訊息之前,或在生成 AI 回覆時作為最後一行提示詞(除了中立/系統角色)。",460 "instruct_last_output_sequence": "插入在最後一則助理訊息之前,或在生成 AI 回覆時作為最後一行提示詞(除了中立/系統角色)。",
461 "Last Assistant Prefix": "末尾助理前綴",461 "Last Assistant Prefix": "末尾助理前綴",
462 "Will be inserted as a last prompt line when using system/neutral generation.": "在使用系統/中立生成時作為最後一行提示詞插入。",462 "Will be inserted as a last prompt line when using system/neutral generation.": "在使用系統/中立生成時作為最後一行提示詞插入。",
463 "System Instruction Prefix": "系統指令前綴",463 "System Instruction Prefix": "系統指令前綴",
464 "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "如果生成了停止序列,包括該序列以及之後的所有內容將從輸出中刪除。",464 "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "如果生成了停止序列,包括該序列以及之後的所有內容將從輸出中刪除。",
465 "Stop Sequence": "停止序列",465 "Stop Sequence": "停止序列",
466 "Will be inserted at the start of the chat history if it doesn't start with a User message.": "如果聊天歷史不是以使用者訊息開始,將在聊天歷史的開頭插入。",466 "Will be inserted at the start of the chat history if it doesn't start with a User message.": "如果聊天歷史不是以使用者訊息開始,將在聊天歷史的開頭插入。",
467 "User Filler Message": "使用者填充訊息",467 "User Filler Message": "使用者填充訊息",
468 "Context Formatting": "上下文格式",468 "Context Formatting": "上下文格式",
469 "(Saved to Context Template)": "(已儲存到上下文範本)",469 "(Saved to Context Template)": "(已儲存到上下文範本)",
470 "Always add character's name to prompt": "總是將角色人物名稱新增到提示詞中",470 "Always add character's name to prompt": "總是將角色名稱新增到提示詞中",
471 "Generate only one line per request": "每次請求僅生成一行",471 "Generate only one line per request": "每次請求僅生成一行",
472 "Trim Incomplete Sentences": "修剪不完整的句子",472 "Trim Incomplete Sentences": "修剪不完整的句子",
473 "Include Newline": "包含換行符號",473 "Include Newline": "包含換行符號",
474 "Misc. Settings": "其他設定",474 "Misc. Settings": "其他設定",
475 "Collapse Consecutive Newlines": "折疊連續的換行符號",475 "Collapse Consecutive Newlines": "折疊連續的換行符號",
476 "Trim spaces": "修剪空格",476 "Trim spaces": "修剪空格",
477 "Tokenizer": "符記化工具",477 "Tokenizer": "分詞器 Tokenizer",
478 "Token Padding": "符記填充",478 "Token Padding": "符元填充",
479 "Start Reply With": "開始回覆",479 "Start Reply With": "開始回覆",
480 "AI reply prefix": "AI 回覆前綴",480 "AI reply prefix": "AI 回覆前綴",
481 "Show reply prefix in chat": "在聊天中顯示回覆前綴",481 "Show reply prefix in chat": "在聊天中顯示回覆前綴",
@@ -485,26 +485,26 @@
485 "JSON serialized array of strings": "JSON 序列化字串數組",485 "JSON serialized array of strings": "JSON 序列化字串數組",
486 "Replace Macro in Custom Stopping Strings": "取代自訂停止字串中的巨集",486 "Replace Macro in Custom Stopping Strings": "取代自訂停止字串中的巨集",
487 "Auto-Continue": "自動繼續",487 "Auto-Continue": "自動繼續",
488 "Allow for Chat Completion APIs": "允許聊天補充 API",488 "Allow for Chat Completion APIs": "允許聊天補全 API",
489 "Target length (tokens)": "目標長度(符記)",489 "Target length (tokens)": "目標長度(符元)",
490 "World Info": "世界資訊",490 "World Info": "世界資訊",
491 "Locked = World Editor will stay open": "上鎖 = 世界編輯器將保持開啟",491 "Locked = World Editor will stay open": "上鎖 = 世界編輯器將保持開啟",
492 "Worlds/Lorebooks": "世界/知識書",492 "Worlds/Lorebooks": "世界/知識書",
493 "Active World(s) for all chats": "所有聊天啟用中的世界書",493 "Active World(s) for all chats": "所有聊天啟用中的世界書",
494 "-- World Info not found --": "-- 未找到世界資訊 --",494 "-- World Info not found --": "-- 未找到世界資訊 --",
495 "Global World Info/Lorebook activation settings": "全球世界資訊/傳說書啟動設置",495 "Global World Info/Lorebook activation settings": "全域世界資訊/知識書啟動設定",
496 "Click to expand": "點擊展開",496 "Click to expand": "點擊展開",
497 "Scan Depth": "掃描深度",497 "Scan Depth": "掃描深度",
498 "Context %": "上下文百分比",498 "Context %": "上下文百分比",
499 "Budget Cap": "預算上限",499 "Budget Cap": "預算上限",
500 "(0 = disabled)": "(0 = 停用)",500 "(0 = disabled)": "(0 = 停用)",
501 "Scan chronologically until reached min entries or token budget.": "按時間順序掃描直到達到最小條目或符記預算",501 "Scan chronologically until reached min entries or token budget.": "按時間順序掃描直到達到最小條目或符元預算",
502 "Min Activations": "最小啟動次數",502 "Min Activations": "最小啟動次數",
503 "Max Depth": "最大深度",503 "Max Depth": "最大深度",
504 "(0 = unlimited, use budget)": "(0 = 無限制, 使用預算)",504 "(0 = unlimited, use budget)": "(0 = 無限制,使用預算)",
505 "Insertion Strategy": "插入策略",505 "Insertion Strategy": "插入策略",
506 "Sorted Evenly": "均等排序",506 "Sorted Evenly": "均等排序",
507 "Character Lore First": "角色人物知識書優先",507 "Character Lore First": "角色知識書優先",
508 "Global Lore First": "全域知識書優先",508 "Global Lore First": "全域知識書優先",
509 "Entries can activate other entries by mentioning their keywords": "條目可以通過提及其關鍵字來啟用其他條目",509 "Entries can activate other entries by mentioning their keywords": "條目可以通過提及其關鍵字來啟用其他條目",
510 "Recursive Scan": "遞迴掃描",510 "Recursive Scan": "遞迴掃描",
@@ -523,19 +523,19 @@
523 "Open all Entries": "開啟所有條目",523 "Open all Entries": "開啟所有條目",
524 "Close all Entries": "關閉所有條目",524 "Close all Entries": "關閉所有條目",
525 "New Entry": "新條目",525 "New Entry": "新條目",
526 "Fill empty Memo/Titles with Keywords": "用關鍵字填充空的備忘錄/標題",526 "Fill empty Memo/Titles with Keywords": "用關鍵字填充空的備忘錄/標題",
527 "Import World Info": "匯入世界資訊",527 "Import World Info": "匯入世界資訊",
528 "Export World Info": "匯出世界資訊",528 "Export World Info": "匯出世界資訊",
529 "Duplicate World Info": "複製世界資訊",529 "Duplicate World Info": "複製世界資訊",
530 "Delete World Info": "刪除世界資訊",530 "Delete World Info": "刪除世界資訊",
531 "Search...": "搜尋...",531 "Search...": "搜尋⋯",
532 "Search": "搜尋",532 "Search": "搜尋",
533 "Priority": "優先順序",533 "Priority": "優先順序",
534 "Custom": "自訂",534 "Custom": "自訂",
535 "Title A-Z": "標題 A-Z",535 "Title A-Z": "標題 A-Z",
536 "Title Z-A": "標題 Z-A",536 "Title Z-A": "標題 Z-A",
537 "Tokens ↗": "符記 ↗",537 "Tokens ↗": "符元 ↗",
538 "Tokens ↘": "符記 ↘",538 "Tokens ↘": "符元 ↘",
539 "Depth ↗": "深度 ↗",539 "Depth ↗": "深度 ↗",
540 "Depth ↘": "深度 ↘",540 "Depth ↘": "深度 ↘",
541 "Order ↗": "順序 ↗",541 "Order ↗": "順序 ↗",
@@ -553,12 +553,12 @@
553 "Admin Panel": "管理面板",553 "Admin Panel": "管理面板",
554 "Logout": "登出",554 "Logout": "登出",
555 "Search Settings": "搜尋設定",555 "Search Settings": "搜尋設定",
556 "UI Theme": "介面佈景主題",556 "UI Theme": "介面主題",
557 "Import a theme file": "匯入布景主題檔案",557 "Import a theme file": "匯入主題檔",
558 "Export a theme file": "匯出布景主題檔案",558 "Export a theme file": "匯出主題檔",
559 "Delete a theme": "刪除主題",559 "Delete a theme": "刪除主題",
560 "Update a theme file": "更新主題檔案",560 "Update a theme file": "更新主題檔",
561 "Save as a new theme": "儲存成新的布景主題",561 "Save as a new theme": "另存為新主題",
562 "Avatar Style": "頭像樣式",562 "Avatar Style": "頭像樣式",
563 "Circle": "圓形",563 "Circle": "圓形",
564 "Square": "方形",564 "Square": "方形",
@@ -567,8 +567,8 @@
567 "Flat": "扁平",567 "Flat": "扁平",
568 "Bubbles": "氣泡",568 "Bubbles": "氣泡",
569 "Document": "文件",569 "Document": "文件",
570 "Specify colors for your theme.": "為您的主題指定顏色",570 "Specify colors for your theme.": "為您的介面主題指定顏色",
571 "Theme Colors": "佈景主題顏色",571 "Theme Colors": "介面主題顏色",
572 "Main Text": "主要文字",572 "Main Text": "主要文字",
573 "Italics Text": "斜體文字",573 "Italics Text": "斜體文字",
574 "Underlined Text": "帶底線的文字",574 "Underlined Text": "帶底線的文字",
@@ -581,22 +581,22 @@
581 "AI Message Blur Tint": "AI 訊息模糊色調",581 "AI Message Blur Tint": "AI 訊息模糊色調",
582 "Chat Width": "對話框寬度",582 "Chat Width": "對話框寬度",
583 "Width of the main chat window in % of screen width": "主聊天視窗寬度占螢幕寬度的百分比",583 "Width of the main chat window in % of screen width": "主聊天視窗寬度占螢幕寬度的百分比",
584 "Font Scale": "字型比例",584 "Font Scale": "字體比例",
585 "Font size": "字體大小",585 "Font size": "字體大小",
586 "Blur Strength": "模糊強度",586 "Blur Strength": "模糊強度",
587 "Blur strength on UI panels.": "UI 面板上的模糊強度",587 "Blur strength on UI panels.": "UI 面板上的模糊強度",
588 "Text Shadow Width": "文字陰影寬度",588 "Text Shadow Width": "文字陰影寬度",
589 "Strength of the text shadows": "文字陰影的強度",589 "Strength of the text shadows": "文字陰影的強度",
590 "Disables animations and transitions": "停用動畫和過渡效果",590 "Disables animations and transitions": "停用動畫和過渡效果",
591 "Reduced Motion": "減少動作",591 "Reduced Motion": "停用動畫過渡效果",
592 "removes blur from window backgrounds": "從視窗背景中移除模糊效果,以加快算繪速度。",592 "removes blur from window backgrounds": "從視窗背景中移除模糊效果,以加快算繪速度。",
593 "No Blur Effect": "無模糊效果",593 "No Blur Effect": "停用模糊效果",
594 "Remove text shadow effect": "移除文字陰影效果。",594 "Remove text shadow effect": "移除文字陰影效果。",
595 "No Text Shadows": "無文字陰影",595 "No Text Shadows": "停用文字陰影效果",
596 "Reduce chat height, and put a static sprite behind the chat window": "減少聊天高度,並在聊天視窗後放置一個靜態 Sprite。",596 "Reduce chat height, and put a static sprite behind the chat window": "減少聊天高度,並在聊天視窗後放置一個靜態 Sprite。",
597 "Waifu Mode": "Waifu 模式",597 "Waifu Mode": "視覺小說模式",
598 "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "始終顯示聊天訊息的訊息動作上下文項目的完整列表,而不是將它們隱藏在「...」後面。",598 "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "始終顯示聊天訊息的訊息動作上下文項目的完整列表,而不是將它們隱藏在「⋯」後面。",
599 "Auto-Expand Message Actions": "自動展開訊息動作",599 "Auto-Expand Message Actions": "展開訊息快速編輯選單",
600 "Alternative UI for numeric sampling parameters with fewer steps": "數值取樣參數的替代 UI,步驟更少",600 "Alternative UI for numeric sampling parameters with fewer steps": "數值取樣參數的替代 UI,步驟更少",
601 "Zen Sliders": "Zen 滑桿",601 "Zen Sliders": "Zen 滑桿",
602 "Entirely unrestrict all numeric sampling parameters": "完全解除所有數值取樣參數的限制。",602 "Entirely unrestrict all numeric sampling parameters": "完全解除所有數值取樣參數的限制。",
@@ -608,39 +608,39 @@
608 "Show an icon for the API that generated the message": "顯示生成訊息的 API 圖示。",608 "Show an icon for the API that generated the message": "顯示生成訊息的 API 圖示。",
609 "Model Icon": "模型圖示",609 "Model Icon": "模型圖示",
610 "Show sequential message numbers in the chat log": "在聊天記錄中顯示連續的訊息編號。",610 "Show sequential message numbers in the chat log": "在聊天記錄中顯示連續的訊息編號。",
611 "Message IDs": "訊息 ID",611 "Message IDs": "顯示訊息 ID",
612 "Hide avatars in chat messages.": "在聊天訊息中隱藏頭像",612 "Hide avatars in chat messages.": "在聊天訊息中隱藏頭像",
613 "Hide Chat Avatars": "隱藏聊天頭像",613 "Hide Chat Avatars": "隱藏聊天頭像",
614 "Show the number of tokens in each message in the chat log": "在聊天記錄中顯示每條訊息中的符記數量",614 "Show the number of tokens in each message in the chat log": "在聊天記錄中顯示每條訊息中的符元數量",
615 "Show Message Token Count": "顯示訊息符記數量",615 "Show Message Token Count": "顯示訊息符元數",
616 "Single-row message input area. Mobile only, no effect on PC": "單行訊息輸入區域。僅適用於行動裝置版。",616 "Single-row message input area. Mobile only, no effect on PC": "將聊天訊息輸入欄預設為單行顯示。僅適用於行動版,電腦版無效。",
617 "Compact Input Area (Mobile)": "緊湊的輸入區域(行動版)",617 "Compact Input Area (Mobile)": "緊湊的聊天訊息輸入欄(行動版)",
618 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色人物管理面板中,顯示加入到最愛角色人物的快速選擇按鈕。",618 "In the Character Management panel, show quick selection buttons for favorited characters": "在角色管理面板中,顯示加入到最愛角色的快速選擇按鈕。",
619 "Characters Hotswap": "角色人物快速選擇",619 "Characters Hotswap": "角色卡快捷選單",
620 "Enable magnification for zoomed avatar display.": "啟用放大顯示頭像",620 "Enable magnification for zoomed avatar display.": "啟用放大顯示頭像",
621 "Avatar Hover Magnification": "頭像懸停時的放大倍數",621 "Avatar Hover Magnification": "頭像懸停時的放大倍數",
622 "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當你在聊天中點選頭像的圖片後,這會啟用滑鼠懸停時的放大效果。",622 "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當你在聊天中點選頭像的圖片後,這會啟用滑鼠懸停時的放大效果。",
623 "Show tagged character folders in the character list": "在角色人物列表中顯示標籤角色人物資料夾。",623 "Show tagged character folders in the character list": "在角色列表中顯示標籤角色資料夾。",
624 "Tags as Folders": "標籤作為資料夾",624 "Tags as Folders": "標籤作為資料夾",
625 "Tags_as_Folders_desc": "最近更改:標籤必須在標籤管理選單中標記為資料夾才能顯示為此類。點選這裡打開。",625 "Tags_as_Folders_desc": "最近更改:標籤必須在標籤管理選單中標記為資料夾才能顯示為此類。點選這裡打開。",
626 "Character Handling": "角色人物處理",626 "Character Handling": "角色處理",
627 "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在進階角色人物定義中設定,這個欄位將顯示在角色人物清單中。",627 "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在進階角色定義中設定,這個欄位將顯示在角色清單中。",
628 "Char List Subheader": "角色人物列表子標題",628 "Char List Subheader": "角色列表子標題",
629 "Character Version": "角色人物版本",629 "Character Version": "角色版本",
630 "Created by": "建立者",630 "Created by": "創作者",
631 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊配對,並通過所有資料欄位在列表中搜尋角色人物,而不僅僅是通過名稱子字串。",631 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊配對,並通過所有資料欄位在列表中搜尋角色,而不僅僅是通過名稱子字串。",
632 "Advanced Character Search": "進階角色人物搜尋",632 "Advanced Character Search": "進階角色搜尋",
633 "If checked and the character card contains a prompt override (System Prompt), use that instead": "如果選中並且角色人物卡包含提示詞覆寫(系統提示詞),則使用該提示詞。",633 "If checked and the character card contains a prompt override (System Prompt), use that instead": "如果選中並且角色卡包含提示詞覆寫(系統提示詞),則使用該提示詞。",
634 "Prefer Character Card Prompt": "偏好角色人物卡提示詞",634 "Prefer Character Card Prompt": "角色卡主要提示詞優先",
635 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "如果選中並且角色人物卡包含越獄覆寫(歷史指示後),則使用該提示詞。",635 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "如果選中並且角色卡包含越獄覆寫(聊天歷史後指示),則使用該提示詞。",
636 "Prefer Character Card Jailbreak": "偏好角色人物卡越獄",636 "Prefer Character Card Jailbreak": "角色卡越獄優先",
637 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "避免裁剪和調整匯入的角色人物圖像大小。未勾選時將會裁剪/調整大小到 512x768。",637 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "避免裁剪和調整匯入的角色圖像大小。未勾選時將會裁剪/調整大小到 512x768。",
638 "Never resize avatars": "永不調整頭像大小",638 "Never resize avatars": "永不調整頭像大小",
639 "Show actual file names on the disk, in the characters list display only": "僅在角色人物列表顯示實際檔案名稱。",639 "Show actual file names on the disk, in the characters list display only": "僅在角色列表顯示實際檔案名稱。",
640 "Show avatar filenames": "顯示頭像檔案名",640 "Show avatar filenames": "顯示頭像檔案名",
641 "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "在角色人物匯入時提示詞匯入嵌入的卡片標籤。否則,嵌入的標籤將被忽略。",641 "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "在角色匯入時提示詞匯入嵌入的卡片標籤。否則,嵌入的標籤將被忽略。",
642 "Import Card Tags": "匯入卡片中的標籤",642 "Import Card Tags": "匯入卡片中的標籤",
643 "Hide character definitions from the editor panel behind a spoiler button": "在編輯器面板中將角色人物定義隱藏在劇透按鈕後面。",643 "Hide character definitions from the editor panel behind a spoiler button": "在編輯器面板中將角色定義隱藏在劇透按鈕後面。",
644 "Spoiler Free Mode": "無劇透模式",644 "Spoiler Free Mode": "無劇透模式",
645 "Miscellaneous": "其他",645 "Miscellaneous": "其他",
646 "Reload and redraw the currently open chat": "重新載入並重繪目前開啟的聊天",646 "Reload and redraw the currently open chat": "重新載入並重繪目前開啟的聊天",
@@ -653,26 +653,26 @@
653 "Play a sound when a message generation finishes": "訊息生成完成時播放音效。",653 "Play a sound when a message generation finishes": "訊息生成完成時播放音效。",
654 "Message Sound": "訊息音效",654 "Message Sound": "訊息音效",
655 "Only play a sound when ST's browser tab is unfocused": "僅在 ST 的瀏覽器分頁未聚焦時播放音效。",655 "Only play a sound when ST's browser tab is unfocused": "僅在 ST 的瀏覽器分頁未聚焦時播放音效。",
656 "Background Sound Only": "僅背景音效",656 "Background Sound Only": "僅作為背景音效",
657 "Reduce the formatting requirements on API URLs": "降低 API URL 的格式要求。",657 "Reduce the formatting requirements on API URLs": "降低 API URL 的格式要求。",
658 "Relaxed API URLS": "寬鬆的 API URL 格式",658 "Relaxed API URLS": "寬鬆的 API URL 格式",
659 "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "當新角色人物含有知識書時,詢問是否要匯入嵌入的世界資訊/知識書。如果未選中,則會顯示簡短的訊息。",659 "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "當新角色含有知識書時,詢問是否要匯入嵌入的世界資訊/知識書。如果未選中,則會顯示簡短的訊息。",
660 "Lorebook Import Dialog": "匯入知識書對話框",660 "Lorebook Import Dialog": "匯入知識書對話框",
661 "Restore unsaved user input on page refresh": "在頁面刷新時還原未儲存的使用者輸入。",661 "Restore unsaved user input on page refresh": "在頁面刷新時還原未儲存的使用者輸入。",
662 "Restore User Input": "還原使用者輸入",662 "Restore User Input": "還原使用者輸入",
663 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允許通過拖動重新定位某些 UI 元素。僅適用於 PC 版。",663 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允許通過拖動重新定位某些 UI 元素。僅適用於 PC 版。",
664 "Movable UI Panels": "可移動的 UI 面板",664 "Movable UI Panels": "可移動的 UI 面板",
665 "MovingUI preset. Predefined/saved draggable positions": "MovingUI 預設。預先定義/儲存可拖動位置。",665 "MovingUI preset. Predefined/saved draggable positions": "MovingUI 預設。預先定義/儲存可拖動位置。",
666 "MUI Preset": "MUI 預設",666 "MUI Preset": "MUI 預設",
667 "Save movingUI changes to a new file": "將移動UI變更儲存到新檔案",667 "Save movingUI changes to a new file": "將移動 UI 變更儲存到新檔案",
668 "Reset MovingUI panel sizes/locations.": "重置 MovingUI 面板大小/位置",668 "Reset MovingUI panel sizes/locations.": "重置 MovingUI 面板大小/位置",
669 "Apply a custom CSS style to all of the ST GUI": "將自訂 CSS 樣式應用於所有 ST GUI",669 "Apply a custom CSS style to all of the ST GUI": "將自訂 CSS 樣式應用於所有 ST GUI",
670 "Custom CSS": "自訂 CSS",670 "Custom CSS": "自訂 CSS",
671 "Expand the editor": "展開編輯器",671 "Expand the editor": "展開編輯器",
672 "Chat/Message Handling": "聊天/訊息處理",672 "Chat/Message Handling": "聊天/訊息處理",
673 "# Messages to Load": "每頁載入的訊息數",673 "# Messages to Load": "每頁載入的訊息數",
674 "The number of chat history messages to load before pagination.": "每頁載入的聊天歷史訊息數",674 "The number of chat history messages to load before pagination.": "每頁載入的聊天歷史訊息數",
675 "(0 = All)": "(0 = 全部)",675 "(0 = All)": "(0 = 全部)",
676 "Streaming FPS": "串流 FPS",676 "Streaming FPS": "串流 FPS",
677 "Update speed of streamed text.": "更新串流文字的速度",677 "Update speed of streamed text.": "更新串流文字的速度",
678 "Example Messages Behavior": "訊息行為範例:",678 "Example Messages Behavior": "訊息行為範例:",
@@ -681,19 +681,19 @@
681 "Never include examples": "永不包含範例",681 "Never include examples": "永不包含範例",
682 "Send on Enter": "按下 Enter 鍵發送:",682 "Send on Enter": "按下 Enter 鍵發送:",
683 "Disabled": "停用",683 "Disabled": "停用",
684 "Automatic (PC)": "自動(PC)",684 "Automatic (PC)": "自動(PC)",
685 "Press Send to continue": "按下傳送繼續",685 "Press Send to continue": "按下傳送繼續",
686 "Show a button in the input area to ask the AI to continue (extend) its last message": "在輸入區域顯示一個按鈕,請求 AI 繼續(擴充)其最後一條訊息",686 "Show a button in the input area to ask the AI to continue (extend) its last message": "在輸入區域顯示一個按鈕,請求 AI 繼續(擴充)其最後一則訊息",
687 "Quick 'Continue' button": "快速「繼續」按鈕",687 "Quick 'Continue' button": "快速「繼續回應」按鈕",
688 "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "在最後的聊天訊息中顯示箭頭按鈕,以生成替代的 AI 回應。適用於 PC 和行動裝置版",688 "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "在最後的聊天訊息中顯示箭頭按鈕,以生成替代的 AI 回應。適用於 PC 和行動版",
689 "Swipes": "滑動",689 "Swipes": "滑動",
690 "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "允許在最後的聊天訊息上使用滑動手勢以觸發滑動生成。僅適用於行動裝置版。",690 "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "允許在最後的聊天訊息上使用滑動手勢以觸發滑動生成。僅適用於行動版。",
691 "Gestures": "手勢",691 "Gestures": "手勢",
692 "Auto-load Last Chat": "自動載入最後的聊天",692 "Auto-load Last Chat": "自動載入最後的聊天",
693 "Auto-scroll Chat": "自動滾動聊天",693 "Auto-scroll Chat": "自動滾動聊天",
694 "Save edits to messages without confirmation as you type": "在輸入時自動儲存訊息的編輯。",694 "Save edits to messages without confirmation as you type": "在輸入時自動儲存訊息的編輯。",
695 "Auto-save Message Edits": "自動儲存編輯的訊息",695 "Auto-save Message Edits": "自動儲存編輯的訊息",
696 "Confirm message deletion": "確認刪除訊息",696 "Confirm message deletion": "刪除訊息前確認",
697 "Auto-fix Markdown": "自動修正 Markdown",697 "Auto-fix Markdown": "自動修正 Markdown",
698 "Disallow embedded media from other domains in chat messages": "禁止在聊天訊息中嵌入來自其他領域的媒體。",698 "Disallow embedded media from other domains in chat messages": "禁止在聊天訊息中嵌入來自其他領域的媒體。",
699 "Forbid External Media": "禁止使用外部媒體",699 "Forbid External Media": "禁止使用外部媒體",
@@ -704,15 +704,15 @@
704 "Allow AI messages in groups to contain lines spoken by other group members": "允許群組中的 AI 訊息包含其他群組成員說的話",704 "Allow AI messages in groups to contain lines spoken by other group members": "允許群組中的 AI 訊息包含其他群組成員說的話",
705 "Relax message trim in Groups": "放寬群組中的訊息修剪",705 "Relax message trim in Groups": "放寬群組中的訊息修剪",
706 "Log prompts to console": "將提示詞記錄到控制台",706 "Log prompts to console": "將提示詞記錄到控制台",
707 "Requests logprobs from the API for the Token Probabilities feature": "從 API 請求 logprobs 用於符記機率功能。",707 "Requests logprobs from the API for the Token Probabilities feature": "從 API 請求 logprobs 用於符元機率功能。",
708 "Request token probabilities": "請求符記機率",708 "Request token probabilities": "請求符元機率",
709 "Automatically reject and re-generate AI message based on configurable criteria": "根據可配置標準自動拒絕並重新生成 AI 訊息。",709 "Automatically reject and re-generate AI message based on configurable criteria": "根據可配置標準自動拒絕並重新生成 AI 訊息。",
710 "Auto-swipe": "自動滑動",710 "Auto-swipe": "自動滑動",
711 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "啟用自動滑動功能。此部分的設定僅在啟用自動滑動時有效。",711 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "啟用自動滑動功能。此部分的設定僅在啟用自動滑動時有效。",
712 "Minimum generated message length": "生成的訊息最小長度",712 "Minimum generated message length": "生成訊息的最小長度",
713 "If the generated message is shorter than this, trigger an auto-swipe": "如果生成的訊息比這個短,將觸發自動滑動。",713 "If the generated message is shorter than this, trigger an auto-swipe": "如果生成的訊息比這個短,將觸發自動滑動。",
714 "Blacklisted words": "黑名單詞語",714 "Blacklisted words": "黑名單詞語",
715 "words you dont want generated separated by comma ','": "您不想生成的文字,使用逗號分隔",715 "words you dont want generated separated by comma ','": "您不想生成的文字,使用逗號分隔",
716 "Blacklisted word count to swipe": "滑動的黑名單詞語數量",716 "Blacklisted word count to swipe": "滑動的黑名單詞語數量",
717 "Minimum number of blacklisted words detected to trigger an auto-swipe": "檢測到的黑名單詞語數量觸發自動滑動的最小值。",717 "Minimum number of blacklisted words detected to trigger an auto-swipe": "檢測到的黑名單詞語數量觸發自動滑動的最小值。",
718 "AutoComplete Settings": "自動完成設定",718 "AutoComplete Settings": "自動完成設定",
@@ -722,62 +722,62 @@
722 "Starts with": "開始於",722 "Starts with": "開始於",
723 "Includes": "包含",723 "Includes": "包含",
724 "Fuzzy": "模糊",724 "Fuzzy": "模糊",
725 "Sets the style of the autocomplete.": "設置自動完成的樣式",725 "Sets the style of the autocomplete.": "設定自動完成的樣式",
726 "Autocomplete Style": "自動完成樣式",726 "Autocomplete Style": "自動完成樣式",
727 "Follow Theme": "參照佈景主題",727 "Follow Theme": "沿用介面主題",
728 "Dark": "深色",728 "Dark": "深色",
729 "Sets the font size of the autocomplete.": "設置自動完成的字體大小",729 "Sets the font size of the autocomplete.": "設定自動完成的字體大小",
730 "Sets the width of the autocomplete.": "設置自動完成的寬度",730 "Sets the width of the autocomplete.": "設定自動完成的寬度",
731 "Autocomplete Width": "自動完成寬度",731 "Autocomplete Width": "自動完成寬度",
732 "chat input box": "聊天輸入框",732 "chat input box": "聊天輸入框",
733 "entire chat width": "整個聊天寬度",733 "entire chat width": "整個聊天寬度",
734 "full window width": "全視窗寬度",734 "full window width": "全視窗寬度",
735 "STscript Settings": "STscript 設定",735 "STscript Settings": "STscript 設定",
736 "Sets default flags for the STscript parser.": "設置 STscript 解析器的預設標誌",736 "Sets default flags for the STscript parser.": "設定 STscript 解析器的預設標誌",
737 "Parser Flags": "解析器標誌",737 "Parser Flags": "解析器標誌",
738 "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "切換到更嚴格的字元跳脫,允許所有分隔符號使用反斜線跳脫,反斜線自己也可以跳脫。",738 "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "切換到更嚴格的字元跳脫,允許所有分隔符號使用反斜線跳脫,反斜線自己也可以跳脫。",
739 "STRICT_ESCAPING": "STRICT_ESCAPING",739 "STRICT_ESCAPING": "STRICT_ESCAPING",
740 "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "將所有 {{getvar::}} 和 {{getglobalvar::}} 巨集取代為作用域變量以避免雙重巨集取代",740 "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "將所有 {{getvar::}} 和 {{getglobalvar::}} 巨集取代為作用域變量以避免雙重巨集取代",
741 "REPLACE_GETVAR": "REPLACE_GETVAR",741 "REPLACE_GETVAR": "REPLACE_GETVAR",
742 "Change Background Image": "更換背景圖片",742 "Change Background Image": "變更背景圖片",
743 "Filter": "篩選",743 "Filter": "篩選",
744 "Automatically select a background based on the chat context": "根據聊天上下文自動選擇背景",744 "Automatically select a background based on the chat context": "根據聊天上下文自動選擇背景",
745 "Auto-select": "自動選擇",745 "Auto-select": "自動選擇",
746 "System Backgrounds": "系統背景圖片",746 "System Backgrounds": "系統背景圖片",
747 "Chat Backgrounds": "聊天背景圖片",747 "Chat Backgrounds": "聊天背景圖片",
748 "bg_chat_hint_1": "使用擴充套件",748 "bg_chat_hint_1": "使用擴充功能",
749 "bg_chat_hint_2": "所產生的背景圖片將會出現在這裡。",749 "bg_chat_hint_2": "所產生的背景圖片將在此顯示。",
750 "Extensions": "擴充套件",750 "Extensions": "擴充功能",
751 "Notify on extension updates": "擴充套件更新時通知",751 "Notify on extension updates": "擴充功能更新時通知",
752 "Manage extensions": "管理擴充套件",752 "Manage extensions": "管理擴充功能",
753 "Import Extension From Git Repo": "從 Git 倉庫匯入擴充套件",753 "Import Extension From Git Repo": "從 Git 倉庫匯入擴充功能",
754 "Install extension": "安裝擴充套件",754 "Install extension": "安裝擴充功能",
755 "Extras API:": "Extras API:",755 "Extras API:": "擴充功能 API:",
756 "Auto-connect": "自動連線",756 "Auto-connect": "自動連線",
757 "Extras API URL": "Extras API URL",757 "Extras API URL": "擴充功能 API URL",
758 "Extras API key (optional)": "Extras API 金鑰(選填)",758 "Extras API key (optional)": "擴充功能 API 金鑰(選填)",
759 "Persona Management": "玩家角色人物管理",759 "Persona Management": "使用者角色管理",
760 "How do I use this?": "我該如何使用這個?",760 "How do I use this?": "我該如何使用這個?",
761 "Click for stats!": "點選查看統計!",761 "Click for stats!": "點擊以查看統計資料!",
762 "Usage Stats": "使用統計",762 "Usage Stats": "統計資料",
763 "Backup your personas to a file": "將您的玩家角色人物備份到檔案中",763 "Backup your personas to a file": "將您的使用者角色備份到檔案中",
764 "Backup": "備份",764 "Backup": "備份",
765 "Restore your personas from a file": "從檔案還原您的角色人物",765 "Restore your personas from a file": "從檔案還原您的角色",
766 "Restore": "還原",766 "Restore": "還原",
767 "Create a dummy persona": "建立一個假玩家角色人物",767 "Create a dummy persona": "建立一個虛構使用者角色",
768 "Create": "建立",768 "Create": "建立",
769 "Toggle grid view": "切換網格視圖",769 "Toggle grid view": "切換為網格視圖",
770 "No persona description": "無玩家角色人物描述",770 "No persona description": "無使用者角色描述",
771 "Name": "名稱",771 "Name": "名稱",
772 "Enter your name": "輸入您的名字",772 "Enter your name": "輸入您的名字",
773 "Click to set a new User Name": "點選以設置新使用者名稱",773 "Click to set a new User Name": "點選以設定新使用者名稱",
774 "Click to lock your selected persona to the current chat. Click again to remove the lock.": "點選以將所選玩家角色人物上鎖到目前聊天。再次點選以移除上鎖。",774 "Click to lock your selected persona to the current chat. Click again to remove the lock.": "點選以綁定目前所選的使用者角色至本次聊天。再次點選則可移除綁定。",
775 "Click to set user name for all messages": "點選以設置所有訊息的使用者名稱",775 "Click to set user name for all messages": "點選以設定所有訊息的使用者名稱",
776 "Persona Description": "玩家角色人物描述",776 "Persona Description": "使用者角色描述",
777 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]",777 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]",
778 "Tokens persona description": "符記角色人物描述",778 "Tokens persona description": "角色描述符元數",
779 "Position:": "位置:",779 "Position:": "插入位置:",
780 "In Story String / Prompt Manager": "在故事字串 / 提示詞管理器",780 "In Story String / Prompt Manager": "提示詞管理器/故事字串中",
781 "Top of Author's Note": "作者備註的頂部",781 "Top of Author's Note": "作者備註的頂部",
782 "Bottom of Author's Note": "作者備註的底部",782 "Bottom of Author's Note": "作者備註的底部",
783 "In-chat @ Depth": "聊天中 @ 深度",783 "In-chat @ Depth": "聊天中 @ 深度",
@@ -786,95 +786,95 @@
786 "System": "系統",786 "System": "系統",
787 "User": "使用者",787 "User": "使用者",
788 "Assistant": "助理",788 "Assistant": "助理",
789 "Show notifications on switching personas": "切換角色人物時顯示通知",789 "Show notifications on switching personas": "切換角色時顯示通知",
790 "Character Management": "角色人物管理",790 "Character Management": "角色管理",
791 "Locked = Character Management panel will stay open": "上鎖 = 角色人物管理面板將保持開啟",791 "Locked = Character Management panel will stay open": "上鎖 = 角色管理面板將保持開啟",
792 "Select/Create Characters": "選擇/建立角色人物",792 "Select/Create Characters": "選擇/建立角色",
793 "Favorite characters to add them to HotSwaps": "將角色人物加入到最愛來新增到快速切換",793 "Favorite characters to add them to HotSwaps": "將角色加入到最愛來新增到快速切換",
794 "Token counts may be inaccurate and provided just for reference.": "符記計數可能不準確,僅供參考。",794 "Token counts may be inaccurate and provided just for reference.": "符元計數可能不準確,僅供參考。",
795 "Total tokens": "符記總計",795 "Total tokens": "符元總計",
796 "Calculating...": "計算中...",796 "Calculating...": "計算中⋯",
797 "Tokens": "符記",797 "Tokens": "符元",
798 "Permanent tokens": "永久符記",798 "Permanent tokens": "永久符元",
799 "Permanent": "永久",799 "Permanent": "永久",
800 "About Token 'Limits'": "關於符記數「限制」",800 "About Token 'Limits'": "關於符元數「限制」",
801 "Toggle character info panel": "切換角色人物資訊面板",801 "Toggle character info panel": "切換角色資訊面板",
802 "Name this character": "為此角色人物命名",802 "Name this character": "為此角色命名",
803 "extension_token_counter": "符記:",803 "extension_token_counter": "符元:",
804 "Click to select a new avatar for this character": "點選以選擇此角色人物的新頭像",804 "Click to select a new avatar for this character": "點選以選擇此角色的新頭像",
805 "Add to Favorites": "新增至我的最愛",805 "Add to Favorites": "新增至我的最愛",
806 "Advanced Definition": "進階定義",806 "Advanced Definition": "進階定義",
807 "Character Lore": "角色人物知識書",807 "Character Lore": "角色知識書",
808 "Chat Lore": "聊天知識",808 "Chat Lore": "聊天知識書",
809 "Export and Download": "匯出和下載",809 "Export and Download": "匯出和下載",
810 "Duplicate Character": "複製角色人物",810 "Duplicate Character": "複製角色",
811 "Create Character": "建立角色人物",811 "Create Character": "建立角色",
812 "Delete Character": "刪除角色人物",812 "Delete Character": "刪除角色",
813 "More...": "更多...",813 "More...": "更多⋯",
814 "Link to World Info": "連結到世界資訊",814 "Link to World Info": "連結到世界資訊",
815 "Import Card Lore": "匯入卡片中的知識書",815 "Import Card Lore": "匯入卡片中的知識書",
816 "Scenario Override": "情境覆寫",816 "Scenario Override": "場景覆寫",
817 "Convert to Persona": "轉換為玩家角色人物",817 "Convert to Persona": "轉換為使用者角色",
818 "Rename": "重新命名",818 "Rename": "重新命名",
819 "Link to Source": "連結到來源",819 "Link to Source": "連結到來源",
820 "Replace / Update": "取代 / 更新",820 "Replace / Update": "取代/更新",
821 "Import Tags": "匯入標籤",821 "Import Tags": "匯入標籤",
822 "Search / Create Tags": "搜尋/建立標籤",822 "Search / Create Tags": "搜尋/建立標籤",
823 "View all tags": "查看所有標籤",823 "View all tags": "查看所有標籤",
824 "Creator's Notes": "建立者備註",824 "Creator's Notes": "創作者備註",
825 "Show / Hide Description and First Message": "顯示/隱藏描述和第一條訊息",825 "Show / Hide Description and First Message": "顯示/隱藏描述和第一則訊息",
826 "Character Description": "角色人物描述",826 "Character Description": "角色描述",
827 "Click to allow/forbid the use of external media for this character.": "點選以允許/禁止此角色人物使用外部媒體",827 "Click to allow/forbid the use of external media for this character.": "點選以允許/禁止此角色使用外部媒體",
828 "Ext. Media": "外部媒體權限",828 "Ext. Media": "外部媒體權限",
829 "Describe your character's physical and mental traits here.": "在此描述角色人物的身體和心理特徵。",829 "Describe your character's physical and mental traits here.": "在此描述角色的身體和心理特徵。",
830 "First message": "初始訊息",830 "First message": "初始訊息",
831 "Click to set additional greeting messages": "點選以設置額外的問候訊息",831 "Click to set additional greeting messages": "點選以設定額外的問候訊息",
832 "Alt. Greetings": "額外問候語",832 "Alt. Greetings": "額外問候語",
833 "This will be the first message from the character that starts every chat.": "這將是每次聊天開始時角色人物發送的第一條訊息。",833 "This will be the first message from the character that starts every chat.": "這將是每次聊天開始時角色發送的第一則訊息。",
834 "Group Controls": "群組控制",834 "Group Controls": "群組控制",
835 "Chat Name (Optional)": "聊天名稱(選填)",835 "Chat Name (Optional)": "聊天名稱(選填)",
836 "Click to select a new avatar for this group": "點選以選擇此群組的新頭像",836 "Click to select a new avatar for this group": "點選以選擇此群組的新頭像",
837 "Group reply strategy": "群組回應策略",837 "Group reply strategy": "群組回應策略",
838 "Natural order": "自然順序",838 "Natural order": "自然順序",
839 "List order": "清單順序",839 "List order": "清單順序",
840 "Group generation handling mode": "群組生成處理模式",840 "Group generation handling mode": "群組生成處理模式",
841 "Swap character cards": "交換角色人物卡",841 "Swap character cards": "交換角色卡",
842 "Join character cards (exclude muted)": "加入角色人物卡(排除靜音)",842 "Join character cards (exclude muted)": "合併角色卡欄位(排除靜音)",
843 "Join character cards (include muted)": "加入角色人物卡(包括靜音)",843 "Join character cards (include muted)": "合併角色卡欄位(包括靜音)",
844 "Inserted before each part of the joined fields.": "插入在合併欄位的每一部分之前。",844 "Inserted before each part of the joined fields.": "插入在合併欄位的每一部分之前。",
845 "Join Prefix": "加入前綴",845 "Join Prefix": "加入前綴",
846 "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)": "當選擇“加入角色卡”時,角色的所有對應欄位將連接在一起。\r這意味著,例如在故事字串中,所有角色描述都將連接到一個大文字中。\r如果您希望分隔這些字段,可以在此處定義前綴或後綴。\r\r該值支援普通宏,並且還將 {{char}} 替換為相關字元的名稱,並將 <FIELDNAME> 替換為部分的名稱(例如:描述、個性、場景等)",846 "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)": "選擇「合併角色卡欄位」時,所有角色的相關欄位將被合併。\r例如,在故事字串中,所有角色的描述將合併為一段大文本。\r若您希望這些欄位保持分隔,您可以在此定義前綴或後綴。\r\r此值支持常規巨集 {{macros}},並會將 {{char}} 替換為相關角色的名稱,可將 <FIELDNAME> 替換為欄位名稱(例如:角色描述、個性、場景等)。",
847 "Inserted after each part of the joined fields.": "插入在合併欄位的每一部分之後。",847 "Inserted after each part of the joined fields.": "插入在合併欄位的每一部分之後。",
848 "Join Suffix": "加入後綴",848 "Join Suffix": "加入後綴",
849 "Set a group chat scenario": "設定群組聊天情境",849 "Set a group chat scenario": "設定群組聊天場景",
850 "Click to allow/forbid the use of external media for this group.": "點選以允許/禁止此群組使用外部媒體",850 "Click to allow/forbid the use of external media for this group.": "點選以允許/禁止此群組使用外部媒體",
851 "Restore collage avatar": "還原預設頭像",851 "Restore collage avatar": "還原預設頭像",
852 "Allow self responses": "允許自我回應",852 "Allow self responses": "允許自我回應",
853 "Auto Mode": "自動模式",853 "Auto Mode": "自動模式",
854 "Auto Mode delay": "自動模式延遲",854 "Auto Mode delay": "自動模式延遲",
855 "Hide Muted Member Sprites": "隱藏靜音成員精靈",855 "Hide Muted Member Sprites": "於群組拼貼頭像中隱藏靜音成員",
856 "Current Members": "目前成員",856 "Current Members": "目前成員",
857 "Add Members": "新增成員",857 "Add Members": "新增成員",
858 "Create New Character": "建立新角色人物",858 "Create New Character": "創建角色",
859 "Import Character from File": "從檔案匯入角色人物",859 "Import Character from File": "由本地檔案匯入角色",
860 "Import content from external URL": "從外部 URL 匯入內容",860 "Import content from external URL": "由外部 URL 匯入內容",
861 "Create New Chat Group": "建立新聊天群組",861 "Create New Chat Group": "創建聊天群組",
862 "Characters sorting order": "角色人物排序依據",862 "Characters sorting order": "角色排序依據",
863 "A-Z": "A-Z",863 "A-Z": "A-Z",
864 "Z-A": "Z-A",864 "Z-A": "Z-A",
865 "Newest": "最新",865 "Newest": "最新",
866 "Oldest": "最舊",866 "Oldest": "最舊",
867 "Favorites": "我的最愛",867 "Favorites": "我的最愛",
868 "Recent": "最近",868 "Recent": "最近",
869 "Most chats": "最多聊天",869 "Most chats": "最常聊天",
870 "Least chats": "最少聊天",870 "Least chats": "最少聊天",
871 "Most tokens": "最多符記",871 "Most tokens": "最多符元",
872 "Least tokens": "最少符記",872 "Least tokens": "最少符元",
873 "Random": "隨機",873 "Random": "隨機",
874 "Toggle character grid view": "切換角色人物網格視圖",874 "Toggle character grid view": "切換為角色網格視圖",
875 "Bulk_edit_characters": "批量編輯角色人物\n\n點選以切換角色人物\nShift + 點選以選擇/取消選擇一範圍的角色人物\n右鍵以查看動作",875 "Bulk_edit_characters": "批次編輯角色\n\n點選以切換角色\n「Shift+點擊」可選擇/取消選擇範圍的角色\n右鍵以查看動作\n右鍵以查看動作",
876 "Bulk select all characters": "全選所有角色人物",876 "Bulk select all characters": "全選所有角色",
877 "Bulk delete characters": "批量刪除角色人物",877 "Bulk delete characters": "批次刪除角色",
878 "popup-button-save": "儲存",878 "popup-button-save": "儲存",
879 "popup-button-yes": "是",879 "popup-button-yes": "是",
880 "popup-button-no": "否",880 "popup-button-no": "否",
@@ -882,60 +882,59 @@
882 "popup-button-import": "匯入",882 "popup-button-import": "匯入",
883 "Advanced Defininitions": "- 進階定義",883 "Advanced Defininitions": "- 進階定義",
884 "Prompt Overrides": "提示詞覆寫",884 "Prompt Overrides": "提示詞覆寫",
885 "(For Chat Completion and Instruct Mode)": "(用於聊天補充和指令模式)",885 "(For Chat Completion and Instruct Mode)": "(用於聊天補全和指令模式)",
886 "Insert {{original}} into either box to include the respective default prompt from system settings.": "在任一框中插入 {{original}} 以包含系統設定中的預設提示詞。",886 "Insert {{original}} into either box to include the respective default prompt from system settings.": "在任一框中插入 {{original}} 以包含系統設定中的預設提示詞。",
887 "Main Prompt": "主要提示詞",887 "Main Prompt": "主要提示詞",
888 "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "此處的任何內容將取代此角色人物使用的預設主要提示詞。(v2 規範:system_prompt)",888 "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "此處的任何內容將取代此角色使用的預設主要提示詞。(v2 規範:system_prompt)",
889 "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "此處的任何內容將取代此角色人物使用的預設越獄提示詞。(v2 規範:post_history_instructions)",889 "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "此處的任何內容將取代此角色使用的預設越獄提示詞。(v2 規範:post_history_instructions)",
890 "Creator's Metadata (Not sent with the AI prompt)": "建立者的中繼資料(不會與 AI 提示詞一起發送)",890 "Creator's Metadata (Not sent with the AI prompt)": "創作者的中繼資料(不會與 AI 提示詞一起發送)",
891 "Creator's Metadata": "建立者的中繼資料",891 "Creator's Metadata": "創作者的中繼資料",
892 "(Not sent with the AI Prompt)": "(不與 AI 提示詞一起發送)",892 "(Not sent with the AI Prompt)": "(不與 AI 提示詞一起發送)",
893 "Everything here is optional": "此處所有內容均為選填",893 "Everything here is optional": "此處所有內容均為選填",
894 "(Botmaker's name / Contact Info)": "(機器人製作者的名字 / 聯繫資訊)",894 "(Botmaker's name / Contact Info)": "(機器人創作者的名字/聯絡資訊)",
895 "(If you want to track character versions)": "(如果您想追蹤角色人物版本)",895 "(If you want to track character versions)": "(若您想追蹤角色版本)",
896 "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(描述機器人,提供使用技巧,或列出已測試的聊天模型。這將顯示在角色人物列表中。)",896 "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "(描述機器人,提供使用技巧,或列出已測試的聊天模型。這將顯示在角色列表中。)",
897 "Tags to Embed": "嵌入標籤",897 "Tags to Embed": "嵌入標籤",
898 "(Write a comma-separated list of tags)": "(使用逗號分隔每個標籤)",898 "(Write a comma-separated list of tags)": "(使用逗號分隔每個標籤)",
899 "Personality summary": "個性摘要",899 "Personality summary": "個性摘要",
900 "(A brief description of the personality)": "(個性的簡短描述)",900 "(A brief description of the personality)": "(關於角色性格的簡要描述)",
901 "Scenario": "情境",901 "Scenario": "場景設想",
902 "(Circumstances and context of the interaction)": "(互動的情況和上下文)",902 "(Circumstances and context of the interaction)": "(互動情形與聊天背景)",
903 "Character's Note": "角色人物筆記",903 "Character's Note": "角色備註",
904 "(Text to be inserted in-chat @ designated depth and role)": "(要在聊天中插入的文字 @ 指定深度和角色)",904 "(Text to be inserted in-chat @ designated depth and role)": "(在聊天中以指定角色於 @ 深度位置插入文本)",
905 "@ Depth": "@ 深度",905 "@ Depth": "@ 深度",
906 "Role": "角色",906 "Role": "角色",
907 "Talkativeness": "健談度",907 "Talkativeness": "健談度",
908 "How often the character speaks in group chats!": "角色人物在群組聊天中說話的頻率!",908 "How often the character speaks in group chats!": "角色在群組聊天中說話的頻率!",
909 "How often the character speaks in": "角色說話的頻率",909 "How often the character speaks in": "角色說話的頻率",
910 "group chats!": "群組聊天!",910 "group chats!": "群組聊天!",
911 "Shy": "害羞",911 "Shy": "寡言",
912 "Normal": "正常",912 "Normal": "正常",
913 "Chatty": "健談",913 "Chatty": "健談",
914 "Examples of dialogue": "對話範例",914 "Examples of dialogue": "對話範例",
915 "Important to set the character's writing style.": "設定角色人物的寫作樣式很重要。",915 "Important to set the character's writing style.": "設定角色的寫作樣式很重要。",
916 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天對話範例。每個範例以新的行並以「START」開始。)",916 "(Examples of chat dialog. Begin each example with START on a new line.)": "(聊天對話範例。每個範例以新的行並以「START」開始。)",
917 "Save": "儲存",917 "Chat History": "聊天記錄",
918 "Chat History": "聊天紀錄",
919 "Import Chat": "匯入聊天",918 "Import Chat": "匯入聊天",
920 "Copy to system backgrounds": "複製到系統背景圖片",919 "Copy to system backgrounds": "複製到系統背景圖片",
921 "Rename background": "重新命名背景圖片",920 "Rename background": "重新命名背景圖片",
922 "Lock": "上鎖",921 "Lock": "上鎖",
923 "Unlock": "解鎖",922 "Unlock": "解鎖",
924 "Delete background": "刪除背景圖片",923 "Delete background": "刪除背景圖片",
925 "Chat Scenario Override": "聊天情境覆寫",924 "Chat Scenario Override": "聊天場景覆寫",
926 "Remove": "刪除",925 "Remove": "刪除",
927 "Type here...": "在此輸入...",926 "Type here...": "在此輸入⋯",
928 "Chat Lorebook": "聊天知識書",927 "Chat Lorebook": "聊天知識書",
929 "Chat Lorebook for": "聊天知識書",928 "Chat Lorebook for": "聊天知識書",
930 "chat_world_template_txt": "選定的世界資訊將附加到此聊天。\n在生成 AI 回覆時,它將與全域和角色知識書中的條目結合。",929 "chat_world_template_txt": "選定的世界資訊將附加到此聊天。\n在生成 AI 回覆時,它將與全域和角色知識書中的條目結合。",
931 "Select a World Info file for": "選擇世界資訊檔案",930 "Select a World Info file for": "選擇世界資訊檔案",
932 "Primary Lorebook": "主要知識書",931 "Primary Lorebook": "主要知識書",
933 "A selected World Info will be bound to this character as its own Lorebook.": "選定的世界資訊將作為此角色人物的知識書附加到此角色人物。",932 "A selected World Info will be bound to this character as its own Lorebook.": "選定的世界資訊將作為此角色的知識書附加到此角色。",
934 "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "生成 AI 回覆時,將與全域世界資訊選擇器中的條目結合。",933 "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "生成 AI 回覆時,將與全域世界資訊選擇器中的條目結合。",
935 "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "匯出角色人物時,也會匯出嵌入 JSON 資料中的選定知識書檔案。",934 "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "匯出角色時,也會匯出嵌入 JSON 資料中的選定知識書檔案。",
936 "Additional Lorebooks": "額外的知識書",935 "Additional Lorebooks": "額外的知識書",
937 "Associate one or more auxillary Lorebooks with this character.": "將一個或多個輔助知識書與此角色人物關聯。",936 "Associate one or more auxillary Lorebooks with this character.": "將一個或多個輔助知識書與此角色關聯。",
938 "NOTE: These choices are optional and won't be preserved on character export!": "注意:這些選項是選填的,在角色人物匯出時不會保留!",937 "NOTE: These choices are optional and won't be preserved on character export!": "請注意:此為額外選項,不會隨角色卡資料一同匯出!",
939 "Rename chat file": "重新命名聊天檔案",938 "Rename chat file": "重新命名聊天檔案",
940 "Export JSONL chat file": "匯出 JSONL 聊天檔案",939 "Export JSONL chat file": "匯出 JSONL 聊天檔案",
941 "Download chat as plain text document": "將聊天下載為純文字檔案",940 "Download chat as plain text document": "將聊天下載為純文字檔案",
@@ -943,15 +942,15 @@
943 "Drag to reorder tag": "拖動以重新排序標籤",942 "Drag to reorder tag": "拖動以重新排序標籤",
944 "Use tag as folder": "將標籤用作資料夾",943 "Use tag as folder": "將標籤用作資料夾",
945 "Delete tag": "刪除標籤",944 "Delete tag": "刪除標籤",
946 "Entry Title/Memo": "條目標題/備註",945 "Entry Title/Memo": "條目標題/備註",
947 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI條目狀態:🔵常數🟢正常🔗向量❌停用",946 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "世界資訊條目狀態:🔵常數 🟢正常 🔗向量 ❌停用",
948 "WI_Entry_Status_Constant": "🔵",947 "WI_Entry_Status_Constant": "🔵",
949 "WI_Entry_Status_Normal": "🟢",948 "WI_Entry_Status_Normal": "🟢",
950 "WI_Entry_Status_Vectorized": "🔗",949 "WI_Entry_Status_Vectorized": "🔗",
951 "WI_Entry_Status_Disabled": "❌",950 "WI_Entry_Status_Disabled": "❌",
952 "T_Position": "↑角色人物:角色人物定義之前\n↓角色人物:角色人物定義之後\n↑備註:作者備註之前\n↓備註:作者備註之後\n@深度",951 "T_Position": "↑角色:角色定義之前\n↓角色:角色定義之後\n↑備註:作者備註之前\n↓備註:作者備註之後\n@深度",
953 "Before Char Defs": "角色人物定義之前",952 "Before Char Defs": "角色定義之前",
954 "After Char Defs": "角色人物定義之後",953 "After Char Defs": "角色定義之後",
955 "Before EM": "範例訊息之前",954 "Before EM": "範例訊息之前",
956 "After EM": "範例訊息之後",955 "After EM": "範例訊息之後",
957 "Before AN": "作者備註之前",956 "Before AN": "作者備註之前",
@@ -962,11 +961,11 @@
962 "Depth": "深度",961 "Depth": "深度",
963 "Order:": "順序:",962 "Order:": "順序:",
964 "Order": "順序",963 "Order": "順序",
965 "Trigger %:": "觸發%",964 "Trigger %:": "觸發%:",
966 "Probability": "機率",965 "Probability": "機率",
967 "Duplicate world info entry": "複製世界資訊物件",966 "Duplicate world info entry": "複製世界資訊物件",
968 "Delete world info entry": "刪除世界資訊物件",967 "Delete world info entry": "刪除世界資訊物件",
969 "Comma separated (required)": "逗號分隔(必填)",968 "Comma separated (required)": "逗號分隔(必填)",
970 "Primary Keywords": "主要關鍵字",969 "Primary Keywords": "主要關鍵字",
971 "Keywords or Regexes": "關鍵字或正規表示式",970 "Keywords or Regexes": "關鍵字或正規表示式",
972 "Comma separated list": "逗號分隔列表",971 "Comma separated list": "逗號分隔列表",
@@ -976,27 +975,27 @@
976 "AND ALL": "AND 所有",975 "AND ALL": "AND 所有",
977 "NOT ALL": "NOT 所有",976 "NOT ALL": "NOT 所有",
978 "NOT ANY": "NOT 任何",977 "NOT ANY": "NOT 任何",
979 "(ignored if empty)": "(如果為空則忽略)",978 "(ignored if empty)": "(如果為空則忽略)",
980 "Optional Filter": "選填過濾器",979 "Optional Filter": "選填過濾器",
981 "Keywords or Regexes (ignored if empty)": "關鍵字或正規表示式(如果為空則忽略)",980 "Keywords or Regexes (ignored if empty)": "關鍵字或正規表示式(如果為空則忽略)",
982 "Comma separated list (ignored if empty)": "逗號分隔列表(如果為空則忽略)",981 "Comma separated list (ignored if empty)": "逗號分隔列表(如果為空則忽略)",
983 "Use global setting": "使用全域設定",982 "Use global setting": "使用全域設定",
984 "Case-Sensitive": "區分大小寫",983 "Case-Sensitive": "區分大小寫",
985 "Yes": "是",984 "Yes": "是",
986 "No": "否",985 "No": "否",
987 "Can be used to automatically activate Quick Replies": "可用於自動啟用快速回覆",986 "Can be used to automatically activate Quick Replies": "可用於自動啟用快速回覆",
988 "Automation ID": "自動化 ID",987 "Automation ID": "自動化 ID",
989 "( None )": "( 無 )",988 "( None )": "(無)",
990 "Content": "內容",989 "Content": "內容",
991 "Exclude from recursion": "不可遞迴(此條目不會被其他條目啟用)",990 "Exclude from recursion": "不可遞迴(此條目不會被其他條目啟用)",
992 "Prevent further recursion (this entry will not activate others)": "防止進一步遞迴(此條目不會啟用其他條目)",991 "Prevent further recursion (this entry will not activate others)": "防止進一步遞迴(此條目不會啟用其他條目)",
993 "Delay until recursion (this entry can only be activated on recursive checking)": "延遲遞迴(此條目只能在遞迴檢查時啟用)",992 "Delay until recursion (this entry can only be activated on recursive checking)": "延遲遞迴(此條目只能在遞迴檢查時啟用)",
994 "What this keyword should mean to the AI, sent verbatim": "這個關鍵字對 AI 應意味著什麼,逐字發送",993 "What this keyword should mean to the AI, sent verbatim": "這個關鍵字對 AI 應意味著什麼,逐字發送",
995 "Filter to Character(s)": "角色人物篩選",994 "Filter to Character(s)": "角色篩選",
996 "Character Exclusion": "角色人物排除",995 "Character Exclusion": "角色排除",
997 "-- Characters not found --": "-- 未找到角色人物 --",996 "-- Characters not found --": "-- 未找到角色 --",
998 "Inclusion Group": "包含的群組",997 "Inclusion Group": "包含的群組",
999 "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "如果觸發多個條目,包含群組可確保一次僅啟動一組中的一個條目。\r支援多個以逗號分隔的群組。\r\r文件:世界資訊 - 包容性集團",998 "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "如果觸發多個條目,包含群組可確保一次僅啟動一組中的一個條目。\r支援多個以逗號分隔的群組。\r\r文件:世界資訊——包容性集團",
1000 "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先考慮此條目:選取後,此條目將在所有選擇中優先。\r如果有多個優先級,則選擇「順序」最高的一個。",999 "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先考慮此條目:選取後,此條目將在所有選擇中優先。\r如果有多個優先級,則選擇「順序」最高的一個。",
1001 "Only one entry with the same label will be activated": "僅會啟用具有相同標籤的一個條目",1000 "Only one entry with the same label will be activated": "僅會啟用具有相同標籤的一個條目",
1002 "A relative likelihood of entry activation within the group": "群組內條目啟用的相對可能性",1001 "A relative likelihood of entry activation within the group": "群組內條目啟用的相對可能性",
@@ -1004,7 +1003,7 @@
1004 "Selective": "選擇性",1003 "Selective": "選擇性",
1005 "Use Probability": "使用機率",1004 "Use Probability": "使用機率",
1006 "Add Memo": "新增備忘錄",1005 "Add Memo": "新增備忘錄",
1007 "Text or token ids": "文字或符記 ID",1006 "Text or token ids": "文字或符元 ID",
1008 "close": "關閉",1007 "close": "關閉",
1009 "prompt_manager_edit": "編輯",1008 "prompt_manager_edit": "編輯",
1010 "prompt_manager_name": "名稱",1009 "prompt_manager_name": "名稱",
@@ -1015,18 +1014,19 @@
1015 "Injection position. Next to other prompts (relative) or in-chat (absolute).": "注入位置。與其他提示詞相鄰(相對位置)或在聊天中(絕對位置)。",1014 "Injection position. Next to other prompts (relative) or in-chat (absolute).": "注入位置。與其他提示詞相鄰(相對位置)或在聊天中(絕對位置)。",
1016 "prompt_manager_relative": "相對位置",1015 "prompt_manager_relative": "相對位置",
1017 "prompt_manager_depth": "深度",1016 "prompt_manager_depth": "深度",
1018 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最後一條訊息之後,1 = 在最後一條訊息之前,以此類推。",1017 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最後一則訊息之後,1 = 在最後一則訊息之前,以此類推。",
1019 "Prompt": "提示詞",1018 "Prompt": "提示詞",
1020 "The prompt to be sent.": "要發送的提示詞。",1019 "The prompt to be sent.": "要發送的提示詞。",
1021 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使啟用偏好覆寫,此提示詞也不能被角色卡片覆寫。",1020 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使啟用優先覆寫,此提示詞也不能被角色卡片覆寫。",
1022 "prompt_manager_forbid_overrides": "禁止覆寫",1021 "prompt_manager_forbid_overrides": "禁止覆寫",
1023 "reset": "重設",1022 "reset": "重設",
1024 "save": "節省",1023 "save": "儲存",
1025 "This message is invisible for the AI": "此訊息對 AI 不可見",1024 "This message is invisible for the AI": "此訊息對 AI 不可見",
1026 "Message Actions": "訊息動作",1025 "Message Actions": "訊息動作",
1027 "Translate message": "翻譯訊息",1026 "Translate message": "翻譯訊息",
1028 "Generate Image": "生成圖片",1027 "Generate Image": "生成圖片",
1029 "Narrate": "敘述",1028 "Stop Image Generation": "終止圖片生成",
1029 "Narrate": "朗讀訊息",
1030 "Exclude message from prompts": "從提示詞中排除訊息",1030 "Exclude message from prompts": "從提示詞中排除訊息",
1031 "Include message in prompts": "在提示詞中包含訊息",1031 "Include message in prompts": "在提示詞中包含訊息",
1032 "Embed file or image": "嵌入檔案或圖片",1032 "Embed file or image": "嵌入檔案或圖片",
@@ -1050,32 +1050,32 @@
1050 "welcome_message_part_6": "加入",1050 "welcome_message_part_6": "加入",
1051 "Discord server": "不和諧伺服器",1051 "Discord server": "不和諧伺服器",
1052 "welcome_message_part_7": "取得公告和資訊。",1052 "welcome_message_part_7": "取得公告和資訊。",
1053 "SillyTavern is aimed at advanced users.": "SillyTavern 旨在進階使用者",1053 "SillyTavern is aimed at advanced users.": "SillyTavern 專為進階使用者設計",
1054 "If you're new to this, enable the simplified UI mode below.": "如果您是新手,請啟用下方的簡化 UI 模式",1054 "If you're new to this, enable the simplified UI mode below.": "如果您是新手,請啟用下方的簡易 UI 模式",
1055 "Change it later in the 'User Settings' panel.": "稍後可在「使用者設定」面板中變更",1055 "Change it later in the 'User Settings' panel.": "稍後可在「使用者設定」面板中變更",
1056 "Enable simple UI mode": "啟用簡單 UI 模式",1056 "Enable simple UI mode": "啟用簡易 UI 模式",
1057 "Looking for AI characters?": "正在尋找 AI 角色人物?",1057 "Looking for AI characters?": "正在尋找 AI 角色?",
1058 "onboarding_import": "匯入",1058 "onboarding_import": "匯入",
1059 "from supported sources or view": "從支援的來源或檢視",1059 "from supported sources or view": "從支援的來源或檢視",
1060 "Sample characters": "範例角色人物",1060 "Sample characters": "範例角色",
1061 "Your Persona": "您的玩家角色人物",1061 "Your Persona": "您的使用者角色",
1062 "Before you get started, you must select a persona name.": "在開始之前,您必須選擇一個玩家角色人物名稱",1062 "Before you get started, you must select a persona name.": "在開始之前,您必須選擇一個使用者角色名稱",
1063 "welcome_message_part_8": "這個隨時可以透過",1063 "welcome_message_part_8": "這個隨時可以透過",
1064 "welcome_message_part_9": "圖示來變更。",1064 "welcome_message_part_9": "圖示來變更。",
1065 "Persona Name:": "玩家角色人物名稱",1065 "Persona Name:": "使用者角色名稱",
1066 "Temporarily disable automatic replies from this character": "暫時停用此角色人物的自動回覆",1066 "Temporarily disable automatic replies from this character": "暫時停用此角色的自動回覆",
1067 "Enable automatic replies from this character": "啟用此角色人物的自動回覆",1067 "Enable automatic replies from this character": "啟用此角色的自動回覆",
1068 "Trigger a message from this character": "觸發此角色人物的訊息",1068 "Trigger a message from this character": "觸發此角色的訊息",
1069 "Move up": "上移",1069 "Move up": "上移",
1070 "Move down": "下移",1070 "Move down": "下移",
1071 "View character card": "查看角色人物卡",1071 "View character card": "查看角色卡",
1072 "Remove from group": "從群組中移除",1072 "Remove from group": "從群組中移除",
1073 "Add to group": "新增到群組",1073 "Add to group": "新增到群組",
1074 "Alternate Greetings": "額外問候語",1074 "Alternate Greetings": "額外問候語",
1075 "Alternate_Greetings_desc": "這些將在開始新聊天時顯示為第一條訊息的滑動選項。\n群組成員可以選擇其中之一來開始對話。",1075 "Alternate_Greetings_desc": "這些將在開始新聊天時顯示為第一則訊息的滑動選項。\n群組成員可以選擇其中之一來開始對話。",
1076 "Alternate Greetings Hint": "額外問候語的提示訊息",1076 "Alternate Greetings Hint": "額外問候語的提示訊息",
1077 "(This will be the first message from the character that starts every chat)": "(這將是每次聊天開始時角色人物發送的第一條訊息)",1077 "(This will be the first message from the character that starts every chat)": "(這將是每次聊天開始時角色發送的第一則訊息)",
1078 "Forbid Media Override explanation": "當前角色/群組在聊天中使用外部媒體的能力。",1078 "Forbid Media Override explanation": "此角色/群組在聊天中使用外部媒體的能力。",
1079 "Forbid Media Override subtitle": "禁止媒體覆寫副標題",1079 "Forbid Media Override subtitle": "禁止媒體覆寫副標題",
1080 "Always forbidden": "總是禁止",1080 "Always forbidden": "總是禁止",
1081 "Always allowed": "總是允許",1081 "Always allowed": "總是允許",
@@ -1083,17 +1083,17 @@
1083 "Remove the file": "刪除檔案",1083 "Remove the file": "刪除檔案",
1084 "Unique to this chat": "此聊天獨有",1084 "Unique to this chat": "此聊天獨有",
1085 "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "檢查點繼承其上級的註釋,之後可以單獨更改",1085 "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "檢查點繼承其上級的註釋,之後可以單獨更改",
1086 "Include in World Info Scanning": "包括在世界資訊掃描中",1086 "Include in World Info Scanning": "納入世界資訊掃描",
1087 "Before Main Prompt / Story String": "在主要提示詞 / 故事字串之前",1087 "Before Main Prompt / Story String": "在主要提示詞/故事字串之前",
1088 "After Main Prompt / Story String": "在主要提示詞 / 故事字串之後",1088 "After Main Prompt / Story String": "在主要提示詞/故事字串之後",
1089 "as": "作為",1089 "as": "作為",
1090 "Insertion Frequency": "插入頻率",1090 "Insertion Frequency": "插入頻率",
1091 "(0 = Disable, 1 = Always)": "(0 = 停用, 1 = 永久)",1091 "(0 = Disable, 1 = Always)": "(0 = 停用, 1 = 永久)",
1092 "User inputs until next insertion:": "使用者輸入直到下一次插入:",1092 "User inputs until next insertion:": "使用者輸入直到下一次插入:",
1093 "Character Author's Note (Private)": "角色人物作者備註(私人)",1093 "Character Author's Note (Private)": "角色作者備註(私人)",
1094 "Won't be shared with the character card on export.": "不會在匯出時與角色人物卡共享",1094 "Won't be shared with the character card on export.": "不會在匯出時與角色卡共享",
1095 "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "將自動新增為此角色人物的作者備註。將在群組中使用,但在群組聊天開啟時無法修改",1095 "Will be automatically added as the author's note for this character. Will be used in groups, but can't be modified when a group chat is open.": "將自動新增為此角色的作者備註。將在群組中使用,但在群組聊天開啟時無法修改",
1096 "Use character author's note": "使用角色人物作者備註",1096 "Use character author's note": "使用角色作者備註",
1097 "Replace Author's Note": "取代作者註釋",1097 "Replace Author's Note": "取代作者註釋",
1098 "Default Author's Note": "預設作者註釋",1098 "Default Author's Note": "預設作者註釋",
1099 "Will be automatically added as the Author's Note for all new chats.": "將自動新增為所有新聊天的作者備註",1099 "Will be automatically added as the Author's Note for all new chats.": "將自動新增為所有新聊天的作者備註",
@@ -1101,29 +1101,29 @@
1101 "1 = disabled": "1 = 停用",1101 "1 = disabled": "1 = 停用",
1102 "write short replies, write replies using past tense": "撰寫簡短回覆,使用過去式撰寫回覆",1102 "write short replies, write replies using past tense": "撰寫簡短回覆,使用過去式撰寫回覆",
1103 "Positive Prompt": "正面提示詞",1103 "Positive Prompt": "正面提示詞",
1104 "Use character CFG scales": "使用角色人物 CFG 比例",1104 "Use character CFG scales": "使用角色 CFG 比例",
1105 "Character CFG": "角色人物 CFG",1105 "Character CFG": "角色 CFG",
1106 "Will be automatically added as the CFG for this character.": "將自動新增為此角色人物的 CFG",1106 "Will be automatically added as the CFG for this character.": "將自動新增為此角色的 CFG",
1107 "Global CFG": "全域 CFG",1107 "Global CFG": "全域 CFG",
1108 "Will be used as the default CFG options for every chat unless overridden.": "將作為每次聊天的預設 CFG 選項,除非被覆寫",1108 "Will be used as the default CFG options for every chat unless overridden.": "將作為每次聊天的預設 CFG 選項,除非被覆寫",
1109 "CFG Prompt Cascading": "CFG 提示詞級聯",1109 "CFG Prompt Cascading": "CFG 提示詞級聯",
1110 "Combine positive/negative prompts from other boxes.": "結合其他文字方塊中的正/負提示詞",1110 "Combine positive/negative prompts from other boxes.": "結合其他文字方塊中的正/負提示詞",
1111 "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "例如,勾選聊天、全域和角色人物框將所有負面提示詞合併為一個逗號分隔的字串",1111 "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "例如:勾選聊天、全域和角色框將所有負面提示詞合併為一個逗號分隔的字串",
1112 "Always Include": "總是包含",1112 "Always Include": "總是包含",
1113 "Chat Negatives": "聊天負面提示詞",1113 "Chat Negatives": "聊天負面提示詞",
1114 "Character Negatives": "角色人物負面提示詞",1114 "Character Negatives": "角色負面提示詞",
1115 "Global Negatives": "全域負面提示詞",1115 "Global Negatives": "全域負面提示詞",
1116 "Custom Separator:": "自訂分隔符:",1116 "Custom Separator:": "自訂分隔符:",
1117 "Insertion Depth:": "插入深度:",1117 "Insertion Depth:": "插入深度:",
1118 "Token Probabilities": "符記機率",1118 "Token Probabilities": "符元機率",
1119 "Select a token to see alternatives considered by the AI.": "選擇一個符記以檢視 AI 考慮的替代方案",1119 "Select a token to see alternatives considered by the AI.": "選擇一個符元以檢視 AI 考慮的替代方案",
1120 "Not connected to API!": "未連線到 API!",1120 "Not connected to API!": "未連線到 API!",
1121 "Type a message, or /? for help": "輸入一個訊息,或輸入 /? 取得支援",1121 "Type a message, or /? for help": "輸入訊息,或 /? 取得支援",
1122 "Continue script execution": "繼續腳本執行",1122 "Continue script execution": "繼續腳本執行",
1123 "Pause script execution": "暫停腳本執行",1123 "Pause script execution": "暫停腳本執行",
1124 "Abort script execution": "中止腳本執行",1124 "Abort script execution": "中止腳本執行",
1125 "Abort request": "中止請求",1125 "Abort request": "中止請求",
1126 "Continue the last message": "繼續上次的訊息",1126 "Continue the last message": "繼續生成最新訊息",
1127 "Send a message": "發送訊息",1127 "Send a message": "發送訊息",
1128 "Close chat": "關閉聊天",1128 "Close chat": "關閉聊天",
1129 "Toggle Panels": "切換面板",1129 "Toggle Panels": "切換面板",
@@ -1133,20 +1133,20 @@
1133 "Start new chat": "開始新聊天",1133 "Start new chat": "開始新聊天",
1134 "Manage chat files": "管理聊天檔案",1134 "Manage chat files": "管理聊天檔案",
1135 "Delete messages": "刪除訊息",1135 "Delete messages": "刪除訊息",
1136 "Regenerate": "重新生成",1136 "Regenerate": "進階提示詞設定",
1137 "Ask AI to write your message for you": "請 AI 為您撰寫訊息",1137 "Ask AI to write your message for you": "請 AI 為您撰寫訊息",
1138 "Impersonate": "AI 扮演使用者",1138 "Impersonate": "AI 扮演使用者",
1139 "Continue": "繼續",1139 "Continue": "繼續",
1140 "Bind user name to that avatar": "將使用者名稱附加到該頭像",1140 "Bind user name to that avatar": "將使用者名稱附加到該頭像",
1141 "Change persona image": "更改玩家角色人物圖片",1141 "Change persona image": "更改使用者角色圖片",
1142 "Select this as default persona for the new chats.": "選擇此作為新聊天的預設玩家角色人物。",1142 "Select this as default persona for the new chats.": "選擇此作為新聊天的預設使用者角色。",
1143 "Delete persona": "刪除玩家角色人物",1143 "Delete persona": "刪除使用者角色",
1144 "These characters are the winners of character design contests and have outstandable quality.": "這些角色都是角色設計比賽的優勝者,品質卓越。",1144 "These characters are the winners of character design contests and have outstandable quality.": "這些角色都是角色設計比賽的優勝者,品質卓越。",
1145 "Contest Winners": "比賽獲勝者",1145 "Contest Winners": "比賽獲勝者",
1146 "These characters are the finalists of character design contests and have remarkable quality.": "這些角色都是角色設計比賽的入圍作品,品質卓越。",1146 "These characters are the finalists of character design contests and have remarkable quality.": "這些角色都是角色設計比賽的入圍作品,品質卓越。",
1147 "Featured Characters": "特色角色人物",1147 "Featured Characters": "特色角色",
1148 "Attach a File": "附加檔案",1148 "Attach a File": "上傳附件檔案",
1149 "Open Data Bank": "打開資料儲藏庫",1149 "Open Data Bank": "開啟資料庫",
1150 "Enter a URL or the ID of a Fandom wiki page to scrape:": "輸入 URL 或 Fandom 維基頁面的 ID 來抓取:",1150 "Enter a URL or the ID of a Fandom wiki page to scrape:": "輸入 URL 或 Fandom 維基頁面的 ID 來抓取:",
1151 "Examples:": "範例:",1151 "Examples:": "範例:",
1152 "Example:": "範例:",1152 "Example:": "範例:",
@@ -1154,89 +1154,90 @@
1154 "All articles will be concatenated into a single file.": "所有文章將連接成一個檔案。",1154 "All articles will be concatenated into a single file.": "所有文章將連接成一個檔案。",
1155 "File per article": "每篇文章一個檔案",1155 "File per article": "每篇文章一個檔案",
1156 "Each article will be saved as a separate file.": "每篇文章將另存為一個檔案。",1156 "Each article will be saved as a separate file.": "每篇文章將另存為一個檔案。",
1157 "Data Bank": "資料儲藏庫",1157 "Data Bank": "資料庫",
1158 "These files will be available for extensions that support attachments (e.g. Vector Storage).": "這些檔案將可用於支援附件的擴充套件(例如向量存儲)。",1158 "These files will be available for extensions that support attachments (e.g. Vector Storage).": "這些檔案將可用於支援附件的擴充功能(例如向量存儲)。",
1159 "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支援的檔案類型:純文字,PDF,Markdown,HTML,EPUB。",1159 "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支援的檔案類型:純文字,PDF,Markdown,HTML,EPUB。",
1160 "Drag and drop files here to upload.": "拖放檔案到這裡以上傳。",1160 "Drag and drop files here to upload.": "拖放檔案至此即可上傳。",
1161 "Date (Newest First)": "日期(最新優先)",1161 "Date (Newest First)": "日期(最新優先)",
1162 "Date (Oldest First)": "日期(最舊優先)",1162 "Date (Oldest First)": "日期(最舊優先)",
1163 "Name (A-Z)": "名稱(A-Z)",1163 "Name (A-Z)": "名稱(A-Z)",
1164 "Name (Z-A)": "名稱(Z-A)",1164 "Name (Z-A)": "名稱(Z-A)",
1165 "Size (Smallest First)": "尺寸(由小到大)",1165 "Size (Smallest First)": "尺寸(由小到大)",
1166 "Size (Largest First)": "尺寸(由大到小)",1166 "Size (Largest First)": "尺寸(由大到小)",
1167 "Bulk Edit": "批次編輯",1167 "Bulk Edit": "批次編輯",
1168 "Select All": "全選",1168 "Select All": "全選",
1169 "Select None": "選擇無",1169 "Select None": "選擇無",
1170 "Global Attachments": "全域附件",1170 "Global Attachments": "全域附件",
1171 "These files are available for all characters in all chats.": "這些檔案在所有聊天中的所有角色人物中可用。",1171 "These files are available for all characters in all chats.": "適用於所有聊天、所有角色。",
1172 "Character Attachments": "角色人物附件",1172 "Character Attachments": "角色附件",
1173 "These files are available the current character in all chats they are in.": "這些檔案在當前角色人物參與的所有聊天中可用。",1173 "These files are available the current character in all chats they are in.": "適用於該角色參與的所有聊天。",
1174 "Saved locally. Not exported.": "本機儲存。不匯出。",1174 "Saved locally. Not exported.": "僅本地保存,不匯出。",
1175 "Chat Attachments": "聊天附件",1175 "Chat Attachments": "聊天附件",
1176 "These files are available to all characters in the current chat.": "這些檔案在當前聊天中的所有角色人物中可用。",1176 "These files are available to all characters in the current chat.": "適用於本次聊天中的所有角色。",
1177 "Enter a base URL of the MediaWiki to scrape.": "輸入要抓取的 MediaWiki 的基礎 URL。",1177 "Enter a base URL of the MediaWiki to scrape.": "輸入要抓取的 MediaWiki 的基礎 URL。",
1178 "Don't include the page name!": "不要包括頁面名稱!",1178 "Don't include the page name!": "不要包括頁面名稱!",
1179 "Enter web URLs to scrape (one per line):": "輸入要抓取的網頁 URL(每行一個):",1179 "Enter web URLs to scrape (one per line):": "輸入要抓取的網頁 URL(每行一個):",
1180 "Enter a video URL to download its transcript.": "輸入影片 URL 來下載其文字記錄。",1180 "Enter a video URL to download its transcript.": "輸入影片 URL 來下載其文字記錄。",
1181 "Expression API": "表達 API",1181 "Expression API": "表達 API",
1182 "Fallback Expression": "回退表達式",1182 "Fallback Expression": "回退表達式",
1183 "ext_sum_with": "總結一下:",1183 "ext_sum_title": "聊天摘要",
1184 "ext_sum_main_api": "主要API",1184 "ext_sum_with": "摘要來源",
1185 "ext_sum_current_summary": "目前摘要:",1185 "ext_sum_main_api": "主要 API",
1186 "ext_sum_restore_previous": "恢復上一個",1186 "ext_sum_current_summary": "摘要內容:",
1187 "ext_sum_memory_placeholder": "摘要將在此處產生...",1187 "ext_sum_restore_previous": "還原為上一則",
1188 "Trigger a summary update right now.": "立即觸發摘要更新。",1188 "ext_sum_memory_placeholder": "將在此生成摘要⋯",
1189 "ext_sum_force_text": "現在總結一下",1189 "Trigger a summary update right now.": "立即更新摘要內容。",
1190 "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "停用自動摘要更新。暫停時,摘要保持原樣。您仍然可以透過按下「立即匯總」按鈕強制更新(僅適用於 Main API)。",1190 "ext_sum_force_text": "重新摘要",
1191 "Disable automatic summary updates. While paused, the summary remains as-is. You can still force an update by pressing the Summarize now button (which is only available with the Main API).": "停用自動摘要更新。暫停時,摘要保持原樣。您仍可以透過點擊「重新摘要」按鈕強制更新(僅適用於使用「主要 API」)。",
1191 "ext_sum_pause": "暫停",1192 "ext_sum_pause": "暫停",
1192 "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "從要總結的文本中省略世界資訊和作者備註。僅在使用主要 API 時有效。額外 API 總是省略 WI/AN。",1193 "Omit World Info and Author's Note from text to be summarized. Only has an effect when using the Main API. The Extras API always omits WI/AN.": "摘要時將省略世界資訊和作者備註。此選項僅適用於使用主要 API,擴充功能 API 始終自動省略世界資訊與作者備註。",
1193 "ext_sum_no_wi_an": "無無線網路/無線網路",1194 "ext_sum_no_wi_an": "排除世界資訊及作者備註",
1194 "ext_sum_settings_tip": "編輯摘要提示、插入位置等",1195 "ext_sum_settings_tip": "編輯摘要提示、插入位置等",
1195 "ext_sum_settings": "摘要設定",1196 "ext_sum_settings": "摘要設定",
1196 "ext_sum_prompt_builder": "提示產生器",1197 "ext_sum_prompt_builder": "摘要提示詞產生器",
1197 "ext_sum_prompt_builder_1_desc": "擴充功能將使用尚未匯總的訊息建立自己的提示。阻止聊天,直到產生摘要。",1198 "ext_sum_prompt_builder_1_desc": "將使用尚未摘要的訊息以建立摘要提示詞,在完成摘要前將暫停聊天功能。",
1198 "ext_sum_prompt_builder_1": "原始、阻塞",1199 "ext_sum_prompt_builder_1": "原始、阻塞",
1199 "ext_sum_prompt_builder_2_desc": "擴充功能將使用尚未匯總的訊息建立自己的提示。產生摘要時不會阻止聊天。並非所有後端都支援此模式。",1200 "ext_sum_prompt_builder_2_desc": "將使用尚未摘要的訊息自動建立摘要提示詞,在完成摘要前仍可正常進行聊天。並非所有後端都支援此模式。",
1200 "ext_sum_prompt_builder_2": "原始、非阻塞",1201 "ext_sum_prompt_builder_2": "原始、非阻塞",
1201 "ext_sum_prompt_builder_3_desc": "擴充功能將使用常規主提示產生器並將摘要請求新增至其中作為最後一個系統訊息。",1202 "ext_sum_prompt_builder_3_desc": "將使用常規主提示產生器,並將摘要請求新增至其中作為最後一則系統訊息。",
1202 "ext_sum_prompt_builder_3": "經典,阻塞",1203 "ext_sum_prompt_builder_3": "經典、阻塞",
1203 "Summary Prompt": "摘要提示詞",1204 "Summary Prompt": "摘要提示詞",
1204 "ext_sum_restore_default_prompt_tip": "恢復預設提示",1205 "ext_sum_restore_default_prompt_tip": "還原為預設提示詞",
1205 "ext_sum_prompt_placeholder": "這個提示詞將發送給 AI 以請求生成摘要。{{words}} 將解析為「字數」參數。",1206 "ext_sum_prompt_placeholder": "此提示詞將發送給 AI 以請求生成摘要。{{words}} 將解析為「字數」參數。",
1206 "ext_sum_target_length_1": "目標摘要長度",1207 "ext_sum_target_length_1": "目標摘要長度",
1207 "ext_sum_target_length_2": "(",1208 "ext_sum_target_length_2": "(",
1208 "ext_sum_target_length_3": "字)",1209 "ext_sum_target_length_3": "字)",
1209 "ext_sum_api_response_length_1": "API響應長度",1210 "ext_sum_api_response_length_1": "API 響應長度",
1210 "ext_sum_api_response_length_2": "(",1211 "ext_sum_api_response_length_2": "(",
1211 "ext_sum_api_response_length_3": "代幣)",1212 "ext_sum_api_response_length_3": "個符元)",
1212 "ext_sum_0_default": "0 = 預設",1213 "ext_sum_0_default": "0 = 預設",
1213 "ext_sum_raw_max_msg": "[原始] 每個請求的最大訊息數",1214 "ext_sum_raw_max_msg": "[原始] 每則請求的最大訊息數",
1214 "ext_sum_0_unlimited": "0 = 無限制",1215 "ext_sum_0_unlimited": "0 = 無限制",
1215 "Update frequency": "更新頻率",1216 "Update frequency": "更新頻率",
1216 "ext_sum_update_every_messages_1": "更新每",1217 "ext_sum_update_every_messages_1": "更新每",
1217 "ext_sum_update_every_messages_2": "訊息",1218 "ext_sum_update_every_messages_2": " 訊息",
1218 "ext_sum_0_disable": "0 = 停用",1219 "ext_sum_0_disable": "0 = 停用",
1219 "ext_sum_auto_adjust_desc": "嘗試根據聊天指標自動調整間隔。",1220 "ext_sum_auto_adjust_desc": "嘗試根據聊天指標自動調整更新間隔。",
1220 "ext_sum_update_every_words_1": "更新每",1221 "ext_sum_update_every_words_1": "更新每",
1221 "ext_sum_update_every_words_2": "字",1222 "ext_sum_update_every_words_2": " 字",
1222 "ext_sum_both_sliders": "如果兩個滑桿都非零,則兩者都將按各自的時間間隔觸發摘要更新。",1223 "ext_sum_both_sliders": "若兩個滑桿數值皆不為零,則將各自按照其時間間隔更新摘要。",
1223 "ext_sum_injection_template": "注射模板",1224 "ext_sum_injection_template": "插入模板",
1224 "ext_sum_memory_template_placeholder": "{{summary}} 會解析為目前的摘要內容。",1225 "ext_sum_memory_template_placeholder": "{{summary}} 會解析為目前的摘要內容。",
1225 "ext_sum_injection_position": "注射位置",1226 "ext_sum_injection_position": "插入位置",
1226 "How many messages before the current end of the chat.": "在聊天目前結束前有多少訊息。",1227 "How many messages before the current end of the chat.": "距離本次聊天結尾前的訊息數量。",
1227 "ext_regex_title": "正規表示式",1228 "ext_regex_title": "正規表示式",
1228 "ext_regex_new_global_script": "+ 全球",1229 "ext_regex_new_global_script": "+ 全域",
1229 "ext_regex_new_scoped_script": "+ 範圍",1230 "ext_regex_new_scoped_script": "+ 局部",
1230 "ext_regex_import_script": "匯入腳本",1231 "ext_regex_import_script": "匯入腳本",
1231 "ext_regex_global_scripts": "全域腳本",1232 "ext_regex_global_scripts": "全域腳本",
1232 "ext_regex_global_scripts_desc": "適用於所有角色。儲存到本地設定。",1233 "ext_regex_global_scripts_desc": "適用於所有角色,資料將儲存到本地。",
1233 "ext_regex_scoped_scripts": "作用域腳本",1234 "ext_regex_scoped_scripts": "局部腳本",
1234 "ext_regex_scoped_scripts_desc": "僅適用於此角色。儲存到卡片資料中。",1235 "ext_regex_scoped_scripts_desc": "僅適用於目前角色,資料將儲存到該角色卡中。",
1235 "Regex Editor": "正規表示式編輯器",1236 "Regex Editor": "正規表示式編輯器",
1236 "Test Mode": "測試模式",1237 "Test Mode": "測試模式",
1237 "ext_regex_desc": "正規表示式(Regex)是一種使用正規表示式尋找/取代字串的工具。如果您想了解更多,請點選標題旁邊的(?)",1238 "ext_regex_desc": "正規表示式(Regex)是一種使用正規表示式尋找/取代字串的工具。如果您想了解更多,請點選標題旁邊的「?」",
1238 "Input": "輸入",1239 "Input": "輸入",
1239 "ext_regex_test_input_placeholder": "在此輸入...",1240 "ext_regex_test_input_placeholder": "在此輸入⋯",
1240 "Output": "輸出",1241 "Output": "輸出",
1241 "ext_regex_output_placeholder": "空的",1242 "ext_regex_output_placeholder": "空的",
1242 "Script Name": "腳本名稱",1243 "Script Name": "腳本名稱",
@@ -1254,42 +1255,42 @@
1254 "ext_regex_min_depth_placeholder": "無限制",1255 "ext_regex_min_depth_placeholder": "無限制",
1255 "ext_regex_max_depth_desc": "當應用於提示或顯示時,僅影響不超過 N 層深度的訊息。 0 = 最後一則訊息,1 = 倒數第二個訊息等。",1256 "ext_regex_max_depth_desc": "當應用於提示或顯示時,僅影響不超過 N 層深度的訊息。 0 = 最後一則訊息,1 = 倒數第二個訊息等。",
1256 "ext_regex_other_options": "其他選項",1257 "ext_regex_other_options": "其他選項",
1257 "Only Format Display": "僅格式化顯示",1258 "Only Format Display": "僅修改聊天顯示",
1258 "ext_regex_only_format_prompt_desc": "聊天記錄不會更改,只會更改發送請求時的提示(生成時)。",1259 "ext_regex_only_format_prompt_desc": "不修改聊天記錄,僅修改發送訊息(請求文本生成時)時的系統提示詞。",
1259 "Only Format Prompt (?)": "僅格式化提示詞(?)",1260 "Only Format Prompt (?)": "僅修改系統提示詞",
1260 "Run On Edit": "編輯時執行",1261 "Run On Edit": "編輯時執行",
1261 "ext_regex_substitute_regex_desc": "在執行「尋找正規表示式」前取代 {{macros}}",1262 "ext_regex_substitute_regex_desc": "在執行「尋找正規表達式」前,將 {{巨集}} 替換為對應內容",
1262 "Substitute Regex": "取代正規表示式",1263 "Substitute Regex": "取代正規表示式",
1263 "ext_regex_import_target": "導入至:",1264 "ext_regex_import_target": "匯入至:",
1264 "ext_regex_disable_script": "停用腳本",1265 "ext_regex_disable_script": "停用腳本",
1265 "ext_regex_enable_script": "啟用腳本",1266 "ext_regex_enable_script": "啟用腳本",
1266 "ext_regex_edit_script": "編輯腳本",1267 "ext_regex_edit_script": "編輯腳本",
1267 "ext_regex_move_to_global": "移至全域腳本",1268 "ext_regex_move_to_global": "移至全域腳本",
1268 "ext_regex_move_to_scoped": "移至作用域腳本",1269 "ext_regex_move_to_scoped": "移至作用域腳本",
1269 "ext_regex_export_script": "導出腳本",1270 "ext_regex_export_script": "匯出腳本",
1270 "ext_regex_delete_script": "刪除腳本",1271 "ext_regex_delete_script": "刪除腳本",
1271 "Trigger Stable Diffusion": "觸發 Stable Diffusion",1272 "Trigger Stable Diffusion": "觸發 Stable Diffusion",
1272 "sd_Yourself": "角色人物",1273 "sd_Yourself": "角色",
1273 "sd_Your_Face": "角色人物的臉",1274 "sd_Your_Face": "角色的臉",
1274 "sd_Me": "玩家",1275 "sd_Me": "使用者",
1275 "sd_The_Whole_Story": "整篇故事",1276 "sd_The_Whole_Story": "整篇故事",
1276 "sd_The_Last_Message": "最後一個訊息",1277 "sd_The_Last_Message": "最後一則訊息",
1277 "sd_Raw_Last_Message": "最後一個原始訊息",1278 "sd_Raw_Last_Message": "最後一則原始訊息",
1278 "sd_Background": "背景",1279 "sd_Background": "背景",
1279 "Image Generation": "圖片生成",1280 "Image Generation": "圖片生成設定",
1280 "sd_refine_mode": "允許在傳送至生成 API 前,手動編輯提示詞字串",1281 "sd_refine_mode": "允許在傳送至生成 API 前,手動編輯提示詞字串",
1281 "sd_refine_mode_txt": "生成前編輯提示詞",1282 "sd_refine_mode_txt": "生成前編輯提示詞",
1282 "sd_interactive_mode": "當發送「給我一張貓的圖片」這類訊息時,自動生成圖片。",1283 "sd_interactive_mode": "當發送「給我一張貓的圖片」這類訊息時,自動生成圖片。",
1283 "sd_interactive_mode_txt": "互動模式",1284 "sd_interactive_mode_txt": "互動模式",
1284 "sd_multimodal_captioning": "根據使用者和角色人物的頭像,使用多模態模型描述生成肖像提示詞。",1285 "sd_multimodal_captioning": "根據使用者和角色的頭像,使用多模態模型描述生成肖像提示詞。",
1285 "sd_multimodal_captioning_txt": "對肖像使用多模態模型描述",1286 "sd_multimodal_captioning_txt": "對肖像使用多模態模型描述",
1286 "sd_expand": "使用文字生成模型自動擴充提示詞。",1287 "sd_expand": "使用文本生成模型自動擴寫提示詞。",
1287 "sd_expand_txt": "自動擴充提示詞",1288 "sd_expand_txt": "自動潤色提示詞",
1288 "sd_snap": "對於具有特定長寬比的生成請求(如肖像、背景),將其調整至最接近的已知解析度,同時儘量保持絕對像素數(建議用於SDXL)。",1289 "sd_snap": "對於具有特定長寬比的生成請求(如肖像、背景),將其調整至最接近的已知解析度,同時儘量保持絕對像素數(建議用於 SDXL)。",
1289 "sd_snap_txt": "自動調整解析度",1290 "sd_snap_txt": "自動調整解析度",
1290 "Source": "來源",1291 "Source": "來源",
1291 "sd_auto_url": "範例: {{auto_url}}",1292 "sd_auto_url": "範例: {{auto_url}}",
1292 "Authentication (optional)": "授權驗證(選填)",1293 "Authentication (optional)": "授權驗證(選填)",
1293 "Example: username:password": "範例:帳號:密碼",1294 "Example: username:password": "範例:帳號:密碼",
1294 "Important:": "重要:",1295 "Important:": "重要:",
1295 "sd_auto_auth_warning_1": "使用",1296 "sd_auto_auth_warning_1": "使用",
@@ -1298,9 +1299,9 @@
1298 "sd_drawthings_auth_txt": "執行 DrawThings 應用程式並在介面中啟用 HTTP API 開關!伺服器必須能夠被 SillyTavern 主機存取。",1299 "sd_drawthings_auth_txt": "執行 DrawThings 應用程式並在介面中啟用 HTTP API 開關!伺服器必須能夠被 SillyTavern 主機存取。",
1299 "sd_vlad_url": "範例: {{vlad_url}}",1300 "sd_vlad_url": "範例: {{vlad_url}}",
1300 "The server must be accessible from the SillyTavern host machine.": "伺服器必須能夠被 SillyTavern 主機存取。",1301 "The server must be accessible from the SillyTavern host machine.": "伺服器必須能夠被 SillyTavern 主機存取。",
1301 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "提示訊息:在 Horde KoboldAI API 設定中儲存一個 API 金鑰,以便在此使用。",1302 "Hint: Save an API key in AI Horde API settings to use it here.": "提示訊息:在 AI Horde API 設定中儲存一個 API 金鑰,以便在此使用。",
1302 "Allow NSFW images from Horde": "允許來自 Horde 的 NSFW 圖片",1303 "Allow NSFW images from Horde": "允許來自 Horde 的 NSFW 圖片",
1303 "Sanitize prompts (recommended)": "清理提示詞(建議)",1304 "Sanitize prompts (recommended)": "清理提示詞(建議)",
1304 "Automatically adjust generation parameters to ensure free image generations.": "自動調整生成參數以確保生成免費的圖片。",1305 "Automatically adjust generation parameters to ensure free image generations.": "自動調整生成參數以確保生成免費的圖片。",
1305 "Avoid spending Anlas": "避免消耗 Anlas 點數",1306 "Avoid spending Anlas": "避免消耗 Anlas 點數",
1306 "Opus tier": "Opus 級別",1307 "Opus tier": "Opus 級別",
@@ -1318,12 +1319,12 @@
1318 "Refine": "精煉",1319 "Refine": "精煉",
1319 "Decrisper": "德克里斯珀",1320 "Decrisper": "德克里斯珀",
1320 "Sampling steps": "取樣步數",1321 "Sampling steps": "取樣步數",
1321 "Width": "寬度(W)",1322 "Width": "寬度(Width)",
1322 "Height": "高度(H)",1323 "Height": "高度(Height)",
1323 "Resolution": "解析度",1324 "Resolution": "解析度",
1324 "Model": "模型",1325 "Model": "模型",
1325 "Sampling method": "取樣方法",1326 "Sampling method": "取樣方法",
1326 "Karras (not all samplers supported)": "Karras(並非所有取樣器都支援)",1327 "Karras (not all samplers supported)": "Karras(並非所有取樣器均受支援)",
1327 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的取樣器經過修改,能在高解析度下表現更佳。",1328 "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA 版本的取樣器經過修改,能在高解析度下表現更佳。",
1328 "SMEA": "SMEA",1329 "SMEA": "SMEA",
1329 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 取樣器的 DYN 變體通常會產生更多樣化的輸出,但在非常高的解析度下可能會失敗。",1330 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 取樣器的 DYN 變體通常會產生更多樣化的輸出,但在非常高的解析度下可能會失敗。",
@@ -1334,21 +1335,21 @@
1334 "Upscaler": "放大演算法",1335 "Upscaler": "放大演算法",
1335 "Upscale by": "放大倍率",1336 "Upscale by": "放大倍率",
1336 "Denoising strength": "重繪幅度",1337 "Denoising strength": "重繪幅度",
1337 "Hires steps (2nd pass)": "高解析步驟 (2nd pass)",1338 "Hires steps (2nd pass)": "高解析步驟(2nd pass)",
1338 "Preset for prompt prefix and negative prompt": "提示詞前綴和負面提示詞的預設設定",1339 "Preset for prompt prefix and negative prompt": "提示詞前綴和負面提示詞的預設設定",
1339 "Style": "樣式",1340 "Style": "樣式",
1340 "Save style": "儲存樣式",1341 "Save style": "儲存樣式",
1341 "Delete style": "刪除樣式",1342 "Delete style": "刪除樣式",
1342 "Common prompt prefix": "通用提示詞前綴",1343 "Common prompt prefix": "通用提示詞前綴",
1343 "sd_prompt_prefix_placeholder": "使用 {prompt} 指定生成的提示詞將被插入的位置。",1344 "sd_prompt_prefix_placeholder": "使用 {prompt} 指定生成的提示詞將被插入的位置。",
1344 "Negative common prompt prefix": "負面通用提示詞前綴",1345 "Negative common prompt prefix": "通用負面提示詞前綴",
1345 "Character-specific prompt prefix": "角色人物特定提示詞前綴",1346 "Character-specific prompt prefix": "角色提示詞前綴",
1346 "Won't be used in groups.": "不會用在群組",1347 "Won't be used in groups.": "群聊中無效",
1347 "sd_character_prompt_placeholder": "描述當前選擇角色人物的特徵。這些特徵將增加在通用提示詞前綴之後。\n例如:女性、綠色眼睛、棕色頭髮、粉紅色襯衫。",1348 "sd_character_prompt_placeholder": "描述該角色的特徵。這些特徵將添加在通用提示詞前綴之後。例如:女性、綠色眼睛、棕色頭髮、粉紅色襯衫。",
1348 "Character-specific negative prompt prefix": "角色人物特定負面提示詞前綴",1349 "Character-specific negative prompt prefix": "角色負面提示詞前綴",
1349 "sd_character_negative_prompt_placeholder": "不應出現在選定角色人物上的任何特徵。這些特徵將增加在負面通用提示詞前綴之後。例如:珠寶、鞋子、眼鏡。",1350 "sd_character_negative_prompt_placeholder": "不應出現在該角色上的任何特徵。這些特徵將添加在負面通用提示詞前綴之後。例如:珠寶、鞋子、眼鏡。",
1350 "Shareable": "可分享",1351 "Shareable": "分享至角色卡",
1351 "Image Prompt Templates": "圖片提示詞範本",1352 "Image Prompt Templates": "圖片生成提示詞",
1352 "Vectors Model Warning": "向量模型警告",1353 "Vectors Model Warning": "向量模型警告",
1353 "Translate files into English before processing": "處理前將檔案翻譯成英文",1354 "Translate files into English before processing": "處理前將檔案翻譯成英文",
1354 "Manager Users": "管理使用者",1355 "Manager Users": "管理使用者",
@@ -1359,7 +1360,7 @@
1359 "User Handle:": "使用者控制代碼:",1360 "User Handle:": "使用者控制代碼:",
1360 "Password:": "密碼:",1361 "Password:": "密碼:",
1361 "Confirm Password:": "確認密碼:",1362 "Confirm Password:": "確認密碼:",
1362 "This will create a new subfolder...": "這將建立一個新的子資料夾...",1363 "This will create a new subfolder...": "這將建立一個新的子資料夾⋯",
1363 "Current Password:": "目前密碼:",1364 "Current Password:": "目前密碼:",
1364 "New Password:": "新密碼:",1365 "New Password:": "新密碼:",
1365 "Confirm New Password:": "確認新密碼:",1366 "Confirm New Password:": "確認新密碼:",
@@ -1371,27 +1372,27 @@
1371 "Warning:": "警告:",1372 "Warning:": "警告:",
1372 "This action is irreversible.": "此動作不可逆轉。",1373 "This action is irreversible.": "此動作不可逆轉。",
1373 "Type the user's handle below to confirm:": "在下方輸入使用者的控制代碼以確認:",1374 "Type the user's handle below to confirm:": "在下方輸入使用者的控制代碼以確認:",
1374 "Import Characters": "導入角色",1375 "Import Characters": "匯入角色",
1375 "Enter the URL of the content to import": "輸入要匯入的內容的 URL",1376 "Enter the URL of the content to import": "輸入要匯入的內容的 URL",
1376 "Supported sources:": "支持的來源:",1377 "Supported sources:": "支持的來源:",
1377 "char_import_1": "Chub角色(直接連結或ID)",1378 "char_import_1": "Chub角色(直接連結或 ID)",
1378 "char_import_example": "例子:",1379 "char_import_example": "例子:",
1379 "char_import_2": "Chub Lorebook(直接連結或ID)",1380 "char_import_2": "Chub Lorebook(直接連結或 ID)",
1380 "char_import_3": "JanitorAI 角色(直接連結或 UUID)",1381 "char_import_3": "JanitorAI 角色(直接連結或 ID)",
1381 "char_import_4": "Pygmalion.chat 角色(直接連結或 UUID)",1382 "char_import_4": "Pygmalion.chat 角色(直接連結或 ID)",
1382 "char_import_5": "AICharacterCard.com 角色(直接連結或 ID)",1383 "char_import_5": "AICharacterCard.com 角色(直接連結或 ID)",
1383 "char_import_6": "直接 PNG 連結(請參閱",1384 "char_import_6": "直接 PNG 連結(請參閱",
1384 "char_import_7": "對於允許的主機)",1385 "char_import_7": "對於允許的主機)",
1385 "char_import_8": "RisuRealm角色(直接連結)",1386 "char_import_8": "RisuRealm角色(直接連結)",
1386 "Supports importing multiple characters.": "支援導入多個字元。",1387 "Supports importing multiple characters.": "支援匯入多個字元。",
1387 "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。",1388 "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。",
1388 "Export for character": "匯出字符",1389 "Export for character": "匯出字符",
1389 "Export prompts for this character, including their order.": "匯出該角色的提示,包括其順序。",1390 "Export prompts for this character, including their order.": "匯出該角色的提示,包括其順序。",
1390 "Export all": "全部導出",1391 "Export all": "全部匯出",
1391 "Export all your prompts to a file": "將所有提示匯出到文件",1392 "Export all your prompts to a file": "將所有提示匯出到文件",
1392 "Insert prompt": "插入提示",1393 "Insert prompt": "插入提示",
1393 "Delete prompt": "刪除提示",1394 "Delete prompt": "刪除提示",
1394 "Import a prompt list": "導入提示列表",1395 "Import a prompt list": "匯入提示列表",
1395 "Export this prompt list": "匯出此提示列表",1396 "Export this prompt list": "匯出此提示列表",
1396 "Reset current character": "重置目前字符",1397 "Reset current character": "重置目前字符",
1397 "New prompt": "新提示",1398 "New prompt": "新提示",
@@ -1399,16 +1400,16 @@
1399 "Total Tokens:": "代幣總數:",1400 "Total Tokens:": "代幣總數:",
1400 "prompt_manager_tokens": "代幣",1401 "prompt_manager_tokens": "代幣",
1401 "Are you sure you want to reset your settings to factory defaults?": "您確定要將設定重設為原廠預設值嗎?",1402 "Are you sure you want to reset your settings to factory defaults?": "您確定要將設定重設為原廠預設值嗎?",
1402 "Don't forget to save a snapshot of your settings before proceeding.": "在繼續之前,請不要忘記儲存您的設定快照。",1403 "Don't forget to save a snapshot of your settings before proceeding.": "在繼續之前,請不要忘記進行備份。",
1403 "Settings Snapshots": "設定值快照",1404 "Settings Snapshots": "設定備份",
1404 "Record a snapshot of your current settings.": "記錄目前設定的快照。",1405 "Record a snapshot of your current settings.": "記錄目前設定的快照。",
1405 "Make a Snapshot": "建立快照",1406 "Make a Snapshot": "建立快照",
1406 "Restore this snapshot": "恢復此快照",1407 "Restore this snapshot": "還原此快照",
1407 "Hi,": "嗨,",1408 "Hi,": "嗨,",
1408 "To enable multi-account features, restart the SillyTavern server with": "要啟用多帳號功能,請在 config.yaml 文件中將",1409 "To enable multi-account features, restart the SillyTavern server with": "要啟用多帳號功能,請在 config.yaml 文件中將",
1409 "set to true in the config.yaml file.": "設為 true,然後重啟 SillyTavern 伺服器。",1410 "set to true in the config.yaml file.": "設為 true 後重啟 SillyTavern 伺服器。",
1410 "Account Info": "帳號資訊",1411 "Account Info": "帳號資訊",
1411 "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "要更改您的使用者頭像,請使用下方按鈕或在玩家角色管理選單中選擇一個預設人物。",1412 "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "要更改您的使用者頭像,請使用下方按鈕或在使用者角色管理選單中選擇一個預設人物。",
1412 "Set your custom avatar.": "設定您的頭像。",1413 "Set your custom avatar.": "設定您的頭像。",
1413 "Remove your custom avatar.": "移除您的頭像。",1414 "Remove your custom avatar.": "移除您的頭像。",
1414 "Handle:": "使用者名稱:",1415 "Handle:": "使用者名稱:",
@@ -1422,18 +1423,18 @@
1422 "Danger Zone": "危險區域",1423 "Danger Zone": "危險區域",
1423 "Reset your settings to factory defaults.": "將您的設定值還原為原廠預設值。",1424 "Reset your settings to factory defaults.": "將您的設定值還原為原廠預設值。",
1424 "Reset Settings": "重設設定值",1425 "Reset Settings": "重設設定值",
1425 "Wipe all user data and reset your account to factory settings.": "刪除您所有使用者設定以及帳號,還原成原廠預設值。",1426 "Wipe all user data and reset your account to factory settings.": "刪除您所有的使用者設定以及帳號資料,並恢復為系統預設值。",
1426 "Reset Everything": "重設全部",1427 "Reset Everything": "刪除所有資料",
1427 "Reset Code:": "重設驗證碼:",1428 "Reset Code:": "重設驗證碼:",
1428 "Want to update?": "想要更新嗎?",1429 "Want to update?": "想更新到最新版嗎?",
1429 "How to start chatting?": "如何開始聊天?",1430 "How to start chatting?": "如何開始聊天?",
1430 "Click _space": "點選",1431 "Click _space": "點選",
1431 "and select a": "並選擇一個",1432 "and select a": "並擇一",
1432 "Chat API": "聊天 API",1433 "Chat API": "聊天 API",
1433 "and pick a character.": "並選擇一個角色人物。",1434 "and pick a character.": "並選擇一個角色。",
1434 "You can browse a list of bundled characters in the": "您可以在",1435 "You can browse a list of bundled characters in the": "您可以在",
1435 "Download Extensions & Assets": "下載擴充套件和資產",1436 "Download Extensions & Assets": "下載擴充功能&額外資源",
1436 "menu within": "選單中瀏覽內建角色人物列表",1437 "menu within": "選單中瀏覽內建角色列表",
1437 "Confused or lost?": "困惑或迷路了嗎?",1438 "Confused or lost?": "困惑或迷路了嗎?",
1438 "click these icons!": "點選這些圖示!",1439 "click these icons!": "點選這些圖示!",
1439 "in the chat bar": "到聊天欄中",1440 "in the chat bar": "到聊天欄中",
@@ -1442,5 +1443,864 @@
1442 "Still have questions?": "還有問題嗎?",1443 "Still have questions?": "還有問題嗎?",
1443 "Join the SillyTavern Discord": "加入 SillyTavern Discord",1444 "Join the SillyTavern Discord": "加入 SillyTavern Discord",
1444 "Post a GitHub issue": "發布 GitHub 問題",1445 "Post a GitHub issue": "發布 GitHub 問題",
1445 "Contact the developers": "聯繫開發者"1446 "Contact the developers": "聯繫開發者",
1447 "(-1 for random)": "(-1 表示隨機)",
1448 "(Optional)": "(可選)",
1449 "(use _space": "(使用",
1450 "api_no_connection": "未連線⋯",
1451 "No model description": "[無描述]",
1452 "openai_logit_bias_no_items": "無項目",
1453 "Any contents here will replace the default Post-History Instructions used for this character. (v2 specpost_history_instructions)": "此處填入的內容將取代該角色的默認聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)",
1454 "comma delimited,no spaces between": "逗號分割,無需空格",
1455 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",
1456 "Example: gpt-3.5-turbo": "例如:gpt-3.5-turbo",
1457 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
1458 "popup-button-crop": "裁剪",
1459 "(disabled when max recursion steps are used)": "(當最大遞歸步驟數使用時將停用)",
1460 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\n(disabled when min activations are used)": "0 = 無限制,1 = 掃描一次且不遞歸,2 = 掃描一次並遞歸一次,以此類推\n(使用最小啟動設定時將停用)",
1461 "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "一種用於 LLM 抽樣的貪婪演算法,用於尋找最可能的單詞或標記序列。該方法會同時展開多個候選序列,並在每一步中保持固定數量的頂級序列(beam width)。",
1462 "A multiplicative factor to expand the overall area that the nodes take up.": "節點佔用該擴充功能區域的倍數。",
1463 "Abort current image generation task": "終止目前的圖片生成任務",
1464 "Add Character and User names to a list of stopping strings.": "將角色和使用者角色名稱添加至停止字符列表。",
1465 "Alignment for rank nodes.": "對排名節點的對齊方式。",
1466 "Always show the node full info panel at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的完整資訊面板顯示在時間軸視圖的左下角。關閉時,將顯示在節點附近。",
1467 "Always show the node tooltip at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的工具提示欄顯示在時間軸視圖的左下角。關閉時,將顯示在節點附近。",
1468 "Apply current sorting as Order": "應用此排序為順序",
1469 "Cap the number of entry activation recursions": "限制入口啟動的遞歸次數",
1470 "Caption": "標題",
1471 "Close popup": "關閉彈出視窗",
1472 "Color configuration for Timelines when 'Use UI Theme' in Style Settings is off.": "關閉「使用介面主題」的時間線顏色。",
1473 "context_allow_post_history_instructions": "在文本完成模式中包含聊天歷史後指示(Post-History Instructions),但可能導致不良輸出。",
1474 "Create a new connection profile": "建立新的連線設定檔",
1475 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定義匯入角色卡時應採取的動作。選擇「詢問」將始終顯示對話框。",
1476 "delay_until_recursion_level": "定義遞迴掃描的延遲層級。\r最初僅匹配第一層(數字最小的層級)。\r未找到匹配時,下一層將成為可匹配的層級。\r此過程會重複,直到所有層級都被檢查完畢。\r與「延遲至遞歸」設定相關聯。",
1477 "Delete a connection profile": "刪除連線設定檔",
1478 "Delete template": "刪除模板",
1479 "Delete the template": "刪除此模板",
1480 "Disabling is not recommended.": "不建議禁用。",
1481 "Display swipe numbers for all messages, not just the last.": "顯示所有訊息的滑動編號,而不僅是最後一條訊息。",
1482 "Duplicate persona": "複製使用者角色",
1483 "Edit a connection profile": "編輯連線設定檔",
1484 "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "啟用自動選擇輸入框中的文本,適用於彈出輸入框及其他自定義輸入框。",
1485 "Entries with a cooldown can't be activated N messages after being triggered.": "設有冷卻時間的條目於觸發後的 N 條訊息內無法再次啟用。",
1486 "Entries with a delay can't be activated until there are N messages present in the chat.": "有延遲的條目需等待聊天中出現 N 條訊息後才能啟用。",
1487 "Expand swipe nodes when the timeline view first opens, and whenever the graph is refreshed. When off, you can expand them by long-pressing a node, or by pressing the Toggle Swipes button.": "時間線視圖首次打開或刷新時展開滑動節點。關閉時可通過長按節點或點選「切換滑動」按鈕展開。",
1488 "Export Advanced Formatting settings": "匯出進階格式設定",
1489 "Export template": "匯出模板",
1490 "Find similar characters": "尋找相似角色",
1491 "Height of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時的節點像素高度。",
1492 "How the automatic graph builder assigns a rank (layout depth) to graph nodes.": "自動圖表生成器分配圖節點等級(佈局深度)的方式。",
1493 "If checked and the character card contains a Post-History Instructions override, use that instead": "勾選後,將使用角色卡中的聊天歷史後指示(Post-History Instructions)覆蓋。",
1494 "Import Advanced Formatting settings": "匯入進階格式設定\n也可提供舊版檔案作為提示詞和上下文範本使用",
1495 "Import template": "匯入模板",
1496 "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群組聊天中,突出顯示該生成回應的角色及順序。",
1497 "Include names with each message into the context for scanning": "將每條訊息的名稱納入掃描上下文",
1498 "Inserted before the first User's message": "插入到第一條使用者訊息前。",
1499 "instruct_enabled": "啟用指令模式(Instruct Mode)",
1500 "instruct_last_input_sequence": "插入到最後一條使用者訊息之前。",
1501 "instruct_template_activation_regex_desc": "連線 API 或選擇模型時,若模型名稱符合所提供的正規表達式,則自動啟動該指令模板(Instruct Template)。",
1502 "Load Asset List": "載入資源列表",
1503 "load_asset_list_desc": "根據資源列表文件載入擴充功能及資源。\n\n該字段中的默認資源 URL 指向官方擴充功能及資源列表。\n可在此插入您的自定義資源列表。\n\n若需安裝單個第三方擴充功能,請使用右上角的「安裝擴充功能」按鈕。",
1504 "markdown_hotkeys_desc": "啟用快捷鍵以在某些文本輸入框中插入 Markdown 格式字符。詳見「/help hotkeys」。",
1505 "Not all samplers supported.": "並非所有採樣器均受支援。",
1506 "Open the timeline view. Same as the slash command '/tl'.": "打開時間線視圖,與斜線指令「/tl」相同。",
1507 "Penalize sequences based on their length.": "根據序列長度進行懲罰。",
1508 "Reload a connection profile": "重新載入連線設定檔",
1509 "Rename current preset": "重新命名此預設",
1510 "Rename current prompt": "重新命名此提示詞",
1511 "Rename current template": "重新命名此模板",
1512 "Reset all Timelines settings to their default values.": "將所有時間軸設定重置為預設值。",
1513 "Restore current prompt": "還原目前的提示詞",
1514 "Restore current template": "還原目前的模板",
1515 "Save prompt as": "另存提示詞為",
1516 "Save template as": "另存模板為",
1517 "sd_adetailer_face": "在生成過程中使用 ADetailer 臉部模型。需在後端安裝 ADetailer 擴充功能。",
1518 "sd_free_extend": "自動使用目前選定的 LLM 擴充功能的「自由模式」提示詞(不包括肖像或背景)。",
1519 "sd_function_tool": "使用功能工具自動檢測意圖以生成圖片。",
1520 "Seed_desc": "用於生成確定性和可重現輸出的隨機種子。設定為 -1 時將使用隨機種子。",
1521 "Select your current Context Template": "選擇您目前的上下文模板",
1522 "Select your current Instruct Template": "選擇您目前的指令模板",
1523 "Select your current System Prompt": "選擇您目前的系統提示詞",
1524 "Separation between adjacent edges in the same rank.": "同一層級中相鄰邊之間的間距。",
1525 "Separation between adjacent nodes in the same rank.": "同一層級中相鄰節點之間的間距。",
1526 "Separation between each rank in the layout.": "佈局中各層級之間的間距。",
1527 "Settings for the visual appearance of the Timelines graph.": "時間線圖形的視覺外觀設置。",
1528 "Show a button in the input area to ask the AI to impersonate your character for a single message": "於輸入框中添加按鈕,讓 AI 模仿您的角色發送一則訊息。",
1529 "Show a legend for colors corresponding to different characters and chat checkpoints.": "顯示一個圖例,標註不同角色和對話檢查點對應的顏色。",
1530 "Show the AI character's avatar as the graph root node. When off, the root node is blank.": "將 AI 角色的頭像作為圖形的根節點;關閉時,根節點為空。",
1531 "Sticky entries will stay active for N messages after being triggered.": "觸發後,置頂條目將在接下來的 N 條訊息中保持活躍。",
1532 "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} 和 {{getglobalvar::}} 巨集的字面巨集樣值被自動解析。\n例如,{{newline}} 將保持為字面字串 {{newline}}。\n\n(此功能通過內部將 {{getvar::}} 和 {{getglobalvar::}} 巨集替換為局部變數來實現。)",
1533 "Style and routing of graph edges.": "圖形邊的樣式和路徑。",
1534 "Swap width and height": "交換寬度與高度",
1535 "Swipe left": "向左滑動",
1536 "Swipe right": "向右滑動",
1537 "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切換角色/標籤篩選,將列出的角色和標籤從此條目的匹配中排除",
1538 "sysprompt_enabled": "啟用系統提示詞",
1539 "The number of sequences generated at each step with Beam Search.": "在 Beam Search 中每一步生成的序列數量。",
1540 "The visual appearance of a node in the graph.": "圖形中節點的視覺外觀。",
1541 "Update a connection profile": "更新連線設定檔",
1542 "Update current prompt": "更新此提示詞",
1543 "Update current template": "更新此模板",
1544 "Use GPU acceleration for positioning the full info panel that appears when you click a node. If the tooltip arrow tends to disappear, turning this off may help.": "啟用 GPU 加速來定位點擊節點時出現的完整資訊面板。若發現工具提示箭頭經常消失,可考慮關閉此功能。",
1545 "Use the colors of the ST GUI theme, instead of the colors configured in Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。",
1546 "View connection profile details": "查看連線設定檔詳情",
1547 "When enabled, nodes that have swipes splitting off of them will appear subtly larger, in addition to having the double border.": "啟用後,具分支滑動的節點將顯示雙重邊框,還會略微放大。",
1548 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界資訊條目狀態:\\r🔵 恆定\\r🟢 正常\\r🔗 向量化",
1549 "Width of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時,節點的像素寬度。",
1550 "world_button_title": "角色背景設定\n點擊以載入\n「Shift+點擊」可開啟「連結至世界資訊」彈窗",
1551 "# of Beams": "# of Beams",
1552 "01.AI API Key": "01.AI API 金鑰",
1553 "01.AI Model": "01.AI 模型",
1554 "取消": "取消匯入",
1555 "Additional Parameters": "其他參數",
1556 "All": "全部",
1557 "Allow fallback models": "允許回退模型",
1558 "Allow fallback providers": "允許回退供應商",
1559 "Allow Post-History Instructions": "允許聊天歷史後指示",
1560 "Allow reverse proxy": "允許反向代理",
1561 "Alternate Greeting #": "備選問候語 #",
1562 "alternate_greetings_hint_1": "點擊",
1563 "alternate_greetings_hint_2": "按鈕開始!",
1564 "Always": "總是",
1565 "ANY support requests will be REFUSED if you are using a proxy.": "使用代理時,所有支援請求均不予受理。",
1566 "API": "API",
1567 "API Key": "API 金鑰",
1568 "Ask": "詢問",
1569 "Ask every time": "每次都詢問",
1570 "Assets URL": "資源 URL",
1571 "Assistant Message Sequences": "助理訊息序列",
1572 "Assistant Prefix": "助理訊息前綴",
1573 "Assistant Suffix": "助理訊息後綴",
1574 "at the end of the URL!": "在 URL 末尾!",
1575 "Audio Playback Speed": "音檔播放速度",
1576 "Auto-select Input Text": "自動選擇輸入文本",
1577 "Automatically caption images": "自動為圖片添加註解",
1578 "Auxiliary": "輔助提示詞",
1579 "Background Image": "背景圖片",
1580 "Block Entropy API Key": "Block Entropy API 金鑰",
1581 "Can be set manually or with an _space": "可以手動設置或使用 _space",
1582 "Caption Prompt": "註解功能提示詞",
1583 "category": "類別",
1584 "Character Expressions": "角色情緒立繪",
1585 "Character Node Color": "角色節點顏色",
1586 "character_names_none": "避免使用角色名稱作為前綴。此功能在群組中可能表現不理想,需謹慎考慮。",
1587 "Characters": "角色",
1588 "Chat Message Visibility (by source)": "聊天訊息可見性(按來源)",
1589 "Chat vectorization settings": "聊天向量化設定",
1590 "Checked: all entries except ❌ status can be activated.": "勾選:除 ❌ 狀態外的所有條目均可啟動。",
1591 "Checkpoint Color": "檢查點節點邊框顏色",
1592 "Chunk boundary": "Chunk 邊界",
1593 "Chunk overlap (%)": "Chunk 重疊(%)",
1594 "Chunk size (chars)": "Chunk 大小(字符數)",
1595 "class": "所有類別",
1596 "Classifier API": "分類器 API",
1597 "Click to set": "點擊以設定",
1598 "CLIP Skip": "CLIP 跳過",
1599 "Completion Object": "完成對象",
1600 "Conf": "設定檔",
1601 "Connection Profile": "連線設定檔",
1602 "Cooldown": "冷卻時間",
1603 "Create new folder in the _space": "請在「SillyTavern > data > 使用者資料夾 > ",
1604 "currently_loaded": "[目前已載入]",
1605 "currently_selected": "[目前已選取]",
1606 "Custom (OpenAI-compatible)": "自定義(相容 OpenAI)",
1607 "Custom Expressions": "自定義角色表情",
1608 "Data Bank files": "數據庫文件",
1609 "Default / Fallback Expression": "默認/回退表情",
1610 "Delay": "延遲",
1611 "Delay until recursion (can only be activated on recursive checking)": "遞迴掃描延遲(僅在啟用遞迴掃描時可用)",
1612 "Do not proceed if you do not agree to this!": "若不同意此條款,請勿繼續!",
1613 "Edge Color": "邊緣顏色",
1614 "Edit captions before saving": "在保存前編輯註解",
1615 "Enable for files": "啟用文件檔案向量化",
1616 "Enable for World Info": "啟用世界資訊向量化",
1617 "enable_functions_desc_1": "允許使用",
1618 "enable_functions_desc_2": "功能工具",
1619 "enable_functions_desc_3": "可供多種擴充功能利用,實現更多功能。",
1620 "Enabled for all entries": "對所有條目啟用",
1621 "Enabled for chat messages": "啟用聊天訊息向量化",
1622 "Endpoint URL": "端點 URL",
1623 "Enter a Model ID": "輸入模型 ID",
1624 "Example: https://****.endpoints.huggingface.cloud": "例如:https://****.endpoints.huggingface.cloud",
1625 "Exclude": "排除",
1626 "Exclude Top Choices (XTC)": "排除頂部選項(XTC)",
1627 "Existing": "現有項目",
1628 "expression_label_pattern": "[情緒名稱].[圖檔格式](例如:neutral.png)。",
1629 "ext_translate_auto_mode": "自動翻譯模式",
1630 "ext_translate_btn_chat": "翻譯聊天內容",
1631 "ext_translate_btn_input": "翻譯輸入內容",
1632 "ext_translate_clear": "清除翻譯",
1633 "ext_translate_mode_both": "翻譯輸入和回應",
1634 "ext_translate_mode_inputs": "僅翻譯輸入",
1635 "ext_translate_mode_none": "無翻譯",
1636 "ext_translate_mode_provider": "翻譯提供者",
1637 "ext_translate_mode_responses": "僅翻譯回應",
1638 "ext_translate_target_lang": "目標語言",
1639 "ext_translate_title": "聊天翻譯",
1640 "Extensions Menu": "擴充功能選單",
1641 "Extras": "擴充功能",
1642 "Extras API": "擴充功能 API",
1643 "Featherless Model Selection": "Featherless 模型選擇",
1644 "File vectorization settings": "檔案向量化設定",
1645 "Filter to Characters or Tags": "角色/標籤篩選",
1646 "First User Prefix": "第一使用者前綴",
1647 "folder of your user data directory and name it as the name of the character.": "」中新建資料夾,並將該資料夾命名為角色名稱(名稱需與使用者資料夾中的角色名稱一致)。",
1648 "Group Scoring": "群組評分",
1649 "Groups and Past Personas": "群組與過去的使用者角色設定",
1650 "Hint:": "提示:",
1651 "Hint: Set the URL in the API connection settings.": "提示:在 API 連線設置中設定 URL。",
1652 "Horde": "Horde",
1653 "HuggingFace Token": "HuggingFace 符元",
1654 "Image Captioning": "圖片註解",
1655 "Generate Caption": "生成圖片註解",
1656 "Image Type - talkinghead (extras)": "圖片類型 - talkinghead(額外選項)",
1657 "Injection Position": "插入位置",
1658 "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "插入位置(與提示詞管理器中的其他提示相比)或聊天中的深度位置。",
1659 "Injection Template": "插入範本",
1660 "Insert#": "插入#",
1661 "Instruct Sequences": "指令序列",
1662 "Instruct Template": "指令範本",
1663 "Interactive Mode": "互動模式",
1664 "Karras": "Karras",
1665 "Keep model in memory": "將模型保存在記憶體中",
1666 "Keyboard": "鍵盤:",
1667 "AI Horde Website": "AI Horde 網站",
1668 "Last User Prefix": "最後用戶前綴",
1669 "Linear": "線性",
1670 "LLM": "LLM",
1671 "LLM Prompt": "LLM 提示詞",
1672 "Load a custom asset list or select": "載入或選擇自定義資源列表",
1673 "Load an asset list": "載入資源列表",
1674 "Local": "本地",
1675 "Local (Transformers)": "本地(Transformers)",
1676 "macro)": "巨集)",
1677 "Main API": "主要 API",
1678 "Markdown Hotkeys": "Markdown 快捷鍵",
1679 "Master Export": "進階匯出",
1680 "Master Import": "進階匯入",
1681 "Max Entries": "最大條目數",
1682 "Max Recursion Steps": "最大遞迴步數",
1683 "Message attachments": "訊息附件",
1684 "Message Template": "註解訊息模板",
1685 "Model ID": "模型 ID",
1686 "mui_reset": "重置",
1687 "Multimodal (OpenAI / Anthropic / llama / Google)": "多模態(OpenAI/Anthropic/llama/Google)",
1688 "must be set in Tabby's config.yml to switch models.": "須在 Tabby's config.yml 中設置以切換模型。",
1689 "Names as Stop Strings": "將名稱用作停止字串",
1690 "Never": "從不",
1691 "NomicAI API Key": "NomicAI API 金鑰",
1692 "Non-recursable (will not be activated by another)": "不可遞迴(不會被其他條目啟動)",
1693 "None (disabled)": "無(已禁用)",
1694 "OK": "確定",
1695 "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "舊訊息會在聊天時逐步向量化。\n若要處理所有先前訊息,請點擊下方按鈕。",
1696 "Only used when Main API or WebLLM Extension is selected.": "僅在選擇主要 API 或 WebLLM 擴充功能時使用。",
1697 "Open a chat to see the character expressions.": "開啟聊天以查看角色表情。",
1698 "Post-History Instructions": "聊天歷史後指示",
1699 "Prefer Character Card Instructions": "角色卡聊天歷史後指示優先",
1700 "Prioritize": "優先處理",
1701 "Prompt Content": "提示詞內容",
1702 "prompt_manager_in_chat": "聊天中的提示詞管理",
1703 "prompt_post_processing_none": "無",
1704 "Purge Vectors": "清除向量",
1705 "Put images with expressions there. File names should follow the pattern:": "將表情立繪放置於此,檔案名稱應遵循以下格式:",
1706 "Quad": "四元數",
1707 "Query messages": "查詢訊息",
1708 "Quick Impersonate button": "快速模擬按鈕",
1709 "Recursion Level": "遞迴層級",
1710 "Remove all image overrides": "移除所有圖片覆蓋",
1711 "Restore default": "",
1712 "Retain#": "保留#",
1713 "Retrieve chunks": "檢索 Chunks",
1714 "Sampler Order": "取樣順序",
1715 "Score threshold": "分數閾值",
1716 "sd_free_extend_small": "(互動/指令)",
1717 "sd_free_extend_txt": "使用「自由模式」。由 LLM 自動擴寫圖片生成提示",
1718 "sd_function_tool_txt": "使用功能工具",
1719 "sd_prompt_-1": "聊天訊息模板",
1720 "sd_prompt_-2": "功能工具提示詞",
1721 "sd_prompt_0": "角色(第二人稱,你)",
1722 "sd_prompt_1": "使用者(第一人稱,我)",
1723 "sd_prompt_10": "肖像(多模態模式)",
1724 "sd_prompt_11": "自由模式(由 LLM 自動擴寫)",
1725 "sd_prompt_2": "場景(擷取場景資訊)",
1726 "sd_prompt_3": "原始最後訊息",
1727 "sd_prompt_4": "最後訊息",
1728 "sd_prompt_5": "肖像(第二人稱,你)",
1729 "sd_prompt_7": "背景",
1730 "sd_prompt_8": "角色(多模態模式)",
1731 "sd_prompt_9": "使用者(多模態模式)",
1732 "Select a Model": "選擇模型",
1733 "Select the API for classifying expressions.": "選擇分類表情的 API。",
1734 "Select with Enter": "按 Enter 選擇",
1735 "Select with Tab": "按 Tab 選擇",
1736 "Select with Tab or Enter": "按 Tab 或 Enter 選擇",
1737 "Separators as Stop Strings": "以分隔符作為停止字串",
1738 "Set the default and fallback expression being used when no matching expression is found.": "設定在無法配對表情時所使用的預設表情和備用圖片。",
1739 "Set your API keys and endpoints in the API Connections tab first.": "請先在「API 連線」頁面中設定您的 API 金鑰和端點。",
1740 "Show default images (emojis) if sprite missing": "無對應圖片時,顯示為預設表情符號(emoji)",
1741 "Show group chat queue": "顯示群組聊天隊列",
1742 "Size threshold (KB)": "大小閾值(KB)",
1743 "Slash Command": "斜線命令",
1744 "space_ slash command.": "斜線命令。",
1745 "Sprite Folder Override": "表情立繪資料夾覆蓋",
1746 "Sprite set:": "立繪組:",
1747 "Show Gallery": "查看畫廊",
1748 "Sticky": "固定",
1749 "Style Preset": "預設樣式",
1750 "Summarize chat messages for vector generation": "摘要聊天訊息以進行向量化處理",
1751 "Summarize chat messages when sending": "傳送時摘要聊天內容",
1752 "Swipe # for All Messages": "為所有訊息分配滑動編號 #",
1753 "System Message Sequences": "系統訊息序列",
1754 "System Prefix": "系統訊息前綴",
1755 "System Prompt Sequences": "系統提示詞序列",
1756 "System Suffix": "系統訊息後綴",
1757 "Tabby Model": "Tabby 模型",
1758 "tag_import_all": "全部匯入",
1759 "tag_import_none": "不匯入",
1760 "Text Generation WebUI (oobabooga)": "文字生成 WebUI (oobabooga)",
1761 "The server MUST be started with the --embedding flag to use this feature!": "若要使用此功能,伺服器必須啟動時加上 --embedding 標誌。",
1762 "Threshold": "閾值",
1763 "to install 3rd party extensions.": "用於安裝第三方擴充功能。",
1764 "Top": "頂部",
1765 "Translate text to English before classification": "在分類前將文本翻譯為英文。",
1766 "Uncheck to hide the extensions messages in chat prompts.": "不勾選即可隱藏聊天提示詞中的擴充功能訊息。",
1767 "Unchecked: only entries with ❌ status can be activated.": "未勾選時:僅允許啟用狀態為 ❌ 的條目。",
1768 "Unified Sampling": "統一取樣(Unified Sampling)",
1769 "Upload sprite pack (ZIP)": "批次上傳立繪包(.ZIP)",
1770 "Use a forward slash to specify a subfolder. Example: _space": "使用「/」來設置子目錄,例如:_space",
1771 "Use ADetailer (Face)": "使用 ADetailer 進行臉部處理。",
1772 "Use an admin API key.": "使用管理員的 API 金鑰。",
1773 "Use global": "啟用全域設定",
1774 "User Message Sequences": "使用者訊息序列",
1775 "User Node Color": "使用者節點顏色",
1776 "User Prefix": "使用者訊息前綴",
1777 "User Suffix": "使用者訊息後綴",
1778 "Using a proxy that youre not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務存在數據隱私洩漏風險。",
1779 "Vector Storage": "向量存儲",
1780 "Vector Summarization": "向量摘要",
1781 "Vectorization Model": "向量生成模型",
1782 "Vectorization Source": "向量化來源",
1783 "Vectorize All": "向量化全部數據",
1784 "View Stats": "查看統計資料",
1785 "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:這可能會導致訊息處理速度變慢,並延長回應時間。",
1786 "WarningThis might cause your sent messages to take a bit to process and slow down response time.": "警告:這將顯著減緩向量生成速度,因為所有消息都需先進行摘要。",
1787 "WebLLM Extension": "WebLLM 擴充功能",
1788 "Whole Words": "匹配完整單字",
1789 "Will be used if the API doesnt support JSON schemas or function calling.": "若 API 不支持 JSON 模式或函數調用,將使用此設定。",
1790 "World Info settings": "世界資訊設定",
1791 "You are in offline mode. Click on the image below to set the expression.": "您目前為離線狀態,請點擊下方圖片進行表情設定。",
1792 "You can find your API key in the Stability AI dashboard.": "API 金鑰可在 Stability AI 儀表板中查看。",
1793 "Stop Inspecting": "停止檢查",
1794 "Inspect Prompts": "檢查提示詞",
1795 "Toggle prompt inspection": "切換提示詞檢查",
1796 "Top nsigma": "Top nsigma",
1797 "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.",
1798 "Confirm token parsing with": "確認符元(Token)解析方式",
1799 "KoboldAI Horde": "KoboldAI Horde",
1800 "KoboldAI Horde Website": "KoboldAI Horde 網站",
1801 "Derive context size from backend": "從後端推導上下文大小",
1802 "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務可能導致您的數據隱私外洩。",
1803 "Claude API Key": "Claude API 金鑰",
1804 "NanoGPT API Key": "NanoGPT API 金鑰",
1805 "NanoGPT Model": "NanoGPT 模型",
1806 "context_derived": "若可能,根據模型元數據推導。",
1807 "instruct_derived": "若可能,根據模型元數據推導。",
1808 "Inserted before the first User's message.": "插入於第一則使用者訊息之前。",
1809 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\\n(disabled when min activations are used)": "0 = 無限制,1 = 掃描一次不遞歸,2 = 掃描一次後遞歸一次 ⋯以此類推\n(啟用最小啟動次數時無效)",
1810 "Quick 'Impersonate' button": "快速「AI 扮演使用者」按鈕",
1811 "Manual": "手動",
1812 "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "此處填入的內容將取代該角色的默認聊天歷史後指示(Post-History Instructions)。\n(v2 specpost_history_instructions)",
1813 "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示內容由其他地方提取,無法在此進行編輯。",
1814 "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "開啟檢查點聊天\n使用「Shift+點擊」將以新檢查點替換現有的。",
1815 "Reroll with the entire prefix": "使用完整前綴重新生成",
1816 "Disable": "停用",
1817 "Enable": "啟用",
1818 "These files are available for the current character in all chats they are in.": "這些檔案適用於該角色所在的所有聊天。",
1819 "These files are available for all characters in the current chat.": "這些檔案適用於本次聊天中的所有角色。",
1820 "Set your API keys and endpoints in the 'API Connections' tab first.": "請先於「API 連線」選單中設定 API 金鑰和端點。",
1821 "Profile name:": "設定檔名稱:",
1822 "Creating a Connection Profile": "建立連線設定檔",
1823 "{{@key}}": "{{@key}}:",
1824 "Enter a name:": "輸入名稱:",
1825 "Omitted Settings:": "忽略的設定:",
1826 "Will be used if the API doesn't support JSON schemas or function calling.": "將於 API 不支援 JSON 結構或函數調用時使用。",
1827 "ext_sum_webllm": "WebLLM 擴充功能",
1828 "ext_sum_restore_tip": "恢復先前的摘要;重複使用以清除此聊天的摘要狀態。",
1829 "ext_sum_force_tip": "將立即更新摘要。",
1830 "ext_sum_include_wi_scan_desc": "於掃描世界資訊時包含最新摘要。",
1831 "ext_sum_include_wi_scan": "包含世界資訊掃描",
1832 "None (not injected)": "無(不插入)",
1833 "ext_sum_injection_position_none": "此摘要將不會插入提示詞中,但可通過 {{summary}} 巨集訪問。",
1834 "Labels and Message": "標籤與訊息",
1835 "Label": "標籤",
1836 "(label of the button, if no icon is chosen) ": "(若未選擇圖標,則為按鈕的標籤)",
1837 "Title": "名稱",
1838 "(tooltip, leave empty to show message or /command)": "(工具提示,留空以顯示訊息或 /command)",
1839 "Message / Command:": "訊息/指令:",
1840 "Word wrap": "自動換行",
1841 "Tab size:": "標籤大小:",
1842 "Ctrl+Enter to execute": "以 Ctrl+Enter 執行",
1843 "Context Menu": "上下文選單",
1844 "Auto-Execute": "自動執行",
1845 "Don't trigger auto-execute": "不觸發自動執行",
1846 "Invisible (auto-execute only)": "隱藏(僅自動執行)",
1847 "Execute on startup": "啟動時執行",
1848 "Execute on user message": "根據使用者訊息執行",
1849 "Execute on AI message": "根據 AI 訊息執行",
1850 "Execute on chat change": "聊天內容變更時執行",
1851 "Execute on new chat": "新建聊天時執行",
1852 "Execute on group member draft": "欲改動群組成員時執行",
1853 "Automation ID:": "自動化 ID:",
1854 "Testing": "測試",
1855 "Quick Reply": "快速回覆",
1856 "Enable Quick Replies": "啟用快速回覆",
1857 "Combine Quick Replies": "合併快速回覆",
1858 "Show Popout Button": "顯示彈出按鈕(桌面版)",
1859 "Global Quick Reply Sets": "全域快速回覆",
1860 "Chat Quick Reply Sets": "僅限目前聊天",
1861 "Edit Quick Replies": "編輯快速回覆",
1862 "Disable Send (Insert Into Input Field)": "停用發送(插入到輸入字段)",
1863 "Place Quick Reply Before Input": "在輸入前插入快速回覆",
1864 "Inject user input automatically": "自動插入使用者輸入",
1865 "(if disabled, use ": "(若停用,請使用",
1866 "macro for manual injection)": "巨集進行手動插入)",
1867 "Color": "顏色",
1868 "Only apply color as accent": "僅使用顏色作為強調",
1869 "ext_regex_new_global_script_desc": "新建「全域」正規表達式",
1870 "ext_regex_new_scoped_script_desc": "新建「作用域」正規表達式",
1871 "ext_regex_disallow_scoped": "不使用作用域正規表達式",
1872 "ext_regex_allow_scoped": "使用作用域正規表達式",
1873 "ext_regex_user_input_desc": "使用者發送的訊息。",
1874 "ext_regex_ai_input_desc": "從生成式 API 接收到的訊息。",
1875 "ext_regex_slash_desc": "使用 STscript 指令發送的訊息。",
1876 "ext_regex_wi_desc": "世界資訊/知識書條目內容。需要勾選「僅格式化提示詞」!",
1877 "ext_regex_run_on_edit_desc": "當指定角色的訊息被編輯時執行正規腳本。",
1878 "Macro in Find Regex": "巨集替換模式",
1879 "Don't substitute": "不替換(純文字匹配)",
1880 "Substitute (raw)": "原始替換(不處理 *、. 等特殊字符)",
1881 "Substitute (escaped)": "轉義替換(將特殊字符 *、. 等當作普通文字處理)",
1882 "Ephemerality": "暫時性",
1883 "ext_regex_only_format_visual_desc": "僅改變聊天界面顯示的訊息,不修改聊天記錄檔案內容。",
1884 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "提示:請於 Horde KoboldAI API 設定中保存 API 金鑰以進行使用。",
1885 "Prompt Upsampling": "提示提升(Upsampling)",
1886 "Uncheck to hide the extension's messages in chat prompts.": "取消選取可在聊天提示詞中隱藏擴充功能的訊息。",
1887 "ext_translate_delete_confirm_1": "確定要刪除嗎?",
1888 "ext_translate_delete_confirm_2": "這將「永久刪除」本次聊天中所有訊息的翻譯文本,且無法復原。",
1889 "Select TTS Provider": "選擇 TTS 提供者",
1890 "tts_enabled": "啟用",
1891 "Narrate user messages": "朗讀使用者訊息",
1892 "Auto Generation": "自動生成",
1893 "Requires auto generation to be enabled.": "需要啟用自動生成功能。",
1894 "Narrate by paragraphs (when streaming)": "按段落朗讀(使用「串流」傳輸時)",
1895 "Only narrate quotes": "僅朗讀「引號」中的文字",
1896 "Ignore text, even quotes, inside asterisk": "忽略 *(星號)內的文字(包括「引號」)",
1897 "Narrate only the translated text": "僅朗讀翻譯後的文本",
1898 "Skip codeblocks": "跳過代碼塊",
1899 "Skip tagged blocks": "跳過 <標記> 塊",
1900 "Pass Asterisks to TTS Engine": "將 *(星號)視為普通文字傳送至 TTS 引擎(否則忽略)",
1901 "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:操作後將顯著降低向量生成速度,因為所有訊息都必須先進行摘要。",
1902 "Note:": "注意:",
1903 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天為臨時聊天,離開後將被刪除。",
1904 "Import Tags For _begin": "為",
1905 "Import Tags For _end": "匯入標籤",
1906 "Click remove on any tag to remove it from this import.<br />Select one of the import options to finish importing the tags.": "點擊任意標籤上的「移除」可將其於本次匯入中刪除。\n選擇一個匯入選項以完成標籤匯入。",
1907 "Existing Tags": "現有標籤",
1908 "New Tags": "新標籤",
1909 "Folder Tags": "資料夾標籤",
1910 "The following tags will be auto-imported based on the currently selected folders": "以下標籤將根據目前選擇的文件夾自動匯入",
1911 "Import None": "不匯入",
1912 "Import All": "全部匯入",
1913 "Import Existing": "匯入現有標籤",
1914 "Import": "匯入",
1915 "chat_rename_1": "輸入此聊天檔案的新名稱:",
1916 "chat_rename_2": "!! 使用已存在的檔案名將導致錯誤 !!",
1917 "chat_rename_3": "這將斷開各檢查點間的連結。",
1918 "chat_rename_4": "無需在末尾加上 `.jsonl`。",
1919 "Include Body Parameters": "包含請求主體參數",
1920 "custom_include_body_desc": "包含在 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- top_k: 20\n- repetition_penalty: 1.1",
1921 "Exclude Body Parameters": "排除請求主體參數",
1922 "custom_exclude_body_desc": "排除於 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- frequency_penalty\n- presence_penalty",
1923 "Include Request Headers": "包含請求頭(Request Headers)",
1924 "custom_include_headers_desc": "添加於 Chat Completion 請求的自定義標頭(YAML 格式)\n\n範例:\n- CustomHeader: custom-value\n- AnotherHeader: custom-value",
1925 "THIS IS PERMANENT!": "這是「永久性」的!",
1926 "Also delete the chat files": "同時刪除此聊天檔案",
1927 "Are you sure you want to duplicate this character?": "您確定要複製該角色嗎?",
1928 "If you just want to start a new chat with the same character...": "若您只是想與該角色開始新聊天,請使用左下角選單中的「開始新聊天」。",
1929 "forbid_media_global_state_forbidden": "(禁止)",
1930 "forbid_media_global_state_allowed": "(允許)",
1931 "help_format_1": "文本格式化命令:",
1932 "help_format_2": "*文本*",
1933 "help_format_3": "顯示為",
1934 "help_format_4": "斜體",
1935 "help_format_5": "**文本**",
1936 "help_format_6": "顯示為",
1937 "help_format_7": "粗體",
1938 "help_format_8": "***text***",
1939 "help_format_9": "顯示為",
1940 "help_format_10": "粗斜體",
1941 "help_format_11": "__文本__",
1942 "help_format_12": "顯示為",
1943 "help_format_13": "底線",
1944 "help_format_14": "~~text~~",
1945 "help_format_15": "顯示為",
1946 "help_format_16": "刪除線",
1947 "help_format_17": "[text](url)",
1948 "help_format_18": "顯示為",
1949 "help_format_19": "超連結",
1950 "help_format_20": "![text](url)",
1951 "help_format_21": "顯示為圖片",
1952 "help_format_22": "```text```",
1953 "help_format_23": "顯示為程式碼區塊(反引號內允許換行)",
1954 "help_format_like_this": "像這樣",
1955 "help_format_24": "`text`",
1956 "help_format_25": "顯示為",
1957 "help_format_26": "單行程式碼",
1958 "help_format_27": "> text",
1959 "help_format_28": "顯示為塊引用(注意 > 後的空格)",
1960 "help_format_29": "# text",
1961 "help_format_30": "顯示為一級標題(注意空格)",
1962 "help_format_32": "## text",
1963 "help_format_33": "顯示為二級標題(注意空格)",
1964 "help_format_35": "### text",
1965 "help_format_36": "顯示為三級標題(注意空格)",
1966 "help_1": "您好!請選擇您想了解的幫助主題:",
1967 "help_2": "斜線命令",
1968 "help_or": "或",
1969 "help_3": "格式化",
1970 "help_4": "快捷鍵",
1971 "help_5": "{{巨集}}",
1972 "help_6": "還有問題嗎?請查看",
1973 "help_7": "SillyTavern 官方文檔網站",
1974 "help_8": " 了解更多資訊!",
1975 "help_hotkeys_0": "聊天快捷鍵",
1976 "help_hotkeys_1": "↑(方向鍵)",
1977 "help_hotkeys_2": "編輯聊天中的最後一則訊息",
1978 "help_hotkeys_3": "Ctrl+↑",
1979 "help_hotkeys_4": "編輯聊天中的最後一則使用者訊息",
1980 "help_hotkeys_5": "←(方向鍵)",
1981 "help_hotkeys_6": "向左滑動",
1982 "help_hotkeys_7": "→(方向鍵)",
1983 "help_hotkeys_8": "向右滑動(注意:若聊天框中已有輸入,滑動快捷鍵將被禁用)",
1984 "help_hotkeys_9": "Enter",
1985 "help_hotkeys_10": "(選中聊天框時)",
1986 "help_hotkeys_10_1": "向 AI 發送您的訊息",
1987 "help_hotkeys_11": "Ctrl+Enter",
1988 "help_hotkeys_12": "重新生成最後一則 AI 回應",
1989 "help_hotkeys_13": "Alt+Enter",
1990 "help_hotkeys_14": "繼續生成最後一則 AI 回應",
1991 "help_hotkeys_15": "Esc 鍵",
1992 "help_hotkeys_16": "停止 AI 回應生成,關閉使用者界面,取消訊息編輯",
1993 "help_hotkeys_17": "Ctrl+Shift+↑",
1994 "help_hotkeys_18": "滾動到上下文行",
1995 "help_hotkeys_19": "Ctrl+Shift+↓",
1996 "help_hotkeys_20": "Markdown 快捷鍵",
1997 "help_hotkeys_21": "適用於聊天框和帶有此圖標的文本區域:",
1998 "help_hotkeys_22": "**粗體**",
1999 "help_hotkeys_23": "*斜體*",
2000 "help_hotkeys_24": "__底線__",
2001 "help_hotkeys_25": "`單行程式碼`",
2002 "help_hotkeys_26": "~~刪除線~~",
2003 "Show Raw Prompt": "顯示原始提示詞",
2004 "Copy Prompt": "複製提示詞",
2005 "Show Prompt Differences": "顯示提示詞差異",
2006 "System-wide Replacement Macros (in order of evaluation):": "系統範圍替換巨集(按評估順序):",
2007 "help_macros_1": "僅用於斜線命令批次處理。替換為前一條命令的返回結果。",
2008 "help_macros_2": "插入一個換行符。",
2009 "help_macros_3": "修剪巨集指令周圍的換行符。",
2010 "help_macros_4": "無操作,僅返回空字串。",
2011 "help_macros_5": "在 API 設定中定義的全域提示詞。僅在高級定義提示詞覆蓋中有效。",
2012 "help_macros_6": "使用者輸入",
2013 "help_macros_7": "角色的主要提示詞覆蓋",
2014 "help_macros_8": "角色的聊天歷史後指示覆蓋",
2015 "help_macros_9": "角色描述",
2016 "help_macros_10": "角色的性格特徵",
2017 "help_macros_11": "角色場景",
2018 "help_macros_12": "您目前的使用者描述",
2019 "help_macros_13": "角色對話範例",
2020 "help_macros_14": "未格式化的對話範例",
2021 "(only for Story String)": "(僅適用於故事字串)",
2022 "help_macros_summary": "由「訊息摘要」擴充功能生成的最新聊天摘要(如果可用)。",
2023 "help_macros_15": "您目前的使用者名稱",
2024 "help_macros_16": "角色名稱",
2025 "help_macros_17": "角色版本",
2026 "help_macros_18": "以逗號分隔的群組成員名稱列表(包含靜音成員)或單人聊天中的角色名稱。別名:{{charIfNotGroup}}",
2027 "help_groupNotMuted": "與 {{group}} 相同,但不包含靜音成員",
2028 "help_macros_19": "目前所選之 API 的文本生成模型名稱。",
2029 "Can be inaccurate!": "可能不準確!",
2030 "help_macros_20": "最新聊天訊息的文本內容。",
2031 "help_macros_lastUser": "最新使用者聊天訊息的文本內容。",
2032 "help_macros_lastChar": "最新角色聊天訊息的文本內容。",
2033 "help_macros_21": "最新聊天訊息的索引 # 編號。適用於斜線命令批次處理。",
2034 "help_macros_22": "包含在上下文中的第一條訊息的 ID。需在目前對話中至少進行一次生成。",
2035 "help_macros_23": "最新聊天訊息中所滑動的 ID(以 1 起始)。若最新訊息為使用者訊息或提示為隱藏,則為空字串。",
2036 "help_macros_24": "最新聊天訊息中的滑動次數。如果最新訊息為使用者訊息或提示為隱藏,則為空字串。",
2037 "help_macros_reverse": "反轉巨集的內容。",
2038 "help_macros_25": "您可以在此留下備註,巨集將被替換為空白內容。對 AI 不可見。",
2039 "help_macros_26": "目前時間",
2040 "help_macros_27": "目前日期",
2041 "help_macros_28": "目前星期幾",
2042 "help_macros_29": "目前 ISO 時間(24 小時制)",
2043 "help_macros_30": "目前 ISO 日期(YYYY-MM-DD)",
2044 "help_macros_31": "指定格式的目前日期/時間,例如,德國日期/時間:",
2045 "help_macros_32": "指定 UTC 時區偏移量的目前時間,例如 UTC-4 或 UTC+2",
2046 "help_macros_33": "計算 time1 和 time2 之間的時間差。接受時間和日期巨集。(例如:{{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})",
2047 "help_macros_34": "上次使用者訊息發送後的時間",
2048 "help_macros_35": "設定 AI 的行為偏好,直到下一次使用者輸入。引號中的文本很重要。",
2049 "help_macros_36": "擲骰子。(例如:",
2050 "space_ will roll a 6-sided dice and return a number between 1 and 6)": "將擲一個六面骰並回傳 1 到 6 間的數字)",
2051 "help_macros_37": "從列表中返回隨機一項。(例如:",
2052 "space_ will return 1 of the 4 numbers at random. Works with text lists too.": "將隨機返回 4 個數字中的 1 個。也適用於文本列表。)",
2053 "help_macros_38": "用於隨機的替代語法,允許在列表中使用逗號。",
2054 "help_macros_39": "從列表中選擇隨機一項。工作原理與 {{random}} 相同,但選擇結果將在本次聊天中保持一致,不會在後續消息或提示處理時重新滾動。",
2055 "help_macros_40": "若使用 Text Generation WebUI 後端,動態將引號中的文本添加到禁用單詞序列中。對其他後端無效。可在任何地方使用(角色描述、世界資訊、作者備註等)。引號內容很重要。",
2056 "Instruct Mode and Context Template Macros:": "指令模式與上下文模板巨集:",
2057 "(enabled in the Advanced Formatting settings)": "(在高級格式化設定中啟用)",
2058 "help_macros_41": "允許的最大提示詞長度(以符元為單位)=(上下文大小 - 回應長度)",
2059 "help_macros_42": "上下文模板對話範例分隔符",
2060 "help_macros_43": "上下文模板聊天開始行",
2061 "help_macros_44": "主要提示詞(啟用後,將覆蓋角色提示詞或預設系統提示)",
2062 "help_macros_45": "主要提示詞",
2063 "help_macros_46": "指令系統提示詞前綴序列",
2064 "help_macros_47": "指令系統提示詞後綴序列",
2065 "help_macros_48": "指令使用者前綴序列",
2066 "help_macros_49": "指令使用者後綴序列",
2067 "help_macros_50": "指令助理前綴序列",
2068 "help_macros_51": "指令助理後綴序列",
2069 "help_macros_52": "指令助理的開頭輸出序列",
2070 "help_macros_53": "指令助理的結尾輸出序列",
2071 "help_macros_54": "指令系統訊息前綴序列",
2072 "help_macros_55": "指令系統訊息後綴序列",
2073 "help_macros_56": "指令系統指令前綴",
2074 "help_macros_57": "指令第一則使用者訊息補全",
2075 "help_macros_58": "指令停止序列",
2076 "help_macros_first_user": "指令使用者開頭輸入序列",
2077 "help_macros_last_user": "指令使用者結尾輸入序列",
2078 "Chat variables Macros:": "聊天變數巨集:",
2079 "Local variables = unique to the current chat": "局部變數 = 僅作用於本次聊天",
2080 "Global variables = works in any chat for any character": "全域變數 = 作用於所有聊天中的所有角色",
2081 "Scoped variables = works in STscript": "局部變數 = 適用於 STscript",
2082 "help_macros_59": "替換為局部變數 \"name\" 的值",
2083 "help_macros_60": "替換為空字串,並將局部變數 \"name\" 設定為 \"value\"",
2084 "help_macros_61": "替換為空字串,並將 \"increment\" 數值添加到局部變數 \"name\"",
2085 "help_macros_62": "替換為局部變數 \"name\" 的值增加 1 後的結果",
2086 "help_macros_63": "替換為局部變數 \"name\" 的值減少 1 後的結果",
2087 "help_macros_64": "替換為全域變數 \"name\" 的值",
2088 "help_macros_65": "替換為空字串,並將全域變數 \"name\" 設定為 \"value\"",
2089 "help_macros_66": "替換為空字串,並將 \"increment\" 數值添加到全域變數 \"name\"",
2090 "help_macros_67": "替換為全域變數 \"name\" 的值增加 1 後的結果",
2091 "help_macros_68": "替換為全域變數 \"name\" 的值減少 1 後的結果",
2092 "help_macros_69": "替換為局部變數 \"name\" 的值",
2093 "help_macros_70": "替換為局部變數 \"name\" 中指定索引(適用於陣列/列表或對象/字典)的值",
2094 "{{name}}": "{{name}}",
2095 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可以稍後從 /backups 資料夾恢復此聊天檔案",
2096 "Also delete the current chat file": "同時刪除目前的聊天檔案",
2097 "Are you sure you want to connect to the following proxy URL?": "您確定要連線到以下代理 URL 嗎?",
2098 "Encountered an error while processing your request.": "處理您的請求時遇到錯誤。",
2099 "Check you have credits available on your": "請檢查您的帳號中是否有可用餘額",
2100 "OpenAI account quora_error": "OpenAI 帳號",
2101 "dot quota_error": "。",
2102 "If you have sufficient credits, please try again later.": "若餘額充足,請稍後重試。",
2103 "Download Model": "下載模型",
2104 "Downloader Options": "下載選項",
2105 "Extra parameters for downloading/HuggingFace API": "下載/使用 HuggingFace API 的額外參數。\r若不確定,請留空。",
2106 "Revision": "修訂",
2107 "Folder Name": "輸出資料夾名稱",
2108 "HF Token": "HF 符元",
2109 "Include Patterns": "包含模式",
2110 "Glob patterns of files to include in the download.": "要包含於下載中文件的全域模式。\r每行輸入一個模式。",
2111 "Exclude Patterns": "排除模式",
2112 "Glob patterns of files to exclude in the download.": "要排除於下載中的文件的全域模式。\r每行輸入一個模式。",
2113 "Tag Management": "管理標籤",
2114 "Save your tags to a file": "將標籤保存到文件",
2115 "Restore tags from a file": "從文件中恢復標籤",
2116 "Create a new tag": "創建新標籤",
2117 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖動以重新排序。點擊名稱重新命名。點擊顏色更改顯示。",
2118 "Click on the folder icon to use this tag as a folder.": "點擊資料夾圖示以將此標籤作為資料夾。",
2119 "Use alphabetical sorting": "使用字母順序排序",
2120 "tags_sorting_desc": "啟用後,標籤將在創建或重命名時將自動按字母排序。\n禁用時,新標籤將附加到末尾。\n若標籤被手動拖動重新排序,則自動排序將被禁用。",
2121 "and connect to an": "並連接到",
2122 "You can add more": "您可以添加更多",
2123 "or_welcome": "或",
2124 "from other websites": "從其他網站取得。",
2125 "Go to the": "前往",
2126 "to install additional features.": "以安裝更多功能。",
2127 "If you're connected to an API, try asking me something!": "若您已連接 API,嘗試問我一些問題吧!",
2128 "Title/Memo": "標題/備註",
2129 "Strategy": "插入策略",
2130 "Position": "位置",
2131 "Trigger %": "觸發%",
2132 "Dialogue Colorizer": "對話著色器",
2133 "Global Dialogue Settings": "全域對話設定",
2134 "Chat Bubble Lightness": "聊天氣泡亮度",
2135 "The lightness to use for the chat bubble color.": "設定聊天氣泡的亮度。",
2136 "Character Dialogue Settings": "角色對話設定",
2137 "Dialogue settings for characters.": "設定角色對話顏色。",
2138 "The static color to use for character dialog if 'Color Source' is set to 'Static Color'.": "若將「顏色來源」設定為「靜態顏色」,請先設定該角色對話的靜態顏色。",
2139 "Persona Dialogue Settings": "使用者對話設定",
2140 "Persona Dialogue Settings Info": "設定使用者對話顏色。",
2141 "Dialogue Color": "對話顏色",
2142 "The color to use for this character's dialogue (quoted text). Overrides the global setting.": "該角色對話中引號文字的顏色。覆蓋全域設定。",
2143 "Avatar Vibrant": "頭像顏色",
2144 "Use a vibrant color dynamically calculated from the character's avatar.": "使用從角色頭像動態提取出的色彩。",
2145 "Static Color": "靜態顏色",
2146 "Use a specified static color.": "使用指定的靜態顏色。",
2147 "Per-Character Only": "僅限特定角色",
2148 "Use the default quote color except for characters with a specified override color.": "除非角色有指定的覆蓋顏色,否則使用預設的引號文字顏色。",
2149 "Chat Bubbles": "聊天氣泡",
2150 "Color the chat bubbles. Only works with the 'Bubbles' chat style.": "為聊天氣泡上色,僅適用於「氣泡」聊天樣式。",
2151 "Quoted Text": "引號文字",
2152 "Color quoted text.": "為引號文字上色。",
2153 "Color both chat bubbles and quoted text.": "同時為聊天氣泡和引號文字上色。",
2154 "Color Source": "顏色來源",
2155 "The source to use for dialogue color.": "設定對話顏色的來源。",
2156 "Color Targets": "顏色目標",
2157 "Which elements to color.": "設定需要上色的元素。",
2158 "Open Chat History": "開啟聊天記錄",
2159 "Reset": "重設",
2160 "Save": "保存",
2161 " folder of your user directory (typically 'data/default-user'). Place your expressions there.": "資料夾內,放置您的角色立繪(通常為「data/default-user」)。",
2162 "Always show the node full info panel at the…e timeline view. When off, show it near the node.": "始終在時間軸視圖底部顯示節點的完整資訊面板。若關閉,則在節點附近顯示。",
2163 "Always show the node tooltip at the bottom …e timeline view. When off, show it near the node.": "始終在時間軸視圖左下角顯示節點的提示框。若關閉,則在節點附近顯示。",
2164 "Dialogue settings for user personas.": "Dialogue settings for user personas.",
2165 "Expand swipe nodes when the timeline view f… a node, or by pressing the Toggle Swipes button.": "在時間軸視圖首次打開時展開滑動節點,或透過按下「切換滑動」按鈕來展開節點。",
2166 "Send as a character": "以角色身份發送",
2167 "Use GPU acceleration for positioning the fu…ow tends to disappear, turning this off may help.": "使用 GPU 加速來定位完整資訊面板。若面板頻繁消失,建議關閉此選項以解決問題。",
2168 "Use the colors of the ST GUI theme, instead…n Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。",
2169 "When enabled, nodes that have swipes splitt… larger, in addition to having the double border.": "啟用後,具有分支滑動的節點除了顯示雙重邊框外,還會顯示為更大的尺寸。",
2170 "Brightness": "亮度",
2171 "Character Tint Settings": "角色色調設定 *",
2172 "Commands": "指令",
2173 "Contrast": "對比度",
2174 "Darken Unfocused Character Sprites": "暗化未聚焦的角色立繪",
2175 "Delete tint": "保存色調",
2176 "Ease": "平滑過渡",
2177 "Ease-In": "淡入",
2178 "Ease-In-Out": "淡入 + 淡出",
2179 "Ease-Out": "淡出",
2180 "Emulate Character Card as Sprite": "[測試版] 模擬角色卡為角色立繪",
2181 "Enable Character Tint (Requires Prome to be enabled)": "使用角色色調(需要啟用 Prome)",
2182 "Enable Chat Tint": "啟用聊天色調",
2183 "Enable Focus Mode": "啟用聚焦模式",
2184 "Enable Prome": "啟用 Prome",
2185 "Enable Sprite Shadow": "啟用角色立繪陰影效果",
2186 "Enable Sprite Shake": "[測試版] 啟用角色立繪震動效果",
2187 "Enable Traditional VN Mode": "啟用傳統視覺小說模式 *",
2188 "Enable User Sprite": "啟用使用者立繪",
2189 "Enable World Tint": "啟用世界色調",
2190 "Features marked with a": "若想使用帶有",
2191 "Focus Mode Animation": "聚焦模式動畫",
2192 "Focus Mode Animation Speed": "聚焦模式動畫速度",
2193 "Focus Mode Settings": "聚焦模式設定",
2194 "Grayscale": "灰階",
2195 "Hide Sheld (Message Box)": "隱藏聊天訊息欄位",
2196 "Horizontal Letterbox": "水平遮罩",
2197 "Hue": "色相",
2198 "Invert": "反轉",
2199 "Inverts the character colors.": "反轉角色顏色。",
2200 "Inverts the world colors.": "反轉世界顏色。",
2201 "Keybinds": "快捷鍵",
2202 "Letterbox Color": "遮罩顏色",
2203 "Letterbox Configuration*": "遮罩設定 *",
2204 "Letterbox Mode": "遮罩模式",
2205 "Letterbox Size": "遮罩大小",
2206 "Makes the character black and white.": "使角色使用灰階效果。",
2207 "Makes the character warmer in color.": "使角色色調更暖。",
2208 "Makes the world black and white.": "使世界使用灰階效果。",
2209 "Makes the world warmer in color.": "使世界色調更暖。",
2210 "Note: Create a sprite folder in the ": "注意:請在",
2211 "require Prome to be enabled.": "標記的功能,需要啟用「Prome」。",
2212 "Saturate": "飽和",
2213 "Saturates the character colors.": "增加角色顏色飽和度。",
2214 "Saturates the world colors.": "增加世界顏色飽和度。",
2215 "Save tint": "刪除色調",
2216 "Select the animation for focus mode.": "選擇聚焦模式的動畫。",
2217 "Select the color of the letterbox.": "選擇遮罩顏色。",
2218 "Select the letterbox mode for the Prome VN UI.": "選擇 Prome 視覺小說介面的遮罩模式",
2219 "Select the tint preset to use for the Prome VN UI.": "選擇用於 Prome 視覺小說介面的色調預設。",
2220 "Sepia": "復古",
2221 "Set the blur of the character shadow.": "設定角色陰影模糊程度。",
2222 "Set the brightness of the character.": "設定角色亮度。",
2223 "Set the brightness of the world.": "設定世界亮度。",
2224 "Set the contrast of the character.": "設定角色對比度。",
2225 "Set the contrast of the world.": "設定世界對比度。",
2226 "Set the hue of the character.": "設定角色色相。",
2227 "Set the hue of the world.": "設定世界色相。",
2228 "Set the size of the letterbox.": "設定遮罩大小。",
2229 "Set the speed of the focus animation.": "設定聚焦動畫速度。",
2230 "Set the strength of the character blur.": "設定角色模糊強度。",
2231 "Set the strength of the world blur.": "設定世界模糊強度。",
2232 "Set the X offset of the character shadow.": "設定角色陰影的 X 軸偏移量。",
2233 "Set the Y offset of the character shadow.": "設定角色陰影的 Y 軸偏移量。",
2234 "Shadow Blur": "模糊陰影",
2235 "Shadow X Offset": "陰影 X 軸偏移量",
2236 "Shadow Y Offset": "陰影 Y 軸偏移量",
2237 "Share World Tint With Characters": "與角色共享世界色調 *",
2238 "Sheld Configuration": "設定聊天訊息欄位",
2239 "Sprite Configuration": "設定角色立繪 *",
2240 "Sprite List": "角色立繪列表",
2241 "Sprite Shadow Configuration": "設定角色立繪陰影",
2242 "Tint Configuration": "設定色調",
2243 "Tint Presets": "預設色調",
2244 "Type the name of the sprite set to use for your pe…rites in the 'characters' folder in SillyTavern).": "輸入您要使用的個人角色立繪集名稱(需將立繪存放於 SillyTavern 中的「characters」資料夾內)。",
2245 "User Sprite Configuration": "[測試版] 使用者立繪設定",
2246 "Vertical Letterbox": "垂直遮罩",
2247 "World Tint Settings": "設定世界色調",
2248 "Prome (Visual Novel Extension)": "Prome(視覺小說模式進階設定)",
2249 "Brought to you by": "由",
2250 "and Prometheus.": "與 Prometheus 呈獻。",
2251 "Type the name of the sprite set to use for your persona. (Place your sprites in the 'characters' folder in SillyTavern).": "輸入您想用於個人立繪的立繪集名稱。(請將立繪放置在 SillyTavern 的「characters」資料夾中)。",
2252 "Prome Keybinds": "Prome 的快捷鍵",
2253 "Hide/Show SillyTavern's Sheld (Message Box)": "隱藏/顯示 SillyTavern 的聊天訊息欄位",
2254 "Prome Commands": "Prome 指令",
2255 "Show/Hide the letterbox (black bars) in the VN UI": "顯示/隱藏視覺小說模式中的黑邊(信箱模式)",
2256 "Toggles focus mode on character sprites": "切換角色立繪的焦點模式",
2257 "Sets the focus mode animation": "設置焦點模式動畫",
2258 "Toggles the defocus tint on non-speaking character sprites": "切換非對話角色立繪的背景色",
2259 "Toggles the shake animation when a character speaks on character sprites": "切換角色立繪對話時的震動動畫",
2260 "Toggles sprite shadows on character sprites": "切換角色立繪的陰影效果",
2261 "Toggles world/character tint on the VN UI": "切換視覺小說模式中的世界/角色色調",
2262 "Toggles world tint on the VN UI": "切換視覺小說模式中的世界色調",
2263 "Toggles character tint on the VN UI": "切換視覺小說模式中的角色色調",
2264 "Toggles sharing world tint with character sprites (This will override Character Tint)": "切換角色立繪是否與世界色調共享色調(此操作將覆蓋角色色調設置)",
2265 "Sets the expression of the user sprite": "設定使用者立繪的表情",
2266 "Sets the user sprite set to use for the user sprite": "設定使用者立繪所使用的立繪集",
2267 "Toggles the user sprite on the VN UI": "切換視覺小說模式中使用者立繪的顯示狀態",
2268 "Close": "關閉",
2269 "View this current chat's chat history.": "查看本次聊天的聊天記錄。",
2270 "WARNING: Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "警告:此類功能僅適用於進階使用者。若您不確定使用後果,請勿點擊任何按鈕。",
2271 "Enter a new display name:": "輸入新的顯示名稱:",
2272 "Enter Checkpoint Name:": "輸入檢查點名稱:",
2273 "(Leave empty to auto-generate)": "(留空將自動命名)",
2274 "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "此檢查點將取消連結並替換為新的檢查點,但仍可在「管理聊天檔案」中找到。",
2275 "Enter the Git URL of the extension to install": "輸入欲安裝的擴充功能 Git URL",
2276 "Disclaimer:": "免責聲明:",
2277 "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "請注意,使用外部擴充功能可能會導致意想不到的副作用並存在安全風險。在匯入前,請務必確保您信任其來源。我們對於第三方擴充功能所引起的任何損害概不負責。",
2278 "Prompt Itemization": "提示詞項目化",
2279 "API/Model": "API/模型",
2280 "Preset": "預設",
2281 "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "所有數字均為估算值,僅白色數字真正重要。灰色項目可能因提示詞格式設定未納入上下文。",
2282 "System Info:": "系統資訊:",
2283 "Bias:": "Bias:",
2284 "World Info:": "世界資訊:",
2285 "Chat History:": "聊天記錄:",
2286 "Extensions:": "擴充功能:",
2287 "Total Tokens in Prompt:": "提示詞中的總符元數:",
2288 "Max Context": "最大上下文長度",
2289 "(Context Size - Response Length)": "(上下文長度 - 回應長度)",
2290 ":": ":",
2291 "API/Model:": "API/模型:",
2292 "Preset:": "預設:",
2293 "Tokenizer:": "分詞器:",
2294 "Choose what to export": "選擇匯出內容",
2295 "Text Completion Preset": "文本補全預設",
2296 "Choose what to import": "選擇匯入內容",
2297 "Enter your password below to confirm:": "請在下方輸入密碼以完成確認:",
2298 "Unique to this chat.": "此設定僅適用於本次聊天。",
2299 "The following scenario text will be used instead of the value set in the character card.": "以下場景內容將覆蓋角色卡中的設定值。",
2300 "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "檢查點將繼承父項的場景覆蓋值,但仍可獨立修改。",
2301 "Are you sure you want to delete the theme?": "您確定要刪除這個介面主題嗎?",
2302 "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "此操作將刪除所有設定與數據,且無法還原。進行重設前請務必完成備份。",
2303 "Account reset code has been posted to the server console.": "帳號重設驗證碼已發送至伺服器控制台。",
2304 "Prompt Tokens:": "提示詞符元數:",
2305 "All group members will use the following scenario text instead of what is specified in their character cards.": "所有群組聊天成員將使用以下場景內容,取代原有角色卡中指定的內容。"
1446}2306}
public/script.js+262 -157
@@ -10,6 +10,7 @@ import {
10 SVGInject,10 SVGInject,
11 Popper,11 Popper,
12 initLibraryShims,12 initLibraryShims,
13 slideToggle,
13 default as libs,14 default as libs,
14} from './lib.js';15} from './lib.js';
1516
@@ -234,7 +235,7 @@ import {
234import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';235import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
235import { hideLoader, showLoader } from './scripts/loader.js';236import { hideLoader, showLoader } from './scripts/loader.js';
236import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';237import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';
237import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js';238import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels, loadGenericModels } from './scripts/textgen-models.js';
238import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js';239import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js';
239import { getPresetManager, initPresetManager } from './scripts/preset-manager.js';240import { getPresetManager, initPresetManager } from './scripts/preset-manager.js';
240import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js';241import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js';
@@ -549,6 +550,7 @@ let optionsPopper = Popper.createPopper(document.getElementById('options_button'
549let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), {550let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), {
550 placement: 'left',551 placement: 'left',
551});552});
553let isExportPopupOpen = false;
552554
553// Saved here for performance reasons555// Saved here for performance reasons
554const messageTemplate = $('#message_template .mes');556const messageTemplate = $('#message_template .mes');
@@ -847,11 +849,9 @@ export let is_send_press = false; //Send generation
847849
848let this_del_mes = -1;850let this_del_mes = -1;
849851
850//message editing and chat scroll position persistence852//message editing
851var this_edit_mes_chname = '';853var this_edit_mes_chname = '';
852var this_edit_mes_id;854var this_edit_mes_id;
853var scroll_holder = 0;
854var is_use_scroll_holder = false;
855855
856//settings856//settings
857export let settings;857export let settings;
@@ -895,6 +895,13 @@ export function getRequestHeaders() {
895 };895 };
896}896}
897897
898export function getSlideToggleOptions() {
899 return {
900 miliseconds: animation_duration * 1.5,
901 transitionFunction: animation_duration > 0 ? 'ease-in-out' : 'step-start',
902 };
903}
904
898$.ajaxPrefilter((options, originalOptions, xhr) => {905$.ajaxPrefilter((options, originalOptions, xhr) => {
899 xhr.setRequestHeader('X-CSRF-Token', token);906 xhr.setRequestHeader('X-CSRF-Token', token);
900});907});
@@ -1173,7 +1180,7 @@ async function getStatusTextgen() {
1173 return resultCheckStatus();1180 return resultCheckStatus();
1174 }1181 }
11751182
1176 if (textgen_settings.type == textgen_types.OOBA && textgen_settings.bypass_status_check) {1183 if ([textgen_types.GENERIC, textgen_types.OOBA].includes(textgen_settings.type) && textgen_settings.bypass_status_check) {
1177 setOnlineStatus('Status check bypassed');1184 setOnlineStatus('Status check bypassed');
1178 return resultCheckStatus();1185 return resultCheckStatus();
1179 }1186 }
@@ -1221,6 +1228,9 @@ async function getStatusTextgen() {
1221 } else if (textgen_settings.type === textgen_types.TABBY) {1228 } else if (textgen_settings.type === textgen_types.TABBY) {
1222 loadTabbyModels(data?.data);1229 loadTabbyModels(data?.data);
1223 setOnlineStatus(textgen_settings.tabby_model || data?.result);1230 setOnlineStatus(textgen_settings.tabby_model || data?.result);
1231 } else if (textgen_settings.type === textgen_types.GENERIC) {
1232 loadGenericModels(data?.data);
1233 setOnlineStatus(textgen_settings.generic_model || data?.result || 'Connected');
1224 } else {1234 } else {
1225 setOnlineStatus(data?.result);1235 setOnlineStatus(data?.result);
1226 }1236 }
@@ -2873,23 +2883,54 @@ function addPersonaDescriptionExtensionPrompt() {
2873 }2883 }
2874}2884}
28752885
2876function getAllExtensionPrompts() {2886/**
2877 const value = Object2887 * Returns all extension prompts combined.
2878 .values(extension_prompts)2888 * @returns {Promise<string>} Combined extension prompts
2879 .filter(x => x.value)2889 */
2880 .map(x => x.value.trim())2890async function getAllExtensionPrompts() {
2881 .join('\n');2891 const values = [];
2892
2893 for (const prompt of Object.values(extension_prompts)) {
2894 const value = prompt?.value?.trim();
2895
2896 if (!value) {
2897 continue;
2898 }
2899
2900 const hasFilter = typeof prompt.filter === 'function';
2901 if (hasFilter && !await prompt.filter()) {
2902 continue;
2903 }
2904
2905 values.push(value);
2906 }
28822907
2883 return value.length ? substituteParams(value) : '';2908 return substituteParams(values.join('\n'));
2884}2909}
28852910
2886// Wrapper to fetch extension prompts by module name2911/**
2887export function getExtensionPromptByName(moduleName) {2912 * Wrapper to fetch extension prompts by module name
2888 if (moduleName) {2913 * @param {string} moduleName Module name
2889 return substituteParams(extension_prompts[moduleName]?.value);2914 * @returns {Promise<string>} Extension prompt
2890 } else {2915 */
2891 return;2916export async function getExtensionPromptByName(moduleName) {
2917 if (!moduleName) {
2918 return '';
2919 }
2920
2921 const prompt = extension_prompts[moduleName];
2922
2923 if (!prompt) {
2924 return '';
2925 }
2926
2927 const hasFilter = typeof prompt.filter === 'function';
2928
2929 if (hasFilter && !await prompt.filter()) {
2930 return '';
2892 }2931 }
2932
2933 return substituteParams(prompt.value);
2893}2934}
28942935
2895/**2936/**
@@ -2900,27 +2941,36 @@ export function getExtensionPromptByName(moduleName) {
2900 * @param {string} [separator] Separator for joining multiple prompts2941 * @param {string} [separator] Separator for joining multiple prompts
2901 * @param {number} [role] Role of the prompt2942 * @param {number} [role] Role of the prompt
2902 * @param {boolean} [wrap] Wrap start and end with a separator2943 * @param {boolean} [wrap] Wrap start and end with a separator
2903 * @returns {string} Extension prompt2944 * @returns {Promise<string>} Extension prompt
2904 */2945 */
2905export function getExtensionPrompt(position = extension_prompt_types.IN_PROMPT, depth = undefined, separator = '\n', role = undefined, wrap = true) {2946export async function getExtensionPrompt(position = extension_prompt_types.IN_PROMPT, depth = undefined, separator = '\n', role = undefined, wrap = true) {
2906 let extension_prompt = Object.keys(extension_prompts)2947 const filterByFunction = async (prompt) => {
2948 const hasFilter = typeof prompt.filter === 'function';
2949 if (hasFilter && !await prompt.filter()) {
2950 return false;
2951 }
2952 return true;
2953 };
2954 const promptPromises = Object.keys(extension_prompts)
2907 .sort()2955 .sort()
2908 .map((x) => extension_prompts[x])2956 .map((x) => extension_prompts[x])
2909 .filter(x => x.position == position && x.value)2957 .filter(x => x.position == position && x.value)
2910 .filter(x => depth === undefined || x.depth === undefined || x.depth === depth)2958 .filter(x => depth === undefined || x.depth === undefined || x.depth === depth)
2911 .filter(x => role === undefined || x.role === undefined || x.role === role)2959 .filter(x => role === undefined || x.role === undefined || x.role === role)
2912 .map(x => x.value.trim())2960 .filter(filterByFunction);
2913 .join(separator);2961 const prompts = await Promise.all(promptPromises);
2914 if (wrap && extension_prompt.length && !extension_prompt.startsWith(separator)) {2962
2915 extension_prompt = separator + extension_prompt;2963 let values = prompts.map(x => x.value.trim()).join(separator);
2964 if (wrap && values.length && !values.startsWith(separator)) {
2965 values = separator + values;
2916 }2966 }
2917 if (wrap && extension_prompt.length && !extension_prompt.endsWith(separator)) {2967 if (wrap && values.length && !values.endsWith(separator)) {
2918 extension_prompt = extension_prompt + separator;2968 values = values + separator;
2919 }2969 }
2920 if (extension_prompt.length) {2970 if (values.length) {
2921 extension_prompt = substituteParams(extension_prompt);2971 values = substituteParams(values);
2922 }2972 }
2923 return extension_prompt;2973 return values;
2924}2974}
29252975
2926export function baseChatReplace(value, name1, name2) {2976export function baseChatReplace(value, name1, name2) {
@@ -3742,6 +3792,23 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3742 }3792 }
3743 }3793 }
37443794
3795 // Fetches the combined prompt for both negative and positive prompts
3796 const cfgGuidanceScale = getGuidanceScale();
3797 const useCfgPrompt = cfgGuidanceScale && cfgGuidanceScale.value !== 1;
3798
3799 // Adjust max context based on CFG prompt to prevent overfitting
3800 if (useCfgPrompt) {
3801 const negativePrompt = getCfgPrompt(cfgGuidanceScale, true, true)?.value || '';
3802 const positivePrompt = getCfgPrompt(cfgGuidanceScale, false, true)?.value || '';
3803 if (negativePrompt || positivePrompt) {
3804 const previousMaxContext = this_max_context;
3805 const [negativePromptTokenCount, positivePromptTokenCount] = await Promise.all([getTokenCountAsync(negativePrompt), getTokenCountAsync(positivePrompt)]);
3806 const decrement = Math.max(negativePromptTokenCount, positivePromptTokenCount);
3807 this_max_context -= decrement;
3808 console.log(`Max context reduced by ${decrement} tokens of CFG prompt (${previousMaxContext} -> ${this_max_context})`);
3809 }
3810 }
3811
3745 console.log(`Core/all messages: ${coreChat.length}/${chat.length}`);3812 console.log(`Core/all messages: ${coreChat.length}/${chat.length}`);
37463813
3747 // kingbri MARK: - Make sure the prompt bias isn't the same as the user bias3814 // kingbri MARK: - Make sure the prompt bias isn't the same as the user bias
@@ -3834,7 +3901,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3834 // Inject all Depth prompts. Chat Completion does it separately3901 // Inject all Depth prompts. Chat Completion does it separately
3835 let injectedIndices = [];3902 let injectedIndices = [];
3836 if (main_api !== 'openai') {3903 if (main_api !== 'openai') {
3837 injectedIndices = doChatInject(coreChat, isContinue);3904 injectedIndices = await doChatInject(coreChat, isContinue);
3838 }3905 }
38393906
3840 // Insert character jailbreak as the last user message (if exists, allowed, preferred, and not using Chat Completion)3907 // Insert character jailbreak as the last user message (if exists, allowed, preferred, and not using Chat Completion)
@@ -3907,8 +3974,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3907 }3974 }
39083975
3909 // Call combined AN into Generate3976 // Call combined AN into Generate
3910 const beforeScenarioAnchor = getExtensionPrompt(extension_prompt_types.BEFORE_PROMPT).trimStart();3977 const beforeScenarioAnchor = (await getExtensionPrompt(extension_prompt_types.BEFORE_PROMPT)).trimStart();
3911 const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.IN_PROMPT);3978 const afterScenarioAnchor = await getExtensionPrompt(extension_prompt_types.IN_PROMPT);
39123979
3913 const storyStringParams = {3980 const storyStringParams = {
3914 description: description,3981 description: description,
@@ -4249,10 +4316,6 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4249 setPromptString();4316 setPromptString();
4250 }4317 }
42514318
4252 // Fetches the combined prompt for both negative and positive prompts
4253 const cfgGuidanceScale = getGuidanceScale();
4254 const useCfgPrompt = cfgGuidanceScale && cfgGuidanceScale.value !== 1;
4255
4256 // For prompt bit itemization4319 // For prompt bit itemization
4257 let mesSendString = '';4320 let mesSendString = '';
42584321
@@ -4471,7 +4534,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4471 ...thisPromptBits[currentArrayEntry],4534 ...thisPromptBits[currentArrayEntry],
4472 rawPrompt: generate_data.prompt || generate_data.input,4535 rawPrompt: generate_data.prompt || generate_data.input,
4473 mesId: getNextMessageId(type),4536 mesId: getNextMessageId(type),
4474 allAnchors: getAllExtensionPrompts(),4537 allAnchors: await getAllExtensionPrompts(),
4475 chatInjects: injectedIndices?.map(index => arrMes[arrMes.length - index - 1])?.join('') || '',4538 chatInjects: injectedIndices?.map(index => arrMes[arrMes.length - index - 1])?.join('') || '',
4476 summarizeString: (extension_prompts['1_memory']?.value || ''),4539 summarizeString: (extension_prompts['1_memory']?.value || ''),
4477 authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''),4540 authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''),
@@ -4536,9 +4599,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4536 const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(lastMessage?.mes) && ['', '...'].includes(streamingProcessor?.result);4599 const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(lastMessage?.mes) && ['', '...'].includes(streamingProcessor?.result);
4537 hasToolCalls && shouldDeleteMessage && await deleteLastMessage();4600 hasToolCalls && shouldDeleteMessage && await deleteLastMessage();
4538 const invocationResult = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls);4601 const invocationResult = await ToolManager.invokeFunctionTools(streamingProcessor.toolCalls);
4602 const shouldStopGeneration = (!invocationResult.invocations.length && shouldDeleteMessage) || invocationResult.stealthCalls.length;
4539 if (hasToolCalls) {4603 if (hasToolCalls) {
4540 if (!invocationResult.invocations.length && shouldDeleteMessage) {4604 if (shouldStopGeneration) {
4541 ToolManager.showToolCallError(invocationResult.errors);4605 if (Array.isArray(invocationResult.errors) && invocationResult.errors.length) {
4606 ToolManager.showToolCallError(invocationResult.errors);
4607 }
4542 unblockGeneration(type);4608 unblockGeneration(type);
4543 generatedPromptCache = '';4609 generatedPromptCache = '';
4544 streamingProcessor = null;4610 streamingProcessor = null;
@@ -4638,9 +4704,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4638 const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(getMessage);4704 const shouldDeleteMessage = type !== 'swipe' && ['', '...'].includes(getMessage);
4639 hasToolCalls && shouldDeleteMessage && await deleteLastMessage();4705 hasToolCalls && shouldDeleteMessage && await deleteLastMessage();
4640 const invocationResult = await ToolManager.invokeFunctionTools(data);4706 const invocationResult = await ToolManager.invokeFunctionTools(data);
4707 const shouldStopGeneration = (!invocationResult.invocations.length && shouldDeleteMessage) || invocationResult.stealthCalls.length;
4641 if (hasToolCalls) {4708 if (hasToolCalls) {
4642 if (!invocationResult.invocations.length && shouldDeleteMessage) {4709 if (shouldStopGeneration) {
4643 ToolManager.showToolCallError(invocationResult.errors);4710 if (Array.isArray(invocationResult.errors) && invocationResult.errors.length) {
4711 ToolManager.showToolCallError(invocationResult.errors);
4712 }
4644 unblockGeneration(type);4713 unblockGeneration(type);
4645 generatedPromptCache = '';4714 generatedPromptCache = '';
4646 return;4715 return;
@@ -4740,9 +4809,9 @@ export function stopGeneration() {
4740 * Injects extension prompts into chat messages.4809 * Injects extension prompts into chat messages.
4741 * @param {object[]} messages Array of chat messages4810 * @param {object[]} messages Array of chat messages
4742 * @param {boolean} isContinue Whether the generation is a continuation. If true, the extension prompts of depth 0 are injected at position 1.4811 * @param {boolean} isContinue Whether the generation is a continuation. If true, the extension prompts of depth 0 are injected at position 1.
4743 * @returns {number[]} Array of indices where the extension prompts were injected4812 * @returns {Promise<number[]>} Array of indices where the extension prompts were injected
4744 */4813 */
4745function doChatInject(messages, isContinue) {4814async function doChatInject(messages, isContinue) {
4746 const injectedIndices = [];4815 const injectedIndices = [];
4747 let totalInsertedMessages = 0;4816 let totalInsertedMessages = 0;
4748 messages.reverse();4817 messages.reverse();
@@ -4760,7 +4829,7 @@ function doChatInject(messages, isContinue) {
4760 const wrap = false;4829 const wrap = false;
47614830
4762 for (const role of roles) {4831 for (const role of roles) {
4763 const extensionPrompt = String(getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, role, wrap)).trimStart();4832 const extensionPrompt = String(await getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, role, wrap)).trimStart();
4764 const isNarrator = role === extension_prompt_roles.SYSTEM;4833 const isNarrator = role === extension_prompt_roles.SYSTEM;
4765 const isUser = role === extension_prompt_roles.USER;4834 const isUser = role === extension_prompt_roles.USER;
4766 const name = names[role];4835 const name = names[role];
@@ -7453,14 +7522,16 @@ function select_rm_characters() {
7453 * @param {number} depth Insertion depth. 0 represets the last message in context. Expected values up to MAX_INJECTION_DEPTH.7522 * @param {number} depth Insertion depth. 0 represets the last message in context. Expected values up to MAX_INJECTION_DEPTH.
7454 * @param {number} role Extension prompt role. Defaults to SYSTEM.7523 * @param {number} role Extension prompt role. Defaults to SYSTEM.
7455 * @param {boolean} scan Should the prompt be included in the world info scan.7524 * @param {boolean} scan Should the prompt be included in the world info scan.
7525 * @param {(function(): Promise<boolean>|boolean)} filter Filter function to determine if the prompt should be injected.
7456 */7526 */
7457export function setExtensionPrompt(key, value, position, depth, scan = false, role = extension_prompt_roles.SYSTEM) {7527export function setExtensionPrompt(key, value, position, depth, scan = false, role = extension_prompt_roles.SYSTEM, filter = null) {
7458 extension_prompts[key] = {7528 extension_prompts[key] = {
7459 value: String(value),7529 value: String(value),
7460 position: Number(position),7530 position: Number(position),
7461 depth: Number(depth),7531 depth: Number(depth),
7462 scan: !!scan,7532 scan: !!scan,
7463 role: Number(role ?? extension_prompt_roles.SYSTEM),7533 role: Number(role ?? extension_prompt_roles.SYSTEM),
7534 filter: filter,
7464 };7535 };
7465}7536}
74667537
@@ -9158,40 +9229,48 @@ function doDrawerOpenClick() {
9158 * @returns {void}9229 * @returns {void}
9159 */9230 */
9160function doNavbarIconClick() {9231function doNavbarIconClick() {
9161 var icon = $(this).find('.drawer-icon');9232 const icon = $(this).find('.drawer-icon');
9162 var drawer = $(this).parent().find('.drawer-content');9233 const drawer = $(this).parent().find('.drawer-content');
9163 if (drawer.hasClass('resizing')) { return; }9234 if (drawer.hasClass('resizing')) { return; }
9164 var drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer');9235 const drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer');
9165 let targetDrawerID = $(this).parent().find('.drawer-content').attr('id');9236 const targetDrawerID = $(this).parent().find('.drawer-content').attr('id');
9166 const pinnedDrawerClicked = drawer.hasClass('pinnedOpen');9237 const pinnedDrawerClicked = drawer.hasClass('pinnedOpen');
91679238
9168 if (!drawerWasOpenAlready) { //to open the drawer9239 if (!drawerWasOpenAlready) { //to open the drawer
9169 $('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', async function () {9240 $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => {
9170 await delay(50); $(this).closest('.drawer-content').removeClass('resizing');9241 slideToggle(el, {
9242 ...getSlideToggleOptions(),
9243 onAnimationEnd: function (el) {
9244 el.closest('.drawer-content').classList.remove('resizing');
9245 },
9246 });
9171 });9247 });
9172 $('.openIcon').toggleClass('closedIcon openIcon');9248 $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon');
9173 $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');9249 $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');
9174 icon.toggleClass('openIcon closedIcon');9250 icon.toggleClass('openIcon closedIcon');
9175 drawer.toggleClass('openDrawer closedDrawer');9251 drawer.toggleClass('openDrawer closedDrawer');
91769252
9177 //console.log(targetDrawerID);9253 //console.log(targetDrawerID);
9178 if (targetDrawerID === 'right-nav-panel') {9254 if (targetDrawerID === 'right-nav-panel') {
9179 $(this).closest('.drawer').find('.drawer-content').addClass('resizing').slideToggle({9255 $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => {
9180 duration: 200,9256 slideToggle(el, {
9181 easing: 'swing',9257 ...getSlideToggleOptions(),
9182 start: function () {9258 elementDisplayStyle: 'flex',
9183 jQuery(this).css('display', 'flex'); //flex needed to make charlist scroll9259 onAnimationEnd: function (el) {
9184 },9260 el.closest('.drawer-content').classList.remove('resizing');
9185 complete: async function () {9261 favsToHotswap();
9186 favsToHotswap();9262 $('#rm_print_characters_block').trigger('scroll');
9187 await delay(50);9263 },
9188 $(this).closest('.drawer-content').removeClass('resizing');9264 });
9189 $('#rm_print_characters_block').trigger('scroll');
9190 },
9191 });9265 });
9192 } else {9266 } else {
9193 $(this).closest('.drawer').find('.drawer-content').addClass('resizing').slideToggle(200, 'swing', async function () {9267 $(this).closest('.drawer').find('.drawer-content').addClass('resizing').each((_, el) => {
9194 await delay(50); $(this).closest('.drawer-content').removeClass('resizing');9268 slideToggle(el, {
9269 ...getSlideToggleOptions(),
9270 onAnimationEnd: function (el) {
9271 el.closest('.drawer-content').classList.remove('resizing');
9272 },
9273 });
9195 });9274 });
9196 }9275 }
91979276
@@ -9207,13 +9286,23 @@ function doNavbarIconClick() {
9207 icon.toggleClass('closedIcon openIcon');9286 icon.toggleClass('closedIcon openIcon');
92089287
9209 if (pinnedDrawerClicked) {9288 if (pinnedDrawerClicked) {
9210 $(drawer).addClass('resizing').slideToggle(200, 'swing', async function () {9289 $(drawer).addClass('resizing').each((_, el) => {
9211 await delay(50); $(this).removeClass('resizing');9290 slideToggle(el, {
9291 ...getSlideToggleOptions(),
9292 onAnimationEnd: function (el) {
9293 el.classList.remove('resizing');
9294 },
9295 });
9212 });9296 });
9213 }9297 }
9214 else {9298 else {
9215 $('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', async function () {9299 $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => {
9216 await delay(50); $(this).closest('.drawer-content').removeClass('resizing');9300 slideToggle(el, {
9301 ...getSlideToggleOptions(),
9302 onAnimationEnd: function (el) {
9303 el.closest('.drawer-content').classList.remove('resizing');
9304 },
9305 });
9217 });9306 });
9218 }9307 }
92199308
@@ -9271,6 +9360,11 @@ function addDebugFunctions() {
9271 toastr.info('Event tracing is now ' + (localStorage.getItem('eventTracing') === 'true' ? 'enabled' : 'disabled'));9360 toastr.info('Event tracing is now ' + (localStorage.getItem('eventTracing') === 'true' ? 'enabled' : 'disabled'));
9272 });9361 });
92739362
9363 registerDebugFunction('toggleRegenerateWarning', 'Toggle Ctrl+Enter regeneration confirmation', 'Toggle the warning when regenerating a message with a Ctrl+Enter hotkey.', () => {
9364 localStorage.setItem('RegenerateWithCtrlEnter', localStorage.getItem('RegenerateWithCtrlEnter') === 'true' ? 'false' : 'true');
9365 toastr.info('Regenerate warning is now ' + (localStorage.getItem('RegenerateWithCtrlEnter') === 'true' ? 'disabled' : 'enabled'));
9366 });
9367
9274 registerDebugFunction('copySetup', 'Copy ST setup to clipboard [WIP]', 'Useful data when reporting bugs', async () => {9368 registerDebugFunction('copySetup', 'Copy ST setup to clipboard [WIP]', 'Useful data when reporting bugs', async () => {
9275 const getContextContents = getContext();9369 const getContextContents = getContext();
9276 const getSettingsContents = settings;9370 const getSettingsContents = settings;
@@ -9649,25 +9743,29 @@ jQuery(async function () {
9649 chooseBogusFolder($(this), tagId);9743 chooseBogusFolder($(this), tagId);
9650 });9744 });
96519745
9652 /**9746 const cssAutofit = CSS.supports('field-sizing', 'content');
9653 * Sets the scroll height of the edit textarea to fit the content.9747 if (!cssAutofit) {
9654 * @param {HTMLTextAreaElement} e Textarea element to auto-fit9748 /**
9655 */9749 * Sets the scroll height of the edit textarea to fit the content.
9656 function autoFitEditTextArea(e) {9750 * @param {HTMLTextAreaElement} e Textarea element to auto-fit
9657 scroll_holder = chatElement[0].scrollTop;9751 */
9658 e.style.height = '0px';9752 function autoFitEditTextArea(e) {
9659 const newHeight = e.scrollHeight + 4;9753 const scrollTop = chatElement.scrollTop();
9660 e.style.height = `${newHeight}px`;9754 e.style.height = '0px';
9661 is_use_scroll_holder = true;9755 const newHeight = e.scrollHeight + 4;
9756 e.style.height = `${newHeight}px`;
9757 chatElement.scrollTop(scrollTop);
9758 }
9759 const autoFitEditTextAreaDebounced = debounce(autoFitEditTextArea, debounce_timeout.short);
9760 document.addEventListener('input', e => {
9761 if (e.target instanceof HTMLTextAreaElement && e.target.classList.contains('edit_textarea')) {
9762 const scrollbarShown = e.target.clientWidth < e.target.offsetWidth && e.target.offsetHeight >= window.innerHeight * 0.75;
9763 const immediately = (e.target.scrollHeight > e.target.offsetHeight && !scrollbarShown) || e.target.value === '';
9764 immediately ? autoFitEditTextArea(e.target) : autoFitEditTextAreaDebounced(e.target);
9765 }
9766 });
9662 }9767 }
9663 const autoFitEditTextAreaDebounced = debounce(autoFitEditTextArea, debounce_timeout.short);9768
9664 document.addEventListener('input', e => {
9665 if (e.target instanceof HTMLTextAreaElement && e.target.classList.contains('edit_textarea')) {
9666 const scrollbarShown = e.target.clientWidth < e.target.offsetWidth && e.target.offsetHeight >= window.innerHeight * 0.75;
9667 const immediately = (e.target.scrollHeight > e.target.offsetHeight && !scrollbarShown) || e.target.value === '';
9668 immediately ? autoFitEditTextArea(e.target) : autoFitEditTextAreaDebounced(e.target);
9669 }
9670 });
9671 const chatElementScroll = document.getElementById('chat');9769 const chatElementScroll = document.getElementById('chat');
9672 const chatScrollHandler = function () {9770 const chatScrollHandler = function () {
9673 if (power_user.waifuMode) {9771 if (power_user.waifuMode) {
@@ -9689,12 +9787,6 @@ jQuery(async function () {
9689 };9787 };
9690 chatElementScroll.addEventListener('wheel', chatScrollHandler, { passive: true });9788 chatElementScroll.addEventListener('wheel', chatScrollHandler, { passive: true });
9691 chatElementScroll.addEventListener('touchmove', chatScrollHandler, { passive: true });9789 chatElementScroll.addEventListener('touchmove', chatScrollHandler, { passive: true });
9692 chatElementScroll.addEventListener('scroll', function () {
9693 if (is_use_scroll_holder) {
9694 this.scrollTop = scroll_holder;
9695 is_use_scroll_holder = false;
9696 }
9697 }, { passive: true });
96989790
9699 $(document).on('click', '.mes', function () {9791 $(document).on('click', '.mes', function () {
9700 //when a 'delete message' parent div is clicked9792 //when a 'delete message' parent div is clicked
@@ -10000,6 +10092,7 @@ jQuery(async function () {
10000 { id: 'api_key_llamacpp', secret: SECRET_KEYS.LLAMACPP },10092 { id: 'api_key_llamacpp', secret: SECRET_KEYS.LLAMACPP },
10001 { id: 'api_key_featherless', secret: SECRET_KEYS.FEATHERLESS },10093 { id: 'api_key_featherless', secret: SECRET_KEYS.FEATHERLESS },
10002 { id: 'api_key_huggingface', secret: SECRET_KEYS.HUGGINGFACE },10094 { id: 'api_key_huggingface', secret: SECRET_KEYS.HUGGINGFACE },
10095 { id: 'api_key_generic', secret: SECRET_KEYS.GENERIC },
10003 ];10096 ];
1000410097
10005 for (const key of keys) {10098 for (const key of keys) {
@@ -10034,20 +10127,21 @@ jQuery(async function () {
10034 await getStatusNovel();10127 await getStatusNovel();
10035 });10128 });
1003610129
10037 var button = $('#options_button');10130 const button = $('#options_button');
10038 var menu = $('#options');10131 const menu = $('#options');
10132 let isOptionsMenuVisible = false;
1003910133
10040 function showMenu() {10134 function showMenu() {
10041 showBookmarksButtons();10135 showBookmarksButtons();
10042 // menu.stop()
10043 menu.fadeIn(animation_duration);10136 menu.fadeIn(animation_duration);
10044 optionsPopper.update();10137 optionsPopper.update();
10138 isOptionsMenuVisible = true;
10045 }10139 }
1004610140
10047 function hideMenu() {10141 function hideMenu() {
10048 // menu.stop();
10049 menu.fadeOut(animation_duration);10142 menu.fadeOut(animation_duration);
10050 optionsPopper.update();10143 optionsPopper.update();
10144 isOptionsMenuVisible = false;
10051 }10145 }
1005210146
10053 function isMouseOverButtonOrMenu() {10147 function isMouseOverButtonOrMenu() {
@@ -10055,26 +10149,15 @@ jQuery(async function () {
10055 }10149 }
1005610150
10057 button.on('click', function () {10151 button.on('click', function () {
10058 if (menu.is(':visible')) {10152 if (isOptionsMenuVisible) {
10059 hideMenu();10153 hideMenu();
10060 } else {10154 } else {
10061 showMenu();10155 showMenu();
10062 }10156 }
10063 });10157 });
10064 button.on('blur', function () {
10065 //delay to prevent menu hiding when mouse leaves button into menu
10066 setTimeout(() => {
10067 if (!isMouseOverButtonOrMenu()) { hideMenu(); }
10068 }, 100);
10069 });
10070 menu.on('blur', function () {
10071 //delay to prevent menu hide when mouseleaves menu into button
10072 setTimeout(() => {
10073 if (!isMouseOverButtonOrMenu()) { hideMenu(); }
10074 }, 100);
10075 });
10076 $(document).on('click', function () {10158 $(document).on('click', function () {
10077 if (!isMouseOverButtonOrMenu() && menu.is(':visible')) { hideMenu(); }10159 if (!isOptionsMenuVisible) return;
10160 if (!isMouseOverButtonOrMenu()) { hideMenu(); }
10078 });10161 });
1007910162
10080 /* $('#set_chat_scenario').on('click', setScenarioOverride); */10163 /* $('#set_chat_scenario').on('click', setScenarioOverride); */
@@ -10442,14 +10525,16 @@ jQuery(async function () {
10442 .closest('.mes_block')10525 .closest('.mes_block')
10443 .find('.mes_text')10526 .find('.mes_text')
10444 .append(10527 .append(
10445 '<textarea id=\'curEditTextarea\' class=\'edit_textarea mdHotkeys\' style=\'max-width:auto;\'></textarea>',10528 '<textarea id=\'curEditTextarea\' class=\'edit_textarea mdHotkeys\'></textarea>',
10446 );10529 );
10447 $('#curEditTextarea').val(text);10530 $('#curEditTextarea').val(text);
10448 let edit_textarea = $(this)10531 let edit_textarea = $(this)
10449 .closest('.mes_block')10532 .closest('.mes_block')
10450 .find('.edit_textarea');10533 .find('.edit_textarea');
10451 edit_textarea.height(0);10534 if (!cssAutofit) {
10452 edit_textarea.height(edit_textarea[0].scrollHeight);10535 edit_textarea.height(0);
10536 edit_textarea.height(edit_textarea[0].scrollHeight);
10537 }
10453 edit_textarea.focus();10538 edit_textarea.focus();
10454 edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text10539 edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text
10455 String(edit_textarea.val()).length,10540 String(edit_textarea.val()).length,
@@ -10470,22 +10555,28 @@ jQuery(async function () {
10470 });10555 });
1047110556
10472 $(document).on('click', '.extraMesButtonsHint', function (e) {10557 $(document).on('click', '.extraMesButtonsHint', function (e) {
10473 const elmnt = e.target;10558 const $hint = $(e.target);
10474 $(elmnt).transition({10559 const $buttons = $hint.siblings('.extraMesButtons');
10560
10561 $hint.transition({
10475 opacity: 0,10562 opacity: 0,
10476 duration: animation_duration,10563 duration: animation_duration,
10477 easing: 'ease-in-out',10564 easing: animation_easing,
10565 complete: function () {
10566 $hint.hide();
10567 $buttons
10568 .addClass('visible')
10569 .css({
10570 opacity: 0,
10571 display: 'flex',
10572 })
10573 .transition({
10574 opacity: 1,
10575 duration: animation_duration,
10576 easing: animation_easing,
10577 });
10578 },
10478 });10579 });
10479 setTimeout(function () {
10480 $(elmnt).hide();
10481 $(elmnt).siblings('.extraMesButtons').css('opcacity', '0');
10482 $(elmnt).siblings('.extraMesButtons').css('display', 'flex');
10483 $(elmnt).siblings('.extraMesButtons').transition({
10484 opacity: 1,
10485 duration: animation_duration,
10486 easing: 'ease-in-out',
10487 });
10488 }, animation_duration);
10489 });10580 });
1049010581
10491 $(document).on('click', function (e) {10582 $(document).on('click', function (e) {
@@ -10496,23 +10587,36 @@ jQuery(async function () {
1049610587
10497 // Check if the click was outside the relevant elements10588 // Check if the click was outside the relevant elements
10498 if (!$(e.target).closest('.extraMesButtons, .extraMesButtonsHint').length) {10589 if (!$(e.target).closest('.extraMesButtons, .extraMesButtonsHint').length) {
10590 const $visibleButtons = $('.extraMesButtons.visible');
10591
10592 if (!$visibleButtons.length) {
10593 return;
10594 }
10595
10596 const $hiddenHints = $('.extraMesButtonsHint:hidden');
10597
10499 // Transition out the .extraMesButtons first10598 // Transition out the .extraMesButtons first
10500 $('.extraMesButtons:visible').transition({10599 $visibleButtons.transition({
10501 opacity: 0,10600 opacity: 0,
10502 duration: animation_duration,10601 duration: animation_duration,
10503 easing: 'ease-in-out',10602 easing: animation_easing,
10504 complete: function () {10603 complete: function () {
10505 $(this).hide(); // Hide the .extraMesButtons after the transition10604 // Hide the .extraMesButtons after the transition
10605 $(this)
10606 .hide()
10607 .removeClass('visible');
1050610608
10507 // Transition the .extraMesButtonsHint back in10609 // Transition the .extraMesButtonsHint back in
10508 $('.extraMesButtonsHint:not(:visible)').show().transition({10610 $hiddenHints
10509 opacity: .3,10611 .show()
10510 duration: animation_duration,10612 .transition({
10511 easing: 'ease-in-out',10613 opacity: 0.3,
10512 complete: function () {10614 duration: animation_duration,
10513 $(this).css('opacity', '');10615 easing: animation_easing,
10514 },10616 complete: function () {
10515 });10617 $(this).css('opacity', '');
10618 },
10619 });
10516 },10620 },
10517 });10621 });
10518 }10622 }
@@ -10696,8 +10800,9 @@ jQuery(async function () {
10696 }10800 }
10697 });10801 });
1069810802
10699 $('#export_button').on('click', function (e) {10803 $('#export_button').on('click', function () {
10700 $('#export_format_popup').toggle();10804 isExportPopupOpen = !isExportPopupOpen;
10805 $('#export_format_popup').toggle(isExportPopupOpen);
10701 exportPopper.update();10806 exportPopper.update();
10702 });10807 });
1070310808
@@ -10708,6 +10813,10 @@ jQuery(async function () {
10708 return;10813 return;
10709 }10814 }
1071010815
10816 $('#export_format_popup').hide();
10817 isExportPopupOpen = false;
10818 exportPopper.update();
10819
10711 // Save before exporting10820 // Save before exporting
10712 await createOrEditCharacter();10821 await createOrEditCharacter();
10713 const body = { format, avatar_url: characters[this_chid].avatar };10822 const body = { format, avatar_url: characters[this_chid].avatar };
@@ -10729,9 +10838,6 @@ jQuery(async function () {
10729 URL.revokeObjectURL(a.href);10838 URL.revokeObjectURL(a.href);
10730 document.body.removeChild(a);10839 document.body.removeChild(a);
10731 }10840 }
10732
10733
10734 $('#export_format_popup').hide();
10735 });10841 });
10736 //**************************CHAT IMPORT EXPORT*************************//10842 //**************************CHAT IMPORT EXPORT*************************//
10737 $('#chat_import_button').click(function () {10843 $('#chat_import_button').click(function () {
@@ -10803,15 +10909,18 @@ jQuery(async function () {
10803 });10909 });
1080410910
10805 $(document).on('click', '.drawer-opener', doDrawerOpenClick);10911 $(document).on('click', '.drawer-opener', doDrawerOpenClick);
10912
10806 $('.drawer-toggle').on('click', doNavbarIconClick);10913 $('.drawer-toggle').on('click', doNavbarIconClick);
1080710914
10808 $('html').on('touchstart mousedown', function (e) {10915 $('html').on('touchstart mousedown', function (e) {
10809 var clickTarget = $(e.target);10916 var clickTarget = $(e.target);
1081010917
10811 if ($('#export_format_popup').is(':visible')10918 if (isExportPopupOpen
10812 && clickTarget.closest('#export_button').length == 010919 && clickTarget.closest('#export_button').length == 0
10813 && clickTarget.closest('#export_format_popup').length == 0) {10920 && clickTarget.closest('#export_format_popup').length == 0) {
10814 $('#export_format_popup').hide();10921 $('#export_format_popup').hide();
10922 isExportPopupOpen = false;
10923 exportPopper.update();
10815 }10924 }
1081610925
10817 const forbiddenTargets = [10926 const forbiddenTargets = [
@@ -10836,12 +10945,16 @@ jQuery(async function () {
10836 if ($('.openDrawer').length !== 0) {10945 if ($('.openDrawer').length !== 0) {
10837 if (targetParentHasOpenDrawer === 0) {10946 if (targetParentHasOpenDrawer === 0) {
10838 //console.log($('.openDrawer').not('.pinnedOpen').length);10947 //console.log($('.openDrawer').not('.pinnedOpen').length);
10839 $('.openDrawer').not('.pinnedOpen').addClass('resizing').slideToggle(200, 'swing', function () {10948 $('.openDrawer').not('.pinnedOpen').addClass('resizing').each((_, el) => {
10840 $(this).closest('.drawer-content').removeClass('resizing');10949 slideToggle(el, {
10950 ...getSlideToggleOptions(),
10951 onAnimationEnd: (el) => {
10952 el.closest('.drawer-content').classList.remove('resizing');
10953 },
10954 });
10841 });10955 });
10842 $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon');10956 $('.openIcon').not('.drawerPinnedOpen').toggleClass('closedIcon openIcon');
10843 $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');10957 $('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');
10844
10845 }10958 }
10846 }10959 }
10847 }10960 }
@@ -11007,14 +11120,6 @@ jQuery(async function () {
11007 case 'renameCharButton':11120 case 'renameCharButton':
11008 renameCharacter();11121 renameCharacter();
11009 break;11122 break;
11010 /*case 'dupe_button':
11011 DupeChar();
11012 break;
11013 case 'export_button':
11014 $('#export_format_popup').toggle();
11015 exportPopper.update();
11016 break;
11017 */
11018 case 'import_character_info':11123 case 'import_character_info':
11019 await importEmbeddedWorldInfo();11124 await importEmbeddedWorldInfo();
11020 saveCharacterDebounced();11125 saveCharacterDebounced();
public/scripts/PromptManager.js+17 -6
@@ -1208,7 +1208,7 @@ class PromptManager {
1208 const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block');1208 const forbidOverridesBlock = document.getElementById(this.configuration.prefix + 'prompt_manager_forbid_overrides_block');
12091209
1210 nameField.value = prompt.name ?? '';1210 nameField.value = prompt.name ?? '';
1211 roleField.value = prompt.role ?? 'system';1211 roleField.value = prompt.role || 'system';
1212 promptField.value = prompt.content ?? '';1212 promptField.value = prompt.content ?? '';
1213 promptField.disabled = prompt.marker ?? false;1213 promptField.disabled = prompt.marker ?? false;
1214 injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE;1214 injectionPositionField.value = prompt.injection_position ?? INJECTION_POSITION.RELATIVE;
@@ -1518,7 +1518,7 @@ class PromptManager {
1518 let detachSpanHtml = '';1518 let detachSpanHtml = '';
1519 if (this.isPromptDeletionAllowed(prompt)) {1519 if (this.isPromptDeletionAllowed(prompt)) {
1520 detachSpanHtml = `1520 detachSpanHtml = `
1521 <span title="Remove" class="prompt-manager-detach-action caution fa-solid fa-chain-broken"></span>1521 <span title="Remove" class="prompt-manager-detach-action caution fa-solid fa-chain-broken fa-xs"></span>
1522 `;1522 `;
1523 } else {1523 } else {
1524 detachSpanHtml = '<span class="fa-solid"></span>';1524 detachSpanHtml = '<span class="fa-solid"></span>';
@@ -1527,7 +1527,7 @@ class PromptManager {
1527 let editSpanHtml = '';1527 let editSpanHtml = '';
1528 if (this.isPromptEditAllowed(prompt)) {1528 if (this.isPromptEditAllowed(prompt)) {
1529 editSpanHtml = `1529 editSpanHtml = `
1530 <span title="edit" class="prompt-manager-edit-action fa-solid fa-pencil"></span>1530 <span title="edit" class="prompt-manager-edit-action fa-solid fa-pencil fa-xs"></span>
1531 `;1531 `;
1532 } else {1532 } else {
1533 editSpanHtml = '<span class="fa-solid"></span>';1533 editSpanHtml = '<span class="fa-solid"></span>';
@@ -1550,16 +1550,27 @@ class PromptManager {
1550 const isInjectionPrompt = prompt.injection_position === INJECTION_POSITION.ABSOLUTE;1550 const isInjectionPrompt = prompt.injection_position === INJECTION_POSITION.ABSOLUTE;
1551 const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier);1551 const isOverriddenPrompt = Array.isArray(this.overriddenPrompts) && this.overriddenPrompts.includes(prompt.identifier);
1552 const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : '';1552 const importantClass = isImportantPrompt ? `${prefix}prompt_manager_important` : '';
1553 const iconLookup = prompt.role === 'system' && (prompt.marker || prompt.system_prompt) ? '' : prompt.role;
1554
1555 //add role icons to the right of prompt name
1556 const promptRoles = {
1557 assistant: { roleIcon: 'fa-robot', roleTitle: 'Prompt will be sent as Assistant' },
1558 user: { roleIcon: 'fa-user', roleTitle: 'Prompt will be sent as User' },
1559 };
1560 const roleIcon = promptRoles[iconLookup]?.roleIcon || '';
1561 const roleTitle = promptRoles[iconLookup]?.roleTitle || '';
1562
1553 listItemHtml += `1563 listItemHtml += `
1554 <li class="${prefix}prompt_manager_prompt ${draggableClass} ${enabledClass} ${markerClass} ${importantClass}" data-pm-identifier="${prompt.identifier}">1564 <li class="${prefix}prompt_manager_prompt ${draggableClass} ${enabledClass} ${markerClass} ${importantClass}" data-pm-identifier="${escapeHtml(prompt.identifier)}">
1555 <span class="${prefix}prompt_manager_prompt_name" data-pm-name="${encodedName}">1565 <span class="${prefix}prompt_manager_prompt_name" data-pm-name="${encodedName}">
1556 ${isMarkerPrompt ? '<span class="fa-fw fa-solid fa-thumb-tack" title="Marker"></span>' : ''}1566 ${isMarkerPrompt ? '<span class="fa-fw fa-solid fa-thumb-tack" title="Marker"></span>' : ''}
1557 ${isSystemPrompt ? '<span class="fa-fw fa-solid fa-square-poll-horizontal" title="Global Prompt"></span>' : ''}1567 ${isSystemPrompt ? '<span class="fa-fw fa-solid fa-square-poll-horizontal" title="Global Prompt"></span>' : ''}
1558 ${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''}1568 ${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''}
1559 ${isUserPrompt ? '<span class="fa-fw fa-solid fa-user" title="User Prompt"></span>' : ''}1569 ${isUserPrompt ? '<span class="fa-fw fa-solid fa-asterisk" title="Preset Prompt"></span>' : ''}
1560 ${isInjectionPrompt ? '<span class="fa-fw fa-solid fa-syringe" title="In-Chat Injection"></span>' : ''}1570 ${isInjectionPrompt ? '<span class="fa-fw fa-solid fa-syringe" title="In-Chat Injection"></span>' : ''}
1561 ${this.isPromptInspectionAllowed(prompt) ? `<a title="${encodedName}" class="prompt-manager-inspect-action">${encodedName}</a>` : `<span title="${encodedName}">${encodedName}</span>`}1571 ${this.isPromptInspectionAllowed(prompt) ? `<a title="${encodedName}" class="prompt-manager-inspect-action">${encodedName}</a>` : `<span title="${encodedName}">${encodedName}</span>`}
1562 ${isInjectionPrompt ? `<small class="prompt-manager-injection-depth">@ ${prompt.injection_depth}</small>` : ''}1572 ${roleIcon ? `<span data-role="${escapeHtml(prompt.role)}" class="fa-xs fa-solid ${roleIcon}" title="${roleTitle}"></span>` : ''}
1573 ${isInjectionPrompt ? `<small class="prompt-manager-injection-depth">@ ${escapeHtml(prompt.injection_depth)}</small>` : ''}
1563 ${isOverriddenPrompt ? '<small class="fa-solid fa-address-card prompt-manager-overridden" title="Pulled from a character card"></small>' : ''}1574 ${isOverriddenPrompt ? '<small class="fa-solid fa-address-card prompt-manager-overridden" title="Pulled from a character card"></small>' : ''}
1564 </span>1575 </span>
1565 <span>1576 <span>
public/scripts/RossAscends-mods.js+44 -10
@@ -1,4 +1,4 @@
1import { DOMPurify, Bowser } from '../lib.js';1import { DOMPurify, Bowser, slideToggle } from '../lib.js';
22
3import {3import {
4 characters,4 characters,
@@ -19,6 +19,7 @@ import {
19 menu_type,19 menu_type,
20 substituteParams,20 substituteParams,
21 sendTextareaMessage,21 sendTextareaMessage,
22 getSlideToggleOptions,
22} from '../script.js';23} from '../script.js';
2324
24import {25import {
@@ -315,7 +316,7 @@ function RA_checkOnlineStatus() {
315 if (online_status == 'no_connection') {316 if (online_status == 'no_connection') {
316 const send_textarea = $('#send_textarea');317 const send_textarea = $('#send_textarea');
317 send_textarea.attr('placeholder', send_textarea.attr('no_connection_text')); //Input bar placeholder tells users they are not connected318 send_textarea.attr('placeholder', send_textarea.attr('no_connection_text')); //Input bar placeholder tells users they are not connected
318 //$('#send_form').addClass('no-connection'); //entire input form area is red when not connected319 $('#send_form').addClass('no-connection');
319 $('#send_but').addClass('displayNone'); //send button is hidden when not connected;320 $('#send_but').addClass('displayNone'); //send button is hidden when not connected;
320 $('#mes_continue').addClass('displayNone'); //continue button is hidden when not connected;321 $('#mes_continue').addClass('displayNone'); //continue button is hidden when not connected;
321 $('#mes_impersonate').addClass('displayNone'); //continue button is hidden when not connected;322 $('#mes_impersonate').addClass('displayNone'); //continue button is hidden when not connected;
@@ -326,7 +327,7 @@ function RA_checkOnlineStatus() {
326 if (online_status !== undefined && online_status !== 'no_connection') {327 if (online_status !== undefined && online_status !== 'no_connection') {
327 const send_textarea = $('#send_textarea');328 const send_textarea = $('#send_textarea');
328 send_textarea.attr('placeholder', send_textarea.attr('connected_text')); //on connect, placeholder tells user to type message329 send_textarea.attr('placeholder', send_textarea.attr('connected_text')); //on connect, placeholder tells user to type message
329 //$('#send_form').removeClass('no-connection');330 $('#send_form').removeClass('no-connection');
330 $('#API-status-top').removeClass('fa-plug-circle-exclamation redOverlayGlow');331 $('#API-status-top').removeClass('fa-plug-circle-exclamation redOverlayGlow');
331 $('#API-status-top').addClass('fa-plug');332 $('#API-status-top').addClass('fa-plug');
332 connection_made = true;333 connection_made = true;
@@ -389,6 +390,7 @@ function RA_autoconnect(PrevApi) {
389 || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI)390 || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI)
390 || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY)391 || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY)
391 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)392 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)
393 || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)
392 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)394 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
393 ) {395 ) {
394 $('#api_button_openai').trigger('click');396 $('#api_button_openai').trigger('click');
@@ -748,8 +750,8 @@ export function initRossMods() {
748 $(RightNavDrawerIcon).removeClass('drawerPinnedOpen');750 $(RightNavDrawerIcon).removeClass('drawerPinnedOpen');
749751
750 if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {752 if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
751 $(RightNavPanel).slideToggle(200, 'swing');753 slideToggle(RightNavPanel, getSlideToggleOptions());
752 $(RightNavDrawerIcon).toggleClass('openIcon closedIcon');754 $(RightNavDrawerIcon).toggleClass('closedIcon openIcon');
753 $(RightNavPanel).toggleClass('openDrawer closedDrawer');755 $(RightNavPanel).toggleClass('openDrawer closedDrawer');
754 }756 }
755 }757 }
@@ -766,8 +768,8 @@ export function initRossMods() {
766 $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen');768 $(LeftNavDrawerIcon).removeClass('drawerPinnedOpen');
767769
768 if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {770 if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
769 $(LeftNavPanel).slideToggle(200, 'swing');771 slideToggle(LeftNavPanel, getSlideToggleOptions());
770 $(LeftNavDrawerIcon).toggleClass('openIcon closedIcon');772 $(LeftNavDrawerIcon).toggleClass('closedIcon openIcon');
771 $(LeftNavPanel).toggleClass('openDrawer closedDrawer');773 $(LeftNavPanel).toggleClass('openDrawer closedDrawer');
772 }774 }
773 }775 }
@@ -786,8 +788,8 @@ export function initRossMods() {
786788
787 if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) {789 if ($(WorldInfo).hasClass('openDrawer') && $('.openDrawer').length > 1) {
788 console.debug('closing WI after lock removal');790 console.debug('closing WI after lock removal');
789 $(WorldInfo).slideToggle(200, 'swing');791 slideToggle(WorldInfo, getSlideToggleOptions());
790 $(WIDrawerIcon).toggleClass('openIcon closedIcon');792 $(WIDrawerIcon).toggleClass('closedIcon openIcon');
791 $(WorldInfo).toggleClass('openDrawer closedDrawer');793 $(WorldInfo).toggleClass('openDrawer closedDrawer');
792 }794 }
793 }795 }
@@ -886,7 +888,40 @@ export function initRossMods() {
886 saveSettingsDebounced();888 saveSettingsDebounced();
887 });889 });
888890
891 const cssAutofit = CSS.supports('field-sizing', 'content');
892
893 if (cssAutofit) {
894 let lastHeight = chatBlock.offsetHeight;
895 const chatBlockResizeObserver = new ResizeObserver((entries) => {
896 for (const entry of entries) {
897 if (entry.target !== chatBlock) {
898 continue;
899 }
900
901 const threshold = 1;
902 const newHeight = chatBlock.offsetHeight;
903 const deltaHeight = newHeight - lastHeight;
904 const isScrollAtBottom = Math.abs(chatBlock.scrollHeight - chatBlock.scrollTop - newHeight) <= threshold;
905
906 if (!isScrollAtBottom && Math.abs(deltaHeight) > threshold) {
907 chatBlock.scrollTop -= deltaHeight;
908 }
909 lastHeight = newHeight;
910 }
911 });
912
913 chatBlockResizeObserver.observe(chatBlock);
914 }
915
889 sendTextArea.addEventListener('input', () => {916 sendTextArea.addEventListener('input', () => {
917 saveUserInputDebounced();
918
919 if (cssAutofit) {
920 // Unset modifications made with a manual resize
921 sendTextArea.style.height = 'auto';
922 return;
923 }
924
890 const hasContent = sendTextArea.value !== '';925 const hasContent = sendTextArea.value !== '';
891 const fitsCurrentSize = sendTextArea.scrollHeight <= sendTextArea.offsetHeight;926 const fitsCurrentSize = sendTextArea.scrollHeight <= sendTextArea.offsetHeight;
892 const isScrollbarShown = sendTextArea.clientWidth < sendTextArea.offsetWidth;927 const isScrollbarShown = sendTextArea.clientWidth < sendTextArea.offsetWidth;
@@ -894,7 +929,6 @@ export function initRossMods() {
894 const needsDebounce = hasContent && (fitsCurrentSize || (isScrollbarShown && isHalfScreenHeight));929 const needsDebounce = hasContent && (fitsCurrentSize || (isScrollbarShown && isHalfScreenHeight));
895 if (needsDebounce) autoFitSendTextAreaDebounced();930 if (needsDebounce) autoFitSendTextAreaDebounced();
896 else autoFitSendTextArea();931 else autoFitSendTextArea();
897 saveUserInputDebounced();
898 });932 });
899933
900 restoreUserInput();934 restoreUserInput();
public/scripts/authors-note.js+1 -1
@@ -440,7 +440,7 @@ async function onChatChanged() {
440 const context = getContext();440 const context = getContext();
441441
442 // Disable the chara note if in a group442 // Disable the chara note if in a group
443 $('#extension_floating_chara').prop('disabled', context.groupId ? true : false);443 $('#extension_floating_chara').prop('disabled', !!context.groupId);
444444
445 const tokenCounter1 = chat_metadata[metadata_keys.prompt] ? await getTokenCountAsync(chat_metadata[metadata_keys.prompt]) : 0;445 const tokenCounter1 = chat_metadata[metadata_keys.prompt] ? await getTokenCountAsync(chat_metadata[metadata_keys.prompt]) : 0;
446 $('#extension_floating_prompt_token_counter').text(tokenCounter1);446 $('#extension_floating_prompt_token_counter').text(tokenCounter1);
public/scripts/backgrounds.js+31 -0
@@ -12,6 +12,7 @@ const LIST_METADATA_KEY = 'chat_backgrounds';
12export let background_settings = {12export let background_settings = {
13 name: '__transparent.png',13 name: '__transparent.png',
14 url: generateUrlParameter('__transparent.png', false),14 url: generateUrlParameter('__transparent.png', false),
15 fitting: 'classic',
15};16};
1617
17export function loadBackgroundSettings(settings) {18export function loadBackgroundSettings(settings) {
@@ -19,7 +20,12 @@ export function loadBackgroundSettings(settings) {
19 if (!backgroundSettings || !backgroundSettings.name || !backgroundSettings.url) {20 if (!backgroundSettings || !backgroundSettings.name || !backgroundSettings.url) {
20 backgroundSettings = background_settings;21 backgroundSettings = background_settings;
21 }22 }
23 if (!backgroundSettings.fitting) {
24 backgroundSettings.fitting = 'classic';
25 }
22 setBackground(backgroundSettings.name, backgroundSettings.url);26 setBackground(backgroundSettings.name, backgroundSettings.url);
27 setFittingClass(backgroundSettings.fitting);
28 $('#background_fitting').val(backgroundSettings.fitting);
23}29}
2430
25/**31/**
@@ -333,6 +339,14 @@ async function autoBackgroundCommand() {
333 const bestMatch = fuse.search(reply, { limit: 1 });339 const bestMatch = fuse.search(reply, { limit: 1 });
334340
335 if (bestMatch.length == 0) {341 if (bestMatch.length == 0) {
342 for (const option of options) {
343 if (String(reply).toLowerCase().includes(option.text.toLowerCase())) {
344 console.debug('Fallback choosing background:', option);
345 option.element.click();
346 return '';
347 }
348 }
349
336 toastr.warning('No match found. Please try again.');350 toastr.warning('No match found. Please try again.');
337 return '';351 return '';
338 }352 }
@@ -462,6 +476,18 @@ function highlightNewBackground(bg) {
462 flashHighlight(newBg);476 flashHighlight(newBg);
463}477}
464478
479/**
480 * Sets the fitting class for the background element
481 * @param {string} fitting Fitting type
482 */
483function setFittingClass(fitting) {
484 const backgrounds = $('#bg1, #bg_custom');
485 backgrounds.toggleClass('cover', fitting === 'cover');
486 backgrounds.toggleClass('contain', fitting === 'contain');
487 backgrounds.toggleClass('stretch', fitting === 'stretch');
488 backgrounds.toggleClass('center', fitting === 'center');
489}
490
465function onBackgroundFilterInput() {491function onBackgroundFilterInput() {
466 const filterValue = String($(this).val()).toLowerCase();492 const filterValue = String($(this).val()).toLowerCase();
467 $('#bg_menu_content > div').each(function () {493 $('#bg_menu_content > div').each(function () {
@@ -502,4 +528,9 @@ export function initBackgrounds() {
502 helpString: 'Automatically changes the background based on the chat context using the AI request prompt',528 helpString: 'Automatically changes the background based on the chat context using the AI request prompt',
503 }));529 }));
504530
531 $('#background_fitting').on('input', function () {
532 background_settings.fitting = String($(this).val());
533 setFittingClass(background_settings.fitting);
534 saveSettingsDebounced();
535 });
505}536}
public/scripts/cfg-scale.js+9 -3
@@ -451,8 +451,14 @@ function getCustomSeparator() {
451 }451 }
452}452}
453453
454// Gets the CFG prompt454/**
455export function getCfgPrompt(guidanceScale, isNegative) {455 * Gets the CFG prompt based on the guidance scale.
456 * @param {{type: number, value: number}} guidanceScale The CFG guidance scale
457 * @param {boolean} isNegative Whether to get the negative prompt
458 * @param {boolean} quiet Whether to suppress console output
459 * @returns {{value: string, depth: number}} The CFG prompt and insertion depth
460 */
461export function getCfgPrompt(guidanceScale, isNegative, quiet = false) {
456 let splitCfgPrompt = [];462 let splitCfgPrompt = [];
457463
458 const cfgPromptCombine = chat_metadata[metadataKeys.prompt_combine] ?? [];464 const cfgPromptCombine = chat_metadata[metadataKeys.prompt_combine] ?? [];
@@ -484,7 +490,7 @@ export function getCfgPrompt(guidanceScale, isNegative) {
484 const customSeparator = getCustomSeparator();490 const customSeparator = getCustomSeparator();
485 const combinedCfgPrompt = splitCfgPrompt.filter((e) => e.length > 0).join(customSeparator);491 const combinedCfgPrompt = splitCfgPrompt.filter((e) => e.length > 0).join(customSeparator);
486 const insertionDepth = chat_metadata[metadataKeys.prompt_insertion_depth] ?? 1;492 const insertionDepth = chat_metadata[metadataKeys.prompt_insertion_depth] ?? 1;
487 console.log(`Setting CFG with guidance scale: ${guidanceScale.value}, negatives: ${combinedCfgPrompt}`);493 !quiet && console.log(`Setting CFG with guidance scale: ${guidanceScale.value}, negatives: ${combinedCfgPrompt}`);
488494
489 return {495 return {
490 value: combinedCfgPrompt,496 value: combinedCfgPrompt,
public/scripts/extensions.js+498 -220
@@ -4,29 +4,57 @@ import { eventSource, event_types, saveSettings, saveSettingsDebounced, getReque
4import { showLoader } from './loader.js';4import { showLoader } from './loader.js';
5import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';5import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
6import { renderTemplate, renderTemplateAsync } from './templates.js';6import { renderTemplate, renderTemplateAsync } from './templates.js';
7import { isSubsetOf, setValueByPath } from './utils.js';7import { delay, isSubsetOf, setValueByPath } from './utils.js';
8import { getContext } from './st-context.js';8import { getContext } from './st-context.js';
9import { isAdmin } from './user.js';
10import { t } from './i18n.js';
11import { debounce_timeout } from './constants.js';
12
9export {13export {
10 getContext,14 getContext,
11 getApiUrl,15 getApiUrl,
12 loadExtensionSettings,
13 runGenerationInterceptors,
14 doExtrasFetch,
15 modules,
16 extension_settings,
17 ModuleWorkerWrapper,
18};16};
1917
20/** @type {string[]} */18/** @type {string[]} */
21export let extensionNames = [];19export let extensionNames = [];
2220
21/**
22 * Holds the type of each extension.
23 * Don't use this directly, use getExtensionType instead!
24 * @type {Record<string, string>}
25 */
26export let extensionTypes = {};
27
28/**
29 * A list of active modules provided by the Extras API.
30 * @type {string[]}
31 */
32export let modules = [];
33
34/**
35 * A set of active extensions.
36 * @type {Set<string>}
37 */
38let activeExtensions = new Set();
39
40const getApiUrl = () => extension_settings.apiUrl;
41const sortManifests = (a, b) => parseInt(a.loading_order) - parseInt(b.loading_order) || String(a.display_name).localeCompare(String(b.display_name));
42let connectedToApi = false;
43
44/**
45 * Holds manifest data for each extension.
46 * @type {Record<string, object>}
47 */
23let manifests = {};48let manifests = {};
24const defaultUrl = 'http://localhost:5100';
2549
26let saveMetadataTimeout = null;50/**
51 * Default URL for the Extras API.
52 */
53const defaultUrl = 'http://localhost:5100';
2754
28let requiresReload = false;55let requiresReload = false;
29let stateChanged = false;56let stateChanged = false;
57let saveMetadataTimeout = null;
3058
31export function saveMetadataDebounced() {59export function saveMetadataDebounced() {
32 const context = getContext();60 const context = getContext();
@@ -51,9 +79,9 @@ export function saveMetadataDebounced() {
51 }79 }
5280
53 console.debug('Saving metadata...');81 console.debug('Saving metadata...');
54 newContext.saveMetadata();82 await newContext.saveMetadata();
55 console.debug('Saved metadata...');83 console.debug('Saved metadata...');
56 }, 1000);84 }, debounce_timeout.relaxed);
57}85}
5886
59/**87/**
@@ -83,7 +111,7 @@ export function renderExtensionTemplateAsync(extensionName, templateId, template
83}111}
84112
85// Disables parallel updates113// Disables parallel updates
86class ModuleWorkerWrapper {114export class ModuleWorkerWrapper {
87 constructor(callback) {115 constructor(callback) {
88 this.isBusy = false;116 this.isBusy = false;
89 this.callback = callback;117 this.callback = callback;
@@ -107,7 +135,7 @@ class ModuleWorkerWrapper {
107 }135 }
108}136}
109137
110const extension_settings = {138export const extension_settings = {
111 apiUrl: defaultUrl,139 apiUrl: defaultUrl,
112 apiKey: '',140 apiKey: '',
113 autoConnect: false,141 autoConnect: false,
@@ -172,12 +200,6 @@ const extension_settings = {
172 disabled_attachments: [],200 disabled_attachments: [],
173};201};
174202
175let modules = [];
176let activeExtensions = new Set();
177
178const getApiUrl = () => extension_settings.apiUrl;
179let connectedToApi = false;
180
181function showHideExtensionsMenu() {203function showHideExtensionsMenu() {
182 // Get the number of menu items that are not hidden204 // Get the number of menu items that are not hidden
183 const hasMenuItems = $('#extensionsMenu').children().filter((_, child) => $(child).css('display') !== 'none').length > 0;205 const hasMenuItems = $('#extensionsMenu').children().filter((_, child) => $(child).css('display') !== 'none').length > 0;
@@ -194,7 +216,23 @@ function showHideExtensionsMenu() {
194// Periodically check for new extensions216// Periodically check for new extensions
195const menuInterval = setInterval(showHideExtensionsMenu, 1000);217const menuInterval = setInterval(showHideExtensionsMenu, 1000);
196218
197async function doExtrasFetch(endpoint, args) {219/**
220 * Gets the type of an extension based on its external ID.
221 * @param {string} externalId External ID of the extension (excluding or including the leading 'third-party/')
222 * @returns {string} Type of the extension (global, local, system, or empty string if not found)
223 */
224function getExtensionType(externalId) {
225 const id = Object.keys(extensionTypes).find(id => id === externalId || (id.startsWith('third-party') && id.endsWith(externalId)));
226 return id ? extensionTypes[id] : '';
227}
228
229/**
230 * Performs a fetch of the Extras API.
231 * @param {string|URL} endpoint Extras API endpoint
232 * @param {RequestInit} args Request arguments
233 * @returns {Promise<Response>} Response from the fetch
234 */
235export async function doExtrasFetch(endpoint, args = {}) {
198 if (!args) {236 if (!args) {
199 args = {};237 args = {};
200 }238 }
@@ -213,10 +251,13 @@ async function doExtrasFetch(endpoint, args) {
213 });251 });
214 }252 }
215253
216 const response = await fetch(endpoint, args);254 return await fetch(endpoint, args);
217 return response;
218}255}
219256
257/**
258 * Discovers extensions from the API.
259 * @returns {Promise<{name: string, type: string}[]>}
260 */
220async function discoverExtensions() {261async function discoverExtensions() {
221 try {262 try {
222 const response = await fetch('/api/extensions/discover');263 const response = await fetch('/api/extensions/discover');
@@ -245,6 +286,11 @@ function onEnableExtensionClick() {
245 enableExtension(name, false);286 enableExtension(name, false);
246}287}
247288
289/**
290 * Enables an extension by name.
291 * @param {string} name Extension name
292 * @param {boolean} [reload=true] If true, reload the page after enabling the extension
293 */
248export async function enableExtension(name, reload = true) {294export async function enableExtension(name, reload = true) {
249 extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name);295 extension_settings.disabledExtensions = extension_settings.disabledExtensions.filter(x => x !== name);
250 stateChanged = true;296 stateChanged = true;
@@ -256,6 +302,11 @@ export async function enableExtension(name, reload = true) {
256 }302 }
257}303}
258304
305/**
306 * Disables an extension by name.
307 * @param {string} name Extension name
308 * @param {boolean} [reload=true] If true, reload the page after disabling the extension
309 */
259export async function disableExtension(name, reload = true) {310export async function disableExtension(name, reload = true) {
260 extension_settings.disabledExtensions.push(name);311 extension_settings.disabledExtensions.push(name);
261 stateChanged = true;312 stateChanged = true;
@@ -267,6 +318,11 @@ export async function disableExtension(name, reload = true) {
267 }318 }
268}319}
269320
321/**
322 * Loads manifest.json files for extensions.
323 * @param {string[]} names Array of extension names
324 * @returns {Promise<Record<string, object>>} Object with extension names as keys and their manifests as values
325 */
270async function getManifests(names) {326async function getManifests(names) {
271 const obj = {};327 const obj = {};
272 const promises = [];328 const promises = [];
@@ -294,43 +350,36 @@ async function getManifests(names) {
294 return obj;350 return obj;
295}351}
296352
353/**
354 * Tries to activate all available extensions that are not already active.
355 * @returns {Promise<void>}
356 */
297async function activateExtensions() {357async function activateExtensions() {
298 const extensions = Object.entries(manifests).sort((a, b) => a[1].loading_order - b[1].loading_order);358 const extensions = Object.entries(manifests).sort((a, b) => sortManifests(a[1], b[1]));
299 const promises = [];359 const promises = [];
300360
301 for (let entry of extensions) {361 for (let entry of extensions) {
302 const name = entry[0];362 const name = entry[0];
303 const manifest = entry[1];363 const manifest = entry[1];
304 const elementExists = document.getElementById(name) !== null;
305364
306 if (elementExists || activeExtensions.has(name)) {365 if (activeExtensions.has(name)) {
307 continue;366 continue;
308 }367 }
309368
310 // all required modules are active (offline extensions require none)369 const meetsModuleRequirements = !Array.isArray(manifest.requires) || isSubsetOf(modules, manifest.requires);
311 if (isSubsetOf(modules, manifest.requires)) {370 const isDisabled = extension_settings.disabledExtensions.includes(name);
312 try {
313 const isDisabled = extension_settings.disabledExtensions.includes(name);
314 const li = document.createElement('li');
315
316 if (!isDisabled) {
317 const promise = Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]);
318 await promise
319 .then(() => activeExtensions.add(name))
320 .catch(err => console.log('Could not activate extension: ' + name, err));
321 promises.push(promise);
322 }
323 else {
324 li.classList.add('disabled');
325 }
326
327 li.id = name;
328 li.innerText = manifest.display_name;
329371
330 $('#extensions_list').append(li);372 if (meetsModuleRequirements && !isDisabled) {
373 try {
374 console.debug('Activating extension', name);
375 const promise = Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]);
376 await promise
377 .then(() => activeExtensions.add(name))
378 .catch(err => console.log('Could not activate extension', name, err));
379 promises.push(promise);
331 }380 }
332 catch (error) {381 catch (error) {
333 console.error(`Could not activate extension: ${name}`);382 console.error('Could not activate extension', name);
334 console.error(error);383 console.error(error);
335 }384 }
336 }385 }
@@ -340,8 +389,8 @@ async function activateExtensions() {
340}389}
341390
342async function connectClickHandler() {391async function connectClickHandler() {
343 const baseUrl = $('#extensions_url').val();392 const baseUrl = String($('#extensions_url').val());
344 extension_settings.apiUrl = String(baseUrl);393 extension_settings.apiUrl = baseUrl;
345 const testApiKey = $('#extensions_api_key').val();394 const testApiKey = $('#extensions_api_key').val();
346 extension_settings.apiKey = String(testApiKey);395 extension_settings.apiKey = String(testApiKey);
347 saveSettingsDebounced();396 saveSettingsDebounced();
@@ -368,26 +417,30 @@ async function addExtensionsButtonAndMenu() {
368417
369 const button = $('#extensionsMenuButton');418 const button = $('#extensionsMenuButton');
370 const dropdown = $('#extensionsMenu');419 const dropdown = $('#extensionsMenu');
371 //dropdown.hide();420 let isDropdownVisible = false;
372421
373 let popper = Popper.createPopper(button.get(0), dropdown.get(0), {422 let popper = Popper.createPopper(button.get(0), dropdown.get(0), {
374 placement: 'top-start',423 placement: 'top-start',
375 });424 });
376425
377 $(button).on('click', function () {426 $(button).on('click', function () {
378 if (dropdown.is(':visible')) {427 if (isDropdownVisible) {
379 dropdown.fadeOut(animation_duration);428 dropdown.fadeOut(animation_duration);
429 isDropdownVisible = false;
380 } else {430 } else {
381 dropdown.fadeIn(animation_duration);431 dropdown.fadeIn(animation_duration);
432 isDropdownVisible = true;
382 }433 }
383 popper.update();434 popper.update();
384 });435 });
385436
386 $('html').on('click', function (e) {437 $('html').on('click', function (e) {
438 if (!isDropdownVisible) return;
387 const clickTarget = $(e.target);439 const clickTarget = $(e.target);
388 const noCloseTargets = ['#sd_gen', '#extensionsMenuButton', '#roll_dice'];440 const noCloseTargets = ['#sd_gen', '#extensionsMenuButton', '#roll_dice'];
389 if (dropdown.is(':visible') && !noCloseTargets.some(id => clickTarget.closest(id).length > 0)) {441 if (!noCloseTargets.some(id => clickTarget.closest(id).length > 0)) {
390 $(dropdown).fadeOut(animation_duration);442 dropdown.fadeOut(animation_duration);
443 isDropdownVisible = false;
391 }444 }
392 });445 });
393}446}
@@ -401,21 +454,11 @@ function notifyUpdatesInputHandler() {
401 }454 }
402}455}
403456
404/* $(document).on('click', function (e) {457/**
405 const target = $(e.target);458 * Connects to the Extras API.
406 if (target.is(dropdown)) return;459 * @param {string} baseUrl Extras API base URL
407 if (target.is(button) && dropdown.is(':hidden')) {460 * @returns {Promise<void>}
408 dropdown.toggle(200);461 */
409 popper.update();
410 }
411 if (target !== dropdown &&
412 target !== button &&
413 dropdown.is(":visible")) {
414 dropdown.hide(200);
415 }
416 });
417} */
418
419async function connectToApi(baseUrl) {462async function connectToApi(baseUrl) {
420 if (!baseUrl) {463 if (!baseUrl) {
421 return;464 return;
@@ -431,7 +474,7 @@ async function connectToApi(baseUrl) {
431 const data = await getExtensionsResult.json();474 const data = await getExtensionsResult.json();
432 modules = data.modules;475 modules = data.modules;
433 await activateExtensions();476 await activateExtensions();
434 eventSource.emit(event_types.EXTRAS_CONNECTED, modules);477 await eventSource.emit(event_types.EXTRAS_CONNECTED, modules);
435 }478 }
436479
437 updateStatus(getExtensionsResult.ok);480 updateStatus(getExtensionsResult.ok);
@@ -441,71 +484,84 @@ async function connectToApi(baseUrl) {
441 }484 }
442}485}
443486
487/**
488 * Updates the status of Extras API connection.
489 * @param {boolean} success Whether the connection was successful
490 */
444function updateStatus(success) {491function updateStatus(success) {
445 connectedToApi = success;492 connectedToApi = success;
446 const _text = success ? 'Connected to API' : 'Could not connect to API';493 const _text = success ? t`Connected to API` : t`Could not connect to API`;
447 const _class = success ? 'success' : 'failure';494 const _class = success ? 'success' : 'failure';
448 $('#extensions_status').text(_text);495 $('#extensions_status').text(_text);
449 $('#extensions_status').attr('class', _class);496 $('#extensions_status').attr('class', _class);
450}497}
451498
499/**
500 * Adds a CSS file for an extension.
501 * @param {string} name Extension name
502 * @param {object} manifest Extension manifest
503 * @returns {Promise<void>} When the CSS is loaded
504 */
452function addExtensionStyle(name, manifest) {505function addExtensionStyle(name, manifest) {
453 if (manifest.css) {506 if (!manifest.css) {
454 return new Promise((resolve, reject) => {507 return Promise.resolve();
455 const url = `/scripts/extensions/${name}/${manifest.css}`;
456
457 if ($(`link[id="${name}"]`).length === 0) {
458 const link = document.createElement('link');
459 link.id = name;
460 link.rel = 'stylesheet';
461 link.type = 'text/css';
462 link.href = url;
463 link.onload = function () {
464 resolve();
465 };
466 link.onerror = function (e) {
467 reject(e);
468 };
469 document.head.appendChild(link);
470 }
471 });
472 }508 }
473509
474 return Promise.resolve();510 return new Promise((resolve, reject) => {
511 const url = `/scripts/extensions/${name}/${manifest.css}`;
512
513 if ($(`link[id="${name}"]`).length === 0) {
514 const link = document.createElement('link');
515 link.id = name;
516 link.rel = 'stylesheet';
517 link.type = 'text/css';
518 link.href = url;
519 link.onload = function () {
520 resolve();
521 };
522 link.onerror = function (e) {
523 reject(e);
524 };
525 document.head.appendChild(link);
526 }
527 });
475}528}
476529
530/**
531 * Loads a JS file for an extension.
532 * @param {string} name Extension name
533 * @param {object} manifest Extension manifest
534 * @returns {Promise<void>} When the script is loaded
535 */
477function addExtensionScript(name, manifest) {536function addExtensionScript(name, manifest) {
478 if (manifest.js) {537 if (!manifest.js) {
479 return new Promise((resolve, reject) => {538 return Promise.resolve();
480 const url = `/scripts/extensions/${name}/${manifest.js}`;
481 let ready = false;
482
483 if ($(`script[id="${name}"]`).length === 0) {
484 const script = document.createElement('script');
485 script.id = name;
486 script.type = 'module';
487 script.src = url;
488 script.async = true;
489 script.onerror = function (err) {
490 reject(err, script);
491 };
492 script.onload = script.onreadystatechange = function () {
493 // console.log(this.readyState); // uncomment this line to see which ready states are called.
494 if (!ready && (!this.readyState || this.readyState == 'complete')) {
495 ready = true;
496 resolve();
497 }
498 };
499 document.body.appendChild(script);
500 }
501 });
502 }539 }
503540
504 return Promise.resolve();541 return new Promise((resolve, reject) => {
542 const url = `/scripts/extensions/${name}/${manifest.js}`;
543 let ready = false;
544
545 if ($(`script[id="${name}"]`).length === 0) {
546 const script = document.createElement('script');
547 script.id = name;
548 script.type = 'module';
549 script.src = url;
550 script.async = true;
551 script.onerror = function (err) {
552 reject(err);
553 };
554 script.onload = function () {
555 if (!ready) {
556 ready = true;
557 resolve();
558 }
559 };
560 document.body.appendChild(script);
561 }
562 });
505}563}
506564
507
508
509/**565/**
510 * Generates HTML string for displaying an extension in the UI.566 * Generates HTML string for displaying an extension in the UI.
511 *567 *
@@ -515,64 +571,85 @@ function addExtensionScript(name, manifest) {
515 * @param {boolean} isDisabled - Whether the extension is disabled or not.571 * @param {boolean} isDisabled - Whether the extension is disabled or not.
516 * @param {boolean} isExternal - Whether the extension is external or not.572 * @param {boolean} isExternal - Whether the extension is external or not.
517 * @param {string} checkboxClass - The class for the checkbox HTML element.573 * @param {string} checkboxClass - The class for the checkbox HTML element.
518 * @return {Promise<string>} - The HTML string that represents the extension.574 * @return {string} - The HTML string that represents the extension.
519 */575 */
520async function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass) {576function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass) {
577 function getExtensionIcon() {
578 const type = getExtensionType(name);
579 switch (type) {
580 case 'global':
581 return '<i class="fa-sm fa-fw fa-solid fa-server" data-i18n="[title]ext_type_global" title="This is a global extension, available for all users."></i>';
582 case 'local':
583 return '<i class="fa-sm fa-fw fa-solid fa-user" data-i18n="[title]ext_type_local" title="This is a local extension, available only for you."></i>';
584 case 'system':
585 return '<i class="fa-sm fa-fw fa-solid fa-cog" data-i18n="[title]ext_type_system" title="This is a built-in extension. It cannot be deleted and updates with the app."></i>';
586 default:
587 return '<i class="fa-sm fa-fw fa-solid fa-question" title="Unknown extension type."></i>';
588 }
589 }
590
591 const isUserAdmin = isAdmin();
592 const extensionIcon = getExtensionIcon();
521 const displayName = manifest.display_name;593 const displayName = manifest.display_name;
522 let displayVersion = manifest.version ? ` v${manifest.version}` : '';594 const displayVersion = manifest.version || '';
523 let isUpToDate = true;595 const externalId = name.replace('third-party', '');
524 let updateButton = '';
525 let originHtml = '';596 let originHtml = '';
526 if (isExternal) {597 if (isExternal) {
527 let data = await getExtensionVersion(name.replace('third-party', ''));598 originHtml = '<a>';
528 let branch = data.currentBranchName;
529 let commitHash = data.currentCommitHash;
530 let origin = data.remoteUrl;
531 isUpToDate = data.isUpToDate;
532 displayVersion = ` (${branch}-${commitHash.substring(0, 7)})`;
533 updateButton = isUpToDate ?
534 `<span class="update-button"><button class="btn_update menu_button" data-name="${name.replace('third-party', '')}" title="Up to date"><i class="fa-solid fa-code-commit fa-fw"></i></button></span>` :
535 `<span class="update-button"><button class="btn_update menu_button" data-name="${name.replace('third-party', '')}" title="Update available"><i class="fa-solid fa-download fa-fw"></i></button></span>`;
536 originHtml = `<a href="${origin}" target="_blank" rel="noopener noreferrer">`;
537 }599 }
538600
539 let toggleElement = isActive || isDisabled ?601 let toggleElement = isActive || isDisabled ?
540 `<input type="checkbox" title="Click to toggle" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :602 `<input type="checkbox" title="Click to toggle" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :
541 `<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;603 `<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;
542604
543 let deleteButton = isExternal ? `<span class="delete-button"><button class="btn_delete menu_button" data-name="${name.replace('third-party', '')}" title="Delete"><i class="fa-solid fa-trash-can"></i></button></span>` : '';605 let deleteButton = isExternal ? `<button class="btn_delete menu_button" data-name="${externalId}" title="Delete"><i class="fa-fw fa-solid fa-trash-can"></i></button>` : '';
544606 let updateButton = isExternal ? `<button class="btn_update menu_button displayNone" data-name="${externalId}" title="Update available"><i class="fa-solid fa-download fa-fw"></i></button>` : '';
545 // if external, wrap the name in a link to the repo607 let moveButton = isExternal && isUserAdmin ? `<button class="btn_move menu_button" data-name="${externalId}" title="Move"><i class="fa-solid fa-folder-tree fa-fw"></i></button>` : '';
546608 let modulesInfo = '';
547 let extensionHtml = `<hr>
548 <h4>
549 ${updateButton}
550 ${deleteButton}
551 ${originHtml}
552 <span class="${isActive ? 'extension_enabled' : isDisabled ? 'extension_disabled' : 'extension_missing'}">
553 ${DOMPurify.sanitize(displayName)}${displayVersion}
554 </span>
555 ${isExternal ? '</a>' : ''}
556
557 <span style="float:right;">${toggleElement}</span>
558 </h4>`;
559609
560 if (isActive && Array.isArray(manifest.optional)) {610 if (isActive && Array.isArray(manifest.optional)) {
561 const optional = new Set(manifest.optional);611 const optional = new Set(manifest.optional);
562 modules.forEach(x => optional.delete(x));612 modules.forEach(x => optional.delete(x));
563 if (optional.size > 0) {613 if (optional.size > 0) {
564 const optionalString = DOMPurify.sanitize([...optional].join(', '));614 const optionalString = DOMPurify.sanitize([...optional].join(', '));
565 extensionHtml += `<p>Optional modules: <span class="optional">${optionalString}</span></p>`;615 modulesInfo = `<div class="extension_modules">Optional modules: <span class="optional">${optionalString}</span></div>`;
566 }616 }
567 } else if (!isDisabled) { // Neither active nor disabled617 } else if (!isDisabled) { // Neither active nor disabled
568 const requirements = new Set(manifest.requires);618 const requirements = new Set(manifest.requires);
569 modules.forEach(x => requirements.delete(x));619 modules.forEach(x => requirements.delete(x));
570 if (requirements.size > 0) {620 if (requirements.size > 0) {
571 const requirementsString = DOMPurify.sanitize([...requirements].join(', '));621 const requirementsString = DOMPurify.sanitize([...requirements].join(', '));
572 extensionHtml += `<p>Missing modules: <span class="failure">${requirementsString}</span></p>`;622 modulesInfo = `<div class="extension_modules">Missing modules: <span class="failure">${requirementsString}</span></div>`;
573 }623 }
574 }624 }
575625
626 // if external, wrap the name in a link to the repo
627
628 let extensionHtml = `
629 <div class="extension_block" data-name="${externalId}">
630 <div class="extension_toggle">
631 ${toggleElement}
632 </div>
633 <div class="extension_icon">
634 ${extensionIcon}
635 </div>
636 <div class="flexGrow extension_text_block">
637 ${originHtml}
638 <span class="${isActive ? 'extension_enabled' : isDisabled ? 'extension_disabled' : 'extension_missing'}">
639 <span class="extension_name">${DOMPurify.sanitize(displayName)}</span>
640 <span class="extension_version">${DOMPurify.sanitize(displayVersion)}</span>
641 ${modulesInfo}
642 </span>
643 ${isExternal ? '</a>' : ''}
644 </div>
645
646 <div class="extension_actions flex-container alignItemsCenter">
647 ${updateButton}
648 ${moveButton}
649 ${deleteButton}
650 </div>
651 </div>`;
652
576 return extensionHtml;653 return extensionHtml;
577}654}
578655
@@ -580,9 +657,9 @@ async function generateExtensionHtml(name, manifest, isActive, isDisabled, isExt
580 * Gets extension data and generates the corresponding HTML for displaying the extension.657 * Gets extension data and generates the corresponding HTML for displaying the extension.
581 *658 *
582 * @param {Array} extension - An array where the first element is the extension name and the second element is the extension manifest.659 * @param {Array} extension - An array where the first element is the extension name and the second element is the extension manifest.
583 * @return {Promise<object>} - An object with 'isExternal' indicating whether the extension is external, and 'extensionHtml' for the extension's HTML string.660 * @return {object} - An object with 'isExternal' indicating whether the extension is external, and 'extensionHtml' for the extension's HTML string.
584 */661 */
585async function getExtensionData(extension) {662function getExtensionData(extension) {
586 const name = extension[0];663 const name = extension[0];
587 const manifest = extension[1];664 const manifest = extension[1];
588 const isActive = activeExtensions.has(name);665 const isActive = activeExtensions.has(name);
@@ -591,7 +668,7 @@ async function getExtensionData(extension) {
591668
592 const checkboxClass = isDisabled ? 'checkbox_disabled' : '';669 const checkboxClass = isDisabled ? 'checkbox_disabled' : '';
593670
594 const extensionHtml = await generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass);671 const extensionHtml = generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass);
595672
596 return { isExternal, extensionHtml };673 return { isExternal, extensionHtml };
597}674}
@@ -614,42 +691,38 @@ function getModuleInformation() {
614 * Generates the HTML strings for all extensions and displays them in a popup.691 * Generates the HTML strings for all extensions and displays them in a popup.
615 */692 */
616async function showExtensionsDetails() {693async function showExtensionsDetails() {
694 const abortController = new AbortController();
617 let popupPromise;695 let popupPromise;
618 try {696 try {
619 const htmlDefault = $('<h3>Built-in Extensions:</h3>');697 // If we are updating an extension, the "old" popup is still active. We should close that.
620 const htmlExternal = $('<h3>Installed Extensions:</h3>').addClass('opacity50p');698 let initialScrollTop = 0;
621 const htmlLoading = $(`<h3 class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5">699 const oldPopup = Popup.util.popups.find(popup => popup.content.querySelector('.extensions_info'));
700 if (oldPopup) {
701 initialScrollTop = oldPopup.content.scrollTop;
702 await oldPopup.completeCancelled();
703 }
704 const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">Built-in Extensions:</h3></div>');
705 const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">Installed Extensions:</h3></div>');
706 const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5">
622 <i class="fa-solid fa-spinner fa-spin"></i>707 <i class="fa-solid fa-spinner fa-spin"></i>
623 <span>Loading third-party extensions... Please wait...</span>708 <span>Loading third-party extensions... Please wait...</span>
624 </h3>`);709 </div>`);
625710
626 /** @type {Promise<any>[]} */711 htmlExternal.append(htmlLoading);
627 const promises = [];
628 const extensions = Object.entries(manifests).sort((a, b) => a[1].loading_order - b[1].loading_order);
629712
630 for (const extension of extensions) {713 const extensions = Object.entries(manifests).sort((a, b) => sortManifests(a[1], b[1])).map(getExtensionData);
631 promises.push(getExtensionData(extension));
632 }
633
634 promises.forEach(promise => {
635 promise.then(value => {
636 const { isExternal, extensionHtml } = value;
637 const container = isExternal ? htmlExternal : htmlDefault;
638 container.append(extensionHtml);
639 });
640 });
641714
642 Promise.allSettled(promises).then(() => {715 extensions.forEach(value => {
643 htmlLoading.remove();716 const { isExternal, extensionHtml } = value;
644 htmlExternal.removeClass('opacity50p');717 const container = isExternal ? htmlExternal : htmlDefault;
718 container.append(extensionHtml);
645 });719 });
646720
647 const html = $('<div></div>')721 const html = $('<div></div>')
648 .addClass('extensions_info')722 .addClass('extensions_info')
649 .append(getModuleInformation())
650 .append(htmlDefault)723 .append(htmlDefault)
651 .append(htmlLoading)724 .append(htmlExternal)
652 .append(htmlExternal);725 .append(getModuleInformation());
653726
654 /** @type {import('./popup.js').CustomPopupButton} */727 /** @type {import('./popup.js').CustomPopupButton} */
655 const updateAllButton = {728 const updateAllButton = {
@@ -662,12 +735,6 @@ async function showExtensionsDetails() {
662 },735 },
663 };736 };
664737
665 // If we are updating an extension, the "old" popup is still active. We should close that.
666 const oldPopup = Popup.util.popups.find(popup => popup.content.querySelector('.extensions_info'));
667 if (oldPopup) {
668 await oldPopup.complete(POPUP_RESULT.CANCELLED);
669 }
670
671 let waitingForSave = false;738 let waitingForSave = false;
672739
673 const popup = new Popup(html, POPUP_TYPE.TEXT, '', {740 const popup = new Popup(html, POPUP_TYPE.TEXT, '', {
@@ -682,7 +749,7 @@ async function showExtensionsDetails() {
682 }749 }
683 if (stateChanged) {750 if (stateChanged) {
684 waitingForSave = true;751 waitingForSave = true;
685 const toast = toastr.info('The page will be reloaded shortly...', 'Extensions state changed');752 const toast = toastr.info(t`The page will be reloaded shortly...`, t`Extensions state changed`);
686 await saveSettings();753 await saveSettings();
687 toastr.clear(toast);754 toastr.clear(toast);
688 waitingForSave = false;755 waitingForSave = false;
@@ -692,12 +759,15 @@ async function showExtensionsDetails() {
692 },759 },
693 });760 });
694 popupPromise = popup.show();761 popupPromise = popup.show();
762 popup.content.scrollTop = initialScrollTop;
763 checkForUpdatesManual(abortController.signal).finally(() => htmlLoading.remove());
695 } catch (error) {764 } catch (error) {
696 toastr.error('Error loading extensions. See browser console for details.');765 toastr.error(t`Error loading extensions. See browser console for details.`);
697 console.error(error);766 console.error(error);
698 }767 }
699 if (popupPromise) {768 if (popupPromise) {
700 await popupPromise;769 await popupPromise;
770 abortController.abort();
701 }771 }
702 if (requiresReload) {772 if (requiresReload) {
703 showLoader();773 showLoader();
@@ -705,17 +775,26 @@ async function showExtensionsDetails() {
705 }775 }
706}776}
707777
708
709/**778/**
710 * Handles the click event for the update button of an extension.779 * Handles the click event for the update button of an extension.
711 * This function makes a POST request to '/update_extension' with the extension's name.780 * This function makes a POST request to '/api/extensions/update' with the extension's name.
712 * If the extension is already up to date, it displays a success message.781 * If the extension is already up to date, it displays a success message.
713 * If the extension is not up to date, it updates the extension and displays a success message with the new commit hash.782 * If the extension is not up to date, it updates the extension and displays a success message with the new commit hash.
714 */783 */
715async function onUpdateClick() {784async function onUpdateClick() {
785 const isCurrentUserAdmin = isAdmin();
716 const extensionName = $(this).data('name');786 const extensionName = $(this).data('name');
717 $(this).find('i').addClass('fa-spin');787 const isGlobal = getExtensionType(extensionName) === 'global';
788 if (isGlobal && !isCurrentUserAdmin) {
789 toastr.error(t`You don't have permission to update global extensions.`);
790 return;
791 }
792
793 const icon = $(this).find('i');
794 icon.addClass('fa-spin');
718 await updateExtension(extensionName, false);795 await updateExtension(extensionName, false);
796 // updateExtension eats the error, but we can at least stop the spinner
797 icon.removeClass('fa-spin');
719}798}
720799
721/**800/**
@@ -728,13 +807,23 @@ async function updateExtension(extensionName, quiet) {
728 const response = await fetch('/api/extensions/update', {807 const response = await fetch('/api/extensions/update', {
729 method: 'POST',808 method: 'POST',
730 headers: getRequestHeaders(),809 headers: getRequestHeaders(),
731 body: JSON.stringify({ extensionName }),810 body: JSON.stringify({
811 extensionName,
812 global: getExtensionType(extensionName) === 'global',
813 }),
732 });814 });
733815
816 if (!response.ok) {
817 const text = await response.text();
818 toastr.error(text || response.statusText, t`Extension update failed`, { timeOut: 5000 });
819 console.error('Extension update failed', response.status, response.statusText, text);
820 return;
821 }
822
734 const data = await response.json();823 const data = await response.json();
735824
736 if (!quiet) {825 if (!quiet) {
737 showExtensionsDetails();826 void showExtensionsDetails();
738 }827 }
739828
740 if (data.isUpToDate) {829 if (data.isUpToDate) {
@@ -757,44 +846,122 @@ async function updateExtension(extensionName, quiet) {
757 */846 */
758async function onDeleteClick() {847async function onDeleteClick() {
759 const extensionName = $(this).data('name');848 const extensionName = $(this).data('name');
849 const isCurrentUserAdmin = isAdmin();
850 const isGlobal = getExtensionType(extensionName) === 'global';
851 if (isGlobal && !isCurrentUserAdmin) {
852 toastr.error(t`You don't have permission to delete global extensions.`);
853 return;
854 }
855
760 // use callPopup to create a popup for the user to confirm before delete856 // use callPopup to create a popup for the user to confirm before delete
761 const confirmation = await callGenericPopup(`Are you sure you want to delete ${extensionName}?`, POPUP_TYPE.CONFIRM, '', {});857 const confirmation = await callGenericPopup(t`Are you sure you want to delete ${extensionName}?`, POPUP_TYPE.CONFIRM, '', {});
762 if (confirmation === POPUP_RESULT.AFFIRMATIVE) {858 if (confirmation === POPUP_RESULT.AFFIRMATIVE) {
763 await deleteExtension(extensionName);859 await deleteExtension(extensionName);
764 }860 }
765}861}
766862
863async function onMoveClick() {
864 const extensionName = $(this).data('name');
865 const isCurrentUserAdmin = isAdmin();
866 const isGlobal = getExtensionType(extensionName) === 'global';
867 if (isGlobal && !isCurrentUserAdmin) {
868 toastr.error(t`You don't have permission to move extensions.`);
869 return;
870 }
871
872 const source = getExtensionType(extensionName);
873 const destination = source === 'global' ? 'local' : 'global';
874
875 const confirmationHeader = t`Move extension`;
876 const confirmationText = source == 'global'
877 ? t`Are you sure you want to move ${extensionName} to your local extensions? This will make it available only for you.`
878 : t`Are you sure you want to move ${extensionName} to the global extensions? This will make it available for all users.`;
879
880 const confirmation = await Popup.show.confirm(confirmationHeader, confirmationText);
881
882 if (!confirmation) {
883 return;
884 }
885
886 $(this).find('i').addClass('fa-spin');
887 await moveExtension(extensionName, source, destination);
888}
889
890/**
891 * Moves an extension via the API.
892 * @param {string} extensionName Extension name
893 * @param {string} source Source type
894 * @param {string} destination Destination type
895 * @returns {Promise<void>}
896 */
897async function moveExtension(extensionName, source, destination) {
898 try {
899 const result = await fetch('/api/extensions/move', {
900 method: 'POST',
901 headers: getRequestHeaders(),
902 body: JSON.stringify({
903 extensionName,
904 source,
905 destination,
906 }),
907 });
908
909 if (!result.ok) {
910 const text = await result.text();
911 toastr.error(text || result.statusText, t`Extension move failed`, { timeOut: 5000 });
912 console.error('Extension move failed', result.status, result.statusText, text);
913 return;
914 }
915
916 toastr.success(t`Extension ${extensionName} moved.`);
917 await loadExtensionSettings({}, false, false);
918 void showExtensionsDetails();
919 } catch (error) {
920 console.error('Error:', error);
921 }
922}
923
924/**
925 * Deletes an extension via the API.
926 * @param {string} extensionName Extension name to delete
927 */
767export async function deleteExtension(extensionName) {928export async function deleteExtension(extensionName) {
768 try {929 try {
769 await fetch('/api/extensions/delete', {930 await fetch('/api/extensions/delete', {
770 method: 'POST',931 method: 'POST',
771 headers: getRequestHeaders(),932 headers: getRequestHeaders(),
772 body: JSON.stringify({ extensionName }),933 body: JSON.stringify({
934 extensionName,
935 global: getExtensionType(extensionName) === 'global',
936 }),
773 });937 });
774 } catch (error) {938 } catch (error) {
775 console.error('Error:', error);939 console.error('Error:', error);
776 }940 }
777941
778 toastr.success(`Extension ${extensionName} deleted`);942 toastr.success(t`Extension ${extensionName} deleted`);
779 showExtensionsDetails();943 delay(1000).then(() => location.reload());
780 // reload the page to remove the extension from the list
781 location.reload();
782}944}
783945
784/**946/**
785 * Fetches the version details of a specific extension.947 * Fetches the version details of a specific extension.
786 *948 *
787 * @param {string} extensionName - The name of the extension.949 * @param {string} extensionName - The name of the extension.
950 * @param {AbortSignal} [abortSignal] - The signal to abort the operation.
788 * @return {Promise<object>} - An object containing the extension's version details.951 * @return {Promise<object>} - An object containing the extension's version details.
789 * This object includes the currentBranchName, currentCommitHash, isUpToDate, and remoteUrl.952 * This object includes the currentBranchName, currentCommitHash, isUpToDate, and remoteUrl.
790 * @throws {error} - If there is an error during the fetch operation, it logs the error to the console.953 * @throws {error} - If there is an error during the fetch operation, it logs the error to the console.
791 */954 */
792async function getExtensionVersion(extensionName) {955async function getExtensionVersion(extensionName, abortSignal) {
793 try {956 try {
794 const response = await fetch('/api/extensions/version', {957 const response = await fetch('/api/extensions/version', {
795 method: 'POST',958 method: 'POST',
796 headers: getRequestHeaders(),959 headers: getRequestHeaders(),
797 body: JSON.stringify({ extensionName }),960 body: JSON.stringify({
961 extensionName,
962 global: getExtensionType(extensionName) === 'global',
963 }),
964 signal: abortSignal,
798 });965 });
799966
800 const data = await response.json();967 const data = await response.json();
@@ -807,22 +974,26 @@ async function getExtensionVersion(extensionName) {
807/**974/**
808 * Installs a third-party extension via the API.975 * Installs a third-party extension via the API.
809 * @param {string} url Extension repository URL976 * @param {string} url Extension repository URL
977 * @param {boolean} global Is the extension global?
810 * @returns {Promise<void>}978 * @returns {Promise<void>}
811 */979 */
812export async function installExtension(url) {980export async function installExtension(url, global) {
813 console.debug('Extension installation started', url);981 console.debug('Extension installation started', url);
814982
815 toastr.info('Please wait...', 'Installing extension');983 toastr.info(t`Please wait...`, t`Installing extension`);
816984
817 const request = await fetch('/api/extensions/install', {985 const request = await fetch('/api/extensions/install', {
818 method: 'POST',986 method: 'POST',
819 headers: getRequestHeaders(),987 headers: getRequestHeaders(),
820 body: JSON.stringify({ url }),988 body: JSON.stringify({
989 url,
990 global,
991 }),
821 });992 });
822993
823 if (!request.ok) {994 if (!request.ok) {
824 const text = await request.text();995 const text = await request.text();
825 toastr.warning(text || request.statusText, 'Extension installation failed', { timeOut: 5000 });996 toastr.warning(text || request.statusText, t`Extension installation failed`, { timeOut: 5000 });
826 console.error('Extension installation failed', request.status, request.statusText, text);997 console.error('Extension installation failed', request.status, request.statusText, text);
827 return;998 return;
828 }999 }
@@ -840,7 +1011,7 @@ export async function installExtension(url) {
840 * @param {boolean} versionChanged Is this a version change?1011 * @param {boolean} versionChanged Is this a version change?
841 * @param {boolean} enableAutoUpdate Enable auto-update1012 * @param {boolean} enableAutoUpdate Enable auto-update
842 */1013 */
843async function loadExtensionSettings(settings, versionChanged, enableAutoUpdate) {1014export async function loadExtensionSettings(settings, versionChanged, enableAutoUpdate) {
844 if (settings.extension_settings) {1015 if (settings.extension_settings) {
845 Object.assign(extension_settings, settings.extension_settings);1016 Object.assign(extension_settings, settings.extension_settings);
846 }1017 }
@@ -852,7 +1023,9 @@ async function loadExtensionSettings(settings, versionChanged, enableAutoUpdate)
8521023
853 // Activate offline extensions1024 // Activate offline extensions
854 await eventSource.emit(event_types.EXTENSIONS_FIRST_LOAD);1025 await eventSource.emit(event_types.EXTENSIONS_FIRST_LOAD);
855 extensionNames = await discoverExtensions();1026 const extensions = await discoverExtensions();
1027 extensionNames = extensions.map(x => x.name);
1028 extensionTypes = Object.fromEntries(extensions.map(x => [x.name, x.type]));
856 manifests = await getManifests(extensionNames);1029 manifests = await getManifests(extensionNames);
8571030
858 if (versionChanged && enableAutoUpdate) {1031 if (versionChanged && enableAutoUpdate) {
@@ -873,6 +1046,86 @@ export function doDailyExtensionUpdatesCheck() {
873 }, 1);1046 }, 1);
874}1047}
8751048
1049const concurrencyLimit = 5;
1050let activeRequestsCount = 0;
1051const versionCheckQueue = [];
1052
1053function enqueueVersionCheck(fn) {
1054 return new Promise((resolve, reject) => {
1055 versionCheckQueue.push(() => fn().then(resolve).catch(reject));
1056 processVersionCheckQueue();
1057 });
1058}
1059
1060function processVersionCheckQueue() {
1061 if (activeRequestsCount >= concurrencyLimit || versionCheckQueue.length === 0) {
1062 return;
1063 }
1064 activeRequestsCount++;
1065 const fn = versionCheckQueue.shift();
1066 fn().finally(() => {
1067 activeRequestsCount--;
1068 processVersionCheckQueue();
1069 });
1070}
1071
1072/**
1073 * Performs a manual check for updates on all 3rd-party extensions.
1074 * @param {AbortSignal} abortSignal Signal to abort the operation
1075 * @returns {Promise<any[]>}
1076 */
1077async function checkForUpdatesManual(abortSignal) {
1078 const promises = [];
1079 for (const id of Object.keys(manifests).filter(x => x.startsWith('third-party')).sort((a, b) => sortManifests(manifests[a], manifests[b]))) {
1080 const externalId = id.replace('third-party', '');
1081 const promise = enqueueVersionCheck(async () => {
1082 try {
1083 const data = await getExtensionVersion(externalId, abortSignal);
1084 const extensionBlock = document.querySelector(`.extension_block[data-name="${externalId}"]`);
1085 if (extensionBlock && data) {
1086 if (data.isUpToDate === false) {
1087 const buttonElement = extensionBlock.querySelector('.btn_update');
1088 if (buttonElement) {
1089 buttonElement.classList.remove('displayNone');
1090 }
1091 const nameElement = extensionBlock.querySelector('.extension_name');
1092 if (nameElement) {
1093 nameElement.classList.add('update_available');
1094 }
1095 }
1096 let branch = data.currentBranchName;
1097 let commitHash = data.currentCommitHash;
1098 let origin = data.remoteUrl;
1099
1100 const originLink = extensionBlock.querySelector('a');
1101 if (originLink) {
1102 try {
1103 const url = new URL(origin);
1104 if (!['https:', 'http:'].includes(url.protocol)) {
1105 throw new Error('Invalid protocol');
1106 }
1107 originLink.href = url.href;
1108 originLink.target = '_blank';
1109 originLink.rel = 'noopener noreferrer';
1110 } catch (error) {
1111 console.log('Error setting origin link', originLink, error);
1112 }
1113 }
1114
1115 const versionElement = extensionBlock.querySelector('.extension_version');
1116 if (versionElement) {
1117 versionElement.textContent += ` (${branch}-${commitHash.substring(0, 7)})`;
1118 }
1119 }
1120 } catch (error) {
1121 console.error('Error checking for extension updates', error);
1122 }
1123 });
1124 promises.push(promise);
1125 }
1126 return Promise.allSettled(promises);
1127}
1128
876/**1129/**
877 * Checks if there are updates available for 3rd-party extensions.1130 * Checks if there are updates available for 3rd-party extensions.
878 * @param {boolean} force Skip nag check1131 * @param {boolean} force Skip nag check
@@ -891,21 +1144,26 @@ async function checkForExtensionUpdates(force) {
891 localStorage.setItem(STORAGE_NAG_KEY, currentDate);1144 localStorage.setItem(STORAGE_NAG_KEY, currentDate);
892 }1145 }
8931146
1147 const isCurrentUserAdmin = isAdmin();
894 const updatesAvailable = [];1148 const updatesAvailable = [];
895 const promises = [];1149 const promises = [];
8961150
897 for (const [id, manifest] of Object.entries(manifests)) {1151 for (const [id, manifest] of Object.entries(manifests)) {
1152 const isGlobal = getExtensionType(id) === 'global';
1153 if (isGlobal && !isCurrentUserAdmin) {
1154 console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`);
1155 continue;
1156 }
1157
898 if (manifest.auto_update && id.startsWith('third-party')) {1158 if (manifest.auto_update && id.startsWith('third-party')) {
899 const promise = new Promise(async (resolve, reject) => {1159 const promise = enqueueVersionCheck(async () => {
900 try {1160 try {
901 const data = await getExtensionVersion(id.replace('third-party', ''));1161 const data = await getExtensionVersion(id.replace('third-party', ''));
902 if (data.isUpToDate === false) {1162 if (!data.isUpToDate) {
903 updatesAvailable.push(manifest.display_name);1163 updatesAvailable.push(manifest.display_name);
904 }1164 }
905 resolve();
906 } catch (error) {1165 } catch (error) {
907 console.error('Error checking for extension updates', error);1166 console.error('Error checking for extension updates', error);
908 reject();
909 }1167 }
910 });1168 });
911 promises.push(promise);1169 promises.push(promise);
@@ -930,8 +1188,14 @@ async function autoUpdateExtensions(forceAll) {
930 }1188 }
9311189
932 const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 });1190 const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 });
1191 const isCurrentUserAdmin = isAdmin();
933 const promises = [];1192 const promises = [];
934 for (const [id, manifest] of Object.entries(manifests)) {1193 for (const [id, manifest] of Object.entries(manifests)) {
1194 const isGlobal = getExtensionType(id) === 'global';
1195 if (isGlobal && !isCurrentUserAdmin) {
1196 console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`);
1197 continue;
1198 }
935 if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) {1199 if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) {
936 console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`);1200 console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`);
937 promises.push(updateExtension(id.replace('third-party', ''), true));1201 promises.push(updateExtension(id.replace('third-party', ''), true));
@@ -947,7 +1211,7 @@ async function autoUpdateExtensions(forceAll) {
947 * @param {number} contextSize Context size1211 * @param {number} contextSize Context size
948 * @returns {Promise<boolean>} True if generation should be aborted1212 * @returns {Promise<boolean>} True if generation should be aborted
949 */1213 */
950async function runGenerationInterceptors(chat, contextSize) {1214export async function runGenerationInterceptors(chat, contextSize) {
951 let aborted = false;1215 let aborted = false;
952 let exitImmediately = false;1216 let exitImmediately = false;
9531217
@@ -956,11 +1220,11 @@ async function runGenerationInterceptors(chat, contextSize) {
956 exitImmediately = immediately;1220 exitImmediately = immediately;
957 };1221 };
9581222
959 for (const manifest of Object.values(manifests).sort((a, b) => a.loading_order - b.loading_order)) {1223 for (const manifest of Object.values(manifests).filter(x => x.generate_interceptor).sort((a, b) => sortManifests(a, b))) {
960 const interceptorKey = manifest.generate_interceptor;1224 const interceptorKey = manifest.generate_interceptor;
961 if (typeof window[interceptorKey] === 'function') {1225 if (typeof globalThis[interceptorKey] === 'function') {
962 try {1226 try {
963 await window[interceptorKey](chat, contextSize, abort);1227 await globalThis[interceptorKey](chat, contextSize, abort);
964 } catch (e) {1228 } catch (e) {
965 console.error(`Failed running interceptor for ${manifest.display_name}`, e);1229 console.error(`Failed running interceptor for ${manifest.display_name}`, e);
966 }1230 }
@@ -1033,8 +1297,23 @@ export async function writeExtensionField(characterId, key, value) {
1033 * @returns {Promise<void>}1297 * @returns {Promise<void>}
1034 */1298 */
1035export async function openThirdPartyExtensionMenu(suggestUrl = '') {1299export async function openThirdPartyExtensionMenu(suggestUrl = '') {
1036 const html = await renderTemplateAsync('installExtension');1300 const isCurrentUserAdmin = isAdmin();
1037 const input = await callGenericPopup(html, POPUP_TYPE.INPUT, suggestUrl ?? '');1301 const html = await renderTemplateAsync('installExtension', { isCurrentUserAdmin });
1302 const okButton = isCurrentUserAdmin ? t`Install just for me` : t`Install`;
1303
1304 let global = false;
1305 const installForAllButton = {
1306 text: t`Install for all users`,
1307 appendAtEnd: false,
1308 action: async () => {
1309 global = true;
1310 await popup.complete(POPUP_RESULT.AFFIRMATIVE);
1311 },
1312 };
1313
1314 const customButtons = isCurrentUserAdmin ? [installForAllButton] : [];
1315 const popup = new Popup(html, POPUP_TYPE.INPUT, suggestUrl ?? '', { okButton, customButtons });
1316 const input = await popup.show();
10381317
1039 if (!input) {1318 if (!input) {
1040 console.debug('Extension install cancelled');1319 console.debug('Extension install cancelled');
@@ -1042,11 +1321,9 @@ export async function openThirdPartyExtensionMenu(suggestUrl = '') {
1042 }1321 }
10431322
1044 const url = String(input).trim();1323 const url = String(input).trim();
1045 await installExtension(url);1324 await installExtension(url, global);
1046}1325}
10471326
1048
1049
1050export async function initExtensions() {1327export async function initExtensions() {
1051 await addExtensionsButtonAndMenu();1328 await addExtensionsButtonAndMenu();
1052 $('#extensionsMenuButton').css('display', 'flex');1329 $('#extensionsMenuButton').css('display', 'flex');
@@ -1055,10 +1332,11 @@ export async function initExtensions() {
1055 $('#extensions_autoconnect').on('input', autoConnectInputHandler);1332 $('#extensions_autoconnect').on('input', autoConnectInputHandler);
1056 $('#extensions_details').on('click', showExtensionsDetails);1333 $('#extensions_details').on('click', showExtensionsDetails);
1057 $('#extensions_notify_updates').on('input', notifyUpdatesInputHandler);1334 $('#extensions_notify_updates').on('input', notifyUpdatesInputHandler);
1058 $(document).on('click', '.toggle_disable', onDisableExtensionClick);1335 $(document).on('click', '.extensions_info .extension_block .toggle_disable', onDisableExtensionClick);
1059 $(document).on('click', '.toggle_enable', onEnableExtensionClick);1336 $(document).on('click', '.extensions_info .extension_block .toggle_enable', onEnableExtensionClick);
1060 $(document).on('click', '.btn_update', onUpdateClick);1337 $(document).on('click', '.extensions_info .extension_block .btn_update', onUpdateClick);
1061 $(document).on('click', '.btn_delete', onDeleteClick);1338 $(document).on('click', '.extensions_info .extension_block .btn_delete', onDeleteClick);
1339 $(document).on('click', '.extensions_info .extension_block .btn_move', onMoveClick);
10621340
1063 /**1341 /**
1064 * Handles the click event for the third-party extension import button.1342 * Handles the click event for the third-party extension import button.
public/scripts/extensions/caption/index.js+1 -1
@@ -393,7 +393,7 @@ jQuery(async function () {
393 const sendButton = $(`393 const sendButton = $(`
394 <div id="send_picture" class="list-group-item flex-container flexGap5">394 <div id="send_picture" class="list-group-item flex-container flexGap5">
395 <div class="fa-solid fa-image extensionsMenuExtensionButton"></div>395 <div class="fa-solid fa-image extensionsMenuExtensionButton"></div>
396 Generate Caption396 <span data-i18n="Generate Caption">Generate Caption</span>
397 </div>`);397 </div>`);
398398
399 $('#caption_wand_container').append(sendButton);399 $('#caption_wand_container').append(sendButton);
public/scripts/extensions/caption/settings.html+2 -1
@@ -53,6 +53,8 @@
53 <option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option>53 <option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option>
54 <option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option>54 <option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option>
55 <option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>55 <option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option>
56 <option data-type="google" value="gemini-2.0-flash-exp">gemini-2.0-flash-exp</option>
57 <option data-type="google" value="gemini-2.0-flash-thinking-exp-1219">gemini-2.0-flash-thinking-exp-1219</option>
56 <option data-type="google" value="gemini-1.5-flash">gemini-1.5-flash</option>58 <option data-type="google" value="gemini-1.5-flash">gemini-1.5-flash</option>
57 <option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>59 <option data-type="google" value="gemini-1.5-flash-latest">gemini-1.5-flash-latest</option>
58 <option data-type="google" value="gemini-1.5-flash-001">gemini-1.5-flash-001</option>60 <option data-type="google" value="gemini-1.5-flash-001">gemini-1.5-flash-001</option>
@@ -69,7 +71,6 @@
69 <option data-type="google" value="gemini-1.5-pro-002">gemini-1.5-pro-002</option>71 <option data-type="google" value="gemini-1.5-pro-002">gemini-1.5-pro-002</option>
70 <option data-type="google" value="gemini-1.5-pro-exp-0801">gemini-1.5-pro-exp-0801</option>72 <option data-type="google" value="gemini-1.5-pro-exp-0801">gemini-1.5-pro-exp-0801</option>
71 <option data-type="google" value="gemini-1.5-pro-exp-0827">gemini-1.5-pro-exp-0827</option>73 <option data-type="google" value="gemini-1.5-pro-exp-0827">gemini-1.5-pro-exp-0827</option>
72 <option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
73 <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option>74 <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option>
74 <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option>75 <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option>
75 <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option>76 <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option>
public/scripts/extensions/expressions/index.js+164 -19
@@ -14,7 +14,7 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '
14import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';14import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
15import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';15import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
16import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';16import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
17import { SlashCommandClosure } from '../../slash-commands/SlashCommandClosure.js';17import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';
18export { MODULE_NAME };18export { MODULE_NAME };
1919
20const MODULE_NAME = 'expressions';20const MODULE_NAME = 'expressions';
@@ -59,6 +59,7 @@ const EXPRESSION_API = {
59 local: 0,59 local: 0,
60 extras: 1,60 extras: 1,
61 llm: 2,61 llm: 2,
62 webllm: 3,
62};63};
6364
64let expressionsList = null;65let expressionsList = null;
@@ -697,6 +698,11 @@ async function moduleWorker() {
697 return;698 return;
698 }699 }
699700
701 // If using LLM api then check if streamingProcessor is finished to avoid sending multiple requests to the API
702 if (extension_settings.expressions.api === EXPRESSION_API.llm && context.streamingProcessor && !context.streamingProcessor.isFinished) {
703 return;
704 }
705
700 // API is busy706 // API is busy
701 if (inApiCall) {707 if (inApiCall) {
702 console.debug('Classification API is busy');708 console.debug('Classification API is busy');
@@ -847,7 +853,7 @@ function setTalkingHeadState(newState) {
847 extension_settings.expressions.talkinghead = newState; // Store setting853 extension_settings.expressions.talkinghead = newState; // Store setting
848 saveSettingsDebounced();854 saveSettingsDebounced();
849855
850 if (extension_settings.expressions.api == EXPRESSION_API.local || extension_settings.expressions.api == EXPRESSION_API.llm) {856 if ([EXPRESSION_API.local, EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api)) {
851 return;857 return;
852 }858 }
853859
@@ -980,6 +986,71 @@ async function setSpriteSlashCommand(_, spriteId) {
980}986}
981987
982/**988/**
989 * Returns the sprite folder name (including override) for a character.
990 * @param {object} char Character object
991 * @param {string} char.avatar Avatar filename with extension
992 * @returns {string} Sprite folder name
993 * @throws {Error} If character not found or avatar not set
994 */
995function spriteFolderNameFromCharacter(char) {
996 const avatarFileName = char.avatar.replace(/\.[^/.]+$/, '');
997 const expressionOverride = extension_settings.expressionOverrides.find(e => e.name === avatarFileName);
998 return expressionOverride?.path ? expressionOverride.path : avatarFileName;
999}
1000
1001/**
1002 * Slash command callback for /uploadsprite
1003 *
1004 * label= is required
1005 * if name= is provided, it will be used as a findChar lookup
1006 * if name= is not provided, the last character's name will be used
1007 * if folder= is a full path, it will be used as the folder
1008 * if folder= is a partial path, it will be appended to the character's name
1009 * if folder= is not provided, the character's override folder will be used, if set
1010 *
1011 * @param {object} args
1012 * @param {string} args.name Character name or avatar key, passed through findChar
1013 * @param {string} args.label Expression label
1014 * @param {string} args.folder Sprite folder path, processed using backslash rules
1015 * @param {string} imageUrl Image URI to fetch and upload
1016 * @returns {Promise<void>}
1017 */
1018async function uploadSpriteCommand({ name, label, folder }, imageUrl) {
1019 if (!imageUrl) throw new Error('Image URL is required');
1020 if (!label || typeof label !== 'string') throw new Error('Expression label is required');
1021
1022 label = label.replace(/[^a-z]/gi, '').toLowerCase().trim();
1023 if (!label) throw new Error('Expression label must contain at least one letter');
1024
1025 name = name || getLastCharacterMessage().original_avatar || getLastCharacterMessage().name;
1026 const char = findChar({ name });
1027
1028 if (!folder) {
1029 folder = spriteFolderNameFromCharacter(char);
1030 } else if (folder.startsWith('/') || folder.startsWith('\\')) {
1031 const subfolder = folder.slice(1);
1032 folder = `${char.name}/${subfolder}`;
1033 }
1034
1035 try {
1036 const response = await fetch(imageUrl);
1037 const blob = await response.blob();
1038 const file = new File([blob], 'image.png', { type: 'image/png' });
1039
1040 const formData = new FormData();
1041 formData.append('name', folder); // this is the folder or character name
1042 formData.append('label', label); // this is the expression label
1043 formData.append('avatar', file); // this is the image file
1044
1045 await handleFileUpload('/api/sprites/upload', formData);
1046 console.debug(`[${MODULE_NAME}] Upload of ${imageUrl} completed for ${name} with label ${label}`);
1047 } catch (error) {
1048 console.error(`[${MODULE_NAME}] Error uploading file:`, error);
1049 throw error;
1050 }
1051}
1052
1053/**
983 * Processes the classification text to reduce the amount of text sent to the API.1054 * Processes the classification text to reduce the amount of text sent to the API.
984 * Quotes and asterisks are to be removed. If the text is less than 300 characters, it is returned as is.1055 * Quotes and asterisks are to be removed. If the text is less than 300 characters, it is returned as is.
985 * If the text is more than 300 characters, the first and last 150 characters are returned.1056 * If the text is more than 300 characters, the first and last 150 characters are returned.
@@ -995,6 +1066,11 @@ function sampleClassifyText(text) {
995 // Replace macros, remove asterisks and quotes1066 // Replace macros, remove asterisks and quotes
996 let result = substituteParams(text).replace(/[*"]/g, '');1067 let result = substituteParams(text).replace(/[*"]/g, '');
9971068
1069 // If using LLM api there is no need to check length of characters
1070 if (extension_settings.expressions.api === EXPRESSION_API.llm) {
1071 return result.trim();
1072 }
1073
998 const SAMPLE_THRESHOLD = 500;1074 const SAMPLE_THRESHOLD = 500;
999 const HALF_SAMPLE_THRESHOLD = SAMPLE_THRESHOLD / 2;1075 const HALF_SAMPLE_THRESHOLD = SAMPLE_THRESHOLD / 2;
10001076
@@ -1047,11 +1123,39 @@ function parseLlmResponse(emotionResponse, labels) {
1047 console.debug(`fuzzy search found: ${result[0].item} as closest for the LLM response:`, emotionResponse);1123 console.debug(`fuzzy search found: ${result[0].item} as closest for the LLM response:`, emotionResponse);
1048 return result[0].item;1124 return result[0].item;
1049 }1125 }
1126 const lowerCaseResponse = String(emotionResponse || '').toLowerCase();
1127 for (const label of labels) {
1128 if (lowerCaseResponse.includes(label.toLowerCase())) {
1129 console.debug(`Found label ${label} in the LLM response:`, emotionResponse);
1130 return label;
1131 }
1132 }
1050 }1133 }
10511134
1052 throw new Error('Could not parse emotion response ' + emotionResponse);1135 throw new Error('Could not parse emotion response ' + emotionResponse);
1053}1136}
10541137
1138/**
1139 * Gets the JSON schema for the LLM API.
1140 * @param {string[]} emotions A list of emotions to search for.
1141 * @returns {object} The JSON schema for the LLM API.
1142 */
1143function getJsonSchema(emotions) {
1144 return {
1145 $schema: 'http://json-schema.org/draft-04/schema#',
1146 type: 'object',
1147 properties: {
1148 emotion: {
1149 type: 'string',
1150 enum: emotions,
1151 },
1152 },
1153 required: [
1154 'emotion',
1155 ],
1156 };
1157}
1158
1055function onTextGenSettingsReady(args) {1159function onTextGenSettingsReady(args) {
1056 // Only call if inside an API call1160 // Only call if inside an API call
1057 if (inApiCall && extension_settings.expressions.api === EXPRESSION_API.llm && isJsonSchemaSupported()) {1161 if (inApiCall && extension_settings.expressions.api === EXPRESSION_API.llm && isJsonSchemaSupported()) {
@@ -1061,19 +1165,7 @@ function onTextGenSettingsReady(args) {
1061 stop: [],1165 stop: [],
1062 stopping_strings: [],1166 stopping_strings: [],
1063 custom_token_bans: [],1167 custom_token_bans: [],
1064 json_schema: {1168 json_schema: getJsonSchema(emotions),
1065 $schema: 'http://json-schema.org/draft-04/schema#',
1066 type: 'object',
1067 properties: {
1068 emotion: {
1069 type: 'string',
1070 enum: emotions,
1071 },
1072 },
1073 required: [
1074 'emotion',
1075 ],
1076 },
1077 });1169 });
1078 }1170 }
1079}1171}
@@ -1129,6 +1221,22 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin
1129 const emotionResponse = await generateRaw(text, main_api, false, false, prompt);1221 const emotionResponse = await generateRaw(text, main_api, false, false, prompt);
1130 return parseLlmResponse(emotionResponse, expressionsList);1222 return parseLlmResponse(emotionResponse, expressionsList);
1131 }1223 }
1224 // Using WebLLM
1225 case EXPRESSION_API.webllm: {
1226 if (!isWebLlmSupported()) {
1227 console.warn('WebLLM is not supported. Using fallback expression');
1228 return getFallbackExpression();
1229 }
1230
1231 const expressionsList = await getExpressionsList();
1232 const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList);
1233 const messages = [
1234 { role: 'user', content: text + '\n\n' + prompt },
1235 ];
1236
1237 const emotionResponse = await generateWebLlmChatPrompt(messages);
1238 return parseLlmResponse(emotionResponse, expressionsList);
1239 }
1132 // Extras1240 // Extras
1133 default: {1241 default: {
1134 const url = new URL(getApiUrl());1242 const url = new URL(getApiUrl());
@@ -1239,8 +1347,6 @@ async function drawSpritesList(character, labels, sprites) {
1239 * @returns {Promise<string>} Rendered list item template1347 * @returns {Promise<string>} Rendered list item template
1240 */1348 */
1241async function getListItem(item, imageSrc, textClass, isCustom) {1349async function getListItem(item, imageSrc, textClass, isCustom) {
1242 const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
1243 imageSrc = isFirefox ? `${imageSrc}?t=${Date.now()}` : imageSrc;
1244 return renderExtensionTemplateAsync(MODULE_NAME, 'list-item', { item, imageSrc, textClass, isCustom });1350 return renderExtensionTemplateAsync(MODULE_NAME, 'list-item', { item, imageSrc, textClass, isCustom });
1245}1351}
12461352
@@ -1593,7 +1699,7 @@ function onExpressionApiChanged() {
1593 const tempApi = this.value;1699 const tempApi = this.value;
1594 if (tempApi) {1700 if (tempApi) {
1595 extension_settings.expressions.api = Number(tempApi);1701 extension_settings.expressions.api = Number(tempApi);
1596 $('.expression_llm_prompt_block').toggle(extension_settings.expressions.api === EXPRESSION_API.llm);1702 $('.expression_llm_prompt_block').toggle([EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api));
1597 expressionsList = null;1703 expressionsList = null;
1598 spriteCache = {};1704 spriteCache = {};
1599 moduleWorker();1705 moduleWorker();
@@ -1930,7 +2036,7 @@ function migrateSettings() {
19302036
1931 await renderAdditionalExpressionSettings();2037 await renderAdditionalExpressionSettings();
1932 $('#expression_api').val(extension_settings.expressions.api ?? EXPRESSION_API.extras);2038 $('#expression_api').val(extension_settings.expressions.api ?? EXPRESSION_API.extras);
1933 $('.expression_llm_prompt_block').toggle(extension_settings.expressions.api === EXPRESSION_API.llm);2039 $('.expression_llm_prompt_block').toggle([EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api));
1934 $('#expression_llm_prompt').val(extension_settings.expressions.llmPrompt ?? '');2040 $('#expression_llm_prompt').val(extension_settings.expressions.llmPrompt ?? '');
1935 $('#expression_llm_prompt').on('input', function () {2041 $('#expression_llm_prompt').on('input', function () {
1936 extension_settings.expressions.llmPrompt = $(this).val();2042 extension_settings.expressions.llmPrompt = $(this).val();
@@ -2173,4 +2279,43 @@ function migrateSettings() {
2173 </div>2279 </div>
2174 `,2280 `,
2175 }));2281 }));
2282 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
2283 name: 'uploadsprite',
2284 callback: async (args, url) => {
2285 await uploadSpriteCommand(args, url);
2286 return '';
2287 },
2288 unnamedArgumentList: [
2289 SlashCommandArgument.fromProps({
2290 description: 'URL of the image to upload',
2291 typeList: [ARGUMENT_TYPE.STRING],
2292 isRequired: true,
2293 }),
2294 ],
2295 namedArgumentList: [
2296 SlashCommandNamedArgument.fromProps({
2297 name: 'name',
2298 description: 'Character name or avatar key (default is current character)',
2299 typeList: [ARGUMENT_TYPE.STRING],
2300 isRequired: false,
2301 acceptsMultiple: false,
2302 }),
2303 SlashCommandNamedArgument.fromProps({
2304 name: 'label',
2305 description: 'Sprite label/expression name',
2306 typeList: [ARGUMENT_TYPE.STRING],
2307 enumProvider: localEnumProviders.expressions,
2308 isRequired: true,
2309 acceptsMultiple: false,
2310 }),
2311 SlashCommandNamedArgument.fromProps({
2312 name: 'folder',
2313 description: 'Override folder to upload into',
2314 typeList: [ARGUMENT_TYPE.STRING],
2315 isRequired: false,
2316 acceptsMultiple: false,
2317 }),
2318 ],
2319 helpString: '<div>Upload a sprite from a URL.</div><div>Example:</div><pre><code>/uploadsprite name=Seraphina label=joy /user/images/Seraphina/Seraphina_2024-12-22@12h37m57s.png</code></pre>',
2320 }));
2176})();2321})();
public/scripts/extensions/expressions/settings.html+2 -1
@@ -24,7 +24,8 @@
24 <select id="expression_api" class="flex1 margin0">24 <select id="expression_api" class="flex1 margin0">
25 <option value="0" data-i18n="Local">Local</option>25 <option value="0" data-i18n="Local">Local</option>
26 <option value="1" data-i18n="Extras">Extras</option>26 <option value="1" data-i18n="Extras">Extras</option>
27 <option value="2" data-i18n="LLM">LLM</option>27 <option value="2" data-i18n="Main API">Main API</option>
28 <option value="3" data-i18n="WebLLM Extension">WebLLM Extension</option>
28 </select>29 </select>
29 </div>30 </div>
30 <div class="expression_llm_prompt_block m-b-1 m-t-1">31 <div class="expression_llm_prompt_block m-b-1 m-t-1">
public/scripts/extensions/stable-diffusion/button.html+2 -2
@@ -1,8 +1,8 @@
1<div id="sd_gen" class="list-group-item flex-container flexGap5">1<div id="sd_gen" class="list-group-item flex-container flexGap5">
2 <div class="fa-solid fa-paintbrush extensionsMenuExtensionButton" title="Trigger Stable Diffusion" data-i18n="[title]Trigger Stable Diffusion"></div>2 <div class="fa-solid fa-paintbrush extensionsMenuExtensionButton" title="Trigger Stable Diffusion" data-i18n="[title]Trigger Stable Diffusion"></div>
3 <span>Generate Image</span>3 <span data-i18n="Generate Image">Generate Image</span>
4</div>4</div>
5<div id="sd_stop_gen" class="list-group-item flex-container flexGap5">5<div id="sd_stop_gen" class="list-group-item flex-container flexGap5">
6 <div class="fa-solid fa-circle-stop extensionsMenuExtensionButton" title="Abort current image generation task" data-i18n="[title]Abort current image generation task"></div>6 <div class="fa-solid fa-circle-stop extensionsMenuExtensionButton" title="Abort current image generation task" data-i18n="[title]Abort current image generation task"></div>
7 <span>Stop Image Generation</span>7 <span data-i18n="Stop Image Generation">Stop Image Generation</span>
8</div>8</div>
public/scripts/extensions/stable-diffusion/index.js+33 -30
@@ -218,7 +218,7 @@ const defaultSettings = {
218 // CFG Scale218 // CFG Scale
219 scale_min: 1,219 scale_min: 1,
220 scale_max: 30,220 scale_max: 30,
221 scale_step: 0.5,221 scale_step: 0.1,
222 scale: 7,222 scale: 7,
223223
224 // Sampler steps224 // Sampler steps
@@ -319,6 +319,7 @@ const defaultSettings = {
319 wand_visible: false,319 wand_visible: false,
320 command_visible: false,320 command_visible: false,
321 interactive_visible: false,321 interactive_visible: false,
322 tool_visible: false,
322323
323 // Stability AI settings324 // Stability AI settings
324 stability_style_preset: 'anime',325 stability_style_preset: 'anime',
@@ -488,6 +489,7 @@ async function loadSettings() {
488 $('#sd_wand_visible').prop('checked', extension_settings.sd.wand_visible);489 $('#sd_wand_visible').prop('checked', extension_settings.sd.wand_visible);
489 $('#sd_command_visible').prop('checked', extension_settings.sd.command_visible);490 $('#sd_command_visible').prop('checked', extension_settings.sd.command_visible);
490 $('#sd_interactive_visible').prop('checked', extension_settings.sd.interactive_visible);491 $('#sd_interactive_visible').prop('checked', extension_settings.sd.interactive_visible);
492 $('#sd_tool_visible').prop('checked', extension_settings.sd.tool_visible);
491 $('#sd_stability_style_preset').val(extension_settings.sd.stability_style_preset);493 $('#sd_stability_style_preset').val(extension_settings.sd.stability_style_preset);
492 $('#sd_huggingface_model_id').val(extension_settings.sd.huggingface_model_id);494 $('#sd_huggingface_model_id').val(extension_settings.sd.huggingface_model_id);
493 $('#sd_function_tool').prop('checked', extension_settings.sd.function_tool);495 $('#sd_function_tool').prop('checked', extension_settings.sd.function_tool);
@@ -844,6 +846,11 @@ function onInteractiveVisibleInput() {
844 saveSettingsDebounced();846 saveSettingsDebounced();
845}847}
846848
849function onToolVisibleInput() {
850 extension_settings.sd.tool_visible = !!$('#sd_tool_visible').prop('checked');
851 saveSettingsDebounced();
852}
853
847function onClipSkipInput() {854function onClipSkipInput() {
848 extension_settings.sd.clip_skip = Number($('#sd_clip_skip').val());855 extension_settings.sd.clip_skip = Number($('#sd_clip_skip').val());
849 $('#sd_clip_skip_value').val(extension_settings.sd.clip_skip);856 $('#sd_clip_skip_value').val(extension_settings.sd.clip_skip);
@@ -1104,7 +1111,8 @@ function onHrSecondPassStepsInput() {
1104}1111}
11051112
1106function onComfyUrlInput() {1113function onComfyUrlInput() {
1107 extension_settings.sd.comfy_url = $('#sd_comfy_url').val();1114 // Remove trailing slashes
1115 extension_settings.sd.comfy_url = String($('#sd_comfy_url').val());
1108 saveSettingsDebounced();1116 saveSettingsDebounced();
1109}1117}
11101118
@@ -1605,17 +1613,12 @@ async function loadVladSamplers() {
1605}1613}
16061614
1607async function loadNovelSamplers() {1615async function loadNovelSamplers() {
1608 if (!secret_state[SECRET_KEYS.NOVEL]) {
1609 console.debug('NovelAI API key is not set.');
1610 return [];
1611 }
1612
1613 return [1616 return [
1617 'k_euler_ancestral',
1618 'k_euler',
1614 'k_dpmpp_2m',1619 'k_dpmpp_2m',
1615 'k_dpmpp_sde',1620 'k_dpmpp_sde',
1616 'k_dpmpp_2s_ancestral',1621 'k_dpmpp_2s_ancestral',
1617 'k_euler',
1618 'k_euler_ancestral',
1619 'k_dpm_fast',1622 'k_dpm_fast',
1620 'ddim',1623 'ddim',
1621 ];1624 ];
@@ -1971,13 +1974,12 @@ async function loadVladModels() {
1971}1974}
19721975
1973async function loadNovelModels() {1976async function loadNovelModels() {
1974 if (!secret_state[SECRET_KEYS.NOVEL]) {
1975 console.debug('NovelAI API key is not set.');
1976 return [];
1977 }
1978
1979 return [1977 return [
1980 {1978 {
1979 value: 'nai-diffusion-4-curated-preview',
1980 text: 'NAI Diffusion Anime V4 (Curated Preview)',
1981 },
1982 {
1981 value: 'nai-diffusion-3',1983 value: 'nai-diffusion-3',
1982 text: 'NAI Diffusion Anime V3',1984 text: 'NAI Diffusion Anime V3',
1983 },1985 },
@@ -1986,21 +1988,9 @@ async function loadNovelModels() {
1986 text: 'NAI Diffusion Anime V2',1988 text: 'NAI Diffusion Anime V2',
1987 },1989 },
1988 {1990 {
1989 value: 'nai-diffusion',
1990 text: 'NAI Diffusion Anime V1 (Full)',
1991 },
1992 {
1993 value: 'safe-diffusion',
1994 text: 'NAI Diffusion Anime V1 (Curated)',
1995 },
1996 {
1997 value: 'nai-diffusion-furry-3',1991 value: 'nai-diffusion-furry-3',
1998 text: 'NAI Diffusion Furry V3',1992 text: 'NAI Diffusion Furry V3',
1999 },1993 },
2000 {
2001 value: 'nai-diffusion-furry',
2002 text: 'NAI Diffusion Furry',
2003 },
2004 ];1994 ];
2005}1995}
20061996
@@ -2041,7 +2031,7 @@ async function loadSchedulers() {
2041 schedulers = await getAutoRemoteSchedulers();2031 schedulers = await getAutoRemoteSchedulers();
2042 break;2032 break;
2043 case sources.novel:2033 case sources.novel:
2044 schedulers = ['N/A'];2034 schedulers = ['karras', 'native', 'exponential', 'polyexponential'];
2045 break;2035 break;
2046 case sources.vlad:2036 case sources.vlad:
2047 schedulers = ['N/A'];2037 schedulers = ['N/A'];
@@ -3041,12 +3031,14 @@ async function generateAutoImage(prompt, negativePrompt, signal) {
3041 enable_hr: !!extension_settings.sd.enable_hr,3031 enable_hr: !!extension_settings.sd.enable_hr,
3042 hr_upscaler: extension_settings.sd.hr_upscaler,3032 hr_upscaler: extension_settings.sd.hr_upscaler,
3043 hr_scale: extension_settings.sd.hr_scale,3033 hr_scale: extension_settings.sd.hr_scale,
3034 hr_additional_modules: [],
3044 denoising_strength: extension_settings.sd.denoising_strength,3035 denoising_strength: extension_settings.sd.denoising_strength,
3045 hr_second_pass_steps: extension_settings.sd.hr_second_pass_steps,3036 hr_second_pass_steps: extension_settings.sd.hr_second_pass_steps,
3046 seed: extension_settings.sd.seed >= 0 ? extension_settings.sd.seed : undefined,3037 seed: extension_settings.sd.seed >= 0 ? extension_settings.sd.seed : undefined,
3047 override_settings: {3038 override_settings: {
3048 CLIP_stop_at_last_layers: extension_settings.sd.clip_skip,3039 CLIP_stop_at_last_layers: extension_settings.sd.clip_skip,
3049 sd_vae: isValidVae ? extension_settings.sd.vae : undefined,3040 sd_vae: isValidVae ? extension_settings.sd.vae : undefined,
3041 forge_additional_modules: isValidVae ? [extension_settings.sd.vae] : undefined, // For SD Forge
3050 },3042 },
3051 override_settings_restore_afterwards: true,3043 override_settings_restore_afterwards: true,
3052 clip_skip: extension_settings.sd.clip_skip, // For SD.Next3044 clip_skip: extension_settings.sd.clip_skip, // For SD.Next
@@ -3150,6 +3142,7 @@ async function generateNovelImage(prompt, negativePrompt, signal) {
3150 prompt: prompt,3142 prompt: prompt,
3151 model: extension_settings.sd.model,3143 model: extension_settings.sd.model,
3152 sampler: extension_settings.sd.sampler,3144 sampler: extension_settings.sd.sampler,
3145 scheduler: extension_settings.sd.scheduler,
3153 steps: steps,3146 steps: steps,
3154 scale: extension_settings.sd.scale,3147 scale: extension_settings.sd.scale,
3155 width: width,3148 width: width,
@@ -3177,13 +3170,18 @@ async function generateNovelImage(prompt, negativePrompt, signal) {
3177 * @returns {{steps: number, width: number, height: number, sm: boolean, sm_dyn: boolean}} - A tuple of parameters for NovelAI API.3170 * @returns {{steps: number, width: number, height: number, sm: boolean, sm_dyn: boolean}} - A tuple of parameters for NovelAI API.
3178 */3171 */
3179function getNovelParams() {3172function getNovelParams() {
3180 let steps = extension_settings.sd.steps;3173 let steps = Math.min(extension_settings.sd.steps, 50);
3181 let width = extension_settings.sd.width;3174 let width = extension_settings.sd.width;
3182 let height = extension_settings.sd.height;3175 let height = extension_settings.sd.height;
3183 let sm = extension_settings.sd.novel_sm;3176 let sm = extension_settings.sd.novel_sm;
3184 let sm_dyn = extension_settings.sd.novel_sm_dyn;3177 let sm_dyn = extension_settings.sd.novel_sm_dyn;
31853178
3186 if (extension_settings.sd.sampler === 'ddim') {3179 // If a source was never changed after the scheduler setting was added, we need to set it to 'karras' for compatibility.
3180 if (!extension_settings.sd.scheduler || extension_settings.sd.scheduler === 'normal') {
3181 extension_settings.sd.scheduler = 'karras';
3182 }
3183
3184 if (extension_settings.sd.sampler === 'ddim' || extension_settings.sd.model === 'nai-diffusion-4-curated-preview') {
3187 sm = false;3185 sm = false;
3188 sm_dyn = false;3186 sm_dyn = false;
3189 }3187 }
@@ -3314,7 +3312,6 @@ async function generateComfyImage(prompt, negativePrompt, signal) {
3314 'scale',3312 'scale',
3315 'width',3313 'width',
3316 'height',3314 'height',
3317 'clip_skip',
3318 ];3315 ];
33193316
3320 const workflowResponse = await fetch('/api/sd/comfy/workflow', {3317 const workflowResponse = await fetch('/api/sd/comfy/workflow', {
@@ -3337,6 +3334,9 @@ async function generateComfyImage(prompt, negativePrompt, signal) {
3337 const denoising_strength = extension_settings.sd.denoising_strength === undefined ? 1.0 : extension_settings.sd.denoising_strength;3334 const denoising_strength = extension_settings.sd.denoising_strength === undefined ? 1.0 : extension_settings.sd.denoising_strength;
3338 workflow = workflow.replaceAll('"%denoise%"', JSON.stringify(denoising_strength));3335 workflow = workflow.replaceAll('"%denoise%"', JSON.stringify(denoising_strength));
33393336
3337 const clip_skip = isNaN(extension_settings.sd.clip_skip) ? -1 : -extension_settings.sd.clip_skip;
3338 workflow = workflow.replaceAll('"%clip_skip%"', JSON.stringify(clip_skip));
3339
3340 placeholders.forEach(ph => {3340 placeholders.forEach(ph => {
3341 workflow = workflow.replaceAll(`"%${ph}%"`, JSON.stringify(extension_settings.sd[ph]));3341 workflow = workflow.replaceAll(`"%${ph}%"`, JSON.stringify(extension_settings.sd[ph]));
3342 });3342 });
@@ -3670,6 +3670,8 @@ function getVisibilityByInitiator(initiator) {
3670 return !!extension_settings.sd.wand_visible;3670 return !!extension_settings.sd.wand_visible;
3671 case initiators.command:3671 case initiators.command:
3672 return !!extension_settings.sd.command_visible;3672 return !!extension_settings.sd.command_visible;
3673 case initiators.tool:
3674 return !!extension_settings.sd.tool_visible;
3673 default:3675 default:
3674 return false;3676 return false;
3675 }3677 }
@@ -4417,6 +4419,7 @@ jQuery(async () => {
4417 $('#sd_wand_visible').on('input', onWandVisibleInput);4419 $('#sd_wand_visible').on('input', onWandVisibleInput);
4418 $('#sd_command_visible').on('input', onCommandVisibleInput);4420 $('#sd_command_visible').on('input', onCommandVisibleInput);
4419 $('#sd_interactive_visible').on('input', onInteractiveVisibleInput);4421 $('#sd_interactive_visible').on('input', onInteractiveVisibleInput);
4422 $('#sd_tool_visible').on('input', onToolVisibleInput);
4420 $('#sd_swap_dimensions').on('click', onSwapDimensionsClick);4423 $('#sd_swap_dimensions').on('click', onSwapDimensionsClick);
4421 $('#sd_stability_key').on('click', onStabilityKeyClick);4424 $('#sd_stability_key').on('click', onStabilityKeyClick);
4422 $('#sd_stability_style_preset').on('change', onStabilityStylePresetChange);4425 $('#sd_stability_style_preset').on('change', onStabilityStylePresetChange);
public/scripts/extensions/stable-diffusion/settings.html+12 -5
@@ -109,7 +109,7 @@
109 <i data-i18n="The server must be accessible from the SillyTavern host machine.">The server must be accessible from the SillyTavern host machine.</i>109 <i data-i18n="The server must be accessible from the SillyTavern host machine.">The server must be accessible from the SillyTavern host machine.</i>
110 </div>110 </div>
111 <div data-sd-source="horde">111 <div data-sd-source="horde">
112 <i data-i18n="Hint: Save an API key in Horde KoboldAI API settings to use it here.">Hint: Save an API key in Horde KoboldAI API settings to use it here.</i>112 <i data-i18n="Hint: Save an API key in AI Horde API settings to use it here.">Hint: Save an API key in AI Horde API settings to use it here.</i>
113 <label for="sd_horde_nsfw" class="checkbox_label">113 <label for="sd_horde_nsfw" class="checkbox_label">
114 <input id="sd_horde_nsfw" type="checkbox" />114 <input id="sd_horde_nsfw" type="checkbox" />
115 <span data-i18n="Allow NSFW images from Horde">115 <span data-i18n="Allow NSFW images from Horde">
@@ -274,7 +274,7 @@
274 <select id="sd_sampler"></select>274 <select id="sd_sampler"></select>
275 </div>275 </div>
276276
277 <div class="flex1" data-sd-source="comfy,auto">277 <div class="flex1" data-sd-source="comfy,auto,novel">
278 <label for="sd_scheduler" data-i18n="Scheduler">Scheduler</label>278 <label for="sd_scheduler" data-i18n="Scheduler">Scheduler</label>
279 <select id="sd_scheduler"></select>279 <select id="sd_scheduler"></select>
280 </div>280 </div>
@@ -459,25 +459,32 @@
459 <div class="flex-container flexFlowColumn marginTopBot5 flexGap10">459 <div class="flex-container flexFlowColumn marginTopBot5 flexGap10">
460 <label for="sd_wand_visible" class="checkbox_label">460 <label for="sd_wand_visible" class="checkbox_label">
461 <span class="flex1 flex-container alignItemsCenter">461 <span class="flex1 flex-container alignItemsCenter">
462 <i class="fa-solid fa-wand-magic-sparkles"></i>462 <i class="fa-solid fa-wand-magic-sparkles fa-fw"></i>
463 <span data-i18n="Extensions Menu">Extensions Menu</span>463 <span data-i18n="Extensions Menu">Extensions Menu</span>
464 </span>464 </span>
465 <input id="sd_wand_visible" type="checkbox" />465 <input id="sd_wand_visible" type="checkbox" />
466 </label>466 </label>
467 <label for="sd_command_visible" class="checkbox_label">467 <label for="sd_command_visible" class="checkbox_label">
468 <span class="flex1 flex-container alignItemsCenter">468 <span class="flex1 flex-container alignItemsCenter">
469 <i class="fa-solid fa-terminal"></i>469 <i class="fa-solid fa-terminal fa-fw"></i>
470 <span data-i18n="Slash Command">Slash Command</span>470 <span data-i18n="Slash Command">Slash Command</span>
471 </span>471 </span>
472 <input id="sd_command_visible" type="checkbox" />472 <input id="sd_command_visible" type="checkbox" />
473 </label>473 </label>
474 <label for="sd_interactive_visible" class="checkbox_label">474 <label for="sd_interactive_visible" class="checkbox_label">
475 <span class="flex1 flex-container alignItemsCenter">475 <span class="flex1 flex-container alignItemsCenter">
476 <i class="fa-solid fa-message"></i>476 <i class="fa-solid fa-message fa-fw"></i>
477 <span data-i18n="Interactive Mode">Interactive Mode</span>477 <span data-i18n="Interactive Mode">Interactive Mode</span>
478 </span>478 </span>
479 <input id="sd_interactive_visible" type="checkbox" />479 <input id="sd_interactive_visible" type="checkbox" />
480 </label>480 </label>
481 <label for="sd_tool_visible" class="checkbox_label">
482 <span class="flex1 flex-container alignItemsCenter">
483 <i class="fa-solid fa-wrench fa-fw"></i>
484 <span data-i18n="Function Tool">Function Tool</span>
485 </span>
486 <input id="sd_tool_visible" type="checkbox" />
487 </label>
481 </div>488 </div>
482 </div>489 </div>
483 </div>490 </div>
public/scripts/extensions/third-party/.gitkeep+0 -0
public/scripts/extensions/translate/index.html+8 -4
@@ -14,16 +14,20 @@
14 </select>14 </select>
15 <label data-i18n="ext_translate_mode_provider" for="translation_provider">Provider</label>15 <label data-i18n="ext_translate_mode_provider" for="translation_provider">Provider</label>
16 <div class="flex-container gap5px flexnowrap marginBot5">16 <div class="flex-container gap5px flexnowrap marginBot5">
17 <select id="translation_provider" name="provider" class="margin0">17 <select id="translation_provider" name="provider" class="margin0 text_pole flex2">
18 <option value="libre">Libre</option>18 <option value="libre">LibreTranslate</option>
19 <option value="google">Google</option>19 <option value="google">Google</option>
20 <option value="lingva">Lingva</option>20 <option value="lingva">Lingva</option>
21 <option value="deepl">DeepL</option>21 <option value="deepl">DeepL API</option>
22 <option value="deeplx">DeepLX</option>22 <option value="deeplx">DeepLX</option>
23 <option value="bing">Bing</option>23 <option value="bing">Bing</option>
24 <option value="oneringtranslator">OneRingTranslator</option>24 <option value="oneringtranslator">OneRingTranslator</option>
25 <option value="yandex">Yandex</option>25 <option value="yandex">Yandex</option>
26 <select>26 <select>
27 <select id="deepl_api_endpoint" class="margin0 text_pole flex1" title="DeepL API Endpoint">
28 <option value="free">Free</option>
29 <option value="pro">Pro</option>
30 </select>
27 <div id="translate_key_button" class="menu_button fa-solid fa-key margin0"></div>31 <div id="translate_key_button" class="menu_button fa-solid fa-key margin0"></div>
28 <div id="translate_url_button" class="menu_button fa-solid fa-link margin0"></div>32 <div id="translate_url_button" class="menu_button fa-solid fa-link margin0"></div>
29 </div>33 </div>
@@ -35,4 +39,4 @@
35 </div>39 </div>
36 </div>40 </div>
37 </div>41 </div>
38</div>
38 \ No newline at end of file \ No newline at end of file
42</div>
public/scripts/extensions/translate/index.js+58 -11
@@ -14,6 +14,8 @@ import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';
14import { findSecret, secret_state, writeSecret } from '../../secrets.js';14import { findSecret, secret_state, writeSecret } from '../../secrets.js';
15import { SlashCommand } from '../../slash-commands/SlashCommand.js';15import { SlashCommand } from '../../slash-commands/SlashCommand.js';
16import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';16import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
17import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
18import { enumTypes, SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
17import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';19import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
18import { splitRecursive } from '../../utils.js';20import { splitRecursive } from '../../utils.js';
1921
@@ -32,6 +34,7 @@ const defaultSettings = {
32 internal_language: 'en',34 internal_language: 'en',
33 provider: 'google',35 provider: 'google',
34 auto_mode: autoModeOptions.NONE,36 auto_mode: autoModeOptions.NONE,
37 deepl_endpoint: 'free',
35};38};
3639
37const languageCodes = {40const languageCodes = {
@@ -106,7 +109,8 @@ const languageCodes = {
106 'Pashto': 'ps',109 'Pashto': 'ps',
107 'Persian': 'fa',110 'Persian': 'fa',
108 'Polish': 'pl',111 'Polish': 'pl',
109 'Portuguese (Portugal, Brazil)': 'pt',112 'Portuguese (Portugal)': 'pt-PT',
113 'Portuguese (Brazil)': 'pt-BR',
110 'Punjabi': 'pa',114 'Punjabi': 'pa',
111 'Romanian': 'ro',115 'Romanian': 'ro',
112 'Russian': 'ru',116 'Russian': 'ru',
@@ -151,6 +155,7 @@ function showKeysButton() {
151 $('#translate_key_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider]));155 $('#translate_key_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider]));
152 $('#translate_url_button').toggle(providerOptionalUrl);156 $('#translate_url_button').toggle(providerOptionalUrl);
153 $('#translate_url_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider + '_url']));157 $('#translate_url_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider + '_url']));
158 $('#deepl_api_endpoint').toggle(extension_settings.translate.provider === 'deepl');
154}159}
155160
156function loadSettings() {161function loadSettings() {
@@ -160,9 +165,10 @@ function loadSettings() {
160 }165 }
161 }166 }
162167
163 $(`#translation_provider option[value="${extension_settings.translate.provider}"]`).attr('selected', true);168 $(`#translation_provider option[value="${extension_settings.translate.provider}"]`).attr('selected', 'true');
164 $(`#translation_target_language option[value="${extension_settings.translate.target_language}"]`).attr('selected', true);169 $(`#translation_target_language option[value="${extension_settings.translate.target_language}"]`).attr('selected', 'true');
165 $(`#translation_auto_mode option[value="${extension_settings.translate.auto_mode}"]`).attr('selected', true);170 $(`#translation_auto_mode option[value="${extension_settings.translate.auto_mode}"]`).attr('selected', 'true');
171 $('#deepl_api_endpoint').val(extension_settings.translate.deepl_endpoint).toggle(extension_settings.translate.provider === 'deepl');
166 showKeysButton();172 showKeysButton();
167}173}
168174
@@ -284,10 +290,11 @@ async function translateProviderDeepl(text, lang) {
284 throw new Error('No DeepL API key');290 throw new Error('No DeepL API key');
285 }291 }
286292
293 const endpoint = extension_settings.translate.deepl_endpoint || 'free';
287 const response = await fetch('/api/translate/deepl', {294 const response = await fetch('/api/translate/deepl', {
288 method: 'POST',295 method: 'POST',
289 headers: getRequestHeaders(),296 headers: getRequestHeaders(),
290 body: JSON.stringify({ text: text, lang: lang }),297 body: JSON.stringify({ text: text, lang: lang, endpoint: endpoint }),
291 });298 });
292299
293 if (response.ok) {300 if (response.ok) {
@@ -394,9 +401,10 @@ async function chunkedTranslate(text, lang, translateFn, chunkSize = 5000) {
394 * Translates text using the selected translation provider401 * Translates text using the selected translation provider
395 * @param {string} text Text to translate402 * @param {string} text Text to translate
396 * @param {string} lang Target language code403 * @param {string} lang Target language code
404 * @param {string} provider Translation provider to use
397 * @returns {Promise<string>} Translated text405 * @returns {Promise<string>} Translated text
398 */406 */
399async function translate(text, lang) {407async function translate(text, lang, provider = null) {
400 try {408 try {
401 if (text == '') {409 if (text == '') {
402 return '';410 return '';
@@ -406,13 +414,17 @@ async function translate(text, lang) {
406 lang = extension_settings.translate.target_language;414 lang = extension_settings.translate.target_language;
407 }415 }
408416
417 if (!provider) {
418 provider = extension_settings.translate.provider;
419 }
420
409 // split text by embedded images links421 // split text by embedded images links
410 const chunks = text.split(/!\[.*?]\([^)]*\)/);422 const chunks = text.split(/!\[.*?]\([^)]*\)/);
411 const links = [...text.matchAll(/!\[.*?]\([^)]*\)/g)];423 const links = [...text.matchAll(/!\[.*?]\([^)]*\)/g)];
412424
413 let result = '';425 let result = '';
414 for (let i = 0; i < chunks.length; i++) {426 for (let i = 0; i < chunks.length; i++) {
415 result += await translateInner(chunks[i], lang);427 result += await translateInner(chunks[i], lang, provider);
416 if (i < links.length) result += links[i][0];428 if (i < links.length) result += links[i][0];
417 }429 }
418430
@@ -423,11 +435,21 @@ async function translate(text, lang) {
423 }435 }
424}436}
425437
426async function translateInner(text, lang) {438/**
439 * Common translation function that handles the translation logic
440 * @param {string} text Text to translate
441 * @param {string} lang Target language code
442 * @param {string} provider Translation provider to use
443 * @returns {Promise<string>} Translated text
444 */
445async function translateInner(text, lang, provider) {
427 if (text == '') {446 if (text == '') {
428 return '';447 return '';
429 }448 }
430 switch (extension_settings.translate.provider) {449 if (!provider) {
450 provider = extension_settings.translate.provider;
451 }
452 switch (provider) {
431 case 'libre':453 case 'libre':
432 return await translateProviderLibre(text, lang);454 return await translateProviderLibre(text, lang);
433 case 'google':455 case 'google':
@@ -445,7 +467,7 @@ async function translateInner(text, lang) {
445 case 'yandex':467 case 'yandex':
446 return await translateProviderYandex(text, lang);468 return await translateProviderYandex(text, lang);
447 default:469 default:
448 console.error('Unknown translation provider', extension_settings.translate.provider);470 console.error('Unknown translation provider', provider);
449 return text;471 return text;
450 }472 }
451}473}
@@ -600,18 +622,34 @@ jQuery(async () => {
600 }622 }
601623
602 $('#translation_auto_mode').on('change', (event) => {624 $('#translation_auto_mode').on('change', (event) => {
625 if (!(event.target instanceof HTMLSelectElement)) {
626 return;
627 }
603 extension_settings.translate.auto_mode = event.target.value;628 extension_settings.translate.auto_mode = event.target.value;
604 saveSettingsDebounced();629 saveSettingsDebounced();
605 });630 });
606 $('#translation_provider').on('change', (event) => {631 $('#translation_provider').on('change', (event) => {
632 if (!(event.target instanceof HTMLSelectElement)) {
633 return;
634 }
607 extension_settings.translate.provider = event.target.value;635 extension_settings.translate.provider = event.target.value;
608 showKeysButton();636 showKeysButton();
609 saveSettingsDebounced();637 saveSettingsDebounced();
610 });638 });
611 $('#translation_target_language').on('change', (event) => {639 $('#translation_target_language').on('change', (event) => {
640 if (!(event.target instanceof HTMLSelectElement)) {
641 return;
642 }
612 extension_settings.translate.target_language = event.target.value;643 extension_settings.translate.target_language = event.target.value;
613 saveSettingsDebounced();644 saveSettingsDebounced();
614 });645 });
646 $('#deepl_api_endpoint').on('change', (event) => {
647 if (!(event.target instanceof HTMLSelectElement)) {
648 return;
649 }
650 extension_settings.translate.deepl_endpoint = event.target.value;
651 saveSettingsDebounced();
652 });
615 $(document).on('click', '.mes_translate', onMessageTranslateClick);653 $(document).on('click', '.mes_translate', onMessageTranslateClick);
616 $('#translate_key_button').on('click', async () => {654 $('#translate_key_button').on('click', async () => {
617 const optionText = $('#translation_provider option:selected').text();655 const optionText = $('#translation_provider option:selected').text();
@@ -687,6 +725,14 @@ jQuery(async () => {
687 helpString: 'Translate text to a target language. If target language is not provided, the value from the extension settings will be used.',725 helpString: 'Translate text to a target language. If target language is not provided, the value from the extension settings will be used.',
688 namedArgumentList: [726 namedArgumentList: [
689 new SlashCommandNamedArgument('target', 'The target language code to translate to', ARGUMENT_TYPE.STRING, false, false, '', Object.values(languageCodes)),727 new SlashCommandNamedArgument('target', 'The target language code to translate to', ARGUMENT_TYPE.STRING, false, false, '', Object.values(languageCodes)),
728 SlashCommandNamedArgument.fromProps({
729 name: 'provider',
730 description: 'The translation provider to use. If not provided, the value from the extension settings will be used.',
731 typeList: [ARGUMENT_TYPE.STRING],
732 isRequired: false,
733 acceptsMultiple: false,
734 enumProvider: () => Array.from(document.getElementById('translation_provider').querySelectorAll('option')).map((option) => new SlashCommandEnumValue(option.value, option.text, enumTypes.name, enumIcons.server)),
735 }),
690 ],736 ],
691 unnamedArgumentList: [737 unnamedArgumentList: [
692 new SlashCommandArgument('The text to translate', ARGUMENT_TYPE.STRING, true, false, ''),738 new SlashCommandArgument('The text to translate', ARGUMENT_TYPE.STRING, true, false, ''),
@@ -695,7 +741,8 @@ jQuery(async () => {
695 const target = args?.target && Object.values(languageCodes).includes(String(args.target))741 const target = args?.target && Object.values(languageCodes).includes(String(args.target))
696 ? String(args.target)742 ? String(args.target)
697 : extension_settings.translate.target_language;743 : extension_settings.translate.target_language;
698 return await translate(String(value), target);744 const provider = args?.provider || extension_settings.translate.provider;
745 return await translate(String(value), target, provider);
699 },746 },
700 returns: ARGUMENT_TYPE.STRING,747 returns: ARGUMENT_TYPE.STRING,
701 }));748 }));
public/scripts/filters.js+0 -1
@@ -448,6 +448,5 @@ export class FilterHelper {
448 for (const cache of Object.values(this.fuzzySearchCaches)) {448 for (const cache of Object.values(this.fuzzySearchCaches)) {
449 cache.resultMap.clear();449 cache.resultMap.clear();
450 }450 }
451 console.log('All fuzzy search caches cleared');
452 }451 }
453}452}
public/scripts/group-chats.js+22 -2
@@ -276,6 +276,20 @@ export function getGroupMembers(groupId = selected_group) {
276}276}
277277
278/**278/**
279 * Retrieves the member names of a group. If the group is not selected, an empty array is returned.
280 * @returns {string[]} An array of character names representing the members of the group.
281 */
282export function getGroupNames() {
283 if (!selected_group) {
284 return [];
285 }
286 const groupMembers = groups.find(x => x.id == selected_group)?.members;
287 return Array.isArray(groupMembers)
288 ? groupMembers.map(x => characters.find(y => y.avatar === x)?.name).filter(x => x)
289 : [];
290}
291
292/**
279 * Finds the character ID for a group member.293 * Finds the character ID for a group member.
280 * @param {string} arg 0-based member index or character name294 * @param {string} arg 0-based member index or character name
281 * @returns {number} 0-based character ID295 * @returns {number} 0-based character ID
@@ -423,14 +437,20 @@ export function getGroupCharacterCards(groupId, characterId) {
423 * @param {string} value Value to replace437 * @param {string} value Value to replace
424 * @param {string} characterName Name of the character438 * @param {string} characterName Name of the character
425 * @param {string} fieldName Name of the field439 * @param {string} fieldName Name of the field
440 * @param {function(string): string} [preprocess] Preprocess function
426 * @returns {string} Prepared text441 * @returns {string} Prepared text
427 * */442 * */
428 function replaceAndPrepareForJoin(value, characterName, fieldName) {443 function replaceAndPrepareForJoin(value, characterName, fieldName, preprocess = null) {
429 value = value.trim();444 value = value.trim();
430 if (!value) {445 if (!value) {
431 return '';446 return '';
432 }447 }
433448
449 // Run preprocess function
450 if (typeof preprocess === 'function') {
451 value = preprocess(value);
452 }
453
434 // Prepare and replace prefixes454 // Prepare and replace prefixes
435 const prefix = customBaseChatReplace(group.generation_mode_join_prefix, fieldName, characterName);455 const prefix = customBaseChatReplace(group.generation_mode_join_prefix, fieldName, characterName);
436 const suffix = customBaseChatReplace(group.generation_mode_join_suffix, fieldName, characterName);456 const suffix = customBaseChatReplace(group.generation_mode_join_suffix, fieldName, characterName);
@@ -465,7 +485,7 @@ export function getGroupCharacterCards(groupId, characterId) {
465 descriptions.push(replaceAndPrepareForJoin(character.description, character.name, 'Description'));485 descriptions.push(replaceAndPrepareForJoin(character.description, character.name, 'Description'));
466 personalities.push(replaceAndPrepareForJoin(character.personality, character.name, 'Personality'));486 personalities.push(replaceAndPrepareForJoin(character.personality, character.name, 'Personality'));
467 scenarios.push(replaceAndPrepareForJoin(character.scenario, character.name, 'Scenario'));487 scenarios.push(replaceAndPrepareForJoin(character.scenario, character.name, 'Scenario'));
468 mesExamplesArray.push(replaceAndPrepareForJoin(character.mes_example, character.name, 'Example Messages'));488 mesExamplesArray.push(replaceAndPrepareForJoin(character.mes_example, character.name, 'Example Messages', (x) => !x.startsWith('<START>') ? `<START>\n${x}` : x));
469 }489 }
470490
471 const description = descriptions.filter(x => x.length).join('\n');491 const description = descriptions.filter(x => x.length).join('\n');
public/scripts/instruct-mode.js+6 -5
@@ -431,7 +431,8 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
431 return mesExamplesArray.map(x => x.replace(/<START>\n/i, blockHeading));431 return mesExamplesArray.map(x => x.replace(/<START>\n/i, blockHeading));
432 }432 }
433433
434 const includeNames = power_user.instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && power_user.instruct.names_behavior === names_behavior_types.FORCE);434 const includeNames = power_user.instruct.names_behavior === names_behavior_types.ALWAYS;
435 const includeGroupNames = selected_group && [names_behavior_types.ALWAYS, names_behavior_types.FORCE].includes(power_user.instruct.names_behavior);
435436
436 let inputPrefix = power_user.instruct.input_sequence || '';437 let inputPrefix = power_user.instruct.input_sequence || '';
437 let outputPrefix = power_user.instruct.output_sequence || '';438 let outputPrefix = power_user.instruct.output_sequence || '';
@@ -463,7 +464,7 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
463464
464 for (const item of mesExamplesArray) {465 for (const item of mesExamplesArray) {
465 const cleanedItem = item.replace(/<START>/i, '{Example Dialogue:}').replace(/\r/gm, '');466 const cleanedItem = item.replace(/<START>/i, '{Example Dialogue:}').replace(/\r/gm, '');
466 const blockExamples = parseExampleIntoIndividual(cleanedItem);467 const blockExamples = parseExampleIntoIndividual(cleanedItem, includeGroupNames);
467468
468 if (blockExamples.length === 0) {469 if (blockExamples.length === 0) {
469 continue;470 continue;
@@ -474,8 +475,9 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
474 }475 }
475476
476 for (const example of blockExamples) {477 for (const example of blockExamples) {
477 // If force group/persona names is set, we should override the include names for the user placeholder478 // If group names were included, we don't want to add any additional prefix as it already was applied.
478 const includeThisName = includeNames || (power_user.instruct.names_behavior === names_behavior_types.FORCE && example.name == 'example_user');479 // Otherwise, if force group/persona names is set, we should override the include names for the user placeholder
480 const includeThisName = !includeGroupNames && (includeNames || (power_user.instruct.names_behavior === names_behavior_types.FORCE && example.name == 'example_user'));
479481
480 const prefix = example.name == 'example_user' ? inputPrefix : outputPrefix;482 const prefix = example.name == 'example_user' ? inputPrefix : outputPrefix;
481 const suffix = example.name == 'example_user' ? inputSuffix : outputSuffix;483 const suffix = example.name == 'example_user' ? inputSuffix : outputSuffix;
@@ -489,7 +491,6 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
489 if (formattedExamples.length === 0) {491 if (formattedExamples.length === 0) {
490 return mesExamplesArray.map(x => x.replace(/<START>\n/i, blockHeading));492 return mesExamplesArray.map(x => x.replace(/<START>\n/i, blockHeading));
491 }493 }
492
493 return formattedExamples;494 return formattedExamples;
494}495}
495496
public/scripts/logit-bias.js+24 -2
@@ -1,6 +1,6 @@
1import { saveSettingsDebounced } from '../script.js';1import { saveSettingsDebounced } from '../script.js';
2import { getTextTokens } from './tokenizers.js';2import { getTextTokens } from './tokenizers.js';
3import { uuidv4 } from './utils.js';3import { getSortableDelay, uuidv4 } from './utils.js';
44
5export const BIAS_CACHE = new Map();5export const BIAS_CACHE = new Map();
66
@@ -16,7 +16,8 @@ export function displayLogitBias(logitBias, containerSelector) {
16 return;16 return;
17 }17 }
1818
19 $(containerSelector).find('.logit_bias_list').empty();19 const list = $(containerSelector).find('.logit_bias_list');
20 list.empty();
2021
21 for (const entry of logitBias) {22 for (const entry of logitBias) {
22 if (entry) {23 if (entry) {
@@ -24,6 +25,27 @@ export function displayLogitBias(logitBias, containerSelector) {
24 }25 }
25 }26 }
2627
28 // Check if a sortable instance exists
29 if (list.sortable('instance') !== undefined) {
30 // Destroy the instance
31 list.sortable('destroy');
32 }
33
34 // Make the list sortable
35 list.sortable({
36 delay: getSortableDelay(),
37 handle: '.drag-handle',
38 stop: function () {
39 const order = [];
40 list.children().each(function () {
41 order.unshift($(this).data('id'));
42 });
43 logitBias.sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
44 console.log('Logit bias reordered:', logitBias);
45 saveSettingsDebounced();
46 },
47 });
48
27 BIAS_CACHE.delete(containerSelector);49 BIAS_CACHE.delete(containerSelector);
28}50}
2951
public/scripts/macros.js+7 -1
@@ -4,6 +4,7 @@ import { timestampToMoment, isDigitsOnly, getStringHash, escapeRegex, uuidv4 } f
4import { textgenerationwebui_banned_in_macros } from './textgen-settings.js';4import { textgenerationwebui_banned_in_macros } from './textgen-settings.js';
5import { getInstructMacros } from './instruct-mode.js';5import { getInstructMacros } from './instruct-mode.js';
6import { getVariableMacros } from './variables.js';6import { getVariableMacros } from './variables.js';
7import { isMobile } from './RossAscends-mods.js';
78
8/**9/**
9 * @typedef Macro10 * @typedef Macro
@@ -516,7 +517,11 @@ export function evaluateMacros(content, env, postProcessFn) {
516 break;517 break;
517 }518 }
518519
519 content = content.replace(macro.regex, (...args) => postProcessFn(macro.replace(...args)));520 try {
521 content = content.replace(macro.regex, (...args) => postProcessFn(macro.replace(...args)));
522 } catch (e) {
523 console.warn(`Macro content can't be replaced: ${macro.regex} in ${content}`, e);
524 }
520 }525 }
521526
522 return content;527 return content;
@@ -538,5 +543,6 @@ export function initMacros() {
538 });543 });
539 }544 }
540545
546 MacrosParser.registerMacro('isMobile', () => String(isMobile()));
541 initLastGenerationType();547 initLastGenerationType();
542}548}
public/scripts/openai.js+205 -46
@@ -33,7 +33,7 @@ import {
33 system_message_types,33 system_message_types,
34 this_chid,34 this_chid,
35} from '../script.js';35} from '../script.js';
36import { selected_group } from './group-chats.js';36import { getGroupNames, selected_group } from './group-chats.js';
3737
38import {38import {
39 chatCompletionDefaultPrompts,39 chatCompletionDefaultPrompts,
@@ -60,6 +60,7 @@ import {
60 parseJsonFile,60 parseJsonFile,
61 resetScrollHeight,61 resetScrollHeight,
62 stringFormat,62 stringFormat,
63 uuidv4,
63} from './utils.js';64} from './utils.js';
64import { countTokensOpenAIAsync, getTokenizerModel } from './tokenizers.js';65import { countTokensOpenAIAsync, getTokenizerModel } from './tokenizers.js';
65import { isMobile } from './RossAscends-mods.js';66import { isMobile } from './RossAscends-mods.js';
@@ -101,16 +102,16 @@ const default_new_group_chat_prompt = '[Start a new group chat. Group members: {
101const default_new_example_chat_prompt = '[Example Chat]';102const default_new_example_chat_prompt = '[Example Chat]';
102const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]';103const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]';
103const default_bias = 'Default (none)';104const default_bias = 'Default (none)';
104const default_personality_format = '[{{char}}\'s personality: {{personality}}]';105const default_personality_format = '{{personality}}';
105const default_scenario_format = '[Circumstances and context of the dialogue: {{scenario}}]';106const default_scenario_format = '{{scenario}}';
106const default_group_nudge_prompt = '[Write the next reply only as {{char}}.]';107const default_group_nudge_prompt = '[Write the next reply only as {{char}}.]';
107const default_bias_presets = {108const default_bias_presets = {
108 [default_bias]: [],109 [default_bias]: [],
109 'Anti-bond': [110 'Anti-bond': [
110 { text: ' bond', value: -50 },111 { id: '22154f79-dd98-41bc-8e34-87015d6a0eaf', text: ' bond', value: -50 },
111 { text: ' future', value: -50 },112 { id: '8ad2d5c4-d8ef-49e4-bc5e-13e7f4690e0f', text: ' future', value: -50 },
112 { text: ' bonding', value: -50 },113 { id: '52a4b280-0956-4940-ac52-4111f83e4046', text: ' bonding', value: -50 },
113 { text: ' connection', value: -25 },114 { id: 'e63037c7-c9d1-4724-ab2d-7756008b433b', text: ' connection', value: -25 },
114 ],115 ],
115};116};
116117
@@ -182,6 +183,7 @@ export const chat_completion_sources = {
182 ZEROONEAI: '01ai',183 ZEROONEAI: '01ai',
183 BLOCKENTROPY: 'blockentropy',184 BLOCKENTROPY: 'blockentropy',
184 NANOGPT: 'nanogpt',185 NANOGPT: 'nanogpt',
186 DEEPSEEK: 'deepseek',
185};187};
186188
187const character_names_behavior = {189const character_names_behavior = {
@@ -203,9 +205,16 @@ const custom_prompt_post_processing_types = {
203 /** @deprecated Use MERGE instead. */205 /** @deprecated Use MERGE instead. */
204 CLAUDE: 'claude',206 CLAUDE: 'claude',
205 MERGE: 'merge',207 MERGE: 'merge',
208 SEMI: 'semi',
206 STRICT: 'strict',209 STRICT: 'strict',
207};210};
208211
212const openrouter_middleout_types = {
213 AUTO: 'auto',
214 ON: 'on',
215 OFF: 'off',
216};
217
209const sensitiveFields = [218const sensitiveFields = [
210 'reverse_proxy',219 'reverse_proxy',
211 'proxy_password',220 'proxy_password',
@@ -254,6 +263,7 @@ const default_settings = {
254 nanogpt_model: 'gpt-4o-mini',263 nanogpt_model: 'gpt-4o-mini',
255 zerooneai_model: 'yi-large',264 zerooneai_model: 'yi-large',
256 blockentropy_model: 'be-70b-base-llama3.1',265 blockentropy_model: 'be-70b-base-llama3.1',
266 deepseek_model: 'deepseek-chat',
257 custom_model: '',267 custom_model: '',
258 custom_url: '',268 custom_url: '',
259 custom_include_body: '',269 custom_include_body: '',
@@ -266,6 +276,7 @@ const default_settings = {
266 openrouter_sort_models: 'alphabetically',276 openrouter_sort_models: 'alphabetically',
267 openrouter_providers: [],277 openrouter_providers: [],
268 openrouter_allow_fallbacks: true,278 openrouter_allow_fallbacks: true,
279 openrouter_middleout: openrouter_middleout_types.ON,
269 jailbreak_system: false,280 jailbreak_system: false,
270 reverse_proxy: '',281 reverse_proxy: '',
271 chat_completion_source: chat_completion_sources.OPENAI,282 chat_completion_source: chat_completion_sources.OPENAI,
@@ -287,6 +298,7 @@ const default_settings = {
287 names_behavior: character_names_behavior.DEFAULT,298 names_behavior: character_names_behavior.DEFAULT,
288 continue_postfix: continue_postfix_types.SPACE,299 continue_postfix: continue_postfix_types.SPACE,
289 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,300 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
301 show_thoughts: false,
290 seed: -1,302 seed: -1,
291 n: 1,303 n: 1,
292};304};
@@ -330,6 +342,7 @@ const oai_settings = {
330 nanogpt_model: 'gpt-4o-mini',342 nanogpt_model: 'gpt-4o-mini',
331 zerooneai_model: 'yi-large',343 zerooneai_model: 'yi-large',
332 blockentropy_model: 'be-70b-base-llama3.1',344 blockentropy_model: 'be-70b-base-llama3.1',
345 deepseek_model: 'deepseek-chat',
333 custom_model: '',346 custom_model: '',
334 custom_url: '',347 custom_url: '',
335 custom_include_body: '',348 custom_include_body: '',
@@ -342,6 +355,7 @@ const oai_settings = {
342 openrouter_sort_models: 'alphabetically',355 openrouter_sort_models: 'alphabetically',
343 openrouter_providers: [],356 openrouter_providers: [],
344 openrouter_allow_fallbacks: true,357 openrouter_allow_fallbacks: true,
358 openrouter_middleout: openrouter_middleout_types.ON,
345 jailbreak_system: false,359 jailbreak_system: false,
346 reverse_proxy: '',360 reverse_proxy: '',
347 chat_completion_source: chat_completion_sources.OPENAI,361 chat_completion_source: chat_completion_sources.OPENAI,
@@ -363,6 +377,7 @@ const oai_settings = {
363 names_behavior: character_names_behavior.DEFAULT,377 names_behavior: character_names_behavior.DEFAULT,
364 continue_postfix: continue_postfix_types.SPACE,378 continue_postfix: continue_postfix_types.SPACE,
365 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,379 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
380 show_thoughts: false,
366 seed: -1,381 seed: -1,
367 n: 1,382 n: 1,
368};383};
@@ -543,11 +558,15 @@ function setupChatCompletionPromptManager(openAiSettings) {
543 * @returns {Message[]} Array of message objects558 * @returns {Message[]} Array of message objects
544 */559 */
545export function parseExampleIntoIndividual(messageExampleString, appendNamesForGroup = true) {560export function parseExampleIntoIndividual(messageExampleString, appendNamesForGroup = true) {
561 const groupBotNames = getGroupNames().map(name => `${name}:`);
562
546 let result = []; // array of msgs563 let result = []; // array of msgs
547 let tmp = messageExampleString.split('\n');564 let tmp = messageExampleString.split('\n');
548 let cur_msg_lines = [];565 let cur_msg_lines = [];
549 let in_user = false;566 let in_user = false;
550 let in_bot = false;567 let in_bot = false;
568 let botName = name2;
569
551 // DRY my cock and balls :)570 // DRY my cock and balls :)
552 function add_msg(name, role, system_name) {571 function add_msg(name, role, system_name) {
553 // join different newlines (we split them by \n and join by \n)572 // join different newlines (we split them by \n and join by \n)
@@ -571,10 +590,14 @@ export function parseExampleIntoIndividual(messageExampleString, appendNamesForG
571 in_user = true;590 in_user = true;
572 // we were in the bot mode previously, add the message591 // we were in the bot mode previously, add the message
573 if (in_bot) {592 if (in_bot) {
574 add_msg(name2, 'system', 'example_assistant');593 add_msg(botName, 'system', 'example_assistant');
575 }594 }
576 in_bot = false;595 in_bot = false;
577 } else if (cur_str.startsWith(name2 + ':')) {596 } else if (cur_str.startsWith(name2 + ':') || groupBotNames.some(n => cur_str.startsWith(n))) {
597 if (!cur_str.startsWith(name2 + ':') && groupBotNames.length) {
598 botName = cur_str.split(':')[0];
599 }
600
578 in_bot = true;601 in_bot = true;
579 // we were in the user mode previously, add the message602 // we were in the user mode previously, add the message
580 if (in_user) {603 if (in_user) {
@@ -589,7 +612,7 @@ export function parseExampleIntoIndividual(messageExampleString, appendNamesForG
589 if (in_user) {612 if (in_user) {
590 add_msg(name1, 'system', 'example_user');613 add_msg(name1, 'system', 'example_user');
591 } else if (in_bot) {614 } else if (in_bot) {
592 add_msg(name2, 'system', 'example_assistant');615 add_msg(botName, 'system', 'example_assistant');
593 }616 }
594 return result;617 return result;
595}618}
@@ -611,8 +634,9 @@ function formatWorldInfo(value) {
611 *634 *
612 * @param {Prompt[]} prompts - Array containing injection prompts.635 * @param {Prompt[]} prompts - Array containing injection prompts.
613 * @param {Object[]} messages - Array containing all messages.636 * @param {Object[]} messages - Array containing all messages.
637 * @returns {Promise<Object[]>} - Array containing all messages with injections.
614 */638 */
615function populationInjectionPrompts(prompts, messages) {639async function populationInjectionPrompts(prompts, messages) {
616 let totalInsertedMessages = 0;640 let totalInsertedMessages = 0;
617641
618 const roleTypes = {642 const roleTypes = {
@@ -635,7 +659,7 @@ function populationInjectionPrompts(prompts, messages) {
635 // Get prompts for current role659 // Get prompts for current role
636 const rolePrompts = depthPrompts.filter(prompt => prompt.role === role).map(x => x.content).join(separator);660 const rolePrompts = depthPrompts.filter(prompt => prompt.role === role).map(x => x.content).join(separator);
637 // Get extension prompt661 // Get extension prompt
638 const extensionPrompt = getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, roleTypes[role], wrap);662 const extensionPrompt = await getExtensionPrompt(extension_prompt_types.IN_CHAT, i, separator, roleTypes[role], wrap);
639663
640 const jointPrompt = [rolePrompts, extensionPrompt].filter(x => x).map(x => x.trim()).join(separator);664 const jointPrompt = [rolePrompts, extensionPrompt].filter(x => x).map(x => x.trim()).join(separator);
641665
@@ -749,7 +773,9 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul
749 if (type === 'continue' && oai_settings.continue_prefill && chatPrompt === firstNonInjected) {773 if (type === 'continue' && oai_settings.continue_prefill && chatPrompt === firstNonInjected) {
750 // in case we are using continue_prefill and the latest message is an assistant message, we want to prepend the users assistant prefill on the message774 // in case we are using continue_prefill and the latest message is an assistant message, we want to prepend the users assistant prefill on the message
751 if (chatPrompt.role === 'assistant') {775 if (chatPrompt.role === 'assistant') {
752 const messageContent = [substituteParams(oai_settings.assistant_prefill), chatMessage.content].filter(x => x).join('\n\n');776 const supportsAssistantPrefill = oai_settings.chat_completion_source === chat_completion_sources.CLAUDE;
777 const assistantPrefill = supportsAssistantPrefill ? substituteParams(oai_settings.assistant_prefill) : '';
778 const messageContent = [assistantPrefill, chatMessage.content].filter(x => x).join('\n\n');
753 const continueMessage = await Message.createAsync(chatMessage.role, messageContent, chatMessage.identifier);779 const continueMessage = await Message.createAsync(chatMessage.role, messageContent, chatMessage.identifier);
754 const collection = new MessageCollection('continuePrefill', continueMessage);780 const collection = new MessageCollection('continuePrefill', continueMessage);
755 chatCompletion.add(collection, -1);781 chatCompletion.add(collection, -1);
@@ -1020,7 +1046,7 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm
1020 }1046 }
10211047
1022 // Add in-chat injections1048 // Add in-chat injections
1023 messages = populationInjectionPrompts(absolutePrompts, messages);1049 messages = await populationInjectionPrompts(absolutePrompts, messages);
10241050
1025 // Decide whether dialogue examples should always be added1051 // Decide whether dialogue examples should always be added
1026 if (power_user.pin_examples) {1052 if (power_user.pin_examples) {
@@ -1051,9 +1077,9 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm
1051 * @param {string} options.systemPromptOverride1077 * @param {string} options.systemPromptOverride
1052 * @param {string} options.jailbreakPromptOverride1078 * @param {string} options.jailbreakPromptOverride
1053 * @param {string} options.personaDescription1079 * @param {string} options.personaDescription
1054 * @returns {Object} prompts - The prepared and merged system and user-defined prompts.1080 * @returns {Promise<Object>} prompts - The prepared and merged system and user-defined prompts.
1055 */1081 */
1056function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, personaDescription }) {1082async function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, worldInfoBefore, worldInfoAfter, charDescription, quietPrompt, bias, extensionPrompts, systemPromptOverride, jailbreakPromptOverride, personaDescription }) {
1057 const scenarioText = Scenario && oai_settings.scenario_format ? substituteParams(oai_settings.scenario_format) : '';1083 const scenarioText = Scenario && oai_settings.scenario_format ? substituteParams(oai_settings.scenario_format) : '';
1058 const charPersonalityText = charPersonality && oai_settings.personality_format ? substituteParams(oai_settings.personality_format) : '';1084 const charPersonalityText = charPersonality && oai_settings.personality_format ? substituteParams(oai_settings.personality_format) : '';
1059 const groupNudge = substituteParams(oai_settings.group_nudge_prompt);1085 const groupNudge = substituteParams(oai_settings.group_nudge_prompt);
@@ -1142,6 +1168,9 @@ function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, wor
1142 if (!extensionPrompts[key].value) continue;1168 if (!extensionPrompts[key].value) continue;
1143 if (![extension_prompt_types.BEFORE_PROMPT, extension_prompt_types.IN_PROMPT].includes(prompt.position)) continue;1169 if (![extension_prompt_types.BEFORE_PROMPT, extension_prompt_types.IN_PROMPT].includes(prompt.position)) continue;
11441170
1171 const hasFilter = typeof prompt.filter === 'function';
1172 if (hasFilter && !await prompt.filter()) continue;
1173
1145 systemPrompts.push({1174 systemPrompts.push({
1146 identifier: key.replace(/\W/g, '_'),1175 identifier: key.replace(/\W/g, '_'),
1147 position: getPromptPosition(prompt.position),1176 position: getPromptPosition(prompt.position),
@@ -1178,7 +1207,8 @@ function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, wor
11781207
1179 // Apply character-specific main prompt1208 // Apply character-specific main prompt
1180 const systemPrompt = prompts.get('main') ?? null;1209 const systemPrompt = prompts.get('main') ?? null;
1181 if (systemPromptOverride && systemPrompt && systemPrompt.forbid_overrides !== true) {1210 const isSystemPromptDisabled = promptManager.isPromptDisabledForActiveCharacter('main');
1211 if (systemPromptOverride && systemPrompt && systemPrompt.forbid_overrides !== true && !isSystemPromptDisabled) {
1182 const mainOriginalContent = systemPrompt.content;1212 const mainOriginalContent = systemPrompt.content;
1183 systemPrompt.content = systemPromptOverride;1213 systemPrompt.content = systemPromptOverride;
1184 const mainReplacement = promptManager.preparePrompt(systemPrompt, mainOriginalContent);1214 const mainReplacement = promptManager.preparePrompt(systemPrompt, mainOriginalContent);
@@ -1187,7 +1217,8 @@ function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, wor
11871217
1188 // Apply character-specific jailbreak1218 // Apply character-specific jailbreak
1189 const jailbreakPrompt = prompts.get('jailbreak') ?? null;1219 const jailbreakPrompt = prompts.get('jailbreak') ?? null;
1190 if (jailbreakPromptOverride && jailbreakPrompt && jailbreakPrompt.forbid_overrides !== true) {1220 const isJailbreakPromptDisabled = promptManager.isPromptDisabledForActiveCharacter('jailbreak');
1221 if (jailbreakPromptOverride && jailbreakPrompt && jailbreakPrompt.forbid_overrides !== true && !isJailbreakPromptDisabled) {
1191 const jbOriginalContent = jailbreakPrompt.content;1222 const jbOriginalContent = jailbreakPrompt.content;
1192 jailbreakPrompt.content = jailbreakPromptOverride;1223 jailbreakPrompt.content = jailbreakPromptOverride;
1193 const jbReplacement = promptManager.preparePrompt(jailbreakPrompt, jbOriginalContent);1224 const jbReplacement = promptManager.preparePrompt(jailbreakPrompt, jbOriginalContent);
@@ -1252,7 +1283,7 @@ export async function prepareOpenAIMessages({
12521283
1253 try {1284 try {
1254 // Merge markers and ordered user prompts with system prompts1285 // Merge markers and ordered user prompts with system prompts
1255 const prompts = preparePromptsForChatCompletion({1286 const prompts = await preparePromptsForChatCompletion({
1256 Scenario,1287 Scenario,
1257 charPersonality,1288 charPersonality,
1258 name2,1289 name2,
@@ -1498,6 +1529,8 @@ function getChatCompletionModel() {
1498 return oai_settings.blockentropy_model;1529 return oai_settings.blockentropy_model;
1499 case chat_completion_sources.NANOGPT:1530 case chat_completion_sources.NANOGPT:
1500 return oai_settings.nanogpt_model;1531 return oai_settings.nanogpt_model;
1532 case chat_completion_sources.DEEPSEEK:
1533 return oai_settings.deepseek_model;
1501 default:1534 default:
1502 throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`);1535 throw new Error(`Unknown chat completion source: ${oai_settings.chat_completion_source}`);
1503 }1536 }
@@ -1673,6 +1706,24 @@ function saveModelList(data) {
16731706
1674 $('#model_nanogpt_select').val(oai_settings.nanogpt_model).trigger('change');1707 $('#model_nanogpt_select').val(oai_settings.nanogpt_model).trigger('change');
1675 }1708 }
1709
1710 if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) {
1711 $('#model_deepseek_select').empty();
1712 model_list.forEach((model) => {
1713 $('#model_deepseek_select').append(
1714 $('<option>', {
1715 value: model.id,
1716 text: model.id,
1717 }));
1718 });
1719
1720 const selectedModel = model_list.find(model => model.id === oai_settings.deepseek_model);
1721 if (model_list.length > 0 && (!selectedModel || !oai_settings.deepseek_model)) {
1722 oai_settings.deepseek_model = model_list[0].id;
1723 }
1724
1725 $('#model_deepseek_select').val(oai_settings.deepseek_model).trigger('change');
1726 }
1676}1727}
16771728
1678function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {1729function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
@@ -1813,6 +1864,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1813 const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;1864 const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ;
1814 const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;1865 const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI;
1815 const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT;1866 const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT;
1867 const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK;
1816 const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);1868 const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model);
1817 const isQuiet = type === 'quiet';1869 const isQuiet = type === 'quiet';
1818 const isImpersonate = type === 'impersonate';1870 const isImpersonate = type === 'impersonate';
@@ -1860,6 +1912,8 @@ async function sendOpenAIRequest(type, messages, signal) {
1860 'n': canMultiSwipe ? oai_settings.n : undefined,1912 'n': canMultiSwipe ? oai_settings.n : undefined,
1861 'user_name': name1,1913 'user_name': name1,
1862 'char_name': name2,1914 'char_name': name2,
1915 'group_names': getGroupNames(),
1916 'show_thoughts': Boolean(oai_settings.show_thoughts),
1863 };1917 };
18641918
1865 // Empty array will produce a validation error1919 // Empty array will produce a validation error
@@ -1875,7 +1929,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1875 }1929 }
18761930
1877 // Add logprobs request (currently OpenAI only, max 5 on their side)1931 // Add logprobs request (currently OpenAI only, max 5 on their side)
1878 if (useLogprobs && (isOAI || isCustom)) {1932 if (useLogprobs && (isOAI || isCustom || isDeepSeek)) {
1879 generate_data['logprobs'] = 5;1933 generate_data['logprobs'] = 5;
1880 }1934 }
18811935
@@ -1904,6 +1958,7 @@ async function sendOpenAIRequest(type, messages, signal) {
1904 generate_data['use_fallback'] = oai_settings.openrouter_use_fallback;1958 generate_data['use_fallback'] = oai_settings.openrouter_use_fallback;
1905 generate_data['provider'] = oai_settings.openrouter_providers;1959 generate_data['provider'] = oai_settings.openrouter_providers;
1906 generate_data['allow_fallbacks'] = oai_settings.openrouter_allow_fallbacks;1960 generate_data['allow_fallbacks'] = oai_settings.openrouter_allow_fallbacks;
1961 generate_data['middleout'] = oai_settings.openrouter_middleout;
19071962
1908 if (isTextCompletion) {1963 if (isTextCompletion) {
1909 generate_data['stop'] = getStoppingStrings(isImpersonate, isContinue);1964 generate_data['stop'] = getStoppingStrings(isImpersonate, isContinue);
@@ -1972,6 +2027,11 @@ async function sendOpenAIRequest(type, messages, signal) {
1972 delete generate_data.stop;2027 delete generate_data.stop;
1973 }2028 }
19742029
2030 // https://api-docs.deepseek.com/api/create-chat-completion
2031 if (isDeepSeek) {
2032 generate_data.top_p = generate_data.top_p || Number.EPSILON;
2033 }
2034
1975 if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) {2035 if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) {
1976 generate_data['seed'] = oai_settings.seed;2036 generate_data['seed'] = oai_settings.seed;
1977 }2037 }
@@ -2073,7 +2133,7 @@ function getStreamingReply(data) {
2073 if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) {2133 if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) {
2074 return data?.delta?.text || '';2134 return data?.delta?.text || '';
2075 } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {2135 } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {
2076 return data?.candidates?.[0]?.content?.parts?.[0]?.text || '';2136 return data?.candidates?.[0]?.content?.parts?.filter(x => oai_settings.show_thoughts || !x.thought)?.map(x => x.text)?.filter(x => x)?.join('\n\n') || '';
2077 } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {2137 } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {
2078 return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || '';2138 return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || '';
2079 } else {2139 } else {
@@ -2085,7 +2145,7 @@ function getStreamingReply(data) {
2085 * parseChatCompletionLogprobs converts the response data returned from a chat2145 * parseChatCompletionLogprobs converts the response data returned from a chat
2086 * completions-like source into an array of TokenLogprobs found in the response.2146 * completions-like source into an array of TokenLogprobs found in the response.
2087 * @param {Object} data - response data from a chat completions-like source2147 * @param {Object} data - response data from a chat completions-like source
2088 * @returns {import('logprobs.js').TokenLogprobs[] | null} converted logprobs2148 * @returns {import('./logprobs.js').TokenLogprobs[] | null} converted logprobs
2089 */2149 */
2090function parseChatCompletionLogprobs(data) {2150function parseChatCompletionLogprobs(data) {
2091 if (!data) {2151 if (!data) {
@@ -2094,6 +2154,7 @@ function parseChatCompletionLogprobs(data) {
20942154
2095 switch (oai_settings.chat_completion_source) {2155 switch (oai_settings.chat_completion_source) {
2096 case chat_completion_sources.OPENAI:2156 case chat_completion_sources.OPENAI:
2157 case chat_completion_sources.DEEPSEEK:
2097 case chat_completion_sources.CUSTOM:2158 case chat_completion_sources.CUSTOM:
2098 if (!data.choices?.length) {2159 if (!data.choices?.length) {
2099 return null;2160 return null;
@@ -2114,7 +2175,7 @@ function parseChatCompletionLogprobs(data) {
2114 * completion API and converts into the structure used by the Token Probabilities2175 * completion API and converts into the structure used by the Token Probabilities
2115 * view.2176 * view.
2116 * @param {{content: { token: string, logprob: number, top_logprobs: { token: string, logprob: number }[] }[]}} logprobs2177 * @param {{content: { token: string, logprob: number, top_logprobs: { token: string, logprob: number }[] }[]}} logprobs
2117 * @returns {import('logprobs.js').TokenLogprobs[] | null} converted logprobs2178 * @returns {import('./logprobs.js').TokenLogprobs[] | null} converted logprobs
2118 */2179 */
2119function parseOpenAIChatLogprobs(logprobs) {2180function parseOpenAIChatLogprobs(logprobs) {
2120 const { content } = logprobs ?? {};2181 const { content } = logprobs ?? {};
@@ -2142,7 +2203,7 @@ function parseOpenAIChatLogprobs(logprobs) {
2142 * completion API and converts into the structure used by the Token Probabilities2203 * completion API and converts into the structure used by the Token Probabilities
2143 * view.2204 * view.
2144 * @param {{tokens: string[], token_logprobs: number[], top_logprobs: { token: string, logprob: number }[][]}} logprobs2205 * @param {{tokens: string[], token_logprobs: number[], top_logprobs: { token: string, logprob: number }[][]}} logprobs
2145 * @returns {import('logprobs.js').TokenLogprobs[] | null} converted logprobs2206 * @returns {import('./logprobs.js').TokenLogprobs[] | null} converted logprobs
2146 */2207 */
2147function parseOpenAITextLogprobs(logprobs) {2208function parseOpenAITextLogprobs(logprobs) {
2148 const { tokens, token_logprobs, top_logprobs } = logprobs ?? {};2209 const { tokens, token_logprobs, top_logprobs } = logprobs ?? {};
@@ -3006,12 +3067,14 @@ function loadOpenAISettings(data, settings) {
3006 oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;3067 oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;
3007 oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;3068 oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;
3008 oai_settings.openrouter_allow_fallbacks = settings.openrouter_allow_fallbacks ?? default_settings.openrouter_allow_fallbacks;3069 oai_settings.openrouter_allow_fallbacks = settings.openrouter_allow_fallbacks ?? default_settings.openrouter_allow_fallbacks;
3070 oai_settings.openrouter_middleout = settings.openrouter_middleout ?? default_settings.openrouter_middleout;
3009 oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;3071 oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;
3010 oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;3072 oai_settings.mistralai_model = settings.mistralai_model ?? default_settings.mistralai_model;
3011 oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model;3073 oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model;
3012 oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model;3074 oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model;
3013 oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model;3075 oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model;
3014 oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model;3076 oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model;
3077 oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model;
3015 oai_settings.blockentropy_model = settings.blockentropy_model ?? default_settings.blockentropy_model;3078 oai_settings.blockentropy_model = settings.blockentropy_model ?? default_settings.blockentropy_model;
3016 oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model;3079 oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model;
3017 oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;3080 oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model;
@@ -3030,6 +3093,7 @@ function loadOpenAISettings(data, settings) {
3030 oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining;3093 oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining;
3031 oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality;3094 oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality;
3032 oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;3095 oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
3096 oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts;
3033 oai_settings.seed = settings.seed ?? default_settings.seed;3097 oai_settings.seed = settings.seed ?? default_settings.seed;
3034 oai_settings.n = settings.n ?? default_settings.n;3098 oai_settings.n = settings.n ?? default_settings.n;
30353099
@@ -3092,6 +3156,8 @@ function loadOpenAISettings(data, settings) {
3092 $(`#model_groq_select option[value="${oai_settings.groq_model}"`).attr('selected', true);3156 $(`#model_groq_select option[value="${oai_settings.groq_model}"`).attr('selected', true);
3093 $('#model_nanogpt_select').val(oai_settings.nanogpt_model);3157 $('#model_nanogpt_select').val(oai_settings.nanogpt_model);
3094 $(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).attr('selected', true);3158 $(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).attr('selected', true);
3159 $('#model_deepseek_select').val(oai_settings.deepseek_model);
3160 $(`#model_deepseek_select option[value="${oai_settings.deepseek_model}"`).prop('selected', true);
3095 $('#model_01ai_select').val(oai_settings.zerooneai_model);3161 $('#model_01ai_select').val(oai_settings.zerooneai_model);
3096 $('#model_blockentropy_select').val(oai_settings.blockentropy_model);3162 $('#model_blockentropy_select').val(oai_settings.blockentropy_model);
3097 $('#custom_model_id').val(oai_settings.custom_model);3163 $('#custom_model_id').val(oai_settings.custom_model);
@@ -3114,6 +3180,7 @@ function loadOpenAISettings(data, settings) {
3114 $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);3180 $('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);
3115 $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks);3181 $('#openrouter_allow_fallbacks').prop('checked', oai_settings.openrouter_allow_fallbacks);
3116 $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change');3182 $('#openrouter_providers_chat').val(oai_settings.openrouter_providers).trigger('change');
3183 $('#openrouter_middleout').val(oai_settings.openrouter_middleout);
3117 $('#squash_system_messages').prop('checked', oai_settings.squash_system_messages);3184 $('#squash_system_messages').prop('checked', oai_settings.squash_system_messages);
3118 $('#continue_prefill').prop('checked', oai_settings.continue_prefill);3185 $('#continue_prefill').prop('checked', oai_settings.continue_prefill);
3119 $('#openai_function_calling').prop('checked', oai_settings.function_calling);3186 $('#openai_function_calling').prop('checked', oai_settings.function_calling);
@@ -3154,6 +3221,7 @@ function loadOpenAISettings(data, settings) {
3154 $('#repetition_penalty_counter_openai').val(Number(oai_settings.repetition_penalty_openai));3221 $('#repetition_penalty_counter_openai').val(Number(oai_settings.repetition_penalty_openai));
3155 $('#seed_openai').val(oai_settings.seed);3222 $('#seed_openai').val(oai_settings.seed);
3156 $('#n_openai').val(oai_settings.n);3223 $('#n_openai').val(oai_settings.n);
3224 $('#openai_show_thoughts').prop('checked', oai_settings.show_thoughts);
31573225
3158 if (settings.reverse_proxy !== undefined) oai_settings.reverse_proxy = settings.reverse_proxy;3226 if (settings.reverse_proxy !== undefined) oai_settings.reverse_proxy = settings.reverse_proxy;
3159 $('#openai_reverse_proxy').val(oai_settings.reverse_proxy);3227 $('#openai_reverse_proxy').val(oai_settings.reverse_proxy);
@@ -3162,6 +3230,14 @@ function loadOpenAISettings(data, settings) {
31623230
3163 $('#openai_logit_bias_preset').empty();3231 $('#openai_logit_bias_preset').empty();
3164 for (const preset of Object.keys(oai_settings.bias_presets)) {3232 for (const preset of Object.keys(oai_settings.bias_presets)) {
3233 // Backfill missing IDs
3234 if (Array.isArray(oai_settings.bias_presets[preset])) {
3235 oai_settings.bias_presets[preset].forEach((bias) => {
3236 if (bias && !bias.id) {
3237 bias.id = uuidv4();
3238 }
3239 });
3240 }
3165 const option = document.createElement('option');3241 const option = document.createElement('option');
3166 option.innerText = preset;3242 option.innerText = preset;
3167 option.value = preset;3243 option.value = preset;
@@ -3270,7 +3346,7 @@ async function getStatusOpen() {
3270 chat_completion_source: oai_settings.chat_completion_source,3346 chat_completion_source: oai_settings.chat_completion_source,
3271 };3347 };
32723348
3273 if (oai_settings.reverse_proxy && (oai_settings.chat_completion_source === chat_completion_sources.OPENAI || oai_settings.chat_completion_source === chat_completion_sources.CLAUDE)) {3349 if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE].includes(oai_settings.chat_completion_source)) {
3274 await validateReverseProxy();3350 await validateReverseProxy();
3275 }3351 }
32763352
@@ -3346,6 +3422,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
3346 openrouter_sort_models: settings.openrouter_sort_models,3422 openrouter_sort_models: settings.openrouter_sort_models,
3347 openrouter_providers: settings.openrouter_providers,3423 openrouter_providers: settings.openrouter_providers,
3348 openrouter_allow_fallbacks: settings.openrouter_allow_fallbacks,3424 openrouter_allow_fallbacks: settings.openrouter_allow_fallbacks,
3425 openrouter_middleout: settings.openrouter_middleout,
3349 ai21_model: settings.ai21_model,3426 ai21_model: settings.ai21_model,
3350 mistralai_model: settings.mistralai_model,3427 mistralai_model: settings.mistralai_model,
3351 cohere_model: settings.cohere_model,3428 cohere_model: settings.cohere_model,
@@ -3405,6 +3482,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
3405 continue_prefill: settings.continue_prefill,3482 continue_prefill: settings.continue_prefill,
3406 continue_postfix: settings.continue_postfix,3483 continue_postfix: settings.continue_postfix,
3407 function_calling: settings.function_calling,3484 function_calling: settings.function_calling,
3485 show_thoughts: settings.show_thoughts,
3408 seed: settings.seed,3486 seed: settings.seed,
3409 n: settings.n,3487 n: settings.n,
3410 };3488 };
@@ -3450,7 +3528,8 @@ function onLogitBiasPresetChange() {
3450 }3528 }
34513529
3452 oai_settings.bias_preset_selected = value;3530 oai_settings.bias_preset_selected = value;
3453 $('.openai_logit_bias_list').empty();3531 const list = $('.openai_logit_bias_list');
3532 list.empty();
34543533
3455 for (const entry of preset) {3534 for (const entry of preset) {
3456 if (entry) {3535 if (entry) {
@@ -3458,12 +3537,33 @@ function onLogitBiasPresetChange() {
3458 }3537 }
3459 }3538 }
34603539
3540 // Check if a sortable instance exists
3541 if (list.sortable('instance') !== undefined) {
3542 // Destroy the instance
3543 list.sortable('destroy');
3544 }
3545
3546 // Make the list sortable
3547 list.sortable({
3548 delay: getSortableDelay(),
3549 handle: '.drag-handle',
3550 stop: function () {
3551 const order = [];
3552 list.children().each(function () {
3553 order.unshift($(this).data('id'));
3554 });
3555 preset.sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
3556 console.log('Logit bias reordered:', preset);
3557 saveSettingsDebounced();
3558 },
3559 });
3560
3461 biasCache = undefined;3561 biasCache = undefined;
3462 saveSettingsDebounced();3562 saveSettingsDebounced();
3463}3563}
34643564
3465function createNewLogitBiasEntry() {3565function createNewLogitBiasEntry() {
3466 const entry = { text: '', value: 0 };3566 const entry = { id: uuidv4(), text: '', value: 0 };
3467 oai_settings.bias_presets[oai_settings.bias_preset_selected].push(entry);3567 oai_settings.bias_presets[oai_settings.bias_preset_selected].push(entry);
3468 biasCache = undefined;3568 biasCache = undefined;
3469 createLogitBiasListItem(entry);3569 createLogitBiasListItem(entry);
@@ -3471,11 +3571,14 @@ function createNewLogitBiasEntry() {
3471}3571}
34723572
3473function createLogitBiasListItem(entry) {3573function createLogitBiasListItem(entry) {
3474 const id = oai_settings.bias_presets[oai_settings.bias_preset_selected].indexOf(entry);3574 if (!entry.id) {
3575 entry.id = uuidv4();
3576 }
3577 const id = entry.id;
3475 const template = $('#openai_logit_bias_template .openai_logit_bias_form').clone();3578 const template = $('#openai_logit_bias_template .openai_logit_bias_form').clone();
3476 template.data('id', id);3579 template.data('id', id);
3477 template.find('.openai_logit_bias_text').val(entry.text).on('input', function () {3580 template.find('.openai_logit_bias_text').val(entry.text).on('input', function () {
3478 oai_settings.bias_presets[oai_settings.bias_preset_selected][id].text = String($(this).val());3581 entry.text = String($(this).val());
3479 biasCache = undefined;3582 biasCache = undefined;
3480 saveSettingsDebounced();3583 saveSettingsDebounced();
3481 });3584 });
@@ -3494,13 +3597,17 @@ function createLogitBiasListItem(entry) {
3494 value = max;3597 value = max;
3495 }3598 }
34963599
3497 oai_settings.bias_presets[oai_settings.bias_preset_selected][id].value = value;3600 entry.value = value;
3498 biasCache = undefined;3601 biasCache = undefined;
3499 saveSettingsDebounced();3602 saveSettingsDebounced();
3500 });3603 });
3501 template.find('.openai_logit_bias_remove').on('click', function () {3604 template.find('.openai_logit_bias_remove').on('click', function () {
3502 $(this).closest('.openai_logit_bias_form').remove();3605 $(this).closest('.openai_logit_bias_form').remove();
3503 oai_settings.bias_presets[oai_settings.bias_preset_selected].splice(id, 1);3606 const preset = oai_settings.bias_presets[oai_settings.bias_preset_selected];
3607 const index = preset.findIndex(item => item.id === id);
3608 if (index >= 0) {
3609 preset.splice(index, 1);
3610 }
3504 onLogitBiasPresetChange();3611 onLogitBiasPresetChange();
3505 });3612 });
3506 $('.openai_logit_bias_list').prepend(template);3613 $('.openai_logit_bias_list').prepend(template);
@@ -3680,6 +3787,9 @@ async function onLogitBiasPresetImportFileChange(e) {
3680 if (typeof entry == 'object' && entry !== null) {3787 if (typeof entry == 'object' && entry !== null) {
3681 if (Object.hasOwn(entry, 'text') &&3788 if (Object.hasOwn(entry, 'text') &&
3682 Object.hasOwn(entry, 'value')) {3789 Object.hasOwn(entry, 'value')) {
3790 if (!entry.id) {
3791 entry.id = uuidv4();
3792 }
3683 validEntries.push(entry);3793 validEntries.push(entry);
3684 }3794 }
3685 }3795 }
@@ -3780,12 +3890,14 @@ function onSettingsPresetChange() {
3780 openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],3890 openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],
3781 openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false],3891 openrouter_providers: ['#openrouter_providers_chat', 'openrouter_providers', false],
3782 openrouter_allow_fallbacks: ['#openrouter_allow_fallbacks', 'openrouter_allow_fallbacks', true],3892 openrouter_allow_fallbacks: ['#openrouter_allow_fallbacks', 'openrouter_allow_fallbacks', true],
3893 openrouter_middleout: ['#openrouter_middleout', 'openrouter_middleout', false],
3783 ai21_model: ['#model_ai21_select', 'ai21_model', false],3894 ai21_model: ['#model_ai21_select', 'ai21_model', false],
3784 mistralai_model: ['#model_mistralai_select', 'mistralai_model', false],3895 mistralai_model: ['#model_mistralai_select', 'mistralai_model', false],
3785 cohere_model: ['#model_cohere_select', 'cohere_model', false],3896 cohere_model: ['#model_cohere_select', 'cohere_model', false],
3786 perplexity_model: ['#model_perplexity_select', 'perplexity_model', false],3897 perplexity_model: ['#model_perplexity_select', 'perplexity_model', false],
3787 groq_model: ['#model_groq_select', 'groq_model', false],3898 groq_model: ['#model_groq_select', 'groq_model', false],
3788 nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false],3899 nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false],
3900 deepseek_model: ['#model_deepseek_select', 'deepseek_model', false],
3789 zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false],3901 zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false],
3790 blockentropy_model: ['#model_blockentropy_select', 'blockentropy_model', false],3902 blockentropy_model: ['#model_blockentropy_select', 'blockentropy_model', false],
3791 custom_model: ['#custom_model_id', 'custom_model', false],3903 custom_model: ['#custom_model_id', 'custom_model', false],
@@ -3828,6 +3940,7 @@ function onSettingsPresetChange() {
3828 continue_prefill: ['#continue_prefill', 'continue_prefill', true],3940 continue_prefill: ['#continue_prefill', 'continue_prefill', true],
3829 continue_postfix: ['#continue_postfix', 'continue_postfix', false],3941 continue_postfix: ['#continue_postfix', 'continue_postfix', false],
3830 function_calling: ['#openai_function_calling', 'function_calling', true],3942 function_calling: ['#openai_function_calling', 'function_calling', true],
3943 show_thoughts: ['#openai_show_thoughts', 'show_thoughts', true],
3831 seed: ['#seed_openai', 'seed', false],3944 seed: ['#seed_openai', 'seed', false],
3832 n: ['#n_openai', 'n', false],3945 n: ['#n_openai', 'n', false],
3833 };3946 };
@@ -4044,6 +4157,16 @@ async function onModelChange() {
4044 oai_settings.nanogpt_model = value;4157 oai_settings.nanogpt_model = value;
4045 }4158 }
40464159
4160 if ($(this).is('#model_deepseek_select')) {
4161 if (!value) {
4162 console.debug('Null DeepSeek model selected. Ignoring.');
4163 return;
4164 }
4165
4166 console.log('DeepSeek model changed to', value);
4167 oai_settings.deepseek_model = value;
4168 }
4169
4047 if (value && $(this).is('#model_01ai_select')) {4170 if (value && $(this).is('#model_01ai_select')) {
4048 console.log('01.AI model changed to', value);4171 console.log('01.AI model changed to', value);
4049 oai_settings.zerooneai_model = value;4172 oai_settings.zerooneai_model = value;
@@ -4075,19 +4198,14 @@ async function onModelChange() {
4075 if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) {4198 if (oai_settings.chat_completion_source == chat_completion_sources.MAKERSUITE) {
4076 if (oai_settings.max_context_unlocked) {4199 if (oai_settings.max_context_unlocked) {
4077 $('#openai_max_context').attr('max', max_2mil);4200 $('#openai_max_context').attr('max', max_2mil);
4078 } else if (value.includes('gemini-exp-1114') || value.includes('gemini-exp-1121')) {4201 } else if (value.includes('gemini-exp-1114') || value.includes('gemini-exp-1121') || value.includes('gemini-2.0-flash-thinking-exp-1219')) {
4079 $('#openai_max_context').attr('max', max_32k);4202 $('#openai_max_context').attr('max', max_32k);
4080 } else if (value.includes('gemini-1.5-pro') || value.includes('gemini-exp-1206')) {4203 } else if (value.includes('gemini-1.5-pro') || value.includes('gemini-exp-1206')) {
4081 $('#openai_max_context').attr('max', max_2mil);4204 $('#openai_max_context').attr('max', max_2mil);
4082 } else if (value.includes('gemini-1.5-flash')) {4205 } else if (value.includes('gemini-1.5-flash') || value.includes('gemini-2.0-flash-exp')) {
4083 $('#openai_max_context').attr('max', max_1mil);4206 $('#openai_max_context').attr('max', max_1mil);
4084 } else if (value.includes('gemini-1.0-pro-vision') || value === 'gemini-pro-vision') {
4085 $('#openai_max_context').attr('max', max_16k);
4086 } else if (value.includes('gemini-1.0-pro') || value === 'gemini-pro') {4207 } else if (value.includes('gemini-1.0-pro') || value === 'gemini-pro') {
4087 $('#openai_max_context').attr('max', max_32k);4208 $('#openai_max_context').attr('max', max_32k);
4088 } else if (value === 'text-bison-001') {
4089 $('#openai_max_context').attr('max', max_8k);
4090 // The ultra endpoints are possibly dead:
4091 } else if (value.includes('gemini-1.0-ultra') || value === 'gemini-ultra') {4209 } else if (value.includes('gemini-1.0-ultra') || value === 'gemini-ultra') {
4092 $('#openai_max_context').attr('max', max_32k);4210 $('#openai_max_context').attr('max', max_32k);
4093 } else {4211 } else {
@@ -4209,16 +4327,13 @@ async function onModelChange() {
4209 if (oai_settings.max_context_unlocked) {4327 if (oai_settings.max_context_unlocked) {
4210 $('#openai_max_context').attr('max', unlocked_max);4328 $('#openai_max_context').attr('max', unlocked_max);
4211 }4329 }
4212 else if (['command-light', 'command'].includes(oai_settings.cohere_model)) {4330 else if (['command-light-nightly', 'command-light', 'command'].includes(oai_settings.cohere_model)) {
4213 $('#openai_max_context').attr('max', max_4k);4331 $('#openai_max_context').attr('max', max_4k);
4214 }4332 }
4215 else if (['command-light-nightly', 'command-nightly'].includes(oai_settings.cohere_model)) {4333 else if (oai_settings.cohere_model.includes('command-r') || ['c4ai-aya-23', 'c4ai-aya-expanse-32b', 'command-nightly'].includes(oai_settings.cohere_model)) {
4216 $('#openai_max_context').attr('max', max_8k);
4217 }
4218 else if (oai_settings.cohere_model.includes('command-r') || ['c4ai-aya-expanse-32b'].includes(oai_settings.cohere_model)) {
4219 $('#openai_max_context').attr('max', max_128k);4334 $('#openai_max_context').attr('max', max_128k);
4220 }4335 }
4221 else if (['c4ai-aya-23', 'c4ai-aya-expanse-8b'].includes(oai_settings.cohere_model)) {4336 else if (['c4ai-aya-23-8b', 'c4ai-aya-expanse-8b'].includes(oai_settings.cohere_model)) {
4222 $('#openai_max_context').attr('max', max_8k);4337 $('#openai_max_context').attr('max', max_8k);
4223 }4338 }
4224 else {4339 else {
@@ -4269,7 +4384,7 @@ async function onModelChange() {
4269 else if (oai_settings.groq_model.includes('llama-3.2') && oai_settings.groq_model.includes('-preview')) {4384 else if (oai_settings.groq_model.includes('llama-3.2') && oai_settings.groq_model.includes('-preview')) {
4270 $('#openai_max_context').attr('max', max_8k);4385 $('#openai_max_context').attr('max', max_8k);
4271 }4386 }
4272 else if (oai_settings.groq_model.includes('llama-3.2') || oai_settings.groq_model.includes('llama-3.1')) {4387 else if (oai_settings.groq_model.includes('llama-3.3') || oai_settings.groq_model.includes('llama-3.2') || oai_settings.groq_model.includes('llama-3.1')) {
4273 $('#openai_max_context').attr('max', max_128k);4388 $('#openai_max_context').attr('max', max_128k);
4274 }4389 }
4275 else if (oai_settings.groq_model.includes('llama3-groq')) {4390 else if (oai_settings.groq_model.includes('llama3-groq')) {
@@ -4368,6 +4483,22 @@ async function onModelChange() {
4368 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');4483 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
4369 }4484 }
43704485
4486 if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) {
4487 if (oai_settings.max_context_unlocked) {
4488 $('#openai_max_context').attr('max', unlocked_max);
4489 } else if (oai_settings.deepseek_model == 'deepseek-chat') {
4490 $('#openai_max_context').attr('max', max_64k);
4491 } else if (oai_settings.deepseek_model == 'deepseek-coder') {
4492 $('#openai_max_context').attr('max', max_16k);
4493 } else {
4494 $('#openai_max_context').attr('max', max_64k);
4495 }
4496
4497 oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context);
4498 $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input');
4499 $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input');
4500 }
4501
4371 if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {4502 if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {
4372 oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1);4503 oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1);
4373 $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input');4504 $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input');
@@ -4585,6 +4716,19 @@ async function onConnectButtonClick(e) {
4585 }4716 }
4586 }4717 }
45874718
4719 if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) {
4720 const api_key_deepseek = String($('#api_key_deepseek').val()).trim();
4721
4722 if (api_key_deepseek.length) {
4723 await writeSecret(SECRET_KEYS.DEEPSEEK, api_key_deepseek);
4724 }
4725
4726 if (!secret_state[SECRET_KEYS.DEEPSEEK]) {
4727 console.log('No secret key saved for DeepSeek');
4728 return;
4729 }
4730 }
4731
4588 if (oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) {4732 if (oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) {
4589 const api_key_01ai = String($('#api_key_01ai').val()).trim();4733 const api_key_01ai = String($('#api_key_01ai').val()).trim();
45904734
@@ -4666,6 +4810,9 @@ function toggleChatCompletionForms() {
4666 else if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) {4810 else if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) {
4667 $('#model_blockentropy_select').trigger('change');4811 $('#model_blockentropy_select').trigger('change');
4668 }4812 }
4813 else if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) {
4814 $('#model_deepseek_select').trigger('change');
4815 }
4669 $('[data-source]').each(function () {4816 $('[data-source]').each(function () {
4670 const validSources = $(this).data('source').split(',');4817 const validSources = $(this).data('source').split(',');
4671 $(this).toggle(validSources.includes(oai_settings.chat_completion_source));4818 $(this).toggle(validSources.includes(oai_settings.chat_completion_source));
@@ -4751,6 +4898,8 @@ export function isImageInliningSupported() {
4751 // gultra just isn't being offered as multimodal, thanks google.4898 // gultra just isn't being offered as multimodal, thanks google.
4752 const visionSupportedModels = [4899 const visionSupportedModels = [
4753 'gpt-4-vision',4900 'gpt-4-vision',
4901 'gemini-2.0-flash-thinking-exp-1219',
4902 'gemini-2.0-flash-exp',
4754 'gemini-1.5-flash',4903 'gemini-1.5-flash',
4755 'gemini-1.5-flash-latest',4904 'gemini-1.5-flash-latest',
4756 'gemini-1.5-flash-001',4905 'gemini-1.5-flash-001',
@@ -4769,7 +4918,6 @@ export function isImageInliningSupported() {
4769 'gemini-1.5-pro-002',4918 'gemini-1.5-pro-002',
4770 'gemini-1.5-pro-exp-0801',4919 'gemini-1.5-pro-exp-0801',
4771 'gemini-1.5-pro-exp-0827',4920 'gemini-1.5-pro-exp-0827',
4772 'gemini-pro-vision',
4773 'claude-3',4921 'claude-3',
4774 'claude-3-5',4922 'claude-3-5',
4775 'gpt-4-turbo',4923 'gpt-4-turbo',
@@ -5213,6 +5361,11 @@ export function initOpenAI() {
5213 saveSettingsDebounced();5361 saveSettingsDebounced();
5214 });5362 });
52155363
5364 $('#openrouter_middleout').on('input', function () {
5365 oai_settings.openrouter_middleout = String($(this).val());
5366 saveSettingsDebounced();
5367 });
5368
5216 $('#squash_system_messages').on('input', function () {5369 $('#squash_system_messages').on('input', function () {
5217 oai_settings.squash_system_messages = !!$(this).prop('checked');5370 oai_settings.squash_system_messages = !!$(this).prop('checked');
5218 saveSettingsDebounced();5371 saveSettingsDebounced();
@@ -5323,6 +5476,11 @@ export function initOpenAI() {
5323 saveSettingsDebounced();5476 saveSettingsDebounced();
5324 });5477 });
53255478
5479 $('#openai_show_thoughts').on('input', function () {
5480 oai_settings.show_thoughts = !!$(this).prop('checked');
5481 saveSettingsDebounced();
5482 });
5483
5326 if (!CSS.supports('field-sizing', 'content')) {5484 if (!CSS.supports('field-sizing', 'content')) {
5327 $(document).on('input', '#openai_settings .autoSetHeight', function () {5485 $(document).on('input', '#openai_settings .autoSetHeight', function () {
5328 resetScrollHeight($(this));5486 resetScrollHeight($(this));
@@ -5368,6 +5526,7 @@ export function initOpenAI() {
5368 $('#model_perplexity_select').on('change', onModelChange);5526 $('#model_perplexity_select').on('change', onModelChange);
5369 $('#model_groq_select').on('change', onModelChange);5527 $('#model_groq_select').on('change', onModelChange);
5370 $('#model_nanogpt_select').on('change', onModelChange);5528 $('#model_nanogpt_select').on('change', onModelChange);
5529 $('#model_deepseek_select').on('change', onModelChange);
5371 $('#model_01ai_select').on('change', onModelChange);5530 $('#model_01ai_select').on('change', onModelChange);
5372 $('#model_blockentropy_select').on('change', onModelChange);5531 $('#model_blockentropy_select').on('change', onModelChange);
5373 $('#model_custom_select').on('change', onModelChange);5532 $('#model_custom_select').on('change', onModelChange);
public/scripts/personas.js+68 -2
@@ -21,8 +21,10 @@ import { PAGINATION_TEMPLATE, debounce, delay, download, ensureImageFormatSuppor
21import { debounce_timeout } from './constants.js';21import { debounce_timeout } from './constants.js';
22import { FILTER_TYPES, FilterHelper } from './filters.js';22import { FILTER_TYPES, FilterHelper } from './filters.js';
23import { selected_group } from './group-chats.js';23import { selected_group } from './group-chats.js';
24import { POPUP_RESULT, POPUP_TYPE, Popup } from './popup.js';24import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
25import { t } from './i18n.js';25import { t } from './i18n.js';
26import { openWorldInfoEditor, world_names } from './world-info.js';
27import { renderTemplateAsync } from './templates.js';
2628
27let savePersonasPage = 0;29let savePersonasPage = 0;
28const GRID_STORAGE_KEY = 'Personas_GridView';30const GRID_STORAGE_KEY = 'Personas_GridView';
@@ -375,6 +377,7 @@ export function initPersona(avatarId, personaName, personaDescription) {
375 position: persona_description_positions.IN_PROMPT,377 position: persona_description_positions.IN_PROMPT,
376 depth: DEFAULT_DEPTH,378 depth: DEFAULT_DEPTH,
377 role: DEFAULT_ROLE,379 role: DEFAULT_ROLE,
380 lorebook: '',
378 };381 };
379382
380 saveSettingsDebounced();383 saveSettingsDebounced();
@@ -418,6 +421,7 @@ export async function convertCharacterToPersona(characterId = null) {
418 position: persona_description_positions.IN_PROMPT,421 position: persona_description_positions.IN_PROMPT,
419 depth: DEFAULT_DEPTH,422 depth: DEFAULT_DEPTH,
420 role: DEFAULT_ROLE,423 role: DEFAULT_ROLE,
424 lorebook: '',
421 };425 };
422426
423 // If the user is currently using this persona, update the description427 // If the user is currently using this persona, update the description
@@ -461,6 +465,7 @@ export function setPersonaDescription() {
461 .val(power_user.persona_description_role)465 .val(power_user.persona_description_role)
462 .find(`option[value="${power_user.persona_description_role}"]`)466 .find(`option[value="${power_user.persona_description_role}"]`)
463 .prop('selected', String(true));467 .prop('selected', String(true));
468 $('#persona_lore_button').toggleClass('world_set', !!power_user.persona_description_lorebook);
464 countPersonaDescriptionTokens();469 countPersonaDescriptionTokens();
465}470}
466471
@@ -490,6 +495,7 @@ async function updatePersonaNameIfExists(avatarId, newName) {
490 position: persona_description_positions.IN_PROMPT,495 position: persona_description_positions.IN_PROMPT,
491 depth: DEFAULT_DEPTH,496 depth: DEFAULT_DEPTH,
492 role: DEFAULT_ROLE,497 role: DEFAULT_ROLE,
498 lorebook: '',
493 };499 };
494 console.log(`Created persona name for ${avatarId} as ${newName}`);500 console.log(`Created persona name for ${avatarId} as ${newName}`);
495 }501 }
@@ -535,6 +541,7 @@ async function bindUserNameToPersona(e) {
535 position: isCurrentPersona ? power_user.persona_description_position : persona_description_positions.IN_PROMPT,541 position: isCurrentPersona ? power_user.persona_description_position : persona_description_positions.IN_PROMPT,
536 depth: isCurrentPersona ? power_user.persona_description_depth : DEFAULT_DEPTH,542 depth: isCurrentPersona ? power_user.persona_description_depth : DEFAULT_DEPTH,
537 role: isCurrentPersona ? power_user.persona_description_role : DEFAULT_ROLE,543 role: isCurrentPersona ? power_user.persona_description_role : DEFAULT_ROLE,
544 lorebook: isCurrentPersona ? power_user.persona_description_lorebook : '',
538 };545 };
539 }546 }
540547
@@ -579,12 +586,20 @@ function selectCurrentPersona() {
579 power_user.persona_description_position = descriptor.position ?? persona_description_positions.IN_PROMPT;586 power_user.persona_description_position = descriptor.position ?? persona_description_positions.IN_PROMPT;
580 power_user.persona_description_depth = descriptor.depth ?? DEFAULT_DEPTH;587 power_user.persona_description_depth = descriptor.depth ?? DEFAULT_DEPTH;
581 power_user.persona_description_role = descriptor.role ?? DEFAULT_ROLE;588 power_user.persona_description_role = descriptor.role ?? DEFAULT_ROLE;
589 power_user.persona_description_lorebook = descriptor.lorebook ?? '';
582 } else {590 } else {
583 power_user.persona_description = '';591 power_user.persona_description = '';
584 power_user.persona_description_position = persona_description_positions.IN_PROMPT;592 power_user.persona_description_position = persona_description_positions.IN_PROMPT;
585 power_user.persona_description_depth = DEFAULT_DEPTH;593 power_user.persona_description_depth = DEFAULT_DEPTH;
586 power_user.persona_description_role = DEFAULT_ROLE;594 power_user.persona_description_role = DEFAULT_ROLE;
587 power_user.persona_descriptions[user_avatar] = { description: '', position: persona_description_positions.IN_PROMPT, depth: DEFAULT_DEPTH, role: DEFAULT_ROLE };595 power_user.persona_description_lorebook = '';
596 power_user.persona_descriptions[user_avatar] = {
597 description: '',
598 position: persona_description_positions.IN_PROMPT,
599 depth: DEFAULT_DEPTH,
600 role: DEFAULT_ROLE,
601 lorebook: '',
602 };
588 }603 }
589604
590 setPersonaDescription();605 setPersonaDescription();
@@ -652,6 +667,7 @@ async function lockPersona() {
652 position: persona_description_positions.IN_PROMPT,667 position: persona_description_positions.IN_PROMPT,
653 depth: DEFAULT_DEPTH,668 depth: DEFAULT_DEPTH,
654 role: DEFAULT_ROLE,669 role: DEFAULT_ROLE,
670 lorebook: '',
655 };671 };
656 }672 }
657673
@@ -731,6 +747,7 @@ function onPersonaDescriptionInput() {
731 position: Number($('#persona_description_position').find(':selected').val()),747 position: Number($('#persona_description_position').find(':selected').val()),
732 depth: Number($('#persona_depth_value').val()),748 depth: Number($('#persona_depth_value').val()),
733 role: Number($('#persona_depth_role').find(':selected').val()),749 role: Number($('#persona_depth_role').find(':selected').val()),
750 lorebook: '',
734 };751 };
735 power_user.persona_descriptions[user_avatar] = object;752 power_user.persona_descriptions[user_avatar] = object;
736 }753 }
@@ -766,6 +783,52 @@ function onPersonaDescriptionDepthRoleInput() {
766 saveSettingsDebounced();783 saveSettingsDebounced();
767}784}
768785
786/**
787 * Opens a popup to set the lorebook for the current persona.
788 * @param {PointerEvent} event Click event
789 */
790async function onPersonaLoreButtonClick(event) {
791 const personaName = power_user.personas[user_avatar];
792 const selectedLorebook = power_user.persona_description_lorebook;
793
794 if (!personaName) {
795 toastr.warning(t`You must bind a name to this persona before you can set a lorebook.`, t`Persona name not set`);
796 return;
797 }
798
799 if (event.altKey && selectedLorebook) {
800 openWorldInfoEditor(selectedLorebook);
801 return;
802 }
803
804 const template = $(await renderTemplateAsync('personaLorebook'));
805
806 const worldSelect = template.find('select');
807 template.find('.persona_name').text(personaName);
808
809 for (const worldName of world_names) {
810 const option = document.createElement('option');
811 option.value = worldName;
812 option.innerText = worldName;
813 option.selected = selectedLorebook === worldName;
814 worldSelect.append(option);
815 }
816
817 worldSelect.on('change', function () {
818 power_user.persona_description_lorebook = String($(this).val());
819
820 if (power_user.personas[user_avatar]) {
821 const object = getOrCreatePersonaDescriptor();
822 object.lorebook = power_user.persona_description_lorebook;
823 }
824
825 $('#persona_lore_button').toggleClass('world_set', !!power_user.persona_description_lorebook);
826 saveSettingsDebounced();
827 });
828
829 await callGenericPopup(template, POPUP_TYPE.TEXT);
830}
831
769function onPersonaDescriptionPositionInput() {832function onPersonaDescriptionPositionInput() {
770 power_user.persona_description_position = Number(833 power_user.persona_description_position = Number(
771 $('#persona_description_position').find(':selected').val(),834 $('#persona_description_position').find(':selected').val(),
@@ -789,6 +852,7 @@ function getOrCreatePersonaDescriptor() {
789 position: power_user.persona_description_position,852 position: power_user.persona_description_position,
790 depth: power_user.persona_description_depth,853 depth: power_user.persona_description_depth,
791 role: power_user.persona_description_role,854 role: power_user.persona_description_role,
855 lorebook: power_user.persona_description_lorebook,
792 };856 };
793 power_user.persona_descriptions[user_avatar] = object;857 power_user.persona_descriptions[user_avatar] = object;
794 }858 }
@@ -1038,6 +1102,7 @@ async function duplicatePersona(avatarId) {
1038 position: descriptor?.position ?? persona_description_positions.IN_PROMPT,1102 position: descriptor?.position ?? persona_description_positions.IN_PROMPT,
1039 depth: descriptor?.depth ?? DEFAULT_DEPTH,1103 depth: descriptor?.depth ?? DEFAULT_DEPTH,
1040 role: descriptor?.role ?? DEFAULT_ROLE,1104 role: descriptor?.role ?? DEFAULT_ROLE,
1105 lorebook: descriptor?.lorebook ?? '',
1041 };1106 };
10421107
1043 await uploadUserAvatar(getUserAvatar(avatarId), newAvatarId);1108 await uploadUserAvatar(getUserAvatar(avatarId), newAvatarId);
@@ -1055,6 +1120,7 @@ export function initPersonas() {
1055 $('#persona_description_position').on('input', onPersonaDescriptionPositionInput);1120 $('#persona_description_position').on('input', onPersonaDescriptionPositionInput);
1056 $('#persona_depth_value').on('input', onPersonaDescriptionDepthValueInput);1121 $('#persona_depth_value').on('input', onPersonaDescriptionDepthValueInput);
1057 $('#persona_depth_role').on('input', onPersonaDescriptionDepthRoleInput);1122 $('#persona_depth_role').on('input', onPersonaDescriptionDepthRoleInput);
1123 $('#persona_lore_button').on('click', onPersonaLoreButtonClick);
1058 $('#personas_backup').on('click', onBackupPersonas);1124 $('#personas_backup').on('click', onBackupPersonas);
1059 $('#personas_restore').on('click', () => $('#personas_restore_input').trigger('click'));1125 $('#personas_restore').on('click', () => $('#personas_restore_input').trigger('click'));
1060 $('#personas_restore_input').on('change', onPersonasRestoreInput);1126 $('#personas_restore_input').on('change', onPersonasRestoreInput);
public/scripts/popup.js+2 -2
@@ -75,7 +75,7 @@ const showPopupHelper = {
75 * Asynchronously displays an input popup with the given header and text, and returns the user's input.75 * Asynchronously displays an input popup with the given header and text, and returns the user's input.
76 *76 *
77 * @param {string?} header - The header text for the popup.77 * @param {string?} header - The header text for the popup.
78 * @param {string?} text - The main text for the popup.78 * @param {string?} [text] - The main text for the popup.
79 * @param {string} [defaultValue=''] - The default value for the input field.79 * @param {string} [defaultValue=''] - The default value for the input field.
80 * @param {PopupOptions} [popupOptions={}] - Options for the popup.80 * @param {PopupOptions} [popupOptions={}] - Options for the popup.
81 * @return {Promise<string?>} A Promise that resolves with the user's input.81 * @return {Promise<string?>} A Promise that resolves with the user's input.
@@ -94,7 +94,7 @@ const showPopupHelper = {
94 * Asynchronously displays a confirmation popup with the given header and text, returning the clicked result button value.94 * Asynchronously displays a confirmation popup with the given header and text, returning the clicked result button value.
95 *95 *
96 * @param {string?} header - The header text for the popup.96 * @param {string?} header - The header text for the popup.
97 * @param {string?} text - The main text for the popup.97 * @param {string?} [text] - The main text for the popup.
98 * @param {PopupOptions} [popupOptions={}] - Options for the popup.98 * @param {PopupOptions} [popupOptions={}] - Options for the popup.
99 * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction.99 * @return {Promise<POPUP_RESULT?>} A Promise that resolves with the result of the user's interaction.
100 */100 */
public/scripts/power-user.js+3 -2
@@ -261,6 +261,7 @@ let power_user = {
261 persona_description_position: persona_description_positions.IN_PROMPT,261 persona_description_position: persona_description_positions.IN_PROMPT,
262 persona_description_role: 0,262 persona_description_role: 0,
263 persona_description_depth: 2,263 persona_description_depth: 2,
264 persona_description_lorebook: '',
264 persona_show_notifications: true,265 persona_show_notifications: true,
265 persona_sort_order: 'asc',266 persona_sort_order: 'asc',
266267
@@ -1756,7 +1757,7 @@ async function loadContextSettings() {
1756 } else {1757 } else {
1757 $element.val(power_user.context[control.property]);1758 $element.val(power_user.context[control.property]);
1758 }1759 }
1759 console.log(`Setting ${$element.prop('id')} to ${power_user.context[control.property]}`);1760 console.debug(`Setting ${$element.prop('id')} to ${power_user.context[control.property]}`);
17601761
1761 // If the setting already exists, no need to duplicate it1762 // If the setting already exists, no need to duplicate it
1762 // TODO: Maybe check the power_user object for the setting instead of a flag?1763 // TODO: Maybe check the power_user object for the setting instead of a flag?
@@ -1767,7 +1768,7 @@ async function loadContextSettings() {
1767 } else {1768 } else {
1768 power_user.context[control.property] = value;1769 power_user.context[control.property] = value;
1769 }1770 }
1770 console.log(`Setting ${$element.prop('id')} to ${value}`);1771 console.debug(`Setting ${$element.prop('id')} to ${value}`);
1771 if (!CSS.supports('field-sizing', 'content') && $(this).is('textarea')) {1772 if (!CSS.supports('field-sizing', 'content') && $(this).is('textarea')) {
1772 await resetScrollHeight($(this));1773 await resetScrollHeight($(this));
1773 }1774 }
public/scripts/preset-manager.js+1 -0
@@ -585,6 +585,7 @@ class PresetManager {
585 'openrouter_allow_fallbacks',585 'openrouter_allow_fallbacks',
586 'tabby_model',586 'tabby_model',
587 'derived',587 'derived',
588 'generic_model',
588 ];589 ];
589 const settings = Object.assign({}, getSettingsByApiId(this.apiId));590 const settings = Object.assign({}, getSettingsByApiId(this.apiId));
590591
public/scripts/samplerSelect.js+13 -0
@@ -129,6 +129,10 @@ function setSamplerListListeners() {
129 relatedDOMElement = $('#sampler_priority_block_ooba');129 relatedDOMElement = $('#sampler_priority_block_ooba');
130 }130 }
131131
132 if (samplerName === 'samplers_priorities') { //this is for aphrodite's sampler priority
133 relatedDOMElement = $('#sampler_priority_block_aphrodite');
134 }
135
132 if (samplerName === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?136 if (samplerName === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
133 relatedDOMElement = $('#contrastiveSearchBlock');137 relatedDOMElement = $('#contrastiveSearchBlock');
134 }138 }
@@ -237,6 +241,11 @@ async function listSamplers(main_api, arrayOnly = false) {
237 displayname = 'Ooba Sampler Priority Block';241 displayname = 'Ooba Sampler Priority Block';
238 }242 }
239243
244 if (sampler === 'samplers_priorities') { //this is for aphrodite's sampler priority
245 targetDOMelement = $('#sampler_priority_block_aphrodite');
246 displayname = 'Aphrodite Sampler Priority Block';
247 }
248
240 if (sampler === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?249 if (sampler === 'penalty_alpha') { //contrastive search only has one sampler, does it need its own block?
241 targetDOMelement = $('#contrastiveSearchBlock');250 targetDOMelement = $('#contrastiveSearchBlock');
242 displayname = 'Contrast Search Block';251 displayname = 'Contrast Search Block';
@@ -373,6 +382,10 @@ export async function validateDisabledSamplers(redraw = false) {
373 relatedDOMElement = $('#sampler_priority_block_ooba');382 relatedDOMElement = $('#sampler_priority_block_ooba');
374 }383 }
375384
385 if (sampler === 'samplers_priorities') { //this is for aphrodite's sampler priority
386 relatedDOMElement = $('#sampler_priority_block_aphrodite');
387 }
388
376 if (sampler === 'dry_multiplier') {389 if (sampler === 'dry_multiplier') {
377 relatedDOMElement = $('#dryBlock');390 relatedDOMElement = $('#dryBlock');
378 targetDisplayType = 'block';391 targetDisplayType = 'block';
public/scripts/secrets.js+4 -0
@@ -38,6 +38,8 @@ export const SECRET_KEYS = {
38 NANOGPT: 'api_key_nanogpt',38 NANOGPT: 'api_key_nanogpt',
39 TAVILY: 'api_key_tavily',39 TAVILY: 'api_key_tavily',
40 BFL: 'api_key_bfl',40 BFL: 'api_key_bfl',
41 GENERIC: 'api_key_generic',
42 DEEPSEEK: 'api_key_deepseek',
41};43};
4244
43const INPUT_MAP = {45const INPUT_MAP = {
@@ -71,6 +73,8 @@ const INPUT_MAP = {
71 [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface',73 [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface',
72 [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy',74 [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy',
73 [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt',75 [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt',
76 [SECRET_KEYS.GENERIC]: '#api_key_generic',
77 [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek',
74};78};
7579
76async function clearSecret() {80async function clearSecret() {
public/scripts/slash-commands.js+112 -8
@@ -47,7 +47,7 @@ import {
47} from '../script.js';47} from '../script.js';
48import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';48import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
49import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';49import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';
50import { getMessageTimeStamp } from './RossAscends-mods.js';50import { getMessageTimeStamp, isMobile } from './RossAscends-mods.js';
51import { hideChatMessageRange } from './chats.js';51import { hideChatMessageRange } from './chats.js';
52import { getContext, saveMetadataDebounced } from './extensions.js';52import { getContext, saveMetadataDebounced } from './extensions.js';
53import { getRegexedString, regex_placement } from './extensions/regex/engine.js';53import { getRegexedString, regex_placement } from './extensions/regex/engine.js';
@@ -84,6 +84,25 @@ export const parser = new SlashCommandParser();
84const registerSlashCommand = SlashCommandParser.addCommand.bind(SlashCommandParser);84const registerSlashCommand = SlashCommandParser.addCommand.bind(SlashCommandParser);
85const getSlashCommandsHelp = parser.getHelpString.bind(parser);85const getSlashCommandsHelp = parser.getHelpString.bind(parser);
8686
87/**
88 * Converts a SlashCommandClosure to a filter function that returns a boolean.
89 * @param {SlashCommandClosure} closure
90 * @returns {() => Promise<boolean>}
91 */
92function closureToFilter(closure) {
93 return async () => {
94 try {
95 const localClosure = closure.getCopy();
96 localClosure.onProgress = () => { };
97 const result = await localClosure.execute();
98 return isTrueBoolean(result.pipe);
99 } catch (e) {
100 console.error('Error executing filter closure', e);
101 return false;
102 }
103 };
104}
105
87export function initDefaultSlashCommands() {106export function initDefaultSlashCommands() {
88 SlashCommandParser.addCommandObject(SlashCommand.fromProps({107 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
89 name: '?',108 name: '?',
@@ -1611,6 +1630,13 @@ export function initDefaultSlashCommands() {
1611 new SlashCommandNamedArgument(1630 new SlashCommandNamedArgument(
1612 'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',1631 'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false',
1613 ),1632 ),
1633 SlashCommandNamedArgument.fromProps({
1634 name: 'filter',
1635 description: 'if a filter is defined, an injection will only be performed if the closure returns true',
1636 typeList: [ARGUMENT_TYPE.CLOSURE],
1637 isRequired: false,
1638 acceptsMultiple: false,
1639 }),
1614 ],1640 ],
1615 unnamedArgumentList: [1641 unnamedArgumentList: [
1616 new SlashCommandArgument(1642 new SlashCommandArgument(
@@ -1892,6 +1918,52 @@ export function initDefaultSlashCommands() {
1892 ],1918 ],
1893 helpString: 'Converts the provided string to lowercase.',1919 helpString: 'Converts the provided string to lowercase.',
1894 }));1920 }));
1921 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1922 name: 'substr',
1923 aliases: ['substring'],
1924 callback: (arg, text) => typeof text === 'string' ? text.slice(...[Number(arg.start), arg.end && Number(arg.end)]) : '',
1925 returns: 'substring',
1926 namedArgumentList: [
1927 new SlashCommandNamedArgument(
1928 'start', 'start index', [ARGUMENT_TYPE.NUMBER], false, false,
1929 ),
1930 new SlashCommandNamedArgument(
1931 'end', 'end index', [ARGUMENT_TYPE.NUMBER], false, false,
1932 ),
1933 ],
1934 unnamedArgumentList: [
1935 new SlashCommandArgument(
1936 'string', [ARGUMENT_TYPE.STRING], true, false,
1937 ),
1938 ],
1939 helpString: `
1940 <div>
1941 Extracts text from the provided string.
1942 </div>
1943 <div>
1944 If <code>start</code> is omitted, it's treated as 0.<br />
1945 If <code>start</code> < 0, the index is counted from the end of the string.<br />
1946 If <code>start</code> >= the string's length, an empty string is returned.<br />
1947 If <code>end</code> is omitted, or if <code>end</code> >= the string's length, extracts to the end of the string.<br />
1948 If <code>end</code> < 0, the index is counted from the end of the string.<br />
1949 If <code>end</code> <= <code>start</code> after normalizing negative values, an empty string is returned.
1950 </div>
1951 <div>
1952 <strong>Example:</strong>
1953 <pre>/let x The morning is upon us. || </pre>
1954 <pre>/substr start=-3 {{var::x}} | /echo |/# us. ||</pre>
1955 <pre>/substr start=-3 end=-1 {{var::x}} | /echo |/# us ||</pre>
1956 <pre>/substr end=-1 {{var::x}} | /echo |/# The morning is upon us ||</pre>
1957 <pre>/substr start=4 end=-1 {{var::x}} | /echo |/# morning is upon us ||</pre>
1958 </div>
1959 `,
1960 }));
1961 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
1962 name: 'is-mobile',
1963 callback: () => String(isMobile()),
1964 returns: ARGUMENT_TYPE.BOOLEAN,
1965 helpString: 'Returns true if the current device is a mobile device, false otherwise. Equivalent to <code>{{isMobile}}</code> macro.',
1966 }));
18951967
1896 registerVariableCommands();1968 registerVariableCommands();
1897}1969}
@@ -1901,6 +1973,11 @@ const NARRATOR_NAME_DEFAULT = 'System';
1901export const COMMENT_NAME_DEFAULT = 'Note';1973export const COMMENT_NAME_DEFAULT = 'Note';
1902const SCRIPT_PROMPT_KEY = 'script_inject_';1974const SCRIPT_PROMPT_KEY = 'script_inject_';
19031975
1976/**
1977 * Adds a new script injection to the chat.
1978 * @param {import('./slash-commands/SlashCommand.js').NamedArguments} args Named arguments
1979 * @param {import('./slash-commands/SlashCommand.js').UnnamedArguments} value Unnamed argument
1980 */
1904function injectCallback(args, value) {1981function injectCallback(args, value) {
1905 const positions = {1982 const positions = {
1906 'before': extension_prompt_types.BEFORE_PROMPT,1983 'before': extension_prompt_types.BEFORE_PROMPT,
@@ -1914,8 +1991,8 @@ function injectCallback(args, value) {
1914 'assistant': extension_prompt_roles.ASSISTANT,1991 'assistant': extension_prompt_roles.ASSISTANT,
1915 };1992 };
19161993
1917 const id = args?.id;1994 const id = String(args?.id);
1918 const ephemeral = isTrueBoolean(args?.ephemeral);1995 const ephemeral = isTrueBoolean(String(args?.ephemeral));
19191996
1920 if (!id) {1997 if (!id) {
1921 console.warn('WARN: No ID provided for /inject command');1998 console.warn('WARN: No ID provided for /inject command');
@@ -1931,9 +2008,15 @@ function injectCallback(args, value) {
1931 const depth = isNaN(depthValue) ? defaultDepth : depthValue;2008 const depth = isNaN(depthValue) ? defaultDepth : depthValue;
1932 const roleValue = typeof args?.role === 'string' ? args.role.toLowerCase().trim() : Number(args?.role ?? extension_prompt_roles.SYSTEM);2009 const roleValue = typeof args?.role === 'string' ? args.role.toLowerCase().trim() : Number(args?.role ?? extension_prompt_roles.SYSTEM);
1933 const role = roles[roleValue] ?? roles[extension_prompt_roles.SYSTEM];2010 const role = roles[roleValue] ?? roles[extension_prompt_roles.SYSTEM];
1934 const scan = isTrueBoolean(args?.scan);2011 const scan = isTrueBoolean(String(args?.scan));
2012 const filter = args?.filter instanceof SlashCommandClosure ? args.filter.rawText : null;
2013 const filterFunction = args?.filter instanceof SlashCommandClosure ? closureToFilter(args.filter) : null;
1935 value = value || '';2014 value = value || '';
19362015
2016 if (args?.filter && !String(filter ?? '').trim()) {
2017 throw new Error('Failed to parse the filter argument. Make sure it is a valid non-empty closure.');
2018 }
2019
1937 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;2020 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;
19382021
1939 if (!chat_metadata.script_injects) {2022 if (!chat_metadata.script_injects) {
@@ -1941,13 +2024,13 @@ function injectCallback(args, value) {
1941 }2024 }
19422025
1943 if (value) {2026 if (value) {
1944 const inject = { value, position, depth, scan, role };2027 const inject = { value, position, depth, scan, role, filter };
1945 chat_metadata.script_injects[id] = inject;2028 chat_metadata.script_injects[id] = inject;
1946 } else {2029 } else {
1947 delete chat_metadata.script_injects[id];2030 delete chat_metadata.script_injects[id];
1948 }2031 }
19492032
1950 setExtensionPrompt(prefixedId, value, position, depth, scan, role);2033 setExtensionPrompt(prefixedId, String(value), position, depth, scan, role, filterFunction);
1951 saveMetadataDebounced();2034 saveMetadataDebounced();
19522035
1953 if (ephemeral) {2036 if (ephemeral) {
@@ -1958,7 +2041,7 @@ function injectCallback(args, value) {
1958 }2041 }
1959 console.log('Removing ephemeral script injection', id);2042 console.log('Removing ephemeral script injection', id);
1960 delete chat_metadata.script_injects[id];2043 delete chat_metadata.script_injects[id];
1961 setExtensionPrompt(prefixedId, '', position, depth, scan, role);2044 setExtensionPrompt(prefixedId, '', position, depth, scan, role, filterFunction);
1962 saveMetadataDebounced();2045 saveMetadataDebounced();
1963 deleted = true;2046 deleted = true;
1964 };2047 };
@@ -2053,9 +2136,28 @@ export function processChatSlashCommands() {
2053 }2136 }
20542137
2055 for (const [id, inject] of Object.entries(context.chatMetadata.script_injects)) {2138 for (const [id, inject] of Object.entries(context.chatMetadata.script_injects)) {
2139 /**
2140 * Rehydrates a filter closure from a string.
2141 * @returns {SlashCommandClosure | null}
2142 */
2143 function reviveFilterClosure() {
2144 if (!inject.filter) {
2145 return null;
2146 }
2147
2148 try {
2149 return new SlashCommandParser().parse(inject.filter, true);
2150 } catch (error) {
2151 console.warn('Failed to revive filter closure for script injection', id, error);
2152 return null;
2153 }
2154 }
2155
2056 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;2156 const prefixedId = `${SCRIPT_PROMPT_KEY}${id}`;
2157 const filterClosure = reviveFilterClosure();
2158 const filter = filterClosure ? closureToFilter(filterClosure) : null;
2057 console.log('Adding script injection', id);2159 console.log('Adding script injection', id);
2058 setExtensionPrompt(prefixedId, inject.value, inject.position, inject.depth, inject.scan, inject.role);2160 setExtensionPrompt(prefixedId, inject.value, inject.position, inject.depth, inject.scan, inject.role, filter);
2059 }2161 }
2060}2162}
20612163
@@ -3687,6 +3789,7 @@ function setBackgroundCallback(_, bg) {
3687function getModelOptions(quiet) {3789function getModelOptions(quiet) {
3688 const nullResult = { control: null, options: null };3790 const nullResult = { control: null, options: null };
3689 const modelSelectMap = [3791 const modelSelectMap = [
3792 { id: 'generic_model_textgenerationwebui', api: 'textgenerationwebui', type: textgen_types.GENERIC },
3690 { id: 'custom_model_textgenerationwebui', api: 'textgenerationwebui', type: textgen_types.OOBA },3793 { id: 'custom_model_textgenerationwebui', api: 'textgenerationwebui', type: textgen_types.OOBA },
3691 { id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },3794 { id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },
3692 { id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },3795 { id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },
@@ -3712,6 +3815,7 @@ function getModelOptions(quiet) {
3712 { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT },3815 { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT },
3713 { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI },3816 { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI },
3714 { id: 'model_blockentropy_select', api: 'openai', type: chat_completion_sources.BLOCKENTROPY },3817 { id: 'model_blockentropy_select', api: 'openai', type: chat_completion_sources.BLOCKENTROPY },
3818 { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK },
3715 { id: 'model_novel_select', api: 'novel', type: null },3819 { id: 'model_novel_select', api: 'novel', type: null },
3716 { id: 'horde_model', api: 'koboldhorde', type: null },3820 { id: 'horde_model', api: 'koboldhorde', type: null },
3717 ];3821 ];
public/scripts/sse-stream.js+6 -1
@@ -144,9 +144,14 @@ async function* parseStreamData(json) {
144 for (let j = 0; j < json.candidates[i].content.parts.length; j++) {144 for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
145 if (typeof json.candidates[i].content.parts[j].text === 'string') {145 if (typeof json.candidates[i].content.parts[j].text === 'string') {
146 for (let k = 0; k < json.candidates[i].content.parts[j].text.length; k++) {146 for (let k = 0; k < json.candidates[i].content.parts[j].text.length; k++) {
147 const str = json.candidates[i].content.parts[j].text[k];147 const moreThanOnePart = json.candidates[i].content.parts.length > 1;
148 const isNotLastPart = j !== json.candidates[i].content.parts.length - 1;
149 const isLastSymbol = k === json.candidates[i].content.parts[j].text.length - 1;
150 const addNewline = moreThanOnePart && isNotLastPart && isLastSymbol;
151 const str = json.candidates[i].content.parts[j].text[k] + (addNewline ? '\n\n' : '');
148 const candidateClone = structuredClone(json.candidates[0]);152 const candidateClone = structuredClone(json.candidates[0]);
149 candidateClone.content.parts[j].text = str;153 candidateClone.content.parts[j].text = str;
154 candidateClone.content.parts = [candidateClone.content.parts[j]];
150 const candidates = [candidateClone];155 const candidates = [candidateClone];
151 yield {156 yield {
152 data: { ...json, candidates },157 data: { ...json, candidates },
public/scripts/st-context.js+3 -1
@@ -63,7 +63,7 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '
63import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';63import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
64import { tag_map, tags } from './tags.js';64import { tag_map, tags } from './tags.js';
65import { textgenerationwebui_settings } from './textgen-settings.js';65import { textgenerationwebui_settings } from './textgen-settings.js';
66import { getTokenCount, getTokenCountAsync, getTokenizerModel } from './tokenizers.js';66import { tokenizers, getTextTokens, getTokenCount, getTokenCountAsync, getTokenizerModel } from './tokenizers.js';
67import { ToolManager } from './tool-calling.js';67import { ToolManager } from './tool-calling.js';
68import { timestampToMoment } from './utils.js';68import { timestampToMoment } from './utils.js';
6969
@@ -95,6 +95,8 @@ export function getContext() {
95 sendStreamingRequest,95 sendStreamingRequest,
96 sendGenerationRequest,96 sendGenerationRequest,
97 stopGeneration,97 stopGeneration,
98 tokenizers,
99 getTextTokens,
98 /** @deprecated Use getTokenCountAsync instead */100 /** @deprecated Use getTokenCountAsync instead */
99 getTokenCount,101 getTokenCount,
100 getTokenCountAsync,102 getTokenCountAsync,
public/scripts/templates/changeName.html+1 -1
@@ -1,5 +1,5 @@
1<div class="flex-container">1<div class="flex-container">
2 <h3>2 <h3 data-i18n="Enter a new display name:">
3 Enter a new display name:3 Enter a new display name:
4 </h3>4 </h3>
5</div>5</div>
public/scripts/templates/chatLorebook.html+18 -0
@@ -0,0 +1,18 @@
1<div class="chat_world range-block flexFlowColumn flex-container">
2 <div class="range-block-title">
3 <h4 data-i18n="Chat Lorebook"><!-- This data-i18n attribute is kept for backward compatibility, use the ones below when translating -->
4 <span data-i18n="Chat Lorebook for">Chat Lorebook for</span> <span class="chat_name"></span>
5 </h4>
6 </div>
7 <div class="range-block-counter justifyLeft flex-container flexFlowColumn margin-bot-10px">
8 <span data-i18n="chat_world_template_txt">
9 A selected World Info will be bound to this chat. When generating an AI reply,
10 it will be combined with the entries from global and character lorebooks.
11 </span>
12 </div>
13 <div class="range-block-range wide100p">
14 <select class="chat_world_info_selector wide100p">
15 <option value="">--- None ---</option>
16 </select>
17 </div>
18</div>
public/scripts/templates/createCheckpoint.html+2 -2
@@ -1,8 +1,8 @@
1<div>1<div>
2 <span class="margin-right-10px">Enter Checkpoint Name:</span><small>(Leave empty to auto-generate)</small>2 <span class="margin-right-10px" data-i18n="Enter Checkpoint Name:">Enter Checkpoint Name:</span><small data-i18n="(Leave empty to auto-generate)">(Leave empty to auto-generate)</small>
3</div>3</div>
4{{#if isReplace}}4{{#if isReplace}}
5<div class="m-t-1">5<div class="m-t-1">
6 <small>The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.</small>6 <small data-i18n="The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.">The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.</small>
7</div>7</div>
8{{/if}}8{{/if}}
public/scripts/templates/debug.html+1 -1
@@ -1,6 +1,6 @@
1<div>1<div>
2 <h3 data-i18n="Debug Menu">Debug Menu</h3>2 <h3 data-i18n="Debug Menu">Debug Menu</h3>
3 <div data-i18n="Debug Warning">3 <div data-i18n="Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.">
4 Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.4 Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.
5 </div>5 </div>
6 <table id="debug_table" class="responsiveTable">6 <table id="debug_table" class="responsiveTable">
public/scripts/templates/installExtension.html+8 -5
@@ -1,7 +1,10 @@
1<h3>Enter the Git URL of the extension to install</h3>1<h3 data-i18n="Enter the Git URL of the extension to install">Enter the Git URL of the extension to install</h3>
2<br>2<br>
3<p><b>Disclaimer:</b> Please be aware that using external extensions can have unintended side effects and may pose3<p>
4 security risks. Always make sure you trust the source before importing an extension. We are not responsible for any4 <b data-i18n="Disclaimer:">Disclaimer:</b>
5 damage caused by third-party extensions.</p>5 <span data-i18n="Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.">
6 Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.
7 </span>
8</p>
6<br>9<br>
7<p>Example: <tt> https://github.com/author/extension-name </tt></p>10<p><span data-i18n="Example:">Example:</span> <tt> https://github.com/author/extension-name </tt></p>
public/scripts/templates/itemizationChat.html+25 -25
@@ -1,21 +1,21 @@
1<h3 class="flex-container justifyCenter alignitemscenter">1<h3 class="flex-container justifyCenter alignitemscenter">
2 Prompt Itemization2 <span data-i18n="Prompt Itemization">Prompt Itemization</span>
3 <div id="showRawPrompt" class="fa-solid fa-square-poll-horizontal menu_button" title="Show Raw Prompt" data-i18n="[title]Show Raw Prompt"></div>3 <div id="showRawPrompt" class="fa-solid fa-square-poll-horizontal menu_button" title="Show Raw Prompt" data-i18n="[title]Show Raw Prompt"></div>
4 <div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div>4 <div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div>
5 <div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div>5 <div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div>
6</h3>6</h3>
7<div>7<div>
8 <div>8 <div>
9 API/Model: {{mainApiFriendlyName}} {{#if apiUsed}}({{apiUsed}}){{/if}} {{#if modelUsed}}&ndash; {{modelUsed}}{{/if}}9 <span data-i18n="API/Model:">API/Model:</span> {{mainApiFriendlyName}} {{#if apiUsed}}({{apiUsed}}){{/if}} {{#if modelUsed}}&ndash; {{modelUsed}}{{/if}}
10 </div>10 </div>
11 <div>11 <div>
12 <small>Preset: {{presetName}}</small>12 <small><span data-i18n="Preset:">Preset:</span> {{presetName}}</small>
13 <span>|</span>13 <span>|</span>
14 <small>Tokenizer: {{selectedTokenizer}}</small>14 <small><span data-i18n="Tokenizer:">Tokenizer:</span> {{selectedTokenizer}}</small>
15 </div>15 </div>
16</div>16</div>
1717
18<span class="tokenItemizingSubclass">18<span class="tokenItemizingSubclass" data-i18n="Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.">
19 Only the white numbers really matter. All numbers are estimates.19 Only the white numbers really matter. All numbers are estimates.
20 Grey color items may not have been included in the context due to certain prompt format settings.20 Grey color items may not have been included in the context due to certain prompt format settings.
21</span>21</span>
@@ -37,12 +37,12 @@
37 <div class="flex-container wide50p">37 <div class="flex-container wide50p">
38 <div class="wide100p flex-container flexNoGap flexFlowColumn">38 <div class="wide100p flex-container flexNoGap flexFlowColumn">
39 <div class="flex-container wide100p">39 <div class="flex-container wide100p">
40 <div class="flex1" style="color: grey;">System Info:</div>40 <div class="flex1" style="color: grey;"><span data-i18n="System Info:">System Info:</span></div>
41 <div class=""> {{oaiSystemTokens}}</div>41 <div class="">{{oaiSystemTokens}}</div>
42 </div>42 </div>
43 <div class="flex-container ">43 <div class="flex-container ">
44 <div class=" flex1 tokenItemizingSubclass">-- Chat Start: </div>44 <div class=" flex1 tokenItemizingSubclass">-- Chat Start: </div>
45 <div class="tokenItemizingSubclass"> {{oaiStartTokens}}</div>45 <div class="tokenItemizingSubclass">{{oaiStartTokens}}</div>
46 </div>46 </div>
47 <div class="flex-container ">47 <div class="flex-container ">
48 <div class=" flex1 tokenItemizingSubclass">-- Main: </div>48 <div class=" flex1 tokenItemizingSubclass">-- Main: </div>
@@ -67,8 +67,8 @@
67 </div>67 </div>
68 <div class="wide100p flex-container flexNoGap flexFlowColumn">68 <div class="wide100p flex-container flexNoGap flexFlowColumn">
69 <div class="flex-container wide100p">69 <div class="flex-container wide100p">
70 <div class="flex1" style="color: indianred;">Prompt Tokens:</div>70 <div class="flex1" style="color: indianred;"><span data-i18n="Prompt Tokens:">Prompt Tokens:</span></div>
71 <div class=""> {{oaiPromptTokens}}</div>71 <div class="">{{oaiPromptTokens}}</div>
72 </div>72 </div>
73 <div class="flex-container ">73 <div class="flex-container ">
74 <div class=" flex1 tokenItemizingSubclass">-- Description: </div>74 <div class=" flex1 tokenItemizingSubclass">-- Description: </div>
@@ -76,7 +76,7 @@
76 </div>76 </div>
77 <div class="flex-container ">77 <div class="flex-container ">
78 <div class=" flex1 tokenItemizingSubclass">-- Personality:</div>78 <div class=" flex1 tokenItemizingSubclass">-- Personality:</div>
79 <div class="tokenItemizingSubclass"> {{charPersonalityTokens}}</div>79 <div class="tokenItemizingSubclass">{{charPersonalityTokens}}</div>
80 </div>80 </div>
81 <div class="flex-container ">81 <div class="flex-container ">
82 <div class=" flex1 tokenItemizingSubclass">-- Scenario: </div>82 <div class=" flex1 tokenItemizingSubclass">-- Scenario: </div>
@@ -84,24 +84,24 @@
84 </div>84 </div>
85 <div class="flex-container ">85 <div class="flex-container ">
86 <div class=" flex1 tokenItemizingSubclass">-- Examples:</div>86 <div class=" flex1 tokenItemizingSubclass">-- Examples:</div>
87 <div class="tokenItemizingSubclass"> {{examplesStringTokens}}</div>87 <div class="tokenItemizingSubclass">{{examplesStringTokens}}</div>
88 </div>88 </div>
89 <div class="flex-container ">89 <div class="flex-container ">
90 <div class=" flex1 tokenItemizingSubclass">-- User Persona:</div>90 <div class=" flex1 tokenItemizingSubclass">-- User Persona:</div>
91 <div class="tokenItemizingSubclass"> {{userPersonaStringTokens}}</div>91 <div class="tokenItemizingSubclass">{{userPersonaStringTokens}}</div>
92 </div>92 </div>
93 </div>93 </div>
94 <div class="wide100p flex-container">94 <div class="wide100p flex-container">
95 <div class="flex1" style="color: gold;">World Info:</div>95 <div class="flex1" style="color: gold;"><span data-i18n="World Info:">World Info:</span></div>
96 <div class="">{{worldInfoStringTokens}}</div>96 <div class="">{{worldInfoStringTokens}}</div>
97 </div>97 </div>
98 <div class="wide100p flex-container">98 <div class="wide100p flex-container">
99 <div class="flex1" style="color: palegreen;">Chat History:</div>99 <div class="flex1" style="color: palegreen;"><span data-i18n="Chat History:">Chat History:</span></div>
100 <div class=""> {{ActualChatHistoryTokens}}</div>100 <div class="">{{ActualChatHistoryTokens}}</div>
101 </div>101 </div>
102 <div class="wide100p flex-container flexNoGap flexFlowColumn">102 <div class="wide100p flex-container flexNoGap flexFlowColumn">
103 <div class="wide100p flex-container">103 <div class="wide100p flex-container">
104 <div class="flex1" style="color: cornflowerblue;">Extensions:</div>104 <div class="flex1" style="color: cornflowerblue;"><span data-i18n="Extensions:">Extensions:</span></div>
105 <div class="">{{allAnchorsTokens}}</div>105 <div class="">{{allAnchorsTokens}}</div>
106 </div>106 </div>
107 <div class="flex-container ">107 <div class="flex-container ">
@@ -110,23 +110,23 @@
110 </div>110 </div>
111 <div class="flex-container ">111 <div class="flex-container ">
112 <div class=" flex1 tokenItemizingSubclass">-- Author's Note:</div>112 <div class=" flex1 tokenItemizingSubclass">-- Author's Note:</div>
113 <div class="tokenItemizingSubclass"> {{authorsNoteStringTokens}}</div>113 <div class="tokenItemizingSubclass">{{authorsNoteStringTokens}}</div>
114 </div>114 </div>
115 <div class="flex-container ">115 <div class="flex-container ">
116 <div class=" flex1 tokenItemizingSubclass">-- Smart Context:</div>116 <div class=" flex1 tokenItemizingSubclass">-- Smart Context:</div>
117 <div class="tokenItemizingSubclass"> {{smartContextStringTokens}}</div>117 <div class="tokenItemizingSubclass">{{smartContextStringTokens}}</div>
118 </div>118 </div>
119 <div class="flex-container ">119 <div class="flex-container ">
120 <div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Chats):</div>120 <div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Chats):</div>
121 <div class="tokenItemizingSubclass"> {{chatVectorsStringTokens}}</div>121 <div class="tokenItemizingSubclass">{{chatVectorsStringTokens}}</div>
122 </div>122 </div>
123 <div class="flex-container ">123 <div class="flex-container ">
124 <div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Data Bank):</div>124 <div class=" flex1 tokenItemizingSubclass">-- Vector Storage (Data Bank):</div>
125 <div class="tokenItemizingSubclass"> {{dataBankVectorsStringTokens}}</div>125 <div class="tokenItemizingSubclass">{{dataBankVectorsStringTokens}}</div>
126 </div>126 </div>
127 </div>127 </div>
128 <div class="wide100p flex-container">128 <div class="wide100p flex-container">
129 <div class="flex1" style="color: mediumpurple;">&lcub;&lcub;&rcub;&rcub; Bias:</div>129 <div class="flex1" style="color: mediumpurple;"><span>&lcub;&lcub;&rcub;&rcub;</span> <span data-i18n="Bias:">Bias:</span></div>
130 <div class="">{{oaiBiasTokens}}</div>130 <div class="">{{oaiBiasTokens}}</div>
131 </div>131 </div>
132 </div>132 </div>
@@ -135,11 +135,11 @@
135 <hr>135 <hr>
136 <div class="wide100p flex-container flexFlowColumns">136 <div class="wide100p flex-container flexFlowColumns">
137 <div class="flex-container wide100p">137 <div class="flex-container wide100p">
138 <div class="flex1">Total Tokens in Prompt:</div>138 <div class="flex1"><span data-i18n="Total Tokens in Prompt:">Total Tokens in Prompt:</span></div>
139 <div class=""> {{finalPromptTokens}}</div>139 <div class="">{{finalPromptTokens}}</div>
140 </div>140 </div>
141 <div class="flex-container wide100p">141 <div class="flex-container wide100p">
142 <div class="flex1">Max Context (Context Size - Response Length):</div>142 <div class="flex1"><span data-i18n="Max Context">Max Context</span>&nbsp;<small data-i18n="(Context Size - Response Length)">(Context Size - Response Length)</small><span data-i18n=":">:</span></div>
143 <div class="">{{thisPrompt_max_context}}</div>143 <div class="">{{thisPrompt_max_context}}</div>
144 </div>144 </div>
145 </div>145 </div>
public/scripts/templates/macros.html+1 -0
@@ -48,6 +48,7 @@
48 <li><tt>&lcub;&lcub;random::(arg1)::(arg2)&rcub;&rcub;</tt> – <span data-i18n="help_macros_38">alternative syntax for random that allows to use commas in the list items.</span></li>48 <li><tt>&lcub;&lcub;random::(arg1)::(arg2)&rcub;&rcub;</tt> – <span data-i18n="help_macros_38">alternative syntax for random that allows to use commas in the list items.</span></li>
49 <li><tt>&lcub;&lcub;pick::(args)&rcub;&rcub;</tt> – <span data-i18n="help_macros_39">picks a random item from the list. Works the same as &lcub;&lcub;random&rcub;&rcub;, with the same possible syntax options, but the pick will stay consistent for this chat once picked and won't be re-rolled on consecutive messages and prompt processing.</span></li>49 <li><tt>&lcub;&lcub;pick::(args)&rcub;&rcub;</tt> – <span data-i18n="help_macros_39">picks a random item from the list. Works the same as &lcub;&lcub;random&rcub;&rcub;, with the same possible syntax options, but the pick will stay consistent for this chat once picked and won't be re-rolled on consecutive messages and prompt processing.</span></li>
50 <li><tt>&lcub;&lcub;banned "text here"&rcub;&rcub;</tt> – <span data-i18n="help_macros_40">dynamically add text in the quotes to banned words sequences, if Text Generation WebUI backend used. Do nothing for others backends. Can be used anywhere (Character description, WI, AN, etc.) Quotes around the text are important.</span></li>50 <li><tt>&lcub;&lcub;banned "text here"&rcub;&rcub;</tt> – <span data-i18n="help_macros_40">dynamically add text in the quotes to banned words sequences, if Text Generation WebUI backend used. Do nothing for others backends. Can be used anywhere (Character description, WI, AN, etc.) Quotes around the text are important.</span></li>
51 <li><tt>&lcub;&lcub;isMobile&rcub;&rcub;</tt> – <span data-i18n="help_macros_isMobile">"true" if currently running in a mobile environment, "false" otherwise</span></li>
51</ul>52</ul>
52<div data-i18n="Instruct Mode and Context Template Macros:">53<div data-i18n="Instruct Mode and Context Template Macros:">
53 Instruct Mode and Context Template Macros:54 Instruct Mode and Context Template Macros:
public/scripts/templates/masterExport.html+1 -1
@@ -1,4 +1,4 @@
1<h3>1<h3 data-i18n="Choose what to export">
2 Choose what to export2 Choose what to export
3</h3>3</h3>
4<div class="flex-container flexFlowColumn justifyLeft">4<div class="flex-container flexFlowColumn justifyLeft">
public/scripts/templates/masterImport.html+1 -1
@@ -1,4 +1,4 @@
1<h3>1<h3 data-i18n="Choose what to import">
2 Choose what to import2 Choose what to import
3</h3>3</h3>
4<div class="flex-container flexFlowColumn justifyLeft">4<div class="flex-container flexFlowColumn justifyLeft">
public/scripts/templates/personaLorebook.html+18 -0
@@ -0,0 +1,18 @@
1<div class="persona_world range-block flexFlowColumn flex-container">
2 <div class="range-block-title">
3 <h4>
4 <span data-i18n="Persona Lorebook for">Persona Lorebook for</span> <span class="persona_name"></span>
5 </h4>
6 </div>
7 <div class="range-block-counter justifyLeft flex-container flexFlowColumn margin-bot-10px">
8 <span data-i18n="persona_world_template_txt">
9 A selected World Info will be bound to this persona. When generating an AI reply,
10 it will be combined with the entries from global, character and chat lorebooks.
11 </span>
12 </div>
13 <div class="range-block-range wide100p">
14 <select class="persona_world_info_selector wide100p">
15 <option value="">--- None ---</option>
16 </select>
17 </div>
18</div>
public/scripts/templates/resetSettings.html+1 -1
@@ -6,7 +6,7 @@
6 Don't forget to save a snapshot of your settings before proceeding.6 Don't forget to save a snapshot of your settings before proceeding.
7 </div>7 </div>
8 <hr>8 <hr>
9 <div>9 <div data-i18n="Enter your password below to confirm:">
10 Enter your password below to confirm:10 Enter your password below to confirm:
11 </div>11 </div>
12 <input id="resetSettingsPassword" name="password" type="password" class="text_pole" placeholder="Password">12 <input id="resetSettingsPassword" name="password" type="password" class="text_pole" placeholder="Password">
public/scripts/templates/scenarioOverride.html+4 -4
@@ -5,10 +5,10 @@
5 class="menu_button fa-solid fa-trash-can remove_scenario_override"></div>5 class="menu_button fa-solid fa-trash-can remove_scenario_override"></div>
6 </div>6 </div>
7 <div class="range-block-counter justifyLeft flex-container flexFlowColumn">7 <div class="range-block-counter justifyLeft flex-container flexFlowColumn">
8 <strong>Unique to this chat.</strong>8 <strong data-i18n="Unique to this chat.">Unique to this chat.</strong>
9 <span data-group="true">All group members will use the following scenario text instead of what is specified in their character cards.</span>9 <span data-group="true" data-i18n="All group members will use the following scenario text instead of what is specified in their character cards.">All group members will use the following scenario text instead of what is specified in their character cards.</span>
10 <span data-character="true">The following scenario text will be used instead of the value set in the character card.</span>10 <span data-character="true" data-i18n="The following scenario text will be used instead of the value set in the character card.">The following scenario text will be used instead of the value set in the character card.</span>
11 Checkpoints inherit the scenario override from their parent, and can be changed individually after that.11 <span data-i18n="Checkpoints inherit the scenario override from their parent, and can be changed individually after that.">Checkpoints inherit the scenario override from their parent, and can be changed individually after that.</span>
12 </div>12 </div>
13 <div class="range-block-range wide100p">13 <div class="range-block-range wide100p">
14 <textarea class="wide100p chat_scenario" class="text_pole" rows="15" data-i18n="[placeholder]Type here..."14 <textarea class="wide100p chat_scenario" class="text_pole" rows="15" data-i18n="[placeholder]Type here..."
public/scripts/templates/tagManagement.html+5 -5
@@ -20,14 +20,14 @@
20 <small>20 <small>
21 <span data-i18n="Drag handle to reorder. Click name to rename. Click color to change display.">Drag handle to reorder. Click name to rename. Click color to change display.</span><br>21 <span data-i18n="Drag handle to reorder. Click name to rename. Click color to change display.">Drag handle to reorder. Click name to rename. Click color to change display.</span><br>
22 {{#if bogus_folders}}<span data-i18n="Click on the folder icon to use this tag as a folder.">Click on the folder icon to use this tag as a folder.</span><br>{{/if}}22 {{#if bogus_folders}}<span data-i18n="Click on the folder icon to use this tag as a folder.">Click on the folder icon to use this tag as a folder.</span><br>{{/if}}
23 <label class="checkbox flex-container alignitemscenter flexNoGap m-t-1" for="auto_sort_tags">23 <label class="checkbox_label flex-container alignItemsCenter m-t-1" for="auto_sort_tags">
24 <input type="checkbox" id="auto_sort_tags" name="auto_sort_tags" {{#if auto_sort_tags}} checked{{/if}} />24 <input type="checkbox" id="auto_sort_tags" name="auto_sort_tags" {{#if auto_sort_tags}} checked{{/if}} />
25 <span data-i18n="Use alphabetical sorting">25 <span data-i18n="Use alphabetical sorting">
26 Use alphabetical sorting26 Use alphabetical sorting
27 </span>27 </span>
28 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]tags_sorting_desc"28 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]tags_sorting_desc"
29 title="If enabled, tags will automatically be sorted alphabetically on creation or rename.\nIf disabled, new tags will be appended at the end.\n\nIf a tag is manually reordered by dragging, automatic sorting will be disabled.">29 title="If enabled, tags will automatically be sorted alphabetically on creation or rename.&#10;If disabled, new tags will be appended at the end.&#10;&#10;If a tag is manually reordered by dragging, automatic sorting will be disabled.">
30 </div>30 </div>
31 </label>31 </label>
32 </small>32 </small>
33 </div>
33 \ No newline at end of file \ No newline at end of file
33 </div>
public/scripts/templates/themeDelete.html+2 -1
@@ -1,3 +1,4 @@
1<div>1<div>
2 Are you sure you want to delete the theme "{{themeName}}"?2 <div data-i18n="Are you sure you want to delete the theme?">Are you sure you want to delete the theme?</div>
3 <b>"{{themeName}}"<b>
3</div>4</div>
public/scripts/templates/userReset.html+3 -2
@@ -1,12 +1,13 @@
1<form action="javascript:void(0);" class="flex-container flexFlowColumn">1<form action="javascript:void(0);" class="flex-container flexFlowColumn">
2 <h3 class="neutral_warning">2 <h3 class="neutral_warning" data-i18n="This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.">
3 This will delete all your settings and data. There will be no undo button.3 This will delete all your settings and data. There will be no undo button.
4 Make sure you have a backup before proceeding.4 Make sure you have a backup before proceeding.
5 </h3>5 </h3>
6 <hr>6 <hr>
7 <div>7 <div data-i18n="Account reset code has been posted to the server console.">
8 Account reset code has been posted to the server console.8 Account reset code has been posted to the server console.
9 </div>9 </div>
10 <br>
10 <div class="currentPasswordBlock">11 <div class="currentPasswordBlock">
11 <label data-i18n="Current Password:" for="user">Current Password:</label>12 <label data-i18n="Current Password:" for="user">Current Password:</label>
12 <input type="password" name="password" class="text_pole" placeholder="[ No password ]" autocomplete="current-password">13 <input type="password" name="password" class="text_pole" placeholder="[ No password ]" autocomplete="current-password">
public/scripts/templates/wandButton.html+1 -1
@@ -1 +1 @@
1<div id="extensionsMenuButton" style="display: none;" class="fa-solid fa-magic-wand-sparkles interactable" title="Extensions" /></div>1<div id="extensionsMenuButton" style="display: none;" class="fa-solid fa-magic-wand-sparkles interactable" title="Extensions" data-i18n="[title]Extensions" /></div>
public/scripts/textgen-models.js+3 -0
@@ -25,6 +25,7 @@ const OPENROUTER_PROVIDERS = [
25 'Anthropic',25 'Anthropic',
26 'Google',26 'Google',
27 'Google AI Studio',27 'Google AI Studio',
28 'Amazon Bedrock',
28 'Groq',29 'Groq',
29 'SambaNova',30 'SambaNova',
30 'Cohere',31 'Cohere',
@@ -50,6 +51,8 @@ const OPENROUTER_PROVIDERS = [
50 'Featherless',51 'Featherless',
51 'Inflection',52 'Inflection',
52 'xAI',53 'xAI',
54 'Cloudflare',
55 'SF Compute',
53 '01.AI',56 '01.AI',
54 'HuggingFace',57 'HuggingFace',
55 'Mancer',58 'Mancer',
@@ -160,6 +163,24 @@ export async function loadInfermaticAIModels(data) {
160 }163 }
public/scripts/textgen-settings.js+0 -0
public/scripts/tokenizers.js+0 -0
public/scripts/tool-calling.js+0 -0
public/scripts/user.js+0 -0
public/scripts/utils.js+0 -0
public/scripts/variables.js+0 -0
public/scripts/world-info.js+0 -0
public/style.css+0 -0
src/additional-headers.js+0 -0
src/constants.js+0 -0
src/endpoints/backends/chat-completions.js+0 -0
src/endpoints/backends/text-completions.js+0 -0
src/endpoints/characters.js+0 -0
src/endpoints/chats.js+0 -0
src/endpoints/extensions.js+0 -0
src/endpoints/novelai.js+0 -0
src/endpoints/secrets.js+0 -0
src/endpoints/sprites.js+0 -0
src/endpoints/stable-diffusion.js+0 -0
src/endpoints/tokenizers.js+0 -0
src/endpoints/translate.js+0 -0
src/endpoints/users-private.js+0 -0
src/prompt-converters.js+0 -0
src/users.js+0 -0
src/util.js+0 -0
Diff truncated