Merge pull request #4516 from SillyTavern/staging Staging
Signed| @@ -54,4 +54,4 @@ public/scripts/extensions/third-party | |||
| 54 | .aider* | 54 | .aider* |
| 55 | .env | 55 | .env |
| 56 | /StartDev.bat | 56 | /StartDev.bat |
| 57 | 57 | yarn.lock | |
| @@ -40,9 +40,15 @@ browserLaunch: | |||
| 40 | port: 8000 | 40 | port: 8000 |
| 41 | # -- SSL options -- | 41 | # -- SSL options -- |
| 42 | ssl: | 42 | ssl: |
| 43 | # Enable SSL/TLS encryption | ||
| 43 | enabled: false | 44 | enabled: false |
| 45 | # Path to certificate (relative to server root) | ||
| 44 | certPath: "./certs/cert.pem" | 46 | certPath: "./certs/cert.pem" |
| 47 | # Path to private key (relative to server root) | ||
| 45 | keyPath: "./certs/privkey.pem" | 48 | keyPath: "./certs/privkey.pem" |
| 49 | # Private key passphrase (leave empty if not needed) | ||
| 50 | # For better security, use a CLI argument or an environment variable (SILLYTAVERN_SSL_KEYPASSPHRASE) | ||
| 51 | keyPassphrase: "" | ||
| 46 | # -- SECURITY CONFIGURATION -- | 52 | # -- SECURITY CONFIGURATION -- |
| 47 | # Toggle whitelist mode | 53 | # Toggle whitelist mode |
| 48 | whitelistMode: true | 54 | whitelistMode: true |
| @@ -88,6 +94,18 @@ autheliaAuth: false | |||
| 88 | # the username and passwords for basic auth are the same as those | 94 | # the username and passwords for basic auth are the same as those |
| 89 | # for the individual accounts | 95 | # for the individual accounts |
| 90 | perUserBasicAuth: false | 96 | perUserBasicAuth: false |
| 97 | # Host whitelist configuration. Recommended if you're using a listen mode | ||
| 98 | hostWhitelist: | ||
| 99 | # Enable or disable host whitelisting | ||
| 100 | enabled: false | ||
| 101 | # Scan incoming requests for potential host header spoofing | ||
| 102 | scan: true | ||
| 103 | # List of allowed hosts. Do not include localhost or IPs, these are safe. | ||
| 104 | # Use a dot to create subdomain patterns. | ||
| 105 | # Examples: | ||
| 106 | # - example.com | ||
| 107 | # - .trycloudflare.com | ||
| 108 | hosts: [] | ||
| 91 | 109 | ||
| 92 | # User session timeout *in seconds* (defaults to 24 hours). | 110 | # User session timeout *in seconds* (defaults to 24 hours). |
| 93 | ## Set to a positive number to expire session after a certain time of inactivity | 111 | ## Set to a positive number to expire session after a certain time of inactivity |
| @@ -0,0 +1,21 @@ | |||
| 1 | <!DOCTYPE html> | ||
| 2 | <html> | ||
| 3 | |||
| 4 | <head> | ||
| 5 | <title>Forbidden</title> | ||
| 6 | </head> | ||
| 7 | |||
| 8 | <body> | ||
| 9 | <h1>Forbidden</h1> | ||
| 10 | <p> | ||
| 11 | If you are the system administrator, add the hostname you are accessing from to the | ||
| 12 | host whitelist, or disable host whitelisting in the | ||
| 13 | <code>config.yaml</code> file located in the root directory of your installation. | ||
| 14 | </p> | ||
| 15 | <hr /> | ||
| 16 | <p> | ||
| 17 | <em>Access from this host is not allowed. This attempt has been logged.</em> | ||
| 18 | </p> | ||
| 19 | </body> | ||
| 20 | |||
| 21 | </html> | ||
| @@ -1,16 +1,16 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "sillytavern", | 2 | "name": "sillytavern", |
| 3 | "version": "1.13.3", | 3 | "version": "1.13.4", |
| 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.13.3", | 9 | "version": "1.13.4", |
| 10 | "hasInstallScript": true, | 10 | "hasInstallScript": true, |
| 11 | "license": "AGPL-3.0", | 11 | "license": "AGPL-3.0", |
| 12 | "dependencies": { | 12 | "dependencies": { |
| 13 | "@adobe/css-tools": "^4.4.3", | 13 | "@adobe/css-tools": "^4.4.4", |
| 14 | "@agnai/sentencepiece-js": "^1.1.1", | 14 | "@agnai/sentencepiece-js": "^1.1.1", |
| 15 | "@agnai/web-tokenizers": "^0.1.3", | 15 | "@agnai/web-tokenizers": "^0.1.3", |
| 16 | "@iconfu/svg-inject": "^1.2.3", | 16 | "@iconfu/svg-inject": "^1.2.3", |
| @@ -42,9 +42,9 @@ | |||
| 42 | "archiver": "^7.0.1", | 42 | "archiver": "^7.0.1", |
| 43 | "bing-translate-api": "^4.1.0", | 43 | "bing-translate-api": "^4.1.0", |
| 44 | "body-parser": "^1.20.2", | 44 | "body-parser": "^1.20.2", |
| 45 | "bowser": "^2.11.0", | 45 | "bowser": "^2.12.1", |
| 46 | "bytes": "^3.1.2", | 46 | "bytes": "^3.1.2", |
| 47 | "chalk": "^5.4.1", | 47 | "chalk": "^5.6.0", |
| 48 | "command-exists": "^1.2.9", | 48 | "command-exists": "^1.2.9", |
| 49 | "compression": "^1.8.1", | 49 | "compression": "^1.8.1", |
| 50 | "cookie-parser": "^1.4.6", | 50 | "cookie-parser": "^1.4.6", |
| @@ -64,6 +64,7 @@ | |||
| 64 | "handlebars": "^4.7.8", | 64 | "handlebars": "^4.7.8", |
| 65 | "helmet": "^8.1.0", | 65 | "helmet": "^8.1.0", |
| 66 | "highlight.js": "^11.11.1", | 66 | "highlight.js": "^11.11.1", |
| 67 | "host-validation-middleware": "^0.1.1", | ||
| 67 | "html-entities": "^2.6.0", | 68 | "html-entities": "^2.6.0", |
| 68 | "iconv-lite": "^0.6.3", | 69 | "iconv-lite": "^0.6.3", |
| 69 | "ip-matching": "^2.1.2", | 70 | "ip-matching": "^2.1.2", |
| @@ -74,7 +75,7 @@ | |||
| 74 | "lodash": "^4.17.21", | 75 | "lodash": "^4.17.21", |
| 75 | "mime-types": "^3.0.1", | 76 | "mime-types": "^3.0.1", |
| 76 | "moment": "^2.30.1", | 77 | "moment": "^2.30.1", |
| 77 | "morphdom": "^2.7.5", | 78 | "morphdom": "^2.7.7", |
| 78 | "multer": "^2.0.2", | 79 | "multer": "^2.0.2", |
| 79 | "node-fetch": "^3.3.2", | 80 | "node-fetch": "^3.3.2", |
| 80 | "node-persist": "^4.0.4", | 81 | "node-persist": "^4.0.4", |
| @@ -90,14 +91,14 @@ | |||
| 90 | "sillytavern-transformers": "2.14.6", | 91 | "sillytavern-transformers": "2.14.6", |
| 91 | "simple-git": "^3.28.0", | 92 | "simple-git": "^3.28.0", |
| 92 | "slidetoggle": "^4.0.0", | 93 | "slidetoggle": "^4.0.0", |
| 93 | "tiktoken": "^1.0.21", | 94 | "tiktoken": "^1.0.22", |
| 94 | "url-join": "^5.0.0", | 95 | "url-join": "^5.0.0", |
| 95 | "vectra": "^0.2.2", | 96 | "vectra": "^0.2.2", |
| 96 | "wavefile": "^11.0.0", | 97 | "wavefile": "^11.0.0", |
| 97 | "webpack": "^5.98.0", | 98 | "webpack": "^5.98.0", |
| 98 | "write-file-atomic": "^5.0.1", | 99 | "write-file-atomic": "^5.0.1", |
| 99 | "ws": "^8.18.3", | 100 | "ws": "^8.18.3", |
| 100 | "yaml": "^2.8.0", | 101 | "yaml": "^2.8.1", |
| 101 | "yargs": "^17.7.1", | 102 | "yargs": "^17.7.1", |
| 102 | "yauzl": "^3.2.0" | 103 | "yauzl": "^3.2.0" |
| 103 | }, | 104 | }, |
| @@ -114,7 +115,7 @@ | |||
| 114 | "@types/cors": "^2.8.19", | 115 | "@types/cors": "^2.8.19", |
| 115 | "@types/deno": "^2.3.0", | 116 | "@types/deno": "^2.3.0", |
| 116 | "@types/express": "^4.17.23", | 117 | "@types/express": "^4.17.23", |
| 117 | "@types/jquery": "^3.5.32", | 118 | "@types/jquery": "^3.5.33", |
| 118 | "@types/jquery-cropper": "^1.0.4", | 119 | "@types/jquery-cropper": "^1.0.4", |
| 119 | "@types/jquery.transit": "^0.9.33", | 120 | "@types/jquery.transit": "^0.9.33", |
| 120 | "@types/jqueryui": "^1.12.24", | 121 | "@types/jqueryui": "^1.12.24", |
| @@ -149,9 +150,9 @@ | |||
| 149 | } | 150 | } |
| 150 | }, | 151 | }, |
| 151 | "node_modules/@adobe/css-tools": { | 152 | "node_modules/@adobe/css-tools": { |
| 152 | "version": "4.4.3", | 153 | "version": "4.4.4", |
| 153 | "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz", | 154 | "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", |
| 154 | "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==", | 155 | "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", |
| 155 | "license": "MIT" | 156 | "license": "MIT" |
| 156 | }, | 157 | }, |
| 157 | "node_modules/@agnai/sentencepiece-js": { | 158 | "node_modules/@agnai/sentencepiece-js": { |
| @@ -1911,9 +1912,9 @@ | |||
| 1911 | "license": "MIT" | 1912 | "license": "MIT" |
| 1912 | }, | 1913 | }, |
| 1913 | "node_modules/@types/jquery": { | 1914 | "node_modules/@types/jquery": { |
| 1914 | "version": "3.5.32", | 1915 | "version": "3.5.33", |
| 1915 | "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.32.tgz", | 1916 | "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.33.tgz", |
| 1916 | "integrity": "sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==", | 1917 | "integrity": "sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==", |
| 1917 | "dev": true, | 1918 | "dev": true, |
| 1918 | "license": "MIT", | 1919 | "license": "MIT", |
| 1919 | "dependencies": { | 1920 | "dependencies": { |
| @@ -2896,9 +2897,9 @@ | |||
| 2896 | "license": "ISC" | 2897 | "license": "ISC" |
| 2897 | }, | 2898 | }, |
| 2898 | "node_modules/bowser": { | 2899 | "node_modules/bowser": { |
| 2899 | "version": "2.11.0", | 2900 | "version": "2.12.1", |
| 2900 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", | 2901 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.12.1.tgz", |
| 2901 | "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", | 2902 | "integrity": "sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==", |
| 2902 | "license": "MIT" | 2903 | "license": "MIT" |
| 2903 | }, | 2904 | }, |
| 2904 | "node_modules/brace-expansion": { | 2905 | "node_modules/brace-expansion": { |
| @@ -3126,9 +3127,9 @@ | |||
| 3126 | } | 3127 | } |
| 3127 | }, | 3128 | }, |
| 3128 | "node_modules/chalk": { | 3129 | "node_modules/chalk": { |
| 3129 | "version": "5.4.1", | 3130 | "version": "5.6.0", |
| 3130 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", | 3131 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", |
| 3131 | "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", | 3132 | "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", |
| 3132 | "license": "MIT", | 3133 | "license": "MIT", |
| 3133 | "engines": { | 3134 | "engines": { |
| 3134 | "node": "^12.17.0 || ^14.13 || >=16.0.0" | 3135 | "node": "^12.17.0 || ^14.13 || >=16.0.0" |
| @@ -5249,6 +5250,15 @@ | |||
| 5249 | "node": ">=12.0.0" | 5250 | "node": ">=12.0.0" |
| 5250 | } | 5251 | } |
| 5251 | }, | 5252 | }, |
| 5253 | "node_modules/host-validation-middleware": { | ||
| 5254 | "version": "0.1.1", | ||
| 5255 | "resolved": "https://registry.npmjs.org/host-validation-middleware/-/host-validation-middleware-0.1.1.tgz", | ||
| 5256 | "integrity": "sha512-fakcpp+x4nbP0fACY5gaHWpaOfstq3w8uB6wvhbPBLqH9GV/tdiM9Ht5mclZVbUuPLGBw1bkH5yyTD6HZq057g==", | ||
| 5257 | "license": "MIT", | ||
| 5258 | "engines": { | ||
| 5259 | "node": "^18.0.0 || >=20.0.0" | ||
| 5260 | } | ||
| 5261 | }, | ||
| 5252 | "node_modules/html-entities": { | 5262 | "node_modules/html-entities": { |
| 5253 | "version": "2.6.0", | 5263 | "version": "2.6.0", |
| 5254 | "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", | 5264 | "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", |
| @@ -6178,9 +6188,9 @@ | |||
| 6178 | } | 6188 | } |
| 6179 | }, | 6189 | }, |
| 6180 | "node_modules/morphdom": { | 6190 | "node_modules/morphdom": { |
| 6181 | "version": "2.7.5", | 6191 | "version": "2.7.7", |
| 6182 | "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.5.tgz", | 6192 | "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.7.tgz", |
| 6183 | "integrity": "sha512-z6bfWFMra7kBqDjQGHud1LSXtq5JJC060viEkQFMBX6baIecpkNr2Ywrn2OQfWP3rXiNFQRPoFjD8/TvJcWcDg==", | 6193 | "integrity": "sha512-04GmsiBcalrSCNmzfo+UjU8tt3PhZJKzcOy+r1FlGA7/zri8wre3I1WkYN9PT3sIeIKfW9bpyElA+VzOg2E24g==", |
| 6184 | "license": "MIT" | 6194 | "license": "MIT" |
| 6185 | }, | 6195 | }, |
| 6186 | "node_modules/ms": { | 6196 | "node_modules/ms": { |
| @@ -8001,9 +8011,9 @@ | |||
| 8001 | "license": "MIT" | 8011 | "license": "MIT" |
| 8002 | }, | 8012 | }, |
| 8003 | "node_modules/tiktoken": { | 8013 | "node_modules/tiktoken": { |
| 8004 | "version": "1.0.21", | 8014 | "version": "1.0.22", |
| 8005 | "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.21.tgz", | 8015 | "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.22.tgz", |
| 8006 | "integrity": "sha512-/kqtlepLMptX0OgbYD9aMYbM7EFrMZCL7EoHM8Psmg2FuhXoo/bH64KqOiZGGwa6oS9TPdSEDKBnV2LuB8+5vQ==", | 8016 | "integrity": "sha512-PKvy1rVF1RibfF3JlXBSP0Jrcw2uq3yXdgcEXtKTYn3QJ/cBRBHDnrJ5jHky+MENZ6DIPwNUGWpkVx+7joCpNA==", |
| 8007 | "license": "MIT" | 8017 | "license": "MIT" |
| 8008 | }, | 8018 | }, |
| 8009 | "node_modules/timm": { | 8019 | "node_modules/timm": { |
| @@ -8610,9 +8620,9 @@ | |||
| 8610 | } | 8620 | } |
| 8611 | }, | 8621 | }, |
| 8612 | "node_modules/yaml": { | 8622 | "node_modules/yaml": { |
| 8613 | "version": "2.8.0", | 8623 | "version": "2.8.1", |
| 8614 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", | 8624 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", |
| 8615 | "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", | 8625 | "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", |
| 8616 | "license": "ISC", | 8626 | "license": "ISC", |
| 8617 | "bin": { | 8627 | "bin": { |
| 8618 | "yaml": "bin.mjs" | 8628 | "yaml": "bin.mjs" |
| @@ -1,6 +1,6 @@ | |||
| 1 | { | 1 | { |
| 2 | "dependencies": { | 2 | "dependencies": { |
| 3 | "@adobe/css-tools": "^4.4.3", | 3 | "@adobe/css-tools": "^4.4.4", |
| 4 | "@agnai/sentencepiece-js": "^1.1.1", | 4 | "@agnai/sentencepiece-js": "^1.1.1", |
| 5 | "@agnai/web-tokenizers": "^0.1.3", | 5 | "@agnai/web-tokenizers": "^0.1.3", |
| 6 | "@iconfu/svg-inject": "^1.2.3", | 6 | "@iconfu/svg-inject": "^1.2.3", |
| @@ -32,9 +32,9 @@ | |||
| 32 | "archiver": "^7.0.1", | 32 | "archiver": "^7.0.1", |
| 33 | "bing-translate-api": "^4.1.0", | 33 | "bing-translate-api": "^4.1.0", |
| 34 | "body-parser": "^1.20.2", | 34 | "body-parser": "^1.20.2", |
| 35 | "bowser": "^2.11.0", | 35 | "bowser": "^2.12.1", |
| 36 | "bytes": "^3.1.2", | 36 | "bytes": "^3.1.2", |
| 37 | "chalk": "^5.4.1", | 37 | "chalk": "^5.6.0", |
| 38 | "command-exists": "^1.2.9", | 38 | "command-exists": "^1.2.9", |
| 39 | "compression": "^1.8.1", | 39 | "compression": "^1.8.1", |
| 40 | "cookie-parser": "^1.4.6", | 40 | "cookie-parser": "^1.4.6", |
| @@ -54,6 +54,7 @@ | |||
| 54 | "handlebars": "^4.7.8", | 54 | "handlebars": "^4.7.8", |
| 55 | "helmet": "^8.1.0", | 55 | "helmet": "^8.1.0", |
| 56 | "highlight.js": "^11.11.1", | 56 | "highlight.js": "^11.11.1", |
| 57 | "host-validation-middleware": "^0.1.1", | ||
| 57 | "html-entities": "^2.6.0", | 58 | "html-entities": "^2.6.0", |
| 58 | "iconv-lite": "^0.6.3", | 59 | "iconv-lite": "^0.6.3", |
| 59 | "ip-matching": "^2.1.2", | 60 | "ip-matching": "^2.1.2", |
| @@ -64,7 +65,7 @@ | |||
| 64 | "lodash": "^4.17.21", | 65 | "lodash": "^4.17.21", |
| 65 | "mime-types": "^3.0.1", | 66 | "mime-types": "^3.0.1", |
| 66 | "moment": "^2.30.1", | 67 | "moment": "^2.30.1", |
| 67 | "morphdom": "^2.7.5", | 68 | "morphdom": "^2.7.7", |
| 68 | "multer": "^2.0.2", | 69 | "multer": "^2.0.2", |
| 69 | "node-fetch": "^3.3.2", | 70 | "node-fetch": "^3.3.2", |
| 70 | "node-persist": "^4.0.4", | 71 | "node-persist": "^4.0.4", |
| @@ -80,14 +81,14 @@ | |||
| 80 | "sillytavern-transformers": "2.14.6", | 81 | "sillytavern-transformers": "2.14.6", |
| 81 | "simple-git": "^3.28.0", | 82 | "simple-git": "^3.28.0", |
| 82 | "slidetoggle": "^4.0.0", | 83 | "slidetoggle": "^4.0.0", |
| 83 | "tiktoken": "^1.0.21", | 84 | "tiktoken": "^1.0.22", |
| 84 | "url-join": "^5.0.0", | 85 | "url-join": "^5.0.0", |
| 85 | "vectra": "^0.2.2", | 86 | "vectra": "^0.2.2", |
| 86 | "wavefile": "^11.0.0", | 87 | "wavefile": "^11.0.0", |
| 87 | "webpack": "^5.98.0", | 88 | "webpack": "^5.98.0", |
| 88 | "write-file-atomic": "^5.0.1", | 89 | "write-file-atomic": "^5.0.1", |
| 89 | "ws": "^8.18.3", | 90 | "ws": "^8.18.3", |
| 90 | "yaml": "^2.8.0", | 91 | "yaml": "^2.8.1", |
| 91 | "yargs": "^17.7.1", | 92 | "yargs": "^17.7.1", |
| 92 | "yauzl": "^3.2.0" | 93 | "yauzl": "^3.2.0" |
| 93 | }, | 94 | }, |
| @@ -112,7 +113,7 @@ | |||
| 112 | "type": "git", | 113 | "type": "git", |
| 113 | "url": "https://github.com/SillyTavern/SillyTavern.git" | 114 | "url": "https://github.com/SillyTavern/SillyTavern.git" |
| 114 | }, | 115 | }, |
| 115 | "version": "1.13.3", | 116 | "version": "1.13.4", |
| 116 | "scripts": { | 117 | "scripts": { |
| 117 | "start": "node server.js", | 118 | "start": "node server.js", |
| 118 | "debug": "node --inspect server.js", | 119 | "debug": "node --inspect server.js", |
| @@ -145,7 +146,7 @@ | |||
| 145 | "@types/cors": "^2.8.19", | 146 | "@types/cors": "^2.8.19", |
| 146 | "@types/deno": "^2.3.0", | 147 | "@types/deno": "^2.3.0", |
| 147 | "@types/express": "^4.17.23", | 148 | "@types/express": "^4.17.23", |
| 148 | "@types/jquery": "^3.5.32", | 149 | "@types/jquery": "^3.5.33", |
| 149 | "@types/jquery-cropper": "^1.0.4", | 150 | "@types/jquery-cropper": "^1.0.4", |
| 150 | "@types/jquery.transit": "^0.9.33", | 151 | "@types/jquery.transit": "^0.9.33", |
| 151 | "@types/jqueryui": "^1.12.24", | 152 | "@types/jqueryui": "^1.12.24", |
| @@ -0,0 +1,229 @@ | |||
| 1 | /* Main Page Backgrounds */ | ||
| 2 | #bg1, | ||
| 3 | #bg_custom { | ||
| 4 | background-repeat: no-repeat; | ||
| 5 | background-attachment: fixed; | ||
| 6 | background-size: cover; | ||
| 7 | position: absolute; | ||
| 8 | width: 100%; | ||
| 9 | height: 100%; | ||
| 10 | transition: background-image var(--animation-duration-3x) ease-in-out; | ||
| 11 | } | ||
| 12 | |||
| 13 | /* Fitting options */ | ||
| 14 | #background_fitting { | ||
| 15 | max-width: 6em; | ||
| 16 | } | ||
| 17 | |||
| 18 | /* Fill/Cover - scales to fill width while maintaining aspect ratio */ | ||
| 19 | #bg1.cover, | ||
| 20 | #bg_custom.cover { | ||
| 21 | background-size: cover; | ||
| 22 | background-position: center; | ||
| 23 | } | ||
| 24 | |||
| 25 | /* Fit/Contain - shows entire image maintaining aspect ratio */ | ||
| 26 | #bg1.contain, | ||
| 27 | #bg_custom.contain { | ||
| 28 | background-size: contain; | ||
| 29 | background-position: center; | ||
| 30 | background-repeat: no-repeat; | ||
| 31 | } | ||
| 32 | |||
| 33 | /* Stretch - stretches to fill entire space */ | ||
| 34 | #bg1.stretch, | ||
| 35 | #bg_custom.stretch { | ||
| 36 | background-size: 100% 100%; | ||
| 37 | } | ||
| 38 | |||
| 39 | /* Center - centers without scaling */ | ||
| 40 | #bg1.center, | ||
| 41 | #bg_custom.center { | ||
| 42 | background-size: auto; | ||
| 43 | background-position: center; | ||
| 44 | background-repeat: no-repeat; | ||
| 45 | } | ||
| 46 | |||
| 47 | body.reduced-motion #bg1, | ||
| 48 | body.reduced-motion #bg_custom { | ||
| 49 | transition: none; | ||
| 50 | } | ||
| 51 | |||
| 52 | #bg1 { | ||
| 53 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='); | ||
| 54 | z-index: -3; | ||
| 55 | } | ||
| 56 | |||
| 57 | #bg_custom { | ||
| 58 | background-image: none; | ||
| 59 | z-index: -2; | ||
| 60 | } | ||
| 61 | |||
| 62 | .bg_example.flex-container.locked:not(:focus-visible) { | ||
| 63 | outline-color: var(--golden); | ||
| 64 | } | ||
| 65 | |||
| 66 | /* This is the main flex container for the entire drawer */ | ||
| 67 | #Backgrounds.drawer-content.openDrawer.bg-drawer-layout { | ||
| 68 | display: flex; | ||
| 69 | flex-direction: column; | ||
| 70 | height: calc(100vh - var(--topBarBlockSize)); | ||
| 71 | max-height: calc(100vh - var(--topBarBlockSize)); | ||
| 72 | height: calc(100dvh - var(--topBarBlockSize)); | ||
| 73 | max-height: calc(100dvh - var(--topBarBlockSize)); | ||
| 74 | overflow: hidden; | ||
| 75 | width: var(--sheldWidth); | ||
| 76 | max-width: var(--sheldWidth); | ||
| 77 | padding: 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | #bg-header-fixed { | ||
| 81 | flex-shrink: 0; | ||
| 82 | padding: 5px; | ||
| 83 | background-color: var(--SmartThemeBlurTintColor); | ||
| 84 | border-bottom: 1px solid var(--SmartThemeBorderColor); | ||
| 85 | } | ||
| 86 | |||
| 87 | #bg-header-fixed>.flex-container { | ||
| 88 | display: flex; | ||
| 89 | align-items: center; | ||
| 90 | gap: 5px; | ||
| 91 | } | ||
| 92 | |||
| 93 | #bg-scrollable-content { | ||
| 94 | flex-grow: 1; | ||
| 95 | overflow-y: auto; | ||
| 96 | overflow-x: hidden; | ||
| 97 | padding: 0 5px 5px; | ||
| 98 | } | ||
| 99 | |||
| 100 | #bg-filter { | ||
| 101 | font-size: calc(var(--mainFontSize) * 0.95); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* Thumbnail Menu & Buttons */ | ||
| 105 | .bg_example .mobile-only-menu-toggle { | ||
| 106 | display: none; | ||
| 107 | } | ||
| 108 | |||
| 109 | .bg_example.flex-container { | ||
| 110 | width: 30%; | ||
| 111 | max-width: 200px; | ||
| 112 | margin: 5px; | ||
| 113 | aspect-ratio: 16/9; | ||
| 114 | cursor: pointer; | ||
| 115 | box-shadow: 0 0 7px var(--black50a); | ||
| 116 | |||
| 117 | position: relative; | ||
| 118 | overflow: hidden; | ||
| 119 | border-radius: 8px; | ||
| 120 | border: 0px solid transparent; | ||
| 121 | outline: 2px solid var(--SmartThemeBorderColor); | ||
| 122 | outline-offset: -1px; | ||
| 123 | } | ||
| 124 | |||
| 125 | .bg_example.flex-container:focus-visible { | ||
| 126 | outline-offset: inherit; | ||
| 127 | } | ||
| 128 | |||
| 129 | .bg_example_img { | ||
| 130 | position: absolute; | ||
| 131 | top: -2px; | ||
| 132 | left: -2px; | ||
| 133 | right: -2px; | ||
| 134 | bottom: -2px; | ||
| 135 | |||
| 136 | background-image: inherit; | ||
| 137 | |||
| 138 | background-size: cover; | ||
| 139 | background-position: center; | ||
| 140 | } | ||
| 141 | |||
| 142 | .bg_example .jg-menu { | ||
| 143 | display: flex; | ||
| 144 | position: absolute; | ||
| 145 | top: 2px; | ||
| 146 | right: 2px; | ||
| 147 | background-color: rgba(0, 0, 0, 0.5); | ||
| 148 | border-radius: 8px; | ||
| 149 | gap: 3px; | ||
| 150 | padding: 3px 5px; | ||
| 151 | z-index: 3; | ||
| 152 | backdrop-filter: blur(4px); | ||
| 153 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 154 | justify-items: center; | ||
| 155 | align-items: center; | ||
| 156 | |||
| 157 | opacity: 0; | ||
| 158 | visibility: hidden; | ||
| 159 | transform: scale(0.9); | ||
| 160 | transform-origin: center; | ||
| 161 | transition: opacity var(--animation-duration) ease-out, visibility var(--animation-duration) ease-out, transform var(--animation-duration) ease-out; | ||
| 162 | } | ||
| 163 | |||
| 164 | .bg_example:hover .jg-menu, | ||
| 165 | .bg_example:focus-within .jg-menu { | ||
| 166 | opacity: 1; | ||
| 167 | visibility: visible; | ||
| 168 | transform: scale(1); | ||
| 169 | } | ||
| 170 | |||
| 171 | .bg_example .jg-button { | ||
| 172 | display: flex; | ||
| 173 | width: 30px; | ||
| 174 | height: 30px; | ||
| 175 | align-items: center; | ||
| 176 | justify-content: center; | ||
| 177 | color: white; | ||
| 178 | padding: 5px; | ||
| 179 | font-size: 1.1em; | ||
| 180 | border-radius: 6px; | ||
| 181 | transition: background-color var(--animation-duration) ease; | ||
| 182 | } | ||
| 183 | |||
| 184 | .bg_example .jg-button:hover { | ||
| 185 | background-color: rgba(255, 255, 255, 0.2); | ||
| 186 | } | ||
| 187 | |||
| 188 | .bg_example .jg-unlock { | ||
| 189 | display: none; | ||
| 190 | } | ||
| 191 | |||
| 192 | .bg_example.locked .jg-lock { | ||
| 193 | display: none; | ||
| 194 | } | ||
| 195 | |||
| 196 | .bg_example.locked .jg-unlock { | ||
| 197 | display: flex; | ||
| 198 | } | ||
| 199 | |||
| 200 | .bg_example:not([custom="true"]) .jg-copy, | ||
| 201 | .bg_example[custom="true"] .jg-edit { | ||
| 202 | display: none; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* Thumbnail Title */ | ||
| 206 | .bg_example .BGSampleTitle { | ||
| 207 | position: absolute; | ||
| 208 | bottom: 0; | ||
| 209 | left: 0; | ||
| 210 | right: 0; | ||
| 211 | background: linear-gradient(transparent, rgba(0, 0, 0, 0.9)); | ||
| 212 | color: var(--SmartThemeBodyColor); | ||
| 213 | font-size: 0.9em; | ||
| 214 | font-weight: 600; | ||
| 215 | padding: 0px 6px 2px; | ||
| 216 | text-align: center; | ||
| 217 | white-space: nowrap; | ||
| 218 | overflow: hidden; | ||
| 219 | text-overflow: ellipsis; | ||
| 220 | opacity: 0; | ||
| 221 | transition: opacity var(--animation-duration) ease-in-out; | ||
| 222 | pointer-events: none; | ||
| 223 | border-radius: 0 0 8px 8px; | ||
| 224 | } | ||
| 225 | |||
| 226 | .bg_example:hover .BGSampleTitle, | ||
| 227 | .bg_example:focus-within .BGSampleTitle { | ||
| 228 | opacity: 1; | ||
| 229 | } | ||
| @@ -25,6 +25,87 @@ | |||
| 25 | font-size: 15px; | 25 | font-size: 15px; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | #Backgrounds .bg_example .BGSampleTitle { | ||
| 29 | opacity: 1; | ||
| 30 | bottom: 0px; | ||
| 31 | } | ||
| 32 | |||
| 33 | .bg_example:hover .jg-menu, | ||
| 34 | .bg_example:focus-within .jg-menu { | ||
| 35 | display: none; | ||
| 36 | } | ||
| 37 | |||
| 38 | .bg_example.mobile-menu-open .jg-menu { | ||
| 39 | display: flex; | ||
| 40 | z-index: 4; | ||
| 41 | } | ||
| 42 | |||
| 43 | .bg_example .mobile-only-menu-toggle { | ||
| 44 | display: flex; | ||
| 45 | align-items: center; | ||
| 46 | justify-content: center; | ||
| 47 | position: absolute; | ||
| 48 | top: 5px; | ||
| 49 | right: 5px; | ||
| 50 | width: 30px; | ||
| 51 | height: 30px; | ||
| 52 | background-color: rgba(0, 0, 0, 0.4); | ||
| 53 | color: white; | ||
| 54 | border-radius: 6px; | ||
| 55 | z-index: 3; | ||
| 56 | cursor: pointer; | ||
| 57 | backdrop-filter: blur(2px); | ||
| 58 | } | ||
| 59 | |||
| 60 | #bg-header-controls { | ||
| 61 | flex-wrap: wrap; | ||
| 62 | row-gap: 10px; | ||
| 63 | } | ||
| 64 | |||
| 65 | #bg-header-fixed>.flex-container { | ||
| 66 | flex-wrap: wrap; | ||
| 67 | row-gap: 0px; | ||
| 68 | } | ||
| 69 | |||
| 70 | #Backgrounds:not(.selection-mode-active) #bg-header-fixed>.flex-container::after { | ||
| 71 | content: ''; | ||
| 72 | order: 1; | ||
| 73 | flex-basis: 100%; | ||
| 74 | height: 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | /* --- Row 1 Item --- */ | ||
| 78 | #bg-header-fixed #bg-header-title { | ||
| 79 | order: 1; | ||
| 80 | flex-grow: 1; | ||
| 81 | } | ||
| 82 | |||
| 83 | #bg-header-fixed #background_fitting, | ||
| 84 | #bg-header-fixed #auto_background { | ||
| 85 | order: 1; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* --- Row 2 Item --- */ | ||
| 89 | #bg-header-fixed #bg-filter { | ||
| 90 | order: 2; | ||
| 91 | flex-grow: 1; | ||
| 92 | min-width: 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | /* --- Row 3 Item --- */ | ||
| 96 | #bg-header-fixed #add_background_button_top { | ||
| 97 | order: 3; | ||
| 98 | width: 100%; | ||
| 99 | text-align: center; | ||
| 100 | padding-top: 0.5em; | ||
| 101 | padding-bottom: 0.5em; | ||
| 102 | } | ||
| 103 | |||
| 104 | #Backgrounds.drawer-content.openDrawer.bg-drawer-layout { | ||
| 105 | width: 100dvw; | ||
| 106 | max-width: 100dvw; | ||
| 107 | } | ||
| 108 | |||
| 28 | #extensions_settings, | 109 | #extensions_settings, |
| 29 | #extensions_settings2 { | 110 | #extensions_settings2 { |
| 30 | width: 100% !important; | 111 | width: 100% !important; |
| @@ -412,10 +493,6 @@ | |||
| 412 | flex-basis: max(calc(100% / 2 - 10px), 180px); | 493 | flex-basis: max(calc(100% / 2 - 10px), 180px); |
| 413 | } | 494 | } |
| 414 | 495 | ||
| 415 | .BGSampleTitle { | ||
| 416 | display: none; | ||
| 417 | } | ||
| 418 | |||
| 419 | .tag.excluded:after { | 496 | .tag.excluded:after { |
| 420 | top: unset; | 497 | top: unset; |
| 421 | bottom: unset; | 498 | bottom: unset; |
| @@ -26,7 +26,6 @@ dialog { | |||
| 26 | 26 | ||
| 27 | /* Fix weird animation issue with font-scaling during popup open */ | 27 | /* Fix weird animation issue with font-scaling during popup open */ |
| 28 | backface-visibility: hidden; | 28 | backface-visibility: hidden; |
| 29 | transform: translateZ(0); | ||
| 30 | -webkit-font-smoothing: subpixel-antialiased; | 29 | -webkit-font-smoothing: subpixel-antialiased; |
| 31 | 30 | ||
| 32 | /* Variables setup */ | 31 | /* Variables setup */ |
| @@ -93,6 +92,11 @@ dialog { | |||
| 93 | animation: fade-in var(--popup-animation-speed) ease-in-out; | 92 | animation: fade-in var(--popup-animation-speed) ease-in-out; |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 95 | /* Fix toast container snapping into the backdrop while the animation is running */ | ||
| 96 | .popup[opening] #toast-container { | ||
| 97 | visibility: hidden; | ||
| 98 | } | ||
| 99 | |||
| 96 | /* Open state of the dialog */ | 100 | /* Open state of the dialog */ |
| 97 | .popup[open] { | 101 | .popup[open] { |
| 98 | color: var(--SmartThemeBodyColor); | 102 | color: var(--SmartThemeBodyColor); |
| @@ -118,17 +122,30 @@ body.no-blur .popup[open]::backdrop { | |||
| 118 | animation: fade-out var(--popup-animation-speed) ease-in-out; | 122 | animation: fade-out var(--popup-animation-speed) ease-in-out; |
| 119 | } | 123 | } |
| 120 | 124 | ||
| 121 | .popup #toast-container { | 125 | /* Edge inset to match Toastr default spacing */ |
| 122 | /* Fix toastr in dialogs by actually placing it at the top of the screen via transform */ | 126 | :root { |
| 123 | height: 100dvh; | 127 | --toast-edge: 12px; |
| 124 | top: calc(50% + var(--topBarBlockSize)); | 128 | } |
| 125 | left: 50%; | ||
| 126 | transform: translate(-50%, -50%); | ||
| 127 | 129 | ||
| 128 | /* Fix text align, popups are centered by default. toasts should not. */ | 130 | .popup #toast-container { |
| 131 | /* Popups are centered by default; toasts should not be */ | ||
| 129 | text-align: left; | 132 | text-align: left; |
| 130 | } | 133 | } |
| 131 | 134 | ||
| 135 | /* Per-position position adjustments caused by the top bar, inside the popup */ | ||
| 136 | .popup #toast-container.toast-top-left { | ||
| 137 | top: calc(var(--toast-edge) + var(--topBarBlockSize)); | ||
| 138 | } | ||
| 139 | |||
| 140 | .popup #toast-container.toast-top-center { | ||
| 141 | /* toastr in core does not have a top offset on center, so we don't do that either in popups */ | ||
| 142 | top: var(--topBarBlockSize); | ||
| 143 | } | ||
| 144 | |||
| 145 | .popup #toast-container.toast-top-right { | ||
| 146 | top: calc(var(--toast-edge) + var(--topBarBlockSize)); | ||
| 147 | } | ||
| 148 | |||
| 132 | .popup-crop-wrap { | 149 | .popup-crop-wrap { |
| 133 | margin: 10px auto; | 150 | margin: 10px auto; |
| 134 | max-height: 75vh; | 151 | max-height: 75vh; |
| @@ -5,20 +5,20 @@ import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyAp | |||
| 5 | 5 | ||
| 6 | declare global { | 6 | declare global { |
| 7 | // Custom types | 7 | // Custom types |
| 8 | declare type InstructSettings = typeof power_user.instruct; | 8 | type InstructSettings = typeof power_user.instruct; |
| 9 | declare type ContextSettings = typeof power_user.context; | 9 | type ContextSettings = typeof power_user.context; |
| 10 | declare type ReasoningSettings = typeof power_user.reasoning; | 10 | type ReasoningSettings = typeof power_user.reasoning; |
| 11 | 11 | ||
| 12 | // Global namespace modules | 12 | // Global namespace modules |
| 13 | interface Window { | 13 | interface Window { |
| 14 | ai: any; | 14 | ai: any; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | declare var pdfjsLib; | 17 | var pdfjsLib; |
| 18 | declare var ePub; | 18 | var ePub; |
| 19 | declare var quickReplyApi: QuickReplyApi; | 19 | var quickReplyApi: QuickReplyApi; |
| 20 | 20 | ||
| 21 | declare var SillyTavern: { | 21 | var SillyTavern: { |
| 22 | getContext(): typeof getContext; | 22 | getContext(): typeof getContext; |
| 23 | llm: any; | 23 | llm: any; |
| 24 | libs: typeof libs; | 24 | libs: typeof libs; |
| @@ -63,7 +63,7 @@ declare global { | |||
| 63 | * @param lang Target language | 63 | * @param lang Target language |
| 64 | * @param provider Translation provider | 64 | * @param provider Translation provider |
| 65 | */ | 65 | */ |
| 66 | async function translate(text: string, lang: string, provider: string = null): Promise<string>; | 66 | function translate(text: string, lang: string, provider?: string | null): Promise<string>; |
| 67 | 67 | ||
| 68 | interface ConvertVideoArgs { | 68 | interface ConvertVideoArgs { |
| 69 | buffer: Uint8Array; | 69 | buffer: Uint8Array; |
| @@ -76,9 +76,9 @@ declare global { | |||
| 76 | */ | 76 | */ |
| 77 | function convertVideoToAnimatedWebp(args: ConvertVideoArgs): Promise<Uint8Array>; | 77 | function convertVideoToAnimatedWebp(args: ConvertVideoArgs): Promise<Uint8Array>; |
| 78 | 78 | ||
| 79 | interface ColorPickerEvent extends JQuery.ChangeEvent<HTMLElement> { | 79 | type ColorPickerEvent = Omit<JQuery.ChangeEvent<HTMLElement>, "detail"> & { |
| 80 | detail: { | 80 | detail: { |
| 81 | rgba: string; | 81 | rgba: string; |
| 82 | }; | 82 | } |
| 83 | } | 83 | }; |
| 84 | } | 84 | } |
| @@ -0,0 +1 @@ | |||
| 1 | <svg id="uuid-adbdae8e-5a41-46d1-8c18-aa73cdbfee32" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18" height="100px" width="100px" transform="rotate(0) scale(1, 1)"><path d="m0,2.7v12.6c0,1.491,1.209,2.7,2.7,2.7h12.6c1.491,0,2.7-1.209,2.7-2.7V2.7c0-1.491-1.209-2.7-2.7-2.7H2.7C1.209,0,0,1.209,0,2.7ZM10.8,0v3.6c0,3.976,3.224,7.2,7.2,7.2h-3.6c-3.976,0-7.199,3.222-7.2,7.198v-3.598c0-3.976-3.224-7.2-7.2-7.2h3.6c3.976,0,7.2-3.224,7.2-7.2Z" stroke-width="0"/></svg> | ||
| @@ -0,0 +1 @@ | |||
| 1 | <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="118.66667" height="177.33333" viewBox="0 0 89 133"><path d="M14.5 1.8c-6.3 3-11.3 8.8-13.2 15.1C-.1 21.8-.2 27.6.6 70.6l.9 48.2 3.1 4.4c1.9 2.6 5.3 5.4 8.4 7l5.2 2.8h26.7c14.8 0 28.2-.5 30.2-1 5.4-1.5 11.6-8.6 12.4-14.3 1-6.5-.2-10.4-4.7-15.3-5.1-5.5-8.3-6.4-23.3-6.4C46.2 96 43 94.9 43 90.5c0-4.3 3.3-5.5 15.4-5.5 13 0 18-1.8 22.7-8.3 5.4-7.5 5-14.4-1.3-21.3-5.1-5.5-11-7.4-22.8-7.4-9.2 0-13-1.5-13-5 0-3.9 3.6-5 16.9-5 14.5 0 19.4-1.6 23.7-7.9 5.4-7.9 5.2-15.9-.6-22.5-5.4-6.1-6.7-6.4-37.5-7.1-26.3-.6-28.2-.5-32 1.3z"/></svg> | ||
| \ No newline at end of file | 1 | \ No newline at end of file | |
| @@ -652,7 +652,7 @@ | |||
| 652 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="65536"> | 652 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="65536"> |
| 653 | </div> | 653 | </div> |
| 654 | </div> | 654 | </div> |
| 655 | <div class="range-block" data-source="openai,custom,xai,aimlapi,moonshot"> | 655 | <div class="range-block" data-source="openai,custom,xai,aimlapi,moonshot,azure_openai"> |
| 656 | <div class="range-block-title" data-i18n="Multiple swipes per generation"> | 656 | <div class="range-block-title" data-i18n="Multiple swipes per generation"> |
| 657 | Multiple swipes per generation | 657 | Multiple swipes per generation |
| 658 | </div> | 658 | </div> |
| @@ -691,7 +691,7 @@ | |||
| 691 | </span> | 691 | </span> |
| 692 | </div> | 692 | </div> |
| 693 | </div> | 693 | </div> |
| 694 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi"> | 694 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai"> |
| 695 | <div class="range-block-title" data-i18n="Temperature"> | 695 | <div class="range-block-title" data-i18n="Temperature"> |
| 696 | Temperature | 696 | Temperature |
| 697 | </div> | 697 | </div> |
| @@ -704,7 +704,7 @@ | |||
| 704 | </div> | 704 | </div> |
| 705 | </div> | 705 | </div> |
| 706 | </div> | 706 | </div> |
| 707 | <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi"> | 707 | <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai"> |
| 708 | <div class="range-block-title" data-i18n="Frequency Penalty"> | 708 | <div class="range-block-title" data-i18n="Frequency Penalty"> |
| 709 | Frequency Penalty | 709 | Frequency Penalty |
| 710 | </div> | 710 | </div> |
| @@ -717,7 +717,7 @@ | |||
| 717 | </div> | 717 | </div> |
| 718 | </div> | 718 | </div> |
| 719 | </div> | 719 | </div> |
| 720 | <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi"> | 720 | <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai"> |
| 721 | <div class="range-block-title" data-i18n="Presence Penalty"> | 721 | <div class="range-block-title" data-i18n="Presence Penalty"> |
| 722 | Presence Penalty | 722 | Presence Penalty |
| 723 | </div> | 723 | </div> |
| @@ -730,7 +730,7 @@ | |||
| 730 | </div> | 730 | </div> |
| 731 | </div> | 731 | </div> |
| 732 | </div> | 732 | </div> |
| 733 | <div class="range-block" data-source="claude,aimlapi,openrouter,makersuite,vertexai,cohere,perplexity"> | 733 | <div class="range-block" data-source="claude,aimlapi,openrouter,makersuite,vertexai,cohere,perplexity,electronhub"> |
| 734 | <div class="range-block-title" data-i18n="Top K"> | 734 | <div class="range-block-title" data-i18n="Top K"> |
| 735 | Top K | 735 | Top K |
| 736 | </div> | 736 | </div> |
| @@ -743,7 +743,7 @@ | |||
| 743 | </div> | 743 | </div> |
| 744 | </div> | 744 | </div> |
| 745 | </div> | 745 | </div> |
| 746 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi"> | 746 | <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai"> |
| 747 | <div class="range-block-title" data-i18n="Top P"> | 747 | <div class="range-block-title" data-i18n="Top P"> |
| 748 | Top P | 748 | Top P |
| 749 | </div> | 749 | </div> |
| @@ -980,7 +980,7 @@ | |||
| 980 | </div> | 980 | </div> |
| 981 | </div> | 981 | </div> |
| 982 | </div> | 982 | </div> |
| 983 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai,pollinations,aimlapi,makersuite,vertexai"> | 983 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,electronhub,nanogpt,xai,pollinations,aimlapi,makersuite,vertexai,azure_openai"> |
| 984 | <div class="range-block-title justifyLeft" data-i18n="Seed"> | 984 | <div class="range-block-title justifyLeft" data-i18n="Seed"> |
| 985 | Seed | 985 | Seed |
| 986 | </div> | 986 | </div> |
| @@ -1970,7 +1970,7 @@ | |||
| 1970 | </span> | 1970 | </span> |
| 1971 | </div> | 1971 | </div> |
| 1972 | </div> | 1972 | </div> |
| 1973 | <div class="range-block" data-source="makersuite,vertexai,aimlapi,openrouter,claude,xai,nanogpt"> | 1973 | <div class="range-block" data-source="makersuite,vertexai,aimlapi,openrouter,claude,xai,electronhub,nanogpt"> |
| 1974 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> | 1974 | <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand"> |
| 1975 | <input id="openai_enable_web_search" type="checkbox" /> | 1975 | <input id="openai_enable_web_search" type="checkbox" /> |
| 1976 | <span data-i18n="Enable web search">Enable web search</span> | 1976 | <span data-i18n="Enable web search">Enable web search</span> |
| @@ -1984,7 +1984,7 @@ | |||
| 1984 | </b> | 1984 | </b> |
| 1985 | </div> | 1985 | </div> |
| 1986 | </div> | 1986 | </div> |
| 1987 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi"> | 1987 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi,electronhub,azure_openai"> |
| 1988 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> | 1988 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> |
| 1989 | <input id="openai_function_calling" type="checkbox" /> | 1989 | <input id="openai_function_calling" type="checkbox" /> |
| 1990 | <span data-i18n="Enable function calling">Enable function calling</span> | 1990 | <span data-i18n="Enable function calling">Enable function calling</span> |
| @@ -1999,7 +1999,7 @@ | |||
| 1999 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong> | 1999 | <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong> |
| 2000 | </div> | 2000 | </div> |
| 2001 | </div> | 2001 | </div> |
| 2002 | <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi"> | 2002 | <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt,electronhub,azure_openai"> |
| 2003 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> | 2003 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 2004 | <input id="openai_image_inlining" type="checkbox" /> | 2004 | <input id="openai_image_inlining" type="checkbox" /> |
| 2005 | <span data-i18n="Send inline images">Send inline images</span> | 2005 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -2015,7 +2015,7 @@ | |||
| 2015 | <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> | 2015 | <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> |
| 2016 | <span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span> | 2016 | <span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span> |
| 2017 | </div> | 2017 | </div> |
| 2018 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere"> | 2018 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere,cometapi,nanogpt,moonshot,aimlapi,openrouter,mistralai,electronhub,azure_openai"> |
| 2019 | <div class="flex-container oneline-dropdown"> | 2019 | <div class="flex-container oneline-dropdown"> |
| 2020 | <label for="openai_inline_image_quality" data-i18n="Inline Image Quality"> | 2020 | <label for="openai_inline_image_quality" data-i18n="Inline Image Quality"> |
| 2021 | Inline Image Quality | 2021 | Inline Image Quality |
| @@ -2077,7 +2077,7 @@ | |||
| 2077 | </span> | 2077 | </span> |
| 2078 | </div> | 2078 | </div> |
| 2079 | </div> | 2079 | </div> |
| 2080 | <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi"> | 2080 | <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi,electronhub,azure_openai"> |
| 2081 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> | 2081 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 2082 | <input id="openai_show_thoughts" type="checkbox" /> | 2082 | <input id="openai_show_thoughts" type="checkbox" /> |
| 2083 | <span data-i18n="Request model reasoning">Request model reasoning</span> | 2083 | <span data-i18n="Request model reasoning">Request model reasoning</span> |
| @@ -2091,7 +2091,7 @@ | |||
| 2091 | </span> | 2091 | </span> |
| 2092 | </div> | 2092 | </div> |
| 2093 | </div> | 2093 | </div> |
| 2094 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity,cometapi"> | 2094 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity,cometapi,electronhub,azure_openai"> |
| 2095 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> | 2095 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> |
| 2096 | <label for="openai_reasoning_effort"> | 2096 | <label for="openai_reasoning_effort"> |
| 2097 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> | 2097 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> |
| @@ -2105,7 +2105,7 @@ | |||
| 2105 | <option data-i18n="openai_reasoning_effort_high" value="high">High</option> | 2105 | <option data-i18n="openai_reasoning_effort_high" value="high">High</option> |
| 2106 | <option data-i18n="openai_reasoning_effort_maximum" value="max">Maximum</option> | 2106 | <option data-i18n="openai_reasoning_effort_maximum" value="max">Maximum</option> |
| 2107 | </select> | 2107 | </select> |
| 2108 | <div class="toggle-description justifyLeft marginBot5" data-source="openai,custom,xai,aimlapi,openrouter,perplexity" data-i18n="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."> | 2108 | <div class="toggle-description justifyLeft marginBot5" data-source="openai,custom,xai,aimlapi,openrouter,perplexity,electronhub,azure_openai" data-i18n="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."> |
| 2109 | OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level. | 2109 | OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level. |
| 2110 | </div> | 2110 | </div> |
| 2111 | <div class="toggle-description justifyLeft marginBot5" data-source="claude" data-i18n="Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking."> | 2111 | <div class="toggle-description justifyLeft marginBot5" data-source="claude" data-i18n="Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking."> |
| @@ -2144,7 +2144,7 @@ | |||
| 2144 | </div> | 2144 | </div> |
| 2145 | </div> | 2145 | </div> |
| 2146 | </div> | 2146 | </div> |
| 2147 | <div class="range-block m-t-1" data-source="openai,aimlapi,openrouter,custom"> | 2147 | <div class="range-block m-t-1" data-source="openai,aimlapi,openrouter,custom,azure_openai"> |
| 2148 | <div id="logit_bias_openai" class="range-block-title openai_restorable" data-i18n="Logit Bias"> | 2148 | <div id="logit_bias_openai" class="range-block-title openai_restorable" data-i18n="Logit Bias"> |
| 2149 | Logit Bias | 2149 | Logit Bias |
| 2150 | </div> | 2150 | </div> |
| @@ -2802,11 +2802,13 @@ | |||
| 2802 | <optgroup> | 2802 | <optgroup> |
| 2803 | <option value="ai21">AI21</option> | 2803 | <option value="ai21">AI21</option> |
| 2804 | <option value="aimlapi">AI/ML API</option> | 2804 | <option value="aimlapi">AI/ML API</option> |
| 2805 | <option value="azure_openai">Azure OpenAI</option> | ||
| 2805 | <option value="claude">Claude</option> | 2806 | <option value="claude">Claude</option> |
| 2806 | <option value="cohere">Cohere</option> | 2807 | <option value="cohere">Cohere</option> |
| 2807 | <!-- Temporarily disabled. --> | 2808 | <!-- Temporarily disabled. --> |
| 2808 | <!-- <option value="cometapi">CometAPI</option> --> | 2809 | <!-- <option value="cometapi">CometAPI</option> --> |
| 2809 | <option value="deepseek">DeepSeek</option> | 2810 | <option value="deepseek">DeepSeek</option> |
| 2811 | <option value="electronhub">Electron Hub</option> | ||
| 2810 | <option value="fireworks">Fireworks AI</option> | 2812 | <option value="fireworks">Fireworks AI</option> |
| 2811 | <option value="groq">Groq</option> | 2813 | <option value="groq">Groq</option> |
| 2812 | <option value="makersuite">Google AI Studio</option> | 2814 | <option value="makersuite">Google AI Studio</option> |
| @@ -3178,6 +3180,7 @@ | |||
| 3178 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 3180 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 3179 | <option value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> | 3181 | <option value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> |
| 3180 | <option value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | 3182 | <option value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> |
| 3183 | <option value="gemini-2.5-flash-image-preview">gemini-2.5-flash-image-preview</option> | ||
| 3181 | </optgroup> | 3184 | </optgroup> |
| 3182 | <optgroup label="Gemini 2.0"> | 3185 | <optgroup label="Gemini 2.0"> |
| 3183 | <option value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> | 3186 | <option value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> |
| @@ -3356,6 +3359,7 @@ | |||
| 3356 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 3359 | <option value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 3357 | <option value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> | 3360 | <option value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> |
| 3358 | <option value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | 3361 | <option value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> |
| 3362 | <option value="gemini-2.5-flash-image-preview">gemini-2.5-flash-image-preview</option> | ||
| 3359 | </optgroup> | 3363 | </optgroup> |
| 3360 | <optgroup label="Gemini 2.0"> | 3364 | <optgroup label="Gemini 2.0"> |
| 3361 | <option value="gemini-2.0-flash-exp" data-mode="full">gemini-2.0-flash-exp</option> | 3365 | <option value="gemini-2.0-flash-exp" data-mode="full">gemini-2.0-flash-exp</option> |
| @@ -3467,6 +3471,20 @@ | |||
| 3467 | <option value="mistral-saba-24b">mistral-saba-24b</option> | 3471 | <option value="mistral-saba-24b">mistral-saba-24b</option> |
| 3468 | </select> | 3472 | </select> |
| 3469 | </div> | 3473 | </div> |
| 3474 | <div id="electronhub_form" data-source="electronhub"> | ||
| 3475 | <h4 data-i18n="Electron Hub API Key">Electron Hub API Key</h4> | ||
| 3476 | <div class="flex-container"> | ||
| 3477 | <input id="api_key_electronhub" name="api_key_electronhub" class="text_pole flex1" value="" type="text" autocomplete="off"> | ||
| 3478 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_electronhub"></div> | ||
| 3479 | </div> | ||
| 3480 | <div data-for="api_key_electronhub" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'."> | ||
| 3481 | For privacy reasons, your API key will be hidden after you click 'Connect'. | ||
| 3482 | </div> | ||
| 3483 | <h4 data-i18n="Electron Hub Model">Electron Hub Model</h4> | ||
| 3484 | <select id="model_electronhub_select"> | ||
| 3485 | <option value="" data-i18n="-- Connect to the API --">-- Connect to the API --</option> | ||
| 3486 | </select> | ||
| 3487 | </div> | ||
| 3470 | <div id="nanogpt_form" data-source="nanogpt"> | 3488 | <div id="nanogpt_form" data-source="nanogpt"> |
| 3471 | <h4 data-i18n="NanoGPT API Key">NanoGPT API Key</h4> | 3489 | <h4 data-i18n="NanoGPT API Key">NanoGPT API Key</h4> |
| 3472 | <div class="flex-container"> | 3490 | <div class="flex-container"> |
| @@ -3718,6 +3736,49 @@ | |||
| 3718 | <option value="kimi-thinking-preview">kimi-thinking-preview</option> | 3736 | <option value="kimi-thinking-preview">kimi-thinking-preview</option> |
| 3719 | </select> | 3737 | </select> |
| 3720 | </div> | 3738 | </div> |
| 3739 | <div id="azure_openai_settings" data-source="azure_openai"> | ||
| 3740 | <!-- Azure Base URL --> | ||
| 3741 | <h4><span data-i18n="Azure Base URL">Azure Base URL</span></h4> | ||
| 3742 | <div class="flex-container"> | ||
| 3743 | <input id="azure_base_url" data-setting="azure_base_url" class="text_pole wide100p" type="text" placeholder="https://your-resource.openai.azure.com/"> | ||
| 3744 | </div> | ||
| 3745 | |||
| 3746 | <!-- Azure Deployment Name --> | ||
| 3747 | <h4><span data-i18n="Deployment Name">Deployment Name</span></h4> | ||
| 3748 | <div class="flex-container"> | ||
| 3749 | <input id="azure_deployment_name" data-setting="azure_deployment_name" class="text_pole wide100p" type="text" placeholder="your-deployment-name" title="The name of your model deployment in Azure." data-i18n="[title]The name of your model deployment in Azure."> | ||
| 3750 | </div> | ||
| 3751 | |||
| 3752 | <!-- Azure API Version Dropdown --> | ||
| 3753 | <h4><span data-i18n="API Version">API Version</span></h4> | ||
| 3754 | <div class="flex-container"> | ||
| 3755 | <select id="azure_api_version" data-setting="azure_api_version" class="text_pole wide100p"> | ||
| 3756 | <option value="2025-04-01-preview">2025-04-01-preview</option> | ||
| 3757 | <option value="2024-10-21">2024-10-21</option> | ||
| 3758 | </select> | ||
| 3759 | </div> | ||
| 3760 | |||
| 3761 | <!-- Azure API Key --> | ||
| 3762 | <h4><span data-i18n="Azure API Key">Azure API Key</span></h4> | ||
| 3763 | <div class="flex-container"> | ||
| 3764 | <input id="api_key_azure_openai" data-setting="api_key_azure_openai" class="text_pole flex1" type="password" autocomplete="off"> | ||
| 3765 | <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_azure_openai"></div> | ||
| 3766 | </div> | ||
| 3767 | <div class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'." data-for="api_key_azure_openai"> | ||
| 3768 | For privacy reasons, your API key will be hidden after you click 'Connect'. | ||
| 3769 | </div> | ||
| 3770 | |||
| 3771 | <!-- Model Name (Select) --> | ||
| 3772 | <h4><span data-i18n="Model Name">Model Name</span></h4> | ||
| 3773 | <div class="flex-container"> | ||
| 3774 | <select id="azure_openai_model" data-setting="azure_openai_model" class="text_pole wide100p"> | ||
| 3775 | <option value="" disabled selected data-i18n="Click 'Connect' to fetch model name">Click 'Connect' to fetch model name</option> | ||
| 3776 | </select> | ||
| 3777 | </div> | ||
| 3778 | <div> | ||
| 3779 | <small data-i18n="The underlying model of your deployment. This is detected automatically when you connect.">The underlying model of your deployment. This is detected automatically when you connect.</small> | ||
| 3780 | </div> | ||
| 3781 | </div> | ||
| 3721 | <div id="prompt_post_processing_form"> | 3782 | <div id="prompt_post_processing_form"> |
| 3722 | <h4> | 3783 | <h4> |
| 3723 | <span data-i18n="Prompt Post-Processing"> | 3784 | <span data-i18n="Prompt Post-Processing"> |
| @@ -5282,13 +5343,11 @@ | |||
| 5282 | <div id="site_logo" class="drawer-toggle drawer-header" title="Change Background Image" data-i18n="[title]Change Background Image"> | 5343 | <div id="site_logo" class="drawer-toggle drawer-header" title="Change Background Image" data-i18n="[title]Change Background Image"> |
| 5283 | <div class="drawer-icon fa-solid fa-panorama fa-fw closedIcon"></div> | 5344 | <div class="drawer-icon fa-solid fa-panorama fa-fw closedIcon"></div> |
| 5284 | </div> | 5345 | </div> |
| 5285 | <div id="Backgrounds" class="drawer-content closedDrawer"> | 5346 | <div id="Backgrounds" class="drawer-content closedDrawer bg-drawer-layout"> |
| 5286 | <div class="flex-container"> | 5347 | <div id="bg-header-fixed"> |
| 5287 | <div class="flex-container alignItemsBaseline wide100p"> | 5348 | <div class="flex-container alignItemsBaseline wide100p"> |
| 5288 | <h3 class="margin0 flex2" data-i18n="Background Image"> | 5349 | <h3 id="bg-header-title" class="margin0" data-i18n="Backgrounds">Backgrounds</h3> |
| 5289 | Background Image | 5350 | <input id="bg-filter" class="text_pole flex1" type="search" data-i18n="[placeholder]Search" placeholder="Search" /> |
| 5290 | </h3> | ||
| 5291 | <input id="bg-filter" data-i18n="[placeholder]Filter" placeholder="Filter" class="text_pole flex1" type="search" /> | ||
| 5292 | <select id="background_fitting" class="text_pole" data-i18n="[title]Background Fitting" title="Background Fitting"> | 5351 | <select id="background_fitting" class="text_pole" data-i18n="[title]Background Fitting" title="Background Fitting"> |
| 5293 | <option value="classic" data-i18n="Classic">Classic</option> | 5352 | <option value="classic" data-i18n="Classic">Classic</option> |
| 5294 | <option value="cover" data-i18n="Cover">Cover</option> | 5353 | <option value="cover" data-i18n="Cover">Cover</option> |
| @@ -5300,17 +5359,17 @@ | |||
| 5300 | <i class="fa-solid fa-wand-magic"></i> | 5359 | <i class="fa-solid fa-wand-magic"></i> |
| 5301 | <span data-i18n="Auto-select">Auto-select</span> | 5360 | <span data-i18n="Auto-select">Auto-select</span> |
| 5302 | </div> | 5361 | </div> |
| 5362 | <label for="add_bg_button" id="add_background_button_top" class="menu_button menu_button_icon interactable" title="Add a new background"> | ||
| 5363 | <i class="fa-solid fa-plus"></i> | ||
| 5364 | <span data-i18n="Add Background">Add Background</span> | ||
| 5365 | </label> | ||
| 5303 | </div> | 5366 | </div> |
| 5367 | </div> | ||
| 5368 | <div id="bg-scrollable-content"> | ||
| 5304 | <h3 data-i18n="System Backgrounds" class="wide100p textAlignCenter"> | 5369 | <h3 data-i18n="System Backgrounds" class="wide100p textAlignCenter"> |
| 5305 | System Backgrounds | 5370 | System Backgrounds |
| 5306 | </h3> | 5371 | </h3> |
| 5307 | <div id="bg_menu_content" class="bg_list"> | 5372 | <div id="bg_menu_content" class="bg_list"> |
| 5308 | <form id="form_bg_download" class="bg_example no-border no-shadow" action="javascript:void(null);" method="post" enctype="multipart/form-data"> | ||
| 5309 | <label class="input-file"> | ||
| 5310 | <input type="file" id="add_bg_button" name="avatar" accept="image/*, video/*"> | ||
| 5311 | <div class="bg_example no-border no-shadow add_bg_but" style="background-image: url('/img/addbg3.png');"></div> | ||
| 5312 | </label> | ||
| 5313 | </form> | ||
| 5314 | </div> | 5373 | </div> |
| 5315 | <h3 data-i18n="Chat Backgrounds" class="wide100p textAlignCenter"> | 5374 | <h3 data-i18n="Chat Backgrounds" class="wide100p textAlignCenter"> |
| 5316 | Chat Backgrounds | 5375 | Chat Backgrounds |
| @@ -5321,6 +5380,9 @@ | |||
| 5321 | <div id="bg_custom_content" class="bg_list"> | 5380 | <div id="bg_custom_content" class="bg_list"> |
| 5322 | </div> | 5381 | </div> |
| 5323 | </div> | 5382 | </div> |
| 5383 | <form id="form_bg_upload" style="display: none;"> | ||
| 5384 | <input type="file" id="add_bg_button" name="avatar" accept="image/jpeg,image/png,image/gif,image/bmp,image/svg+xml,video/*"> | ||
| 5385 | </form> | ||
| 5324 | </div> | 5386 | </div> |
| 5325 | </div> | 5387 | </div> |
| 5326 | <div id="extensions-settings-button" class="drawer"> | 5388 | <div id="extensions-settings-button" class="drawer"> |
| @@ -5410,7 +5472,7 @@ | |||
| 5410 | <div class="drawer-toggle"> | 5472 | <div class="drawer-toggle"> |
| 5411 | <div class="drawer-icon fa-solid fa-face-smile fa-fw closedIcon" title="Persona Management" data-i18n="[title]Persona Management"></div> | 5473 | <div class="drawer-icon fa-solid fa-face-smile fa-fw closedIcon" title="Persona Management" data-i18n="[title]Persona Management"></div> |
| 5412 | </div> | 5474 | </div> |
| 5413 | <div class="drawer-content closedDrawer"> | 5475 | <div id="PersonaManagement" class="drawer-content closedDrawer"> |
| 5414 | <div class="flex-container wide100p alignitemscenter spaceBetween flexNoGap"> | 5476 | <div class="flex-container wide100p alignitemscenter spaceBetween flexNoGap"> |
| 5415 | <div class="flex-container alignItemsBaseline wide100p"> | 5477 | <div class="flex-container alignItemsBaseline wide100p"> |
| 5416 | <div class="flex1 flex-container alignItemsBaseline"> | 5478 | <div class="flex1 flex-container alignItemsBaseline"> |
| @@ -6254,14 +6316,20 @@ | |||
| 6254 | </div> | 6316 | </div> |
| 6255 | </div> | 6317 | </div> |
| 6256 | <div id="background_template" class="template_element"> | 6318 | <div id="background_template" class="template_element"> |
| 6257 | <div class="bg_example flex-container" bgfile="" class="bg_example_img" title=""> | 6319 | <div class="bg_example flex-container" bgfile="" title=""> |
| 6258 | <div title="Copy to system backgrounds" data-i18n="[title]Copy to system backgrounds" class="bg_button bg_example_copy fa-solid fa-file-arrow-up"></div> | 6320 | <div class="bg_example_img"></div> |
| 6259 | <div title="Rename background" data-i18n="[title]Rename background" class="bg_button bg_example_edit fa-solid fa-pencil"></div> | 6321 | <div class="mobile-only-menu-toggle"> |
| 6260 | <div title="Lock" data-i18n="[title]Lock" class="bg_button bg_example_lock fa-solid fa-lock"></div> | 6322 | <i class="fa-solid fa-ellipsis-vertical"></i> |
| 6261 | <div title="Unlock" data-i18n="[title]Unlock" class="bg_button bg_example_unlock fa-solid fa-lock-open"></div> | 6323 | </div> |
| 6262 | <div title="Delete background" data-i18n="[title]Delete background" class="bg_button bg_example_cross fa-solid fa-circle-xmark"></div> | 6324 | <div class="jg-menu"> |
| 6263 | <div class="BGSampleTitle"> | 6325 | <div data-action="copy" class="jg-button jg-copy fa-solid fa-file-arrow-up" data-i18n="[title]Copy to system backgrounds" title="Copy to system backgrounds"></div> |
| 6326 | <!-- temporarily moved lock icon here (will be moved to header) --> | ||
| 6327 | <div data-action="lock" class="jg-button jg-lock fa-solid fa-lock fa-fw pointer" data-i18n="[title]Lock" title="Lock"></div> | ||
| 6328 | <div data-action="unlock" class="jg-button jg-unlock fa-solid fa-lock-open fa-fw pointer" data-i18n="[title]Unlock" title="Unlock"></div> | ||
| 6329 | <div data-action="edit" class="jg-button jg-edit fa-solid fa-pen-to-square fa-fw pointer" data-i18n="[title]Rename Background" title="Rename Background"></div> | ||
| 6330 | <div data-action="delete" class="jg-button jg-delete fa-solid fa-trash-can fa-fw pointer" data-i18n="[title]Delete Background" title="Delete Background"></div> | ||
| 6264 | </div> | 6331 | </div> |
| 6332 | <div class="BGSampleTitle"></div> | ||
| 6265 | </div> | 6333 | </div> |
| 6266 | </div> | 6334 | </div> |
| 6267 | <!-- templates for JS to reuse when needed --> | 6335 | <!-- templates for JS to reuse when needed --> |
| @@ -6437,7 +6505,7 @@ | |||
| 6437 | </span> | 6505 | </span> |
| 6438 | <div class="flex-container"> | 6506 | <div class="flex-container"> |
| 6439 | <div class="flex-container flexFlowColumn"> | 6507 | <div class="flex-container flexFlowColumn"> |
| 6440 | <label class="checkbox flex-container alignitemscenter flexNoGap" title="This entry will not be recursively activated by other entries."> | 6508 | <label class="checkbox flex-container alignitemscenter flexNoGap" data-i18n="[title]This entry will not be recursively activated by other entries." title="This entry will not be recursively activated by other entries."> |
| 6441 | <input type="checkbox" name="excludeRecursion" /> | 6509 | <input type="checkbox" name="excludeRecursion" /> |
| 6442 | <span data-i18n="Non-recursable"> | 6510 | <span data-i18n="Non-recursable"> |
| 6443 | Non-recursable | 6511 | Non-recursable |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "وضع علامة", | 317 | "flag": "وضع علامة", |
| 318 | "API key (optional)": "مفتاح API (اختياري)", | 318 | "API key (optional)": "مفتاح API (اختياري)", |
| 319 | "Server url": "رابط الخادم", | 319 | "Server url": "رابط الخادم", |
| 320 | "Electron Hub API Key": "مفتاح API لـ Electron Hub", | ||
| 321 | "Electron Hub Model": "نموذج Electron Hub", | ||
| 320 | "Example: http://127.0.0.1:5000": "مثال: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "مثال: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "نموذج مخصص (اختياري)", | 323 | "Custom model (optional)": "نموذج مخصص (اختياري)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (وضع غلاف OpenAI API)", | 324 | "vllm-project/vllm": "vllm-project/vllm (وضع غلاف OpenAI API)", |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "Flagge", | 317 | "flag": "Flagge", |
| 318 | "API key (optional)": "API-Schlüssel (optional)", | 318 | "API key (optional)": "API-Schlüssel (optional)", |
| 319 | "Server url": "Server-URL", | 319 | "Server url": "Server-URL", |
| 320 | "Electron Hub API Key": "Electron Hub API-Schlüssel", | ||
| 321 | "Electron Hub Model": "Electron Hub-Modell", | ||
| 320 | "Example: http://127.0.0.1:5000": "Beispiel: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "Beispiel: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "Benutzerdefiniertes Modell (optional)", | 323 | "Custom model (optional)": "Benutzerdefiniertes Modell (optional)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API-Wrappermodus)", | 324 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API-Wrappermodus)", |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "bandera", | 317 | "flag": "bandera", |
| 318 | "API key (optional)": "Clave API (opcional)", | 318 | "API key (optional)": "Clave API (opcional)", |
| 319 | "Server url": "URL del servidor", | 319 | "Server url": "URL del servidor", |
| 320 | "Electron Hub API Key": "Clave API de Electron Hub", | ||
| 321 | "Electron Hub Model": "Modelo de Electron Hub", | ||
| 320 | "Example: http://127.0.0.1:5000": "Ejemplo: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "Ejemplo: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "Modelo personalizado (opcional)", | 323 | "Custom model (optional)": "Modelo personalizado (opcional)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (modo contenedor de API OpenAI)", | 324 | "vllm-project/vllm": "vllm-project/vllm (modo contenedor de API OpenAI)", |
| @@ -1411,6 +1411,8 @@ | |||
| 1411 | "Do not proceed if you do not agree to this!": "Ne continuez pas si vous n'êtes pas d'accord avec cela !", | 1411 | "Do not proceed if you do not agree to this!": "Ne continuez pas si vous n'êtes pas d'accord avec cela !", |
| 1412 | "Claude API Key": "Clé API Claude", | 1412 | "Claude API Key": "Clé API Claude", |
| 1413 | "Allow fallback models": "Autoriser les modèles de secours", | 1413 | "Allow fallback models": "Autoriser les modèles de secours", |
| 1414 | "Electron Hub API Key": "Clé API Electron Hub", | ||
| 1415 | "Electron Hub Model": "Modèle Electron Hub", | ||
| 1414 | "NanoGPT API Key": "Clé API NanoGPT", | 1416 | "NanoGPT API Key": "Clé API NanoGPT", |
| 1415 | "NanoGPT Model": "Modèle NanoGPT", | 1417 | "NanoGPT Model": "Modèle NanoGPT", |
| 1416 | "DeepSeek API Key": "Clé API DeepSeek", | 1418 | "DeepSeek API Key": "Clé API DeepSeek", |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "bandiera", | 317 | "flag": "bandiera", |
| 318 | "API key (optional)": "Chiave API (opzionale)", | 318 | "API key (optional)": "Chiave API (opzionale)", |
| 319 | "Server url": "URL del server", | 319 | "Server url": "URL del server", |
| 320 | "Electron Hub API Key": "Chiave API di Electron Hub", | ||
| 321 | "Electron Hub Model": "Modello di Electron Hub", | ||
| 320 | "Example: http://127.0.0.1:5000": "Esempio: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "Esempio: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "Modello personalizzato (opzionale)", | 323 | "Custom model (optional)": "Modello personalizzato (opzionale)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (modalità wrapper API OpenAI)", | 324 | "vllm-project/vllm": "vllm-project/vllm (modalità wrapper API OpenAI)", |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "フラグ", | 317 | "flag": "フラグ", |
| 318 | "API key (optional)": "APIキー(オプション)", | 318 | "API key (optional)": "APIキー(オプション)", |
| 319 | "Server url": "サーバーURL", | 319 | "Server url": "サーバーURL", |
| 320 | "Electron Hub API Key": "Electron Hub API キー", | ||
| 321 | "Electron Hub Model": "Electron Hub モデル", | ||
| 320 | "Example: http://127.0.0.1:5000": "例: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "例: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "カスタムモデル(オプション)", | 323 | "Custom model (optional)": "カスタムモデル(オプション)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API ラッパーモード)", | 324 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API ラッパーモード)", |
| @@ -319,6 +319,8 @@ | |||
| 319 | "flag": "깃발", | 319 | "flag": "깃발", |
| 320 | "API key (optional)": "API 키 (선택 사항)", | 320 | "API key (optional)": "API 키 (선택 사항)", |
| 321 | "Server url": "서버 URL", | 321 | "Server url": "서버 URL", |
| 322 | "Electron Hub API Key": "Electron Hub API 키", | ||
| 323 | "Electron Hub Model": "Electron Hub 모델", | ||
| 322 | "Example: http://127.0.0.1:5000": "예시: http://127.0.0.1:5000", | 324 | "Example: http://127.0.0.1:5000": "예시: http://127.0.0.1:5000", |
| 323 | "Custom model (optional)": "사용자 정의 모델 (선택 사항)", | 325 | "Custom model (optional)": "사용자 정의 모델 (선택 사항)", |
| 324 | "vllm-project/vllm": "vllm-project/vllm(OpenAI API 래퍼 모드)", | 326 | "vllm-project/vllm": "vllm-project/vllm(OpenAI API 래퍼 모드)", |
| @@ -1,17 +1,66 @@ | |||
| 1 | [ | ||
| 2 | { "lang": "ar-sa", "display": "عربي (Arabic)" }, | ||
| 3 | { "lang": "zh-cn", "display": "简体中文 (Chinese) (Simplified)" }, | ||
| 4 | { "lang": "zh-tw", "display": "繁體中文 (Chinese) (Taiwan)" }, | ||
| 5 | { "lang": "nl-nl", "display": "Nederlands (Dutch)" }, | ||
| 6 | { "lang": "de-de", "display": "Deutsch (German)" }, | ||
| 7 | { "lang": "fr-fr", "display": "Français (French)" }, | ||
| 8 | { "lang": "is-is", "display": "íslenska (Icelandic)" }, | ||
| 9 | { "lang": "it-it", "display": "Italiano (Italian)" }, | ||
| 10 | { "lang": "ja-jp", "display": "日本語 (Japanese)" }, | ||
| 11 | { "lang": "ko-kr", "display": "한국어 (Korean)" }, | ||
| 12 | { "lang": "pt-pt", "display": "Português (Portuguese brazil)" }, | ||
| 13 | { "lang": "ru-ru", "display": "Русский (Russian)" }, | ||
| 14 | { "lang": "es-es", "display": "Español (Spanish)" }, | ||
| 15 | { "lang": "uk-ua", "display": "Yкраїнська (Ukrainian)" }, | ||
| 16 | { "lang": "vi-vn", "display": "Tiếng Việt (Vietnamese)" } | ||
| 17 | ] | ||
| 17 | \ No newline at end of file | \ No newline at end of file | |
| 1 | [ | ||
| 2 | { | ||
| 3 | "lang": "ar-sa", | ||
| 4 | "display": "عربي (Arabic)" | ||
| 5 | }, | ||
| 6 | { | ||
| 7 | "lang": "zh-cn", | ||
| 8 | "display": "简体中文 (Chinese) (Simplified)" | ||
| 9 | }, | ||
| 10 | { | ||
| 11 | "lang": "zh-tw", | ||
| 12 | "display": "繁體中文 (Chinese) (Taiwan)" | ||
| 13 | }, | ||
| 14 | { | ||
| 15 | "lang": "nl-nl", | ||
| 16 | "display": "Nederlands (Dutch)" | ||
| 17 | }, | ||
| 18 | { | ||
| 19 | "lang": "de-de", | ||
| 20 | "display": "Deutsch (German)" | ||
| 21 | }, | ||
| 22 | { | ||
| 23 | "lang": "fr-fr", | ||
| 24 | "display": "Français (French)" | ||
| 25 | }, | ||
| 26 | { | ||
| 27 | "lang": "is-is", | ||
| 28 | "display": "íslenska (Icelandic)" | ||
| 29 | }, | ||
| 30 | { | ||
| 31 | "lang": "it-it", | ||
| 32 | "display": "Italiano (Italian)" | ||
| 33 | }, | ||
| 34 | { | ||
| 35 | "lang": "ja-jp", | ||
| 36 | "display": "日本語 (Japanese)" | ||
| 37 | }, | ||
| 38 | { | ||
| 39 | "lang": "ko-kr", | ||
| 40 | "display": "한국어 (Korean)" | ||
| 41 | }, | ||
| 42 | { | ||
| 43 | "lang": "pt-pt", | ||
| 44 | "display": "Português (Portuguese brazil)" | ||
| 45 | }, | ||
| 46 | { | ||
| 47 | "lang": "ru-ru", | ||
| 48 | "display": "Русский (Russian)" | ||
| 49 | }, | ||
| 50 | { | ||
| 51 | "lang": "es-es", | ||
| 52 | "display": "Español (Spanish)" | ||
| 53 | }, | ||
| 54 | { | ||
| 55 | "lang": "uk-ua", | ||
| 56 | "display": "Українська (Ukrainian)" | ||
| 57 | }, | ||
| 58 | { | ||
| 59 | "lang": "vi-vn", | ||
| 60 | "display": "Tiếng Việt (Vietnamese)" | ||
| 61 | }, | ||
| 62 | { | ||
| 63 | "lang": "th-th", | ||
| 64 | "display": "ไทย (Thai)" | ||
| 65 | } | ||
| 66 | ] | ||
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "bandeira", | 317 | "flag": "bandeira", |
| 318 | "API key (optional)": "Chave da API (opcional)", | 318 | "API key (optional)": "Chave da API (opcional)", |
| 319 | "Server url": "URL do servidor", | 319 | "Server url": "URL do servidor", |
| 320 | "Electron Hub API Key": "Chave API Electron Hub", | ||
| 321 | "Electron Hub Model": "Modelo Electron Hub", | ||
| 320 | "Example: http://127.0.0.1:5000": "Exemplo: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "Exemplo: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "Modelo personalizado (opcional)", | 323 | "Custom model (optional)": "Modelo personalizado (opcional)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (modo wrapper da API OpenAI)", | 324 | "vllm-project/vllm": "vllm-project/vllm (modo wrapper da API OpenAI)", |
| @@ -40,7 +40,7 @@ | |||
| 40 | "Smoothing Factor": "Коэффициент сглаживания", | 40 | "Smoothing Factor": "Коэффициент сглаживания", |
| 41 | "No Repeat Ngram Size": "Размер no_repeat_ngram", | 41 | "No Repeat Ngram Size": "Размер no_repeat_ngram", |
| 42 | "Min Length": "Мин. длина", | 42 | "Min Length": "Мин. длина", |
| 43 | "Alternative server URL (leave empty to use the default value).": "URL альтернативного сервера (оставьте пустым для стандартного значения)", | 43 | "Alternative server URL (leave empty to use the default value).": "URL реверс-прокси (оставьте пустым для стандартного значения)", |
| 44 | "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Удалите свой личный OAI API Key из панели API, и ТОЛЬКО ПОСЛЕ ЭТОГО вводите что-то сюда", | 44 | "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "Удалите свой личный OAI API Key из панели API, и ТОЛЬКО ПОСЛЕ ЭТОГО вводите что-то сюда", |
| 45 | "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Мы не сможем предоставить помощь с проблемами, с которыми вы столкнетесь при использовании неофициальных прокси для OpenAI", | 45 | "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "Мы не сможем предоставить помощь с проблемами, с которыми вы столкнетесь при использовании неофициальных прокси для OpenAI", |
| 46 | "Context Size (tokens)": "Размер контекста (в токенах)", | 46 | "Context Size (tokens)": "Размер контекста (в токенах)", |
| @@ -145,7 +145,7 @@ | |||
| 145 | "View API Usage Metrics": "Посмотреть статистику использования API", | 145 | "View API Usage Metrics": "Посмотреть статистику использования API", |
| 146 | "Show External models (provided by API)": "Показать \"сторонние\" модели (предоставленные API)", | 146 | "Show External models (provided by API)": "Показать \"сторонние\" модели (предоставленные API)", |
| 147 | "Allow fallback routes": "Разрешить резервные маршруты", | 147 | "Allow fallback routes": "Разрешить резервные маршруты", |
| 148 | "Allow fallback routes Description": "Автоматически выбирает альтернативную модель, если выбранная модель не может удовлетворить ваш запрос.", | 148 | "Allow fallback routes Description": "Автоматически выбирает альтернативную модель, если выбранная модель не может обслужить ваш запрос.", |
| 149 | "OpenRouter API Key": "Ключ от OpenRouter API", | 149 | "OpenRouter API Key": "Ключ от OpenRouter API", |
| 150 | "OpenRouter Model": "Модель OpenRouter", | 150 | "OpenRouter Model": "Модель OpenRouter", |
| 151 | "View Remaining Credits": "Посмотреть оставшиеся кредиты", | 151 | "View Remaining Credits": "Посмотреть оставшиеся кредиты", |
| @@ -154,7 +154,7 @@ | |||
| 154 | "View hidden API keys": "Посмотреть скрытые API-ключи", | 154 | "View hidden API keys": "Посмотреть скрытые API-ключи", |
| 155 | "Advanced Formatting": "Расширенное форматирование", | 155 | "Advanced Formatting": "Расширенное форматирование", |
| 156 | "Context Template": "Шаблон контекста", | 156 | "Context Template": "Шаблон контекста", |
| 157 | "Replace Macro in Stop Strings": "Заменять макросы в пользовательских стоп-строках", | 157 | "Replace Macro in Stop Strings": "Заменять макросы в стоп-строках", |
| 158 | "Story String": "Общий шаблон", | 158 | "Story String": "Общий шаблон", |
| 159 | "Example Separator": "Разделитель примеров сообщений", | 159 | "Example Separator": "Разделитель примеров сообщений", |
| 160 | "Chat Start": "Начало чата", | 160 | "Chat Start": "Начало чата", |
| @@ -184,7 +184,7 @@ | |||
| 184 | "Scan Depth": "Глубина сканирования", | 184 | "Scan Depth": "Глубина сканирования", |
| 185 | "Case-Sensitive": "С учетом регистра", | 185 | "Case-Sensitive": "С учетом регистра", |
| 186 | "Match Whole Words": "Только полное совпадение", | 186 | "Match Whole Words": "Только полное совпадение", |
| 187 | "Use global setting": "Использовать глобальную настройку", | 187 | "Use global setting": "Глоб. настройка", |
| 188 | "Yes": "Да", | 188 | "Yes": "Да", |
| 189 | "No": "Нет", | 189 | "No": "Нет", |
| 190 | "Context %": "Процент контекста", | 190 | "Context %": "Процент контекста", |
| @@ -201,7 +201,7 @@ | |||
| 201 | "Bubbles": "Пузыри", | 201 | "Bubbles": "Пузыри", |
| 202 | "No Blur Effect": "Отключить размытие", | 202 | "No Blur Effect": "Отключить размытие", |
| 203 | "No Text Shadows": "Отключить тень текста", | 203 | "No Text Shadows": "Отключить тень текста", |
| 204 | "Waifu Mode": "Рeжим Вайфу", | 204 | "Waifu Mode": "Режим вайфу", |
| 205 | "Message Timer": "Таймер сообщений", | 205 | "Message Timer": "Таймер сообщений", |
| 206 | "Model Icon": "Значки моделей", | 206 | "Model Icon": "Значки моделей", |
| 207 | "Advanced Character Search": "Расширенный поиск по персонажам", | 207 | "Advanced Character Search": "Расширенный поиск по персонажам", |
| @@ -279,7 +279,7 @@ | |||
| 279 | "Impersonate": "Перевоплощение", | 279 | "Impersonate": "Перевоплощение", |
| 280 | "Regenerate": "Повторная генерация", | 280 | "Regenerate": "Повторная генерация", |
| 281 | "Message Sound": "Звук сообщения", | 281 | "Message Sound": "Звук сообщения", |
| 282 | "Author's Note": "Заметки автора", | 282 | "Author's Note": "Авторские заметки", |
| 283 | "Replace empty message": "Заменять пустые сообщения", | 283 | "Replace empty message": "Заменять пустые сообщения", |
| 284 | "Send this text instead of nothing when the text box is empty.": "Этот текст будет отправлен в случае отсутствия текста на отправку.", | 284 | "Send this text instead of nothing when the text box is empty.": "Этот текст будет отправлен в случае отсутствия текста на отправку.", |
| 285 | "Unrestricted maximum value for the context slider": "Убрать потолок для ползунка контекста. Включайте только если точно понимаете, что делаете", | 285 | "Unrestricted maximum value for the context slider": "Убрать потолок для ползунка контекста. Включайте только если точно понимаете, что делаете", |
| @@ -322,8 +322,8 @@ | |||
| 322 | "Order ↘": "Порядок ↘", | 322 | "Order ↘": "Порядок ↘", |
| 323 | "UID ↗": "UID ↗", | 323 | "UID ↗": "UID ↗", |
| 324 | "UID ↘": "UID ↘", | 324 | "UID ↘": "UID ↘", |
| 325 | "Trigger% ↗": "Триггер% ↗", | 325 | "Trigger% ↗": "% срабатываний ↗", |
| 326 | "Trigger% ↘": "Триггер% ↘", | 326 | "Trigger% ↘": "% срабатываний ↘", |
| 327 | "Depth:": "Глубина:", | 327 | "Depth:": "Глубина:", |
| 328 | "Character Lore First": "Сначала лор персонажа", | 328 | "Character Lore First": "Сначала лор персонажа", |
| 329 | "Global Lore First": "Сначала глобальный лор", | 329 | "Global Lore First": "Сначала глобальный лор", |
| @@ -334,12 +334,17 @@ | |||
| 334 | "Exclude from recursion": "Исключить из рекурсии", | 334 | "Exclude from recursion": "Исключить из рекурсии", |
| 335 | "Entry Title/Memo": "Название или заметка о записи", | 335 | "Entry Title/Memo": "Название или заметка о записи", |
| 336 | "Position:": "Положение:", | 336 | "Position:": "Положение:", |
| 337 | "T_Position": "↑Char: Перед определениями Персонажа\n↓Char: После определений Персонажа\n↑AN: Перед Пометок автора\n↓AN: После Пометок автора\n@D: На глубине", | 337 | "T_Position": "↑Перс: Перед описанием персонажа\n↓Перс: После описания персонажа\n↑ПС: Перед примерами сообщений\n↓ПС: После примеров сообщений\n↑АЗ: Перед авторскими заметками\n↓АЗ: После авторских заметок\nНа глуб. ⚙️: на глубине (система)\nНа глуб. 👤: на глубине (пользователь)\nНа глуб. 🤖: на глубине (ассистент)", |
| 338 | "Before Char Defs": "↑Перс.", | 338 | "Before Char Defs": "↑Перс.", |
| 339 | "After Char Defs": "↓Перс.", | 339 | "After Char Defs": "↓Перс.", |
| 340 | "Before AN": "↑АЗ", | 340 | "Before AN": "↑АЗ", |
| 341 | "After AN": "↓АЗ", | 341 | "After AN": "↓АЗ", |
| 342 | "Order": "Очерёдность:", | 342 | "Before EM": "↑ПС", |
| 343 | "After EM": "↓ПС", | ||
| 344 | "at Depth System": "На глуб. ⚙️", | ||
| 345 | "at Depth User": "На глуб. 👤", | ||
| 346 | "at Depth AI": "На глуб. 🤖", | ||
| 347 | "Order": "Приоритет:", | ||
| 343 | "Update a theme file": "Обновить файл темы", | 348 | "Update a theme file": "Обновить файл темы", |
| 344 | "Save as a new theme": "Сохранить как новую тему", | 349 | "Save as a new theme": "Сохранить как новую тему", |
| 345 | "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.", | 350 | "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.", |
| @@ -385,7 +390,7 @@ | |||
| 385 | "Remove text shadow effect": "Удаление эффекта тени от текста.", | 390 | "Remove text shadow effect": "Удаление эффекта тени от текста.", |
| 386 | "Reduce chat height, and put a static sprite behind the chat window": "Уменьшить высоту чата и поместить статичный спрайт за окном чата.", | 391 | "Reduce chat height, and put a static sprite behind the chat window": "Уменьшить высоту чата и поместить статичный спрайт за окном чата.", |
| 387 | "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Всегда показывать полный список действий с сообщением, а не прятать их за '...'.", | 392 | "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Всегда показывать полный список действий с сообщением, а не прятать их за '...'.", |
| 388 | "Alternative UI for numeric sampling parameters with fewer steps": "Альтернативный пользовательский интерфейс для числовых параметров выборки с меньшим количеством шагов.", | 393 | "Alternative UI for numeric sampling parameters with fewer steps": "Уменьшить кол-во шагов для параметров, регулируемых слайдерами.", |
| 389 | "Entirely unrestrict all numeric sampling parameters": "Снять ограничения со всех числовых сэмплеров.", | 394 | "Entirely unrestrict all numeric sampling parameters": "Снять ограничения со всех числовых сэмплеров.", |
| 390 | "Time the AI's message generation, and show the duration in the chat log": "Время генерации сообщений ИИ и его показ в журнале чата.", | 395 | "Time the AI's message generation, and show the duration in the chat log": "Время генерации сообщений ИИ и его показ в журнале чата.", |
| 391 | "Show a timestamp for each message in the chat log": "Показывать временную метку для каждого сообщения в журнале чата.", | 396 | "Show a timestamp for each message in the chat log": "Показывать временную метку для каждого сообщения в журнале чата.", |
| @@ -409,7 +414,7 @@ | |||
| 409 | "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "При включении этой опции, пользовательский джейлбрейк будет заменяться кастомным джейлбрейком из карточки (при его наличии).", | 414 | "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "При включении этой опции, пользовательский джейлбрейк будет заменяться кастомным джейлбрейком из карточки (при его наличии).", |
| 410 | "Show actual file names on the disk, in the characters list display only": "Отображение названий файлов персонажей на диске, только в списке персонажей.", | 415 | "Show actual file names on the disk, in the characters list display only": "Отображение названий файлов персонажей на диске, только в списке персонажей.", |
| 411 | "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Запрашивать разрешения на импорт встроенных тегов карт при импорте персонажей. В противном случае встроенные теги игнорируются.", | 416 | "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "Запрашивать разрешения на импорт встроенных тегов карт при импорте персонажей. В противном случае встроенные теги игнорируются.", |
| 412 | "Hide character definitions from the editor panel behind a spoiler button": "Спрятать определения персонажей из панели редактора за кнопку спойлера.", | 417 | "Hide character definitions from the editor panel behind a spoiler button": "Спрятать описания персонажей из панели редактора за кнопку спойлера.", |
| 413 | "Show a button in the input area to ask the AI to continue (extend) its last message": "Показывать на форме ответа кнопку, по нажатии на которую ИИ продолжит своё предыдущее сообщение.", | 418 | "Show a button in the input area to ask the AI to continue (extend) its last message": "Показывать на форме ответа кнопку, по нажатии на которую ИИ продолжит своё предыдущее сообщение.", |
| 414 | "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Показывать кнопки со стрелками на последнем сообщении в чате, чтобы генерировать альтернативные ответы ИИ. Как для ПК, так и для мобильных устройств.", | 419 | "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "Показывать кнопки со стрелками на последнем сообщении в чате, чтобы генерировать альтернативные ответы ИИ. Как для ПК, так и для мобильных устройств.", |
| 415 | "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Позволяет использовать жесты смахивания на последнем сообщении в чате, чтобы вызвать альтернативную генерацию. Только для мобильных устройств, на ПК не работает.", | 420 | "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "Позволяет использовать жесты смахивания на последнем сообщении в чате, чтобы вызвать альтернативную генерацию. Только для мобильных устройств, на ПК не работает.", |
| @@ -427,8 +432,8 @@ | |||
| 427 | "Your Persona": "Ваша персона", | 432 | "Your Persona": "Ваша персона", |
| 428 | "Show notifications on switching personas": "Показывать уведомления при смене персоны", | 433 | "Show notifications on switching personas": "Показывать уведомления при смене персоны", |
| 429 | "In Story String / Prompt Manager": "В общем шаблоне / Менеджере промптов", | 434 | "In Story String / Prompt Manager": "В общем шаблоне / Менеджере промптов", |
| 430 | "Top of Author's Note": "Сверху от заметок автора", | 435 | "Top of Author's Note": "Сверху от авторских заметок", |
| 431 | "Bottom of Author's Note": "Снизу от заметок автора", | 436 | "Bottom of Author's Note": "Снизу от авторских заметок", |
| 432 | "How do I use this?": "Как пользоваться?", | 437 | "How do I use this?": "Как пользоваться?", |
| 433 | "More...": "Ещё...", | 438 | "More...": "Ещё...", |
| 434 | "Link to World Info": "Ссылка на информацию о мире", | 439 | "Link to World Info": "Ссылка на информацию о мире", |
| @@ -436,7 +441,7 @@ | |||
| 436 | "Scenario Override": "Перезапись сценария", | 441 | "Scenario Override": "Перезапись сценария", |
| 437 | "Rename": "Переименовать", | 442 | "Rename": "Переименовать", |
| 438 | "Character Description": "Описание персонажа", | 443 | "Character Description": "Описание персонажа", |
| 439 | "Creator's Notes": "Заметки создателя", | 444 | "Creator's Notes": "Примечание от создателя", |
| 440 | "A-Z": "A-Z", | 445 | "A-Z": "A-Z", |
| 441 | "Z-A": "Z-A", | 446 | "Z-A": "Z-A", |
| 442 | "Newest": "Сначала новые", | 447 | "Newest": "Сначала новые", |
| @@ -471,7 +476,7 @@ | |||
| 471 | "Enter your name": "Введите свое имя", | 476 | "Enter your name": "Введите свое имя", |
| 472 | "Name this character": "Назовите этого персонажа", | 477 | "Name this character": "Назовите этого персонажа", |
| 473 | "Search / Create Tags": "Искать / Создать тэги", | 478 | "Search / Create Tags": "Искать / Создать тэги", |
| 474 | "Describe your character's physical and mental traits here.": "Опишите ментальные и физические черты персонажа", | 479 | "Describe your character's physical and mental traits here.": "Опишите характер персонажа и его внешность", |
| 475 | "This will be the first message from the character that starts every chat.": "Это будет первое сообщение от персонажа при начале нового чата", | 480 | "This will be the first message from the character that starts every chat.": "Это будет первое сообщение от персонажа при начале нового чата", |
| 476 | "Chat Name (Optional)": "Название чата (необязательно)", | 481 | "Chat Name (Optional)": "Название чата (необязательно)", |
| 477 | "Search...": "Поиск...", | 482 | "Search...": "Поиск...", |
| @@ -483,10 +488,10 @@ | |||
| 483 | "(Write a comma-separated list of tags)": "(Список тегов через запятую)", | 488 | "(Write a comma-separated list of tags)": "(Список тегов через запятую)", |
| 484 | "(A brief description of the personality)": "(Краткое описание личности)", | 489 | "(A brief description of the personality)": "(Краткое описание личности)", |
| 485 | "(Circumstances and context of the interaction)": "(Обстоятельства и контекст этого диалога)", | 490 | "(Circumstances and context of the interaction)": "(Обстоятельства и контекст этого диалога)", |
| 486 | "(Examples of chat dialog. Begin each example with START on a new line.)": "(Примеры диалога. Начинайте каждый пример с START или новой строкой.)", | 491 | "(Examples of chat dialog. Begin each example with START on a new line.)": "(Примеры диалога. Начинайте каждый пример со START и на новой строке.)", |
| 487 | "Type here...": "Пишите здесь...", | 492 | "Type here...": "Пишите здесь...", |
| 488 | "Comma separated (required)": "Через запятую (обязательное поле)", | 493 | "Comma separated (required)": "Через запятую (обязательное поле)", |
| 489 | "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно", | 494 | "What this keyword should mean to the AI, sent verbatim": "Объясните ИИ, что он должен знать об этом ключевом слове", |
| 490 | "Filter to Character(s)": "Фильтр по персонажу(ам)", | 495 | "Filter to Character(s)": "Фильтр по персонажу(ам)", |
| 491 | "Character Exclusion": "Исключить персонажей", | 496 | "Character Exclusion": "Исключить персонажей", |
| 492 | "Inclusion Group": "Группа записей", | 497 | "Inclusion Group": "Группа записей", |
| @@ -569,12 +574,12 @@ | |||
| 569 | "Remove": "Убрать", | 574 | "Remove": "Убрать", |
| 570 | "Select a World Info file for": "Выбрать файл с миром для", | 575 | "Select a World Info file for": "Выбрать файл с миром для", |
| 571 | "Primary Lorebook": "Основной лорбук", | 576 | "Primary Lorebook": "Основной лорбук", |
| 572 | "A selected World Info will be bound to this character as its own Lorebook.": "Информация о мире будет привязана к персонажу как его собственный лорбук.", | 577 | "A selected World Info will be bound to this character as its own Lorebook.": "Данный мир будет привязан к персонажу как его собственный лорбук.", |
| 573 | "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Когда ИИ генерирует ответ, он будет совмещён с записями из глобально выбранного мира.", | 578 | "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "При генерации ответа, данный лорбук будет работать вместе с глобально выбранным лорбуком.", |
| 574 | "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON.", | 579 | "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON.", |
| 575 | "Additional Lorebooks": "Вспомогательные лорбуки", | 580 | "Additional Lorebooks": "Вспомогательные лорбуки", |
| 576 | "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков", | 581 | "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков.", |
| 577 | "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: эти выборы необязательные и не будут сохранены при экспорте персонажа!", | 582 | "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: вспомогательные лорбуки не будут выгружены при экспорте персонажа!", |
| 578 | "Rename chat file": "Переименовать чат", | 583 | "Rename chat file": "Переименовать чат", |
| 579 | "Export JSONL chat file": "Экспортировать чат в формате JSONL", | 584 | "Export JSONL chat file": "Экспортировать чат в формате JSONL", |
| 580 | "Download chat as plain text document": "Скачать чат в формате .txt", | 585 | "Download chat as plain text document": "Скачать чат в формате .txt", |
| @@ -784,20 +789,20 @@ | |||
| 784 | "Enable magnification for zoomed avatar display.": "Добавляет возможность приближать увеличенную версию аватарки.", | 789 | "Enable magnification for zoomed avatar display.": "Добавляет возможность приближать увеличенную версию аватарки.", |
| 785 | "Unique to this chat": "Только для текущего чата", | 790 | "Unique to this chat": "Только для текущего чата", |
| 786 | "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Чекпоинты наследуют заметки от родительского чата, но впоследствие их всегда можно изменить.", | 791 | "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Чекпоинты наследуют заметки от родительского чата, но впоследствие их всегда можно изменить.", |
| 787 | "Include in World Info Scanning": "Учитывать при сканировании Информации о мире", | 792 | "Include in World Info Scanning": "Учитывать при сканировании лорбуком", |
| 788 | "Before Main Prompt / Story String": "Перед основным промптом / строкой истории", | 793 | "Before Main Prompt / Story String": "Перед основным промптом / общим шаблоном", |
| 789 | "After Main Prompt / Story String": "После основного промпта / строки истории", | 794 | "After Main Prompt / Story String": "После основного промпта / общего шаблона", |
| 790 | "In-chat @ Depth": "Встав. на глуб.", | 795 | "In-chat @ Depth": "Встав. на глуб.", |
| 791 | "as": "роль:", | 796 | "as": "роль:", |
| 792 | "Insertion Frequency": "Частота вставки", | 797 | "Insertion Frequency": "Частота вставки", |
| 793 | "(0 = Disable, 1 = Always)": "(0 = никогда, 1 = всегда)", | 798 | "(0 = Disable, 1 = Always)": "(0 = никогда, 1 = всегда)", |
| 794 | "User inputs until next insertion:": "Ваших сообщений до след. вставки:", | 799 | "User inputs until next insertion:": "Ваших сообщений до след. вставки:", |
| 795 | "Character Author's Note (Private)": "Заметки автора персонажа (личные)", | 800 | "Character Author's Note (Private)": "Авторские заметки для персонажа (личные)", |
| 796 | "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.": "Автоматически применятся к этому персонажу в качестве заметок автора. Будут использоваться в группах, но при активном групповом чате к редактированию недоступны.", | 801 | "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.": "Автоматически применятся к этому персонажу в качестве авторских заметок. Будут использоваться в группах, но при активном групповом чате к редактированию недоступны.", |
| 797 | "Use character author's note": "Использовать заметки автора персонажа", | 802 | "Use character author's note": "Использовать авторские заметки для персонажа", |
| 798 | "Replace Author's Note": "Вместо заметок автора", | 803 | "Replace Author's Note": "Вместо авторских заметок", |
| 799 | "Default Author's Note": "Стандартные заметки автора", | 804 | "Default Author's Note": "Стандартные авторские заметки", |
| 800 | "Will be automatically added as the Author's Note for all new chats.": "Будут автоматически добавляться во все новые чаты в качестве Заметок автора", | 805 | "Will be automatically added as the Author's Note for all new chats.": "Будут автоматически добавляться во все новые чаты в качестве авторских заметок", |
| 801 | "1 = disabled": "1 = откл.", | 806 | "1 = disabled": "1 = откл.", |
| 802 | "write short replies, write replies using past tense": "пиши короткие ответы, пиши в настоящем времени", | 807 | "write short replies, write replies using past tense": "пиши короткие ответы, пиши в настоящем времени", |
| 803 | "Positive Prompt": "Положительный промпт", | 808 | "Positive Prompt": "Положительный промпт", |
| @@ -906,7 +911,7 @@ | |||
| 906 | "ext_sum_force_text": "Пересказать сейчас", | 911 | "ext_sum_force_text": "Пересказать сейчас", |
| 907 | "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)", | 912 | "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)", |
| 908 | "ext_sum_pause": "Приостановить", | 913 | "ext_sum_pause": "Приостановить", |
| 909 | "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. Extras API всегда их исключает.", | 914 | "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. Extras API всегда их исключает.", |
| 910 | "ext_sum_no_wi_an": "Без мира и заметок", | 915 | "ext_sum_no_wi_an": "Без мира и заметок", |
| 911 | "ext_sum_settings_tip": "Изменить промпт пересказа, место для инжекта и т.д.", | 916 | "ext_sum_settings_tip": "Изменить промпт пересказа, место для инжекта и т.д.", |
| 912 | "ext_sum_settings": "Настройки пересказа", | 917 | "ext_sum_settings": "Настройки пересказа", |
| @@ -1333,13 +1338,7 @@ | |||
| 1333 | "WI_Entry_Status_Normal": "Обычная", | 1338 | "WI_Entry_Status_Normal": "Обычная", |
| 1334 | "WI_Entry_Status_Vectorized": "Векторизованная", | 1339 | "WI_Entry_Status_Vectorized": "Векторизованная", |
| 1335 | "WI_Entry_Status_Disabled": "Отключена", | 1340 | "WI_Entry_Status_Disabled": "Отключена", |
| 1336 | "Before EM": "↑EM", | ||
| 1337 | "After EM": "↓EM", | ||
| 1338 | "at Depth System": "@D ⚙️", | ||
| 1339 | "at Depth User": "@D 👤", | ||
| 1340 | "at Depth AI": "@D 🤖", | ||
| 1341 | "Depth": "Глубина", | 1341 | "Depth": "Глубина", |
| 1342 | "Trigger %:": "Trigger %:", | ||
| 1343 | "Probability": "Вероятность", | 1342 | "Probability": "Вероятность", |
| 1344 | "Duplicate world info entry": "Дублировать запись", | 1343 | "Duplicate world info entry": "Дублировать запись", |
| 1345 | "Delete world info entry": "Удалить запись", | 1344 | "Delete world info entry": "Удалить запись", |
| @@ -1411,26 +1410,7 @@ | |||
| 1411 | "ext_regex_title": "Regex", | 1410 | "ext_regex_title": "Regex", |
| 1412 | "ext_regex_import_target": "Импортировать в:", | 1411 | "ext_regex_import_target": "Импортировать в:", |
| 1413 | "ext_regex_move_to_scoped": "Сделать локальным", | 1412 | "ext_regex_move_to_scoped": "Сделать локальным", |
| 1414 | "Trigger Stable Diffusion": "Trigger Stable Diffusion", | ||
| 1415 | "sd_Yourself": "Yourself", | ||
| 1416 | "sd_Your_Face": "Your Face", | ||
| 1417 | "sd_Me": "Me", | ||
| 1418 | "sd_The_Whole_Story": "The Whole Story", | ||
| 1419 | "sd_The_Last_Message": "The Last Message", | ||
| 1420 | "sd_Raw_Last_Message": "Raw Last Message", | ||
| 1421 | "sd_Background": "Background", | ||
| 1422 | "Image Generation": "Image Generation", | 1413 | "Image Generation": "Image Generation", |
| 1423 | "sd_refine_mode": "Allow to edit prompts manually before sending them to generation API", | ||
| 1424 | "sd_refine_mode_txt": "Edit prompts before generation", | ||
| 1425 | "sd_interactive_mode": "Automatically generate images when sending messages like 'send me a picture of cat'.", | ||
| 1426 | "sd_interactive_mode_txt": "Interactive mode", | ||
| 1427 | "sd_multimodal_captioning": "Use multimodal captioning to generate prompts for user and character portraits based on their avatars.", | ||
| 1428 | "sd_multimodal_captioning_txt": "Use multimodal captioning for portraits", | ||
| 1429 | "sd_expand": "Automatically extend prompts using text generation model", | ||
| 1430 | "sd_expand_txt": "Auto-enhance prompts", | ||
| 1431 | "sd_snap": "Snap generation requests with a forced aspect ratio (portraits, backgrounds) to the nearest known resolution, while trying to preserve the absolute pixel counts (recommended for SDXL).", | ||
| 1432 | "sd_snap_txt": "Snap auto-adjusted resolutions", | ||
| 1433 | "Source": "Source", | ||
| 1434 | "sd_auto_url": "Example: {{auto_url}}", | 1414 | "sd_auto_url": "Example: {{auto_url}}", |
| 1435 | "Authentication (optional)": "Authentication (optional)", | 1415 | "Authentication (optional)": "Authentication (optional)", |
| 1436 | "Example: username:password": "Example: username:password", | 1416 | "Example: username:password": "Example: username:password", |
| @@ -1441,18 +1421,10 @@ | |||
| 1441 | "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.", | 1421 | "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.", |
| 1442 | "sd_vlad_url": "Example: {{vlad_url}}", | 1422 | "sd_vlad_url": "Example: {{vlad_url}}", |
| 1443 | "The server must be accessible from the SillyTavern host machine.": "The server must be accessible from the SillyTavern host machine.", | 1423 | "The server must be accessible from the SillyTavern host machine.": "The server must be accessible from the SillyTavern host machine.", |
| 1444 | "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.", | ||
| 1445 | "Allow NSFW images from Horde": "Разрешить NSFW-картинки в Horde", | 1424 | "Allow NSFW images from Horde": "Разрешить NSFW-картинки в Horde", |
| 1446 | "Sanitize prompts (recommended)": "Sanitize prompts (recommended)", | ||
| 1447 | "Automatically adjust generation parameters to ensure free image generations.": "Automatically adjust generation parameters to ensure free image generations.", | ||
| 1448 | "Avoid spending Anlas": "Avoid spending Anlas", | 1425 | "Avoid spending Anlas": "Avoid spending Anlas", |
| 1449 | "Opus tier": "(Opus tier)", | 1426 | "Opus tier": "(Opus tier)", |
| 1450 | "View my Anlas": "View my Anlas", | 1427 | "View my Anlas": "View my Anlas", |
| 1451 | "These settings only apply to DALL-E 3": "These settings only apply to DALL-E 3", | ||
| 1452 | "Image Style": "Image Style", | ||
| 1453 | "Image Quality": "Image Quality", | ||
| 1454 | "Standard": "Standard", | ||
| 1455 | "HD": "HD", | ||
| 1456 | "sd_comfy_url": "Example: {{comfy_url}}", | 1428 | "sd_comfy_url": "Example: {{comfy_url}}", |
| 1457 | "Open workflow editor": "Open workflow editor", | 1429 | "Open workflow editor": "Open workflow editor", |
| 1458 | "Create new workflow": "Create new workflow", | 1430 | "Create new workflow": "Create new workflow", |
| @@ -1460,9 +1432,6 @@ | |||
| 1460 | "Enhance": "Enhance", | 1432 | "Enhance": "Enhance", |
| 1461 | "Refine": "Refine", | 1433 | "Refine": "Refine", |
| 1462 | "Decrisper": "Decrisper", | 1434 | "Decrisper": "Decrisper", |
| 1463 | "Sampling steps": "Sampling steps ()", | ||
| 1464 | "Width": "Width ()", | ||
| 1465 | "Height": "Height ()", | ||
| 1466 | "Resolution": "Resolution", | 1435 | "Resolution": "Resolution", |
| 1467 | "Model": "Model", | 1436 | "Model": "Model", |
| 1468 | "Sampling method": "Sampling method", | 1437 | "Sampling method": "Sampling method", |
| @@ -1472,8 +1441,6 @@ | |||
| 1472 | "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.", | 1441 | "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.", |
| 1473 | "DYN": "DYN", | 1442 | "DYN": "DYN", |
| 1474 | "Scheduler": "Scheduler", | 1443 | "Scheduler": "Scheduler", |
| 1475 | "Restore Faces": "Restore Faces", | ||
| 1476 | "Hires. Fix": "Hires. Fix", | ||
| 1477 | "Upscaler": "Upscaler", | 1444 | "Upscaler": "Upscaler", |
| 1478 | "Upscale by": "Upscale by", | 1445 | "Upscale by": "Upscale by", |
| 1479 | "Denoising strength": "Denoising strength", | 1446 | "Denoising strength": "Denoising strength", |
| @@ -1484,7 +1451,6 @@ | |||
| 1484 | "Delete style": "Delete style", | 1451 | "Delete style": "Delete style", |
| 1485 | "Common prompt prefix": "Common prompt prefix", | 1452 | "Common prompt prefix": "Common prompt prefix", |
| 1486 | "sd_prompt_prefix_placeholder": "Use {prompt} to specify where the generated prompt will be inserted", | 1453 | "sd_prompt_prefix_placeholder": "Use {prompt} to specify where the generated prompt will be inserted", |
| 1487 | "Negative common prompt prefix": "Negative common prompt prefix", | ||
| 1488 | "Character-specific prompt prefix": "Character-specific prompt prefix", | 1454 | "Character-specific prompt prefix": "Character-specific prompt prefix", |
| 1489 | "Won't be used in groups.": "Won't be used in groups.", | 1455 | "Won't be used in groups.": "Won't be used in groups.", |
| 1490 | "sd_character_prompt_placeholder": "Any characteristics that describe the currently selected character. Will be added after a common prompt prefix.\nExample: female, green eyes, brown hair, pink shirt", | 1456 | "sd_character_prompt_placeholder": "Any characteristics that describe the currently selected character. Will be added after a common prompt prefix.\nExample: female, green eyes, brown hair, pink shirt", |
| @@ -1836,13 +1802,13 @@ | |||
| 1836 | "Also delete the chat files": "Также удалить файлы чатов", | 1802 | "Also delete the chat files": "Также удалить файлы чатов", |
| 1837 | "Delete the character?": "Удалить персонажа?", | 1803 | "Delete the character?": "Удалить персонажа?", |
| 1838 | "Not a valid number": "Некорректное число", | 1804 | "Not a valid number": "Некорректное число", |
| 1839 | "Author's Note depth updated": "Глубина заметок автора обновлена", | 1805 | "Author's Note depth updated": "Глубина авторских заметок обновлена", |
| 1840 | "Author's Note frequency updated": "Частота заметок автора обновлена", | 1806 | "Author's Note frequency updated": "Частота авторских заметок обновлена", |
| 1841 | "Not a valid position": "Некорректная позиция", | 1807 | "Not a valid position": "Некорректная позиция", |
| 1842 | "Author's Note position updated": "Позиция заметок автора обновлена", | 1808 | "Author's Note position updated": "Позиция авторских заметок обновлена", |
| 1843 | "Something went wrong. Could not save character's author's note.": "Что-то пошло не так. Не удалось сохранить заметки автора для этого персонажа.", | 1809 | "Something went wrong. Could not save character's author's note.": "Что-то пошло не так. Не удалось сохранить авторские заметки для этого персонажа.", |
| 1844 | "Select a character before trying to use Author's Note": "Сначала необходимо выбрать персонажа", | 1810 | "Select a character before trying to use Author's Note": "Сначала необходимо выбрать персонажа", |
| 1845 | "Author's Note text updated": "Текст заметок автора обновлён", | 1811 | "Author's Note text updated": "Текст авторских заметок обновлён", |
| 1846 | "Group Validation": "Валидация группы", | 1812 | "Group Validation": "Валидация группы", |
| 1847 | "Warning: Listed member ${0} does not exist as a character. It will be removed from the group.": "Предупреждение: персонаж ${0} не существует в виде карточки. Он будет удалён из группы.", | 1813 | "Warning: Listed member ${0} does not exist as a character. It will be removed from the group.": "Предупреждение: персонаж ${0} не существует в виде карточки. Он будет удалён из группы.", |
| 1848 | "Group Chat could not be saved": "Не удалось сохранить групповой чат", | 1814 | "Group Chat could not be saved": "Не удалось сохранить групповой чат", |
| @@ -1938,7 +1904,7 @@ | |||
| 1938 | "Do you want to remove these fields before exporting?": "Желаете ли удалить эти поля перед экспортом?", | 1904 | "Do you want to remove these fields before exporting?": "Желаете ли удалить эти поля перед экспортом?", |
| 1939 | "Save": "Сохранить", | 1905 | "Save": "Сохранить", |
| 1940 | "Chat Lorebook": "Лорбук для чата", | 1906 | "Chat Lorebook": "Лорбук для чата", |
| 1941 | "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет добавляться в промпт наряду с глобальным лорбуком и лором персонажа.", | 1907 | "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет работать наряду с глобальным лорбуком и лором персонажа.", |
| 1942 | "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + ЛКМ, чтобы открыть диалог привязки мира", | 1908 | "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + ЛКМ, чтобы открыть диалог привязки мира", |
| 1943 | "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.", | 1909 | "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.", |
| 1944 | "ext_regex_user_input_desc": "Отправленные вами сообщения.", | 1910 | "ext_regex_user_input_desc": "Отправленные вами сообщения.", |
| @@ -2010,7 +1976,7 @@ | |||
| 2010 | "Imported tags:": "Импортируемые теги:", | 1976 | "Imported tags:": "Импортируемые теги:", |
| 2011 | "Importing Tags": "Импорт тегов", | 1977 | "Importing Tags": "Импорт тегов", |
| 2012 | "Couldn't import tags:": "Не удалось импортировать теги:", | 1978 | "Couldn't import tags:": "Не удалось импортировать теги:", |
| 2013 | "Allow fallback models": "Разрешить fallback-модели", | 1979 | "Allow fallback models": "Разрешить резервные модели", |
| 2014 | "Allow fallback providers": "Разрешить fallback-провайдеров", | 1980 | "Allow fallback providers": "Разрешить fallback-провайдеров", |
| 2015 | "To use instruct formatting, switch to OpenRouter under Text Completion API.": "Переключитесь на OpenRouter в Text Completion API, чтобы использовать форматирование Instruct-режима.", | 1981 | "To use instruct formatting, switch to OpenRouter under Text Completion API.": "Переключитесь на OpenRouter в Text Completion API, чтобы использовать форматирование Instruct-режима.", |
| 2016 | "Select providers. No selection = all providers.": "Выберите провайдера. Нет выбранного = выбраны все.", | 1982 | "Select providers. No selection = all providers.": "Выберите провайдера. Нет выбранного = выбраны все.", |
| @@ -2028,6 +1994,8 @@ | |||
| 2028 | "Click on the setting name to omit it from the profile.": "Нажмите на название настройки, чтобы исключить её из профиля", | 1994 | "Click on the setting name to omit it from the profile.": "Нажмите на название настройки, чтобы исключить её из профиля", |
| 2029 | "Included settings:": "Сохранённые параметры:", | 1995 | "Included settings:": "Сохранённые параметры:", |
| 2030 | "Server URL": "Адрес сервера", | 1996 | "Server URL": "Адрес сервера", |
| 1997 | "Electron Hub API Key": "Ключ от API Electron Hub", | ||
| 1998 | "Electron Hub Model": "Модель Electron Hub", | ||
| 2031 | "NanoGPT API Key": "Ключ от API NanoGPT", | 1999 | "NanoGPT API Key": "Ключ от API NanoGPT", |
| 2032 | "NanoGPT Model": "Модель NanoGPT", | 2000 | "NanoGPT Model": "Модель NanoGPT", |
| 2033 | "Use extension settings": "Использовать настройки из расширения", | 2001 | "Use extension settings": "Использовать настройки из расширения", |
| @@ -2044,14 +2012,14 @@ | |||
| 2044 | "Title/Memo": "Название", | 2012 | "Title/Memo": "Название", |
| 2045 | "Strategy": "Статус", | 2013 | "Strategy": "Статус", |
| 2046 | "Position": "Позиция", | 2014 | "Position": "Позиция", |
| 2047 | "Trigger %": "% срабатывания", | 2015 | "Trigger %": "% срабатываний", |
| 2048 | "Use global": "Глоб. настройка", | 2016 | "Use global": "Глоб. настройка", |
| 2049 | "Whole Words": "Целые слова", | 2017 | "Whole Words": "Целые слова", |
| 2050 | "Non-recursable": "Не рекурсивная", | 2018 | "Non-recursable": "Не рекурсивная", |
| 2051 | "Delay until recursion": "Рекурсивная", | 2019 | "Delay until recursion": "Рекурсивная", |
| 2052 | "Toggle entry's active state.": "Вкл/выкл запись.", | 2020 | "Toggle entry's active state.": "Вкл/выкл запись.", |
| 2053 | "Prioritize": "Важная", | 2021 | "Prioritize": "Важная", |
| 2054 | "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.": "Важная запись получает приоритет среди всех выбранных. Если важных записей несколько, выбирается та, у которой выше \"Очерёдность\".", | 2022 | "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.": "Важная запись получает приоритет среди всех выбранных. Если важных записей несколько, выбирается та, у которой выше \"Приоритет\".", |
| 2055 | "Group Weight": "Вес в группе", | 2023 | "Group Weight": "Вес в группе", |
| 2056 | "A relative likelihood of entry activation within the group": "Относительная вероятность активации записи в рамках группы", | 2024 | "A relative likelihood of entry activation within the group": "Относительная вероятность активации записи в рамках группы", |
| 2057 | "Sticky": "Липучка", | 2025 | "Sticky": "Липучка", |
| @@ -2067,7 +2035,7 @@ | |||
| 2067 | "Switch to plaintext mode": "Вкл/выкл режим чистого текста", | 2035 | "Switch to plaintext mode": "Вкл/выкл режим чистого текста", |
| 2068 | "Exclude": "Режим исключения", | 2036 | "Exclude": "Режим исключения", |
| 2069 | "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "Инвертировать логику: для выбранных в фильтре персонажей/тегов данная запись активна НЕ БУДЕТ", | 2037 | "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "Инвертировать логику: для выбранных в фильтре персонажей/тегов данная запись активна НЕ БУДЕТ", |
| 2070 | "Apply current sorting as Order": "Настроить Очерёдность в соответствии с текущей сортировкой", | 2038 | "Apply current sorting as Order": "Настроить Приоритет в соответствии с текущей сортировкой", |
| 2071 | "Create a new World Info": "Создать новый мир", | 2039 | "Create a new World Info": "Создать новый мир", |
| 2072 | "Enter a name for the new file:": "Название нового файла:", | 2040 | "Enter a name for the new file:": "Название нового файла:", |
| 2073 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Если сразу несколько записей из одной группы окажутся активированными, по факту сработает только одна. Одна запись может входить в несколько групп, отделяются запятыми. Раздел в документации: World Info - Inclusion Group", | 2041 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Если сразу несколько записей из одной группы окажутся активированными, по факту сработает только одна. Одна запись может входить в несколько групп, отделяются запятыми. Раздел в документации: World Info - Inclusion Group", |
| @@ -2165,7 +2133,7 @@ | |||
| 2165 | "openai_reasoning_effort_high": "Подробные", | 2133 | "openai_reasoning_effort_high": "Подробные", |
| 2166 | "Persona Lore Alt+Click to open the lorebook": "Лорбук данной персоны\nAlt + ЛКМ чтобы открыть лорбук", | 2134 | "Persona Lore Alt+Click to open the lorebook": "Лорбук данной персоны\nAlt + ЛКМ чтобы открыть лорбук", |
| 2167 | "Persona Lorebook for": "Лорбук для персоны", | 2135 | "Persona Lorebook for": "Лорбук для персоны", |
| 2168 | "persona_world_template_txt": "Выбранная Информация о мире будет привязана к этой персоне. Информация будет добавляться в каждом промпте вместе с глобальным лорбуком и лорбуками персонажа и чата.", | 2136 | "persona_world_template_txt": "Выбранный мир будет привязан к этой персоне. Будет работать вместе с глобальным лорбуком и лорбуками персонажа и чата.", |
| 2169 | "Global list": "Глобальный список", | 2137 | "Global list": "Глобальный список", |
| 2170 | "Preset-specific list": "Список для данного пресета", | 2138 | "Preset-specific list": "Список для данного пресета", |
| 2171 | "Banned tokens/strings are being sent in the request.": "Запрещённые токены и строки отсылаются в запросе.", | 2139 | "Banned tokens/strings are being sent in the request.": "Запрещённые токены и строки отсылаются в запросе.", |
| @@ -2280,7 +2248,7 @@ | |||
| 2280 | "Character Words": "Слов отправлено персонажем", | 2248 | "Character Words": "Слов отправлено персонажем", |
| 2281 | "stats_header_User": "пользователю", | 2249 | "stats_header_User": "пользователю", |
| 2282 | "stats_header_Character": "персонажу", | 2250 | "stats_header_Character": "персонажу", |
| 2283 | "${0} Stats": "Статистика по ${0}", | 2251 | "${0} Stats": "Статистика по ${0}", |
| 2284 | "Context": "Контекст", | 2252 | "Context": "Контекст", |
| 2285 | "Response": "Ответ", | 2253 | "Response": "Ответ", |
| 2286 | "Connected": "Подключено", | 2254 | "Connected": "Подключено", |
| @@ -2521,6 +2489,16 @@ | |||
| 2521 | "Automatically generated chat backups.": "Автоматически создаваемые бэкапы чатов.", | 2489 | "Automatically generated chat backups.": "Автоматически создаваемые бэкапы чатов.", |
| 2522 | "Settings Backups": "Копии настроек", | 2490 | "Settings Backups": "Копии настроек", |
| 2523 | "Automatically generated settings backups.": "Автоматически создаваемые бэкапы настроек.", | 2491 | "Automatically generated settings backups.": "Автоматически создаваемые бэкапы настроек.", |
| 2492 | "Files": "Файлы", | ||
| 2493 | "Files that are not associated with chat messages or Data Bank. WILL DELETE MANUAL UPLOADS!": "Файлы, не связанные ни с одним сообщением или банком данных. ЗАГРУЖЕННЫЕ ВРУЧНУЮ ФАЙЛЫ ТАКЖЕ БУДУТ УДАЛЕНЫ!", | ||
| 2494 | "Images": "Изображения", | ||
| 2495 | "Images that are not associated with chat messages. WILL DELETE MANUAL UPLOADS!": "Картинки, не связанные ни с одним сообщением. ЗАГРУЖЕННЫЕ ВРУЧНУЮ ФАЙЛЫ ТАКЖЕ БУДУТ УДАЛЕНЫ!", | ||
| 2496 | "Avatar Thumbnails": "Превью для аватарок", | ||
| 2497 | "Thumbnails for avatars of missing or deleted characters.": "Превью для аватарок удалённых персонажей", | ||
| 2498 | "Background Thumbnails": "Превью для фонов", | ||
| 2499 | "Thumbnails for missing or deleted backgrounds.": "Превью для удалённых фоновых изображений", | ||
| 2500 | "Persona Thumbnails": "Превью для персон", | ||
| 2501 | "Thumbnails for missing or deleted personas.": "Превью для удалённых персон", | ||
| 2524 | "Delete all items in this category": "Удалить всё в этой категории", | 2502 | "Delete all items in this category": "Удалить всё в этой категории", |
| 2525 | "View item content": "Посмотреть содержимое", | 2503 | "View item content": "Посмотреть содержимое", |
| 2526 | "Download item": "Скачать содержимое", | 2504 | "Download item": "Скачать содержимое", |
| @@ -2583,5 +2561,96 @@ | |||
| 2583 | "Moonshot AI API Key": "Ключ от API Moonshot AI", | 2561 | "Moonshot AI API Key": "Ключ от API Moonshot AI", |
| 2584 | "Moonshot AI Model": "Модель Moonshot AI", | 2562 | "Moonshot AI Model": "Модель Moonshot AI", |
| 2585 | "AI/ML API Key": "Ключ от API AI/ML", | 2563 | "AI/ML API Key": "Ключ от API AI/ML", |
| 2586 | "AI/ML Model": "Модель AI/ML" | 2564 | "AI/ML Model": "Модель AI/ML", |
| 2565 | "Replace Character": "Заменить персонажа", | ||
| 2566 | "Choose a new character card to replace this character with.": "Выберите, каким персонажем хотите заменить текущего.", | ||
| 2567 | "All chats, assets and group memberships will be preserved, but local changes to the character data will be lost.": "Чаты с персонажем, его ассеты и членство в группах сохранятся. Однако сделанные вами изменения в карточке будут утеряны.", | ||
| 2568 | "Proceed?": "Продолжить?", | ||
| 2569 | "No Creator's Notes provided.": "Создатель не оставил примечаний.", | ||
| 2570 | "No auxiliary Lorebooks set. Click here to select.": "Вспомогательных лорбуков нет. ЛКМ, чтобы выбрать.", | ||
| 2571 | "Persona Title (optional, display only)": "Сноска (не влияет на чат, только в интерфейсе)", | ||
| 2572 | "This entry will not be recursively activated by other entries.": "Не будет активироваться другими записями.", | ||
| 2573 | "This entry will not activate other entries recursively.": "Не будет активировать другие записи.", | ||
| 2574 | "This entry can only be activated on recursive checking.": "Активируется только другими записями.", | ||
| 2575 | "This entry will be included ignoring budget constraints, assuming all other checks pass.": "Будет включена в промпт даже при превышении бюджета токенов (при условии, что все остальные условия соблюдены)", | ||
| 2576 | "Ignore budget": "Игнорировать бюджет", | ||
| 2577 | "Filter to Generation Triggers": "Только для опред. типов генераций", | ||
| 2578 | "Apply current sorting as Order": "Выставить приоритеты по текущей сортировке", | ||
| 2579 | "Apply your current sorting to the \"Order\" field. The Order values will go down from the chosen number.": "Заполнить поле \"Приоритет\" в соответствии с текущей сортировкой для всех записей. Поля будут заполнены значениями, начиная с этого числа:", | ||
| 2580 | "More than 100 entries in this world. If you don't choose a number higher than that, the lower entries will default to 0.<br />(Usual default: 100)<br />Minimum: ${0}": "В этом лорбуке больше 100 записей! Если не выставить число больше 100, то последние записи будут иметь приоритет 0.<br/>(Стандартное значение: 100)<br/>(Минимальное число: ${0})", | ||
| 2581 | "Apply": "Применить", | ||
| 2582 | "Apply Current Sorting": "Выставить приоритеты по сортировке", | ||
| 2583 | "Delete the entry with UID: ${0}?": "Удалить запись с UID: ${0}?", | ||
| 2584 | "This action is irreversible!": "Отменить будет невозможно!", | ||
| 2585 | "Recursion Level": "Уровень рекурсии", | ||
| 2586 | "delay_until_recursion_level": "Насколько глубоко должна зайти рекурсия, чтобы иметь возможность активировать эту запись.\n\nИзначально рекурсия делает проход по 1 уровню. Если там не находится подходящих записей, то она идёт на 2 уровень, и там повторяет процесс.\nИ так, пока не дойдёт до самого глубокого уровня.\n\nАктуально только для рекурсивных записей (с отмеченной галочкой \"Рекурсивная\").", | ||
| 2587 | "A number lower than the entry count has been chosen. All entries below that will default to 0.": "Введённое число меньше, чем общее кол-во записей. Всем записям внизу списка присвоен приоритет 0.", | ||
| 2588 | "Invalid number: ${0}": "Некорректное число: ${0}", | ||
| 2589 | "Allow animations for WEBP backgrounds. This is only a change for the selection menu.": "Разрешить анимации в WEBP фонах. Актуально только для меню выбора.", | ||
| 2590 | "sd_refine_mode_txt": "Редактировать промпты перед генерацией", | ||
| 2591 | "sd_refine_mode": "Отправлять промпты на проверку вам, прежде чем пересылать в API", | ||
| 2592 | "sd_function_tool_txt": "Использовать вызов функций", | ||
| 2593 | "sd_function_tool": "Использовать функцию, чтобы понимать, когда пора генерировать изображение", | ||
| 2594 | "sd_interactive_mode_txt": "Интерактивный режим", | ||
| 2595 | "sd_interactive_mode": "Автоматически генерировать изображения, когда появляется сообщение вида \"send me a picture of a cat\"", | ||
| 2596 | "sd_multimodal_captioning_txt": "Мультимодальный промптинг", | ||
| 2597 | "sd_multimodal_captioning": "Использовать мультимодальный промптинг для создания портретов пользователя и персонажа, основываясь на их аватарках", | ||
| 2598 | "sd_free_extend_txt": "Дописывать промпты в свободном режиме", | ||
| 2599 | "sd_free_extend_small": "(для интерактивного режима или команд)", | ||
| 2600 | "sd_free_extend": "Автоматически дописывать промпты в свободном режиме (для всего, что не касается фонов и портретов), используя текущую выбранную LLM", | ||
| 2601 | "sd_snap_txt": "Корректировать автоматически выбранное разрешение", | ||
| 2602 | "sd_snap": "Подгонять картинки с фиксированным соотношением сторон (фоны, портреты) к ближайшему известному разрешению (рекомендуется для SDXL)", | ||
| 2603 | "Source": "API", | ||
| 2604 | "Hint: Save an API key in AI Horde API settings to use it here.": "Подсказка: сохраните ключ от API в настройках API на сайте AI Horde, чтобы использовать его автоматически.", | ||
| 2605 | "Sanitize prompts (recommended)": "Прогонять промпты через санитайзер (рекомендуется)", | ||
| 2606 | "Sampling method": "Метод сэмплинга", | ||
| 2607 | "Resolution": "Целевое разрешение", | ||
| 2608 | "Sampling steps": "Кол-во шагов", | ||
| 2609 | "Width": "Ширина", | ||
| 2610 | "Height": "Высота", | ||
| 2611 | "Not all samplers supported.": "Поддерживает не все виды сэмплинга.", | ||
| 2612 | "(-1 for random)": "(-1 для случайного)", | ||
| 2613 | "Common prompt prefix": "Фиксированный префикс для промптов", | ||
| 2614 | "Preset for prompt prefix and negative prompt": "Пресет для префиксов промпта и для негативных промптов", | ||
| 2615 | "Style": "Стиль", | ||
| 2616 | "Negative common prompt prefix": "Фиксированный префикс для негативных промптов", | ||
| 2617 | "Chat Message Visibility (by source)": "Видимость сообщений в чате (по источникам)", | ||
| 2618 | "Uncheck to hide the extension's messages in chat prompts.": "Снимите галочку, чтобы скрыть из промптов сообщения, приходящие из этого источника.", | ||
| 2619 | "Extensions Menu": "Меню расширений", | ||
| 2620 | "Slash Command": "Слэш-команды", | ||
| 2621 | "Interactive Mode": "Интерактивный режим", | ||
| 2622 | "Function Tool": "Функция", | ||
| 2623 | "Save style": "Сохранить стиль", | ||
| 2624 | "Delete style": "Удалить стиль", | ||
| 2625 | "Are you sure you want to delete the style \"${0}\"?": "Вы точно хотите удалить стиль \"${0}\"?", | ||
| 2626 | "API Key": "Ключ от API", | ||
| 2627 | "These settings only apply to DALL-E 3": "Данные настройки применяются только для DALL-E 3", | ||
| 2628 | "Image Style": "Стиль изображения", | ||
| 2629 | "Image Quality": "Качество изображения", | ||
| 2630 | "Standard": "Стандарт", | ||
| 2631 | "sd_res_512x512": "512x512 (1:1, иконки, аватарки)", | ||
| 2632 | "sd_res_600x600": "600x600(1:1, иконки, аватарки)", | ||
| 2633 | "sd_res_512x768": "512x768 (2:3, вертикальная аватарка для карточки)", | ||
| 2634 | "sd_res_768x512": "768x512 (3:2, 35мм плёнка для кинофильмов, альбомн. ориентация)", | ||
| 2635 | "sd_res_960x540": "960x540 (16:9, обои, альбомн. ориентация)", | ||
| 2636 | "sd_res_540x960": "540x960 (9:16, обои, книжн. ориентация)", | ||
| 2637 | "sd_res_1920x1088": "1920x1088 (16:9, обои, альбомн. ориентация)", | ||
| 2638 | "sd_res_1088x1920": "1088x1920 (9:16, обои, книжн. ориентация)", | ||
| 2639 | "sd_res_1280x720": "1280x720 (16:9, обои, альбомн. ориентация)", | ||
| 2640 | "sd_res_720x1280": "720x1280 (9:16, обои, книжн. ориентация)", | ||
| 2641 | "Click to set": "Нажмите чтобы задать", | ||
| 2642 | "Prompt Upsampling": "Применять Prompt Upsampling", | ||
| 2643 | "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.": "При активации автоматически модифицирует промпт, чтобы сделать процесс генерации более креативным.", | ||
| 2644 | "Important:": "Важно:", | ||
| 2645 | "The server must be accessible from the SillyTavern host machine.": " Адрес должен быть доступен с сервера SillyTavern.", | ||
| 2646 | "Open workflow editor": "Открыть редактор воркфлоу", | ||
| 2647 | "Create new workflow": "Создать новый воркфлоу", | ||
| 2648 | "Delete workflow": "Удалить воркфлоу", | ||
| 2649 | "Delete the workflow? This action is irreversible.": "Удалить этот воркфлоу? Отменить будет невозможно.", | ||
| 2650 | "Swap width and height": "Поменять местами ширину и высоту", | ||
| 2651 | "Authentication (optional)": "Данные для аутентификации (необязательно)", | ||
| 2652 | "sd_auto_auth_warning_1": " запускайте Stable Diffusion с флагом", | ||
| 2653 | "sd_auto_auth_warning_2": "! Адрес SD должен быть доступен с сервера SillyTavern.", | ||
| 2654 | "Upscale by": "Множитель апскейлинга", | ||
| 2655 | "Hires steps (2nd pass)": "Кол-во шагов Hires (на втором проходе)" | ||
| 2587 | } | 2656 | } |
| @@ -0,0 +1,1461 @@ | |||
| 1 | { | ||
| 2 | "Favorite": "รายการโปรด", | ||
| 3 | "Tag": "แท็ก", | ||
| 4 | "Duplicate": "คัดลอก", | ||
| 5 | "Persona": "ตัวตน", | ||
| 6 | "Delete": "ลบ", | ||
| 7 | "AI Response Configuration": "ตั้งค่าการตอบกลับ AI", | ||
| 8 | "AI Configuration panel will stay open": "แผงการตั้งค่า AI จะคงเปิดอยู่", | ||
| 9 | "clickslidertips": "คลิกเพื่อดูคำแนะนำสไลเดอร์", | ||
| 10 | "MAD LAB MODE ON": "เปิดโหมด Mad Lab", | ||
| 11 | "Documentation on sampling parameters": "เอกสารอธิบายค่าพารามิเตอร์การสุ่ม", | ||
| 12 | "kobldpresets": "พรีเซ็ต KoboldAI", | ||
| 13 | "guikoboldaisettings": "การตั้งค่า GUI KoboldAI", | ||
| 14 | "Update current preset": "อัปเดตพรีเซ็ตปัจจุบัน", | ||
| 15 | "Save preset as": "บันทึกการปรับแต่ง", | ||
| 16 | "Import preset": "นำเข้าการปรับแต่ง", | ||
| 17 | "Export preset": "ส่งออกการปรับแต่ง", | ||
| 18 | "Restore current preset": "กู้คืนการปรับแต่งล่าสุด", | ||
| 19 | "Delete the preset": "ลบการปรับแต่ง", | ||
| 20 | "novelaipresets": "พรีเซ็ต NovelAI", | ||
| 21 | "Default": "ค่าเริ่มต้น", | ||
| 22 | "openaipresets": "พรีเซ็ต OpenAI", | ||
| 23 | "Text Completion presets": "รูปแบบของ Text Completion", | ||
| 24 | "AI Module": "โมดูลเอไอ", | ||
| 25 | "Changes the style of the generated text.": "ปรับเปลี่ยนสไตล์ในการสร้างข้อความ", | ||
| 26 | "No Module": "ไม่พบโมดูล", | ||
| 27 | "Instruct": "โหมดคำสั่ง", | ||
| 28 | "Prose Augmenter": "Prose Augmenter", | ||
| 29 | "Text Adventure": "เกมข้อความผจญภัย", | ||
| 30 | "response legth(tokens)": "ความยาวในการตอบ (ต่อโทเค็น)", | ||
| 31 | "Streaming": "สตรีมมิ่ง", | ||
| 32 | "Streaming_desc": "แสดงข้อความเป็นบิตต่อบิตขณะที่ถูกสร้างขึ้น", | ||
| 33 | "context size(tokens)": "ขนาดความจำ (ต่อโทเค็น)", | ||
| 34 | "unlocked": "ปลดล็อค", | ||
| 35 | "Only enable this if your model supports context sizes greater than 8192 tokens": "ให้เปิดสิ่งนี้เฉพาะถ้าหากความจำในโมเดลของคุณรองรับได้มากกว่า 8192 โทเค็น", | ||
| 36 | "Max prompt cost:": "ค่าใช้จ่ายสูงสุดของพรอมต์:", | ||
| 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.": "หากปิดสิ่งนี้ ระบบจะแสดงข้อความมาให้ทั้งหมดในครั้งเดียวเมื่อถูกสร้างจนจบ", | ||
| 39 | "Temperature": "Temperature", | ||
| 40 | "rep.pen": "rep.pen", | ||
| 41 | "Rep. Pen. Range.": "Rep. Pen. Range.", | ||
| 42 | "Rep. Pen. Slope": "Rep. Pen. Slope", | ||
| 43 | "Rep. Pen. Freq.": "Rep. Pen. Freq.", | ||
| 44 | "Rep. Pen. Presence": "Rep. Pen. Presence", | ||
| 45 | "TFS": "การสุ่มแบบ Tail Free", | ||
| 46 | "Phrase Repetition Penalty": "โทษการพูดซ้ำ", | ||
| 47 | "Off": "ปิด", | ||
| 48 | "Very light": "สว่างมาก", | ||
| 49 | "Light": "สว่าง", | ||
| 50 | "Medium": "ปานกลาง", | ||
| 51 | "Aggressive": "รุนแรง", | ||
| 52 | "Very aggressive": "รุนแรงมาก", | ||
| 53 | "Unlocked Context Size": "ปลดล๊อคขนาดความจำ", | ||
| 54 | "Unrestricted maximum value for the context slider": "ค่าสูงสุดไม่จำกัดสำหรับตัวปรับความจำ", | ||
| 55 | "Context Size (tokens)": "ขนาดความจำ (ต่อโทเค็น)", | ||
| 56 | "Max Response Length (tokens)": "ความยาวในการตอบสูงสุด (ต่อโทเค็น)", | ||
| 57 | "Multiple swipes per generation": "ปัดหลายครั้งต่อการสร้าง", | ||
| 58 | "Enable OpenAI completion streaming": "เปิดใช้งานการสตรีมผลลัพธ์จาก OpenAI", | ||
| 59 | "Frequency Penalty": "Frequency Penalty", | ||
| 60 | "Presence Penalty": "Presence Penalty", | ||
| 61 | "Count Penalty": "Count Penalty", | ||
| 62 | "Top K": "Top K", | ||
| 63 | "Top P": "Top P", | ||
| 64 | "Repetition Penalty": "Repetition Penalty", | ||
| 65 | "Min P": "Min P", | ||
| 66 | "Top A": "Top A", | ||
| 67 | "Quick Prompts Edit": "แก้ไขชุดคำสั่งแบบรวบรัด", | ||
| 68 | "Main": "หน้าหลัก", | ||
| 69 | "NSFW": "เนื้อหาไม่เหมาะสม", | ||
| 70 | "Jailbreak": "เจลเบรค", | ||
| 71 | "Utility Prompts": "ชุดคำสั่งเพิ่มเติม", | ||
| 72 | "Impersonation prompt": "ชุดคำสั่งสำหรับการสวมบทบาท", | ||
| 73 | "Restore default prompt": "คืนค่าชุดคำสั่งเริ่มต้น", | ||
| 74 | "Prompt that is used for Impersonation function": "ชุดคำสั่งที่จะถูกใช้ในฟังชั่นการสวมบทบาท", | ||
| 75 | "World Info Format Template": "เท็มเพลตรูปแบบของ World Info", | ||
| 76 | "Restore default format": "คืนค่ารูปแบบเริ่มต้น", | ||
| 77 | "Wraps activated World Info entries before inserting into the prompt.": "ห่อหุ้มรายการ World Info ที่เปิดใช้งานก่อนแทรกลงในพรอมต์", | ||
| 78 | "scenario_format_template_part_1": "ใช้", | ||
| 79 | "scenario_format_template_part_2": "เพื่อทำเครื่องหมายตำแหน่งที่จะแทรกเนื้อหา", | ||
| 80 | "Scenario Format Template": "เทมเพลตรูปแบบสถานการณ์", | ||
| 81 | "Personality Format Template": "เทมเพลตรูปแบบบุคลิกภาพ", | ||
| 82 | "Group Nudge Prompt Template": "เทมเพลตพรอมต์กระตุ้นกลุ่ม", | ||
| 83 | "Sent at the end of the group chat history to force reply from a specific character.": "ส่งท้ายประวัติแชทกลุ่มเพื่อบังคับให้ตัวละครหนึ่งตอบกลับ", | ||
| 84 | "New Chat": "เริ่มแชทใหม่", | ||
| 85 | "Restore new chat prompt": "คืนค่าชุดคำสั่งสำหรับแชทใหม่", | ||
| 86 | "Set at the beginning of the chat history to indicate that a new chat is about to start.": "ตั้งค่าไว้ต้นประวัติการแชทเพื่อระบุว่าแชทใหม่กำลังจะเริ่มต้น", | ||
| 87 | "New Group Chat": "เริ่มต้นแชทกลุ่มใหม่", | ||
| 88 | "Restore new group chat prompt": "คืนค่าชุดคำสั่งแชทกลุ่มใหม่", | ||
| 89 | "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "ตั้งค่าไว้ต้นประวัติการแชทเพื่อระบุว่าแชทกลุ่มใหม่กำลังจะเริ่มต้น", | ||
| 90 | "New Example Chat": "ตัวอย่างการพูดคุยใหม่", | ||
| 91 | "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "ตั้งค่าไว้ต้นตัวอย่างบทสนทนาเพื่อระบุว่าตัวอย่างแชทใหม่กำลังจะเริ่มต้น", | ||
| 92 | "Continue nudge": "กระตุ้นให้ดำเนินต่อ", | ||
| 93 | "Set at the end of the chat history when the continue button is pressed.": "ตั้งค่าไว้ท้ายประวัติการแชทเมื่อกดปุ่มดำเนินต่อ", | ||
| 94 | "Replace empty message": "เขียนทับข้อความที่ว่างเปล่า", | ||
| 95 | "Send this text instead of nothing when the text box is empty.": "ส่งข้อความที่กำหนดนี้ไปแทนข้อความที่ว่างเปล่า หากช่องแชทไม่ได้ส่งข้อความใดๆไป", | ||
| 96 | "Seed": "Seed", | ||
| 97 | "Set to get deterministic results. Use -1 for random seed.": "ตั้งค่าเพื่อให้ได้ผลลัพธ์ที่แน่นอน ใช้ -1 สำหรับ seed แบบสุ่ม", | ||
| 98 | "Temperature controls the randomness in token selection": "Temperature ควบคุมอัตราสุ่มในการเลือกโทเค็น", | ||
| 99 | "Top_K_desc": "จำกัดทางเลือกโทเค็นตามอันดับความน่าจะเป็นสูงสุด K ตัว", | ||
| 100 | "Top_P_desc": "จำกัดทางเลือกโทเค็นตามเปอร์เซ็นต์ความน่าจะเป็นสะสม", | ||
| 101 | "Typical P": "Typical P", | ||
| 102 | "Typical_P_desc": "การควบคุมการสุ่มโดยเลือกโทเค็นที่มีความน่าจะเป็นใกล้เคียงกับค่าเฉลี่ย", | ||
| 103 | "Min_P_desc": "กำหนดขีดจำกัดความน่าจะเป็นขั้นต่ำสำหรับการเลือกโทเค็น", | ||
| 104 | "Top_A_desc": "การสุ่มแบบ Top A ที่ปรับให้เหมาะสมกับบริบท", | ||
| 105 | "Tail_Free_Sampling_desc": "การสุ่มโดยตัดโทเค็นที่มีความน่าจะเป็นต่ำออก", | ||
| 106 | "rep.pen range": "ขอบเขตโทษการซ้ำ", | ||
| 107 | "Mirostat": "Mirostat", | ||
| 108 | "Mode": "โหมด", | ||
| 109 | "Mirostat_Mode_desc": "อธิบายโหมด Mirostat", | ||
| 110 | "Tau": "Tau", | ||
| 111 | "Mirostat_Tau_desc": "พารามิเตอร์ความแปรปรวนสำหรับผลลัพธ์ Mirostat", | ||
| 112 | "Eta": "Eta", | ||
| 113 | "Mirostat_Eta_desc": "อัตราการเรียนรู้ของ Mirostat", | ||
| 114 | "Ban EOS Token": "ห้ามใช้โทเค็น EOS", | ||
| 115 | "Ban_EOS_Token_desc": "บังคับให้โมเดลไม่จบการสร้างข้อความก่อนเวลาอันควร", | ||
| 116 | "GBNF Grammar": "ไวยากรณ์ GBNF", | ||
| 117 | "Type in the desired custom grammar": "พิมพ์ไวยากรณ์ที่ต้องการ", | ||
| 118 | "Samplers Order": "ลำดับของตัวสุ่ม", | ||
| 119 | "Samplers will be applied in a top-down order. Use with caution.": "ตัวสุ่มจะถูกใช้งานตามลำดับจากบนลงล่าง ใช้ด้วยความระมัดระวัง", | ||
| 120 | "Tail Free Sampling": "การสุ่มแบบ Tail Free", | ||
| 121 | "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 Bias", | ||
| 127 | "Add": "เพิ่ม", | ||
| 128 | "Helps to ban or reenforce the usage of certain words": "ช่วยห้ามหรือเสริมการใช้คำบางคำ", | ||
| 129 | "CFG Scale": "CFG Scale", | ||
| 130 | "Negative Prompt": "Negative Prompt", | ||
| 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 ไม่ได้ถูกตั้งค่าทั่วไป ต่อแชท หรือตัวละคร", | ||
| 133 | "Mirostat Tau": "Mirostat Tau", | ||
| 134 | "Mirostat LR": "Mirostat LR", | ||
| 135 | "Min Length": "ความยาวต่ำสุด", | ||
| 136 | "Top K Sampling": "การสุ่มแบบ Top K", | ||
| 137 | "Nucleus Sampling": "การสุ่มแบบ Nucleus", | ||
| 138 | "Top A Sampling": "การสุ่มแบบ Top A", | ||
| 139 | "CFG": "CFG", | ||
| 140 | "Neutralize Samplers": "ทำให้ตัวสุ่มเป็นกลาง", | ||
| 141 | "Set all samplers to their neutral/disabled state.": "ตั้งค่าตัวสุ่มทั้งหมดให้เป็นสถานะเป็นกลาง/ปิดใช้งาน", | ||
| 142 | "Sampler Select": "เลือกตัวสุ่ม", | ||
| 143 | "Customize displayed samplers or add custom samplers.": "ปรับแต่งตัวสุ่มที่แสดงหรือเพิ่มตัวสุ่มแบบกำหนดเอง", | ||
| 144 | "Epsilon Cutoff": "Epsilon Cutoff", | ||
| 145 | "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon cutoff กำหนดขีดจำกัดความน่าจะเป็นขั้นต่ำที่โทเค็นจะถูกแยกออกจากการสุ่ม", | ||
| 146 | "Eta Cutoff": "Eta Cutoff", | ||
| 147 | "Eta_Cutoff_desc": "คำอธิบาย Eta Cutoff สำหรับการกรองโทเค็น", | ||
| 148 | "rep.pen decay": "การลดลงของ rep.pen", | ||
| 149 | "Encoder Rep. Pen.": "Encoder Rep. Pen.", | ||
| 150 | "No Repeat Ngram Size": "ขนาด Ngram ที่ไม่ซ้ำ", | ||
| 151 | "Skew": "ความเบี้ยว", | ||
| 152 | "Max Tokens Second": "โทเค็นสูงสุดต่อวินาที", | ||
| 153 | "Smooth Sampling": "Smooth Sampling", | ||
| 154 | "Smooth_Sampling_desc": "สามารถปรับการกระจายโดยใช้การแปลงดีกรี 2/3 ได้ ค่าที่ต่ำกว่าของ Smoothing Factor จะให้ความคิดสร้างสรรค์มากขึ้น โดยปกติ 0.2-0.3 จะเป็นจุดที่เหมาะสม (สมมติว่าเส้นโค้ง = 1) ค่าที่สูงขึ้นของ Smoothing Curve จะทำให้เส้นโค้งชันขึ้น และการเลือกที่มีความน่าจะเป็นต่ำจะได้รับการลงโทษอย่างรุนแรงมากขึ้น เส้นโค้ง 1.0 เหมือนกับการใช้ Smoothing Factor เพียงอย่างเดียว", | ||
| 155 | "Smoothing Factor": "Smoothing Factor", | ||
| 156 | "Smoothing Curve": "Smoothing Curve", | ||
| 157 | "DRY_Repetition_Penalty_desc": "DRY จะลงโทษโทเค็นที่ขยายจุดสิ้นสุดของข้อมูลนำเข้าเป็นลำดับที่เกิดขึ้นก่อนหน้านี้ในข้อมูลนำเข้า ตั้งค่า multiplier เป็น 0 เพื่อปิดใช้งาน", | ||
| 158 | "DRY Repetition Penalty": "DRY Repetition Penalty", | ||
| 159 | "DRY_Multiplier_desc": "ตั้งค่าให้มากกว่า 0 เพื่อเปิดใช้งาน DRY ควบคุมขนาดของโทษสำหรับลำดับสั้นที่สุดที่ได้รับโทษ", | ||
| 160 | "Multiplier": "Multiplier", | ||
| 161 | "DRY_Base_desc": "ควบคุมอัตราที่โทษเพิ่มขึ้นตามความยาวของลำดับที่เพิ่มขึ้น", | ||
| 162 | "Base": "ค่าพื้นฐาน", | ||
| 163 | "DRY_Allowed_Length_desc": "ลำดับที่ยาวที่สุดที่สามารถทำซ้ำได้โดยไม่มีโทษ", | ||
| 164 | "Allowed Length": "ความยาวที่อนุญาต", | ||
| 165 | "Penalty Range": "Penalty Range", | ||
| 166 | "DRY_Sequence_Breakers_desc": "โทเค็นที่ทำให้การจับคู่ลำดับไม่ต่อเนื่อง ระบุเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาคของสตริงที่อยู่ในเครื่องหมายคำพูด", | ||
| 167 | "Sequence Breakers": "Sequence Breakers", | ||
| 168 | "JSON-serialized array of strings.": "อาร์เรย์ของสตริงในรูปแบบ JSON", | ||
| 169 | "Dynamic Temperature": "Tempurature แบบไดนามิก", | ||
| 170 | "Scale Temperature dynamically per token, based on the variation of probabilities": "ปรับขนาด Tempurature แบบไดนามิกต่อโทเค็น ตามความแปรปรวนของความน่าจะเป็น", | ||
| 171 | "Minimum Temp": "Temp ต่ำสุด", | ||
| 172 | "Maximum Temp": "Temp สูงสุด", | ||
| 173 | "Exponent": "เลขชี้กำลัง", | ||
| 174 | "Mirostat (mode=1 is only for llama.cpp)": "Mirostat (โหมด=1 สำหรับ llama.cpp เท่านั้น)", | ||
| 175 | "Mirostat_desc": "อธิบาย Mirostat", | ||
| 176 | "Mirostat Mode": "โหมด Mirostat", | ||
| 177 | "Variability parameter for Mirostat outputs": "พารามิเตอร์ความแปรปรวนสำหรับผลลัพธ์ Mirostat", | ||
| 178 | "Mirostat Eta": "Mirostat Eta", | ||
| 179 | "Learning rate of Mirostat": "อัตราการเรียนรู้ของ Mirostat", | ||
| 180 | "Beam search": "การค้นหาแบบ Beam", | ||
| 181 | "Helpful tip coming soon.": "เคล็ดลับมีประโยชน์จะมาเร็วๆ นี้", | ||
| 182 | "Number of Beams": "จำนวน Beam", | ||
| 183 | "Length Penalty": "โทษความยาว", | ||
| 184 | "Early Stopping": "การหยุดล่วงหน้า", | ||
| 185 | "Contrastive search": "การค้นหาแบบ Contrastive", | ||
| 186 | "Penalty Alpha": "Penalty Alpha", | ||
| 187 | "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "ความแรงของเทอม regularization ของ Contrastive Search ตั้งเป็น 0 เพื่อปิด CS", | ||
| 188 | "Do Sample": "Do Sample", | ||
| 189 | "Add BOS Token": "เพิ่ม BOS Token", | ||
| 190 | "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "เพิ่ม bos_token ไว้ต้นพรอมต์ การปิดสิ่งนี้อาจทำให้การตอบกลับสร้างสรรค์มากขึ้น", | ||
| 191 | "Ban the eos_token. This forces the model to never end the generation prematurely": "ห้าม eos_token ทำให้โมเดลไม่สิ้นสุดการสร้างก่อนเวลาอันควร", | ||
| 192 | "Ignore EOS Token": "เพิกเฉยต่อ EOS Token", | ||
| 193 | "Ignore the EOS Token even if it generates.": "เพิกเฉย EOS Token แม้ว่าจะถูกสร้างขึ้น", | ||
| 194 | "Skip Special Tokens": "ข้าม Special Tokens", | ||
| 195 | "Temperature Last": "อุณหภูมิสุดท้าย", | ||
| 196 | "Temperature_Last_desc": "ใช้อุณหภูมิเป็นขั้นตอนสุดท้ายในการสุ่ม", | ||
| 197 | "Speculative Ngram": "Speculative Ngram", | ||
| 198 | "Use a different speculative decoding method without a draft model": "ใช้วิธีการ speculative decoding ที่แตกต่างกันโดยไม่ต้องใช้โมเดลร่าง", | ||
| 199 | "Spaces Between Special Tokens": "ช่องว่างระหว่าง Special Tokens", | ||
| 200 | "LLaMA / Mistral / Yi models only": "เฉพาะโมเดล LLaMA / Mistral / Yi เท่านั้น", | ||
| 201 | "Example: some text [42, 69, 1337]": "ตัวอย่าง: ข้อความบางส่วน [42, 69, 1337]", | ||
| 202 | "Classifier Free Guidance. More helpful tip coming soon": "คำแนะนำฟรีเกี่ยวกับเครื่องมือจำแนกประเภท จะมีเคล็ดลับที่เป็นประโยชน์เพิ่มเติมเร็วๆ นี้", | ||
| 203 | "Scale": "ขนาด", | ||
| 204 | "JSON Schema": "JSON Schema", | ||
| 205 | "Type in the desired JSON schema": "พิมพ์ JSON schema ที่ต้องการ", | ||
| 206 | "Grammar String": "สตริงไวยากรณ์", | ||
| 207 | "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF หรือ EBNF ขึ้นอยู่กับแบ็กเอนด์ที่ใช้ หากคุณใช้สิ่งนี้ คุณควรรู้ว่าเป็นแบบไหน", | ||
| 208 | "Top P & Min P": "Top P & Min P", | ||
| 209 | "Load default order": "โหลดลำดับเริ่มต้น", | ||
| 210 | "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "เฉพาะ llama.cpp กำหนดลำดับของตัวสุ่ม หากโหมด Mirostat ไม่ใช่ 0 ลำดับตัวสุ่มจะถูกเพิกเฉย", | ||
| 211 | "Sampler Priority": "ลำดับความสำคัญของตัวสุ่ม", | ||
| 212 | "Ooba only. Determines the order of samplers.": "เฉพาะ Ooba กำหนดลำดับของตัวสุ่ม", | ||
| 213 | "Character Names Behavior": "พฤติกรรมการแสดงชื่อตัวละคร", | ||
| 214 | "Helps the model to associate messages with characters.": "ช่วยให้โมเดลเชื่อมโยงข้อความกับตัวละคร", | ||
| 215 | "None": "ไม่มี", | ||
| 216 | "character_names_default": "ชื่อตัวละครเริ่มต้น", | ||
| 217 | "Don't add character names.": "ไม่เพิ่มชื่อตัวละคร", | ||
| 218 | "Completion": "การเสร็จสิ้น", | ||
| 219 | "character_names_completion": "การเสร็จสิ้นชื่อตัวละคร", | ||
| 220 | "Add character names to completion objects.": "เพิ่มชื่อตัวละครไปยังออบเจ็กต์การเสร็จสิ้น", | ||
| 221 | "Message Content": "เนื้อหาของข้อความ", | ||
| 222 | "Prepend character names to message contents.": "เพิ่มชื่อตัวละครไว้หน้าเนื้อหาข้อความ", | ||
| 223 | "Continue Postfix": "Continue Postfix", | ||
| 224 | "The next chunk of the continued message will be appended using this as a separator.": "ส่วนต่อไปของข้อความที่ต่อเนื่องจะถูกผนวกโดยใช้สิ่งนี้เป็นตัวคั่น", | ||
| 225 | "Space": "พื้นที่ว่าง", | ||
| 226 | "Newline": "ขึ้นบรรทัดใหม่", | ||
| 227 | "Double Newline": "ขึ้นสองบรรทัด", | ||
| 228 | "Wrap user messages in quotes before sending": "ครอบข้อความของผู้ใช้ด้วยเครื่องหมายคำพูดก่อนส่ง", | ||
| 229 | "Wrap in Quotes": "Wrap in Quotes", | ||
| 230 | "Wrap entire user message in quotes before sending.": "ครอบข้อความของผู้ใช้ทั้งหมดด้วยเครื่องหมายคำพูดก่อนส่ง", | ||
| 231 | "Leave off if you use quotes manually for speech.": "ปิดถ้าคุณใช้เครื่องหมายคำพูดด้วยตนเองสำหรับการพูด", | ||
| 232 | "Continue prefill": "Continue prefill", | ||
| 233 | "Continue sends the last message as assistant role instead of system message with instruction.": "Continue ส่งข้อความสุดท้ายเป็นบทบาทผู้ช่วยแทนที่จะเป็นข้อความระบบพร้อมคำแนะนำ", | ||
| 234 | "Squash system messages": "Squash system messages", | ||
| 235 | "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "รวมข้อความระบบที่ติดต่อกันเป็นหนึ่งเดียว (ไม่รวมบทสนทนาตัวอย่าง) อาจปรับปรุงความสอดคล้องสำหรับโมเดลบางรุ่น", | ||
| 236 | "Enable function calling": "Enable function calling", | ||
| 237 | "enable_functions_desc_1":"อนุญาตให้มีการใช้งาน ", | ||
| 238 | "enable_functions_desc_2":"function tools" , | ||
| 239 | "enable_functions_desc_3": "สามารถใช้งานโดยใช้ผ่าน Extension เพื่อเพิ่มฟังก์ชั่นเพิ่มเติม", | ||
| 240 | "enable_functions_desc_4": "ไม่ Support ถ้า Prompt Post-Processing with \"no tools\" ถูกเปิดใช้งาน", | ||
| 241 | "Allows the model to return its thinking process.": "อนุญาตให้โมเดลส่งคืนกระบวนการคิดของตัวเอง", | ||
| 242 | "This setting affects visibility only.": "การตั้งค่านี้มีผลต่อการมองเห็นเท่านั้น", | ||
| 243 | "Send inline images": "ส่งรูปภาพแบบ inline", | ||
| 244 | "image_inlining_hint_1": "ส่งรูปภาพในพรอมต์หากโมเดลรองรับ โดยใช้", | ||
| 245 | "image_inlining_hint_2": "เพื่อดำเนินการในข้อความนั้นๆ หรือใช้ตัวเลือก", | ||
| 246 | "image_inlining_hint_3": "เพื่อแนบไฟล์รูปภาพลงในแชท", | ||
| 247 | "Inline Image Quality": "คุณภาพรูปภาพ Inline", | ||
| 248 | "openai_inline_image_quality_auto": "อัตโนมัติ", | ||
| 249 | "openai_inline_image_quality_low": "ต่ำ", | ||
| 250 | "openai_inline_image_quality_high": "สูง", | ||
| 251 | "Use AI21 Tokenizer": "ใช้ AI21 Tokenizer", | ||
| 252 | "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "ใช้ tokenizer ที่เหมาะสมสำหรับโมเดล Jurassic ซึ่งมีประสิทธิภาพมากกว่าของ GPT", | ||
| 253 | "Use Google Tokenizer": "ใช้ Google Tokenizer", | ||
| 254 | "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "ใช้ tokenizer ที่เหมาะสมสำหรับโมเดล Google ผ่าน API ช้ากว่าในการประมวลผลพรอมต์ แต่นับโทเค็นได้แม่นยำมากกว่า", | ||
| 255 | "Use system prompt": "ใช้คำสั่งระบบ (system prompt)", | ||
| 256 | "(Gemini 1.5 Pro/Flash only)": "(เฉพาะ Gemini 1.5 Pro/Flash เท่านั้น)", | ||
| 257 | "Merges_all_system_messages_desc_1": "รวมข้อความระบบทั้งหมดจนถึงข้อความแรกที่ไม่ใช่บทบาทระบบ และส่งในฟิลด์", | ||
| 258 | "Merges_all_system_messages_desc_2": "เดี่ยว", | ||
| 259 | "Assistant Prefill": "Assistant Prefill", | ||
| 260 | "Start Claude's answer with...": "เริ่มคำตอบของ Claude ด้วย...", | ||
| 261 | "Assistant Impersonation Prefill": "Assistant Impersonation Prefill", | ||
| 262 | "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "ส่งพรอมต์ระบบสำหรับโมเดลที่รองรับ หากปิดใช้งาน ข้อความผู้ใช้จะถูกเพิ่มไว้ต้นพรอมต์", | ||
| 263 | "User first message": "ข้อความเริ่มต้นของผู้ใช้", | ||
| 264 | "Restore User first message": "คืนค่าข้อความเริ่มต้นของผู้ใช้", | ||
| 265 | "Human message": "ข้อความของยูเซอร์", | ||
| 266 | "New preset": "เพิ่มการปรับแต่งใหม่", | ||
| 267 | "Delete preset": "ลบการปรับแต่ง", | ||
| 268 | "View / Edit bias preset": "ดู / แก้ไข bias preset", | ||
| 269 | "Add bias entry": "เพิ่มรายการ bias", | ||
| 270 | "Most tokens have a leading space.": "โทเค็นส่วนใหญ่มีช่องว่างนำหน้า", | ||
| 271 | "API Connections": "การเชื่อมต่อ API", | ||
| 272 | "Text Completion": "Text Completion", | ||
| 273 | "Chat Completion": "Chat Completion", | ||
| 274 | "NovelAI": "NovelAI", | ||
| 275 | "AI Horde": "AI Horde", | ||
| 276 | "KoboldAI": "KoboldAI", | ||
| 277 | "Avoid sending sensitive information to the Horde.": "โปรดหลีกเลี่ยงการส่งข้อมูลที่ละเอียดอ่อนไปยัง Horde", | ||
| 278 | "Review the Privacy statement": "ตรวจสอบนโยบายความเป็นส่วนตัว", | ||
| 279 | "Register a Horde account for faster queue times": "ลงทะเบียนบัญชี Horde เพื่อเวลาคิวที่เร็วขึ้น", | ||
| 280 | "Learn how to contribute your idle GPU cycles to the Horde": "เรียนรู้วิธีการใช้งาน GPU ของคุณกับ Horde", | ||
| 281 | "Adjust context size to worker capabilities": "ปรับขนาดบริบทให้เหมาะกับความสามารถของ worker", | ||
| 282 | "Adjust response length to worker capabilities": "ปรับความยาวการตอบกลับให้เหมาะกับความสามารถของ worker", | ||
| 283 | "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "สามารถช่วยแก้ไขการตอบกลับที่ไม่ดีโดยการจัดคิวเฉพาะ worker ที่ได้รับการอนุมัติ อาจทำให้เวลาตอบกลับช้าลง", | ||
| 284 | "Trusted workers only": "เฉพาะ worker ที่เชื่อถือได้", | ||
| 285 | "API key": "คีย์ API", | ||
| 286 | "Get it here:": "รับได้ที่นี่:", | ||
| 287 | "Register": "ลงทะเบียน", | ||
| 288 | "View my Kudos": "ดู Kudos ของฉัน", | ||
| 289 | "Enter": "ส่ง", | ||
| 290 | "to use anonymous mode.": "เพื่อใช้โหมดไม่ระบุชื่อ", | ||
| 291 | "Clear your API key": "ล้างคีย์ API ของคุณ", | ||
| 292 | "For privacy reasons, your API key will be hidden after you reload the page.": "ด้วยเหตุผลด้านความเป็นส่วนตัว คีย์ API ของคุณจะถูกซ่อนไว้หลังจากรีเฟรชหน้าเว็บไซต์แล้ว", | ||
| 293 | "Models": "รุ่นโมเดล", | ||
| 294 | "Refresh models": "รีเฟรชโมเดล", | ||
| 295 | "-- Horde models not loaded --": "-- โมเดล Horde ไม่ได้โหลด --", | ||
| 296 | "Not connected...": "ไม่มีการเชื่อมต่อ...", | ||
| 297 | "API url": "URL ของ API", | ||
| 298 | "Example: http://127.0.0.1:5000/api ": "ตัวอย่าง: http://127.0.0.1:5000/api", | ||
| 299 | "Connect": "เชื่อมต่อ", | ||
| 300 | "Cancel": "ยกเลิก", | ||
| 301 | "Novel API key": "คีย์ API ของ Novel", | ||
| 302 | "Get your NovelAI API Key": "รับคีย์ API ของ NovelAI ได้ที่นี่", | ||
| 303 | "Enter it in the box below": "กรอกคีย์ที่ได้รับลงในช่องด้านล่าง", | ||
| 304 | "Novel AI Model": "โมเดลของ NovelAI", | ||
| 305 | "No connection...": "ไม่มีการเชื่อมต่อ...", | ||
| 306 | "API Type": "ประเภทของ API", | ||
| 307 | "Default (completions compatible)": "ค่าเริ่มต้น (รองรับการเติมข้อความอัตโนมัติ)", | ||
| 308 | "TogetherAI API Key": "คีย์ API ของ Together AI", | ||
| 309 | "TogetherAI Model": "โมเดลของ TogetherAI", | ||
| 310 | "-- Connect to the API --": "-- เชื่อมต่อ API --", | ||
| 311 | "OpenRouter API Key": "คีย์ API ของ OpenRouter", | ||
| 312 | "Click Authorize below or get the key from": "กดปุ่ม Authorize ข้างล่างเพื่อยืนยัน Persona หรือให้ทำการนำคีย์มาใส่เพื่อใช้งาน", | ||
| 313 | "View Remaining Credits": "เช็คเครดิตคงเหลือ", | ||
| 314 | "OpenRouter Model": "OpenRouter โมเดล", | ||
| 315 | "Model Providers": "ผู้ให้บริการโมเดล", | ||
| 316 | "InfermaticAI API Key": "คีย์ API ของ InfermaticAI", | ||
| 317 | "InfermaticAI Model": "โมเดลของ InfermaticAI", | ||
| 318 | "DreamGen API key": "คีย์ API ของ DreamGen", | ||
| 319 | "DreamGen Model": "โมเดลของ DreamGen", | ||
| 320 | "Mancer API key": "คีย์ API ของ Mancer", | ||
| 321 | "Mancer Model": "โมเดลของ Mancer", | ||
| 322 | "Make sure you run it with": "ให้แน่ใจว่าคุณเปิดมันโดยใช้...", | ||
| 323 | "flag": "flag", | ||
| 324 | "API key (optional)": "API key (ไม่บังคับ)", | ||
| 325 | "Server url": "ที่อยู่ของเซิร์ฟเวอร์ (URL)", | ||
| 326 | "Example: http://127.0.0.1:5000": "ตัวอย่าง: http://127.0.0.1:5000", | ||
| 327 | "Custom model (optional)": "โมเดลที่กำหนดเอง (ไม่บังคับ)", | ||
| 328 | "vllm-project/vllm": "vllm-project/vllm", | ||
| 329 | "vLLM API key": "คีย์ API ของ vLLM", | ||
| 330 | "Example: http://127.0.0.1:8000": "ตัวอย่าง: http://127.0.0.1:8000", | ||
| 331 | "vLLM Model": "โมเดลของ vLLM", | ||
| 332 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine", | ||
| 333 | "Aphrodite API key": "คีย์ API ของ Aphrodite", | ||
| 334 | "Aphrodite Model": "โมเดลของ Aphrodite", | ||
| 335 | "ggerganov/llama.cpp": "ggerganov/llama.cpp", | ||
| 336 | "Example: http://127.0.0.1:8080": "ตัวอย่าง: http://127.0.0.1:8080", | ||
| 337 | "Example: http://127.0.0.1:11434": "ตัวอย่าง: http://127.0.0.1:11434", | ||
| 338 | "Ollama Model": "โมเดลของ Ollama", | ||
| 339 | "Download": "ดาวน์โหลด", | ||
| 340 | "Tabby API key": "คีย์ API ของ Tabby", | ||
| 341 | "koboldcpp API key (optional)": "คีย์ API ของ koboldcpp (เพิ่มเติม)", | ||
| 342 | "Example: http://127.0.0.1:5001": "ตัวอย่าง: http://127.0.0.1:5001", | ||
| 343 | "Authorize": "อนุญาต", | ||
| 344 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "โปรดเข้าสู่ระบบเพื่อรับ OpenRouter API Token โดยใช้ OAuth Flow จากนั้นคุณจะถูกเปลี่ยนเส้นทางไปยังเว็บไซต์ของ openrouter.ai", | ||
| 345 | "Bypass status check": "ข้ามการตรวจสอบสถานะ", | ||
| 346 | "Chat Completion Source": "แหล่งที่มาของ Chat Completion", | ||
| 347 | "Reverse Proxy": "Reverse Proxy", | ||
| 348 | "Proxy Presets": "พรีเซ็ต Proxy", | ||
| 349 | "Saved addresses and passwords.": "ที่อยู่และรหัสผ่านที่บันทึกไว้", | ||
| 350 | "Save Proxy": "เซฟพร็อกซี", | ||
| 351 | "Delete Proxy": "ลบพร็อกซี", | ||
| 352 | "Proxy Name": "ชื่อพร็อกซี", | ||
| 353 | "This will show up as your saved preset.": "สิ่งนี้จะปรากฏเป็นพรีเซ็ตที่คุณเซฟไว้", | ||
| 354 | "Proxy Server URL": "Proxy Server URL", | ||
| 355 | "Alternative server URL (leave empty to use the default value).": "URL เซิร์ฟเวอร์สำรอง (เว้นว่างไว้เพื่อใช้ค่าเริ่มต้น)", | ||
| 356 | "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "โปรดลบคีย์ OAI API จริงของคุณออกจากหน้า API Panel ก่อนที่จะเริ่มพิมพ์ข้อความใด ๆ ลงในช่องนี้", | ||
| 357 | "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "เราไม่สามารถช่วยเหลือปัญหาจากการใช้พร็อกซีของ OpenAI ที่ไม่ได้รับการรับรองอย่างเป็นทางการ", | ||
| 358 | "Doesn't work? Try adding": "ไม่ทำงาน? ลองเพิ่ม", | ||
| 359 | "at the end!": "ไว้ท้ายสุด!", | ||
| 360 | "Proxy Password": "รหัสผ่าน Proxy", | ||
| 361 | "Will be used as a password for the proxy instead of API key.": "สิ่งนี้จะถูกใช้เป็นรหัสผ่านสำหรับเข้าถึงพร็อกซี แทนที่คีย์ API", | ||
| 362 | "Peek a password": "แสดงรหัสผ่าน", | ||
| 363 | "OpenAI API key": "คีย์ API ของ OpenAI", | ||
| 364 | "View API Usage Metrics": "ดูสถิติการใช้งาน API", | ||
| 365 | "Follow": "ติดตาม", | ||
| 366 | "these directions": "คำแนะนำเหล่านี้", | ||
| 367 | "to get your OpenAI API key.": "เพื่อรับคีย์ API ของ OpenAI", | ||
| 368 | "Use Proxy password field instead. This input will be ignored.": "ใช้ฟิลด์รหัสผ่าน Proxy แทน อินพุตนี้จะถูกเพิกเฉย", | ||
| 369 | "OpenAI Model": "โมเดล OpenAI", | ||
| 370 | "Bypass API status check": "ข้ามการตรวจสอบสถานะ API", | ||
| 371 | "Show External models (provided by API)": "แสดงโมเดลภายนอก (ที่ API จัดให้)", | ||
| 372 | "Get your key from": "รับคีย์ของคุณจาก", | ||
| 373 | "Anthropic's developer console": "คอนโซลนักพัฒนาของ Anthropic", | ||
| 374 | "Claude Model": "โมเดล Claude", | ||
| 375 | "Window AI Model": "โมเดล Window AI", | ||
| 376 | "Model Order": "ลำดับโมเดล", | ||
| 377 | "Alphabetically": "เรียงตามตัวอักษร", | ||
| 378 | "Price": "ราคา", | ||
| 379 | "Context Size": "ขนาดของบริบท", | ||
| 380 | "Group by vendors": "จัดกลุ่มตามผู้ขาย", | ||
| 381 | "Group by vendors Description": "คำอธิบายการจัดกลุ่มตามผู้ขาย", | ||
| 382 | "Allow fallback routes": "อนุญาตเส้นทางสำรอง", | ||
| 383 | "Allow fallback routes Description": "คำอธิบายการอนุญาตเส้นทางสำรอง", | ||
| 384 | "Scale API Key": "คีย์ API ของ Scale", | ||
| 385 | "Clear your cookie": "ล้างคุกกี้ของคุณ", | ||
| 386 | "Alt Method": "วิธีสำรอง", | ||
| 387 | "AI21 API Key": "คีย์ API ของ AI21", | ||
| 388 | "AI21 Model": "โมเดล AI21", | ||
| 389 | "Google AI Studio API Key": "คีย์ API ของ Google AI Studio", | ||
| 390 | "Google Model": "โมเดล Google", | ||
| 391 | "MistralAI API Key": "คีย์ API ของ MistralAI", | ||
| 392 | "MistralAI Model": "โมเดล MistralAI", | ||
| 393 | "Groq API Key": "คีย์ API ของ Groq", | ||
| 394 | "Groq Model": "โมเดล Groq", | ||
| 395 | "Perplexity API Key": "คีย์ API ของ Perplexity", | ||
| 396 | "Perplexity Model": "โมเดลของ Perplexity", | ||
| 397 | "Cohere API Key": "คีย์ API ของ Cohere", | ||
| 398 | "Cohere Model": "โมเดลของ Cohere", | ||
| 399 | "Custom Endpoint (Base URL)": "จุดปลายทางกำหนดเอง (Base URL)", | ||
| 400 | "Custom API Key": "คีย์ API แบบกำหนดเอง", | ||
| 401 | "Available Models": "โมเดลที่สามารถใช้ได้", | ||
| 402 | "Prompt Post-Processing": "การประมวลผลพรอมต์หลังการส่ง", | ||
| 403 | "Applies additional processing to the prompt before sending it to the API.": "ใช้การประมวลผลเพิ่มเติมกับพรอมต์ก่อนส่งไปยัง API", | ||
| 404 | "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "ตรวจสอบการเชื่อมต่อ API โดยส่งข้อความทดสอบสั้นๆ โปรดทราบว่าคุณจะถูกเรียกเก็บเงินสำหรับการทดสอบนี้!", | ||
| 405 | "Test Message": "ทดสอบการส่งข้อความ", | ||
| 406 | "Auto-connect to Last Server": "เชื่อมต่อเซิฟเวอร์อัตโนมัติ", | ||
| 407 | "Missing key": "โปรดใส่ API Key", | ||
| 408 | "Key saved": "บันทึก API Key แล้ว", | ||
| 409 | "View hidden API keys": "แสดง API Key", | ||
| 410 | "AI Response Formatting": "แบบแผนการตอบกลับของ AI", | ||
| 411 | "Advanced Formatting": "แบบแผนขั้นสูง", | ||
| 412 | "Context Template": "เทมเพลต Context", | ||
| 413 | "Auto-select this preset for Instruct Mode": "เลือกพรีเซ็ตนี้โดยอัตโนมัติสำหรับโหมดคำสั่ง", | ||
| 414 | "Story String": "สตริงเรื่องราว", | ||
| 415 | "Example Separator": "ตัวแยกตัวอย่าง", | ||
| 416 | "Chat Start": "เริ่มต้นการแชท", | ||
| 417 | "Add Chat Start and Example Separator to a list of stopping strings.": "เพิ่ม Chat Start และ Example Separator ไปยังรายการสตริงหยุด", | ||
| 418 | "Use as Stop Strings": "ใช้เป็นสตริงหยุด", | ||
| 419 | "Allow Jailbreak": "อนุญาต Jailbreak", | ||
| 420 | "Context Order": "ลำดับ Context", | ||
| 421 | "Summary": "สรุป", | ||
| 422 | "Author's Note": "หมายเหตุจากผู้เขียน", | ||
| 423 | "Example Dialogues": "ตัวอย่างบทสนทนา", | ||
| 424 | "Hint": "คำแนะนำ", | ||
| 425 | "In-Chat Position not affected": "ตำแหน่งในแชทไม่ได้รับผลกระทบ", | ||
| 426 | "Instruct Mode": "โหมดคำสั่ง", | ||
| 427 | "Enabled": "เปิดใช้งาน", | ||
| 428 | "instruct_bind_to_context": "ผูกกับ context", | ||
| 429 | "Bind to Context": "ผูกกับ Context", | ||
| 430 | "Presets": "พรีเซ็ต", | ||
| 431 | "Auto-select this preset on API connection": "เลือกพรีเซ็ตนี้โดยอัตโนมัติเมื่อเชื่อมต่อ API", | ||
| 432 | "Activation Regex": "Regex การเปิดใช้งาน", | ||
| 433 | "Wrap Sequences with Newline": "ห่อลำดับด้วยบรรทัดใหม่", | ||
| 434 | "Replace Macro in Sequences": "แทนที่แมโครในลำดับ", | ||
| 435 | "Skip Example Dialogues Formatting": "ข้ามการจัดรูปแบบตัวอย่างบทสนทนา", | ||
| 436 | "Include Names": "รวมชื่อ", | ||
| 437 | "Force for Groups and Personas": "บังคับสำหรับกลุ่มและ Persona", | ||
| 438 | "System Prompt": "Prompt ของระบบ", | ||
| 439 | "Instruct Mode Sequences": "ลำดับโหมดคำสั่ง", | ||
| 440 | "System Prompt Wrapping": "การห่อหุ้ม System Prompt", | ||
| 441 | "Inserted before a System prompt.": "แทรกก่อน System prompt", | ||
| 442 | "System Prompt Prefix": "คำนำหน้า System Prompt", | ||
| 443 | "Inserted after a System prompt.": "แทรกหลัง System prompt", | ||
| 444 | "System Prompt Suffix": "คำต่อท้าย System Prompt", | ||
| 445 | "Chat Messages Wrapping": "การห่อหุ้มข้อความแชท", | ||
| 446 | "Inserted before a User message and as a last prompt line when impersonating.": "แทรกก่อนข้อความผู้ใช้และเป็นบรรทัดพรอมต์สุดท้ายเมื่อสวมบทบาท", | ||
| 447 | "User Message Prefix": "คำนำหน้าข้อความผู้ใช้", | ||
| 448 | "Inserted after a User message.": "แทรกหลังข้อความผู้ใช้", | ||
| 449 | "User Message Suffix": "คำต่อท้ายข้อความผู้ใช้", | ||
| 450 | "Inserted before an Assistant message and as a last prompt line when generating an AI reply.": "แทรกก่อนข้อความผู้ช่วยและเป็นบรรทัดพรอมต์สุดท้ายเมื่อสร้างการตอบกลับ AI", | ||
| 451 | "Assistant Message Prefix": "คำนำหน้าข้อความผู้ช่วย", | ||
| 452 | "Inserted after an Assistant message.": "แทรกหลังข้อความผู้ช่วย", | ||
| 453 | "Assistant Message Suffix": "คำต่อท้ายข้อความผู้ช่วย", | ||
| 454 | "Inserted before a System (added by slash commands or extensions) message.": "แทรกก่อนข้อความระบบ (ที่เพิ่มโดยคำสั่ง slash หรือส่วนขยาย)", | ||
| 455 | "System Message Prefix": "คำนำหน้าข้อความระบบ", | ||
| 456 | "Inserted after a System message.": "แทรกหลังข้อความระบบ", | ||
| 457 | "System Message Suffix": "คำต่อท้ายข้อความระบบ", | ||
| 458 | "If enabled, System Sequences will be the same as User Sequences.": "หากเปิดใช้งาน System Sequences จะเหมือนกับ User Sequences", | ||
| 459 | "System same as User": "ระบบเหมือนกับผู้ใช้", | ||
| 460 | "Misc. Sequences": "ลำดับเบ็ดเตล็ด", | ||
| 461 | "Inserted before the first Assistant's message.": "แทรกก่อนข้อความแรกของผู้ช่วย", | ||
| 462 | "First Assistant Prefix": "คำนำหน้าผู้ช่วยแรก", | ||
| 463 | "instruct_last_output_sequence": "ลำดับผลลัพธ์สุดท้ายของคำสั่ง", | ||
| 464 | "Last Assistant Prefix": "คำนำหน้าผู้ช่วยสุดท้าย", | ||
| 465 | "Will be inserted as a last prompt line when using system/neutral generation.": "จะถูกแทรกเป็นบรรทัดพรอมต์สุดท้ายเมื่อใช้การสร้างแบบระบบ/เป็นกลาง", | ||
| 466 | "System Instruction Prefix": "คำนำหน้าคำสั่งระบบ", | ||
| 467 | "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "หากมีลำดับหยุดถูกสร้างขึ้น ทุกอย่างหลังจากนั้นจะถูกลบออกจากผลลัพธ์ (รวมลำดับหยุดด้วย)", | ||
| 468 | "Stop Sequence": "ลำดับหยุด", | ||
| 469 | "Will be inserted at the start of the chat history if it doesn't start with a User message.": "จะถูกแทรกที่ต้นประวัติการแชทหากไม่เริ่มต้นด้วยข้อความของผู้ใช้", | ||
| 470 | "User Filler Message": "ข้อความเติมของผู้ใช้", | ||
| 471 | "Context Formatting": "การจัดรูปแบบ Context", | ||
| 472 | "(Saved to Context Template)": "(บันทึกไปยัง Context Template)", | ||
| 473 | "Always add character's name to prompt": "เพิ่มชื่อตัวละครลงในพรอมต์เสมอ", | ||
| 474 | "Generate only one line per request": "สร้างเพียงหนึ่งบรรทัดต่อคำขอ", | ||
| 475 | "Trim Incomplete Sentences": "ตัดประโยคที่ไม่สมบูรณ์", | ||
| 476 | "Include Newline": "รวมบรรทัดใหม่", | ||
| 477 | "Misc. Settings": "การตั้งค่าเบ็ดเตล็ด", | ||
| 478 | "Collapse Consecutive Newlines": "ยุบบรรทัดใหม่ที่ติดต่อกัน", | ||
| 479 | "Trim spaces": "ตัดช่องว่าง", | ||
| 480 | "Tokenizer": "ตัวแบ่งโทเค็น", | ||
| 481 | "Token Padding": "การเพิ่มโทเค็น", | ||
| 482 | "Start Reply With": "เริ่มตอบด้วย", | ||
| 483 | "AI reply prefix": "คำนำหน้าการตอบของ AI", | ||
| 484 | "Show reply prefix in chat": "แสดงคำนำหน้าการตอบในแชท", | ||
| 485 | "Non-markdown strings": "Non-markdown strings", | ||
| 486 | "separate with commas w/o space between": "แยกด้วยเครื่องหมายจุลภาคโดยไม่มีช่องว่าง", | ||
| 487 | "Custom Stopping Strings": "สตริงหยุดกำหนดเอง", | ||
| 488 | "JSON serialized array of strings": "อาร์เรย์ของสตริงในรูปแบบ JSON", | ||
| 489 | "Replace Macro in Stop Strings": "แทนที่แมโครในสตริงหยุด", | ||
| 490 | "Auto-Continue": "ต่อบทอัตโนมัติ", | ||
| 491 | "Allow for Chat Completion APIs": "อนุญาตสำหรับ Chat Completion APIs", | ||
| 492 | "Target length (tokens)": "ความยาวเป้าหมาย (โทเค็น)", | ||
| 493 | "World Info": "ข้อมูลโลก (World info)", | ||
| 494 | "Locked = World Editor will stay open": "Locked = สามารถแก้ไขข้อมูลโลกได้เสมอ", | ||
| 495 | "Worlds/Lorebooks": "ข้อมูลโลก/Lorebooks", | ||
| 496 | "Active World(s) for all chats": "ข้อมูลโลกที่ถูกเปิดใช้งานทุกแชท", | ||
| 497 | "-- World Info not found --": "-- ไม่พบข้อมูลโลก --", | ||
| 498 | "Global World Info/Lorebook activation settings": "ตั้งค่าการใช้งานข้อมูลโลก/Lorebook", | ||
| 499 | "Click to expand": "กดเพื่อแสดงข้อมูล", | ||
| 500 | "Scan Depth": "Scan Depth", | ||
| 501 | "Context %": "Context %", | ||
| 502 | "Budget Cap": "Budget Cap", | ||
| 503 | "(0 = disabled)": "(0 = ปิดใช้งาน)", | ||
| 504 | "Scan chronologically until reached min entries or token budget.": "สแกนตามลำดับเวลาจนกว่าจะถึงรายการขั้นต่ำหรืองบโทเค็น", | ||
| 505 | "Min Activations": "การเปิดใช้งานขั้นต่ำ", | ||
| 506 | "Max Depth": "ความลึกสูงสุด", | ||
| 507 | "(0 = unlimited, use budget)": "(0 = ไม่จำกัด ใช้งบประมาณ)", | ||
| 508 | "Insertion Strategy": "กลยุทธ์การแทรก", | ||
| 509 | "Sorted Evenly": "เรียงลำดับเท่าๆ กัน", | ||
| 510 | "Create a new World Info": "สร้าง Lorebook ใหม่", | ||
| 511 | "Character Lore First": "เลือกใช้เนื้อหาตัวละครก่อน", | ||
| 512 | "Global Lore First": "เลือกใช้เนื้อหาหลักของโลกก่อน", | ||
| 513 | "Entries can activate other entries by mentioning their keywords": "สามารถเรียกใช้รายการเนื้อหาที่เกี่ยวข้องกันด้วย Keywords", | ||
| 514 | "Recursive Scan": "Recursive Scan", | ||
| 515 | "Lookup for the entry keys in the context will respect the case": "Lookup for the entry keys in the context will respect the case", | ||
| 516 | "Case Sensitive": "แยกตัวพิมพ์ใหญ่-เล็ก", | ||
| 517 | "If the entry key consists of only one word, it would not be matched as part of other words": "If the entry key consists of only one word, it would not be matched as part of other words", | ||
| 518 | "Match Whole Words": "ตรงกับคำทั้งหมด", | ||
| 519 | "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "จะเลือกเนื้อหาที่มี keyword ตรงกันมากที่สุดเท่านั้น", | ||
| 520 | "Use Group Scoring": "Use Group Scoring", | ||
| 521 | "Alert if your world info is greater than the allocated budget.": "Alert if your world info is greater than the allocated budget.", | ||
| 522 | "Alert On Overflow": "Alert On Overflow", | ||
| 523 | "New": "ใหม่", | ||
| 524 | "or": "หรือ", | ||
| 525 | "--- Pick to Edit ---": "กดเพื่อแก้ไข", | ||
| 526 | "Rename World Info": "แก้ไขชื่อของข้อมูลโลก", | ||
| 527 | "Open all Entries": "แสดงเนื้อหาทั้งหมด", | ||
| 528 | "Close all Entries": "ปิดการแสดงเนื้อหาทั้งหมด", | ||
| 529 | "New Entry": "สร้างเนื้อหาใหม่", | ||
| 530 | "Fill empty Memo/Titles with Keywords": "สร้าง Keywords แทน Memo/ชื่อเรื่องที่ว่าง", | ||
| 531 | "Import World Info": "นำเข้าข้อมูลโลก/Lorebook", | ||
| 532 | "Export World Info": "ส่งออกข้อมูลโลก/Lorebook", | ||
| 533 | "Duplicate World Info": "ทำสำเนา ข้อมูลโลก/Lorebook", | ||
| 534 | "Delete World Info": "Delete World Info", | ||
| 535 | "Search...": "ค้นหา...", | ||
| 536 | "Search": "ค้นหา", | ||
| 537 | "Priority": "ลำดับความสำคัญ", | ||
| 538 | "Custom": "ปรับแต่ง", | ||
| 539 | "Title A-Z": "ชื่อเรียงจาก A-Z", | ||
| 540 | "Title Z-A": "ชื่อเรียงจาก Z-A", | ||
| 541 | "Tokens ↗": "Tokens ↗", | ||
| 542 | "Tokens ↘": "Tokens ↘", | ||
| 543 | "Depth ↗": "Depth ↗", | ||
| 544 | "Depth ↘": "Depth ↘", | ||
| 545 | "Order ↗": "Order ↗", | ||
| 546 | "Order ↘": "Order ↘", | ||
| 547 | "UID ↗": "UID ↗", | ||
| 548 | "UID ↘": "UID ↘", | ||
| 549 | "Trigger% ↗": "Trigger% ↗", | ||
| 550 | "Trigger% ↘": "Trigger% ↘", | ||
| 551 | "Refresh": "รีเฟรช", | ||
| 552 | "User Settings": "ตั้งค่าส่วนผู้ใช้งาน", | ||
| 553 | "Simple": "Simple", | ||
| 554 | "Advanced": "ขั้นสูง", | ||
| 555 | "UI Language": "ภาษา UI", | ||
| 556 | "Account": "บัญชีผู้ใช้งาน", | ||
| 557 | "Admin Panel": "แผงควบคุมผู้ดูแล", | ||
| 558 | "Logout": "ออกจากระบบ", | ||
| 559 | "Search Settings": "ค้นหาการตั้งค่า", | ||
| 560 | "UI Theme": "ธีม UI", | ||
| 561 | "Import a theme file": "นำเข้าไฟล์ธีม", | ||
| 562 | "Export a theme file": "ส่งออกไฟล์ธีม", | ||
| 563 | "Delete a theme": "ลบธีม", | ||
| 564 | "Update a theme file": "อัพเดทไฟล์ธีม", | ||
| 565 | "Save as a new theme": "บันทึกเป็นธีมใหม่", | ||
| 566 | "Avatar Style:": "รูปแบบภาพ Avatar:", | ||
| 567 | "Circle": "วงกลม", | ||
| 568 | "Square": "สี่เหลี่ยมผืนผ้า", | ||
| 569 | "Rectangle": "ทรงเหลี่ยม", | ||
| 570 | "Chat Style:": "รูปแบบหน้าต่างแชท:", | ||
| 571 | "Flat": "ขอบเรียบ", | ||
| 572 | "Bubbles": "บับเบิล", | ||
| 573 | "Document": "เอกสาร", | ||
| 574 | "Specify colors for your theme.": "เลือกเฉดสีสำหรับธีมของคุณ", | ||
| 575 | "Theme Colors": "สีธีม", | ||
| 576 | "Main Text": "ข้อความหลัก", | ||
| 577 | "Italics Text": "อักษรตัวเอียง", | ||
| 578 | "Underlined Text": "อักษรขีดเส้นใต้", | ||
| 579 | "Quote Text": "ข้อความคำพูด", | ||
| 580 | "Shadow Color": "เงาตัวอักษร", | ||
| 581 | "Chat Background": "สีพื้นหลังแชท", | ||
| 582 | "UI Background": "พื้นหลัง UI", | ||
| 583 | "UI Border": "เส้นขอบ UI", | ||
| 584 | "User Message Blur Tint": "สีข้อความ User", | ||
| 585 | "AI Message Blur Tint": "สีข้อความ AI", | ||
| 586 | "Chat Width": "ความกว้างแชท", | ||
| 587 | "Width of the main chat window in % of screen width": "ความกว้างของแชทเป็น % ของหน้าจอ", | ||
| 588 | "Font Scale": "ขนาดตัวอักษร", | ||
| 589 | "Font size": "ขนาดของตัวอักษร", | ||
| 590 | "Blur Strength": "ระดับความเบลอภาพพื้นหลัง", | ||
| 591 | "Blur strength on UI panels.": "ระดับความเบลอแผง UI", | ||
| 592 | "Text Shadow Width": "ขนาดของเงาอักษร", | ||
| 593 | "Strength of the text shadows": "ความหนาของเงาอักษร", | ||
| 594 | "Disables animations and transitions": "ปิดแอนิเมชั่นและการเปลี่ยนภาพ", | ||
| 595 | "Reduced Motion": "ลดการเคลื่อนไหว", | ||
| 596 | "removes blur from window backgrounds": "ลบความเบลอภาพพื้นหลัง", | ||
| 597 | "No Blur Effect": "ไม่มีเอฟเฟกต์เบลอ", | ||
| 598 | "Remove text shadow effect": "ลบเงาตัวอักษร", | ||
| 599 | "No Text Shadows": "ไม่มีเงาข้อความ", | ||
| 600 | "Reduce chat height, and put a static sprite behind the chat window": "ลดความสูงของหน้าต่างแชทและวาง sprite ตัวละครไว้ด้านหลังหน้าต่างแชท", | ||
| 601 | "Waifu Mode": "โหมด Waifu", | ||
| 602 | "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "แสดงบริบทการบรรยายข้อความทั้งหมดเสมอโดยไม่ใส่ไว้หลัง '....'", | ||
| 603 | "Auto-Expand Message Actions": "ขยายตัวอักษรอัตโนมัติ", | ||
| 604 | "Alternative UI for numeric sampling parameters with fewer steps": "Alternative UI for numeric sampling parameters with fewer steps", | ||
| 605 | "Zen Sliders": "Zen Sliders", | ||
| 606 | "Entirely unrestrict all numeric sampling parameters": "Entirely unrestrict all numeric sampling parameters", | ||
| 607 | "Mad Lab Mode": "Mad Lab Mode", | ||
| 608 | "Time the AI's message generation, and show the duration in the chat log": "แสดงเวลาที่ใช้ในการสร้างข้อความของ AI, และให้แสดงจำนวนในประวัติแชท", | ||
| 609 | "Message Timer": "แสดงเวลาที่ AI ใช้ในการตอบข้อความ", | ||
| 610 | "Show a timestamp for each message in the chat log": "แสดงเวลาที่ส่งข้อความตอบกลับในประวัติการแชท", | ||
| 611 | "Chat Timestamps": "แสดงเวลาที่ส่งข้อความตอบกลับในแชท", | ||
| 612 | "Show an icon for the API that generated the message": "แสดงไอคอนสำหรับ API ที่สร้างข้อความ", | ||
| 613 | "Model Icon": "แสดงไอคอน Model AI ที่ตอบแชท", | ||
| 614 | "Show sequential message numbers in the chat log": "แสดงหมายเลขลำดับข้อความในประวัติแชท", | ||
| 615 | "Message IDs": "แสดงเลขจำนวนข้อความ", | ||
| 616 | "Hide avatars in chat messages.": "ซ่อนภาพ avatar ในแชทข้อความ", | ||
| 617 | "Hide Chat Avatars": "ซ่อนรูปโปรไฟล์แชท", | ||
| 618 | "Show the number of tokens in each message in the chat log": "แสดงจำนวนโทเค็นในแต่ละข้อความในบันทึกแชท", | ||
| 619 | "Show Message Token Count": "แสดงจำนวนโทเค็นที่ Ai ตอบแชท", | ||
| 620 | "Single-row message input area. Mobile only, no effect on PC": "พื้นที่ป้อนข้อความแบบแถวเดียวไม่ขึ้นบรรทัดใหม่ เฉพาะในมือถือเท่านั้น", | ||
| 621 | "Compact Input Area (Mobile)": "พื้นที่ป้อนข้อความขนาดกระทัดรัด (มือถือ)", | ||
| 622 | "In the Character Management panel, show quick selection buttons for favorited characters": "แสดงปุ่มลัดบอทตัวละครโปรดในแถบเลือกตัวละคร", | ||
| 623 | "Characters Hotswap": "การเปลี่ยนบอทตัวละครแบบรวดเร็ว", | ||
| 624 | "Enable magnification for zoomed avatar display.": "อนุญาตการซูมภาพโปรไฟล์อวาตาร์", | ||
| 625 | "Avatar Hover Magnification": "Avatar Hover Magnification", | ||
| 626 | "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "เปิดเอฟเฟกต์ Magnification เมื่อคลิกรูปตัวละครค้างไว้ หลังจากคลิกดูรูปตัวละครแบบขยายในแชท", | ||
| 627 | "Show tagged character folders in the character list": "แสดงโฟลเดอร์ตัวละครตามแท็กในรายการ", | ||
| 628 | "Tags as Folders": "Tags as Folders", | ||
| 629 | "Tags_as_Folders_desc": "Tags_as_Folders_desc", | ||
| 630 | "Character Handling": "การจัดการตัวละคร", | ||
| 631 | "If set in the advanced character definitions, this field will be displayed in the characters list.": "หากตั้งค่าในคำจำกัดความตัวละครขั้นสูง ฟิลด์นี้จะแสดงในรายการตัวละคร", | ||
| 632 | "Char List Subheader": "หัวข้อย่อยรายการตัวละคร", | ||
| 633 | "Character Version": "เวอร์ชั่นของตัวละคร", | ||
| 634 | "Created by": "สร้างโดย", | ||
| 635 | "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "ใช้การจับคู่แบบเลือน และค้นหาตัวละครในรายการด้วยฟิลด์ข้อมูลทั้งหมด ไม่ใช่แค่ชื่อ", | ||
| 636 | "Advanced Character Search": "การค้นหาตัวละครขั้นสูง", | ||
| 637 | "If checked and the character card contains a prompt override (System Prompt), use that instead": "ใช้ System Prompt ของการ์ดตัวละคร (ถ้ามี)", | ||
| 638 | "Prefer Character Card Prompt": "ใช้ Prompt ของการ์ดตัวละคร (ถ้ามี)", | ||
| 639 | "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "หากเลือกและการ์ดตัวละครมี jailbreak override (คำแนะนำหลังประวัติ) ให้ใช้แทน", | ||
| 640 | "Prefer Character Card Jailbreak": "ใช้ Jailbreak ของการ์ดตัวละคร (ถ้ามี)", | ||
| 641 | "never_resize_avatars_tooltip": "คำแนะนำไม่ปรับขนาดรูปตัวแทน", | ||
| 642 | "Never resize avatars": "ห้ามปรับขนาดรูปตัวแทน", | ||
| 643 | "Show actual file names on the disk, in the characters list display only": "แสดงชื่อไฟล์จริงในดิสก์ แสดงเฉพาะในรายการตัวละคร", | ||
| 644 | "Show avatar filenames": "แสดงชื่อไฟล์ของรูปตัวแทน", | ||
| 645 | "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "แจ้งให้นำเข้าแท็กที่ฝังในการ์ดเมื่อนำเข้าตัวละคร มิฉะนั้นแท็กที่ฝังจะถูกเพิกเฉย", | ||
| 646 | "Import Card Tags": "นำเข้าการ์ดแท็ก", | ||
| 647 | "Hide character definitions from the editor panel behind a spoiler button": "ซ่อนคำจำกัดความตัวละครจากแผงตัวแก้ไขด้วยปุ่มสปอยเลอร์", | ||
| 648 | "Spoiler Free Mode": "โหมดปลอดสปอยเลอร์", | ||
| 649 | "Miscellaneous": "Miscellaneous", | ||
| 650 | "Reload and redraw the currently open chat": "โหลดและวาดแชทที่เปิดอยู่ใหม่", | ||
| 651 | "Reload Chat": "รีโหลดแชท", | ||
| 652 | "Debug Menu": "เมนูดีบัก", | ||
| 653 | "Smooth Streaming": "การสตรีมแบบนุ่มนวล", | ||
| 654 | "Experimental feature. May not work for all backends.": "ฟีเจอร์ทดลอง อาจไม่ทำงานกับแบ็กเอนด์ทั้งหมด", | ||
| 655 | "Slow": "ช้า", | ||
| 656 | "Fast": "เร็ว", | ||
| 657 | "Play a sound when a message generation finishes": "เล่นเสียงเมื่อการสร้างข้อความเสร็จสิ้น", | ||
| 658 | "Message Sound": "เสียงข้อความ", | ||
| 659 | "Only play a sound when ST's browser tab is unfocused": "เล่นเสียงเฉพาะเมื่อแท็บเบราว์เซอร์ของ ST ไม่ได้โฟกัส", | ||
| 660 | "Background Sound Only": "เฉพาะเสียงของพื้นหลังเท่านั้น", | ||
| 661 | "Reduce the formatting requirements on API URLs": "ลดข้อกำหนดการจัดรูปแบบสำหรับ URL ของ API", | ||
| 662 | "Relaxed API URLS": "URL API แบบผ่อนปรน", | ||
| 663 | "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "ถามเพื่อนำเข้า World Info/Lorebook สำหรับตัวละครใหม่ทุกตัวที่มี lorebook ฝังอยู่ หากไม่เลือก จะแสดงข้อความสั้นๆ แทน", | ||
| 664 | "Lorebook Import Dialog": "กล่องโต้ตอบการนำเข้า Lorebook", | ||
| 665 | "Restore unsaved user input on page refresh": "คืนค่าข้อมูลผู้ใช้ที่ไม่ได้บันทึกเมื่อรีเฟรชหน้า", | ||
| 666 | "Restore User Input": "คืนค่าข้อมูลผู้ใช้", | ||
| 667 | "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "อนุญาตให้จัดตำแหน่งองค์ประกอบ UI บางส่วนด้วยการลาก เฉพาะ PC ไม่มีผลกับมือถือ", | ||
| 668 | "Movable UI Panels": "แผง UI ที่เคลื่อนย้ายได้", | ||
| 669 | "MovingUI preset. Predefined/saved draggable positions": "พรีเซ็ต MovingUI ตำแหน่งลากที่กำหนดไว้ล่วงหน้า/บันทึกไว้", | ||
| 670 | "MUI Preset": "พรีเซ็ต MUI", | ||
| 671 | "Save movingUI changes to a new file": "บันทึกการเปลี่ยนแปลง movingUI เป็นไฟล์ใหม่", | ||
| 672 | "Reset MovingUI panel sizes/locations.": "รีเซ็ตขนาด/ตำแหน่งแผง MovingUI", | ||
| 673 | "Apply a custom CSS style to all of the ST GUI": "ใช้สไตล์ CSS แบบกำหนดเองกับ GUI ของ ST ทั้งหมด", | ||
| 674 | "Custom CSS": "CSS แบบกำหนดเอง", | ||
| 675 | "Expand the editor": "ขยายตัวแก้ไข", | ||
| 676 | "Chat/Message Handling": "การจัดการแชท/ข้อความ", | ||
| 677 | "# Messages to Load": "จำนวนข้อความที่โหลด", | ||
| 678 | "The number of chat history messages to load before pagination.": "จำนวนข้อความในประวัติแชทที่จะโหลดก่อนแบ่งหน้า", | ||
| 679 | "(0 = All)": "(0 = ทั้งหมด)", | ||
| 680 | "Streaming FPS": "อัตราเฟรมการสตรีม", | ||
| 681 | "Update speed of streamed text.": "ความเร็วการอัปเดตข้อความที่สตรีม", | ||
| 682 | "Example Messages Behavior": "พฤติกรรมข้อความตัวอย่าง", | ||
| 683 | "Gradual push-out": "ผลักออกทีละน้อย", | ||
| 684 | "Always include examples": "รวมตัวอย่างเสมอ", | ||
| 685 | "Never include examples": "ไม่รวมตัวอย่าง", | ||
| 686 | "Send on Enter": "ส่งเมื่อกด Enter", | ||
| 687 | "Disabled": "ปิดใช้งาน", | ||
| 688 | "Automatic (PC)": "อัตโนมัติ (PC)", | ||
| 689 | "Press Send to continue": "กด Send เพื่อดำเนินต่อ", | ||
| 690 | "Show a button in the input area to ask the AI to continue (extend) its last message": "แสดงปุ่มในพื้นที่ป้อนข้อมูลเพื่อขอให้ AI ดำเนินต่อ (ขยาย) ข้อความสุดท้าย", | ||
| 691 | "Quick 'Continue' button": "ปุ่ม 'ดำเนินการต่อ' ด่วน", | ||
| 692 | "Show arrow buttons on the last in-chat message to generate alternative AI responses. Both PC and mobile": "แสดงปุ่มลูกศรในข้อความสุดท้ายในแชทเพื่อสร้างการตอบกลับ AI ทางเลือก ทั้ง PC และมือถือ", | ||
| 693 | "Swipes": "ปัด", | ||
| 694 | "Allow using swiping gestures on the last in-chat message to trigger swipe generation. Mobile only, no effect on PC": "อนุญาตให้ใช้ท่าทางปัดในข้อความสุดท้ายในแชทเพื่อเรียกใช้การสร้างแบบปัด เฉพาะมือถือ ไม่มีผลกับ PC", | ||
| 695 | "Gestures": "ท่าทาง", | ||
| 696 | "Auto-load Last Chat": "โหลดแชทล่าสุดอัตโนมัติ", | ||
| 697 | "Auto-scroll Chat": "เลื่อนแชทอัตโนมัติ", | ||
| 698 | "Save edits to messages without confirmation as you type": "บันทึกการแก้ไขข้อความโดยอัตโนมัติขณะพิมพ์โดยไม่ต้องยืนยัน", | ||
| 699 | "Auto-save Message Edits": "บันทึกการแก้ไขข้อความอัตโนมัติ", | ||
| 700 | "Confirm message deletion": "ยืนยันการลบข้อความ", | ||
| 701 | "Auto-fix Markdown": "แก้ไข Markdown อัตโนมัติ", | ||
| 702 | "Disallow embedded media from other domains in chat messages": "ไม่อนุญาตสื่อที่ฝังจากโดเมนอื่นในข้อความแชท", | ||
| 703 | "Forbid External Media": "ห้ามสื่อภายนอก", | ||
| 704 | "Allow {{char}}: in bot messages": "อนุญาตให้ใช้ {{char}}: ในข้อความของบอท", | ||
| 705 | "Allow {{user}}: in bot messages": "อนุญาตให้ใช้ {{user}}: ในข้อความของบอท", | ||
| 706 | "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "ข้ามการเข้ารหัสตัวอักษร < และ > ในข้อความ อนุญาต HTML markup บางส่วนรวมถึง Markdown", | ||
| 707 | "Show tags in responses": "แสดง HTML tag ในข้อความ", | ||
| 708 | "Allow AI messages in groups to contain lines spoken by other group members": "อนุญาตให้ข้อความ AI ในกลุ่มมีบรรทัดที่พูดโดยสมาชิกกลุ่มอื่น", | ||
| 709 | "Relax message trim in Groups": "ผ่อนปรนการตัดข้อความในกลุ่ม", | ||
| 710 | "Log prompts to console": "บันทึกพรอมต์ไปยังคอนโซล", | ||
| 711 | "Requests logprobs from the API for the Token Probabilities feature": "ขอ logprobs จาก API สำหรับฟีเจอร์ Token Probabilities", | ||
| 712 | "Request token probabilities": "ขอความน่าจะเป็นของโทเค็น", | ||
| 713 | "Automatically reject and re-generate AI message based on configurable criteria": "ปฏิเสธและสร้างข้อความ AI ใหม่โดยอัตโนมัติตามเกณฑ์ที่กำหนดได้", | ||
| 714 | "Auto-swipe": "ปัดแบบอัตโนมัติ", | ||
| 715 | "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "เปิดการใช้งานฟังก์ชั่นปัดแบบอัตโนมัติ การตั้งค่าในส่วนนี้มีผลก็ต่อเมื่อเปิดใช้งานฟังก์ชั่นปัดแบบอัตโนมัติแล้วเท่านั้น", | ||
| 716 | "Minimum generated message length": "ความยาวข้อความที่สร้างขั้นต่ำ", | ||
| 717 | "If the generated message is shorter than these many characters, trigger an auto-swipe": "หากข้อความที่สร้างสั้นกว่าจำนวนตัวอักษรนี้ จะเรียกใช้การปัดอัตโนมัติ", | ||
| 718 | "Blacklisted words": "คำต้องห้าม", | ||
| 719 | "words you dont want generated separated by comma ','": "คำที่คุณไม่ต้องการให้สร้าง คั่นด้วยเครื่องหมายจุลภาค ','", | ||
| 720 | "Blacklisted word count to swipe": "จำนวนคำต้องห้ามเพื่อปัด", | ||
| 721 | "Minimum number of blacklisted words detected to trigger an auto-swipe": "จำนวนขั้นต่ำของคำต้องห้ามที่ตรวจพบเพื่อเรียกใช้การปัดอัตโนมัติ", | ||
| 722 | "AutoComplete Settings": "การตั้งค่าการเติมข้อความอัตโนมัติ", | ||
| 723 | "Automatically hide details": "ซ่อนรายละเอียดอัตโนมัติ", | ||
| 724 | "Determines how entries are found for autocomplete.": "กำหนดวิธีการค้นหารายการสำหรับการเติมข้อความอัตโนมัติ", | ||
| 725 | "Autocomplete Matching": "การจับคู่การเติมข้อความอัตโนมัติ", | ||
| 726 | "Starts with": "เริ่มต้นด้วย", | ||
| 727 | "Includes": "รวมถึง", | ||
| 728 | "Fuzzy": "แบบเลือน", | ||
| 729 | "Sets the style of the autocomplete.": "ตั้งค่าสไตล์ของการเติมข้อความอัตโนมัติ", | ||
| 730 | "Autocomplete Style": "สไตล์การเติมข้อความอัตโนมัติ", | ||
| 731 | "Follow Theme": "ตามธีม", | ||
| 732 | "Dark": "มืด", | ||
| 733 | "Sets the font size of the autocomplete.": "ตั้งค่าขนาดตัวอักษรของการเติมข้อความอัตโนมัติ", | ||
| 734 | "Sets the width of the autocomplete.": "ตั้งค่าความกว้างของการเติมข้อความอัตโนมัติ", | ||
| 735 | "Autocomplete Width": "ความกว้างการเติมข้อความอัตโนมัติ", | ||
| 736 | "chat input box": "กล่องป้อนข้อความแชท", | ||
| 737 | "entire chat width": "ความกว้างแชททั้งหมด", | ||
| 738 | "full window width": "ความกว้างหน้าต่างเต็ม", | ||
| 739 | "STscript Settings": "การตั้งค่า STscript", | ||
| 740 | "Sets default flags for the STscript parser.": "ตั้งค่าแฟล็กเริ่มต้นสำหรับตัวแยกวิเคราะห์ STscript", | ||
| 741 | "Parser Flags": "แฟล็กตัวแยกวิเคราะห์", | ||
| 742 | "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "เปลี่ยนเป็นการ escape ที่เข้มงวดกว่า อนุญาตให้ตัวอักษรคั่นทั้งหมดถูก escape ด้วยแบ็กสแลช และแบ็กสแลชก็สามารถ escape ได้เช่นกัน", | ||
| 743 | "STRICT_ESCAPING": "STRICT_ESCAPING", | ||
| 744 | "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "แทนที่แมโคร {{getvar::}} และ {{getglobalvar::}} ทั้งหมดด้วยตัวแปรขอบเขตเพื่อหลีกเลี่ยงการแทนที่แมโครซ้ำ", | ||
| 745 | "REPLACE_GETVAR": "REPLACE_GETVAR", | ||
| 746 | "Change Background Image": "เปลี่ยนรูปภาพพื้นหลัง", | ||
| 747 | "Filter": "ตัวกรอง", | ||
| 748 | "Automatically select a background based on the chat context": "เลือกพื้นหลังโดยอัตโนมัติตามบริบทของแชท", | ||
| 749 | "Auto-select": "เลือกอัตโนมัติ", | ||
| 750 | "System Backgrounds": "พื้นหลังของระบบ", | ||
| 751 | "Chat Backgrounds": "พื้นหลังแชท", | ||
| 752 | "bg_chat_hint_1": "พื้นหลังของแชทที่ถูกสร้างด้วย", | ||
| 753 | "bg_chat_hint_2": "จะปรากฏที่นี่", | ||
| 754 | "Extensions": "โปรแกรมส่วนขยาย", | ||
| 755 | "Notify on extension updates": "แจ้งเตือนเมื่อมีการอัปเดตส่วนขยาย", | ||
| 756 | "Manage extensions": "จัดการส่วนขยาย", | ||
| 757 | "Import Extension From Git Repo": "นำเข้าส่วนขยายจาก Git Repo", | ||
| 758 | "Install extension": "ติดตั้งส่วนขยาย", | ||
| 759 | "Extras API:": "Extras API:", | ||
| 760 | "Auto-connect": "เชื่อมต่ออัตโนมัติ", | ||
| 761 | "Extras API URL": "Extras API URL", | ||
| 762 | "Extras API key (optional)": "คีย์ Extras API (ไม่บังคับ)", | ||
| 763 | "Persona Management": "การจัดการ Persona", | ||
| 764 | "How do I use this?": "ฉันจะใช้สิ่งนี้ยังไง?", | ||
| 765 | "Click for stats!": "คลิกเพื่อดูสถิติ!", | ||
| 766 | "Usage Stats": "ค่าสถิติการใช้งาน", | ||
| 767 | "Backup your personas to a file": "สำรองข้อมูล persona ของคุณเป็นไฟล์", | ||
| 768 | "Backup": "สำรองข้อมูล", | ||
| 769 | "Restore your personas from a file": "คืนค่า persona ของคุณจากไฟล์", | ||
| 770 | "Restore": "คืนค่า", | ||
| 771 | "Create a dummy persona": "สร้าง persona จำลอง", | ||
| 772 | "Create": "สร้าง", | ||
| 773 | "Toggle grid view": "เปลี่ยนการมองแบบตาราง", | ||
| 774 | "No persona description": "ไม่มีข้อมูล Persona", | ||
| 775 | "Name": "ชื่อ", | ||
| 776 | "Enter your name": "กรอกชื่อของคุณ", | ||
| 777 | "Click to set a new User Name": "คลิกเลือกเพื่อตั้งชื่อผู้ใช้ใหม่", | ||
| 778 | "Click to lock your selected persona to the current chat. Click again to remove the lock.": "กดเพื่อล็อก Persona ที่คุณเลือกไว้กับแชทปัจจุบัน หรือให้กดอีกครั้งเพื่อปลดล็อก", | ||
| 779 | "Click to set user name for all messages": "คลิกเพื่อตั้งชื่อผู้ใช้สำหรับข้อความทั้งหมด", | ||
| 780 | "Persona Description": "ข้อมูล Persona", | ||
| 781 | "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "ตัวอย่าง: [{{user}} เป็นสาวสวยน่ารักอายุ 25 ปี]", | ||
| 782 | "Tokens persona description": "คำอธิบาย persona ในโทเค็น", | ||
| 783 | "Position:": "ตำแหน่ง:", | ||
| 784 | "In Story String / Prompt Manager": "ในสตริงเรื่องราว / ตัวจัดการพรอมต์", | ||
| 785 | "Top of Author's Note": "ด้านบนของหมายเหตุผู้เขียน", | ||
| 786 | "Bottom of Author's Note": "ด้านล่างของหมายเหตุผู้เขียน", | ||
| 787 | "In-chat @ Depth": "ในแชท @ ความลึก", | ||
| 788 | "Depth:": "ความลึก:", | ||
| 789 | "Role:": "บทบาท:", | ||
| 790 | "System": "ระบบ", | ||
| 791 | "User": "ผู้ใช้", | ||
| 792 | "Assistant": "ผู้ช่วย", | ||
| 793 | "Show notifications on switching personas": "แสดงการแจ้งเตือนเมื่อเปลี่ยน persona", | ||
| 794 | "Allow multiple persona connections per character": "อนุญาตการเชื่อมต่อหลาย persona ต่อ 1 ตัวละคร", | ||
| 795 | "Auto-lock a chosen persona to the chat": "ล็อก persona ที่เลือกไว้กับแชทโดยอัตโนมัติ", | ||
| 796 | "Character Management": "จัดการตัวละคร", | ||
| 797 | "Locked = Character Management panel will stay open": "ล็อค = แผงการจัดการตัวละครจะเปิดค้างไว้", | ||
| 798 | "Select/Create Characters": "เลือก/สร้างตัวละคร", | ||
| 799 | "Favorite characters to add them to HotSwaps": "ใส่ตัวละครโปรดเพื่อเพิ่มลงใน HotSwaps", | ||
| 800 | "Token counts may be inaccurate and provided just for reference.": "จำนวนโทเค็นอาจไม่แม่นยำและให้ไว้เพื่ออ้างอิงเท่านั้น", | ||
| 801 | "Total tokens": "จำนวนโทเค็นทั้งหมด", | ||
| 802 | "Calculating...": "กำลังคำนวณผล...", | ||
| 803 | "Tokens": "จำนวนโทเค็น", | ||
| 804 | "Permanent tokens": "โทเค็นถาวร", | ||
| 805 | "Permanent": "ถาวร", | ||
| 806 | "About Token 'Limits'": "เกี่ยวกับ 'ขีดจำกัด' โทเค็น", | ||
| 807 | "Toggle character info panel": "เปิด/ปิดแผงข้อมูลตัวละคร", | ||
| 808 | "Name this character": "ชื่อของตัวละครนี้", | ||
| 809 | "extension_token_counter": "ตัวนับโทเค็นส่วนขยาย", | ||
| 810 | "Click to select a new avatar for this character": "กดเพื่อเลือกรูปตัวละครรูปใหม่", | ||
| 811 | "Add to Favorites": "เพิ่มไปยังรายการโปรด", | ||
| 812 | "Advanced Definition": "การตั้งค่าเพิ่มเติม", | ||
| 813 | "Character Lore": "Character Lore", | ||
| 814 | "Chat Lore": "Chat Lore", | ||
| 815 | "Export and Download": "นำออกและดาวน์โหลดการ์ดตัวละคร", | ||
| 816 | "Duplicate Character": "ทำสำเนาการ์ดตัวละครนั้นๆ", | ||
| 817 | "Create Character": "สร้างตัวละคร", | ||
| 818 | "Delete Character": "ลบตัวละคร", | ||
| 819 | "More...": "เพิ่มเติม", | ||
| 820 | "Link to World Info": "ลิงค์ตัวละครกับ Lorebook", | ||
| 821 | "Import Card Lore": "นำเข้า Lorebook ของการ์ดตัวละคร", | ||
| 822 | "Scenario Override": "เขียนทับ Scenario ของการ์ด", | ||
| 823 | "Convert to Persona": "แปลงการ์ดตัวละครไปเป็น Persona", | ||
| 824 | "Rename": "เปลี่ยนชื่อ", | ||
| 825 | "Link to Source": "ลิงค์ไปยัง Source", | ||
| 826 | "Replace / Update": "Replace / Update", | ||
| 827 | "Import Tags": "นำเข้าแท็ก", | ||
| 828 | "Search / Create Tags": "ค้นหา / สร้างแท็ก", | ||
| 829 | "View all tags": "ดูแท็กทั้งหมด", | ||
| 830 | "Creator's Notes": "ข้อความของผู้สร้าง", | ||
| 831 | "Show / Hide Description and First Message": "แสดง / ซ่อนคำอธิบายและข้อความแรก", | ||
| 832 | "Character Description": "คำอธิบายตัวละคร", | ||
| 833 | "Click to allow/forbid the use of external media for this character.": "คลิกเพื่ออนุญาตหรือห้ามการใช้สื่อภายนอกสำหรับตัวละครนี้", | ||
| 834 | "Ext. Media": "สื่อภายนอก", | ||
| 835 | "Describe your character's physical and mental traits here.": "กรอกรายละเอียดเกี่ยวกับรูปลักษณ์และบุคลิกของตัวละครของคุณที่นี่", | ||
| 836 | "First message": "ข้อความเริ่มต้น", | ||
| 837 | "Click to set additional greeting messages": "คลิกเพื่อกำหนดข้อความทักทายเพิ่มเติม", | ||
| 838 | "Alt. Greetings": "ข้อความทักทายแบบอื่น", | ||
| 839 | "This will be the first message from the character that starts every chat.": "ตัวละครจะเริ่มแชททุกครั้งด้วยข้อความนี้", | ||
| 840 | "Group Controls": "การควบคุมกลุ่ม", | ||
| 841 | "Chat Name (Optional)": "ชื่อแชท (ไม่บังคับ)", | ||
| 842 | "Click to select a new avatar for this group": "เลือกรูปภาพใหม่สำหรับกลุ่มนี้", | ||
| 843 | "Group reply strategy": "กลยุทธ์การตอบกลับของกลุ่ม", | ||
| 844 | "Natural order": "ลำดับธรรมชาติ", | ||
| 845 | "List order": "ลำดับรายการ", | ||
| 846 | "Group generation handling mode": "โหมดการจัดการการสร้างกลุ่ม", | ||
| 847 | "Swap character cards": "สลับการ์ดตัวละคร", | ||
| 848 | "Join character cards (exclude muted)": "รวมการ์ดตัวละคร (ยกเว้นที่ปิดเสียง)", | ||
| 849 | "Join character cards (include muted)": "รวมการ์ดตัวละคร (รวมที่ปิดเสียง)", | ||
| 850 | "Inserted before each part of the joined fields.": "แทรกก่อนแต่ละส่วนของฟิลด์ที่เชื่อมต่อ", | ||
| 851 | "Join Prefix": "คำนำหน้าการเชื่อมต่อ", | ||
| 852 | "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> ด้วยชื่อของส่วน (เช่น: description, personality, scenario, ฯลฯ)", | ||
| 853 | "Inserted after each part of the joined fields.": "แทรกหลังแต่ละส่วนของฟิลด์ที่เชื่อมต่อ", | ||
| 854 | "Join Suffix": "คำต่อท้ายการเชื่อมต่อ", | ||
| 855 | "Set a group chat scenario": "ตั้งค่าสถานการณ์แชทกลุ่ม", | ||
| 856 | "Click to allow/forbid the use of external media for this group.": "คลิกเพื่ออนุญาต/ห้ามการใช้สื่อภายนอกสำหรับกลุ่มนี้", | ||
| 857 | "Restore collage avatar": "คืนค่าอวาตาร์แบบคอลลาจ", | ||
| 858 | "Allow self responses": "อนุญาตการตอบกลับตนเอง", | ||
| 859 | "Auto Mode": "โหมดอัตโนมัติ", | ||
| 860 | "Auto Mode delay": "ความล่าช้าของโหมดอัตโนมัติ", | ||
| 861 | "Hide Muted Member Sprites": "ซ่อน Sprite ของสมาชิกที่ปิดเสียง", | ||
| 862 | "Current Members": "สมาชิกปัจจุบัน", | ||
| 863 | "Add Members": "เพิ่มสมาชิก", | ||
| 864 | "Create New Character": "สร้างตัวละครใหม่", | ||
| 865 | "Import Character from File": "นำเข้าตัวละครจากไฟล์", | ||
| 866 | "Import content from external URL": "นำเข้าเนื้อหาจาก URL ภายนอก", | ||
| 867 | "Create New Chat Group": "สร้างกลุ่มการสนทนาใหม่", | ||
| 868 | "Characters sorting order": "การเรียงลำดับตัวละคร", | ||
| 869 | "A-Z": "A-Z", | ||
| 870 | "Z-A": "Z-A", | ||
| 871 | "Newest": "ใหม่ที่สุด", | ||
| 872 | "Oldest": "เก่าที่สุด", | ||
| 873 | "Favorites": "รายการโปรด", | ||
| 874 | "Recent": "ล่าสุด", | ||
| 875 | "Most chats": "แชทมากที่สุด", | ||
| 876 | "Least chats": "แชทน้อยที่สุด", | ||
| 877 | "Most tokens": "โทเค่นมากที่สุด", | ||
| 878 | "Least tokens": "โทเค่นน้อยที่สุด", | ||
| 879 | "Random": "สุ่ม", | ||
| 880 | "Toggle character grid view": "เปิด/ปิด การดูตัวละครแบบตาราง", | ||
| 881 | "Bulk_edit_characters": "แก้ไขตัวละครทั้งหมดพร้อมกัน", | ||
| 882 | "Bulk select all characters": "เลือกตัวละครทั้งหมดพร้อมกัน", | ||
| 883 | "Bulk delete characters": "ลบตัวละครทั้งหมด", | ||
| 884 | "popup-button-save": "บันทึก", | ||
| 885 | "popup-button-yes": "ตกลง", | ||
| 886 | "popup-button-no": "ไม่", | ||
| 887 | "popup-button-cancel": "ยกเลิก", | ||
| 888 | "popup-button-import": "นำเข้า", | ||
| 889 | "Advanced Definitions": "คำจำกัดความขั้นสูง", | ||
| 890 | "Prompt Overrides": "การกำหนด prompt ใหม่", | ||
| 891 | "(For Chat Completion and Instruct Mode)": "(สำหรับโหมดสนทนาและโหมดคำสั่ง)", | ||
| 892 | "Insert {{original}} into either box to include the respective default prompt from system settings.": "ใส่ {{original}} ลงในกล่องข้อความใดก็ได้ เพื่อดึงข้อความพร้อมท์เริ่มต้นตามการตั้งค่าระบบมาใช้งาน", | ||
| 893 | "Main Prompt": "Main Prompt", | ||
| 894 | "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "เนื้อหาใด ๆ ที่ใส่ที่นี่จะมาแทนที่ข้อความพร้อมท์เจลเบรกเริ่มต้นที่ใช้กับตัวละครนี้ (ตามสเปกเวอร์ชัน 2: prompt ของระบบ)", | ||
| 895 | "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "เนื้อหาใด ๆ ที่ใส่ที่นี่จะมาแทนที่ข้อความพร้อมท์เจลเบรกเริ่มต้นที่ใช้กับตัวละครนี้ (ตามสเปกเวอร์ชัน 2: คำแนะนำหลังประวัติการสนทนา)", | ||
| 896 | "Creator's Metadata (Not sent with the AI prompt)": "ข้อมูล Meta ของผู้สร้าง (จะไม่ถูกส่งพร้อมกับคำสั่ง AI)", | ||
| 897 | "Creator's Metadata": "ข้อมูล Meta ของผู้สร้าง", | ||
| 898 | "(Not sent with the AI Prompt)": "จะไม่ถูกส่งพร้อมกับ AI Prompt", | ||
| 899 | "Everything here is optional": "ทุกอย่างที่นี่ไม่บังคับ", | ||
| 900 | "(Botmaker's name / Contact Info)": "(ชื่อผู้สร้างบอท / ข้อมูลติดต่อ)", | ||
| 901 | "(If you want to track character versions)": "(ถ้าคุณต้องการติดตามเวอร์ชันของตัวละคร)", | ||
| 902 | "(Describe the bot, give use tips, or list the chat models it has been tested on. This will be displayed in the character list.)": "อธิบายบอท,ให้คำแนะนำการใช้งานหรือระบุรุ่นของโมเดลแชทที่ได้ทดสอบมา ข้อมูลนี้จะแสดงในรายการตัวละคร", | ||
| 903 | "Tags to Embed": "แท็กที่จะใส่", | ||
| 904 | "(Write a comma-separated list of tags)": "(เขียนรายการแท็กโดยคั่นด้วยเครื่องหมายจุลภาค)", | ||
| 905 | "Personality summary": "ลักษณะนิสัย , ลักษณะบุคลิกภาพ", | ||
| 906 | "(A brief description of the personality)": "คำบรรยายสั้น ๆ ของลักษณะนิสัย", | ||
| 907 | "Scenario": "ฉาก , สถานการณ์ , เหตุการณ์", | ||
| 908 | "(Circumstances and context of the interaction)": "สถานการณ์และบริบทของการโต้ตอบ", | ||
| 909 | "Character's Note": "บันทึกของตัวละคร , หมายเหตุของตัวละคร", | ||
| 910 | "(Text to be inserted in-chat @ designated depth and role)": "(Text to be inserted in-chat @ designated depth and role)", | ||
| 911 | "@ Depth": "@ Depth", | ||
| 912 | "Role": "บทบาท (Role)", | ||
| 913 | "Talkativeness": "ความช่างพูด", | ||
| 914 | "How often the character speaks in group chats!": "ความถี่ในการตอบแชทกลุ่มของตัวละคร!", | ||
| 915 | "How often the character speaks in": "ตัวละครพูดบ่อยแค่ไหนใน", | ||
| 916 | "group chats!": "แชทกลุ่ม!", | ||
| 917 | "Shy": "ขี้อาย", | ||
| 918 | "Normal": "ปกติ", | ||
| 919 | "Chatty": "ช่างจ้อ", | ||
| 920 | "Examples of dialogue": "บทสนทนาตัวอย่าง", | ||
| 921 | "Important to set the character's writing style.": "\"การตั้งค่าสไตล์การพูดของตัวละครเป็นสิ่งสำคัญ\"", | ||
| 922 | "(Examples of chat dialog. Begin each example with START on a new line.)": "\"(ตัวอย่างบทสนทนาให้เริ่มต้นด้วย START ตามด้วยประโยคใหม่)\"", | ||
| 923 | "Save": "บันทึก", | ||
| 924 | "Chat History": "ประวัติการแชท", | ||
| 925 | "Import Chat": "นำเข้าไฟล์แชท", | ||
| 926 | "Copy to system backgrounds": "คัดลอกไปยังพื้นหลัง", | ||
| 927 | "Rename background": "เปลี่ยนชื่อพื้นหลัง", | ||
| 928 | "Lock": "ล็อค", | ||
| 929 | "Unlock": "ปลดล็อค", | ||
| 930 | "Delete background": "ลบพื้นหลัง", | ||
| 931 | "Chat Scenario Override": "แทนที่สถานการณ์ในแชท", | ||
| 932 | "Remove": "ลบ", | ||
| 933 | "Type here...": "\"พิมพ์ที่นี่...\"", | ||
| 934 | "Chat Lorebook": "แชท Lorebook", | ||
| 935 | "Chat Lorebook for": "แชท Lorebook สำหรับ", | ||
| 936 | "chat_world_template_txt": "chat_world_template_txt", | ||
| 937 | "Select a World Info file for": "เลือกไฟล์ข้อมูลโลกสำหรับ", | ||
| 938 | "Primary Lorebook": "Lorebook หลัก", | ||
| 939 | "A selected World Info will be bound to this character as its own Lorebook.": "\"ข้อมูลโลก/Lorebook ที่เลือกจะถูกผูกติดกับตัวละครเหมือนเป็นเนื้อหาของมัน\"", | ||
| 940 | "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "เมื่อสร้างการตอบกลับ AI จะรวมกับรายการจากตัวเลือก World Info ทั่วไป", | ||
| 941 | "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "เมื่อส่งออกบอทจะมี Lorebook ที่ฝังไว้ติดไปกับบอทตัวละครด้วยทุกครั้ง", | ||
| 942 | "Additional Lorebooks": "Lorebook เพิ่มเติม", | ||
| 943 | "Associate one or more auxillary Lorebooks with this character.": "เชื่อมโยงหนึ่งหรือหลาย Lorebook เสริมกับตัวละครนี้", | ||
| 944 | "NOTE: These choices are optional and won't be preserved on character export!": "หมายเหตุ: ตัวเลือกเหล่านี้ไว้สำหรับเป็นทางเลือกเฉพาะทางเท่านั้น และจะไม่ถูกผูกไปด้วยเมื่อนำการ์ดตัวละครออก!", | ||
| 945 | "Rename chat file": "เปลี่ยนชื่อไฟล์แชท", | ||
| 946 | "Export JSONL chat file": "ส่งออกไฟล์แชทในรูปแบบJSONL", | ||
| 947 | "Download chat as plain text document": "ดาวน์โหลดแชทเป็นไฟล์ข้อความธรรมดา", | ||
| 948 | "Delete chat file": "ลบแชทไฟล์", | ||
| 949 | "Use tag as folder": "ใช้แท็กเป็นโฟลเดอร์", | ||
| 950 | "Hide on character card": "ซ่อนในการ์ดตัวละคร", | ||
| 951 | "Delete tag": "ลบแท็ก", | ||
| 952 | "Entry Title/Memo": "ชื่อเรื่อง/บันทึก", | ||
| 953 | "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled", | ||
| 954 | "WI_Entry_Status_Constant": "Constant", | ||
| 955 | "WI_Entry_Status_Normal": "Normal", | ||
| 956 | "WI_Entry_Status_Vectorized": "Vectorized", | ||
| 957 | "WI_Entry_Status_Disabled": "Disabled", | ||
| 958 | "T_Position": "T_Position", | ||
| 959 | "Before Char Defs": "Before Char Defs", | ||
| 960 | "After Char Defs": "After Char Defs", | ||
| 961 | "Before EM": "Before EM", | ||
| 962 | "After EM": "After EM", | ||
| 963 | "Before AN": "Before AN", | ||
| 964 | "After AN": "After AN", | ||
| 965 | "at Depth System": "at Depth System", | ||
| 966 | "at Depth User": "at Depth User", | ||
| 967 | "at Depth AI": "at Depth AI", | ||
| 968 | "Depth": "Depth", | ||
| 969 | "Order:": "Order:", | ||
| 970 | "Order": "Order", | ||
| 971 | "Trigger %:": "Trigger %:", | ||
| 972 | "Probability": "Probability", | ||
| 973 | "Duplicate world info entry": "Duplicate world info entry", | ||
| 974 | "Delete world info entry": "Delete world info entry", | ||
| 975 | "Comma separated (required)": "ต้องคั่นด้วยเครื่องหมายจุลภาค , (จำเป็นต้องกรอก)", | ||
| 976 | "Primary Keywords": "คีย์เวิร์ดหลัก", | ||
| 977 | "Keywords or Regexes": "Keywords or Regexes", | ||
| 978 | "Comma separated list": "คั่นด้วยเครื่องหมาย comma", | ||
| 979 | "Switch to plaintext mode": "Switch to plaintext mode", | ||
| 980 | "Logic": "Logic", | ||
| 981 | "AND ANY": "AND ANY", | ||
| 982 | "AND ALL": "AND ALL", | ||
| 983 | "NOT ALL": "NOT ALL", | ||
| 984 | "NOT ANY": "NOT ANY", | ||
| 985 | "(ignored if empty)": "จะไม่ถูกนำมาพิจารณาถ้าว่างเปล่า", | ||
| 986 | "Optional Filter": "Optional Filter", | ||
| 987 | "Keywords or Regexes (ignored if empty)": "คำสำคัญหรือรูปแบบการค้นหา (จะไม่ถูกนำมาพิจารณาถ้าว่างเปล่า)", | ||
| 988 | "Comma separated list (ignored if empty)": "Comma separated list (ignored if empty)", | ||
| 989 | "Use global setting": "ใช้การตั้งค่าทั่วไป", | ||
| 990 | "Case-Sensitive": "รวจสอบความแตกต่างของตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก", | ||
| 991 | "Yes": "ใช่", | ||
| 992 | "No": "ไม่", | ||
| 993 | "Can be used to automatically activate Quick Replies": "สามารถใช้เพื่อเปิดใช้งานการตอบกลับด่วนโดยอัตโนมัติ", | ||
| 994 | "Automation ID": "รหัสอัตโนมัติ", | ||
| 995 | "( None )": "( ไม่ระบุ )", | ||
| 996 | "Content": "เนื้อหา", | ||
| 997 | "Exclude from recursion": "ยกเว้นจากการทำซ้ำ", | ||
| 998 | "Prevent further recursion (this entry will not activate others)": "ป้องกันการเรียกซ้ำเพิ่มเติม (รายการนี้จะไม่ทำให้รายการอื่นทำงาน)", | ||
| 999 | "Delay until recursion (this entry can only be activated on recursive checking)": "หน่วงเวลาจนกว่าจะเกิดการเรียกซ้ำ (รายการนี้จะถูกเปิดใช้งานได้เฉพาะเมื่อตรวจสอบแบบเรียกซ้ำเท่านั้น)", | ||
| 1000 | "What this keyword should mean to the AI, sent verbatim": "เนื้อหาของ Entry นั้นๆ", | ||
| 1001 | "Filter to Character(s)": "กรองเฉพาะตัวละคร", | ||
| 1002 | "Character Exclusion": "Character Exclusion", | ||
| 1003 | "-- Characters not found --": "ไม่พบตัวละคร", | ||
| 1004 | "Inclusion Group": "Inclusion Group", | ||
| 1005 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group", | ||
| 1006 | "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.": "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.", | ||
| 1007 | "Only one entry with the same label will be activated": "Only one entry with the same label will be activated", | ||
| 1008 | "A relative likelihood of entry activation within the group": "A relative likelihood of entry activation within the group", | ||
| 1009 | "Group Weight": "Group Weight", | ||
| 1010 | "Selective": "Selective", | ||
| 1011 | "Click to Edit": "คลิกเพื่อแก้ไข", | ||
| 1012 | "Use Probability": "Use Probability", | ||
| 1013 | "Add Memo": "เพิ่ม Memo", | ||
| 1014 | "Delete the background?": "ลบพื้นหลังหรือไม่?", | ||
| 1015 | "Text or token ids": "Text or token ids", | ||
| 1016 | "close": "ปิด", | ||
| 1017 | "prompt_manager_edit": "แก้ไข", | ||
| 1018 | "prompt_manager_name": "ชื่อ", | ||
| 1019 | "A name for this prompt.": "A name for this prompt.", | ||
| 1020 | "To whom this message will be attributed.": "To whom this message will be attributed.", | ||
| 1021 | "AI Assistant": "AI ผู้ช่วย", | ||
| 1022 | "prompt_manager_position": "position", | ||
| 1023 | "Next to other prompts (relative) or in-chat (absolute).": "Next to other prompts (relative) or in-chat (absolute).", | ||
| 1024 | "prompt_manager_relative": "relative", | ||
| 1025 | "prompt_manager_depth": "depth", | ||
| 1026 | "0 = after the last message, 1 = before the last message, etc.": "\"0 = หลังข้อความสุดท้าย, 1 = ก่อนข้อความสุดท้าย, เป็นต้น\"", | ||
| 1027 | "Prompt": "Prompt", | ||
| 1028 | "The prompt to be sent.": "The prompt to be sent.", | ||
| 1029 | "This prompt cannot be overridden by character cards, even if overrides are preferred.": "This prompt cannot be overridden by character cards, even if overrides are preferred.", | ||
| 1030 | "prompt_manager_forbid_overrides": "forbid overrides", | ||
| 1031 | "reset": "รีเซ็ต", | ||
| 1032 | "save": "บันทึก", | ||
| 1033 | "This message is invisible for the AI": "ข้อความนี้เอไอจะมองไม่เห็น", | ||
| 1034 | "Message Actions": "การดำเนินการกับข้อความ , การจัดการข้อความ", | ||
| 1035 | "Translate message": "แปลข้อความ", | ||
| 1036 | "Generate Image": "สร้างภาพ", | ||
| 1037 | "Narrate": "บรรยาย", | ||
| 1038 | "Exclude message from prompts": "ไม่รวมข้อความนี้ในพรอมต์", | ||
| 1039 | "Include message in prompts": "รวมข้อความนี้ในพรอมต์", | ||
| 1040 | "Embed file or image": "ฝังไฟล์หรือภาพ", | ||
| 1041 | "Create checkpoint": "สร้างจุดเช็คพอยท์", | ||
| 1042 | "Create Branch": "Create Branch", | ||
| 1043 | "Copy": "คัดลอก", | ||
| 1044 | "Open checkpoint chat": "เปิดแชทจากจุดบันทึก", | ||
| 1045 | "Edit": "แก้ไข", | ||
| 1046 | "Confirm": "ยืนยัน", | ||
| 1047 | "Copy this message": "คัดลอกข้อความนี้", | ||
| 1048 | "Delete this message": "ลบข้อความนี้", | ||
| 1049 | "Move message up": "เลื่อนข้อความขึ้น", | ||
| 1050 | "Move message down": "เลื่อนข้อความลง", | ||
| 1051 | "Enlarge": "ขยาย", | ||
| 1052 | "Welcome to SillyTavern!": "ยินดีต้อนรับสู่ SillyTavern!", | ||
| 1053 | "welcome_message_part_1": "ยินดีต้อนรับสู่ SillyTavern! แอปพลิเคชันแชทบอทสำหรับมือโปร", | ||
| 1054 | "welcome_message_part_2": "เพื่อเริ่มใช้งาน คุณจะต้องเชื่อมต่อกับ API", | ||
| 1055 | "welcome_message_part_3": "โดยใช้เมนู API Connections ที่ไอคอนรูปปลั๊กด้านบน", | ||
| 1056 | "welcome_message_part_4": "หากคุณเป็นมือใหม่ ให้เปิดโหมด UI แบบเบสิคด้วยการพิมพ์คำสั่ง", | ||
| 1057 | "welcome_message_part_5": "เพื่อเรียนรู้เรื่องคำสั่งและสัญลักษณ์มาโคร", | ||
| 1058 | "welcome_message_part_6": "หากมีคำถามหรือข้อสงสัย สามารถเข้าร่วมดิสคอร์ดของเราได้ที่นี่", | ||
| 1059 | "Discord server": "เซิฟเวอร์ดิสคอร์ด", | ||
| 1060 | "welcome_message_part_7": "", | ||
| 1061 | "SillyTavern is aimed at advanced users.": "SillyTavern เหมาะสำหรับผู้ใช้งานระดับสูง", | ||
| 1062 | "If you're new to this, enable the simplified UI mode below.": "หากคุณเป็นผู้ใช้ใหม่ โปรดเปิดโหมดUI แบบง่ายด้านล่าง", | ||
| 1063 | "Change it later in the 'User Settings' panel.": "สามารถเปลี่ยนแปลงได้ภายหลังในรายการ ‘การตั้งค่าผู้ใช้'", | ||
| 1064 | "Enable simple UI mode": "เปิดใช้งานโหมด UI แบบง่าย", | ||
| 1065 | "Looking for AI characters?": "กำลังมองหาตัวละคร AI อยู่หรือไม่?", | ||
| 1066 | "onboarding_import": "Import", | ||
| 1067 | "from supported sources or view": "จากแหล่งที่รองรับหรือดู", | ||
| 1068 | "Sample characters": "ตัวอย่างตัวละคร", | ||
| 1069 | "Your Persona": "Persona ของคุณ", | ||
| 1070 | "Before you get started, you must select a persona name.": "ก่อนเริ่มต้นใช้งาน คุณต้องเลือกชื่อ Persona ก่อน", | ||
| 1071 | "welcome_message_part_8": "ข้อมูลนี้สามารถเปลี่ยนแปลงได้ตลอดเวลาที่ไอค่อน", | ||
| 1072 | "welcome_message_part_9": "", | ||
| 1073 | "Persona Name:": "ชื่อ Persona :", | ||
| 1074 | "Temporarily disable automatic replies from this character": "ปิดการตอบกลับอัตโนมัติจากตัวละครนี้ชั่วคราว", | ||
| 1075 | "Enable automatic replies from this character": "เปิดใช้งานการตอบกลับอัตโนมัติจากตัวละครนี้", | ||
| 1076 | "Trigger a message from this character": "เรียกให้ตัวละครนี้ส่งข้อความ", | ||
| 1077 | "Move up": "เลื่อนขึ้น", | ||
| 1078 | "Move down": "เลื่อนลง", | ||
| 1079 | "View character card": "ดูการ์ดตัวละคร", | ||
| 1080 | "Remove from group": "ลบออกจากกลุ่ม", | ||
| 1081 | "Add to group": "เพิ่มเข้ากลุ่ม", | ||
| 1082 | "Alternate Greetings": "รูปแบบการทักทายอื่น ๆ", | ||
| 1083 | "Alternate_Greetings_desc": " รายละเอียดของรูปแบบการทักทายอื่น ๆ", | ||
| 1084 | "Alternate Greetings Hint": "Alternate Greetings Hint", | ||
| 1085 | "(This will be the first message from the character that starts every chat)": "(This will be the first message from the character that starts every chat)", | ||
| 1086 | "Forbid Media Override explanation": "Forbid Media Override explanation", | ||
| 1087 | "Forbid Media Override subtitle": "Forbid Media Override subtitle", | ||
| 1088 | "Always forbidden": "ไม่อนุญาตโดยเด็ดขาด", | ||
| 1089 | "Always allowed": "อนุญาตเสมอ", | ||
| 1090 | "View contents": "ดูเนื้อหา", | ||
| 1091 | "Remove the file": "ลบไฟล์", | ||
| 1092 | "Unique to this chat": "Unique to this chat", | ||
| 1093 | "Checkpoints inherit the Note from their parent, and can be changed individually after that.": "Checkpoints inherit the Note from their parent, and can be changed individually after that.", | ||
| 1094 | "Include in World Info Scanning": "Include in World Info Scanning", | ||
| 1095 | "Before Main Prompt / Story String": "Before Main Prompt / Story String", | ||
| 1096 | "After Main Prompt / Story String": "ข้อความหลังพรอมต์หลัก / ส่วนเริ่มต้นของเรื่อง", | ||
| 1097 | "as": "เช่น", | ||
| 1098 | "Insertion Frequency": "Insertion Frequency", | ||
| 1099 | "(0 = Disable, 1 = Always)": "(0 = ปิดใช้งาน, 1 = เปิดใช้งานเสมอ)", | ||
| 1100 | "User inputs until next insertion:": "User inputs until next insertion:", | ||
| 1101 | "Character Author's Note (Private)": "Character Author's Note (Private)", | ||
| 1102 | "Won't be shared with the character card on export.": "Won't be shared with the character card on export.", | ||
| 1103 | "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.": "จะถูกเพิ่มเป็นบันทึกของผู้เขียนสำหรับตัวละครนี้โดยอัตโนมัติ สามารถใช้ในกลุ่มได้ แต่ไม่สามารถแก้ไขได้เมื่อมีการเปิดแชทกลุ่มอยู่", | ||
| 1104 | "Use character author's note": "Use character author's note", | ||
| 1105 | "Replace Author's Note": "Replace Author's Note", | ||
| 1106 | "Default Author's Note": "Default Author's Note", | ||
| 1107 | "Will be automatically added as the Author's Note for all new chats.": "Will be automatically added as the Author's Note for all new chats.", | ||
| 1108 | "Chat CFG": "Chat CFG", | ||
| 1109 | "1 = disabled": "1 = ปิดใช้งาน", | ||
| 1110 | "write short replies, write replies using past tense": "write short replies, write replies using past tense", | ||
| 1111 | "Positive Prompt": "Positive Prompt", | ||
| 1112 | "Use character CFG scales": "Use character CFG scales", | ||
| 1113 | "Character CFG": "Character CFG", | ||
| 1114 | "Will be automatically added as the CFG for this character.": "Will be automatically added as the CFG for this character.", | ||
| 1115 | "Global CFG": "Global CFG", | ||
| 1116 | "Will be used as the default CFG options for every chat unless overridden.": "Will be used as the default CFG options for every chat unless overridden.", | ||
| 1117 | "CFG Prompt Cascading": "CFG Prompt Cascading", | ||
| 1118 | "Combine positive/negative prompts from other boxes.": "Combine positive/negative prompts from other boxes.", | ||
| 1119 | "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.": "For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.", | ||
| 1120 | "Always Include": "Always Include", | ||
| 1121 | "Chat Negatives": "ข้อเสียในการแชท", | ||
| 1122 | "Character Negatives": "ลักษณะนิสัยด้านลบของตัวละคร", | ||
| 1123 | "Global Negatives": "Global Negatives", | ||
| 1124 | "Custom Separator:": "Custom Separator:", | ||
| 1125 | "Insertion Depth:": "Insertion Depth:", | ||
| 1126 | "Token Probabilities": "Token Probabilities", | ||
| 1127 | "Select a token to see alternatives considered by the AI.": "Select a token to see alternatives considered by the AI.", | ||
| 1128 | "Not connected to API!": "ไม่ได้เชื่อมต่อ API!", | ||
| 1129 | "Type a message, or /? for help": "Type a message, or /? for help", | ||
| 1130 | "Continue script execution": "Continue script execution", | ||
| 1131 | "Pause script execution": "Pause script execution", | ||
| 1132 | "Abort script execution": "Abort script execution", | ||
| 1133 | "Abort request": "Abort request", | ||
| 1134 | "Continue the last message": "ต่อจากข้อความล่าสุด", | ||
| 1135 | "Send a message": "ส่งข้อความ", | ||
| 1136 | "Close chat": "ปิดแชทนี้", | ||
| 1137 | "Toggle Panels": "เปลี่ยนไปหน้าจัดการแชท", | ||
| 1138 | "Back to parent chat": "กลับไปที่แชทหลัก", | ||
| 1139 | "Save checkpoint": "เซฟเช็คพอยต์", | ||
| 1140 | "Convert to group": "เปลี่ยนเป็นแชทกลุ่ม", | ||
| 1141 | "Start new chat": "สร้างแชทใหม่", | ||
| 1142 | "Manage chat files": "จัดการแชทไฟล์", | ||
| 1143 | "Delete messages": "ลบข้อความ", | ||
| 1144 | "Regenerate": "รีข้อความใหม่", | ||
| 1145 | "Ask AI to write your message for you": "ให้ AI ช่วยเขียนข้อความสำหรับคุณ", | ||
| 1146 | "Impersonate": "สวมบทบาทในมุมมองของ User", | ||
| 1147 | "Continue": "ต่อจากเดิม", | ||
| 1148 | "Bind user name to that avatar": "เชื่อมชื่อผู้ใช้กับรูปตัวแทนนั้น", | ||
| 1149 | "Change persona image": "เปลี่ยนรูป Persona", | ||
| 1150 | "Select this as default persona for the new chats.": "ตั้งค่าตัวละครหลักสำหรับแชทใหม่ทุกครั้ง", | ||
| 1151 | "Delete persona": "ลบ persona", | ||
| 1152 | "These characters are the winners of character design contests and have outstandable quality.": "ตัวละครเหล่านี้เป็นผู้ชนะการประกวดออกแบบตัวละคร", | ||
| 1153 | "Contest Winners": "ผู้ชนะการประกวด", | ||
| 1154 | "These characters are the finalists of character design contests and have remarkable quality.": "ตัวละครเหล่านี้เป็นผู้เข้ารอบสุดท้ายของการประกวดออกแบบตัวละคร ", | ||
| 1155 | "Featured Characters": "ตัวละครยอดนิยม", | ||
| 1156 | "Attach a File": "แนบไฟล์ (รูป,เอกสาร)", | ||
| 1157 | "Open Data Bank": "เปิด Data Bank", | ||
| 1158 | "Enter a URL or the ID of a Fandom wiki page to scrape:": "Enter a URL or the ID of a Fandom wiki page to scrape:", | ||
| 1159 | "Examples:": "ตัวอย่าง:", | ||
| 1160 | "Example:": "ตัวอย่าง:", | ||
| 1161 | "Single file": "ไฟล์เดี่ยว", | ||
| 1162 | "All articles will be concatenated into a single file.": "All articles will be concatenated into a single file.", | ||
| 1163 | "File per article": "File per article", | ||
| 1164 | "Each article will be saved as a separate file.": "Each article will be saved as a separate file.", | ||
| 1165 | "Data Bank": "Data Bank", | ||
| 1166 | "These files will be available for extensions that support attachments (e.g. Vector Storage).": "These files will be available for extensions that support attachments (e.g. Vector Storage).", | ||
| 1167 | "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.", | ||
| 1168 | "Drag and drop files here to upload.": "Drag and drop files here to upload.", | ||
| 1169 | "Date (Newest First)": "เรียงจากวันที่ล่าสุดก่อน", | ||
| 1170 | "Date (Oldest First)": "เรียงจากวันที่เก่าสุดก่อน", | ||
| 1171 | "Name (A-Z)": "ชื่อ (A-Z)", | ||
| 1172 | "Name (Z-A)": "ชื่อ (Z-A)", | ||
| 1173 | "Size (Smallest First)": "ขนาด (เล็กที่สุดก่อน)", | ||
| 1174 | "Size (Largest First)": "ขนาด (ใหญ่ที่สุดก่อน)", | ||
| 1175 | "Bulk Edit": "แก้ไขกลุ่ม", | ||
| 1176 | "Select All": "เลือกทั้งหมด", | ||
| 1177 | "Select None": "ไม่เลือก", | ||
| 1178 | "Global Attachments": "ไฟล์แนบทั่วไป", | ||
| 1179 | "These files are available for all characters in all chats.": "ไฟล์เหล่านี้พร้อมใช้งานสำหรับตัวละครทั้งหมดในทุกแชท", | ||
| 1180 | "Character Attachments": "ไฟล์แนบตัวละคร", | ||
| 1181 | "These files are available the current character in all chats they are in.": "ไฟล์เหล่านี้พร้อมใช้งานสำหรับตัวละครปัจจุบันในทุกแชทที่มีส่วนร่วม", | ||
| 1182 | "Saved locally. Not exported.": "บันทึกในเครื่อง ไม่ส่งออก", | ||
| 1183 | "Chat Attachments": "ไฟล์แนบแชท", | ||
| 1184 | "These files are available to all characters in the current chat.": "ไฟล์เหล่านี้พร้อมใช้งานสำหรับตัวละครทั้งหมดในแชทปัจจุบัน", | ||
| 1185 | "Enter a base URL of the MediaWiki to scrape.": "ใส่ URL หลักของ MediaWiki ที่จะดึงข้อมูล", | ||
| 1186 | "Don't include the page name!": "อย่าใส่ชื่อหน้า!", | ||
| 1187 | "Enter web URLs to scrape (one per line):": "ใส่ URL เว็บที่จะดึงข้อมูล (หนึ่ง URL ต่อบรรทัด):", | ||
| 1188 | "Enter a video URL to download its transcript.": "ใส่ URL วิดีโอเพื่อดาวน์โหลดสคริปต์", | ||
| 1189 | "Expression API": "Expression API", | ||
| 1190 | "ext_sum_with": "สรุปด้วย:", | ||
| 1191 | "ext_sum_main_api": "API หลัก", | ||
| 1192 | "ext_sum_current_summary": "บทสรุปปัจจุบัน:", | ||
| 1193 | "ext_sum_restore_previous": "คืนค่าสถานะก่อนหน้า", | ||
| 1194 | "ext_sum_memory_placeholder": "บทสรุปจะถูกสร้างที่นี่...", | ||
| 1195 | "Trigger a summary update right now.": "สรุปทันที", | ||
| 1196 | "ext_sum_force_text": "สรุปทันที", | ||
| 1197 | "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 หลักเท่านั้น)", | ||
| 1198 | "ext_sum_pause": "หยุดชั่วคราว", | ||
| 1199 | "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.": "ละเว้น World Info และ Author's Note จากข้อความที่จะสรุป มีผลเฉพาะเมื่อใช้ API หลัก Extras API จะละเว้น WI/AN เสมอ", | ||
| 1200 | "ext_sum_no_wi_an": "ไม่มี WI/AN", | ||
| 1201 | "ext_sum_settings_tip": "แก้ไขพรอมต์สรุป ตำแหน่งแทรก และอื่นๆ", | ||
| 1202 | "ext_sum_settings": "การตั้งค่าบทสรุป", | ||
| 1203 | "ext_sum_prompt_builder": "ตัวสร้างพรอมต์", | ||
| 1204 | "ext_sum_prompt_builder_1_desc": "ส่วนขยายสร้างพรอมต์ของตัวเองโดยใช้ข้อความที่ยังไม่ได้สรุป บล็อกการแชทจนกว่าจะสร้างบทสรุปเสร็จ", | ||
| 1205 | "ext_sum_prompt_builder_1": "ดิบ, บล็อกกิ้ง", | ||
| 1206 | "ext_sum_prompt_builder_2_desc": "ส่วนขยายสร้างพรอมต์ของตัวเองโดยใช้ข้อความที่ยังไม่ได้สรุป ไม่บล็อกการแชทขณะสร้างบทสรุป แบ็กเอนด์ไม่ใช่ทั้งหมดที่รองรับโหมดนี้", | ||
| 1207 | "ext_sum_prompt_builder_2": "ดิบ, ไม่บล็อกกิ้ง", | ||
| 1208 | "ext_sum_prompt_builder_3_desc": "ส่วนขยายใช้ตัวสร้างพรอมต์หลักปกติและเพิ่มคำขอสรุปเป็นข้อความระบบสุดท้าย", | ||
| 1209 | "ext_sum_prompt_builder_3": "คลาสสิก, บล็อกกิ้ง", | ||
| 1210 | "Summary Prompt": "พรอมต์สรุป", | ||
| 1211 | "ext_sum_restore_default_prompt_tip": "คืนค่าพรอมต์เริ่มต้น", | ||
| 1212 | "ext_sum_prompt_placeholder": "พรอมต์นี้จะถูกส่งไปยัง AI เพื่อขอให้สร้างบทสรุป {{words}} จะถูกแทนที่ด้วยพารามิเตอร์ 'จำนวนคำ'", | ||
| 1213 | "ext_sum_target_length_1": "ความยาวบทสรุปเป้าหมาย", | ||
| 1214 | "ext_sum_target_length_2": "(", | ||
| 1215 | "ext_sum_target_length_3": "คำ)", | ||
| 1216 | "ext_sum_api_response_length_1": "ความยาวการตอบสนอง API", | ||
| 1217 | "ext_sum_api_response_length_2": "(", | ||
| 1218 | "ext_sum_api_response_length_3": "โทเค็น)", | ||
| 1219 | "ext_sum_0_default": "0 = เริ่มต้น", | ||
| 1220 | "ext_sum_raw_max_msg": "[ดิบ] ข้อความสูงสุดต่อคำขอ", | ||
| 1221 | "ext_sum_0_unlimited": "0 = ไม่จำกัด", | ||
| 1222 | "Update frequency": "ความถี่การอัปเดต", | ||
| 1223 | "ext_sum_update_every_messages_1": "อัปเดตทุก", | ||
| 1224 | "ext_sum_update_every_messages_2": "ข้อความ", | ||
| 1225 | "ext_sum_0_disable": "0 = ปิดใช้งาน", | ||
| 1226 | "ext_sum_auto_adjust_desc": "พยายามปรับช่วงเวลาโดยอัตโนมัติตามเมตริกของการแชท", | ||
| 1227 | "ext_sum_update_every_words_1": "อัปเดตทุก", | ||
| 1228 | "ext_sum_update_every_words_2": "คำ", | ||
| 1229 | "ext_sum_both_sliders": "หากทั้งสองสไลเดอร์เป็นค่าที่ไม่ใช่ศูนย์ ทั้งคู่จะทริกเกอร์การอัปเดตบทสรุปที่ช่วงเวลาของแต่ละอัน", | ||
| 1230 | "ext_sum_injection_template": "เทมเพลตการแทรก", | ||
| 1231 | "ext_sum_memory_template_placeholder": "{{summary}} จะถูกแทนที่ด้วยเนื้อหาบทสรุปปัจจุบัน", | ||
| 1232 | "ext_sum_injection_position": "ตำแหน่งการแทรก", | ||
| 1233 | "How many messages before the current end of the chat.": "จำนวนข้อความก่อนจุดสิ้นสุดปัจจุบันของการแชท", | ||
| 1234 | "ext_regex_title": "Regular Expression", | ||
| 1235 | "ext_regex_new_global_script": "+ โกลบอล", | ||
| 1236 | "ext_regex_new_scoped_script": "+ สโคป", | ||
| 1237 | "ext_regex_import_script": "นำเข้า", | ||
| 1238 | "ext_regex_global_scripts": "สคริปต์โกลบอล", | ||
| 1239 | "ext_regex_global_scripts_desc": "ใช้ได้กับตัวละครทั้งหมด บันทึกในการตั้งค่าท้องถิ่น", | ||
| 1240 | "ext_regex_scoped_scripts": "สคริปต์สโคป", | ||
| 1241 | "ext_regex_scoped_scripts_desc": "ใช้ได้เฉพาะตัวละครนี้ บันทึกในข้อมูลการ์ด", | ||
| 1242 | "Regex Editor": "ตัวแก้ไข Regex", | ||
| 1243 | "Test Mode": "โหมดทดสอบ", | ||
| 1244 | "ext_regex_desc": "Regex เป็นเครื่องมือสำหรับค้นหา/แทนที่สตริงโดยใช้นิพจน์ปกติ หากต้องการทราบรายละเอียด ให้คลิก [?] ข้างชื่อเรื่อง", | ||
| 1245 | "Input": "ป้อนข้อมูล", | ||
| 1246 | "ext_regex_test_input_placeholder": "พิมพ์ที่นี่...", | ||
| 1247 | "Output": "ผลลัพธ์", | ||
| 1248 | "ext_regex_output_placeholder": "ว่างเปล่า", | ||
| 1249 | "Script Name": "ชื่อสคริปต์", | ||
| 1250 | "Find Regex": "ค้นหา Regex", | ||
| 1251 | "Replace With": "แทนที่ด้วย", | ||
| 1252 | "ext_regex_replace_string_placeholder": "ใช้ {{match}} เพื่อรวมข้อความที่ตรงกันจากการค้นหา regex และใช้ $1, $2 เป็นต้น สำหรับกลุ่มที่จับได้", | ||
| 1253 | "Trim Out": "ตัดออก", | ||
| 1254 | "ext_regex_trim_placeholder": "ตัดส่วนที่ไม่ต้องการออกจากการจับคู่ regex โดยรวมก่อนการแทนที่ แยกแต่ละรายการด้วย Enter", | ||
| 1255 | "ext_regex_affects": "ส่งผลต่อ", | ||
| 1256 | "ext_regex_user_input": "ข้อมูลที่ผู้ใช้ป้อน", | ||
| 1257 | "ext_regex_ai_output": "ผลลัพธ์ AI", | ||
| 1258 | "Slash Commands": "คำสั่ง Slash", | ||
| 1259 | "ext_regex_min_depth_desc": "เมื่อใช้กับพรอมต์หรือการแสดงผล จะส่งผลต่อข้อความที่มีความลึกอย่างน้อย N ระดับเท่านั้น 0 = ข้อความสุดท้าย, 1 = ข้อความที่สองจากท้าย เป็นต้น นับเฉพาะรายการ WI @Depth และข้อความที่ใช้ได้ (ไม่ใช่ข้อความที่ซ่อนหรือระบบ)", | ||
| 1260 | "Min Depth": "ความลึกขั้นต่ำ", | ||
| 1261 | "ext_regex_min_depth_placeholder": "ไม่จำกัด", | ||
| 1262 | "ext_regex_max_depth_desc": "เมื่อใช้กับพรอมต์หรือการแสดงผล จะส่งผลต่อข้อความที่มีความลึกไม่เกิน N ระดับเท่านั้น 0 = ข้อความสุดท้าย, 1 = ข้อความที่สองจากท้าย เป็นต้น นับเฉพาะรายการ WI @Depth และข้อความที่ใช้ได้ (ไม่ใช่ข้อความที่ซ่อนหรือระบบ)", | ||
| 1263 | "ext_regex_other_options": "ตัวเลือกอื่นๆ", | ||
| 1264 | "Only Format Display": "จัดรูปแบบการแสดงผลเท่านั้น", | ||
| 1265 | "ext_regex_only_format_prompt_desc": "ประวัติการแชทจะไม่เปลี่ยนแปลง มีการเปลี่ยนแปลงเฉพาะพรอมต์เมื่อส่งคำขอ (ในระหว่างการสร้าง)", | ||
| 1266 | "Only Format Prompt (?)": "จัดรูปแบบพรอมต์เท่านั้น (?)", | ||
| 1267 | "Run On Edit": "ทำงานเมื่อแก้ไข", | ||
| 1268 | "ext_regex_substitute_regex_desc": "แทนที่ {{macros}} ใน Find Regex ก่อนการทำงาน", | ||
| 1269 | "Substitute Regex": "แทนที่ Regex", | ||
| 1270 | "ext_regex_import_target": "นำเข้าไปยัง:", | ||
| 1271 | "ext_regex_disable_script": "ปิดใช้งานสคริปต์", | ||
| 1272 | "ext_regex_enable_script": "เปิดใช้งานสคริปต์", | ||
| 1273 | "ext_regex_edit_script": "แก้ไขสคริปต์", | ||
| 1274 | "ext_regex_move_to_global": "ย้ายไปยังสคริปต์โกลบอล", | ||
| 1275 | "ext_regex_move_to_scoped": "ย้ายไปยังสคริปต์สโคป", | ||
| 1276 | "ext_regex_export_script": "ส่งออกสคริปต์", | ||
| 1277 | "ext_regex_delete_script": "ลบสคริปต์", | ||
| 1278 | "Trigger Stable Diffusion": "เรียกใช้ Stable Diffusion", | ||
| 1279 | "sd_Yourself": "ตัวคุณเอง", | ||
| 1280 | "sd_Your_Face": "ใบหน้าของคุณ", | ||
| 1281 | "sd_Me": "ฉัน", | ||
| 1282 | "sd_The_Whole_Story": "เรื่องราวทั้งหมด", | ||
| 1283 | "sd_The_Last_Message": "ข้อความสุดท้าย", | ||
| 1284 | "sd_Raw_Last_Message": "ข้อความสุดท้ายดิบ", | ||
| 1285 | "sd_Background": "พื้นหลัง", | ||
| 1286 | "Image Generation": "การสร้างภาพ", | ||
| 1287 | "Stop Image Generation": "หยุดการสร้างภาพ", | ||
| 1288 | "Generate Caption": "สร้างคำบรรยาย", | ||
| 1289 | "sd_refine_mode": "อนุญาตให้แก้ไขพรอมต์ด้วยตนเองก่อนส่งไปยัง API การสร้าง", | ||
| 1290 | "sd_refine_mode_txt": "แก้ไขพรอมต์ก่อนสร้าง", | ||
| 1291 | "sd_interactive_mode": "สร้างภาพโดยอัตโนมัติเมื่อส่งข้อความแบบ \"โปรดส่งรูปแมว\"", | ||
| 1292 | "sd_interactive_mode_txt": "โหมดโต้ตอบ", | ||
| 1293 | "sd_multimodal_captioning": "ใช้คำบรรยายมัลติโมดัลเพื่อสร้างพรอมต์สำหรับภาพพอร์ตเทรตผู้ใช้และตัวละครตามอวาตาร์", | ||
| 1294 | "sd_multimodal_captioning_txt": "ใช้คำบรรยายมัลติโมดัลสำหรับภาพพอร์ตเทรต", | ||
| 1295 | "sd_expand": "ขยายพรอมต์โดยอัตโนมัติโดยใช้โมเดลการสร้างข้อความ", | ||
| 1296 | "sd_expand_txt": "พรอมต์ปรับปรุงอัตโนมัติ", | ||
| 1297 | "sd_snap": "จัดคำขอการสร้างให้ตรงกับความละเอียดที่รู้จักที่ใกล้เคียงที่สุดด้วยอัตราส่วนที่บังคับ (พอร์ตเทรต, พื้นหลัง) โดยรักษาจำนวนพิกเซลสัมบูรณ์ (แนะนำสำหรับ SDXL)", | ||
| 1298 | "sd_snap_txt": "จัดความละเอียดอัตโนมัติ", | ||
| 1299 | "Source": "แหล่งที่มา", | ||
| 1300 | "sd_auto_url": "ตัวอย่าง: {{auto_url}}", | ||
| 1301 | "Authentication (optional)": "การยืนยันตัวตน (ไม่บังคับ)", | ||
| 1302 | "Example: username:password": "ตัวอย่าง: ชื่อผู้ใช้:รหัสผ่าน", | ||
| 1303 | "Important:": "สำคัญ:", | ||
| 1304 | "sd_auto_auth_warning_1": "ทำงาน SD Web UI ด้วย", | ||
| 1305 | "sd_auto_auth_warning_2": "แฟล็ก! เซิร์ฟเวอร์ต้องสามารถเข้าถึงได้จากเครื่อง SillyTavern โฮสต์", | ||
| 1306 | "sd_drawthings_url": "ตัวอย่าง: {{drawthings_url}}", | ||
| 1307 | "sd_drawthings_auth_txt": "ทำงานแอป DrawThings โดยเปิดใช้งานสวิตช์ HTTP API ใน UI เซิร์ฟเวอร์ต้องสามารถเข้าถึงได้จากเครื่อง SillyTavern โฮสต์", | ||
| 1308 | "sd_vlad_url": "ตัวอย่าง: {{vlad_url}}", | ||
| 1309 | "The server must be accessible from the SillyTavern host machine.": "The server must be accessible from the SillyTavern host machine.", | ||
| 1310 | "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.", | ||
| 1311 | "Allow NSFW images from Horde": "อนุญาตภาพที่ไม่เหมาะสมจาก Horde", | ||
| 1312 | "Sanitize prompts (recommended)": "Sanitize prompts (recommended)", | ||
| 1313 | "Automatically adjust generation parameters to ensure free image generations.": "Automatically adjust generation parameters to ensure free image generations.", | ||
| 1314 | "Avoid spending Anlas": "Avoid spending Anlas", | ||
| 1315 | "Opus tier": "Opus tier", | ||
| 1316 | "View my Anlas": "View my Anlas", | ||
| 1317 | "These settings only apply to DALL-E 3": "These settings only apply to DALL-E 3", | ||
| 1318 | "Image Style": "รูปแบบของรูปภาพ", | ||
| 1319 | "Image Quality": "คุณภาพของรูปภาพ", | ||
| 1320 | "Standard": "มาตรฐาน", | ||
| 1321 | "HD": "HD", | ||
| 1322 | "sd_comfy_url": "ตัวอย่าง: {{comfy_url}}", | ||
| 1323 | "Open workflow editor": "Open workflow editor", | ||
| 1324 | "Create new workflow": "Create new workflow", | ||
| 1325 | "Delete workflow": "Delete workflow", | ||
| 1326 | "Enhance": "Enhance", | ||
| 1327 | "Refine": "Refine", | ||
| 1328 | "Decrisper": "Decrisper", | ||
| 1329 | "Sampling steps": "Sampling steps", | ||
| 1330 | "Width": "ความกว้าง", | ||
| 1331 | "Height": "ความสูง", | ||
| 1332 | "Resolution": "ความละเอียดของรูปภาพ", | ||
| 1333 | "Model": "Model", | ||
| 1334 | "Sampling method": "Sampling method", | ||
| 1335 | "Karras (not all samplers supported)": "Karras (not all samplers supported)", | ||
| 1336 | "SMEA versions of samplers are modified to perform better at high resolution.": "SMEA versions of samplers are modified to perform better at high resolution.", | ||
| 1337 | "SMEA": "SMEA", | ||
| 1338 | "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.", | ||
| 1339 | "DYN": "DYN", | ||
| 1340 | "Scheduler": "Scheduler", | ||
| 1341 | "Restore Faces": "Restore Faces", | ||
| 1342 | "Hires. Fix": "Hires. Fix", | ||
| 1343 | "Upscaler": "Upscaler", | ||
| 1344 | "Upscale by": "Upscale by", | ||
| 1345 | "Denoising strength": "Denoising strength", | ||
| 1346 | "Hires steps (2nd pass)": "Hires steps (2nd pass)", | ||
| 1347 | "Preset for prompt prefix and negative prompt": "Preset for prompt prefix and negative prompt", | ||
| 1348 | "Style": "รูปแบบ", | ||
| 1349 | "Save style": "เซฟรูปแบบ", | ||
| 1350 | "Delete style": "ลบรูปแบบ", | ||
| 1351 | "Common prompt prefix": "Common prompt prefix", | ||
| 1352 | "sd_prompt_prefix_placeholder": "ใช้ {prompt} เพื่อระบุตำแหน่งที่จะแทรกพรอมต์ที่สร้างขึ้น", | ||
| 1353 | "Negative common prompt prefix": "Negative common prompt prefix", | ||
| 1354 | "Character-specific prompt prefix": "Character-specific prompt prefix", | ||
| 1355 | "Won't be used in groups.": "Won't be used in groups.", | ||
| 1356 | "sd_character_prompt_placeholder": "ลักษณะเฉพาะที่อธิบายตัวละครที่เลือกอยู่ จะถูกเพิ่มหลังจาก common prompt prefix\nตัวอย่าง: ผู้หญิง, ตาสีเขียว, ผมสีน้ำตาล, เสื้อสีชมพู", | ||
| 1357 | "Character-specific negative prompt prefix": "Character-specific negative prompt prefix", | ||
| 1358 | "sd_character_negative_prompt_placeholder": "ลักษณะที่ไม่ควรปรากฏในตัวละครที่เลือก จะถูกเพิ่มหลังจาก common negative prompt prefix\nตัวอย่าง: เครื่องประดับ, รองเท้า, แว่นตา", | ||
| 1359 | "Shareable": "Shareable", | ||
| 1360 | "Image Prompt Templates": "Image Prompt Templates", | ||
| 1361 | "Vectors Model Warning": "Vectors Model Warning", | ||
| 1362 | "Translate files into English before processing": "แปลไฟล์เป็นภาษาอังกฤษก่อนดำเนินการ", | ||
| 1363 | "Manager Users": "จัดการผู้ใช้", | ||
| 1364 | "Enter a name for this persona:": "ใส่ชื่อสำหรับ Persona นี้", | ||
| 1365 | "New User": "ผู้ใช้ใหม่", | ||
| 1366 | "Status:": "สถานะ:", | ||
| 1367 | "Created:": "สร้าง:", | ||
| 1368 | "Display Name:": "ชื่อที่แสดง:", | ||
| 1369 | "User Handle:": "ตัวจัดการผู้ใช้:", | ||
| 1370 | "Password:": "รหัสผ่าน:", | ||
| 1371 | "Confirm Password:": "ยืนยันรหัสผ่าน:", | ||
| 1372 | "This will create a new subfolder...": "การกระทำนี้จะสร้างโฟลเดอร์ย่อยใหม่...", | ||
| 1373 | "Current Password:": "รหัสผ่านปัจจุบัน:", | ||
| 1374 | "New Password:": "รหัสผ่านใหม่:", | ||
| 1375 | "Confirm New Password:": "ยืนยันรหัสผ่านใหม่:", | ||
| 1376 | "Debug Warning": "Debug Warning", | ||
| 1377 | "Execute": "ดำเนินการ", | ||
| 1378 | "Are you sure you want to delete this user?": "คุณแน่ใจแล้วใช่ไหมที่ต้องการลบผู้ใช้นี้?", | ||
| 1379 | "Deleting:": "กำลังลบ...", | ||
| 1380 | "Also wipe user data.": "ลบข้อมูลผู้ใช้ด้วย", | ||
| 1381 | "Warning:": "คำเตือน", | ||
| 1382 | "This action is irreversible.": "การกระทำนี้ไม่สามารถย้อนกลับได้.", | ||
| 1383 | "Type the user's handle below to confirm:": "Type the user's handle below to confirm:", | ||
| 1384 | "Import Characters": "นำเข้าตัวละคร", | ||
| 1385 | "Enter the URL of the content to import": "ใส่ URL ของเนื้อหาที่จะนำเข้า", | ||
| 1386 | "Supported sources:": "แหล่งที่รองรับ:", | ||
| 1387 | "char_import_1": "การ์ดตัวละคร Chub (ลิงก์โดยตรงหรือ ID)", | ||
| 1388 | "char_import_example": "ตัวอย่าง:", | ||
| 1389 | "char_import_2": "Lorebook ของ Chub (ลิงก์โดยตรงหรือ ID)", | ||
| 1390 | "char_import_3": "การ์ดตัวละคร JanitorAI (ลิงก์โดยตรงหรือ UUID)", | ||
| 1391 | "char_import_4": "การ์ดตัวละคร Pygmalion.chat (ลิงก์โดยตรงหรือ UUID)", | ||
| 1392 | "char_import_5": "การ์ดตัวละคร AICharacterCards.com (ลิงก์โดยตรงหรือ ID)", | ||
| 1393 | "char_import_6": "ลิงก์ PNG โดยตรง (ดู", | ||
| 1394 | "char_import_7": "โฮสต์ที่อนุญาต)", | ||
| 1395 | "char_import_8": "การ์ดตัวละคร RisuRealm (ลิงก์โดยตรง)", | ||
| 1396 | "char_import_10": "การ์ดตัวละคร Perchance (ลิงก์โดยตรงหรือ UUID + .gz)", | ||
| 1397 | "Supports importing multiple characters.": "รองรับการนำเข้าตัวละครหลายตัว", | ||
| 1398 | "Write each URL or ID into a new line.": "เขียน URL หรือ ID แต่ละอันในบรรทัดใหม่", | ||
| 1399 | "Export for character": "ส่งออกการ์ดตัวละคร", | ||
| 1400 | "Export prompts for this character, including their order.": "ส่งออกข้อความสำหรับตัวละครนี้ พร้อมเรียงลำดับข้อความ", | ||
| 1401 | "Export all": "ส่งออกทั้งหมด", | ||
| 1402 | "Export all your prompts to a file": "ส่งออก Prompts ทั้งหมดในรูปแบบไฟล์", | ||
| 1403 | "Insert prompt": "แทรก prompt", | ||
| 1404 | "Delete prompt": "ลบ prompt", | ||
| 1405 | "Import a prompt list": "นำเข้ารายการ prompt", | ||
| 1406 | "Export this prompt list": "ส่งออกรายการ prompt", | ||
| 1407 | "Reset current character": "รีเซ็ตตัวละครปัจจุบัน", | ||
| 1408 | "New prompt": "New prompt", | ||
| 1409 | "Prompts": "Prompts", | ||
| 1410 | "Total Tokens:": "จำนวนโทเค็นทั้งหมด:", | ||
| 1411 | "prompt_manager_tokens": "โทเค็น", | ||
| 1412 | "Are you sure you want to reset your settings to factory defaults?": "คุณแน่ใจไหมว่าต้องการคืนค่าการตั้งค่าเป็นค่าเริ่มต้น?", | ||
| 1413 | "Don't forget to save a snapshot of your settings before proceeding.": "อย่าลืมบันทึกสแนปช็อตการตั้งค่าของคุณก่อนดำเนินการ", | ||
| 1414 | "Settings Snapshots": "สแนปช็อตการตั้งค่า", | ||
| 1415 | "Record a snapshot of your current settings.": "บันทึกสแนปช็อตของการตั้งค่าปัจจุบันของคุณ", | ||
| 1416 | "Make a Snapshot": "สร้างสแนปช็อต", | ||
| 1417 | "Restore this snapshot": "คืนค่าสแนปช็อตนี้", | ||
| 1418 | "Hi,": "สวัสดี,", | ||
| 1419 | "To enable multi-account features, restart the SillyTavern server with": "เพื่อเปิดระบบ Multiple Account ให้รีสตาร์ทเซิร์ฟเวอร์ SillyTavern อีกครั้ง", | ||
| 1420 | "Account Info": "รายละเอียดของบัญชี", | ||
| 1421 | "To change your user avatar, use the buttons below or select a default persona in the Persona Management menu.": "เพื่อเปลี่ยนรูปโปรไฟล์ของคุณ ให้ใช้ปุ่มด้านล่างหรือเลือก Persona ในเมนูการจัดการตัวละคร", | ||
| 1422 | "Set your custom avatar.": "ตั้งค่ารูปโปรไฟล์ของคุณ", | ||
| 1423 | "Remove your custom avatar.": "ลบรูปโปรไฟล์ของคุณ", | ||
| 1424 | "Handle:": "Handle:", | ||
| 1425 | "This account is password protected.": "บัญชีนี้มีการป้องกันด้วยรหัสผ่าน", | ||
| 1426 | "This account is not password protected.": "บัญชีนี้ไม่มีการป้องกันด้วยรหัสผ่าน", | ||
| 1427 | "Account Actions": "การดำเนินการบัญชี", | ||
| 1428 | "Change Password": "เปลี่ยนรหัสผ่าน", | ||
| 1429 | "Manage your settings snapshots.": "จัดการการตั้งค่า Snapshot ของคุณ", | ||
| 1430 | "Download a complete backup of your user data.": "ดาวน์โหลดการสำรองข้อมูลทั้งหมดของข้อมูลผู้ใช้", | ||
| 1431 | "Download Backup": "ดาวน์โหลดการสำรองข้อมูล", | ||
| 1432 | "Danger Zone": "Danger Zone", | ||
| 1433 | "Reset your settings to factory defaults.": "รีเซ็ตการตั้งค่าเป็นค่าเริ่มต้น", | ||
| 1434 | "Reset Settings": "รีเซ็ตการตั้งค่า", | ||
| 1435 | "Wipe all user data and reset your account to factory settings.": "ลบข้อมูลผู้ใช้ทั้งหมดและรีเซ็ตบัญชีของคุณเป็นการตั้งค่าเริ่มต้น", | ||
| 1436 | "Reset Everything": "คืนค่าทุกอย่างเป็นค่าเริ่มต้น", | ||
| 1437 | "Reset Code:": "Reset Code:", | ||
| 1438 | "Want to update?": "ต้องการอัพเดตไหม?", | ||
| 1439 | "How to start chatting?": "จะเริ่มการสนทนาอย่างไร?", | ||
| 1440 | "Click _space": "Click space", | ||
| 1441 | "and select a": "และเลือก", | ||
| 1442 | "Chat API": "Chat API", | ||
| 1443 | "and pick a character.": "และเลือกตัวละคร", | ||
| 1444 | "You can browse a list of bundled characters in the": "คุณสามารถเรียกดูรายการตัวละครที่มีมาให้ใน", | ||
| 1445 | "Download Extensions & Assets": "ดาวน์โหลดส่วนขยายและทรัพยากร", | ||
| 1446 | "Load a custom asset list or select": "โหลดรายการทรัพยากรที่กำหนดเองหรือเลือกจาก", | ||
| 1447 | "to install 3rd party extensions.": "เพื่อติดตั้งส่วนขยายจาก 3rd party", | ||
| 1448 | "menu within": "เมนูใน", | ||
| 1449 | "Confused or lost?": "สับสนหรือหลงทาง?", | ||
| 1450 | "click these icons!": "คลิกไอคอนเหล่านี้!", | ||
| 1451 | "in the chat bar": "ในแถบแชท", | ||
| 1452 | "SillyTavern Documentation Site": "เว็บไซต์เอกสาร SillyTavern", | ||
| 1453 | "Extras Installation Guide": "คู่มือการติดตั้ง Extras", | ||
| 1454 | "Still have questions?": "ยังคงมีคำถามอยู่ใช่ไหม?", | ||
| 1455 | "Join the SillyTavern Discord": "เข้าร่วมดิสคอร์ด SillyTavern ", | ||
| 1456 | "Post a GitHub issue": "Post a GitHub issue", | ||
| 1457 | "Contact the developers": "ติดต่อผู้พัฒนา", | ||
| 1458 | "Stop Inspecting": "Stop Inspecting", | ||
| 1459 | "Inspect Prompts": "ตรวจสอบ Prompt", | ||
| 1460 | "Toggle prompt inspection": "สลับการตรวจสอบ Prompt" | ||
| 1461 | } | ||
| \ No newline at end of file | 1461 | \ No newline at end of file | |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "прапорцем", | 317 | "flag": "прапорцем", |
| 318 | "API key (optional)": "Ключ API (необов'язково)", | 318 | "API key (optional)": "Ключ API (необов'язково)", |
| 319 | "Server url": "URL-адреса сервера", | 319 | "Server url": "URL-адреса сервера", |
| 320 | "Electron Hub API Key": "Ключ API для Electron Hub", | ||
| 321 | "Electron Hub Model": "Модель Electron Hub", | ||
| 320 | "Example: http://127.0.0.1:5000": "Приклад: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "Приклад: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "Власна модель (необов'язково)", | 323 | "Custom model (optional)": "Власна модель (необов'язково)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (режим оболонки OpenAI API)", | 324 | "vllm-project/vllm": "vllm-project/vllm (режим оболонки OpenAI API)", |
| @@ -317,6 +317,8 @@ | |||
| 317 | "flag": "cờ", | 317 | "flag": "cờ", |
| 318 | "API key (optional)": "Key API (tùy chọn)", | 318 | "API key (optional)": "Key API (tùy chọn)", |
| 319 | "Server url": "URL máy chủ", | 319 | "Server url": "URL máy chủ", |
| 320 | "Electron Hub API Key": "Key API Electron Hub", | ||
| 321 | "Electron Hub Model": "Model Electron Hub", | ||
| 320 | "Example: http://127.0.0.1:5000": "Ví dụ: http://127.0.0.1:5000", | 322 | "Example: http://127.0.0.1:5000": "Ví dụ: http://127.0.0.1:5000", |
| 321 | "Custom model (optional)": "Model tùy chỉnh (tùy chọn)", | 323 | "Custom model (optional)": "Model tùy chỉnh (tùy chọn)", |
| 322 | "vllm-project/vllm": "vllm-project/vllm (Chế độ trình bao bọc API OpenAI)", | 324 | "vllm-project/vllm": "vllm-project/vllm (Chế độ trình bao bọc API OpenAI)", |
| @@ -2,7 +2,7 @@ | |||
| 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配置面板将保持打开", |
| @@ -21,10 +21,11 @@ | |||
| 21 | "novelaipresets": "NovelAI 预设", | 21 | "novelaipresets": "NovelAI 预设", |
| 22 | "Default": "默认", | 22 | "Default": "默认", |
| 23 | "openaipresets": "对话补全预设", | 23 | "openaipresets": "对话补全预设", |
| 24 | "Bind presets to API connections": "将预设与 API 配置绑定", | ||
| 24 | "Text Completion presets": "文本补全预设", | 25 | "Text Completion presets": "文本补全预设", |
| 25 | "response legth(tokens)": "回复长度(以词符数计)", | 26 | "response legth(tokens)": "回复长度(以词符数计)", |
| 26 | "Streaming": "流式传输", | 27 | "Streaming": "流式传输", |
| 27 | "Streaming_desc": "逐位显示生成的回复", | 28 | "Streaming_desc": "逐词显示生成的回复", |
| 28 | "context size(tokens)": "上下文长度(以词符数计)", | 29 | "context size(tokens)": "上下文长度(以词符数计)", |
| 29 | "unlocked": "解锁", | 30 | "unlocked": "解锁", |
| 30 | "Only enable this if your model supports context sizes greater than 8192 tokens": "仅在您的模型支持大于8192个词符的上下文长度时启用此选项", | 31 | "Only enable this if your model supports context sizes greater than 8192 tokens": "仅在您的模型支持大于8192个词符的上下文长度时启用此选项", |
| @@ -73,10 +74,12 @@ | |||
| 73 | "Context Size (tokens)": "上下文长度(以词符数计)", | 74 | "Context Size (tokens)": "上下文长度(以词符数计)", |
| 74 | "Max Response Length (tokens)": "最大回复长度(以词符数计)", | 75 | "Max Response Length (tokens)": "最大回复长度(以词符数计)", |
| 75 | "Multiple swipes per generation": "每次生成多个备选回复", | 76 | "Multiple swipes per generation": "每次生成多个备选回复", |
| 76 | "Middle-out Transform": "Middle-out Transform", | 77 | "Allow compressing requests by removing messages from the middle of the prompt.": "允许通过移除提示词中间的消息来压缩请求。", |
| 77 | "Auto": "Auto", | 78 | "Middle-out Transform": "中心向外算法", |
| 78 | "Allow": "Allow", | 79 | "Auto": "自动", |
| 79 | "Forbid": "Forbid", | 80 | "Allow": "允许", |
| 81 | "Forbid": "禁止", | ||
| 82 | "Unknown": "未知", | ||
| 80 | "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输", | 83 | "Enable OpenAI completion streaming": "启用OpenAI文本补全流式传输", |
| 81 | "Display the response bit by bit as it is generated.": "随着回复的生成,逐词逐句地显示结果。", | 84 | "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.": "当此选项关闭时,回复将在完成后一次性显示。", | 85 | "When this is off, responses will be displayed all at once when they are complete.": "当此选项关闭时,回复将在完成后一次性显示。", |
| @@ -147,8 +150,9 @@ | |||
| 147 | "Epsilon Cutoff": "ε 截断", | 150 | "Epsilon Cutoff": "ε 截断", |
| 148 | "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "ε 截断设置了一个概率下限,低于该下限的词符将被排除在采样之外。\n以 1e-4 单位;合适的值为 3。将其设置为 0 以禁用。", | 151 | "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "ε 截断设置了一个概率下限,低于该下限的词符将被排除在采样之外。\n以 1e-4 单位;合适的值为 3。将其设置为 0 以禁用。", |
| 149 | "Top nsigma": "Top nsigma", | 152 | "Top nsigma": "Top nsigma", |
| 153 | "Min Keep": "Min Keep", | ||
| 150 | "Eta Cutoff": "η 截断", | 154 | "Eta Cutoff": "η 截断", |
| 151 | "Eta_Cutoff_desc": "η截断是特殊η采样技术的主要参数。 以1e-4为单位;合理的值为3。 设置为0以禁用。 有关详细信息,请参阅Hewitt等人的论文《Truncation Sampling as Language Model Desmoothing》(2022年)。", | 155 | "Eta_Cutoff_desc": "η截断是特殊η采样技术的主要参数。以1e-4为单位;合理的值为3。设置为0以禁用。详细请参阅《Truncation Sampling as Language Model Desmoothing》(Hewitt et al., 2022)。", |
| 152 | "rep.pen decay": "重复惩罚衰减", | 156 | "rep.pen decay": "重复惩罚衰减", |
| 153 | "Encoder Rep. Pen.": "编码器重复惩罚", | 157 | "Encoder Rep. Pen.": "编码器重复惩罚", |
| 154 | "No Repeat Ngram Size": "无重复n-gram大小", | 158 | "No Repeat Ngram Size": "无重复n-gram大小", |
| @@ -187,9 +191,9 @@ | |||
| 187 | "Beam search": "束搜索", | 191 | "Beam search": "束搜索", |
| 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.": "一种在LLM采样中使用的贪婪暴力算法,用于找到最可能的单词或标记序列。它一次扩展多个候选序列,在每一步保留固定数量(光束宽度)的最佳序列。", | 192 | "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采样中使用的贪婪暴力算法,用于找到最可能的单词或标记序列。它一次扩展多个候选序列,在每一步保留固定数量(光束宽度)的最佳序列。", |
| 189 | "# of Beams": "光束数量", | 193 | "# 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.", | 194 | "The number of sequences generated at each step with Beam Search.": "束搜索每步生成的序列数量。", |
| 191 | "Length Penalty": "长度惩罚", | 195 | "Length Penalty": "长度惩罚", |
| 192 | "Penalize sequences based on their length.": "Penalize sequences based on their length.", | 196 | "Penalize sequences based on their length.": "根据序列长度对其进行惩罚。", |
| 193 | "Early Stopping": "提前停止", | 197 | "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.": "控制光束搜索的停止条件。勾选时,当生成到达‘光束数量’的序列时停止。如果未勾选,则采用启发式方法,当几乎不可能找到更好的候选项时停止生成。", | 198 | "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.": "控制光束搜索的停止条件。勾选时,当生成到达‘光束数量’的序列时停止。如果未勾选,则采用启发式方法,当几乎不可能找到更好的候选项时停止生成。", |
| 195 | "Contrastive search": "对比搜索", | 199 | "Contrastive search": "对比搜索", |
| @@ -203,7 +207,7 @@ | |||
| 203 | "Ignore EOS Token": "忽略序列结束词符", | 207 | "Ignore EOS Token": "忽略序列结束词符", |
| 204 | "Ignore the EOS Token even if it generates.": "即使生成了序列结束词符,也忽略它。", | 208 | "Ignore the EOS Token even if it generates.": "即使生成了序列结束词符,也忽略它。", |
| 205 | "Skip Special Tokens": "跳过特殊词符", | 209 | "Skip Special Tokens": "跳过特殊词符", |
| 206 | "Request Model Reasoning": "Request Model Reasoning", | 210 | "Request Model Reasoning": "请求模型推理", |
| 207 | "Temperature Last": "温度放最后", | 211 | "Temperature Last": "温度放最后", |
| 208 | "Temperature_Last_desc": "温度采样器放到最后使用。这通常是合理的。\n当启用时:首先进行潜在词符的选择,然后应用温度来修正它们的相对概率(技术上是对数似然)。\n当禁用时:首先应用温度来修正所有词符的相对概率,然后从中选择潜在词符。\n禁用此项可以增大分布在尾部的词符概率,这可能加大得到不相关回复的几率。", | 212 | "Temperature_Last_desc": "温度采样器放到最后使用。这通常是合理的。\n当启用时:首先进行潜在词符的选择,然后应用温度来修正它们的相对概率(技术上是对数似然)。\n当禁用时:首先应用温度来修正所有词符的相对概率,然后从中选择潜在词符。\n禁用此项可以增大分布在尾部的词符概率,这可能加大得到不相关回复的几率。", |
| 209 | "Speculative Ngram": "推测性 Ngram", | 213 | "Speculative Ngram": "推测性 Ngram", |
| @@ -254,10 +258,16 @@ | |||
| 254 | "Continue sends the last message as assistant role instead of system message with instruction.": "继续发送的是作为助手角色的最后一条消息,而不是带有指示的系统消息。", | 258 | "Continue sends the last message as assistant role instead of system message with instruction.": "继续发送的是作为助手角色的最后一条消息,而不是带有指示的系统消息。", |
| 255 | "Squash system messages": "压缩系统消息", | 259 | "Squash system messages": "压缩系统消息", |
| 256 | "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "将连续的系统消息合并为一条(不包括示例对话),可能会提高一些模型的连贯性。", | 260 | "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "将连续的系统消息合并为一条(不包括示例对话),可能会提高一些模型的连贯性。", |
| 261 | "Enable web search": "启用联网搜索", | ||
| 262 | "Use search capabilities provided by the backend.": "使用后端提供的联网搜索功能。", | ||
| 263 | "openrouter_web_search_fee": "收费,每个提示词会多收 $0.02。", | ||
| 257 | "Enable function calling": "启用函数调用", | 264 | "Enable function calling": "启用函数调用", |
| 265 | "Supported by the current model": "当前模型支持", | ||
| 266 | "Unsupported by the current model": "当前模型不支持", | ||
| 258 | "enable_functions_desc_1": "允许使用", | 267 | "enable_functions_desc_1": "允许使用", |
| 259 | "enable_functions_desc_2": "功能工具", | 268 | "enable_functions_desc_2": "功能工具", |
| 260 | "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。", | 269 | "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。", |
| 270 | "enable_functions_desc_4": "当提示词后处理没有选择工具时不支持。", | ||
| 261 | "Send inline images": "发送图片", | 271 | "Send inline images": "发送图片", |
| 262 | "image_inlining_hint_1": "如果模型支持,就可以在提示词中发送图片。\n发送消息时,点击", | 272 | "image_inlining_hint_1": "如果模型支持,就可以在提示词中发送图片。\n发送消息时,点击", |
| 263 | "image_inlining_hint_2": "在这里(", | 273 | "image_inlining_hint_2": "在这里(", |
| @@ -266,23 +276,38 @@ | |||
| 266 | "openai_inline_image_quality_auto": "自动", | 276 | "openai_inline_image_quality_auto": "自动", |
| 267 | "openai_inline_image_quality_low": "低", | 277 | "openai_inline_image_quality_low": "低", |
| 268 | "openai_inline_image_quality_high": "高", | 278 | "openai_inline_image_quality_high": "高", |
| 279 | "Send inline videos": "发送视频", | ||
| 280 | "video_inlining_hint_1": "当模型支持时,将视频发送给模型。使用", | ||
| 281 | "video_inlining_hint_2": "在任意消息上添加视频,或", | ||
| 282 | "video_inlining_hint_3": "菜单来添加视频。", | ||
| 283 | "video_inlining_hint_4": "视频必须在 20MB 以下且时长不超过1分钟。", | ||
| 284 | "Request inline images": "请求图片返回", | ||
| 285 | "Allows the model to return image attachments.": "允许模型返回图片附件。", | ||
| 286 | "Request inline images_desc_2": "与以下几个功能不兼容:函数调用、联网搜搜、系统提示词。", | ||
| 269 | "Use system prompt": "使用系统提示词", | 287 | "Use system prompt": "使用系统提示词", |
| 270 | "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过", | 288 | "Merges_all_system_messages_desc_1": "合并所有系统消息,直到第一条具有非系统角色的消息,然后通过", |
| 271 | "Merges_all_system_messages_desc_2": "字段发送。", | 289 | "Merges_all_system_messages_desc_2": "字段发送。", |
| 272 | "Request model reasoning": "请求思维链", | 290 | "Request model reasoning": "请求思维链", |
| 273 | "Allows the model to return its thinking process.": "允许模型返回其思维过程。", | 291 | "Allows the model to return its thinking process.": "允许模型返回其思维过程。", |
| 292 | "This setting affects visibility only.": "此设置只影响思维链是否可见。", | ||
| 274 | "Constrains effort on reasoning for reasoning models.": "限定模型推理的强度。\n当前支持低、中、高三种强度。\n降低推理强度可以让模型更快回复,并节省推理所用的词符数。。", | 293 | "Constrains effort on reasoning for reasoning models.": "限定模型推理的强度。\n当前支持低、中、高三种强度。\n降低推理强度可以让模型更快回复,并节省推理所用的词符数。。", |
| 275 | "Reasoning Effort": "推理强度", | 294 | "Reasoning Effort": "推理强度", |
| 295 | "openai_reasoning_effort_auto": "自动", | ||
| 296 | "openai_reasoning_effort_minimum": "极低", | ||
| 276 | "openai_reasoning_effort_low": "低", | 297 | "openai_reasoning_effort_low": "低", |
| 277 | "openai_reasoning_effort_medium": "中", | 298 | "openai_reasoning_effort_medium": "中", |
| 278 | "openai_reasoning_effort_high": "高", | 299 | "openai_reasoning_effort_high": "高", |
| 300 | "openai_reasoning_effort_maximum": "极高", | ||
| 301 | "OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level.": "OpenAI式选项:低、中、高。极低等于低,极高等于高。选择自动,则不传入推理强度参数。", | ||
| 302 | "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "将最大回复空间的一部分分配给思维链(极低:1024词符,低:10%,中:25%,高:50%,极高:95%),最低1024词符。选择“自动”不会请求模型思维链。", | ||
| 303 | "Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide.": "将最大回复空间的一部分分配给思维链(仅 2.5 Flash / 2.5 Pro 模型)(极低:0/128词符,低:10%,中:25%,高:50%,极高:24576/32768词符),最低1024词符。选择“自动”会让模型自己决定。", | ||
| 279 | "Assistant Prefill": "AI预填", | 304 | "Assistant Prefill": "AI预填", |
| 280 | "Expand the editor": "展开编辑器", | 305 | "Expand the editor": "展开编辑器", |
| 281 | "Start Claude's answer with...": "以如下内容开始Claude的回答...", | 306 | "Start Claude's answer with...": "以如下内容开始Claude的回答...", |
| 282 | "Assistant Impersonation Prefill": "AI帮答预填", | 307 | "Assistant Impersonation Prefill": "AI帮答预填", |
| 283 | "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。", | 308 | "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "为支持的模型发送系统提示词。如果禁用,则用户消息将添加到提示词的开头。", |
| 284 | "Confirm token parsing with": "确认使用以下工具进行词符解析", | 309 | "Confirm token parsing with": "确认使用以下工具进行词符解析", |
| 285 | "Tokenizer": "词符化器", | 310 | "Tokenizer": "分词器", |
| 286 | "New preset": "新预设", | 311 | "New preset": "新预设", |
| 287 | "Delete preset": "删除预设", | 312 | "Delete preset": "删除预设", |
| 288 | "View / Edit bias preset": "查看/编辑偏置预设", | 313 | "View / Edit bias preset": "查看/编辑偏置预设", |
| @@ -305,14 +330,17 @@ | |||
| 305 | "Adjust response length to worker capabilities": "根据工作单元能力调整响应长度", | 330 | "Adjust response length to worker capabilities": "根据工作单元能力调整响应长度", |
| 306 | "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "可以通过仅排队认证的工作单元来帮助处理不良回复。这可能会减慢回复速度。", | 331 | "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "可以通过仅排队认证的工作单元来帮助处理不良回复。这可能会减慢回复速度。", |
| 307 | "Trusted workers only": "仅信任的工作单元", | 332 | "Trusted workers only": "仅信任的工作单元", |
| 333 | "Context": "上下文", | ||
| 334 | "Response": "回复", | ||
| 308 | "API key": "API密钥", | 335 | "API key": "API密钥", |
| 309 | "Get it here:": "在此获取:", | 336 | "Get it here:": "在此获取:", |
| 310 | "Register": "注册", | 337 | "Register": "注册", |
| 311 | "View my Kudos": "查看我的荣誉", | 338 | "View my Kudos": "查看我的荣誉", |
| 312 | "Enter": "输入", | 339 | "Enter": "输入", |
| 313 | "to use anonymous mode.": "以使用匿名模式。", | 340 | "to use anonymous mode.": "以使用匿名模式。", |
| 314 | "Clear your API key": "清除您的API密钥", | 341 | "Save and connect": "保存并连接", |
| 315 | "For privacy reasons, your API key will be hidden after you reload the page.": "出于隐私原因,重新加载页面后您的 API 密钥将被隐藏。", | 342 | "Manage API keys": "管理 API 密钥", |
| 343 | "For privacy reasons, your API key will be hidden after you click 'Connect'.": "出于隐私考虑,您的 API 密钥将会在点击“连接”后隐藏。", | ||
| 316 | "Models": "模型", | 344 | "Models": "模型", |
| 317 | "Refresh models": "刷新模型", | 345 | "Refresh models": "刷新模型", |
| 318 | "-- Horde models not loaded --": "-- Horde 模型未加载 --", | 346 | "-- Horde models not loaded --": "-- Horde 模型未加载 --", |
| @@ -351,14 +379,16 @@ | |||
| 351 | "Make sure you run it with": "确保您在运行时加上", | 379 | "Make sure you run it with": "确保您在运行时加上", |
| 352 | "flag": "标志", | 380 | "flag": "标志", |
| 353 | "Custom model (optional)": "自定义模型(可选)", | 381 | "Custom model (optional)": "自定义模型(可选)", |
| 354 | "Featherless Model Selection": "Featherless Model Selection", | 382 | "Featherless Model Selection": "Featherless 模型选择", |
| 355 | "Search...": "搜索...", | 383 | "Search...": "搜索...", |
| 356 | "Search": "搜索", | 384 | "Search": "搜索", |
| 385 | "Date Asc": "日期顺序", | ||
| 386 | "Date Desc": "日期倒序", | ||
| 357 | "category": "分类", | 387 | "category": "分类", |
| 358 | "Top": "Top", | 388 | "Top": "热门", |
| 359 | "New": "新建", | 389 | "New": "新建", |
| 360 | "All": "All", | 390 | "All": "全部", |
| 361 | "class": "All Classes", | 391 | "All Classes": "所有分类", |
| 362 | "Toggle grid view": "切换网格视图", | 392 | "Toggle grid view": "切换网格视图", |
| 363 | "No model description": "[无描述]", | 393 | "No model description": "[无描述]", |
| 364 | "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)", | 394 | "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)", |
| @@ -378,6 +408,7 @@ | |||
| 378 | "Download": "下载", | 408 | "Download": "下载", |
| 379 | "Tabby API key": "Tabby API 密钥", | 409 | "Tabby API key": "Tabby API 密钥", |
| 380 | "Tabby Model": "Tabby 模型", | 410 | "Tabby Model": "Tabby 模型", |
| 411 | "Experimental feature. Use at your own risk.": "实验性功能,请自行承担可能的风险。", | ||
| 381 | "must be set in Tabby's config.yml to switch models.": "必须在Tabby的config.yml内设置以切换模型", | 412 | "must be set in Tabby's config.yml to switch models.": "必须在Tabby的config.yml内设置以切换模型", |
| 382 | "Use an admin API key.": "使用管理员API密钥。", | 413 | "Use an admin API key.": "使用管理员API密钥。", |
| 383 | "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)", | 414 | "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)", |
| @@ -397,8 +428,9 @@ | |||
| 397 | "This will show up as your saved preset.": "这将显示为您保存的预设。", | 428 | "This will show up as your saved preset.": "这将显示为您保存的预设。", |
| 398 | "Proxy Server URL": "代理服务器 URL", | 429 | "Proxy Server URL": "代理服务器 URL", |
| 399 | "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。", | 430 | "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。", |
| 400 | "Doesn't work? Try adding": "不起作用?在末尾添加", | 431 | "Doesn't work? Try adding": "不行?在 URL 末尾添加", |
| 401 | "at the end!": "试试!", | 432 | "at the end!": "试试!", |
| 433 | "suffix will be added automatically.": "的后缀会被自动补全。", | ||
| 402 | "Proxy Password": "代理密码", | 434 | "Proxy Password": "代理密码", |
| 403 | "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。", | 435 | "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。", |
| 404 | "Peek a password": "查看密码", | 436 | "Peek a password": "查看密码", |
| @@ -418,8 +450,6 @@ | |||
| 418 | "Get your key from": "从以下位置获取您的密钥", | 450 | "Get your key from": "从以下位置获取您的密钥", |
| 419 | "Anthropic's developer console": "Anthropic 开发者控制台", | 451 | "Anthropic's developer console": "Anthropic 开发者控制台", |
| 420 | "Claude Model": "Claude 模型", | 452 | "Claude Model": "Claude 模型", |
| 421 | "Window AI Model": "Window AI 模型", | ||
| 422 | "Use extension settings": "使用扩展程序中的设定", | ||
| 423 | "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。", | 453 | "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。", |
| 424 | "Allow fallback models": "允许后备模型", | 454 | "Allow fallback models": "允许后备模型", |
| 425 | "Model Order": "OpenRouter 模型顺序", | 455 | "Model Order": "OpenRouter 模型顺序", |
| @@ -428,25 +458,43 @@ | |||
| 428 | "Context Size": "上下文长度", | 458 | "Context Size": "上下文长度", |
| 429 | "Group by vendors": "按厂商分组", | 459 | "Group by vendors": "按厂商分组", |
| 430 | "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。", | 460 | "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。", |
| 431 | "To use instruct formatting, switch to OpenRouter under Text Completion API.": "To use instruct formatting, switch to OpenRouter under Text Completion API.", | 461 | "To use instruct formatting, switch to OpenRouter under Text Completion API.": "要使用指导格式,请在 文字补全API 下切换到 OpenRouter。", |
| 432 | "AI21 API Key": "AI21 API 密钥", | 462 | "AI21 API Key": "AI21 API 密钥", |
| 433 | "AI21 Model": "AI21 模型", | 463 | "AI21 Model": "AI21 模型", |
| 434 | "Google AI Studio API Key": "Google AI Studio API 密钥", | 464 | "Google AI Studio API Key": "Google AI Studio API 密钥", |
| 435 | "Google Model": "Google 模型", | 465 | "Google Model": "Google 模型", |
| 466 | "Google Vertex AI Configuration": "Google Vertex AI 配置", | ||
| 467 | "Authentication Mode": "验证模式:", | ||
| 468 | "Express Mode (API Key)": "快速模式(API 密钥)", | ||
| 469 | "Full Version (Service Account)": "完整版本(Service Account)", | ||
| 470 | "(Express mode)": "(快速模式)", | ||
| 471 | "API Key": "API 密钥", | ||
| 472 | "Project ID": "项目ID:", | ||
| 473 | "Project ID is required when selecting regions other than the default (us-central1). You can find this in a model 404 error message.": "仅当选择非默认区域(us-central1)时才需要`项目ID`。\n 您可以在模型 404 错误消息中找到它。", | ||
| 474 | "Service Account Configuration": "服务帐户配置", | ||
| 475 | "Service Account JSON Content": "服务帐户 JSON 内容:", | ||
| 476 | "For privacy reasons, your Service Account JSON content will be hidden after you click 'Validate JSON'.": "出于隐私考虑,你的服务账号 JSON 内容将在点击“验证JSON”后隐藏。", | ||
| 477 | "Validate JSON": "验证JSON", | ||
| 478 | "Region": "地区:", | ||
| 479 | "View available regions and models": "查看可用地区和模型", | ||
| 436 | "MistralAI API Key": "MistralAI API 密钥", | 480 | "MistralAI API Key": "MistralAI API 密钥", |
| 437 | "MistralAI Model": "MistralAI 模型", | 481 | "MistralAI Model": "MistralAI 模型", |
| 438 | "Groq API Key": "Groq API 密钥", | 482 | "Groq API Key": "Groq API 密钥", |
| 439 | "Groq Model": "Groq 模型", | 483 | "Groq Model": "Groq 模型", |
| 440 | "NanoGPT API Key": "NanoGPT API Key", | 484 | "Electron Hub API Key": "Electron Hub API 密钥", |
| 441 | "NanoGPT Model": "NanoGPT Model", | 485 | "Electron Hub Model": "Electron Hub 模型", |
| 486 | "NanoGPT API Key": "NanoGPT API 密钥", | ||
| 487 | "NanoGPT Model": "NanoGPT 模型", | ||
| 442 | "DeepSeek API Key": "DeepSeek API 密钥", | 488 | "DeepSeek API Key": "DeepSeek API 密钥", |
| 443 | "DeepSeek Model": "DeepSeek 模型", | 489 | "DeepSeek Model": "DeepSeek 模型", |
| 490 | "Fireworks AI API Key": "Fireworks AI API 密钥", | ||
| 491 | "Fireworks AI Model": "Fireworks AI 模型", | ||
| 492 | "CometAPI API Key": "CometAPI API 密钥", | ||
| 493 | "CometAPI Model": "CometAPI 模型", | ||
| 444 | "Perplexity API Key": "Perplexity API 密钥", | 494 | "Perplexity API Key": "Perplexity API 密钥", |
| 445 | "Perplexity Model": "Perplexity 模型", | 495 | "Perplexity Model": "Perplexity 模型", |
| 446 | "Cohere API Key": "Cohere API 密钥", | 496 | "Cohere API Key": "Cohere API 密钥", |
| 447 | "Cohere Model": "Cohere 模型", | 497 | "Cohere Model": "Cohere 模型", |
| 448 | "Block Entropy API Key": "Block Entropy API 密钥", | ||
| 449 | "Select a Model": "选择一个模型", | ||
| 450 | "Custom Endpoint (Base URL)": "自定义端点(基础 URL)", | 498 | "Custom Endpoint (Base URL)": "自定义端点(基础 URL)", |
| 451 | "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1", | 499 | "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1", |
| 452 | "Custom API Key": "自定义 API 密钥", | 500 | "Custom API Key": "自定义 API 密钥", |
| @@ -454,15 +502,28 @@ | |||
| 454 | "Enter a Model ID": "输入模型名", | 502 | "Enter a Model ID": "输入模型名", |
| 455 | "Example: gpt-4o": "例如:gpt-4o", | 503 | "Example: gpt-4o": "例如:gpt-4o", |
| 456 | "Available Models": "可用模型", | 504 | "Available Models": "可用模型", |
| 505 | "xAI API Key": "xAI API 密钥", | ||
| 506 | "xAI Model": "xAI 模型", | ||
| 507 | "AI/ML API Key": "AI/ML API 密钥", | ||
| 508 | "AI/ML Model": "AI/ML 模型", | ||
| 509 | "Pollinations Model": "Pollinations 模型", | ||
| 510 | "Provided free of charge by Pollinations.AI": "由 Pollinations.AI 免费提供", | ||
| 511 | "Avoid sending sensitive information. Provider's outputs may include ads.": "请避免发送敏感信息。输出可能有提供商的广告。", | ||
| 512 | "Moonshot AI API Key": "Moonshot AI API 密钥", | ||
| 513 | "Moonshot AI Model": "Moonshot AI 模型", | ||
| 457 | "Prompt Post-Processing": "提示词后处理", | 514 | "Prompt Post-Processing": "提示词后处理", |
| 458 | "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。", | 515 | "Applies additional processing to the prompt before sending it to the API.": "在将提示词发送到 API 之前对其进行额外处理。", |
| 459 | "prompt_post_processing_none": "未选择", | 516 | "prompt_post_processing_none": "未选择", |
| 517 | "prompt_post_processing_merge_tools": "合并相同角色连续的发言(含工具)", | ||
| 518 | "prompt_post_processing_semi_tools": "半严格(强制对话角色交替)(含工具)", | ||
| 519 | "prompt_post_processing_strict_tools": "严格(强制对话角色交替、用户最先)(含工具)", | ||
| 460 | "prompt_post_processing_merge": "合并相同角色连续的发言", | 520 | "prompt_post_processing_merge": "合并相同角色连续的发言", |
| 461 | "prompt_post_processing_semi": "半严格(强制对话角色交替)", | 521 | "prompt_post_processing_semi": "半严格(强制对话角色交替)", |
| 462 | "prompt_post_processing_strict": "严格(强制对话角色交替、用户最先)", | 522 | "prompt_post_processing_strict": "严格(强制对话角色交替、用户最先)", |
| 523 | "prompt_post_processing_single": "单一用户消息(无工具)", | ||
| 463 | "Additional Parameters": "附加参数", | 524 | "Additional Parameters": "附加参数", |
| 464 | "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意,您将因此消耗额度!", | ||
| 465 | "Test Message": "发送测试消息", | 525 | "Test Message": "发送测试消息", |
| 526 | "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "通过发送简短的测试消息验证您的API连接。请注意,您将因此消耗额度!", | ||
| 466 | "Auto-connect to Last Server": "自动连接到上次的服务器", | 527 | "Auto-connect to Last Server": "自动连接到上次的服务器", |
| 467 | "Missing key": "❌ 缺少密钥", | 528 | "Missing key": "❌ 缺少密钥", |
| 468 | "Key saved": "密钥已保存", | 529 | "Key saved": "密钥已保存", |
| @@ -484,6 +545,14 @@ | |||
| 484 | "Restore current template": "还原当前模板", | 545 | "Restore current template": "还原当前模板", |
| 485 | "Delete the template": "删除模板", | 546 | "Delete the template": "删除模板", |
| 486 | "Story String": "故事字符串", | 547 | "Story String": "故事字符串", |
| 548 | "Position:": "位置:", | ||
| 549 | "Default (top of context)": "默认(上下文顶部)", | ||
| 550 | "In-chat @ Depth": "聊天的特定深度", | ||
| 551 | "Depth:": "深度:", | ||
| 552 | "Role:": "身份:", | ||
| 553 | "System": "系统", | ||
| 554 | "User": "用户", | ||
| 555 | "Assistant": "助手", | ||
| 487 | "Example Separator": "示例分隔符", | 556 | "Example Separator": "示例分隔符", |
| 488 | "Chat Start": "聊天开始", | 557 | "Chat Start": "聊天开始", |
| 489 | "Context Formatting": "上下文格式", | 558 | "Context Formatting": "上下文格式", |
| @@ -497,7 +566,6 @@ | |||
| 497 | "Separators as Stop Strings": "分隔符作为终止字符串", | 566 | "Separators as Stop Strings": "分隔符作为终止字符串", |
| 498 | "Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。", | 567 | "Add Character and User names to a list of stopping strings.": "将角色和用户名添加到停止字符串列表中。", |
| 499 | "Names as Stop Strings": "名称作为终止字符串", | 568 | "Names as Stop Strings": "名称作为终止字符串", |
| 500 | "context_allow_post_history_instructions": "如果在角色卡中定义并且启用了“首选角色卡说明”,则在提示末尾包含后历史说明。\n不建议在文本补全模型中使用此功能,否则会导致输出错误。", | ||
| 501 | "Instruct Template": "指导模板", | 569 | "Instruct Template": "指导模板", |
| 502 | "instruct_derived": "如果可能,从模型元数据中获取", | 570 | "instruct_derived": "如果可能,从模型元数据中获取", |
| 503 | "instruct_bind_to_context": "如果启用,上下文模板将根据所选的指导模板名称或偏好自动选择。", | 571 | "instruct_bind_to_context": "如果启用,上下文模板将根据所选的指导模板名称或偏好自动选择。", |
| @@ -508,12 +576,19 @@ | |||
| 508 | "instruct_template_activation_regex_desc": "当连接到API或选择模型时,若模型名称与给定的正则表达式匹配,自动启用此指导模板。", | 576 | "instruct_template_activation_regex_desc": "当连接到API或选择模型时,若模型名称与给定的正则表达式匹配,自动启用此指导模板。", |
| 509 | "Wrap Sequences with Newline": "用换行符包裹序列", | 577 | "Wrap Sequences with Newline": "用换行符包裹序列", |
| 510 | "Replace Macro in Sequences": "替换序列中的宏", | 578 | "Replace Macro in Sequences": "替换序列中的宏", |
| 579 | "Sequences as Stop Strings": "将序列用作终止字符串", | ||
| 511 | "Skip Example Dialogues Formatting": "跳过示例对话格式化", | 580 | "Skip Example Dialogues Formatting": "跳过示例对话格式化", |
| 512 | "Include Names": "包括名称", | 581 | "Include Names": "包括名称", |
| 513 | "Never": "永不", | 582 | "Never": "永不", |
| 514 | "Groups and Past Personas": "群聊和过去的用户角色", | 583 | "Groups and Past Personas": "群聊和过去的用户设定", |
| 515 | "Always": "永远", | 584 | "Always": "永远", |
| 516 | "Instruct Sequences": "指令序列", | 585 | "Instruct Sequences": "指令序列", |
| 586 | "Story String Sequences": "故事字符串序列", | ||
| 587 | "Used in Default position only.": "仅在默认位置使用。", | ||
| 588 | "Inserted before a Story String.": "插入在故事字符串之前。", | ||
| 589 | "Story String Prefix": "故事字符串前缀", | ||
| 590 | "Inserted after a Story String.": "插入在故事字符串之后。", | ||
| 591 | "Story String Suffix": "故事字符串后缀", | ||
| 517 | "User Message Sequences": "用户消息序列", | 592 | "User Message Sequences": "用户消息序列", |
| 518 | "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。", | 593 | "Inserted before a User message and as a last prompt line when impersonating.": "插入到用户消息之前并作为模拟时的最后一行提示词。", |
| 519 | "User Prefix": "用户消息前缀", | 594 | "User Prefix": "用户消息前缀", |
| @@ -531,11 +606,6 @@ | |||
| 531 | "System Suffix": "系统消息后缀", | 606 | "System Suffix": "系统消息后缀", |
| 532 | "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。", | 607 | "If enabled, System Sequences will be the same as User Sequences.": "如果启用,系统序列将与用户序列相同。", |
| 533 | "System same as User": "系统与用户相同", | 608 | "System same as User": "系统与用户相同", |
| 534 | "System Prompt Sequences": "系统提示词序列", | ||
| 535 | "Inserted before a System prompt.": "插入到系统提示词之前。", | ||
| 536 | "System Prompt Prefix": "系统提示词前缀", | ||
| 537 | "Inserted after a System prompt.": "在系统提示词后插入。", | ||
| 538 | "System Prompt Suffix": "系统提示词后缀", | ||
| 539 | "Misc. Sequences": "杂项序列", | 609 | "Misc. Sequences": "杂项序列", |
| 540 | "Inserted before the first Assistant's message.": "插入到第一个助理的消息之前。", | 610 | "Inserted before the first Assistant's message.": "插入到第一个助理的消息之前。", |
| 541 | "First Assistant Prefix": "第一个助理前缀", | 611 | "First Assistant Prefix": "第一个助理前缀", |
| @@ -565,7 +635,7 @@ | |||
| 565 | "Replace Macro in Stop Strings": "替换自定义停止字符串中的宏", | 635 | "Replace Macro in Stop Strings": "替换自定义停止字符串中的宏", |
| 566 | "Token Padding": "词符填充", | 636 | "Token Padding": "词符填充", |
| 567 | "Reasoning": "推理", | 637 | "Reasoning": "推理", |
| 568 | "reasoning_auto_parse": "Automatically parse reasoning blocks from main content between the reasoning prefix/suffix. Both fields must be defined and non-empty.", | 638 | "reasoning_auto_parse": "自动从消息内容中提取由推理块前后缀包裹的推理块。前后缀都必须设置且不为空。", |
| 569 | "Auto-Parse": "自动解析", | 639 | "Auto-Parse": "自动解析", |
| 570 | "reasoning_auto_expand": "自动展开推理内容块。", | 640 | "reasoning_auto_expand": "自动展开推理内容块。", |
| 571 | "Auto-Expand": "自动展开", | 641 | "Auto-Expand": "自动展开", |
| @@ -573,9 +643,10 @@ | |||
| 573 | "Show Hidden": "显示隐藏内容", | 643 | "Show Hidden": "显示隐藏内容", |
| 574 | "reasoning_add_to_prompts": "将已有的推理块添加到提示词。若需新增一个推理块,请使用消息编辑菜单。", | 644 | "reasoning_add_to_prompts": "将已有的推理块添加到提示词。若需新增一个推理块,请使用消息编辑菜单。", |
| 575 | "Add to Prompts": "添加到提示词", | 645 | "Add to Prompts": "添加到提示词", |
| 576 | "reasoning_max_additions": "Maximum number of reasoning blocks to be added per prompt, counting from the last message.", | 646 | "reasoning_max_additions": "从最后一条消息开始,最多有多少个思维链可以被加入提示词。", |
| 577 | "Max": "最大值", | 647 | "Max": "最大值", |
| 578 | "Reasoning Formatting": "推理内容格式化", | 648 | "Reasoning Formatting": "推理内容格式化", |
| 649 | "Select your current Reasoning Template": "选择你当前的推理模板", | ||
| 579 | "reasoning_prefix": "插入在推理内容之前。", | 650 | "reasoning_prefix": "插入在推理内容之前。", |
| 580 | "Prefix": "前缀", | 651 | "Prefix": "前缀", |
| 581 | "reasoning_suffix": "插入在推理内容之后。", | 652 | "reasoning_suffix": "插入在推理内容之后。", |
| @@ -583,6 +654,8 @@ | |||
| 583 | "reasoning_separator": "插入在推理内容和消息内容之间。", | 654 | "reasoning_separator": "插入在推理内容和消息内容之间。", |
| 584 | "Separator": "分隔符", | 655 | "Separator": "分隔符", |
| 585 | "Miscellaneous": "杂项", | 656 | "Miscellaneous": "杂项", |
| 657 | "Bind Model to Templates": "将模型与模板绑定", | ||
| 658 | "bind_model_templates_desc": "当连接到一个API或选择一个模型,且它们的名字与当前的指导和上下文模板名字匹配时,自动激活当前的指导和上下文模板。", | ||
| 586 | "Non-markdown strings": "非 Markdown 字符串", | 659 | "Non-markdown strings": "非 Markdown 字符串", |
| 587 | "comma delimited,no spaces between": "以逗号分隔,无需空格", | 660 | "comma delimited,no spaces between": "以逗号分隔,无需空格", |
| 588 | "Start Reply With": "以...开始回复", | 661 | "Start Reply With": "以...开始回复", |
| @@ -623,20 +696,20 @@ | |||
| 623 | "Alert On Overflow": "溢出警报", | 696 | "Alert On Overflow": "溢出警报", |
| 624 | "or": "或", | 697 | "or": "或", |
| 625 | "--- Pick to Edit ---": "--- 选择以编辑 ---", | 698 | "--- Pick to Edit ---": "--- 选择以编辑 ---", |
| 699 | "Import World Info": "导入世界书", | ||
| 700 | "Export World Info": "导出世界书", | ||
| 626 | "Rename World Info": "重命名世界书", | 701 | "Rename World Info": "重命名世界书", |
| 702 | "Duplicate World Info": "复制世界书", | ||
| 703 | "Delete World Info": "删除世界书", | ||
| 704 | "New Entry": "新条目", | ||
| 627 | "Open all Entries": "打开所有条目", | 705 | "Open all Entries": "打开所有条目", |
| 628 | "Close all Entries": "关闭所有条目", | 706 | "Close all Entries": "关闭所有条目", |
| 629 | "New Entry": "新条目", | ||
| 630 | "Fill empty Memo/Titles with Keywords": "使用关键字填充空的备忘录/标题", | 707 | "Fill empty Memo/Titles with Keywords": "使用关键字填充空的备忘录/标题", |
| 631 | "Apply current sorting as Order": "应用当前排序作为顺序", | 708 | "Apply current sorting as Order": "应用当前排序作为顺序", |
| 632 | "Import World Info": "导入世界书", | ||
| 633 | "Export World Info": "导出世界书", | ||
| 634 | "Duplicate World Info": "复制世界书", | ||
| 635 | "Delete World Info": "删除世界书", | ||
| 636 | "Priority": "优先级", | 709 | "Priority": "优先级", |
| 637 | "Custom": "自定义", | 710 | "Custom": "自定义", |
| 638 | "Title A-Z": "标题 A-Z", | 711 | "Title A-Z": "标题 A 到 Z", |
| 639 | "Title Z-A": "标题 Z-A", | 712 | "Title Z-A": "标题 Z 到 A", |
| 640 | "Tokens ↗": "词符 ↗", | 713 | "Tokens ↗": "词符 ↗", |
| 641 | "Tokens ↘": "词符 ↘", | 714 | "Tokens ↘": "词符 ↘", |
| 642 | "Depth ↗": "深度 ↗", | 715 | "Depth ↗": "深度 ↗", |
| @@ -663,11 +736,19 @@ | |||
| 663 | "Avatar Style:": "头像样式:", | 736 | "Avatar Style:": "头像样式:", |
| 664 | "Circle": "圆形", | 737 | "Circle": "圆形", |
| 665 | "Square": "正方形", | 738 | "Square": "正方形", |
| 739 | "Rounded": "圆角", | ||
| 666 | "Rectangle": "矩形", | 740 | "Rectangle": "矩形", |
| 667 | "Chat Style:": "聊天风格:", | 741 | "Chat Style:": "聊天风格:", |
| 668 | "Flat": "扁平", | 742 | "Flat": "扁平", |
| 669 | "Bubbles": "气泡", | 743 | "Bubbles": "气泡", |
| 670 | "Document": "文档", | 744 | "Document": "文档", |
| 745 | "Notifications:": "通知:", | ||
| 746 | "Top Left": "左上", | ||
| 747 | "Top Center": "顶部居中", | ||
| 748 | "Top Right": "右上", | ||
| 749 | "Bottom Left": "左下", | ||
| 750 | "Bottom Center": "底部居中", | ||
| 751 | "Bottom Right": "右下", | ||
| 671 | "Specify colors for your theme.": "指定您的主题的颜色。", | 752 | "Specify colors for your theme.": "指定您的主题的颜色。", |
| 672 | "Theme Colors": "主题颜色", | 753 | "Theme Colors": "主题颜色", |
| 673 | "Main Text": "主要文本", | 754 | "Main Text": "主要文本", |
| @@ -726,6 +807,8 @@ | |||
| 726 | "Show tagged character folders in the character list": "在角色列表中显示已标记的角色文件夹", | 807 | "Show tagged character folders in the character list": "在角色列表中显示已标记的角色文件夹", |
| 727 | "Tags as Folders": "标签作为文件夹", | 808 | "Tags as Folders": "标签作为文件夹", |
| 728 | "Tags_as_Folders_desc": "最近更改:标签必须在标签管理菜单中标记为文件夹才能显示。单击此处将其调出。", | 809 | "Tags_as_Folders_desc": "最近更改:标签必须在标签管理菜单中标记为文件夹才能显示。单击此处将其调出。", |
| 810 | "Click the message text in the chat log to edit it.": "单机聊天记录中的消息就可以直接编辑。", | ||
| 811 | "Click to Edit": "单击编辑消息", | ||
| 729 | "Character Handling": "角色处理", | 812 | "Character Handling": "角色处理", |
| 730 | "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在高级角色定义中设置,此字段将显示在角色列表中。", | 813 | "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在高级角色定义中设置,此字段将显示在角色列表中。", |
| 731 | "Char List Subheader": "角色列表子标题", | 814 | "Char List Subheader": "角色列表子标题", |
| @@ -745,6 +828,8 @@ | |||
| 745 | "Prefer Character Card Instructions": "首选角色卡说明", | 828 | "Prefer Character Card Instructions": "首选角色卡说明", |
| 746 | "never_resize_avatars_tooltip": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。", | 829 | "never_resize_avatars_tooltip": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。", |
| 747 | "Never resize avatars": "永不调整头像大小", | 830 | "Never resize avatars": "永不调整头像大小", |
| 831 | "Allow animations for WEBP backgrounds. This is only a change for the selection menu.": "允许WEBP格式的背景动画。此更改仅对选择菜单生效", | ||
| 832 | "Animated background thumbnails": "背景缩略图动画", | ||
| 748 | "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。", | 833 | "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。", |
| 749 | "Show avatar filenames": "显示头像文件名", | 834 | "Show avatar filenames": "显示头像文件名", |
| 750 | "Hide character definitions from the editor panel behind a spoiler button": "在编辑器面板中,将角色定义隐藏在一个剧透按钮后面。", | 835 | "Hide character definitions from the editor panel behind a spoiler button": "在编辑器面板中,将角色定义隐藏在一个剧透按钮后面。", |
| @@ -752,6 +837,8 @@ | |||
| 752 | "Reload and redraw the currently open chat": "重新加载并重新渲染当前打开的聊天", | 837 | "Reload and redraw the currently open chat": "重新加载并重新渲染当前打开的聊天", |
| 753 | "Reload Chat": "重新加载聊天", | 838 | "Reload Chat": "重新加载聊天", |
| 754 | "Debug Menu": "调试菜单", | 839 | "Debug Menu": "调试菜单", |
| 840 | "Find and delete backups, unused chats, files, images, etc.": "寻找和删除备份、未使用的聊天、文件、图片等。", | ||
| 841 | "Clean-Up": "清理", | ||
| 755 | "Smooth Streaming": "平滑流式传输", | 842 | "Smooth Streaming": "平滑流式传输", |
| 756 | "Experimental feature. May not work for all backends.": "实验性功能。可能不适用于所有后端。", | 843 | "Experimental feature. May not work for all backends.": "实验性功能。可能不适用于所有后端。", |
| 757 | "Slow": "慢", | 844 | "Slow": "慢", |
| @@ -821,6 +908,8 @@ | |||
| 821 | "Request token probabilities": "请求词符概率", | 908 | "Request token probabilities": "请求词符概率", |
| 822 | "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群聊中,突出显示当前排队等待生成响应的角色以及他们响应的顺序。", | 909 | "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群聊中,突出显示当前排队等待生成响应的角色以及他们响应的顺序。", |
| 823 | "Show group chat queue": "显示群聊队列", | 910 | "Show group chat queue": "显示群聊队列", |
| 911 | "Always render style tags from greetings, even if the message is unloaded due to lazy loading.": "始终渲染问候消息里的样式标签,即便消息因懒加载策略还未被加载。", | ||
| 912 | "Pin greeting message styles": "固定问候消息样式", | ||
| 824 | "Automatically reject and re-generate AI message based on configurable criteria": "根据可配置的条件自动拒绝并重新生成AI消息", | 913 | "Automatically reject and re-generate AI message based on configurable criteria": "根据可配置的条件自动拒绝并重新生成AI消息", |
| 825 | "Auto-swipe": "自动滑动", | 914 | "Auto-swipe": "自动滑动", |
| 826 | "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效", | 915 | "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效", |
| @@ -835,6 +924,10 @@ | |||
| 835 | "Allow for Chat Completion APIs": "允许使用聊天补全API", | 924 | "Allow for Chat Completion APIs": "允许使用聊天补全API", |
| 836 | "Target length (tokens)": "目标长度(以词符数计)", | 925 | "Target length (tokens)": "目标长度(以词符数计)", |
| 837 | "AutoComplete Settings": "自动补全设置", | 926 | "AutoComplete Settings": "自动补全设置", |
| 927 | "Visibility": "可见性", | ||
| 928 | "Don't show": "不显示", | ||
| 929 | "Input length > 1": "输入长度 > 1", | ||
| 930 | "Always show": "始终显示", | ||
| 838 | "Automatically hide details": "自动隐藏详细信息", | 931 | "Automatically hide details": "自动隐藏详细信息", |
| 839 | "Determines how entries are found for autocomplete.": "确定如何找到自动补全的条目。", | 932 | "Determines how entries are found for autocomplete.": "确定如何找到自动补全的条目。", |
| 840 | "Autocomplete Matching": "匹配", | 933 | "Autocomplete Matching": "匹配", |
| @@ -863,8 +956,7 @@ | |||
| 863 | "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} {{getglobalvar::}} 宏具有自动评估的文字宏类值。\n例如,“{{newline}}”保留为文字字符串“{{newline}}”\n\n(这是通过在内部用范围变量替换 {{getvar::}} {{getglobalvar::}} 宏来实现的。)", | 956 | "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} {{getglobalvar::}} 宏具有自动评估的文字宏类值。\n例如,“{{newline}}”保留为文字字符串“{{newline}}”\n\n(这是通过在内部用范围变量替换 {{getvar::}} {{getglobalvar::}} 宏来实现的。)", |
| 864 | "REPLACE_GETVAR": "替换GETVAR", | 957 | "REPLACE_GETVAR": "替换GETVAR", |
| 865 | "Change Background Image": "更改背景图片", | 958 | "Change Background Image": "更改背景图片", |
| 866 | "Background Image": "背景图片", | 959 | "Backgrounds": "背景", |
| 867 | "Filter": "搜索", | ||
| 868 | "Background Fitting": "背景图片尺寸", | 960 | "Background Fitting": "背景图片尺寸", |
| 869 | "Classic": "经典", | 961 | "Classic": "经典", |
| 870 | "Cover": "填充", | 962 | "Cover": "填充", |
| @@ -873,6 +965,7 @@ | |||
| 873 | "Center": "居中", | 965 | "Center": "居中", |
| 874 | "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景", | 966 | "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景", |
| 875 | "Auto-select": "自动选择", | 967 | "Auto-select": "自动选择", |
| 968 | "Add Background": "添加背景", | ||
| 876 | "System Backgrounds": "系统背景", | 969 | "System Backgrounds": "系统背景", |
| 877 | "Chat Backgrounds": "聊天背景", | 970 | "Chat Backgrounds": "聊天背景", |
| 878 | "bg_chat_hint_1": "使用生成的聊天背景", | 971 | "bg_chat_hint_1": "使用生成的聊天背景", |
| @@ -880,43 +973,50 @@ | |||
| 880 | "Extensions": "扩展", | 973 | "Extensions": "扩展", |
| 881 | "Notify on extension updates": "在扩展更新时通知", | 974 | "Notify on extension updates": "在扩展更新时通知", |
| 882 | "Manage extensions": "管理扩展", | 975 | "Manage extensions": "管理扩展", |
| 883 | "Import Extension From Git Repo": "从Git存储库导入扩展", | 976 | "Import Extension From Git Repo": "从 Git 仓库导入扩展", |
| 884 | "Install extension": "安装扩展", | 977 | "Install extension": "安装扩展", |
| 978 | "(DEPRECATED)": "(已弃用)", | ||
| 885 | "Extras API:": "扩展API:", | 979 | "Extras API:": "扩展API:", |
| 886 | "Auto-connect": "自动连接", | 980 | "Auto-connect": "自动连接", |
| 887 | "Extras API URL": "附加 API URL", | 981 | "Extras API URL": "附加 API URL", |
| 888 | "Extras API key (optional)": "扩展API密钥(可选)", | 982 | "Extras API key (optional)": "扩展API密钥(可选)", |
| 889 | "Persona Management": "用户角色管理", | 983 | "Persona Management": "用户设定管理", |
| 890 | "Click for stats!": "点击查看统计!", | 984 | "Click for stats!": "点击即可查看统计~", |
| 891 | "Usage Stats": "使用统计", | 985 | "Usage Stats": "使用统计", |
| 892 | "Backup your personas to a file": "将用户角色备份到文件中", | 986 | "Backup your personas to a file": "将用户设定备份到文件中", |
| 893 | "Backup": "备份", | 987 | "Backup": "备份", |
| 894 | "Restore your personas from a file": "从文件中恢复用户角色", | 988 | "Restore your personas from a file": "从文件中恢复用户设定", |
| 895 | "Restore": "恢复", | 989 | "Restore": "恢复", |
| 896 | "Create a dummy persona": "创建空白用户角色", | 990 | "Create a dummy persona": "创建空白用户设定", |
| 897 | "Create": "创建", | 991 | "Create": "创建", |
| 898 | "No persona description": "[没有描述]", | 992 | "No persona description": "[没有人设描述]", |
| 899 | "Name": "名称", | 993 | "Current Persona": "当前人设", |
| 900 | "Enter your name": "输入您的名字", | 994 | "Rename Persona": "重命名人设", |
| 901 | "Click to set a new User Name": "点击设置新的用户名", | ||
| 902 | "Click to lock your selected persona to the current chat. Click again to remove the lock.": "单击以将您选择的用户角色锁定到当前聊天。再次单击以移除锁定。", | ||
| 903 | "Click to set user name for all messages": "点击为所有消息设置用户名", | 995 | "Click to set user name for all messages": "点击为所有消息设置用户名", |
| 904 | "Persona Lore Alt+Click to open the lorebook": "Persona Lore\nAlt+Click to open the lorebook", | 996 | "Persona Lore Alt+Click to open the lorebook": "Persona Lore\nAlt+Click to open the lorebook", |
| 905 | "Persona Description": "用户角色描述", | 997 | "Change Persona Image": "更改人设图", |
| 998 | "Duplicate Persona": "复制人设", | ||
| 999 | "Delete Persona": "删除人设", | ||
| 1000 | "Persona Description": "用户设定描述", | ||
| 906 | "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "示例:[{{user}}是一个28岁的罗马尼亚猫娘。]", | 1001 | "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "示例:[{{user}}是一个28岁的罗马尼亚猫娘。]", |
| 907 | "Tokens persona description": "用户角色描述词符数", | 1002 | "Position": "插入位置", |
| 908 | "Position:": "位置:", | 1003 | "Tokens persona description": "人设词符数", |
| 909 | "None (disabled)": "无(已禁用)", | 1004 | "None (disabled)": "无(已禁用)", |
| 910 | "In Story String / Prompt Manager": "在故事字符串/提示词管理器中", | 1005 | "In Story String / Prompt Manager": "在故事字符串/提示词管理器中", |
| 911 | "Top of Author's Note": "作者注的顶部", | 1006 | "Top of Author's Note": "作者注的顶部", |
| 912 | "Bottom of Author's Note": "作者注的底部", | 1007 | "Bottom of Author's Note": "作者注的底部", |
| 913 | "In-chat @ Depth": "聊天的特定深度", | 1008 | "Connections": "链接", |
| 914 | "Depth:": "深度:", | 1009 | "Click to select this as default persona for the new chats. Click again to remove it.": "点击将此人设设置为新聊天的默认人设。再次点击以移除。", |
| 915 | "Role:": "身份:", | 1010 | "Click to lock your selected persona to the current character. Click again to remove the lock.": "点击将选择的用户设定与当前角色绑定。再次点击以解绑。", |
| 916 | "System": "系统", | 1011 | "Character": "角色", |
| 917 | "User": "用户", | 1012 | "Click to lock your selected persona to the current chat. Click again to remove the lock.": "点击将选择的人设与当前聊天绑定。再次点击以解绑。", |
| 918 | "Assistant": "助手", | 1013 | "Chat": "聊天", |
| 919 | "Show notifications on switching personas": "切换用户角色时显示通知", | 1014 | "Global Settings": "全局设置", |
| 1015 | "Show notifications on switching personas": "切换用户设定时显示通知", | ||
| 1016 | "When multiple personas are connected to a character, a popup will appear to select which one to use": "当多个用户设定与一个角色绑定时,会弹出一个弹窗让用户选择使用哪一个。", | ||
| 1017 | "Allow multiple persona connections per character": "允许每个角色与多个用户设定绑定", | ||
| 1018 | "Whenever a persona is selected, it will be locked to the current chat and automatically selected when the chat is opened.": "当一个用户设定被选择,它会被自动绑定到当前聊天,并在此聊天后续打开时被自动选中。", | ||
| 1019 | "Auto-lock a chosen persona to the chat": "自动将选择的用户设定绑定到聊天", | ||
| 920 | "Character Management": "角色管理", | 1020 | "Character Management": "角色管理", |
| 921 | "Locked = Character Management panel will stay open": "锁定 = 角色管理面板将保持打开状态", | 1021 | "Locked = Character Management panel will stay open": "锁定 = 角色管理面板将保持打开状态", |
| 922 | "Select/Create Characters": "选择/创建角色", | 1022 | "Select/Create Characters": "选择/创建角色", |
| @@ -934,8 +1034,9 @@ | |||
| 934 | "Click to select a new avatar for this character": "单击以为此角色选择新的头像", | 1034 | "Click to select a new avatar for this character": "单击以为此角色选择新的头像", |
| 935 | "Add to Favorites": "添加到收藏夹", | 1035 | "Add to Favorites": "添加到收藏夹", |
| 936 | "Advanced Definition": "高级定义", | 1036 | "Advanced Definition": "高级定义", |
| 937 | "world_button_title": "Character Lore\n\nClick to load\nShift-click to open 'Link to World Info' popup", | 1037 | "world_button_title": "角色世界书\n\n单击加载\nShift+单击打开“链接到世界信息”弹出窗口", |
| 938 | "Chat Lore Alt+Click to open the lorebook": "Chat Lore\nAlt+Click to open the lorebook", | 1038 | "Chat Lore Alt+Click to open the lorebook": "聊天世界书\nAlt+单击打开世界书", |
| 1039 | "Connected Personas": "绑定的用户设定", | ||
| 939 | "Export and Download": "导出并下载", | 1040 | "Export and Download": "导出并下载", |
| 940 | "Duplicate Character": "复制角色", | 1041 | "Duplicate Character": "复制角色", |
| 941 | "Create Character": "创建角色", | 1042 | "Create Character": "创建角色", |
| @@ -949,11 +1050,14 @@ | |||
| 949 | "Link to Source": "来源链接", | 1050 | "Link to Source": "来源链接", |
| 950 | "Replace / Update": "替换 / 更新", | 1051 | "Replace / Update": "替换 / 更新", |
| 951 | "Import Tags": "导入标签", | 1052 | "Import Tags": "导入标签", |
| 1053 | "Set / Unset as Welcome Page Assistant": "设置 / 取消 为欢迎页面助理", | ||
| 952 | "Search / Create Tags": "搜索/创建标签", | 1054 | "Search / Create Tags": "搜索/创建标签", |
| 953 | "View all tags": "查看所有标签", | 1055 | "View all tags": "查看所有标签", |
| 954 | "Creator's Notes": "创作者的注释", | 1056 | "Creator's Notes": "创作者的注释", |
| 955 | "Character details are hidden.": "角色详情已隐藏。", | 1057 | "Allow / Forbid the use of global styles for this character.": "允许 / 禁止 该角色使用全局样式。", |
| 956 | "Show / Hide Description and First Message": "显示/隐藏描述和第一条消息", | 1058 | "Show / Hide Description and First Message": "显示/隐藏描述和第一条消息", |
| 1059 | "No Creator's Notes provided.": "无创作者注释", | ||
| 1060 | "Character details are hidden.": "角色详情已隐藏。", | ||
| 957 | "Character Description": "角色描述", | 1061 | "Character Description": "角色描述", |
| 958 | "Click to allow/forbid the use of external media for this character.": "单击以允许/禁止此角色使用外部媒体。", | 1062 | "Click to allow/forbid the use of external media for this character.": "单击以允许/禁止此角色使用外部媒体。", |
| 959 | "Ext. Media": "扩展媒体", | 1063 | "Ext. Media": "扩展媒体", |
| @@ -970,6 +1074,7 @@ | |||
| 970 | "Manual": "手动", | 1074 | "Manual": "手动", |
| 971 | "Natural order": "自然顺序", | 1075 | "Natural order": "自然顺序", |
| 972 | "List order": "从上到下", | 1076 | "List order": "从上到下", |
| 1077 | "Pooled order": "随机轮流顺序", | ||
| 973 | "Group generation handling mode": "群组生成处理模式", | 1078 | "Group generation handling mode": "群组生成处理模式", |
| 974 | "Swap character cards": "交换角色卡", | 1079 | "Swap character cards": "交换角色卡", |
| 975 | "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)", | 1080 | "Join character cards (exclude muted)": "加入角色卡(不包括被禁言的)", |
| @@ -987,7 +1092,9 @@ | |||
| 987 | "Auto Mode delay": "自动模式延迟", | 1092 | "Auto Mode delay": "自动模式延迟", |
| 988 | "Hide Muted Member Sprites": "隐藏拼贴头像中被禁言的成员", | 1093 | "Hide Muted Member Sprites": "隐藏拼贴头像中被禁言的成员", |
| 989 | "Current Members": "当前成员", | 1094 | "Current Members": "当前成员", |
| 1095 | "Group is empty.": "暂无成员", | ||
| 990 | "Add Members": "添加成员", | 1096 | "Add Members": "添加成员", |
| 1097 | "No characters available": "无可用角色", | ||
| 991 | "Create New Character": "新建角色", | 1098 | "Create New Character": "新建角色", |
| 992 | "Import Character from File": "从文件导入角色", | 1099 | "Import Character from File": "从文件导入角色", |
| 993 | "Import content from external URL": "从外部URL导入内容", | 1100 | "Import content from external URL": "从外部URL导入内容", |
| @@ -1004,15 +1111,13 @@ | |||
| 1004 | "Most tokens": "最多词符", | 1111 | "Most tokens": "最多词符", |
| 1005 | "Least tokens": "最少词符", | 1112 | "Least tokens": "最少词符", |
| 1006 | "Random": "随机", | 1113 | "Random": "随机", |
| 1114 | "Toggle search bar": "切换搜索栏", | ||
| 1007 | "Toggle character grid view": "切换角色网格视图", | 1115 | "Toggle character grid view": "切换角色网格视图", |
| 1008 | "Bulk_edit_characters": "批量编辑角色", | 1116 | "Bulk_edit_characters": "批量编辑角色", |
| 1009 | "Bulk select all characters": "批量选择所有角色", | 1117 | "Bulk select all characters": "批量选择所有角色", |
| 1010 | "Bulk delete characters": "批量删除角色", | 1118 | "Bulk delete characters": "批量删除角色", |
| 1011 | "Bind user name to that avatar": "将用户名称绑定到该头像", | 1119 | "Persona is locked to the current chat": "用户设定已被绑定到当前聊天", |
| 1012 | "Change persona image": "更改用户角色头像", | 1120 | "Persona is locked to the current character": "用户设定已被绑定到当前角色", |
| 1013 | "Select this as default persona for the new chats.": "选择此项作为新聊天的默认用户角色。", | ||
| 1014 | "Duplicate persona": "复制用户角色", | ||
| 1015 | "Delete persona": "删除用户角色", | ||
| 1016 | "popup-button-save": "保存", | 1121 | "popup-button-save": "保存", |
| 1017 | "popup-button-yes": "是", | 1122 | "popup-button-yes": "是", |
| 1018 | "popup-button-no": "否", | 1123 | "popup-button-no": "否", |
| @@ -1058,10 +1163,10 @@ | |||
| 1058 | "Chat History": "聊天记录", | 1163 | "Chat History": "聊天记录", |
| 1059 | "Import Chat": "导入聊天", | 1164 | "Import Chat": "导入聊天", |
| 1060 | "Copy to system backgrounds": "复制到系统背景", | 1165 | "Copy to system backgrounds": "复制到系统背景", |
| 1061 | "Rename background": "重命名背景", | ||
| 1062 | "Lock": "锁定", | 1166 | "Lock": "锁定", |
| 1063 | "Unlock": "解锁", | 1167 | "Unlock": "解锁", |
| 1064 | "Delete background": "删除背景", | 1168 | "Rename Background": "重命名背景", |
| 1169 | "Delete Background": "删除背景", | ||
| 1065 | "Select a World Info file for": "选择一个世界书文件给", | 1170 | "Select a World Info file for": "选择一个世界书文件给", |
| 1066 | "Primary Lorebook": "主要知识书", | 1171 | "Primary Lorebook": "主要知识书", |
| 1067 | "A selected World Info will be bound to this character as its own Lorebook.": "所选的世界信息将会于该角色绑定,作为该角色自己的知识书", | 1172 | "A selected World Info will be bound to this character as its own Lorebook.": "所选的世界信息将会于该角色绑定,作为该角色自己的知识书", |
| @@ -1076,30 +1181,8 @@ | |||
| 1076 | "Delete chat file": "删除聊天文件", | 1181 | "Delete chat file": "删除聊天文件", |
| 1077 | "Drag to reorder tag": "拖动以排序", | 1182 | "Drag to reorder tag": "拖动以排序", |
| 1078 | "Use tag as folder": "标记为文件夹", | 1183 | "Use tag as folder": "标记为文件夹", |
| 1079 | "Hide on character card": "在角色卡上隐藏", | 1184 | "tag_entries": "标签条目", |
| 1080 | "Delete tag": "删除标签", | 1185 | "Delete tag": "删除标签", |
| 1081 | "Toggle entry's active state.": "切换条目激活状态。", | ||
| 1082 | "Entry Title/Memo": "条目标题/备忘录", | ||
| 1083 | "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界书条目状态:\r🔵 永久\r🟢 关键词\r🔗 向量化", | ||
| 1084 | "WI_Entry_Status_Constant": "永久", | ||
| 1085 | "WI_Entry_Status_Normal": "关键词", | ||
| 1086 | "WI_Entry_Status_Vectorized": "向量化", | ||
| 1087 | "T_Position": "↑Char:在角色定义之前\n↓Char:在角色定义之后\n↑AN:在作者注释之前\n↓AN:在作者注释之后\n@D:在深度D处", | ||
| 1088 | "Before Char Defs": "角色定义之前", | ||
| 1089 | "After Char Defs": "角色定义之后", | ||
| 1090 | "Before EM": "↑EM", | ||
| 1091 | "After EM": "↓EM", | ||
| 1092 | "Before AN": "作者注释之前", | ||
| 1093 | "After AN": "作者注释之后", | ||
| 1094 | "at Depth System": "@D ⚙️", | ||
| 1095 | "at Depth User": "@D 👤", | ||
| 1096 | "at Depth AI": "@D 🤖", | ||
| 1097 | "Depth": "深度", | ||
| 1098 | "Order:": "顺序:", | ||
| 1099 | "Order": "顺序", | ||
| 1100 | "Trigger %:": "触发 %:", | ||
| 1101 | "Duplicate world info entry": "重复的世界信息条目", | ||
| 1102 | "Delete world info entry": "删除世界信息条目", | ||
| 1103 | "Comma separated (required)": "逗号分隔(必填)", | 1186 | "Comma separated (required)": "逗号分隔(必填)", |
| 1104 | "Primary Keywords": "主要关键字", | 1187 | "Primary Keywords": "主要关键字", |
| 1105 | "Keywords or Regexes": "关键字或正则表达式", | 1188 | "Keywords or Regexes": "关键字或正则表达式", |
| @@ -1119,17 +1202,22 @@ | |||
| 1119 | "Use global": "使用全局", | 1202 | "Use global": "使用全局", |
| 1120 | "Yes": "是", | 1203 | "Yes": "是", |
| 1121 | "No": "否", | 1204 | "No": "否", |
| 1122 | "Whole Words": "Whole Words", | 1205 | "Whole Words": "完整单词", |
| 1123 | "Group Scoring": "Group Scoring", | 1206 | "Group Scoring": "组评分", |
| 1124 | "Can be used to automatically activate Quick Replies": "可用于自动激活快速回复", | 1207 | "Can be used to automatically activate Quick Replies": "可用于自动激活快速回复", |
| 1125 | "Automation ID": "自动化ID", | 1208 | "Automation ID": "自动化ID", |
| 1126 | "( None )": "(没有任何)", | 1209 | "( None )": "(没有任何)", |
| 1127 | "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.", | 1210 | "delay_until_recursion_level": "定义递归扫描的延迟级别。\n最初,只有第一级(最小数字)会匹配。\n一旦未找到匹配项,下一个级别将变为匹配的候选项。\n这将重复,直到检查所有级别。\n与“延迟到递归”设置相关联。", |
| 1128 | "Recursion Level": "递归等级", | 1211 | "Recursion Level": "递归等级", |
| 1129 | "Content": "内容", | 1212 | "Content": "内容", |
| 1213 | "This entry will not be recursively activated by other entries.": "此条目不会被其他条目递归激活。", | ||
| 1130 | "Non-recursable": "不可递归(不会被其他条目激活)", | 1214 | "Non-recursable": "不可递归(不会被其他条目激活)", |
| 1215 | "This entry will not activate other entries recursively.": "此条目不会被其他条目激活。", | ||
| 1131 | "Prevent further recursion": "防止进一步递归", | 1216 | "Prevent further recursion": "防止进一步递归", |
| 1217 | "This entry can only be activated on recursive checking.": "此条目只能在递归检查时被激活。", | ||
| 1132 | "Delay until recursion": "延迟到递归", | 1218 | "Delay until recursion": "延迟到递归", |
| 1219 | "This entry will be included ignoring budget constraints, assuming all other checks pass.": "只要其他检查通过,此条目将无视回复限额,直接加入提示词中", | ||
| 1220 | "Ignore budget": "无视回复限额", | ||
| 1133 | "What this keyword should mean to the AI, sent verbatim": "这个关键词对AI的含义,逐字发送", | 1221 | "What this keyword should mean to the AI, sent verbatim": "这个关键词对AI的含义,逐字发送", |
| 1134 | "Inclusion Group": "包含组", | 1222 | "Inclusion Group": "包含组", |
| 1135 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "包含组可确保每次仅激活组中的一项(如果触发了多项)。支持多个逗号分隔的组。文档:世界信息 - 包含组", | 1223 | "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "包含组可确保每次仅激活组中的一项(如果触发了多项)。支持多个逗号分隔的组。文档:世界信息 - 包含组", |
| @@ -1151,28 +1239,66 @@ | |||
| 1151 | "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外", | 1239 | "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "切换角色/标签筛选方式,将列出的角色和标签排除在匹配范围之外", |
| 1152 | "Exclude": "排除", | 1240 | "Exclude": "排除", |
| 1153 | "-- Characters not found --": "-- 未找到角色 --", | 1241 | "-- Characters not found --": "-- 未找到角色 --", |
| 1242 | "Filter to Generation Triggers": "筛选生成触发器", | ||
| 1243 | "Continue": "继续", | ||
| 1244 | "Impersonate": "AI 帮答", | ||
| 1245 | "Swipe": "滑动", | ||
| 1246 | "Regenerate": "重新生成", | ||
| 1247 | "Quiet": "静默", | ||
| 1154 | "Selective": "选择性", | 1248 | "Selective": "选择性", |
| 1155 | "Use Probability": "使用概率", | 1249 | "Use Probability": "使用概率", |
| 1156 | "Add Memo": "添加备忘录", | 1250 | "Add Memo": "添加备忘录", |
| 1251 | "Additional Matching Sources": "额外匹配来源", | ||
| 1252 | "Character Personality": "角色性格", | ||
| 1253 | "Toggle entry's active state.": "切换条目激活状态。", | ||
| 1254 | "Entry Title/Memo": "条目标题/备忘录", | ||
| 1255 | "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界书条目状态:\r🔵 永久\r🟢 关键词\r🔗 向量化", | ||
| 1256 | "WI_Entry_Status_Constant": "永久", | ||
| 1257 | "WI_Entry_Status_Normal": "关键词", | ||
| 1258 | "WI_Entry_Status_Vectorized": "向量化", | ||
| 1259 | "T_Position": "↑Char:在角色定义之前\n↓Char:在角色定义之后\n↑AN:在作者注释之前\n↓AN:在作者注释之后\n@D:在深度D处", | ||
| 1260 | "Before Char Defs": "角色定义之前", | ||
| 1261 | "After Char Defs": "角色定义之后", | ||
| 1262 | "Before EM": "示例消息前(↑EM)", | ||
| 1263 | "After EM": "示例消息后(↓EM)", | ||
| 1264 | "Before AN": "作者注释之前", | ||
| 1265 | "After AN": "作者注释之后", | ||
| 1266 | "at Depth System": "@D ⚙ [系统]在深度️", | ||
| 1267 | "at Depth User": "@D 👤 [用户]在深度", | ||
| 1268 | "at Depth AI": "@D 🤖 [AI]在深度", | ||
| 1269 | "Depth": "深度", | ||
| 1270 | "Order:": "顺序:", | ||
| 1271 | "Order": "顺序", | ||
| 1272 | "Trigger %:": "触发 %:", | ||
| 1273 | "Move/Copy Entry to Another Lorebook": "移动或复制条目到其他世界书", | ||
| 1274 | "Duplicate world info entry": "重复的世界信息条目", | ||
| 1275 | "Delete world info entry": "删除世界信息条目", | ||
| 1276 | "This character will be used as a welcome page assistant.": "此角色将作为欢迎页面助理。", | ||
| 1157 | "Text or token ids": "文本或 [token ID]", | 1277 | "Text or token ids": "文本或 [token ID]", |
| 1158 | "Type here...": "在此处输入...", | 1278 | "Type here...": "在此处输入...", |
| 1159 | "close": "关闭", | 1279 | "close": "关闭", |
| 1160 | "prompt_manager_edit": "编辑", | 1280 | "prompt_manager_edit": "编辑", |
| 1161 | "prompt_manager_name": "姓名", | 1281 | "prompt_manager_name": "姓名", |
| 1162 | "A name for this prompt.": "此提示词的名称。", | 1282 | "A name for this prompt.": "此提示词的名称。", |
| 1163 | "To whom this message will be attributed.": "此消息应归于谁。", | ||
| 1164 | "AI Assistant": "AI助手", | 1283 | "AI Assistant": "AI助手", |
| 1284 | "To whom this message will be attributed.": "此消息应归于谁。", | ||
| 1285 | "Triggers": "触发器", | ||
| 1286 | "Filter to specific generation types.": "筛选到特定的生成类型。", | ||
| 1165 | "prompt_manager_position": "位置", | 1287 | "prompt_manager_position": "位置", |
| 1166 | "Relative (to other prompts in prompt manager) or In-chat @ Depth.": "相对(相对于提示管理器中的其他提示)或在聊天中@深度。", | ||
| 1167 | "prompt_manager_relative": "相对", | 1288 | "prompt_manager_relative": "相对", |
| 1168 | "prompt_manager_in_chat": "聊天中", | 1289 | "prompt_manager_in_chat": "聊天中", |
| 1290 | "Relative (to other prompts in prompt manager) or In-chat @ Depth.": "相对(相对于提示管理器中的其他提示)或在聊天中@深度。", | ||
| 1169 | "prompt_manager_depth": "深度", | 1291 | "prompt_manager_depth": "深度", |
| 1170 | "0 = after the last message, 1 = before the last message, etc.": "“0”为在最后一条消息之后,“1”为在最后一条消息之前,等等。", | 1292 | "0 = after the last message, 1 = before the last message, etc.": "“0”为在最后一条消息之后,“1”为在最后一条消息之前,等等。", |
| 1293 | "prompt_manager_order": "排序", | ||
| 1294 | "prompt_manager_order_note": "来自其他来源(世界信息、作者注释等)的提示注入的默认顺序为 100。", | ||
| 1295 | "Ordered from low/top to high/bottom, and at same order: Assistant, User, System.": "从低/顶到高/底排序,并按相同顺序:助手、用户、系统。", | ||
| 1171 | "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示词的内容是从其他地方提取的,无法在此处进行编辑。", | 1296 | "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示词的内容是从其他地方提取的,无法在此处进行编辑。", |
| 1172 | "Prompt": "提示词", | 1297 | "Prompt": "提示词", |
| 1173 | "The prompt to be sent.": "要发送的提示词。", | ||
| 1174 | "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。", | 1298 | "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使选择覆盖,此提示词也不能被角色卡覆盖。", |
| 1175 | "prompt_manager_forbid_overrides": "禁止覆盖", | 1299 | "prompt_manager_forbid_overrides": "禁止覆盖", |
| 1300 | "Source:": "来源:", | ||
| 1301 | "The prompt to be sent.": "要发送的提示词。", | ||
| 1176 | "reset": "重置", | 1302 | "reset": "重置", |
| 1177 | "save": "保存", | 1303 | "save": "保存", |
| 1178 | "This message is invisible for the AI": "此消息对AI不可见", | 1304 | "This message is invisible for the AI": "此消息对AI不可见", |
| @@ -1197,13 +1323,14 @@ | |||
| 1197 | "Thought for some time": "思考了一会", | 1323 | "Thought for some time": "思考了一会", |
| 1198 | "Confirm Edit": "确认", | 1324 | "Confirm Edit": "确认", |
| 1199 | "Remove reasoning": "删除推理内容", | 1325 | "Remove reasoning": "删除推理内容", |
| 1200 | "Cancel edit": "Cancel edit", | 1326 | "Cancel edit": "取消编辑", |
| 1327 | "Collapse all reasoning blocks": "折叠所有推理块", | ||
| 1201 | "Copy reasoning": "复制推理内容", | 1328 | "Copy reasoning": "复制推理内容", |
| 1202 | "Edit reasoning": "编辑推理内容", | 1329 | "Edit reasoning": "编辑推理内容", |
| 1203 | "Enlarge": "放大", | 1330 | "Expand and zoom": "展开并缩放", |
| 1204 | "Caption": "标题", | 1331 | "Caption": "标题", |
| 1205 | "Swipe left": "Swipe left", | 1332 | "Swipe left": "向左滑动", |
| 1206 | "Swipe right": "Swipe right", | 1333 | "Swipe right": "向右滑动", |
| 1207 | "Welcome to SillyTavern!": "欢迎来到 SillyTavern!", | 1334 | "Welcome to SillyTavern!": "欢迎来到 SillyTavern!", |
| 1208 | "SillyTavern is aimed at advanced users.": "SillyTavern 面向高级用户。", | 1335 | "SillyTavern is aimed at advanced users.": "SillyTavern 面向高级用户。", |
| 1209 | "welcome_message_part_1": "阅读", | 1336 | "welcome_message_part_1": "阅读", |
| @@ -1218,11 +1345,11 @@ | |||
| 1218 | "onboarding_import": "导入", | 1345 | "onboarding_import": "导入", |
| 1219 | "from supported sources or view": "来自受支持的来源或查看", | 1346 | "from supported sources or view": "来自受支持的来源或查看", |
| 1220 | "Sample characters": "示例角色", | 1347 | "Sample characters": "示例角色", |
| 1221 | "Your Persona": "您的用户角色", | 1348 | "Your Persona": "您的用户设定", |
| 1222 | "Before you get started, you must select a persona name.": "在开始之前,您必须选择一个用户角色名称。", | 1349 | "Before you get started, you must select a persona name.": "在开始之前,您必须起一个用户名。", |
| 1223 | "welcome_message_part_8": "您可随时通过", | 1350 | "welcome_message_part_8": "您可随时通过", |
| 1224 | "welcome_message_part_9": "图标来更改此设置。", | 1351 | "welcome_message_part_9": "图标来更改此设置。", |
| 1225 | "Persona Name:": "用户角色名称:", | 1352 | "Persona Name:": "用户设定名称:", |
| 1226 | "Temporarily disable automatic replies from this character": "临时禁言此角色", | 1353 | "Temporarily disable automatic replies from this character": "临时禁言此角色", |
| 1227 | "Enable automatic replies from this character": "解除禁言此角色", | 1354 | "Enable automatic replies from this character": "解除禁言此角色", |
| 1228 | "Trigger a message from this character": "强制触发该角色发言", | 1355 | "Trigger a message from this character": "强制触发该角色发言", |
| @@ -1231,6 +1358,8 @@ | |||
| 1231 | "View character card": "查看角色卡片", | 1358 | "View character card": "查看角色卡片", |
| 1232 | "Remove from group": "踢出群聊", | 1359 | "Remove from group": "踢出群聊", |
| 1233 | "Add to group": "拉入群聊", | 1360 | "Add to group": "拉入群聊", |
| 1361 | "in this group": "在此群组中", | ||
| 1362 | "Go back": "返回", | ||
| 1234 | "Alternate Greetings": "额外问候语", | 1363 | "Alternate Greetings": "额外问候语", |
| 1235 | "Alternate_Greetings_desc": "开始新聊天时,这些按钮将显示为第一条消息的滑动选项。\n群成员可以选择其中之一来发起对话。", | 1364 | "Alternate_Greetings_desc": "开始新聊天时,这些按钮将显示为第一条消息的滑动选项。\n群成员可以选择其中之一来发起对话。", |
| 1236 | "alternate_greetings_hint_1": "点击", | 1365 | "alternate_greetings_hint_1": "点击", |
| @@ -1295,9 +1424,6 @@ | |||
| 1295 | "Start new chat": "开始新聊天", | 1424 | "Start new chat": "开始新聊天", |
| 1296 | "Manage chat files": "管理聊天文件", | 1425 | "Manage chat files": "管理聊天文件", |
| 1297 | "Delete messages": "删除消息", | 1426 | "Delete messages": "删除消息", |
| 1298 | "Regenerate": "重新生成", | ||
| 1299 | "Impersonate": "AI 帮答", | ||
| 1300 | "Continue": "继续", | ||
| 1301 | "extension_install_1": "若想从此页安装扩展程序,你需要提前安装", | 1427 | "extension_install_1": "若想从此页安装扩展程序,你需要提前安装", |
| 1302 | "extension_install_2": "。", | 1428 | "extension_install_2": "。", |
| 1303 | "extension_install_3": "点这个图标(", | 1429 | "extension_install_3": "点这个图标(", |
| @@ -1314,6 +1440,7 @@ | |||
| 1314 | "Load an asset list": "加载资产列表", | 1440 | "Load an asset list": "加载资产列表", |
| 1315 | "Load Asset List": "加载资产列表", | 1441 | "Load Asset List": "加载资产列表", |
| 1316 | "Characters": "人物", | 1442 | "Characters": "人物", |
| 1443 | "Attach a file or image to a current chat.": "将文件或图像附加到当前聊天中。", | ||
| 1317 | "Attach a File": "附加文件", | 1444 | "Attach a File": "附加文件", |
| 1318 | "Enter a URL or the ID of a Fandom wiki page to scrape:": "输入要抓取的 Fandom wiki 页面的 URL 或 ID:", | 1445 | "Enter a URL or the ID of a Fandom wiki page to scrape:": "输入要抓取的 Fandom wiki 页面的 URL 或 ID:", |
| 1319 | "Examples:": "例:", | 1446 | "Examples:": "例:", |
| @@ -1327,12 +1454,12 @@ | |||
| 1327 | "These files will be available for extensions that support attachments (e.g. Vector Storage).": "这些文件将可用于支持附件的扩展(例如 Vector Storage)。", | 1454 | "These files will be available for extensions that support attachments (e.g. Vector Storage).": "这些文件将可用于支持附件的扩展(例如 Vector Storage)。", |
| 1328 | "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支持的文件类型:纯文本、PDF、Markdown、HTML、EPUB。", | 1455 | "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支持的文件类型:纯文本、PDF、Markdown、HTML、EPUB。", |
| 1329 | "Drag and drop files here to upload.": "将文件拖放到此处进行上传。", | 1456 | "Drag and drop files here to upload.": "将文件拖放到此处进行上传。", |
| 1330 | "Date (Newest First)": "日期(最新日期)", | 1457 | "Date (Newest First)": "日期(最新在先)", |
| 1331 | "Date (Oldest First)": "日期(最早日期)", | 1458 | "Date (Oldest First)": "日期(最老在先)", |
| 1332 | "Name (A-Z)": "姓名(从 A 到 Z)", | 1459 | "Name (A-Z)": "姓名(从 A 到 Z)", |
| 1333 | "Name (Z-A)": "姓名 (Z-A)", | 1460 | "Name (Z-A)": "姓名(从 Z 到 A)", |
| 1334 | "Size (Smallest First)": "尺寸(最小)", | 1461 | "Size (Smallest First)": "大小(最小在先)", |
| 1335 | "Size (Largest First)": "尺寸(最大尺寸优先)", | 1462 | "Size (Largest First)": "大小(最大在先)", |
| 1336 | "Bulk Edit": "批量编辑", | 1463 | "Bulk Edit": "批量编辑", |
| 1337 | "Select All": "全选", | 1464 | "Select All": "全选", |
| 1338 | "Select None": "清空选择", | 1465 | "Select None": "清空选择", |
| @@ -1360,16 +1487,21 @@ | |||
| 1360 | "Model": "模型", | 1487 | "Model": "模型", |
| 1361 | "currently_selected": "[当前选定]", | 1488 | "currently_selected": "[当前选定]", |
| 1362 | "currently_loaded": "[当前正在加载]", | 1489 | "currently_loaded": "[当前正在加载]", |
| 1490 | "Custom Model Tag": "自定义模型标签", | ||
| 1491 | "(for [Custom model] option)": "(自定义模型选项用)", | ||
| 1363 | "Allow reverse proxy": "允许反向代理", | 1492 | "Allow reverse proxy": "允许反向代理", |
| 1364 | "Hint:": "提示:", | 1493 | "Hint:": "提示:", |
| 1365 | "Set your API keys and endpoints in the 'API Connections' tab first.": "首先在“API 连接”选项卡中设置您的 API 密钥和端点。", | 1494 | "Set your API keys and endpoints in the 'API Connections' tab first.": "首先在“API 连接”选项卡中设置您的 API 密钥和端点。", |
| 1495 | "Use secondary URL": "使用备用URL", | ||
| 1496 | "Secondary captioning endpoint URL": "备用的描述文字生成端点URL", | ||
| 1366 | "Caption Prompt": "图像描述提示词", | 1497 | "Caption Prompt": "图像描述提示词", |
| 1367 | "Ask every time": "每次都询问", | 1498 | "Ask every time": "每次都询问", |
| 1368 | "Message Template": "消息模板", | 1499 | "Message Template": "消息模板", |
| 1369 | "(use _space": "(使用", | 1500 | "(use _space": "(使用", |
| 1370 | "macro)": "宏指令)", | 1501 | "macro)": "宏指令)", |
| 1371 | "Automatically caption images": "自动为图像添加标题", | 1502 | "Automatically caption images": "自动为图像添加描述文字", |
| 1372 | "Edit captions before saving": "保存前编辑标题", | 1503 | "Edit captions before saving": "保存前编辑描述文字", |
| 1504 | "Show captions in chat": "在聊天中显示描述文字", | ||
| 1373 | "Included settings:": "包含的设置:", | 1505 | "Included settings:": "包含的设置:", |
| 1374 | "{{@key}}": "{{@key}}:", | 1506 | "{{@key}}": "{{@key}}:", |
| 1375 | "Profile name:": "配置名称:", | 1507 | "Profile name:": "配置名称:", |
| @@ -1394,9 +1526,14 @@ | |||
| 1394 | "Classifier API": "分类器 API", | 1526 | "Classifier API": "分类器 API", |
| 1395 | "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。", | 1527 | "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。", |
| 1396 | "Main API": "当前连接的 API", | 1528 | "Main API": "当前连接的 API", |
| 1397 | "WebLLM Extension": "WebLLM Extension", | 1529 | "WebLLM Extension": "WebLLM 扩展程序", |
| 1530 | "When using LLM or WebLLM classifier, only show and use expressions that have sprites assigned to them.": "When using LLM or WebLLM classifier, only show and use expressions that have sprites assigned to them.", | ||
| 1531 | "Filter expressions for available sprites": "Filter expressions for available sprites", | ||
| 1398 | "LLM Prompt": "大语言模型提示词", | 1532 | "LLM Prompt": "大语言模型提示词", |
| 1399 | "Will be used if the API doesn't support JSON schemas or function calling.": "如果 API 不支持 JSON 模式或函数调用,则会使用它。", | 1533 | "Used in addition to JSON schemas and function calling.": "Used in addition to JSON schemas and function calling.", |
| 1534 | "LLM Prompt Strategy": "LLM Prompt Strategy", | ||
| 1535 | "Limited Context": "Limited Context", | ||
| 1536 | "Full Context": "Full Context", | ||
| 1400 | "Default / Fallback Expression": "默认/后备表达式", | 1537 | "Default / Fallback Expression": "默认/后备表达式", |
| 1401 | "Set the default and fallback expression being used when no matching expression is found.": "设置在未找到匹配表达式时使用的默认表达式和后备表达式。", | 1538 | "Set the default and fallback expression being used when no matching expression is found.": "设置在未找到匹配表达式时使用的默认表达式和后备表达式。", |
| 1402 | "Custom Expressions": "自定义表达式", | 1539 | "Custom Expressions": "自定义表达式", |
| @@ -1422,29 +1559,29 @@ | |||
| 1422 | "ext_sum_with": "总结如下:", | 1559 | "ext_sum_with": "总结如下:", |
| 1423 | "ext_sum_main_api": "主要 API", | 1560 | "ext_sum_main_api": "主要 API", |
| 1424 | "ext_sum_webllm": "WebLLM 扩展", | 1561 | "ext_sum_webllm": "WebLLM 扩展", |
| 1425 | "ext_sum_current_summary": "当前摘要:", | 1562 | "ext_sum_current_summary": "当前总结:", |
| 1426 | "ext_sum_restore_tip": "恢复先前的摘要;重复使用以清除此聊天的摘要状态", | 1563 | "ext_sum_restore_tip": "恢复先前的总结;重复使用以清除此聊天的总结状态", |
| 1427 | "ext_sum_restore_previous": "恢复上一个", | 1564 | "ext_sum_restore_previous": "恢复上一个", |
| 1428 | "ext_sum_memory_placeholder": "摘要将在这里生成...", | 1565 | "ext_sum_memory_placeholder": "总结将在这里生成...", |
| 1429 | "ext_sum_force_tip": "立即触发摘要更新。", | 1566 | "ext_sum_force_tip": "立即触发总结。", |
| 1430 | "ext_sum_force_text": "现在总结", | 1567 | "ext_sum_force_text": "立即总结", |
| 1431 | "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)强制更新。", | 1568 | "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)强制更新。", |
| 1432 | "ext_sum_pause": "暂停", | 1569 | "ext_sum_pause": "暂停", |
| 1433 | "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 始终省略世界书/作者注。", | 1570 | "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 始终省略世界书/作者注。", |
| 1434 | "ext_sum_no_wi_an": "无世界书/作者注", | 1571 | "ext_sum_no_wi_an": "无世界书/作者注", |
| 1435 | "ext_sum_settings_tip": "编辑摘要提示词、插入位置等。", | 1572 | "ext_sum_settings_tip": "编辑总结提示词、插入位置等。", |
| 1436 | "ext_sum_settings": "摘要设置", | 1573 | "ext_sum_settings": "总结设置", |
| 1437 | "ext_sum_prompt_builder": "提示词生成器", | 1574 | "ext_sum_prompt_builder": "提示词生成器", |
| 1438 | "ext_sum_prompt_builder_1_desc": "扩展将使用尚未汇总的消息构建自己的提示词。阻止聊天,直到生成摘要为止。", | 1575 | "ext_sum_prompt_builder_1_desc": "将使用尚未被总结的消息构建提示词,在总结生成前暂停聊天。", |
| 1439 | "ext_sum_prompt_builder_1": "原始,阻塞", | 1576 | "ext_sum_prompt_builder_1": "原始,阻塞", |
| 1440 | "ext_sum_prompt_builder_2_desc": "扩展将使用尚未汇总的消息构建自己的提示词。在生成摘要时不会阻止聊天。并非所有后端都支持此模式。", | 1577 | "ext_sum_prompt_builder_2_desc": "将使用尚未被总结的消息构建提示词。在生成总结时不会暂停聊天。并非所有后端都支持此模式。", |
| 1441 | "ext_sum_prompt_builder_2": "原始,非阻塞", | 1578 | "ext_sum_prompt_builder_2": "原始,非阻塞", |
| 1442 | "ext_sum_prompt_builder_3_desc": "扩展将使用常规主提示词生成器并将摘要请求添加为其作为最后的系统消息。", | 1579 | "ext_sum_prompt_builder_3_desc": "将使用常规主提示词生成器,并将总结请求设为系统消息添加到提示词最后。", |
| 1443 | "ext_sum_prompt_builder_3": "经典,阻塞", | 1580 | "ext_sum_prompt_builder_3": "经典,阻塞", |
| 1444 | "Summary Prompt": "摘要提示词", | 1581 | "Summary Prompt": "总结提示词", |
| 1445 | "ext_sum_restore_default_prompt_tip": "恢复默认提示词", | 1582 | "ext_sum_restore_default_prompt_tip": "恢复默认提示词", |
| 1446 | "ext_sum_prompt_placeholder": "该提示词将被发送给 AI,以请求生成摘要。{{words}} 将解析为“字数”参数。", | 1583 | "ext_sum_prompt_placeholder": "该提示词将被发送给 AI,以请求生成总结。{{words}} 将解析为“字数”参数。", |
| 1447 | "ext_sum_target_length_1": "目标摘要长度", | 1584 | "ext_sum_target_length_1": "目标总结长度", |
| 1448 | "ext_sum_target_length_2": "(", | 1585 | "ext_sum_target_length_2": "(", |
| 1449 | "ext_sum_target_length_3": "字)", | 1586 | "ext_sum_target_length_3": "字)", |
| 1450 | "ext_sum_api_response_length_1": "API 响应长度", | 1587 | "ext_sum_api_response_length_1": "API 响应长度", |
| @@ -1464,10 +1601,10 @@ | |||
| 1464 | "ext_sum_injection_template": "插入模板", | 1601 | "ext_sum_injection_template": "插入模板", |
| 1465 | "ext_sum_memory_template_placeholder": "{{summary}} 将解析当前摘要内容。", | 1602 | "ext_sum_memory_template_placeholder": "{{summary}} 将解析当前摘要内容。", |
| 1466 | "ext_sum_injection_position": "插入位置", | 1603 | "ext_sum_injection_position": "插入位置", |
| 1467 | "ext_sum_include_wi_scan_desc": "在 WI 扫描中包括最新摘要。", | 1604 | "ext_sum_include_wi_scan_desc": "在世界信息扫描中加入最新总结。", |
| 1468 | "ext_sum_include_wi_scan": "纳入世界信息扫描", | 1605 | "ext_sum_include_wi_scan": "纳入世界信息扫描", |
| 1469 | "None (not injected)": "无(未注入)", | 1606 | "None (not injected)": "无(未注入)", |
| 1470 | "ext_sum_injection_position_none": "摘要不会被注入到提示中。您仍然可以通过 {{summary}} 宏访问它。", | 1607 | "ext_sum_injection_position_none": "总结不会被注入到提示中。您仍然可以通过 {{summary}} 宏访问它。", |
| 1471 | "How many messages before the current end of the chat.": "当前聊天结束前还有多少条消息。", | 1608 | "How many messages before the current end of the chat.": "当前聊天结束前还有多少条消息。", |
| 1472 | "Labels and Message": "标签和信息", | 1609 | "Labels and Message": "标签和信息", |
| 1473 | "Label": "标签", | 1610 | "Label": "标签", |
| @@ -1489,6 +1626,7 @@ | |||
| 1489 | "Execute on chat change": "聊天内容改变时执行", | 1626 | "Execute on chat change": "聊天内容改变时执行", |
| 1490 | "Execute on new chat": "在新聊天中执行", | 1627 | "Execute on new chat": "在新聊天中执行", |
| 1491 | "Execute on group member draft": "起草群组成员时执行", | 1628 | "Execute on group member draft": "起草群组成员时执行", |
| 1629 | "Execute before message generation": "在消息生成前执行", | ||
| 1492 | "Automation ID:": "自动化标识", | 1630 | "Automation ID:": "自动化标识", |
| 1493 | "Testing": "测试", | 1631 | "Testing": "测试", |
| 1494 | "Execute": "执行", | 1632 | "Execute": "执行", |
| @@ -1498,6 +1636,8 @@ | |||
| 1498 | "Show Popout Button": "(在电脑上)展示弹出式按钮", | 1636 | "Show Popout Button": "(在电脑上)展示弹出式按钮", |
| 1499 | "Global Quick Reply Sets": "全局快速回复集", | 1637 | "Global Quick Reply Sets": "全局快速回复集", |
| 1500 | "Chat Quick Reply Sets": "聊天快速回复集", | 1638 | "Chat Quick Reply Sets": "聊天快速回复集", |
| 1639 | "Character Quick Reply Sets": "角色快速回复集", | ||
| 1640 | "(Private)": "(私密)", | ||
| 1501 | "Edit Quick Replies": "编辑快速回复", | 1641 | "Edit Quick Replies": "编辑快速回复", |
| 1502 | "Disable Send (Insert Into Input Field)": "禁用发送(插入输入字段)", | 1642 | "Disable Send (Insert Into Input Field)": "禁用发送(插入输入字段)", |
| 1503 | "Place Quick Reply Before Input": "在输入前放置快速回复", | 1643 | "Place Quick Reply Before Input": "在输入前放置快速回复", |
| @@ -1506,14 +1646,36 @@ | |||
| 1506 | "macro for manual injection)": "宏用于手动注入)", | 1646 | "macro for manual injection)": "宏用于手动注入)", |
| 1507 | "Color": "颜色", | 1647 | "Color": "颜色", |
| 1508 | "Only apply color as accent": "仅应用颜色作为强调", | 1648 | "Only apply color as accent": "仅应用颜色作为强调", |
| 1649 | "ext_regex_new_global_script_desc": "新增「全局」正规表达式", | ||
| 1650 | "ext_regex_new_scoped_script_desc": "新增「局部」正规表达式", | ||
| 1651 | "ext_regex_debugger_active_rules": "激活的规则", | ||
| 1652 | "ext_regex_debugger_save_order": "保存此顺序", | ||
| 1653 | "ext_regex_debugger_testing_area": "测试区域", | ||
| 1654 | "ext_regex_debugger_raw_input": "原始输入", | ||
| 1655 | "ext_regex_debugger_run_test": "运行测试", | ||
| 1656 | "ext_regex_debugger_display_replace": "替换", | ||
| 1657 | "ext_regex_debugger_display_highlight": "高亮", | ||
| 1658 | "ext_regex_debugger_render_text": "渲染为文本", | ||
| 1659 | "ext_regex_debugger_render_message": "渲染为消息", | ||
| 1660 | "ext_regex_debugger_step_by_step": "逐步转换", | ||
| 1661 | "ext_regex_debugger_final_output": "最终输出", | ||
| 1509 | "ext_regex_title": "正则", | 1662 | "ext_regex_title": "正则", |
| 1510 | "ext_regex_new_global_script_desc": "新的全局正则表达式脚本", | 1663 | "ext_regex_presets": "正则预设", |
| 1664 | "ext_regex_presets_desc": "可以轻松保存并切换多组正则开关状态。", | ||
| 1665 | "ext_regex_preset_create": "创建新预设", | ||
| 1666 | "ext_regex_preset_update": "更新已有预设", | ||
| 1667 | "ext_regex_preset_apply": "重新应用当前预设", | ||
| 1668 | "ext_regex_preset_delete": "删除当前预设", | ||
| 1511 | "ext_regex_new_global_script": "新建全局正则", | 1669 | "ext_regex_new_global_script": "新建全局正则", |
| 1512 | "ext_regex_new_scoped_script_desc": "新的作用域正则表达式脚本", | ||
| 1513 | "ext_regex_new_scoped_script": "新建局部正则", | 1670 | "ext_regex_new_scoped_script": "新建局部正则", |
| 1514 | "ext_regex_import_script": "导入正则", | 1671 | "ext_regex_import_script": "导入正则", |
| 1672 | "ext_regex_bulk_edit": "批量编辑", | ||
| 1673 | "ext_regex_debugger_desc": "高级正则调试工具", | ||
| 1674 | "ext_regex_debugger": "调试工具", | ||
| 1675 | "Export": "导出", | ||
| 1515 | "ext_regex_global_scripts": "全局正则脚本", | 1676 | "ext_regex_global_scripts": "全局正则脚本", |
| 1516 | "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中", | 1677 | "ext_regex_global_scripts_desc": "影响所有角色,保存在本地设定中", |
| 1678 | "No scripts found": "没有找到脚本", | ||
| 1517 | "ext_regex_scoped_scripts": "局部正则脚本", | 1679 | "ext_regex_scoped_scripts": "局部正则脚本", |
| 1518 | "ext_regex_disallow_scoped": "不允许使用局部正则", | 1680 | "ext_regex_disallow_scoped": "不允许使用局部正则", |
| 1519 | "ext_regex_allow_scoped": "允许使用局部正则", | 1681 | "ext_regex_allow_scoped": "允许使用局部正则", |
| @@ -1521,6 +1683,7 @@ | |||
| 1521 | "Regex Editor": "正则表达式编辑器", | 1683 | "Regex Editor": "正则表达式编辑器", |
| 1522 | "Test Mode": "测试模式", | 1684 | "Test Mode": "测试模式", |
| 1523 | "ext_regex_desc": "“正则”是一个使用“正则表达式”来查找/替换字符串的工具。如果您想了解更多信息,请点击标题旁边的“?”。", | 1685 | "ext_regex_desc": "“正则”是一个使用“正则表达式”来查找/替换字符串的工具。如果您想了解更多信息,请点击标题旁边的“?”。", |
| 1686 | "ext_regex_flags_help": "点击此处了解更多关于正则表达式修饰符的知识。", | ||
| 1524 | "Input": "输入", | 1687 | "Input": "输入", |
| 1525 | "ext_regex_test_input_placeholder": "在此输入...", | 1688 | "ext_regex_test_input_placeholder": "在此输入...", |
| 1526 | "Output": "输出", | 1689 | "Output": "输出", |
| @@ -1553,10 +1716,14 @@ | |||
| 1553 | "Substitute (raw)": "替换(原始)", | 1716 | "Substitute (raw)": "替换(原始)", |
| 1554 | "Substitute (escaped)": "替换(转义)", | 1717 | "Substitute (escaped)": "替换(转义)", |
| 1555 | "Ephemerality": "短暂", | 1718 | "Ephemerality": "短暂", |
| 1719 | "ext_regex_other_options_desc": "默认情况下,正则脚本将直接地、不可逆转地修改聊天文件。\r启用下方任意一或多项可以避免对聊天文件的修改,但仍然修改特定项目。", | ||
| 1556 | "ext_regex_only_format_visual_desc": "正则仅在聊天页面生效,聊天文件内的内容不会被改变。", | 1720 | "ext_regex_only_format_visual_desc": "正则仅在聊天页面生效,聊天文件内的内容不会被改变。", |
| 1557 | "Only Format Display": "仅格式显示", | 1721 | "Only Format Display": "仅格式显示", |
| 1558 | "ext_regex_only_format_prompt_desc": "聊天记录不会改变,只有在请求发送时(生成时)才会出现提示词。", | 1722 | "ext_regex_only_format_prompt_desc": "聊天记录不会改变,只有在请求发送时(生成时)才会出现提示词。", |
| 1559 | "Only Format Prompt (?)": "仅格式提示词", | 1723 | "Only Format Prompt (?)": "仅格式提示词", |
| 1724 | "This character has embedded regex script(s).": "此角色含有内置正则脚本。", | ||
| 1725 | "Would you like to allow using them?": "你想要启用它们吗?", | ||
| 1726 | "If you want to do it later, select 'Regex' from the extensions menu.": "你可以稍后在扩展栏的 \"正则\" 区域管理它们。", | ||
| 1560 | "ext_regex_import_target": "导入至:", | 1727 | "ext_regex_import_target": "导入至:", |
| 1561 | "ext_regex_disable_script": "禁用脚本", | 1728 | "ext_regex_disable_script": "禁用脚本", |
| 1562 | "ext_regex_enable_script": "启用脚本", | 1729 | "ext_regex_enable_script": "启用脚本", |
| @@ -1608,6 +1775,7 @@ | |||
| 1608 | "Avoid spending Anlas": "避免花费 Anlas", | 1775 | "Avoid spending Anlas": "避免花费 Anlas", |
| 1609 | "Opus tier": "(作品层)", | 1776 | "Opus tier": "(作品层)", |
| 1610 | "View my Anlas": "查看我的目录", | 1777 | "View my Anlas": "查看我的目录", |
| 1778 | "Click to set": "点击设置", | ||
| 1611 | "These settings only apply to DALL-E 3": "这些设置仅适用于 DALL-E 3", | 1779 | "These settings only apply to DALL-E 3": "这些设置仅适用于 DALL-E 3", |
| 1612 | "Image Style": "图像风格", | 1780 | "Image Style": "图像风格", |
| 1613 | "Image Quality": "画面质量", | 1781 | "Image Quality": "画面质量", |
| @@ -1618,10 +1786,9 @@ | |||
| 1618 | "Create new workflow": "创建新的工作流", | 1786 | "Create new workflow": "创建新的工作流", |
| 1619 | "Delete workflow": "删除工作流", | 1787 | "Delete workflow": "删除工作流", |
| 1620 | "Enhance": "提高", | 1788 | "Enhance": "提高", |
| 1621 | "API Key": "API 密钥", | ||
| 1622 | "Click to set": "点击设置", | ||
| 1623 | "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。", | 1789 | "You can find your API key in the Stability AI dashboard.": "您可以在 Stability AI 仪表板中找到您的 API 密钥。", |
| 1624 | "Style Preset": "风格预设", | 1790 | "Style Preset": "风格预设", |
| 1791 | "Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation.": "是否对提示词使用提示词增强(Upsampling)。若开启,则会自动修改提示词,使回复更有创造力。", | ||
| 1625 | "Prompt Upsampling": "提示词增强(Upsampling)", | 1792 | "Prompt Upsampling": "提示词增强(Upsampling)", |
| 1626 | "Sampling method": "采样方法", | 1793 | "Sampling method": "采样方法", |
| 1627 | "Scheduler": "调度器", | 1794 | "Scheduler": "调度器", |
| @@ -1646,6 +1813,8 @@ | |||
| 1646 | "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。", | 1813 | "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 采样器的 DYN 变体通常会产生更加多样化的输出,但在非常高的分辨率下可能会失败。", |
| 1647 | "DYN": "动态", | 1814 | "DYN": "动态", |
| 1648 | "Decrisper": "去伪器", | 1815 | "Decrisper": "去伪器", |
| 1816 | "Enable guidance only after body has been formed, to improve diversity and saturation of samples. May reduce relevance": "Enable guidance only after body has been formed, to improve diversity and saturation of samples. May reduce relevance", | ||
| 1817 | "Variety+": "Variety+", | ||
| 1649 | "(-1 for random)": "(“-1”为随机)", | 1818 | "(-1 for random)": "(“-1”为随机)", |
| 1650 | "Preset for prompt prefix and negative prompt": "提示词前缀和负面提示词的预设", | 1819 | "Preset for prompt prefix and negative prompt": "提示词前缀和负面提示词的预设", |
| 1651 | "Style": "风格", | 1820 | "Style": "风格", |
| @@ -1665,7 +1834,7 @@ | |||
| 1665 | "Extensions Menu": "扩展菜单", | 1834 | "Extensions Menu": "扩展菜单", |
| 1666 | "Slash Command": "快捷命令", | 1835 | "Slash Command": "快捷命令", |
| 1667 | "Interactive Mode": "交互模式", | 1836 | "Interactive Mode": "交互模式", |
| 1668 | "Function Tool": "Function Tool", | 1837 | "Function Tool": "函数工具", |
| 1669 | "Image Prompt Templates": "图像提示模板", | 1838 | "Image Prompt Templates": "图像提示模板", |
| 1670 | "Token Counter": "词符计数器", | 1839 | "Token Counter": "词符计数器", |
| 1671 | "Type / paste in the box below to see the number of tokens in the text.": "在下方框中输入或粘贴你想要统计词符数量的文本。", | 1840 | "Type / paste in the box below to see the number of tokens in the text.": "在下方框中输入或粘贴你想要统计词符数量的文本。", |
| @@ -1700,10 +1869,13 @@ | |||
| 1700 | "Skip codeblocks": "跳过代码块", | 1869 | "Skip codeblocks": "跳过代码块", |
| 1701 | "Skip tagged blocks": "跳过标签块里的内容(<标签>跳过这里</标签>)", | 1870 | "Skip tagged blocks": "跳过标签块里的内容(<标签>跳过这里</标签>)", |
| 1702 | "Pass Asterisks to TTS Engine": "将星号传递给文本转语音服务", | 1871 | "Pass Asterisks to TTS Engine": "将星号传递给文本转语音服务", |
| 1872 | "Works best when: Pass Asterisks to TTS Engine is enabled, and both Only narrate quotes and Ignore *text, even 'quotes', inside asterisks* are disabled.": "Works best when: Pass Asterisks to TTS Engine is enabled, and both Only narrate quotes and Ignore *text, even 'quotes', inside asterisks* are disabled.", | ||
| 1873 | "Different voices for quotes and text inside asterisks": "Different voices for \"quotes\", *text inside asterisks* and other text", | ||
| 1703 | "Audio Playback Speed": "音频播放速度", | 1874 | "Audio Playback Speed": "音频播放速度", |
| 1704 | "Vector Storage": "向量存储", | 1875 | "Vector Storage": "向量存储", |
| 1705 | "Vectorization Source": "向量化源", | 1876 | "Vectorization Source": "向量化源", |
| 1706 | "Local (Transformers)": "本地(Transformers)", | 1877 | "Local (Transformers)": "本地(Transformers)", |
| 1878 | "Secondary Embedding endpoint URL": "Secondary Embedding endpoint URL", | ||
| 1707 | "Vectorization Model": "向量化模型", | 1879 | "Vectorization Model": "向量化模型", |
| 1708 | "Keep model in memory": "将模型保存在内存中", | 1880 | "Keep model in memory": "将模型保存在内存中", |
| 1709 | "Hint: Set the URL in the API connection settings.": "提示:在 API 连接设置中设置 URL。", | 1881 | "Hint: Set the URL in the API connection settings.": "提示:在 API 连接设置中设置 URL。", |
| @@ -1756,6 +1928,9 @@ | |||
| 1756 | "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。", | 1928 | "This will create a new subfolder...": "这将在 /data/ 目录中创建一个新的子文件夹,以用户的句柄作为文件夹名称。", |
| 1757 | "Note:": "提示:", | 1929 | "Note:": "提示:", |
| 1758 | "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。", | 1930 | "this chat is temporary and will be deleted as soon as you leave it.": "此聊天会话是临时的,会在你离开时被删除。", |
| 1931 | "Import from JSONL": "从 JSONL 文件导入", | ||
| 1932 | "Load": "加载", | ||
| 1933 | "Export as JSONL": "导出为 JSONL 文件", | ||
| 1759 | "Enter a new display name:": "输入一个新的昵称:", | 1934 | "Enter a new display name:": "输入一个新的昵称:", |
| 1760 | "Current Password:": "当前密码:", | 1935 | "Current Password:": "当前密码:", |
| 1761 | "New Password:": "新密码:", | 1936 | "New Password:": "新密码:", |
| @@ -1787,9 +1962,21 @@ | |||
| 1787 | "custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数(YAML 数组)\n\n示例:\n- frequency_penalty\n- presence_penalty", | 1962 | "custom_exclude_body_desc": "要从聊天完成请求主体中排除的参数(YAML 数组)\n\n示例:\n- frequency_penalty\n- presence_penalty", |
| 1788 | "Include Request Headers": "包含请求标头", | 1963 | "Include Request Headers": "包含请求标头", |
| 1789 | "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\nCustomHeader:自定义值\nAnotherHeader:自定义值", | 1964 | "custom_include_headers_desc": "聊天完成请求的附加标头(YAML 对象)\n\n示例:\nCustomHeader:自定义值\nAnotherHeader:自定义值", |
| 1965 | "{{name}}": "{{name}}", | ||
| 1966 | "Delete all items in this category": "删除此分类下的所有项目", | ||
| 1967 | "View item content": "查看项目内容", | ||
| 1968 | "Download item": "下载项目", | ||
| 1969 | "Delete this item": "删除此项目", | ||
| 1970 | "Once deleted, the files will be gone forever!": "一旦删除,文件将会永久消失!(真的很久!)", | ||
| 1971 | "Make sure to back up your data in advance.": "确保你已提前备份好数据。", | ||
| 1972 | "Scan": "扫描", | ||
| 1973 | "No results yet. Tap 'Scan' to start scanning.": "暂无结果。点击 '扫描' 以启动扫描。", | ||
| 1790 | "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。", | 1974 | "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此类别中的功能仅供高级用户使用。如果您不确定后果,请不要点击任何内容。", |
| 1791 | "THIS IS PERMANENT!": "此操作不可逆!", | 1975 | "THIS IS PERMANENT!": "此操作不可逆!", |
| 1792 | "Also delete the chat files": "同时删除聊天文件", | 1976 | "Also delete the chat files": "同时删除聊天文件", |
| 1977 | "Delete Tag": "删除标签", | ||
| 1978 | "Do you want to delete the tag": "确定删除这个标签吗?", | ||
| 1979 | "If you want to merge all references to this tag into another tag, select it below:": "如果你想要将所有此标签的引用合并到其他标签,请从下方选择:", | ||
| 1793 | "Are you sure you want to delete this user?": "您确定要删除该用户吗?", | 1980 | "Are you sure you want to delete this user?": "您确定要删除该用户吗?", |
| 1794 | "Deleting:": "删除:", | 1981 | "Deleting:": "删除:", |
| 1795 | "Also wipe user data.": "同时清空用户数据", | 1982 | "Also wipe user data.": "同时清空用户数据", |
| @@ -1798,6 +1985,12 @@ | |||
| 1798 | "Type the user's handle below to confirm:": "在下面输入此用户的用户句柄以确认删除操作:", | 1985 | "Type the user's handle below to confirm:": "在下面输入此用户的用户句柄以确认删除操作:", |
| 1799 | "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?", | 1986 | "Are you sure you want to duplicate this character?": "你确定要复制这个角色吗?", |
| 1800 | "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。", | 1987 | "If you just want to start a new chat with the same character...": "如果你只是想要与此角色开启一个新的聊天,只需点击聊天左下方菜单中的“开始新聊天”按钮。", |
| 1988 | "There are no items to display.": "没有项目可供展示。", | ||
| 1989 | "Do you want to export connection data with the preset?": "你想要把API连接配置和预设一起导出吗?", | ||
| 1990 | "This includes the selected source, models, and other preferences set in the API Connections panel.": "这包含你在API连接配置页面中设置的URL、模型和其他偏好设置。", | ||
| 1991 | "Your stored API keys are never exported.": "你存储的API密钥永远不会被导出。", | ||
| 1992 | "Export connection data": "导出API连接配置", | ||
| 1993 | "Do not export connection data": "不导出API连接配置", | ||
| 1801 | "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。", | 1994 | "Forbid Media Override explanation": "当前角色/群聊成员使用外部媒体的能力。", |
| 1802 | "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。", | 1995 | "Forbid Media Override subtitle": "媒体:图像、视频、音频。外部:不在本地服务器上托管。", |
| 1803 | "forbid_media_global_state_forbidden": "(禁止)", | 1996 | "forbid_media_global_state_forbidden": "(禁止)", |
| @@ -1810,19 +2003,19 @@ | |||
| 1810 | "help_format_4": "斜体", | 2003 | "help_format_4": "斜体", |
| 1811 | "help_format_5": "**文本**", | 2004 | "help_format_5": "**文本**", |
| 1812 | "help_format_6": "显示为", | 2005 | "help_format_6": "显示为", |
| 1813 | "help_format_7": "大胆的", | 2006 | "help_format_7": "粗体", |
| 1814 | "help_format_8": "***文本***", | 2007 | "help_format_8": "***文本***", |
| 1815 | "help_format_9": "显示为", | 2008 | "help_format_9": "显示为", |
| 1816 | "help_format_10": "粗斜体", | 2009 | "help_format_10": "粗斜体", |
| 1817 | "help_format_11": "__文本__", | 2010 | "help_format_11": "__文本__", |
| 1818 | "help_format_12": "显示为", | 2011 | "help_format_12": "显示为", |
| 1819 | "help_format_13": "强调", | 2012 | "help_format_13": "下划线", |
| 1820 | "help_format_14": "~~文本~~", | 2013 | "help_format_14": "~~文本~~", |
| 1821 | "help_format_15": "显示为", | 2014 | "help_format_15": "显示为", |
| 1822 | "help_format_16": "删除线", | 2015 | "help_format_16": "删除线", |
| 1823 | "help_format_17": "[文本](网址)", | 2016 | "help_format_17": "[文本](网址)", |
| 1824 | "help_format_18": "显示为", | 2017 | "help_format_18": "显示为", |
| 1825 | "help_format_19": "超级链接", | 2018 | "help_format_19": "超链接", |
| 1826 | "help_format_20": "", | 2019 | "help_format_20": "", |
| 1827 | "help_format_21": "显示为图像", | 2020 | "help_format_21": "显示为图像", |
| 1828 | "help_format_22": "```文本```", | 2021 | "help_format_22": "```文本```", |
| @@ -1830,15 +2023,23 @@ | |||
| 1830 | "help_format_like_this": "像这样", | 2023 | "help_format_like_this": "像这样", |
| 1831 | "help_format_24": "`文本`", | 2024 | "help_format_24": "`文本`", |
| 1832 | "help_format_25": "显示为", | 2025 | "help_format_25": "显示为", |
| 1833 | "help_format_26": "内联代码", | 2026 | "help_format_26": "行内代码块", |
| 1834 | "help_format_27": "> 文本", | 2027 | "help_format_27": "> 文本", |
| 1835 | "help_format_28": "显示为块引用(请注意 > 后面的空格)", | 2028 | "help_format_28": "显示为引用(请注意 > 后面要加一个空格)", |
| 1836 | "help_format_29": "# 文本", | 2029 | "help_format_29": "# 文本", |
| 1837 | "help_format_30": "显示为大标题(注意空格)", | 2030 | "help_format_30": "显示为大标题(注意空格)", |
| 1838 | "help_format_32": "## 文本", | 2031 | "help_format_32": "## 文本", |
| 1839 | "help_format_33": "显示为中等标题(注意空格)", | 2032 | "help_format_33": "显示为中等标题(注意空格)", |
| 1840 | "help_format_35": "### 文本", | 2033 | "help_format_35": "### 文本", |
| 1841 | "help_format_36": "显示为小标题(注意空格)", | 2034 | "help_format_36": "显示为小标题(注意空格)", |
| 2035 | "Creator's Notes contain CSS style tags. Do you want to apply them just to Creator's Notes or to the entire application?": "创作者注释中包含CSS样式标签。你是想把这个样式只应用到创作者注释,还是应用到整个页面?", | ||
| 2036 | "CAUTION: Malformed styles may cause issues.": "警告:错误样式可能会出问题。", | ||
| 2037 | "To change the preference later, use the": "若想后续修改偏好设置,请点击创作者注释处的", | ||
| 2038 | "button in the Creator's Notes block.": "按钮。", | ||
| 2039 | "Class names will be automatically prefixed with 'custom-'.": "CSS类名将会自动添加 'custom-' 前缀。", | ||
| 2040 | "Choose how to apply CSS style tags if they are defined in Creator's Notes of this character:": "选择如何应用这个角色的创作者注释中定义的CSS样式:", | ||
| 2041 | "Just to Creator's Notes": "仅应用到创作者注释", | ||
| 2042 | "Apply to the entire app": "应用到整个页面", | ||
| 1842 | "help_1": "您好!请选择您想要详细了解的帮助主题:", | 2043 | "help_1": "您好!请选择您想要详细了解的帮助主题:", |
| 1843 | "help_2": "斜线命令", | 2044 | "help_2": "斜线命令", |
| 1844 | "help_or": "或者", | 2045 | "help_or": "或者", |
| @@ -1848,6 +2049,7 @@ | |||
| 1848 | "help_6": "还有其他问题吗?", | 2049 | "help_6": "还有其他问题吗?", |
| 1849 | "help_7": "SillyTavern 官方文档网站", | 2050 | "help_7": "SillyTavern 官方文档网站", |
| 1850 | "help_8": "有更多信息!", | 2051 | "help_8": "有更多信息!", |
| 2052 | "Characters and groups hidden by filters or closed folders": "因筛选条件或关闭的文件夹隐藏的角色和群组", | ||
| 1851 | "help_hotkeys_0": "热键/按键绑定", | 2053 | "help_hotkeys_0": "热键/按键绑定", |
| 1852 | "help_hotkeys_1": "上", | 2054 | "help_hotkeys_1": "上", |
| 1853 | "help_hotkeys_2": "编辑聊天中的最后一条消息", | 2055 | "help_hotkeys_2": "编辑聊天中的最后一条消息", |
| @@ -1926,11 +2128,11 @@ | |||
| 1926 | "help_macros_12": "您当前的角色描述", | 2128 | "help_macros_12": "您当前的角色描述", |
| 1927 | "help_macros_13": "角色对话示例", | 2129 | "help_macros_13": "角色对话示例", |
| 1928 | "help_macros_14": "未格式化的对话示例", | 2130 | "help_macros_14": "未格式化的对话示例", |
| 1929 | "(only for Story String)": "(仅适用于故事字符串)", | 2131 | "help_macros_summary": "“总结”扩展程序生成的最新聊天总结(如果有)。", |
| 1930 | "help_macros_summary": "“Summarize”扩展生成的最新聊天摘要(如果有)。", | 2132 | "help_macros_15": "您当前的用户设定名称", |
| 1931 | "help_macros_15": "您当前的用户角色名称", | ||
| 1932 | "help_macros_16": "角色的名字", | 2133 | "help_macros_16": "角色的名字", |
| 1933 | "help_macros_17": "角色的版本号", | 2134 | "help_macros_17": "角色的版本号", |
| 2135 | "help_macros_charDepthPrompt": "角色的 @ 深度注释", | ||
| 1934 | "help_macros_18": "以逗号分隔的群成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}", | 2136 | "help_macros_18": "以逗号分隔的群成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}", |
| 1935 | "help_groupNotMuted": "与 {{group}} 相同,但排除被禁言的成员", | 2137 | "help_groupNotMuted": "与 {{group}} 相同,但排除被禁言的成员", |
| 1936 | "help_macros_19": "当前选定的 API 的文本生成模型名称。", | 2138 | "help_macros_19": "当前选定的 API 的文本生成模型名称。", |
| @@ -2002,16 +2204,11 @@ | |||
| 2002 | "help_macros_69": "替换为范围变量“name”的值", | 2204 | "help_macros_69": "替换为范围变量“name”的值", |
| 2003 | "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换", | 2205 | "help_macros_70": "用范围变量“name”的索引处的项目值(对于数组/列表或对象/字典)替换", |
| 2004 | "Choose what to export": "选择您想要导出什么:", | 2206 | "Choose what to export": "选择您想要导出什么:", |
| 2005 | "{{name}}": "{{name}}", | ||
| 2006 | "Choose what to import": "选择您想要导入什么:", | 2207 | "Choose what to import": "选择您想要导入什么:", |
| 2007 | "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。", | 2208 | "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可稍后在 /backups 文件夹中恢复此聊天文件。", |
| 2008 | "Also delete the current chat file": "同时删除当前聊天文件", | 2209 | "Also delete the current chat file": "同时删除当前聊天文件", |
| 2009 | "Persona Lorebook for": "Persona Lorebook for", | 2210 | "Persona Lorebook for": "Persona Lorebook for", |
| 2010 | "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.", | 2211 | "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.", |
| 2011 | "Export for character": "导出角色", | ||
| 2012 | "Export prompts for this character, including their order.": "导出此角色的提示词,包括其顺序。", | ||
| 2013 | "Export all": "全部导出", | ||
| 2014 | "Export all your prompts to a file": "将所有提示词导出到文件", | ||
| 2015 | "Insert prompt": "插入提示词", | 2212 | "Insert prompt": "插入提示词", |
| 2016 | "Import a prompt list": "导入提示词列表", | 2213 | "Import a prompt list": "导入提示词列表", |
| 2017 | "Export this prompt list": "导出此提示词列表", | 2214 | "Export this prompt list": "导出此提示词列表", |
| @@ -2019,6 +2216,7 @@ | |||
| 2019 | "New prompt": "新提示词", | 2216 | "New prompt": "新提示词", |
| 2020 | "Prompts": "提示词", | 2217 | "Prompts": "提示词", |
| 2021 | "Total Tokens:": "总词符数:", | 2218 | "Total Tokens:": "总词符数:", |
| 2219 | "Name": "名称", | ||
| 2022 | "prompt_manager_tokens": "词符", | 2220 | "prompt_manager_tokens": "词符", |
| 2023 | "Are you sure you want to connect to the following proxy URL?": "你确定要连接到下面的代理URL吗?", | 2221 | "Are you sure you want to connect to the following proxy URL?": "你确定要连接到下面的代理URL吗?", |
| 2024 | "Encountered an error while processing your request.": "处理请求时遇到了问题。", | 2222 | "Encountered an error while processing your request.": "处理请求时遇到了问题。", |
| @@ -2029,12 +2227,20 @@ | |||
| 2029 | "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?", | 2227 | "Are you sure you want to reset your settings to factory defaults?": "您确定要将您的设置重置为出厂默认设置吗?", |
| 2030 | "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。", | 2228 | "Don't forget to save a snapshot of your settings before proceeding.": "在继续之前,不要忘记保存您的设置快照。", |
| 2031 | "Enter your password below to confirm:": "输入您的密码以确认:", | 2229 | "Enter your password below to confirm:": "输入您的密码以确认:", |
| 2230 | "Reset custom sampler selection": "重置自定义采样器选择", | ||
| 2231 | "Here you can toggle the display of individual samplers. (WIP)": "在此可以切换单个采样器的显示。(开发中)", | ||
| 2032 | "Chat Scenario Override": "聊天场景覆盖", | 2232 | "Chat Scenario Override": "聊天场景覆盖", |
| 2033 | "Remove": "移除", | 2233 | "Remove": "移除", |
| 2034 | "Unique to this chat.": "仅对此聊天生效。", | 2234 | "Unique to this chat.": "仅对此聊天生效。", |
| 2035 | "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.", | 2235 | "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.", |
| 2036 | "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.", | 2236 | "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.", |
| 2037 | "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.", | 2237 | "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.", |
| 2238 | "API:": "API:", | ||
| 2239 | "Key:": "密钥:", | ||
| 2240 | "Add Secret": "添加密钥", | ||
| 2241 | "No secrets saved.": "无保存的密钥。", | ||
| 2242 | "Copy ID": "复制 ID", | ||
| 2243 | "Select": "选择", | ||
| 2038 | "Settings Snapshots": "设置快照", | 2244 | "Settings Snapshots": "设置快照", |
| 2039 | "Record a snapshot of your current settings.": "记录当前设置的快照。", | 2245 | "Record a snapshot of your current settings.": "记录当前设置的快照。", |
| 2040 | "Make a Snapshot": "制作快照", | 2246 | "Make a Snapshot": "制作快照", |
| @@ -2050,6 +2256,8 @@ | |||
| 2050 | "Exclude Patterns": "排除模式", | 2256 | "Exclude Patterns": "排除模式", |
| 2051 | "Glob patterns of files to exclude in the download.": "下载中要排除的文件的 Glob 模式。每个模式用换行符分隔。", | 2257 | "Glob patterns of files to exclude in the download.": "下载中要排除的文件的 Glob 模式。每个模式用换行符分隔。", |
| 2052 | "Tag Management": "标签管理", | 2258 | "Tag Management": "标签管理", |
| 2259 | "Remove unused tags": "删除未被使用的标签", | ||
| 2260 | "Prune": "精简", | ||
| 2053 | "Save your tags to a file": "将标签保存为文件", | 2261 | "Save your tags to a file": "将标签保存为文件", |
| 2054 | "Restore tags from a file": "从文件中恢复标签", | 2262 | "Restore tags from a file": "从文件中恢复标签", |
| 2055 | "Create a new tag": "新建一个标签", | 2263 | "Create a new tag": "新建一个标签", |
| @@ -2078,8 +2286,8 @@ | |||
| 2078 | "Reset Settings": "重置设置", | 2286 | "Reset Settings": "重置设置", |
| 2079 | "Wipe all user data and reset your account to factory settings.": "删除所有用户数据并将您的账号重置为默认设置。", | 2287 | "Wipe all user data and reset your account to factory settings.": "删除所有用户数据并将您的账号重置为默认设置。", |
| 2080 | "Reset Everything": "重置一切", | 2288 | "Reset Everything": "重置一切", |
| 2081 | "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "This will delete all your settings and data. There will be no undo button.\n Make sure you have a backup before proceeding.", | 2289 | "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "这将删除您所有的设置和数据,不可撤销。请确保您已备份数据。", |
| 2082 | "Account reset code has been posted to the server console.": "Account reset code has been posted to the server console.", | 2290 | "Account reset code has been posted to the server console.": "账户重置代码已发布到服务器控制台。", |
| 2083 | "Reset Code:": "重置代码:", | 2291 | "Reset Code:": "重置代码:", |
| 2084 | "Want to update?": "获取最新版本", | 2292 | "Want to update?": "获取最新版本", |
| 2085 | "How to start chatting?": "如何快速开始聊天?", | 2293 | "How to start chatting?": "如何快速开始聊天?", |
| @@ -2100,29 +2308,17 @@ | |||
| 2100 | "Join the SillyTavern Discord": "加入 SillyTavern 的 Discord群组", | 2308 | "Join the SillyTavern Discord": "加入 SillyTavern 的 Discord群组", |
| 2101 | "Post a GitHub issue": "在 GitHub 发布问题", | 2309 | "Post a GitHub issue": "在 GitHub 发布问题", |
| 2102 | "Contact the developers": "联系开发者", | 2310 | "Contact the developers": "联系开发者", |
| 2103 | "If you're connected to an API, try asking me something!": "若您已经配置好API,尝试发送些什么吧!", | 2311 | "Show recent chats": "显示最近的聊天", |
| 2312 | "Hide recent chats": "隐藏最近的聊天", | ||
| 2313 | "Recent Chats": "最近的聊天", | ||
| 2314 | "Docs": "文档", | ||
| 2315 | "GitHub": "GitHub", | ||
| 2316 | "Discord": "Discord", | ||
| 2317 | "Temporary Chat": "临时聊天", | ||
| 2318 | "No recent chats": "无最近聊天", | ||
| 2319 | "Rename chat": "重命名聊天", | ||
| 2320 | "Delete chat": "删除聊天", | ||
| 2104 | "Title/Memo": "标题(备忘)", | 2321 | "Title/Memo": "标题(备忘)", |
| 2105 | "Strategy": "触发策略", | 2322 | "Strategy": "触发策略", |
| 2106 | "Position": "插入位置", | 2323 | "Trigger %": "触发概率%" |
| 2107 | "Trigger %": "触发概率%", | ||
| 2108 | "Generate Caption": "生成图片描述", | ||
| 2109 | "(DEPRECATED)": "(已弃用)", | ||
| 2110 | "[Currently loaded]": "[当前加载]", | ||
| 2111 | "Change Persona Image": "更改角色图片", | ||
| 2112 | "Delete Persona": "删除角色", | ||
| 2113 | "Duplicate Persona": "复制角色", | ||
| 2114 | "Enter a name for this persona:": "输入角色名", | ||
| 2115 | "Enable web search": "启用联网搜索", | ||
| 2116 | "Current Persona": "当前角色", | ||
| 2117 | "Global Settings": "全局设置", | ||
| 2118 | "Select a model": "选择模型", | ||
| 2119 | "Thinking...": "思考中", | ||
| 2120 | "Valid": "有效", | ||
| 2121 | "Rename Persona": "重命名角色", | ||
| 2122 | "Sort By: Name (Z-A)": "排序: 名称(Z-A)", | ||
| 2123 | "Sort By: Name (A-Z)": "排序: 名称(A-Z)", | ||
| 2124 | "Sort By: Date (Oldest First)": "排序: 日期(从最远到最新)", | ||
| 2125 | "Sort By: Date (Newest First)": "排序: 日期(从最新到最远)", | ||
| 2126 | "Set the reasoning block of a message. Returns the reasoning block content.": "设置消息的推理块。返回推理块内容。", | ||
| 2127 | "Select providers. No selection = all providers.": "选择服务商。未选择 = 所有服务商。" | ||
| 2128 | } | 2324 | } |
| @@ -1791,6 +1791,8 @@ | |||
| 1791 | "Derive context size from backend": "從後端推導上下文大小", | 1791 | "Derive context size from backend": "從後端推導上下文大小", |
| 1792 | "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務可能導致您的資料隱私外洩。", | 1792 | "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務可能導致您的資料隱私外洩。", |
| 1793 | "Claude API Key": "Claude API 金鑰", | 1793 | "Claude API Key": "Claude API 金鑰", |
| 1794 | "Electron Hub API Key": "Electron Hub API 金鑰", | ||
| 1795 | "Electron Hub Model": "Electron Hub 模型", | ||
| 1794 | "NanoGPT API Key": "NanoGPT API 金鑰", | 1796 | "NanoGPT API Key": "NanoGPT API 金鑰", |
| 1795 | "NanoGPT Model": "NanoGPT 模型", | 1797 | "NanoGPT Model": "NanoGPT 模型", |
| 1796 | "context_derived": "若可能,根據模型後設資料推導。", | 1798 | "context_derived": "若可能,根據模型後設資料推導。", |
| @@ -84,7 +84,7 @@ | |||
| 84 | </div> | 84 | </div> |
| 85 | 85 | ||
| 86 | <script src="lib/jquery-3.5.1.min.js"></script> | 86 | <script src="lib/jquery-3.5.1.min.js"></script> |
| 87 | <script src="scripts/login.js"></script> | 87 | <script src="scripts/login.js" type="module"></script> |
| 88 | </body> | 88 | </body> |
| 89 | 89 | ||
| 90 | </html> | 90 | </html> |
| @@ -266,6 +266,7 @@ import { initDataMaid } from './scripts/data-maid.js'; | |||
| 266 | import { clearItemizedPrompts, deleteItemizedPrompts, findItemizedPromptSet, initItemizedPrompts, itemizedParams, itemizedPrompts, loadItemizedPrompts, promptItemize, replaceItemizedPromptText, saveItemizedPrompts } from './scripts/itemized-prompts.js'; | 266 | import { clearItemizedPrompts, deleteItemizedPrompts, findItemizedPromptSet, initItemizedPrompts, itemizedParams, itemizedPrompts, loadItemizedPrompts, promptItemize, replaceItemizedPromptText, saveItemizedPrompts } from './scripts/itemized-prompts.js'; |
| 267 | import { getSystemMessageByType, initSystemMessages, SAFETY_CHAT, sendSystemMessage, system_message_types, system_messages } from './scripts/system-messages.js'; | 267 | import { getSystemMessageByType, initSystemMessages, SAFETY_CHAT, sendSystemMessage, system_message_types, system_messages } from './scripts/system-messages.js'; |
| 268 | import { event_types, eventSource } from './scripts/events.js'; | 268 | import { event_types, eventSource } from './scripts/events.js'; |
| 269 | import { initAccessibility } from './scripts/a11y.js'; | ||
| 269 | 270 | ||
| 270 | // API OBJECT FOR EXTERNAL WIRING | 271 | // API OBJECT FOR EXTERNAL WIRING |
| 271 | globalThis.SillyTavern = { | 272 | globalThis.SillyTavern = { |
| @@ -687,6 +688,7 @@ async function firstLoadInit() { | |||
| 687 | initCustomSelectedSamplers(); | 688 | initCustomSelectedSamplers(); |
| 688 | initDataMaid(); | 689 | initDataMaid(); |
| 689 | initItemizedPrompts(); | 690 | initItemizedPrompts(); |
| 691 | initAccessibility(); | ||
| 690 | addDebugFunctions(); | 692 | addDebugFunctions(); |
| 691 | doDailyExtensionUpdatesCheck(); | 693 | doDailyExtensionUpdatesCheck(); |
| 692 | await hideLoader(); | 694 | await hideLoader(); |
| @@ -5237,7 +5239,13 @@ function extractImageFromData(data, { mainApi = null, chatCompletionSource = nul | |||
| 5237 | return `data:${inlineData.mimeType};base64,${inlineData.data}`; | 5239 | return `data:${inlineData.mimeType};base64,${inlineData.data}`; |
| 5238 | } | 5240 | } |
| 5239 | } break; | 5241 | } break; |
| 5240 | 5242 | case chat_completion_sources.OPENROUTER: { | |
| 5243 | const imageUrl = data?.choices[0]?.message?.images?.find(x => x.type === 'image_url')?.image_url?.url; | ||
| 5244 | if (isDataURL(imageUrl)) { | ||
| 5245 | return imageUrl; | ||
| 5246 | } | ||
| 5247 | // TODO: Handle remote URLs | ||
| 5248 | } | ||
| 5241 | } | 5249 | } |
| 5242 | } break; | 5250 | } break; |
| 5243 | } | 5251 | } |
| @@ -5361,6 +5369,8 @@ export function extractJsonFromData(data, { mainApi = null, chatCompletionSource | |||
| 5361 | case chat_completion_sources.CUSTOM: | 5369 | case chat_completion_sources.CUSTOM: |
| 5362 | case chat_completion_sources.COHERE: | 5370 | case chat_completion_sources.COHERE: |
| 5363 | case chat_completion_sources.XAI: | 5371 | case chat_completion_sources.XAI: |
| 5372 | case chat_completion_sources.ELECTRONHUB: | ||
| 5373 | case chat_completion_sources.AZURE_OPENAI: | ||
| 5364 | default: | 5374 | default: |
| 5365 | result = tryParse(text); | 5375 | result = tryParse(text); |
| 5366 | break; | 5376 | break; |
| @@ -10808,7 +10818,7 @@ jQuery(async function () { | |||
| 10808 | } | 10818 | } |
| 10809 | } break; | 10819 | } break; |
| 10810 | case 'replace_update': { | 10820 | case 'replace_update': { |
| 10811 | const confirm = await Popup.show.confirm('Replace Character', '<p>Choose a new character card to replace this character with.</p>All chats, assets and group memberships will be preserved, but local changes to the character data will be lost.<br />Proceed?'); | 10821 | const confirm = await Popup.show.confirm(t`Replace Character`, '<p>' + t`Choose a new character card to replace this character with.` + '</p>' + t`All chats, assets and group memberships will be preserved, but local changes to the character data will be lost.` + '<br />' + t`Proceed?`); |
| 10812 | if (confirm) { | 10822 | if (confirm) { |
| 10813 | async function uploadReplacementCard(e) { | 10823 | async function uploadReplacementCard(e) { |
| 10814 | const file = e.target.files[0]; | 10824 | const file = e.target.files[0]; |
| @@ -402,6 +402,7 @@ function RA_autoconnect(PrevApi) { | |||
| 402 | || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) | 402 | || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE) |
| 403 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) | 403 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) |
| 404 | || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ) | 404 | || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ) |
| 405 | || (secret_state[SECRET_KEYS.ELECTRONHUB] && oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) | ||
| 405 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) | 406 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) |
| 406 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) | 407 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) |
| 407 | || (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI) | 408 | || (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI) |
| @@ -411,6 +412,7 @@ function RA_autoconnect(PrevApi) { | |||
| 411 | || (secret_state[SECRET_KEYS.COMETAPI] && oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) | 412 | || (secret_state[SECRET_KEYS.COMETAPI] && oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) |
| 412 | || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) | 413 | || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS) |
| 413 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) | 414 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) |
| 415 | || (secret_state[SECRET_KEYS.AZURE_OPENAI] && oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) | ||
| 414 | ) { | 416 | ) { |
| 415 | $('#api_button_openai').trigger('click'); | 417 | $('#api_button_openai').trigger('click'); |
| 416 | } | 418 | } |
| @@ -480,8 +482,7 @@ export function dragElement($elmnt) { | |||
| 480 | 482 | ||
| 481 | let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; | 483 | let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; |
| 482 | let height, width, top, left, right, bottom, | 484 | let height, width, top, left, right, bottom, |
| 483 | maxX, maxY, winHeight, winWidth, | 485 | maxX, maxY, winHeight, winWidth; |
| 484 | topbar; | ||
| 485 | 486 | ||
| 486 | const elmntName = $elmnt.attr('id'); | 487 | const elmntName = $elmnt.attr('id'); |
| 487 | const elmntNameEscaped = $.escapeSelector(elmntName); | 488 | const elmntNameEscaped = $.escapeSelector(elmntName); |
| @@ -540,11 +541,6 @@ export function dragElement($elmnt) { | |||
| 540 | winWidth = window.innerWidth; | 541 | winWidth = window.innerWidth; |
| 541 | winHeight = window.innerHeight; | 542 | winHeight = window.innerHeight; |
| 542 | 543 | ||
| 543 | topbar = document.getElementById('top-bar'); | ||
| 544 | const topbarstyle = getComputedStyle(topbar); | ||
| 545 | topBarFirstX = parseInt(topbarstyle.marginInline); | ||
| 546 | topBarLastY = parseInt(topbarstyle.height); | ||
| 547 | |||
| 548 | // Prepare state object if missing | 544 | // Prepare state object if missing |
| 549 | if (!power_user.movingUIState[elmntName]) power_user.movingUIState[elmntName] = {}; | 545 | if (!power_user.movingUIState[elmntName]) power_user.movingUIState[elmntName] = {}; |
| 550 | 546 | ||
| @@ -1066,6 +1062,19 @@ export function initRossMods() { | |||
| 1066 | $('#option_regenerate').trigger('click'); | 1062 | $('#option_regenerate').trigger('click'); |
| 1067 | $('#options').hide(); | 1063 | $('#options').hide(); |
| 1068 | } | 1064 | } |
| 1065 | |||
| 1066 | // If there is input text, we do not trigger a regenerate - we just send it | ||
| 1067 | if ($('#send_textarea').val() !== '') { | ||
| 1068 | if (shouldSendOnEnter()) { | ||
| 1069 | console.debug('Sending with Ctrl+Enter'); | ||
| 1070 | event.preventDefault(); | ||
| 1071 | sendTextareaMessage(); | ||
| 1072 | } else { | ||
| 1073 | console.debug('Text area is not empty, but send on enter is disabled'); | ||
| 1074 | } | ||
| 1075 | return; | ||
| 1076 | } | ||
| 1077 | |||
| 1069 | if (skipConfirm) { | 1078 | if (skipConfirm) { |
| 1070 | doRegenerate(); | 1079 | doRegenerate(); |
| 1071 | } else { | 1080 | } else { |
| @@ -0,0 +1,116 @@ | |||
| 1 | /** | ||
| 2 | * Shared module between login and main app. | ||
| 3 | * Be careful what you import! | ||
| 4 | */ | ||
| 5 | |||
| 6 | const buttonSelectors = [ | ||
| 7 | '.menu_button', | ||
| 8 | '.right_menu_button', | ||
| 9 | '.mes_button', | ||
| 10 | '.drawer-icon', | ||
| 11 | '.inline-drawer-icon', | ||
| 12 | '.swipe_left', | ||
| 13 | '.swipe_right', | ||
| 14 | '.character_select', | ||
| 15 | '.tags .tag', | ||
| 16 | '.jg-menu .jg-button', | ||
| 17 | '.bg_example .mobile-only-menu-toggle', | ||
| 18 | '.paginationjs-pages li a', | ||
| 19 | ].join(', '); | ||
| 20 | |||
| 21 | const listSelectors = [ | ||
| 22 | '.options-content', | ||
| 23 | '.list-group', | ||
| 24 | '#rm_print_characters_block', | ||
| 25 | '#rm_group_members', | ||
| 26 | '#rm_group_add_members', | ||
| 27 | '.tag_view_list_tags', | ||
| 28 | '.secretKeyManagerList', | ||
| 29 | '.recentChatList', | ||
| 30 | '.dataMaidCategoryContent', | ||
| 31 | '#userList', | ||
| 32 | '.bg_list', | ||
| 33 | ].join(', '); | ||
| 34 | |||
| 35 | const listItemSelectors = [ | ||
| 36 | '.options-content .list-group-item', | ||
| 37 | '.list-group .list-group-item', | ||
| 38 | '#rm_print_characters_block .entity_block', | ||
| 39 | '#rm_group_members .group_member', | ||
| 40 | '#rm_group_add_members .group_member', | ||
| 41 | '.tag_view_list_tags .tag_view_item', | ||
| 42 | '.secretKeyManagerList .secretKeyManagerItem', | ||
| 43 | '.recentChatList .recentChat', | ||
| 44 | '.dataMaidCategoryContent .dataMaidItem', | ||
| 45 | '#userList .userSelect', | ||
| 46 | '.bg_list .bg_example', | ||
| 47 | ].join(', '); | ||
| 48 | |||
| 49 | const toolbarSelectors = [ | ||
| 50 | '.jg-menu', | ||
| 51 | ].join(', '); | ||
| 52 | |||
| 53 | /** @type {Record<string, (element: Element) => void>} */ | ||
| 54 | const a11yRules = { | ||
| 55 | [buttonSelectors]: (element) => { | ||
| 56 | element.setAttribute('role', 'button'); | ||
| 57 | }, | ||
| 58 | [listSelectors]: (element) => { | ||
| 59 | element.setAttribute('role', 'list'); | ||
| 60 | }, | ||
| 61 | [listItemSelectors]: (element) => { | ||
| 62 | element.setAttribute('role', 'listitem'); | ||
| 63 | }, | ||
| 64 | [toolbarSelectors]: (element) => { | ||
| 65 | element.setAttribute('role', 'toolbar'); | ||
| 66 | }, | ||
| 67 | '#toast-container .toast': (element) => { | ||
| 68 | element.setAttribute('role', 'status'); | ||
| 69 | }, | ||
| 70 | }; | ||
| 71 | |||
| 72 | /** | ||
| 73 | * Apply accessibility rules to an element. | ||
| 74 | * @param {Element} element Element to process. | ||
| 75 | */ | ||
| 76 | function applyA11yRules(element) { | ||
| 77 | try { | ||
| 78 | for (const [selector, rule] of Object.entries(a11yRules)) { | ||
| 79 | // Apply if the element directly matches the selector | ||
| 80 | if (element.matches(selector)) { | ||
| 81 | rule(element); | ||
| 82 | } | ||
| 83 | // Apply the rule to descendants | ||
| 84 | element.querySelectorAll(selector).forEach(rule); | ||
| 85 | } | ||
| 86 | } catch (error) { | ||
| 87 | console.error('Error applying accessibility rules to element:', element, error); | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | function setAccessibilityObserver() { | ||
| 92 | // Apply for existing elements | ||
| 93 | applyA11yRules(document.body); | ||
| 94 | |||
| 95 | // Setup observer for dynamic content | ||
| 96 | const observer = new MutationObserver((mutationsList) => { | ||
| 97 | for (const mutation of mutationsList) { | ||
| 98 | if (mutation.type === 'childList') { | ||
| 99 | for (const addedNode of mutation.addedNodes) { | ||
| 100 | if (addedNode instanceof Element && addedNode.nodeType === Node.ELEMENT_NODE) { | ||
| 101 | applyA11yRules(addedNode); | ||
| 102 | } | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } | ||
| 106 | }); | ||
| 107 | |||
| 108 | observer.observe(document.body, { | ||
| 109 | childList: true, | ||
| 110 | subtree: true, | ||
| 111 | }); | ||
| 112 | } | ||
| 113 | |||
| 114 | export function initAccessibility() { | ||
| 115 | setAccessibilityObserver(); | ||
| 116 | } | ||
| @@ -265,9 +265,10 @@ async function onCopyToSystemBackgroundClick(e) { | |||
| 265 | * It caches the thumbnail in local storage and returns a blob URL for the thumbnail. | 265 | * It caches the thumbnail in local storage and returns a blob URL for the thumbnail. |
| 266 | * If the thumbnail cannot be fetched, it returns a transparent PNG pixel as a fallback. | 266 | * If the thumbnail cannot be fetched, it returns a transparent PNG pixel as a fallback. |
| 267 | * @param {string} bg Background URL | 267 | * @param {string} bg Background URL |
| 268 | * @param {boolean} isCustom Is the background custom? | ||
| 268 | * @returns {Promise<string>} Blob URL of the thumbnail | 269 | * @returns {Promise<string>} Blob URL of the thumbnail |
| 269 | */ | 270 | */ |
| 270 | async function getThumbnailFromStorage(bg) { | 271 | async function getThumbnailFromStorage(bg, isCustom) { |
| 271 | const cachedBlobUrl = THUMBNAIL_BLOBS.get(bg); | 272 | const cachedBlobUrl = THUMBNAIL_BLOBS.get(bg); |
| 272 | if (cachedBlobUrl) { | 273 | if (cachedBlobUrl) { |
| 273 | return cachedBlobUrl; | 274 | return cachedBlobUrl; |
| @@ -281,7 +282,8 @@ async function getThumbnailFromStorage(bg) { | |||
| 281 | } | 282 | } |
| 282 | 283 | ||
| 283 | try { | 284 | try { |
| 284 | const response = await fetch(getBackgroundPath(bg), { cache: 'force-cache' }); | 285 | const url = isCustom ? bg : getBackgroundPath(bg); |
| 286 | const response = await fetch(url, { cache: 'force-cache' }); | ||
| 285 | if (!response.ok) { | 287 | if (!response.ok) { |
| 286 | throw new Error('Fetch failed with status: ' + response.status); | 288 | throw new Error('Fetch failed with status: ' + response.status); |
| 287 | } | 289 | } |
| @@ -519,7 +521,7 @@ async function resolveImageUrl(bg, isCustom) { | |||
| 519 | const fileExtension = bg.split('.').pop().toLowerCase(); | 521 | const fileExtension = bg.split('.').pop().toLowerCase(); |
| 520 | const isAnimated = ['mp4', 'webp'].includes(fileExtension); | 522 | const isAnimated = ['mp4', 'webp'].includes(fileExtension); |
| 521 | const thumbnailUrl = isAnimated && !background_settings.animation | 523 | const thumbnailUrl = isAnimated && !background_settings.animation |
| 522 | ? await getThumbnailFromStorage(bg) | 524 | ? await getThumbnailFromStorage(bg, isCustom) |
| 523 | : isCustom | 525 | : isCustom |
| 524 | ? bg | 526 | ? bg |
| 525 | : getThumbnailUrl('bg', bg); | 527 | : getThumbnailUrl('bg', bg); |
| @@ -573,14 +575,21 @@ async function delBackground(bg) { | |||
| 573 | } | 575 | } |
| 574 | 576 | ||
| 575 | async function onBackgroundUploadSelected() { | 577 | async function onBackgroundUploadSelected() { |
| 576 | const form = $('#form_bg_download').get(0); | 578 | const form = $('#form_bg_upload').get(0); |
| 577 | 579 | ||
| 578 | if (!(form instanceof HTMLFormElement)) { | 580 | if (!(form instanceof HTMLFormElement)) { |
| 579 | console.error('form_bg_download is not a form'); | 581 | console.error('form_bg_upload is not a form'); |
| 580 | return; | 582 | return; |
| 581 | } | 583 | } |
| 582 | 584 | ||
| 583 | const formData = new FormData(form); | 585 | const formData = new FormData(form); |
| 586 | |||
| 587 | const file = formData.get('avatar'); | ||
| 588 | if (!(file instanceof File) || file.size === 0) { | ||
| 589 | form.reset(); | ||
| 590 | return; | ||
| 591 | } | ||
| 592 | |||
| 584 | await convertFileIfVideo(formData); | 593 | await convertFileIfVideo(formData); |
| 585 | await uploadBackground(formData); | 594 | await uploadBackground(formData); |
| 586 | form.reset(); | 595 | form.reset(); |
| @@ -614,7 +623,7 @@ async function convertFileIfVideo(formData) { | |||
| 614 | const sourceBuffer = await file.arrayBuffer(); | 623 | const sourceBuffer = await file.arrayBuffer(); |
| 615 | const convertedBuffer = await globalThis.convertVideoToAnimatedWebp({ buffer: new Uint8Array(sourceBuffer), name: file.name }); | 624 | const convertedBuffer = await globalThis.convertVideoToAnimatedWebp({ buffer: new Uint8Array(sourceBuffer), name: file.name }); |
| 616 | const convertedFileName = file.name.replace(/\.[^/.]+$/, '.webp'); | 625 | const convertedFileName = file.name.replace(/\.[^/.]+$/, '.webp'); |
| 617 | const convertedFile = new File([convertedBuffer], convertedFileName, { type: 'image/webp' }); | 626 | const convertedFile = new File([new Uint8Array(convertedBuffer)], convertedFileName, { type: 'image/webp' }); |
| 618 | formData.set('avatar', convertedFile); | 627 | formData.set('avatar', convertedFile); |
| 619 | toastMessage.remove(); | 628 | toastMessage.remove(); |
| 620 | } catch (error) { | 629 | } catch (error) { |
| @@ -693,12 +702,42 @@ function onBackgroundFilterInput() { | |||
| 693 | export function initBackgrounds() { | 702 | export function initBackgrounds() { |
| 694 | eventSource.on(event_types.CHAT_CHANGED, onChatChanged); | 703 | eventSource.on(event_types.CHAT_CHANGED, onChatChanged); |
| 695 | eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground); | 704 | eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground); |
| 696 | $(document).on('click', '.bg_example', onSelectBackgroundClick); | 705 | |
| 697 | $(document).on('click', '.bg_example_lock', onLockBackgroundClick); | 706 | $(document) |
| 698 | $(document).on('click', '.bg_example_unlock', onUnlockBackgroundClick); | 707 | .off('click', '.bg_example').on('click', '.bg_example', onSelectBackgroundClick) |
| 699 | $(document).on('click', '.bg_example_edit', onRenameBackgroundClick); | 708 | .off('click', '.bg_example .mobile-only-menu-toggle').on('click', '.bg_example .mobile-only-menu-toggle', function (e) { |
| 700 | $(document).on('click', '.bg_example_cross', onDeleteBackgroundClick); | 709 | e.stopPropagation(); |
| 701 | $(document).on('click', '.bg_example_copy', onCopyToSystemBackgroundClick); | 710 | const $context = $(this).closest('.bg_example'); |
| 711 | const wasOpen = $context.hasClass('mobile-menu-open'); | ||
| 712 | // Close all other open menus before opening a new one. | ||
| 713 | $('.bg_example.mobile-menu-open').removeClass('mobile-menu-open'); | ||
| 714 | if (!wasOpen) { | ||
| 715 | $context.addClass('mobile-menu-open'); | ||
| 716 | } | ||
| 717 | }) | ||
| 718 | .off('click', '.jg-button').on('click', '.jg-button', function (e) { | ||
| 719 | e.stopPropagation(); | ||
| 720 | const action = $(this).data('action'); | ||
| 721 | |||
| 722 | switch (action) { | ||
| 723 | case 'lock': | ||
| 724 | onLockBackgroundClick.call(this, e.originalEvent); | ||
| 725 | break; | ||
| 726 | case 'unlock': | ||
| 727 | onUnlockBackgroundClick.call(this, e.originalEvent); | ||
| 728 | break; | ||
| 729 | case 'edit': | ||
| 730 | onRenameBackgroundClick.call(this, e.originalEvent); | ||
| 731 | break; | ||
| 732 | case 'delete': | ||
| 733 | onDeleteBackgroundClick.call(this, e.originalEvent); | ||
| 734 | break; | ||
| 735 | case 'copy': | ||
| 736 | onCopyToSystemBackgroundClick.call(this, e.originalEvent); | ||
| 737 | break; | ||
| 738 | } | ||
| 739 | }); | ||
| 740 | |||
| 702 | $('#auto_background').on('click', autoBackgroundCommand); | 741 | $('#auto_background').on('click', autoBackgroundCommand); |
| 703 | $('#add_bg_button').on('change', onBackgroundUploadSelected); | 742 | $('#add_bg_button').on('change', onBackgroundUploadSelected); |
| 704 | $('#bg-filter').on('input', onBackgroundFilterInput); | 743 | $('#bg-filter').on('input', onBackgroundFilterInput); |
| @@ -1758,7 +1758,34 @@ export function addDOMPurifyHooks() { | |||
| 1758 | 1758 | ||
| 1759 | // Replace line breaks with <br> in unknown elements | 1759 | // Replace line breaks with <br> in unknown elements |
| 1760 | if (node instanceof HTMLUnknownElement) { | 1760 | if (node instanceof HTMLUnknownElement) { |
| 1761 | node.innerHTML = node.innerHTML.trim().replaceAll('\n', '<br>'); | 1761 | node.innerHTML = node.innerHTML.trim(); |
| 1762 | |||
| 1763 | /** @type {Text[]} */ | ||
| 1764 | const candidates = []; | ||
| 1765 | const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT); | ||
| 1766 | while (walker.nextNode()) { | ||
| 1767 | const textNode = /** @type {Text} */ (walker.currentNode); | ||
| 1768 | if (!textNode.data.includes('\n')) continue; | ||
| 1769 | |||
| 1770 | // Skip if this text node is within a <pre> (any ancestor) | ||
| 1771 | if (textNode.parentElement && textNode.parentElement.closest('pre')) continue; | ||
| 1772 | |||
| 1773 | candidates.push(textNode); | ||
| 1774 | } | ||
| 1775 | |||
| 1776 | for (const textNode of candidates) { | ||
| 1777 | const parts = textNode.data.split('\n'); | ||
| 1778 | const frag = document.createDocumentFragment(); | ||
| 1779 | parts.forEach((part, idx) => { | ||
| 1780 | if (part.length) { | ||
| 1781 | frag.appendChild(document.createTextNode(part)); | ||
| 1782 | } | ||
| 1783 | if (idx < parts.length - 1) { | ||
| 1784 | frag.appendChild(document.createElement('br')); | ||
| 1785 | } | ||
| 1786 | }); | ||
| 1787 | textNode.replaceWith(frag); | ||
| 1788 | } | ||
| 1762 | } | 1789 | } |
| 1763 | 1790 | ||
| 1764 | const isMediaAllowed = isExternalMediaAllowed(); | 1791 | const isMediaAllowed = isExternalMediaAllowed(); |
| @@ -33,7 +33,8 @@ const observer = new MutationObserver(mutations => { | |||
| 33 | * @param {boolean} [options.fromExtension=false] - Indicates if the styles are from an extension | 33 | * @param {boolean} [options.fromExtension=false] - Indicates if the styles are from an extension |
| 34 | */ | 34 | */ |
| 35 | function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { | 35 | function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { |
| 36 | /** @type {{baseSelector: string, rule: CSSStyleRule}[]} */ | 36 | /** @typedef {{ type: 'media'|'supports'|'container', conditionText: string }} WrapperCond */ |
| 37 | /** @type {{baseSelector: string, rule: CSSStyleRule, wrappers: WrapperCond[]}[]} */ | ||
| 37 | const hoverRules = []; | 38 | const hoverRules = []; |
| 38 | /** @type {Set<string>} */ | 39 | /** @type {Set<string>} */ |
| 39 | const focusRules = new Set(); | 40 | const focusRules = new Set(); |
| @@ -41,14 +42,28 @@ function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { | |||
| 41 | const PLACEHOLDER = ':__PLACEHOLDER__'; | 42 | const PLACEHOLDER = ':__PLACEHOLDER__'; |
| 42 | 43 | ||
| 43 | /** | 44 | /** |
| 45 | * Builds a stable signature string for a chain of wrapper conditions so we can distinguish | ||
| 46 | * identical selectors under different contexts (e.g., different @media queries) | ||
| 47 | * @param {WrapperCond[]} wrappers | ||
| 48 | * @returns {string} | ||
| 49 | */ | ||
| 50 | function wrapperSignature(wrappers) { | ||
| 51 | return wrappers.map(w => `${w.type}:${w.conditionText}`).join(';'); | ||
| 52 | } | ||
| 53 | |||
| 54 | /** | ||
| 44 | * Processes the CSS rules and separates selectors for hover and focus | 55 | * Processes the CSS rules and separates selectors for hover and focus |
| 45 | * @param {CSSRuleList} rules - The CSS rules to process | 56 | * @param {CSSRuleList} rules - The CSS rules to process |
| 57 | * @param {WrapperCond[]} wrappers - Current chain of wrapper conditions (@media/@supports/etc.) | ||
| 46 | */ | 58 | */ |
| 47 | function processRules(rules) { | 59 | function processRules(rules, wrappers = []) { |
| 48 | Array.from(rules).forEach(rule => { | 60 | Array.from(rules).forEach(rule => { |
| 49 | if (rule instanceof CSSImportRule) { | 61 | if (rule instanceof CSSImportRule) { |
| 50 | // Make sure that @import rules are processed recursively | 62 | // Make sure that @import rules are processed recursively |
| 51 | processImportedStylesheet(rule.styleSheet); | 63 | // If the @import has media conditions, treat them as wrappers as well |
| 64 | /** @type {WrapperCond[]} */ | ||
| 65 | const extra = (rule.media && rule.media.mediaText) ? [{ type: 'media', conditionText: rule.media.mediaText }] : []; | ||
| 66 | processImportedStylesheet(rule.styleSheet, [...wrappers, ...extra]); | ||
| 52 | } else if (rule instanceof CSSStyleRule) { | 67 | } else if (rule instanceof CSSStyleRule) { |
| 53 | // Separate multiple selectors on a rule | 68 | // Separate multiple selectors on a rule |
| 54 | const selectors = rule.selectorText.split(',').map(s => s.trim()); | 69 | const selectors = rule.selectorText.split(',').map(s => s.trim()); |
| @@ -60,17 +75,25 @@ function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { | |||
| 60 | // We currently do nothing here. Rules containing both hover and focus are very specific and should never be automatically touched | 75 | // We currently do nothing here. Rules containing both hover and focus are very specific and should never be automatically touched |
| 61 | } | 76 | } |
| 62 | else if (isHover) { | 77 | else if (isHover) { |
| 63 | const baseSelector = selector.replace(':hover', PLACEHOLDER).trim(); | 78 | const baseSelector = selector.replace(/:hover/g, PLACEHOLDER).trim(); |
| 64 | hoverRules.push({ baseSelector, rule }); | 79 | hoverRules.push({ baseSelector, rule, wrappers: [...wrappers] }); |
| 65 | } else if (isFocus) { | 80 | } else if (isFocus) { |
| 66 | // We need to make sure that we remember all existing :focus, :focus-within and :focus-visible rules | 81 | // We need to make sure that we remember all existing :focus, :focus-within and :focus-visible rules |
| 67 | const baseSelector = selector.replace(':focus-within', PLACEHOLDER).replace(':focus-visible', PLACEHOLDER).replace(':focus', PLACEHOLDER).trim(); | 82 | const baseSelector = selector.replace(/:focus(-within|-visible)?/g, PLACEHOLDER).trim(); |
| 68 | focusRules.add(baseSelector); | 83 | focusRules.add(`${baseSelector}|${wrapperSignature(wrappers)}`); |
| 69 | } | 84 | } |
| 70 | }); | 85 | }); |
| 71 | } else if (rule instanceof CSSMediaRule || rule instanceof CSSSupportsRule) { | 86 | } else if (rule instanceof CSSMediaRule) { |
| 72 | // Recursively process nested rules | 87 | // Recursively process nested @media rules |
| 73 | processRules(rule.cssRules); | 88 | processRules(rule.cssRules, [...wrappers, { type: 'media', conditionText: rule.conditionText }]); |
| 89 | } else if (rule instanceof CSSSupportsRule) { | ||
| 90 | // Recursively process nested @supports rules | ||
| 91 | processRules(rule.cssRules, [...wrappers, { type: 'supports', conditionText: rule.conditionText }]); | ||
| 92 | } else if (rule instanceof window.CSSContainerRule) { | ||
| 93 | // Recursively process nested @container rules (if supported by the browser) | ||
| 94 | // Note: conditionText contains the query like "(min-width: 300px)" or "style(color)" | ||
| 95 | // Using 'container' as the type ensures uniqueness separate from @media/@supports | ||
| 96 | processRules(rule.cssRules, [...wrappers, { type: 'container', conditionText: rule.conditionText }]); | ||
| 74 | } | 97 | } |
| 75 | }); | 98 | }); |
| 76 | } | 99 | } |
| @@ -78,21 +101,22 @@ function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { | |||
| 78 | /** | 101 | /** |
| 79 | * Processes the CSS rules of an imported stylesheet recursively | 102 | * Processes the CSS rules of an imported stylesheet recursively |
| 80 | * @param {CSSStyleSheet} sheet - The imported stylesheet to process | 103 | * @param {CSSStyleSheet} sheet - The imported stylesheet to process |
| 104 | * @param {WrapperCond[]} wrappers - Wrapper conditions inherited from (at)import media | ||
| 81 | */ | 105 | */ |
| 82 | function processImportedStylesheet(sheet) { | 106 | function processImportedStylesheet(sheet, wrappers = []) { |
| 83 | if (sheet && sheet.cssRules) { | 107 | if (sheet && sheet.cssRules) { |
| 84 | processRules(sheet.cssRules); | 108 | processRules(sheet.cssRules, wrappers); |
| 85 | } | 109 | } |
| 86 | } | 110 | } |
| 87 | 111 | ||
| 88 | processRules(styleSheet.cssRules); | 112 | processRules(styleSheet.cssRules, []); |
| 89 | 113 | ||
| 90 | /** @type {CSSStyleSheet} */ | 114 | /** @type {CSSStyleSheet} */ |
| 91 | let targetStyleSheet = null; | 115 | let targetStyleSheet = null; |
| 92 | 116 | ||
| 93 | // Now finally create the dynamic focus rules | 117 | // Now finally create the dynamic focus rules |
| 94 | hoverRules.forEach(({ baseSelector, rule }) => { | 118 | hoverRules.forEach(({ baseSelector, rule, wrappers }) => { |
| 95 | if (!focusRules.has(baseSelector)) { | 119 | if (!focusRules.has(`${baseSelector}|${wrapperSignature(wrappers)}`)) { |
| 96 | // Only initialize the dynamic stylesheet if needed | 120 | // Only initialize the dynamic stylesheet if needed |
| 97 | targetStyleSheet ??= getDynamicStyleSheet({ fromExtension }); | 121 | targetStyleSheet ??= getDynamicStyleSheet({ fromExtension }); |
| 98 | 122 | ||
| @@ -103,7 +127,19 @@ function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) { | |||
| 103 | // If something like :focus-within or a more specific selector like `.blah:has(:focus-visible)` for elements inside, | 127 | // If something like :focus-within or a more specific selector like `.blah:has(:focus-visible)` for elements inside, |
| 104 | // it should be manually defined in CSS. | 128 | // it should be manually defined in CSS. |
| 105 | const focusSelector = rule.selectorText.replace(/:hover/g, ':focus-visible'); | 129 | const focusSelector = rule.selectorText.replace(/:hover/g, ':focus-visible'); |
| 106 | const focusRule = `${focusSelector} { ${rule.style.cssText} }`; | 130 | let focusRule = `${focusSelector} { ${rule.style.cssText} }`; |
| 131 | |||
| 132 | // Wrap the generated rule into the same @media/@supports/@container chain (if any) | ||
| 133 | if (wrappers.length > 0) { | ||
| 134 | // Build nested blocks from outermost to innermost | ||
| 135 | // Example: @media (x) { @supports (y) { <rule> } } | ||
| 136 | focusRule = wrappers.reduceRight((inner, w) => { | ||
| 137 | if (w.type === 'media') return `@media ${w.conditionText} { ${inner} }`; | ||
| 138 | if (w.type === 'supports') return `@supports ${w.conditionText} { ${inner} }`; | ||
| 139 | if (w.type === 'container') return `@container ${w.conditionText} { ${inner} }`; | ||
| 140 | return inner; | ||
| 141 | }, focusRule); | ||
| 142 | } | ||
| 107 | 143 | ||
| 108 | try { | 144 | try { |
| 109 | targetStyleSheet.insertRule(focusRule, targetStyleSheet.cssRules.length); | 145 | targetStyleSheet.insertRule(focusRule, targetStyleSheet.cssRules.length); |
| @@ -188,6 +188,8 @@ export const extension_settings = { | |||
| 188 | dice: {}, | 188 | dice: {}, |
| 189 | /** @type {import('./char-data.js').RegexScriptData[]} */ | 189 | /** @type {import('./char-data.js').RegexScriptData[]} */ |
| 190 | regex: [], | 190 | regex: [], |
| 191 | /** @type {import('./extensions/regex/index.js').RegexPreset[]} */ | ||
| 192 | regex_presets: [], | ||
| 191 | character_allowed_regex: [], | 193 | character_allowed_regex: [], |
| 192 | tts: {}, | 194 | tts: {}, |
| 193 | sd: { | 195 | sd: { |
| @@ -439,6 +439,8 @@ jQuery(async function () { | |||
| 439 | 'cohere': SECRET_KEYS.COHERE, | 439 | 'cohere': SECRET_KEYS.COHERE, |
| 440 | 'aimlapi': SECRET_KEYS.AIMLAPI, | 440 | 'aimlapi': SECRET_KEYS.AIMLAPI, |
| 441 | 'moonshot': SECRET_KEYS.MOONSHOT, | 441 | 'moonshot': SECRET_KEYS.MOONSHOT, |
| 442 | 'nanogpt': SECRET_KEYS.NANOGPT, | ||
| 443 | 'electronhub': SECRET_KEYS.ELECTRONHUB, | ||
| 442 | }; | 444 | }; |
| 443 | 445 | ||
| 444 | if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) { | 446 | if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) { |
| @@ -543,8 +545,10 @@ jQuery(async function () { | |||
| 543 | } | 545 | } |
| 544 | 546 | ||
| 545 | await processEndpoint('openrouter', '/api/openrouter/models/multimodal'); | 547 | await processEndpoint('openrouter', '/api/openrouter/models/multimodal'); |
| 546 | await processEndpoint('aimlapi', '/api/backends/chat-completions/aimlapi/models/multimodal'); | 548 | await processEndpoint('aimlapi', '/api/backends/chat-completions/multimodal-models/aimlapi'); |
| 547 | await processEndpoint('pollinations', '/api/backends/chat-completions/pollinations/models/multimodal'); | 549 | await processEndpoint('pollinations', '/api/backends/chat-completions/multimodal-models/pollinations'); |
| 550 | await processEndpoint('nanogpt', '/api/backends/chat-completions/multimodal-models/nanogpt'); | ||
| 551 | await processEndpoint('electronhub', '/api/backends/chat-completions/multimodal-models/electronhub'); | ||
| 548 | } | 552 | } |
| 549 | 553 | ||
| 550 | await addSettings(); | 554 | await addSettings(); |
| @@ -588,10 +592,12 @@ jQuery(async function () { | |||
| 588 | saveSettingsDebounced(); | 592 | saveSettingsDebounced(); |
| 589 | }); | 593 | }); |
| 590 | $('#caption_ollama_pull').on('click', (e) => { | 594 | $('#caption_ollama_pull').on('click', (e) => { |
| 591 | const presetModel = extension_settings.caption.multimodal_model !== 'ollama_current' ? extension_settings.caption.multimodal_model : ''; | 595 | const selectedModel = extension_settings.caption.multimodal_model; |
| 596 | const staticModels = { 'ollama_current': textgenerationwebui_settings.ollama_model, 'ollama_custom': extension_settings.caption.ollama_custom_model }; | ||
| 597 | const presetModel = staticModels[selectedModel] || selectedModel; | ||
| 592 | e.preventDefault(); | 598 | e.preventDefault(); |
| 593 | $('#ollama_download_model').trigger('click'); | 599 | $('#ollama_download_model').trigger('click'); |
| 594 | $('#dialogue_popup_input').val(presetModel); | 600 | $('.popup .popup-input').val(presetModel); |
| 595 | }); | 601 | }); |
| 596 | $('#caption_multimodal_api').on('change', async () => { | 602 | $('#caption_multimodal_api').on('change', async () => { |
| 597 | const api = String($('#caption_multimodal_api').val()); | 603 | const api = String($('#caption_multimodal_api').val()); |
| @@ -616,6 +622,10 @@ jQuery(async function () { | |||
| 616 | extension_settings.caption.show_in_chat = !!$('#caption_show_in_chat').prop('checked'); | 622 | extension_settings.caption.show_in_chat = !!$('#caption_show_in_chat').prop('checked'); |
| 617 | saveSettingsDebounced(); | 623 | saveSettingsDebounced(); |
| 618 | }); | 624 | }); |
| 625 | $('#caption_ollama_custom_model').val(extension_settings.caption.ollama_custom_model || '').on('input', () => { | ||
| 626 | extension_settings.caption.ollama_custom_model = String($('#caption_ollama_custom_model').val()).trim(); | ||
| 627 | saveSettingsDebounced(); | ||
| 628 | }); | ||
| 619 | 629 | ||
| 620 | const onMessageEvent = async (index) => { | 630 | const onMessageEvent = async (index) => { |
| 621 | if (!extension_settings.caption.auto_mode) { | 631 | if (!extension_settings.caption.auto_mode) { |
| @@ -21,6 +21,7 @@ | |||
| 21 | <option value="anthropic">Anthropic</option> | 21 | <option value="anthropic">Anthropic</option> |
| 22 | <option value="cohere">Cohere</option> | 22 | <option value="cohere">Cohere</option> |
| 23 | <option value="custom" data-i18n="Custom (OpenAI-compatible)">Custom (OpenAI-compatible)</option> | 23 | <option value="custom" data-i18n="Custom (OpenAI-compatible)">Custom (OpenAI-compatible)</option> |
| 24 | <option value="electronhub">Electron Hub</option> | ||
| 24 | <option value="google">Google AI Studio</option> | 25 | <option value="google">Google AI Studio</option> |
| 25 | <option value="vertexai">Google Vertex AI</option> | 26 | <option value="vertexai">Google Vertex AI</option> |
| 26 | <option value="groq">Groq</option> | 27 | <option value="groq">Groq</option> |
| @@ -28,6 +29,7 @@ | |||
| 28 | <option value="llamacpp">llama.cpp</option> | 29 | <option value="llamacpp">llama.cpp</option> |
| 29 | <option value="mistral">MistralAI</option> | 30 | <option value="mistral">MistralAI</option> |
| 30 | <option value="moonshot">Moonshot AI</option> | 31 | <option value="moonshot">Moonshot AI</option> |
| 32 | <option value="nanogpt">NanoGPT</option> | ||
| 31 | <option value="ollama">Ollama</option> | 33 | <option value="ollama">Ollama</option> |
| 32 | <option value="openai">OpenAI</option> | 34 | <option value="openai">OpenAI</option> |
| 33 | <option value="openrouter">OpenRouter</option> | 35 | <option value="openrouter">OpenRouter</option> |
| @@ -40,7 +42,7 @@ | |||
| 40 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> | 42 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> |
| 41 | <label for="caption_multimodal_model" data-i18n="Model">Model</label> | 43 | <label for="caption_multimodal_model" data-i18n="Model">Model</label> |
| 42 | <select id="caption_multimodal_model" class="flex1 text_pole"> | 44 | <select id="caption_multimodal_model" class="flex1 text_pole"> |
| 43 | <!-- AI/ML API, OpenRouter, Pollinations are added externally by JavaScript --> | 45 | <!-- AI/ML API, OpenRouter, Pollinations, NanoGPT are added externally by JavaScript --> |
| 44 | <option data-type="cohere" value="c4ai-aya-vision-8b">c4ai-aya-vision-8b</option> | 46 | <option data-type="cohere" value="c4ai-aya-vision-8b">c4ai-aya-vision-8b</option> |
| 45 | <option data-type="cohere" value="c4ai-aya-vision-32b">c4ai-aya-vision-32b</option> | 47 | <option data-type="cohere" value="c4ai-aya-vision-32b">c4ai-aya-vision-32b</option> |
| 46 | <option data-type="cohere" value="command-a-vision-07-2025">command-a-vision-07-2025</option> | 48 | <option data-type="cohere" value="command-a-vision-07-2025">command-a-vision-07-2025</option> |
| @@ -110,6 +112,7 @@ | |||
| 110 | <option data-type="google" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 112 | <option data-type="google" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 111 | <option data-type="google" value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> | 113 | <option data-type="google" value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> |
| 112 | <option data-type="google" value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | 114 | <option data-type="google" value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> |
| 115 | <option data-type="google" value="gemini-2.5-flash-image-preview">gemini-2.5-flash-image-preview</option> | ||
| 113 | <option data-type="google" value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> | 116 | <option data-type="google" value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05 → 2.5-pro-exp-03-25</option> |
| 114 | <option data-type="google" value="gemini-2.0-pro-exp">gemini-2.0-pro-exp → 2.5-pro-exp-03-25</option> | 117 | <option data-type="google" value="gemini-2.0-pro-exp">gemini-2.0-pro-exp → 2.5-pro-exp-03-25</option> |
| 115 | <option data-type="google" value="gemini-exp-1206">gemini-exp-1206 → 2.5-pro-exp-03-25</option> | 118 | <option data-type="google" value="gemini-exp-1206">gemini-exp-1206 → 2.5-pro-exp-03-25</option> |
| @@ -146,17 +149,26 @@ | |||
| 146 | <option data-type="vertexai" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | 149 | <option data-type="vertexai" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> |
| 147 | <option data-type="vertexai" value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> | 150 | <option data-type="vertexai" value="gemini-2.5-flash-lite">gemini-2.5-flash-lite</option> |
| 148 | <option data-type="vertexai" value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> | 151 | <option data-type="vertexai" value="gemini-2.5-flash-lite-preview-06-17">gemini-2.5-flash-lite-preview-06-17</option> |
| 152 | <option data-type="vertexai" value="gemini-2.5-flash-image-preview">gemini-2.5-flash-image-preview</option> | ||
| 149 | <option data-type="vertexai" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> | 153 | <option data-type="vertexai" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option> |
| 150 | <option data-type="vertexai" value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> | 154 | <option data-type="vertexai" value="gemini-2.0-flash-lite-001">gemini-2.0-flash-lite-001</option> |
| 151 | <option data-type="groq" value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option> | 155 | <option data-type="groq" value="meta-llama/llama-4-scout-17b-16e-instruct">meta-llama/llama-4-scout-17b-16e-instruct</option> |
| 152 | <option data-type="groq" value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview</option> | 156 | <option data-type="groq" value="meta-llama/llama-4-maverick-17b-128e-instruct">meta-llama/llama-4-maverick-17b-128e-instruct</option> |
| 153 | <option data-type="groq" value="llava-v1.5-7b-4096-preview">llava-v1.5-7b-4096-preview</option> | ||
| 154 | <option data-type="ollama" value="ollama_current" data-i18n="currently_selected">[Currently selected]</option> | 157 | <option data-type="ollama" value="ollama_current" data-i18n="currently_selected">[Currently selected]</option> |
| 158 | <option data-type="ollama" value="ollama_custom" data-i18n="[Custom model]">[Custom model]</option> | ||
| 155 | <option data-type="ollama" value="bakllava">bakllava</option> | 159 | <option data-type="ollama" value="bakllava">bakllava</option> |
| 156 | <option data-type="ollama" value="llava">llava</option> | 160 | <option data-type="ollama" value="llava">llava</option> |
| 157 | <option data-type="ollama" value="llava-llama3">llava-llama3</option> | 161 | <option data-type="ollama" value="llava-llama3">llava-llama3</option> |
| 158 | <option data-type="ollama" value="llava-phi3">llava-phi3</option> | 162 | <option data-type="ollama" value="llava-phi3">llava-phi3</option> |
| 159 | <option data-type="ollama" value="moondream">moondream</option> | 163 | <option data-type="ollama" value="moondream">moondream</option> |
| 164 | <option data-type="ollama" value="gemma3">gemma3</option> | ||
| 165 | <option data-type="ollama" value="minicpm-v">minicpm-v</option> | ||
| 166 | <option data-type="ollama" value="qwen2.5vl">qwen2.5vl</option> | ||
| 167 | <option data-type="ollama" value="granite3.2-vision">granite3.2-vision</option> | ||
| 168 | <option data-type="ollama" value="mistral-small3.1">mistral-small3.1</option> | ||
| 169 | <option data-type="ollama" value="mistral-small3.2">mistral-small3.2</option> | ||
| 170 | <option data-type="ollama" value="llama3.2-vision">llama3.2-vision</option> | ||
| 171 | <option data-type="ollama" value="llama4">llama4</option> | ||
| 160 | <option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option> | 172 | <option data-type="llamacpp" value="llamacpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 161 | <option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option> | 173 | <option data-type="ooba" value="ooba_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 162 | <option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option> | 174 | <option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| @@ -168,16 +180,25 @@ | |||
| 168 | </select> | 180 | </select> |
| 169 | </div> | 181 | </div> |
| 170 | <div data-type="ollama"> | 182 | <div data-type="ollama"> |
| 171 | The model must be downloaded first! Do it with the <code>ollama pull</code> command or <a href="#" id="caption_ollama_pull">click here</a>. | 183 | <div> |
| 184 | The model must be downloaded first! Do it with the <code>ollama pull</code> command or <a href="#" id="caption_ollama_pull">click here</a>. | ||
| 185 | </div> | ||
| 186 | <div class="marginTop5"> | ||
| 187 | <label for="caption_ollama_custom_model"> | ||
| 188 | <span data-i18n="Custom Model Tag">Custom Model Tag</span> | ||
| 189 | <small data-i18n="(for [Custom model] option)">(for [Custom model] option)</small> | ||
| 190 | </label> | ||
| 191 | <input id="caption_ollama_custom_model" class="text_pole" type="text" placeholder="e.g. gemma3:latest" /> | ||
| 192 | </div> | ||
| 172 | </div> | 193 | </div> |
| 173 | <label data-type="openai,anthropic,google,vertexai,mistral,xai" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> | 194 | <label data-type="openai,anthropic,google,vertexai,mistral,xai" class="checkbox_label flexBasis100p" for="caption_allow_reverse_proxy" title="Allow using reverse proxy if defined and valid."> |
| 174 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> | 195 | <input id="caption_allow_reverse_proxy" type="checkbox" class="checkbox"> |
| 175 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> | 196 | <span data-i18n="Allow reverse proxy">Allow reverse proxy</span> |
| 176 | </label> | 197 | </label> |
| 177 | <div class="flexBasis100p m-b-1"> | 198 | <div class="flexBasis100p marginBot10"> |
| 178 | <small><b data-i18n="Hint:">Hint:</b> <span data-i18n="Set your API keys and endpoints in the 'API Connections' tab first.">Set your API keys and endpoints in the 'API Connections' tab first.</span></small> | 199 | <small><b data-i18n="Hint:">Hint:</b> <span data-i18n="Set your API keys and endpoints in the 'API Connections' tab first.">Set your API keys and endpoints in the 'API Connections' tab first.</span></small> |
| 179 | </div> | 200 | </div> |
| 180 | <div data-type="koboldcpp,ollama,vllm,llamacpp,ooba" class="flex-container flexFlowColumn"> | 201 | <div data-type="koboldcpp,ollama,vllm,llamacpp,ooba" class="flex-container flexFlowColumn wide100p"> |
| 181 | <label for="caption_altEndpoint_enabled" class="checkbox_label"> | 202 | <label for="caption_altEndpoint_enabled" class="checkbox_label"> |
| 182 | <input id="caption_altEndpoint_enabled" type="checkbox"> | 203 | <input id="caption_altEndpoint_enabled" type="checkbox"> |
| 183 | <span data-i18n="Use secondary URL">Use secondary URL</span> | 204 | <span data-i18n="Use secondary URL">Use secondary URL</span> |
| @@ -43,6 +43,7 @@ const CC_COMMANDS = [ | |||
| 43 | 'reasoning-template', | 43 | 'reasoning-template', |
| 44 | 'prompt-post-processing', | 44 | 'prompt-post-processing', |
| 45 | 'secret-id', | 45 | 'secret-id', |
| 46 | 'regex-preset', | ||
| 46 | ]; | 47 | ]; |
| 47 | 48 | ||
| 48 | const TC_COMMANDS = [ | 49 | const TC_COMMANDS = [ |
| @@ -60,6 +61,7 @@ const TC_COMMANDS = [ | |||
| 60 | 'start-reply-with', | 61 | 'start-reply-with', |
| 61 | 'reasoning-template', | 62 | 'reasoning-template', |
| 62 | 'secret-id', | 63 | 'secret-id', |
| 64 | 'regex-preset', | ||
| 63 | ]; | 65 | ]; |
| 64 | 66 | ||
| 65 | const FANCY_NAMES = { | 67 | const FANCY_NAMES = { |
| @@ -79,6 +81,7 @@ const FANCY_NAMES = { | |||
| 79 | 'reasoning-template': 'Reasoning Template', | 81 | 'reasoning-template': 'Reasoning Template', |
| 80 | 'prompt-post-processing': 'Prompt Post-Processing', | 82 | 'prompt-post-processing': 'Prompt Post-Processing', |
| 81 | 'secret-id': 'Secret', | 83 | 'secret-id': 'Secret', |
| 84 | 'regex-preset': 'Regex Preset', | ||
| 82 | }; | 85 | }; |
| 83 | 86 | ||
| 84 | /** | 87 | /** |
| @@ -357,6 +360,14 @@ function makeFancyProfile(profile) { | |||
| 357 | } | 360 | } |
| 358 | } | 361 | } |
| 359 | 362 | ||
| 363 | if (key === 'regex-preset') { | ||
| 364 | const label = extension_settings.regex_presets?.find(p => p.id === profile[key])?.name; | ||
| 365 | if (label) { | ||
| 366 | acc[value] = label; | ||
| 367 | return acc; | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 360 | acc[value] = profile[key]; | 371 | acc[value] = profile[key]; |
| 361 | return acc; | 372 | return acc; |
| 362 | }, {}); | 373 | }, {}); |
| @@ -63,10 +63,10 @@ mutationObserver.observe(document.body, { | |||
| 63 | }); | 63 | }); |
| 64 | 64 | ||
| 65 | const SORT = Object.freeze({ | 65 | const SORT = Object.freeze({ |
| 66 | NAME_ASC: { value: 'nameAsc', field: 'name', order: 'asc', label: t`Sort By: Name (A-Z)` }, | 66 | NAME_ASC: { value: 'nameAsc', field: 'name', order: 'asc', label: t`Name (A-Z)` }, |
| 67 | NAME_DESC: { value: 'nameDesc', field: 'name', order: 'desc', label: t`Sort By: Name (Z-A)` }, | 67 | NAME_DESC: { value: 'nameDesc', field: 'name', order: 'desc', label: t`Name (Z-A)` }, |
| 68 | DATE_ASC: { value: 'dateAsc', field: 'date', order: 'asc', label: t`Sort By: Date (Oldest First)` }, | 68 | DATE_DESC: { value: 'dateDesc', field: 'date', order: 'desc', label: t`Newest` }, |
| 69 | DATE_DESC: { value: 'dateDesc', field: 'date', order: 'desc', label: t`Sort By: Date (Newest First)` }, | 69 | DATE_ASC: { value: 'dateAsc', field: 'date', order: 'asc', label: t`Oldest` }, |
| 70 | }); | 70 | }); |
| 71 | 71 | ||
| 72 | const defaultSettings = Object.freeze({ | 72 | const defaultSettings = Object.freeze({ |
| @@ -376,6 +376,11 @@ async function makeMovable(url) { | |||
| 376 | const titleText = document.createElement('span'); | 376 | const titleText = document.createElement('span'); |
| 377 | titleText.textContent = t`Image Gallery`; | 377 | titleText.textContent = t`Image Gallery`; |
| 378 | dragTitle.append(titleText); | 378 | dragTitle.append(titleText); |
| 379 | |||
| 380 | // Create a container for the controls | ||
| 381 | const controlsContainer = document.createElement('div'); | ||
| 382 | controlsContainer.classList.add('flex-container', 'alignItemsCenter'); | ||
| 383 | |||
| 379 | const sortSelect = document.createElement('select'); | 384 | const sortSelect = document.createElement('select'); |
| 380 | sortSelect.classList.add('gallery-sort-select'); | 385 | sortSelect.classList.add('gallery-sort-select'); |
| 381 | 386 | ||
| @@ -394,7 +399,42 @@ async function makeMovable(url) { | |||
| 394 | }); | 399 | }); |
| 395 | 400 | ||
| 396 | sortSelect.value = getSortOrder(); | 401 | sortSelect.value = getSortOrder(); |
| 397 | dragTitle.append(sortSelect); | 402 | controlsContainer.appendChild(sortSelect); |
| 403 | |||
| 404 | // Create the "Add Image" button | ||
| 405 | const addImageButton = document.createElement('div'); | ||
| 406 | addImageButton.classList.add('menu_button', 'menu_button_icon', 'interactable'); | ||
| 407 | addImageButton.title = 'Add Image'; | ||
| 408 | addImageButton.innerHTML = '<i class="fa-solid fa-plus fa-fw"></i><div>Add Image</div>'; | ||
| 409 | |||
| 410 | // Create a hidden file input | ||
| 411 | const fileInput = document.createElement('input'); | ||
| 412 | fileInput.type = 'file'; | ||
| 413 | fileInput.accept = 'image/*'; | ||
| 414 | fileInput.multiple = true; | ||
| 415 | fileInput.style.display = 'none'; | ||
| 416 | |||
| 417 | // Trigger file input when the button is clicked | ||
| 418 | addImageButton.addEventListener('click', () => { | ||
| 419 | fileInput.click(); | ||
| 420 | }); | ||
| 421 | |||
| 422 | // Handle file selection | ||
| 423 | fileInput.addEventListener('change', async () => { | ||
| 424 | const files = fileInput.files; | ||
| 425 | if (files.length > 0) { | ||
| 426 | for (const file of files) { | ||
| 427 | await uploadFile(file, url); | ||
| 428 | } | ||
| 429 | // Refresh the gallery | ||
| 430 | closeButton.trigger('click'); | ||
| 431 | await showCharGallery(); | ||
| 432 | } | ||
| 433 | }); | ||
| 434 | |||
| 435 | controlsContainer.appendChild(addImageButton); | ||
| 436 | dragTitle.append(controlsContainer); | ||
| 437 | newElement.append(fileInput); // Append hidden file input to the main element | ||
| 398 | 438 | ||
| 399 | // add no-scrollbar class to this element | 439 | // add no-scrollbar class to this element |
| 400 | newElement.addClass('no-scrollbar'); | 440 | newElement.addClass('no-scrollbar'); |
| @@ -2,6 +2,7 @@ | |||
| 2 | display: flex; | 2 | display: flex; |
| 3 | align-items: center; | 3 | align-items: center; |
| 4 | justify-content: center; | 4 | justify-content: center; |
| 5 | gap: 4px; | ||
| 5 | } | 6 | } |
| 6 | 7 | ||
| 7 | .gallery-folder-input { | 8 | .gallery-folder-input { |
| @@ -26,13 +27,13 @@ | |||
| 26 | text-overflow: ellipsis; | 27 | text-overflow: ellipsis; |
| 27 | width: 100%; | 28 | width: 100%; |
| 28 | opacity: 0.8; | 29 | opacity: 0.8; |
| 29 | background: none; | 30 | background-color: var(--black30a); |
| 31 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 30 | background-image: url(/img/down-arrow.svg); | 32 | background-image: url(/img/down-arrow.svg); |
| 31 | background-repeat: no-repeat; | 33 | background-repeat: no-repeat; |
| 32 | background-position: right 6px center; | 34 | background-position: right 6px center; |
| 33 | background-size: 8px 5px; | 35 | background-size: 8px 5px; |
| 34 | padding-right: 20px; | 36 | padding-right: 20px; |
| 35 | font-size: calc(var(--mainFontSize)* 0.9); | ||
| 36 | margin-bottom: 0; | 37 | margin-bottom: 0; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| @@ -0,0 +1,263 @@ | |||
| 1 | /* Styles for the debugger UI */ | ||
| 2 | #regex_debugger_rules { | ||
| 3 | margin: 10px 0; | ||
| 4 | } | ||
| 5 | |||
| 6 | #regex_debugger_rules, | ||
| 7 | #regex_debugger_rules .sortable-list { | ||
| 8 | padding-left: 0; | ||
| 9 | } | ||
| 10 | |||
| 11 | .regex-debugger-rules-list { | ||
| 12 | position: relative; | ||
| 13 | } | ||
| 14 | |||
| 15 | .regex-debugger-rule { | ||
| 16 | display: flex; | ||
| 17 | align-items: center; | ||
| 18 | padding: 8px 10px; | ||
| 19 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 20 | border-radius: 5px; | ||
| 21 | cursor: pointer; | ||
| 22 | background-color: var(--black30a); | ||
| 23 | gap: 5px; | ||
| 24 | margin-bottom: 5px; | ||
| 25 | } | ||
| 26 | |||
| 27 | #regex_debugger_run_test_header { | ||
| 28 | justify-content: space-between; | ||
| 29 | align-items: center; | ||
| 30 | } | ||
| 31 | |||
| 32 | #regex_debugger_expand_steps, | ||
| 33 | #regex_debugger_expand_final, | ||
| 34 | #regex_debugger_save_order { | ||
| 35 | position: absolute; | ||
| 36 | top: 0; | ||
| 37 | right: 0; | ||
| 38 | margin: 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | .regex-debugger-rule:hover { | ||
| 42 | filter: brightness(1.1); | ||
| 43 | } | ||
| 44 | |||
| 45 | .regex-debugger-rule .handle { | ||
| 46 | cursor: grab; | ||
| 47 | margin-right: 5px; | ||
| 48 | } | ||
| 49 | |||
| 50 | .regex-debugger-rule .rule-details { | ||
| 51 | flex-grow: 1; | ||
| 52 | text-align: left; | ||
| 53 | display: flex; | ||
| 54 | align-items: baseline; | ||
| 55 | gap: 5px; | ||
| 56 | } | ||
| 57 | |||
| 58 | .regex-debugger-rule .rule-name { | ||
| 59 | font-weight: bold; | ||
| 60 | } | ||
| 61 | |||
| 62 | .regex-debugger-rule .rule-regex { | ||
| 63 | font-size: 0.8em; | ||
| 64 | opacity: 0.8; | ||
| 65 | font-family: var(--monoFontFamily); | ||
| 66 | } | ||
| 67 | |||
| 68 | .regex-debugger-rule .rule-scope { | ||
| 69 | font-size: 0.8em; | ||
| 70 | padding: 2px 6px; | ||
| 71 | border-radius: 5px; | ||
| 72 | background-color: var(--black30a); | ||
| 73 | margin-left: auto; | ||
| 74 | margin-right: 10px; | ||
| 75 | } | ||
| 76 | |||
| 77 | .regex-debugger-rule .menu_button { | ||
| 78 | margin: 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | #regex_debugger_raw_input { | ||
| 82 | min-height: 1.8em; | ||
| 83 | } | ||
| 84 | |||
| 85 | #regex_debugger_steps_output { | ||
| 86 | min-height: 2em; | ||
| 87 | max-height: 300px; | ||
| 88 | overflow-y: auto; | ||
| 89 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 90 | border-radius: 5px; | ||
| 91 | padding: 5px; | ||
| 92 | background-color: var(--black30a); | ||
| 93 | font-family: var(--monoFontFamily); | ||
| 94 | font-size: 0.9em; | ||
| 95 | } | ||
| 96 | |||
| 97 | #regex_debugger_final_output { | ||
| 98 | min-height: 2em; | ||
| 99 | max-height: 300px; | ||
| 100 | overflow-y: auto; | ||
| 101 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 102 | border-radius: 5px; | ||
| 103 | padding: 5px; | ||
| 104 | background-color: var(--black30a); | ||
| 105 | white-space: pre-wrap; | ||
| 106 | word-break: break-word; | ||
| 107 | text-align: left; | ||
| 108 | } | ||
| 109 | |||
| 110 | .step-header { | ||
| 111 | margin-top: 10px; | ||
| 112 | margin-bottom: 5px; | ||
| 113 | } | ||
| 114 | |||
| 115 | .step-output { | ||
| 116 | white-space: pre-wrap; | ||
| 117 | word-break: break-all; | ||
| 118 | padding: 5px; | ||
| 119 | background-color: var(--black30a); | ||
| 120 | border-radius: 5px; | ||
| 121 | text-align: left; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* Classes to replace inline styles */ | ||
| 125 | .regex-debugger-no-rules { | ||
| 126 | padding: 10px; | ||
| 127 | text-align: center; | ||
| 128 | opacity: 0.8; | ||
| 129 | } | ||
| 130 | |||
| 131 | .regex-debugger-list-header { | ||
| 132 | font-weight: bold; | ||
| 133 | padding: 10px; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* Styles for statistics */ | ||
| 137 | .step-header { | ||
| 138 | display: flex; | ||
| 139 | justify-content: space-between; | ||
| 140 | align-items: center; | ||
| 141 | } | ||
| 142 | |||
| 143 | .step-metrics { | ||
| 144 | font-size: 0.8em; | ||
| 145 | opacity: 0.8; | ||
| 146 | font-weight: normal; | ||
| 147 | } | ||
| 148 | |||
| 149 | .regex-debugger-summary { | ||
| 150 | padding: 8px; | ||
| 151 | margin-bottom: 10px; | ||
| 152 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 153 | background-color: var(--black30a); | ||
| 154 | border-radius: 5px; | ||
| 155 | text-align: center; | ||
| 156 | font-size: 0.9em; | ||
| 157 | } | ||
| 158 | |||
| 159 | .regex-debugger-tester .results-header { | ||
| 160 | position: relative; | ||
| 161 | margin: 10px 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | .regex-debugger-tester .radio_group { | ||
| 165 | text-align: left; | ||
| 166 | } | ||
| 167 | |||
| 168 | /* Styles for statistics and highlighting additions */ | ||
| 169 | .step-header { | ||
| 170 | display: flex; | ||
| 171 | justify-content: space-between; | ||
| 172 | align-items: center; | ||
| 173 | flex-wrap: wrap; | ||
| 174 | /* Allow wrapping on small screens */ | ||
| 175 | } | ||
| 176 | |||
| 177 | .step-metrics { | ||
| 178 | font-size: 0.8em; | ||
| 179 | opacity: 0.8; | ||
| 180 | font-weight: normal; | ||
| 181 | white-space: nowrap; | ||
| 182 | /* Prevent metrics from breaking line */ | ||
| 183 | margin-left: 10px; | ||
| 184 | } | ||
| 185 | |||
| 186 | .regex-debugger-summary { | ||
| 187 | padding: 8px; | ||
| 188 | margin-bottom: 10px; | ||
| 189 | border: 1px solid var(--SmartThemeBorderColor); | ||
| 190 | background-color: var(--black30a); | ||
| 191 | border-radius: 5px; | ||
| 192 | text-align: center; | ||
| 193 | font-size: 0.9em; | ||
| 194 | } | ||
| 195 | |||
| 196 | /* New highlight color for added text */ | ||
| 197 | mark.green_hl { | ||
| 198 | background-color: #28a745; | ||
| 199 | /* A standard green color */ | ||
| 200 | color: white; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* New highlight color for deleted text */ | ||
| 204 | mark.red_hl { | ||
| 205 | background-color: #dc3545; | ||
| 206 | /* A standard red color */ | ||
| 207 | color: white; | ||
| 208 | text-decoration: line-through; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* Styles for the expanded view with navigation */ | ||
| 212 | .expanded-regex-container { | ||
| 213 | display: flex; | ||
| 214 | height: 75vh; | ||
| 215 | /* Give the container a good height */ | ||
| 216 | overflow: hidden; | ||
| 217 | } | ||
| 218 | |||
| 219 | .expanded-regex-nav { | ||
| 220 | flex: 0 0 200px; | ||
| 221 | /* Fixed width for the nav bar */ | ||
| 222 | border-right: 1px solid var(--SmartThemeBorderColor); | ||
| 223 | padding: 5px; | ||
| 224 | overflow-y: auto; | ||
| 225 | background-color: var(--black30a); | ||
| 226 | } | ||
| 227 | |||
| 228 | .expanded-regex-nav a { | ||
| 229 | display: block; | ||
| 230 | padding: 6px 8px; | ||
| 231 | text-decoration: none; | ||
| 232 | color: var(--SmartThemeMainColor); | ||
| 233 | border-radius: 5px; | ||
| 234 | white-space: nowrap; | ||
| 235 | overflow: hidden; | ||
| 236 | text-overflow: ellipsis; | ||
| 237 | } | ||
| 238 | |||
| 239 | .expanded-regex-nav a:hover { | ||
| 240 | background-color: var(--background_hover_color); | ||
| 241 | } | ||
| 242 | |||
| 243 | .expanded-regex-nav a.active { | ||
| 244 | background-color: var(--highlight_color); | ||
| 245 | color: var(--text_color_black); | ||
| 246 | } | ||
| 247 | |||
| 248 | .expanded-regex-content { | ||
| 249 | flex-grow: 1; | ||
| 250 | overflow-y: auto; | ||
| 251 | padding-left: 10px; | ||
| 252 | } | ||
| 253 | |||
| 254 | #regex_debugger_render_mode { | ||
| 255 | padding-right: 20px; | ||
| 256 | margin-top: 5px; | ||
| 257 | } | ||
| 258 | |||
| 259 | .regex-popup-content { | ||
| 260 | white-space: pre-wrap; | ||
| 261 | word-break: break-all; | ||
| 262 | text-align: left; | ||
| 263 | } | ||
| @@ -0,0 +1,175 @@ | |||
| 1 | <div class="regex-debugger-container"> | ||
| 2 | <!-- Rules List Column --> | ||
| 3 | <div class="regex-debugger-rules-list"> | ||
| 4 | <h3> | ||
| 5 | <i class="fa-solid fa-list-ol"></i> | ||
| 6 | <span data-i18n="ext_regex_debugger_active_rules" | ||
| 7 | >Active Rules</span | ||
| 8 | > | ||
| 9 | </h3> | ||
| 10 | <div class="flex-container"> | ||
| 11 | <button | ||
| 12 | id="regex_debugger_save_order" | ||
| 13 | class="menu_button menu_button_icon interactable" | ||
| 14 | title="Save current rule order" | ||
| 15 | tabindex="0" | ||
| 16 | > | ||
| 17 | <i class="fa-solid fa-floppy-disk"></i> | ||
| 18 | <span data-i18n="ext_regex_debugger_save_order" | ||
| 19 | >Save Order</span | ||
| 20 | > | ||
| 21 | </button> | ||
| 22 | </div> | ||
| 23 | <ul id="regex_debugger_rules" class="sortable-list"> | ||
| 24 | <!-- Rules will be populated here by JavaScript --> | ||
| 25 | </ul> | ||
| 26 | </div> | ||
| 27 | |||
| 28 | <!-- Testing Area Column --> | ||
| 29 | <div class="regex-debugger-tester"> | ||
| 30 | <h3> | ||
| 31 | <i class="fa-solid fa-vial"></i> | ||
| 32 | <span data-i18n="ext_regex_debugger_testing_area" | ||
| 33 | >Testing Area</span | ||
| 34 | > | ||
| 35 | </h3> | ||
| 36 | <div class="regex-debugger-io"> | ||
| 37 | <div class="regex-debugger-input"> | ||
| 38 | <label | ||
| 39 | for="regex_debugger_raw_input" | ||
| 40 | data-i18n="ext_regex_debugger_raw_input" | ||
| 41 | >Raw Input</label | ||
| 42 | > | ||
| 43 | <textarea | ||
| 44 | id="regex_debugger_raw_input" | ||
| 45 | class="text_pole autoSetHeight" | ||
| 46 | rows="4" | ||
| 47 | ></textarea> | ||
| 48 | </div> | ||
| 49 | <div | ||
| 50 | id="regex_debugger_run_test_header" | ||
| 51 | class="flex-container" | ||
| 52 | > | ||
| 53 | <button | ||
| 54 | id="regex_debugger_run_test" | ||
| 55 | class="menu_button menu_button_icon interactable" | ||
| 56 | title="Run the test pipeline" | ||
| 57 | tabindex="0" | ||
| 58 | > | ||
| 59 | <i class="fa-solid fa-play"></i> | ||
| 60 | <span data-i18n="ext_regex_debugger_run_test" | ||
| 61 | >Run Test</span | ||
| 62 | > | ||
| 63 | </button> | ||
| 64 | <div class="flex-container gap10px"> | ||
| 65 | <div class="radio_group"> | ||
| 66 | <label | ||
| 67 | ><input | ||
| 68 | type="radio" | ||
| 69 | name="display_mode" | ||
| 70 | value="replace" | ||
| 71 | checked | ||
| 72 | /> | ||
| 73 | <span data-i18n="ext_regex_debugger_display_replace" | ||
| 74 | >Replace</span | ||
| 75 | ></label | ||
| 76 | > | ||
| 77 | <label | ||
| 78 | ><input | ||
| 79 | type="radio" | ||
| 80 | name="display_mode" | ||
| 81 | value="highlight" | ||
| 82 | /> | ||
| 83 | <span | ||
| 84 | data-i18n="ext_regex_debugger_display_highlight" | ||
| 85 | >Highlight</span | ||
| 86 | ></label | ||
| 87 | > | ||
| 88 | </div> | ||
| 89 | <select | ||
| 90 | id="regex_debugger_render_mode" | ||
| 91 | > | ||
| 92 | <option | ||
| 93 | value="text" | ||
| 94 | data-i18n="ext_regex_debugger_render_text" | ||
| 95 | > | ||
| 96 | Render as Text | ||
| 97 | </option> | ||
| 98 | <option | ||
| 99 | value="message" | ||
| 100 | data-i18n="ext_regex_debugger_render_message" | ||
| 101 | > | ||
| 102 | Render as Message | ||
| 103 | </option> | ||
| 104 | </select> | ||
| 105 | </div> | ||
| 106 | </div> | ||
| 107 | <div class="regex-debugger-results"> | ||
| 108 | <div class="results-header"> | ||
| 109 | <h4> | ||
| 110 | <i class="fa-solid fa-shoe-prints"></i> | ||
| 111 | <span data-i18n="ext_regex_debugger_step_by_step" | ||
| 112 | >Step-by-step Transformation</span | ||
| 113 | > | ||
| 114 | </h4> | ||
| 115 | <div | ||
| 116 | id="regex_debugger_expand_steps" | ||
| 117 | class="menu_button menu_button_icon" | ||
| 118 | title="Expand view" | ||
| 119 | > | ||
| 120 | <i class="fa-solid fa-expand"></i> | ||
| 121 | </div> | ||
| 122 | </div> | ||
| 123 | <div id="regex_debugger_steps_output" class="results-box"></div> | ||
| 124 | |||
| 125 | <div class="results-header"> | ||
| 126 | <h4> | ||
| 127 | <i class="fa-solid fa-flag-checkered"></i> | ||
| 128 | <span data-i18n="ext_regex_debugger_final_output" | ||
| 129 | >Final Output</span | ||
| 130 | > | ||
| 131 | </h4> | ||
| 132 | <div | ||
| 133 | id="regex_debugger_expand_final" | ||
| 134 | class="menu_button menu_button_icon" | ||
| 135 | title="Expand view" | ||
| 136 | > | ||
| 137 | <i class="fa-solid fa-expand"></i> | ||
| 138 | </div> | ||
| 139 | </div> | ||
| 140 | <div | ||
| 141 | id="regex_debugger_final_output" | ||
| 142 | class="results-box final-output" | ||
| 143 | ></div> | ||
| 144 | </div> | ||
| 145 | </div> | ||
| 146 | </div> | ||
| 147 | </div> | ||
| 148 | |||
| 149 | <!-- Template for a single rule item --> | ||
| 150 | <template id="regex_debugger_rule_template"> | ||
| 151 | <li class="regex-debugger-rule" draggable="true"> | ||
| 152 | <i class="fa-solid fa-grip-vertical handle"></i> | ||
| 153 | <label class="checkbox"> | ||
| 154 | <input type="checkbox" class="rule-enabled" checked /> | ||
| 155 | </label> | ||
| 156 | <div class="rule-details"> | ||
| 157 | <span class="rule-name"></span> | ||
| 158 | <code class="rule-regex"></code> | ||
| 159 | <small class="rule-scope"></small> | ||
| 160 | </div> | ||
| 161 | <div class="menu_button menu_button_icon edit_rule" title="Edit Rule"> | ||
| 162 | <i class="fa-solid fa-pencil"></i> | ||
| 163 | </div> | ||
| 164 | </li> | ||
| 165 | </template> | ||
| 166 | |||
| 167 | <!-- Template for a single transformation step --> | ||
| 168 | <template id="regex_debugger_step_template"> | ||
| 169 | <div class="step-result"> | ||
| 170 | <div class="step-header"> | ||
| 171 | <strong></strong> | ||
| 172 | </div> | ||
| 173 | <pre class="step-output"></pre> | ||
| 174 | </div> | ||
| 175 | </template> | ||
| @@ -26,6 +26,10 @@ | |||
| 26 | <i class="fa-solid fa-edit"></i> | 26 | <i class="fa-solid fa-edit"></i> |
| 27 | <small data-i18n="ext_regex_bulk_edit">Bulk Edit</small> | 27 | <small data-i18n="ext_regex_bulk_edit">Bulk Edit</small> |
| 28 | </label> | 28 | </label> |
| 29 | <div id="open_regex_debugger" class="menu_button menu_button_icon" data-i18n="[title]ext_regex_debugger_desc" title="Advanced Regex Debugger"> | ||
| 30 | <i class="fa-solid fa-bug-slash"></i> | ||
| 31 | <small data-i18n="ext_regex_debugger">Debugger</small> | ||
| 32 | </div> | ||
| 29 | </div> | 33 | </div> |
| 30 | <div class="regex_bulk_operations flex-container justifyCenter"> | 34 | <div class="regex_bulk_operations flex-container justifyCenter"> |
| 31 | <div id="bulk_select_all_toggle" class="menu_button menu_button_icon" title="Toggle Select All"> | 35 | <div id="bulk_select_all_toggle" class="menu_button menu_button_icon" title="Toggle Select All"> |
| @@ -49,6 +53,22 @@ | |||
| 49 | </div> | 53 | </div> |
| 50 | </div> | 54 | </div> |
| 51 | <hr /> | 55 | <hr /> |
| 56 | <div id="regex_presets_block"> | ||
| 57 | <div class="flex-container alignItemsBaseline"> | ||
| 58 | <strong class="flex1" data-i18n="ext_regex_presets">Regex Presets</strong> | ||
| 59 | </div> | ||
| 60 | <small data-i18n="ext_regex_presets_desc"> | ||
| 61 | Save and switch between groups of enabled regex scripts. | ||
| 62 | </small> | ||
| 63 | <div class="flex-container marginTop5"> | ||
| 64 | <select id="regex_presets" class="text_pole flex1"></select> | ||
| 65 | <div id="regex_preset_create" class="menu_button fa-solid fa-file-circle-plus" data-i18n="[title]ext_regex_preset_create" title="Create a new regex preset"></div> | ||
| 66 | <div id="regex_preset_update" class="menu_button fa-solid fa-save" data-i18n="[title]ext_regex_preset_update" title="Update existing regex preset"></div> | ||
| 67 | <div id="regex_preset_apply" class="menu_button fa-solid fa-recycle" data-i18n="[title]ext_regex_preset_apply" title="Re-apply current preset"></div> | ||
| 68 | <div id="regex_preset_delete" class="menu_button fa-solid fa-trash" data-i18n="[title]ext_regex_preset_delete" title="Delete current preset"></div> | ||
| 69 | </div> | ||
| 70 | </div> | ||
| 71 | <hr /> | ||
| 52 | <div id="global_scripts_block" class="padding5"> | 72 | <div id="global_scripts_block" class="padding5"> |
| 53 | <div> | 73 | <div> |
| 54 | <strong data-i18n="ext_regex_global_scripts">Global Scripts</strong> | 74 | <strong data-i18n="ext_regex_global_scripts">Global Scripts</strong> |
| @@ -1,13 +1,13 @@ | |||
| 1 | import { characters, eventSource, event_types, getCurrentChatId, reloadCurrentChat, saveSettingsDebounced, this_chid } from '../../../script.js'; | 1 | import { characters, eventSource, event_types, getCurrentChatId, messageFormatting, reloadCurrentChat, saveSettingsDebounced, this_chid } from '../../../script.js'; |
| 2 | import { extension_settings, renderExtensionTemplateAsync, writeExtensionField } from '../../extensions.js'; | 2 | import { extension_settings, renderExtensionTemplateAsync, writeExtensionField } from '../../extensions.js'; |
| 3 | import { selected_group } from '../../group-chats.js'; | 3 | import { selected_group } from '../../group-chats.js'; |
| 4 | import { callGenericPopup, POPUP_TYPE } from '../../popup.js'; | 4 | import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js'; |
| 5 | import { SlashCommand } from '../../slash-commands/SlashCommand.js'; | 5 | import { SlashCommand } from '../../slash-commands/SlashCommand.js'; |
| 6 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js'; | 6 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js'; |
| 7 | import { commonEnumProviders, enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; | 7 | import { commonEnumProviders, enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 8 | import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js'; | 8 | import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js'; |
| 9 | import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; | 9 | import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; |
| 10 | import { download, equalsIgnoreCaseAndAccents, getFileText, getSortableDelay, isFalseBoolean, isTrueBoolean, regexFromString, setInfoBlock, uuidv4 } from '../../utils.js'; | 10 | import { download, equalsIgnoreCaseAndAccents, getFileText, getSortableDelay, isFalseBoolean, isTrueBoolean, regexFromString, setInfoBlock, uuidv4, escapeHtml } from '../../utils.js'; |
| 11 | import { regex_placement, runRegexScript, substitute_find_regex } from './engine.js'; | 11 | import { regex_placement, runRegexScript, substitute_find_regex } from './engine.js'; |
| 12 | import { t } from '../../i18n.js'; | 12 | import { t } from '../../i18n.js'; |
| 13 | import { accountStorage } from '../../util/AccountStorage.js'; | 13 | import { accountStorage } from '../../util/AccountStorage.js'; |
| @@ -19,6 +19,452 @@ const sanitizeFileName = name => name.replace(/[\s.<>:"/\\|?*\x00-\x1F\x7F]/g, ' | |||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | /** | 21 | /** |
| 22 | * @typedef {object} RegexPresetItem | ||
| 23 | * @property {string} id - UUID of the regex script | ||
| 24 | */ | ||
| 25 | |||
| 26 | /** | ||
| 27 | * @typedef {object} RegexPreset | ||
| 28 | * @property {string} id - UUID of the preset | ||
| 29 | * @property {string} name - Name of the preset | ||
| 30 | * @property {boolean} isSelected - Whether the preset is currently selected | ||
| 31 | * @property {RegexPresetItem[]} global - The list of global preset items | ||
| 32 | * @property {RegexPresetItem[]} scoped - The list of scoped preset items | ||
| 33 | */ | ||
| 34 | |||
| 35 | /** | ||
| 36 | * @typedef {object} RegexPresetState | ||
| 37 | * @property {string[]} global - List of enabled global regex script IDs | ||
| 38 | * @property {string[]} scoped - List of enabled scoped regex script IDs | ||
| 39 | */ | ||
| 40 | |||
| 41 | class RegexPresetManager { | ||
| 42 | /** @type {HTMLSelectElement} */ | ||
| 43 | presetSelect = null; | ||
| 44 | |||
| 45 | /** @type {HTMLElement} */ | ||
| 46 | presetCreateButton = null; | ||
| 47 | |||
| 48 | /** @type {HTMLElement} */ | ||
| 49 | presetUpdateButton = null; | ||
| 50 | |||
| 51 | /** @type {HTMLElement} */ | ||
| 52 | presetApplyButton = null; | ||
| 53 | |||
| 54 | /** @type {HTMLElement} */ | ||
| 55 | presetDeleteButton = null; | ||
| 56 | |||
| 57 | /** @type {string|null} */ | ||
| 58 | currentPresetId = null; | ||
| 59 | |||
| 60 | /** @type {RegexPresetState|null} */ | ||
| 61 | lastKnownState = null; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * Captures the current state of enabled regex scripts for change detection. | ||
| 65 | * @returns {RegexPresetState} The current state object | ||
| 66 | */ | ||
| 67 | captureCurrentState() { | ||
| 68 | const globalScripts = this.regexListToPresetItems(extension_settings.regex) || []; | ||
| 69 | const scopedScripts = this.regexListToPresetItems(characters[this_chid]?.data?.extensions?.regex_scripts) || []; | ||
| 70 | |||
| 71 | return { | ||
| 72 | global: globalScripts.map(item => item.id).sort(), | ||
| 73 | scoped: scopedScripts.map(item => item.id).sort(), | ||
| 74 | }; | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Compares two state objects to detect changes. | ||
| 79 | * @param {RegexPresetState} state1 First state object | ||
| 80 | * @param {RegexPresetState} state2 Second state object | ||
| 81 | * @returns {boolean} True if states are different | ||
| 82 | */ | ||
| 83 | hasStateChanged(state1, state2) { | ||
| 84 | if (!state1 || !state2) return false; | ||
| 85 | |||
| 86 | const global1 = state1.global || []; | ||
| 87 | const global2 = state2.global || []; | ||
| 88 | const scoped1 = state1.scoped || []; | ||
| 89 | const scoped2 = state2.scoped || []; | ||
| 90 | |||
| 91 | if (global1.length !== global2.length || scoped1.length !== scoped2.length) { | ||
| 92 | return true; | ||
| 93 | } | ||
| 94 | |||
| 95 | return !global1.every(id => global2.includes(id)) || | ||
| 96 | !scoped1.every(id => scoped2.includes(id)); | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Updates the stored state after a preset is applied or saved. | ||
| 101 | * @param {string} presetId - The current preset ID | ||
| 102 | */ | ||
| 103 | updateStoredState(presetId) { | ||
| 104 | this.currentPresetId = presetId; | ||
| 105 | this.lastKnownState = this.captureCurrentState(); | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | * Checks if there are unsaved changes and shows a confirmation dialog. | ||
| 110 | * @returns {Promise<boolean>} True if user wants to proceed without saving | ||
| 111 | */ | ||
| 112 | async checkUnsavedChanges() { | ||
| 113 | if (!this.currentPresetId || !this.lastKnownState) { | ||
| 114 | return true; // No current preset or state to compare | ||
| 115 | } | ||
| 116 | |||
| 117 | const currentState = this.captureCurrentState(); | ||
| 118 | if (!this.hasStateChanged(this.lastKnownState, currentState)) { | ||
| 119 | return true; // No changes detected | ||
| 120 | } | ||
| 121 | |||
| 122 | const currentPreset = extension_settings.regex_presets.find(p => p.id === this.currentPresetId); | ||
| 123 | const presetName = currentPreset ? currentPreset.name : t`Unknown Preset`; | ||
| 124 | |||
| 125 | const choice = await Popup.show.confirm( | ||
| 126 | t`You have unsaved changes to the "${presetName}" preset.`, | ||
| 127 | t`Do you want to save them before switching?`, | ||
| 128 | { | ||
| 129 | okButton: t`Save Changes`, | ||
| 130 | cancelButton: t`Discard Changes`, | ||
| 131 | }, | ||
| 132 | ); | ||
| 133 | |||
| 134 | if (choice) { | ||
| 135 | // User chose to save changes | ||
| 136 | await this.savePreset(this.currentPresetId, true); | ||
| 137 | this.renderPresetList(); | ||
| 138 | return true; | ||
| 139 | } | ||
| 140 | |||
| 141 | // User chose to discard changes | ||
| 142 | return true; | ||
| 143 | } | ||
| 144 | |||
| 145 | /** | ||
| 146 | * Sets up event listeners for the preset management UI. | ||
| 147 | * @returns {void} | ||
| 148 | */ | ||
| 149 | setupEventListeners() { | ||
| 150 | this.presetSelect = /** @type {HTMLSelectElement} */ (document.getElementById('regex_presets')); | ||
| 151 | if (!this.presetSelect) { | ||
| 152 | console.error('RegexPresetManager: Could not find preset select element in the DOM.'); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | |||
| 156 | this.presetSelect.addEventListener('change', async (event) => { | ||
| 157 | const selectedPresetId = this.presetSelect.value; | ||
| 158 | const fromSlashCommand = event instanceof CustomEvent && event?.detail?.fromSlashCommand === true; | ||
| 159 | |||
| 160 | // Check for unsaved changes before switching | ||
| 161 | if (!fromSlashCommand) { | ||
| 162 | const canProceed = await this.checkUnsavedChanges(); | ||
| 163 | if (!canProceed) { | ||
| 164 | // Revert the selection | ||
| 165 | event.preventDefault(); | ||
| 166 | const currentPreset = extension_settings.regex_presets.find(p => p.id === this.currentPresetId); | ||
| 167 | if (currentPreset) { | ||
| 168 | this.presetSelect.value = currentPreset.id; | ||
| 169 | } | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | await this.applyPreset(selectedPresetId); | ||
| 175 | extension_settings.regex_presets.forEach(p => { p.isSelected = p.id === selectedPresetId; }); | ||
| 176 | saveSettingsDebounced(); | ||
| 177 | this.updateStoredState(selectedPresetId); | ||
| 178 | }); | ||
| 179 | |||
| 180 | this.presetCreateButton = document.getElementById('regex_preset_create'); | ||
| 181 | if (!this.presetCreateButton) { | ||
| 182 | console.error('RegexPresetManager: Could not find preset create button in the DOM.'); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 186 | this.presetCreateButton.addEventListener('click', async () => { | ||
| 187 | const newId = uuidv4(); | ||
| 188 | await this.savePreset(newId, false); | ||
| 189 | this.renderPresetList(); | ||
| 190 | this.updateStoredState(newId); | ||
| 191 | }); | ||
| 192 | |||
| 193 | this.presetUpdateButton = document.getElementById('regex_preset_update'); | ||
| 194 | if (!this.presetUpdateButton) { | ||
| 195 | console.error('RegexPresetManager: Could not find preset update button in the DOM.'); | ||
| 196 | return; | ||
| 197 | } | ||
| 198 | |||
| 199 | this.presetUpdateButton.addEventListener('click', async () => { | ||
| 200 | const selectedPresetId = this.presetSelect.value; | ||
| 201 | await this.savePreset(selectedPresetId, true); | ||
| 202 | this.renderPresetList(); | ||
| 203 | this.updateStoredState(selectedPresetId); | ||
| 204 | }); | ||
| 205 | |||
| 206 | this.presetApplyButton = document.getElementById('regex_preset_apply'); | ||
| 207 | if (!this.presetApplyButton) { | ||
| 208 | console.error('RegexPresetManager: Could not find preset apply button in the DOM.'); | ||
| 209 | return; | ||
| 210 | } | ||
| 211 | |||
| 212 | this.presetApplyButton.addEventListener('click', async () => { | ||
| 213 | const selectedPresetId = this.presetSelect.value; | ||
| 214 | await this.applyPreset(selectedPresetId); | ||
| 215 | this.updateStoredState(selectedPresetId); | ||
| 216 | }); | ||
| 217 | |||
| 218 | this.presetDeleteButton = document.getElementById('regex_preset_delete'); | ||
| 219 | if (!this.presetDeleteButton) { | ||
| 220 | console.error('RegexPresetManager: Could not find preset delete button in the DOM.'); | ||
| 221 | return; | ||
| 222 | } | ||
| 223 | |||
| 224 | this.presetDeleteButton.addEventListener('click', async () => { | ||
| 225 | const selectedPresetId = this.presetSelect.value; | ||
| 226 | await this.deletePreset(selectedPresetId); | ||
| 227 | this.renderPresetList(); | ||
| 228 | |||
| 229 | const newSelectedPresetId = extension_settings.regex_presets.find(p => p.isSelected)?.id; | ||
| 230 | if (newSelectedPresetId) { | ||
| 231 | await this.applyPreset(newSelectedPresetId); | ||
| 232 | this.presetSelect.value = newSelectedPresetId; | ||
| 233 | this.updateStoredState(newSelectedPresetId); | ||
| 234 | } else { | ||
| 235 | this.currentPresetId = null; | ||
| 236 | this.lastKnownState = null; | ||
| 237 | } | ||
| 238 | }); | ||
| 239 | |||
| 240 | this.renderPresetList(); | ||
| 241 | |||
| 242 | // Initialize the stored state with the currently selected preset | ||
| 243 | const selectedPreset = extension_settings.regex_presets?.find(p => p.isSelected); | ||
| 244 | if (selectedPreset) { | ||
| 245 | this.updateStoredState(selectedPreset.id); | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | /** | ||
| 250 | * Registers slash commands related to regex presets. | ||
| 251 | * @returns {void} | ||
| 252 | */ | ||
| 253 | registerSlashCommands() { | ||
| 254 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 255 | name: 'regex-preset', | ||
| 256 | helpString: t`Selects a regex preset by name or ID. Gets the current regex preset ID if no argument is provided.`, | ||
| 257 | callback: (args, name) => { | ||
| 258 | if (!this.presetSelect) { | ||
| 259 | return ''; | ||
| 260 | } | ||
| 261 | |||
| 262 | name = String(name ?? '').trim(); | ||
| 263 | |||
| 264 | if (name) { | ||
| 265 | const quiet = isTrueBoolean(args?.quiet?.toString()); | ||
| 266 | const foundId = extension_settings.regex_presets.find(p => equalsIgnoreCaseAndAccents(p.id, name) || equalsIgnoreCaseAndAccents(p.name, name))?.id; | ||
| 267 | |||
| 268 | if (foundId) { | ||
| 269 | this.presetSelect.value = foundId; | ||
| 270 | this.presetSelect.dispatchEvent(new CustomEvent('change', { detail: { fromSlashCommand: true } })); | ||
| 271 | return foundId; | ||
| 272 | } | ||
| 273 | |||
| 274 | !quiet && toastr.warning(`Regex preset "${name}" not found`); | ||
| 275 | return ''; | ||
| 276 | } | ||
| 277 | |||
| 278 | return this.presetSelect.value; | ||
| 279 | }, | ||
| 280 | returns: 'current preset ID', | ||
| 281 | namedArgumentList: [ | ||
| 282 | SlashCommandNamedArgument.fromProps({ | ||
| 283 | name: 'quiet', | ||
| 284 | description: 'Suppress the toast message on preset change', | ||
| 285 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 286 | defaultValue: 'false', | ||
| 287 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 288 | }), | ||
| 289 | ], | ||
| 290 | unnamedArgumentList: [ | ||
| 291 | SlashCommandArgument.fromProps({ | ||
| 292 | description: 'regex preset name or ID', | ||
| 293 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 294 | enumProvider: () => extension_settings.regex_presets.map(x => new SlashCommandEnumValue(x.id, x.name, enumTypes.enum, enumIcons.preset)), | ||
| 295 | }), | ||
| 296 | ], | ||
| 297 | })); | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * Renders the list of regex presets in the UI. | ||
| 302 | * @returns {void} | ||
| 303 | */ | ||
| 304 | renderPresetList() { | ||
| 305 | if (!this.presetSelect) { | ||
| 306 | return; | ||
| 307 | } | ||
| 308 | |||
| 309 | this.presetSelect.innerHTML = ''; | ||
| 310 | |||
| 311 | if (!Array.isArray(extension_settings.regex_presets) || extension_settings.regex_presets.length === 0) { | ||
| 312 | const fallbackOption = new Option(t`[No presets saved]`, '', true, true); | ||
| 313 | this.presetSelect.appendChild(fallbackOption); | ||
| 314 | this.presetSelect.disabled = true; | ||
| 315 | return; | ||
| 316 | } | ||
| 317 | |||
| 318 | extension_settings.regex_presets.forEach(preset => { | ||
| 319 | const option = new Option(preset.name, preset.id, preset.isSelected, preset.isSelected); | ||
| 320 | this.presetSelect.appendChild(option); | ||
| 321 | }); | ||
| 322 | |||
| 323 | this.presetSelect.disabled = false; | ||
| 324 | } | ||
| 325 | |||
| 326 | /** | ||
| 327 | * Applies a preset list to a target list of scripts. | ||
| 328 | * @param {Object} params The parameters object | ||
| 329 | * @param {RegexPresetItem[]} params.presetList The list of preset items | ||
| 330 | * @param {RegexScript[]} params.targetList The list of target scripts to modify | ||
| 331 | * @param {(targetList: RegexScript[]) => Promise<any>} params.saveFunction Function to save the modified list | ||
| 332 | */ | ||
| 333 | async applyPresetList({ presetList, targetList, saveFunction }) { | ||
| 334 | if (!Array.isArray(targetList) || !Array.isArray(presetList)) { | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | |||
| 338 | // Only enable scripts that are in the preset | ||
| 339 | targetList.forEach((script => { | ||
| 340 | script.disabled = !presetList.some(p => p.id === script.id); | ||
| 341 | })); | ||
| 342 | |||
| 343 | // First sort by the order in the preset, then the original order | ||
| 344 | targetList.sort((a, b) => { | ||
| 345 | const aIndex = presetList.findIndex(p => p.id === a.id); | ||
| 346 | const bIndex = presetList.findIndex(p => p.id === b.id); | ||
| 347 | return aIndex - bIndex || targetList.indexOf(a) - targetList.indexOf(b); | ||
| 348 | }); | ||
| 349 | |||
| 350 | await saveFunction(targetList); | ||
| 351 | } | ||
| 352 | |||
| 353 | /** | ||
| 354 | * Applies a regex preset to the current context. | ||
| 355 | * @param {string} presetId - The ID of the preset to apply | ||
| 356 | * @returns {Promise<void>} | ||
| 357 | */ | ||
| 358 | async applyPreset(presetId) { | ||
| 359 | const preset = extension_settings.regex_presets.find(p => p.id === presetId); | ||
| 360 | if (!preset) { | ||
| 361 | toastr.error(t`Could not find the selected preset.`); | ||
| 362 | return; | ||
| 363 | } | ||
| 364 | |||
| 365 | // Apply to both global and scoped lists | ||
| 366 | await this.applyPresetList({ | ||
| 367 | presetList: preset.global, | ||
| 368 | targetList: extension_settings.regex, | ||
| 369 | saveFunction: () => saveSettingsDebounced(), | ||
| 370 | }); | ||
| 371 | await this.applyPresetList({ | ||
| 372 | presetList: preset.scoped, | ||
| 373 | targetList: characters[this_chid]?.data?.extensions?.regex_scripts, | ||
| 374 | saveFunction: (scripts) => writeExtensionField(this_chid, 'regex_scripts', scripts), | ||
| 375 | }); | ||
| 376 | |||
| 377 | // Render the changes to the UI | ||
| 378 | await loadRegexScripts(); | ||
| 379 | // Apply the changes to the current chat | ||
| 380 | await reloadCurrentChat(); | ||
| 381 | } | ||
| 382 | |||
| 383 | /** | ||
| 384 | * Converts a list of regex scripts to preset items. | ||
| 385 | * @param {RegexScript[]} list The list of regex scripts | ||
| 386 | * @returns {RegexPresetItem[] | null} The list of preset items, or null if the input is invalid | ||
| 387 | */ | ||
| 388 | regexListToPresetItems(list) { | ||
| 389 | if (!Array.isArray(list)) { | ||
| 390 | return null; | ||
| 391 | } | ||
| 392 | |||
| 393 | return list.filter(x => !x.disabled).map(s => ({ id: s.id })); | ||
| 394 | } | ||
| 395 | |||
| 396 | /** | ||
| 397 | * Saves a regex preset. | ||
| 398 | * @param {string} presetId - The ID of the preset | ||
| 399 | * @param {boolean} isUpdate - Whether this is an update operation | ||
| 400 | * @returns {Promise<void>} | ||
| 401 | */ | ||
| 402 | async savePreset(presetId, isUpdate) { | ||
| 403 | const existingPreset = isUpdate ? extension_settings.regex_presets.find(p => p.id === presetId) : null; | ||
| 404 | |||
| 405 | if (isUpdate && !existingPreset) { | ||
| 406 | toastr.error(t`Could not find the preset to update.`); | ||
| 407 | return; | ||
| 408 | } | ||
| 409 | |||
| 410 | const name = isUpdate ? existingPreset.name : await Popup.show.input(t`Enter a name for the new regex preset:`, ''); | ||
| 411 | const id = isUpdate ? existingPreset.id : presetId; | ||
| 412 | |||
| 413 | if (!name || !name.trim().length) { | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | |||
| 417 | const preset = { | ||
| 418 | id: id, | ||
| 419 | name: name, | ||
| 420 | isSelected: false, | ||
| 421 | global: this.regexListToPresetItems(extension_settings.regex), | ||
| 422 | scoped: this.regexListToPresetItems(characters[this_chid]?.data?.extensions?.regex_scripts), | ||
| 423 | }; | ||
| 424 | |||
| 425 | if (isUpdate) { | ||
| 426 | Object.assign(existingPreset, preset); | ||
| 427 | } else { | ||
| 428 | extension_settings.regex_presets.push(preset); | ||
| 429 | } | ||
| 430 | |||
| 431 | extension_settings.regex_presets.forEach(p => { p.isSelected = p.id === id; }); | ||
| 432 | saveSettingsDebounced(); | ||
| 433 | |||
| 434 | toastr.success(isUpdate ? t`Regex preset updated` : t`Regex preset saved`); | ||
| 435 | } | ||
| 436 | |||
| 437 | /** | ||
| 438 | * Deletes a regex preset. | ||
| 439 | * @param {string} presetId - The ID of the preset to delete | ||
| 440 | * @returns {Promise<void>} | ||
| 441 | */ | ||
| 442 | async deletePreset(presetId) { | ||
| 443 | const presetIndex = extension_settings.regex_presets.findIndex(p => p.id === presetId); | ||
| 444 | if (presetIndex === -1) { | ||
| 445 | toastr.error(t`Could not find the preset to delete.`); | ||
| 446 | return; | ||
| 447 | } | ||
| 448 | |||
| 449 | const presetName = extension_settings.regex_presets[presetIndex].name; | ||
| 450 | const confirm = await Popup.show.confirm(t`Are you sure you want to delete this regex preset?`, presetName); | ||
| 451 | if (!confirm) { | ||
| 452 | return; | ||
| 453 | } | ||
| 454 | |||
| 455 | extension_settings.regex_presets.splice(presetIndex, 1); | ||
| 456 | |||
| 457 | // Select the first preset if any exist | ||
| 458 | extension_settings.regex_presets.forEach((p, i) => { p.isSelected = i === 0; }); | ||
| 459 | saveSettingsDebounced(); | ||
| 460 | |||
| 461 | toastr.success(t`Regex preset deleted`); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | const presetManager = new RegexPresetManager(); | ||
| 466 | |||
| 467 | /** | ||
| 22 | * Retrieves the list of regex scripts by combining the scripts from the extension settings and the character data | 468 | * Retrieves the list of regex scripts by combining the scripts from the extension settings and the character data |
| 23 | * | 469 | * |
| 24 | * @return {RegexScript[]} An array of regex scripts, where each script is an object containing the necessary information. | 470 | * @return {RegexScript[]} An array of regex scripts, where each script is an object containing the necessary information. |
| @@ -94,13 +540,18 @@ async function saveRegexScript(regexScript, existingScriptIndex, isScoped) { | |||
| 94 | if (currentChatId !== undefined && currentChatId !== null) { | 540 | if (currentChatId !== undefined && currentChatId !== null) { |
| 95 | await reloadCurrentChat(); | 541 | await reloadCurrentChat(); |
| 96 | } | 542 | } |
| 543 | |||
| 544 | const debuggerPopup = $('#regex_debugger_popup'); | ||
| 545 | if (debuggerPopup.length) { | ||
| 546 | populateDebuggerRuleList(debuggerPopup.parent()); | ||
| 547 | } | ||
| 97 | } | 548 | } |
| 98 | 549 | ||
| 99 | async function deleteRegexScript({ id, isScoped }) { | 550 | async function deleteRegexScript({ id, isScoped }) { |
| 100 | const array = (isScoped ? characters[this_chid]?.data?.extensions?.regex_scripts : extension_settings.regex) ?? []; | 551 | const array = (isScoped ? characters[this_chid]?.data?.extensions?.regex_scripts : extension_settings.regex) ?? []; |
| 101 | 552 | ||
| 102 | const existingScriptIndex = array.findIndex((script) => script.id === id); | 553 | const existingScriptIndex = array.findIndex((script) => script.id === id); |
| 103 | if (!existingScriptIndex || existingScriptIndex !== -1) { | 554 | if (existingScriptIndex !== -1) { |
| 104 | array.splice(existingScriptIndex, 1); | 555 | array.splice(existingScriptIndex, 1); |
| 105 | 556 | ||
| 106 | if (isScoped) { | 557 | if (isScoped) { |
| @@ -330,6 +781,442 @@ async function onRegexEditorOpenClick(existingId, isScoped) { | |||
| 330 | } | 781 | } |
| 331 | 782 | ||
| 332 | /** | 783 | /** |
| 784 | * Builds an HTML string for a replacement, highlighting literal parts in green | ||
| 785 | * and keeping back-referenced parts plain. | ||
| 786 | * @param {RegExpMatchArray} match The match object from `matchAll`. | ||
| 787 | * @param {string} pattern The replacement pattern string (e.g., "new text $1"). | ||
| 788 | * @returns {string} The constructed HTML string. | ||
| 789 | */ | ||
| 790 | function buildReplacementHtml(match, pattern) { | ||
| 791 | const container = document.createDocumentFragment(); | ||
| 792 | let lastIndex = 0; | ||
| 793 | const backrefRegex = /\$\$|\$&|\$`|\$'|\$(\d{1,2})/g; | ||
| 794 | |||
| 795 | let reMatch; | ||
| 796 | while ((reMatch = backrefRegex.exec(pattern)) !== null) { | ||
| 797 | // Part of the pattern before the back-reference is a literal. | ||
| 798 | const literalPart = pattern.substring(lastIndex, reMatch.index); | ||
| 799 | if (literalPart) { | ||
| 800 | const mark = document.createElement('mark'); | ||
| 801 | mark.className = 'green_hl'; | ||
| 802 | mark.innerText = literalPart; | ||
| 803 | container.appendChild(mark); | ||
| 804 | } | ||
| 805 | |||
| 806 | const backref = reMatch[0]; | ||
| 807 | if (backref === '$$') { | ||
| 808 | container.appendChild(document.createTextNode('$')); | ||
| 809 | } else if (backref === '$&') { | ||
| 810 | const mark = document.createElement('mark'); | ||
| 811 | mark.className = 'yellow_hl'; | ||
| 812 | mark.innerText = match[0]; | ||
| 813 | container.appendChild(mark); | ||
| 814 | } else if (backref === '$`') { | ||
| 815 | container.appendChild(document.createTextNode(match.input.substring(0, match.index))); | ||
| 816 | } else if (backref === '$\'') { | ||
| 817 | container.appendChild(document.createTextNode(match.input.substring(match.index + match[0].length))); | ||
| 818 | } else { // It's a numbered capture group, $n. | ||
| 819 | const groupIndex = parseInt(reMatch[1], 10); | ||
| 820 | if (groupIndex > 0 && groupIndex < match.length && match[groupIndex] !== undefined) { | ||
| 821 | const mark = document.createElement('mark'); | ||
| 822 | mark.className = 'yellow_hl'; | ||
| 823 | mark.innerText = match[groupIndex]; | ||
| 824 | container.appendChild(mark); | ||
| 825 | } else { | ||
| 826 | // Not a valid group index, treat it as a literal. | ||
| 827 | const mark = document.createElement('mark'); | ||
| 828 | mark.className = 'green_hl'; | ||
| 829 | mark.innerText = backref; | ||
| 830 | container.appendChild(mark); | ||
| 831 | } | ||
| 832 | } | ||
| 833 | lastIndex = backrefRegex.lastIndex; | ||
| 834 | } | ||
| 835 | |||
| 836 | // The final part of the pattern after the last back-reference. | ||
| 837 | const finalLiteralPart = pattern.substring(lastIndex); | ||
| 838 | if (finalLiteralPart) { | ||
| 839 | const mark = document.createElement('mark'); | ||
| 840 | mark.className = 'green_hl'; | ||
| 841 | mark.innerText = finalLiteralPart; | ||
| 842 | container.appendChild(mark); | ||
| 843 | } | ||
| 844 | |||
| 845 | // To get the HTML content, we need a temporary parent element. | ||
| 846 | const tempDiv = document.createElement('div'); | ||
| 847 | tempDiv.appendChild(container); | ||
| 848 | return tempDiv.innerHTML; | ||
| 849 | } | ||
| 850 | |||
| 851 | function executeRegexScriptForDebugging(script, text) { | ||
| 852 | let err; | ||
| 853 | let originalRegex; | ||
| 854 | |||
| 855 | try { | ||
| 856 | originalRegex = regexFromString(script.findRegex); | ||
| 857 | if (!originalRegex) throw new Error('Invalid regex string'); | ||
| 858 | } catch (e) { | ||
| 859 | err = `Compile error: ${e.message}`; | ||
| 860 | return { output: text, highlightedOutput: text, error: err, charsCaptured: 0, charsAdded: 0, charsRemoved: 0 }; | ||
| 861 | } | ||
| 862 | |||
| 863 | const globalRegex = new RegExp(originalRegex.source, originalRegex.flags.includes('g') ? originalRegex.flags : originalRegex.flags + 'g'); | ||
| 864 | const matches = [...text.matchAll(globalRegex)]; | ||
| 865 | |||
| 866 | if (matches.length === 0) { | ||
| 867 | return { output: text, highlightedOutput: escapeHtml(text), error: null, charsCaptured: 0, charsAdded: 0, charsRemoved: 0 }; | ||
| 868 | } | ||
| 869 | |||
| 870 | let outputText = ''; | ||
| 871 | let highlightedOutput = ''; // This will now be our "diff view" | ||
| 872 | let lastIndex = 0; | ||
| 873 | let totalCharsCaptured = 0; | ||
| 874 | let totalCharsAdded = 0; | ||
| 875 | let totalCharsRemoved = 0; | ||
| 876 | |||
| 877 | try { | ||
| 878 | for (const match of matches) { | ||
| 879 | const originalMatchText = match[0]; | ||
| 880 | totalCharsCaptured += originalMatchText.length; | ||
| 881 | |||
| 882 | // Append text between matches (this part is unchanged) | ||
| 883 | const precedingText = text.substring(lastIndex, match.index); | ||
| 884 | outputText += precedingText; | ||
| 885 | highlightedOutput += escapeHtml(precedingText); | ||
| 886 | |||
| 887 | // --- Start of new diff and statistics logic --- | ||
| 888 | let charsAddedInMatch = 0; | ||
| 889 | let charsKeptFromMatch = 0; | ||
| 890 | const backrefRegex = /\$\$|\$&|\$`|\$'|\$(\d{1,2})/g; | ||
| 891 | let lastPatternIndex = 0; | ||
| 892 | let reMatch; | ||
| 893 | let replacementForPlainText = ''; | ||
| 894 | |||
| 895 | // This loop calculates the stats accurately | ||
| 896 | while ((reMatch = backrefRegex.exec(script.replaceString)) !== null) { | ||
| 897 | const literalPart = script.replaceString.substring(lastPatternIndex, reMatch.index); | ||
| 898 | charsAddedInMatch += literalPart.length; | ||
| 899 | replacementForPlainText += literalPart; | ||
| 900 | const backref = reMatch[0]; | ||
| 901 | if (backref === '$$') { | ||
| 902 | replacementForPlainText += '$'; | ||
| 903 | } else if (backref === '$&') { | ||
| 904 | charsKeptFromMatch += (match[0] || '').length; replacementForPlainText += (match[0] || ''); | ||
| 905 | } else if (backref === '$`') { | ||
| 906 | const part = match.input.substring(0, match.index); charsKeptFromMatch += part.length; replacementForPlainText += part; | ||
| 907 | } else if (backref === '$\'') { | ||
| 908 | const part = match.input.substring(match.index + match[0].length); charsKeptFromMatch += part.length; replacementForPlainText += part; | ||
| 909 | } else { | ||
| 910 | const groupIndex = parseInt(reMatch[1], 10); | ||
| 911 | if (groupIndex > 0 && groupIndex < match.length && match[groupIndex] !== undefined) { | ||
| 912 | charsKeptFromMatch += match[groupIndex].length; | ||
| 913 | replacementForPlainText += match[groupIndex]; | ||
| 914 | } | ||
| 915 | } | ||
| 916 | lastPatternIndex = backrefRegex.lastIndex; | ||
| 917 | } | ||
| 918 | const finalLiteralPart = script.replaceString.substring(lastPatternIndex); | ||
| 919 | charsAddedInMatch += finalLiteralPart.length; | ||
| 920 | replacementForPlainText += finalLiteralPart; | ||
| 921 | |||
| 922 | totalCharsAdded += charsAddedInMatch; | ||
| 923 | totalCharsRemoved += (originalMatchText.length - charsKeptFromMatch); | ||
| 924 | |||
| 925 | outputText += replacementForPlainText; | ||
| 926 | // --- End of statistics logic --- | ||
| 927 | |||
| 928 | // --- Build the new Diff View HTML --- | ||
| 929 | // 1. Show the entire original match as "removed" (red strikethrough) | ||
| 930 | highlightedOutput += `<mark class='red_hl'>${escapeHtml(originalMatchText)}</mark>`; | ||
| 931 | // 2. Add an arrow to signify transformation | ||
| 932 | highlightedOutput += ' → '; | ||
| 933 | // 3. Build the replacement string with green (added) and yellow (kept) parts | ||
| 934 | highlightedOutput += buildReplacementHtml(match, script.replaceString); | ||
| 935 | |||
| 936 | lastIndex = match.index + originalMatchText.length; | ||
| 937 | } | ||
| 938 | |||
| 939 | // Append text after the last match | ||
| 940 | const trailingText = text.substring(lastIndex); | ||
| 941 | outputText += trailingText; | ||
| 942 | highlightedOutput += escapeHtml(trailingText); | ||
| 943 | |||
| 944 | } catch (e) { | ||
| 945 | err = (err ? err + '; ' : '') + `Replace error: ${e.message}`; | ||
| 946 | outputText = text; // Fallback | ||
| 947 | highlightedOutput = escapeHtml(text); | ||
| 948 | } | ||
| 949 | |||
| 950 | return { | ||
| 951 | output: outputText, | ||
| 952 | highlightedOutput: highlightedOutput, | ||
| 953 | error: err, | ||
| 954 | charsCaptured: totalCharsCaptured, | ||
| 955 | charsAdded: totalCharsAdded, | ||
| 956 | charsRemoved: totalCharsRemoved, | ||
| 957 | }; | ||
| 958 | } | ||
| 959 | |||
| 960 | function populateDebuggerRuleList(container) { | ||
| 961 | const rulesContainer = container.find('#regex_debugger_rules'); | ||
| 962 | const ruleTemplate = container.find('#regex_debugger_rule_template'); | ||
| 963 | if (!rulesContainer.length || !ruleTemplate.length) { | ||
| 964 | console.error('Regex Debugger: Could not find rule list or template in the DOM.'); | ||
| 965 | return; | ||
| 966 | } | ||
| 967 | |||
| 968 | rulesContainer.empty(); | ||
| 969 | |||
| 970 | const allScripts = getRegexScripts(); | ||
| 971 | if (!allScripts || allScripts.length === 0) { | ||
| 972 | rulesContainer.append('<div class="regex-debugger-no-rules">No regex rules found.</div>'); | ||
| 973 | return; | ||
| 974 | } | ||
| 975 | |||
| 976 | const globalScriptIds = new Set((extension_settings.regex ?? []).map(s => s.id)); | ||
| 977 | const globalScripts = []; | ||
| 978 | const scopedScripts = []; | ||
| 979 | |||
| 980 | allScripts.forEach(script => { | ||
| 981 | const scriptCopy = structuredClone(script); // Use structuredClone for deep copy | ||
| 982 | if (globalScriptIds.has(script.id)) { | ||
| 983 | // @ts-ignore | ||
| 984 | scriptCopy.isScoped = false; | ||
| 985 | globalScripts.push(scriptCopy); | ||
| 986 | } else { | ||
| 987 | // @ts-ignore | ||
| 988 | scriptCopy.isScoped = true; | ||
| 989 | scopedScripts.push(scriptCopy); | ||
| 990 | } | ||
| 991 | }); | ||
| 992 | |||
| 993 | container.data('allScripts', [...globalScripts, ...scopedScripts]); | ||
| 994 | |||
| 995 | const renderRule = (script) => { | ||
| 996 | if (!script.id) script.id = uuidv4(); | ||
| 997 | const ruleElementContent = $(ruleTemplate.prop('content')).clone(); | ||
| 998 | const ruleElement = ruleElementContent.find('.regex-debugger-rule'); | ||
| 999 | |||
| 1000 | ruleElement.attr('data-id', script.id); | ||
| 1001 | // @ts-ignore | ||
| 1002 | ruleElement.find('.rule-name').text(script.scriptName); | ||
| 1003 | ruleElement.find('.rule-regex').text(script.findRegex); | ||
| 1004 | // @ts-ignore | ||
| 1005 | ruleElement.find('.rule-scope').text(script.isScoped ? 'Scoped' : 'Global'); | ||
| 1006 | ruleElement.find('.rule-enabled').prop('checked', !script.disabled); | ||
| 1007 | // @ts-ignore | ||
| 1008 | ruleElement.find('.edit_rule').on('click', () => onRegexEditorOpenClick(script.id, script.isScoped)); | ||
| 1009 | |||
| 1010 | ruleElement.on('click', function (event) { | ||
| 1011 | if ($(event.target).is('input, .menu_button, .menu_button i')) { | ||
| 1012 | return; | ||
| 1013 | } | ||
| 1014 | const scriptId = $(this).data('id'); | ||
| 1015 | const stepElement = $(`#step-result-${scriptId}`); | ||
| 1016 | const container = $('#regex_debugger_steps_output'); | ||
| 1017 | |||
| 1018 | if (stepElement.length && container.length) { | ||
| 1019 | // Replace scrollIntoView with scrollTop animation | ||
| 1020 | const targetTop = stepElement.position().top; | ||
| 1021 | const containerScrollTop = container.scrollTop(); | ||
| 1022 | const containerHeight = container.height(); | ||
| 1023 | |||
| 1024 | // Center the element if possible | ||
| 1025 | let scrollTo = containerScrollTop + targetTop - (containerHeight / 2) + (stepElement.height() / 2); | ||
| 1026 | |||
| 1027 | container.animate({ scrollTop: scrollTo }, 300); // 300ms smooth scroll | ||
| 1028 | |||
| 1029 | stepElement.css('transition', 'background-color 0.5s').css('background-color', 'var(--highlight_color)'); | ||
| 1030 | setTimeout(() => stepElement.css('background-color', ''), 1000); | ||
| 1031 | } | ||
| 1032 | }); | ||
| 1033 | |||
| 1034 | return ruleElementContent; | ||
| 1035 | }; | ||
| 1036 | |||
| 1037 | if (globalScripts.length > 0) { | ||
| 1038 | rulesContainer.append('<div class="list-header regex-debugger-list-header">Global Rules</div>'); | ||
| 1039 | const globalList = $('<ul id="regex_debugger_rules_global" class="sortable-list"></ul>'); | ||
| 1040 | globalScripts.forEach(script => globalList.append(renderRule(script))); | ||
| 1041 | rulesContainer.append(globalList); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | if (scopedScripts.length > 0) { | ||
| 1045 | rulesContainer.append('<div class="list-header regex-debugger-list-header">Scoped Rules</div>'); | ||
| 1046 | const scopedList = $('<ul id="regex_debugger_rules_scoped" class="sortable-list"></ul>'); | ||
| 1047 | scopedScripts.forEach(script => scopedList.append(renderRule(script))); | ||
| 1048 | rulesContainer.append(scopedList); | ||
| 1049 | } | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | /** | ||
| 1053 | * Opens the regex debugger. | ||
| 1054 | * @returns {Promise<void>} | ||
| 1055 | */ | ||
| 1056 | async function onRegexDebuggerOpenClick() { | ||
| 1057 | const templateContent = await renderExtensionTemplateAsync('regex', 'debugger'); | ||
| 1058 | const debuggerHtml = $('<div>').html(templateContent); | ||
| 1059 | |||
| 1060 | const stepTemplate = debuggerHtml.find('#regex_debugger_step_template'); | ||
| 1061 | |||
| 1062 | populateDebuggerRuleList(debuggerHtml); | ||
| 1063 | |||
| 1064 | // @ts-ignore | ||
| 1065 | debuggerHtml.find('#regex_debugger_rules_global').sortable({ delay: getSortableDelay() }).disableSelection(); | ||
| 1066 | // @ts-ignore | ||
| 1067 | debuggerHtml.find('#regex_debugger_rules_scoped').sortable({ delay: getSortableDelay() }).disableSelection(); | ||
| 1068 | |||
| 1069 | debuggerHtml.find('#regex_debugger_run_test').on('click', function () { | ||
| 1070 | const allScripts = debuggerHtml.data('allScripts'); | ||
| 1071 | const orderedRuleIds = [ | ||
| 1072 | ...$('#regex_debugger_rules_global').find('li.regex-debugger-rule').map((i, el) => $(el).data('id')).get(), | ||
| 1073 | ...$('#regex_debugger_rules_scoped').find('li.regex-debugger-rule').map((i, el) => $(el).data('id')).get(), | ||
| 1074 | ]; | ||
| 1075 | |||
| 1076 | const rawInput = String($('#regex_debugger_raw_input').val()); | ||
| 1077 | const stepsOutput = $('#regex_debugger_steps_output'); | ||
| 1078 | const finalOutput = $('#regex_debugger_final_output'); | ||
| 1079 | |||
| 1080 | if (!stepsOutput.length || !finalOutput.length) return; | ||
| 1081 | |||
| 1082 | const displayMode = $('input[name="display_mode"]:checked').val(); | ||
| 1083 | stepsOutput.empty(); | ||
| 1084 | finalOutput.empty(); | ||
| 1085 | $('#regex_debugger_final_summary').remove(); | ||
| 1086 | |||
| 1087 | if (!allScripts) return; | ||
| 1088 | let textForNextStep = rawInput; | ||
| 1089 | let totalCharsCaptured = 0; | ||
| 1090 | let totalCharsAdded = 0; | ||
| 1091 | let totalCharsRemoved = 0; | ||
| 1092 | |||
| 1093 | orderedRuleIds.forEach(scriptId => { | ||
| 1094 | const ruleElement = $(`#regex_debugger_rules [data-id="${scriptId}"]`); | ||
| 1095 | if (!ruleElement.find('.rule-enabled').is(':checked')) return; | ||
| 1096 | |||
| 1097 | const script = allScripts.find(s => s.id === scriptId); | ||
| 1098 | |||
| 1099 | if (script) { | ||
| 1100 | const result = executeRegexScriptForDebugging(script, textForNextStep); | ||
| 1101 | totalCharsCaptured += result.charsCaptured; | ||
| 1102 | totalCharsAdded += result.charsAdded; | ||
| 1103 | totalCharsRemoved += result.charsRemoved; | ||
| 1104 | |||
| 1105 | const stepElement = $(stepTemplate.prop('content')).clone(); | ||
| 1106 | // Set the ID on the TOP-LEVEL element that is being appended. | ||
| 1107 | stepElement.find('>:first-child').attr('id', `step-result-${script.id}`); | ||
| 1108 | const stepHeader = stepElement.find('.step-header'); | ||
| 1109 | stepHeader.find('strong').text(`After: ${script.scriptName}`); | ||
| 1110 | |||
| 1111 | const metricsHtml = `<span class="step-metrics">Captured: ${result.charsCaptured}, Added: +${result.charsAdded}, Removed: -${result.charsRemoved}</span>`; | ||
| 1112 | stepHeader.append(metricsHtml); | ||
| 1113 | |||
| 1114 | if (displayMode === 'highlight') { | ||
| 1115 | stepElement.find('.step-output').html(result.highlightedOutput); | ||
| 1116 | } else { | ||
| 1117 | stepElement.find('.step-output').text(result.output); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | if (result.error) { | ||
| 1121 | stepHeader.append($(`<div class='warning_text text_rose-500'>${result.error}</div>`)); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | stepsOutput.append(stepElement); | ||
| 1125 | textForNextStep = result.output; | ||
| 1126 | } | ||
| 1127 | }); | ||
| 1128 | |||
| 1129 | const summaryHtml = ` | ||
| 1130 | <div id="regex_debugger_final_summary" class="regex-debugger-summary"> | ||
| 1131 | <strong>Total Captured:</strong> ${totalCharsCaptured} | <strong>Total Added:</strong> +${totalCharsAdded} | <strong>Total Removed:</strong> -${totalCharsRemoved} | ||
| 1132 | </div> | ||
| 1133 | `; | ||
| 1134 | finalOutput.before(summaryHtml); | ||
| 1135 | |||
| 1136 | const renderMode = $('#regex_debugger_render_mode').val(); | ||
| 1137 | if (renderMode === 'message') { | ||
| 1138 | const formattedHtml = messageFormatting(textForNextStep, 'Debugger', true, false, null); | ||
| 1139 | const messageBlock = $('<div class="mes"><div class="mes_text"></div></div>'); | ||
| 1140 | messageBlock.find('.mes_text').html(formattedHtml); | ||
| 1141 | finalOutput.append(messageBlock); | ||
| 1142 | } else { | ||
| 1143 | finalOutput.text(textForNextStep); | ||
| 1144 | } | ||
| 1145 | }); | ||
| 1146 | |||
| 1147 | debuggerHtml.find('#regex_debugger_save_order').on('click', async function () { | ||
| 1148 | const allKnownScripts = getRegexScripts(); | ||
| 1149 | const newGlobalScripts = $('#regex_debugger_rules_global').children('li').map((_, el) => allKnownScripts.find(s => s.id === $(el).data('id'))).get().filter(Boolean); | ||
| 1150 | const newScopedScripts = $('#regex_debugger_rules_scoped').children('li').map((_, el) => allKnownScripts.find(s => s.id === $(el).data('id'))).get().filter(Boolean); | ||
| 1151 | |||
| 1152 | extension_settings.regex = newGlobalScripts; | ||
| 1153 | if (this_chid !== undefined) { | ||
| 1154 | await writeExtensionField(this_chid, 'regex_scripts', newScopedScripts); | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | saveSettingsDebounced(); | ||
| 1158 | await loadRegexScripts(); | ||
| 1159 | toastr.success(t`Regex script order saved!`); | ||
| 1160 | |||
| 1161 | const currentPopupContent = $('div:has(> #regex_debugger_rules)'); | ||
| 1162 | populateDebuggerRuleList(currentPopupContent); | ||
| 1163 | // @ts-ignore | ||
| 1164 | currentPopupContent.find('#regex_debugger_rules_global').sortable({ delay: getSortableDelay() }).disableSelection(); | ||
| 1165 | // @ts-ignore | ||
| 1166 | currentPopupContent.find('#regex_debugger_rules_scoped').sortable({ delay: getSortableDelay() }).disableSelection(); | ||
| 1167 | }); | ||
| 1168 | |||
| 1169 | debuggerHtml.find('#regex_debugger_expand_steps').on('click', function () { | ||
| 1170 | const popupContainer = $('<div class="expanded-regex-container"></div>'); | ||
| 1171 | const navPanel = $('<div class="expanded-regex-nav"><h4>Steps</h4></div>'); | ||
| 1172 | const contentPanel = $('<div class="expanded-regex-content"></div>'); | ||
| 1173 | |||
| 1174 | const content = $('#regex_debugger_steps_output').clone().html(); | ||
| 1175 | contentPanel.html(content); | ||
| 1176 | |||
| 1177 | $('#regex_debugger_rules .regex-debugger-rule').each(function () { | ||
| 1178 | const ruleElement = $(this); | ||
| 1179 | const scriptId = ruleElement.data('id'); | ||
| 1180 | const scriptName = ruleElement.find('.rule-name').text(); | ||
| 1181 | |||
| 1182 | const link = $(`<a href="#">${escapeHtml(scriptName)}</a>`); | ||
| 1183 | link.data('target-id', `step-result-${scriptId}`); | ||
| 1184 | |||
| 1185 | link.on('click', function (e) { | ||
| 1186 | e.preventDefault(); | ||
| 1187 | navPanel.find('a').removeClass('active'); | ||
| 1188 | $(this).addClass('active'); | ||
| 1189 | |||
| 1190 | const targetId = $(this).data('target-id'); | ||
| 1191 | // The selector is now correct for the structure. | ||
| 1192 | const targetElement = contentPanel.find(`#${targetId}`); | ||
| 1193 | |||
| 1194 | if (targetElement.length) { | ||
| 1195 | const scrollTo = contentPanel.scrollTop() + targetElement.position().top; | ||
| 1196 | contentPanel.animate({ scrollTop: scrollTo }, 300); | ||
| 1197 | |||
| 1198 | targetElement.css('transition', 'background-color 0.5s').css('background-color', 'var(--highlight_color)'); | ||
| 1199 | setTimeout(() => targetElement.css('background-color', ''), 1000); | ||
| 1200 | } | ||
| 1201 | }); | ||
| 1202 | |||
| 1203 | navPanel.append(link); | ||
| 1204 | }); | ||
| 1205 | |||
| 1206 | popupContainer.append(navPanel).append(contentPanel); | ||
| 1207 | callGenericPopup(popupContainer, POPUP_TYPE.TEXT, 'Step-by-step Transformation', { wide: true, allowVerticalScrolling: false }); | ||
| 1208 | }); | ||
| 1209 | |||
| 1210 | debuggerHtml.find('#regex_debugger_expand_final').on('click', function () { | ||
| 1211 | const content = $('#regex_debugger_final_output').html(); | ||
| 1212 | const popupContent = $('<div class="regex-popup-content"></div>').html(content); | ||
| 1213 | callGenericPopup(popupContent, POPUP_TYPE.TEXT, 'Final Output', { wide: true, large: true, allowVerticalScrolling: true }); | ||
| 1214 | }); | ||
| 1215 | |||
| 1216 | await callGenericPopup(debuggerHtml.children(), POPUP_TYPE.TEXT, '', { wide: true, allowVerticalScrolling: true }); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | /** | ||
| 333 | * Updates the info block in the regex editor with hints regarding the find regex. | 1220 | * Updates the info block in the regex editor with hints regarding the find regex. |
| 334 | * @param {JQuery<HTMLElement>} editorHtml The editor HTML | 1221 | * @param {JQuery<HTMLElement>} editorHtml The editor HTML |
| 335 | */ | 1222 | */ |
| @@ -592,8 +1479,12 @@ async function checkEmbeddedRegexScripts() { | |||
| 592 | // Workaround for loading in sequence with other extensions | 1479 | // Workaround for loading in sequence with other extensions |
| 593 | // NOTE: Always puts extension at the top of the list, but this is fine since it's static | 1480 | // NOTE: Always puts extension at the top of the list, but this is fine since it's static |
| 594 | jQuery(async () => { | 1481 | jQuery(async () => { |
| 595 | if (extension_settings.regex) { | 1482 | if (!Array.isArray(extension_settings.regex)) { |
| 596 | migrateSettings(); | 1483 | extension_settings.regex = []; |
| 1484 | } | ||
| 1485 | |||
| 1486 | if (!Array.isArray(extension_settings.regex_presets)) { | ||
| 1487 | extension_settings.regex_presets = []; | ||
| 597 | } | 1488 | } |
| 598 | 1489 | ||
| 599 | // Manually disable the extension since static imports auto-import the JS file | 1490 | // Manually disable the extension since static imports auto-import the JS file |
| @@ -601,11 +1492,14 @@ jQuery(async () => { | |||
| 601 | return; | 1492 | return; |
| 602 | } | 1493 | } |
| 603 | 1494 | ||
| 1495 | migrateSettings(); | ||
| 1496 | |||
| 604 | const settingsHtml = $(await renderExtensionTemplateAsync('regex', 'dropdown')); | 1497 | const settingsHtml = $(await renderExtensionTemplateAsync('regex', 'dropdown')); |
| 605 | $('#regex_container').append(settingsHtml); | 1498 | $('#regex_container').append(settingsHtml); |
| 606 | $('#open_regex_editor').on('click', function () { | 1499 | $('#open_regex_editor').on('click', function () { |
| 607 | onRegexEditorOpenClick(false, false); | 1500 | onRegexEditorOpenClick(false, false); |
| 608 | }); | 1501 | }); |
| 1502 | $('#open_regex_debugger').on('click', onRegexDebuggerOpenClick); | ||
| 609 | $('#open_scoped_editor').on('click', function () { | 1503 | $('#open_scoped_editor').on('click', function () { |
| 610 | if (this_chid === undefined) { | 1504 | if (this_chid === undefined) { |
| 611 | toastr.error(t`No character selected.`); | 1505 | toastr.error(t`No character selected.`); |
| @@ -726,6 +1620,7 @@ jQuery(async () => { | |||
| 726 | }, | 1620 | }, |
| 727 | ]; | 1621 | ]; |
| 728 | for (const { selector, setter, getter } of sortableDatas) { | 1622 | for (const { selector, setter, getter } of sortableDatas) { |
| 1623 | // @ts-ignore | ||
| 729 | $(selector).sortable({ | 1624 | $(selector).sortable({ |
| 730 | delay: getSortableDelay(), | 1625 | delay: getSortableDelay(), |
| 731 | stop: async function () { | 1626 | stop: async function () { |
| @@ -778,6 +1673,7 @@ jQuery(async () => { | |||
| 778 | }); | 1673 | }); |
| 779 | 1674 | ||
| 780 | await loadRegexScripts(); | 1675 | await loadRegexScripts(); |
| 1676 | // @ts-ignore | ||
| 781 | $('#saved_regex_scripts').sortable('enable'); | 1677 | $('#saved_regex_scripts').sortable('enable'); |
| 782 | 1678 | ||
| 783 | const localEnumProviders = { | 1679 | const localEnumProviders = { |
| @@ -856,4 +1752,7 @@ jQuery(async () => { | |||
| 856 | 1752 | ||
| 857 | eventSource.on(event_types.CHAT_CHANGED, checkEmbeddedRegexScripts); | 1753 | eventSource.on(event_types.CHAT_CHANGED, checkEmbeddedRegexScripts); |
| 858 | eventSource.on(event_types.CHARACTER_DELETED, purgeEmbeddedRegexScripts); | 1754 | eventSource.on(event_types.CHARACTER_DELETED, purgeEmbeddedRegexScripts); |
| 1755 | |||
| 1756 | presetManager.setupEventListeners(); | ||
| 1757 | presetManager.registerSlashCommands(); | ||
| 859 | }); | 1758 | }); |
| @@ -1,3 +1,5 @@ | |||
| 1 | @import "debugger.css"; | ||
| 2 | |||
| 1 | .regex_settings .menu_button { | 3 | .regex_settings .menu_button { |
| 2 | width: fit-content; | 4 | width: fit-content; |
| 3 | display: flex; | 5 | display: flex; |
| @@ -39,19 +41,19 @@ | |||
| 39 | opacity: 0.5; | 41 | opacity: 0.5; |
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | .enable_scoped:checked ~ .regex-toggle-on { | 44 | .enable_scoped:checked~.regex-toggle-on { |
| 43 | display: block; | 45 | display: block; |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 46 | .enable_scoped:checked ~ .regex-toggle-off { | 48 | .enable_scoped:checked~.regex-toggle-off { |
| 47 | display: none; | 49 | display: none; |
| 48 | } | 50 | } |
| 49 | 51 | ||
| 50 | .enable_scoped:not(:checked) ~ .regex-toggle-on { | 52 | .enable_scoped:not(:checked)~.regex-toggle-on { |
| 51 | display: none; | 53 | display: none; |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | .enable_scoped:not(:checked) ~ .regex-toggle-off { | 56 | .enable_scoped:not(:checked)~.regex-toggle-off { |
| 55 | display: block; | 57 | display: block; |
| 56 | } | 58 | } |
| 57 | 59 | ||
| @@ -90,19 +92,19 @@ input.enable_scoped { | |||
| 90 | cursor: pointer; | 92 | cursor: pointer; |
| 91 | } | 93 | } |
| 92 | 94 | ||
| 93 | .disable_regex:checked ~ .regex-toggle-off { | 95 | .disable_regex:checked~.regex-toggle-off { |
| 94 | display: block; | 96 | display: block; |
| 95 | } | 97 | } |
| 96 | 98 | ||
| 97 | .disable_regex:checked ~ .regex-toggle-on { | 99 | .disable_regex:checked~.regex-toggle-on { |
| 98 | display: none; | 100 | display: none; |
| 99 | } | 101 | } |
| 100 | 102 | ||
| 101 | .disable_regex:not(:checked) ~ .regex-toggle-off { | 103 | .disable_regex:not(:checked)~.regex-toggle-off { |
| 102 | display: none; | 104 | display: none; |
| 103 | } | 105 | } |
| 104 | 106 | ||
| 105 | .disable_regex:not(:checked) ~ .regex-toggle-on { | 107 | .disable_regex:not(:checked)~.regex-toggle-on { |
| 106 | display: block; | 108 | display: block; |
| 107 | } | 109 | } |
| 108 | 110 | ||
| @@ -22,12 +22,6 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 22 | 22 | ||
| 23 | throwIfInvalidModel(useReverseProxy); | 23 | throwIfInvalidModel(useReverseProxy); |
| 24 | 24 | ||
| 25 | const noPrefix = ['ollama'].includes(extension_settings.caption.multimodal_api); | ||
| 26 | |||
| 27 | if (noPrefix && base64Img.startsWith('data:image/')) { | ||
| 28 | base64Img = base64Img.split(',')[1]; | ||
| 29 | } | ||
| 30 | |||
| 31 | // OpenRouter has a payload limit of ~2MB. Google is 4MB, but we love democracy. | 25 | // OpenRouter has a payload limit of ~2MB. Google is 4MB, but we love democracy. |
| 32 | // Ooba requires all images to be JPEGs. Koboldcpp just asked nicely. | 26 | // Ooba requires all images to be JPEGs. Koboldcpp just asked nicely. |
| 33 | const isOllama = extension_settings.caption.multimodal_api === 'ollama'; | 27 | const isOllama = extension_settings.caption.multimodal_api === 'ollama'; |
| @@ -47,6 +41,9 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 47 | } else if (!safeMimeTypes.includes(mimeType)) { | 41 | } else if (!safeMimeTypes.includes(mimeType)) { |
| 48 | base64Img = await createThumbnail(base64Img, null, null); | 42 | base64Img = await createThumbnail(base64Img, null, null); |
| 49 | } | 43 | } |
| 44 | if (isOllama && base64Img.startsWith('data:image/')) { | ||
| 45 | base64Img = base64Img.split(',')[1]; | ||
| 46 | } | ||
| 50 | 47 | ||
| 51 | const proxyUrl = useReverseProxy ? oai_settings.reverse_proxy : ''; | 48 | const proxyUrl = useReverseProxy ? oai_settings.reverse_proxy : ''; |
| 52 | const proxyPassword = useReverseProxy ? oai_settings.proxy_password : ''; | 49 | const proxyPassword = useReverseProxy ? oai_settings.proxy_password : ''; |
| @@ -72,6 +69,10 @@ export async function getMultimodalCaption(base64Img, prompt) { | |||
| 72 | requestBody.model = textgenerationwebui_settings.ollama_model; | 69 | requestBody.model = textgenerationwebui_settings.ollama_model; |
| 73 | } | 70 | } |
| 74 | 71 | ||
| 72 | if (extension_settings.caption.multimodal_model === 'ollama_custom') { | ||
| 73 | requestBody.model = extension_settings.caption.ollama_custom_model; | ||
| 74 | } | ||
| 75 | |||
| 75 | requestBody.server_url = extension_settings.caption.alt_endpoint_enabled | 76 | requestBody.server_url = extension_settings.caption.alt_endpoint_enabled |
| 76 | ? extension_settings.caption.alt_endpoint_url | 77 | ? extension_settings.caption.alt_endpoint_url |
| 77 | : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]; | 78 | : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]; |
| @@ -211,6 +212,10 @@ function throwIfInvalidModel(useReverseProxy) { | |||
| 211 | throw new Error('Ollama model is not set.'); | 212 | throw new Error('Ollama model is not set.'); |
| 212 | } | 213 | } |
| 213 | 214 | ||
| 215 | if (multimodalApi === 'ollama' && multimodalModel === 'ollama_custom' && !extension_settings.caption.ollama_custom_model) { | ||
| 216 | throw new Error('Ollama custom model tag is not set.'); | ||
| 217 | } | ||
| 218 | |||
| 214 | if (multimodalApi === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP] && !altEndpointEnabled) { | 219 | if (multimodalApi === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP] && !altEndpointEnabled) { |
| 215 | throw new Error('LlamaCPP server URL is not set.'); | 220 | throw new Error('LlamaCPP server URL is not set.'); |
| 216 | } | 221 | } |
| @@ -242,6 +247,14 @@ function throwIfInvalidModel(useReverseProxy) { | |||
| 242 | if (multimodalApi === 'moonshot' && !secret_state[SECRET_KEYS.MOONSHOT]) { | 247 | if (multimodalApi === 'moonshot' && !secret_state[SECRET_KEYS.MOONSHOT]) { |
| 243 | throw new Error('Moonshot AI API key is not set.'); | 248 | throw new Error('Moonshot AI API key is not set.'); |
| 244 | } | 249 | } |
| 250 | |||
| 251 | if (multimodalApi === 'nanogpt' && !secret_state[SECRET_KEYS.NANOGPT]) { | ||
| 252 | throw new Error('NanoGPT API key is not set.'); | ||
| 253 | } | ||
| 254 | |||
| 255 | if (multimodalApi === 'electronhub' && !secret_state[SECRET_KEYS.ELECTRONHUB]) { | ||
| 256 | throw new Error('Electron Hub API key is not set.'); | ||
| 257 | } | ||
| 245 | } | 258 | } |
| 246 | 259 | ||
| 247 | /** | 260 | /** |
| @@ -57,7 +57,7 @@ import { callGenericPopup, Popup, POPUP_TYPE } from '../../popup.js'; | |||
| 57 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; | 57 | import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 58 | import { ToolManager } from '../../tool-calling.js'; | 58 | import { ToolManager } from '../../tool-calling.js'; |
| 59 | import { MacrosParser } from '../../macros.js'; | 59 | import { MacrosParser } from '../../macros.js'; |
| 60 | import { t } from '../../i18n.js'; | 60 | import { t, translate } from '../../i18n.js'; |
| 61 | import { oai_settings } from '../../openai.js'; | 61 | import { oai_settings } from '../../openai.js'; |
| 62 | 62 | ||
| 63 | export { MODULE_NAME }; | 63 | export { MODULE_NAME }; |
| @@ -82,6 +82,7 @@ const sources = { | |||
| 82 | pollinations: 'pollinations', | 82 | pollinations: 'pollinations', |
| 83 | stability: 'stability', | 83 | stability: 'stability', |
| 84 | huggingface: 'huggingface', | 84 | huggingface: 'huggingface', |
| 85 | electronhub: 'electronhub', | ||
| 85 | nanogpt: 'nanogpt', | 86 | nanogpt: 'nanogpt', |
| 86 | bfl: 'bfl', | 87 | bfl: 'bfl', |
| 87 | falai: 'falai', | 88 | falai: 'falai', |
| @@ -650,7 +651,7 @@ async function onDeleteStyleClick() { | |||
| 650 | return; | 651 | return; |
| 651 | } | 652 | } |
| 652 | 653 | ||
| 653 | const confirmed = await callGenericPopup(`Are you sure you want to delete the style "${selectedStyle}"?`, POPUP_TYPE.CONFIRM, '', { okButton: 'Delete', cancelButton: 'Cancel' }); | 654 | const confirmed = await callGenericPopup(t`Are you sure you want to delete the style "${selectedStyle}"?`, POPUP_TYPE.CONFIRM, '', { okButton: 'Delete', cancelButton: 'Cancel' }); |
| 654 | 655 | ||
| 655 | if (!confirmed) { | 656 | if (!confirmed) { |
| 656 | return; | 657 | return; |
| @@ -925,16 +926,16 @@ function onADetailerFaceChange() { | |||
| 925 | } | 926 | } |
| 926 | 927 | ||
| 927 | const resolutionOptions = { | 928 | const resolutionOptions = { |
| 928 | sd_res_512x512: { width: 512, height: 512, name: '512x512 (1:1, icons, profile pictures)' }, | 929 | sd_res_512x512: { width: 512, height: 512, name: translate('512x512 (1:1, icons, profile pictures)', 'sd_res_512x512') }, |
| 929 | sd_res_600x600: { width: 600, height: 600, name: '600x600 (1:1, icons, profile pictures)' }, | 930 | sd_res_600x600: { width: 600, height: 600, name: translate('600x600 (1:1, icons, profile pictures)', 'sd_res_600x600') }, |
| 930 | sd_res_512x768: { width: 512, height: 768, name: '512x768 (2:3, vertical character card)' }, | 931 | sd_res_512x768: { width: 512, height: 768, name: translate('512x768 (2:3, vertical character card)', 'sd_res_512x768') }, |
| 931 | sd_res_768x512: { width: 768, height: 512, name: '768x512 (3:2, horizontal 35-mm movie film)' }, | 932 | sd_res_768x512: { width: 768, height: 512, name: translate('768x512 (3:2, horizontal 35-mm movie film)', 'sd_res_768x512') }, |
| 932 | sd_res_960x540: { width: 960, height: 540, name: '960x540 (16:9, horizontal wallpaper)' }, | 933 | sd_res_960x540: { width: 960, height: 540, name: translate('960x540 (16:9, horizontal wallpaper)', 'sd_res_960x540') }, |
| 933 | sd_res_540x960: { width: 540, height: 960, name: '540x960 (9:16, vertical wallpaper)' }, | 934 | sd_res_540x960: { width: 540, height: 960, name: translate('540x960 (9:16, vertical wallpaper)', 'sd_res_540x960') }, |
| 934 | sd_res_1920x1088: { width: 1920, height: 1088, name: '1920x1088 (16:9, 1080p, horizontal wallpaper)' }, | 935 | sd_res_1920x1088: { width: 1920, height: 1088, name: translate('1920x1088 (16:9, 1080p, horizontal wallpaper)', 'sd_res_1920x1088') }, |
| 935 | sd_res_1088x1920: { width: 1088, height: 1920, name: '1088x1920 (9:16, 1080p, vertical wallpaper)' }, | 936 | sd_res_1088x1920: { width: 1088, height: 1920, name: translate('1088x1920 (9:16, 1080p, vertical wallpaper)', 'sd_res_1088x1920') }, |
| 936 | sd_res_1280x720: { width: 1280, height: 720, name: '1280x720 (16:9, 720p, horizontal wallpaper)' }, | 937 | sd_res_1280x720: { width: 1280, height: 720, name: translate('1280x720 (16:9, 720p, horizontal wallpaper)', 'sd_res_1280x720') }, |
| 937 | sd_res_720x1280: { width: 720, height: 1280, name: '720x1280 (9:16, 720p, vertical wallpaper)' }, | 938 | sd_res_720x1280: { width: 720, height: 1280, name: translate('720x1280 (9:16, 720p, vertical wallpaper)', 'sd_res_720x1280') }, |
| 938 | sd_res_1024x1024: { width: 1024, height: 1024, name: '1024x1024 (1:1, SDXL)' }, | 939 | sd_res_1024x1024: { width: 1024, height: 1024, name: '1024x1024 (1:1, SDXL)' }, |
| 939 | sd_res_1152x896: { width: 1152, height: 896, name: '1152x896 (9:7, SDXL)' }, | 940 | sd_res_1152x896: { width: 1152, height: 896, name: '1152x896 (9:7, SDXL)' }, |
| 940 | sd_res_896x1152: { width: 896, height: 1152, name: '896x1152 (7:9, SDXL)' }, | 941 | sd_res_896x1152: { width: 896, height: 1152, name: '896x1152 (7:9, SDXL)' }, |
| @@ -1289,6 +1290,7 @@ async function onModelChange() { | |||
| 1289 | sources.pollinations, | 1290 | sources.pollinations, |
| 1290 | sources.stability, | 1291 | sources.stability, |
| 1291 | sources.huggingface, | 1292 | sources.huggingface, |
| 1293 | sources.electronhub, | ||
| 1292 | sources.nanogpt, | 1294 | sources.nanogpt, |
| 1293 | sources.bfl, | 1295 | sources.bfl, |
| 1294 | sources.falai, | 1296 | sources.falai, |
| @@ -1506,6 +1508,9 @@ async function loadSamplers() { | |||
| 1506 | case sources.huggingface: | 1508 | case sources.huggingface: |
| 1507 | samplers = ['N/A']; | 1509 | samplers = ['N/A']; |
| 1508 | break; | 1510 | break; |
| 1511 | case sources.electronhub: | ||
| 1512 | samplers = ['N/A']; | ||
| 1513 | break; | ||
| 1509 | case sources.nanogpt: | 1514 | case sources.nanogpt: |
| 1510 | samplers = ['N/A']; | 1515 | samplers = ['N/A']; |
| 1511 | break; | 1516 | break; |
| @@ -1702,6 +1707,9 @@ async function loadModels() { | |||
| 1702 | case sources.huggingface: | 1707 | case sources.huggingface: |
| 1703 | models = [{ value: '', text: '<Enter Model ID above>' }]; | 1708 | models = [{ value: '', text: '<Enter Model ID above>' }]; |
| 1704 | break; | 1709 | break; |
| 1710 | case sources.electronhub: | ||
| 1711 | models = await loadElectronHubModels(); | ||
| 1712 | break; | ||
| 1705 | case sources.nanogpt: | 1713 | case sources.nanogpt: |
| 1706 | models = await loadNanoGPTModels(); | 1714 | models = await loadNanoGPTModels(); |
| 1707 | break; | 1715 | break; |
| @@ -1806,6 +1814,24 @@ async function loadTogetherAIModels() { | |||
| 1806 | return []; | 1814 | return []; |
| 1807 | } | 1815 | } |
| 1808 | 1816 | ||
| 1817 | async function loadElectronHubModels() { | ||
| 1818 | if (!secret_state[SECRET_KEYS.ELECTRONHUB]) { | ||
| 1819 | console.debug('Electron Hub API key is not set.'); | ||
| 1820 | return []; | ||
| 1821 | } | ||
| 1822 | |||
| 1823 | const result = await fetch('/api/sd/electronhub/models', { | ||
| 1824 | method: 'POST', | ||
| 1825 | headers: getRequestHeaders(), | ||
| 1826 | }); | ||
| 1827 | |||
| 1828 | if (result.ok) { | ||
| 1829 | return await result.json(); | ||
| 1830 | } | ||
| 1831 | |||
| 1832 | return []; | ||
| 1833 | } | ||
| 1834 | |||
| 1809 | async function loadNanoGPTModels() { | 1835 | async function loadNanoGPTModels() { |
| 1810 | if (!secret_state[SECRET_KEYS.NANOGPT]) { | 1836 | if (!secret_state[SECRET_KEYS.NANOGPT]) { |
| 1811 | console.debug('NanoGPT API key is not set.'); | 1837 | console.debug('NanoGPT API key is not set.'); |
| @@ -2131,6 +2157,9 @@ async function loadSchedulers() { | |||
| 2131 | case sources.huggingface: | 2157 | case sources.huggingface: |
| 2132 | schedulers = ['N/A']; | 2158 | schedulers = ['N/A']; |
| 2133 | break; | 2159 | break; |
| 2160 | case sources.electronhub: | ||
| 2161 | schedulers = ['N/A']; | ||
| 2162 | break; | ||
| 2134 | case sources.nanogpt: | 2163 | case sources.nanogpt: |
| 2135 | schedulers = ['N/A']; | 2164 | schedulers = ['N/A']; |
| 2136 | break; | 2165 | break; |
| @@ -2228,6 +2257,9 @@ async function loadVaes() { | |||
| 2228 | case sources.huggingface: | 2257 | case sources.huggingface: |
| 2229 | vaes = ['N/A']; | 2258 | vaes = ['N/A']; |
| 2230 | break; | 2259 | break; |
| 2260 | case sources.electronhub: | ||
| 2261 | vaes = ['N/A']; | ||
| 2262 | break; | ||
| 2231 | case sources.nanogpt: | 2263 | case sources.nanogpt: |
| 2232 | vaes = ['N/A']; | 2264 | vaes = ['N/A']; |
| 2233 | break; | 2265 | break; |
| @@ -2811,6 +2843,9 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | |||
| 2811 | case sources.huggingface: | 2843 | case sources.huggingface: |
| 2812 | result = await generateHuggingFaceImage(prefixedPrompt, signal); | 2844 | result = await generateHuggingFaceImage(prefixedPrompt, signal); |
| 2813 | break; | 2845 | break; |
| 2846 | case sources.electronhub: | ||
| 2847 | result = await generateElectronHubImage(prefixedPrompt, signal); | ||
| 2848 | break; | ||
| 2814 | case sources.nanogpt: | 2849 | case sources.nanogpt: |
| 2815 | result = await generateNanoGPTImage(prefixedPrompt, negativePrompt, signal); | 2850 | result = await generateNanoGPTImage(prefixedPrompt, negativePrompt, signal); |
| 2816 | break; | 2851 | break; |
| @@ -3014,6 +3049,56 @@ function getClosestAspectRatio(width, height, source) { | |||
| 3014 | } | 3049 | } |
| 3015 | 3050 | ||
| 3016 | /** | 3051 | /** |
| 3052 | * Get closest size for Electron Hub | ||
| 3053 | * @param {number} width - The width of the image | ||
| 3054 | * @param {number} height - The height of the image | ||
| 3055 | * @returns {Promise<string>} - The closest size | ||
| 3056 | */ | ||
| 3057 | async function getClosestSize(width, height) { | ||
| 3058 | const response = await fetch('/api/sd/electronhub/sizes', { | ||
| 3059 | method: 'POST', | ||
| 3060 | headers: getRequestHeaders(), | ||
| 3061 | body: JSON.stringify({ | ||
| 3062 | model: extension_settings.sd.model, | ||
| 3063 | }), | ||
| 3064 | }); | ||
| 3065 | if (!response.ok) { | ||
| 3066 | const text = await response.text(); | ||
| 3067 | throw new Error(text); | ||
| 3068 | } | ||
| 3069 | const result = await response.json(); | ||
| 3070 | const sizesData = result.sizes; | ||
| 3071 | |||
| 3072 | const closestSize = sizesData.reduce((closest, size) => { | ||
| 3073 | if (!size || typeof size !== 'string') { | ||
| 3074 | return closest; | ||
| 3075 | } | ||
| 3076 | const sizeParts = size.split('x'); | ||
| 3077 | if (sizeParts.length !== 2) { | ||
| 3078 | return closest; | ||
| 3079 | } | ||
| 3080 | |||
| 3081 | const sizeWidth = Number(sizeParts[0]); | ||
| 3082 | const sizeHeight = Number(sizeParts[1]); | ||
| 3083 | const targetWidth = Number(width); | ||
| 3084 | const targetHeight = Number(height); | ||
| 3085 | |||
| 3086 | if (isNaN(sizeWidth) || isNaN(sizeHeight) || isNaN(targetWidth) || isNaN(targetHeight)) { | ||
| 3087 | return closest; | ||
| 3088 | } | ||
| 3089 | |||
| 3090 | const sizeArea = sizeWidth * sizeHeight; | ||
| 3091 | const targetArea = targetWidth * targetHeight; | ||
| 3092 | const diff = Math.abs(sizeArea - targetArea); | ||
| 3093 | |||
| 3094 | return diff < closest.diff ? { size, diff } : closest; | ||
| 3095 | }, { size: null, diff: Infinity }); | ||
| 3096 | |||
| 3097 | const size = closestSize.size; | ||
| 3098 | return size; | ||
| 3099 | } | ||
| 3100 | |||
| 3101 | /** | ||
| 3017 | * Generates an image using Stability AI. | 3102 | * Generates an image using Stability AI. |
| 3018 | * @param {string} prompt - The main instruction used to guide the image generation. | 3103 | * @param {string} prompt - The main instruction used to guide the image generation. |
| 3019 | * @param {string} negativePrompt - The instruction used to restrict the image generation. | 3104 | * @param {string} negativePrompt - The instruction used to restrict the image generation. |
| @@ -3565,6 +3650,35 @@ async function generateHuggingFaceImage(prompt, signal) { | |||
| 3565 | } | 3650 | } |
| 3566 | 3651 | ||
| 3567 | /** | 3652 | /** |
| 3653 | * Generates an image using the Electron Hub API. | ||
| 3654 | * @param {string} prompt - The main instruction used to guide the image generation. | ||
| 3655 | * @param {AbortSignal} signal - An AbortSignal object that can be used to cancel the request. | ||
| 3656 | * @returns {Promise<{format: string, data: string}>} - A promise that resolves when the image generation and processing are complete. | ||
| 3657 | */ | ||
| 3658 | async function generateElectronHubImage(prompt, signal) { | ||
| 3659 | const size = await getClosestSize(extension_settings.sd.width, extension_settings.sd.height); | ||
| 3660 | |||
| 3661 | const result = await fetch('/api/sd/electronhub/generate', { | ||
| 3662 | method: 'POST', | ||
| 3663 | headers: getRequestHeaders(), | ||
| 3664 | signal: signal, | ||
| 3665 | body: JSON.stringify({ | ||
| 3666 | model: extension_settings.sd.model, | ||
| 3667 | prompt: prompt, | ||
| 3668 | size: size, | ||
| 3669 | }), | ||
| 3670 | }); | ||
| 3671 | |||
| 3672 | if (result.ok) { | ||
| 3673 | const data = await result.json(); | ||
| 3674 | return { format: 'jpg', data: data.image }; | ||
| 3675 | } else { | ||
| 3676 | const text = await result.text(); | ||
| 3677 | throw new Error(text); | ||
| 3678 | } | ||
| 3679 | } | ||
| 3680 | |||
| 3681 | /** | ||
| 3568 | * Generates an image using the NanoGPT API. | 3682 | * Generates an image using the NanoGPT API. |
| 3569 | * @param {string} prompt - The main instruction used to guide the image generation. | 3683 | * @param {string} prompt - The main instruction used to guide the image generation. |
| 3570 | * @param {string} negativePrompt - The instruction used to restrict the image generation. | 3684 | * @param {string} negativePrompt - The instruction used to restrict the image generation. |
| @@ -3847,7 +3961,7 @@ async function onComfyNewWorkflowClick() { | |||
| 3847 | } | 3961 | } |
| 3848 | 3962 | ||
| 3849 | async function onComfyDeleteWorkflowClick() { | 3963 | async function onComfyDeleteWorkflowClick() { |
| 3850 | const confirm = await callGenericPopup('Delete the workflow? This action is irreversible.', POPUP_TYPE.CONFIRM, '', { okButton: 'Delete', cancelButton: 'Cancel' }); | 3964 | const confirm = await callGenericPopup(t`Delete the workflow? This action is irreversible.`, POPUP_TYPE.CONFIRM, '', { okButton: t`Delete`, cancelButton: t`Cancel` }); |
| 3851 | if (!confirm) { | 3965 | if (!confirm) { |
| 3852 | return; | 3966 | return; |
| 3853 | } | 3967 | } |
| @@ -4014,6 +4128,8 @@ function isValidState() { | |||
| 4014 | return secret_state[SECRET_KEYS.STABILITY]; | 4128 | return secret_state[SECRET_KEYS.STABILITY]; |
| 4015 | case sources.huggingface: | 4129 | case sources.huggingface: |
| 4016 | return secret_state[SECRET_KEYS.HUGGINGFACE]; | 4130 | return secret_state[SECRET_KEYS.HUGGINGFACE]; |
| 4131 | case sources.electronhub: | ||
| 4132 | return secret_state[SECRET_KEYS.ELECTRONHUB]; | ||
| 4017 | case sources.nanogpt: | 4133 | case sources.nanogpt: |
| 4018 | return secret_state[SECRET_KEYS.NANOGPT]; | 4134 | return secret_state[SECRET_KEYS.NANOGPT]; |
| 4019 | case sources.bfl: | 4135 | case sources.bfl: |
| @@ -41,6 +41,7 @@ | |||
| 41 | <option value="bfl">BFL (Black Forest Labs)</option> | 41 | <option value="bfl">BFL (Black Forest Labs)</option> |
| 42 | <option value="comfy">ComfyUI</option> | 42 | <option value="comfy">ComfyUI</option> |
| 43 | <option value="drawthings">DrawThings HTTP API</option> | 43 | <option value="drawthings">DrawThings HTTP API</option> |
| 44 | <option value="electronhub">Electron Hub</option> | ||
| 44 | <option value="extras">Extras API (deprecated)</option> | 45 | <option value="extras">Extras API (deprecated)</option> |
| 45 | <option value="falai">FAL.AI</option> | 46 | <option value="falai">FAL.AI</option> |
| 46 | <option value="google">Google AI</option> | 47 | <option value="google">Google AI</option> |
| @@ -93,6 +94,9 @@ | |||
| 93 | <label for="sd_huggingface_model_id" data-i18n="Model ID">Model ID</label> | 94 | <label for="sd_huggingface_model_id" data-i18n="Model ID">Model ID</label> |
| 94 | <input id="sd_huggingface_model_id" type="text" class="text_pole" data-i18n="[placeholder]e.g. black-forest-labs/FLUX.1-dev" placeholder="e.g. black-forest-labs/FLUX.1-dev" value="" /> | 95 | <input id="sd_huggingface_model_id" type="text" class="text_pole" data-i18n="[placeholder]e.g. black-forest-labs/FLUX.1-dev" placeholder="e.g. black-forest-labs/FLUX.1-dev" value="" /> |
| 95 | </div> | 96 | </div> |
| 97 | <div data-sd-source="electronhub"> | ||
| 98 | <i>Hint: Save an API key in the Electron Hub (Chat Completion) API settings to use it here.</i> | ||
| 99 | </div> | ||
| 96 | <div data-sd-source="nanogpt"> | 100 | <div data-sd-source="nanogpt"> |
| 97 | <i>Hint: Save an API key in the NanoGPT (Chat Completion) API settings to use it here.</i> | 101 | <i>Hint: Save an API key in the NanoGPT (Chat Completion) API settings to use it here.</i> |
| 98 | </div> | 102 | </div> |
| @@ -260,7 +264,7 @@ | |||
| 260 | <span data-i18n="Click to set">Click to set</span> | 264 | <span data-i18n="Click to set">Click to set</span> |
| 261 | </div> | 265 | </div> |
| 262 | </div> | 266 | </div> |
| 263 | <label class="checkbox_label marginBot5" for="sd_bfl_upsampling" title="Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation."> | 267 | <label class="checkbox_label marginBot5" for="sd_bfl_upsampling" data-i18n="[title]Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation." title="Whether to perform upsampling on the prompt. If active, automatically modifies the prompt for more creative generation."> |
| 264 | <input id="sd_bfl_upsampling" type="checkbox" /> | 268 | <input id="sd_bfl_upsampling" type="checkbox" /> |
| 265 | <span data-i18n="Prompt Upsampling"> | 269 | <span data-i18n="Prompt Upsampling"> |
| 266 | Prompt Upsampling | 270 | Prompt Upsampling |
| @@ -182,9 +182,11 @@ function isGeneratingSwipe(messageId) { | |||
| 182 | return $(`#chat .mes[mesid="${messageId}"] .mes_text`).text() === '...'; | 182 | return $(`#chat .mes[mesid="${messageId}"] .mes_text`).text() === '...'; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | async function translateImpersonate(text) { | 185 | async function translateImpersonate() { |
| 186 | const sendTextArea = $('#send_textarea'); | ||
| 187 | const text = sendTextArea.val().toString(); | ||
| 186 | const translatedText = await translate(text, extension_settings.translate.target_language); | 188 | const translatedText = await translate(text, extension_settings.translate.target_language); |
| 187 | $('#send_textarea').val(translatedText); | 189 | sendTextArea.val(translatedText); |
| 188 | } | 190 | } |
| 189 | 191 | ||
| 190 | /** | 192 | /** |
| @@ -637,11 +637,8 @@ async function processTtsQueue() { | |||
| 637 | } | 637 | } |
| 638 | 638 | ||
| 639 | if (extension_settings.tts.narrate_quoted_only) { | 639 | if (extension_settings.tts.narrate_quoted_only) { |
| 640 | const special_quotes = /[“”«»「」『』""]/g; // Extend this regex to include other special quotes | ||
| 641 | text = text.replace(special_quotes, '"'); | ||
| 642 | const matches = text.match(/".*?"/g); // Matches text inside double quotes, non-greedily | ||
| 643 | const partJoiner = (ttsProvider?.separator || ' ... '); | 640 | const partJoiner = (ttsProvider?.separator || ' ... '); |
| 644 | text = matches ? matches.join(partJoiner) : text; | 641 | text = joinQuotedBlocks(text, { separator: partJoiner, includeQuotes: true }); |
| 645 | } | 642 | } |
| 646 | 643 | ||
| 647 | // Remove embedded images | 644 | // Remove embedded images |
| @@ -702,6 +699,82 @@ async function processTtsQueue() { | |||
| 702 | } | 699 | } |
| 703 | } | 700 | } |
| 704 | 701 | ||
| 702 | /** | ||
| 703 | * Extract and join quoted blocks with proper matching pairs and nesting. | ||
| 704 | * - Captures outermost quotes and everything inside (including different inner quote styles). | ||
| 705 | * - Requires matching opener/closer style (e.g., “ ... ”, 「 ... 」, « ... », etc.). | ||
| 706 | * - Ignores incomplete/unclosed quotes (doesn't include them in the result). | ||
| 707 | * - Symmetric quotes like "..." and "..." are supported (not nesting the same symmetric style). | ||
| 708 | * | ||
| 709 | * @param {string} text - The text to process | ||
| 710 | * @param {object} [opts={}] - Optional options object | ||
| 711 | * @param {string} [opts.separator=' ... '] - String to join multiple quoted blocks | ||
| 712 | * @param {boolean} [opts.includeQuotes=true] - Keep the quote chars around the captured text | ||
| 713 | * @param {boolean} [opts.returnEmptyOnNoQuotes=false] - Return an empty string if no quotes are found | ||
| 714 | * @param {Array<[string,string]>} [opts.pairs] - Custom quote pairs; defaults cover EN/DE/FR/JP | ||
| 715 | * @returns {string} The joined quoted blocks, or the original text if no quotes found | ||
| 716 | */ | ||
| 717 | function joinQuotedBlocks(text, opts = {}) { | ||
| 718 | const { | ||
| 719 | separator = ' ... ', | ||
| 720 | includeQuotes = true, | ||
| 721 | returnEmptyOnNoQuotes = false, | ||
| 722 | pairs = [ | ||
| 723 | // typographic doubles | ||
| 724 | ['„', '“'], // DE low-high | ||
| 725 | ['“', '”'], // EN | ||
| 726 | ['«', '»'], // FR open « close » | ||
| 727 | ['»', '«'], // Some locales open » | ||
| 728 | // typographic singles | ||
| 729 | ['‘', '’'], | ||
| 730 | ['‚', '‘'], | ||
| 731 | // Japanese corner quotes | ||
| 732 | ['「', '」'], | ||
| 733 | ['『', '』'], | ||
| 734 | // symmetric doubles | ||
| 735 | ['"', '"'], | ||
| 736 | ['"', '"'], | ||
| 737 | ], | ||
| 738 | } = opts; | ||
| 739 | |||
| 740 | if (!text || typeof text !== 'string') return text; | ||
| 741 | |||
| 742 | const openToClose = Object.fromEntries(pairs); | ||
| 743 | |||
| 744 | const segments = []; | ||
| 745 | const stack = []; // [{ opener, expectedClose, start }] | ||
| 746 | for (let i = 0; i < text.length; i++) { | ||
| 747 | const ch = text[i]; | ||
| 748 | const top = stack[stack.length - 1]; | ||
| 749 | |||
| 750 | // Prefer closing the current open pair if the char matches its expected closer | ||
| 751 | if (top && ch === top.expectedClose) { | ||
| 752 | const finished = stack.pop(); | ||
| 753 | if (stack.length === 0) { | ||
| 754 | // Only collect outermost quotes (contains all nested content) | ||
| 755 | segments.push(text.slice(finished.start, i + 1)); | ||
| 756 | } | ||
| 757 | continue; | ||
| 758 | } | ||
| 759 | |||
| 760 | // Otherwise, see if this is a new opener | ||
| 761 | if (openToClose[ch]) { | ||
| 762 | stack.push({ opener: ch, expectedClose: openToClose[ch], start: i }); | ||
| 763 | continue; | ||
| 764 | } | ||
| 765 | |||
| 766 | // If it's a stray closer that doesn't match current top, ignore | ||
| 767 | } | ||
| 768 | |||
| 769 | if (!segments.length) return returnEmptyOnNoQuotes ? '' : text; | ||
| 770 | |||
| 771 | const cleaned = includeQuotes | ||
| 772 | ? segments | ||
| 773 | : segments.map(s => s.slice(1, -1)); // all defined pairs are single-char quotes | ||
| 774 | |||
| 775 | return cleaned.join(separator); | ||
| 776 | } | ||
| 777 | |||
| 705 | async function playFullConversation() { | 778 | async function playFullConversation() { |
| 706 | resetTtsPlayback(); | 779 | resetTtsPlayback(); |
| 707 | 780 | ||
| @@ -11,7 +11,7 @@ const interactableSelectors = [ | |||
| 11 | '.avatar-container', // Persona list blocks | 11 | '.avatar-container', // Persona list blocks |
| 12 | '.tag .tag_remove', // Remove button in removable tags | 12 | '.tag .tag_remove', // Remove button in removable tags |
| 13 | '.bg_example', // Background elements in the background menu | 13 | '.bg_example', // Background elements in the background menu |
| 14 | '.bg_example .bg_button', // The inline buttons on the backgrounds | 14 | '.bg_example .jg-button, .bg_example .mobile-only-menu-toggle', // The inline buttons on the backgrounds |
| 15 | '#options a', // Option entries in the popup options menu | 15 | '#options a', // Option entries in the popup options menu |
| 16 | '.mes_buttons .mes_button', // Small inline buttons on the chat messages | 16 | '.mes_buttons .mes_button', // Small inline buttons on the chat messages |
| 17 | '.extraMesButtons>div:not(.mes_button)', // The extra/extension buttons inline on the chat messages | 17 | '.extraMesButtons>div:not(.mes_button)', // The extra/extension buttons inline on the chat messages |
| @@ -1,3 +1,5 @@ | |||
| 1 | import { initAccessibility } from './a11y.js'; | ||
| 2 | |||
| 1 | /** | 3 | /** |
| 2 | * CRSF token for requests. | 4 | * CRSF token for requests. |
| 3 | */ | 5 | */ |
| @@ -265,6 +267,8 @@ function configureDiscreetLogin() { | |||
| 265 | } | 267 | } |
| 266 | 268 | ||
| 267 | (async function () { | 269 | (async function () { |
| 270 | initAccessibility(); | ||
| 271 | |||
| 268 | csrfToken = await getCsrfToken(); | 272 | csrfToken = await getCsrfToken(); |
| 269 | const userList = await getUserList(); | 273 | const userList = await getUserList(); |
| 270 | 274 | ||
| @@ -179,6 +179,7 @@ export const chat_completion_sources = { | |||
| 179 | COHERE: 'cohere', | 179 | COHERE: 'cohere', |
| 180 | PERPLEXITY: 'perplexity', | 180 | PERPLEXITY: 'perplexity', |
| 181 | GROQ: 'groq', | 181 | GROQ: 'groq', |
| 182 | ELECTRONHUB: 'electronhub', | ||
| 182 | NANOGPT: 'nanogpt', | 183 | NANOGPT: 'nanogpt', |
| 183 | DEEPSEEK: 'deepseek', | 184 | DEEPSEEK: 'deepseek', |
| 184 | AIMLAPI: 'aimlapi', | 185 | AIMLAPI: 'aimlapi', |
| @@ -187,6 +188,7 @@ export const chat_completion_sources = { | |||
| 187 | MOONSHOT: 'moonshot', | 188 | MOONSHOT: 'moonshot', |
| 188 | FIREWORKS: 'fireworks', | 189 | FIREWORKS: 'fireworks', |
| 189 | COMETAPI: 'cometapi', | 190 | COMETAPI: 'cometapi', |
| 191 | AZURE_OPENAI: 'azure_openai', | ||
| 190 | }; | 192 | }; |
| 191 | 193 | ||
| 192 | const character_names_behavior = { | 194 | const character_names_behavior = { |
| @@ -240,6 +242,8 @@ const sensitiveFields = [ | |||
| 240 | 'custom_include_headers', | 242 | 'custom_include_headers', |
| 241 | 'vertexai_region', | 243 | 'vertexai_region', |
| 242 | 'vertexai_express_project_id', | 244 | 'vertexai_express_project_id', |
| 245 | 'azure_base_url', | ||
| 246 | 'azure_deployment_name', | ||
| 243 | ]; | 247 | ]; |
| 244 | 248 | ||
| 245 | /** | 249 | /** |
| @@ -271,6 +275,7 @@ export const settingsToUpdate = { | |||
| 271 | cohere_model: ['#model_cohere_select', 'cohere_model', false, true], | 275 | cohere_model: ['#model_cohere_select', 'cohere_model', false, true], |
| 272 | perplexity_model: ['#model_perplexity_select', 'perplexity_model', false, true], | 276 | perplexity_model: ['#model_perplexity_select', 'perplexity_model', false, true], |
| 273 | groq_model: ['#model_groq_select', 'groq_model', false, true], | 277 | groq_model: ['#model_groq_select', 'groq_model', false, true], |
| 278 | electronhub_model: ['#model_electronhub_select', 'electronhub_model', false, true], | ||
| 274 | nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false, true], | 279 | nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false, true], |
| 275 | deepseek_model: ['#model_deepseek_select', 'deepseek_model', false, true], | 280 | deepseek_model: ['#model_deepseek_select', 'deepseek_model', false, true], |
| 276 | aimlapi_model: ['#model_aimlapi_select', 'aimlapi_model', false, true], | 281 | aimlapi_model: ['#model_aimlapi_select', 'aimlapi_model', false, true], |
| @@ -329,6 +334,10 @@ export const settingsToUpdate = { | |||
| 329 | n: ['#n_openai', 'n', false, false], | 334 | n: ['#n_openai', 'n', false, false], |
| 330 | bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true, true], | 335 | bypass_status_check: ['#openai_bypass_status_check', 'bypass_status_check', true, true], |
| 331 | request_images: ['#openai_request_images', 'request_images', true, false], | 336 | request_images: ['#openai_request_images', 'request_images', true, false], |
| 337 | azure_base_url: ['#azure_base_url', 'azure_base_url', false, true], | ||
| 338 | azure_deployment_name: ['#azure_deployment_name', 'azure_deployment_name', false, true], | ||
| 339 | azure_api_version: ['#azure_api_version', 'azure_api_version', false, true], | ||
| 340 | azure_openai_model: ['#azure_openai_model', 'azure_openai_model', false, true], | ||
| 332 | extensions: ['#NULL_SELECTOR', 'extensions', false, false], | 341 | extensions: ['#NULL_SELECTOR', 'extensions', false, false], |
| 333 | }; | 342 | }; |
| 334 | 343 | ||
| @@ -369,6 +378,7 @@ const default_settings = { | |||
| 369 | cohere_model: 'command-r-plus', | 378 | cohere_model: 'command-r-plus', |
| 370 | perplexity_model: 'sonar-pro', | 379 | perplexity_model: 'sonar-pro', |
| 371 | groq_model: 'llama-3.3-70b-versatile', | 380 | groq_model: 'llama-3.3-70b-versatile', |
| 381 | electronhub_model: 'gpt-4o-mini', | ||
| 372 | nanogpt_model: 'gpt-4o-mini', | 382 | nanogpt_model: 'gpt-4o-mini', |
| 373 | deepseek_model: 'deepseek-chat', | 383 | deepseek_model: 'deepseek-chat', |
| 374 | aimlapi_model: 'gpt-4o-mini-2024-07-18', | 384 | aimlapi_model: 'gpt-4o-mini-2024-07-18', |
| @@ -377,6 +387,10 @@ const default_settings = { | |||
| 377 | cometapi_model: 'gpt-4o', | 387 | cometapi_model: 'gpt-4o', |
| 378 | moonshot_model: 'kimi-latest', | 388 | moonshot_model: 'kimi-latest', |
| 379 | fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct', | 389 | fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct', |
| 390 | azure_base_url: '', | ||
| 391 | azure_deployment_name: '', | ||
| 392 | azure_api_version: '2024-02-15-preview', | ||
| 393 | azure_openai_model: '', | ||
| 380 | custom_model: '', | 394 | custom_model: '', |
| 381 | custom_url: '', | 395 | custom_url: '', |
| 382 | custom_include_body: '', | 396 | custom_include_body: '', |
| @@ -458,6 +472,7 @@ const oai_settings = { | |||
| 458 | cohere_model: 'command-r-plus', | 472 | cohere_model: 'command-r-plus', |
| 459 | perplexity_model: 'sonar-pro', | 473 | perplexity_model: 'sonar-pro', |
| 460 | groq_model: 'llama-3.1-70b-versatile', | 474 | groq_model: 'llama-3.1-70b-versatile', |
| 475 | electronhub_model: 'gpt-4o-mini', | ||
| 461 | nanogpt_model: 'gpt-4o-mini', | 476 | nanogpt_model: 'gpt-4o-mini', |
| 462 | deepseek_model: 'deepseek-chat', | 477 | deepseek_model: 'deepseek-chat', |
| 463 | aimlapi_model: 'gpt-4-turbo', | 478 | aimlapi_model: 'gpt-4-turbo', |
| @@ -466,6 +481,10 @@ const oai_settings = { | |||
| 466 | cometapi_model: 'gpt-4o', | 481 | cometapi_model: 'gpt-4o', |
| 467 | moonshot_model: 'kimi-latest', | 482 | moonshot_model: 'kimi-latest', |
| 468 | fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct', | 483 | fireworks_model: 'accounts/fireworks/models/kimi-k2-instruct', |
| 484 | azure_base_url: '', | ||
| 485 | azure_deployment_name: '', | ||
| 486 | azure_api_version: '2024-02-15-preview', | ||
| 487 | azure_openai_model: '', | ||
| 469 | custom_model: '', | 488 | custom_model: '', |
| 470 | custom_url: '', | 489 | custom_url: '', |
| 471 | custom_include_body: '', | 490 | custom_include_body: '', |
| @@ -905,7 +924,6 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 905 | 924 | ||
| 906 | // Insert chat messages as long as there is budget available | 925 | // Insert chat messages as long as there is budget available |
| 907 | const chatPool = [...messages].reverse(); | 926 | const chatPool = [...messages].reverse(); |
| 908 | const firstNonInjected = chatPool.find(x => !x.injected); | ||
| 909 | for (let index = 0; index < chatPool.length; index++) { | 927 | for (let index = 0; index < chatPool.length; index++) { |
| 910 | const chatPrompt = chatPool[index]; | 928 | const chatPrompt = chatPool[index]; |
| 911 | 929 | ||
| @@ -946,22 +964,6 @@ async function populateChatHistory(messages, prompts, chatCompletion, type = nul | |||
| 946 | } | 964 | } |
| 947 | 965 | ||
| 948 | if (chatCompletion.canAfford(chatMessage)) { | 966 | if (chatCompletion.canAfford(chatMessage)) { |
| 949 | if (type === 'continue' && oai_settings.continue_prefill && chatPrompt === firstNonInjected) { | ||
| 950 | // 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 | ||
| 951 | if (chatPrompt.role === 'assistant') { | ||
| 952 | const supportsAssistantPrefill = oai_settings.chat_completion_source === chat_completion_sources.CLAUDE; | ||
| 953 | const assistantPrefill = supportsAssistantPrefill ? substituteParams(oai_settings.assistant_prefill) : ''; | ||
| 954 | const messageContent = [assistantPrefill, chatMessage.content].filter(x => x).join('\n\n'); | ||
| 955 | const continueMessage = await Message.createAsync(chatMessage.role, messageContent, chatMessage.identifier); | ||
| 956 | const collection = new MessageCollection('continuePrefill', continueMessage); | ||
| 957 | chatCompletion.add(collection, -1); | ||
| 958 | continue; | ||
| 959 | } | ||
| 960 | const collection = new MessageCollection('continuePrefill', chatMessage); | ||
| 961 | chatCompletion.add(collection, -1); | ||
| 962 | continue; | ||
| 963 | } | ||
| 964 | |||
| 965 | chatCompletion.insertAtStart(chatMessage, 'chatHistory'); | 967 | chatCompletion.insertAtStart(chatMessage, 'chatHistory'); |
| 966 | } else { | 968 | } else { |
| 967 | break; | 969 | break; |
| @@ -1221,6 +1223,21 @@ async function populateChatCompletion(prompts, chatCompletion, { bias, quietProm | |||
| 1221 | chatCompletion.reserveBudget(toolTokens); | 1223 | chatCompletion.reserveBudget(toolTokens); |
| 1222 | } | 1224 | } |
| 1223 | 1225 | ||
| 1226 | // Displace the message to be continued from its original position before performing in-chat injections | ||
| 1227 | // In case if it is an assistant message, we want to prepend the users assistant prefill on the message | ||
| 1228 | if (type === 'continue' && oai_settings.continue_prefill && messages.length) { | ||
| 1229 | const chatMessage = messages.shift(); | ||
| 1230 | const isAssistantRole = chatMessage.role === 'assistant'; | ||
| 1231 | const supportsAssistantPrefill = oai_settings.chat_completion_source === chat_completion_sources.CLAUDE; | ||
| 1232 | const namesInCompletion = oai_settings.names_behavior === character_names_behavior.COMPLETION; | ||
| 1233 | const assistantPrefill = isAssistantRole && supportsAssistantPrefill ? substituteParams(oai_settings.assistant_prefill) : ''; | ||
| 1234 | const messageContent = [assistantPrefill, chatMessage.content].filter(x => x).join('\n\n'); | ||
| 1235 | const continueMessage = await Message.createAsync(chatMessage.role, messageContent, 'continuePrefill'); | ||
| 1236 | chatMessage.name && namesInCompletion && await continueMessage.setName(promptManager.sanitizeName(chatMessage.name)); | ||
| 1237 | controlPrompts.add(continueMessage); | ||
| 1238 | chatCompletion.reserveBudget(continueMessage); | ||
| 1239 | } | ||
| 1240 | |||
| 1224 | // Add in-chat injections | 1241 | // Add in-chat injections |
| 1225 | messages = await populationInjectionPrompts(absolutePrompts, messages); | 1242 | messages = await populationInjectionPrompts(absolutePrompts, messages); |
| 1226 | 1243 | ||
| @@ -1544,6 +1561,11 @@ export function tryParseStreamingError(response, decoded, { quiet = false } = {} | |||
| 1544 | !quiet && toastr.error(data.message, 'Chat Completion API'); | 1561 | !quiet && toastr.error(data.message, 'Chat Completion API'); |
| 1545 | throw new Error(data); | 1562 | throw new Error(data); |
| 1546 | } | 1563 | } |
| 1564 | |||
| 1565 | if (data.detail) { | ||
| 1566 | !quiet && toastr.error(data.detail?.error?.message || response.statusText, 'Chat Completion API'); | ||
| 1567 | throw new Error(data); | ||
| 1568 | } | ||
| 1547 | } | 1569 | } |
| 1548 | catch { | 1570 | catch { |
| 1549 | // No JSON. Do nothing. | 1571 | // No JSON. Do nothing. |
| @@ -1616,6 +1638,8 @@ export function getChatCompletionModel(source = null) { | |||
| 1616 | return oai_settings.perplexity_model; | 1638 | return oai_settings.perplexity_model; |
| 1617 | case chat_completion_sources.GROQ: | 1639 | case chat_completion_sources.GROQ: |
| 1618 | return oai_settings.groq_model; | 1640 | return oai_settings.groq_model; |
| 1641 | case chat_completion_sources.ELECTRONHUB: | ||
| 1642 | return oai_settings.electronhub_model; | ||
| 1619 | case chat_completion_sources.NANOGPT: | 1643 | case chat_completion_sources.NANOGPT: |
| 1620 | return oai_settings.nanogpt_model; | 1644 | return oai_settings.nanogpt_model; |
| 1621 | case chat_completion_sources.DEEPSEEK: | 1645 | case chat_completion_sources.DEEPSEEK: |
| @@ -1632,6 +1656,8 @@ export function getChatCompletionModel(source = null) { | |||
| 1632 | return oai_settings.moonshot_model; | 1656 | return oai_settings.moonshot_model; |
| 1633 | case chat_completion_sources.FIREWORKS: | 1657 | case chat_completion_sources.FIREWORKS: |
| 1634 | return oai_settings.fireworks_model; | 1658 | return oai_settings.fireworks_model; |
| 1659 | case chat_completion_sources.AZURE_OPENAI: | ||
| 1660 | return oai_settings.azure_openai_model; | ||
| 1635 | default: | 1661 | default: |
| 1636 | console.error(`Unknown chat completion source: ${activeSource}`); | 1662 | console.error(`Unknown chat completion source: ${activeSource}`); |
| 1637 | return ''; | 1663 | return ''; |
| @@ -1776,6 +1802,26 @@ function saveModelList(data) { | |||
| 1776 | } | 1802 | } |
| 1777 | } | 1803 | } |
| 1778 | 1804 | ||
| 1805 | if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) { | ||
| 1806 | $('#model_electronhub_select').empty(); | ||
| 1807 | model_list.forEach((model) => { | ||
| 1808 | if (model?.endpoints?.includes('/v1/chat/completions')) { | ||
| 1809 | $('#model_electronhub_select').append( | ||
| 1810 | $('<option>', { | ||
| 1811 | value: model.id, | ||
| 1812 | text: model.name, | ||
| 1813 | })); | ||
| 1814 | } | ||
| 1815 | }); | ||
| 1816 | |||
| 1817 | const selectedModel = model_list.find(model => model.id === oai_settings.electronhub_model); | ||
| 1818 | if (model_list.length > 0 && (!selectedModel || !oai_settings.electronhub_model)) { | ||
| 1819 | oai_settings.electronhub_model = model_list[0].id; | ||
| 1820 | } | ||
| 1821 | |||
| 1822 | $('#model_electronhub_select').val(oai_settings.electronhub_model).trigger('change'); | ||
| 1823 | } | ||
| 1824 | |||
| 1779 | if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) { | 1825 | if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) { |
| 1780 | $('#model_nanogpt_select').empty(); | 1826 | $('#model_nanogpt_select').empty(); |
| 1781 | model_list.forEach((model) => { | 1827 | model_list.forEach((model) => { |
| @@ -1928,6 +1974,16 @@ function saveModelList(data) { | |||
| 1928 | 1974 | ||
| 1929 | $('#model_cometapi_select').val(oai_settings.cometapi_model).trigger('change'); | 1975 | $('#model_cometapi_select').val(oai_settings.cometapi_model).trigger('change'); |
| 1930 | } | 1976 | } |
| 1977 | |||
| 1978 | if (oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) { | ||
| 1979 | const modelId = model_list?.[0]?.id || ''; | ||
| 1980 | oai_settings.azure_openai_model = modelId; | ||
| 1981 | |||
| 1982 | $('#azure_openai_model') | ||
| 1983 | .empty() | ||
| 1984 | .append(new Option(modelId || 'None', modelId || '', true, true)) | ||
| 1985 | .trigger('change'); | ||
| 1986 | } | ||
| 1931 | } | 1987 | } |
| 1932 | 1988 | ||
| 1933 | function appendOpenRouterOptions(model_list, groupModels = false, sort = false) { | 1989 | function appendOpenRouterOptions(model_list, groupModels = false, sort = false) { |
| @@ -2039,6 +2095,7 @@ function getReasoningEffort() { | |||
| 2039 | // These sources expect the effort as string. | 2095 | // These sources expect the effort as string. |
| 2040 | const reasoningEffortSources = [ | 2096 | const reasoningEffortSources = [ |
| 2041 | chat_completion_sources.OPENAI, | 2097 | chat_completion_sources.OPENAI, |
| 2098 | chat_completion_sources.AZURE_OPENAI, | ||
| 2042 | chat_completion_sources.CUSTOM, | 2099 | chat_completion_sources.CUSTOM, |
| 2043 | chat_completion_sources.XAI, | 2100 | chat_completion_sources.XAI, |
| 2044 | chat_completion_sources.AIMLAPI, | 2101 | chat_completion_sources.AIMLAPI, |
| @@ -2046,24 +2103,43 @@ function getReasoningEffort() { | |||
| 2046 | chat_completion_sources.POLLINATIONS, | 2103 | chat_completion_sources.POLLINATIONS, |
| 2047 | chat_completion_sources.PERPLEXITY, | 2104 | chat_completion_sources.PERPLEXITY, |
| 2048 | chat_completion_sources.COMETAPI, | 2105 | chat_completion_sources.COMETAPI, |
| 2106 | chat_completion_sources.ELECTRONHUB, | ||
| 2049 | ]; | 2107 | ]; |
| 2050 | 2108 | ||
| 2051 | if (!reasoningEffortSources.includes(oai_settings.chat_completion_source)) { | 2109 | if (!reasoningEffortSources.includes(oai_settings.chat_completion_source)) { |
| 2052 | return oai_settings.reasoning_effort; | 2110 | return oai_settings.reasoning_effort; |
| 2053 | } | 2111 | } |
| 2054 | 2112 | ||
| 2055 | switch (oai_settings.reasoning_effort) { | 2113 | function resolveReasoningEffort() { |
| 2056 | case reasoning_effort_types.auto: | 2114 | switch (oai_settings.reasoning_effort) { |
| 2115 | case reasoning_effort_types.auto: | ||
| 2116 | return undefined; | ||
| 2117 | case reasoning_effort_types.min: | ||
| 2118 | return [chat_completion_sources.OPENAI, chat_completion_sources.AZURE_OPENAI].includes(oai_settings.chat_completion_source) && /^gpt-5/.test(getChatCompletionModel()) | ||
| 2119 | ? reasoning_effort_types.min | ||
| 2120 | : reasoning_effort_types.low; | ||
| 2121 | case reasoning_effort_types.max: | ||
| 2122 | return reasoning_effort_types.high; | ||
| 2123 | default: | ||
| 2124 | return oai_settings.reasoning_effort; | ||
| 2125 | } | ||
| 2126 | } | ||
| 2127 | |||
| 2128 | const reasoningEffort = resolveReasoningEffort(); | ||
| 2129 | |||
| 2130 | // Check if the resolved effort supported by the model | ||
| 2131 | if (oai_settings.chat_completion_source === chat_completion_sources.ELECTRONHUB) { | ||
| 2132 | if (Array.isArray(model_list) && reasoningEffort) { | ||
| 2133 | const currentModel = model_list.find(m => m.id === oai_settings.electronhub_model); | ||
| 2134 | const supportedEfforts = currentModel?.metadata?.supported_reasoning_efforts; | ||
| 2135 | if (Array.isArray(supportedEfforts) && supportedEfforts.includes(reasoningEffort)) { | ||
| 2136 | return reasoningEffort; | ||
| 2137 | } | ||
| 2057 | return undefined; | 2138 | return undefined; |
| 2058 | case reasoning_effort_types.min: | 2139 | } |
| 2059 | return chat_completion_sources.OPENAI === oai_settings.chat_completion_source && /^gpt-5/.test(oai_settings.openai_model) | ||
| 2060 | ? reasoning_effort_types.min | ||
| 2061 | : reasoning_effort_types.low; | ||
| 2062 | case reasoning_effort_types.max: | ||
| 2063 | return reasoning_effort_types.high; | ||
| 2064 | default: | ||
| 2065 | return oai_settings.reasoning_effort; | ||
| 2066 | } | 2140 | } |
| 2141 | |||
| 2142 | return reasoningEffort; | ||
| 2067 | } | 2143 | } |
| 2068 | 2144 | ||
| 2069 | /** | 2145 | /** |
| @@ -2102,18 +2178,20 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2102 | const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ; | 2178 | const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ; |
| 2103 | const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK; | 2179 | const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK; |
| 2104 | const isAimlapi = oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI; | 2180 | const isAimlapi = oai_settings.chat_completion_source == chat_completion_sources.AIMLAPI; |
| 2181 | const isElectronHub = oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB; | ||
| 2105 | const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI; | 2182 | const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI; |
| 2106 | const isPollinations = oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS; | 2183 | const isPollinations = oai_settings.chat_completion_source == chat_completion_sources.POLLINATIONS; |
| 2107 | const isMoonshot = oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT; | 2184 | const isMoonshot = oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT; |
| 2185 | const isAzureOpenAI = oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI; // Add this line | ||
| 2108 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); | 2186 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); |
| 2109 | const isQuiet = type === 'quiet'; | 2187 | const isQuiet = type === 'quiet'; |
| 2110 | const isImpersonate = type === 'impersonate'; | 2188 | const isImpersonate = type === 'impersonate'; |
| 2111 | const isContinue = type === 'continue'; | 2189 | const isContinue = type === 'continue'; |
| 2112 | const stream = oai_settings.stream_openai && !isQuiet && !(isOAI && ['o1-2024-12-17', 'o1'].includes(oai_settings.openai_model)); | 2190 | const stream = oai_settings.stream_openai && !isQuiet && !((isOAI || isAzureOpenAI) && ['o1-2024-12-17', 'o1'].includes(getChatCompletionModel())); |
| 2113 | const useLogprobs = !!power_user.request_token_probabilities; | 2191 | const useLogprobs = !!power_user.request_token_probabilities; |
| 2114 | const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isCustom || isXAI || isAimlapi || isMoonshot); | 2192 | const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isAzureOpenAI || isCustom || isXAI || isAimlapi || isMoonshot); |
| 2115 | 2193 | ||
| 2116 | const logitBiasSources = [chat_completion_sources.OPENAI, chat_completion_sources.OPENROUTER, chat_completion_sources.CUSTOM]; | 2194 | const logitBiasSources = [chat_completion_sources.OPENAI, chat_completion_sources.AZURE_OPENAI, chat_completion_sources.OPENROUTER, chat_completion_sources.CUSTOM]; |
| 2117 | if (oai_settings.bias_preset_selected | 2195 | if (oai_settings.bias_preset_selected |
| 2118 | && logitBiasSources.includes(oai_settings.chat_completion_source) | 2196 | && logitBiasSources.includes(oai_settings.chat_completion_source) |
| 2119 | && Array.isArray(oai_settings.bias_presets[oai_settings.bias_preset_selected]) | 2197 | && Array.isArray(oai_settings.bias_presets[oai_settings.bias_preset_selected]) |
| @@ -2151,6 +2229,16 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2151 | 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing, | 2229 | 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing, |
| 2152 | }; | 2230 | }; |
| 2153 | 2231 | ||
| 2232 | if (isAzureOpenAI) { | ||
| 2233 | generate_data.azure_base_url = oai_settings.azure_base_url; | ||
| 2234 | generate_data.azure_deployment_name = oai_settings.azure_deployment_name; | ||
| 2235 | generate_data.azure_api_version = oai_settings.azure_api_version; | ||
| 2236 | // Reasoning effort is not supported on some Azure models (e.g. GPT-3.x, GPT-4.x) | ||
| 2237 | if (/^gpt-[34]/.test(oai_settings.azure_openai_model)) { | ||
| 2238 | delete generate_data.reasoning_effort; | ||
| 2239 | } | ||
| 2240 | } | ||
| 2241 | |||
| 2154 | if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) { | 2242 | if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) { |
| 2155 | await ToolManager.registerFunctionToolsOpenAI(generate_data); | 2243 | await ToolManager.registerFunctionToolsOpenAI(generate_data); |
| 2156 | } | 2244 | } |
| @@ -2168,18 +2256,18 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2168 | } | 2256 | } |
| 2169 | 2257 | ||
| 2170 | // Add logprobs request (currently OpenAI only, max 5 on their side) | 2258 | // Add logprobs request (currently OpenAI only, max 5 on their side) |
| 2171 | if (useLogprobs && (isOAI || isCustom || isDeepSeek || isXAI || isAimlapi)) { | 2259 | if (useLogprobs && (isOAI || isAzureOpenAI || isCustom || isDeepSeek || isXAI || isAimlapi)) { |
| 2172 | generate_data['logprobs'] = 5; | 2260 | generate_data['logprobs'] = 5; |
| 2173 | } | 2261 | } |
| 2174 | 2262 | ||
| 2175 | // Remove logit bias/logprobs/stop-strings if not supported by the model | 2263 | // Remove logit bias/logprobs/stop-strings if not supported by the model |
| 2176 | const isVision = (m) => ['gpt', 'vision'].every(x => m.includes(x)); | 2264 | const isVision = (m) => ['gpt', 'vision'].every(x => m.includes(x)); |
| 2177 | if (isOAI && isVision(oai_settings.openai_model) || isOpenRouter && isVision(oai_settings.openrouter_model)) { | 2265 | if ((isOAI && isVision(oai_settings.openai_model)) || (isAzureOpenAI && isVision(oai_settings.azure_openai_model)) || (isOpenRouter && isVision(oai_settings.openrouter_model))) { |
| 2178 | delete generate_data.logit_bias; | 2266 | delete generate_data.logit_bias; |
| 2179 | delete generate_data.stop; | 2267 | delete generate_data.stop; |
| 2180 | delete generate_data.logprobs; | 2268 | delete generate_data.logprobs; |
| 2181 | } | 2269 | } |
| 2182 | if (isOAI && oai_settings.openai_model.includes('gpt-4.5') || isOpenRouter && oai_settings.openrouter_model.includes('gpt-4.5')) { | 2270 | if ((isOAI && oai_settings.openai_model.includes('gpt-4.5')) || (isAzureOpenAI && oai_settings.azure_openai_model.includes('gpt-4.5')) || (isOpenRouter && oai_settings.openrouter_model.includes('gpt-4.5'))) { |
| 2183 | delete generate_data.logprobs; | 2271 | delete generate_data.logprobs; |
| 2184 | } | 2272 | } |
| 2185 | 2273 | ||
| @@ -2262,16 +2350,6 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2262 | // https://api-docs.deepseek.com/api/create-chat-completion | 2350 | // https://api-docs.deepseek.com/api/create-chat-completion |
| 2263 | if (isDeepSeek) { | 2351 | if (isDeepSeek) { |
| 2264 | generate_data.top_p = generate_data.top_p || Number.EPSILON; | 2352 | generate_data.top_p = generate_data.top_p || Number.EPSILON; |
| 2265 | |||
| 2266 | if (generate_data.model.endsWith('-reasoner')) { | ||
| 2267 | delete generate_data.top_p; | ||
| 2268 | delete generate_data.temperature; | ||
| 2269 | delete generate_data.frequency_penalty; | ||
| 2270 | delete generate_data.presence_penalty; | ||
| 2271 | delete generate_data.top_logprobs; | ||
| 2272 | delete generate_data.logprobs; | ||
| 2273 | delete generate_data.logit_bias; | ||
| 2274 | } | ||
| 2275 | } | 2353 | } |
| 2276 | 2354 | ||
| 2277 | if (isXAI) { | 2355 | if (isXAI) { |
| @@ -2295,13 +2373,20 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2295 | delete generate_data.max_tokens; | 2373 | delete generate_data.max_tokens; |
| 2296 | } | 2374 | } |
| 2297 | 2375 | ||
| 2376 | // https://docs.electronhub.ai/api-reference/chat/completions | ||
| 2377 | if (isElectronHub) { | ||
| 2378 | generate_data['top_k'] = Number(oai_settings.top_k_openai); | ||
| 2379 | } | ||
| 2380 | |||
| 2298 | const seedSupportedSources = [ | 2381 | const seedSupportedSources = [ |
| 2299 | chat_completion_sources.OPENAI, | 2382 | chat_completion_sources.OPENAI, |
| 2383 | chat_completion_sources.AZURE_OPENAI, | ||
| 2300 | chat_completion_sources.OPENROUTER, | 2384 | chat_completion_sources.OPENROUTER, |
| 2301 | chat_completion_sources.MISTRALAI, | 2385 | chat_completion_sources.MISTRALAI, |
| 2302 | chat_completion_sources.CUSTOM, | 2386 | chat_completion_sources.CUSTOM, |
| 2303 | chat_completion_sources.COHERE, | 2387 | chat_completion_sources.COHERE, |
| 2304 | chat_completion_sources.GROQ, | 2388 | chat_completion_sources.GROQ, |
| 2389 | chat_completion_sources.ELECTRONHUB, | ||
| 2305 | chat_completion_sources.NANOGPT, | 2390 | chat_completion_sources.NANOGPT, |
| 2306 | chat_completion_sources.XAI, | 2391 | chat_completion_sources.XAI, |
| 2307 | chat_completion_sources.POLLINATIONS, | 2392 | chat_completion_sources.POLLINATIONS, |
| @@ -2313,7 +2398,7 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2313 | generate_data['seed'] = oai_settings.seed; | 2398 | generate_data['seed'] = oai_settings.seed; |
| 2314 | } | 2399 | } |
| 2315 | 2400 | ||
| 2316 | if (isOAI && /^(o1|o3|o4)/.test(oai_settings.openai_model)) { | 2401 | if ((isOAI && /^(o1|o3|o4)/.test(oai_settings.openai_model)) || (isAzureOpenAI && /^(o1|o3|o4)/.test(oai_settings.azure_openai_model))) { |
| 2317 | generate_data.max_completion_tokens = generate_data.max_tokens; | 2402 | generate_data.max_completion_tokens = generate_data.max_tokens; |
| 2318 | delete generate_data.max_tokens; | 2403 | delete generate_data.max_tokens; |
| 2319 | delete generate_data.logprobs; | 2404 | delete generate_data.logprobs; |
| @@ -2336,7 +2421,7 @@ async function sendOpenAIRequest(type, messages, signal, { jsonSchema = null } = | |||
| 2336 | } | 2421 | } |
| 2337 | } | 2422 | } |
| 2338 | 2423 | ||
| 2339 | if (isOAI && /^gpt-5/.test(oai_settings.openai_model)) { | 2424 | if ((isOAI && /^gpt-5/.test(oai_settings.openai_model)) || (isAzureOpenAI && /^gpt-5/.test(oai_settings.azure_openai_model))) { |
| 2340 | generate_data.max_completion_tokens = generate_data.max_tokens; | 2425 | generate_data.max_completion_tokens = generate_data.max_tokens; |
| 2341 | delete generate_data.max_tokens; | 2426 | delete generate_data.max_tokens; |
| 2342 | delete generate_data.logprobs; | 2427 | delete generate_data.logprobs; |
| @@ -2466,11 +2551,15 @@ export function getStreamingReply(data, state, { chatCompletionSource = null, ov | |||
| 2466 | } | 2551 | } |
| 2467 | return data.choices?.[0]?.delta?.content || ''; | 2552 | return data.choices?.[0]?.delta?.content || ''; |
| 2468 | } else if (chat_completion_source === chat_completion_sources.OPENROUTER) { | 2553 | } else if (chat_completion_source === chat_completion_sources.OPENROUTER) { |
| 2554 | const imageUrl = data?.choices?.[0]?.delta?.images?.find(x => x.type === 'image_url')?.image_url?.url; | ||
| 2555 | if (imageUrl) { | ||
| 2556 | state.image = imageUrl; | ||
| 2557 | } | ||
| 2469 | if (show_thoughts) { | 2558 | if (show_thoughts) { |
| 2470 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); | 2559 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); |
| 2471 | } | 2560 | } |
| 2472 | return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? ''; | 2561 | return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? ''; |
| 2473 | } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT, chat_completion_sources.COMETAPI].includes(chat_completion_source)) { | 2562 | } else if ([chat_completion_sources.CUSTOM, chat_completion_sources.POLLINATIONS, chat_completion_sources.AIMLAPI, chat_completion_sources.MOONSHOT, chat_completion_sources.COMETAPI, chat_completion_sources.ELECTRONHUB].includes(chat_completion_source)) { |
| 2474 | if (show_thoughts) { | 2563 | if (show_thoughts) { |
| 2475 | state.reasoning += | 2564 | state.reasoning += |
| 2476 | data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ?? | 2565 | data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ?? |
| @@ -2502,6 +2591,7 @@ function parseChatCompletionLogprobs(data) { | |||
| 2502 | 2591 | ||
| 2503 | switch (oai_settings.chat_completion_source) { | 2592 | switch (oai_settings.chat_completion_source) { |
| 2504 | case chat_completion_sources.OPENAI: | 2593 | case chat_completion_sources.OPENAI: |
| 2594 | case chat_completion_sources.AZURE_OPENAI: | ||
| 2505 | case chat_completion_sources.DEEPSEEK: | 2595 | case chat_completion_sources.DEEPSEEK: |
| 2506 | case chat_completion_sources.XAI: | 2596 | case chat_completion_sources.XAI: |
| 2507 | case chat_completion_sources.CUSTOM: | 2597 | case chat_completion_sources.CUSTOM: |
| @@ -2510,7 +2600,7 @@ function parseChatCompletionLogprobs(data) { | |||
| 2510 | } | 2600 | } |
| 2511 | // OpenAI Text Completion API is treated as a chat completion source | 2601 | // OpenAI Text Completion API is treated as a chat completion source |
| 2512 | // by SillyTavern, hence its presence in this function. | 2602 | // by SillyTavern, hence its presence in this function. |
| 2513 | return textCompletionModels.includes(oai_settings.openai_model) | 2603 | return textCompletionModels.includes(getChatCompletionModel()) |
| 2514 | ? parseOpenAITextLogprobs(data.choices[0]?.logprobs) | 2604 | ? parseOpenAITextLogprobs(data.choices[0]?.logprobs) |
| 2515 | : parseOpenAIChatLogprobs(data.choices[0]?.logprobs); | 2605 | : parseOpenAIChatLogprobs(data.choices[0]?.logprobs); |
| 2516 | default: | 2606 | default: |
| @@ -3432,6 +3522,7 @@ function loadOpenAISettings(data, settings) { | |||
| 3432 | oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model; | 3522 | oai_settings.cohere_model = settings.cohere_model ?? default_settings.cohere_model; |
| 3433 | oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model; | 3523 | oai_settings.perplexity_model = settings.perplexity_model ?? default_settings.perplexity_model; |
| 3434 | oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model; | 3524 | oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model; |
| 3525 | oai_settings.electronhub_model = settings.electronhub_model ?? default_settings.electronhub_model; | ||
| 3435 | oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model; | 3526 | oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model; |
| 3436 | oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model; | 3527 | oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model; |
| 3437 | oai_settings.aimlapi_model = settings.aimlapi_model ?? default_settings.aimlapi_model; | 3528 | oai_settings.aimlapi_model = settings.aimlapi_model ?? default_settings.aimlapi_model; |
| @@ -3447,6 +3538,10 @@ function loadOpenAISettings(data, settings) { | |||
| 3447 | oai_settings.custom_include_headers = settings.custom_include_headers ?? default_settings.custom_include_headers; | 3538 | oai_settings.custom_include_headers = settings.custom_include_headers ?? default_settings.custom_include_headers; |
| 3448 | oai_settings.custom_prompt_post_processing = settings.custom_prompt_post_processing ?? default_settings.custom_prompt_post_processing; | 3539 | oai_settings.custom_prompt_post_processing = settings.custom_prompt_post_processing ?? default_settings.custom_prompt_post_processing; |
| 3449 | oai_settings.google_model = settings.google_model ?? default_settings.google_model; | 3540 | oai_settings.google_model = settings.google_model ?? default_settings.google_model; |
| 3541 | oai_settings.azure_base_url = settings.azure_base_url ?? default_settings.azure_base_url; | ||
| 3542 | oai_settings.azure_deployment_name = settings.azure_deployment_name ?? default_settings.azure_deployment_name; | ||
| 3543 | oai_settings.azure_api_version = settings.azure_api_version ?? default_settings.azure_api_version; | ||
| 3544 | oai_settings.azure_openai_model = settings.azure_openai_model ?? default_settings.azure_openai_model; | ||
| 3450 | oai_settings.vertexai_model = settings.vertexai_model ?? default_settings.vertexai_model; | 3545 | oai_settings.vertexai_model = settings.vertexai_model ?? default_settings.vertexai_model; |
| 3451 | oai_settings.chat_completion_source = settings.chat_completion_source ?? default_settings.chat_completion_source; | 3546 | oai_settings.chat_completion_source = settings.chat_completion_source ?? default_settings.chat_completion_source; |
| 3452 | oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models; | 3547 | oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models; |
| @@ -3527,6 +3622,8 @@ function loadOpenAISettings(data, settings) { | |||
| 3527 | $(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).prop('selected', true); | 3622 | $(`#model_perplexity_select option[value="${oai_settings.perplexity_model}"`).prop('selected', true); |
| 3528 | $('#model_groq_select').val(oai_settings.groq_model); | 3623 | $('#model_groq_select').val(oai_settings.groq_model); |
| 3529 | $(`#model_groq_select option[value="${oai_settings.groq_model}"`).prop('selected', true); | 3624 | $(`#model_groq_select option[value="${oai_settings.groq_model}"`).prop('selected', true); |
| 3625 | $('#model_electronhub_select').val(oai_settings.electronhub_model); | ||
| 3626 | $(`#model_electronhub_select option[value="${oai_settings.electronhub_model}"`).prop('selected', true); | ||
| 3530 | $('#model_nanogpt_select').val(oai_settings.nanogpt_model); | 3627 | $('#model_nanogpt_select').val(oai_settings.nanogpt_model); |
| 3531 | $(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).prop('selected', true); | 3628 | $(`#model_nanogpt_select option[value="${oai_settings.nanogpt_model}"`).prop('selected', true); |
| 3532 | $('#model_deepseek_select').val(oai_settings.deepseek_model); | 3629 | $('#model_deepseek_select').val(oai_settings.deepseek_model); |
| @@ -3541,6 +3638,11 @@ function loadOpenAISettings(data, settings) { | |||
| 3541 | $(`#model_moonshot_select option[value="${oai_settings.moonshot_model}"`).prop('selected', true); | 3638 | $(`#model_moonshot_select option[value="${oai_settings.moonshot_model}"`).prop('selected', true); |
| 3542 | $('#custom_model_id').val(oai_settings.custom_model); | 3639 | $('#custom_model_id').val(oai_settings.custom_model); |
| 3543 | $('#custom_api_url_text').val(oai_settings.custom_url); | 3640 | $('#custom_api_url_text').val(oai_settings.custom_url); |
| 3641 | $('#azure_base_url').val(oai_settings.azure_base_url); | ||
| 3642 | $('#azure_deployment_name').val(oai_settings.azure_deployment_name); | ||
| 3643 | $('#azure_api_version').val(oai_settings.azure_api_version); | ||
| 3644 | $('#azure_openai_model').val(oai_settings.azure_openai_model); | ||
| 3645 | |||
| 3544 | $('#openai_max_context').val(oai_settings.openai_max_context); | 3646 | $('#openai_max_context').val(oai_settings.openai_max_context); |
| 3545 | $('#openai_max_context_counter').val(`${oai_settings.openai_max_context}`); | 3647 | $('#openai_max_context_counter').val(`${oai_settings.openai_max_context}`); |
| 3546 | $('#model_openrouter_select').val(oai_settings.openrouter_model); | 3648 | $('#model_openrouter_select').val(oai_settings.openrouter_model); |
| @@ -3719,6 +3821,12 @@ async function getStatusOpen() { | |||
| 3719 | return resultCheckStatus(); | 3821 | return resultCheckStatus(); |
| 3720 | } | 3822 | } |
| 3721 | 3823 | ||
| 3824 | if (oai_settings.chat_completion_source === chat_completion_sources.AZURE_OPENAI && !isValidUrl(oai_settings.azure_base_url)) { | ||
| 3825 | console.debug('Invalid endpoint URL of Azure OpenAI API:', oai_settings.azure_base_url); | ||
| 3826 | setOnlineStatus(t`Invalid Azure endpoint URL. Requests may fail.`); | ||
| 3827 | return resultCheckStatus(); | ||
| 3828 | } | ||
| 3829 | |||
| 3722 | let data = { | 3830 | let data = { |
| 3723 | reverse_proxy: oai_settings.reverse_proxy, | 3831 | reverse_proxy: oai_settings.reverse_proxy, |
| 3724 | proxy_password: oai_settings.proxy_password, | 3832 | proxy_password: oai_settings.proxy_password, |
| @@ -3744,6 +3852,12 @@ async function getStatusOpen() { | |||
| 3744 | data.custom_include_headers = oai_settings.custom_include_headers; | 3852 | data.custom_include_headers = oai_settings.custom_include_headers; |
| 3745 | } | 3853 | } |
| 3746 | 3854 | ||
| 3855 | if (oai_settings.chat_completion_source === chat_completion_sources.AZURE_OPENAI) { | ||
| 3856 | data.azure_base_url = oai_settings.azure_base_url; | ||
| 3857 | data.azure_deployment_name = oai_settings.azure_deployment_name; | ||
| 3858 | data.azure_api_version = oai_settings.azure_api_version; | ||
| 3859 | } | ||
| 3860 | |||
| 3747 | const canBypass = (oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check) || oai_settings.chat_completion_source === chat_completion_sources.CUSTOM; | 3861 | const canBypass = (oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check) || oai_settings.chat_completion_source === chat_completion_sources.CUSTOM; |
| 3748 | if (canBypass) { | 3862 | if (canBypass) { |
| 3749 | setOnlineStatus(t`Status check bypassed`); | 3863 | setOnlineStatus(t`Status check bypassed`); |
| @@ -3813,6 +3927,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | |||
| 3813 | xai_model: settings.xai_model, | 3927 | xai_model: settings.xai_model, |
| 3814 | pollinations_model: settings.pollinations_model, | 3928 | pollinations_model: settings.pollinations_model, |
| 3815 | aimlapi_model: settings.aimlapi_model, | 3929 | aimlapi_model: settings.aimlapi_model, |
| 3930 | electronhub_model: settings.electronhub_model, | ||
| 3816 | moonshot_model: settings.moonshot_model, | 3931 | moonshot_model: settings.moonshot_model, |
| 3817 | fireworks_model: settings.fireworks_model, | 3932 | fireworks_model: settings.fireworks_model, |
| 3818 | cometapi_model: settings.cometapi_model, | 3933 | cometapi_model: settings.cometapi_model, |
| @@ -3824,6 +3939,10 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | |||
| 3824 | custom_prompt_post_processing: settings.custom_prompt_post_processing, | 3939 | custom_prompt_post_processing: settings.custom_prompt_post_processing, |
| 3825 | google_model: settings.google_model, | 3940 | google_model: settings.google_model, |
| 3826 | vertexai_model: settings.vertexai_model, | 3941 | vertexai_model: settings.vertexai_model, |
| 3942 | azure_base_url: settings.azure_base_url, | ||
| 3943 | azure_deployment_name: settings.azure_deployment_name, | ||
| 3944 | azure_api_version: settings.azure_api_version, | ||
| 3945 | azure_openai_model: settings.azure_openai_model, | ||
| 3827 | temperature: settings.temp_openai, | 3946 | temperature: settings.temp_openai, |
| 3828 | frequency_penalty: settings.freq_pen_openai, | 3947 | frequency_penalty: settings.freq_pen_openai, |
| 3829 | presence_penalty: settings.pres_pen_openai, | 3948 | presence_penalty: settings.pres_pen_openai, |
| @@ -4578,6 +4697,47 @@ function getFireworksMaxContext(model, isUnlocked) { | |||
| 4578 | return max_32k; | 4697 | return max_32k; |
| 4579 | } | 4698 | } |
| 4580 | 4699 | ||
| 4700 | /** | ||
| 4701 | * Get the maximum context size for the ElectronHub model | ||
| 4702 | * @param {string} model Model identifier | ||
| 4703 | * @param {boolean} isUnlocked Whether context limits are unlocked | ||
| 4704 | * @returns {number} Maximum context size in tokens | ||
| 4705 | */ | ||
| 4706 | function getElectronHubMaxContext(model, isUnlocked) { | ||
| 4707 | if (isUnlocked) { | ||
| 4708 | return unlocked_max; | ||
| 4709 | } | ||
| 4710 | |||
| 4711 | if (Array.isArray(model_list)) { | ||
| 4712 | const modelInfo = model_list.find(m => m.id === model); | ||
| 4713 | if (modelInfo?.tokens) { | ||
| 4714 | return modelInfo.tokens; | ||
| 4715 | } | ||
| 4716 | } | ||
| 4717 | return max_8k; | ||
| 4718 | } | ||
| 4719 | |||
| 4720 | /** | ||
| 4721 | * Get the maximum context size for the NanoGPT model | ||
| 4722 | * @param {string} model Model identifier | ||
| 4723 | * @param {boolean} isUnlocked Whether context limits are unlocked | ||
| 4724 | * @returns {number} Maximum context size in tokens | ||
| 4725 | */ | ||
| 4726 | function getNanoGptMaxContext(model, isUnlocked) { | ||
| 4727 | if (isUnlocked) { | ||
| 4728 | return unlocked_max; | ||
| 4729 | } | ||
| 4730 | |||
| 4731 | if (Array.isArray(model_list)) { | ||
| 4732 | const modelInfo = model_list.find(m => m.id === model); | ||
| 4733 | if (modelInfo?.context_length) { | ||
| 4734 | return modelInfo.context_length; | ||
| 4735 | } | ||
| 4736 | } | ||
| 4737 | |||
| 4738 | return max_128k; | ||
| 4739 | } | ||
| 4740 | |||
| 4581 | async function onModelChange() { | 4741 | async function onModelChange() { |
| 4582 | biasCache = undefined; | 4742 | biasCache = undefined; |
| 4583 | let value = String($(this).val() || ''); | 4743 | let value = String($(this).val() || ''); |
| @@ -4668,6 +4828,15 @@ async function onModelChange() { | |||
| 4668 | oai_settings.groq_model = value; | 4828 | oai_settings.groq_model = value; |
| 4669 | } | 4829 | } |
| 4670 | 4830 | ||
| 4831 | if ($(this).is('#model_electronhub_select')) { | ||
| 4832 | if (!value) { | ||
| 4833 | console.debug('Null ElectronHub model selected. Ignoring.'); | ||
| 4834 | return; | ||
| 4835 | } | ||
| 4836 | console.log('ElectronHub model changed to', value); | ||
| 4837 | oai_settings.electronhub_model = value; | ||
| 4838 | } | ||
| 4839 | |||
| 4671 | if ($(this).is('#model_nanogpt_select')) { | 4840 | if ($(this).is('#model_nanogpt_select')) { |
| 4672 | if (!value) { | 4841 | if (!value) { |
| 4673 | console.debug('Null NanoGPT model selected. Ignoring.'); | 4842 | console.debug('Null NanoGPT model selected. Ignoring.'); |
| @@ -4736,11 +4905,21 @@ async function onModelChange() { | |||
| 4736 | oai_settings.cometapi_model = value; | 4905 | oai_settings.cometapi_model = value; |
| 4737 | } | 4906 | } |
| 4738 | 4907 | ||
| 4908 | if ($(this).is('#azure_openai_model')) { | ||
| 4909 | if (!value) { | ||
| 4910 | console.debug('Null Azure OpenAI model selected. Ignoring.'); | ||
| 4911 | return; | ||
| 4912 | } | ||
| 4913 | oai_settings.azure_openai_model = value; | ||
| 4914 | } | ||
| 4915 | |||
| 4739 | if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) { | 4916 | if ([chat_completion_sources.MAKERSUITE, chat_completion_sources.VERTEXAI].includes(oai_settings.chat_completion_source)) { |
| 4740 | if (oai_settings.max_context_unlocked) { | 4917 | if (oai_settings.max_context_unlocked) { |
| 4741 | $('#openai_max_context').attr('max', max_2mil); | 4918 | $('#openai_max_context').attr('max', max_2mil); |
| 4742 | } else if (value.includes('gemini-1.5-pro')) { | 4919 | } else if (value.includes('gemini-1.5-pro')) { |
| 4743 | $('#openai_max_context').attr('max', max_2mil); | 4920 | $('#openai_max_context').attr('max', max_2mil); |
| 4921 | } else if (value.includes('gemini-2.5-flash-image-preview')) { | ||
| 4922 | $('#openai_max_context').attr('max', max_32k); | ||
| 4744 | } else if (value.includes('gemini-1.5-flash') || value.includes('gemini-2.0-flash') || value.includes('gemini-2.0-pro') || value.includes('gemini-exp') || value.includes('gemini-2.5-flash') || value.includes('gemini-2.5-pro') || value.includes('learnlm-2.0-flash')) { | 4923 | } else if (value.includes('gemini-1.5-flash') || value.includes('gemini-2.0-flash') || value.includes('gemini-2.0-pro') || value.includes('gemini-exp') || value.includes('gemini-2.5-flash') || value.includes('gemini-2.5-pro') || value.includes('learnlm-2.0-flash')) { |
| 4745 | $('#openai_max_context').attr('max', max_1mil); | 4924 | $('#openai_max_context').attr('max', max_1mil); |
| 4746 | } else if (value.includes('gemma-3-27b-it')) { | 4925 | } else if (value.includes('gemma-3-27b-it')) { |
| @@ -4808,7 +4987,7 @@ async function onModelChange() { | |||
| 4808 | $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input'); | 4987 | $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4809 | } | 4988 | } |
| 4810 | 4989 | ||
| 4811 | if (oai_settings.chat_completion_source == chat_completion_sources.OPENAI) { | 4990 | if ([chat_completion_sources.AZURE_OPENAI, chat_completion_sources.OPENAI].includes(oai_settings.chat_completion_source)) { |
| 4812 | $('#openai_max_context').attr('max', getMaxContextOpenAI(value)); | 4991 | $('#openai_max_context').attr('max', getMaxContextOpenAI(value)); |
| 4813 | oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max'))); | 4992 | oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max'))); |
| 4814 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | 4993 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); |
| @@ -4907,15 +5086,21 @@ async function onModelChange() { | |||
| 4907 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | 5086 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4908 | } | 5087 | } |
| 4909 | 5088 | ||
| 4910 | if (oai_settings.chat_completion_source === chat_completion_sources.NANOGPT) { | 5089 | if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) { |
| 4911 | if (oai_settings.max_context_unlocked) { | 5090 | const maxContext = getElectronHubMaxContext(oai_settings.electronhub_model, oai_settings.max_context_unlocked); |
| 4912 | $('#openai_max_context').attr('max', unlocked_max); | 5091 | $('#openai_max_context').attr('max', maxContext); |
| 4913 | } else { | 5092 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); |
| 4914 | $('#openai_max_context').attr('max', max_128k); | 5093 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); |
| 4915 | } | 5094 | oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai); |
| 5095 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | ||
| 5096 | } | ||
| 4916 | 5097 | ||
| 5098 | if (oai_settings.chat_completion_source === chat_completion_sources.NANOGPT) { | ||
| 5099 | const maxContext = getNanoGptMaxContext(oai_settings.nanogpt_model, oai_settings.max_context_unlocked); | ||
| 5100 | $('#openai_max_context').attr('max', maxContext); | ||
| 4917 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); | 5101 | oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); |
| 4918 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | 5102 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); |
| 5103 | oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai); | ||
| 4919 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | 5104 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4920 | } | 5105 | } |
| 4921 | 5106 | ||
| @@ -5204,6 +5389,19 @@ async function onConnectButtonClick(e) { | |||
| 5204 | } | 5389 | } |
| 5205 | } | 5390 | } |
| 5206 | 5391 | ||
| 5392 | if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) { | ||
| 5393 | const api_key_electronhub = String($('#api_key_electronhub').val()).trim(); | ||
| 5394 | |||
| 5395 | if (api_key_electronhub.length) { | ||
| 5396 | await writeSecret(SECRET_KEYS.ELECTRONHUB, api_key_electronhub); | ||
| 5397 | } | ||
| 5398 | |||
| 5399 | if (!secret_state[SECRET_KEYS.ELECTRONHUB]) { | ||
| 5400 | console.log('No secret key saved for Electron Hub'); | ||
| 5401 | return; | ||
| 5402 | } | ||
| 5403 | } | ||
| 5404 | |||
| 5207 | if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) { | 5405 | if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) { |
| 5208 | const api_key_nanogpt = String($('#api_key_nanogpt').val()).trim(); | 5406 | const api_key_nanogpt = String($('#api_key_nanogpt').val()).trim(); |
| 5209 | 5407 | ||
| @@ -5295,6 +5493,20 @@ async function onConnectButtonClick(e) { | |||
| 5295 | } | 5493 | } |
| 5296 | } | 5494 | } |
| 5297 | 5495 | ||
| 5496 | if (oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) { | ||
| 5497 | const api_key_azure_openai = String($('#api_key_azure_openai').val()).trim(); | ||
| 5498 | |||
| 5499 | if (api_key_azure_openai.length) { | ||
| 5500 | await writeSecret(SECRET_KEYS.AZURE_OPENAI, api_key_azure_openai); | ||
| 5501 | } | ||
| 5502 | |||
| 5503 | if (!api_key_azure_openai && !secret_state[SECRET_KEYS.AZURE_OPENAI]) { | ||
| 5504 | console.log('No secret key saved for Azure OpenAI'); | ||
| 5505 | return; | ||
| 5506 | } | ||
| 5507 | } | ||
| 5508 | |||
| 5509 | |||
| 5298 | startStatusLoading(); | 5510 | startStatusLoading(); |
| 5299 | saveSettingsDebounced(); | 5511 | saveSettingsDebounced(); |
| 5300 | await getStatusOpen(); | 5512 | await getStatusOpen(); |
| @@ -5338,6 +5550,9 @@ function toggleChatCompletionForms() { | |||
| 5338 | else if (oai_settings.chat_completion_source == chat_completion_sources.GROQ) { | 5550 | else if (oai_settings.chat_completion_source == chat_completion_sources.GROQ) { |
| 5339 | $('#model_groq_select').trigger('change'); | 5551 | $('#model_groq_select').trigger('change'); |
| 5340 | } | 5552 | } |
| 5553 | else if (oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB) { | ||
| 5554 | $('#model_electronhub_select').trigger('change'); | ||
| 5555 | } | ||
| 5341 | else if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) { | 5556 | else if (oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) { |
| 5342 | $('#model_nanogpt_select').trigger('change'); | 5557 | $('#model_nanogpt_select').trigger('change'); |
| 5343 | } | 5558 | } |
| @@ -5365,6 +5580,9 @@ function toggleChatCompletionForms() { | |||
| 5365 | else if (oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) { | 5580 | else if (oai_settings.chat_completion_source == chat_completion_sources.COMETAPI) { |
| 5366 | $('#model_cometapi_select').trigger('change'); | 5581 | $('#model_cometapi_select').trigger('change'); |
| 5367 | } | 5582 | } |
| 5583 | else if (oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI) { | ||
| 5584 | $('#azure_openai_model').trigger('change'); | ||
| 5585 | } | ||
| 5368 | 5586 | ||
| 5369 | $('[data-source]').each(function () { | 5587 | $('[data-source]').each(function () { |
| 5370 | const validSources = $(this).data('source').split(','); | 5588 | const validSources = $(this).data('source').split(','); |
| @@ -5484,10 +5702,15 @@ export function isImageInliningSupported() { | |||
| 5484 | 5702 | ||
| 5485 | switch (oai_settings.chat_completion_source) { | 5703 | switch (oai_settings.chat_completion_source) { |
| 5486 | case chat_completion_sources.OPENAI: | 5704 | case chat_completion_sources.OPENAI: |
| 5705 | case chat_completion_sources.AZURE_OPENAI: { | ||
| 5706 | const modelToCheck = oai_settings.chat_completion_source === chat_completion_sources.AZURE_OPENAI | ||
| 5707 | ? oai_settings.azure_openai_model | ||
| 5708 | : oai_settings.openai_model; | ||
| 5487 | return visionSupportedModels.some(model => | 5709 | return visionSupportedModels.some(model => |
| 5488 | oai_settings.openai_model.includes(model) | 5710 | modelToCheck.includes(model) |
| 5489 | && ['gpt-4-turbo-preview', 'o1-mini', 'o3-mini'].some(x => !oai_settings.openai_model.includes(x)), | 5711 | && ['gpt-4-turbo-preview', 'o1-mini', 'o3-mini'].some(x => !modelToCheck.includes(x)), |
| 5490 | ); | 5712 | ); |
| 5713 | } | ||
| 5491 | case chat_completion_sources.MAKERSUITE: | 5714 | case chat_completion_sources.MAKERSUITE: |
| 5492 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); | 5715 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); |
| 5493 | case chat_completion_sources.VERTEXAI: | 5716 | case chat_completion_sources.VERTEXAI: |
| @@ -5495,7 +5718,7 @@ export function isImageInliningSupported() { | |||
| 5495 | case chat_completion_sources.CLAUDE: | 5718 | case chat_completion_sources.CLAUDE: |
| 5496 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); | 5719 | return visionSupportedModels.some(model => oai_settings.claude_model.includes(model)); |
| 5497 | case chat_completion_sources.OPENROUTER: | 5720 | case chat_completion_sources.OPENROUTER: |
| 5498 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.openrouter_model)?.architecture?.modality === 'text+image->text'); | 5721 | return (Array.isArray(model_list) && ['text+image->text+image', 'text+image->text'].includes(model_list.find(m => m.id === oai_settings.openrouter_model)?.architecture?.modality)); |
| 5499 | case chat_completion_sources.CUSTOM: | 5722 | case chat_completion_sources.CUSTOM: |
| 5500 | return true; | 5723 | return true; |
| 5501 | case chat_completion_sources.MISTRALAI: | 5724 | case chat_completion_sources.MISTRALAI: |
| @@ -5506,12 +5729,16 @@ export function isImageInliningSupported() { | |||
| 5506 | return visionSupportedModels.some(model => oai_settings.xai_model.includes(model)); | 5729 | return visionSupportedModels.some(model => oai_settings.xai_model.includes(model)); |
| 5507 | case chat_completion_sources.AIMLAPI: | 5730 | case chat_completion_sources.AIMLAPI: |
| 5508 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.aimlapi_model)?.features?.includes('openai/chat-completion.vision')); | 5731 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.aimlapi_model)?.features?.includes('openai/chat-completion.vision')); |
| 5732 | case chat_completion_sources.ELECTRONHUB: | ||
| 5733 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.electronhub_model)?.metadata?.vision); | ||
| 5509 | case chat_completion_sources.POLLINATIONS: | 5734 | case chat_completion_sources.POLLINATIONS: |
| 5510 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.pollinations_model)?.vision); | 5735 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.pollinations_model)?.vision); |
| 5511 | case chat_completion_sources.COMETAPI: | 5736 | case chat_completion_sources.COMETAPI: |
| 5512 | return true; | 5737 | return true; |
| 5513 | case chat_completion_sources.MOONSHOT: | 5738 | case chat_completion_sources.MOONSHOT: |
| 5514 | return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model)); | 5739 | return visionSupportedModels.some(model => oai_settings.moonshot_model.includes(model)); |
| 5740 | case chat_completion_sources.NANOGPT: | ||
| 5741 | return (Array.isArray(model_list) && model_list.find(m => m.id === oai_settings.nanogpt_model)?.capabilities?.vision); | ||
| 5515 | default: | 5742 | default: |
| 5516 | return false; | 5743 | return false; |
| 5517 | } | 5744 | } |
| @@ -6164,6 +6391,21 @@ export function initOpenAI() { | |||
| 6164 | saveSettingsDebounced(); | 6391 | saveSettingsDebounced(); |
| 6165 | }); | 6392 | }); |
| 6166 | 6393 | ||
| 6394 | $('#azure_base_url').on('input', function () { | ||
| 6395 | oai_settings.azure_base_url = String($(this).val()); | ||
| 6396 | saveSettingsDebounced(); | ||
| 6397 | }); | ||
| 6398 | |||
| 6399 | $('#azure_deployment_name').on('input', function () { | ||
| 6400 | oai_settings.azure_deployment_name = String($(this).val()); | ||
| 6401 | saveSettingsDebounced(); | ||
| 6402 | }); | ||
| 6403 | |||
| 6404 | $('#azure_api_version').on('input change', function () { | ||
| 6405 | oai_settings.azure_api_version = String($(this).val()); | ||
| 6406 | saveSettingsDebounced(); | ||
| 6407 | }); | ||
| 6408 | |||
| 6167 | $('#character_names_none').on('input', function () { | 6409 | $('#character_names_none').on('input', function () { |
| 6168 | oai_settings.names_behavior = character_names_behavior.NONE; | 6410 | oai_settings.names_behavior = character_names_behavior.NONE; |
| 6169 | setNamesBehaviorControls(); | 6411 | setNamesBehaviorControls(); |
| @@ -6312,6 +6554,7 @@ export function initOpenAI() { | |||
| 6312 | $('#model_cohere_select').on('change', onModelChange); | 6554 | $('#model_cohere_select').on('change', onModelChange); |
| 6313 | $('#model_perplexity_select').on('change', onModelChange); | 6555 | $('#model_perplexity_select').on('change', onModelChange); |
| 6314 | $('#model_groq_select').on('change', onModelChange); | 6556 | $('#model_groq_select').on('change', onModelChange); |
| 6557 | $('#model_electronhub_select').on('change', onModelChange); | ||
| 6315 | $('#model_nanogpt_select').on('change', onModelChange); | 6558 | $('#model_nanogpt_select').on('change', onModelChange); |
| 6316 | $('#model_deepseek_select').on('change', onModelChange); | 6559 | $('#model_deepseek_select').on('change', onModelChange); |
| 6317 | $('#model_aimlapi_select').on('change', onModelChange); | 6560 | $('#model_aimlapi_select').on('change', onModelChange); |
| @@ -6321,6 +6564,7 @@ export function initOpenAI() { | |||
| 6321 | $('#model_cometapi_select').on('change', onModelChange); | 6564 | $('#model_cometapi_select').on('change', onModelChange); |
| 6322 | $('#model_moonshot_select').on('change', onModelChange); | 6565 | $('#model_moonshot_select').on('change', onModelChange); |
| 6323 | $('#model_fireworks_select').on('change', onModelChange); | 6566 | $('#model_fireworks_select').on('change', onModelChange); |
| 6567 | $('#azure_openai_model').on('change', onModelChange); | ||
| 6324 | $('#settings_preset_openai').on('change', onSettingsPresetChange); | 6568 | $('#settings_preset_openai').on('change', onSettingsPresetChange); |
| 6325 | $('#new_oai_preset').on('click', onNewPresetClick); | 6569 | $('#new_oai_preset').on('click', onNewPresetClick); |
| 6326 | $('#delete_oai_preset').on('click', onDeletePresetClick); | 6570 | $('#delete_oai_preset').on('click', onDeletePresetClick); |
| @@ -1348,6 +1348,29 @@ function registerReasoningAppEvents() { | |||
| 1348 | for (const event of [event_types.GENERATION_STOPPED, event_types.GENERATION_ENDED, event_types.CHAT_CHANGED]) { | 1348 | for (const event of [event_types.GENERATION_STOPPED, event_types.GENERATION_ENDED, event_types.CHAT_CHANGED]) { |
| 1349 | eventSource.on(event, () => PromptReasoning.clearLatest()); | 1349 | eventSource.on(event, () => PromptReasoning.clearLatest()); |
| 1350 | } | 1350 | } |
| 1351 | |||
| 1352 | eventSource.makeFirst(event_types.IMPERSONATE_READY, async () => { | ||
| 1353 | if (!power_user.reasoning.auto_parse) { | ||
| 1354 | return; | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | const sendTextArea = /** @type {HTMLTextAreaElement} */ (document.getElementById('send_textarea')); | ||
| 1358 | |||
| 1359 | if (!sendTextArea) { | ||
| 1360 | console.warn('[Reasoning] Send textarea not found'); | ||
| 1361 | return; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | console.debug('[Reasoning] Auto-parsing reasoning block for impersonation'); | ||
| 1365 | |||
| 1366 | if (!sendTextArea.value) { | ||
| 1367 | console.debug('[Reasoning] Reasoning is empty, skipping'); | ||
| 1368 | return; | ||
| 1369 | } | ||
| 1370 | |||
| 1371 | sendTextArea.value = removeReasoningFromString(sendTextArea.value); | ||
| 1372 | sendTextArea.dispatchEvent(new Event('input', { bubbles: true })); | ||
| 1373 | }); | ||
| 1351 | } | 1374 | } |
| 1352 | 1375 | ||
| 1353 | /** | 1376 | /** |
| @@ -47,10 +47,12 @@ export const SECRET_KEYS = { | |||
| 47 | PERPLEXITY: 'api_key_perplexity', | 47 | PERPLEXITY: 'api_key_perplexity', |
| 48 | GROQ: 'api_key_groq', | 48 | GROQ: 'api_key_groq', |
| 49 | AZURE_TTS: 'api_key_azure_tts', | 49 | AZURE_TTS: 'api_key_azure_tts', |
| 50 | AZURE_OPENAI: 'api_key_azure_openai', | ||
| 50 | FEATHERLESS: 'api_key_featherless', | 51 | FEATHERLESS: 'api_key_featherless', |
| 51 | HUGGINGFACE: 'api_key_huggingface', | 52 | HUGGINGFACE: 'api_key_huggingface', |
| 52 | STABILITY: 'api_key_stability', | 53 | STABILITY: 'api_key_stability', |
| 53 | CUSTOM_OPENAI_TTS: 'api_key_custom_openai_tts', | 54 | CUSTOM_OPENAI_TTS: 'api_key_custom_openai_tts', |
| 55 | ELECTRONHUB: 'api_key_electronhub', | ||
| 54 | NANOGPT: 'api_key_nanogpt', | 56 | NANOGPT: 'api_key_nanogpt', |
| 55 | TAVILY: 'api_key_tavily', | 57 | TAVILY: 'api_key_tavily', |
| 56 | BFL: 'api_key_bfl', | 58 | BFL: 'api_key_bfl', |
| @@ -95,6 +97,7 @@ const FRIENDLY_NAMES = { | |||
| 95 | [SECRET_KEYS.GROQ]: 'Groq', | 97 | [SECRET_KEYS.GROQ]: 'Groq', |
| 96 | [SECRET_KEYS.FEATHERLESS]: 'Featherless', | 98 | [SECRET_KEYS.FEATHERLESS]: 'Featherless', |
| 97 | [SECRET_KEYS.HUGGINGFACE]: 'HuggingFace', | 99 | [SECRET_KEYS.HUGGINGFACE]: 'HuggingFace', |
| 100 | [SECRET_KEYS.ELECTRONHUB]: 'Electron Hub', | ||
| 98 | [SECRET_KEYS.NANOGPT]: 'NanoGPT', | 101 | [SECRET_KEYS.NANOGPT]: 'NanoGPT', |
| 99 | [SECRET_KEYS.GENERIC]: 'Generic (OpenAI-compatible)', | 102 | [SECRET_KEYS.GENERIC]: 'Generic (OpenAI-compatible)', |
| 100 | [SECRET_KEYS.DEEPSEEK]: 'DeepSeek', | 103 | [SECRET_KEYS.DEEPSEEK]: 'DeepSeek', |
| @@ -120,6 +123,7 @@ const FRIENDLY_NAMES = { | |||
| 120 | [SECRET_KEYS.MINIMAX_GROUP_ID]: 'MiniMax Group ID', | 123 | [SECRET_KEYS.MINIMAX_GROUP_ID]: 'MiniMax Group ID', |
| 121 | [SECRET_KEYS.MOONSHOT]: 'Moonshot AI', | 124 | [SECRET_KEYS.MOONSHOT]: 'Moonshot AI', |
| 122 | [SECRET_KEYS.COMETAPI]: 'CometAPI', | 125 | [SECRET_KEYS.COMETAPI]: 'CometAPI', |
| 126 | [SECRET_KEYS.AZURE_OPENAI]: 'Azure OpenAI', | ||
| 123 | }; | 127 | }; |
| 124 | 128 | ||
| 125 | const INPUT_MAP = { | 129 | const INPUT_MAP = { |
| @@ -148,6 +152,7 @@ const INPUT_MAP = { | |||
| 148 | [SECRET_KEYS.GROQ]: '#api_key_groq', | 152 | [SECRET_KEYS.GROQ]: '#api_key_groq', |
| 149 | [SECRET_KEYS.FEATHERLESS]: '#api_key_featherless', | 153 | [SECRET_KEYS.FEATHERLESS]: '#api_key_featherless', |
| 150 | [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface', | 154 | [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface', |
| 155 | [SECRET_KEYS.ELECTRONHUB]: '#api_key_electronhub', | ||
| 151 | [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt', | 156 | [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt', |
| 152 | [SECRET_KEYS.GENERIC]: '#api_key_generic', | 157 | [SECRET_KEYS.GENERIC]: '#api_key_generic', |
| 153 | [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek', | 158 | [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek', |
| @@ -157,6 +162,7 @@ const INPUT_MAP = { | |||
| 157 | [SECRET_KEYS.MOONSHOT]: '#api_key_moonshot', | 162 | [SECRET_KEYS.MOONSHOT]: '#api_key_moonshot', |
| 158 | [SECRET_KEYS.FIREWORKS]: '#api_key_fireworks', | 163 | [SECRET_KEYS.FIREWORKS]: '#api_key_fireworks', |
| 159 | [SECRET_KEYS.COMETAPI]: '#api_key_cometapi', | 164 | [SECRET_KEYS.COMETAPI]: '#api_key_cometapi', |
| 165 | [SECRET_KEYS.AZURE_OPENAI]: '#api_key_azure_openai', | ||
| 160 | }; | 166 | }; |
| 161 | 167 | ||
| 162 | const getLabel = () => moment().format('L LT'); | 168 | const getLabel = () => moment().format('L LT'); |
| @@ -229,7 +229,7 @@ export function initDefaultSlashCommands() { | |||
| 229 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 229 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 230 | name: 'dupe', | 230 | name: 'dupe', |
| 231 | callback: duplicateCharacter, | 231 | callback: duplicateCharacter, |
| 232 | helpString: 'Duplicates the currently selected character.', | 232 | helpString: t`Duplicates the currently selected character.`, |
| 233 | })); | 233 | })); |
| 234 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 234 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 235 | name: 'api', | 235 | name: 'api', |
| @@ -306,11 +306,11 @@ export function initDefaultSlashCommands() { | |||
| 306 | toastr.clear(toast); | 306 | toastr.clear(toast); |
| 307 | return text?.toString()?.trim() ?? ''; | 307 | return text?.toString()?.trim() ?? ''; |
| 308 | }, | 308 | }, |
| 309 | returns: 'the current API', | 309 | returns: t`the current API`, |
| 310 | namedArgumentList: [ | 310 | namedArgumentList: [ |
| 311 | SlashCommandNamedArgument.fromProps({ | 311 | SlashCommandNamedArgument.fromProps({ |
| 312 | name: 'quiet', | 312 | name: 'quiet', |
| 313 | description: 'Suppress the toast message on connection', | 313 | description: t`Suppress the toast message on connection`, |
| 314 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 314 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 315 | defaultValue: 'false', | 315 | defaultValue: 'false', |
| 316 | enumList: commonEnumProviders.boolean('trueFalse')(), | 316 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| @@ -318,7 +318,7 @@ export function initDefaultSlashCommands() { | |||
| 318 | ], | 318 | ], |
| 319 | unnamedArgumentList: [ | 319 | unnamedArgumentList: [ |
| 320 | SlashCommandArgument.fromProps({ | 320 | SlashCommandArgument.fromProps({ |
| 321 | description: 'API to connect to', | 321 | description: t`API to connect to`, |
| 322 | typeList: [ARGUMENT_TYPE.STRING], | 322 | typeList: [ARGUMENT_TYPE.STRING], |
| 323 | enumList: Object.entries(CONNECT_API_MAP).sort(([a], [b]) => a.localeCompare(b)).map(([api, { selected }]) => | 323 | enumList: Object.entries(CONNECT_API_MAP).sort(([a], [b]) => a.localeCompare(b)).map(([api, { selected }]) => |
| 324 | new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === selected)), | 324 | new SlashCommandEnumValue(api, selected, enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === selected)), |
| @@ -327,10 +327,10 @@ export function initDefaultSlashCommands() { | |||
| 327 | ], | 327 | ], |
| 328 | helpString: ` | 328 | helpString: ` |
| 329 | <div> | 329 | <div> |
| 330 | Connect to an API. If no argument is provided, it will return the currently connected API. | 330 | ${t`Connect to an API. If no argument is provided, it will return the currently connected API.`} |
| 331 | </div> | 331 | </div> |
| 332 | <div> | 332 | <div> |
| 333 | <strong>Available APIs:</strong> | 333 | <strong>${t`Available APIs:`}</strong> |
| 334 | <pre><code>${Object.keys(CONNECT_API_MAP).sort((a, b) => a.localeCompare(b)).join(', ')}</code></pre> | 334 | <pre><code>${Object.keys(CONNECT_API_MAP).sort((a, b) => a.localeCompare(b)).join(', ')}</code></pre> |
| 335 | </div> | 335 | </div> |
| 336 | `, | 336 | `, |
| @@ -367,7 +367,7 @@ export function initDefaultSlashCommands() { | |||
| 367 | namedArgumentList: [ | 367 | namedArgumentList: [ |
| 368 | new SlashCommandNamedArgument( | 368 | new SlashCommandNamedArgument( |
| 369 | 'await', | 369 | 'await', |
| 370 | 'Whether to await for the triggered generation before continuing', | 370 | t`Whether to await for the triggered generation before continuing`, |
| 371 | [ARGUMENT_TYPE.BOOLEAN], | 371 | [ARGUMENT_TYPE.BOOLEAN], |
| 372 | false, | 372 | false, |
| 373 | false, | 373 | false, |
| @@ -381,13 +381,13 @@ export function initDefaultSlashCommands() { | |||
| 381 | ], | 381 | ], |
| 382 | helpString: ` | 382 | helpString: ` |
| 383 | <div> | 383 | <div> |
| 384 | Calls an impersonation response, with an optional additional prompt. | 384 | ${t`Calls an impersonation response, with an optional additional prompt.`} |
| 385 | </div> | 385 | </div> |
| 386 | <div> | 386 | <div> |
| 387 | If <code>await=true</code> named argument is passed, the command will wait for the impersonation to end before continuing. | 387 | ${t`If <code>await=true</code> named argument is passed, the command will wait for the impersonation to end before continuing.`} |
| 388 | </div> | 388 | </div> |
| 389 | <div> | 389 | <div> |
| 390 | <strong>Example:</strong> | 390 | <strong>${t`Example:`}</strong> |
| 391 | <ul> | 391 | <ul> |
| 392 | <li> | 392 | <li> |
| 393 | <pre><code class="language-stscript">/impersonate What is the meaning of life?</code></pre> | 393 | <pre><code class="language-stscript">/impersonate What is the meaning of life?</code></pre> |
| @@ -426,7 +426,7 @@ export function initDefaultSlashCommands() { | |||
| 426 | $(currentChatDeleteButton).trigger('click', { fromSlashCommand: true }); | 426 | $(currentChatDeleteButton).trigger('click', { fromSlashCommand: true }); |
| 427 | })); | 427 | })); |
| 428 | }, | 428 | }, |
| 429 | helpString: 'Deletes the current chat.', | 429 | helpString: t`Deletes the current chat.`, |
| 430 | })); | 430 | })); |
| 431 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 431 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 432 | name: 'renamechat', | 432 | name: 'renamechat', |
| @@ -449,18 +449,18 @@ export function initDefaultSlashCommands() { | |||
| 449 | }, | 449 | }, |
| 450 | unnamedArgumentList: [ | 450 | unnamedArgumentList: [ |
| 451 | new SlashCommandArgument( | 451 | new SlashCommandArgument( |
| 452 | 'new chat name', [ARGUMENT_TYPE.STRING], true, | 452 | t`new chat name`, [ARGUMENT_TYPE.STRING], true, |
| 453 | ), | 453 | ), |
| 454 | ], | 454 | ], |
| 455 | helpString: 'Renames the current chat.', | 455 | helpString: t`Renames the current chat.`, |
| 456 | })); | 456 | })); |
| 457 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 457 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 458 | name: 'getchatname', | 458 | name: 'getchatname', |
| 459 | callback: async function doGetChatName() { | 459 | callback: async function doGetChatName() { |
| 460 | return getCurrentChatDetails().sessionName; | 460 | return getCurrentChatDetails().sessionName; |
| 461 | }, | 461 | }, |
| 462 | returns: 'chat file name', | 462 | returns: t`chat file name`, |
| 463 | helpString: 'Returns the name of the current chat file into the pipe.', | 463 | helpString: t`Returns the name of the current chat file into the pipe.`, |
| 464 | })); | 464 | })); |
| 465 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 465 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 466 | name: 'closechat', | 466 | name: 'closechat', |
| @@ -468,7 +468,7 @@ export function initDefaultSlashCommands() { | |||
| 468 | $('#option_close_chat').trigger('click'); | 468 | $('#option_close_chat').trigger('click'); |
| 469 | return ''; | 469 | return ''; |
| 470 | }, | 470 | }, |
| 471 | helpString: 'Closes the current chat.', | 471 | helpString: t`Closes the current chat.`, |
| 472 | })); | 472 | })); |
| 473 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 473 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 474 | name: 'tempchat', | 474 | name: 'tempchat', |
| @@ -476,7 +476,7 @@ export function initDefaultSlashCommands() { | |||
| 476 | return new Promise((resolve, reject) => { | 476 | return new Promise((resolve, reject) => { |
| 477 | const eventCallback = async (chatId) => { | 477 | const eventCallback = async (chatId) => { |
| 478 | if (chatId) { | 478 | if (chatId) { |
| 479 | return reject('Not in a temporary chat'); | 479 | return reject(t`Not in a temporary chat`); |
| 480 | } | 480 | } |
| 481 | await newAssistantChat({ temporary: true }); | 481 | await newAssistantChat({ temporary: true }); |
| 482 | return resolve(''); | 482 | return resolve(''); |
| @@ -484,12 +484,12 @@ export function initDefaultSlashCommands() { | |||
| 484 | eventSource.once(event_types.CHAT_CHANGED, eventCallback); | 484 | eventSource.once(event_types.CHAT_CHANGED, eventCallback); |
| 485 | $('#option_close_chat').trigger('click'); | 485 | $('#option_close_chat').trigger('click'); |
| 486 | setTimeout(() => { | 486 | setTimeout(() => { |
| 487 | reject('Failed to open temporary chat'); | 487 | reject(t`Failed to open temporary chat`); |
| 488 | eventSource.removeListener(event_types.CHAT_CHANGED, eventCallback); | 488 | eventSource.removeListener(event_types.CHAT_CHANGED, eventCallback); |
| 489 | }, debounce_timeout.relaxed); | 489 | }, debounce_timeout.relaxed); |
| 490 | }); | 490 | }); |
| 491 | }, | 491 | }, |
| 492 | helpString: 'Opens a temporary chat with Assistant.', | 492 | helpString: t`Opens a temporary chat with Assistant.`, |
| 493 | })); | 493 | })); |
| 494 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 494 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 495 | name: 'panels', | 495 | name: 'panels', |
| @@ -498,17 +498,17 @@ export function initDefaultSlashCommands() { | |||
| 498 | return ''; | 498 | return ''; |
| 499 | }, | 499 | }, |
| 500 | aliases: ['togglepanels'], | 500 | aliases: ['togglepanels'], |
| 501 | helpString: 'Toggle UI panels on/off', | 501 | helpString: t`Toggle UI panels on/off`, |
| 502 | })); | 502 | })); |
| 503 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 503 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 504 | name: 'forcesave', | 504 | name: 'forcesave', |
| 505 | callback: async function () { | 505 | callback: async function () { |
| 506 | await saveSettings(); | 506 | await saveSettings(); |
| 507 | await saveChatConditional(); | 507 | await saveChatConditional(); |
| 508 | toastr.success('Chat and settings saved.'); | 508 | toastr.success(t`Chat and settings saved.`); |
| 509 | return ''; | 509 | return ''; |
| 510 | }, | 510 | }, |
| 511 | helpString: 'Forces a save of the current chat and settings', | 511 | helpString: t`Forces a save of the current chat and settings`, |
| 512 | })); | 512 | })); |
| 513 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 513 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 514 | name: 'instruct', | 514 | name: 'instruct', |
| @@ -531,18 +531,18 @@ export function initDefaultSlashCommands() { | |||
| 531 | selectInstructPreset(foundName, { quiet: quiet }); | 531 | selectInstructPreset(foundName, { quiet: quiet }); |
| 532 | return foundName; | 532 | return foundName; |
| 533 | }, | 533 | }, |
| 534 | returns: 'current template', | 534 | returns: t`current template`, |
| 535 | namedArgumentList: [ | 535 | namedArgumentList: [ |
| 536 | SlashCommandNamedArgument.fromProps({ | 536 | SlashCommandNamedArgument.fromProps({ |
| 537 | name: 'quiet', | 537 | name: 'quiet', |
| 538 | description: 'Suppress the toast message on template change', | 538 | description: t`Suppress the toast message on template change`, |
| 539 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 539 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 540 | defaultValue: 'false', | 540 | defaultValue: 'false', |
| 541 | enumList: commonEnumProviders.boolean('trueFalse')(), | 541 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 542 | }), | 542 | }), |
| 543 | SlashCommandNamedArgument.fromProps({ | 543 | SlashCommandNamedArgument.fromProps({ |
| 544 | name: 'forceGet', | 544 | name: 'forceGet', |
| 545 | description: 'Force getting a name even if instruct mode is disabled', | 545 | description: t`Force getting a name even if instruct mode is disabled`, |
| 546 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 546 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 547 | defaultValue: 'false', | 547 | defaultValue: 'false', |
| 548 | enumList: commonEnumProviders.boolean('trueFalse')(), | 548 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| @@ -550,18 +550,18 @@ export function initDefaultSlashCommands() { | |||
| 550 | ], | 550 | ], |
| 551 | unnamedArgumentList: [ | 551 | unnamedArgumentList: [ |
| 552 | SlashCommandArgument.fromProps({ | 552 | SlashCommandArgument.fromProps({ |
| 553 | description: 'instruct template name', | 553 | description: t`instruct template name`, |
| 554 | typeList: [ARGUMENT_TYPE.STRING], | 554 | typeList: [ARGUMENT_TYPE.STRING], |
| 555 | enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)), | 555 | enumProvider: () => instruct_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)), |
| 556 | }), | 556 | }), |
| 557 | ], | 557 | ], |
| 558 | helpString: ` | 558 | helpString: ` |
| 559 | <div> | 559 | <div> |
| 560 | Selects instruct mode template by name. Enables instruct mode if not already enabled. | 560 | ${t`Selects instruct mode template by name. Enables instruct mode if not already enabled.`} |
| 561 | Gets the current instruct template if no name is provided and instruct mode is enabled or <code>forceGet=true</code> is passed. | 561 | ${t`Gets the current instruct template if no name is provided and instruct mode is enabled or <code>forceGet=true</code> is passed.`} |
| 562 | </div> | 562 | </div> |
| 563 | <div> | 563 | <div> |
| 564 | <strong>Example:</strong> | 564 | <strong>${t`Example:`}</strong> |
| 565 | <ul> | 565 | <ul> |
| 566 | <li> | 566 | <li> |
| 567 | <pre><code class="language-stscript">/instruct creative</code></pre> | 567 | <pre><code class="language-stscript">/instruct creative</code></pre> |
| @@ -573,20 +573,20 @@ export function initDefaultSlashCommands() { | |||
| 573 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 573 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 574 | name: 'instruct-on', | 574 | name: 'instruct-on', |
| 575 | callback: enableInstructCallback, | 575 | callback: enableInstructCallback, |
| 576 | helpString: 'Enables instruct mode.', | 576 | helpString: t`Enables instruct mode.`, |
| 577 | })); | 577 | })); |
| 578 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 578 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 579 | name: 'instruct-off', | 579 | name: 'instruct-off', |
| 580 | callback: disableInstructCallback, | 580 | callback: disableInstructCallback, |
| 581 | helpString: 'Disables instruct mode', | 581 | helpString: t`Disables instruct mode`, |
| 582 | })); | 582 | })); |
| 583 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 583 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 584 | name: 'instruct-state', | 584 | name: 'instruct-state', |
| 585 | aliases: ['instruct-toggle'], | 585 | aliases: ['instruct-toggle'], |
| 586 | helpString: 'Gets the current instruct mode state. If an argument is provided, it will set the instruct mode state.', | 586 | helpString: t`Gets the current instruct mode state. If an argument is provided, it will set the instruct mode state.`, |
| 587 | unnamedArgumentList: [ | 587 | unnamedArgumentList: [ |
| 588 | SlashCommandArgument.fromProps({ | 588 | SlashCommandArgument.fromProps({ |
| 589 | description: 'instruct mode state', | 589 | description: t`instruct mode state`, |
| 590 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 590 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 591 | enumList: commonEnumProviders.boolean('trueFalse')(), | 591 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 592 | }), | 592 | }), |
| @@ -622,11 +622,11 @@ export function initDefaultSlashCommands() { | |||
| 622 | selectContextPreset(foundName, { quiet: quiet }); | 622 | selectContextPreset(foundName, { quiet: quiet }); |
| 623 | return foundName; | 623 | return foundName; |
| 624 | }, | 624 | }, |
| 625 | returns: 'template name', | 625 | returns: t`template name`, |
| 626 | namedArgumentList: [ | 626 | namedArgumentList: [ |
| 627 | SlashCommandNamedArgument.fromProps({ | 627 | SlashCommandNamedArgument.fromProps({ |
| 628 | name: 'quiet', | 628 | name: 'quiet', |
| 629 | description: 'Suppress the toast message on template change', | 629 | description: t`Suppress the toast message on template change`, |
| 630 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 630 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 631 | defaultValue: 'false', | 631 | defaultValue: 'false', |
| 632 | enumList: commonEnumProviders.boolean('trueFalse')(), | 632 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| @@ -634,12 +634,12 @@ export function initDefaultSlashCommands() { | |||
| 634 | ], | 634 | ], |
| 635 | unnamedArgumentList: [ | 635 | unnamedArgumentList: [ |
| 636 | SlashCommandArgument.fromProps({ | 636 | SlashCommandArgument.fromProps({ |
| 637 | description: 'context template name', | 637 | description: t`context template name`, |
| 638 | typeList: [ARGUMENT_TYPE.STRING], | 638 | typeList: [ARGUMENT_TYPE.STRING], |
| 639 | enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)), | 639 | enumProvider: () => context_presets.map(preset => new SlashCommandEnumValue(preset.name, null, enumTypes.enum, enumIcons.preset)), |
| 640 | }), | 640 | }), |
| 641 | ], | 641 | ], |
| 642 | helpString: 'Selects context template by name. Gets the current template if no name is provided', | 642 | helpString: t`Selects context template by name. Gets the current template if no name is provided`, |
| 643 | })); | 643 | })); |
| 644 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 644 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 645 | name: 'chat-manager', | 645 | name: 'chat-manager', |
| @@ -648,32 +648,32 @@ export function initDefaultSlashCommands() { | |||
| 648 | return ''; | 648 | return ''; |
| 649 | }, | 649 | }, |
| 650 | aliases: ['chat-history', 'manage-chats'], | 650 | aliases: ['chat-history', 'manage-chats'], |
| 651 | helpString: 'Opens the chat manager for the current character/group.', | 651 | helpString: t`Opens the chat manager for the current character/group.`, |
| 652 | })); | 652 | })); |
| 653 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 653 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 654 | name: '?', | 654 | name: '?', |
| 655 | callback: helpCommandCallback, | 655 | callback: helpCommandCallback, |
| 656 | aliases: ['help'], | 656 | aliases: ['help'], |
| 657 | unnamedArgumentList: [SlashCommandArgument.fromProps({ | 657 | unnamedArgumentList: [SlashCommandArgument.fromProps({ |
| 658 | description: 'help topic', | 658 | description: t`help topic`, |
| 659 | typeList: [ARGUMENT_TYPE.STRING], | 659 | typeList: [ARGUMENT_TYPE.STRING], |
| 660 | enumList: [ | 660 | enumList: [ |
| 661 | new SlashCommandEnumValue('slash', 'slash commands (STscript)', enumTypes.command, '/'), | 661 | new SlashCommandEnumValue('slash', t`slash commands (STscript)`, enumTypes.command, '/'), |
| 662 | new SlashCommandEnumValue('macros', '{{macros}} (text replacement)', enumTypes.macro, enumIcons.macro), | 662 | new SlashCommandEnumValue('macros', t`{{macros}} (text replacement)`, enumTypes.macro, enumIcons.macro), |
| 663 | new SlashCommandEnumValue('format', 'chat/text formatting', enumTypes.name, '★'), | 663 | new SlashCommandEnumValue('format', t`chat/text formatting`, enumTypes.name, '★'), |
| 664 | new SlashCommandEnumValue('hotkeys', 'keyboard shortcuts', enumTypes.enum, '⏎'), | 664 | new SlashCommandEnumValue('hotkeys', t`keyboard shortcuts`, enumTypes.enum, '⏎'), |
| 665 | ], | 665 | ], |
| 666 | })], | 666 | })], |
| 667 | helpString: 'Get help on macros, chat formatting and commands.', | 667 | helpString: t`Get help on macros, chat formatting and commands.`, |
| 668 | })); | 668 | })); |
| 669 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 669 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 670 | name: 'bg', | 670 | name: 'bg', |
| 671 | callback: setBackgroundCallback, | 671 | callback: setBackgroundCallback, |
| 672 | aliases: ['background'], | 672 | aliases: ['background'], |
| 673 | returns: 'the current background', | 673 | returns: t`the current background`, |
| 674 | unnamedArgumentList: [ | 674 | unnamedArgumentList: [ |
| 675 | SlashCommandArgument.fromProps({ | 675 | SlashCommandArgument.fromProps({ |
| 676 | description: 'background filename', | 676 | description: t`background filename`, |
| 677 | typeList: [ARGUMENT_TYPE.STRING], | 677 | typeList: [ARGUMENT_TYPE.STRING], |
| 678 | enumProvider: () => [...document.querySelectorAll('.bg_example')] | 678 | enumProvider: () => [...document.querySelectorAll('.bg_example')] |
| 679 | .map(it => new SlashCommandEnumValue(it.getAttribute('bgfile'))) | 679 | .map(it => new SlashCommandEnumValue(it.getAttribute('bgfile'))) |
| @@ -682,13 +682,13 @@ export function initDefaultSlashCommands() { | |||
| 682 | ], | 682 | ], |
| 683 | helpString: ` | 683 | helpString: ` |
| 684 | <div> | 684 | <div> |
| 685 | Sets a background according to the provided filename. Partial names allowed. | 685 | ${t`Sets a background according to the provided filename. Partial names allowed.`} |
| 686 | </div> | 686 | </div> |
| 687 | <div> | 687 | <div> |
| 688 | If no background is provided, this will return the currently selected background. | 688 | ${t`If no background is provided, this will return the currently selected background.`} |
| 689 | </div> | 689 | </div> |
| 690 | <div> | 690 | <div> |
| 691 | <strong>Example:</strong> | 691 | <strong>${t`Example:`}</strong> |
| 692 | <ul> | 692 | <ul> |
| 693 | <li> | 693 | <li> |
| 694 | <pre><code>/bg beach.jpg</code></pre> | 694 | <pre><code>/bg beach.jpg</code></pre> |
| @@ -704,31 +704,31 @@ export function initDefaultSlashCommands() { | |||
| 704 | name: 'char-find', | 704 | name: 'char-find', |
| 705 | aliases: ['findchar'], | 705 | aliases: ['findchar'], |
| 706 | callback: (args, name) => { | 706 | callback: (args, name) => { |
| 707 | if (typeof name !== 'string') throw new Error('name must be a string'); | 707 | if (typeof name !== 'string') throw new Error(t`name must be a string`); |
| 708 | if (args.preferCurrent instanceof SlashCommandClosure || Array.isArray(args.preferCurrent)) throw new Error('preferCurrent cannot be a closure or array'); | 708 | if (args.preferCurrent instanceof SlashCommandClosure || Array.isArray(args.preferCurrent)) throw new Error(t`preferCurrent cannot be a closure or array`); |
| 709 | if (args.quiet instanceof SlashCommandClosure || Array.isArray(args.quiet)) throw new Error('quiet cannot be a closure or array'); | 709 | if (args.quiet instanceof SlashCommandClosure || Array.isArray(args.quiet)) throw new Error(t`quiet cannot be a closure or array`); |
| 710 | 710 | ||
| 711 | const char = findChar({ name: name, filteredByTags: validateArrayArgString(args.tag, 'tag'), preferCurrentChar: !isFalseBoolean(args.preferCurrent), quiet: isTrueBoolean(args.quiet) }); | 711 | const char = findChar({ name: name, filteredByTags: validateArrayArgString(args.tag, 'tag'), preferCurrentChar: !isFalseBoolean(args.preferCurrent), quiet: isTrueBoolean(args.quiet) }); |
| 712 | return char?.avatar ?? ''; | 712 | return char?.avatar ?? ''; |
| 713 | }, | 713 | }, |
| 714 | returns: 'the avatar key (unique identifier) of the character', | 714 | returns: t`the avatar key (unique identifier) of the character`, |
| 715 | namedArgumentList: [ | 715 | namedArgumentList: [ |
| 716 | SlashCommandNamedArgument.fromProps({ | 716 | SlashCommandNamedArgument.fromProps({ |
| 717 | name: 'tag', | 717 | name: 'tag', |
| 718 | description: 'Supply one or more tags to filter down to the correct character for the provided name, if multiple characters have the same name.', | 718 | description: t`Supply one or more tags to filter down to the correct character for the provided name, if multiple characters have the same name.`, |
| 719 | typeList: [ARGUMENT_TYPE.STRING], | 719 | typeList: [ARGUMENT_TYPE.STRING], |
| 720 | enumProvider: commonEnumProviders.tags('assigned'), | 720 | enumProvider: commonEnumProviders.tags('assigned'), |
| 721 | acceptsMultiple: true, | 721 | acceptsMultiple: true, |
| 722 | }), | 722 | }), |
| 723 | SlashCommandNamedArgument.fromProps({ | 723 | SlashCommandNamedArgument.fromProps({ |
| 724 | name: 'preferCurrent', | 724 | name: 'preferCurrent', |
| 725 | description: 'Prefer current character or characters in a group, if multiple characters match', | 725 | description: t`Prefer current character or characters in a group, if multiple characters match`, |
| 726 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 726 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 727 | defaultValue: 'true', | 727 | defaultValue: 'true', |
| 728 | }), | 728 | }), |
| 729 | SlashCommandNamedArgument.fromProps({ | 729 | SlashCommandNamedArgument.fromProps({ |
| 730 | name: 'quiet', | 730 | name: 'quiet', |
| 731 | description: 'Do not show warning if multiple charactrers are found', | 731 | description: t`Do not show warning if multiple charactrers are found`, |
| 732 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 732 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 733 | defaultValue: 'false', | 733 | defaultValue: 'false', |
| 734 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 734 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| @@ -736,31 +736,29 @@ export function initDefaultSlashCommands() { | |||
| 736 | ], | 736 | ], |
| 737 | unnamedArgumentList: [ | 737 | unnamedArgumentList: [ |
| 738 | SlashCommandArgument.fromProps({ | 738 | SlashCommandArgument.fromProps({ |
| 739 | description: 'Character name - or unique character identifier (avatar key)', | 739 | description: t`Character name - or unique character identifier (avatar key)`, |
| 740 | typeList: [ARGUMENT_TYPE.STRING], | 740 | typeList: [ARGUMENT_TYPE.STRING], |
| 741 | enumProvider: commonEnumProviders.characters('character'), | 741 | enumProvider: commonEnumProviders.characters('character'), |
| 742 | }), | 742 | }), |
| 743 | ], | 743 | ], |
| 744 | helpString: ` | 744 | helpString: ` |
| 745 | <div> | 745 | <div> |
| 746 | Searches for a character and returns its avatar key. | 746 | ${t`Searches for a character and returns its avatar key.`} |
| 747 | </div> | 747 | </div> |
| 748 | <div> | 748 | <div> |
| 749 | This can be used to choose the correct character for something like <code>/sendas</code> or other commands in need of a character name | 749 | ${t`This can be used to choose the correct character for something like <code>/sendas</code> or other commands in need of a character name if you have multiple characters with the same name.`} |
| 750 | if you have multiple characters with the same name. | ||
| 751 | </div> | 750 | </div> |
| 752 | <div> | 751 | <div> |
| 753 | <strong>Example:</strong> | 752 | <strong>${t`Example:`}</strong> |
| 754 | <ul> | 753 | <ul> |
| 755 | <li> | 754 | <li> |
| 756 | <pre><code>/char-find name="Chloe"</code></pre> | 755 | <pre><code>/char-find name="Chloe"</code></pre> |
| 757 | Returns the avatar key for "Chloe". | 756 | ${t`Returns the avatar key for "Chloe".`} |
| 758 | </li> | 757 | </li> |
| 759 | <li> | 758 | <li> |
| 760 | <pre><code>/search name="Chloe" tag="friend"</code></pre> | 759 | <pre><code>/search name="Chloe" tag="friend"</code></pre> |
| 761 | Returns the avatar key for the character "Chloe" that is tagged with "friend". | 760 | ${t`Returns the avatar key for the character "Chloe" that is tagged with "friend".`} |
| 762 | This is useful if you for example have multiple characters named "Chloe", and the others are "foe", "goddess", or anything else, | 761 | ${t`This is useful if you for example have multiple characters named "Chloe", and the others are "foe", "goddess", or anything else, so you can actually select the character you are looking for.`} |
| 763 | so you can actually select the character you are looking for. | ||
| 764 | </li> | 762 | </li> |
| 765 | </ul> | 763 | </ul> |
| 766 | </div> | 764 | </div> |
| @@ -770,36 +768,36 @@ export function initDefaultSlashCommands() { | |||
| 770 | name: 'sendas', | 768 | name: 'sendas', |
| 771 | rawQuotes: true, | 769 | rawQuotes: true, |
| 772 | callback: sendMessageAs, | 770 | callback: sendMessageAs, |
| 773 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', | 771 | returns: t`Optionally the text of the sent message, if specified in the "return" argument`, |
| 774 | namedArgumentList: [ | 772 | namedArgumentList: [ |
| 775 | SlashCommandNamedArgument.fromProps({ | 773 | SlashCommandNamedArgument.fromProps({ |
| 776 | name: 'name', | 774 | name: 'name', |
| 777 | description: 'Character name - or unique character identifier (avatar key)', | 775 | description: t`Character name - or unique character identifier (avatar key)`, |
| 778 | typeList: [ARGUMENT_TYPE.STRING], | 776 | typeList: [ARGUMENT_TYPE.STRING], |
| 779 | isRequired: true, | 777 | isRequired: true, |
| 780 | enumProvider: commonEnumProviders.characters('character'), | 778 | enumProvider: commonEnumProviders.characters('character'), |
| 781 | }), | 779 | }), |
| 782 | SlashCommandNamedArgument.fromProps({ | 780 | SlashCommandNamedArgument.fromProps({ |
| 783 | name: 'avatar', | 781 | name: 'avatar', |
| 784 | description: 'Character avatar override (Can be either avatar key or just the character name to pull the avatar from)', | 782 | description: t`Character avatar override (Can be either avatar key or just the character name to pull the avatar from)`, |
| 785 | typeList: [ARGUMENT_TYPE.STRING], | 783 | typeList: [ARGUMENT_TYPE.STRING], |
| 786 | enumProvider: commonEnumProviders.characters('character'), | 784 | enumProvider: commonEnumProviders.characters('character'), |
| 787 | }), | 785 | }), |
| 788 | SlashCommandNamedArgument.fromProps({ | 786 | SlashCommandNamedArgument.fromProps({ |
| 789 | name: 'compact', | 787 | name: 'compact', |
| 790 | description: 'Use compact layout', | 788 | description: t`Use compact layout`, |
| 791 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 789 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 792 | defaultValue: 'false', | 790 | defaultValue: 'false', |
| 793 | }), | 791 | }), |
| 794 | SlashCommandNamedArgument.fromProps({ | 792 | SlashCommandNamedArgument.fromProps({ |
| 795 | name: 'at', | 793 | name: 'at', |
| 796 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 794 | description: t`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how 'depth' usually works. For example, -1 will insert the message right before the last message in chat.`, |
| 797 | typeList: [ARGUMENT_TYPE.NUMBER], | 795 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 798 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 796 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 799 | }), | 797 | }), |
| 800 | SlashCommandNamedArgument.fromProps({ | 798 | SlashCommandNamedArgument.fromProps({ |
| 801 | name: 'return', | 799 | name: 'return', |
| 802 | description: 'The way how you want the return value to be provided', | 800 | description: t`The way how you want the return value to be provided`, |
| 803 | typeList: [ARGUMENT_TYPE.STRING], | 801 | typeList: [ARGUMENT_TYPE.STRING], |
| 804 | defaultValue: 'none', | 802 | defaultValue: 'none', |
| 805 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 803 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| @@ -807,7 +805,7 @@ export function initDefaultSlashCommands() { | |||
| 807 | }), | 805 | }), |
| 808 | SlashCommandNamedArgument.fromProps({ | 806 | SlashCommandNamedArgument.fromProps({ |
| 809 | name: 'raw', | 807 | name: 'raw', |
| 810 | description: 'If true, does not alter quoted literal unnamed arguments', | 808 | description: t`If true, does not alter quoted literal unnamed arguments`, |
| 811 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 809 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 812 | defaultValue: 'true', | 810 | defaultValue: 'true', |
| 813 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 811 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| @@ -821,23 +819,23 @@ export function initDefaultSlashCommands() { | |||
| 821 | ], | 819 | ], |
| 822 | helpString: ` | 820 | helpString: ` |
| 823 | <div> | 821 | <div> |
| 824 | Sends a message as a specific character. Uses the character avatar if it exists in the characters list. | 822 | ${t`Sends a message as a specific character. Uses the character avatar if it exists in the characters list.`} |
| 825 | </div> | 823 | </div> |
| 826 | <div> | 824 | <div> |
| 827 | <strong>Example:</strong> | 825 | <strong>${t`Example:`}</strong> |
| 828 | <ul> | 826 | <ul> |
| 829 | <li> | 827 | <li> |
| 830 | <pre><code>/sendas name="Chloe" Hello, guys!</code></pre> | 828 | <pre><code>/sendas name="Chloe" Hello, guys!</code></pre> |
| 831 | will send "Hello, guys!" from "Chloe". | 829 | ${t`will send "Hello, guys!" from "Chloe".`} |
| 832 | </li> | 830 | </li> |
| 833 | <li> | 831 | <li> |
| 834 | <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre> | 832 | <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre> |
| 835 | will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss". | 833 | ${t`will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".`} |
| 836 | </li> | 834 | </li> |
| 837 | </ul> | 835 | </ul> |
| 838 | </div> | 836 | </div> |
| 839 | <div> | 837 | <div> |
| 840 | If "compact" is set to true, the message is sent using a compact layout. | 838 | ${t`If "compact" is set to true, the message is sent using a compact layout.`} |
| 841 | </div> | 839 | </div> |
| 842 | `, | 840 | `, |
| 843 | })); | 841 | })); |
| @@ -846,11 +844,11 @@ export function initDefaultSlashCommands() { | |||
| 846 | rawQuotes: true, | 844 | rawQuotes: true, |
| 847 | callback: sendNarratorMessage, | 845 | callback: sendNarratorMessage, |
| 848 | aliases: ['nar'], | 846 | aliases: ['nar'], |
| 849 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', | 847 | returns: t`Optionally the text of the sent message, if specified in the "return" argument`, |
| 850 | namedArgumentList: [ | 848 | namedArgumentList: [ |
| 851 | new SlashCommandNamedArgument( | 849 | new SlashCommandNamedArgument( |
| 852 | 'compact', | 850 | 'compact', |
| 853 | 'compact layout', | 851 | t`compact layout`, |
| 854 | [ARGUMENT_TYPE.BOOLEAN], | 852 | [ARGUMENT_TYPE.BOOLEAN], |
| 855 | false, | 853 | false, |
| 856 | false, | 854 | false, |
| @@ -858,18 +856,18 @@ export function initDefaultSlashCommands() { | |||
| 858 | ), | 856 | ), |
| 859 | SlashCommandNamedArgument.fromProps({ | 857 | SlashCommandNamedArgument.fromProps({ |
| 860 | name: 'at', | 858 | name: 'at', |
| 861 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 859 | description: t`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how 'depth' usually works. For example, -1 will insert the message right before the last message in chat.`, |
| 862 | typeList: [ARGUMENT_TYPE.NUMBER], | 860 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 863 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 861 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 864 | }), | 862 | }), |
| 865 | SlashCommandNamedArgument.fromProps({ | 863 | SlashCommandNamedArgument.fromProps({ |
| 866 | name: 'name', | 864 | name: 'name', |
| 867 | description: 'Optional custom display name to use for this system narrator message.', | 865 | description: t`Optional custom display name to use for this system narrator message.`, |
| 868 | typeList: [ARGUMENT_TYPE.STRING], | 866 | typeList: [ARGUMENT_TYPE.STRING], |
| 869 | }), | 867 | }), |
| 870 | SlashCommandNamedArgument.fromProps({ | 868 | SlashCommandNamedArgument.fromProps({ |
| 871 | name: 'return', | 869 | name: 'return', |
| 872 | description: 'The way how you want the return value to be provided', | 870 | description: t`The way how you want the return value to be provided`, |
| 873 | typeList: [ARGUMENT_TYPE.STRING], | 871 | typeList: [ARGUMENT_TYPE.STRING], |
| 874 | defaultValue: 'none', | 872 | defaultValue: 'none', |
| 875 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 873 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| @@ -877,7 +875,7 @@ export function initDefaultSlashCommands() { | |||
| 877 | }), | 875 | }), |
| 878 | SlashCommandNamedArgument.fromProps({ | 876 | SlashCommandNamedArgument.fromProps({ |
| 879 | name: 'raw', | 877 | name: 'raw', |
| 880 | description: 'If true, does not alter quoted literal unnamed arguments', | 878 | description: t`If true, does not alter quoted literal unnamed arguments`, |
| 881 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 879 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 882 | defaultValue: 'true', | 880 | defaultValue: 'true', |
| 883 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 881 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| @@ -891,13 +889,13 @@ export function initDefaultSlashCommands() { | |||
| 891 | ], | 889 | ], |
| 892 | helpString: ` | 890 | helpString: ` |
| 893 | <div> | 891 | <div> |
| 894 | Sends a message as a system narrator. | 892 | ${t`Sends a message as a system narrator.`} |
| 895 | </div> | 893 | </div> |
| 896 | <div> | 894 | <div> |
| 897 | If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout. | 895 | ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`} |
| 898 | </div> | 896 | </div> |
| 899 | <div> | 897 | <div> |
| 900 | <strong>Example:</strong> | 898 | <strong>${t`Example:`}</strong> |
| 901 | <ul> | 899 | <ul> |
| 902 | <li> | 900 | <li> |
| 903 | <pre><code>/sys The sun sets in the west.</code></pre> | 901 | <pre><code>/sys The sun sets in the west.</code></pre> |
| @@ -914,20 +912,20 @@ export function initDefaultSlashCommands() { | |||
| 914 | callback: setNarratorName, | 912 | callback: setNarratorName, |
| 915 | unnamedArgumentList: [ | 913 | unnamedArgumentList: [ |
| 916 | new SlashCommandArgument( | 914 | new SlashCommandArgument( |
| 917 | 'name', [ARGUMENT_TYPE.STRING], false, | 915 | t`name`, [ARGUMENT_TYPE.STRING], false, |
| 918 | ), | 916 | ), |
| 919 | ], | 917 | ], |
| 920 | helpString: 'Sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.', | 918 | helpString: t`Sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.`, |
| 921 | })); | 919 | })); |
| 922 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 920 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 923 | name: 'comment', | 921 | name: 'comment', |
| 924 | rawQuotes: true, | 922 | rawQuotes: true, |
| 925 | callback: sendCommentMessage, | 923 | callback: sendCommentMessage, |
| 926 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', | 924 | returns: t`Optionally the text of the sent message, if specified in the "return" argument`, |
| 927 | namedArgumentList: [ | 925 | namedArgumentList: [ |
| 928 | new SlashCommandNamedArgument( | 926 | new SlashCommandNamedArgument( |
| 929 | 'compact', | 927 | 'compact', |
| 930 | 'Whether to use a compact layout', | 928 | t`Whether to use a compact layout`, |
| 931 | [ARGUMENT_TYPE.BOOLEAN], | 929 | [ARGUMENT_TYPE.BOOLEAN], |
| 932 | false, | 930 | false, |
| 933 | false, | 931 | false, |
| @@ -935,13 +933,13 @@ export function initDefaultSlashCommands() { | |||
| 935 | ), | 933 | ), |
| 936 | SlashCommandNamedArgument.fromProps({ | 934 | SlashCommandNamedArgument.fromProps({ |
| 937 | name: 'at', | 935 | name: 'at', |
| 938 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 936 | description: t`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how 'depth' usually works. For example, -1 will insert the message right before the last message in chat.`, |
| 939 | typeList: [ARGUMENT_TYPE.NUMBER], | 937 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 940 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 938 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 941 | }), | 939 | }), |
| 942 | SlashCommandNamedArgument.fromProps({ | 940 | SlashCommandNamedArgument.fromProps({ |
| 943 | name: 'return', | 941 | name: 'return', |
| 944 | description: 'The way how you want the return value to be provided', | 942 | description: t`The way how you want the return value to be provided`, |
| 945 | typeList: [ARGUMENT_TYPE.STRING], | 943 | typeList: [ARGUMENT_TYPE.STRING], |
| 946 | defaultValue: 'none', | 944 | defaultValue: 'none', |
| 947 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 945 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| @@ -949,7 +947,7 @@ export function initDefaultSlashCommands() { | |||
| 949 | }), | 947 | }), |
| 950 | SlashCommandNamedArgument.fromProps({ | 948 | SlashCommandNamedArgument.fromProps({ |
| 951 | name: 'raw', | 949 | name: 'raw', |
| 952 | description: 'If true, does not alter quoted literal unnamed arguments', | 950 | description: t`If true, does not alter quoted literal unnamed arguments`, |
| 953 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 951 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 954 | defaultValue: 'true', | 952 | defaultValue: 'true', |
| 955 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 953 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| @@ -965,13 +963,13 @@ export function initDefaultSlashCommands() { | |||
| 965 | ], | 963 | ], |
| 966 | helpString: ` | 964 | helpString: ` |
| 967 | <div> | 965 | <div> |
| 968 | Adds a note/comment message not part of the chat. | 966 | ${t`Adds a note/comment message not part of the chat.`} |
| 969 | </div> | 967 | </div> |
| 970 | <div> | 968 | <div> |
| 971 | If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout. | 969 | ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`} |
| 972 | </div> | 970 | </div> |
| 973 | <div> | 971 | <div> |
| 974 | <strong>Example:</strong> | 972 | <strong>${t`Example:`}</strong> |
| 975 | <ul> | 973 | <ul> |
| 976 | <li> | 974 | <li> |
| 977 | <pre><code>/comment This is a comment</code></pre> | 975 | <pre><code>/comment This is a comment</code></pre> |
| @@ -987,19 +985,19 @@ export function initDefaultSlashCommands() { | |||
| 987 | name: 'single', | 985 | name: 'single', |
| 988 | callback: setStoryModeCallback, | 986 | callback: setStoryModeCallback, |
| 989 | aliases: ['story'], | 987 | aliases: ['story'], |
| 990 | helpString: 'Sets the message style to single document mode without names or avatars visible.', | 988 | helpString: t`Sets the message style to single document mode without names or avatars visible.`, |
| 991 | })); | 989 | })); |
| 992 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 990 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 993 | name: 'bubble', | 991 | name: 'bubble', |
| 994 | callback: setBubbleModeCallback, | 992 | callback: setBubbleModeCallback, |
| 995 | aliases: ['bubbles'], | 993 | aliases: ['bubbles'], |
| 996 | helpString: 'Sets the message style to bubble chat mode.', | 994 | helpString: t`Sets the message style to bubble chat mode.`, |
| 997 | })); | 995 | })); |
| 998 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 996 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 999 | name: 'flat', | 997 | name: 'flat', |
| 1000 | callback: setFlatModeCallback, | 998 | callback: setFlatModeCallback, |
| 1001 | aliases: ['default'], | 999 | aliases: ['default'], |
| 1002 | helpString: 'Sets the message style to flat chat mode.', | 1000 | helpString: t`Sets the message style to flat chat mode.`, |
| 1003 | })); | 1001 | })); |
| 1004 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1002 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1005 | name: 'continue', | 1003 | name: 'continue', |
| @@ -1008,7 +1006,7 @@ export function initDefaultSlashCommands() { | |||
| 1008 | namedArgumentList: [ | 1006 | namedArgumentList: [ |
| 1009 | new SlashCommandNamedArgument( | 1007 | new SlashCommandNamedArgument( |
| 1010 | 'await', | 1008 | 'await', |
| 1011 | 'Whether to await for the continued generation before proceeding', | 1009 | t`Whether to await for the continued generation before proceeding`, |
| 1012 | [ARGUMENT_TYPE.BOOLEAN], | 1010 | [ARGUMENT_TYPE.BOOLEAN], |
| 1013 | false, | 1011 | false, |
| 1014 | false, | 1012 | false, |
| @@ -1022,21 +1020,21 @@ export function initDefaultSlashCommands() { | |||
| 1022 | ], | 1020 | ], |
| 1023 | helpString: ` | 1021 | helpString: ` |
| 1024 | <div> | 1022 | <div> |
| 1025 | Continues the last message in the chat, with an optional additional prompt. | 1023 | ${t`Continues the last message in the chat, with an optional additional prompt.`} |
| 1026 | </div> | 1024 | </div> |
| 1027 | <div> | 1025 | <div> |
| 1028 | If <code>await=true</code> named argument is passed, the command will await for the continued generation before proceeding. | 1026 | ${t`If <code>await=true</code> named argument is passed, the command will await for the continued generation before proceeding.`} |
| 1029 | </div> | 1027 | </div> |
| 1030 | <div> | 1028 | <div> |
| 1031 | <strong>Example:</strong> | 1029 | <strong>${t`Example:`}</strong> |
| 1032 | <ul> | 1030 | <ul> |
| 1033 | <li> | 1031 | <li> |
| 1034 | <pre><code>/continue</code></pre> | 1032 | <pre><code>/continue</code></pre> |
| 1035 | Continues the chat with no additional prompt and immediately proceeds to the next command. | 1033 | ${t`Continues the chat with no additional prompt and immediately proceeds to the next command.`} |
| 1036 | </li> | 1034 | </li> |
| 1037 | <li> | 1035 | <li> |
| 1038 | <pre><code>/continue await=true Let's explore this further...</code></pre> | 1036 | <pre><code>/continue await=true Let's explore this further...</code></pre> |
| 1039 | Continues the chat with the provided prompt and waits for the generation to finish. | 1037 | ${t`Continues the chat with the provided prompt and waits for the generation to finish.`} |
| 1040 | </li> | 1038 | </li> |
| 1041 | </ul> | 1039 | </ul> |
| 1042 | </div> | 1040 | </div> |
| @@ -1045,16 +1043,16 @@ export function initDefaultSlashCommands() { | |||
| 1045 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1043 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1046 | name: 'go', | 1044 | name: 'go', |
| 1047 | callback: goToCharacterCallback, | 1045 | callback: goToCharacterCallback, |
| 1048 | returns: 'The character/group name', | 1046 | returns: t`The character/group name`, |
| 1049 | unnamedArgumentList: [ | 1047 | unnamedArgumentList: [ |
| 1050 | SlashCommandArgument.fromProps({ | 1048 | SlashCommandArgument.fromProps({ |
| 1051 | description: 'Character name - or unique character identifier (avatar key)', | 1049 | description: t`Character name - or unique character identifier (avatar key)`, |
| 1052 | typeList: [ARGUMENT_TYPE.STRING], | 1050 | typeList: [ARGUMENT_TYPE.STRING], |
| 1053 | isRequired: true, | 1051 | isRequired: true, |
| 1054 | enumProvider: commonEnumProviders.characters('all'), | 1052 | enumProvider: commonEnumProviders.characters('all'), |
| 1055 | }), | 1053 | }), |
| 1056 | ], | 1054 | ], |
| 1057 | helpString: 'Opens up a chat with the character or group by its name', | 1055 | helpString: t`Opens up a chat with the character or group by its name`, |
| 1058 | aliases: ['char'], | 1056 | aliases: ['char'], |
| 1059 | })); | 1057 | })); |
| 1060 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1058 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| @@ -1064,21 +1062,21 @@ export function initDefaultSlashCommands() { | |||
| 1064 | const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null }); | 1062 | const renamed = await renameCharacter(name, { silent: isTrueBoolean(silent), renameChats: chats !== null ? isTrueBoolean(chats) : null }); |
| 1065 | return String(renamed); | 1063 | return String(renamed); |
| 1066 | }, | 1064 | }, |
| 1067 | returns: 'true/false - Whether the rename was successful', | 1065 | returns: t`true/false - Whether the rename was successful`, |
| 1068 | namedArgumentList: [ | 1066 | namedArgumentList: [ |
| 1069 | new SlashCommandNamedArgument( | 1067 | new SlashCommandNamedArgument( |
| 1070 | 'silent', 'Hide any blocking popups. (if false, the name is optional. If not supplied, a popup asking for it will appear)', [ARGUMENT_TYPE.BOOLEAN], false, false, 'true', | 1068 | 'silent', t`Hide any blocking popups. (if false, the name is optional. If not supplied, a popup asking for it will appear)`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'true', |
| 1071 | ), | 1069 | ), |
| 1072 | new SlashCommandNamedArgument( | 1070 | new SlashCommandNamedArgument( |
| 1073 | 'chats', 'Rename char in all previous chats', [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>', | 1071 | 'chats', t`Rename char in all previous chats`, [ARGUMENT_TYPE.BOOLEAN], false, false, '<null>', |
| 1074 | ), | 1072 | ), |
| 1075 | ], | 1073 | ], |
| 1076 | unnamedArgumentList: [ | 1074 | unnamedArgumentList: [ |
| 1077 | new SlashCommandArgument( | 1075 | new SlashCommandArgument( |
| 1078 | 'new char name', [ARGUMENT_TYPE.STRING], true, | 1076 | t`new char name`, [ARGUMENT_TYPE.STRING], true, |
| 1079 | ), | 1077 | ), |
| 1080 | ], | 1078 | ], |
| 1081 | helpString: 'Renames the current character.', | 1079 | helpString: t`Renames the current character.`, |
| 1082 | })); | 1080 | })); |
| 1083 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1081 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1084 | name: 'sysgen', | 1082 | name: 'sysgen', |
| @@ -1086,7 +1084,7 @@ export function initDefaultSlashCommands() { | |||
| 1086 | namedArgumentList: [ | 1084 | namedArgumentList: [ |
| 1087 | SlashCommandNamedArgument.fromProps({ | 1085 | SlashCommandNamedArgument.fromProps({ |
| 1088 | name: 'trim', | 1086 | name: 'trim', |
| 1089 | description: 'Trim the output by the last sentence boundary', | 1087 | description: t`Trim the output by the last sentence boundary`, |
| 1090 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1088 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1091 | defaultValue: 'false', | 1089 | defaultValue: 'false', |
| 1092 | isRequired: false, | 1090 | isRequired: false, |
| @@ -1094,7 +1092,7 @@ export function initDefaultSlashCommands() { | |||
| 1094 | }), | 1092 | }), |
| 1095 | SlashCommandNamedArgument.fromProps({ | 1093 | SlashCommandNamedArgument.fromProps({ |
| 1096 | name: 'compact', | 1094 | name: 'compact', |
| 1097 | description: 'Use a compact layout for the message', | 1095 | description: t`Use a compact layout for the message`, |
| 1098 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1096 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1099 | defaultValue: 'false', | 1097 | defaultValue: 'false', |
| 1100 | isRequired: false, | 1098 | isRequired: false, |
| @@ -1103,18 +1101,18 @@ export function initDefaultSlashCommands() { | |||
| 1103 | }), | 1101 | }), |
| 1104 | SlashCommandNamedArgument.fromProps({ | 1102 | SlashCommandNamedArgument.fromProps({ |
| 1105 | name: 'at', | 1103 | name: 'at', |
| 1106 | description: 'Position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 1104 | description: t`Position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how 'depth' usually works. For example, -1 will insert the message right before the last message in chat.`, |
| 1107 | typeList: [ARGUMENT_TYPE.NUMBER], | 1105 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1108 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 1106 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 1109 | }), | 1107 | }), |
| 1110 | SlashCommandNamedArgument.fromProps({ | 1108 | SlashCommandNamedArgument.fromProps({ |
| 1111 | name: 'name', | 1109 | name: 'name', |
| 1112 | description: 'Optional custom display name to use for this system narrator message.', | 1110 | description: t`Optional custom display name to use for this system narrator message.`, |
| 1113 | typeList: [ARGUMENT_TYPE.STRING], | 1111 | typeList: [ARGUMENT_TYPE.STRING], |
| 1114 | }), | 1112 | }), |
| 1115 | SlashCommandNamedArgument.fromProps({ | 1113 | SlashCommandNamedArgument.fromProps({ |
| 1116 | name: 'return', | 1114 | name: 'return', |
| 1117 | description: 'The way how you want the return value to be provided', | 1115 | description: t`The way how you want the return value to be provided`, |
| 1118 | typeList: [ARGUMENT_TYPE.STRING], | 1116 | typeList: [ARGUMENT_TYPE.STRING], |
| 1119 | defaultValue: 'none', | 1117 | defaultValue: 'none', |
| 1120 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 1118 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| @@ -1126,23 +1124,23 @@ export function initDefaultSlashCommands() { | |||
| 1126 | 'prompt', [ARGUMENT_TYPE.STRING], true, | 1124 | 'prompt', [ARGUMENT_TYPE.STRING], true, |
| 1127 | ), | 1125 | ), |
| 1128 | ], | 1126 | ], |
| 1129 | helpString: 'Generates a system message using a specified prompt.', | 1127 | helpString: t`Generates a system message using a specified prompt.`, |
| 1130 | })); | 1128 | })); |
| 1131 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1129 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1132 | name: 'ask', | 1130 | name: 'ask', |
| 1133 | callback: askCharacter, | 1131 | callback: askCharacter, |
| 1134 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', | 1132 | returns: t`Optionally the text of the sent message, if specified in the "return" argument`, |
| 1135 | namedArgumentList: [ | 1133 | namedArgumentList: [ |
| 1136 | SlashCommandNamedArgument.fromProps({ | 1134 | SlashCommandNamedArgument.fromProps({ |
| 1137 | name: 'name', | 1135 | name: 'name', |
| 1138 | description: 'Character name - or unique character identifier (avatar key)', | 1136 | description: t`Character name - or unique character identifier (avatar key)`, |
| 1139 | typeList: [ARGUMENT_TYPE.STRING], | 1137 | typeList: [ARGUMENT_TYPE.STRING], |
| 1140 | isRequired: true, | 1138 | isRequired: true, |
| 1141 | enumProvider: commonEnumProviders.characters('character'), | 1139 | enumProvider: commonEnumProviders.characters('character'), |
| 1142 | }), | 1140 | }), |
| 1143 | SlashCommandNamedArgument.fromProps({ | 1141 | SlashCommandNamedArgument.fromProps({ |
| 1144 | name: 'return', | 1142 | name: 'return', |
| 1145 | description: 'The way how you want the return value to be provided', | 1143 | description: t`The way how you want the return value to be provided`, |
| 1146 | typeList: [ARGUMENT_TYPE.STRING], | 1144 | typeList: [ARGUMENT_TYPE.STRING], |
| 1147 | defaultValue: 'pipe', | 1145 | defaultValue: 'pipe', |
| 1148 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 1146 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| @@ -1154,7 +1152,7 @@ export function initDefaultSlashCommands() { | |||
| 1154 | 'prompt', [ARGUMENT_TYPE.STRING], false, false, | 1152 | 'prompt', [ARGUMENT_TYPE.STRING], false, false, |
| 1155 | ), | 1153 | ), |
| 1156 | ], | 1154 | ], |
| 1157 | helpString: 'Asks a specified character card a prompt. Character name must be provided in a named argument.', | 1155 | helpString: t`Asks a specified character card a prompt. Character name must be provided in a named argument.`, |
| 1158 | })); | 1156 | })); |
| 1159 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1157 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1160 | name: 'delname', | 1158 | name: 'delname', |
| @@ -1162,7 +1160,7 @@ export function initDefaultSlashCommands() { | |||
| 1162 | namedArgumentList: [], | 1160 | namedArgumentList: [], |
| 1163 | unnamedArgumentList: [ | 1161 | unnamedArgumentList: [ |
| 1164 | SlashCommandArgument.fromProps({ | 1162 | SlashCommandArgument.fromProps({ |
| 1165 | description: 'Character name - or unique character identifier (avatar key)', | 1163 | description: t`Character name - or unique character identifier (avatar key)`, |
| 1166 | typeList: [ARGUMENT_TYPE.STRING], | 1164 | typeList: [ARGUMENT_TYPE.STRING], |
| 1167 | isRequired: true, | 1165 | isRequired: true, |
| 1168 | enumProvider: commonEnumProviders.characters('character'), | 1166 | enumProvider: commonEnumProviders.characters('character'), |
| @@ -1171,10 +1169,10 @@ export function initDefaultSlashCommands() { | |||
| 1171 | aliases: ['cancel'], | 1169 | aliases: ['cancel'], |
| 1172 | helpString: ` | 1170 | helpString: ` |
| 1173 | <div> | 1171 | <div> |
| 1174 | Deletes all messages attributed to a specified name. | 1172 | ${t`Deletes all messages attributed to a specified name.`} |
| 1175 | </div> | 1173 | </div> |
| 1176 | <div> | 1174 | <div> |
| 1177 | <strong>Example:</strong> | 1175 | <strong>${t`Example:`}</strong> |
| 1178 | <ul> | 1176 | <ul> |
| 1179 | <li> | 1177 | <li> |
| 1180 | <pre><code>/delname John</code></pre> | 1178 | <pre><code>/delname John</code></pre> |
| @@ -1187,11 +1185,11 @@ export function initDefaultSlashCommands() { | |||
| 1187 | name: 'send', | 1185 | name: 'send', |
| 1188 | rawQuotes: true, | 1186 | rawQuotes: true, |
| 1189 | callback: sendUserMessageCallback, | 1187 | callback: sendUserMessageCallback, |
| 1190 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', | 1188 | returns: t`Optionally the text of the sent message, if specified in the "return" argument`, |
| 1191 | namedArgumentList: [ | 1189 | namedArgumentList: [ |
| 1192 | new SlashCommandNamedArgument( | 1190 | new SlashCommandNamedArgument( |
| 1193 | 'compact', | 1191 | 'compact', |
| 1194 | 'whether to use a compact layout', | 1192 | t`whether to use a compact layout`, |
| 1195 | [ARGUMENT_TYPE.BOOLEAN], | 1193 | [ARGUMENT_TYPE.BOOLEAN], |
| 1196 | false, | 1194 | false, |
| 1197 | false, | 1195 | false, |
| @@ -1199,20 +1197,20 @@ export function initDefaultSlashCommands() { | |||
| 1199 | ), | 1197 | ), |
| 1200 | SlashCommandNamedArgument.fromProps({ | 1198 | SlashCommandNamedArgument.fromProps({ |
| 1201 | name: 'at', | 1199 | name: 'at', |
| 1202 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 1200 | description: t`position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how 'depth' usually works. For example, -1 will insert the message right before the last message in chat.`, |
| 1203 | typeList: [ARGUMENT_TYPE.NUMBER], | 1201 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1204 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 1202 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 1205 | }), | 1203 | }), |
| 1206 | SlashCommandNamedArgument.fromProps({ | 1204 | SlashCommandNamedArgument.fromProps({ |
| 1207 | name: 'name', | 1205 | name: 'name', |
| 1208 | description: 'display name', | 1206 | description: t`display name`, |
| 1209 | typeList: [ARGUMENT_TYPE.STRING], | 1207 | typeList: [ARGUMENT_TYPE.STRING], |
| 1210 | defaultValue: '{{user}}', | 1208 | defaultValue: '{{user}}', |
| 1211 | enumProvider: commonEnumProviders.personas, | 1209 | enumProvider: commonEnumProviders.personas, |
| 1212 | }), | 1210 | }), |
| 1213 | SlashCommandNamedArgument.fromProps({ | 1211 | SlashCommandNamedArgument.fromProps({ |
| 1214 | name: 'return', | 1212 | name: 'return', |
| 1215 | description: 'The way how you want the return value to be provided', | 1213 | description: t`The way how you want the return value to be provided`, |
| 1216 | typeList: [ARGUMENT_TYPE.STRING], | 1214 | typeList: [ARGUMENT_TYPE.STRING], |
| 1217 | defaultValue: 'none', | 1215 | defaultValue: 'none', |
| 1218 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 1216 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| @@ -1220,7 +1218,7 @@ export function initDefaultSlashCommands() { | |||
| 1220 | }), | 1218 | }), |
| 1221 | SlashCommandNamedArgument.fromProps({ | 1219 | SlashCommandNamedArgument.fromProps({ |
| 1222 | name: 'raw', | 1220 | name: 'raw', |
| 1223 | description: 'If true, does not alter quoted literal unnamed arguments', | 1221 | description: t`If true, does not alter quoted literal unnamed arguments`, |
| 1224 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1222 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1225 | defaultValue: 'true', | 1223 | defaultValue: 'true', |
| 1226 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 1224 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| @@ -1236,16 +1234,16 @@ export function initDefaultSlashCommands() { | |||
| 1236 | ], | 1234 | ], |
| 1237 | helpString: ` | 1235 | helpString: ` |
| 1238 | <div> | 1236 | <div> |
| 1239 | Adds a user message to the chat log without triggering a generation. | 1237 | ${t`Adds a user message to the chat log without triggering a generation.`} |
| 1240 | </div> | 1238 | </div> |
| 1241 | <div> | 1239 | <div> |
| 1242 | If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout. | 1240 | ${t`If <code>compact</code> is set to <code>true</code>, the message is sent using a compact layout.`} |
| 1243 | </div> | 1241 | </div> |
| 1244 | <div> | 1242 | <div> |
| 1245 | If <code>name</code> is set, it will be displayed as the message sender. Can be an empty for no name. | 1243 | ${t`If <code>name</code> is set, it will be displayed as the message sender. Can be an empty for no name.`} |
| 1246 | </div> | 1244 | </div> |
| 1247 | <div> | 1245 | <div> |
| 1248 | <strong>Example:</strong> | 1246 | <strong>${t`Example:`}</strong> |
| 1249 | <ul> | 1247 | <ul> |
| 1250 | <li> | 1248 | <li> |
| 1251 | <pre><code>/send Hello there!</code></pre> | 1249 | <pre><code>/send Hello there!</code></pre> |
| @@ -1263,7 +1261,7 @@ export function initDefaultSlashCommands() { | |||
| 1263 | namedArgumentList: [ | 1261 | namedArgumentList: [ |
| 1264 | new SlashCommandNamedArgument( | 1262 | new SlashCommandNamedArgument( |
| 1265 | 'await', | 1263 | 'await', |
| 1266 | 'Whether to await for the triggered generation before continuing', | 1264 | t`Whether to await for the triggered generation before continuing`, |
| 1267 | [ARGUMENT_TYPE.BOOLEAN], | 1265 | [ARGUMENT_TYPE.BOOLEAN], |
| 1268 | false, | 1266 | false, |
| 1269 | false, | 1267 | false, |
| @@ -1272,7 +1270,7 @@ export function initDefaultSlashCommands() { | |||
| 1272 | ], | 1270 | ], |
| 1273 | unnamedArgumentList: [ | 1271 | unnamedArgumentList: [ |
| 1274 | SlashCommandArgument.fromProps({ | 1272 | SlashCommandArgument.fromProps({ |
| 1275 | description: 'group member index (starts with 0) or name', | 1273 | description: t`group member index (starts with 0) or name`, |
| 1276 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1274 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1277 | isRequired: false, | 1275 | isRequired: false, |
| 1278 | enumProvider: commonEnumProviders.groupMembers(), | 1276 | enumProvider: commonEnumProviders.groupMembers(), |
| @@ -1280,10 +1278,10 @@ export function initDefaultSlashCommands() { | |||
| 1280 | ], | 1278 | ], |
| 1281 | helpString: ` | 1279 | helpString: ` |
| 1282 | <div> | 1280 | <div> |
| 1283 | Triggers a message generation. If in group, can trigger a message for the specified group member index or name. | 1281 | ${t`Triggers a message generation. If in group, can trigger a message for the specified group member index or name.`} |
| 1284 | </div> | 1282 | </div> |
| 1285 | <div> | 1283 | <div> |
| 1286 | If <code>await=true</code> named argument is passed, the command will await for the triggered generation before continuing. | 1284 | ${t`If <code>await=true</code> named argument is passed, the command will await for the triggered generation before continuing.`} |
| 1287 | </div> | 1285 | </div> |
| 1288 | `, | 1286 | `, |
| 1289 | })); | 1287 | })); |
| @@ -1293,7 +1291,7 @@ export function initDefaultSlashCommands() { | |||
| 1293 | namedArgumentList: [ | 1291 | namedArgumentList: [ |
| 1294 | SlashCommandNamedArgument.fromProps({ | 1292 | SlashCommandNamedArgument.fromProps({ |
| 1295 | name: 'name', | 1293 | name: 'name', |
| 1296 | description: 'only hide messages from a certain character or persona', | 1294 | description: t`only hide messages from a certain character or persona`, |
| 1297 | typeList: [ARGUMENT_TYPE.STRING], | 1295 | typeList: [ARGUMENT_TYPE.STRING], |
| 1298 | enumProvider: commonEnumProviders.messageNames, | 1296 | enumProvider: commonEnumProviders.messageNames, |
| 1299 | isRequired: false, | 1297 | isRequired: false, |
| @@ -1302,13 +1300,13 @@ export function initDefaultSlashCommands() { | |||
| 1302 | ], | 1300 | ], |
| 1303 | unnamedArgumentList: [ | 1301 | unnamedArgumentList: [ |
| 1304 | SlashCommandArgument.fromProps({ | 1302 | SlashCommandArgument.fromProps({ |
| 1305 | description: 'message index (starts with 0) or range, defaults to the last message index if not provided', | 1303 | description: t`message index (starts with 0) or range, defaults to the last message index if not provided`, |
| 1306 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], | 1304 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], |
| 1307 | isRequired: false, | 1305 | isRequired: false, |
| 1308 | enumProvider: commonEnumProviders.messages(), | 1306 | enumProvider: commonEnumProviders.messages(), |
| 1309 | }), | 1307 | }), |
| 1310 | ], | 1308 | ], |
| 1311 | helpString: 'Hides a chat message from the prompt.', | 1309 | helpString: t`Hides a chat message from the prompt.`, |
| 1312 | })); | 1310 | })); |
| 1313 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1311 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1314 | name: 'unhide', | 1312 | name: 'unhide', |
| @@ -1316,7 +1314,7 @@ export function initDefaultSlashCommands() { | |||
| 1316 | namedArgumentList: [ | 1314 | namedArgumentList: [ |
| 1317 | SlashCommandNamedArgument.fromProps({ | 1315 | SlashCommandNamedArgument.fromProps({ |
| 1318 | name: 'name', | 1316 | name: 'name', |
| 1319 | description: 'only unhide messages from a certain character or persona', | 1317 | description: t`only unhide messages from a certain character or persona`, |
| 1320 | typeList: [ARGUMENT_TYPE.STRING], | 1318 | typeList: [ARGUMENT_TYPE.STRING], |
| 1321 | enumProvider: commonEnumProviders.messageNames, | 1319 | enumProvider: commonEnumProviders.messageNames, |
| 1322 | isRequired: false, | 1320 | isRequired: false, |
| @@ -1325,36 +1323,36 @@ export function initDefaultSlashCommands() { | |||
| 1325 | ], | 1323 | ], |
| 1326 | unnamedArgumentList: [ | 1324 | unnamedArgumentList: [ |
| 1327 | SlashCommandArgument.fromProps({ | 1325 | SlashCommandArgument.fromProps({ |
| 1328 | description: 'message index (starts with 0) or range, defaults to the last message index if not provided', | 1326 | description: t`message index (starts with 0) or range, defaults to the last message index if not provided`, |
| 1329 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], | 1327 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], |
| 1330 | isRequired: false, | 1328 | isRequired: false, |
| 1331 | enumProvider: commonEnumProviders.messages(), | 1329 | enumProvider: commonEnumProviders.messages(), |
| 1332 | }), | 1330 | }), |
| 1333 | ], | 1331 | ], |
| 1334 | helpString: 'Unhides a message from the prompt.', | 1332 | helpString: t`Unhides a message from the prompt.`, |
| 1335 | })); | 1333 | })); |
| 1336 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1334 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1337 | name: 'member-get', | 1335 | name: 'member-get', |
| 1338 | aliases: ['getmember', 'memberget'], | 1336 | aliases: ['getmember', 'memberget'], |
| 1339 | callback: (async ({ field = 'name' }, arg) => { | 1337 | callback: (async ({ field = 'name' }, arg) => { |
| 1340 | if (!selected_group) { | 1338 | if (!selected_group) { |
| 1341 | toastr.warning('Cannot run /member-get command outside of a group chat.'); | 1339 | toastr.warning(t`Cannot run /member-get command outside of a group chat.`); |
| 1342 | return ''; | 1340 | return ''; |
| 1343 | } | 1341 | } |
| 1344 | if (field === '') { | 1342 | if (field === '') { |
| 1345 | toastr.warning('\'/member-get field=\' argument required!'); | 1343 | toastr.warning(t`'/member-get field=' argument required!`); |
| 1346 | return ''; | 1344 | return ''; |
| 1347 | } | 1345 | } |
| 1348 | field = field.toString(); | 1346 | field = field.toString(); |
| 1349 | arg = arg.toString(); | 1347 | arg = arg.toString(); |
| 1350 | if (!['name', 'index', 'id', 'avatar'].includes(field)) { | 1348 | if (!['name', 'index', 'id', 'avatar'].includes(field)) { |
| 1351 | toastr.warning('\'/member-get field=\' argument required!'); | 1349 | toastr.warning(t`'/member-get field=' argument required!`); |
| 1352 | return ''; | 1350 | return ''; |
| 1353 | } | 1351 | } |
| 1354 | const isId = !isNaN(parseInt(arg)); | 1352 | const isId = !isNaN(parseInt(arg)); |
| 1355 | const groupMember = findGroupMemberId(arg, true); | 1353 | const groupMember = findGroupMemberId(arg, true); |
| 1356 | if (!groupMember) { | 1354 | if (!groupMember) { |
| 1357 | toastr.warning(`No group member found using ${isId ? 'id' : 'string'} ${arg}`); | 1355 | toastr.warning(t`No group member found using ${isId ? 'id' : 'string'} ${arg}`); |
| 1358 | return ''; | 1356 | return ''; |
| 1359 | } | 1357 | } |
| 1360 | return groupMember[field]; | 1358 | return groupMember[field]; |
| @@ -1362,27 +1360,27 @@ export function initDefaultSlashCommands() { | |||
| 1362 | namedArgumentList: [ | 1360 | namedArgumentList: [ |
| 1363 | SlashCommandNamedArgument.fromProps({ | 1361 | SlashCommandNamedArgument.fromProps({ |
| 1364 | name: 'field', | 1362 | name: 'field', |
| 1365 | description: 'Whether to retrieve the name, index, id, or avatar.', | 1363 | description: t`Whether to retrieve the name, index, id, or avatar.`, |
| 1366 | typeList: [ARGUMENT_TYPE.STRING], | 1364 | typeList: [ARGUMENT_TYPE.STRING], |
| 1367 | isRequired: true, | 1365 | isRequired: true, |
| 1368 | defaultValue: 'name', | 1366 | defaultValue: 'name', |
| 1369 | enumList: [ | 1367 | enumList: [ |
| 1370 | new SlashCommandEnumValue('name', 'Character name'), | 1368 | new SlashCommandEnumValue('name', t`Character name`), |
| 1371 | new SlashCommandEnumValue('index', 'Group member index'), | 1369 | new SlashCommandEnumValue('index', t`Group member index`), |
| 1372 | new SlashCommandEnumValue('avatar', 'Character avatar'), | 1370 | new SlashCommandEnumValue('avatar', t`Character avatar`), |
| 1373 | new SlashCommandEnumValue('id', 'Character index'), | 1371 | new SlashCommandEnumValue('id', t`Character index`), |
| 1374 | ], | 1372 | ], |
| 1375 | }), | 1373 | }), |
| 1376 | ], | 1374 | ], |
| 1377 | unnamedArgumentList: [ | 1375 | unnamedArgumentList: [ |
| 1378 | SlashCommandArgument.fromProps({ | 1376 | SlashCommandArgument.fromProps({ |
| 1379 | description: 'member index (starts with 0), name, or avatar', | 1377 | description: t`member index (starts with 0), name, or avatar`, |
| 1380 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1378 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1381 | isRequired: true, | 1379 | isRequired: true, |
| 1382 | enumProvider: commonEnumProviders.groupMembers(), | 1380 | enumProvider: commonEnumProviders.groupMembers(), |
| 1383 | }), | 1381 | }), |
| 1384 | ], | 1382 | ], |
| 1385 | helpString: 'Retrieves a group member\'s name, index, id, or avatar.', | 1383 | helpString: t`Retrieves a group member's name, index, id, or avatar.`, |
| 1386 | })); | 1384 | })); |
| 1387 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1385 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1388 | name: 'member-disable', | 1386 | name: 'member-disable', |
| @@ -1390,13 +1388,13 @@ export function initDefaultSlashCommands() { | |||
| 1390 | aliases: ['disable', 'disablemember', 'memberdisable'], | 1388 | aliases: ['disable', 'disablemember', 'memberdisable'], |
| 1391 | unnamedArgumentList: [ | 1389 | unnamedArgumentList: [ |
| 1392 | SlashCommandArgument.fromProps({ | 1390 | SlashCommandArgument.fromProps({ |
| 1393 | description: 'member index (starts with 0) or name', | 1391 | description: t`member index (starts with 0) or name`, |
| 1394 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1392 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1395 | isRequired: true, | 1393 | isRequired: true, |
| 1396 | enumProvider: commonEnumProviders.groupMembers(), | 1394 | enumProvider: commonEnumProviders.groupMembers(), |
| 1397 | }), | 1395 | }), |
| 1398 | ], | 1396 | ], |
| 1399 | helpString: 'Disables a group member from being drafted for replies.', | 1397 | helpString: t`Disables a group member from being drafted for replies.`, |
| 1400 | })); | 1398 | })); |
| 1401 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1399 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1402 | name: 'member-enable', | 1400 | name: 'member-enable', |
| @@ -1404,13 +1402,13 @@ export function initDefaultSlashCommands() { | |||
| 1404 | callback: enableGroupMemberCallback, | 1402 | callback: enableGroupMemberCallback, |
| 1405 | unnamedArgumentList: [ | 1403 | unnamedArgumentList: [ |
| 1406 | SlashCommandArgument.fromProps({ | 1404 | SlashCommandArgument.fromProps({ |
| 1407 | description: 'member index (starts with 0) or name', | 1405 | description: t`member index (starts with 0) or name`, |
| 1408 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1406 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1409 | isRequired: true, | 1407 | isRequired: true, |
| 1410 | enumProvider: commonEnumProviders.groupMembers(), | 1408 | enumProvider: commonEnumProviders.groupMembers(), |
| 1411 | }), | 1409 | }), |
| 1412 | ], | 1410 | ], |
| 1413 | helpString: 'Enables a group member to be drafted for replies.', | 1411 | helpString: t`Enables a group member to be drafted for replies.`, |
| 1414 | })); | 1412 | })); |
| 1415 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1413 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1416 | name: 'member-add', | 1414 | name: 'member-add', |
| @@ -1418,7 +1416,7 @@ export function initDefaultSlashCommands() { | |||
| 1418 | aliases: ['addmember', 'memberadd'], | 1416 | aliases: ['addmember', 'memberadd'], |
| 1419 | unnamedArgumentList: [ | 1417 | unnamedArgumentList: [ |
| 1420 | SlashCommandArgument.fromProps({ | 1418 | SlashCommandArgument.fromProps({ |
| 1421 | description: 'Character name - or unique character identifier (avatar key)', | 1419 | description: t`Character name - or unique character identifier (avatar key)`, |
| 1422 | typeList: [ARGUMENT_TYPE.STRING], | 1420 | typeList: [ARGUMENT_TYPE.STRING], |
| 1423 | isRequired: true, | 1421 | isRequired: true, |
| 1424 | enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [], | 1422 | enumProvider: () => selected_group ? commonEnumProviders.characters('character')() : [], |
| @@ -1426,10 +1424,10 @@ export function initDefaultSlashCommands() { | |||
| 1426 | ], | 1424 | ], |
| 1427 | helpString: ` | 1425 | helpString: ` |
| 1428 | <div> | 1426 | <div> |
| 1429 | Adds a new group member to the group chat. | 1427 | ${t`Adds a new group member to the group chat.`} |
| 1430 | </div> | 1428 | </div> |
| 1431 | <div> | 1429 | <div> |
| 1432 | <strong>Example:</strong> | 1430 | <strong>${t`Example:`}</strong> |
| 1433 | <ul> | 1431 | <ul> |
| 1434 | <li> | 1432 | <li> |
| 1435 | <pre><code>/member-add John Doe</code></pre> | 1433 | <pre><code>/member-add John Doe</code></pre> |
| @@ -1444,7 +1442,7 @@ export function initDefaultSlashCommands() { | |||
| 1444 | aliases: ['removemember', 'memberremove'], | 1442 | aliases: ['removemember', 'memberremove'], |
| 1445 | unnamedArgumentList: [ | 1443 | unnamedArgumentList: [ |
| 1446 | SlashCommandArgument.fromProps({ | 1444 | SlashCommandArgument.fromProps({ |
| 1447 | description: 'member index (starts with 0) or name', | 1445 | description: t`member index (starts with 0) or name`, |
| 1448 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1446 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1449 | isRequired: true, | 1447 | isRequired: true, |
| 1450 | enumProvider: commonEnumProviders.groupMembers(), | 1448 | enumProvider: commonEnumProviders.groupMembers(), |
| @@ -1452,10 +1450,10 @@ export function initDefaultSlashCommands() { | |||
| 1452 | ], | 1450 | ], |
| 1453 | helpString: ` | 1451 | helpString: ` |
| 1454 | <div> | 1452 | <div> |
| 1455 | Removes a group member from the group chat. | 1453 | ${t`Removes a group member from the group chat.`} |
| 1456 | </div> | 1454 | </div> |
| 1457 | <div> | 1455 | <div> |
| 1458 | <strong>Example:</strong> | 1456 | <strong>${t`Example:`}</strong> |
| 1459 | <ul> | 1457 | <ul> |
| 1460 | <li> | 1458 | <li> |
| 1461 | <pre><code>/member-remove 2</code></pre> | 1459 | <pre><code>/member-remove 2</code></pre> |
| @@ -1471,13 +1469,13 @@ export function initDefaultSlashCommands() { | |||
| 1471 | aliases: ['upmember', 'memberup'], | 1469 | aliases: ['upmember', 'memberup'], |
| 1472 | unnamedArgumentList: [ | 1470 | unnamedArgumentList: [ |
| 1473 | SlashCommandArgument.fromProps({ | 1471 | SlashCommandArgument.fromProps({ |
| 1474 | description: 'member index (starts with 0) or name', | 1472 | description: t`member index (starts with 0) or name`, |
| 1475 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1473 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1476 | isRequired: true, | 1474 | isRequired: true, |
| 1477 | enumProvider: commonEnumProviders.groupMembers(), | 1475 | enumProvider: commonEnumProviders.groupMembers(), |
| 1478 | }), | 1476 | }), |
| 1479 | ], | 1477 | ], |
| 1480 | helpString: 'Moves a group member up in the group chat list.', | 1478 | helpString: t`Moves a group member up in the group chat list.`, |
| 1481 | })); | 1479 | })); |
| 1482 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1480 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1483 | name: 'member-down', | 1481 | name: 'member-down', |
| @@ -1485,13 +1483,13 @@ export function initDefaultSlashCommands() { | |||
| 1485 | aliases: ['downmember', 'memberdown'], | 1483 | aliases: ['downmember', 'memberdown'], |
| 1486 | unnamedArgumentList: [ | 1484 | unnamedArgumentList: [ |
| 1487 | SlashCommandArgument.fromProps({ | 1485 | SlashCommandArgument.fromProps({ |
| 1488 | description: 'member index (starts with 0) or name', | 1486 | description: t`member index (starts with 0) or name`, |
| 1489 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1487 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1490 | isRequired: true, | 1488 | isRequired: true, |
| 1491 | enumProvider: commonEnumProviders.groupMembers(), | 1489 | enumProvider: commonEnumProviders.groupMembers(), |
| 1492 | }), | 1490 | }), |
| 1493 | ], | 1491 | ], |
| 1494 | helpString: 'Moves a group member down in the group chat list.', | 1492 | helpString: t`Moves a group member down in the group chat list.`, |
| 1495 | })); | 1493 | })); |
| 1496 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1494 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1497 | name: 'member-peek', | 1495 | name: 'member-peek', |
| @@ -1499,7 +1497,7 @@ export function initDefaultSlashCommands() { | |||
| 1499 | callback: peekCallback, | 1497 | callback: peekCallback, |
| 1500 | unnamedArgumentList: [ | 1498 | unnamedArgumentList: [ |
| 1501 | SlashCommandArgument.fromProps({ | 1499 | SlashCommandArgument.fromProps({ |
| 1502 | description: 'member index (starts with 0) or name', | 1500 | description: t`member index (starts with 0) or name`, |
| 1503 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], | 1501 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.STRING], |
| 1504 | isRequired: true, | 1502 | isRequired: true, |
| 1505 | enumProvider: commonEnumProviders.groupMembers(), | 1503 | enumProvider: commonEnumProviders.groupMembers(), |
| @@ -1507,14 +1505,14 @@ export function initDefaultSlashCommands() { | |||
| 1507 | ], | 1505 | ], |
| 1508 | helpString: ` | 1506 | helpString: ` |
| 1509 | <div> | 1507 | <div> |
| 1510 | Shows a group member character card without switching chats. | 1508 | ${t`Shows a group member character card without switching chats.`} |
| 1511 | </div> | 1509 | </div> |
| 1512 | <div> | 1510 | <div> |
| 1513 | <strong>Examples:</strong> | 1511 | <strong>${t`Examples:`}</strong> |
| 1514 | <ul> | 1512 | <ul> |
| 1515 | <li> | 1513 | <li> |
| 1516 | <pre><code>/peek Gloria</code></pre> | 1514 | <pre><code>/peek Gloria</code></pre> |
| 1517 | Shows the character card for the character named "Gloria". | 1515 | ${t`Shows the character card for the character named "Gloria".`} |
| 1518 | </li> | 1516 | </li> |
| 1519 | </ul> | 1517 | </ul> |
| 1520 | </div> | 1518 | </div> |
| @@ -1524,16 +1522,16 @@ export function initDefaultSlashCommands() { | |||
| 1524 | name: 'member-count', | 1522 | name: 'member-count', |
| 1525 | callback: countGroupMemberCallback, | 1523 | callback: countGroupMemberCallback, |
| 1526 | aliases: ['countmember', 'membercount'], | 1524 | aliases: ['countmember', 'membercount'], |
| 1527 | helpString: 'Returns the total number of group members in the group chat list.', | 1525 | helpString: t`Returns the total number of group members in the group chat list.`, |
| 1528 | })); | 1526 | })); |
| 1529 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1527 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1530 | name: 'delswipe', | 1528 | name: 'delswipe', |
| 1531 | callback: deleteSwipeCallback, | 1529 | callback: deleteSwipeCallback, |
| 1532 | returns: 'the new, currently selected swipe id', | 1530 | returns: t`the new, currently selected swipe id`, |
| 1533 | aliases: ['swipedel'], | 1531 | aliases: ['swipedel'], |
| 1534 | unnamedArgumentList: [ | 1532 | unnamedArgumentList: [ |
| 1535 | SlashCommandArgument.fromProps({ | 1533 | SlashCommandArgument.fromProps({ |
| 1536 | description: '1-based swipe id', | 1534 | description: t`1-based swipe id`, |
| 1537 | typeList: [ARGUMENT_TYPE.NUMBER], | 1535 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1538 | isRequired: true, | 1536 | isRequired: true, |
| 1539 | enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ? | 1537 | enumProvider: () => Array.isArray(chat[chat.length - 1]?.swipes) ? |
| @@ -1543,18 +1541,18 @@ export function initDefaultSlashCommands() { | |||
| 1543 | ], | 1541 | ], |
| 1544 | helpString: ` | 1542 | helpString: ` |
| 1545 | <div> | 1543 | <div> |
| 1546 | Deletes a swipe from the last chat message. If swipe id is not provided, it deletes the current swipe. | 1544 | ${t`Deletes a swipe from the last chat message. If swipe id is not provided, it deletes the current swipe.`} |
| 1547 | </div> | 1545 | </div> |
| 1548 | <div> | 1546 | <div> |
| 1549 | <strong>Example:</strong> | 1547 | <strong>${t`Example:`}</strong> |
| 1550 | <ul> | 1548 | <ul> |
| 1551 | <li> | 1549 | <li> |
| 1552 | <pre><code>/delswipe</code></pre> | 1550 | <pre><code>/delswipe</code></pre> |
| 1553 | Deletes the current swipe. | 1551 | ${t`Deletes the current swipe.`} |
| 1554 | </li> | 1552 | </li> |
| 1555 | <li> | 1553 | <li> |
| 1556 | <pre><code>/delswipe 2</code></pre> | 1554 | <pre><code>/delswipe 2</code></pre> |
| 1557 | Deletes the second swipe from the last chat message. | 1555 | ${t`Deletes the second swipe from the last chat message.`} |
| 1558 | </li> | 1556 | </li> |
| 1559 | </ul> | 1557 | </ul> |
| 1560 | </div> | 1558 | </div> |
| @@ -1564,14 +1562,14 @@ export function initDefaultSlashCommands() { | |||
| 1564 | name: 'echo', | 1562 | name: 'echo', |
| 1565 | rawQuotes: true, | 1563 | rawQuotes: true, |
| 1566 | callback: echoCallback, | 1564 | callback: echoCallback, |
| 1567 | returns: 'the text', | 1565 | returns: t`the text`, |
| 1568 | namedArgumentList: [ | 1566 | namedArgumentList: [ |
| 1569 | new SlashCommandNamedArgument( | 1567 | new SlashCommandNamedArgument( |
| 1570 | 'title', 'title of the toast message', [ARGUMENT_TYPE.STRING], false, | 1568 | 'title', t`title of the toast message`, [ARGUMENT_TYPE.STRING], false, |
| 1571 | ), | 1569 | ), |
| 1572 | SlashCommandNamedArgument.fromProps({ | 1570 | SlashCommandNamedArgument.fromProps({ |
| 1573 | name: 'severity', | 1571 | name: 'severity', |
| 1574 | description: 'severity level of the toast message', | 1572 | description: t`severity level of the toast message`, |
| 1575 | typeList: [ARGUMENT_TYPE.STRING], | 1573 | typeList: [ARGUMENT_TYPE.STRING], |
| 1576 | defaultValue: 'info', | 1574 | defaultValue: 'info', |
| 1577 | enumProvider: () => [ | 1575 | enumProvider: () => [ |
| @@ -1583,54 +1581,54 @@ export function initDefaultSlashCommands() { | |||
| 1583 | }), | 1581 | }), |
| 1584 | SlashCommandNamedArgument.fromProps({ | 1582 | SlashCommandNamedArgument.fromProps({ |
| 1585 | name: 'timeout', | 1583 | name: 'timeout', |
| 1586 | description: 'time in milliseconds to display the toast message. Set this and \'extendedTimeout\' to 0 to show indefinitely until dismissed.', | 1584 | description: t`time in milliseconds to display the toast message. Set this and 'extendedTimeout' to 0 to show indefinitely until dismissed.`, |
| 1587 | typeList: [ARGUMENT_TYPE.NUMBER], | 1585 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1588 | defaultValue: `${toastr.options.timeOut}`, | 1586 | defaultValue: `${toastr.options.timeOut}`, |
| 1589 | }), | 1587 | }), |
| 1590 | SlashCommandNamedArgument.fromProps({ | 1588 | SlashCommandNamedArgument.fromProps({ |
| 1591 | name: 'extendedTimeout', | 1589 | name: 'extendedTimeout', |
| 1592 | description: 'time in milliseconds to display the toast message. Set this and \'timeout\' to 0 to show indefinitely until dismissed.', | 1590 | description: t`time in milliseconds to display the toast message. Set this and 'timeout' to 0 to show indefinitely until dismissed.`, |
| 1593 | typeList: [ARGUMENT_TYPE.NUMBER], | 1591 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1594 | defaultValue: `${toastr.options.extendedTimeOut}`, | 1592 | defaultValue: `${toastr.options.extendedTimeOut}`, |
| 1595 | }), | 1593 | }), |
| 1596 | SlashCommandNamedArgument.fromProps({ | 1594 | SlashCommandNamedArgument.fromProps({ |
| 1597 | name: 'preventDuplicates', | 1595 | name: 'preventDuplicates', |
| 1598 | description: 'prevent duplicate toasts with the same message from being displayed.', | 1596 | description: t`prevent duplicate toasts with the same message from being displayed.`, |
| 1599 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1597 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1600 | defaultValue: 'false', | 1598 | defaultValue: 'false', |
| 1601 | enumList: commonEnumProviders.boolean('trueFalse')(), | 1599 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1602 | }), | 1600 | }), |
| 1603 | SlashCommandNamedArgument.fromProps({ | 1601 | SlashCommandNamedArgument.fromProps({ |
| 1604 | name: 'awaitDismissal', | 1602 | name: 'awaitDismissal', |
| 1605 | description: 'wait for the toast to be dismissed before continuing.', | 1603 | description: t`wait for the toast to be dismissed before continuing.`, |
| 1606 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1604 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1607 | defaultValue: 'false', | 1605 | defaultValue: 'false', |
| 1608 | enumList: commonEnumProviders.boolean('trueFalse')(), | 1606 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1609 | }), | 1607 | }), |
| 1610 | SlashCommandNamedArgument.fromProps({ | 1608 | SlashCommandNamedArgument.fromProps({ |
| 1611 | name: 'cssClass', | 1609 | name: 'cssClass', |
| 1612 | description: 'additional CSS class to add to the toast message (e.g. for custom styling)', | 1610 | description: t`additional CSS class to add to the toast message (e.g. for custom styling)`, |
| 1613 | typeList: [ARGUMENT_TYPE.STRING], | 1611 | typeList: [ARGUMENT_TYPE.STRING], |
| 1614 | }), | 1612 | }), |
| 1615 | SlashCommandNamedArgument.fromProps({ | 1613 | SlashCommandNamedArgument.fromProps({ |
| 1616 | name: 'color', | 1614 | name: 'color', |
| 1617 | description: 'custom CSS color of the toast message. Accepts all valid CSS color values (e.g. \'red\', \'#FF0000\', \'rgb(255, 0, 0)\').<br />>Can be more customizable with the \'cssClass\' argument and custom classes.', | 1615 | description: t`custom CSS color of the toast message. Accepts all valid CSS color values (e.g. 'red', '#FF0000', 'rgb(255, 0, 0)').<br />>Can be more customizable with the 'cssClass' argument and custom classes.`, |
| 1618 | }), | 1616 | }), |
| 1619 | SlashCommandNamedArgument.fromProps({ | 1617 | SlashCommandNamedArgument.fromProps({ |
| 1620 | name: 'escapeHtml', | 1618 | name: 'escapeHtml', |
| 1621 | description: 'whether to escape HTML in the toast message.', | 1619 | description: t`whether to escape HTML in the toast message.`, |
| 1622 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1620 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1623 | defaultValue: 'true', | 1621 | defaultValue: 'true', |
| 1624 | enumList: commonEnumProviders.boolean('trueFalse')(), | 1622 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 1625 | }), | 1623 | }), |
| 1626 | SlashCommandNamedArgument.fromProps({ | 1624 | SlashCommandNamedArgument.fromProps({ |
| 1627 | name: 'onClick', | 1625 | name: 'onClick', |
| 1628 | description: 'a closure to call when the toast is clicked. This executed closure receives scope as provided in the script. Careful about possible side effects when manipulating variables and more.', | 1626 | description: t`a closure to call when the toast is clicked. This executed closure receives scope as provided in the script. Careful about possible side effects when manipulating variables and more.`, |
| 1629 | typeList: [ARGUMENT_TYPE.CLOSURE], | 1627 | typeList: [ARGUMENT_TYPE.CLOSURE], |
| 1630 | }), | 1628 | }), |
| 1631 | SlashCommandNamedArgument.fromProps({ | 1629 | SlashCommandNamedArgument.fromProps({ |
| 1632 | name: 'raw', | 1630 | name: 'raw', |
| 1633 | description: 'If true, does not alter quoted literal unnamed arguments', | 1631 | description: t`If true, does not alter quoted literal unnamed arguments`, |
| 1634 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1632 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1635 | defaultValue: 'true', | 1633 | defaultValue: 'true', |
| 1636 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 1634 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| @@ -1665,32 +1663,32 @@ export function initDefaultSlashCommands() { | |||
| 1665 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1663 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1666 | name: 'gen', | 1664 | name: 'gen', |
| 1667 | callback: generateCallback, | 1665 | callback: generateCallback, |
| 1668 | returns: 'generated text', | 1666 | returns: t`generated text`, |
| 1669 | namedArgumentList: [ | 1667 | namedArgumentList: [ |
| 1670 | SlashCommandNamedArgument.fromProps({ | 1668 | SlashCommandNamedArgument.fromProps({ |
| 1671 | name: 'trim', | 1669 | name: 'trim', |
| 1672 | description: 'Trim the output by the last sentence boundary', | 1670 | description: t`Trim the output by the last sentence boundary`, |
| 1673 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1671 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1674 | defaultValue: 'false', | 1672 | defaultValue: 'false', |
| 1675 | isRequired: false, | 1673 | isRequired: false, |
| 1676 | enumProvider: commonEnumProviders.boolean('trueFalse'), | 1674 | enumProvider: commonEnumProviders.boolean('trueFalse'), |
| 1677 | }), | 1675 | }), |
| 1678 | new SlashCommandNamedArgument( | 1676 | new SlashCommandNamedArgument( |
| 1679 | 'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(), | 1677 | 'lock', t`lock user input during generation`, [ARGUMENT_TYPE.BOOLEAN], false, false, null, commonEnumProviders.boolean('onOff')(), |
| 1680 | ), | 1678 | ), |
| 1681 | SlashCommandNamedArgument.fromProps({ | 1679 | SlashCommandNamedArgument.fromProps({ |
| 1682 | name: 'name', | 1680 | name: 'name', |
| 1683 | description: 'in-prompt character name for instruct mode (or unique character identifier (avatar key), which will be used as name)', | 1681 | description: t`in-prompt character name for instruct mode (or unique character identifier (avatar key), which will be used as name)`, |
| 1684 | typeList: [ARGUMENT_TYPE.STRING], | 1682 | typeList: [ARGUMENT_TYPE.STRING], |
| 1685 | defaultValue: 'System', | 1683 | defaultValue: 'System', |
| 1686 | enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)], | 1684 | enumProvider: () => [...commonEnumProviders.characters('character')(), new SlashCommandEnumValue('System', null, enumTypes.enum, enumIcons.assistant)], |
| 1687 | }), | 1685 | }), |
| 1688 | new SlashCommandNamedArgument( | 1686 | new SlashCommandNamedArgument( |
| 1689 | 'length', 'API response length in tokens', [ARGUMENT_TYPE.NUMBER], false, | 1687 | 'length', t`API response length in tokens`, [ARGUMENT_TYPE.NUMBER], false, |
| 1690 | ), | 1688 | ), |
| 1691 | SlashCommandNamedArgument.fromProps({ | 1689 | SlashCommandNamedArgument.fromProps({ |
| 1692 | name: 'as', | 1690 | name: 'as', |
| 1693 | description: 'role of the output prompt', | 1691 | description: t`role of the output prompt`, |
| 1694 | typeList: [ARGUMENT_TYPE.STRING], | 1692 | typeList: [ARGUMENT_TYPE.STRING], |
| 1695 | enumList: [ | 1693 | enumList: [ |
| 1696 | new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant), | 1694 | new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.assistant), |
| @@ -1705,30 +1703,30 @@ export function initDefaultSlashCommands() { | |||
| 1705 | ], | 1703 | ], |
| 1706 | helpString: ` | 1704 | helpString: ` |
| 1707 | <div> | 1705 | <div> |
| 1708 | Generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating and allowing to configure the in-prompt name for instruct mode (default = "System"). | 1706 | ${t`Generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating and allowing to configure the in-prompt name for instruct mode (default = "System").`} |
| 1709 | </div> | 1707 | </div> |
| 1710 | <div> | 1708 | <div> |
| 1711 | "as" argument controls the role of the output prompt: system (default) or char. If "length" argument is provided as a number in tokens, allows to temporarily override an API response length. | 1709 | ${t`"as" argument controls the role of the output prompt: system (default) or char. If "length" argument is provided as a number in tokens, allows to temporarily override an API response length.`} |
| 1712 | </div> | 1710 | </div> |
| 1713 | `, | 1711 | `, |
| 1714 | })); | 1712 | })); |
| 1715 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1713 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1716 | name: 'genraw', | 1714 | name: 'genraw', |
| 1717 | callback: generateRawCallback, | 1715 | callback: generateRawCallback, |
| 1718 | returns: 'generated text', | 1716 | returns: t`generated text`, |
| 1719 | namedArgumentList: [ | 1717 | namedArgumentList: [ |
| 1720 | new SlashCommandNamedArgument( | 1718 | new SlashCommandNamedArgument( |
| 1721 | 'lock', 'lock user input during generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(), | 1719 | 'lock', t`lock user input during generation`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(), |
| 1722 | ), | 1720 | ), |
| 1723 | new SlashCommandNamedArgument( | 1721 | new SlashCommandNamedArgument( |
| 1724 | 'instruct', 'use instruct mode', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(), | 1722 | 'instruct', t`use instruct mode`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(), |
| 1725 | ), | 1723 | ), |
| 1726 | new SlashCommandNamedArgument( | 1724 | new SlashCommandNamedArgument( |
| 1727 | 'stop', 'one-time custom stop strings', [ARGUMENT_TYPE.LIST], false, false, '[]', | 1725 | 'stop', t`one-time custom stop strings`, [ARGUMENT_TYPE.LIST], false, false, '[]', |
| 1728 | ), | 1726 | ), |
| 1729 | SlashCommandNamedArgument.fromProps({ | 1727 | SlashCommandNamedArgument.fromProps({ |
| 1730 | name: 'as', | 1728 | name: 'as', |
| 1731 | description: 'role of the output prompt', | 1729 | description: t`role of the output prompt`, |
| 1732 | defaultValue: 'system', | 1730 | defaultValue: 'system', |
| 1733 | typeList: [ARGUMENT_TYPE.STRING], | 1731 | typeList: [ARGUMENT_TYPE.STRING], |
| 1734 | enumList: [ | 1732 | enumList: [ |
| @@ -1737,16 +1735,16 @@ export function initDefaultSlashCommands() { | |||
| 1737 | ], | 1735 | ], |
| 1738 | }), | 1736 | }), |
| 1739 | new SlashCommandNamedArgument( | 1737 | new SlashCommandNamedArgument( |
| 1740 | 'system', 'system prompt at the start', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, | 1738 | 'system', t`system prompt at the start`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, |
| 1741 | ), | 1739 | ), |
| 1742 | new SlashCommandNamedArgument( | 1740 | new SlashCommandNamedArgument( |
| 1743 | 'prefill', 'prefill prompt at the end', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, | 1741 | 'prefill', t`prefill prompt at the end`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.VARIABLE_NAME], false, |
| 1744 | ), | 1742 | ), |
| 1745 | new SlashCommandNamedArgument( | 1743 | new SlashCommandNamedArgument( |
| 1746 | 'length', 'API response length in tokens', [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], false, | 1744 | 'length', t`API response length in tokens`, [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], false, |
| 1747 | ), | 1745 | ), |
| 1748 | new SlashCommandNamedArgument( | 1746 | new SlashCommandNamedArgument( |
| 1749 | 'trim', 'trim {{user}} and {{char}} prefixes from the output', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(), | 1747 | 'trim', t`trim {{user}} and {{char}} prefixes from the output`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(), |
| 1750 | ), | 1748 | ), |
| 1751 | ], | 1749 | ], |
| 1752 | unnamedArgumentList: [ | 1750 | unnamedArgumentList: [ |
| @@ -1756,31 +1754,31 @@ export function initDefaultSlashCommands() { | |||
| 1756 | ], | 1754 | ], |
| 1757 | helpString: ` | 1755 | helpString: ` |
| 1758 | <div> | 1756 | <div> |
| 1759 | Generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating. Does not include chat history or character card. | 1757 | ${t`Generates text using the provided prompt and passes it to the next command through the pipe, optionally locking user input while generating. Does not include chat history or character card.`} |
| 1760 | </div> | 1758 | </div> |
| 1761 | <div> | 1759 | <div> |
| 1762 | Use instruct=off to skip instruct formatting, e.g. <pre><code>/genraw instruct=off Why is the sky blue?</code></pre> | 1760 | ${t`Use instruct=off to skip instruct formatting, e.g. <pre><code>/genraw instruct=off Why is the sky blue?</code></pre>`} |
| 1763 | </div> | 1761 | </div> |
| 1764 | <div> | 1762 | <div> |
| 1765 | Use stop=... with a JSON-serialized array to add one-time custom stop strings, e.g. <pre><code>/genraw stop=["\\n"] Say hi</code></pre> | 1763 | ${t`Use stop=... with a JSON-serialized array to add one-time custom stop strings, e.g. <pre><code>/genraw stop=["\\n"] Say hi</code></pre>`} |
| 1766 | </div> | 1764 | </div> |
| 1767 | <div> | 1765 | <div> |
| 1768 | "as" argument controls the role of the output prompt: system (default) or char. "system" argument adds an (optional) system prompt at the start. | 1766 | ${t`"as" argument controls the role of the output prompt: system (default) or char. "system" argument adds an (optional) system prompt at the start.`} |
| 1769 | </div> | 1767 | </div> |
| 1770 | <div> | 1768 | <div> |
| 1771 | If "length" argument is provided as a number in tokens, allows to temporarily override an API response length. | 1769 | ${t`If "length" argument is provided as a number in tokens, allows to temporarily override an API response length.`} |
| 1772 | </div> | 1770 | </div> |
| 1773 | `, | 1771 | `, |
| 1774 | })); | 1772 | })); |
| 1775 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1773 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1776 | name: 'addswipe', | 1774 | name: 'addswipe', |
| 1777 | callback: addSwipeCallback, | 1775 | callback: addSwipeCallback, |
| 1778 | returns: 'the new swipe id', | 1776 | returns: t`the new swipe id`, |
| 1779 | aliases: ['swipeadd'], | 1777 | aliases: ['swipeadd'], |
| 1780 | namedArgumentList: [ | 1778 | namedArgumentList: [ |
| 1781 | SlashCommandNamedArgument.fromProps({ | 1779 | SlashCommandNamedArgument.fromProps({ |
| 1782 | name: 'switch', | 1780 | name: 'switch', |
| 1783 | description: 'switch to the new swipe', | 1781 | description: t`switch to the new swipe`, |
| 1784 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1782 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1785 | enumList: commonEnumProviders.boolean()(), | 1783 | enumList: commonEnumProviders.boolean()(), |
| 1786 | }), | 1784 | }), |
| @@ -1792,10 +1790,10 @@ export function initDefaultSlashCommands() { | |||
| 1792 | ], | 1790 | ], |
| 1793 | helpString: ` | 1791 | helpString: ` |
| 1794 | <div> | 1792 | <div> |
| 1795 | Adds a swipe to the last chat message. | 1793 | ${t`Adds a swipe to the last chat message.`} |
| 1796 | </div> | 1794 | </div> |
| 1797 | <div> | 1795 | <div> |
| 1798 | Use switch=true to switch to directly switch to the new swipe. | 1796 | ${t`Use switch=true to switch to directly switch to the new swipe.`} |
| 1799 | </div>`, | 1797 | </div>`, |
| 1800 | })); | 1798 | })); |
| 1801 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1799 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| @@ -1804,14 +1802,13 @@ export function initDefaultSlashCommands() { | |||
| 1804 | const stopped = stopGeneration(); | 1802 | const stopped = stopGeneration(); |
| 1805 | return String(stopped); | 1803 | return String(stopped); |
| 1806 | }, | 1804 | }, |
| 1807 | returns: 'true/false, whether the generation was running and got stopped', | 1805 | returns: t`true/false, whether the generation was running and got stopped`, |
| 1808 | helpString: ` | 1806 | helpString: ` |
| 1809 | <div> | 1807 | <div> |
| 1810 | Stops the generation and any streaming if it is currently running. | 1808 | ${t`Stops the generation and any streaming if it is currently running.`} |
| 1811 | </div> | 1809 | </div> |
| 1812 | <div> | 1810 | <div> |
| 1813 | Note: This command cannot be executed from the chat input, as sending any message or script from there is blocked during generation. | 1811 | ${t`Note: This command cannot be executed from the chat input, as sending any message or script from there is blocked during generation. But it can be executed via automations or QR scripts/buttons.`} |
| 1814 | But it can be executed via automations or QR scripts/buttons. | ||
| 1815 | </div> | 1812 | </div> |
| 1816 | `, | 1813 | `, |
| 1817 | aliases: ['generate-stop'], | 1814 | aliases: ['generate-stop'], |
| @@ -1822,27 +1819,27 @@ export function initDefaultSlashCommands() { | |||
| 1822 | namedArgumentList: [ | 1819 | namedArgumentList: [ |
| 1823 | SlashCommandNamedArgument.fromProps({ | 1820 | SlashCommandNamedArgument.fromProps({ |
| 1824 | name: 'quiet', | 1821 | name: 'quiet', |
| 1825 | description: 'Whether to suppress the toast message notifying about the /abort call.', | 1822 | description: t`Whether to suppress the toast message notifying about the /abort call.`, |
| 1826 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1823 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1827 | defaultValue: 'true', | 1824 | defaultValue: 'true', |
| 1828 | }), | 1825 | }), |
| 1829 | ], | 1826 | ], |
| 1830 | unnamedArgumentList: [ | 1827 | unnamedArgumentList: [ |
| 1831 | SlashCommandArgument.fromProps({ | 1828 | SlashCommandArgument.fromProps({ |
| 1832 | description: 'The reason for aborting command execution. Shown when quiet=false', | 1829 | description: t`The reason for aborting command execution. Shown when quiet=false`, |
| 1833 | typeList: [ARGUMENT_TYPE.STRING], | 1830 | typeList: [ARGUMENT_TYPE.STRING], |
| 1834 | }), | 1831 | }), |
| 1835 | ], | 1832 | ], |
| 1836 | helpString: 'Aborts the slash command batch execution.', | 1833 | helpString: t`Aborts the slash command batch execution.`, |
| 1837 | })); | 1834 | })); |
| 1838 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1835 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1839 | name: 'fuzzy', | 1836 | name: 'fuzzy', |
| 1840 | callback: fuzzyCallback, | 1837 | callback: fuzzyCallback, |
| 1841 | returns: 'matching item', | 1838 | returns: t`matching item`, |
| 1842 | namedArgumentList: [ | 1839 | namedArgumentList: [ |
| 1843 | SlashCommandNamedArgument.fromProps({ | 1840 | SlashCommandNamedArgument.fromProps({ |
| 1844 | name: 'list', | 1841 | name: 'list', |
| 1845 | description: 'list of items to match against', | 1842 | description: t`list of items to match against`, |
| 1846 | acceptsMultiple: false, | 1843 | acceptsMultiple: false, |
| 1847 | isRequired: true, | 1844 | isRequired: true, |
| 1848 | typeList: [ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.VARIABLE_NAME], | 1845 | typeList: [ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.VARIABLE_NAME], |
| @@ -1850,7 +1847,7 @@ export function initDefaultSlashCommands() { | |||
| 1850 | }), | 1847 | }), |
| 1851 | SlashCommandNamedArgument.fromProps({ | 1848 | SlashCommandNamedArgument.fromProps({ |
| 1852 | name: 'threshold', | 1849 | name: 'threshold', |
| 1853 | description: 'fuzzy match threshold (0.0 to 1.0)', | 1850 | description: t`fuzzy match threshold (0.0 to 1.0)`, |
| 1854 | typeList: [ARGUMENT_TYPE.NUMBER], | 1851 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1855 | isRequired: false, | 1852 | isRequired: false, |
| 1856 | defaultValue: '0.4', | 1853 | defaultValue: '0.4', |
| @@ -1858,44 +1855,43 @@ export function initDefaultSlashCommands() { | |||
| 1858 | }), | 1855 | }), |
| 1859 | SlashCommandNamedArgument.fromProps({ | 1856 | SlashCommandNamedArgument.fromProps({ |
| 1860 | name: 'mode', | 1857 | name: 'mode', |
| 1861 | description: 'fuzzy match mode', | 1858 | description: t`fuzzy match mode`, |
| 1862 | typeList: [ARGUMENT_TYPE.STRING], | 1859 | typeList: [ARGUMENT_TYPE.STRING], |
| 1863 | isRequired: false, | 1860 | isRequired: false, |
| 1864 | defaultValue: 'first', | 1861 | defaultValue: 'first', |
| 1865 | acceptsMultiple: false, | 1862 | acceptsMultiple: false, |
| 1866 | enumList: [ | 1863 | enumList: [ |
| 1867 | new SlashCommandEnumValue('first', 'first match below the threshold', enumTypes.enum, enumIcons.default), | 1864 | new SlashCommandEnumValue('first', t`first match below the threshold`, enumTypes.enum, enumIcons.default), |
| 1868 | new SlashCommandEnumValue('best', 'best match below the threshold', enumTypes.enum, enumIcons.default), | 1865 | new SlashCommandEnumValue('best', t`best match below the threshold`, enumTypes.enum, enumIcons.default), |
| 1869 | ], | 1866 | ], |
| 1870 | }), | 1867 | }), |
| 1871 | ], | 1868 | ], |
| 1872 | unnamedArgumentList: [ | 1869 | unnamedArgumentList: [ |
| 1873 | new SlashCommandArgument( | 1870 | new SlashCommandArgument( |
| 1874 | 'text to search', [ARGUMENT_TYPE.STRING], true, | 1871 | t`text to search`, [ARGUMENT_TYPE.STRING], true, |
| 1875 | ), | 1872 | ), |
| 1876 | ], | 1873 | ], |
| 1877 | helpString: ` | 1874 | helpString: ` |
| 1878 | <div> | 1875 | <div> |
| 1879 | Performs a fuzzy match of each item in the <code>list</code> against the <code>text to search</code>. | 1876 | ${t`Performs a fuzzy match of each item in the <code>list</code> against the <code>text to search</code>. If any item matches, then its name is returned. If no item matches the text, no value is returned.`} |
| 1880 | If any item matches, then its name is returned. If no item matches the text, no value is returned. | ||
| 1881 | </div> | 1877 | </div> |
| 1882 | <div> | 1878 | <div> |
| 1883 | The optional <code>threshold</code> (default is 0.4) allows control over the match strictness. | 1879 | ${t`The optional <code>threshold</code> (default is 0.4) allows control over the match strictness.`} |
| 1884 | A low value (min 0.0) means the match is very strict. | 1880 | ${t`A low value (min 0.0) means the match is very strict.`} |
| 1885 | At 1.0 (max) the match is very loose and will match anything. | 1881 | ${t`At 1.0 (max) the match is very loose and will match anything.`} |
| 1886 | </div> | 1882 | </div> |
| 1887 | <div> | 1883 | <div> |
| 1888 | The optional <code>mode</code> argument allows to control the behavior when multiple items match the text. | 1884 | ${t`The optional <code>mode</code> argument allows to control the behavior when multiple items match the text.`} |
| 1889 | <ul> | 1885 | <ul> |
| 1890 | <li><code>first</code> (default) returns the first match below the threshold.</li> | 1886 | <li>${t`<code>first</code> (default) returns the first match below the threshold.`}</li> |
| 1891 | <li><code>best</code> returns the best match below the threshold.</li> | 1887 | <li>${t`<code>best</code> returns the best match below the threshold.`}</li> |
| 1892 | </ul> | 1888 | </ul> |
| 1893 | </div> | 1889 | </div> |
| 1894 | <div> | 1890 | <div> |
| 1895 | The returned value passes to the next command through the pipe. | 1891 | ${t`The returned value passes to the next command through the pipe.`} |
| 1896 | </div> | 1892 | </div> |
| 1897 | <div> | 1893 | <div> |
| 1898 | <strong>Example:</strong> | 1894 | <strong>${t`Example:`}</strong> |
| 1899 | <ul> | 1895 | <ul> |
| 1900 | <li> | 1896 | <li> |
| 1901 | <pre><code>/fuzzy list=["a","b","c"] threshold=0.4 abc</code></pre> | 1897 | <pre><code>/fuzzy list=["a","b","c"] threshold=0.4 abc</code></pre> |
| @@ -1908,23 +1904,23 @@ export function initDefaultSlashCommands() { | |||
| 1908 | name: 'pass', | 1904 | name: 'pass', |
| 1909 | callback: (_, arg) => { | 1905 | callback: (_, arg) => { |
| 1910 | // We do not support arrays of closures. Arrays of strings will be send as JSON | 1906 | // We do not support arrays of closures. Arrays of strings will be send as JSON |
| 1911 | if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error('Command /pass does not support multiple closures'); | 1907 | if (Array.isArray(arg) && arg.some(x => x instanceof SlashCommandClosure)) throw new Error(t`Command /pass does not support multiple closures`); |
| 1912 | if (Array.isArray(arg)) return JSON.stringify(arg); | 1908 | if (Array.isArray(arg)) return JSON.stringify(arg); |
| 1913 | return arg; | 1909 | return arg; |
| 1914 | }, | 1910 | }, |
| 1915 | returns: 'the provided value', | 1911 | returns: t`the provided value`, |
| 1916 | unnamedArgumentList: [ | 1912 | unnamedArgumentList: [ |
| 1917 | new SlashCommandArgument( | 1913 | new SlashCommandArgument( |
| 1918 | 'text', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY, ARGUMENT_TYPE.CLOSURE], true, | 1914 | t`text`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY, ARGUMENT_TYPE.CLOSURE], true, |
| 1919 | ), | 1915 | ), |
| 1920 | ], | 1916 | ], |
| 1921 | aliases: ['return'], | 1917 | aliases: ['return'], |
| 1922 | helpString: ` | 1918 | helpString: ` |
| 1923 | <div> | 1919 | <div> |
| 1924 | <pre><span class="monospace">/pass (text)</span> – passes the text to the next command through the pipe.</pre> | 1920 | <pre><span class="monospace">/pass (text)</span> – ${t`passes the text to the next command through the pipe.`}</pre> |
| 1925 | </div> | 1921 | </div> |
| 1926 | <div> | 1922 | <div> |
| 1927 | <strong>Example:</strong> | 1923 | <strong>${t`Example:`}</strong> |
| 1928 | <ul> | 1924 | <ul> |
| 1929 | <li><pre><code>/pass Hello world</code></pre></li> | 1925 | <li><pre><code>/pass Hello world</code></pre></li> |
| 1930 | </ul> | 1926 | </ul> |
| @@ -1937,15 +1933,15 @@ export function initDefaultSlashCommands() { | |||
| 1937 | aliases: ['wait', 'sleep'], | 1933 | aliases: ['wait', 'sleep'], |
| 1938 | unnamedArgumentList: [ | 1934 | unnamedArgumentList: [ |
| 1939 | new SlashCommandArgument( | 1935 | new SlashCommandArgument( |
| 1940 | 'milliseconds', [ARGUMENT_TYPE.NUMBER], true, | 1936 | t`milliseconds`, [ARGUMENT_TYPE.NUMBER], true, |
| 1941 | ), | 1937 | ), |
| 1942 | ], | 1938 | ], |
| 1943 | helpString: ` | 1939 | helpString: ` |
| 1944 | <div> | 1940 | <div> |
| 1945 | Delays the next command in the pipe by the specified number of milliseconds. | 1941 | ${t`Delays the next command in the pipe by the specified number of milliseconds.`} |
| 1946 | </div> | 1942 | </div> |
| 1947 | <div> | 1943 | <div> |
| 1948 | <strong>Example:</strong> | 1944 | <strong>${t`Example:`}</strong> |
| 1949 | <ul> | 1945 | <ul> |
| 1950 | <li> | 1946 | <li> |
| 1951 | <pre><code>/delay 1000</code></pre> | 1947 | <pre><code>/delay 1000</code></pre> |
| @@ -1958,59 +1954,59 @@ export function initDefaultSlashCommands() { | |||
| 1958 | name: 'input', | 1954 | name: 'input', |
| 1959 | aliases: ['prompt'], | 1955 | aliases: ['prompt'], |
| 1960 | callback: inputCallback, | 1956 | callback: inputCallback, |
| 1961 | returns: 'user input', | 1957 | returns: t`user input`, |
| 1962 | namedArgumentList: [ | 1958 | namedArgumentList: [ |
| 1963 | SlashCommandNamedArgument.fromProps({ | 1959 | SlashCommandNamedArgument.fromProps({ |
| 1964 | name: 'default', | 1960 | name: 'default', |
| 1965 | description: 'default value of the input field', | 1961 | description: t`default value of the input field`, |
| 1966 | typeList: [ARGUMENT_TYPE.STRING], | 1962 | typeList: [ARGUMENT_TYPE.STRING], |
| 1967 | }), | 1963 | }), |
| 1968 | SlashCommandNamedArgument.fromProps({ | 1964 | SlashCommandNamedArgument.fromProps({ |
| 1969 | name: 'large', | 1965 | name: 'large', |
| 1970 | description: 'popup window will be shown larger in height, with more space for content (input field needs to be sized via \'rows\' argument)', | 1966 | description: t`popup window will be shown larger in height, with more space for content (input field needs to be sized via 'rows' argument)`, |
| 1971 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1967 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1972 | defaultValue: 'off', | 1968 | defaultValue: 'off', |
| 1973 | enumList: commonEnumProviders.boolean('onOff')(), | 1969 | enumList: commonEnumProviders.boolean('onOff')(), |
| 1974 | }), | 1970 | }), |
| 1975 | SlashCommandNamedArgument.fromProps({ | 1971 | SlashCommandNamedArgument.fromProps({ |
| 1976 | name: 'wide', | 1972 | name: 'wide', |
| 1977 | description: 'popup window will be shown wider, with a wider input field', | 1973 | description: t`popup window will be shown wider, with a wider input field`, |
| 1978 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 1974 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 1979 | defaultValue: 'off', | 1975 | defaultValue: 'off', |
| 1980 | enumList: commonEnumProviders.boolean('onOff')(), | 1976 | enumList: commonEnumProviders.boolean('onOff')(), |
| 1981 | }), | 1977 | }), |
| 1982 | SlashCommandNamedArgument.fromProps({ | 1978 | SlashCommandNamedArgument.fromProps({ |
| 1983 | name: 'okButton', | 1979 | name: 'okButton', |
| 1984 | description: 'text for the ok button', | 1980 | description: t`text for the ok button`, |
| 1985 | typeList: [ARGUMENT_TYPE.STRING], | 1981 | typeList: [ARGUMENT_TYPE.STRING], |
| 1986 | defaultValue: 'Ok', | 1982 | defaultValue: 'Ok', |
| 1987 | }), | 1983 | }), |
| 1988 | SlashCommandNamedArgument.fromProps({ | 1984 | SlashCommandNamedArgument.fromProps({ |
| 1989 | name: 'rows', | 1985 | name: 'rows', |
| 1990 | description: 'number of rows for the input field (lines being displayed)', | 1986 | description: t`number of rows for the input field (lines being displayed)`, |
| 1991 | typeList: [ARGUMENT_TYPE.NUMBER], | 1987 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 1992 | }), | 1988 | }), |
| 1993 | SlashCommandNamedArgument.fromProps({ | 1989 | SlashCommandNamedArgument.fromProps({ |
| 1994 | name: 'onSuccess', | 1990 | name: 'onSuccess', |
| 1995 | description: 'closure to execute when the ok button is clicked or the input is closed as successful (via Enter, etc)', | 1991 | description: t`closure to execute when the ok button is clicked or the input is closed as successful (via Enter, etc)`, |
| 1996 | typeList: [ARGUMENT_TYPE.CLOSURE], | 1992 | typeList: [ARGUMENT_TYPE.CLOSURE], |
| 1997 | }), | 1993 | }), |
| 1998 | SlashCommandNamedArgument.fromProps({ | 1994 | SlashCommandNamedArgument.fromProps({ |
| 1999 | name: 'onCancel', | 1995 | name: 'onCancel', |
| 2000 | description: 'closure to execute when the cancel button is clicked or the input is closed as cancelled (via Escape, etc)', | 1996 | description: t`closure to execute when the cancel button is clicked or the input is closed as cancelled (via Escape, etc)`, |
| 2001 | typeList: [ARGUMENT_TYPE.CLOSURE], | 1997 | typeList: [ARGUMENT_TYPE.CLOSURE], |
| 2002 | }), | 1998 | }), |
| 2003 | ], | 1999 | ], |
| 2004 | unnamedArgumentList: [ | 2000 | unnamedArgumentList: [ |
| 2005 | SlashCommandArgument.fromProps({ | 2001 | SlashCommandArgument.fromProps({ |
| 2006 | description: 'text to display', | 2002 | description: t`text to display`, |
| 2007 | typeList: [ARGUMENT_TYPE.STRING], | 2003 | typeList: [ARGUMENT_TYPE.STRING], |
| 2008 | }), | 2004 | }), |
| 2009 | ], | 2005 | ], |
| 2010 | helpString: ` | 2006 | helpString: ` |
| 2011 | <div> | 2007 | <div> |
| 2012 | Shows a popup with the provided text and an input field. | 2008 | ${t`Shows a popup with the provided text and an input field.`} |
| 2013 | The <code>default</code> argument is the default value of the input field, and the text argument is the text to display. | 2009 | ${t`The <code>default</code> argument is the default value of the input field, and the text argument is the text to display.`} |
| 2014 | </div> | 2010 | </div> |
| 2015 | `, | 2011 | `, |
| 2016 | })); | 2012 | })); |
| @@ -2018,15 +2014,15 @@ export function initDefaultSlashCommands() { | |||
| 2018 | name: 'run', | 2014 | name: 'run', |
| 2019 | aliases: ['call', 'exec'], | 2015 | aliases: ['call', 'exec'], |
| 2020 | callback: runCallback, | 2016 | callback: runCallback, |
| 2021 | returns: 'result of the executed closure of QR', | 2017 | returns: t`result of the executed closure of QR`, |
| 2022 | namedArgumentList: [ | 2018 | namedArgumentList: [ |
| 2023 | new SlashCommandNamedArgument( | 2019 | new SlashCommandNamedArgument( |
| 2024 | 'args', 'named arguments', [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY], false, true, | 2020 | 'args', t`named arguments`, [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.BOOLEAN, ARGUMENT_TYPE.LIST, ARGUMENT_TYPE.DICTIONARY], false, true, |
| 2025 | ), | 2021 | ), |
| 2026 | ], | 2022 | ], |
| 2027 | unnamedArgumentList: [ | 2023 | unnamedArgumentList: [ |
| 2028 | SlashCommandArgument.fromProps({ | 2024 | SlashCommandArgument.fromProps({ |
| 2029 | description: 'scoped variable or qr label', | 2025 | description: t`scoped variable or qr label`, |
| 2030 | typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.CLOSURE], | 2026 | typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.CLOSURE], |
| 2031 | isRequired: true, | 2027 | isRequired: true, |
| 2032 | enumProvider: (executor, scope) => [ | 2028 | enumProvider: (executor, scope) => [ |
| @@ -2037,8 +2033,8 @@ export function initDefaultSlashCommands() { | |||
| 2037 | ], | 2033 | ], |
| 2038 | helpString: ` | 2034 | helpString: ` |
| 2039 | <div> | 2035 | <div> |
| 2040 | Runs a closure from a scoped variable, or a Quick Reply with the specified name from a currently active preset or from another preset. | 2036 | ${t`Runs a closure from a scoped variable, or a Quick Reply with the specified name from a currently active preset or from another preset.`} |
| 2041 | Named arguments can be referenced in a QR with <code>{{arg::key}}</code>. | 2037 | ${t`Named arguments can be referenced in a QR with <code>{{arg::key}}</code>.`} |
| 2042 | </div> | 2038 | </div> |
| 2043 | `, | 2039 | `, |
| 2044 | })); | 2040 | })); |
| @@ -2048,14 +2044,14 @@ export function initDefaultSlashCommands() { | |||
| 2048 | aliases: ['message'], | 2044 | aliases: ['message'], |
| 2049 | namedArgumentList: [ | 2045 | namedArgumentList: [ |
| 2050 | new SlashCommandNamedArgument( | 2046 | new SlashCommandNamedArgument( |
| 2051 | 'names', 'show message author names', [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(), | 2047 | 'names', t`show message author names`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'off', commonEnumProviders.boolean('onOff')(), |
| 2052 | ), | 2048 | ), |
| 2053 | new SlashCommandNamedArgument( | 2049 | new SlashCommandNamedArgument( |
| 2054 | 'hidden', 'include hidden messages', [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(), | 2050 | 'hidden', t`include hidden messages`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'on', commonEnumProviders.boolean('onOff')(), |
| 2055 | ), | 2051 | ), |
| 2056 | SlashCommandNamedArgument.fromProps({ | 2052 | SlashCommandNamedArgument.fromProps({ |
| 2057 | name: 'role', | 2053 | name: 'role', |
| 2058 | description: 'filter messages by role', | 2054 | description: t`filter messages by role`, |
| 2059 | typeList: [ARGUMENT_TYPE.STRING], | 2055 | typeList: [ARGUMENT_TYPE.STRING], |
| 2060 | enumList: [ | 2056 | enumList: [ |
| 2061 | new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system), | 2057 | new SlashCommandEnumValue('system', null, enumTypes.enum, enumIcons.system), |
| @@ -2066,33 +2062,33 @@ export function initDefaultSlashCommands() { | |||
| 2066 | ], | 2062 | ], |
| 2067 | unnamedArgumentList: [ | 2063 | unnamedArgumentList: [ |
| 2068 | SlashCommandArgument.fromProps({ | 2064 | SlashCommandArgument.fromProps({ |
| 2069 | description: 'message index (starts with 0) or range', | 2065 | description: t`message index (starts with 0) or range`, |
| 2070 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], | 2066 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.RANGE], |
| 2071 | isRequired: true, | 2067 | isRequired: true, |
| 2072 | enumProvider: commonEnumProviders.messages(), | 2068 | enumProvider: commonEnumProviders.messages(), |
| 2073 | }), | 2069 | }), |
| 2074 | ], | 2070 | ], |
| 2075 | returns: 'the specified message or range of messages as a string', | 2071 | returns: t`the specified message or range of messages as a string`, |
| 2076 | helpString: ` | 2072 | helpString: ` |
| 2077 | <div> | 2073 | <div> |
| 2078 | Returns the specified message or range of messages as a string. | 2074 | ${t`Returns the specified message or range of messages as a string.`} |
| 2079 | </div> | 2075 | </div> |
| 2080 | <div> | 2076 | <div> |
| 2081 | Use the <code>hidden=off</code> argument to exclude hidden messages. | 2077 | ${t`Use the <code>hidden=off</code> argument to exclude hidden messages.`} |
| 2082 | </div> | 2078 | </div> |
| 2083 | <div> | 2079 | <div> |
| 2084 | Use the <code>role</code> argument to filter messages by role. Possible values are: system, assistant, user. | 2080 | ${t`Use the <code>role</code> argument to filter messages by role. Possible values are: system, assistant, user.`} |
| 2085 | </div> | 2081 | </div> |
| 2086 | <div> | 2082 | <div> |
| 2087 | <strong>Examples:</strong> | 2083 | <strong>${t`Examples:`}</strong> |
| 2088 | <ul> | 2084 | <ul> |
| 2089 | <li> | 2085 | <li> |
| 2090 | <pre><code>/messages 10</code></pre> | 2086 | <pre><code>/messages 10</code></pre> |
| 2091 | Returns the 10th message. | 2087 | ${t`Returns the 10th message.`} |
| 2092 | </li> | 2088 | </li> |
| 2093 | <li> | 2089 | <li> |
| 2094 | <pre><code>/messages names=on 5-10</code></pre> | 2090 | <pre><code>/messages names=on 5-10</code></pre> |
| 2095 | Returns messages 5 through 10 with author names. | 2091 | ${t`Returns messages 5 through 10 with author names.`} |
| 2096 | </li> | 2092 | </li> |
| 2097 | </ul> | 2093 | </ul> |
| 2098 | </div> | 2094 | </div> |
| @@ -2103,15 +2099,15 @@ export function initDefaultSlashCommands() { | |||
| 2103 | callback: setInputCallback, | 2099 | callback: setInputCallback, |
| 2104 | unnamedArgumentList: [ | 2100 | unnamedArgumentList: [ |
| 2105 | new SlashCommandArgument( | 2101 | new SlashCommandArgument( |
| 2106 | 'text', [ARGUMENT_TYPE.STRING], true, | 2102 | t`text`, [ARGUMENT_TYPE.STRING], true, |
| 2107 | ), | 2103 | ), |
| 2108 | ], | 2104 | ], |
| 2109 | helpString: ` | 2105 | helpString: ` |
| 2110 | <div> | 2106 | <div> |
| 2111 | Sets the user input to the specified text and passes it to the next command through the pipe. | 2107 | ${t`Sets the user input to the specified text and passes it to the next command through the pipe.`} |
| 2112 | </div> | 2108 | </div> |
| 2113 | <div> | 2109 | <div> |
| 2114 | <strong>Example:</strong> | 2110 | <strong>${t`Example:`}</strong> |
| 2115 | <ul> | 2111 | <ul> |
| 2116 | <li> | 2112 | <li> |
| 2117 | <pre><code>/setinput Hello world</code></pre> | 2113 | <pre><code>/setinput Hello world</code></pre> |
| @@ -2123,57 +2119,57 @@ export function initDefaultSlashCommands() { | |||
| 2123 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2119 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2124 | name: 'popup', | 2120 | name: 'popup', |
| 2125 | callback: popupCallback, | 2121 | callback: popupCallback, |
| 2126 | returns: 'popup text', | 2122 | returns: t`popup text`, |
| 2127 | namedArgumentList: [ | 2123 | namedArgumentList: [ |
| 2128 | SlashCommandNamedArgument.fromProps({ | 2124 | SlashCommandNamedArgument.fromProps({ |
| 2129 | name: 'scroll', | 2125 | name: 'scroll', |
| 2130 | description: 'allows vertical scrolling of the content', | 2126 | description: t`allows vertical scrolling of the content`, |
| 2131 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2127 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2132 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2128 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2133 | defaultValue: 'true', | 2129 | defaultValue: 'true', |
| 2134 | }), | 2130 | }), |
| 2135 | SlashCommandNamedArgument.fromProps({ | 2131 | SlashCommandNamedArgument.fromProps({ |
| 2136 | name: 'large', | 2132 | name: 'large', |
| 2137 | description: 'show large popup', | 2133 | description: t`show large popup`, |
| 2138 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2134 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2139 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2135 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2140 | defaultValue: 'false', | 2136 | defaultValue: 'false', |
| 2141 | }), | 2137 | }), |
| 2142 | SlashCommandNamedArgument.fromProps({ | 2138 | SlashCommandNamedArgument.fromProps({ |
| 2143 | name: 'wide', | 2139 | name: 'wide', |
| 2144 | description: 'show wide popup', | 2140 | description: t`show wide popup`, |
| 2145 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2141 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2146 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2142 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2147 | defaultValue: 'false', | 2143 | defaultValue: 'false', |
| 2148 | }), | 2144 | }), |
| 2149 | SlashCommandNamedArgument.fromProps({ | 2145 | SlashCommandNamedArgument.fromProps({ |
| 2150 | name: 'wider', | 2146 | name: 'wider', |
| 2151 | description: 'show wider popup', | 2147 | description: t`show wider popup`, |
| 2152 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2148 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2153 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2149 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2154 | defaultValue: 'false', | 2150 | defaultValue: 'false', |
| 2155 | }), | 2151 | }), |
| 2156 | SlashCommandNamedArgument.fromProps({ | 2152 | SlashCommandNamedArgument.fromProps({ |
| 2157 | name: 'transparent', | 2153 | name: 'transparent', |
| 2158 | description: 'show transparent popup', | 2154 | description: t`show transparent popup`, |
| 2159 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2155 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2160 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2156 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2161 | defaultValue: 'false', | 2157 | defaultValue: 'false', |
| 2162 | }), | 2158 | }), |
| 2163 | SlashCommandNamedArgument.fromProps({ | 2159 | SlashCommandNamedArgument.fromProps({ |
| 2164 | name: 'okButton', | 2160 | name: 'okButton', |
| 2165 | description: 'text for the OK button', | 2161 | description: t`text for the OK button`, |
| 2166 | typeList: [ARGUMENT_TYPE.STRING], | 2162 | typeList: [ARGUMENT_TYPE.STRING], |
| 2167 | defaultValue: 'OK', | 2163 | defaultValue: 'OK', |
| 2168 | }), | 2164 | }), |
| 2169 | SlashCommandNamedArgument.fromProps({ | 2165 | SlashCommandNamedArgument.fromProps({ |
| 2170 | name: 'cancelButton', | 2166 | name: 'cancelButton', |
| 2171 | description: 'text for the Cancel button', | 2167 | description: t`text for the Cancel button`, |
| 2172 | typeList: [ARGUMENT_TYPE.STRING], | 2168 | typeList: [ARGUMENT_TYPE.STRING], |
| 2173 | }), | 2169 | }), |
| 2174 | SlashCommandNamedArgument.fromProps({ | 2170 | SlashCommandNamedArgument.fromProps({ |
| 2175 | name: 'result', | 2171 | name: 'result', |
| 2176 | description: 'if enabled, returns the popup result (as an integer) instead of the popup text. Resolves to 1 for OK and 0 cancel button, empty string for exiting out.', | 2172 | description: t`if enabled, returns the popup result (as an integer) instead of the popup text. Resolves to 1 for OK and 0 cancel button, empty string for exiting out.`, |
| 2177 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2173 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2178 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2174 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2179 | defaultValue: 'false', | 2175 | defaultValue: 'false', |
| @@ -2181,18 +2177,18 @@ export function initDefaultSlashCommands() { | |||
| 2181 | ], | 2177 | ], |
| 2182 | unnamedArgumentList: [ | 2178 | unnamedArgumentList: [ |
| 2183 | SlashCommandArgument.fromProps({ | 2179 | SlashCommandArgument.fromProps({ |
| 2184 | description: 'popup text', | 2180 | description: t`popup text`, |
| 2185 | typeList: [ARGUMENT_TYPE.STRING], | 2181 | typeList: [ARGUMENT_TYPE.STRING], |
| 2186 | isRequired: true, | 2182 | isRequired: true, |
| 2187 | }), | 2183 | }), |
| 2188 | ], | 2184 | ], |
| 2189 | helpString: ` | 2185 | helpString: ` |
| 2190 | <div> | 2186 | <div> |
| 2191 | Shows a blocking popup with the specified text and buttons. | 2187 | ${t`Shows a blocking popup with the specified text and buttons.`} |
| 2192 | Returns the popup text. | 2188 | ${t`Returns the popup text.`} |
| 2193 | </div> | 2189 | </div> |
| 2194 | <div> | 2190 | <div> |
| 2195 | <strong>Example:</strong> | 2191 | <strong>${t`Example:`}</strong> |
| 2196 | <ul> | 2192 | <ul> |
| 2197 | <li> | 2193 | <li> |
| 2198 | <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre> | 2194 | <pre><code>/popup large=on wide=on okButton="Confirm" Please confirm this action.</code></pre> |
| @@ -2207,17 +2203,17 @@ export function initDefaultSlashCommands() { | |||
| 2207 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2203 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2208 | name: 'buttons', | 2204 | name: 'buttons', |
| 2209 | callback: buttonsCallback, | 2205 | callback: buttonsCallback, |
| 2210 | returns: 'clicked button label (or array of labels if multiple is enabled)', | 2206 | returns: t`clicked button label (or array of labels if multiple is enabled)`, |
| 2211 | namedArgumentList: [ | 2207 | namedArgumentList: [ |
| 2212 | SlashCommandNamedArgument.fromProps({ | 2208 | SlashCommandNamedArgument.fromProps({ |
| 2213 | name: 'labels', | 2209 | name: 'labels', |
| 2214 | description: 'button labels', | 2210 | description: t`button labels`, |
| 2215 | typeList: [ARGUMENT_TYPE.LIST], | 2211 | typeList: [ARGUMENT_TYPE.LIST], |
| 2216 | isRequired: true, | 2212 | isRequired: true, |
| 2217 | }), | 2213 | }), |
| 2218 | SlashCommandNamedArgument.fromProps({ | 2214 | SlashCommandNamedArgument.fromProps({ |
| 2219 | name: 'multiple', | 2215 | name: 'multiple', |
| 2220 | description: 'if enabled multiple buttons can be clicked/toggled, and all clicked buttons are returned as an array', | 2216 | description: t`if enabled multiple buttons can be clicked/toggled, and all clicked buttons are returned as an array`, |
| 2221 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2217 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2222 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2218 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2223 | defaultValue: 'false', | 2219 | defaultValue: 'false', |
| @@ -2225,18 +2221,18 @@ export function initDefaultSlashCommands() { | |||
| 2225 | ], | 2221 | ], |
| 2226 | unnamedArgumentList: [ | 2222 | unnamedArgumentList: [ |
| 2227 | SlashCommandArgument.fromProps({ | 2223 | SlashCommandArgument.fromProps({ |
| 2228 | description: 'text', | 2224 | description: t`text`, |
| 2229 | typeList: [ARGUMENT_TYPE.STRING], | 2225 | typeList: [ARGUMENT_TYPE.STRING], |
| 2230 | isRequired: true, | 2226 | isRequired: true, |
| 2231 | }), | 2227 | }), |
| 2232 | ], | 2228 | ], |
| 2233 | helpString: ` | 2229 | helpString: ` |
| 2234 | <div> | 2230 | <div> |
| 2235 | Shows a blocking popup with the specified text and buttons. | 2231 | ${t`Shows a blocking popup with the specified text and buttons.`} |
| 2236 | Returns the clicked button label into the pipe or empty string if canceled. | 2232 | ${t`Returns the clicked button label into the pipe or empty string if canceled.`} |
| 2237 | </div> | 2233 | </div> |
| 2238 | <div> | 2234 | <div> |
| 2239 | <strong>Example:</strong> | 2235 | <strong>${t`Example:`}</strong> |
| 2240 | <ul> | 2236 | <ul> |
| 2241 | <li> | 2237 | <li> |
| 2242 | <pre><code>/buttons labels=["Yes","No"] Do you want to continue?</code></pre> | 2238 | <pre><code>/buttons labels=["Yes","No"] Do you want to continue?</code></pre> |
| @@ -2248,14 +2244,14 @@ export function initDefaultSlashCommands() { | |||
| 2248 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2244 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2249 | name: 'trimtokens', | 2245 | name: 'trimtokens', |
| 2250 | callback: trimTokensCallback, | 2246 | callback: trimTokensCallback, |
| 2251 | returns: 'trimmed text', | 2247 | returns: t`trimmed text`, |
| 2252 | namedArgumentList: [ | 2248 | namedArgumentList: [ |
| 2253 | new SlashCommandNamedArgument( | 2249 | new SlashCommandNamedArgument( |
| 2254 | 'limit', 'number of tokens to keep', [ARGUMENT_TYPE.NUMBER], true, | 2250 | 'limit', t`number of tokens to keep`, [ARGUMENT_TYPE.NUMBER], true, |
| 2255 | ), | 2251 | ), |
| 2256 | SlashCommandNamedArgument.fromProps({ | 2252 | SlashCommandNamedArgument.fromProps({ |
| 2257 | name: 'direction', | 2253 | name: 'direction', |
| 2258 | description: 'trim direction', | 2254 | description: t`trim direction`, |
| 2259 | typeList: [ARGUMENT_TYPE.STRING], | 2255 | typeList: [ARGUMENT_TYPE.STRING], |
| 2260 | isRequired: true, | 2256 | isRequired: true, |
| 2261 | enumList: [ | 2257 | enumList: [ |
| @@ -2266,15 +2262,15 @@ export function initDefaultSlashCommands() { | |||
| 2266 | ], | 2262 | ], |
| 2267 | unnamedArgumentList: [ | 2263 | unnamedArgumentList: [ |
| 2268 | new SlashCommandArgument( | 2264 | new SlashCommandArgument( |
| 2269 | 'text', [ARGUMENT_TYPE.STRING], false, | 2265 | t`text`, [ARGUMENT_TYPE.STRING], false, |
| 2270 | ), | 2266 | ), |
| 2271 | ], | 2267 | ], |
| 2272 | helpString: ` | 2268 | helpString: ` |
| 2273 | <div> | 2269 | <div> |
| 2274 | Trims the start or end of text to the specified number of tokens. | 2270 | ${t`Trims the start or end of text to the specified number of tokens.`} |
| 2275 | </div> | 2271 | </div> |
| 2276 | <div> | 2272 | <div> |
| 2277 | <strong>Example:</strong> | 2273 | <strong>${t`Example:`}</strong> |
| 2278 | <ul> | 2274 | <ul> |
| 2279 | <li> | 2275 | <li> |
| 2280 | <pre><code>/trimtokens limit=5 direction=start This is a long sentence with many words</code></pre> | 2276 | <pre><code>/trimtokens limit=5 direction=start This is a long sentence with many words</code></pre> |
| @@ -2286,18 +2282,18 @@ export function initDefaultSlashCommands() { | |||
| 2286 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2282 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2287 | name: 'trimstart', | 2283 | name: 'trimstart', |
| 2288 | callback: trimStartCallback, | 2284 | callback: trimStartCallback, |
| 2289 | returns: 'trimmed text', | 2285 | returns: t`trimmed text`, |
| 2290 | unnamedArgumentList: [ | 2286 | unnamedArgumentList: [ |
| 2291 | new SlashCommandArgument( | 2287 | new SlashCommandArgument( |
| 2292 | 'text', [ARGUMENT_TYPE.STRING], true, | 2288 | t`text`, [ARGUMENT_TYPE.STRING], true, |
| 2293 | ), | 2289 | ), |
| 2294 | ], | 2290 | ], |
| 2295 | helpString: ` | 2291 | helpString: ` |
| 2296 | <div> | 2292 | <div> |
| 2297 | Trims the text to the start of the first full sentence. | 2293 | ${t`Trims the text to the start of the first full sentence.`} |
| 2298 | </div> | 2294 | </div> |
| 2299 | <div> | 2295 | <div> |
| 2300 | <strong>Example:</strong> | 2296 | <strong>${t`Example:`}</strong> |
| 2301 | <ul> | 2297 | <ul> |
| 2302 | <li> | 2298 | <li> |
| 2303 | <pre><code>/trimstart This is a sentence. And here is another sentence.</code></pre> | 2299 | <pre><code>/trimstart This is a sentence. And here is another sentence.</code></pre> |
| @@ -2309,38 +2305,38 @@ export function initDefaultSlashCommands() { | |||
| 2309 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2305 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2310 | name: 'trimend', | 2306 | name: 'trimend', |
| 2311 | callback: trimEndCallback, | 2307 | callback: trimEndCallback, |
| 2312 | returns: 'trimmed text', | 2308 | returns: t`trimmed text`, |
| 2313 | unnamedArgumentList: [ | 2309 | unnamedArgumentList: [ |
| 2314 | new SlashCommandArgument( | 2310 | new SlashCommandArgument( |
| 2315 | 'text', [ARGUMENT_TYPE.STRING], true, | 2311 | t`text`, [ARGUMENT_TYPE.STRING], true, |
| 2316 | ), | 2312 | ), |
| 2317 | ], | 2313 | ], |
| 2318 | helpString: 'Trims the text to the end of the last full sentence.', | 2314 | helpString: t`Trims the text to the end of the last full sentence.`, |
| 2319 | })); | 2315 | })); |
| 2320 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2316 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2321 | name: 'inject', | 2317 | name: 'inject', |
| 2322 | returns: 'injection ID', | 2318 | returns: t`injection ID`, |
| 2323 | callback: injectCallback, | 2319 | callback: injectCallback, |
| 2324 | namedArgumentList: [ | 2320 | namedArgumentList: [ |
| 2325 | SlashCommandNamedArgument.fromProps({ | 2321 | SlashCommandNamedArgument.fromProps({ |
| 2326 | name: 'id', | 2322 | name: 'id', |
| 2327 | description: 'injection ID', | 2323 | description: t`injection ID`, |
| 2328 | typeList: [ARGUMENT_TYPE.STRING], | 2324 | typeList: [ARGUMENT_TYPE.STRING], |
| 2329 | isRequired: false, | 2325 | isRequired: false, |
| 2330 | enumProvider: commonEnumProviders.injects, | 2326 | enumProvider: commonEnumProviders.injects, |
| 2331 | }), | 2327 | }), |
| 2332 | new SlashCommandNamedArgument( | 2328 | new SlashCommandNamedArgument( |
| 2333 | 'position', 'injection position', [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat', 'none'], | 2329 | 'position', t`injection position`, [ARGUMENT_TYPE.STRING], false, false, 'after', ['before', 'after', 'chat', 'none'], |
| 2334 | ), | 2330 | ), |
| 2335 | new SlashCommandNamedArgument( | 2331 | new SlashCommandNamedArgument( |
| 2336 | 'depth', 'injection depth', [ARGUMENT_TYPE.NUMBER], false, false, '4', | 2332 | 'depth', t`injection depth`, [ARGUMENT_TYPE.NUMBER], false, false, '4', |
| 2337 | ), | 2333 | ), |
| 2338 | new SlashCommandNamedArgument( | 2334 | new SlashCommandNamedArgument( |
| 2339 | 'scan', 'include injection content into World Info scans', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', | 2335 | 'scan', t`include injection content into World Info scans`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', |
| 2340 | ), | 2336 | ), |
| 2341 | SlashCommandNamedArgument.fromProps({ | 2337 | SlashCommandNamedArgument.fromProps({ |
| 2342 | name: 'role', | 2338 | name: 'role', |
| 2343 | description: 'role for in-chat injections', | 2339 | description: t`role for in-chat injections`, |
| 2344 | typeList: [ARGUMENT_TYPE.STRING], | 2340 | typeList: [ARGUMENT_TYPE.STRING], |
| 2345 | isRequired: false, | 2341 | isRequired: false, |
| 2346 | enumList: [ | 2342 | enumList: [ |
| @@ -2350,11 +2346,11 @@ export function initDefaultSlashCommands() { | |||
| 2350 | ], | 2346 | ], |
| 2351 | }), | 2347 | }), |
| 2352 | new SlashCommandNamedArgument( | 2348 | new SlashCommandNamedArgument( |
| 2353 | 'ephemeral', 'remove injection after generation', [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', | 2349 | 'ephemeral', t`remove injection after generation`, [ARGUMENT_TYPE.BOOLEAN], false, false, 'false', |
| 2354 | ), | 2350 | ), |
| 2355 | SlashCommandNamedArgument.fromProps({ | 2351 | SlashCommandNamedArgument.fromProps({ |
| 2356 | name: 'filter', | 2352 | name: 'filter', |
| 2357 | description: 'if a filter is defined, an injection will only be performed if the closure returns true', | 2353 | description: t`if a filter is defined, an injection will only be performed if the closure returns true`, |
| 2358 | typeList: [ARGUMENT_TYPE.CLOSURE], | 2354 | typeList: [ARGUMENT_TYPE.CLOSURE], |
| 2359 | isRequired: false, | 2355 | isRequired: false, |
| 2360 | acceptsMultiple: false, | 2356 | acceptsMultiple: false, |
| @@ -2362,20 +2358,20 @@ export function initDefaultSlashCommands() { | |||
| 2362 | ], | 2358 | ], |
| 2363 | unnamedArgumentList: [ | 2359 | unnamedArgumentList: [ |
| 2364 | new SlashCommandArgument( | 2360 | new SlashCommandArgument( |
| 2365 | 'text', [ARGUMENT_TYPE.STRING], false, | 2361 | t`text`, [ARGUMENT_TYPE.STRING], false, |
| 2366 | ), | 2362 | ), |
| 2367 | ], | 2363 | ], |
| 2368 | helpString: 'Injects a text into the LLM prompt for the current chat. Requires a unique injection ID (will be auto-generated if not provided). Positions: "before" main prompt, "after" main prompt, in-"chat", hidden with "none" (default: after). Depth: injection depth for the prompt (default: 4). Role: role for in-chat injections (default: system). Scan: include injection content into World Info scans (default: false). Hidden injects in "none" position are not inserted into the prompt but can be used for triggering WI entries. Returns the injection ID.', | 2364 | helpString: t`Injects a text into the LLM prompt for the current chat. Requires a unique injection ID (will be auto-generated if not provided). Positions: "before" main prompt, "after" main prompt, in-"chat", hidden with "none" (default: after). Depth: injection depth for the prompt (default: 4). Role: role for in-chat injections (default: system). Scan: include injection content into World Info scans (default: false). Hidden injects in "none" position are not inserted into the prompt but can be used for triggering WI entries. Returns the injection ID.`, |
| 2369 | })); | 2365 | })); |
| 2370 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2366 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2371 | name: 'listinjects', | 2367 | name: 'listinjects', |
| 2372 | callback: listInjectsCallback, | 2368 | callback: listInjectsCallback, |
| 2373 | helpString: 'Lists all script injections for the current chat. Displays injects in a popup by default. Use the <code>return</code> argument to change the return type.', | 2369 | helpString: t`Lists all script injections for the current chat. Displays injects in a popup by default. Use the <code>return</code> argument to change the return type.`, |
| 2374 | returns: 'Optionalls the JSON object of script injections', | 2370 | returns: t`Optionally the JSON object of script injections`, |
| 2375 | namedArgumentList: [ | 2371 | namedArgumentList: [ |
| 2376 | SlashCommandNamedArgument.fromProps({ | 2372 | SlashCommandNamedArgument.fromProps({ |
| 2377 | name: 'return', | 2373 | name: 'return', |
| 2378 | description: 'The way how you want the return value to be provided', | 2374 | description: t`The way how you want the return value to be provided`, |
| 2379 | typeList: [ARGUMENT_TYPE.STRING], | 2375 | typeList: [ARGUMENT_TYPE.STRING], |
| 2380 | defaultValue: 'popup-html', | 2376 | defaultValue: 'popup-html', |
| 2381 | enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }), | 2377 | enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }), |
| @@ -2384,14 +2380,14 @@ export function initDefaultSlashCommands() { | |||
| 2384 | // TODO remove some day | 2380 | // TODO remove some day |
| 2385 | SlashCommandNamedArgument.fromProps({ | 2381 | SlashCommandNamedArgument.fromProps({ |
| 2386 | name: 'format', | 2382 | name: 'format', |
| 2387 | description: '!!! DEPRECATED - use "return" instead !!! output format', | 2383 | description: t`!!! DEPRECATED - use "return" instead !!! output format`, |
| 2388 | typeList: [ARGUMENT_TYPE.STRING], | 2384 | typeList: [ARGUMENT_TYPE.STRING], |
| 2389 | isRequired: true, | 2385 | isRequired: true, |
| 2390 | forceEnum: true, | 2386 | forceEnum: true, |
| 2391 | enumList: [ | 2387 | enumList: [ |
| 2392 | new SlashCommandEnumValue('popup', 'Show injects in a popup.', enumTypes.enum, enumIcons.default), | 2388 | new SlashCommandEnumValue('popup', t`Show injects in a popup.`, enumTypes.enum, enumIcons.default), |
| 2393 | new SlashCommandEnumValue('chat', 'Post a system message to the chat.', enumTypes.enum, enumIcons.default), | 2389 | new SlashCommandEnumValue('chat', t`Post a system message to the chat.`, enumTypes.enum, enumIcons.default), |
| 2394 | new SlashCommandEnumValue('none', 'Just return the injects as a JSON object.', enumTypes.enum, enumIcons.default), | 2390 | new SlashCommandEnumValue('none', t`Just return the injects as a JSON object.`, enumTypes.enum, enumIcons.default), |
| 2395 | ], | 2391 | ], |
| 2396 | }), | 2392 | }), |
| 2397 | ], | 2393 | ], |
| @@ -2401,37 +2397,37 @@ export function initDefaultSlashCommands() { | |||
| 2401 | aliases: ['flushinjects'], | 2397 | aliases: ['flushinjects'], |
| 2402 | unnamedArgumentList: [ | 2398 | unnamedArgumentList: [ |
| 2403 | SlashCommandArgument.fromProps({ | 2399 | SlashCommandArgument.fromProps({ |
| 2404 | description: 'injection ID or a variable name pointing to ID', | 2400 | description: t`injection ID or a variable name pointing to ID`, |
| 2405 | typeList: [ARGUMENT_TYPE.STRING], | 2401 | typeList: [ARGUMENT_TYPE.STRING], |
| 2406 | defaultValue: '', | 2402 | defaultValue: '', |
| 2407 | enumProvider: commonEnumProviders.injects, | 2403 | enumProvider: commonEnumProviders.injects, |
| 2408 | }), | 2404 | }), |
| 2409 | ], | 2405 | ], |
| 2410 | callback: flushInjectsCallback, | 2406 | callback: flushInjectsCallback, |
| 2411 | helpString: 'Removes a script injection for the current chat. If no ID is provided, removes all script injections.', | 2407 | helpString: t`Removes a script injection for the current chat. If no ID is provided, removes all script injections.`, |
| 2412 | })); | 2408 | })); |
| 2413 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2409 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2414 | name: 'tokens', | 2410 | name: 'tokens', |
| 2415 | callback: (_, text) => { | 2411 | callback: (_, text) => { |
| 2416 | if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error('Unnamed argument cannot be a closure for command /tokens'); | 2412 | if (text instanceof SlashCommandClosure || Array.isArray(text)) throw new Error(t`Unnamed argument cannot be a closure for command /tokens`); |
| 2417 | return getTokenCountAsync(text).then(count => String(count)); | 2413 | return getTokenCountAsync(text).then(count => String(count)); |
| 2418 | }, | 2414 | }, |
| 2419 | returns: 'number of tokens', | 2415 | returns: t`number of tokens`, |
| 2420 | unnamedArgumentList: [ | 2416 | unnamedArgumentList: [ |
| 2421 | new SlashCommandArgument( | 2417 | new SlashCommandArgument( |
| 2422 | 'text', [ARGUMENT_TYPE.STRING], true, | 2418 | t`text`, [ARGUMENT_TYPE.STRING], true, |
| 2423 | ), | 2419 | ), |
| 2424 | ], | 2420 | ], |
| 2425 | helpString: 'Counts the number of tokens in the provided text.', | 2421 | helpString: t`Counts the number of tokens in the provided text.`, |
| 2426 | })); | 2422 | })); |
| 2427 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2423 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2428 | name: 'model', | 2424 | name: 'model', |
| 2429 | callback: modelCallback, | 2425 | callback: modelCallback, |
| 2430 | returns: 'current model', | 2426 | returns: t`current model`, |
| 2431 | namedArgumentList: [ | 2427 | namedArgumentList: [ |
| 2432 | SlashCommandNamedArgument.fromProps({ | 2428 | SlashCommandNamedArgument.fromProps({ |
| 2433 | name: 'quiet', | 2429 | name: 'quiet', |
| 2434 | description: 'suppress the toast message on model change', | 2430 | description: t`suppress the toast message on model change`, |
| 2435 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2431 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2436 | defaultValue: 'false', | 2432 | defaultValue: 'false', |
| 2437 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2433 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| @@ -2439,22 +2435,22 @@ export function initDefaultSlashCommands() { | |||
| 2439 | ], | 2435 | ], |
| 2440 | unnamedArgumentList: [ | 2436 | unnamedArgumentList: [ |
| 2441 | SlashCommandArgument.fromProps({ | 2437 | SlashCommandArgument.fromProps({ |
| 2442 | description: 'model name', | 2438 | description: t`model name`, |
| 2443 | typeList: [ARGUMENT_TYPE.STRING], | 2439 | typeList: [ARGUMENT_TYPE.STRING], |
| 2444 | enumProvider: () => getModelOptions(true)?.options?.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)) ?? [], | 2440 | enumProvider: () => getModelOptions(true)?.options?.map(option => new SlashCommandEnumValue(option.value, option.value !== option.text ? option.text : null)) ?? [], |
| 2445 | }), | 2441 | }), |
| 2446 | ], | 2442 | ], |
| 2447 | helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.', | 2443 | helpString: t`Sets the model for the current API. Gets the current model name if no argument is provided.`, |
| 2448 | })); | 2444 | })); |
| 2449 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2445 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2450 | name: 'getpromptentry', | 2446 | name: 'getpromptentry', |
| 2451 | aliases: ['getpromptentries'], | 2447 | aliases: ['getpromptentries'], |
| 2452 | callback: getPromptEntryCallback, | 2448 | callback: getPromptEntryCallback, |
| 2453 | returns: 'true/false state of prompt(s)', | 2449 | returns: t`true/false state of prompt(s)`, |
| 2454 | namedArgumentList: [ | 2450 | namedArgumentList: [ |
| 2455 | SlashCommandNamedArgument.fromProps({ | 2451 | SlashCommandNamedArgument.fromProps({ |
| 2456 | name: 'identifier', | 2452 | name: 'identifier', |
| 2457 | description: 'Prompt entry identifier(s) to retrieve', | 2453 | description: t`Prompt entry identifier(s) to retrieve`, |
| 2458 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | 2454 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], |
| 2459 | acceptsMultiple: true, | 2455 | acceptsMultiple: true, |
| 2460 | enumProvider: () => | 2456 | enumProvider: () => |
| @@ -2464,7 +2460,7 @@ export function initDefaultSlashCommands() { | |||
| 2464 | }), | 2460 | }), |
| 2465 | SlashCommandNamedArgument.fromProps({ | 2461 | SlashCommandNamedArgument.fromProps({ |
| 2466 | name: 'name', | 2462 | name: 'name', |
| 2467 | description: 'Prompt entry name(s) to retrieve', | 2463 | description: t`Prompt entry name(s) to retrieve`, |
| 2468 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | 2464 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], |
| 2469 | acceptsMultiple: true, | 2465 | acceptsMultiple: true, |
| 2470 | enumProvider: () => | 2466 | enumProvider: () => |
| @@ -2474,7 +2470,7 @@ export function initDefaultSlashCommands() { | |||
| 2474 | }), | 2470 | }), |
| 2475 | SlashCommandNamedArgument.fromProps({ | 2471 | SlashCommandNamedArgument.fromProps({ |
| 2476 | name: 'return', | 2472 | name: 'return', |
| 2477 | description: 'Whether the return will be simple, a list, or a dict.', | 2473 | description: t`Whether the return will be simple, a list, or a dict.`, |
| 2478 | typeList: [ARGUMENT_TYPE.STRING], | 2474 | typeList: [ARGUMENT_TYPE.STRING], |
| 2479 | defaultValue: 'simple', | 2475 | defaultValue: 'simple', |
| 2480 | enumList: ['simple', 'list', 'dict'], | 2476 | enumList: ['simple', 'list', 'dict'], |
| @@ -2482,10 +2478,10 @@ export function initDefaultSlashCommands() { | |||
| 2482 | ], | 2478 | ], |
| 2483 | helpString: ` | 2479 | helpString: ` |
| 2484 | <div> | 2480 | <div> |
| 2485 | Gets the state of the specified prompt entries. | 2481 | ${t`Gets the state of the specified prompt entries.`} |
| 2486 | </div> | 2482 | </div> |
| 2487 | <div> | 2483 | <div> |
| 2488 | If <code>return</code> is <code>simple</code> (default) then the return will be a single value if only one value was retrieved; otherwise uses a dict (if the identifier parameter was used) or a list. | 2484 | ${t`If <code>return</code> is <code>simple</code> (default) then the return will be a single value if only one value was retrieved; otherwise uses a dict (if the identifier parameter was used) or a list.`} |
| 2489 | </div> | 2485 | </div> |
| 2490 | `, | 2486 | `, |
| 2491 | })); | 2487 | })); |
| @@ -2496,7 +2492,7 @@ export function initDefaultSlashCommands() { | |||
| 2496 | namedArgumentList: [ | 2492 | namedArgumentList: [ |
| 2497 | SlashCommandNamedArgument.fromProps({ | 2493 | SlashCommandNamedArgument.fromProps({ |
| 2498 | name: 'identifier', | 2494 | name: 'identifier', |
| 2499 | description: 'Prompt entry identifier(s) to target', | 2495 | description: t`Prompt entry identifier(s) to target`, |
| 2500 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | 2496 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], |
| 2501 | acceptsMultiple: true, | 2497 | acceptsMultiple: true, |
| 2502 | enumProvider: () => { | 2498 | enumProvider: () => { |
| @@ -2506,7 +2502,7 @@ export function initDefaultSlashCommands() { | |||
| 2506 | }), | 2502 | }), |
| 2507 | SlashCommandNamedArgument.fromProps({ | 2503 | SlashCommandNamedArgument.fromProps({ |
| 2508 | name: 'name', | 2504 | name: 'name', |
| 2509 | description: 'Prompt entry name(s) to target', | 2505 | description: t`Prompt entry name(s) to target`, |
| 2510 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | 2506 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], |
| 2511 | acceptsMultiple: true, | 2507 | acceptsMultiple: true, |
| 2512 | enumProvider: () => { | 2508 | enumProvider: () => { |
| @@ -2517,7 +2513,7 @@ export function initDefaultSlashCommands() { | |||
| 2517 | ], | 2513 | ], |
| 2518 | unnamedArgumentList: [ | 2514 | unnamedArgumentList: [ |
| 2519 | SlashCommandArgument.fromProps({ | 2515 | SlashCommandArgument.fromProps({ |
| 2520 | description: 'Set entry/entries on or off', | 2516 | description: t`Set entry/entries on or off`, |
| 2521 | typeList: [ARGUMENT_TYPE.STRING], | 2517 | typeList: [ARGUMENT_TYPE.STRING], |
| 2522 | isRequired: true, | 2518 | isRequired: true, |
| 2523 | acceptsMultiple: false, | 2519 | acceptsMultiple: false, |
| @@ -2525,16 +2521,16 @@ export function initDefaultSlashCommands() { | |||
| 2525 | enumList: commonEnumProviders.boolean('onOffToggle')(), | 2521 | enumList: commonEnumProviders.boolean('onOffToggle')(), |
| 2526 | }), | 2522 | }), |
| 2527 | ], | 2523 | ], |
| 2528 | helpString: 'Sets the specified prompt manager entry/entries on or off.', | 2524 | helpString: t`Sets the specified prompt manager entry/entries on or off.`, |
| 2529 | })); | 2525 | })); |
| 2530 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2526 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2531 | name: 'pick-icon', | 2527 | name: 'pick-icon', |
| 2532 | callback: async () => ((await showFontAwesomePicker()) ?? false).toString(), | 2528 | callback: async () => ((await showFontAwesomePicker()) ?? false).toString(), |
| 2533 | returns: 'The chosen icon name or false if cancelled.', | 2529 | returns: t`The chosen icon name or false if cancelled.`, |
| 2534 | helpString: ` | 2530 | helpString: ` |
| 2535 | <div>Opens a popup with all the available Font Awesome icons and returns the selected icon's name.</div> | 2531 | <div>${t`Opens a popup with all the available Font Awesome icons and returns the selected icon's name.`}</div> |
| 2536 | <div> | 2532 | <div> |
| 2537 | <strong>Example:</strong> | 2533 | <strong>${t`Example:`}</strong> |
| 2538 | <ul> | 2534 | <ul> |
| 2539 | <li> | 2535 | <li> |
| 2540 | <pre><code>/pick-icon |\n/if left={{pipe}} rule=eq right=false\n\telse={: /echo chosen icon: "{{pipe}}" :}\n\t{: /echo cancelled icon selection :}\n|</code></pre> | 2536 | <pre><code>/pick-icon |\n/if left={{pipe}} rule=eq right=false\n\telse={: /echo chosen icon: "{{pipe}}" :}\n\t{: /echo cancelled icon selection :}\n|</code></pre> |
| @@ -2546,12 +2542,12 @@ export function initDefaultSlashCommands() { | |||
| 2546 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2542 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2547 | name: 'api-url', | 2543 | name: 'api-url', |
| 2548 | callback: setApiUrlCallback, | 2544 | callback: setApiUrlCallback, |
| 2549 | returns: 'the current API url', | 2545 | returns: t`the current API url`, |
| 2550 | aliases: ['server'], | 2546 | aliases: ['server'], |
| 2551 | namedArgumentList: [ | 2547 | namedArgumentList: [ |
| 2552 | SlashCommandNamedArgument.fromProps({ | 2548 | SlashCommandNamedArgument.fromProps({ |
| 2553 | name: 'api', | 2549 | name: 'api', |
| 2554 | description: 'API to set/get the URL for - if not provided, current API is used', | 2550 | description: t`API to set/get the URL for - if not provided, current API is used`, |
| 2555 | typeList: [ARGUMENT_TYPE.STRING], | 2551 | typeList: [ARGUMENT_TYPE.STRING], |
| 2556 | enumList: [ | 2552 | enumList: [ |
| 2557 | new SlashCommandEnumValue('custom', 'custom OpenAI-compatible', enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === 'openai')), 'O'), | 2553 | new SlashCommandEnumValue('custom', 'custom OpenAI-compatible', enumTypes.getBasedOnIndex(UNIQUE_APIS.findIndex(x => x === 'openai')), 'O'), |
| @@ -2561,14 +2557,14 @@ export function initDefaultSlashCommands() { | |||
| 2561 | }), | 2557 | }), |
| 2562 | SlashCommandNamedArgument.fromProps({ | 2558 | SlashCommandNamedArgument.fromProps({ |
| 2563 | name: 'connect', | 2559 | name: 'connect', |
| 2564 | description: 'Whether to auto-connect to the API after setting the URL', | 2560 | description: t`Whether to auto-connect to the API after setting the URL`, |
| 2565 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2561 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2566 | defaultValue: 'true', | 2562 | defaultValue: 'true', |
| 2567 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2563 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| 2568 | }), | 2564 | }), |
| 2569 | SlashCommandNamedArgument.fromProps({ | 2565 | SlashCommandNamedArgument.fromProps({ |
| 2570 | name: 'quiet', | 2566 | name: 'quiet', |
| 2571 | description: 'suppress the toast message on API change', | 2567 | description: t`suppress the toast message on API change`, |
| 2572 | typeList: [ARGUMENT_TYPE.BOOLEAN], | 2568 | typeList: [ARGUMENT_TYPE.BOOLEAN], |
| 2573 | defaultValue: 'false', | 2569 | defaultValue: 'false', |
| 2574 | enumList: commonEnumProviders.boolean('trueFalse')(), | 2570 | enumList: commonEnumProviders.boolean('trueFalse')(), |
| @@ -2576,31 +2572,29 @@ export function initDefaultSlashCommands() { | |||
| 2576 | ], | 2572 | ], |
| 2577 | unnamedArgumentList: [ | 2573 | unnamedArgumentList: [ |
| 2578 | SlashCommandArgument.fromProps({ | 2574 | SlashCommandArgument.fromProps({ |
| 2579 | description: 'API url to connect to', | 2575 | description: t`API url to connect to`, |
| 2580 | typeList: [ARGUMENT_TYPE.STRING], | 2576 | typeList: [ARGUMENT_TYPE.STRING], |
| 2581 | }), | 2577 | }), |
| 2582 | ], | 2578 | ], |
| 2583 | helpString: ` | 2579 | helpString: ` |
| 2584 | <div> | 2580 | <div> |
| 2585 | Set the API url / server url for the currently selected API, including the port. If no argument is provided, it will return the current API url. | 2581 | ${t`Set the API url / server url for the currently selected API, including the port. If no argument is provided, it will return the current API url.`} |
| 2586 | </div> | 2582 | </div> |
| 2587 | <div> | 2583 | <div> |
| 2588 | If a manual API is provided to <b>set</b> the URL, make sure to set <code>connect=false</code>, as auto-connect only works for the currently selected API, | 2584 | ${t`If a manual API is provided to <b>set</b> the URL, make sure to set <code>connect=false</code>, as auto-connect only works for the currently selected API, or consider switching to it with <code>/api</code> first.`} |
| 2589 | or consider switching to it with <code>/api</code> first. | ||
| 2590 | </div> | 2585 | </div> |
| 2591 | <div> | 2586 | <div> |
| 2592 | This slash command works for most of the Text Completion sources, KoboldAI Classic, and also Custom OpenAI compatible for the Chat Completion sources. If unsure which APIs are supported, | 2587 | ${t`This slash command works for most of the Text Completion sources, KoboldAI Classic, and also Custom OpenAI compatible for the Chat Completion sources. If unsure which APIs are supported, check the auto-completion of the optional <code>api</code> argument of this command.`} |
| 2593 | check the auto-completion of the optional <code>api</code> argument of this command. | ||
| 2594 | </div> | 2588 | </div> |
| 2595 | `, | 2589 | `, |
| 2596 | })); | 2590 | })); |
| 2597 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2591 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2598 | name: 'tokenizer', | 2592 | name: 'tokenizer', |
| 2599 | callback: selectTokenizerCallback, | 2593 | callback: selectTokenizerCallback, |
| 2600 | returns: 'current tokenizer', | 2594 | returns: t`current tokenizer`, |
| 2601 | unnamedArgumentList: [ | 2595 | unnamedArgumentList: [ |
| 2602 | SlashCommandArgument.fromProps({ | 2596 | SlashCommandArgument.fromProps({ |
| 2603 | description: 'tokenizer name', | 2597 | description: t`tokenizer name`, |
| 2604 | typeList: [ARGUMENT_TYPE.STRING], | 2598 | typeList: [ARGUMENT_TYPE.STRING], |
| 2605 | enumList: getAvailableTokenizers().map(tokenizer => | 2599 | enumList: getAvailableTokenizers().map(tokenizer => |
| 2606 | new SlashCommandEnumValue(tokenizer.tokenizerKey, tokenizer.tokenizerName, enumTypes.enum, enumIcons.default)), | 2600 | new SlashCommandEnumValue(tokenizer.tokenizerKey, tokenizer.tokenizerName, enumTypes.enum, enumIcons.default)), |
| @@ -2608,10 +2602,10 @@ export function initDefaultSlashCommands() { | |||
| 2608 | ], | 2602 | ], |
| 2609 | helpString: ` | 2603 | helpString: ` |
Diff truncated