Merge pull request #3690 from SillyTavern/staging Staging

d8c8bfa8a43f34ba02ff421fc8adcc8376daff61

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

Signed
196 files changed, +3716 -1974Showing whitespace changes
.eslintrc.cjs+1 -0
@@ -75,6 +75,7 @@ module.exports = {
75 'plugins/**',75 'plugins/**',
76 '**/*.min.js',76 '**/*.min.js',
77 'public/scripts/extensions/quick-reply/lib/**',77 'public/scripts/extensions/quick-reply/lib/**',
78 'public/scripts/extensions/tts/lib/**',
78 ],79 ],
79 rules: {80 rules: {
80 'no-unused-vars': ['error', { args: 'none' }],81 'no-unused-vars': ['error', { args: 'none' }],
.github/ISSUE_TEMPLATE/bug-report.yml+1 -0
@@ -1,4 +1,5 @@
1name: Bug Report 🐛1name: Bug Report 🐛
2type: Bug
2description: Report something that's not working the intended way. Support requests for external programs (reverse proxies, 3rd party servers, other peoples' forks) will be refused! Please use English only.3description: Report something that's not working the intended way. Support requests for external programs (reverse proxies, 3rd party servers, other peoples' forks) will be refused! Please use English only.
3title: '[BUG] <title>'4title: '[BUG] <title>'
4labels: ['🐛 Bug']5labels: ['🐛 Bug']
.github/ISSUE_TEMPLATE/feature-request.yml+1 -0
@@ -1,4 +1,5 @@
1name: Feature Request ✨1name: Feature Request ✨
2type: Feature
2description: Suggest an idea for future development of this project. Please use English only.3description: Suggest an idea for future development of this project. Please use English only.
3title: '[FEATURE_REQUEST] <title>'4title: '[FEATURE_REQUEST] <title>'
4labels: ['🦄 Feature Request']5labels: ['🦄 Feature Request']
.github/close-label.yml+0 -2
@@ -1,2 +0,0 @@
1🐛 Bug: ✅ Fixed
2🦄 Feature Request: ✅ Implemented
2 \ No newline at end of file \ No newline at end of file
.github/issue-auto-comments.yml+0 -62
@@ -1,62 +0,0 @@
1comment:
2 footer: |
3 ---
4 > I am a bot, and this is an automated message 🤖
5labels:
6 - name: ✖️ Invalid
7 labeled:
8 issue:
9 action: close
10 body: >
11 Hello @{{ issue.user.login }} your ticket has been marked as invalid.
12 Please ensure you follow the issue template, provide all requested info,
13 and be sure to check the docs + previous issues prior to raising tickets.
14 pr:
15 body: Thank you @{{ pull_request.user.login }} for suggesting this. Please follow the pull request templates.
16 action: close
17
18 - name: 👩‍💻 Good First Issue
19 labeled:
20 issue:
21 body: >
22 This issue has been marked as a good first issue for first-time contributors to implement!
23 This is a great way to support the project, while also improving your skills, you'll also be credited as a contributor once your PR is merged.
24 If you're new to SillyTavern [here are a collection of resources](https://docs.sillytavern.app/)
25 If you need any support at all, feel free to reach out via [Discord](https://discord.gg/sillytavern).
26
27 - name: ❌ wontfix
28 labeled:
29 issue:
30 action: close
31 body: >
32 This ticked has been marked as 'wontfix', which usually means it is out-of-scope, or not feasible at this time.
33 You can still fork the project and make the changes yourself.
34
35 - name: ✅ Fixed
36 labeled:
37 issue:
38 body: >
39 Hello @{{ issue.user.login }}! It looks like all or part of this issue has now been implemented.
40
41
42 - name: ‼️ High Priority
43 labeled:
44 issue:
45 body: >
46 This ticket has been marked as high priority, and has been bumped to the top of the priority list.
47 You should expect an implementation to be pushed out soon. Thank you for your patience.
48
49 - name: 💀 Spam
50 labeled:
51 issue:
52 action: close
53 locking: lock
54 lock_reason: spam
55 body: >
56 This issue has been identified as spam, and is now locked.
57 Users who repeatedly raise spam issues may be blocked or reported.
58
59 - name: ⛔ Don't Merge
60 labeled:
61 pr:
62 body: This PR has been temporarily blocked from merging.
62 \ No newline at end of file \ No newline at end of file
.github/issues-auto-comments.yml+69 -0
@@ -0,0 +1,69 @@
1labels:
2 - name: ✖️ Invalid
3 labeled:
4 issue:
5 action: close
6 body: >
7 Hey @{{ issue.user.login }}, this issue has been marked as invalid.
8
9 Please double-check that you've followed the issue template, included all necessary details, and reviewed the docs & previous issues before submitting.
10 If provided, follow the instructions given by maintainers.
11
12 - name: 👩‍💻 Good First Issue
13 labeled:
14 issue:
15 body: >
16 🏆 This issue has been marked as a good first issue for contributors to implement!
17 This is a great way to support the project. While also improving your skills, you'll also be credited as a contributor once your PR is merged.
18
19 If you're new to SillyTavern [here is the official documentation](https://docs.sillytavern.app/). The official contribution guide can be found [here](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md).
20 If you need any support, feel free to reach out via [Discord](https://discord.gg/sillytavern), or let us know in this issue or via [discussions](https://github.com/SillyTavern/SillyTavern/discussions).
21
22 - name: ❌ wontfix
23 labeled:
24 issue:
25 action: close
26 body: >
27 ❌ This issue has been marked as 'wontfix', which usually means it is out-of-scope, not feasible at this time or will not be implemented for various reasons.
28 If you have any questions about this, feel free to reach out.
29
30 - name: 🛑 Out of Scope
31 labeled:
32 issue:
33 action: close
34 body: >
35 🛑 This issue has been marked as 'out of scope', as this can't or won't be implemented.
36 If you have any questions about this, feel free to reach out.
37
38 - name: ✅ Done (staging)
39 labeled:
40 issue:
41 body: >
42 ✅ It looks like all or part of this issue has now been implemented as part of the `staging` branch.
43 If you currently are on the `release` branch, you can switch to `staging` to test this right away.
44
45 Note that `staging` is considered less stable than the official releases. To switch, follow existing instructions,
46 or simply enter the following command: `git switch staging`
47
48 - name: ✅ Done
49 labeled:
50 issue:
51 body: >
52 ✅ It looks like all or part of this issue has now been implemented as part of the latest release.
53
54 - name: ‼️ High Priority
55 labeled:
56 issue:
57 body: >
58 🚨 This issue has been marked high priority, meaning it's important to the maintainers or community.
59 While we can't promise immediate changes, it is on our radar and will be addressed whenever possible. Thanks for your patience!
60
61 - name: 💀 Spam
62 labeled:
63 issue:
64 action: close
65 locking: lock
66 lock_reason: spam
67 body: >
68 💀 This issue has been flagged as spam and is now locked.
69 Please avoid posting spam - it disrupts the community and wastes everyone's time.
.github/labeler.yml → .github/issues-auto-labels.yml+6 -4
@@ -1,7 +1,3 @@
1# Add/remove 'critical' label if issue contains the words 'urgent' or 'critical'
2#critical:
3# - '(critical|urgent)'
4
5🪟 Windows:1🪟 Windows:
6 - '(🪟 Windows)'2 - '(🪟 Windows)'
73
@@ -16,3 +12,9 @@
1612
17🐧 Linux:13🐧 Linux:
18 - '(🐧 Linux)'14 - '(🐧 Linux)'
15
16🦊 Firefox:
17 - '(firefox|mozilla)'
18
19📱 Mobile:
20 - '(iphone|ios|android|📱 Termux)'
.github/pr-auto-comments.yml+51 -0
@@ -0,0 +1,51 @@
1labels:
2 - name: ✖️ Invalid
3 labeled:
4 pr:
5 action: close
6 body: >
7 Hey @{{ pull_request.user.login }}, thanks for your contribution!
8 Unfortunately, this PR has been marked as invalid.
9
10 Please check that you've followed the PR template, included all relevant details, and are targeting the correct branch (`staging` for regular contributions, `release` only for hotfixes).
11
12 If you need help, feel free to ask!
13
14 - name: ⛔ Don't Merge
15 labeled:
16 pr:
17 body: >
18 🚨 This PR has been temporarily blocked from merging.
19
20 - name: 💥💣 Breaking Changes
21 labeled:
22 pr:
23 body: >
24 ⚠️ Heads up! This PR introduces breaking changes.
25
26 Make sure these changes are well-documented and that users will be properly informed when this is released.
27
28 - name: ⛔ Waiting For External/Upstream
29 labeled:
30 pr:
31 body: >
32 ⛔ This PR is awaiting external or upstream changes or approval.
33 It can only be merged once those changes have been implemented and approved.
34
35 Please inform us of any progress on the upstream changes or approval.
36
37 - name: 🔬 Needs Testing
38 labeled:
39 pr:
40 body: >
41 🔬 This PR needs testing!
42 Any contributor can test and leave reviews, so feel free to help us out!
43
44 - name: 🟥 ⬤⬤⬤⬤⬤
45 labeled:
46 pr:
47 body: >
48 ⚠️ This PR is over 1000 lines, which is larger than recommended.
49
50 Please make sure that it only addresses a single issue - PRs this large are hard to test and may be rejected.
51
.github/pr-auto-labels-by-branch.yml+77 -0
@@ -0,0 +1,77 @@
1####################################
2# Label PRs against 'release' #
3####################################
4❗ Against Release Branch:
5- base-branch: 'release'
6
7####################################
8# Labels based on PR branch name #
9####################################
10🦋 Bug Fix:
11- head-branch: ['^fix[/-]', '\bfixes\b']
12
13🚑 Hot Fix:
14- head-branch: ['^hotfix[/-]']
15
16✨ New Feature:
17- head-branch: ['^feat(ure)?[/-].*?\badd', '^add-']
18
19✨ Feature Changes:
20- head-branch: ['^feat(ure)?[/-](?!.*\badd\b)', '\bchanges?\b']
21
22🤖 API / Model:
23- head-branch: ['\bapi\b', '\bmodels?\b']
24
25🏭 Backend Changes:
26- head-branch: ['\bbackend\b', '\bendpoints?\b']
27
28🐋 Docker:
29- head-branch: ['\bdocker\b']
30
31➕ Extension:
32- head-branch: ['\bextension\b', '\bext\b']
33
34🦊 Firefox:
35- head-branch: ['\bfirefox\b']
36
37🖼️ Image Gen:
38- head-branch: ['\bimage-gen\b']
39
40🌐 Language:
41- head-branch: ['\btranslations?\b', '\blanguages?\b']
42
43🐧 Linux:
44- head-branch: ['\blinux\b']
45
46🧩 Macros:
47- head-branch: ['\bmacros?\b']
48
49📱 Mobile:
50- head-branch: ['\bmobile\b', '\bios\b', '\bandroid\b']
51
52🚄 Performance:
53- head-branch: ['\bperformance\b']
54
55⚙️ Preset:
56- head-branch: ['\bpresets?\b']
57
58📜 Prompt:
59- head-branch: ['\bprompt\b']
60
61🚚 Refactor:
62- head-branch: ['\brefactor(s|ed)?\b']
63
64📜 STscript:
65- head-branch: ['\bstscript\b', '\bslash-commands\b']
66
67🏷️ Tags / Folders:
68- head-branch: ['\btags\b']
69
70🎙️ TTS / Voice:
71- head-branch: ['\btts\b', '\bvoice\b']
72
73🌟 UX:
74- head-branch: ['\bux\b']
75
76🗺️ World Info:
77- head-branch: ['\bworld-info\b', '\bwi\b']
.github/pr-auto-labels-by-files.yml+46 -0
@@ -0,0 +1,46 @@
1####################################
2# Labels based on changed files #
3####################################
4🏭 Backend Changes:
5- changed-files:
6 - any-glob-to-any-file:
7 - "src/**"
8 - "default/config.yaml"
9 - "server.js"
10 - "plugins.js"
11 - "recover.js"
12 - "webpack.config.js"
13 - "Start.bat"
14 - "start.sh"
15 - "UpdateAndStart.bat"
16 - "UpdateForkAndStart.bat"
17
18⚙️ config.yaml:
19- changed-files:
20 - any-glob-to-any-file:
21 - "default/config.yaml"
22
23🛠️ Build Changes:
24- changed-files:
25 - any-glob-to-any-file:
26 - ".github/workflows/**"
27 - "docker/**"
28 - ".dockerignore"
29 - "Dockerfile"
30 - "webpack.config.js"
31
32🌐 Language:
33- changed-files:
34 - any-glob-to-any-file:
35 - "public/locales/**"
36
37📥 Dependencies:
38- changed-files:
39 - any-glob-to-any-file:
40 - "public/lib/**" # Every frontend lib counts as a dependency as well
41 - "package.json"
42 - "package-lock.json"
43 - "tests/package.json"
44 - "tests/package-lock.json"
45 - "src/electron/package.json"
46 - "src/electron/package-lock.json"
.github/readme.md+99 -62
@@ -23,7 +23,7 @@ We have a [Documentation website](https://docs.sillytavern.app/) to answer most
2323
24SillyTavern (or ST for short) is a locally installed user interface that allows you to interact with text generation LLMs, image generation engines, and TTS voice models.24SillyTavern (or ST for short) is a locally installed user interface that allows you to interact with text generation LLMs, image generation engines, and TTS voice models.
2525
26Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 100 contributors and 2 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists.26Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 200 contributors and 2 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists.
2727
28## Our Vision28## Our Vision
2929
@@ -113,7 +113,9 @@ SillyTavern has extensibility support.
113113
114Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern.app/).114Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern.app/).
115115
116# ⌛ Installation116## ⌛ Installation
117
118### 🪟 Windows
117119
118> \[!WARNING]120> \[!WARNING]
119>121>
@@ -121,9 +123,7 @@ Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern
121> * DO NOT RUN START.BAT WITH ADMIN PERMISSIONS123> * DO NOT RUN START.BAT WITH ADMIN PERMISSIONS
122> * INSTALLATION ON WINDOWS 7 IS IMPOSSIBLE AS IT CAN NOT RUN NODEJS 18.16124> * INSTALLATION ON WINDOWS 7 IS IMPOSSIBLE AS IT CAN NOT RUN NODEJS 18.16
123125
124## 🪟 Windows126#### Installing via Git (recommended)
125
126### Installing via Git
127127
1281. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended)1281. Install [NodeJS](https://nodejs.org/en) (latest LTS version is recommended)
1292. Install [Git for Windows](https://gitforwindows.org/)1292. Install [Git for Windows](https://gitforwindows.org/)
@@ -138,7 +138,7 @@ Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern
1387. Once everything is cloned, double-click `Start.bat` to make NodeJS install its requirements.1387. Once everything is cloned, double-click `Start.bat` to make NodeJS install its requirements.
1398. The server will then start, and SillyTavern will pop up in your browser.1398. The server will then start, and SillyTavern will pop up in your browser.
140140
141### Installing via GitHub Desktop141#### Installing via GitHub Desktop
142142
143(This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/))143(This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/))
144144
@@ -152,7 +152,7 @@ Tutorials on how to use them can be found in the [Docs](https://docs.sillytavern
152 9. After the installation process, if everything is working, the command console window should look like this and a SillyTavern tab should be open in your browser:152 9. After the installation process, if everything is working, the command console window should look like this and a SillyTavern tab should be open in your browser:
153 10. Connect to any of the [supported APIs](https://docs.sillytavern.app/usage/api-connections/) and start chatting!153 10. Connect to any of the [supported APIs](https://docs.sillytavern.app/usage/api-connections/) and start chatting!
154154
155## 🐧 Linux & 🍎 MacOS155### 🐧 Linux & 🍎 MacOS
156156
157For MacOS / Linux all of these will be done in a Terminal.157For MacOS / Linux all of these will be done in a Terminal.
158158
@@ -168,6 +168,57 @@ For MacOS / Linux all of these will be done in a Terminal.
168* `./start.sh`168* `./start.sh`
169* `bash start.sh`169* `bash start.sh`
170170
171## 🐋 Installing via Docker
172
173These instructions assume you have installed Docker, are able to access your command line for the installation of containers, and familiar with their general operation.
174
175### Using the GitHub Container Registry
176
177#### Docker Compose (easiest)
178
179Grab the `docker-compose.yml` file from the [GitHub Repository](https://github.com/SillyTavern/SillyTavern/blob/release/docker/docker-compose.yml) and run the following command in the directory where the file is located. This will pull the latest release image from the GitHub Container Registry and start the container, automatically creating the necessary volumes.
180
181```shell
182docker-compose up
183```
184
185Customize the `docker-compose.yml` file to your needs. The default port is 8000. If you want to adjust the server configuration using environment variables, read the documentation [here](https://docs.sillytavern.app/administration/config-yaml/#environment-variables).
186
187#### Docker CLI (advanced)
188
189You will need two mandatory directory mappings and a port mapping to allow SillyTavern to function. In the command, replace your selections in the following places:
190
191#### Container Variables
192
193##### Volume Mappings
194
195* [config] - The directory where SillyTavern configuration files will be stored on your host machine
196* [data] - The directory where SillyTavern user data (including characters) will be stored on your host machine
197* [plugins] - (optional) The directory where SillyTavern server plugins will be stored on your host machine
198* [extensions] - (optional) The directory where global UI extensions will be stored on your host machine
199
200##### Port Mappings
201
202* [PublicPort] - The port to expose the traffic on. This is mandatory, as you will be accessing the instance from outside of its virtual machine container. DO NOT expose this to the internet without implementing a separate service for security.
203
204##### Additional Settings
205
206* [DockerNet] - The docker network that the container should be created with a connection to. If you don't know what it is, see the [official Docker documentation](https://docs.docker.com/reference/cli/docker/network/).
207* [version] - On the right-hand side of this GitHub page, you'll see "Packages". Select the "sillytavern" package and you'll see the image versions. The image tag "latest" will keep you up-to-date with the current release. You can also utilize "staging" and "release" tags that point to the nightly images of the respective branches, but this may not be appropriate, if you are utilizing extensions that could be broken, and may need time to update.
208
209#### Install command
210
2111. Open your Command Line
2122. Run the following command
213
214`docker run --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' -v '[extensions]':'/home/node/app/public/scripts/extensions/third-party':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'`
215
216> Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config.
217
218### Building the image yourself
219
220We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself.
221
171## ⚡ Installing via SillyTavern Launcher222## ⚡ Installing via SillyTavern Launcher
172223
173SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference.224SillyTavern Launcher is an installation wizard that will help you get setup with many options, including installing a backend for local inference.
@@ -239,45 +290,6 @@ chmod +x install.sh && ./install.sh
239chmod +x launcher.sh && ./launcher.sh290chmod +x launcher.sh && ./launcher.sh
240```291```
241292
242## 🐋 Installing via Docker
243
244These instructions assume you have installed Docker, are able to access your command line for the installation of containers, and familiar with their general operation.
245
246### Building the image yourself
247
248We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself.
249
250### Using the GitHub Container Registry (easiest)
251
252You will need two mandatory directory mappings and a port mapping to allow SillyTavern to function. In the command, replace your selections in the following places:
253
254#### Container Variables
255
256##### Volume Mappings
257
258* [config] - The directory where SillyTavern configuration files will be stored on your host machine
259* [data] - The directory where SillyTavern user data (including characters) will be stored on your host machine
260* [plugins] - (optional) The directory where SillyTavern server plugins will be stored on your host machine
261* [extensions] - (optional) The directory where global UI extensions will be stored on your host machine
262
263##### Port Mappings
264
265* [PublicPort] - The port to expose the traffic on. This is mandatory, as you will be accessing the instance from outside of its virtual machine container. DO NOT expose this to the internet without implementing a separate service for security.
266
267##### Additional Settings
268
269* [DockerNet] - The docker network that the container should be created with a connection to. If you don't know what it is, see the [official Docker documentation](https://docs.docker.com/reference/cli/docker/network/).
270* [version] - On the right-hand side of this GitHub page, you'll see "Packages". Select the "sillytavern" package and you'll see the image versions. The image tag "latest" will keep you up-to-date with the current release. You can also utilize "staging" and "release" tags that point to the nightly images of the respective branches, but this may not be appropriate, if you are utilizing extensions that could be broken, and may need time to update.
271
272#### Install command
273
2741. Open your Command Line
2752. Run the following command
276
277`docker run --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' -v '[extensions]':'/home/node/app/public/scripts/extensions/third-party':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'`
278
279> Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config.
280
281## 📱 Installing via Termux on Android OS293## 📱 Installing via Termux on Android OS
282294
283> \[!NOTE]295> \[!NOTE]
@@ -317,29 +329,34 @@ Start.bat --port 8000 --listen false
317329
318### Supported arguments330### Supported arguments
319331
332> \[!TIP]
333> None of the arguments are required. If you don't provide them, SillyTavern will use the settings in `config.yaml`.
334
320| Option | Description | Type |335| Option | Description | Type |
321|-------------------------|------------------------------------------------------------------------------------------------------|----------|336|-------------------------|----------------------------------------------------------------------|----------|
322| `--version` | Show version number | boolean |337| `--version` | Show version number | boolean |
323| `--enableIPv6` | Enables IPv6. | boolean |
324| `--enableIPv4` | Enables IPv4. | boolean |
325| `--port` | Sets the port under which SillyTavern will run. If not provided falls back to yaml config 'port'. | number |
326| `--dnsPreferIPv6` | Prefers IPv6 for dns. If not provided falls back to yaml config 'preferIPv6'. | boolean |
327| `--autorun` | Automatically launch SillyTavern in the browser. If not provided falls back to yaml config 'autorun'.| boolean |
328| `--autorunHostname` | The autorun hostname, probably best left on 'auto'. | string |
329| `--autorunPortOverride` | Overrides the port for autorun. | string |
330| `--listen` | SillyTavern is listening on all network interfaces. If not provided falls back to yaml config 'listen'.| boolean |
331| `--corsProxy` | Enables CORS proxy. If not provided falls back to yaml config 'enableCorsProxy'. | boolean |
332| `--disableCsrf` | Disables CSRF protection | boolean |
333| `--ssl` | Enables SSL | boolean |
334| `--certPath` | Path to your certificate file. | string |
335| `--keyPath` | Path to your private key file. | string |
336| `--whitelist` | Enables whitelist mode | boolean |
337| `--dataRoot` | Root directory for data storage | string |338| `--dataRoot` | Root directory for data storage | string |
338| `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode. | boolean |339| `--port` | Sets the port under which SillyTavern will run | number |
340| `--listen` | SillyTavern will listen on all network interfaces | boolean |
341| `--whitelist` | Enables whitelist mode | boolean |
339| `--basicAuthMode` | Enables basic authentication | boolean |342| `--basicAuthMode` | Enables basic authentication | boolean |
343| `--enableIPv4` | Enables IPv4 protocol | boolean |
344| `--enableIPv6` | Enables IPv6 protocol | boolean |
345| `--listenAddressIPv4` | Specific IPv4 address to listen to | string |
346| `--listenAddressIPv6` | Specific IPv6 address to listen to | string |
347| `--dnsPreferIPv6` | Prefers IPv6 for DNS | boolean |
348| `--ssl` | Enables SSL | boolean |
349| `--certPath` | Path to your certificate file | string |
350| `--keyPath` | Path to your private key file | string |
351| `--autorun` | Automatically launch SillyTavern in the browser | boolean |
352| `--autorunHostname` | Autorun hostname | string |
353| `--autorunPortOverride` | Overrides the port for autorun | string |
354| `--avoidLocalhost` | Avoids using 'localhost' for autorun in auto mode | boolean |
355| `--corsProxy` | Enables CORS proxy | boolean |
340| `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean |356| `--requestProxyEnabled` | Enables a use of proxy for outgoing requests | boolean |
341| `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string |357| `--requestProxyUrl` | Request proxy URL (HTTP or SOCKS protocols) | string |
342| `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array |358| `--requestProxyBypass` | Request proxy bypass list (space separated list of hosts) | array |
359| `--disableCsrf` | Disables CSRF protection (NOT RECOMMENDED) | boolean |
343360
344## Remote connections361## Remote connections
345362
@@ -351,10 +368,29 @@ You may also want to configure SillyTavern user profiles with (optional) passwor
351368
352## Performance issues?369## Performance issues?
353370
371### General tips
372
3541. Disable the Blur Effect and enable Reduced Motion on the User Settings panel (UI Theme toggles category).3731. Disable the Blur Effect and enable Reduced Motion on the User Settings panel (UI Theme toggles category).
3552. If using response streaming, set the streaming FPS to a lower value (10-15 FPS is recommended).3742. If using response streaming, set the streaming FPS to a lower value (10-15 FPS is recommended).
3563. Make sure the browser is enabled to use GPU acceleration for rendering.3753. Make sure the browser is enabled to use GPU acceleration for rendering.
357376
377### Input lag
378
379Performance degradation, particularly input lag, is most commonly attributed to browser extensions. Known problematic extensions include:
380
381* iCloud Password Manager
382* DeepL Translation
383* AI-based grammar correction tools
384* Various ad-blocking extensions
385
386If you experience performance issues and cannot identify the cause, or suspect an issue with SillyTavern itself, please:
387
3881. [Record a performance profile](https://developer.chrome.com/docs/devtools/performance/reference)
3892. Export the profile as a JSON file
3903. Submit it to the development team for analysis
391
392We recommend first testing with all browser extensions and third-party SillyTavern extensions disabled to isolate the source of the performance degradation.
393
358## License and credits394## License and credits
359395
360**This program is distributed in the hope that it will be useful,396**This program is distributed in the hope that it will be useful,
@@ -369,6 +405,7 @@ GNU Affero General Public License for more details.**
369* Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)405* Icon theme by Font Awesome <https://fontawesome.com> (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
370* Default content by @OtisAlejandro (Seraphina character and lorebook) and @kallmeflocc (10K Discord Users Celebratory Background)406* Default content by @OtisAlejandro (Seraphina character and lorebook) and @kallmeflocc (10K Discord Users Celebratory Background)
371* Docker guide by [@mrguymiah](https://github.com/mrguymiah) and [@Bronya-Rand](https://github.com/Bronya-Rand)407* Docker guide by [@mrguymiah](https://github.com/mrguymiah) and [@Bronya-Rand](https://github.com/Bronya-Rand)
408* kokoro-js library by [@hexgrad](https://github.com/hexgrad) (Apache-2.0 License)
372409
373## Top Contributors410## Top Contributors
374411
.github/workflows/add-comment-from-tag.yml+0 -28
@@ -1,28 +0,0 @@
1# Based on a label applied to an issue, the bot will add a comment with some additional info
2
3name: 🎯 Auto-Reply to Labeled Tickets
4on:
5 issues:
6 types:
7 - labeled
8 - unlabeled
9 pull_request_target:
10 types:
11 - labeled
12 - unlabeled
13permissions:
14 contents: read
15 issues: write
16 pull-requests: write
17
18jobs:
19 comment:
20 runs-on: ubuntu-20.04
21 steps:
22 - name: Checkout
23 uses: actions/checkout@v2
24 - name: Label Commenter
25 uses: peaceiris/actions-label-commenter@v1
26 with:
27 config_file: .github/issue-auto-comments.yml
28 github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
28 \ No newline at end of file \ No newline at end of file
.github/workflows/check-merge-conflicts.yml+0 -17
@@ -1,17 +0,0 @@
1# Detect and label pull requests that have merge conflicts
2name: 🏗️ Check Merge Conflicts
3on:
4 push:
5 branches:
6 - staging
7jobs:
8 check-conflicts:
9 if: github.repository == 'SillyTavern/SillyTavern'
10 runs-on: ubuntu-latest
11 steps:
12 - uses: mschilde/auto-label-merge-conflicts@master
13 with:
14 CONFLICT_LABEL_NAME: "🚫 Merge Conflicts"
15 GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
16 MAX_RETRIES: 5
17 WAIT_MS: 5000
17 \ No newline at end of file \ No newline at end of file
.github/workflows/close-stale-issues.yml+0 -82
@@ -1,82 +0,0 @@
1# Closes any issues that no longer have user interaction
2name: 🎯 Close Stale Issues
3
4on:
5 workflow_dispatch:
6 schedule:
7 - cron: '0 0 * * *' # Runs every day at midnight UTC
8
9jobs:
10 stale:
11 runs-on: ubuntu-latest
12
13 steps:
14 # Comment on, then close issues that haven't been updated for ages
15 - name: Close Stale Issues
16 uses: actions/stale@v4
17 with:
18 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
19 days-before-stale: 183
20 days-before-close: 7
21 operations-per-run: 30
22 remove-stale-when-updated: true
23 enable-statistics: true
24 stale-issue-message: >
25 This issue has gone 6 months without an update. To keep the ticket open, please indicate that it is still relevant in a comment below.
26 Otherwise it will be closed in 7 days.
27 stale-pr-message: >
28 This PR is stale because it has been open 6 months with no activity. Either remove the stale label or comment below with a short update,
29 otherwise this PR will be closed in 7 days.
30 close-issue-message: >
31 This issue was automatically closed because it has been stalled for over 6 months with no activity.
32 close-pr-message: >
33 This pull request was automatically closed because it has been stalled for over 6 months with no activity.
34 stale-issue-label: '⚰️ Stale'
35 close-issue-label: '🕸️ Inactive'
36 stale-pr-label: '⚰️ Stale'
37 close-pr-label: '🕸️ Inactive'
38 exempt-issue-labels: '📌 Keep Open'
39 exempt-pr-labels: '📌 Keep Open'
40 labels-to-add-when-unstale: '📌 Keep Open'
41
42 # Comment on, then close issues that required a response from the user, but didn't get one
43 - name: Close Issues without Response
44 uses: actions/stale@v4
45 with:
46 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
47 days-before-stale: 7
48 days-before-close: 7
49 operations-per-run: 30
50 remove-stale-when-updated: true
51 stale-issue-message: >
52 Hi! Looks like additional info is required for this issue to be addressed.
53 Don't forget to provide this within the next few days to keep your ticket open.
54 close-issue-message: 'Issue closed due to no response from user.'
55 only-labels: '🚏 Awaiting User Response'
56 labels-to-remove-when-unstale: '🚏 Awaiting User Response, 🛑 No Response'
57 stale-issue-label: '🛑 No Response'
58 close-issue-label: '🕸️ Inactive'
59 exempt-issue-labels: '📌 Keep Open'
60 exempt-pr-labels: '📌 Keep Open'
61
62 # Comment on issues that we should have replied to
63 - name: Notify Repo Owner to Respond
64 uses: actions/stale@v4
65 with:
66 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
67 days-before-stale: 7
68 days-before-close: 183
69 operations-per-run: 30
70 remove-stale-when-updated: true
71 stale-issue-message: Hey SillyTavern, - Don't forget to respond!
72 stale-pr-message: Hey SillyTavern, - Don't forget to respond!
73 only-labels: '👤 Awaiting Maintainer Response'
74 labels-to-remove-when-unstale: '👤 Awaiting Maintainer Response'
75 close-issue-message: 'Closed due to no response from repo author for over a year'
76 close-pr-message: 'Closed due to no response from repo author for over a year'
77 stale-issue-label: '👤 Awaiting Maintainer Response'
78 stale-pr-label: '👤 Awaiting Maintainer Response'
79 close-issue-label: '🕸️ Inactive'
80 close-pr-label: '🕸️ Inactive'
81 exempt-issue-labels: '📌 Keep Open'
82 exempt-pr-labels: '📌 Keep Open'
.github/workflows/get-pr-size.yml+0 -39
@@ -1,39 +0,0 @@
1# Adds a comment to new PRs, showing the compressed size and size difference of new code
2# And also labels the PR based on the number of lines changes
3
4name: 🌈 Check PR Size
5on: [pull_request]
6jobs:
7 build:
8 runs-on: ubuntu-latest
9 steps:
10 - name: Checkout
11 uses: actions/checkout@v2
12 # Find and comment with compressed size
13 - name: Get Compressed Size
14 uses: preactjs/compressed-size-action@v2
15 with:
16 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
17 pattern: './dist/**/*.{js,css,html}'
18 strip-hash: '\\b\\w{8}\\.'
19 exclude: '**/node_modules/**'
20 minimum-change-threshold: 100
21 # Check number of lines of code added
22 - name: Label based on Lines of Code
23 uses: codelytv/pr-size-labeler@v1
24 with:
25 GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
26 xs_max_size: '10'
27 s_max_size: '100'
28 m_max_size: '500'
29 l_max_size: '1000'
30 s_label: '🟩 PR - Small'
31 m_label: '🟨 PR - Medium'
32 l_label: '🟧 PR - Large'
33 xl_label: '🟥 PR - XL'
34 fail_if_xl: 'false'
35 message_if_xl: >
36 It looks like this PR is very large (over 1000 lines).
37 Try to avoid addressing multiple issues in a single PR, and
38 in the future consider breaking large tasks down into smaller steps.
39 This it to make reviewing, testing, reverting and general quality management easier.
39 \ No newline at end of file \ No newline at end of file
.github/workflows/issues-auto-manager.yml+112 -0
@@ -0,0 +1,112 @@
1name: 🛠️ Issues Manager
2
3on:
4 issues:
5 types: [opened, edited, labeled, unlabeled]
6 # Re also listen to comments, to remove stale labels right away
7 issue_comment:
8 types: [created]
9
10jobs:
11 label-on-content:
12 name: 🏷️ Label Issues by Content
13 runs-on: ubuntu-latest
14
15 steps:
16 - name: Checkout Repository
17 # Checkout
18 # https://github.com/marketplace/actions/checkout
19 uses: actions/checkout@v4
20
21 - name: Auto-Label Issues (Based on Issue Content)
22 # only auto label based on issue content once, on open (to prevent re-labeling removed labels)
23 if: github.event.action == 'opened'
24
25 # Issue Labeler
26 # https://github.com/marketplace/actions/regex-issue-labeler
27 uses: github/issue-labeler@v3
28 with:
29 configuration-path: .github/issues-auto-labels.yml
30 enable-versioned-regex: 0
31 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
32
33 label-on-labels:
34 name: 🏷️ Label Issues by Labels
35 runs-on: ubuntu-latest
36
37 steps:
38 - name: ✅ Add "👍 Approved" for relevant labels
39 if: contains(fromJSON('["👩‍💻 Good First Issue", "🙏 Help Wanted", "🪲 Confirmed", "⚠️ High Priority", "❕ Medium Priority", "💤 Low Priority"]'), github.event.label.name)
40 # 🤖 Issues Helper
41 # https://github.com/marketplace/actions/issues-helper
42 uses: actions-cool/issues-helper@v3
43 with:
44 actions: 'add-labels'
45 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
46 labels: '👍 Approved'
47
48 - name: ❌ Remove progress labels when issue is marked done or stale
49 if: contains(fromJSON('["✅ Done", "✅ Done (staging)", "⚰️ Stale", "❌ wontfix"]'), github.event.label.name)
50 # 🤖 Issues Helper
51 # https://github.com/marketplace/actions/issues-helper
52 uses: actions-cool/issues-helper@v3
53 with:
54 actions: 'remove-labels'
55 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
56 labels: '🧑‍💻 In Progress,🤔 Unsure,🤔 Under Consideration'
57
58 - name: ❌ Remove temporary labels when confirmed labels are added
59 if: contains(fromJSON('["❌ wontfix","👍 Approved","👩‍💻 Good First Issue"]'), github.event.label.name)
60 # 🤖 Issues Helper
61 # https://github.com/marketplace/actions/issues-helper
62 uses: actions-cool/issues-helper@v3
63 with:
64 actions: 'remove-labels'
65 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
66 labels: '🤔 Unsure,🤔 Under Consideration'
67
68 - name: ❌ Remove no bug labels when "🪲 Confirmed" is added
69 if: github.event.label.name == '🪲 Confirmed'
70 # 🤖 Issues Helper
71 # https://github.com/marketplace/actions/issues-helper
72 uses: actions-cool/issues-helper@v3
73 with:
74 actions: 'remove-labels'
75 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
76 labels: '✖️ Not Reproducible,✖️ Not A Bug'
77
78 remove-stale-label:
79 name: 🗑️ Remove Stale Label on Comment
80 runs-on: ubuntu-latest
81 # Only run this on new comments, to automatically remove the stale label
82 if: github.event_name == 'issue_comment' && github.actor != 'github-actions[bot]'
83
84 steps:
85 - name: Remove Stale Label
86 # 🤖 Issues Helper
87 # https://github.com/marketplace/actions/issues-helper
88 uses: actions-cool/issues-helper@v3
89 with:
90 actions: 'remove-labels'
91 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
92 issue-number: ${{ github.event.issue.number }}
93 labels: '⚰️ Stale,🕸️ Inactive,🚏 Awaiting User Response,🛑 No Response'
94
95 write-auto-comments:
96 name: 💬 Post Issue Comments Based on Labels
97 needs: [label-on-content, label-on-labels]
98 runs-on: ubuntu-latest
99
100 steps:
101 - name: Checkout Repository
102 # Checkout
103 # https://github.com/marketplace/actions/checkout
104 uses: actions/checkout@v4
105
106 - name: Post Issue Comments Based on Labels
107 # Label Commenter
108 # https://github.com/marketplace/actions/label-commenter
109 uses: peaceiris/actions-label-commenter@v1
110 with:
111 config_file: .github/issues-auto-comments.yml
112 github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
.github/workflows/issues-updates-on-merge.yml+41 -0
@@ -0,0 +1,41 @@
1name: 🔄 Update Issues on Push
2
3on:
4 push:
5 branches:
6 - staging
7 - release
8
9jobs:
10 # This runs commits to staging/release, reading the commit messages. Check `pr-auto-manager.yml`:`update-linked-issues` for PR-linked updates.
11 update-linked-issues:
12 name: 🔗 Mark Linked Issues Done on Push
13 runs-on: ubuntu-latest
14
15 steps:
16 - name: Checkout Repository
17 # Checkout
18 # https://github.com/marketplace/actions/checkout
19 uses: actions/checkout@v4
20
21 - name: Extract Linked Issues from Commit Message
22 id: extract_issues
23 run: |
24 ISSUES=$(git log -1 --pretty=%B | grep -oiE '(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #([0-9]+)' | awk '{print $2}' | tr -d '#' | jq -R -s -c 'split("\n")[:-1]')
25 echo "issues=$ISSUES" >> $GITHUB_ENV
26
27 - name: Label Linked Issues
28 id: label_linked_issues
29 env:
30 GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
31 run: |
32 for ISSUE in $(echo $issues | jq -r '.[]'); do
33 if [ "${{ github.ref }}" == "refs/heads/staging" ]; then
34 LABEL="✅ Done (staging)"
35 gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL"
36 elif [ "${{ github.ref }}" == "refs/heads/release" ]; then
37 LABEL="✅ Done"
38 gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL"
39 fi
40 echo "Added label '$LABEL' to issue #$ISSUE"
41 done
.github/workflows/job-close-stale.yml+95 -0
@@ -0,0 +1,95 @@
1name: 🕒 Close Stale Issues/PRs Workflow
2
3on:
4 # Run the workflow every day
5 workflow_dispatch:
6 schedule:
7 - cron: '0 0 * * *' # Runs every day at midnight UTC
8
9jobs:
10 mark-inactivity:
11 name: ⏳ Mark Issues/PRs without Activity
12 runs-on: ubuntu-latest
13
14 steps:
15 - name: Mark Issues/PRs without Activity
16 # Close Stale Issues and PRs
17 # https://github.com/marketplace/actions/close-stale-issues
18 uses: actions/stale@v9
19 with:
20 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
21 days-before-stale: 183
22 days-before-close: 7
23 operations-per-run: 30
24 remove-stale-when-updated: true
25 enable-statistics: true
26 stale-issue-message: >
27 ⏳ This issue has been inactive for 6 months. If it's still relevant, drop a comment below to keep it open.
28 Otherwise, it will be auto-closed in 7 days.
29 stale-pr-message: >
30 ⏳ This PR has been inactive for 6 months. If it's still relevant, update it or remove the stale label.
31 Otherwise, it will be auto-closed in 7 days.
32 close-issue-message: >
33 🔒 This issue was auto-closed due to inactivity for over 6 months.
34 close-pr-message: >
35 🔒 This PR was auto-closed due to inactivity for over 6 months.
36 stale-issue-label: '⚰️ Stale'
37 close-issue-label: '🕸️ Inactive'
38 stale-pr-label: '⚰️ Stale'
39 close-pr-label: '🕸️ Inactive'
40 exempt-issue-labels: '📌 Keep Open'
41 exempt-pr-labels: '📌 Keep Open'
42
43 await-user-response:
44 name: ⚠️ Mark Issues/PRs Awaiting User Response
45 runs-on: ubuntu-latest
46 needs: mark-inactivity
47
48 steps:
49 - name: Mark Issues/PRs Awaiting User Response
50 # Close Stale Issues and PRs
51 # https://github.com/marketplace/actions/close-stale-issues
52 uses: actions/stale@v9
53 with:
54 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
55 days-before-stale: 7
56 days-before-close: 7
57 operations-per-run: 30
58 remove-stale-when-updated: true
59 stale-issue-message: >
60 ⚠️ Hey! We need some more info to move forward with this issue.
61 Please provide the requested details in the next few days to keep this ticket open.
62 close-issue-message: >
63 🔒 This issue was auto-closed due to no response from user.
64 only-labels: '🚏 Awaiting User Response'
65 labels-to-remove-when-unstale: '🚏 Awaiting User Response'
66 stale-issue-label: '🛑 No Response'
67 close-issue-label: '🕸️ Inactive'
68 exempt-issue-labels: '🚧 Alternative Exists'
69
70 alternative-exists:
71 name: 🔄 Mark Issues with Alternative Exists
72 runs-on: ubuntu-latest
73 needs: await-user-response
74
75 steps:
76 - name: Mark Issues with Alternative Exists
77 # Close Stale Issues and PRs
78 # https://github.com/marketplace/actions/close-stale-issues
79 uses: actions/stale@v9
80 with:
81 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
82 days-before-stale: 7
83 days-before-close: 7
84 operations-per-run: 30
85 remove-stale-when-updated: true
86 stale-issue-message: >
87 🔄 An alternative solution has been provided for this issue.
88 Did this solve your problem? If so, we'll go ahead and close it.
89 If you still need help, drop a comment within the next 7 days to keep this open.
90 close-issue-message: >
91 ✅ Closing this issue due to no confirmation on the alternative solution.
92 only-labels: '🚧 Alternative Exists'
93 stale-issue-label: '🚏 Awaiting User Response'
94 close-issue-label: '🕸️ Inactive'
95 exempt-issue-labels: '📌 Keep Open'
.github/workflows/labeler.yml+0 -19
@@ -1,19 +0,0 @@
1name: "Issue Labeler"
2on:
3 issues:
4 types: [opened, edited]
5
6permissions:
7 issues: write
8 contents: read
9
10jobs:
11 triage:
12 runs-on: ubuntu-latest
13 steps:
14 - uses: github/issue-labeler@v3.4
15 with:
16 configuration-path: .github/labeler.yml
17# not-before: 2020-01-15T02:54:32Z # optional and will result in any issues prior to this timestamp to be ignored.
18 enable-versioned-regex: 0
19 repo-token: ${{ github.token }}
19 \ No newline at end of file \ No newline at end of file
.github/workflows/manage-pending-labels-closed.yml+0 -17
@@ -1,17 +0,0 @@
1# When a new comment is added to an issue, if it had the Stale or Awaiting User Response labels, then those labels will be removed
2
3name: 🎯 Remove Pending Labels on Close
4on:
5 issues:
6 types: [closed]
7jobs:
8 remove-labels:
9 runs-on: ubuntu-latest
10 steps:
11 - name: Remove Labels when Closed
12 uses: actions-cool/issues-helper@v2
13 with:
14 actions: remove-labels
15 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
16 issue-number: ${{ github.event.issue.number }}
17 labels: '🚏 Awaiting User Response,⚰️ Stale,👤 Awaiting Maintainer Response'
17 \ No newline at end of file \ No newline at end of file
.github/workflows/manage-pending-labels.yml+0 -42
@@ -1,42 +0,0 @@
1# When a new comment is added to an issue, if it had the Stale or Awaiting User Response labels, then those labels will be removed
2
3name: 🎯 Add/ Remove Awaiting Response Labels
4on:
5 issue_comment:
6 types: [created]
7jobs:
8 remove-stale:
9 runs-on: ubuntu-latest
10 if: ${{ github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' }}
11 steps:
12 - name: Remove Stale labels when Updated
13 uses: actions-cool/issues-helper@v2
14 with:
15 actions: remove-labels
16 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
17 issue-number: ${{ github.event.issue.number }}
18 labels: '🚏 Awaiting User Response,⚰️ Stale'
19
20 add-awaiting-author:
21 runs-on: ubuntu-latest
22 if: ${{!github.event.issue.pull_request && github.event.comment.author_association != 'COLLABORATOR' && github.event.comment.author_association != 'OWNER' && github.event.issue.state == 'open' }}
23 steps:
24 - name: Add Awaiting Author labels when Updated
25 uses: actions-cool/issues-helper@v2
26 with:
27 actions: add-labels
28 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
29 issue-number: ${{ github.event.issue.number }}
30 labels: '👤 Awaiting Maintainer Response'
31
32 remove-awaiting-author:
33 runs-on: ubuntu-latest
34 if: ${{ github.event.comment.author_association == 'OWNER' }}
35 steps:
36 - name: Remove Awaiting Author labels when Updated
37 uses: actions-cool/issues-helper@v2
38 with:
39 actions: remove-labels
40 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
41 issue-number: ${{ github.event.issue.number }}
42 labels: '👤 Awaiting Maintainer Response'
42 \ No newline at end of file \ No newline at end of file
.github/workflows/on-close-handler.yml+23 -0
@@ -0,0 +1,23 @@
1name: 🚪 Issues/PRs On Close Handler
2
3on:
4 issues:
5 types: [closed]
6 pull_request_target:
7 types: [closed]
8
9jobs:
10 remove-labels:
11 name: 🗑️ Remove Pending Labels on Close
12 runs-on: ubuntu-latest
13
14 steps:
15 - name: Remove Pending Labels on Close
16 # 🤖 Issues Helper
17 # https://github.com/marketplace/actions/issues-helper
18 uses: actions-cool/issues-helper@v3
19 with:
20 actions: remove-labels
21 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
22 issue-number: ${{ github.event.issue.number || github.event.pull_request.number }}
23 labels: '🚏 Awaiting User Response,🧑‍💻 In Progress,📌 Keep Open,🚫 Merge Conflicts,🔬 Needs Testing,🔨 Needs Work,⚰️ Stale,⛔ Waiting For External/Upstream'
.github/workflows/on-open-handler.yml+24 -0
@@ -0,0 +1,24 @@
1name: 📨 Issues/PRs Open Handler
2
3on:
4 issues:
5 types: [opened]
6 pull_request_target:
7 types: [opened]
8
9jobs:
10 label-maintainer:
11 name: 🏷️ Label if Author is a Repo Maintainer
12 runs-on: ubuntu-latest
13 if: contains(fromJson('["Cohee1207", "RossAscends", "Wolfsblvt"]'), github.actor)
14
15 steps:
16 - name: Label if Author is a Repo Maintainer
17 # 🤖 Issues Helper
18 # https://github.com/marketplace/actions/issues-helper
19 uses: actions-cool/issues-helper@v3
20 with:
21 actions: 'add-labels'
22 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
23 issue-number: ${{ github.event.issue.number || github.event.pull_request.number }}
24 labels: '👷 Maintainer'
.github/workflows/pr-auto-manager.yml+192 -0
@@ -0,0 +1,192 @@
1name: 🔀 Pull Request Manager
2
3on:
4 pull_request_target:
5 types: [opened, synchronize, reopened, edited, labeled, unlabeled, closed]
6 pull_request_review_comment:
7 types: [created]
8
9jobs:
10 label-by-size:
11 name: 🏷️ Label PR by Size
12 runs-on: ubuntu-latest
13
14 steps:
15 - name: Label PR Size
16 # Pull Request Size Labeler
17 # https://github.com/marketplace/actions/pull-request-size-labeler
18 uses: codelytv/pr-size-labeler@v1
19 with:
20 GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
21 xs_label: '🟩 ⬤○○○○'
22 xs_max_size: '20'
23 s_label: '🟩 ⬤⬤○○○'
24 s_max_size: '100'
25 m_label: '🟨 ⬤⬤⬤○○'
26 m_max_size: '500'
27 l_label: '🟧 ⬤⬤⬤⬤○'
28 l_max_size: '1000'
29 xl_label: '🟥 ⬤⬤⬤⬤⬤'
30 fail_if_xl: 'false'
31 github_api_url: 'https://api.github.com'
32 files_to_ignore: |
33 "package-lock.json"
34 "public/lib/*"
35
36 label-by-branches:
37 name: 🏷️ Label PR by Branches
38 runs-on: ubuntu-latest
39 # Only label once when PR is created or branches are changed, to allow manual label removal
40 if: github.event.action == 'opened' || (github.event.action == 'synchronize' && (github.event.changes.base || github.event.changes.head))
41
42 steps:
43 - name: Checkout Repository
44 # Checkout
45 # https://github.com/marketplace/actions/checkout
46 uses: actions/checkout@v4
47
48 - name: Apply Labels Based on Branch Name and Target Branch
49 # Pull Request Labeler
50 # https://github.com/marketplace/actions/labeler
51 uses: actions/labeler@v5
52 with:
53 configuration-path: .github/pr-auto-labels-by-branch.yml
54 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
55
56 label-by-files:
57 name: 🏷️ Label PR by Files
58 runs-on: ubuntu-latest
59
60 steps:
61 - name: Checkout Repository
62 # Checkout
63 # https://github.com/marketplace/actions/checkout
64 uses: actions/checkout@v4
65
66 - name: Apply Labels Based on Changed Files
67 # Pull Request Labeler
68 # https://github.com/marketplace/actions/labeler
69 uses: actions/labeler@v5
70 with:
71 configuration-path: .github/pr-auto-labels-by-files.yml
72 repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
73
74 remove-stale-label:
75 name: 🗑️ Remove Stale Label on Comment
76 runs-on: ubuntu-latest
77 # Only runs when this is not done by the github actions bot
78 if: github.actor != 'github-actions[bot]'
79
80 steps:
81 - name: Remove Stale Label
82 # 🤖 Issues Helper
83 # https://github.com/marketplace/actions/issues-helper
84 uses: actions-cool/issues-helper@v3
85 with:
86 actions: 'remove-labels'
87 token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
88 issue-number: ${{ github.event.pull_request.number }}
89 labels: '⚰️ Stale'
90
91 check-merge-blocking-labels:
92 name: 🚫 Check Merge Blocking Labels
93 needs: [label-by-branches, label-by-files]
94 runs-on: ubuntu-latest
95 # Run, even if the previous jobs were skipped/failed
96 if: always()
97
98 steps:
99 - name: Check Merge Blocking
100 # GitHub Script
101 # https://github.com/marketplace/actions/github-scriptLabels
102 id: label-check
103 uses: actions/github-script@v7
104 with:
105 script: |
106 const prLabels = context.payload.pull_request.labels.map(label => label.name);
107 const blockingLabels = [
108 "⛔ Don't Merge",
109 "🔨 Needs Work",
110 "🔬 Needs Testing",
111 "⛔ Waiting For External/Upstream",
112 "❗ Against Release Branch",
113 "💥💣 Breaking Changes"
114 ];
115 const hasBlockingLabel = prLabels.some(label => blockingLabels.includes(label));
116
117 if (hasBlockingLabel) {
118 console.log("Blocking label detected. Setting warning status.");
119 await github.rest.checks.create({
120 owner: context.repo.owner,
121 repo: context.repo.repo,
122 name: "PR Label Warning",
123 head_sha: context.payload.pull_request.head.sha,
124 status: "completed",
125 conclusion: "neutral",
126 output: {
127 title: "Potential Merge Issue",
128 summary: "This PR has a merge-blocking label. Proceed with caution."
129 }
130 });
131 } else {
132 console.log("No merge-blocking labels found.");
133 }
134
135 write-auto-comments:
136 name: 💬 Post PR Comments Based on Labels
137 needs: [label-by-size, label-by-branches, label-by-files]
138 runs-on: ubuntu-latest
139 # Run, even if the previous jobs were skipped/failed
140 if: always()
141
142 steps:
143 - name: Checkout Repository
144 # Checkout
145 # https://github.com/marketplace/actions/checkout
146 uses: actions/checkout@v4
147
148 - name: Post PR Comments Based on Labels
149 # Label Commenter for PRs
150 # https://github.com/marketplace/actions/label-commenter
151 uses: peaceiris/actions-label-commenter@v1
152 with:
153 config_file: .github/pr-auto-comments.yml
154 github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
155
156 # This runs on merged PRs to staging, reading the PR body and directly linked issues. Check `issues-updates-on-merge.yml`:`update-linked-issues` for commit-based updates.
157 update-linked-issues:
158 name: 🔗 Mark Linked Issues Done on Staging Merge
159 runs-on: ubuntu-latest
160 if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'staging'
161
162 steps:
163 - name: Extract Linked Issues From PR Description
164 id: extract_issues
165 run: |
166 ISSUES=$(jq -r '.pull_request.body' "$GITHUB_EVENT_PATH" | grep -oiE '(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #([0-9]+)' | awk '{print $2}' | tr -d '#' | jq -R -s -c 'split("\n")[:-1]')
167 echo "issues=$ISSUES" >> $GITHUB_ENV
168
169 - name: Fetch Directly Linked Issues
170 id: fetch_linked_issues
171 run: |
172 PR_NUMBER=${{ github.event.pull_request.number }}
173 REPO=${{ github.repository }}
174 API_URL="https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/issues"
175 ISSUES=$(curl -s -H "Authorization: token ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}" "$API_URL" | jq -r '.[].number' | jq -R -s -c 'split("\n")[:-1]')
176 echo "linked_issues=$ISSUES" >> $GITHUB_ENV
177
178 - name: Merge Issue Lists
179 id: merge_issues
180 run: |
181 ISSUES=$(jq -c -n --argjson a "$issues" --argjson b "$linked_issues" '$a + $b | unique')
182 echo "final_issues=$ISSUES" >> $GITHUB_ENV
183
184 - name: Label Linked Issues
185 id: label_linked_issues
186 env:
187 GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
188 run: |
189 for ISSUE in $(echo $final_issues | jq -r '.[]'); do
190 gh issue edit $ISSUE -R ${{ github.repository }} --add-label "✅ Done (staging)"
191 echo "Added label '✅ Done (staging)' to issue #$ISSUE"
192 done
.github/workflows/pr-check-merge-conflicts.yaml+24 -0
@@ -0,0 +1,24 @@
1name: ⚔️ Check Merge Conflicts
2
3on:
4 # So that PRs touching the same files as the push are updated
5 push:
6 # So that the `dirtyLabel` is removed if conflicts are resolved
7 pull_request_target:
8 types: [synchronize]
9
10jobs:
11 check-merge-conflicts:
12 name: ⚔️ Check Merge Conflicts
13 runs-on: ubuntu-latest
14
15 steps:
16 - name: Check Merge Conflicts
17 # Label Conflicting Pull Requests
18 # https://github.com/marketplace/actions/label-conflicting-pull-requests
19 uses: eps1lon/actions-label-merge-conflict@v3
20 with:
21 dirtyLabel: '🚫 Merge Conflicts'
22 repoToken: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
23 commentOnDirty: >
24 ⚠️ This PR has conflicts that need to be resolved before it can be merged.
Dockerfile+1 -1
@@ -4,7 +4,7 @@ FROM node:lts-alpine3.19
4ARG APP_HOME=/home/node/app4ARG APP_HOME=/home/node/app
55
6# Install system dependencies6# Install system dependencies
7RUN apk add gcompat tini git7RUN apk add --no-cache gcompat tini git
88
9# Create app directory9# Create app directory
10WORKDIR ${APP_HOME}10WORKDIR ${APP_HOME}
default/config.yaml+27 -6
@@ -1,8 +1,6 @@
1# -- DATA CONFIGURATION --1# -- DATA CONFIGURATION --
2# Root directory for user data storage2# Root directory for user data storage
3dataRoot: ./data3dataRoot: ./data
4# The maximum amount of memory that parsed character cards can use in MB
5cardsCacheCapacity: 100
6# -- SERVER CONFIGURATION --4# -- SERVER CONFIGURATION --
7# Listen for incoming connections5# Listen for incoming connections
8listen: false6listen: false
@@ -28,6 +26,11 @@ port: 8000
28# - Use -1 to use the server port.26# - Use -1 to use the server port.
29# - Specify a port to override the default.27# - Specify a port to override the default.
30autorunPortOverride: -128autorunPortOverride: -1
29# -- SSL options --
30ssl:
31 enabled: false
32 certPath: "./certs/cert.pem"
33 keyPath: "./certs/privkey.pem"
31# -- SECURITY CONFIGURATION --34# -- SECURITY CONFIGURATION --
32# Toggle whitelist mode35# Toggle whitelist mode
33whitelistMode: true36whitelistMode: true
@@ -37,6 +40,8 @@ enableForwardedWhitelist: true
37whitelist:40whitelist:
38 - ::141 - ::1
39 - 127.0.0.142 - 127.0.0.1
43# Automatically whitelist Docker host and gateway IPs
44whitelistDockerHosts: true
40# Toggle basic authentication for endpoints45# Toggle basic authentication for endpoints
41basicAuthMode: false46basicAuthMode: false
42# Basic authentication credentials47# Basic authentication credentials
@@ -71,20 +76,28 @@ autheliaAuth: false
71# the username and passwords for basic auth are the same as those76# the username and passwords for basic auth are the same as those
72# for the individual accounts77# for the individual accounts
73perUserBasicAuth: false78perUserBasicAuth: false
74# Minimum log level to display in the terminal (DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3)
75minLogLevel: 0
7679
77# User session timeout *in seconds* (defaults to 24 hours).80# User session timeout *in seconds* (defaults to 24 hours).
78## Set to a positive number to expire session after a certain time of inactivity81## Set to a positive number to expire session after a certain time of inactivity
79## Set to 0 to expire session when the browser is closed82## Set to 0 to expire session when the browser is closed
80## Set to a negative number to disable session expiration83## Set to a negative number to disable session expiration
81sessionTimeout: -184sessionTimeout: -1
82# Used to sign session cookies. Will be auto-generated if not set
83cookieSecret: ''
84# Disable CSRF protection - NOT RECOMMENDED85# Disable CSRF protection - NOT RECOMMENDED
85disableCsrfProtection: false86disableCsrfProtection: false
86# Disable startup security checks - NOT RECOMMENDED87# Disable startup security checks - NOT RECOMMENDED
87securityOverride: false88securityOverride: false
89# -- LOGGING CONFIGURATION --
90logging:
91 # Enable access logging to access.log file
92 # Records new connections with timestamp, IP address and user agent
93 enableAccessLog: true
94 # Minimum log level to display in the terminal (DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3)
95 minLogLevel: 0
96# -- RATE LIMITING CONFIGURATION --
97rateLimiting:
98 # Use X-Real-IP header instead of socket IP for rate limiting
99 # Only enable this if you are using a properly configured reverse proxy (like Nginx/traefik/Caddy)
100 preferRealIpHeader: false
88# -- ADVANCED CONFIGURATION --101# -- ADVANCED CONFIGURATION --
89# Open the browser automatically102# Open the browser automatically
90autorun: true103autorun: true
@@ -120,6 +133,14 @@ thumbnails:
120 # Maximum thumbnail dimensions per type [width, height]133 # Maximum thumbnail dimensions per type [width, height]
121 dimensions: { 'bg': [160, 90], 'avatar': [96, 144] }134 dimensions: { 'bg': [160, 90], 'avatar': [96, 144] }
122135
136# PERFORMANCE-RELATED CONFIGURATION
137performance:
138 # Enables lazy loading of character cards. Improves performances with large card libraries.
139 # May have compatibility issues with some extensions.
140 lazyLoadCharacters: false
141 # The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching.
142 memoryCacheCapacity: '100mb'
143
123# Allow secret keys exposure via API144# Allow secret keys exposure via API
124allowKeysExposure: false145allowKeysExposure: false
125# Skip new default content checks146# Skip new default content checks
default/content/presets/openai/Default.json+1 -2
@@ -28,12 +28,11 @@
28 "wrap_in_quotes": false,28 "wrap_in_quotes": false,
29 "names_behavior": 0,29 "names_behavior": 0,
30 "send_if_empty": "",30 "send_if_empty": "",
31 "jailbreak_system": false,
32 "impersonation_prompt": "[Write your next reply from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Don't write as {{char}} or system. Don't describe actions of {{char}}.]",31 "impersonation_prompt": "[Write your next reply from the point of view of {{user}}, using the chat history so far as a guideline for the writing style of {{user}}. Don't write as {{char}} or system. Don't describe actions of {{char}}.]",
33 "new_chat_prompt": "[Start a new Chat]",32 "new_chat_prompt": "[Start a new Chat]",
34 "new_group_chat_prompt": "[Start a new group chat. Group members: {{group}}]",33 "new_group_chat_prompt": "[Start a new group chat. Group members: {{group}}]",
35 "new_example_chat_prompt": "[Example Chat]",34 "new_example_chat_prompt": "[Example Chat]",
36 "continue_nudge_prompt": "[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]",35 "continue_nudge_prompt": "[Continue your last message without repeating its original content.]",
37 "bias_preset_selected": "Default (none)",36 "bias_preset_selected": "Default (none)",
38 "reverse_proxy": "",37 "reverse_proxy": "",
39 "proxy_password": "",38 "proxy_password": "",
default/content/settings.json+1 -2
@@ -593,7 +593,7 @@
593 "new_chat_prompt": "[Start a new Chat]",593 "new_chat_prompt": "[Start a new Chat]",
594 "new_group_chat_prompt": "[Start a new group chat. Group members: {{group}}]",594 "new_group_chat_prompt": "[Start a new group chat. Group members: {{group}}]",
595 "new_example_chat_prompt": "[Example Chat]",595 "new_example_chat_prompt": "[Example Chat]",
596 "continue_nudge_prompt": "[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]",596 "continue_nudge_prompt": "[Continue your last message without repeating its original content.]",
597 "bias_preset_selected": "Default (none)",597 "bias_preset_selected": "Default (none)",
598 "bias_presets": {598 "bias_presets": {
599 "Default (none)": [],599 "Default (none)": [],
@@ -626,7 +626,6 @@
626 "ai21_model": "jamba-1.5-large",626 "ai21_model": "jamba-1.5-large",
627 "windowai_model": "",627 "windowai_model": "",
628 "openrouter_model": "OR_Website",628 "openrouter_model": "OR_Website",
629 "jailbreak_system": true,
630 "reverse_proxy": "",629 "reverse_proxy": "",
631 "chat_completion_source": "openai",630 "chat_completion_source": "openai",
632 "max_context_unlocked": false,631 "max_context_unlocked": false,
docker/build-lib.js+1 -1
@@ -1,4 +1,4 @@
1import getWebpackServeMiddleware from '../src/middleware/webpack-serve.js';1import getWebpackServeMiddleware from '../src/middleware/webpack-serve.js';
22
3const middleware = getWebpackServeMiddleware();3const middleware = getWebpackServeMiddleware();
4await middleware.runWebpackCompiler();4await middleware.runWebpackCompiler({ forceDist: true });
docker/docker-compose.yml+3 -1
@@ -1,10 +1,12 @@
1version: "3"
2services:1services:
3 sillytavern:2 sillytavern:
4 build: ..3 build: ..
5 container_name: sillytavern4 container_name: sillytavern
6 hostname: sillytavern5 hostname: sillytavern
7 image: ghcr.io/sillytavern/sillytavern:latest6 image: ghcr.io/sillytavern/sillytavern:latest
7 environment:
8 - NODE_ENV=production
9 - FORCE_COLOR=1
8 ports:10 ports:
9 - "8000:8000"11 - "8000:8000"
10 volumes:12 volumes:
docker/docker-entrypoint.sh+3 -0
@@ -5,5 +5,8 @@ if [ ! -e "config/config.yaml" ]; then
5 cp -r "default/config.yaml" "config/config.yaml"5 cp -r "default/config.yaml" "config/config.yaml"
6fi6fi
77
8# Execute postinstall to auto-populate config.yaml with missing values
9npm run postinstall
10
8# Start the server11# Start the server
9exec node server.js --listen "$@"12exec node server.js --listen "$@"
index.d.ts+36 -2
@@ -1,7 +1,36 @@
1import { UserDirectoryList, User } from "./src/users";1import { EventEmitter } from 'node:events';
2import { CsrfSyncedToken } from "csrf-sync";2import { CsrfSyncedToken } from 'csrf-sync';
3import { UserDirectoryList, User } from './src/users.js';
4import { CommandLineArguments } from './src/command-line.js';
5import { EVENT_NAMES } from './src/server-events.js';
6
7/**
8 * Event payload for SERVER_STARTED event.
9 */
10export interface ServerStartedEvent {
11 /**
12 * The URL the server is listening on.
13 */
14 url: URL;
15}
16
17/**
18 * Map of all server events to their payload types.
19 */
20export interface ServerEventMap {
21 [EVENT_NAMES.SERVER_STARTED]: [ServerStartedEvent];
22}
323
4declare global {24declare global {
25 declare namespace NodeJS {
26 export interface Process {
27 /**
28 * A global instance of the server events emitter.
29 */
30 serverEvents: EventEmitter<ServerEventMap>;
31 }
32 }
33
5 declare namespace CookieSessionInterfaces {34 declare namespace CookieSessionInterfaces {
6 export interface CookieSessionObject {35 export interface CookieSessionObject {
7 /**36 /**
@@ -32,4 +61,9 @@ declare global {
32 * The root directory for user data.61 * The root directory for user data.
33 */62 */
34 var DATA_ROOT: string;63 var DATA_ROOT: string;
64
65 /**
66 * Parsed command line arguments.
67 */
68 var COMMAND_LINE_ARGS: CommandLineArguments;
35}69}
package-lock.json+640 -477
@@ -1,28 +1,30 @@
1{1{
2 "name": "sillytavern",2 "name": "sillytavern",
3 "version": "1.12.12",3 "version": "1.12.13",
4 "lockfileVersion": 3,4 "lockfileVersion": 3,
5 "requires": true,5 "requires": true,
6 "packages": {6 "packages": {
7 "": {7 "": {
8 "name": "sillytavern",8 "name": "sillytavern",
9 "version": "1.12.12",9 "version": "1.12.13",
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.0",13 "@adobe/css-tools": "^4.4.2",
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",
17 "@mozilla/readability": "^0.5.0",17 "@mozilla/readability": "^0.6.0",
18 "@popperjs/core": "^2.11.8",18 "@popperjs/core": "^2.11.8",
19 "@zeldafan0225/ai_horde": "^5.1.0",19 "@zeldafan0225/ai_horde": "^5.2.0",
20 "archiver": "^7.0.1",20 "archiver": "^7.0.1",
21 "bing-translate-api": "^4.0.2",21 "bing-translate-api": "^4.0.2",
22 "body-parser": "^1.20.2",22 "body-parser": "^1.20.2",
23 "bowser": "^2.11.0",23 "bowser": "^2.11.0",
24 "bytes": "^3.1.2",
25 "chalk": "^5.4.1",
24 "command-exists": "^1.2.9",26 "command-exists": "^1.2.9",
25 "compression": "^1",27 "compression": "^1.8.0",
26 "cookie-parser": "^1.4.6",28 "cookie-parser": "^1.4.6",
27 "cookie-session": "^2.1.0",29 "cookie-session": "^2.1.0",
28 "cors": "^2.8.5",30 "cors": "^2.8.5",
@@ -31,18 +33,19 @@
31 "dompurify": "^3.2.4",33 "dompurify": "^3.2.4",
32 "droll": "^0.2.1",34 "droll": "^0.2.1",
33 "express": "^4.21.0",35 "express": "^4.21.0",
34 "form-data": "^4.0.0",36 "form-data": "^4.0.2",
35 "fuse.js": "^7.0.0",37 "fuse.js": "^7.1.0",
36 "google-translate-api-browser": "^3.0.1",38 "google-translate-api-browser": "^3.0.1",
37 "google-translate-api-x": "^10.7.1",39 "google-translate-api-x": "^10.7.2",
38 "handlebars": "^4.7.8",40 "handlebars": "^4.7.8",
39 "helmet": "^7.1.0",41 "helmet": "^7.2.0",
40 "highlight.js": "^11.10.0",42 "highlight.js": "^11.11.1",
41 "html-entities": "^2.5.2",43 "html-entities": "^2.5.2",
42 "iconv-lite": "^0.6.3",44 "iconv-lite": "^0.6.3",
43 "ip-matching": "^2.1.2",45 "ip-matching": "^2.1.2",
44 "ip-regex": "^5.0.0",46 "ip-regex": "^5.0.0",
45 "ipaddr.js": "^2.0.1",47 "ipaddr.js": "^2.2.0",
48 "is-docker": "^3.0.0",
46 "jimp": "^0.22.10",49 "jimp": "^0.22.10",
47 "localforage": "^1.10.0",50 "localforage": "^1.10.0",
48 "lodash": "^4.17.21",51 "lodash": "^4.17.21",
@@ -51,28 +54,28 @@
51 "morphdom": "^2.7.4",54 "morphdom": "^2.7.4",
52 "multer": "^1.4.5-lts.1",55 "multer": "^1.4.5-lts.1",
53 "node-fetch": "^3.3.2",56 "node-fetch": "^3.3.2",
54 "node-persist": "^4.0.1",57 "node-persist": "^4.0.4",
55 "open": "^8.4.2",58 "open": "^8.4.2",
56 "png-chunk-text": "^1.0.0",59 "png-chunk-text": "^1.0.0",
57 "png-chunks-encode": "^1.0.0",60 "png-chunks-encode": "^1.0.0",
58 "png-chunks-extract": "^1.0.0",61 "png-chunks-extract": "^1.0.0",
59 "proxy-agent": "^6.4.0",62 "proxy-agent": "^6.5.0",
60 "rate-limiter-flexible": "^5.0.0",63 "rate-limiter-flexible": "^5.0.5",
61 "response-time": "^2.3.2",64 "response-time": "^2.3.3",
62 "sanitize-filename": "^1.6.3",65 "sanitize-filename": "^1.6.3",
63 "seedrandom": "^3.0.5",66 "seedrandom": "^3.0.5",
64 "showdown": "^2.1.0",67 "showdown": "^2.1.0",
65 "sillytavern-transformers": "2.14.6",68 "sillytavern-transformers": "2.14.6",
66 "simple-git": "^3.19.1",69 "simple-git": "^3.27.0",
67 "slidetoggle": "^4.0.0",70 "slidetoggle": "^4.0.0",
68 "tiktoken": "^1.0.16",71 "tiktoken": "^1.0.20",
69 "url-join": "^5.0.0",72 "url-join": "^5.0.0",
70 "vectra": "^0.2.2",73 "vectra": "^0.2.2",
71 "wavefile": "^11.0.0",74 "wavefile": "^11.0.0",
72 "webpack": "^5.95.0",75 "webpack": "^5.98.0",
73 "write-file-atomic": "^5.0.1",76 "write-file-atomic": "^5.0.1",
74 "ws": "^8.17.1",77 "ws": "^8.18.1",
75 "yaml": "^2.3.4",78 "yaml": "^2.7.0",
76 "yargs": "^17.7.1",79 "yargs": "^17.7.1",
77 "yauzl": "^2.10.0"80 "yauzl": "^2.10.0"
78 },81 },
@@ -80,23 +83,23 @@
80 "sillytavern": "server.js"83 "sillytavern": "server.js"
81 },84 },
82 "devDependencies": {85 "devDependencies": {
83 "@types/archiver": "^6.0.2",86 "@types/archiver": "^6.0.3",
87 "@types/bytes": "^3.1.5",
84 "@types/command-exists": "^1.2.3",88 "@types/command-exists": "^1.2.3",
85 "@types/compression": "^1.7.5",89 "@types/compression": "^1.7.5",
86 "@types/cookie-parser": "^1.4.7",90 "@types/cookie-parser": "^1.4.8",
87 "@types/cookie-session": "^2.0.49",91 "@types/cookie-session": "^2.0.49",
88 "@types/cors": "^2.8.17",92 "@types/cors": "^2.8.17",
89 "@types/deno": "^2.0.0",93 "@types/deno": "^2.2.0",
90 "@types/dompurify": "^3.2.0",
91 "@types/express": "^4.17.21",94 "@types/express": "^4.17.21",
92 "@types/jquery": "^3.5.29",95 "@types/jquery": "^3.5.32",
93 "@types/jquery-cropper": "^1.0.4",96 "@types/jquery-cropper": "^1.0.4",
94 "@types/jquery.transit": "^0.9.33",97 "@types/jquery.transit": "^0.9.33",
95 "@types/jqueryui": "^1.12.23",98 "@types/jqueryui": "^1.12.24",
96 "@types/lodash": "^4.17.10",99 "@types/lodash": "^4.17.16",
97 "@types/mime-types": "^2.1.4",100 "@types/mime-types": "^2.1.4",
98 "@types/multer": "^1.4.12",101 "@types/multer": "^1.4.12",
99 "@types/node": "^18.19.55",102 "@types/node": "^18.19.80",
100 "@types/node-persist": "^3.1.8",103 "@types/node-persist": "^3.1.8",
101 "@types/png-chunk-text": "^1.0.3",104 "@types/png-chunk-text": "^1.0.3",
102 "@types/png-chunks-encode": "^1.0.2",105 "@types/png-chunks-encode": "^1.0.2",
@@ -107,7 +110,7 @@
107 "@types/write-file-atomic": "^4.0.3",110 "@types/write-file-atomic": "^4.0.3",
108 "@types/yargs": "^17.0.33",111 "@types/yargs": "^17.0.33",
109 "@types/yauzl": "^2.10.3",112 "@types/yauzl": "^2.10.3",
110 "eslint": "^8.57.0"113 "eslint": "^8.57.1"
111 },114 },
112 "engines": {115 "engines": {
113 "node": ">= 18"116 "node": ">= 18"
@@ -124,9 +127,9 @@
124 }127 }
125 },128 },
126 "node_modules/@adobe/css-tools": {129 "node_modules/@adobe/css-tools": {
127 "version": "4.4.0",130 "version": "4.4.2",
128 "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz",131 "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz",
129 "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==",132 "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==",
130 "license": "MIT"133 "license": "MIT"
131 },134 },
132 "node_modules/@agnai/sentencepiece-js": {135 "node_modules/@agnai/sentencepiece-js": {
@@ -220,9 +223,9 @@
220 "license": "MIT"223 "license": "MIT"
221 },224 },
222 "node_modules/@eslint/js": {225 "node_modules/@eslint/js": {
223 "version": "8.57.0",226 "version": "8.57.1",
224 "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",227 "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
225 "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",228 "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
226 "dev": true,229 "dev": true,
227 "license": "MIT",230 "license": "MIT",
228 "engines": {231 "engines": {
@@ -239,14 +242,14 @@
239 }242 }
240 },243 },
241 "node_modules/@humanwhocodes/config-array": {244 "node_modules/@humanwhocodes/config-array": {
242 "version": "0.11.14",245 "version": "0.13.0",
243 "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",246 "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
244 "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",247 "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
245 "deprecated": "Use @eslint/config-array instead",248 "deprecated": "Use @eslint/config-array instead",
246 "dev": true,249 "dev": true,
247 "license": "Apache-2.0",250 "license": "Apache-2.0",
248 "dependencies": {251 "dependencies": {
249 "@humanwhocodes/object-schema": "^2.0.2",252 "@humanwhocodes/object-schema": "^2.0.3",
250 "debug": "^4.3.1",253 "debug": "^4.3.1",
251 "minimatch": "^3.0.5"254 "minimatch": "^3.0.5"
252 },255 },
@@ -255,13 +258,13 @@
255 }258 }
256 },259 },
257 "node_modules/@humanwhocodes/config-array/node_modules/debug": {260 "node_modules/@humanwhocodes/config-array/node_modules/debug": {
258 "version": "4.3.6",261 "version": "4.4.0",
259 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",262 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
260 "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",263 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
261 "dev": true,264 "dev": true,
262 "license": "MIT",265 "license": "MIT",
263 "dependencies": {266 "dependencies": {
264 "ms": "2.1.2"267 "ms": "^2.1.3"
265 },268 },
266 "engines": {269 "engines": {
267 "node": ">=6.0"270 "node": ">=6.0"
@@ -273,9 +276,9 @@
273 }276 }
274 },277 },
275 "node_modules/@humanwhocodes/config-array/node_modules/ms": {278 "node_modules/@humanwhocodes/config-array/node_modules/ms": {
276 "version": "2.1.2",279 "version": "2.1.3",
277 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",280 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
278 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",281 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
279 "dev": true,282 "dev": true,
280 "license": "MIT"283 "license": "MIT"
281 },284 },
@@ -816,9 +819,9 @@
816 }819 }
817 },820 },
818 "node_modules/@jridgewell/gen-mapping": {821 "node_modules/@jridgewell/gen-mapping": {
819 "version": "0.3.5",822 "version": "0.3.8",
820 "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",823 "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
821 "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",824 "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
822 "license": "MIT",825 "license": "MIT",
823 "dependencies": {826 "dependencies": {
824 "@jridgewell/set-array": "^1.2.1",827 "@jridgewell/set-array": "^1.2.1",
@@ -912,9 +915,9 @@
912 "license": "MIT"915 "license": "MIT"
913 },916 },
914 "node_modules/@mozilla/readability": {917 "node_modules/@mozilla/readability": {
915 "version": "0.5.0",918 "version": "0.6.0",
916 "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.5.0.tgz",919 "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz",
917 "integrity": "sha512-Z+CZ3QaosfFaTqvhQsIktyGrjFjSC0Fa4EMph4mqKnWhmyoGICsV/8QK+8HpXut6zV7zwfWwqDmEjtk1Qf6EgQ==",920 "integrity": "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==",
918 "license": "Apache-2.0",921 "license": "Apache-2.0",
919 "engines": {922 "engines": {
920 "node": ">=14.0.0"923 "node": ">=14.0.0"
@@ -1084,9 +1087,9 @@
1084 "license": "MIT"1087 "license": "MIT"
1085 },1088 },
1086 "node_modules/@types/archiver": {1089 "node_modules/@types/archiver": {
1087 "version": "6.0.2",1090 "version": "6.0.3",
1088 "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.2.tgz",1091 "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.3.tgz",
1089 "integrity": "sha512-KmROQqbQzKGuaAbmK+ZcytkJ51+YqDa7NmbXjmtC5YBLSyQYo21YaUnQ3HbaPFKL1ooo6RQ6OPYPIDyxfpDDXw==",1092 "integrity": "sha512-a6wUll6k3zX6qs5KlxIggs1P1JcYJaTCx2gnlr+f0S1yd2DoaEwoIK10HmBaLnZwWneBz+JBm0dwcZu0zECBcQ==",
1090 "dev": true,1093 "dev": true,
1091 "license": "MIT",1094 "license": "MIT",
1092 "dependencies": {1095 "dependencies": {
@@ -1104,6 +1107,13 @@
1104 "@types/node": "*"1107 "@types/node": "*"
1105 }1108 }
1106 },1109 },
1110 "node_modules/@types/bytes": {
1111 "version": "3.1.5",
1112 "resolved": "https://registry.npmjs.org/@types/bytes/-/bytes-3.1.5.tgz",
1113 "integrity": "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ==",
1114 "dev": true,
1115 "license": "MIT"
1116 },
1107 "node_modules/@types/cacheable-request": {1117 "node_modules/@types/cacheable-request": {
1108 "version": "6.0.3",1118 "version": "6.0.3",
1109 "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",1119 "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
@@ -1144,12 +1154,12 @@
1144 }1154 }
1145 },1155 },
1146 "node_modules/@types/cookie-parser": {1156 "node_modules/@types/cookie-parser": {
1147 "version": "1.4.7",1157 "version": "1.4.8",
1148 "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.7.tgz",1158 "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.8.tgz",
1149 "integrity": "sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==",1159 "integrity": "sha512-l37JqFrOJ9yQfRQkljb41l0xVphc7kg5JTjjr+pLRZ0IyZ49V4BQ8vbF4Ut2C2e+WH4al3xD3ZwYwIUfnbT4NQ==",
1150 "dev": true,1160 "dev": true,
1151 "license": "MIT",1161 "license": "MIT",
1152 "dependencies": {1162 "peerDependencies": {
1153 "@types/express": "*"1163 "@types/express": "*"
1154 }1164 }
1155 },1165 },
@@ -1175,21 +1185,30 @@
1175 }1185 }
1176 },1186 },
1177 "node_modules/@types/deno": {1187 "node_modules/@types/deno": {
1178 "version": "2.0.0",1188 "version": "2.2.0",
1179 "resolved": "https://registry.npmjs.org/@types/deno/-/deno-2.0.0.tgz",1189 "resolved": "https://registry.npmjs.org/@types/deno/-/deno-2.2.0.tgz",
1180 "integrity": "sha512-O9/jRVlq93kqfkl4sYR5N7+Pz4ukzXVIbMnE/VgvpauNHsvjQ9iBVnJ3X0gAvMa2khcoFD8DSO7mQVCuiuDMPg==",1190 "integrity": "sha512-4x6M/ZSyoQy6fJeMArP0dvvNT4IOolfySyukuqqKhsLmSXDV4wGanqXIZ+xFihw3TlReS6JTa4hRG9nAZInpmw==",
1181 "dev": true,1191 "dev": true,
1182 "license": "MIT"1192 "license": "MIT"
1183 },1193 },
1184 "node_modules/@types/dompurify": {1194 "node_modules/@types/eslint": {
1185 "version": "3.2.0",1195 "version": "9.6.1",
1186 "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.2.0.tgz",1196 "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
1187 "integrity": "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==",1197 "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
1188 "deprecated": "This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed.",1198 "license": "MIT",
1189 "dev": true,1199 "dependencies": {
1200 "@types/estree": "*",
1201 "@types/json-schema": "*"
1202 }
1203 },
1204 "node_modules/@types/eslint-scope": {
1205 "version": "3.7.7",
1206 "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
1207 "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
1190 "license": "MIT",1208 "license": "MIT",
1191 "dependencies": {1209 "dependencies": {
1192 "dompurify": "*"1210 "@types/eslint": "*",
1211 "@types/estree": "*"
1193 }1212 }
1194 },1213 },
1195 "node_modules/@types/estree": {1214 "node_modules/@types/estree": {
@@ -1236,9 +1255,9 @@
1236 "license": "MIT"1255 "license": "MIT"
1237 },1256 },
1238 "node_modules/@types/jquery": {1257 "node_modules/@types/jquery": {
1239 "version": "3.5.31",1258 "version": "3.5.32",
1240 "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.31.tgz",1259 "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.32.tgz",
1241 "integrity": "sha512-rf/iB+cPJ/YZfMwr+FVuQbm7IaWC4y3FVYfVDxRGqmUCFjjPII0HWaP0vTPJGp6m4o13AXySCcMbWfrWtBFAKw==",1260 "integrity": "sha512-b9Xbf4CkMqS02YH8zACqN1xzdxc3cO735Qe5AbSUFmyOiaWAbcpqh9Wna+Uk0vgACvoQHpWDg2rGdHkYPLmCiQ==",
1242 "dev": true,1261 "dev": true,
1243 "license": "MIT",1262 "license": "MIT",
1244 "dependencies": {1263 "dependencies": {
@@ -1266,9 +1285,9 @@
1266 }1285 }
1267 },1286 },
1268 "node_modules/@types/jqueryui": {1287 "node_modules/@types/jqueryui": {
1269 "version": "1.12.23",1288 "version": "1.12.24",
1270 "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.23.tgz",1289 "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.24.tgz",
1271 "integrity": "sha512-pm1yVNVI29B9IGw41anCEzA5eR2r1pYc7flqD471ZT7B0yUXIY7YNe/zq7LGpihIGXNzWyG+Q4YQSzv2AF3fNA==",1290 "integrity": "sha512-E2sGULwzMhg4kAeOV+gYcXjg988RuPkviWCt09jLe6GGK9sHM7dTqS8H7JMuUWoZQBucIBzBAgM5o/ezKUFkeg==",
1272 "dev": true,1291 "dev": true,
1273 "license": "MIT",1292 "license": "MIT",
1274 "dependencies": {1293 "dependencies": {
@@ -1298,9 +1317,9 @@
1298 }1317 }
1299 },1318 },
1300 "node_modules/@types/lodash": {1319 "node_modules/@types/lodash": {
1301 "version": "4.17.10",1320 "version": "4.17.16",
1302 "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.10.tgz",1321 "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz",
1303 "integrity": "sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==",1322 "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==",
1304 "dev": true,1323 "dev": true,
1305 "license": "MIT"1324 "license": "MIT"
1306 },1325 },
@@ -1335,9 +1354,9 @@
1335 }1354 }
1336 },1355 },
1337 "node_modules/@types/node": {1356 "node_modules/@types/node": {
1338 "version": "18.19.55",1357 "version": "18.19.80",
1339 "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.55.tgz",1358 "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz",
1340 "integrity": "sha512-zzw5Vw52205Zr/nmErSEkN5FLqXPuKX/k5d1D7RKHATGqU7y6YfX9QxZraUzUrFGqH6XzOzG196BC35ltJC4Cw==",1359 "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==",
1341 "license": "MIT",1360 "license": "MIT",
1342 "dependencies": {1361 "dependencies": {
1343 "undici-types": "~5.26.4"1362 "undici-types": "~5.26.4"
@@ -1527,148 +1546,148 @@
1527 "license": "ISC"1546 "license": "ISC"
1528 },1547 },
1529 "node_modules/@webassemblyjs/ast": {1548 "node_modules/@webassemblyjs/ast": {
1530 "version": "1.12.1",1549 "version": "1.14.1",
1531 "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",1550 "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
1532 "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",1551 "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
1533 "license": "MIT",1552 "license": "MIT",
1534 "dependencies": {1553 "dependencies": {
1535 "@webassemblyjs/helper-numbers": "1.11.6",1554 "@webassemblyjs/helper-numbers": "1.13.2",
1536 "@webassemblyjs/helper-wasm-bytecode": "1.11.6"1555 "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
1537 }1556 }
1538 },1557 },
1539 "node_modules/@webassemblyjs/floating-point-hex-parser": {1558 "node_modules/@webassemblyjs/floating-point-hex-parser": {
1540 "version": "1.11.6",1559 "version": "1.13.2",
1541 "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",1560 "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
1542 "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",1561 "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
1543 "license": "MIT"1562 "license": "MIT"
1544 },1563 },
1545 "node_modules/@webassemblyjs/helper-api-error": {1564 "node_modules/@webassemblyjs/helper-api-error": {
1546 "version": "1.11.6",1565 "version": "1.13.2",
1547 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",1566 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
1548 "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",1567 "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
1549 "license": "MIT"1568 "license": "MIT"
1550 },1569 },
1551 "node_modules/@webassemblyjs/helper-buffer": {1570 "node_modules/@webassemblyjs/helper-buffer": {
1552 "version": "1.12.1",1571 "version": "1.14.1",
1553 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",1572 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
1554 "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==",1573 "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
1555 "license": "MIT"1574 "license": "MIT"
1556 },1575 },
1557 "node_modules/@webassemblyjs/helper-numbers": {1576 "node_modules/@webassemblyjs/helper-numbers": {
1558 "version": "1.11.6",1577 "version": "1.13.2",
1559 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",1578 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
1560 "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",1579 "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
1561 "license": "MIT",1580 "license": "MIT",
1562 "dependencies": {1581 "dependencies": {
1563 "@webassemblyjs/floating-point-hex-parser": "1.11.6",1582 "@webassemblyjs/floating-point-hex-parser": "1.13.2",
1564 "@webassemblyjs/helper-api-error": "1.11.6",1583 "@webassemblyjs/helper-api-error": "1.13.2",
1565 "@xtuc/long": "4.2.2"1584 "@xtuc/long": "4.2.2"
1566 }1585 }
1567 },1586 },
1568 "node_modules/@webassemblyjs/helper-wasm-bytecode": {1587 "node_modules/@webassemblyjs/helper-wasm-bytecode": {
1569 "version": "1.11.6",1588 "version": "1.13.2",
1570 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",1589 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
1571 "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",1590 "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
1572 "license": "MIT"1591 "license": "MIT"
1573 },1592 },
1574 "node_modules/@webassemblyjs/helper-wasm-section": {1593 "node_modules/@webassemblyjs/helper-wasm-section": {
1575 "version": "1.12.1",1594 "version": "1.14.1",
1576 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",1595 "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
1577 "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",1596 "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
1578 "license": "MIT",1597 "license": "MIT",
1579 "dependencies": {1598 "dependencies": {
1580 "@webassemblyjs/ast": "1.12.1",1599 "@webassemblyjs/ast": "1.14.1",
1581 "@webassemblyjs/helper-buffer": "1.12.1",1600 "@webassemblyjs/helper-buffer": "1.14.1",
1582 "@webassemblyjs/helper-wasm-bytecode": "1.11.6",1601 "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
1583 "@webassemblyjs/wasm-gen": "1.12.1"1602 "@webassemblyjs/wasm-gen": "1.14.1"
1584 }1603 }
1585 },1604 },
1586 "node_modules/@webassemblyjs/ieee754": {1605 "node_modules/@webassemblyjs/ieee754": {
1587 "version": "1.11.6",1606 "version": "1.13.2",
1588 "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",1607 "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
1589 "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",1608 "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
1590 "license": "MIT",1609 "license": "MIT",
1591 "dependencies": {1610 "dependencies": {
1592 "@xtuc/ieee754": "^1.2.0"1611 "@xtuc/ieee754": "^1.2.0"
1593 }1612 }
1594 },1613 },
1595 "node_modules/@webassemblyjs/leb128": {1614 "node_modules/@webassemblyjs/leb128": {
1596 "version": "1.11.6",1615 "version": "1.13.2",
1597 "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",1616 "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
1598 "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",1617 "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
1599 "license": "Apache-2.0",1618 "license": "Apache-2.0",
1600 "dependencies": {1619 "dependencies": {
1601 "@xtuc/long": "4.2.2"1620 "@xtuc/long": "4.2.2"
1602 }1621 }
1603 },1622 },
1604 "node_modules/@webassemblyjs/utf8": {1623 "node_modules/@webassemblyjs/utf8": {
1605 "version": "1.11.6",1624 "version": "1.13.2",
1606 "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",1625 "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
1607 "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",1626 "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
1608 "license": "MIT"1627 "license": "MIT"
1609 },1628 },
1610 "node_modules/@webassemblyjs/wasm-edit": {1629 "node_modules/@webassemblyjs/wasm-edit": {
1611 "version": "1.12.1",1630 "version": "1.14.1",
1612 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",1631 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
1613 "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",1632 "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
1614 "license": "MIT",1633 "license": "MIT",
1615 "dependencies": {1634 "dependencies": {
1616 "@webassemblyjs/ast": "1.12.1",1635 "@webassemblyjs/ast": "1.14.1",
1617 "@webassemblyjs/helper-buffer": "1.12.1",1636 "@webassemblyjs/helper-buffer": "1.14.1",
1618 "@webassemblyjs/helper-wasm-bytecode": "1.11.6",1637 "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
1619 "@webassemblyjs/helper-wasm-section": "1.12.1",1638 "@webassemblyjs/helper-wasm-section": "1.14.1",
1620 "@webassemblyjs/wasm-gen": "1.12.1",1639 "@webassemblyjs/wasm-gen": "1.14.1",
1621 "@webassemblyjs/wasm-opt": "1.12.1",1640 "@webassemblyjs/wasm-opt": "1.14.1",
1622 "@webassemblyjs/wasm-parser": "1.12.1",1641 "@webassemblyjs/wasm-parser": "1.14.1",
1623 "@webassemblyjs/wast-printer": "1.12.1"1642 "@webassemblyjs/wast-printer": "1.14.1"
1624 }1643 }
1625 },1644 },
1626 "node_modules/@webassemblyjs/wasm-gen": {1645 "node_modules/@webassemblyjs/wasm-gen": {
1627 "version": "1.12.1",1646 "version": "1.14.1",
1628 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",1647 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
1629 "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",1648 "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
1630 "license": "MIT",1649 "license": "MIT",
1631 "dependencies": {1650 "dependencies": {
1632 "@webassemblyjs/ast": "1.12.1",1651 "@webassemblyjs/ast": "1.14.1",
1633 "@webassemblyjs/helper-wasm-bytecode": "1.11.6",1652 "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
1634 "@webassemblyjs/ieee754": "1.11.6",1653 "@webassemblyjs/ieee754": "1.13.2",
1635 "@webassemblyjs/leb128": "1.11.6",1654 "@webassemblyjs/leb128": "1.13.2",
1636 "@webassemblyjs/utf8": "1.11.6"1655 "@webassemblyjs/utf8": "1.13.2"
1637 }1656 }
1638 },1657 },
1639 "node_modules/@webassemblyjs/wasm-opt": {1658 "node_modules/@webassemblyjs/wasm-opt": {
1640 "version": "1.12.1",1659 "version": "1.14.1",
1641 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",1660 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
1642 "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",1661 "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
1643 "license": "MIT",1662 "license": "MIT",
1644 "dependencies": {1663 "dependencies": {
1645 "@webassemblyjs/ast": "1.12.1",1664 "@webassemblyjs/ast": "1.14.1",
1646 "@webassemblyjs/helper-buffer": "1.12.1",1665 "@webassemblyjs/helper-buffer": "1.14.1",
1647 "@webassemblyjs/wasm-gen": "1.12.1",1666 "@webassemblyjs/wasm-gen": "1.14.1",
1648 "@webassemblyjs/wasm-parser": "1.12.1"1667 "@webassemblyjs/wasm-parser": "1.14.1"
1649 }1668 }
1650 },1669 },
1651 "node_modules/@webassemblyjs/wasm-parser": {1670 "node_modules/@webassemblyjs/wasm-parser": {
1652 "version": "1.12.1",1671 "version": "1.14.1",
1653 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",1672 "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
1654 "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",1673 "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
1655 "license": "MIT",1674 "license": "MIT",
1656 "dependencies": {1675 "dependencies": {
1657 "@webassemblyjs/ast": "1.12.1",1676 "@webassemblyjs/ast": "1.14.1",
1658 "@webassemblyjs/helper-api-error": "1.11.6",1677 "@webassemblyjs/helper-api-error": "1.13.2",
1659 "@webassemblyjs/helper-wasm-bytecode": "1.11.6",1678 "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
1660 "@webassemblyjs/ieee754": "1.11.6",1679 "@webassemblyjs/ieee754": "1.13.2",
1661 "@webassemblyjs/leb128": "1.11.6",1680 "@webassemblyjs/leb128": "1.13.2",
1662 "@webassemblyjs/utf8": "1.11.6"1681 "@webassemblyjs/utf8": "1.13.2"
1663 }1682 }
1664 },1683 },
1665 "node_modules/@webassemblyjs/wast-printer": {1684 "node_modules/@webassemblyjs/wast-printer": {
1666 "version": "1.12.1",1685 "version": "1.14.1",
1667 "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",1686 "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
1668 "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",1687 "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
1669 "license": "MIT",1688 "license": "MIT",
1670 "dependencies": {1689 "dependencies": {
1671 "@webassemblyjs/ast": "1.12.1",1690 "@webassemblyjs/ast": "1.14.1",
1672 "@xtuc/long": "4.2.2"1691 "@xtuc/long": "4.2.2"
1673 }1692 }
1674 },1693 },
@@ -1685,9 +1704,10 @@
1685 "license": "Apache-2.0"1704 "license": "Apache-2.0"
1686 },1705 },
1687 "node_modules/@zeldafan0225/ai_horde": {1706 "node_modules/@zeldafan0225/ai_horde": {
1688 "version": "5.1.0",1707 "version": "5.2.0",
1689 "resolved": "https://registry.npmjs.org/@zeldafan0225/ai_horde/-/ai_horde-5.1.0.tgz",1708 "resolved": "https://registry.npmjs.org/@zeldafan0225/ai_horde/-/ai_horde-5.2.0.tgz",
1690 "integrity": "sha512-rPC0nmmFSXK808Oon0zFPA7yGSUKBXiLtMejkmKTyfAzzOHHQt/i2lO4ccfN2e355LzX1lBLwSi+nlATVA43Sw==",1709 "integrity": "sha512-IkFFwt8nTW+F87Kndl1b5ZQfZVgnTm2qf5By4M82fEH+KyHXvnkSTzOl/rUaqW0tjAXIyD+DM0D35TpdolPj4g==",
1710 "license": "MIT",
1691 "dependencies": {1711 "dependencies": {
1692 "@thunder04/supermap": "^3.0.2"1712 "@thunder04/supermap": "^3.0.2"
1693 },1713 },
@@ -1721,9 +1741,9 @@
1721 }1741 }
1722 },1742 },
1723 "node_modules/acorn": {1743 "node_modules/acorn": {
1724 "version": "8.11.2",1744 "version": "8.14.0",
1725 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz",1745 "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
1726 "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==",1746 "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
1727 "license": "MIT",1747 "license": "MIT",
1728 "bin": {1748 "bin": {
1729 "acorn": "bin/acorn"1749 "acorn": "bin/acorn"
@@ -1732,15 +1752,6 @@
1732 "node": ">=0.4.0"1752 "node": ">=0.4.0"
1733 }1753 }
1734 },1754 },
1735 "node_modules/acorn-import-attributes": {
1736 "version": "1.9.5",
1737 "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
1738 "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
1739 "license": "MIT",
1740 "peerDependencies": {
1741 "acorn": "^8"
1742 }
1743 },
1744 "node_modules/acorn-jsx": {1755 "node_modules/acorn-jsx": {
1745 "version": "5.3.2",1756 "version": "5.3.2",
1746 "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",1757 "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
@@ -1752,40 +1763,14 @@
1752 }1763 }
1753 },1764 },
1754 "node_modules/agent-base": {1765 "node_modules/agent-base": {
1755 "version": "7.1.1",1766 "version": "7.1.3",
1756 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",1767 "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
1757 "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",1768 "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
1758 "license": "MIT",1769 "license": "MIT",
1759 "dependencies": {
1760 "debug": "^4.3.4"
1761 },
1762 "engines": {1770 "engines": {
1763 "node": ">= 14"1771 "node": ">= 14"
1764 }1772 }
1765 },1773 },
1766 "node_modules/agent-base/node_modules/debug": {
1767 "version": "4.3.7",
1768 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
1769 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
1770 "license": "MIT",
1771 "dependencies": {
1772 "ms": "^2.1.3"
1773 },
1774 "engines": {
1775 "node": ">=6.0"
1776 },
1777 "peerDependenciesMeta": {
1778 "supports-color": {
1779 "optional": true
1780 }
1781 }
1782 },
1783 "node_modules/agent-base/node_modules/ms": {
1784 "version": "2.1.3",
1785 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1786 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1787 "license": "MIT"
1788 },
1789 "node_modules/agentkeepalive": {1774 "node_modules/agentkeepalive": {
1790 "version": "4.5.0",1775 "version": "4.5.0",
1791 "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",1776 "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
@@ -1802,6 +1787,7 @@
1802 "version": "6.12.6",1787 "version": "6.12.6",
1803 "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",1788 "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
1804 "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",1789 "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
1790 "dev": true,
1805 "license": "MIT",1791 "license": "MIT",
1806 "dependencies": {1792 "dependencies": {
1807 "fast-deep-equal": "^3.1.1",1793 "fast-deep-equal": "^3.1.1",
@@ -1814,14 +1800,44 @@
1814 "url": "https://github.com/sponsors/epoberezkin"1800 "url": "https://github.com/sponsors/epoberezkin"
1815 }1801 }
1816 },1802 },
1817 "node_modules/ajv-keywords": {1803 "node_modules/ajv-formats": {
1818 "version": "3.5.2",1804 "version": "2.1.1",
1819 "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",1805 "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
1820 "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",1806 "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
1821 "license": "MIT",1807 "license": "MIT",
1808 "dependencies": {
1809 "ajv": "^8.0.0"
1810 },
1822 "peerDependencies": {1811 "peerDependencies": {
1823 "ajv": "^6.9.1"1812 "ajv": "^8.0.0"
1813 },
1814 "peerDependenciesMeta": {
1815 "ajv": {
1816 "optional": true
1824 }1817 }
1818 }
1819 },
1820 "node_modules/ajv-formats/node_modules/ajv": {
1821 "version": "8.17.1",
1822 "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
1823 "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
1824 "license": "MIT",
1825 "dependencies": {
1826 "fast-deep-equal": "^3.1.3",
1827 "fast-uri": "^3.0.1",
1828 "json-schema-traverse": "^1.0.0",
1829 "require-from-string": "^2.0.2"
1830 },
1831 "funding": {
1832 "type": "github",
1833 "url": "https://github.com/sponsors/epoberezkin"
1834 }
1835 },
1836 "node_modules/ajv-formats/node_modules/json-schema-traverse": {
1837 "version": "1.0.0",
1838 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
1839 "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
1840 "license": "MIT"
1825 },1841 },
1826 "node_modules/ansi-regex": {1842 "node_modules/ansi-regex": {
1827 "version": "5.0.1",1843 "version": "5.0.1",
@@ -2220,15 +2236,6 @@
2220 "npm": "1.2.8000 || >= 1.4.16"2236 "npm": "1.2.8000 || >= 1.4.16"
2221 }2237 }
2222 },2238 },
2223 "node_modules/body-parser/node_modules/bytes": {
2224 "version": "3.1.2",
2225 "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
2226 "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
2227 "license": "MIT",
2228 "engines": {
2229 "node": ">= 0.8"
2230 }
2231 },
2232 "node_modules/body-parser/node_modules/iconv-lite": {2239 "node_modules/body-parser/node_modules/iconv-lite": {
2233 "version": "0.4.24",2240 "version": "0.4.24",
2234 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",2241 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -2356,9 +2363,9 @@
2356 }2363 }
2357 },2364 },
2358 "node_modules/bytes": {2365 "node_modules/bytes": {
2359 "version": "3.0.0",2366 "version": "3.1.2",
2360 "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",2367 "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
2361 "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",2368 "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
2362 "license": "MIT",2369 "license": "MIT",
2363 "engines": {2370 "engines": {
2364 "node": ">= 0.8"2371 "node": ">= 0.8"
@@ -2410,6 +2417,19 @@
2410 "url": "https://github.com/sponsors/ljharb"2417 "url": "https://github.com/sponsors/ljharb"
2411 }2418 }
2412 },2419 },
2420 "node_modules/call-bind-apply-helpers": {
2421 "version": "1.0.2",
2422 "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
2423 "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
2424 "license": "MIT",
2425 "dependencies": {
2426 "es-errors": "^1.3.0",
2427 "function-bind": "^1.1.2"
2428 },
2429 "engines": {
2430 "node": ">= 0.4"
2431 }
2432 },
2413 "node_modules/callsites": {2433 "node_modules/callsites": {
2414 "version": "3.1.0",2434 "version": "3.1.0",
2415 "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",2435 "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -2450,17 +2470,12 @@
2450 }2470 }
2451 },2471 },
2452 "node_modules/chalk": {2472 "node_modules/chalk": {
2453 "version": "4.1.2",2473 "version": "5.4.1",
2454 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",2474 "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
2455 "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",2475 "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
2456 "dev": true,
2457 "license": "MIT",2476 "license": "MIT",
2458 "dependencies": {
2459 "ansi-styles": "^4.1.0",
2460 "supports-color": "^7.1.0"
2461 },
2462 "engines": {2477 "engines": {
2463 "node": ">=10"2478 "node": "^12.17.0 || ^14.13 || >=16.0.0"
2464 },2479 },
2465 "funding": {2480 "funding": {
2466 "url": "https://github.com/chalk/chalk?sponsor=1"2481 "url": "https://github.com/chalk/chalk?sponsor=1"
@@ -2703,23 +2718,52 @@
2703 }2718 }
2704 },2719 },
2705 "node_modules/compression": {2720 "node_modules/compression": {
2706 "version": "1.7.4",2721 "version": "1.8.0",
2707 "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",2722 "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
2708 "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",2723 "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
2709 "license": "MIT",2724 "license": "MIT",
2710 "dependencies": {2725 "dependencies": {
2711 "accepts": "~1.3.5",2726 "bytes": "3.1.2",
2712 "bytes": "3.0.0",2727 "compressible": "~2.0.18",
2713 "compressible": "~2.0.16",
2714 "debug": "2.6.9",2728 "debug": "2.6.9",
2729 "negotiator": "~0.6.4",
2715 "on-headers": "~1.0.2",2730 "on-headers": "~1.0.2",
2716 "safe-buffer": "5.1.2",2731 "safe-buffer": "5.2.1",
2717 "vary": "~1.1.2"2732 "vary": "~1.1.2"
2718 },2733 },
2719 "engines": {2734 "engines": {
2720 "node": ">= 0.8.0"2735 "node": ">= 0.8.0"
2721 }2736 }
2722 },2737 },
2738 "node_modules/compression/node_modules/negotiator": {
2739 "version": "0.6.4",
2740 "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
2741 "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
2742 "license": "MIT",
2743 "engines": {
2744 "node": ">= 0.6"
2745 }
2746 },
2747 "node_modules/compression/node_modules/safe-buffer": {
2748 "version": "5.2.1",
2749 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
2750 "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
2751 "funding": [
2752 {
2753 "type": "github",
2754 "url": "https://github.com/sponsors/feross"
2755 },
2756 {
2757 "type": "patreon",
2758 "url": "https://www.patreon.com/feross"
2759 },
2760 {
2761 "type": "consulting",
2762 "url": "https://feross.org/support"
2763 }
2764 ],
2765 "license": "MIT"
2766 },
2723 "node_modules/concat-map": {2767 "node_modules/concat-map": {
2724 "version": "0.0.1",2768 "version": "0.0.1",
2725 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",2769 "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -3280,6 +3324,20 @@
3280 "node": ">=0.8.0"3324 "node": ">=0.8.0"
3281 }3325 }
3282 },3326 },
3327 "node_modules/dunder-proto": {
3328 "version": "1.0.1",
3329 "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
3330 "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
3331 "license": "MIT",
3332 "dependencies": {
3333 "call-bind-apply-helpers": "^1.0.1",
3334 "es-errors": "^1.3.0",
3335 "gopd": "^1.2.0"
3336 },
3337 "engines": {
3338 "node": ">= 0.4"
3339 }
3340 },
3283 "node_modules/eastasianwidth": {3341 "node_modules/eastasianwidth": {
3284 "version": "0.2.0",3342 "version": "0.2.0",
3285 "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",3343 "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -3347,9 +3405,9 @@
3347 }3405 }
3348 },3406 },
3349 "node_modules/es-define-property": {3407 "node_modules/es-define-property": {
3350 "version": "1.0.0",3408 "version": "1.0.1",
3351 "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",3409 "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
3352 "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",3410 "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
3353 "license": "MIT",3411 "license": "MIT",
3354 "dependencies": {3412 "dependencies": {
3355 "get-intrinsic": "^1.2.4"3413 "get-intrinsic": "^1.2.4"
@@ -3373,6 +3431,33 @@
3373 "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",3431 "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==",
3374 "license": "MIT"3432 "license": "MIT"
3375 },3433 },
3434 "node_modules/es-object-atoms": {
3435 "version": "1.1.1",
3436 "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
3437 "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
3438 "license": "MIT",
3439 "dependencies": {
3440 "es-errors": "^1.3.0"
3441 },
3442 "engines": {
3443 "node": ">= 0.4"
3444 }
3445 },
3446 "node_modules/es-set-tostringtag": {
3447 "version": "2.1.0",
3448 "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
3449 "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
3450 "license": "MIT",
3451 "dependencies": {
3452 "es-errors": "^1.3.0",
3453 "get-intrinsic": "^1.2.6",
3454 "has-tostringtag": "^1.0.2",
3455 "hasown": "^2.0.2"
3456 },
3457 "engines": {
3458 "node": ">= 0.4"
3459 }
3460 },
3376 "node_modules/escalade": {3461 "node_modules/escalade": {
3377 "version": "3.2.0",3462 "version": "3.2.0",
3378 "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",3463 "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -3419,17 +3504,18 @@
3419 }3504 }
3420 },3505 },
3421 "node_modules/eslint": {3506 "node_modules/eslint": {
3422 "version": "8.57.0",3507 "version": "8.57.1",
3423 "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",3508 "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
3424 "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",3509 "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
3510 "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
3425 "dev": true,3511 "dev": true,
3426 "license": "MIT",3512 "license": "MIT",
3427 "dependencies": {3513 "dependencies": {
3428 "@eslint-community/eslint-utils": "^4.2.0",3514 "@eslint-community/eslint-utils": "^4.2.0",
3429 "@eslint-community/regexpp": "^4.6.1",3515 "@eslint-community/regexpp": "^4.6.1",
3430 "@eslint/eslintrc": "^2.1.4",3516 "@eslint/eslintrc": "^2.1.4",
3431 "@eslint/js": "8.57.0",3517 "@eslint/js": "8.57.1",
3432 "@humanwhocodes/config-array": "^0.11.14",3518 "@humanwhocodes/config-array": "^0.13.0",
3433 "@humanwhocodes/module-importer": "^1.0.1",3519 "@humanwhocodes/module-importer": "^1.0.1",
3434 "@nodelib/fs.walk": "^1.2.8",3520 "@nodelib/fs.walk": "^1.2.8",
3435 "@ungap/structured-clone": "^1.2.0",3521 "@ungap/structured-clone": "^1.2.0",
@@ -3504,6 +3590,23 @@
3504 "url": "https://opencollective.com/eslint"3590 "url": "https://opencollective.com/eslint"
3505 }3591 }
3506 },3592 },
3593 "node_modules/eslint/node_modules/chalk": {
3594 "version": "4.1.2",
3595 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
3596 "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
3597 "dev": true,
3598 "license": "MIT",
3599 "dependencies": {
3600 "ansi-styles": "^4.1.0",
3601 "supports-color": "^7.1.0"
3602 },
3603 "engines": {
3604 "node": ">=10"
3605 },
3606 "funding": {
3607 "url": "https://github.com/chalk/chalk?sponsor=1"
3608 }
3609 },
3507 "node_modules/eslint/node_modules/debug": {3610 "node_modules/eslint/node_modules/debug": {
3508 "version": "4.3.4",3611 "version": "4.3.4",
3509 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",3612 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -3750,6 +3853,7 @@
3750 "version": "2.1.0",3853 "version": "2.1.0",
3751 "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",3854 "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
3752 "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",3855 "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
3856 "dev": true,
3753 "license": "MIT"3857 "license": "MIT"
3754 },3858 },
3755 "node_modules/fast-levenshtein": {3859 "node_modules/fast-levenshtein": {
@@ -3759,6 +3863,22 @@
3759 "dev": true,3863 "dev": true,
3760 "license": "MIT"3864 "license": "MIT"
3761 },3865 },
3866 "node_modules/fast-uri": {
3867 "version": "3.0.6",
3868 "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
3869 "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
3870 "funding": [
3871 {
3872 "type": "github",
3873 "url": "https://github.com/sponsors/fastify"
3874 },
3875 {
3876 "type": "opencollective",
3877 "url": "https://opencollective.com/fastify"
3878 }
3879 ],
3880 "license": "BSD-3-Clause"
3881 },
3762 "node_modules/fastq": {3882 "node_modules/fastq": {
3763 "version": "1.15.0",3883 "version": "1.15.0",
3764 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",3884 "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
@@ -3929,13 +4049,14 @@
3929 }4049 }
3930 },4050 },
3931 "node_modules/form-data": {4051 "node_modules/form-data": {
3932 "version": "4.0.0",4052 "version": "4.0.2",
3933 "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",4053 "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
3934 "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",4054 "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
3935 "license": "MIT",4055 "license": "MIT",
3936 "dependencies": {4056 "dependencies": {
3937 "asynckit": "^0.4.0",4057 "asynckit": "^0.4.0",
3938 "combined-stream": "^1.0.8",4058 "combined-stream": "^1.0.8",
4059 "es-set-tostringtag": "^2.1.0",
3939 "mime-types": "^2.1.12"4060 "mime-types": "^2.1.12"
3940 },4061 },
3941 "engines": {4062 "engines": {
@@ -4000,20 +4121,6 @@
4000 "node": ">= 0.6"4121 "node": ">= 0.6"
4001 }4122 }
4002 },4123 },
4003 "node_modules/fs-extra": {
4004 "version": "11.2.0",
4005 "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
4006 "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
4007 "license": "MIT",
4008 "dependencies": {
4009 "graceful-fs": "^4.2.0",
4010 "jsonfile": "^6.0.1",
4011 "universalify": "^2.0.0"
4012 },
4013 "engines": {
4014 "node": ">=14.14"
4015 }
4016 },
4017 "node_modules/fs.realpath": {4124 "node_modules/fs.realpath": {
4018 "version": "1.0.0",4125 "version": "1.0.0",
4019 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",4126 "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -4031,9 +4138,9 @@
4031 }4138 }
4032 },4139 },
4033 "node_modules/fuse.js": {4140 "node_modules/fuse.js": {
4034 "version": "7.0.0",4141 "version": "7.1.0",
4035 "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz",4142 "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz",
4036 "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==",4143 "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==",
4037 "license": "Apache-2.0",4144 "license": "Apache-2.0",
4038 "engines": {4145 "engines": {
4039 "node": ">=10"4146 "node": ">=10"
@@ -4049,16 +4156,21 @@
4049 }4156 }
4050 },4157 },
4051 "node_modules/get-intrinsic": {4158 "node_modules/get-intrinsic": {
4052 "version": "1.2.4",4159 "version": "1.3.0",
4053 "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",4160 "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
4054 "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",4161 "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
4055 "license": "MIT",4162 "license": "MIT",
4056 "dependencies": {4163 "dependencies": {
4164 "call-bind-apply-helpers": "^1.0.2",
4165 "es-define-property": "^1.0.1",
4057 "es-errors": "^1.3.0",4166 "es-errors": "^1.3.0",
4167 "es-object-atoms": "^1.1.1",
4058 "function-bind": "^1.1.2",4168 "function-bind": "^1.1.2",
4059 "has-proto": "^1.0.1",4169 "get-proto": "^1.0.1",
4060 "has-symbols": "^1.0.3",4170 "gopd": "^1.2.0",
4061 "hasown": "^2.0.0"4171 "has-symbols": "^1.1.0",
4172 "hasown": "^2.0.2",
4173 "math-intrinsics": "^1.1.0"
4062 },4174 },
4063 "engines": {4175 "engines": {
4064 "node": ">= 0.4"4176 "node": ">= 0.4"
@@ -4067,6 +4179,19 @@
4067 "url": "https://github.com/sponsors/ljharb"4179 "url": "https://github.com/sponsors/ljharb"
4068 }4180 }
4069 },4181 },
4182 "node_modules/get-proto": {
4183 "version": "1.0.1",
4184 "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
4185 "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
4186 "license": "MIT",
4187 "dependencies": {
4188 "dunder-proto": "^1.0.1",
4189 "es-object-atoms": "^1.0.0"
4190 },
4191 "engines": {
4192 "node": ">= 0.4"
4193 }
4194 },
4070 "node_modules/get-stream": {4195 "node_modules/get-stream": {
4071 "version": "5.2.0",4196 "version": "5.2.0",
4072 "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",4197 "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
@@ -4083,24 +4208,23 @@
4083 }4208 }
4084 },4209 },
4085 "node_modules/get-uri": {4210 "node_modules/get-uri": {
4086 "version": "6.0.3",4211 "version": "6.0.4",
4087 "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz",4212 "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz",
4088 "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==",4213 "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==",
4089 "license": "MIT",4214 "license": "MIT",
4090 "dependencies": {4215 "dependencies": {
4091 "basic-ftp": "^5.0.2",4216 "basic-ftp": "^5.0.2",
4092 "data-uri-to-buffer": "^6.0.2",4217 "data-uri-to-buffer": "^6.0.2",
4093 "debug": "^4.3.4",4218 "debug": "^4.3.4"
4094 "fs-extra": "^11.2.0"
4095 },4219 },
4096 "engines": {4220 "engines": {
4097 "node": ">= 14"4221 "node": ">= 14"
4098 }4222 }
4099 },4223 },
4100 "node_modules/get-uri/node_modules/debug": {4224 "node_modules/get-uri/node_modules/debug": {
4101 "version": "4.3.7",4225 "version": "4.4.0",
4102 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",4226 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
4103 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",4227 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
4104 "license": "MIT",4228 "license": "MIT",
4105 "dependencies": {4229 "dependencies": {
4106 "ms": "^2.1.3"4230 "ms": "^2.1.3"
@@ -4190,9 +4314,9 @@
4190 "license": "MIT"4314 "license": "MIT"
4191 },4315 },
4192 "node_modules/google-translate-api-x": {4316 "node_modules/google-translate-api-x": {
4193 "version": "10.7.1",4317 "version": "10.7.2",
4194 "resolved": "https://registry.npmjs.org/google-translate-api-x/-/google-translate-api-x-10.7.1.tgz",4318 "resolved": "https://registry.npmjs.org/google-translate-api-x/-/google-translate-api-x-10.7.2.tgz",
4195 "integrity": "sha512-OdZDS6jRWzn1woOk62aOKQ5OyVaJSA+eyc6CktOWxo36IWfstOjwG/dkvnGl3Z2Sbpmk1A+jc2WwrBiRjqaY2A==",4319 "integrity": "sha512-GSmbvGMcnULaih2NFgD4Y6840DLAMot90mLWgwoB+FG/QpetyZkFrZkxop8ZxXgOAQXGskFOhGJady8nA6ZJ2g==",
4196 "license": "MIT",4320 "license": "MIT",
4197 "engines": {4321 "engines": {
4198 "node": ">=14.0.0"4322 "node": ">=14.0.0"
@@ -4203,12 +4327,12 @@
4203 }4327 }
4204 },4328 },
4205 "node_modules/gopd": {4329 "node_modules/gopd": {
4206 "version": "1.0.1",4330 "version": "1.2.0",
4207 "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",4331 "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
4208 "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",4332 "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
4209 "license": "MIT",4333 "license": "MIT",
4210 "dependencies": {4334 "engines": {
4211 "get-intrinsic": "^1.1.3"4335 "node": ">= 0.4"
4212 },4336 },
4213 "funding": {4337 "funding": {
4214 "url": "https://github.com/sponsors/ljharb"4338 "url": "https://github.com/sponsors/ljharb"
@@ -4305,10 +4429,10 @@
4305 "url": "https://github.com/sponsors/ljharb"4429 "url": "https://github.com/sponsors/ljharb"
4306 }4430 }
4307 },4431 },
4308 "node_modules/has-proto": {4432 "node_modules/has-symbols": {
4309 "version": "1.0.3",4433 "version": "1.1.0",
4310 "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",4434 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
4311 "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",4435 "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
4312 "license": "MIT",4436 "license": "MIT",
4313 "engines": {4437 "engines": {
4314 "node": ">= 0.4"4438 "node": ">= 0.4"
@@ -4317,11 +4441,14 @@
4317 "url": "https://github.com/sponsors/ljharb"4441 "url": "https://github.com/sponsors/ljharb"
4318 }4442 }
4319 },4443 },
4320 "node_modules/has-symbols": {4444 "node_modules/has-tostringtag": {
4321 "version": "1.0.3",4445 "version": "1.0.2",
4322 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",4446 "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
4323 "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",4447 "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
4324 "license": "MIT",4448 "license": "MIT",
4449 "dependencies": {
4450 "has-symbols": "^1.0.3"
4451 },
4325 "engines": {4452 "engines": {
4326 "node": ">= 0.4"4453 "node": ">= 0.4"
4327 },4454 },
@@ -4342,17 +4469,18 @@
4342 }4469 }
4343 },4470 },
4344 "node_modules/helmet": {4471 "node_modules/helmet": {
4345 "version": "7.1.0",4472 "version": "7.2.0",
4346 "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz",4473 "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz",
4347 "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==",4474 "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==",
4475 "license": "MIT",
4348 "engines": {4476 "engines": {
4349 "node": ">=16.0.0"4477 "node": ">=16.0.0"
4350 }4478 }
4351 },4479 },
4352 "node_modules/highlight.js": {4480 "node_modules/highlight.js": {
4353 "version": "11.10.0",4481 "version": "11.11.1",
4354 "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz",4482 "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
4355 "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==",4483 "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
4356 "license": "BSD-3-Clause",4484 "license": "BSD-3-Clause",
4357 "engines": {4485 "engines": {
4358 "node": ">=12.0.0"4486 "node": ">=12.0.0"
@@ -4429,9 +4557,9 @@
4429 }4557 }
4430 },4558 },
4431 "node_modules/http-proxy-agent/node_modules/debug": {4559 "node_modules/http-proxy-agent/node_modules/debug": {
4432 "version": "4.3.7",4560 "version": "4.4.0",
4433 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",4561 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
4434 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",4562 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
4435 "license": "MIT",4563 "license": "MIT",
4436 "dependencies": {4564 "dependencies": {
4437 "ms": "^2.1.3"4565 "ms": "^2.1.3"
@@ -4465,12 +4593,12 @@
4465 }4593 }
4466 },4594 },
4467 "node_modules/https-proxy-agent": {4595 "node_modules/https-proxy-agent": {
4468 "version": "7.0.5",4596 "version": "7.0.6",
4469 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",4597 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
4470 "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",4598 "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
4471 "license": "MIT",4599 "license": "MIT",
4472 "dependencies": {4600 "dependencies": {
4473 "agent-base": "^7.0.2",4601 "agent-base": "^7.1.2",
4474 "debug": "4"4602 "debug": "4"
4475 },4603 },
4476 "engines": {4604 "engines": {
@@ -4478,9 +4606,9 @@
4478 }4606 }
4479 },4607 },
4480 "node_modules/https-proxy-agent/node_modules/debug": {4608 "node_modules/https-proxy-agent/node_modules/debug": {
4481 "version": "4.3.7",4609 "version": "4.4.0",
4482 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",4610 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
4483 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",4611 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
4484 "license": "MIT",4612 "license": "MIT",
4485 "dependencies": {4613 "dependencies": {
4486 "ms": "^2.1.3"4614 "ms": "^2.1.3"
@@ -4647,9 +4775,9 @@
4647 }4775 }
4648 },4776 },
4649 "node_modules/ipaddr.js": {4777 "node_modules/ipaddr.js": {
4650 "version": "2.1.0",4778 "version": "2.2.0",
4651 "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz",4779 "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
4652 "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==",4780 "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==",
4653 "license": "MIT",4781 "license": "MIT",
4654 "engines": {4782 "engines": {
4655 "node": ">= 10"4783 "node": ">= 10"
@@ -4662,15 +4790,15 @@
4662 "license": "MIT"4790 "license": "MIT"
4663 },4791 },
4664 "node_modules/is-docker": {4792 "node_modules/is-docker": {
4665 "version": "2.2.1",4793 "version": "3.0.0",
4666 "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",4794 "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
4667 "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",4795 "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
4668 "license": "MIT",4796 "license": "MIT",
4669 "bin": {4797 "bin": {
4670 "is-docker": "cli.js"4798 "is-docker": "cli.js"
4671 },4799 },
4672 "engines": {4800 "engines": {
4673 "node": ">=8"4801 "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
4674 },4802 },
4675 "funding": {4803 "funding": {
4676 "url": "https://github.com/sponsors/sindresorhus"4804 "url": "https://github.com/sponsors/sindresorhus"
@@ -4747,6 +4875,21 @@
4747 "node": ">=8"4875 "node": ">=8"
4748 }4876 }
4749 },4877 },
4878 "node_modules/is-wsl/node_modules/is-docker": {
4879 "version": "2.2.1",
4880 "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
4881 "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
4882 "license": "MIT",
4883 "bin": {
4884 "is-docker": "cli.js"
4885 },
4886 "engines": {
4887 "node": ">=8"
4888 },
4889 "funding": {
4890 "url": "https://github.com/sponsors/sindresorhus"
4891 }
4892 },
4750 "node_modules/isarray": {4893 "node_modules/isarray": {
4751 "version": "1.0.0",4894 "version": "1.0.0",
4752 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",4895 "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -4960,6 +5103,7 @@
4960 "version": "0.4.1",5103 "version": "0.4.1",
4961 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",5104 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
4962 "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",5105 "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
5106 "dev": true,
4963 "license": "MIT"5107 "license": "MIT"
4964 },5108 },
4965 "node_modules/json-stable-stringify-without-jsonify": {5109 "node_modules/json-stable-stringify-without-jsonify": {
@@ -4969,18 +5113,6 @@
4969 "dev": true,5113 "dev": true,
4970 "license": "MIT"5114 "license": "MIT"
4971 },5115 },
4972 "node_modules/jsonfile": {
4973 "version": "6.1.0",
4974 "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
4975 "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
4976 "license": "MIT",
4977 "dependencies": {
4978 "universalify": "^2.0.0"
4979 },
4980 "optionalDependencies": {
4981 "graceful-fs": "^4.1.6"
4982 }
4983 },
4984 "node_modules/keygrip": {5116 "node_modules/keygrip": {
4985 "version": "1.1.0",5117 "version": "1.1.0",
4986 "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",5118 "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
@@ -5127,6 +5259,15 @@
5127 "node": "14 || >=16.14"5259 "node": "14 || >=16.14"
5128 }5260 }
5129 },5261 },
5262 "node_modules/math-intrinsics": {
5263 "version": "1.1.0",
5264 "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
5265 "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
5266 "license": "MIT",
5267 "engines": {
5268 "node": ">= 0.4"
5269 }
5270 },
5130 "node_modules/md5": {5271 "node_modules/md5": {
5131 "version": "2.3.0",5272 "version": "2.3.0",
5132 "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",5273 "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@@ -5383,9 +5524,13 @@
5383 }5524 }
5384 },5525 },
5385 "node_modules/node-persist": {5526 "node_modules/node-persist": {
5386 "version": "4.0.1",5527 "version": "4.0.4",
5387 "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-4.0.1.tgz",5528 "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-4.0.4.tgz",
5388 "integrity": "sha512-QtRjwAlcOQChQpfG6odtEhxYmA3nS5XYr+bx9JRjwahl1TM3sm9J3CCn51/MI0eoHRb2DrkEsCOFo8sq8jG5sQ==",5529 "integrity": "sha512-8sPAz/7tw1mCCc8xBG4f0wi+flHkSSgQeX998iQ75Pu27evA6UUWCjSE7xnrYTg2q33oU5leJ061EKPDv6BocQ==",
5530 "license": "MIT",
5531 "dependencies": {
5532 "p-limit": "^3.1.0"
5533 },
5389 "engines": {5534 "engines": {
5390 "node": ">=10.12.0"5535 "node": ">=10.12.0"
5391 }5536 }
@@ -5531,6 +5676,21 @@
5531 "url": "https://github.com/sponsors/sindresorhus"5676 "url": "https://github.com/sponsors/sindresorhus"
5532 }5677 }
5533 },5678 },
5679 "node_modules/open/node_modules/is-docker": {
5680 "version": "2.2.1",
5681 "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
5682 "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
5683 "license": "MIT",
5684 "bin": {
5685 "is-docker": "cli.js"
5686 },
5687 "engines": {
5688 "node": ">=8"
5689 },
5690 "funding": {
5691 "url": "https://github.com/sponsors/sindresorhus"
5692 }
5693 },
5534 "node_modules/openai": {5694 "node_modules/openai": {
5535 "version": "4.17.4",5695 "version": "4.17.4",
5536 "resolved": "https://registry.npmjs.org/openai/-/openai-4.17.4.tgz",5696 "resolved": "https://registry.npmjs.org/openai/-/openai-4.17.4.tgz",
@@ -5602,7 +5762,6 @@
5602 "version": "3.1.0",5762 "version": "3.1.0",
5603 "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",5763 "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
5604 "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",5764 "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
5605 "dev": true,
5606 "license": "MIT",5765 "license": "MIT",
5607 "dependencies": {5766 "dependencies": {
5608 "yocto-queue": "^0.1.0"5767 "yocto-queue": "^0.1.0"
@@ -5631,28 +5790,28 @@
5631 }5790 }
5632 },5791 },
5633 "node_modules/pac-proxy-agent": {5792 "node_modules/pac-proxy-agent": {
5634 "version": "7.0.2",5793 "version": "7.2.0",
5635 "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz",5794 "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
5636 "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==",5795 "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
5637 "license": "MIT",5796 "license": "MIT",
5638 "dependencies": {5797 "dependencies": {
5639 "@tootallnate/quickjs-emscripten": "^0.23.0",5798 "@tootallnate/quickjs-emscripten": "^0.23.0",
5640 "agent-base": "^7.0.2",5799 "agent-base": "^7.1.2",
5641 "debug": "^4.3.4",5800 "debug": "^4.3.4",
5642 "get-uri": "^6.0.1",5801 "get-uri": "^6.0.1",
5643 "http-proxy-agent": "^7.0.0",5802 "http-proxy-agent": "^7.0.0",
5644 "https-proxy-agent": "^7.0.5",5803 "https-proxy-agent": "^7.0.6",
5645 "pac-resolver": "^7.0.1",5804 "pac-resolver": "^7.0.1",
5646 "socks-proxy-agent": "^8.0.4"5805 "socks-proxy-agent": "^8.0.5"
5647 },5806 },
5648 "engines": {5807 "engines": {
5649 "node": ">= 14"5808 "node": ">= 14"
5650 }5809 }
5651 },5810 },
5652 "node_modules/pac-proxy-agent/node_modules/debug": {5811 "node_modules/pac-proxy-agent/node_modules/debug": {
5653 "version": "4.3.7",5812 "version": "4.4.0",
5654 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",5813 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
5655 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",5814 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
5656 "license": "MIT",5815 "license": "MIT",
5657 "dependencies": {5816 "dependencies": {
5658 "ms": "^2.1.3"5817 "ms": "^2.1.3"
@@ -5988,19 +6147,19 @@
5988 }6147 }
5989 },6148 },
5990 "node_modules/proxy-agent": {6149 "node_modules/proxy-agent": {
5991 "version": "6.4.0",6150 "version": "6.5.0",
5992 "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz",6151 "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
5993 "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==",6152 "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
5994 "license": "MIT",6153 "license": "MIT",
5995 "dependencies": {6154 "dependencies": {
5996 "agent-base": "^7.0.2",6155 "agent-base": "^7.1.2",
5997 "debug": "^4.3.4",6156 "debug": "^4.3.4",
5998 "http-proxy-agent": "^7.0.1",6157 "http-proxy-agent": "^7.0.1",
5999 "https-proxy-agent": "^7.0.3",6158 "https-proxy-agent": "^7.0.6",
6000 "lru-cache": "^7.14.1",6159 "lru-cache": "^7.14.1",
6001 "pac-proxy-agent": "^7.0.1",6160 "pac-proxy-agent": "^7.1.0",
6002 "proxy-from-env": "^1.1.0",6161 "proxy-from-env": "^1.1.0",
6003 "socks-proxy-agent": "^8.0.2"6162 "socks-proxy-agent": "^8.0.5"
6004 },6163 },
6005 "engines": {6164 "engines": {
6006 "node": ">= 14"6165 "node": ">= 14"
@@ -6135,9 +6294,10 @@
6135 }6294 }
6136 },6295 },
6137 "node_modules/rate-limiter-flexible": {6296 "node_modules/rate-limiter-flexible": {
6138 "version": "5.0.0",6297 "version": "5.0.5",
6139 "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-5.0.0.tgz",6298 "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-5.0.5.tgz",
6140 "integrity": "sha512-ivCyLBwPtR5IRrz+aZnztVwX16ZK3iAjdlW21I/vjHq56at5Zb8eIefDzODg8R7hwPOHpBtb6Pj9Zdmn0nRb8g=="6299 "integrity": "sha512-+/dSQfo+3FYwYygUs/V2BBdwGa9nFtakDwKt4l0bnvNB53TNT++QSFewwHX9qXrZJuMe9j+TUaU21lm5ARgqdQ==",
6300 "license": "ISC"
6141 },6301 },
6142 "node_modules/raw-body": {6302 "node_modules/raw-body": {
6143 "version": "2.5.2",6303 "version": "2.5.2",
@@ -6154,15 +6314,6 @@
6154 "node": ">= 0.8"6314 "node": ">= 0.8"
6155 }6315 }
6156 },6316 },
6157 "node_modules/raw-body/node_modules/bytes": {
6158 "version": "3.1.2",
6159 "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
6160 "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
6161 "license": "MIT",
6162 "engines": {
6163 "node": ">= 0.8"
6164 }
6165 },
6166 "node_modules/raw-body/node_modules/iconv-lite": {6317 "node_modules/raw-body/node_modules/iconv-lite": {
6167 "version": "0.4.24",6318 "version": "0.4.24",
6168 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",6319 "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -6262,6 +6413,15 @@
6262 "node": ">=0.10.0"6413 "node": ">=0.10.0"
6263 }6414 }
6264 },6415 },
6416 "node_modules/require-from-string": {
6417 "version": "2.0.2",
6418 "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
6419 "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
6420 "license": "MIT",
6421 "engines": {
6422 "node": ">=0.10.0"
6423 }
6424 },
6265 "node_modules/resolve-alpn": {6425 "node_modules/resolve-alpn": {
6266 "version": "1.2.1",6426 "version": "1.2.1",
6267 "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",6427 "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
@@ -6279,27 +6439,18 @@
6279 }6439 }
6280 },6440 },
6281 "node_modules/response-time": {6441 "node_modules/response-time": {
6282 "version": "2.3.2",6442 "version": "2.3.3",
6283 "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz",6443 "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.3.tgz",
6284 "integrity": "sha512-MUIDaDQf+CVqflfTdQ5yam+aYCkXj1PY8fjlPDQ6ppxJlmgZb864pHtA750mayywNg8tx4rS7qH9JXd/OF+3gw==",6444 "integrity": "sha512-SsjjOPHl/FfrTQNgmc5oen8Hr1Jxpn6LlHNXxCIFdYMHuK1kMeYMobb9XN3mvxaGQm3dbegqYFMX4+GDORfbWg==",
6285 "license": "MIT",6445 "license": "MIT",
6286 "dependencies": {6446 "dependencies": {
6287 "depd": "~1.1.0",6447 "depd": "~2.0.0",
6288 "on-headers": "~1.0.1"6448 "on-headers": "~1.0.1"
6289 },6449 },
6290 "engines": {6450 "engines": {
6291 "node": ">= 0.8.0"6451 "node": ">= 0.8.0"
6292 }6452 }
6293 },6453 },
6294 "node_modules/response-time/node_modules/depd": {
6295 "version": "1.1.2",
6296 "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
6297 "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
6298 "license": "MIT",
6299 "engines": {
6300 "node": ">= 0.6"
6301 }
6302 },
6303 "node_modules/responselike": {6454 "node_modules/responselike": {
6304 "version": "2.0.1",6455 "version": "2.0.1",
6305 "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",6456 "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
@@ -6390,6 +6541,59 @@
6390 "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",6541 "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
6391 "license": "ISC"6542 "license": "ISC"
6392 },6543 },
6544 "node_modules/schema-utils": {
6545 "version": "4.3.0",
6546 "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz",
6547 "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==",
6548 "license": "MIT",
6549 "dependencies": {
6550 "@types/json-schema": "^7.0.9",
6551 "ajv": "^8.9.0",
6552 "ajv-formats": "^2.1.1",
6553 "ajv-keywords": "^5.1.0"
6554 },
6555 "engines": {
6556 "node": ">= 10.13.0"
6557 },
6558 "funding": {
6559 "type": "opencollective",
6560 "url": "https://opencollective.com/webpack"
6561 }
6562 },
6563 "node_modules/schema-utils/node_modules/ajv": {
6564 "version": "8.17.1",
6565 "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
6566 "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
6567 "license": "MIT",
6568 "dependencies": {
6569 "fast-deep-equal": "^3.1.3",
6570 "fast-uri": "^3.0.1",
6571 "json-schema-traverse": "^1.0.0",
6572 "require-from-string": "^2.0.2"
6573 },
6574 "funding": {
6575 "type": "github",
6576 "url": "https://github.com/sponsors/epoberezkin"
6577 }
6578 },
6579 "node_modules/schema-utils/node_modules/ajv-keywords": {
6580 "version": "5.1.0",
6581 "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
6582 "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
6583 "license": "MIT",
6584 "dependencies": {
6585 "fast-deep-equal": "^3.1.3"
6586 },
6587 "peerDependencies": {
6588 "ajv": "^8.8.2"
6589 }
6590 },
6591 "node_modules/schema-utils/node_modules/json-schema-traverse": {
6592 "version": "1.0.0",
6593 "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
6594 "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
6595 "license": "MIT"
6596 },
6393 "node_modules/seedrandom": {6597 "node_modules/seedrandom": {
6394 "version": "3.0.5",6598 "version": "3.0.5",
6395 "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",6599 "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
@@ -6570,14 +6774,14 @@
6570 }6774 }
6571 },6775 },
6572 "node_modules/simple-git": {6776 "node_modules/simple-git": {
6573 "version": "3.19.1",6777 "version": "3.27.0",
6574 "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.19.1.tgz",6778 "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz",
6575 "integrity": "sha512-Ck+rcjVaE1HotraRAS8u/+xgTvToTuoMkT9/l9lvuP5jftwnYUp6DwuJzsKErHgfyRk8IB8pqGHWEbM3tLgV1w==",6779 "integrity": "sha512-ivHoFS9Yi9GY49ogc6/YAi3Fl9ROnF4VyubNylgCkA+RVqLaKWnDSzXOVzya8csELIaWaYNutsEuAhZrtOjozA==",
6576 "license": "MIT",6780 "license": "MIT",
6577 "dependencies": {6781 "dependencies": {
6578 "@kwsites/file-exists": "^1.1.1",6782 "@kwsites/file-exists": "^1.1.1",
6579 "@kwsites/promise-deferred": "^1.1.1",6783 "@kwsites/promise-deferred": "^1.1.1",
6580 "debug": "^4.3.4"6784 "debug": "^4.3.5"
6581 },6785 },
6582 "funding": {6786 "funding": {
6583 "type": "github",6787 "type": "github",
@@ -6585,12 +6789,12 @@
6585 }6789 }
6586 },6790 },
6587 "node_modules/simple-git/node_modules/debug": {6791 "node_modules/simple-git/node_modules/debug": {
6588 "version": "4.3.4",6792 "version": "4.4.0",
6589 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",6793 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
6590 "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",6794 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
6591 "license": "MIT",6795 "license": "MIT",
6592 "dependencies": {6796 "dependencies": {
6593 "ms": "2.1.2"6797 "ms": "^2.1.3"
6594 },6798 },
6595 "engines": {6799 "engines": {
6596 "node": ">=6.0"6800 "node": ">=6.0"
@@ -6602,9 +6806,9 @@
6602 }6806 }
6603 },6807 },
6604 "node_modules/simple-git/node_modules/ms": {6808 "node_modules/simple-git/node_modules/ms": {
6605 "version": "2.1.2",6809 "version": "2.1.3",
6606 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",6810 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
6607 "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",6811 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
6608 "license": "MIT"6812 "license": "MIT"
6609 },6813 },
6610 "node_modules/sliced": {6814 "node_modules/sliced": {
@@ -6630,9 +6834,9 @@
6630 }6834 }
6631 },6835 },
6632 "node_modules/socks": {6836 "node_modules/socks": {
6633 "version": "2.8.3",6837 "version": "2.8.4",
6634 "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",6838 "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
6635 "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",6839 "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
6636 "license": "MIT",6840 "license": "MIT",
6637 "dependencies": {6841 "dependencies": {
6638 "ip-address": "^9.0.5",6842 "ip-address": "^9.0.5",
@@ -6644,12 +6848,12 @@
6644 }6848 }
6645 },6849 },
6646 "node_modules/socks-proxy-agent": {6850 "node_modules/socks-proxy-agent": {
6647 "version": "8.0.4",6851 "version": "8.0.5",
6648 "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",6852 "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
6649 "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",6853 "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
6650 "license": "MIT",6854 "license": "MIT",
6651 "dependencies": {6855 "dependencies": {
6652 "agent-base": "^7.1.1",6856 "agent-base": "^7.1.2",
6653 "debug": "^4.3.4",6857 "debug": "^4.3.4",
6654 "socks": "^2.8.3"6858 "socks": "^2.8.3"
6655 },6859 },
@@ -6658,9 +6862,9 @@
6658 }6862 }
6659 },6863 },
6660 "node_modules/socks-proxy-agent/node_modules/debug": {6864 "node_modules/socks-proxy-agent/node_modules/debug": {
6661 "version": "4.3.7",6865 "version": "4.4.0",
6662 "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",6866 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
6663 "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",6867 "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
6664 "license": "MIT",6868 "license": "MIT",
6665 "dependencies": {6869 "dependencies": {
6666 "ms": "^2.1.3"6870 "ms": "^2.1.3"
@@ -6858,9 +7062,9 @@
6858 }7062 }
6859 },7063 },
6860 "node_modules/terser": {7064 "node_modules/terser": {
6861 "version": "5.36.0",7065 "version": "5.39.0",
6862 "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz",7066 "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
6863 "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==",7067 "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
6864 "license": "BSD-2-Clause",7068 "license": "BSD-2-Clause",
6865 "dependencies": {7069 "dependencies": {
6866 "@jridgewell/source-map": "^0.3.3",7070 "@jridgewell/source-map": "^0.3.3",
@@ -6876,16 +7080,16 @@
6876 }7080 }
6877 },7081 },
6878 "node_modules/terser-webpack-plugin": {7082 "node_modules/terser-webpack-plugin": {
6879 "version": "5.3.10",7083 "version": "5.3.12",
6880 "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",7084 "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.12.tgz",
6881 "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",7085 "integrity": "sha512-jDLYqo7oF8tJIttjXO6jBY5Hk8p3A8W4ttih7cCEq64fQFWmgJ4VqAQjKr7WwIDlmXKEc6QeoRb5ecjZ+2afcg==",
6882 "license": "MIT",7086 "license": "MIT",
6883 "dependencies": {7087 "dependencies": {
6884 "@jridgewell/trace-mapping": "^0.3.20",7088 "@jridgewell/trace-mapping": "^0.3.25",
6885 "jest-worker": "^27.4.5",7089 "jest-worker": "^27.4.5",
6886 "schema-utils": "^3.1.1",7090 "schema-utils": "^4.3.0",
6887 "serialize-javascript": "^6.0.1",7091 "serialize-javascript": "^6.0.2",
6888 "terser": "^5.26.0"7092 "terser": "^5.31.1"
6889 },7093 },
6890 "engines": {7094 "engines": {
6891 "node": ">= 10.13.0"7095 "node": ">= 10.13.0"
@@ -6909,24 +7113,6 @@
6909 }7113 }
6910 }7114 }
6911 },7115 },
6912 "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
6913 "version": "3.3.0",
6914 "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
6915 "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
6916 "license": "MIT",
6917 "dependencies": {
6918 "@types/json-schema": "^7.0.8",
6919 "ajv": "^6.12.5",
6920 "ajv-keywords": "^3.5.2"
6921 },
6922 "engines": {
6923 "node": ">= 10.13.0"
6924 },
6925 "funding": {
6926 "type": "opencollective",
6927 "url": "https://opencollective.com/webpack"
6928 }
6929 },
6930 "node_modules/text-table": {7116 "node_modules/text-table": {
6931 "version": "0.2.0",7117 "version": "0.2.0",
6932 "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",7118 "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -6935,9 +7121,9 @@
6935 "license": "MIT"7121 "license": "MIT"
6936 },7122 },
6937 "node_modules/tiktoken": {7123 "node_modules/tiktoken": {
6938 "version": "1.0.16",7124 "version": "1.0.20",
6939 "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.16.tgz",7125 "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.20.tgz",
6940 "integrity": "sha512-hRcORIGF2YlAgWx3nzrGJOrKSJwLoc81HpXmMQk89632XAgURc7IeV2FgQ2iXo9z/J96fCvpsHg2kWoHcbj9fg==",7126 "integrity": "sha512-zVIpXp84kth/Ni2me1uYlJgl2RZ2EjxwDaWLeDY/s6fZiyO9n1QoTOM5P7ZSYfToPvAvwYNMbg5LETVYVKyzfQ==",
6941 "license": "MIT"7127 "license": "MIT"
6942 },7128 },
6943 "node_modules/timm": {7129 "node_modules/timm": {
@@ -7000,9 +7186,9 @@
7000 }7186 }
7001 },7187 },
7002 "node_modules/tslib": {7188 "node_modules/tslib": {
7003 "version": "2.7.0",7189 "version": "2.8.1",
7004 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",7190 "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
7005 "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",7191 "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
7006 "license": "0BSD"7192 "license": "0BSD"
7007 },7193 },
7008 "node_modules/tsscmp": {7194 "node_modules/tsscmp": {
@@ -7077,15 +7263,6 @@
7077 "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",7263 "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
7078 "license": "MIT"7264 "license": "MIT"
7079 },7265 },
7080 "node_modules/universalify": {
7081 "version": "2.0.1",
7082 "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
7083 "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
7084 "license": "MIT",
7085 "engines": {
7086 "node": ">= 10.0.0"
7087 }
7088 },
7089 "node_modules/unpipe": {7266 "node_modules/unpipe": {
7090 "version": "1.0.0",7267 "version": "1.0.0",
7091 "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",7268 "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -7129,6 +7306,7 @@
7129 "version": "4.4.1",7306 "version": "4.4.1",
7130 "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",7307 "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
7131 "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",7308 "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
7309 "dev": true,
7132 "license": "BSD-2-Clause",7310 "license": "BSD-2-Clause",
7133 "dependencies": {7311 "dependencies": {
7134 "punycode": "^2.1.0"7312 "punycode": "^2.1.0"
@@ -7257,18 +7435,18 @@
7257 }7435 }
7258 },7436 },
7259 "node_modules/webpack": {7437 "node_modules/webpack": {
7260 "version": "5.95.0",7438 "version": "5.98.0",
7261 "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.95.0.tgz",7439 "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz",
7262 "integrity": "sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==",7440 "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==",
7263 "license": "MIT",7441 "license": "MIT",
7264 "dependencies": {7442 "dependencies": {
7265 "@types/estree": "^1.0.5",7443 "@types/eslint-scope": "^3.7.7",
7266 "@webassemblyjs/ast": "^1.12.1",7444 "@types/estree": "^1.0.6",
7267 "@webassemblyjs/wasm-edit": "^1.12.1",7445 "@webassemblyjs/ast": "^1.14.1",
7268 "@webassemblyjs/wasm-parser": "^1.12.1",7446 "@webassemblyjs/wasm-edit": "^1.14.1",
7269 "acorn": "^8.7.1",7447 "@webassemblyjs/wasm-parser": "^1.14.1",
7270 "acorn-import-attributes": "^1.9.5",7448 "acorn": "^8.14.0",
7271 "browserslist": "^4.21.10",7449 "browserslist": "^4.24.0",
7272 "chrome-trace-event": "^1.0.2",7450 "chrome-trace-event": "^1.0.2",
7273 "enhanced-resolve": "^5.17.1",7451 "enhanced-resolve": "^5.17.1",
7274 "es-module-lexer": "^1.2.1",7452 "es-module-lexer": "^1.2.1",
@@ -7280,9 +7458,9 @@
7280 "loader-runner": "^4.2.0",7458 "loader-runner": "^4.2.0",
7281 "mime-types": "^2.1.27",7459 "mime-types": "^2.1.27",
7282 "neo-async": "^2.6.2",7460 "neo-async": "^2.6.2",
7283 "schema-utils": "^3.2.0",7461 "schema-utils": "^4.3.0",
7284 "tapable": "^2.1.1",7462 "tapable": "^2.1.1",
7285 "terser-webpack-plugin": "^5.3.10",7463 "terser-webpack-plugin": "^5.3.11",
7286 "watchpack": "^2.4.1",7464 "watchpack": "^2.4.1",
7287 "webpack-sources": "^3.2.3"7465 "webpack-sources": "^3.2.3"
7288 },7466 },
@@ -7333,24 +7511,6 @@
7333 "node": ">=4.0"7511 "node": ">=4.0"
7334 }7512 }
7335 },7513 },
7336 "node_modules/webpack/node_modules/schema-utils": {
7337 "version": "3.3.0",
7338 "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
7339 "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
7340 "license": "MIT",
7341 "dependencies": {
7342 "@types/json-schema": "^7.0.8",
7343 "ajv": "^6.12.5",
7344 "ajv-keywords": "^3.5.2"
7345 },
7346 "engines": {
7347 "node": ">= 10.13.0"
7348 },
7349 "funding": {
7350 "type": "opencollective",
7351 "url": "https://opencollective.com/webpack"
7352 }
7353 },
7354 "node_modules/whatwg-fetch": {7514 "node_modules/whatwg-fetch": {
7355 "version": "3.6.20",7515 "version": "3.6.20",
7356 "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",7516 "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz",
@@ -7445,9 +7605,10 @@
7445 }7605 }
7446 },7606 },
7447 "node_modules/ws": {7607 "node_modules/ws": {
7448 "version": "8.17.1",7608 "version": "8.18.1",
7449 "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",7609 "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz",
7450 "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",7610 "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==",
7611 "license": "MIT",
7451 "engines": {7612 "engines": {
7452 "node": ">=10.0.0"7613 "node": ">=10.0.0"
7453 },7614 },
@@ -7523,10 +7684,13 @@
7523 }7684 }
7524 },7685 },
7525 "node_modules/yaml": {7686 "node_modules/yaml": {
7526 "version": "2.3.4",7687 "version": "2.7.0",
7527 "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",7688 "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
7528 "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==",7689 "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
7529 "license": "ISC",7690 "license": "ISC",
7691 "bin": {
7692 "yaml": "bin.mjs"
7693 },
7530 "engines": {7694 "engines": {
7531 "node": ">= 14"7695 "node": ">= 14"
7532 }7696 }
@@ -7572,7 +7736,6 @@
7572 "version": "0.1.0",7736 "version": "0.1.0",
7573 "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",7737 "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
7574 "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",7738 "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
7575 "dev": true,
7576 "license": "MIT",7739 "license": "MIT",
7577 "engines": {7740 "engines": {
7578 "node": ">=10"7741 "node": ">=10"
package.json+34 -30
@@ -1,18 +1,20 @@
1{1{
2 "dependencies": {2 "dependencies": {
3 "@adobe/css-tools": "^4.4.0",3 "@adobe/css-tools": "^4.4.2",
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",
7 "@mozilla/readability": "^0.5.0",7 "@mozilla/readability": "^0.6.0",
8 "@popperjs/core": "^2.11.8",8 "@popperjs/core": "^2.11.8",
9 "@zeldafan0225/ai_horde": "^5.1.0",9 "@zeldafan0225/ai_horde": "^5.2.0",
10 "archiver": "^7.0.1",10 "archiver": "^7.0.1",
11 "bing-translate-api": "^4.0.2",11 "bing-translate-api": "^4.0.2",
12 "body-parser": "^1.20.2",12 "body-parser": "^1.20.2",
13 "bowser": "^2.11.0",13 "bowser": "^2.11.0",
14 "bytes": "^3.1.2",
15 "chalk": "^5.4.1",
14 "command-exists": "^1.2.9",16 "command-exists": "^1.2.9",
15 "compression": "^1",17 "compression": "^1.8.0",
16 "cookie-parser": "^1.4.6",18 "cookie-parser": "^1.4.6",
17 "cookie-session": "^2.1.0",19 "cookie-session": "^2.1.0",
18 "cors": "^2.8.5",20 "cors": "^2.8.5",
@@ -21,18 +23,19 @@
21 "dompurify": "^3.2.4",23 "dompurify": "^3.2.4",
22 "droll": "^0.2.1",24 "droll": "^0.2.1",
23 "express": "^4.21.0",25 "express": "^4.21.0",
24 "form-data": "^4.0.0",26 "form-data": "^4.0.2",
25 "fuse.js": "^7.0.0",27 "fuse.js": "^7.1.0",
26 "google-translate-api-browser": "^3.0.1",28 "google-translate-api-browser": "^3.0.1",
27 "google-translate-api-x": "^10.7.1",29 "google-translate-api-x": "^10.7.2",
28 "handlebars": "^4.7.8",30 "handlebars": "^4.7.8",
29 "helmet": "^7.1.0",31 "helmet": "^7.2.0",
30 "highlight.js": "^11.10.0",32 "highlight.js": "^11.11.1",
31 "html-entities": "^2.5.2",33 "html-entities": "^2.5.2",
32 "iconv-lite": "^0.6.3",34 "iconv-lite": "^0.6.3",
33 "ip-matching": "^2.1.2",35 "ip-matching": "^2.1.2",
34 "ip-regex": "^5.0.0",36 "ip-regex": "^5.0.0",
35 "ipaddr.js": "^2.0.1",37 "ipaddr.js": "^2.2.0",
38 "is-docker": "^3.0.0",
36 "jimp": "^0.22.10",39 "jimp": "^0.22.10",
37 "localforage": "^1.10.0",40 "localforage": "^1.10.0",
38 "lodash": "^4.17.21",41 "lodash": "^4.17.21",
@@ -41,28 +44,28 @@
41 "morphdom": "^2.7.4",44 "morphdom": "^2.7.4",
42 "multer": "^1.4.5-lts.1",45 "multer": "^1.4.5-lts.1",
43 "node-fetch": "^3.3.2",46 "node-fetch": "^3.3.2",
44 "node-persist": "^4.0.1",47 "node-persist": "^4.0.4",
45 "open": "^8.4.2",48 "open": "^8.4.2",
46 "png-chunk-text": "^1.0.0",49 "png-chunk-text": "^1.0.0",
47 "png-chunks-encode": "^1.0.0",50 "png-chunks-encode": "^1.0.0",
48 "png-chunks-extract": "^1.0.0",51 "png-chunks-extract": "^1.0.0",
49 "proxy-agent": "^6.4.0",52 "proxy-agent": "^6.5.0",
50 "rate-limiter-flexible": "^5.0.0",53 "rate-limiter-flexible": "^5.0.5",
51 "response-time": "^2.3.2",54 "response-time": "^2.3.3",
52 "sanitize-filename": "^1.6.3",55 "sanitize-filename": "^1.6.3",
53 "seedrandom": "^3.0.5",56 "seedrandom": "^3.0.5",
54 "showdown": "^2.1.0",57 "showdown": "^2.1.0",
55 "sillytavern-transformers": "2.14.6",58 "sillytavern-transformers": "2.14.6",
56 "simple-git": "^3.19.1",59 "simple-git": "^3.27.0",
57 "slidetoggle": "^4.0.0",60 "slidetoggle": "^4.0.0",
58 "tiktoken": "^1.0.16",61 "tiktoken": "^1.0.20",
59 "url-join": "^5.0.0",62 "url-join": "^5.0.0",
60 "vectra": "^0.2.2",63 "vectra": "^0.2.2",
61 "wavefile": "^11.0.0",64 "wavefile": "^11.0.0",
62 "webpack": "^5.95.0",65 "webpack": "^5.98.0",
63 "write-file-atomic": "^5.0.1",66 "write-file-atomic": "^5.0.1",
64 "ws": "^8.17.1",67 "ws": "^8.18.1",
65 "yaml": "^2.3.4",68 "yaml": "^2.7.0",
66 "yargs": "^17.7.1",69 "yargs": "^17.7.1",
67 "yauzl": "^2.10.0"70 "yauzl": "^2.10.0"
68 },71 },
@@ -87,10 +90,11 @@
87 "type": "git",90 "type": "git",
88 "url": "https://github.com/SillyTavern/SillyTavern.git"91 "url": "https://github.com/SillyTavern/SillyTavern.git"
89 },92 },
90 "version": "1.12.12",93 "version": "1.12.13",
91 "scripts": {94 "scripts": {
92 "start": "node server.js",95 "start": "node server.js",
93 "debug": "node server.js --inspect",96 "debug": "node --inspect server.js",
97 "start:electron": "cd ./src/electron && npm run start",
94 "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",98 "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
95 "start:bun": "bun server.js",99 "start:bun": "bun server.js",
96 "start:no-csrf": "node server.js --disableCsrf",100 "start:no-csrf": "node server.js --disableCsrf",
@@ -109,23 +113,23 @@
109 },113 },
110 "main": "server.js",114 "main": "server.js",
111 "devDependencies": {115 "devDependencies": {
112 "@types/archiver": "^6.0.2",116 "@types/archiver": "^6.0.3",
117 "@types/bytes": "^3.1.5",
113 "@types/command-exists": "^1.2.3",118 "@types/command-exists": "^1.2.3",
114 "@types/compression": "^1.7.5",119 "@types/compression": "^1.7.5",
115 "@types/cookie-parser": "^1.4.7",120 "@types/cookie-parser": "^1.4.8",
116 "@types/cookie-session": "^2.0.49",121 "@types/cookie-session": "^2.0.49",
117 "@types/cors": "^2.8.17",122 "@types/cors": "^2.8.17",
118 "@types/deno": "^2.0.0",123 "@types/deno": "^2.2.0",
119 "@types/dompurify": "^3.2.0",
120 "@types/express": "^4.17.21",124 "@types/express": "^4.17.21",
121 "@types/jquery": "^3.5.29",125 "@types/jquery": "^3.5.32",
122 "@types/jquery-cropper": "^1.0.4",126 "@types/jquery-cropper": "^1.0.4",
123 "@types/jquery.transit": "^0.9.33",127 "@types/jquery.transit": "^0.9.33",
124 "@types/jqueryui": "^1.12.23",128 "@types/jqueryui": "^1.12.24",
125 "@types/lodash": "^4.17.10",129 "@types/lodash": "^4.17.16",
126 "@types/mime-types": "^2.1.4",130 "@types/mime-types": "^2.1.4",
127 "@types/multer": "^1.4.12",131 "@types/multer": "^1.4.12",
128 "@types/node": "^18.19.55",132 "@types/node": "^18.19.80",
129 "@types/node-persist": "^3.1.8",133 "@types/node-persist": "^3.1.8",
130 "@types/png-chunk-text": "^1.0.3",134 "@types/png-chunk-text": "^1.0.3",
131 "@types/png-chunks-encode": "^1.0.2",135 "@types/png-chunks-encode": "^1.0.2",
@@ -136,6 +140,6 @@
136 "@types/write-file-atomic": "^4.0.3",140 "@types/write-file-atomic": "^4.0.3",
137 "@types/yargs": "^17.0.33",141 "@types/yargs": "^17.0.33",
138 "@types/yauzl": "^2.10.3",142 "@types/yauzl": "^2.10.3",
139 "eslint": "^8.57.0"143 "eslint": "^8.57.1"
140 }144 }
141}145}
plugins.js+2 -2
@@ -8,7 +8,7 @@ import path from 'node:path';
8import process from 'node:process';8import process from 'node:process';
9import { fileURLToPath } from 'node:url';9import { fileURLToPath } from 'node:url';
1010
11import { default as git } from 'simple-git';11import { default as git, CheckRepoActions } from 'simple-git';
12import { color } from './src/util.js';12import { color } from './src/util.js';
1313
14const __dirname = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url));14const __dirname = import.meta.dirname ?? path.dirname(fileURLToPath(import.meta.url));
@@ -49,7 +49,7 @@ async function updatePlugins() {
49 const pluginPath = path.join(pluginsPath, directory);49 const pluginPath = path.join(pluginsPath, directory);
50 const pluginRepo = git(pluginPath);50 const pluginRepo = git(pluginPath);
5151
52 const isRepo = await pluginRepo.checkIsRepo();52 const isRepo = await pluginRepo.checkIsRepo(CheckRepoActions.IS_REPO_ROOT);
53 if (!isRepo) {53 if (!isRepo) {
54 console.log(`Directory ${color.yellow(directory)} is not a Git repository`);54 console.log(`Directory ${color.yellow(directory)} is not a Git repository`);
55 continue;55 continue;
post-install.js+31 -16
@@ -7,26 +7,13 @@ import crypto from 'node:crypto';
7import process from 'node:process';7import process from 'node:process';
8import yaml from 'yaml';8import yaml from 'yaml';
9import _ from 'lodash';9import _ from 'lodash';
10import chalk from 'chalk';
10import { createRequire } from 'node:module';11import { createRequire } from 'node:module';
1112
12/**13/**
13 * Colorizes console output.14 * Colorizes console output.
14 */15 */
15const color = {16const color = chalk;
16 byNum: (mess, fgNum) => {
17 mess = mess || '';
18 fgNum = fgNum === undefined ? 31 : fgNum;
19 return '\u001b[' + fgNum + 'm' + mess + '\u001b[39m';
20 },
21 black: (mess) => color.byNum(mess, 30),
22 red: (mess) => color.byNum(mess, 31),
23 green: (mess) => color.byNum(mess, 32),
24 yellow: (mess) => color.byNum(mess, 33),
25 blue: (mess) => color.byNum(mess, 34),
26 magenta: (mess) => color.byNum(mess, 35),
27 cyan: (mess) => color.byNum(mess, 36),
28 white: (mess) => color.byNum(mess, 37),
29};
3017
31const keyMigrationMap = [18const keyMigrationMap = [
32 {19 {
@@ -104,6 +91,25 @@ const keyMigrationMap = [
104 newKey: 'extensions.models.textToSpeech',91 newKey: 'extensions.models.textToSpeech',
105 migrate: (value) => value,92 migrate: (value) => value,
106 },93 },
94 {
95 oldKey: 'minLogLevel',
96 newKey: 'logging.minLogLevel',
97 migrate: (value) => value,
98 },
99 {
100 oldKey: 'cardsCacheCapacity',
101 newKey: 'performance.memoryCacheCapacity',
102 migrate: (value) => `${value}mb`,
103 },
104 // uncomment one release after 1.12.13
105 /*
106 {
107 oldKey: 'cookieSecret',
108 newKey: 'cookieSecret',
109 migrate: () => void 0,
110 remove: true,
111 },
112 */
107];113];
108114
109/**115/**
@@ -163,8 +169,17 @@ function addMissingConfigValues() {
163169
164 // Migrate old keys to new keys170 // Migrate old keys to new keys
165 const migratedKeys = [];171 const migratedKeys = [];
166 for (const { oldKey, newKey, migrate } of keyMigrationMap) {172 for (const { oldKey, newKey, migrate, remove } of keyMigrationMap) {
167 if (_.has(config, oldKey)) {173 if (_.has(config, oldKey)) {
174 if (remove) {
175 _.unset(config, oldKey);
176 migratedKeys.push({
177 oldKey,
178 newValue: void 0,
179 });
180 continue;
181 }
182
168 const oldValue = _.get(config, oldKey);183 const oldValue = _.get(config, oldKey);
169 const newValue = migrate(oldValue);184 const newValue = migrate(oldValue);
170 _.set(config, newKey, newValue);185 _.set(config, newKey, newValue);
public/css/scrollable-button.css+0 -1
@@ -1,6 +1,5 @@
1.scrollable-buttons-container {1.scrollable-buttons-container {
2 max-height: 50vh; /* Use viewport height instead of fixed pixels */2 max-height: 50vh; /* Use viewport height instead of fixed pixels */
3 overflow-y: auto;
4 -webkit-overflow-scrolling: touch; /* Momentum scrolling on iOS */3 -webkit-overflow-scrolling: touch; /* Momentum scrolling on iOS */
5 margin-top: 1rem; /* m-t-1 is equivalent to margin-top: 1rem; */4 margin-top: 1rem; /* m-t-1 is equivalent to margin-top: 1rem; */
6 flex-shrink: 1;5 flex-shrink: 1;
public/css/toggle-dependent.css+6 -5
@@ -96,11 +96,6 @@ body.charListGrid #rm_print_characters_block .group_select .group_name_block,
96 flex-direction: column;96 flex-direction: column;
97}97}
9898
99#user_avatar_block.gridView .avatar-container .avatar-buttons {
100 flex-wrap: wrap;
101 justify-content: space-evenly;
102}
103
104body.charListGrid #rm_print_characters_block .bogus_folder_select .character_select_container,99body.charListGrid #rm_print_characters_block .bogus_folder_select .character_select_container,
105body.charListGrid #rm_print_characters_block .character_select .character_select_container,100body.charListGrid #rm_print_characters_block .character_select .character_select_container,
106body.charListGrid #rm_print_characters_block .group_select .group_select_container,101body.charListGrid #rm_print_characters_block .group_select .group_select_container,
@@ -231,10 +226,16 @@ body.big-avatars .avatars_inline_small .avatar img {
231body.big-avatars .avatars_inline {226body.big-avatars .avatars_inline {
232 max-height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) + 2 * var(--avatar-base-border-radius));227 max-height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) + 2 * var(--avatar-base-border-radius));
233}228}
229body.big-avatars .avatars_inline.avatars_multiline {
230 max-height: fit-content;
231}
234232
235body.big-avatars .avatars_inline.avatars_inline_small {233body.big-avatars .avatars_inline.avatars_inline_small {
236 height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-small-factor) + 2 * var(--avatar-base-border-radius));234 height: calc(var(--avatar-base-height) * var(--big-avatar-height-factor) * var(--inline-avatar-small-factor) + 2 * var(--avatar-base-border-radius));
237}235}
236body.big-avatars .avatars_inline.avatars_inline_small.avatars_multiline {
237 height: inherit;
238}
238239
239body:not(.big-avatars) .avatars_inline_small .avatar_collage {240body:not(.big-avatars) .avatars_inline_small .avatar_collage {
240 min-width: calc(var(--avatar-base-width) * var(--inline-avatar-small-factor));241 min-width: calc(var(--avatar-base-width) * var(--inline-avatar-small-factor));
public/global.d.ts+13 -2
@@ -1,8 +1,12 @@
1import libs from './lib';1import libs from './lib';
2import getContext from './scripts/st-context';2import getContext from './scripts/st-context';
33
4declare global {
4 // Global namespace modules5 // Global namespace modules
5declare var ai;6 interface Window {
7 ai: any;
8 }
9
6 declare var pdfjsLib;10 declare var pdfjsLib;
7 declare var ePub;11 declare var ePub;
812
@@ -12,7 +16,6 @@ declare var SillyTavern: {
12 libs: typeof libs;16 libs: typeof libs;
13 };17 };
1418
15declare global {
16 // Jquery plugins19 // Jquery plugins
17 interface JQuery {20 interface JQuery {
18 nanogallery2(options?: any): JQuery;21 nanogallery2(options?: any): JQuery;
@@ -40,4 +43,12 @@ declare global {
40 searchInputCssClass?: string;43 searchInputCssClass?: string;
41 }44 }
42 }45 }
46
47 /**
48 * Translates a text to a target language using a translation provider.
49 * @param text Text to translate
50 * @param lang Target language
51 * @param provider Translation provider
52 */
53 async function translate(text: string, lang: string, provider: string = null): Promise<string>;
43}54}
public/index.html+190 -76
@@ -1294,8 +1294,8 @@
1294 <span data-i18n="TFS">TFS</span>1294 <span data-i18n="TFS">TFS</span>
1295 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>1295 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>
1296 </small>1296 </small>
1297 <input class="neo-range-slider" type="range" id="tfs_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1297 <input class="neo-range-slider" type="range" id="tfs_textgenerationwebui" name="volume" min="0" max="1" step="0.001">
1298 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="tfs_textgenerationwebui" id="tfs_counter_textgenerationwebui">1298 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="tfs_textgenerationwebui" id="tfs_counter_textgenerationwebui">
1299 </div>1299 </div>
1300 <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1300 <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1301 <small>1301 <small>
@@ -1305,7 +1305,7 @@
1305 <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01">1305 <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01">
1306 <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui">1306 <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui">
1307 </div>1307 </div>
1308 <div data-tg-type="aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1308 <div data-tg-type="aphrodite,koboldcpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1309 <small>1309 <small>
1310 <span data-i18n="Top nsigma">Top nsigma</span>1310 <span data-i18n="Top nsigma">Top nsigma</span>
1311 <div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div>1311 <div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div>
@@ -1477,8 +1477,8 @@
1477 </div>1477 </div>
1478 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1478 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1479 <small data-i18n="Exponent">Exponent</small>1479 <small data-i18n="Exponent">Exponent</small>
1480 <input class="neo-range-slider" type="range" id="dynatemp_exponent_textgenerationwebui" name="volume" min="0.01" max="10" step="0.01" />1480 <input class="neo-range-slider" type="range" id="dynatemp_exponent_textgenerationwebui" name="volume" min="0.001" max="10" step="0.001" />
1481 <input class="neo-range-input" type="number" min="0.01" max="10" step="0.01" data-for="dynatemp_exponent_textgenerationwebui" id="dynatemp_exponent_counter_textgenerationwebui">1481 <input class="neo-range-input" type="number" min="0.001" max="10" step="0.001" data-for="dynatemp_exponent_textgenerationwebui" id="dynatemp_exponent_counter_textgenerationwebui">
1482 </div>1482 </div>
1483 </div>1483 </div>
1484 </div>1484 </div>
@@ -1951,7 +1951,18 @@
1951 </span>1951 </span>
1952 </div>1952 </div>
1953 </div>1953 </div>
1954 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek">1954 <div class="range-block" data-source="makersuite,openrouter">
1955 <label for="openai_enable_web_search" class="checkbox_label flexWrap widthFreeExpand">
1956 <input id="openai_enable_web_search" type="checkbox" />
1957 <span data-i18n="Enable web search">Enable web search</span>
1958 </label>
1959 <div class="flexBasis100p toggle-description justifyLeft">
1960 <span>
1961 Use search capabilities provided by the backend.
1962 </span>
1963 </div>
1964 </div>
1965 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21">
1955 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">1966 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
1956 <input id="openai_function_calling" type="checkbox" />1967 <input id="openai_function_calling" type="checkbox" />
1957 <span data-i18n="Enable function calling">Enable function calling</span>1968 <span data-i18n="Enable function calling">Enable function calling</span>
@@ -1987,6 +1998,23 @@
1987 </div>1998 </div>
1988 </div>1999 </div>
1989 <div class="range-block" data-source="makersuite">2000 <div class="range-block" data-source="makersuite">
2001 <label for="openai_request_images" class="checkbox_label widthFreeExpand">
2002 <input id="openai_request_images" type="checkbox" />
2003 <span>
2004 <span data-i18n="Request inline images">Request inline images</span>
2005 <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Flash Experimental"></i>
2006 </span>
2007 </label>
2008 <div class="toggle-description justifyLeft marginBot5">
2009 <span data-i18n="Allows the model to return image attachments.">
2010 Allows the model to return image attachments.
2011 </span>
2012 <em data-source="makersuite" data-i18n="Request inline images_desc_2">
2013 Incompatible with the following features: function calling, web search, system prompt.
2014 </em>
2015 </div>
2016 </div>
2017 <div class="range-block" data-source="makersuite">
1990 <label for="use_makersuite_sysprompt" class="checkbox_label widthFreeExpand">2018 <label for="use_makersuite_sysprompt" class="checkbox_label widthFreeExpand">
1991 <input id="use_makersuite_sysprompt" type="checkbox" />2019 <input id="use_makersuite_sysprompt" type="checkbox" />
1992 <span>2020 <span>
@@ -2000,7 +2028,7 @@
2000 </span>2028 </span>
2001 </div>2029 </div>
2002 </div>2030 </div>
2003 <div class="range-block" data-source="deepseek,openrouter">2031 <div class="range-block" data-source="deepseek,openrouter,custom,claude">
2004 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">2032 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
2005 <input id="openai_show_thoughts" type="checkbox" />2033 <input id="openai_show_thoughts" type="checkbox" />
2006 <span>2034 <span>
@@ -2014,10 +2042,11 @@
2014 </span>2042 </span>
2015 </div>2043 </div>
2016 </div>2044 </div>
2017 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom">2045 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude">
2018 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;Currently supported values are low, medium, and high.&#10;Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.">2046 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;Currently supported values are low, medium, and high.&#10;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.">
2019 <label for="openai_reasoning_effort" data-i18n="Reasoning Effort">2047 <label for="openai_reasoning_effort">
2020 Reasoning Effort2048 <span data-i18n="Reasoning Effort">Reasoning Effort</span>
2049 <i data-source="claude" class="opacity50p fa-solid fa-circle-info" title="Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%), but minimum 1024 tokens."></i>
2021 </label>2050 </label>
2022 <select id="openai_reasoning_effort">2051 <select id="openai_reasoning_effort">
2023 <option data-i18n="openai_reasoning_effort_low" value="low">Low</option>2052 <option data-i18n="openai_reasoning_effort_low" value="low">Low</option>
@@ -2866,6 +2895,10 @@
2866 <option value="o3-mini">o3-mini</option>2895 <option value="o3-mini">o3-mini</option>
2867 <option value="o3-mini-2025-01-31">o3-mini-2025-01-31</option>2896 <option value="o3-mini-2025-01-31">o3-mini-2025-01-31</option>
2868 </optgroup>2897 </optgroup>
2898 <optgroup label="GPT-4.5">
2899 <option value="gpt-4.5-preview">gpt-4.5-preview</option>
2900 <option value="gpt-4.5-preview-2025-02-27">gpt-4.5-preview-2025-02-27</option>
2901 </optgroup>
2869 <optgroup label="GPT-4 Turbo and GPT-4">2902 <optgroup label="GPT-4 Turbo and GPT-4">
2870 <option value="gpt-4-turbo">gpt-4-turbo</option>2903 <option value="gpt-4-turbo">gpt-4-turbo</option>
2871 <option value="gpt-4-turbo-2024-04-09">gpt-4-turbo-2024-04-09</option>2904 <option value="gpt-4-turbo-2024-04-09">gpt-4-turbo-2024-04-09</option>
@@ -2915,6 +2948,8 @@
2915 <h4 data-i18n="Claude Model">Claude Model</h4>2948 <h4 data-i18n="Claude Model">Claude Model</h4>
2916 <select id="model_claude_select">2949 <select id="model_claude_select">
2917 <optgroup label="Versions">2950 <optgroup label="Versions">
2951 <option value="claude-3-7-sonnet-latest">claude-3-7-sonnet-latest</option>
2952 <option value="claude-3-7-sonnet-20250219">claude-3-7-sonnet-20250219</option>
2918 <option value="claude-3-5-sonnet-latest">claude-3-5-sonnet-latest</option>2953 <option value="claude-3-5-sonnet-latest">claude-3-5-sonnet-latest</option>
2919 <option value="claude-3-5-sonnet-20241022">claude-3-5-sonnet-20241022</option>2954 <option value="claude-3-5-sonnet-20241022">claude-3-5-sonnet-20241022</option>
2920 <option value="claude-3-5-sonnet-20240620">claude-3-5-sonnet-20240620</option>2955 <option value="claude-3-5-sonnet-20240620">claude-3-5-sonnet-20240620</option>
@@ -3060,7 +3095,15 @@
3060 <div>3095 <div>
3061 <h4 data-i18n="AI21 Model">AI21 Model</h4>3096 <h4 data-i18n="AI21 Model">AI21 Model</h4>
3062 <select id="model_ai21_select">3097 <select id="model_ai21_select">
3063 <optgroup label="Jamba 1.5">3098 <optgroup label="Jamba (Latest)">
3099 <option value="jamba-mini">jamba-mini</option>
3100 <option value="jamba-large">jamba-large</option>
3101 </optgroup>
3102 <optgroup label="Jamba 1.6">
3103 <option value="jamba-1.6-mini">jamba-1.6-mini</option>
3104 <option value="jamba-1.6-large">jamba-1.6-large</option>
3105 </optgroup>
3106 <optgroup label="Jamba 1.5 (Deprecated)">
3064 <option value="jamba-1.5-mini">jamba-1.5-mini</option>3107 <option value="jamba-1.5-mini">jamba-1.5-mini</option>
3065 <option value="jamba-1.5-large">jamba-1.5-large</option>3108 <option value="jamba-1.5-large">jamba-1.5-large</option>
3066 </optgroup>3109 </optgroup>
@@ -3091,6 +3134,9 @@
3091 <option value="gemini-ultra">Gemini Ultra (1.0)</option>3134 <option value="gemini-ultra">Gemini Ultra (1.0)</option>
3092 <option value="gemini-1.0-ultra-latest">Gemini 1.0 Ultra</option>3135 <option value="gemini-1.0-ultra-latest">Gemini 1.0 Ultra</option>
3093 </optgroup>3136 </optgroup>
3137 <optgroup label="Gemma">
3138 <option value="gemma-3-27b-it">Gemma 3 27B</option>
3139 </optgroup>
3094 <optgroup label="Subversions">3140 <optgroup label="Subversions">
3095 <option value="gemini-2.0-pro-exp">Gemini 2.0 Pro Experimental</option>3141 <option value="gemini-2.0-pro-exp">Gemini 2.0 Pro Experimental</option>
3096 <option value="gemini-2.0-pro-exp-02-05">Gemini 2.0 Pro Experimental 2025-02-05</option>3142 <option value="gemini-2.0-pro-exp-02-05">Gemini 2.0 Pro Experimental 2025-02-05</option>
@@ -3101,6 +3147,7 @@
3101 <option value="gemini-2.0-flash-thinking-exp-01-21">Gemini 2.0 Flash Thinking Experimental 2025-01-21</option>3147 <option value="gemini-2.0-flash-thinking-exp-01-21">Gemini 2.0 Flash Thinking Experimental 2025-01-21</option>
3102 <option value="gemini-2.0-flash-thinking-exp-1219">Gemini 2.0 Flash Thinking Experimental 2024-12-19</option>3148 <option value="gemini-2.0-flash-thinking-exp-1219">Gemini 2.0 Flash Thinking Experimental 2024-12-19</option>
3103 <option value="gemini-2.0-flash-exp">Gemini 2.0 Flash Experimental</option>3149 <option value="gemini-2.0-flash-exp">Gemini 2.0 Flash Experimental</option>
3150 <option value="gemini-2.0-flash-exp-image-generation">Gemini 2.0 Flash (Image Generation) Experimental</option>
3104 <option value="gemini-exp-1114">Gemini Experimental 2024-11-14</option>3151 <option value="gemini-exp-1114">Gemini Experimental 2024-11-14</option>
3105 <option value="gemini-exp-1121">Gemini Experimental 2024-11-21</option>3152 <option value="gemini-exp-1121">Gemini Experimental 2024-11-21</option>
3106 <option value="gemini-exp-1206">Gemini Experimental 2024-12-06</option>3153 <option value="gemini-exp-1206">Gemini Experimental 2024-12-06</option>
@@ -3186,21 +3233,33 @@
3186 </div>3233 </div>
3187 <h4 data-i18n="Groq Model">Groq Model</h4>3234 <h4 data-i18n="Groq Model">Groq Model</h4>
3188 <select id="model_groq_select">3235 <select id="model_groq_select">
3189 <optgroup label="Production Models">3236 <optgroup label="Alibaba Cloud">
3190 <option value="gemma2-9b-it">gemma2-9b-it</option>3237 <option value="qwen-2.5-32b">qwen-2.5-32b</option>
3191 <option value="llama-3.3-70b-versatile">llama-3.3-70b-versatile</option>3238 <option value="qwen-2.5-coder-32b">qwen-2.5-coder-32b</option>
3192 <option value="llama-3.1-8b-instant">llama-3.1-8b-instant</option>3239 </optgroup>
3193 <option value="llama3-70b-8192">llama3-70b-8192</option>3240 <optgroup label="DeepSeek / Alibaba Cloud">
3194 <option value="llama3-8b-8192">llama3-8b-8192</option>3241 <option value="deepseek-r1-distill-qwen-32b">deepseek-r1-distill-qwen-32b</option>
3195 <option value="mixtral-8x7b-32768">mixtral-8x7b-32768</option>
3196 </optgroup>3242 </optgroup>
3197 <optgroup label="Preview Models">3243 <optgroup label="DeepSeek / Meta">
3198 <option value="deepseek-r1-distill-llama-70b">deepseek-r1-distill-llama-70b</option>3244 <option value="deepseek-r1-distill-llama-70b">deepseek-r1-distill-llama-70b</option>
3199 <option value="llama-3.3-70b-specdec">llama-3.3-70b-specdec</option>3245 </optgroup>
3246 <optgroup label="Google">
3247 <option value="gemma2-9b-it">gemma2-9b-it</option>
3248 </optgroup>
3249 <optgroup label="Meta">
3250 <option value="llama-3.1-8b-instant">llama-3.1-8b-instant </option>
3251 <option value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview </option>
3200 <option value="llama-3.2-1b-preview">llama-3.2-1b-preview </option>3252 <option value="llama-3.2-1b-preview">llama-3.2-1b-preview </option>
3201 <option value="llama-3.2-3b-preview">llama-3.2-3b-preview </option>3253 <option value="llama-3.2-3b-preview">llama-3.2-3b-preview </option>
3202 <option value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview</option>
3203 <option value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview </option>3254 <option value="llama-3.2-90b-vision-preview">llama-3.2-90b-vision-preview </option>
3255 <option value="llama-3.3-70b-specdec">llama-3.3-70b-specdec </option>
3256 <option value="llama-3.3-70b-versatile">llama-3.3-70b-versatile </option>
3257 <option value="llama-guard-3-8b">llama-guard-3-8b </option>
3258 <option value="llama3-70b-8192">llama3-70b-8192 </option>
3259 <option value="llama3-8b-8192">llama3-8b-8192 </option>
3260 </optgroup>
3261 <optgroup label="Mistral AI">
3262 <option value="mixtral-8x7b-32768">mixtral-8x7b-32768</option>
3204 </optgroup>3263 </optgroup>
3205 </select>3264 </select>
3206 </div>3265 </div>
@@ -3253,6 +3312,10 @@
3253 <option value="sonar">sonar</option>3312 <option value="sonar">sonar</option>
3254 <option value="sonar-pro">sonar-pro</option>3313 <option value="sonar-pro">sonar-pro</option>
3255 <option value="sonar-reasoning">sonar-reasoning</option>3314 <option value="sonar-reasoning">sonar-reasoning</option>
3315 <option value="sonar-reasoning-pro">sonar-reasoning-pro</option>
3316 </optgroup>
3317 <optgroup label="Offline Models">
3318 <option value="r1-1776">r1-1776</option>
3256 </optgroup>3319 </optgroup>
3257 <optgroup label="Deprecated Models">3320 <optgroup label="Deprecated Models">
3258 <!-- These are scheduled for deprecation after 2/22/2025 -->3321 <!-- These are scheduled for deprecation after 2/22/2025 -->
@@ -3282,6 +3345,8 @@
3282 <option value="c4ai-aya-23">c4ai-aya-23</option>3345 <option value="c4ai-aya-23">c4ai-aya-23</option>
3283 <option value="c4ai-aya-expanse-8b">c4ai-aya-expanse-8b</option>3346 <option value="c4ai-aya-expanse-8b">c4ai-aya-expanse-8b</option>
3284 <option value="c4ai-aya-expanse-32b">c4ai-aya-expanse-32b</option>3347 <option value="c4ai-aya-expanse-32b">c4ai-aya-expanse-32b</option>
3348 <option value="c4ai-aya-vision-8b">c4ai-aya-vision-8b</option>
3349 <option value="c4ai-aya-vision-32b">c4ai-aya-vision-32b</option>
3285 <option value="command-light">command-light</option>3350 <option value="command-light">command-light</option>
3286 <option value="command">command</option>3351 <option value="command">command</option>
3287 <option value="command-r">command-r</option>3352 <option value="command-r">command-r</option>
@@ -3289,6 +3354,7 @@
3289 <option value="command-r-08-2024">command-r-08-2024</option>3354 <option value="command-r-08-2024">command-r-08-2024</option>
3290 <option value="command-r-plus-08-2024">command-r-plus-08-2024</option>3355 <option value="command-r-plus-08-2024">command-r-plus-08-2024</option>
3291 <option value="command-r7b-12-2024">command-r7b-12-2024</option>3356 <option value="command-r7b-12-2024">command-r7b-12-2024</option>
3357 <option value="command-a-03-2025">command-a-03-2025</option>
3292 </optgroup>3358 </optgroup>
3293 <optgroup label="Nightly">3359 <optgroup label="Nightly">
3294 <option value="command-light-nightly">command-light-nightly</option>3360 <option value="command-light-nightly">command-light-nightly</option>
@@ -3318,7 +3384,7 @@
3318 </div>3384 </div>
3319 <div>3385 <div>
3320 <small>3386 <small>
3321 <span data-i18n="Doesn't work? Try adding">Doesn't work? Try adding</span> <code>/v1</code> <span data-i18n="at the end of the URL!">at the end of the URL!</span>3387 <span data-i18n="Doesn't work? Try adding">Doesn't work? Try adding</span> <code>/v1</code> <span data-i18n="at the end!">at the end!</span>
3322 </small>3388 </small>
3323 </div>3389 </div>
3324 <h4>3390 <h4>
@@ -3790,6 +3856,7 @@
3790 <option value="14">Jamba</option>3856 <option value="14">Jamba</option>
3791 <option value="15">Qwen2</option>3857 <option value="15">Qwen2</option>
3792 <option value="16">Command-R</option>3858 <option value="16">Command-R</option>
3859 <option value="19">Command-A</option>
3793 <option value="4">NerdStash (NovelAI Clio)</option>3860 <option value="4">NerdStash (NovelAI Clio)</option>
3794 <option value="5">NerdStash v2 (NovelAI Kayra)</option>3861 <option value="5">NerdStash v2 (NovelAI Kayra)</option>
3795 <option value="7">Mistral V1</option>3862 <option value="7">Mistral V1</option>
@@ -4001,7 +4068,7 @@
4001 <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" title="Cap the number of entry activation recursions" data-i18n="[title]Cap the number of entry activation recursions">4068 <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" title="Cap the number of entry activation recursions" data-i18n="[title]Cap the number of entry activation recursions">
4002 <small>4069 <small>
4003 <span data-i18n="Max Recursion Steps">Max Recursion Steps</span>4070 <span data-i18n="Max Recursion Steps">Max Recursion Steps</span>
4004 <div class="fa-solid fa-triangle-exclamation opacity50p" data-i18n="[title]0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\n(disabled when min activations are used)" title="0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc&#10;(disabled when min activations are used)"></div>4071 <div class="fa-solid fa-triangle-exclamation opacity50p" data-i18n="[title]0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc" title="0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc&#10;(disabled when min activations are used)"></div>
4005 </small>4072 </small>
4006 <input class="neo-range-slider" type="range" id="world_info_max_recursion_steps" name="world_info_max_recursion_steps" min="0" max="10" step="1">4073 <input class="neo-range-slider" type="range" id="world_info_max_recursion_steps" name="world_info_max_recursion_steps" min="0" max="10" step="1">
4007 <input class="neo-range-input" type="number" min="0" max="10" step="1" data-for="world_info_max_recursion_steps" id="world_info_max_recursion_steps_counter">4074 <input class="neo-range-input" type="number" min="0" max="10" step="1" data-for="world_info_max_recursion_steps" id="world_info_max_recursion_steps_counter">
@@ -4130,7 +4197,7 @@
4130 </div>4197 </div>
4131 <div id="UI-language-block" class="flex-container alignItemsBaseline">4198 <div id="UI-language-block" class="flex-container alignItemsBaseline">
4132 <span data-i18n="UI Language">Language:</span>4199 <span data-i18n="UI Language">Language:</span>
4133 <select id="ui_language_select" class="flex1 margin0">4200 <select id="ui_language_select" class="flex1 margin0 text_pole">
4134 <option value="" data-i18n="Default">Default</option>4201 <option value="" data-i18n="Default">Default</option>
4135 <option value="en">English</option>4202 <option value="en">English</option>
4136 </select>4203 </select>
@@ -4188,7 +4255,7 @@
4188 <!-- <h4><span data-i18n="UI Colors">Theme Settings</span></h4> -->4255 <!-- <h4><span data-i18n="UI Colors">Theme Settings</span></h4> -->
4189 <div name="AvatarAndChatDisplay" class="flex-container flexFlowColumn">4256 <div name="AvatarAndChatDisplay" class="flex-container flexFlowColumn">
4190 <div class="flex-container alignItemsBaseline">4257 <div class="flex-container alignItemsBaseline">
4191 <span data-i18n="Avatar Style">Avatars:</span>4258 <span data-i18n="Avatar Style:">Avatars:</span>
4192 <select id="avatar_style" class="widthNatural flex1 margin0">4259 <select id="avatar_style" class="widthNatural flex1 margin0">
4193 <option value="0" data-i18n="Circle">Circle</option>4260 <option value="0" data-i18n="Circle">Circle</option>
4194 <option value="2" data-i18n="Square">Square</option>4261 <option value="2" data-i18n="Square">Square</option>
@@ -4398,7 +4465,7 @@
4398 <option data-i18n="Ask" value="1">Ask</option>4465 <option data-i18n="Ask" value="1">Ask</option>
4399 <option data-i18n="tag_import_none" value="2">None</option>4466 <option data-i18n="tag_import_none" value="2">None</option>
4400 <option data-i18n="tag_import_all" value="3">All</option>4467 <option data-i18n="tag_import_all" value="3">All</option>
4401 <option data-i18n="Existing" value="4">Existing</option>4468 <option data-i18n="tag_import_existing" value="4">Existing</option>
4402 </select>4469 </select>
4403 </div>4470 </div>
4404 <label class="checkbox_label" for="fuzzy_search_checkbox" title="Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring." data-i18n="[title]Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring">4471 <label class="checkbox_label" for="fuzzy_search_checkbox" title="Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring." data-i18n="[title]Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring">
@@ -4413,7 +4480,7 @@
4413 <input id="prefer_character_jailbreak" type="checkbox" />4480 <input id="prefer_character_jailbreak" type="checkbox" />
4414 <small data-i18n="Prefer Character Card Instructions">Prefer Char. Instructions</small>4481 <small data-i18n="Prefer Character Card Instructions">Prefer Char. Instructions</small>
4415 </label>4482 </label>
4416 <label class="checkbox_label" for="never_resize_avatars" title="Avoid cropping and resizing imported character images. When off, crop/resize to 512x768." data-i18n="[title]Avoid cropping and resizing imported character images. When off, crop/resize to 512x768">4483 <label class="checkbox_label" for="never_resize_avatars" title="Avoid cropping and resizing imported character images. When off, crop/resize to 512x768.&#10;This will disable the upload cropping popup for avatars." data-i18n="[title]never_resize_avatars_tooltip">
4417 <input id="never_resize_avatars" type="checkbox" />4484 <input id="never_resize_avatars" type="checkbox" />
4418 <small data-i18n="Never resize avatars">Never resize avatars</small>4485 <small data-i18n="Never resize avatars">Never resize avatars</small>
4419 </label>4486 </label>
@@ -4666,7 +4733,7 @@
4666 <small data-i18n="Enabled">Enabled</small>4733 <small data-i18n="Enabled">Enabled</small>
4667 </label>4734 </label>
4668 <small data-i18n="Minimum generated message length">Minimum generated message length</small>4735 <small data-i18n="Minimum generated message length">Minimum generated message length</small>
4669 <input id="auto_swipe_minimum_length" name="auto_swipe_minimum_length" type="number" min="0" step="1" value="0" class="text_pole" title="If the generated message is shorter than this, trigger an auto-swipe." data-i18n="[title]If the generated message is shorter than this, trigger an auto-swipe">4736 <input id="auto_swipe_minimum_length" name="auto_swipe_minimum_length" type="number" min="0" step="1" value="0" class="text_pole" title="If the generated message is shorter than these many characters, trigger an auto-swipe." data-i18n="[title]If the generated message is shorter than these many characters, trigger an auto-swipe">
4670 <small data-i18n="Blacklisted words">Blacklisted words</small>4737 <small data-i18n="Blacklisted words">Blacklisted words</small>
4671 <div class="auto_swipe">4738 <div class="auto_swipe">
4672 <textarea id="auto_swipe_blacklist" name="auto_swipe_blacklist" data-i18n="[placeholder]words you dont want generated separated by comma ','" placeholder="words you don't want generated separated by comma ','" class="text_pole textarea_compact" value="" autocomplete="off" rows="3"></textarea>4739 <textarea id="auto_swipe_blacklist" name="auto_swipe_blacklist" data-i18n="[placeholder]words you dont want generated separated by comma ','" placeholder="words you don't want generated separated by comma ','" class="text_pole textarea_compact" value="" autocomplete="off" rows="3"></textarea>
@@ -4917,7 +4984,10 @@
4917 </div>4984 </div>
4918 <hr class="wide100p margin0">4985 <hr class="wide100p margin0">
4919 <div class="alignitemscenter flex-container justifyCenter wide100p" style="justify-content: space-between;">4986 <div class="alignitemscenter flex-container justifyCenter wide100p" style="justify-content: space-between;">
4920 <h4 class="margin0"><span data-i18n="Extras API:">Extras API:</span></h4>4987 <h4 class="margin0">
4988 <span data-i18n="(DEPRECATED)">(DEPRECATED)</span>
4989 <span data-i18n="Extras API:">Extras API:</span>
4990 </h4>
4921 <div class="flex-container">4991 <div class="flex-container">
4922 <div id="extensions_status" data-i18n="Not connected...">Not connected...</div>4992 <div id="extensions_status" data-i18n="Not connected...">Not connected...</div>
4923 <label for="extensions_autoconnect" class="checkbox_label flexNoGap">4993 <label for="extensions_autoconnect" class="checkbox_label flexNoGap">
@@ -4968,7 +5038,7 @@
4968 </div>5038 </div>
4969 </div>5039 </div>
4970 <div id="persona-management-block" class="flex-container wide100p flexGap10">5040 <div id="persona-management-block" class="flex-container wide100p flexGap10">
4971 <div class="flex1 overflowHidden wide100p">5041 <div class="persona_management_left_column flex1 overflowHidden wide100p">
4972 <div class="flex-container marginBot10 alignitemscenter">5042 <div class="flex-container marginBot10 alignitemscenter">
4973 <div id="create_dummy_persona" class="menu_button menu_button_icon" title="Create a dummy persona" data-i18n="[title]Create a dummy persona">5043 <div id="create_dummy_persona" class="menu_button menu_button_icon" title="Create a dummy persona" data-i18n="[title]Create a dummy persona">
4974 <i class="fa-solid fa-person-circle-question fa-fw"></i>5044 <i class="fa-solid fa-person-circle-question fa-fw"></i>
@@ -4991,27 +5061,34 @@
4991 <input type="hidden" id="avatar_upload_overwrite" name="overwrite_name" value="">5061 <input type="hidden" id="avatar_upload_overwrite" name="overwrite_name" value="">
4992 </form>5062 </form>
4993 </div>5063 </div>
4994 <div class="flex1">5064 <div class="persona_management_right_column flex1">
4995 <h4 data-i18n="Name">Name</h4>5065 <div class="persona_management_current_persona">
4996 <div class="change_name">5066 <h4 class="standoutHeader" data-i18n="Current Persona">Current Persona</h4>
4997 <input id="your_name" name="your_name" data-i18n="[placeholder]Enter your name" placeholder="Enter your name" class="text_pole wide100p" value="" autocomplete="off">5067
4998 <div id="your_name_button" class="menu_button fa-solid fa-check" title="Click to set a new User Name" data-i18n="[title]Click to set a new User Name">5068 <div id="persona_controls" class="flex-container">
4999 </div>5069 <h5 id="your_name" class="persona_name">[Persona Name]</h5>
5000 <div id="lock_user_name" class="menu_button fa-solid fa-unlock" title="Click to lock your selected persona to the current chat. Click again to remove the lock." data-i18n="[title]Click to lock your selected persona to the current chat. Click again to remove the lock.">5070 <div class="persona_controls_buttons_block buttons_block">
5001 </div>5071 <div id="persona_rename_button" class="menu_button fa-solid fa-pencil" title="Rename Persona" data-i18n="[title]Rename Persona"></div>
5002 <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages" data-i18n="[title]Click to set user name for all messages">5072 <div id="sync_name_button" class="menu_button fa-solid fa-sync" title="Click to set user name for all messages" data-i18n="[title]Click to set user name for all messages"></div>
5003 </div>5073 <div id="persona_lore_button" class="menu_button fa-solid fa-globe" title="Persona Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Persona Lore Alt+Click to open the lorebook"></div>
5004 <div id="persona_lore_button" class="menu_button fa-solid fa-globe" title="Persona Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Persona Lore Alt+Click to open the lorebook">5074
5075 <div id="persona_set_image_button" class="menu_button fa-solid fa-image" title="Change Persona Image" data-i18n="[title]Change Persona Image"></div>
5076 <div id="persona_duplicate_button" class="menu_button fa-solid fa-clone" title="Duplicate Persona" data-i18n="[title]Duplicate Persona"></div>
5077 <div id="persona_delete_button" class="menu_button fa-solid fa-skull red_button" title="Delete Persona" data-i18n="[title]Delete Persona"></div>
5005 </div>5078 </div>
5006 </div>5079 </div>
5007 <div>5080
5008 <h4 data-i18n="Persona Description">Persona Description</h4>5081 <h4 data-i18n="Persona Description">Persona Description</h4>
5009 <textarea id="persona_description" name="persona_description" data-i18n="[placeholder]Example: [{{user}} is a 28-year-old Romanian cat girl.]" placeholder="Example:&#10;[{{user}} is a 28-year-old Romanian cat girl.]" class="text_pole textarea_compact" value="" autocomplete="off" rows="8"></textarea>5082 <textarea id="persona_description" name="persona_description" data-i18n="[placeholder]Example: [{{user}} is a 28-year-old Romanian cat girl.]" placeholder="Example:&#10;[{{user}} is a 28-year-old Romanian cat girl.]" class="text_pole textarea_compact" value="" autocomplete="off" rows="8"></textarea>
5010 <div class="extension_token_counter">5083
5084 <div class="flex-container justifySpaceBetween">
5085 <h4 data-i18n="Position">Position</h4>
5086 <div class="extension_token_counter widthFitContent">
5011 <span data-i18n="Tokens persona description">Tokens</span>: <span id="persona_description_token_count">0</span>5087 <span data-i18n="Tokens persona description">Tokens</span>: <span id="persona_description_token_count">0</span>
5012 </div>5088 </div>
5013 <div>5089 </div>
5014 <label for="persona_description_position" data-i18n="Position:">Position:</label>5090
5091 <div class="persona_management_description_position_container">
5015 <select id="persona_description_position">5092 <select id="persona_description_position">
5016 <option value="9" data-i18n="None (disabled)">None (disabled)</option>5093 <option value="9" data-i18n="None (disabled)">None (disabled)</option>
5017 <option value="0" data-i18n="In Story String / Prompt Manager">In Story String / Prompt Manager</option>5094 <option value="0" data-i18n="In Story String / Prompt Manager">In Story String / Prompt Manager</option>
@@ -5034,7 +5111,30 @@
5034 </div>5111 </div>
5035 </div>5112 </div>
5036 </div>5113 </div>
5114
5115 <h4 data-i18n="Connections">Connections</h4>
5116 <div id="persona_connections_buttons" class="flex-container">
5117 <div id="lock_persona_default" class="menu_button menu_button_icon" title="Click to select this as default persona for the new chats. Click again to remove it." data-i18n="[title]Click to select this as default persona for the new chats. Click again to remove it.">
5118 <i class="icon fa-solid fa-crown fa-fw"></i>
5119 <div data-i18n="Default">Default</div>
5120 </div>
5121 <div id="lock_persona_to_char" class="menu_button menu_button_icon" title="Click to lock your selected persona to the current character. Click again to remove the lock." data-i18n="[title]Click to lock your selected persona to the current character. Click again to remove the lock.">
5122 <i class="icon fa-solid fa-unlock fa-fw"></i>
5123 <div data-i18n="Character">Character</div>
5124 </div>
5125 <div id="lock_user_name" class="menu_button menu_button_icon" title="Click to lock your selected persona to the current chat. Click again to remove the lock." data-i18n="[title]Click to lock your selected persona to the current chat. Click again to remove the lock.">
5126 <i class="icon fa-solid fa-unlock fa-fw"></i>
5127 <div data-i18n="Chat">Chat</div>
5128 </div>
5129 </div>
5130 <div id="persona_connections_info_block"></div>
5131 <div id="persona_connections_list" class="text_muted m-b-1 avatars_inline avatars_multiline scroll-reset-container expander">
5132 </div>
5037 </div>5133 </div>
5134
5135 <div class="persona_management_global_settings">
5136 <h4 class="standoutHeader" data-i18n="Global Settings">Global Settings</h4>
5137
5038 <div class="range-block">5138 <div class="range-block">
5039 <label for="persona_show_notifications" class="checkbox_label">5139 <label for="persona_show_notifications" class="checkbox_label">
5040 <input id="persona_show_notifications" type="checkbox" />5140 <input id="persona_show_notifications" type="checkbox" />
@@ -5043,6 +5143,23 @@
5043 </span>5143 </span>
5044 </label>5144 </label>
5045 </div>5145 </div>
5146 <div class="range-block">
5147 <label for="persona_allow_multi_connections" class="checkbox_label" title="When multiple personas are connected to a character, a popup will appear to select which one to use." data-i18n="[title]When multiple personas are connected to a character, a popup will appear to select which one to use">
5148 <input id="persona_allow_multi_connections" type="checkbox" />
5149 <span data-i18n="Allow multiple persona connections per character">
5150 Allow multiple persona connections per character
5151 </span>
5152 </label>
5153 </div>
5154 <div class="range-block">
5155 <label for="persona_auto_lock" class="checkbox_label" title="Whenever a persona is selected, it will be locked to the current chat and automatically selected when the chat is opened." data-i18n="[title]Whenever a persona is selected, it will be locked to the current chat and automatically selected when the chat is opened.">
5156 <input id="persona_auto_lock" type="checkbox" />
5157 <span data-i18n="Auto-lock a chosen persona to the chat">
5158 Auto-lock a chosen persona to the chat
5159 </span>
5160 </label>
5161 </div>
5162 </div>
5046 </div>5163 </div>
5047 </div>5164 </div>
5048 </div>5165 </div>
@@ -5068,7 +5185,7 @@
5068 <div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters" data-i18n="[title]Select/Create Characters"></div>5185 <div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters" data-i18n="[title]Select/Create Characters"></div>
5069 </div>5186 </div>
5070 <div id="HotSwapWrapper" class="alignitemscenter flex-container margin0auto wide100p">5187 <div id="HotSwapWrapper" class="alignitemscenter flex-container margin0auto wide100p">
5071 <div class="hotswap avatars_inline flex-container scroll-reset-container expander" data-i18n="[no_favs]Favorite characters to add them to HotSwaps" no_favs="Favorite characters to add them to HotSwaps"></div>5188 <div class="hotswap avatars_inline scroll-reset-container expander" data-i18n="[no_favs]Favorite characters to add them to HotSwaps" no_favs="Favorite characters to add them to HotSwaps"></div>
5072 </div>5189 </div>
5073 </div>5190 </div>
5074 <hr>5191 <hr>
@@ -5106,13 +5223,13 @@
5106 </div>5223 </div>
5107 </div>5224 </div>
5108 <div class="flex-container flexFlowColumn expander flexNoGap">5225 <div class="flex-container flexFlowColumn expander flexNoGap">
5109 <div id="avatar_div" class="avatar_div alignitemsflexstart justifySpaceBetween flexnowrap">5226 <div id="avatar_div" class="avatar_div buttons_block alignitemsflexstart justifySpaceBetween flexnowrap">
5110 <label id="avatar_div_div" class="add_avatar avatar" for="add_avatar_button" title="Click to select a new avatar for this character" data-i18n="[title]Click to select a new avatar for this character">5227 <label id="avatar_div_div" class="add_avatar avatar" for="add_avatar_button" title="Click to select a new avatar for this character" data-i18n="[title]Click to select a new avatar for this character">
5111 <img id="avatar_load_preview" src="img/ai4.png" alt="avatar">5228 <img id="avatar_load_preview" src="img/ai4.png" alt="avatar">
5112 <input hidden type="file" id="add_avatar_button" name="avatar" accept="image/*">5229 <input hidden type="file" id="add_avatar_button" name="avatar" accept="image/*">
5113 </label>5230 </label>
5114 <div class="flex-container" id="avatar_controls">5231 <div class="flex-container" id="avatar_controls">
5115 <div class="form_create_bottom_buttons_block">5232 <div class="form_create_bottom_buttons_block buttons_block">
5116 <div id="rm_button_back" class="menu_button fa-solid fa-left-long "></div>5233 <div id="rm_button_back" class="menu_button fa-solid fa-left-long "></div>
5117 <!-- <div id="renameCharButton" class="menu_button fa-solid fa-user-pen" title="Rename Character"></div> -->5234 <!-- <div id="renameCharButton" class="menu_button fa-solid fa-user-pen" title="Rename Character"></div> -->
5118 <div id="favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>5235 <div id="favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>
@@ -5120,6 +5237,7 @@
5120 <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div>5237 <div id="advanced_div" class="menu_button fa-solid fa-book " title="Advanced Definitions" data-i18n="[title]Advanced Definition"></div>
5121 <div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore&#10;&#10;Click to load&#10;Shift-click to open 'Link to World Info' popup" data-i18n="[title]world_button_title"></div>5238 <div id="world_button" class="menu_button fa-solid fa-globe" title="Character Lore&#10;&#10;Click to load&#10;Shift-click to open 'Link to World Info' popup" data-i18n="[title]world_button_title"></div>
5122 <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div>5239 <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div>
5240 <div id="char_connections_button" class="menu_button fa-solid fa-face-smile" title="Connected Personas" data-i18n="[title]Connected Personas"></div>
5123 <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>5241 <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>
5124 <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->5242 <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->
5125 <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->5243 <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->
@@ -5127,7 +5245,7 @@
5127 <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character" data-i18n="[title]Create Character">5245 <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character" data-i18n="[title]Create Character">
5128 <input type="submit" id="create_button" name="create_button">5246 <input type="submit" id="create_button" name="create_button">
5129 </label>5247 </label>
5130 <div id="delete_button" class="menu_button fa-solid fa-skull " title="Delete Character" data-i18n="[title]Delete Character"></div>5248 <div id="delete_button" class="menu_button fa-solid fa-skull red_button" title="Delete Character" data-i18n="[title]Delete Character"></div>
5131 </div>5249 </div>
5132 <label class="flex1 height100p" for="char-management-dropdown">5250 <label class="flex1 height100p" for="char-management-dropdown">
5133 <select id="char-management-dropdown" class="text_pole">5251 <select id="char-management-dropdown" class="text_pole">
@@ -5287,6 +5405,7 @@
5287 <option value="2" data-i18n="Manual">Manual</option>5405 <option value="2" data-i18n="Manual">Manual</option>
5288 <option value="0" data-i18n="Natural order">Natural order</option>5406 <option value="0" data-i18n="Natural order">Natural order</option>
5289 <option value="1" data-i18n="List order">List order</option>5407 <option value="1" data-i18n="List order">List order</option>
5408 <option value="3" data-i18n="Pooled order">Pooled order</option>
5290 </select>5409 </select>
5291 </div>5410 </div>
5292 <div class="flex1 flexGap5">5411 <div class="flex1 flexGap5">
@@ -5317,17 +5436,17 @@
5317 </div>5436 </div>
5318 </div>5437 </div>
5319 <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1">5438 <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1">
5320 <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-left-long"></div>5439 <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-left-long"></div>
5321 <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div>5440 <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div>
5322 <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>5441 <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>
5323 <input id="rm_group_fav" type="hidden" />5442 <input id="rm_group_fav" type="hidden" />
5324 <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group.">5443 <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group.">
5325 <i id="group_media_allowed_icon" class="fa-solid fa-fw fa-link"></i>5444 <i id="group_media_allowed_icon" class="fa-solid fa-fw fa-link"></i>
5326 <i id="group_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i>5445 <i id="group_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i>
5327 </div>5446 </div>
5328 <div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-check" title="Create" data-i18n="[title]Create"></div>5447 <div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-check" title="Create" data-i18n="[title]Create"></div>
5329 <div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-images" title="Restore collage avatar" data-i18n="[title]Restore collage avatar"></div>5448 <div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-images" title="Restore collage avatar" data-i18n="[title]Restore collage avatar"></div>
5330 <div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-trash-can" title="Delete" data-i18n="[title]Delete"></div>5449 <div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-trash-can" title="Delete" data-i18n="[title]Delete"></div>
5331 <div class="flex1">5450 <div class="flex1">
5332 <label class="checkbox_label whitespacenowrap">5451 <label class="checkbox_label whitespacenowrap">
5333 <input id="rm_group_allow_self_responses" type="checkbox" />5452 <input id="rm_group_allow_self_responses" type="checkbox" />
@@ -5464,25 +5583,20 @@
5464 <div class="flex-container wide100pLess70px character_select_container">5583 <div class="flex-container wide100pLess70px character_select_container">
5465 <div class="wide100p character_name_block">5584 <div class="wide100p character_name_block">
5466 <span class="ch_name flex1"></span>5585 <span class="ch_name flex1"></span>
5467 <div class="avatar-buttons">
5468 <button class="menu_button bind_user_name" title="Bind user name to that avatar" data-i18n="[title]Bind user name to that avatar">
5469 <i class="fa-fw fa-solid fa-user-edit fa-sm"></i>
5470 </button>
5471 <button class="menu_button set_persona_image" title="Change persona image" data-i18n="[title]Change persona image">
5472 <i class="fa-fw fa-solid fa-image fa-sm"></i>
5473 </button>
5474 <button class="menu_button set_default_persona" title="Select this as default persona for the new chats." data-i18n="[title]Select this as default persona for the new chats.">
5475 <i class="fa-fw fa-solid fa-crown fa-sm"></i>
5476 </button>
5477 <button class="menu_button duplicate_persona" title="Duplicate persona" data-i18n="[title]Duplicate persona">
5478 <i class="fa-fw fa-solid fa-clone fa-sm"></i>
5479 </button>
5480 <button class="menu_button delete_avatar" title="Delete persona" data-i18n="[title]Delete persona">
5481 <i class="fa-fw fa-solid fa-trash-alt fa-sm"></i>
5482 </button>
5483 </div>
5484 </div>5586 </div>
5485 <div class="ch_description"></div>5587 <div class="ch_description"></div>
5588 <div class="avatar_container_states buttons_block">
5589 <div class="locked_to_chat_label avatar_state has_hover_label menu_button menu_button_icon disabled" title="Persona is locked to the current chat" data-i18n="[title]Persona is locked to the current chat">
5590 <i class="icon fa-solid fa-lock fa-fw"></i>
5591 <i class="label_icon icon fa-solid fa-comments fa-fw"></i>
5592 <div class="label" data-i18n="Chat">Chat</div>
5593 </div>
5594 <div class="locked_to_character_label avatar_state has_hover_label menu_button menu_button_icon disabled " title="Persona is locked to the current character" data-i18n="[title]Persona is locked to the current character">
5595 <i class="icon fa-solid fa-lock fa-fw"></i>
5596 <i class="label_icon icon fa-solid fa-user fa-fw"></i>
5597 <div class="label" data-i18n="Character">Character</div>
5598 </div>
5599 </div>
5486 </div>5600 </div>
5487 </div>5601 </div>
5488 </div>5602 </div>
@@ -6308,7 +6422,7 @@
6308 </div>6422 </div>
6309 </div>6423 </div>
6310 <div class="mes_reasoning_actions flex-container">6424 <div class="mes_reasoning_actions flex-container">
6311 <div class="mes_reasoning_edit_done menu_button edit_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirmedit"></div>6425 <div class="mes_reasoning_edit_done menu_button edit_button fa-solid fa-check" title="Confirm" data-i18n="[title]Confirm Edit"></div>
6312 <div class="mes_reasoning_delete menu_button edit_button fa-solid fa-trash-can" title="Remove reasoning" data-i18n="[title]Remove reasoning"></div>6426 <div class="mes_reasoning_delete menu_button edit_button fa-solid fa-trash-can" title="Remove reasoning" data-i18n="[title]Remove reasoning"></div>
6313 <div class="mes_reasoning_edit_cancel menu_button edit_button fa-solid fa-xmark" title="Cancel edit" data-i18n="[title]Cancel edit"></div>6427 <div class="mes_reasoning_edit_cancel menu_button edit_button fa-solid fa-xmark" title="Cancel edit" data-i18n="[title]Cancel edit"></div>
6314 <div class="mes_reasoning_copy mes_button fa-solid fa-copy" title="Copy reasoning" data-i18n="[title]Copy reasoning"></div>6428 <div class="mes_reasoning_copy mes_button fa-solid fa-copy" title="Copy reasoning" data-i18n="[title]Copy reasoning"></div>
@@ -6890,8 +7004,8 @@
6890 </div>7004 </div>
6891 <div id="form_sheld">7005 <div id="form_sheld">
6892 <div id="dialogue_del_mes">7006 <div id="dialogue_del_mes">
6893 <div id="dialogue_del_mes_ok" class="menu_button">Delete</div>7007 <div id="dialogue_del_mes_ok" data-i18n="Delete" class="menu_button">Delete</div>
6894 <div id="dialogue_del_mes_cancel" class="menu_button">Cancel</div>7008 <div id="dialogue_del_mes_cancel" data-i18n="Cancel" class="menu_button">Cancel</div>
6895 </div>7009 </div>
6896 <div id="send_form" class="no-connection">7010 <div id="send_form" class="no-connection">
6897 <form id="file_form" class="wide100p displayNone">7011 <form id="file_form" class="wide100p displayNone">
public/jsconfig.json+2 -1
@@ -14,7 +14,8 @@
14 "**/.git/**",14 "**/.git/**",
15 "lib/**",15 "lib/**",
16 "**/*.min.js",16 "**/*.min.js",
17 "scripts/extensions/quick-reply/lib/**"17 "scripts/extensions/quick-reply/lib/**",
18 "scripts/extensions/tts/lib/**"
18 ],19 ],
19 "typeAcquisition": {20 "typeAcquisition": {
20 "include": []21 "include": []
public/lib.js+3 -0
@@ -20,6 +20,7 @@ import * as Popper from '@popperjs/core';
20import droll from 'droll';20import droll from 'droll';
21import morphdom from 'morphdom';21import morphdom from 'morphdom';
22import { toggle as slideToggle } from 'slidetoggle';22import { toggle as slideToggle } from 'slidetoggle';
23import chalk from 'chalk';
2324
24/**25/**
25 * Expose the libraries to the 'window' object.26 * Expose the libraries to the 'window' object.
@@ -96,6 +97,7 @@ export default {
96 droll,97 droll,
97 morphdom,98 morphdom,
98 slideToggle,99 slideToggle,
100 chalk,
99};101};
100102
101export {103export {
@@ -118,4 +120,5 @@ export {
118 droll,120 droll,
119 morphdom,121 morphdom,
120 slideToggle,122 slideToggle,
123 chalk,
121};124};
public/lib/eventemitter.js+42 -1
@@ -24,10 +24,22 @@ if (typeof Array.prototype.indexOf === 'function') {
2424
2525
26/* Polyfill EventEmitter. */26/* Polyfill EventEmitter. */
27var EventEmitter = function () {27/**
28 * Creates an event emitter.
29 * @param {string[]} autoFireAfterEmit Auto-fire event names
30 */
31var EventEmitter = function (autoFireAfterEmit = []) {
28 this.events = {};32 this.events = {};
33 this.autoFireLastArgs = new Map();
34 this.autoFireAfterEmit = new Set(autoFireAfterEmit);
29};35};
3036
37/**
38 * Adds a listener to an event.
39 * @param {string} event Event name
40 * @param {function} listener Event listener
41 * @returns
42 */
31EventEmitter.prototype.on = function (event, listener) {43EventEmitter.prototype.on = function (event, listener) {
32 // Unknown event used by external libraries?44 // Unknown event used by external libraries?
33 if (event === undefined) {45 if (event === undefined) {
@@ -40,6 +52,10 @@ EventEmitter.prototype.on = function (event, listener) {
40 }52 }
4153
42 this.events[event].push(listener);54 this.events[event].push(listener);
55
56 if (this.autoFireAfterEmit.has(event) && this.autoFireLastArgs.has(event)) {
57 listener.apply(this, this.autoFireLastArgs.get(event));
58 }
43};59};
4460
45/**61/**
@@ -60,6 +76,10 @@ EventEmitter.prototype.makeLast = function (event, listener) {
60 }76 }
6177
62 events.push(listener);78 events.push(listener);
79
80 if (this.autoFireAfterEmit.has(event) && this.autoFireLastArgs.has(event)) {
81 listener.apply(this, this.autoFireLastArgs.get(event));
82 }
63}83}
6484
65/**85/**
@@ -80,8 +100,17 @@ EventEmitter.prototype.makeFirst = function (event, listener) {
80 }100 }
81101
82 events.unshift(listener);102 events.unshift(listener);
103
104 if (this.autoFireAfterEmit.has(event) && this.autoFireLastArgs.has(event)) {
105 listener.apply(this, this.autoFireLastArgs.get(event));
106 }
83}107}
84108
109/**
110 * Removes a listener from an event.
111 * @param {string} event Event name
112 * @param {function} listener Event listener
113 */
85EventEmitter.prototype.removeListener = function (event, listener) {114EventEmitter.prototype.removeListener = function (event, listener) {
86 var idx;115 var idx;
87116
@@ -94,6 +123,10 @@ EventEmitter.prototype.removeListener = function (event, listener) {
94 }123 }
95};124};
96125
126/**
127 * Emits an event with optional arguments.
128 * @param {string} event Event name
129 */
97EventEmitter.prototype.emit = async function (event) {130EventEmitter.prototype.emit = async function (event) {
98 let args = [].slice.call(arguments, 1);131 let args = [].slice.call(arguments, 1);
99 if (localStorage.getItem('eventTracing') === 'true') {132 if (localStorage.getItem('eventTracing') === 'true') {
@@ -118,6 +151,10 @@ EventEmitter.prototype.emit = async function (event) {
118 }151 }
119 }152 }
120 }153 }
154
155 if (this.autoFireAfterEmit.has(event)) {
156 this.autoFireLastArgs.set(event, args);
157 }
121};158};
122159
123EventEmitter.prototype.emitAndWait = function (event) {160EventEmitter.prototype.emitAndWait = function (event) {
@@ -144,6 +181,10 @@ EventEmitter.prototype.emitAndWait = function (event) {
144 }181 }
145 }182 }
146 }183 }
184
185 if (this.autoFireAfterEmit.has(event)) {
186 this.autoFireLastArgs.set(event, args);
187 }
147};188};
148189
149EventEmitter.prototype.once = function (event, listener) {190EventEmitter.prototype.once = function (event, listener) {
public/locales/ar-sa.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "حذف موضوع",558 "Delete a theme": "حذف موضوع",
559 "Update a theme file": "تحديث ملف السمة",559 "Update a theme file": "تحديث ملف السمة",
560 "Save as a new theme": "حفظ كسمة جديدة",560 "Save as a new theme": "حفظ كسمة جديدة",
561 "Avatar Style": "نمط الصورة الرمزية",561 "Avatar Style:": "نمط الصورة الرمزية",
562 "Circle": "دائرة",562 "Circle": "دائرة",
563 "Square": "مربع",563 "Square": "مربع",
564 "Rectangle": "مستطيل",564 "Rectangle": "مستطيل",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "تفضيل التعليمات من بطاقة الشخصية",633 "Prefer Character Card Prompt": "تفضيل التعليمات من بطاقة الشخصية",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "إذا تم التحقق وكانت بطاقة الشخصية تحتوي على تجاوز للكسر (تعليمات تاريخ المشاركة)، استخدم ذلك بدلاً من ذلك",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "إذا تم التحقق وكانت بطاقة الشخصية تحتوي على تجاوز للكسر (تعليمات تاريخ المشاركة)، استخدم ذلك بدلاً من ذلك",
635 "Prefer Character Card Jailbreak": "تفضيل كسر الحصار من بطاقة الشخصية",635 "Prefer Character Card Jailbreak": "تفضيل كسر الحصار من بطاقة الشخصية",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "تجنب اقتصاص صور الأحرف المستوردة وتغيير حجمها. عند إيقاف التشغيل، قم بالقص/تغيير الحجم إلى 512 × 768.",636 "never_resize_avatars_tooltip": "تجنب اقتصاص صور الأحرف المستوردة وتغيير حجمها. عند إيقاف التشغيل، قم بالقص/تغيير الحجم إلى 512 × 768.",
637 "Never resize avatars": "لا تغيير حجم الصور الرمزية أبدًا",637 "Never resize avatars": "لا تغيير حجم الصور الرمزية أبدًا",
638 "Show actual file names on the disk, in the characters list display only": "عرض الأسماء الفعلية للملفات على القرص، في عرض قائمة الشخصيات فقط",638 "Show actual file names on the disk, in the characters list display only": "عرض الأسماء الفعلية للملفات على القرص، في عرض قائمة الشخصيات فقط",
639 "Show avatar filenames": "عرض أسماء ملفات الصور الرمزية",639 "Show avatar filenames": "عرض أسماء ملفات الصور الرمزية",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "السحب التلقائي",709 "Auto-swipe": "السحب التلقائي",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "تمكين وظيفة السحب التلقائي. الإعدادات في هذا القسم تؤثر فقط عند تمكين السحب التلقائي",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "تمكين وظيفة السحب التلقائي. الإعدادات في هذا القسم تؤثر فقط عند تمكين السحب التلقائي",
711 "Minimum generated message length": "الحد الأدنى لطول الرسالة المولدة",711 "Minimum generated message length": "الحد الأدنى لطول الرسالة المولدة",
712 "If the generated message is shorter than this, trigger an auto-swipe": "إذا كانت الرسالة المولدة أقصر من هذا، فتحريض السحب التلقائي",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "إذا كانت الرسالة المولدة أقصر من هذا، فتحريض السحب التلقائي",
713 "Blacklisted words": "الكلمات الممنوعة",713 "Blacklisted words": "الكلمات الممنوعة",
714 "words you dont want generated separated by comma ','": "الكلمات التي لا تريد توليدها مفصولة بفاصلة ','",714 "words you dont want generated separated by comma ','": "الكلمات التي لا تريد توليدها مفصولة بفاصلة ','",
715 "Blacklisted word count to swipe": "عدد الكلمات الممنوعة للسحب",715 "Blacklisted word count to swipe": "عدد الكلمات الممنوعة للسحب",
public/locales/de-de.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Löschen eines Designs",558 "Delete a theme": "Löschen eines Designs",
559 "Update a theme file": "Ein Theme-Datei aktualisieren",559 "Update a theme file": "Ein Theme-Datei aktualisieren",
560 "Save as a new theme": "Als neues Theme speichern",560 "Save as a new theme": "Als neues Theme speichern",
561 "Avatar Style": "Avatar-Stil",561 "Avatar Style:": "Avatar-Stil",
562 "Circle": "Kreis",562 "Circle": "Kreis",
563 "Square": "Quadrat",563 "Square": "Quadrat",
564 "Rectangle": "Rechteck",564 "Rectangle": "Rechteck",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Bevorzuge Charakterkarten-Prompt",633 "Prefer Character Card Prompt": "Bevorzuge Charakterkarten-Prompt",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Wenn aktiviert und die Charakterkarte eine Jailbreak-Überschreibung enthält (Post-History-Instruction), verwende stattdessen diese",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Wenn aktiviert und die Charakterkarte eine Jailbreak-Überschreibung enthält (Post-History-Instruction), verwende stattdessen diese",
635 "Prefer Character Card Jailbreak": "Bevorzuge Charakterkarten-Jailbreak",635 "Prefer Character Card Jailbreak": "Bevorzuge Charakterkarten-Jailbreak",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Vermeiden Sie das Zuschneiden und Ändern der Größe importierter Zeichenbilder. Wenn deaktiviert, wird die Größe auf 512 x 768 zugeschnitten/angepasst.",636 "never_resize_avatars_tooltip": "Vermeiden Sie das Zuschneiden und Ändern der Größe importierter Zeichenbilder. Wenn deaktiviert, wird die Größe auf 512 x 768 zugeschnitten/angepasst.",
637 "Never resize avatars": "Avatare niemals verkleinern",637 "Never resize avatars": "Avatare niemals verkleinern",
638 "Show actual file names on the disk, in the characters list display only": "Zeige tatsächliche Dateinamen auf der Festplatte, nur in der Anzeige der Charakterliste",638 "Show actual file names on the disk, in the characters list display only": "Zeige tatsächliche Dateinamen auf der Festplatte, nur in der Anzeige der Charakterliste",
639 "Show avatar filenames": "Avatar-Dateinamen anzeigen",639 "Show avatar filenames": "Avatar-Dateinamen anzeigen",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Automatisches Wischen",709 "Auto-swipe": "Automatisches Wischen",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Aktiviere die Auto-Wisch-Funktion. Einstellungen in diesem Abschnitt haben nur dann Auswirkungen, wenn das automatische Wischen aktiviert ist",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Aktiviere die Auto-Wisch-Funktion. Einstellungen in diesem Abschnitt haben nur dann Auswirkungen, wenn das automatische Wischen aktiviert ist",
711 "Minimum generated message length": "Minimale generierte Nachrichtenlänge",711 "Minimum generated message length": "Minimale generierte Nachrichtenlänge",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Wenn die generierte Nachricht kürzer ist als diese, löse automatisches Wischen aus",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Wenn die generierte Nachricht kürzer ist als diese, löse automatisches Wischen aus",
713 "Blacklisted words": "Verbotene Wörter",713 "Blacklisted words": "Verbotene Wörter",
714 "words you dont want generated separated by comma ','": "Wörter, die du nicht generiert haben möchtest, durch Komma ',' getrennt",714 "words you dont want generated separated by comma ','": "Wörter, die du nicht generiert haben möchtest, durch Komma ',' getrennt",
715 "Blacklisted word count to swipe": "Anzahl der verbotenen Wörter, um zu wischen",715 "Blacklisted word count to swipe": "Anzahl der verbotenen Wörter, um zu wischen",
public/locales/es-es.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Eliminar un tema",558 "Delete a theme": "Eliminar un tema",
559 "Update a theme file": "Actualizar un archivo de tema",559 "Update a theme file": "Actualizar un archivo de tema",
560 "Save as a new theme": "Guardar como nuevo tema",560 "Save as a new theme": "Guardar como nuevo tema",
561 "Avatar Style": "Estilo de Avatar",561 "Avatar Style:": "Estilo de Avatar",
562 "Circle": "Círculo",562 "Circle": "Círculo",
563 "Square": "Cuadrado",563 "Square": "Cuadrado",
564 "Rectangle": "Rectángulo",564 "Rectangle": "Rectángulo",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Preferir Indicaciones en Tarjeta de Personaje",633 "Prefer Character Card Prompt": "Preferir Indicaciones en Tarjeta de Personaje",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Si está marcado y la tarjeta de personaje contiene una anulación de jailbreak (Instrucciones Post Historial), usar eso en su lugar",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Si está marcado y la tarjeta de personaje contiene una anulación de jailbreak (Instrucciones Post Historial), usar eso en su lugar",
635 "Prefer Character Card Jailbreak": "Preferir Jailbreak en Tarjeta de Personaje",635 "Prefer Character Card Jailbreak": "Preferir Jailbreak en Tarjeta de Personaje",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Evite recortar y cambiar el tamaño de las imágenes de personajes importados. Cuando esté desactivado, recorte/cambie el tamaño a 512x768.",636 "never_resize_avatars_tooltip": "Evite recortar y cambiar el tamaño de las imágenes de personajes importados. Cuando esté desactivado, recorte/cambie el tamaño a 512x768.",
637 "Never resize avatars": "Nunca redimensionar avatares",637 "Never resize avatars": "Nunca redimensionar avatares",
638 "Show actual file names on the disk, in the characters list display only": "Mostrar nombres de archivo reales en el disco, solo en la visualización de la lista de personajes",638 "Show actual file names on the disk, in the characters list display only": "Mostrar nombres de archivo reales en el disco, solo en la visualización de la lista de personajes",
639 "Show avatar filenames": "Mostrar nombres de archivo de avatares",639 "Show avatar filenames": "Mostrar nombres de archivo de avatares",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Deslizamiento automático",709 "Auto-swipe": "Deslizamiento automático",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Habilitar la función de deslizamiento automático. La configuración en esta sección solo tiene efecto cuando el deslizamiento automático está habilitado",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Habilitar la función de deslizamiento automático. La configuración en esta sección solo tiene efecto cuando el deslizamiento automático está habilitado",
711 "Minimum generated message length": "Longitud mínima del mensaje generado",711 "Minimum generated message length": "Longitud mínima del mensaje generado",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Si el mensaje generado es más corto que esto, activar un deslizamiento automático",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Si el mensaje generado es más corto que esto, activar un deslizamiento automático",
713 "Blacklisted words": "Palabras prohibidas",713 "Blacklisted words": "Palabras prohibidas",
714 "words you dont want generated separated by comma ','": "palabras que no desea generar separadas por coma ','",714 "words you dont want generated separated by comma ','": "palabras que no desea generar separadas por coma ','",
715 "Blacklisted word count to swipe": "Número de palabras prohibidas para deslizar",715 "Blacklisted word count to swipe": "Número de palabras prohibidas para deslizar",
public/locales/fr-fr.json+5 -7
@@ -508,7 +508,7 @@
508 "Delete a theme": "Supprimer un thème",508 "Delete a theme": "Supprimer un thème",
509 "Update a theme file": "Mettre à jour un fichier de thème",509 "Update a theme file": "Mettre à jour un fichier de thème",
510 "Save as a new theme": "Enregistrer en tant que nouveau thème",510 "Save as a new theme": "Enregistrer en tant que nouveau thème",
511 "Avatar Style": "Style d'avatar",511 "Avatar Style:": "Style d'avatar",
512 "Circle": "Cercle",512 "Circle": "Cercle",
513 "Square": "Carré",513 "Square": "Carré",
514 "Rectangle": "Rectangle",514 "Rectangle": "Rectangle",
@@ -581,7 +581,7 @@
581 "Advanced Character Search": "Recherche de personnage avancée",581 "Advanced Character Search": "Recherche de personnage avancée",
582 "If checked and the character card contains a prompt override (System Prompt), use that instead": "Si cochée et si la carte de personnage contient un prompt de remplacement (prompt système), l'utiliser à la place",582 "If checked and the character card contains a prompt override (System Prompt), use that instead": "Si cochée et si la carte de personnage contient un prompt de remplacement (prompt système), l'utiliser à la place",
583 "Prefer Character Card Prompt": "Préférer le prompt du personnage",583 "Prefer Character Card Prompt": "Préférer le prompt du personnage",
584 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Évitez de recadrer et de redimensionner les images de personnages importés. Lorsqu'il est désactivé, recadrez/redimensionnez à 512 x 768.",584 "never_resize_avatars_tooltip": "Évitez de recadrer et de redimensionner les images de personnages importés. Lorsqu'il est désactivé, recadrez/redimensionnez à 512 x 768.",
585 "Never resize avatars": "Ne jamais redimensionner les avatars",585 "Never resize avatars": "Ne jamais redimensionner les avatars",
586 "Show actual file names on the disk, in the characters list display only": "Afficher les noms de fichier réels sur le disque, dans l'affichage de la liste de personnages uniquement",586 "Show actual file names on the disk, in the characters list display only": "Afficher les noms de fichier réels sur le disque, dans l'affichage de la liste de personnages uniquement",
587 "Show avatar filenames": "Afficher les noms de fichier des avatars",587 "Show avatar filenames": "Afficher les noms de fichier des avatars",
@@ -656,7 +656,7 @@
656 "Auto-swipe": "Balayage automatique",656 "Auto-swipe": "Balayage automatique",
657 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Activer la fonction de balayage automatique. Les paramètres de cette section n'ont d'effet que lorsque le balayage automatique est activé",657 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Activer la fonction de balayage automatique. Les paramètres de cette section n'ont d'effet que lorsque le balayage automatique est activé",
658 "Minimum generated message length": "Longueur minimale du message généré",658 "Minimum generated message length": "Longueur minimale du message généré",
659 "If the generated message is shorter than this, trigger an auto-swipe": "Si le message généré est plus court que cela, déclenchez un balayage automatique",659 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Si le message généré est plus court que cela, déclenchez un balayage automatique",
660 "Blacklisted words": "Mots en liste noire",660 "Blacklisted words": "Mots en liste noire",
661 "words you dont want generated separated by comma ','": "mots que vous ne voulez pas générer séparés par des virgules ','",661 "words you dont want generated separated by comma ','": "mots que vous ne voulez pas générer séparés par des virgules ','",
662 "Blacklisted word count to swipe": "Nombre de mots en liste noire pour balayer",662 "Blacklisted word count to swipe": "Nombre de mots en liste noire pour balayer",
@@ -1420,7 +1420,6 @@
1420 "Block Entropy API Key": "Clé API Block Entropy",1420 "Block Entropy API Key": "Clé API Block Entropy",
1421 "Select a Model": "Sélectionner un modèle",1421 "Select a Model": "Sélectionner un modèle",
1422 "Example: http://localhost:1234/v1": "Exemple: http://localhost:1234/v1",1422 "Example: http://localhost:1234/v1": "Exemple: http://localhost:1234/v1",
1423 "at the end of the URL!": "à la fin de l'URL !",
1424 "(Optional)": "(Optionnel)",1423 "(Optional)": "(Optionnel)",
1425 "Enter a Model ID": "Saisir un ID de modèle",1424 "Enter a Model ID": "Saisir un ID de modèle",
1426 "Example: gpt-3.5-turbo": "Exemple: gpt-3.5-turbo",1425 "Example: gpt-3.5-turbo": "Exemple: gpt-3.5-turbo",
@@ -1485,7 +1484,7 @@
1485 "(disabled when max recursion steps are used)": "(désactivé lorsque le nombre maximum de pas de récursivité est utilisé)",1484 "(disabled when max recursion steps are used)": "(désactivé lorsque le nombre maximum de pas de récursivité est utilisé)",
1486 "Cap the number of entry activation recursions": "Plafonner le nombre de récursions d'activation d'entrée",1485 "Cap the number of entry activation recursions": "Plafonner le nombre de récursions d'activation d'entrée",
1487 "Max Recursion Steps": "Nombre maximal d'étapes de récursivité",1486 "Max Recursion Steps": "Nombre maximal d'étapes de récursivité",
1488 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\\n(disabled when min activations are used)": "0 = illimité, 1 = scanne une fois et ne récure pas, 2 = scanne une fois et récure une fois, etc.\n(désactivé lorsque des activations minimales sont utilisées)",1487 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = illimité, 1 = scanne une fois et ne récure pas, 2 = scanne une fois et récure une fois, etc.\n(désactivé lorsque des activations minimales sont utilisées)",
1489 "Include names with each message into the context for scanning": "Inclure les noms dans chaque message dans le contexte pour l'analyse.",1488 "Include names with each message into the context for scanning": "Inclure les noms dans chaque message dans le contexte pour l'analyse.",
1490 "Apply current sorting as Order": "Appliquer le tri actuel comme ordre",1489 "Apply current sorting as Order": "Appliquer le tri actuel comme ordre",
1491 "Display swipe numbers for all messages, not just the last.": "Afficher le nombre de balayage sur tous les messages, et pas seulement le dernier.",1490 "Display swipe numbers for all messages, not just the last.": "Afficher le nombre de balayage sur tous les messages, et pas seulement le dernier.",
@@ -1494,7 +1493,7 @@
1494 "Ask": "Demander",1493 "Ask": "Demander",
1495 "tag_import_none": "Aucun",1494 "tag_import_none": "Aucun",
1496 "tag_import_all": "Tous",1495 "tag_import_all": "Tous",
1497 "Existing": "Existant",1496 "tag_import_existing": "Existant",
1498 "If checked and the character card contains a Post-History Instructions override, use that instead": "Si cette case est cochée et que la carte de personnage contient une instruction de remplacement pour le post-histoire, utilisez-la à la place.",1497 "If checked and the character card contains a Post-History Instructions override, use that instead": "Si cette case est cochée et que la carte de personnage contient une instruction de remplacement pour le post-histoire, utilisez-la à la place.",
1499 "Prefer Character Card Instructions": "Préférer les instructions du personnage",1498 "Prefer Character Card Instructions": "Préférer les instructions du personnage",
1500 "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "Active la sélection automatique du texte saisi dans certains champs de texte lorsque l'on clique dessus ou qu'on les sélectionne. S'applique aux zones de texte de type popup et, éventuellement, à d'autres champs de saisie personnalisés.",1499 "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "Active la sélection automatique du texte saisi dans certains champs de texte lorsque l'on clique dessus ou qu'on les sélectionne. S'applique aux zones de texte de type popup et, éventuellement, à d'autres champs de saisie personnalisés.",
@@ -1602,7 +1601,6 @@
1602 "Character Expressions": "Expressions de personnages",1601 "Character Expressions": "Expressions de personnages",
1603 "Translate text to English before classification": "Traduire le texte en anglais avant de le classer",1602 "Translate text to English before classification": "Traduire le texte en anglais avant de le classer",
1604 "Show default images (emojis) if sprite missing": "Afficher les images par défaut (emojis) si le sprite est manquant",1603 "Show default images (emojis) if sprite missing": "Afficher les images par défaut (emojis) si le sprite est manquant",
1605 "Image Type - talkinghead (extras)": "Type d'image - talkinghead (extras)",
1606 "Classifier API": "API de classification",1604 "Classifier API": "API de classification",
1607 "Select the API for classifying expressions.": "Sélectionnez l'API pour classer les expressions.",1605 "Select the API for classifying expressions.": "Sélectionnez l'API pour classer les expressions.",
1608 "Main API": "API principale",1606 "Main API": "API principale",
public/locales/is-is.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Eyða þema",558 "Delete a theme": "Eyða þema",
559 "Update a theme file": "Uppfæra þemu skrá",559 "Update a theme file": "Uppfæra þemu skrá",
560 "Save as a new theme": "Vista sem nýja þemu",560 "Save as a new theme": "Vista sem nýja þemu",
561 "Avatar Style": "Avatar Stíll",561 "Avatar Style:": "Avatar Stíll",
562 "Circle": "Hring",562 "Circle": "Hring",
563 "Square": "Reitur",563 "Square": "Reitur",
564 "Rectangle": "Ferhyrningur",564 "Rectangle": "Ferhyrningur",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Kosstu kvenkortu fyrirspurn",633 "Prefer Character Card Prompt": "Kosstu kvenkortu fyrirspurn",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Ef merkt er og kortið inniheldur fangabrotsskil, notaðu það í staðinn",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Ef merkt er og kortið inniheldur fangabrotsskil, notaðu það í staðinn",
635 "Prefer Character Card Jailbreak": "Kosstu kvenkortu fangabrot",635 "Prefer Character Card Jailbreak": "Kosstu kvenkortu fangabrot",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Forðastu að klippa og breyta stærð innfluttra stafamynda. Þegar slökkt er á því skaltu skera/breyta stærð í 512x768.",636 "never_resize_avatars_tooltip": "Forðastu að klippa og breyta stærð innfluttra stafamynda. Þegar slökkt er á því skaltu skera/breyta stærð í 512x768.",
637 "Never resize avatars": "Aldrei breyta stærðinni á merkjum",637 "Never resize avatars": "Aldrei breyta stærðinni á merkjum",
638 "Show actual file names on the disk, in the characters list display only": "Sýna raunveruleg nöfn skráa á diskinum, í lista yfir persónur sýna aðeins",638 "Show actual file names on the disk, in the characters list display only": "Sýna raunveruleg nöfn skráa á diskinum, í lista yfir persónur sýna aðeins",
639 "Show avatar filenames": "Sýna nöfn merkja",639 "Show avatar filenames": "Sýna nöfn merkja",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Sjálfvirkur sveip",709 "Auto-swipe": "Sjálfvirkur sveip",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Virkjaðu sjálfvirka sveiflugerð. Stillingar í þessum hluta hafa aðeins áhrif þegar sjálfvirkur sveiflugerð er virk",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Virkjaðu sjálfvirka sveiflugerð. Stillingar í þessum hluta hafa aðeins áhrif þegar sjálfvirkur sveiflugerð er virk",
711 "Minimum generated message length": "Lágmarks lengd á mynduðum skilaboðum",711 "Minimum generated message length": "Lágmarks lengd á mynduðum skilaboðum",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Ef mynduðu skilaboðin eru styttri en þessi, kallaðu fram sjálfvirkar sveiflugerðar",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Ef mynduðu skilaboðin eru styttri en þessi, kallaðu fram sjálfvirkar sveiflugerðar",
713 "Blacklisted words": "Svört orð",713 "Blacklisted words": "Svört orð",
714 "words you dont want generated separated by comma ','": "orð sem þú vilt ekki að framleiða aðskilin með kommu ','",714 "words you dont want generated separated by comma ','": "orð sem þú vilt ekki að framleiða aðskilin með kommu ','",
715 "Blacklisted word count to swipe": "Fjöldi svörtra orða til að sveipa",715 "Blacklisted word count to swipe": "Fjöldi svörtra orða til að sveipa",
public/locales/it-it.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Elimina un tema",558 "Delete a theme": "Elimina un tema",
559 "Update a theme file": "Aggiorna un file di tema",559 "Update a theme file": "Aggiorna un file di tema",
560 "Save as a new theme": "Salva come nuovo tema",560 "Save as a new theme": "Salva come nuovo tema",
561 "Avatar Style": "Stile avatar",561 "Avatar Style:": "Stile avatar",
562 "Circle": "Cerchio",562 "Circle": "Cerchio",
563 "Square": "Quadrato",563 "Square": "Quadrato",
564 "Rectangle": "Rettangolo",564 "Rectangle": "Rettangolo",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Preferisci Prompt della Scheda Personaggio",633 "Prefer Character Card Prompt": "Preferisci Prompt della Scheda Personaggio",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Se selezionato e la scheda del personaggio contiene una sovrascrittura jailbreak (Istruzione Storico Post), usalo invece",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Se selezionato e la scheda del personaggio contiene una sovrascrittura jailbreak (Istruzione Storico Post), usalo invece",
635 "Prefer Character Card Jailbreak": "Preferisci Jailbreak della Scheda Personaggio",635 "Prefer Character Card Jailbreak": "Preferisci Jailbreak della Scheda Personaggio",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Evita di ritagliare e ridimensionare le immagini dei personaggi importati. Quando è disattivato, ritaglia/ridimensiona a 512x768.",636 "never_resize_avatars_tooltip": "Evita di ritagliare e ridimensionare le immagini dei personaggi importati. Quando è disattivato, ritaglia/ridimensiona a 512x768.",
637 "Never resize avatars": "Non ridimensionare mai gli avatar",637 "Never resize avatars": "Non ridimensionare mai gli avatar",
638 "Show actual file names on the disk, in the characters list display only": "Mostra i nomi file effettivi sul disco, solo nella visualizzazione dell'elenco dei personaggi",638 "Show actual file names on the disk, in the characters list display only": "Mostra i nomi file effettivi sul disco, solo nella visualizzazione dell'elenco dei personaggi",
639 "Show avatar filenames": "Mostra nomi file avatar",639 "Show avatar filenames": "Mostra nomi file avatar",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Auto-swipe",709 "Auto-swipe": "Auto-swipe",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Abilita la funzione di auto-swipe. Le impostazioni in questa sezione hanno effetto solo quando l'auto-swipe è abilitato",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Abilita la funzione di auto-swipe. Le impostazioni in questa sezione hanno effetto solo quando l'auto-swipe è abilitato",
711 "Minimum generated message length": "Lunghezza minima del messaggio generato",711 "Minimum generated message length": "Lunghezza minima del messaggio generato",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Se il messaggio generato è più breve di questo, attiva un'automatica rimozione",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Se il messaggio generato è più breve di questo, attiva un'automatica rimozione",
713 "Blacklisted words": "Parole in blacklist",713 "Blacklisted words": "Parole in blacklist",
714 "words you dont want generated separated by comma ','": "parole che non vuoi generate separate da virgola ','",714 "words you dont want generated separated by comma ','": "parole che non vuoi generate separate da virgola ','",
715 "Blacklisted word count to swipe": "Numero di parole in blacklist per attivare un'automatica rimozione",715 "Blacklisted word count to swipe": "Numero di parole in blacklist per attivare un'automatica rimozione",
public/locales/ja-jp.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "テーマを削除する",558 "Delete a theme": "テーマを削除する",
559 "Update a theme file": "テーマファイルを更新",559 "Update a theme file": "テーマファイルを更新",
560 "Save as a new theme": "新しいテーマとして保存",560 "Save as a new theme": "新しいテーマとして保存",
561 "Avatar Style": "アバタースタイル",561 "Avatar Style:": "アバタースタイル",
562 "Circle": "円",562 "Circle": "円",
563 "Square": "正方形",563 "Square": "正方形",
564 "Rectangle": "長方形",564 "Rectangle": "長方形",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "キャラクターカードのプロンプトを優先",633 "Prefer Character Card Prompt": "キャラクターカードのプロンプトを優先",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "チェックされていてキャラクターカードにジェイルブレイクオーバーライド(投稿履歴指示)が含まれている場合、それを代わりに使用します",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "チェックされていてキャラクターカードにジェイルブレイクオーバーライド(投稿履歴指示)が含まれている場合、それを代わりに使用します",
635 "Prefer Character Card Jailbreak": "キャラクターカードのJailbreakを優先",635 "Prefer Character Card Jailbreak": "キャラクターカードのJailbreakを優先",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "インポートした文字画像の切り取りやサイズ変更を避けます。オフにすると、512x768 に切り取り/サイズ変更されます。",636 "never_resize_avatars_tooltip": "インポートした文字画像の切り取りやサイズ変更を避けます。オフにすると、512x768 に切り取り/サイズ変更されます。",
637 "Never resize avatars": "アバターを常にリサイズしない",637 "Never resize avatars": "アバターを常にリサイズしない",
638 "Show actual file names on the disk, in the characters list display only": "ディスク上の実際のファイル名を表示します。キャラクターリストの表示にのみ",638 "Show actual file names on the disk, in the characters list display only": "ディスク上の実際のファイル名を表示します。キャラクターリストの表示にのみ",
639 "Show avatar filenames": "アバターのファイル名を表示",639 "Show avatar filenames": "アバターのファイル名を表示",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "オートスワイプ",709 "Auto-swipe": "オートスワイプ",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "自動スワイプ機能を有効にします。このセクションの設定は、自動スワイプが有効になっている場合にのみ効果があります",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "自動スワイプ機能を有効にします。このセクションの設定は、自動スワイプが有効になっている場合にのみ効果があります",
711 "Minimum generated message length": "生成されたメッセージの最小長",711 "Minimum generated message length": "生成されたメッセージの最小長",
712 "If the generated message is shorter than this, trigger an auto-swipe": "生成されたメッセージがこれよりも短い場合、自動スワイプをトリガーします",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "生成されたメッセージがこれよりも短い場合、自動スワイプをトリガーします",
713 "Blacklisted words": "ブラックリストされた単語",713 "Blacklisted words": "ブラックリストされた単語",
714 "words you dont want generated separated by comma ','": "コンマ ',' で区切られた生成したくない単語",714 "words you dont want generated separated by comma ','": "コンマ ',' で区切られた生成したくない単語",
715 "Blacklisted word count to swipe": "スワイプするブラックリストされた単語の数",715 "Blacklisted word count to swipe": "スワイプするブラックリストされた単語の数",
public/locales/ko-kr.json+4 -5
@@ -568,7 +568,7 @@
568 "Delete a theme": "테마 삭제",568 "Delete a theme": "테마 삭제",
569 "Update a theme file": "테마 파일 업데이트",569 "Update a theme file": "테마 파일 업데이트",
570 "Save as a new theme": "새 테마로 저장",570 "Save as a new theme": "새 테마로 저장",
571 "Avatar Style": "캐릭터 프로필 스타일",571 "Avatar Style:": "캐릭터 프로필 스타일",
572 "Circle": "원",572 "Circle": "원",
573 "Square": "정사각형",573 "Square": "정사각형",
574 "Rectangle": "사각형",574 "Rectangle": "사각형",
@@ -646,7 +646,7 @@
646 "Prefer Character Card Prompt": "캐릭터 카드 프롬프트 선호",646 "Prefer Character Card Prompt": "캐릭터 카드 프롬프트 선호",
647 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "선택되어 있고 캐릭터 카드에 (Post-History 지시)탈옥 재정의가 포함 된 경우, 그것을 대신 사용합니다.",647 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "선택되어 있고 캐릭터 카드에 (Post-History 지시)탈옥 재정의가 포함 된 경우, 그것을 대신 사용합니다.",
648 "Prefer Character Card Jailbreak": "캐릭터 카드 탈옥 선호",648 "Prefer Character Card Jailbreak": "캐릭터 카드 탈옥 선호",
649 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "가져온 캐릭터 이미지를 자르거나 크기를 조정하지 마세요. 꺼져 있으면 512x768로 자르거나 크기를 조정합니다.",649 "never_resize_avatars_tooltip": "가져온 캐릭터 이미지를 자르거나 크기를 조정하지 마세요. 꺼져 있으면 512x768로 자르거나 크기를 조정합니다.",
650 "Never resize avatars": "아바타 크기 변경하지 않음",650 "Never resize avatars": "아바타 크기 변경하지 않음",
651 "Show actual file names on the disk, in the characters list display only": "실제 파일 이름을 디스크에 표시하며 캐릭터 목록 디스플레이에만",651 "Show actual file names on the disk, in the characters list display only": "실제 파일 이름을 디스크에 표시하며 캐릭터 목록 디스플레이에만",
652 "Show avatar filenames": "아바타 파일 이름 표시",652 "Show avatar filenames": "아바타 파일 이름 표시",
@@ -724,7 +724,7 @@
724 "Auto-swipe": "자동 스와이프",724 "Auto-swipe": "자동 스와이프",
725 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "자동 스와이프 기능을 활성화합니다. 이 섹션의 설정은 자동 스와이프가 활성화되었을 때만 영향을 미칩니다",725 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "자동 스와이프 기능을 활성화합니다. 이 섹션의 설정은 자동 스와이프가 활성화되었을 때만 영향을 미칩니다",
726 "Minimum generated message length": "생성된 메시지 최소 길이",726 "Minimum generated message length": "생성된 메시지 최소 길이",
727 "If the generated message is shorter than this, trigger an auto-swipe": "생성된 메시지가이보다 짧으면 자동 스와이프를 트리거합니다",727 "If the generated message is shorter than these many characters, trigger an auto-swipe": "생성된 메시지가이보다 짧으면 자동 스와이프를 트리거합니다",
728 "Blacklisted words": "금지어",728 "Blacklisted words": "금지어",
729 "words you dont want generated separated by comma ','": "쉼표로 구분된 생성하지 않으려는 단어",729 "words you dont want generated separated by comma ','": "쉼표로 구분된 생성하지 않으려는 단어",
730 "Blacklisted word count to swipe": "스와이프할 금지어 개수",730 "Blacklisted word count to swipe": "스와이프할 금지어 개수",
@@ -1467,7 +1467,6 @@
1467 "menu within": "내의 메뉴",1467 "menu within": "내의 메뉴",
1468 "Translate text to English before classification": "분류 전에 텍스트를 영어로 번역합니다.",1468 "Translate text to English before classification": "분류 전에 텍스트를 영어로 번역합니다.",
1469 "Show default images (emojis) if sprite missing": "해당하는 스프라이트가 없으면 기본 이미지 (이모지들)을 표시합니다.",1469 "Show default images (emojis) if sprite missing": "해당하는 스프라이트가 없으면 기본 이미지 (이모지들)을 표시합니다.",
1470 "Image Type - talkinghead (extras)": "이미지 유형 - 토킹 헤드 (부가 사항)",
1471 "Classifier API": "분류를 위한 API",1470 "Classifier API": "분류를 위한 API",
1472 "Select the API for classifying expressions.": "감정 이미지들을 분류할 API를 선택하세요.",1471 "Select the API for classifying expressions.": "감정 이미지들을 분류할 API를 선택하세요.",
1473 "Local": "로컬",1472 "Local": "로컬",
@@ -1614,7 +1613,7 @@
1614 "Ask": "묻기",1613 "Ask": "묻기",
1615 "tag_import_none": "불러오지 않음",1614 "tag_import_none": "불러오지 않음",
1616 "tag_import_all": "전부",1615 "tag_import_all": "전부",
1617 "Existing": "기존 태그 참조",1616 "tag_import_existing": "기존 태그 참조",
1618 "You can add more": "원한다면",1617 "You can add more": "원한다면",
1619 "or_welcome": "또는",1618 "or_welcome": "또는",
1620 "from other websites": "를 통해 다른 웹사이트들로부터 불러올 수 있습니다.",1619 "from other websites": "를 통해 다른 웹사이트들로부터 불러올 수 있습니다.",
public/locales/nl-nl.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Verwijder een thema",558 "Delete a theme": "Verwijder een thema",
559 "Update a theme file": "Werk een themabestand bij",559 "Update a theme file": "Werk een themabestand bij",
560 "Save as a new theme": "Opslaan als nieuw thema",560 "Save as a new theme": "Opslaan als nieuw thema",
561 "Avatar Style": "Avatarstijl",561 "Avatar Style:": "Avatarstijl",
562 "Circle": "Cirkel",562 "Circle": "Cirkel",
563 "Square": "Vierkant",563 "Square": "Vierkant",
564 "Rectangle": "Rechthoek",564 "Rectangle": "Rechthoek",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Voorkeur karakterkaart prompt",633 "Prefer Character Card Prompt": "Voorkeur karakterkaart prompt",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Als aangevinkt en de karakterkaart bevat een jailbreak-override (Post History Instruction), gebruik die in plaats daarvan",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Als aangevinkt en de karakterkaart bevat een jailbreak-override (Post History Instruction), gebruik die in plaats daarvan",
635 "Prefer Character Card Jailbreak": "Voorkeur karakterkaart jailbreak",635 "Prefer Character Card Jailbreak": "Voorkeur karakterkaart jailbreak",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Vermijd het bijsnijden en vergroten/verkleinen van geïmporteerde karakterafbeeldingen. Indien uitgeschakeld, bijsnijden/formaat wijzigen naar 512 x 768.",636 "never_resize_avatars_tooltip": "Vermijd het bijsnijden en vergroten/verkleinen van geïmporteerde karakterafbeeldingen. Indien uitgeschakeld, bijsnijden/formaat wijzigen naar 512 x 768.",
637 "Never resize avatars": "Avatars nooit verkleinen",637 "Never resize avatars": "Avatars nooit verkleinen",
638 "Show actual file names on the disk, in the characters list display only": "Toon de werkelijke bestandsnamen op de schijf, alleen in de weergave van de lijst met personages",638 "Show actual file names on the disk, in the characters list display only": "Toon de werkelijke bestandsnamen op de schijf, alleen in de weergave van de lijst met personages",
639 "Show avatar filenames": "Toon avatar bestandsnamen",639 "Show avatar filenames": "Toon avatar bestandsnamen",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Automatisch vegen",709 "Auto-swipe": "Automatisch vegen",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Schakel de automatische-vegen functie in. Instellingen in dit gedeelte hebben alleen effect wanneer automatisch vegen is ingeschakeld",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Schakel de automatische-vegen functie in. Instellingen in dit gedeelte hebben alleen effect wanneer automatisch vegen is ingeschakeld",
711 "Minimum generated message length": "Minimale gegenereerde berichtlengte",711 "Minimum generated message length": "Minimale gegenereerde berichtlengte",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Als het gegenereerde bericht korter is dan dit, activeer dan een automatische veeg",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Als het gegenereerde bericht korter is dan dit, activeer dan een automatische veeg",
713 "Blacklisted words": "Verboden woorden",713 "Blacklisted words": "Verboden woorden",
714 "words you dont want generated separated by comma ','": "woorden die je niet gegenereerd wilt hebben gescheiden door komma ','",714 "words you dont want generated separated by comma ','": "woorden die je niet gegenereerd wilt hebben gescheiden door komma ','",
715 "Blacklisted word count to swipe": "Aantal verboden woorden om te vegen",715 "Blacklisted word count to swipe": "Aantal verboden woorden om te vegen",
public/locales/pt-pt.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Excluir um tema",558 "Delete a theme": "Excluir um tema",
559 "Update a theme file": "Atualizar um arquivo de tema",559 "Update a theme file": "Atualizar um arquivo de tema",
560 "Save as a new theme": "Salvar como um novo tema",560 "Save as a new theme": "Salvar como um novo tema",
561 "Avatar Style": "Estilo de Avatar",561 "Avatar Style:": "Estilo de Avatar",
562 "Circle": "Círculo",562 "Circle": "Círculo",
563 "Square": "Quadrado",563 "Square": "Quadrado",
564 "Rectangle": "Retângulo",564 "Rectangle": "Retângulo",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Preferir Prompt do Cartão de Personagem",633 "Prefer Character Card Prompt": "Preferir Prompt do Cartão de Personagem",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Se marcado e o cartão de personagem contiver uma substituição de jailbreak (Instrução de Histórico de Postagens), use isso em vez disso",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Se marcado e o cartão de personagem contiver uma substituição de jailbreak (Instrução de Histórico de Postagens), use isso em vez disso",
635 "Prefer Character Card Jailbreak": "Preferir Jailbreak do Cartão de Personagem",635 "Prefer Character Card Jailbreak": "Preferir Jailbreak do Cartão de Personagem",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Evite cortar e redimensionar imagens de personagens importados. Quando desativado, corte/redimensione para 512x768.",636 "never_resize_avatars_tooltip": "Evite cortar e redimensionar imagens de personagens importados. Quando desativado, corte/redimensione para 512x768.",
637 "Never resize avatars": "Nunca redimensionar avatares",637 "Never resize avatars": "Nunca redimensionar avatares",
638 "Show actual file names on the disk, in the characters list display only": "Mostrar nomes de arquivo reais no disco, apenas na exibição da lista de personagens",638 "Show actual file names on the disk, in the characters list display only": "Mostrar nomes de arquivo reais no disco, apenas na exibição da lista de personagens",
639 "Show avatar filenames": "Mostrar nomes de arquivo de avatar",639 "Show avatar filenames": "Mostrar nomes de arquivo de avatar",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Auto-swipe",709 "Auto-swipe": "Auto-swipe",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Ativar a função de auto-swipe. As configurações nesta seção só têm efeito quando o auto-swipe está ativado",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Ativar a função de auto-swipe. As configurações nesta seção só têm efeito quando o auto-swipe está ativado",
711 "Minimum generated message length": "Comprimento mínimo da mensagem gerada",711 "Minimum generated message length": "Comprimento mínimo da mensagem gerada",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Se a mensagem gerada for mais curta que isso, acione um auto-swipe",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Se a mensagem gerada for mais curta que isso, acione um auto-swipe",
713 "Blacklisted words": "Palavras proibidas",713 "Blacklisted words": "Palavras proibidas",
714 "words you dont want generated separated by comma ','": "palavras que você não quer geradas separadas por vírgula ','",714 "words you dont want generated separated by comma ','": "palavras que você não quer geradas separadas por vírgula ','",
715 "Blacklisted word count to swipe": "Contagem de palavras proibidas para swipe",715 "Blacklisted word count to swipe": "Contagem de palavras proibidas para swipe",
public/locales/ru-ru.json+76 -17
@@ -195,12 +195,12 @@
195 "Yes": "Да",195 "Yes": "Да",
196 "No": "Нет",196 "No": "Нет",
197 "Context %": "Процент контекста",197 "Context %": "Процент контекста",
198 "Budget Cap": "Бюджетный лимит",198 "Budget Cap": "Лимит бюджета",
199 "(0 = disabled)": "(0 = отключено)",199 "(0 = disabled)": "(0 = отключено)",
200 "None": "Отсутствует",200 "None": "Отсутствует",
201 "User Settings": "Настройки пользователя",201 "User Settings": "Настройки пользователя",
202 "UI Language": "Язык интерфейса",202 "UI Language": "Язык интерфейса",
203 "Avatar Style": "Аватарки",203 "Avatar Style:": "Аватарки",
204 "Circle": "Круглые",204 "Circle": "Круглые",
205 "Rectangle": "Прямоугольные",205 "Rectangle": "Прямоугольные",
206 "Square": "Квадратные",206 "Square": "Квадратные",
@@ -426,7 +426,7 @@
426 "Requests logprobs from the API for the Token Probabilities feature": "Запросить логпробы из API для функции Token Probabilities.",426 "Requests logprobs from the API for the Token Probabilities feature": "Запросить логпробы из API для функции Token Probabilities.",
427 "Automatically reject and re-generate AI message based on configurable criteria": "Автоматическое отклонение и повторная генерация сообщений AI на основе настраиваемых критериев.",427 "Automatically reject and re-generate AI message based on configurable criteria": "Автоматическое отклонение и повторная генерация сообщений AI на основе настраиваемых критериев.",
428 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Включить авто-свайп. Настройки в этом разделе действуют только при включенном авто-свайпе.",428 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Включить авто-свайп. Настройки в этом разделе действуют только при включенном авто-свайпе.",
429 "If the generated message is shorter than this, trigger an auto-swipe": "Если сгенерированное сообщение короче этого значения, срабатывает авто-свайп.",429 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Если сгенерированное сообщение короче этого значения, срабатывает авто-свайп.",
430 "Reload and redraw the currently open chat": "Перезагрузить и перерисовать открытый в данный момент чат.",430 "Reload and redraw the currently open chat": "Перезагрузить и перерисовать открытый в данный момент чат.",
431 "Auto-Expand Message Actions": "Развернуть действия",431 "Auto-Expand Message Actions": "Развернуть действия",
432 "Persona Management": "Управление персоной",432 "Persona Management": "Управление персоной",
@@ -575,10 +575,10 @@
575 "Characters sorting order": "Порядок сортировки персонажей",575 "Characters sorting order": "Порядок сортировки персонажей",
576 "Remove": "Убрать",576 "Remove": "Убрать",
577 "Select a World Info file for": "Выбрать файл с миром для",577 "Select a World Info file for": "Выбрать файл с миром для",
578 "Primary Lorebook": "Основного лорбука",578 "Primary Lorebook": "Основной лорбук",
579 "A selected World Info will be bound to this character as its own Lorebook.": "Информация о мире будет привязана к персонажу как его собственный лорбук",579 "A selected World Info will be bound to this character as its own Lorebook.": "Информация о мире будет привязана к персонажу как его собственный лорбук.",
580 "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Когда ИИ генерирует ответ, он будет совмещён с записями из глобально выбранного мира",580 "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Когда ИИ генерирует ответ, он будет совмещён с записями из глобально выбранного мира.",
581 "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON",581 "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON.",
582 "Additional Lorebooks": "Вспомогательные лорбуки",582 "Additional Lorebooks": "Вспомогательные лорбуки",
583 "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков",583 "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков",
584 "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: эти выборы необязательные и не будут сохранены при экспорте персонажа!",584 "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: эти выборы необязательные и не будут сохранены при экспорте персонажа!",
@@ -593,7 +593,7 @@
593 "Prompt": "Промпт",593 "Prompt": "Промпт",
594 "Copy": "Скопировать",594 "Copy": "Скопировать",
595 "Confirm": "Подтвердить",595 "Confirm": "Подтвердить",
596 "Copy this message": "Скопировать сообщение",596 "Copy this message": "Продублировать сообщение",
597 "Delete this message": "Удалить сообщение",597 "Delete this message": "Удалить сообщение",
598 "Move message up": "Переместить сообщение вверх",598 "Move message up": "Переместить сообщение вверх",
599 "Move message down": "Переместить сообщение вниз",599 "Move message down": "Переместить сообщение вниз",
@@ -612,7 +612,7 @@
612 "Ask AI to write your message for you": "Попросить ИИ написать сообщение за вас",612 "Ask AI to write your message for you": "Попросить ИИ написать сообщение за вас",
613 "Continue the last message": "Продолжить текущее сообщение",613 "Continue the last message": "Продолжить текущее сообщение",
614 "Bind user name to that avatar": "Закрепить имя за этим аватаром",614 "Bind user name to that avatar": "Закрепить имя за этим аватаром",
615 "Select this as default persona for the new chats.": "Выберать эту Персону в качестве персоны по умолчанию для новых чатов.",615 "Select this as default persona for the new chats.": "Выбирать эту персону по умолчанию для всех новых чатов.",
616 "Change persona image": "Сменить аватар персоны",616 "Change persona image": "Сменить аватар персоны",
617 "Delete persona": "Удалить персону",617 "Delete persona": "Удалить персону",
618 "Reduced Motion": "Сокращение анимаций",618 "Reduced Motion": "Сокращение анимаций",
@@ -640,7 +640,7 @@
640 "Token Probabilities": "Вероятности токенов",640 "Token Probabilities": "Вероятности токенов",
641 "Close chat": "Закрыть чат",641 "Close chat": "Закрыть чат",
642 "Manage chat files": "Все чаты",642 "Manage chat files": "Все чаты",
643 "Import Extension From Git Repo": "Импортировать расширение из Git Repository",643 "Import Extension From Git Repo": "Импортировать расширение из Git-репозитория.",
644 "Install extension": "Установить расширение",644 "Install extension": "Установить расширение",
645 "Manage extensions": "Управление расширениями",645 "Manage extensions": "Управление расширениями",
646 "Tokens persona description": "Токенов",646 "Tokens persona description": "Токенов",
@@ -995,7 +995,7 @@
995 "Set your custom avatar.": "Установить аватарку",995 "Set your custom avatar.": "Установить аватарку",
996 "Remove your custom avatar.": "Сбросить аватарку",996 "Remove your custom avatar.": "Сбросить аватарку",
997 "Make a Snapshot": "Сделать снимок",997 "Make a Snapshot": "Сделать снимок",
998 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Не менять размер картинок у импортируемых персонажей. При отключении все картинки будут приводиться к размеру 512х768",998 "never_resize_avatars_tooltip": "Не менять размер картинок у импортируемых персонажей. При отключении все картинки будут приводиться к размеру 512х768",
999 "Char List Subheader": "Доп. заголовок в списке персонажей",999 "Char List Subheader": "Доп. заголовок в списке персонажей",
1000 "# Messages to Load": "Сколько сообщений загружать",1000 "# Messages to Load": "Сколько сообщений загружать",
1001 "(0 = All)": "(0 = все)",1001 "(0 = All)": "(0 = все)",
@@ -1122,12 +1122,11 @@
1122 "help_hotkeys_0": "Горячие клавиши",1122 "help_hotkeys_0": "Горячие клавиши",
1123 "You can browse a list of bundled characters in the": "Комплектных персонажей можно найти в меню",1123 "You can browse a list of bundled characters in the": "Комплектных персонажей можно найти в меню",
1124 "Download Extensions & Assets": "Загрузить расширения и ресурсы",1124 "Download Extensions & Assets": "Загрузить расширения и ресурсы",
1125 "menu within": "внутри этих кубиков",1125 "menu within": "в меню",
1126 "Assets URL": "URL с описанием ресурсов",1126 "Assets URL": "URL с описанием ресурсов",
1127 "Custom (OpenAI-compatible)": "Кастомный (совместимый с OpenAI)",1127 "Custom (OpenAI-compatible)": "Кастомный (совместимый с OpenAI)",
1128 "Custom Endpoint (Base URL)": "Кастомный эндпоинт (базовый URL)",1128 "Custom Endpoint (Base URL)": "Кастомный эндпоинт (базовый URL)",
1129 "Example: http://localhost:1234/v1": "Пример: http://localhost:1234/v1",1129 "Example: http://localhost:1234/v1": "Пример: http://localhost:1234/v1",
1130 "at the end of the URL!": "!",
1131 "Custom API Key": "Ключ от кастомного API",1130 "Custom API Key": "Ключ от кастомного API",
1132 "(Optional)": "(необязательно)",1131 "(Optional)": "(необязательно)",
1133 "Enter a Model ID": "Введите идентификатор модели",1132 "Enter a Model ID": "Введите идентификатор модели",
@@ -1622,7 +1621,7 @@
1622 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "Выберите, какие действия следует предпринять по отношению к тегам импортируемой карточки. При выборе опции \"Спрашивать\" вы будете решать это индивидуально для каждой карточки.",1621 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "Выберите, какие действия следует предпринять по отношению к тегам импортируемой карточки. При выборе опции \"Спрашивать\" вы будете решать это индивидуально для каждой карточки.",
1623 "Ask": "Спрашивать",1622 "Ask": "Спрашивать",
1624 "tag_import_all": "Все",1623 "tag_import_all": "Все",
1625 "Existing": "Только существующие",1624 "tag_import_existing": "Только существующие",
1626 "tag_import_none": "Не импортировать",1625 "tag_import_none": "Не импортировать",
1627 "Using a proxy that you're not running yourself is a risk to your data privacy.": "Помните, что используя чужую прокси, вы подвергаете риску конфиденциальность своих данных.",1626 "Using a proxy that you're not running yourself is a risk to your data privacy.": "Помните, что используя чужую прокси, вы подвергаете риску конфиденциальность своих данных.",
1628 "ANY support requests will be REFUSED if you are using a proxy.": "НЕ РАССЧИТЫВАЙТЕ на нашу поддержку, если используете прокси.",1627 "ANY support requests will be REFUSED if you are using a proxy.": "НЕ РАССЧИТЫВАЙТЕ на нашу поддержку, если используете прокси.",
@@ -1943,7 +1942,7 @@
1943 "and connect to an": "и подключитесь к",1942 "and connect to an": "и подключитесь к",
1944 "You can add more": "Можете добавить больше",1943 "You can add more": "Можете добавить больше",
1945 "from other websites": "с других сайтов.",1944 "from other websites": "с других сайтов.",
1946 "Go to the": "Загляните в",1945 "Go to the": "Заходите в",
1947 "to install additional features.": ", чтобы установить разные дополнительные ресурсы.",1946 "to install additional features.": ", чтобы установить разные дополнительные ресурсы.",
1948 "or_welcome": "; также доступен",1947 "or_welcome": "; также доступен",
1949 "Claude API Key": "Ключ от API Claude",1948 "Claude API Key": "Ключ от API Claude",
@@ -1958,7 +1957,7 @@
1958 "Save": "Сохранить",1957 "Save": "Сохранить",
1959 "Chat Lorebook": "Лорбук для чата",1958 "Chat Lorebook": "Лорбук для чата",
1960 "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет добавляться в промпт наряду с глобальным лорбуком и лором персонажа.",1959 "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет добавляться в промпт наряду с глобальным лорбуком и лором персонажа.",
1961 "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + клик, чтобы открыть диалог привязки мира",1960 "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + ЛКМ, чтобы открыть диалог привязки мира",
1962 "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.",1961 "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.",
1963 "ext_regex_user_input_desc": "Отправленные вами сообщения.",1962 "ext_regex_user_input_desc": "Отправленные вами сообщения.",
1964 "ext_regex_ai_input_desc": "Полученные от API ответы.",1963 "ext_regex_ai_input_desc": "Полученные от API ответы.",
@@ -2144,5 +2143,65 @@
2144 "Not connected to the API!": "Нет соединения с API!",2143 "Not connected to the API!": "Нет соединения с API!",
2145 "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.",2144 "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.",
2146 "Update all": "Обновить все",2145 "Update all": "Обновить все",
2147 "Close": "Закрыть"2146 "Close": "Закрыть",
2147 "Optional modules:": "Необязательные модули:",
2148 "Sort: Display Name": "Сортировать: по названию",
2149 "Sort: Loading Order": "Сортировать: в порядке загрузки",
2150 "Click to toggle": "Нажмите, чтобы включить или выключить",
2151 "Loading Asset List": "Загрузить список ресурсов",
2152 "Don't ask again for this URL": "Запомнить выбор для этого адреса",
2153 "Are you sure you want to connect to the following url?": "Вы точно хотите подключиться к этому адресу?",
2154 "All": "Всё",
2155 "Characters": "Персонажи",
2156 "Ambient sounds": "Звуковой эмбиент",
2157 "Blip sounds": "Звуки уведомлений",
2158 "Background music": "Фоновая музыка",
2159 "Search": "Поиск",
2160 "extension_install_1": "Чтобы загружать расширения из этого списка, у вас должен быть установлен ",
2161 "extension_install_2": ".",
2162 "extension_install_3": "Нажмите на иконку ",
2163 "extension_install_4": ", чтобы перейти в репозиторий расширения и получить более подробную информацию о нём.",
2164 "Extension repo/guide:": "Репозиторий расширения:",
2165 "Preview in browser": "Предпросмотр",
2166 "Adds a function tool": "Частично или полностью работает через вызов функций",
2167 "Tool": "Функции",
2168 "Move extension": "Переместить расширение",
2169 "ext_type_local": "Это локальное расширение, доступно только вам",
2170 "ext_type_global": "Это глобальное расширение, доступно всем пользователям",
2171 "Move": "Переместить",
2172 "Enter the Git URL of the extension to install": "Введите Git-адрес расширения",
2173 "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "помните, что используя расширения от сторонних авторов, вы можете подвергать систему опасности. Устанавливайте расширения только от проверенных разработчиков. Мы не несём ответственности за любой ущерб, причинённый сторонними расширениями.",
2174 "Disclaimer:": "Внимание:",
2175 "Example:": "Пример:",
2176 "context_derived": "Считывать из метаданных модели (по возможности)",
2177 "instruct_derived": "Считывать из метаданных модели (по возможности)",
2178 "Confirm token parsing with": "Чтобы убедиться в правильности выделения токенов, используйте",
2179 "Reasoning Effort": "Рассуждения",
2180 "Constrains effort on reasoning for reasoning models.": "Регулирует объём внутренних рассуждений модели (reasoning), для моделей которые поддерживают эту возможность.\nНа данный момент поддерживаются три значения: Подробные, Обычные, Поверхностные.\nПри менее подробном рассуждении ответ получается быстрее, а также экономятся токены, уходящие на рассуждения.",
2181 "openai_reasoning_effort_low": "Поверхностные",
2182 "openai_reasoning_effort_medium": "Обычные",
2183 "openai_reasoning_effort_high": "Подробные",
2184 "Persona Lore Alt+Click to open the lorebook": "Лорбук данной персоны\nAlt + ЛКМ чтобы открыть лорбук",
2185 "Persona Lorebook for": "Лорбук для персоны",
2186 "persona_world_template_txt": "Выбранная Информация о мире будет привязана к этой персоне. Информация будет добавляться в каждом промпте вместе с глобальным лорбуком и лорбуками персонажа и чата.",
2187 "Global list": "Глобальный список",
2188 "Preset-specific list": "Список для данного пресета",
2189 "Banned tokens/strings are being sent in the request.": "Запрещённые токены и строки отсылаются в запросе.",
2190 "Banned tokens/strings are NOT being sent in the request.": "Запрещённые токены и строки НЕ отсылаются в запросе.",
2191 "Add a reasoning block": "Добавить блок рассуждений",
2192 "Create a copy of this message?": "Продублировать это сообщение?",
2193 "Max Recursion Steps": "Макс. глубина рекурсии",
2194 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = неограничено, 1 = сканировать единожды, 2 = сканировать единожды и сделать один повторный проход, и т.д.\n(неактивно при указанном мин. числе активаций)",
2195 "(disabled when max recursion steps are used)": "(неактивно при указанной макс. глубине рекурсии)",
2196 "Enter a valid API URL": "Введите корректный адрес API",
2197 "No Ollama model selected.": "Не выбрана модель Ollama",
2198 "Background Fitting": "Способ подгонки фона под разрешение",
2199 "Chat Lore Alt+Click to open the lorebook": "Лорбук данного чата\nAlt + ЛКМ чтобы открыть лорбук",
2200 "Token Counter": "Подсчитать токены",
2201 "Type / paste in the box below to see the number of tokens in the text.": "Введите или вставьте текст в окошко ниже, чтобы подсчитать количество токенов в нём.",
2202 "Selected tokenizer:": "Выбранный токенайзер:",
2203 "Input:": "Входные данные:",
2204 "Tokenized text:": "Токенизированный текст:",
2205 "Token IDs:": "Идентификаторы токенов:",
2206 "Tokens:": "Токенов:"
2148}2207}
public/locales/uk-ua.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Видалити тему",558 "Delete a theme": "Видалити тему",
559 "Update a theme file": "Оновити файл теми",559 "Update a theme file": "Оновити файл теми",
560 "Save as a new theme": "Зберегти як нову тему",560 "Save as a new theme": "Зберегти як нову тему",
561 "Avatar Style": "Стиль аватара",561 "Avatar Style:": "Стиль аватара",
562 "Circle": "Коло",562 "Circle": "Коло",
563 "Square": "Квадрат",563 "Square": "Квадрат",
564 "Rectangle": "Прямокутник",564 "Rectangle": "Прямокутник",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Перевага запиту персонажа",633 "Prefer Character Card Prompt": "Перевага запиту персонажа",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Якщо відмічено і картка персонажа містить заміну джейлбрейку (Інструкцію), використовуйте її замість цього",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Якщо відмічено і картка персонажа містить заміну джейлбрейку (Інструкцію), використовуйте її замість цього",
635 "Prefer Character Card Jailbreak": "Перевага джейлбрейку персонажа",635 "Prefer Character Card Jailbreak": "Перевага джейлбрейку персонажа",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Уникайте обрізання та зміни розміру імпортованих зображень символів. Коли вимкнено, обрізати/змінити розмір до 512x768.",636 "never_resize_avatars_tooltip": "Уникайте обрізання та зміни розміру імпортованих зображень символів. Коли вимкнено, обрізати/змінити розмір до 512x768.",
637 "Never resize avatars": "Ніколи не змінювати розмір аватарів",637 "Never resize avatars": "Ніколи не змінювати розмір аватарів",
638 "Show actual file names on the disk, in the characters list display only": "Показувати фактичні назви файлів на диску, тільки у відображенні списку персонажів",638 "Show actual file names on the disk, in the characters list display only": "Показувати фактичні назви файлів на диску, тільки у відображенні списку персонажів",
639 "Show avatar filenames": "Показувати імена файлів аватарів",639 "Show avatar filenames": "Показувати імена файлів аватарів",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Автоматичний змах",709 "Auto-swipe": "Автоматичний змах",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Вмикає функцію автоматичного змаху. Налаштування в цьому розділі діють лише тоді, коли увімкнено автоматичний змах",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Вмикає функцію автоматичного змаху. Налаштування в цьому розділі діють лише тоді, коли увімкнено автоматичний змах",
711 "Minimum generated message length": "Мінімальна довжина згенерованого повідомлення",711 "Minimum generated message length": "Мінімальна довжина згенерованого повідомлення",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Якщо згенероване повідомлення коротше за це, викликайте автоматичний змаху",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Якщо згенероване повідомлення коротше за це, викликайте автоматичний змаху",
713 "Blacklisted words": "Список заборонених слів",713 "Blacklisted words": "Список заборонених слів",
714 "words you dont want generated separated by comma ','": "слова, які ви не хочете генерувати, розділені комою ','",714 "words you dont want generated separated by comma ','": "слова, які ви не хочете генерувати, розділені комою ','",
715 "Blacklisted word count to swipe": "Кількість заборонених слів для змаху",715 "Blacklisted word count to swipe": "Кількість заборонених слів для змаху",
public/locales/vi-vn.json+3 -3
@@ -558,7 +558,7 @@
558 "Delete a theme": "Xóa một chủ đề",558 "Delete a theme": "Xóa một chủ đề",
559 "Update a theme file": "Cập nhật một tập tin chủ đề",559 "Update a theme file": "Cập nhật một tập tin chủ đề",
560 "Save as a new theme": "Lưu dưới dạng chủ đề mới",560 "Save as a new theme": "Lưu dưới dạng chủ đề mới",
561 "Avatar Style": "Kiểu hình đại diện",561 "Avatar Style:": "Kiểu hình đại diện",
562 "Circle": "Hình tròn",562 "Circle": "Hình tròn",
563 "Square": "Hình vuông",563 "Square": "Hình vuông",
564 "Rectangle": "Hình chữ nhật",564 "Rectangle": "Hình chữ nhật",
@@ -633,7 +633,7 @@
633 "Prefer Character Card Prompt": "Ưu tiên Gợi ý từ Card",633 "Prefer Character Card Prompt": "Ưu tiên Gợi ý từ Card",
634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Nếu được kiểm tra và thẻ nhân vật chứa một lệnh phá vỡ giam giữ (Hướng dẫn Lịch sử Bài viết), hãy sử dụng thay vào đó",634 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "Nếu được kiểm tra và thẻ nhân vật chứa một lệnh phá vỡ giam giữ (Hướng dẫn Lịch sử Bài viết), hãy sử dụng thay vào đó",
635 "Prefer Character Card Jailbreak": "Ưu tiên Jailbreak từ Card",635 "Prefer Character Card Jailbreak": "Ưu tiên Jailbreak từ Card",
636 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Tránh cắt xén và thay đổi kích thước hình ảnh ký tự đã nhập. Khi tắt, hãy cắt/thay đổi kích thước thành 512x768.",636 "never_resize_avatars_tooltip": "Tránh cắt xén và thay đổi kích thước hình ảnh ký tự đã nhập. Khi tắt, hãy cắt/thay đổi kích thước thành 512x768.",
637 "Never resize avatars": "Không bao giờ thay đổi kích thước hình đại diện",637 "Never resize avatars": "Không bao giờ thay đổi kích thước hình đại diện",
638 "Show actual file names on the disk, in the characters list display only": "Hiển thị tên tệp thực tế trên đĩa, chỉ trong danh sách nhân vật",638 "Show actual file names on the disk, in the characters list display only": "Hiển thị tên tệp thực tế trên đĩa, chỉ trong danh sách nhân vật",
639 "Show avatar filenames": "Hiển thị tên tệp hình đại diện",639 "Show avatar filenames": "Hiển thị tên tệp hình đại diện",
@@ -709,7 +709,7 @@
709 "Auto-swipe": "Tự động vuốt",709 "Auto-swipe": "Tự động vuốt",
710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Bật chức năng tự động vuốt. Các cài đặt trong phần này chỉ có tác dụng khi tự động vuốt được bật",710 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "Bật chức năng tự động vuốt. Các cài đặt trong phần này chỉ có tác dụng khi tự động vuốt được bật",
711 "Minimum generated message length": "Độ dài tối thiểu của tin nhắn được tạo",711 "Minimum generated message length": "Độ dài tối thiểu của tin nhắn được tạo",
712 "If the generated message is shorter than this, trigger an auto-swipe": "Nếu tin nhắn được tạo ra ngắn hơn điều này, kích hoạt tự động vuốt",712 "If the generated message is shorter than these many characters, trigger an auto-swipe": "Nếu tin nhắn được tạo ra ngắn hơn điều này, kích hoạt tự động vuốt",
713 "Blacklisted words": "Từ trong danh sách đen",713 "Blacklisted words": "Từ trong danh sách đen",
714 "words you dont want generated separated by comma ','": "các từ bạn không muốn được tạo ra được phân tách bằng dấu phẩy ','",714 "words you dont want generated separated by comma ','": "các từ bạn không muốn được tạo ra được phân tách bằng dấu phẩy ','",
715 "Blacklisted word count to swipe": "Số từ trong danh sách đen để vuốt",715 "Blacklisted word count to swipe": "Số từ trong danh sách đen để vuốt",
public/locales/zh-cn.json+102 -41
@@ -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配置面板将保持打开",
@@ -203,6 +203,7 @@
203 "Ignore EOS Token": "忽略序列结束词符",203 "Ignore EOS Token": "忽略序列结束词符",
204 "Ignore the EOS Token even if it generates.": "即使生成了序列结束词符,也忽略它。",204 "Ignore the EOS Token even if it generates.": "即使生成了序列结束词符,也忽略它。",
205 "Skip Special Tokens": "跳过特殊词符",205 "Skip Special Tokens": "跳过特殊词符",
206 "Request Model Reasoning": "Request Model Reasoning",
206 "Temperature Last": "温度放最后",207 "Temperature Last": "温度放最后",
207 "Temperature_Last_desc": "温度采样器放到最后使用。这通常是合理的。\n当启用时:首先进行潜在词符的选择,然后应用温度来修正它们的相对概率(技术上是对数似然)。\n当禁用时:首先应用温度来修正所有词符的相对概率,然后从中选择潜在词符。\n禁用此项可以增大分布在尾部的词符概率,这可能加大得到不相关回复的几率。",208 "Temperature_Last_desc": "温度采样器放到最后使用。这通常是合理的。\n当启用时:首先进行潜在词符的选择,然后应用温度来修正它们的相对概率(技术上是对数似然)。\n当禁用时:首先应用温度来修正所有词符的相对概率,然后从中选择潜在词符。\n禁用此项可以增大分布在尾部的词符概率,这可能加大得到不相关回复的几率。",
208 "Speculative Ngram": "推测性 Ngram",209 "Speculative Ngram": "推测性 Ngram",
@@ -210,7 +211,9 @@
210 "Spaces Between Special Tokens": "特殊词符之间的空格",211 "Spaces Between Special Tokens": "特殊词符之间的空格",
211 "Seed_desc": "一个用于生成确定性和可复现的输出的随机种子。设置为 -1 时会使用随机种子。",212 "Seed_desc": "一个用于生成确定性和可复现的输出的随机种子。设置为 -1 时会使用随机种子。",
212 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",213 "LLaMA / Mistral / Yi models only": "LLaMA / Mistral / Yi模型专用。首先确保您选择了适当的词符化器。\n这项设置决定了你不想在结果中看到的字符串。\n每行一个字符串。可以是文本或者[词符id]。\n许多词符以空格开头。如果不确定,请使用词符计数器。",
214 "Global list": "Global list",
213 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",215 "Example: some text [42, 69, 1337]": "例如:\n一些文本\n[42, 69, 1337]",
216 "Preset-specific list": "Preset-specific list",
214 "CFG": "CFG",217 "CFG": "CFG",
215 "Classifier Free Guidance. More helpful tip coming soon": "无分类器指导(CFG)。更多有用的提示敬请期待。",218 "Classifier Free Guidance. More helpful tip coming soon": "无分类器指导(CFG)。更多有用的提示敬请期待。",
216 "Scale": "缩放比例",219 "Scale": "缩放比例",
@@ -255,11 +258,11 @@
255 "enable_functions_desc_1": "允许使用",258 "enable_functions_desc_1": "允许使用",
256 "enable_functions_desc_2": "功能工具",259 "enable_functions_desc_2": "功能工具",
257 "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。",260 "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。",
258 "Send inline images": "发送内联图像",261 "Send inline images": "发送图片",
259 "image_inlining_hint_1": "如果模型支持,则在提示词中发送图像(例如 GPT-4V、Claude 3 或 Llava 13B)。\n对任何消息使用",262 "image_inlining_hint_1": "如果模型支持,就可以在提示词中发送图片(例如 GPT-4V、Claude 3 或 Llava 13B)。\n发送消息时,点击",
260 "image_inlining_hint_2": "或",263 "image_inlining_hint_2": "在这里(",
261 "image_inlining_hint_3": "菜单将图像文件附加到聊天中。",264 "image_inlining_hint_3": ")将图片添加到消息中。",
262 "Inline Image Quality": "内联图像质量",265 "Inline Image Quality": "图片画质",
263 "openai_inline_image_quality_auto": "自动",266 "openai_inline_image_quality_auto": "自动",
264 "openai_inline_image_quality_low": "低",267 "openai_inline_image_quality_low": "低",
265 "openai_inline_image_quality_high": "高",268 "openai_inline_image_quality_high": "高",
@@ -268,6 +271,11 @@
268 "Merges_all_system_messages_desc_2": "字段发送。",271 "Merges_all_system_messages_desc_2": "字段发送。",
269 "Request model reasoning": "请求思维链",272 "Request model reasoning": "请求思维链",
270 "Allows the model to return its thinking process.": "允许模型返回其思维过程。",273 "Allows the model to return its thinking process.": "允许模型返回其思维过程。",
274 "Constrains effort on reasoning for reasoning models.": "限定模型推理的强度。\n当前支持低、中、高三种强度。\n降低推理强度可以让模型更快回复,并节省推理所用的词符数。。",
275 "Reasoning Effort": "推理强度",
276 "openai_reasoning_effort_low": "低",
277 "openai_reasoning_effort_medium": "中",
278 "openai_reasoning_effort_high": "高",
271 "Assistant Prefill": "AI预填",279 "Assistant Prefill": "AI预填",
272 "Expand the editor": "展开编辑器",280 "Expand the editor": "展开编辑器",
273 "Start Claude's answer with...": "以如下内容开始Claude的回答...",281 "Start Claude's answer with...": "以如下内容开始Claude的回答...",
@@ -328,7 +336,8 @@
328 "Click Authorize below or get the key from": "点击下方授权或从以下位置获取密钥",336 "Click Authorize below or get the key from": "点击下方授权或从以下位置获取密钥",
329 "View Remaining Credits": "查看剩余额度",337 "View Remaining Credits": "查看剩余额度",
330 "OpenRouter Model": "OpenRouter 模型",338 "OpenRouter Model": "OpenRouter 模型",
331 "Model Providers": "模型提供者",339 "Model Providers": "模型提供商",
340 "Automatically chooses an alternative provider if chosen providers can't serve your request.": "在当前选择的模型提供商无效时,自动选择备用的提供商。",
332 "Allow fallback providers": "允许后备提供者",341 "Allow fallback providers": "允许后备提供者",
333 "InfermaticAI API Key": "InfermaticAI API 密钥",342 "InfermaticAI API Key": "InfermaticAI API 密钥",
334 "InfermaticAI Model": "InfermaticAI 模型",343 "InfermaticAI Model": "InfermaticAI 模型",
@@ -374,7 +383,7 @@
374 "Use an admin API key.": "使用管理员API密钥。",383 "Use an admin API key.": "使用管理员API密钥。",
375 "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)",384 "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)",
376 "Example: 127.0.0.1:5001": "示例:127.0.0.1:5001",385 "Example: 127.0.0.1:5001": "示例:127.0.0.1:5001",
377 "Bypass status check": "绕过状态检查",386 "Bypass status check": "跳过状态检查",
378 "Derive context size from backend": "从后端获取上下文长度",387 "Derive context size from backend": "从后端获取上下文长度",
379 "Authorize": "授权",388 "Authorize": "授权",
380 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用OAuth流程获取您的OpenRouter API令牌。您将被重定向到openrouter.ai",389 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用OAuth流程获取您的OpenRouter API令牌。您将被重定向到openrouter.ai",
@@ -389,8 +398,8 @@
389 "This will show up as your saved preset.": "这将显示为您保存的预设。",398 "This will show up as your saved preset.": "这将显示为您保存的预设。",
390 "Proxy Server URL": "代理服务器 URL",399 "Proxy Server URL": "代理服务器 URL",
391 "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。",400 "Alternative server URL (leave empty to use the default value).": "备用服务器 URL(留空以使用默认值)。",
392 "Doesn't work? Try adding": "不起作用?尝试添加",401 "Doesn't work? Try adding": "不起作用?在末尾添加",
393 "at the end!": "!",402 "at the end!": "试试!",
394 "Proxy Password": "代理密码",403 "Proxy Password": "代理密码",
395 "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。",404 "Will be used as a password for the proxy instead of API key.": "将用作代理的密码,而不是 API 密钥。",
396 "Peek a password": "查看密码",405 "Peek a password": "查看密码",
@@ -411,6 +420,7 @@
411 "Anthropic's developer console": "Anthropic 开发者控制台",420 "Anthropic's developer console": "Anthropic 开发者控制台",
412 "Claude Model": "Claude 模型",421 "Claude Model": "Claude 模型",
413 "Window AI Model": "Window AI 模型",422 "Window AI Model": "Window AI 模型",
423 "Use extension settings": "使用扩展程序中的设定",
414 "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。",424 "Allow fallback routes Description": "如果所选模型无法响应您的请求,则自动选择备用模型。",
415 "Allow fallback models": "允许后备模型",425 "Allow fallback models": "允许后备模型",
416 "Model Order": "OpenRouter 模型顺序",426 "Model Order": "OpenRouter 模型顺序",
@@ -419,6 +429,7 @@
419 "Context Size": "上下文长度",429 "Context Size": "上下文长度",
420 "Group by vendors": "按厂商分组",430 "Group by vendors": "按厂商分组",
421 "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。",431 "Group by vendors Description": "将 OpenAI 模型放在一组,将 Anthropic 模型放在另一组,等等。可以与排序结合。",
432 "To use instruct formatting, switch to OpenRouter under Text Completion API.": "To use instruct formatting, switch to OpenRouter under Text Completion API.",
422 "Scale API Key": "Scale API密钥",433 "Scale API Key": "Scale API密钥",
423 "Clear your cookie": "清除你的 Cookie",434 "Clear your cookie": "清除你的 Cookie",
424 "Alt Method": "备用方法",435 "Alt Method": "备用方法",
@@ -442,7 +453,6 @@
442 "Select a Model": "选择一个模型",453 "Select a Model": "选择一个模型",
443 "Custom Endpoint (Base URL)": "自定义端点(基础 URL)",454 "Custom Endpoint (Base URL)": "自定义端点(基础 URL)",
444 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",455 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
445 "at the end of the URL!": "到 URL 的末尾!",
446 "Custom API Key": "自定义 API 密钥",456 "Custom API Key": "自定义 API 密钥",
447 "(Optional)": "(可选)",457 "(Optional)": "(可选)",
448 "Enter a Model ID": "输入模型名",458 "Enter a Model ID": "输入模型名",
@@ -466,9 +476,9 @@
466 "AI Response Formatting": "AI回复格式化",476 "AI Response Formatting": "AI回复格式化",
467 "Advanced Formatting": "高级格式化设置",477 "Advanced Formatting": "高级格式化设置",
468 "Import Advanced Formatting settings": "导入高级格式化设置\n\n对于指导和上下文模板,你也可以提供旧版文件。",478 "Import Advanced Formatting settings": "导入高级格式化设置\n\n对于指导和上下文模板,你也可以提供旧版文件。",
469 "Master Import": "Master Import",479 "Master Import": "全局导入",
470 "Export Advanced Formatting settings": "导出高级格式化设置",480 "Export Advanced Formatting settings": "导出高级格式化设置",
471 "Master Export": "Master Export",481 "Master Export": "全局导出",
472 "Context Template": "上下文模板",482 "Context Template": "上下文模板",
473 "context_derived": "若可能,从模型的元数据获取。",483 "context_derived": "若可能,从模型的元数据获取。",
474 "Select your current Context Template": "选择你当前的上下文模板",484 "Select your current Context Template": "选择你当前的上下文模板",
@@ -508,7 +518,7 @@
508 "Skip Example Dialogues Formatting": "跳过示例对话格式化",518 "Skip Example Dialogues Formatting": "跳过示例对话格式化",
509 "Include Names": "包括名称",519 "Include Names": "包括名称",
510 "Never": "永不",520 "Never": "永不",
511 "Groups and Past Personas": "Groups and Past Personas",521 "Groups and Past Personas": "群聊和过去的用户角色",
512 "Always": "永远",522 "Always": "永远",
513 "Instruct Sequences": "指令序列",523 "Instruct Sequences": "指令序列",
514 "User Message Sequences": "用户消息序列",524 "User Message Sequences": "用户消息序列",
@@ -561,6 +571,24 @@
561 "JSON serialized array of strings": "JSON序列化的字符串数组",571 "JSON serialized array of strings": "JSON序列化的字符串数组",
562 "Replace Macro in Stop Strings": "替换自定义停止字符串中的宏",572 "Replace Macro in Stop Strings": "替换自定义停止字符串中的宏",
563 "Token Padding": "词符填充",573 "Token Padding": "词符填充",
574 "Reasoning": "推理",
575 "reasoning_auto_parse": "Automatically parse reasoning blocks from main content between the reasoning prefix/suffix. Both fields must be defined and non-empty.",
576 "Auto-Parse": "自动解析",
577 "reasoning_auto_expand": "自动展开推理内容块。",
578 "Auto-Expand": "自动展开",
579 "reasoning_show_hidden": "对于隐藏推理内容的模型,展示其推理用时。",
580 "Show Hidden": "显示隐藏内容",
581 "reasoning_add_to_prompts": "将已有的推理块添加到提示词。若需新增一个推理块,请使用消息编辑菜单。",
582 "Add to Prompts": "添加到提示词",
583 "reasoning_max_additions": "Maximum number of reasoning blocks to be added per prompt, counting from the last message.",
584 "Max": "最大值",
585 "Reasoning Formatting": "推理内容格式化",
586 "reasoning_prefix": "插入在推理内容之前。",
587 "Prefix": "前缀",
588 "reasoning_suffix": "插入在推理内容之后。",
589 "Suffix": "后缀",
590 "reasoning_separator": "插入在推理内容和消息内容之间。",
591 "Separator": "分隔符",
564 "Miscellaneous": "杂项",592 "Miscellaneous": "杂项",
565 "Non-markdown strings": "非 Markdown 字符串",593 "Non-markdown strings": "非 Markdown 字符串",
566 "comma delimited,no spaces between": "以逗号分隔,无需空格",594 "comma delimited,no spaces between": "以逗号分隔,无需空格",
@@ -584,7 +612,7 @@
584 "(0 = unlimited, use budget)": "(“0”为无限制,使用预算)",612 "(0 = unlimited, use budget)": "(“0”为无限制,使用预算)",
585 "Cap the number of entry activation recursions": "限制条目激活递归的次数",613 "Cap the number of entry activation recursions": "限制条目激活递归的次数",
586 "Max Recursion Steps": "最大递归深度",614 "Max Recursion Steps": "最大递归深度",
587 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\\n(disabled when min activations are used)": "“0”为无限制,“1”为扫描一次且不递归,“2”为扫描一次且递归一次,依此类推\n(当使用最小激活次数时,此功能被禁用)",615 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "“0”为无限制,“1”为扫描一次且不递归,“2”为扫描一次且递归一次,依此类推\n(当使用最小激活次数时,此功能被禁用)",
588 "Insertion Strategy": "插入策略",616 "Insertion Strategy": "插入策略",
589 "Sorted Evenly": "均匀排序",617 "Sorted Evenly": "均匀排序",
590 "Character Lore First": "角色世界书优先",618 "Character Lore First": "角色世界书优先",
@@ -639,7 +667,7 @@
639 "Delete a theme": "删除主题",667 "Delete a theme": "删除主题",
640 "Update a theme file": "更新主题文件",668 "Update a theme file": "更新主题文件",
641 "Save as a new theme": "另存为新主题",669 "Save as a new theme": "另存为新主题",
642 "Avatar Style": "头像样式",670 "Avatar Style:": "头像样式:",
643 "Circle": "圆形",671 "Circle": "圆形",
644 "Square": "正方形",672 "Square": "正方形",
645 "Rectangle": "矩形",673 "Rectangle": "矩形",
@@ -713,16 +741,16 @@
713 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定义在导入卡片时应选择哪种操作来导入其列出的标签。“询问”将始终显示对话框。",741 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定义在导入卡片时应选择哪种操作来导入其列出的标签。“询问”将始终显示对话框。",
714 "Import Card Tags": "导入卡片标签",742 "Import Card Tags": "导入卡片标签",
715 "Ask": "询问",743 "Ask": "询问",
716 "tag_import_none": "无",744 "tag_import_none": "不导入",
717 "tag_import_all": "全部",745 "tag_import_all": "导入全部",
718 "Existing": "现存的",746 "tag_import_existing": "仅导入现有的",
719 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊匹配,在列表中通过所有数据字段搜索角色,而不仅仅是名称子字符串",747 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊匹配,在列表中通过所有数据字段搜索角色,而不仅仅是名称子字符串",
720 "Advanced Character Search": "高级角色搜索",748 "Advanced Character Search": "高级角色搜索",
721 "If checked and the character card contains a prompt override (System Prompt), use that instead": "开启后,如果角色卡已包含系统提示词,则覆盖当前的系统提示词。",749 "If checked and the character card contains a prompt override (System Prompt), use that instead": "开启后,如果角色卡已包含系统提示词,则覆盖当前的系统提示词。",
722 "Prefer Character Card Prompt": "角色卡提示词优先",750 "Prefer Character Card Prompt": "角色卡提示词优先",
723 "If checked and the character card contains a Post-History Instructions override, use that instead": "开启后,如果角色卡包含后历史指令覆盖,则使用它。",751 "If checked and the character card contains a Post-History Instructions override, use that instead": "开启后,如果角色卡包含后历史指令覆盖,则使用它。",
724 "Prefer Character Card Instructions": "首选角色卡说明",752 "Prefer Character Card Instructions": "首选角色卡说明",
725 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。",753 "never_resize_avatars_tooltip": "避免裁剪和调整导入的角色图像的大小。关闭时,裁剪/调整大小为 512x768。",
726 "Never resize avatars": "永不调整头像大小",754 "Never resize avatars": "永不调整头像大小",
727 "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。",755 "Show actual file names on the disk, in the characters list display only": "在角色列表显示中,显示磁盘上实际的文件名。",
728 "Show avatar filenames": "显示头像文件名",756 "Show avatar filenames": "显示头像文件名",
@@ -751,7 +779,7 @@
751 "Restore User Input": "恢复用户输入",779 "Restore User Input": "恢复用户输入",
752 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允许通过拖动重新定位某些UI元素。仅适用于PC,对移动设备无影响",780 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允许通过拖动重新定位某些UI元素。仅适用于PC,对移动设备无影响",
753 "Movable UI Panels": "可移动 UI 面板",781 "Movable UI Panels": "可移动 UI 面板",
754 "Reset MovingUI panel sizes/locations.": "重置 MovingUI 面板大小/位置。",782 "Reset MovingUI panel sizes/locations.": "重置 可移动UI 面板大小/位置。",
755 "mui_reset": "Reset",783 "mui_reset": "Reset",
756 "MovingUI preset. Predefined/saved draggable positions": "可移动UI预设。预定义/保存的可拖动位置",784 "MovingUI preset. Predefined/saved draggable positions": "可移动UI预设。预定义/保存的可拖动位置",
757 "MUI Preset": "可移动 UI 预设",785 "MUI Preset": "可移动 UI 预设",
@@ -759,7 +787,7 @@
759 "Apply a custom CSS style to all of the ST GUI": "将自定义CSS样式应用于所有ST GUI",787 "Apply a custom CSS style to all of the ST GUI": "将自定义CSS样式应用于所有ST GUI",
760 "Custom CSS": "自定义 CSS",788 "Custom CSS": "自定义 CSS",
761 "Chat/Message Handling": "聊天/消息处理",789 "Chat/Message Handling": "聊天/消息处理",
762 "# Messages to Load": "# 要加载的消息",790 "# Messages to Load": "要加载 # 条消息",
763 "The number of chat history messages to load before pagination.": "分页前要加载的聊天历史消息数。",791 "The number of chat history messages to load before pagination.": "分页前要加载的聊天历史消息数。",
764 "(0 = All)": "(“0”为全部)",792 "(0 = All)": "(“0”为全部)",
765 "Streaming FPS": "流式传输帧速率",793 "Streaming FPS": "流式传输帧速率",
@@ -804,11 +832,12 @@
804 "Auto-swipe": "自动滑动",832 "Auto-swipe": "自动滑动",
805 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效",833 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "启用自动滑动功能。仅当启用自动滑动时,本节中的设置才会生效",
806 "Minimum generated message length": "生成的消息的最小长度",834 "Minimum generated message length": "生成的消息的最小长度",
807 "If the generated message is shorter than this, trigger an auto-swipe": "如果生成的消息短于此长度,则触发自动滑动",835 "If the generated message is shorter than these many characters, trigger an auto-swipe": "如果生成的消息短于此长度,则触发自动滑动",
808 "Blacklisted words": "屏蔽词",836 "Blacklisted words": "屏蔽词",
809 "words you dont want generated separated by comma ','": "不想生成的词语,用半角逗号“,”分隔",837 "words you dont want generated separated by comma ','": "不想生成的词语,用半角逗号“,”分隔",
810 "Blacklisted word count to swipe": "触发滑动的黑名单词语数量",838 "Blacklisted word count to swipe": "触发滑动的黑名单词语数量",
811 "Minimum number of blacklisted words detected to trigger an auto-swipe": "触发自动滑动刷新回复所需检测到的最少违禁词数量。",839 "Minimum number of blacklisted words detected to trigger an auto-swipe": "触发自动滑动刷新回复所需检测到的最少违禁词数量。",
840 "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "当回复没有达到特定词符数时,自动让模型“继续”这个回复。",
812 "Auto-Continue": "自动继续",841 "Auto-Continue": "自动继续",
813 "Allow for Chat Completion APIs": "允许使用聊天补全API",842 "Allow for Chat Completion APIs": "允许使用聊天补全API",
814 "Target length (tokens)": "目标长度(以词符数计)",843 "Target length (tokens)": "目标长度(以词符数计)",
@@ -843,12 +872,12 @@
843 "Change Background Image": "更改背景图片",872 "Change Background Image": "更改背景图片",
844 "Background Image": "背景图片",873 "Background Image": "背景图片",
845 "Filter": "搜索",874 "Filter": "搜索",
846 "Background Fitting": "Background Fitting",875 "Background Fitting": "背景图片尺寸",
847 "Classic": "Classic",876 "Classic": "经典",
848 "Cover": "Cover",877 "Cover": "填充",
849 "Contain": "Contain",878 "Contain": "不变换",
850 "Stretch": "Stretch",879 "Stretch": "拉伸",
851 "Center": "Center",880 "Center": "居中",
852 "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景",881 "Automatically select a background based on the chat context": "根据聊天上下文自动选择背景",
853 "Auto-select": "自动选择",882 "Auto-select": "自动选择",
854 "System Backgrounds": "系统背景",883 "System Backgrounds": "系统背景",
@@ -930,6 +959,7 @@
930 "Search / Create Tags": "搜索/创建标签",959 "Search / Create Tags": "搜索/创建标签",
931 "View all tags": "查看所有标签",960 "View all tags": "查看所有标签",
932 "Creator's Notes": "创作者的注释",961 "Creator's Notes": "创作者的注释",
962 "Character details are hidden.": "角色详情已隐藏。",
933 "Show / Hide Description and First Message": "显示/隐藏描述和第一条消息",963 "Show / Hide Description and First Message": "显示/隐藏描述和第一条消息",
934 "Character Description": "角色描述",964 "Character Description": "角色描述",
935 "Click to allow/forbid the use of external media for this character.": "单击以允许/禁止此角色使用外部媒体。",965 "Click to allow/forbid the use of external media for this character.": "单击以允许/禁止此角色使用外部媒体。",
@@ -1054,6 +1084,7 @@
1054 "Drag to reorder tag": "拖动以排序",1084 "Drag to reorder tag": "拖动以排序",
1055 "Use tag as folder": "标记为文件夹",1085 "Use tag as folder": "标记为文件夹",
1056 "Delete tag": "删除标签",1086 "Delete tag": "删除标签",
1087 "Toggle entry's active state.": "切换条目激活状态。",
1057 "Entry Title/Memo": "条目标题/备忘录",1088 "Entry Title/Memo": "条目标题/备忘录",
1058 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界书条目状态:\r🔵 永久\r🟢 关键词\r🔗 向量化",1089 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界书条目状态:\r🔵 永久\r🟢 关键词\r🔗 向量化",
1059 "WI_Entry_Status_Constant": "永久",1090 "WI_Entry_Status_Constant": "永久",
@@ -1072,7 +1103,7 @@
1072 "Depth": "深度",1103 "Depth": "深度",
1073 "Order:": "顺序:",1104 "Order:": "顺序:",
1074 "Order": "顺序",1105 "Order": "顺序",
1075 "Trigger %:": "触发 %:",1106 "Trigger %:": "触发 %:",
1076 "Duplicate world info entry": "重复的世界信息条目",1107 "Duplicate world info entry": "重复的世界信息条目",
1077 "Delete world info entry": "删除世界信息条目",1108 "Delete world info entry": "删除世界信息条目",
1078 "Comma separated (required)": "逗号分隔(必填)",1109 "Comma separated (required)": "逗号分隔(必填)",
@@ -1154,7 +1185,7 @@
1154 "Message Actions": "消息操作",1185 "Message Actions": "消息操作",
1155 "Translate message": "翻译消息",1186 "Translate message": "翻译消息",
1156 "Generate Image": "生成图片",1187 "Generate Image": "生成图片",
1157 "Narrate": "叙述",1188 "Narrate": "朗读",
1158 "Exclude message from prompts": "从提示词中排除消息",1189 "Exclude message from prompts": "从提示词中排除消息",
1159 "Include message in prompts": "将消息包含在提示词中",1190 "Include message in prompts": "将消息包含在提示词中",
1160 "Embed file or image": "嵌入文件或图像",1191 "Embed file or image": "嵌入文件或图像",
@@ -1165,9 +1196,16 @@
1165 "Edit": "编辑",1196 "Edit": "编辑",
1166 "Confirm": "确认",1197 "Confirm": "确认",
1167 "Copy this message": "复制此消息",1198 "Copy this message": "复制此消息",
1199 "Add a reasoning block": "添加一个推理块",
1168 "Delete this message": "删除此消息",1200 "Delete this message": "删除此消息",
1169 "Move message up": "将消息上移",1201 "Move message up": "将消息上移",
1170 "Move message down": "将消息下移",1202 "Move message down": "将消息下移",
1203 "Thought for some time": "思考了一会",
1204 "Confirm Edit": "确认",
1205 "Remove reasoning": "删除推理内容",
1206 "Cancel edit": "Cancel edit",
1207 "Copy reasoning": "复制推理内容",
1208 "Edit reasoning": "编辑推理内容",
1171 "Enlarge": "放大",1209 "Enlarge": "放大",
1172 "Caption": "标题",1210 "Caption": "标题",
1173 "Swipe left": "Swipe left",1211 "Swipe left": "Swipe left",
@@ -1266,6 +1304,10 @@
1266 "Regenerate": "重新生成",1304 "Regenerate": "重新生成",
1267 "Impersonate": "AI 帮答",1305 "Impersonate": "AI 帮答",
1268 "Continue": "继续",1306 "Continue": "继续",
1307 "extension_install_1": "若想从此页安装扩展程序,你需要提前安装",
1308 "extension_install_2": "。",
1309 "extension_install_3": "点这个图标(",
1310 "extension_install_4": ")前往扩展程序的代码仓库以了解如何使用它。",
1269 "These characters are the winners of character design contests and have outstandable quality.": "这些角色都是角色设计大赛的获奖者,品质非常出色。",1311 "These characters are the winners of character design contests and have outstandable quality.": "这些角色都是角色设计大赛的获奖者,品质非常出色。",
1270 "Contest Winners": "比赛获胜者",1312 "Contest Winners": "比赛获胜者",
1271 "These characters are the finalists of character design contests and have remarkable quality.": "这些角色都是角色设计大赛的入围作品,品质十分出色。",1313 "These characters are the finalists of character design contests and have remarkable quality.": "这些角色都是角色设计大赛的入围作品,品质十分出色。",
@@ -1334,9 +1376,11 @@
1334 "macro)": "宏指令)",1376 "macro)": "宏指令)",
1335 "Automatically caption images": "自动为图像添加标题",1377 "Automatically caption images": "自动为图像添加标题",
1336 "Edit captions before saving": "保存前编辑标题",1378 "Edit captions before saving": "保存前编辑标题",
1379 "Included settings:": "包含的设置:",
1380 "{{@key}}": "{{@key}}:",
1337 "Profile name:": "配置名称:",1381 "Profile name:": "配置名称:",
1338 "Creating a Connection Profile": "新建API连接配置",1382 "Creating a Connection Profile": "新建API连接配置",
1339 "{{@key}}": "{{@key}}:",1383 "Click on the setting name to omit it from the profile.": "点击设置名称以将其从连接配置中删除。",
1340 "Enter a name:": "输入名字:",1384 "Enter a name:": "输入名字:",
1341 "Connection Profile": "API连接配置",1385 "Connection Profile": "API连接配置",
1342 "View connection profile details": "查看API连接配置详情",1386 "View connection profile details": "查看API连接配置详情",
@@ -1345,14 +1389,17 @@
1345 "Edit a connection profile": "编辑API连接配置",1389 "Edit a connection profile": "编辑API连接配置",
1346 "Reload a connection profile": "重载API连接配置",1390 "Reload a connection profile": "重载API连接配置",
1347 "Delete a connection profile": "删除API连接配置",1391 "Delete a connection profile": "删除API连接配置",
1348 "Omitted Settings:": "Omitted Settings:",1392 "Omitted Settings:": "排除的设置:",
1349 "Character Expressions": "角色表情",1393 "Character Expressions": "角色表情",
1394 "Use the selected API from Chat Translation extension settings.": "使用聊天翻译扩展程序中已选择的API。",
1350 "Translate text to English before classification": "分类之前将文本翻译成英文",1395 "Translate text to English before classification": "分类之前将文本翻译成英文",
1351 "Show default images (emojis) if sprite missing": "如果表情包缺失,则显示默认图像(表情符号)",1396 "A single expression can have multiple sprites. Whenever the expression is chosen, a random sprite for this expression will be selected.": "A single expression can have multiple sprites. Whenever the expression is chosen, a random sprite for this expression will be selected.",
1352 "Image Type - talkinghead (extras)": "图像类型 - 说话头像(附加内容)",1397 "Allow multiple sprites per expression": "Allow multiple sprites per expression",
1398 "If the same expression is used again, re-roll the sprite. This only applies to expressions that have multiple available sprites assigned.": "If the same expression is used again, re-roll the sprite. This only applies to expressions that have multiple available sprites assigned.",
1399 "Re-roll if same expression is used again": "Re-roll if same sprite is used again",
1353 "Classifier API": "分类器 API",1400 "Classifier API": "分类器 API",
1354 "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。",1401 "Select the API for classifying expressions.": "选择用于对表达式进行分类的API。",
1355 "Main API": "主要 API",1402 "Main API": "当前连接的 API",
1356 "WebLLM Extension": "WebLLM Extension",1403 "WebLLM Extension": "WebLLM Extension",
1357 "LLM Prompt": "大语言模型提示词",1404 "LLM Prompt": "大语言模型提示词",
1358 "Will be used if the API doesn't support JSON schemas or function calling.": "如果 API 不支持 JSON 模式或函数调用,则会使用它。",1405 "Will be used if the API doesn't support JSON schemas or function calling.": "如果 API 不支持 JSON 模式或函数调用,则会使用它。",
@@ -1372,6 +1419,10 @@
1372 "Put images with expressions there. File names should follow the pattern:": "将带有表情的图像放在那里。文件名应遵循以下模式:",1419 "Put images with expressions there. File names should follow the pattern:": "将带有表情的图像放在那里。文件名应遵循以下模式:",
1373 "expression_label_pattern": "[表达式标签].[图像格式]",1420 "expression_label_pattern": "[表达式标签].[图像格式]",
1374 "Sprite set:": "表情集:",1421 "Sprite set:": "表情集:",
1422 "upload_expression_request": "请输入表情名称(不用加后缀)。",
1423 "upload_expression_naming_1": "素材名称必须符合所选表情 {{expression}} 的命名规范",
1424 "upload_expression_naming_2": "当存在多个表情时,名称应由表情名称与合法后缀构成,允许使用横杠'-'或英文句号'.'作为分隔符。",
1425 "upload_expression_replace": "点击“替换”以替换当前表情:",
1375 "Show Gallery": "展示图库",1426 "Show Gallery": "展示图库",
1376 "ext_sum_title": "总结",1427 "ext_sum_title": "总结",
1377 "ext_sum_with": "总结如下:",1428 "ext_sum_with": "总结如下:",
@@ -1494,6 +1545,7 @@
1494 "ext_regex_slash_desc": "通过 STscript 命令发送的消息。",1545 "ext_regex_slash_desc": "通过 STscript 命令发送的消息。",
1495 "Slash Commands": "快捷命令",1546 "Slash Commands": "快捷命令",
1496 "ext_regex_wi_desc": "知识书/世界书 条目的内容。需要勾选“仅格式提示词”!",1547 "ext_regex_wi_desc": "知识书/世界书 条目的内容。需要勾选“仅格式提示词”!",
1548 "ext_regex_reasoning_desc": "推理块内容。当'仅格式提示词'被选中时,它会影响提示词里的推理内容。",
1497 "ext_regex_min_depth_desc": "当应用于提示或显示时,仅影响深度至少为 N 级的消息。“0”为最后一条消息,“1”为倒数第二条消息等。仅计算 WI 条目 @Depth 和可用消息,即非隐藏或系统消息。",1549 "ext_regex_min_depth_desc": "当应用于提示或显示时,仅影响深度至少为 N 级的消息。“0”为最后一条消息,“1”为倒数第二条消息等。仅计算 WI 条目 @Depth 和可用消息,即非隐藏或系统消息。",
1498 "Min Depth": "最小深度",1550 "Min Depth": "最小深度",
1499 "ext_regex_min_depth_placeholder": "无限",1551 "ext_regex_min_depth_placeholder": "无限",
@@ -1621,6 +1673,13 @@
1621 "Interactive Mode": "交互模式",1673 "Interactive Mode": "交互模式",
1622 "Function Tool": "Function Tool",1674 "Function Tool": "Function Tool",
1623 "Image Prompt Templates": "图像提示模板",1675 "Image Prompt Templates": "图像提示模板",
1676 "Token Counter": "词符计数器",
1677 "Type / paste in the box below to see the number of tokens in the text.": "在下方框中输入或粘贴你想要统计词符数量的文本。",
1678 "Selected tokenizer:": "已选分词器:",
1679 "Input:": "输入:",
1680 "Tokens:": "词符:",
1681 "Tokenized text:": "词符化文本:",
1682 "Token IDs:": "词符ID:",
1624 "ext_translate_btn_chat": "翻译聊天",1683 "ext_translate_btn_chat": "翻译聊天",
1625 "ext_translate_btn_input": "翻译输入",1684 "ext_translate_btn_input": "翻译输入",
1626 "ext_translate_delete_confirm_1": "你确定吗?",1685 "ext_translate_delete_confirm_1": "你确定吗?",
@@ -1640,11 +1699,12 @@
1640 "Auto Generation": "自动生成",1699 "Auto Generation": "自动生成",
1641 "Requires auto generation to be enabled.": "需要启用自动生成功能。",1700 "Requires auto generation to be enabled.": "需要启用自动生成功能。",
1642 "Narrate by paragraphs (when streaming)": "按段朗读(流式播放时)",1701 "Narrate by paragraphs (when streaming)": "按段朗读(流式播放时)",
1702 "Narrate by paragraphs (when not streaming)": "按段朗读(非流式播放时)",
1643 "Only narrate quotes": "只朗读引号内文本",1703 "Only narrate quotes": "只朗读引号内文本",
1644 "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹",1704 "Ignore text, even quotes, inside asterisk": "不朗读所有*星号内文本*,即使其被引号包裹",
1645 "Narrate only the translated text": "只朗读翻译后文本",1705 "Narrate only the translated text": "只朗读翻译后文本",
1646 "Skip codeblocks": "跳过代码块",1706 "Skip codeblocks": "跳过代码块",
1647 "Skip tagged blocks": "跳过标签化的块(<tagged>)",1707 "Skip tagged blocks": "跳过标签块里的内容(<标签>跳过这里</标签>)",
1648 "Pass Asterisks to TTS Engine": "将星号传递给文本转语音服务",1708 "Pass Asterisks to TTS Engine": "将星号传递给文本转语音服务",
1649 "Audio Playback Speed": "音频播放速度",1709 "Audio Playback Speed": "音频播放速度",
1650 "Vector Storage": "向量存储",1710 "Vector Storage": "向量存储",
@@ -1666,6 +1726,7 @@
1666 "Max Entries": "最大条目数",1726 "Max Entries": "最大条目数",
1667 "File vectorization settings": "文件向量化设置",1727 "File vectorization settings": "文件向量化设置",
1668 "Enable for files": "为文件启用",1728 "Enable for files": "为文件启用",
1729 "Only chunk on custom boundary": "仅按自定义边界分块",
1669 "Translate files into English before processing": "处理之前将文件翻译成英文",1730 "Translate files into English before processing": "处理之前将文件翻译成英文",
1670 "Message attachments": "消息附件",1731 "Message attachments": "消息附件",
1671 "Size threshold (KB)": "大小阈值(KB)",1732 "Size threshold (KB)": "大小阈值(KB)",
@@ -1855,7 +1916,6 @@
1855 "Total Tokens in Prompt:": "提示词的总Token数量:",1916 "Total Tokens in Prompt:": "提示词的总Token数量:",
1856 "Max Context": "最大上下文:",1917 "Max Context": "最大上下文:",
1857 "(Context Size - Response Length)": "(上下文长度 - 回复长度)",1918 "(Context Size - Response Length)": "(上下文长度 - 回复长度)",
1858 ":": ":",
1859 "System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):",1919 "System-wide Replacement Macros (in order of evaluation):": "系统范围的替换宏(按评估顺序):",
1860 "help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。",1920 "help_macros_1": "仅适用于斜线命令批处理。替换为上一个命令的返回结果。",
1861 "help_macros_2": "仅插入一个换行符。",1921 "help_macros_2": "仅插入一个换行符。",
@@ -1873,18 +1933,19 @@
1873 "help_macros_14": "未格式化的对话示例",1933 "help_macros_14": "未格式化的对话示例",
1874 "(only for Story String)": "(仅适用于故事字符串)",1934 "(only for Story String)": "(仅适用于故事字符串)",
1875 "help_macros_summary": "“Summarize”扩展生成的最新聊天摘要(如果有)。",1935 "help_macros_summary": "“Summarize”扩展生成的最新聊天摘要(如果有)。",
1876 "help_macros_15": "您当前的 Persona 用户名",1936 "help_macros_15": "您当前的用户角色名称",
1877 "help_macros_16": "角色的名字",1937 "help_macros_16": "角色的名字",
1878 "help_macros_17": "角色的版本号",1938 "help_macros_17": "角色的版本号",
1879 "help_macros_18": "以逗号分隔的群成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}",1939 "help_macros_18": "以逗号分隔的群成员名称列表或单人聊天中的角色名称。别名:{{charIfNotGroup}}",
1880 "help_groupNotMuted": "与 {{group}} 相同,但排除被禁言的成员",1940 "help_groupNotMuted": "与 {{group}} 相同,但排除被禁言的成员",
1881 "help_macros_19": "当前选定的 API 的文本生成模型名称。",1941 "help_macros_19": "当前选定的 API 的文本生成模型名称。",
1882 "Can be inaccurate!": "可能不准确!",1942 "Can be inaccurate!": "不一定准确!",
1883 "help_macros_20": "最新聊天消息的文本。",1943 "help_macros_20": "最新聊天消息的文本。",
1884 "help_macros_lastUser": "最后的用户聊天消息文本。",1944 "help_macros_lastUser": "最后的用户聊天消息文本。",
1885 "help_macros_lastChar": "最后的角色聊天消息文本。",1945 "help_macros_lastChar": "最后的角色聊天消息文本。",
1886 "help_macros_21": "最新聊天消息的索引号。对于斜线命令批处理很有用。",1946 "help_macros_21": "最新聊天消息的索引号。对于斜线命令批处理很有用。",
1887 "help_macros_22": "上下文中包含的第一条消息的 ID。要求在当前会话中至少运行一次生成。",1947 "help_macros_22": "上下文中包含的第一条消息的 ID。要求在当前会话中至少运行一次生成。",
1948 "help_macros_firstDisplayedMessageId": "第一条载入可见聊天的消息的ID",
1888 "help_macros_23": "最后一条聊天消息中当前滑动的 ID(以 1 为基数)。如果最后一条消息是用户或提示隐藏的,则为空字符串。",1949 "help_macros_23": "最后一条聊天消息中当前滑动的 ID(以 1 为基数)。如果最后一条消息是用户或提示隐藏的,则为空字符串。",
1889 "help_macros_24": "最后一条聊天消息中的滑动次数。如果最后一条消息是用户隐藏或提示隐藏的,则为空字符串。",1950 "help_macros_24": "最后一条聊天消息中的滑动次数。如果最后一条消息是用户隐藏或提示隐藏的,则为空字符串。",
1890 "help_macros_reverse": "反转宏的内容。",1951 "help_macros_reverse": "反转宏的内容。",
@@ -2041,7 +2102,7 @@
2041 "in the chat bar": "至聊天框",2102 "in the chat bar": "至聊天框",
2042 "SillyTavern Documentation Site": "访问 SillyTavern 帮助文档",2103 "SillyTavern Documentation Site": "访问 SillyTavern 帮助文档",
2043 "Still have questions?": "仍有疑问?",2104 "Still have questions?": "仍有疑问?",
2044 "Join the SillyTavern Discord": "加入 SillyTavern Discord群组",2105 "Join the SillyTavern Discord": "加入 SillyTavern 的 Discord群组",
2045 "Post a GitHub issue": "在 GitHub 发布问题",2106 "Post a GitHub issue": "在 GitHub 发布问题",
2046 "Contact the developers": "联系开发者",2107 "Contact the developers": "联系开发者",
2047 "If you're connected to an API, try asking me something!": "若您已经配置好API,尝试发送些什么吧!",2108 "If you're connected to an API, try asking me something!": "若您已经配置好API,尝试发送些什么吧!",
public/locales/zh-tw.json+504 -333
@@ -4,23 +4,23 @@
4 "Duplicate": "複製",4 "Duplicate": "複製",
5 "Persona": "使用者角色",5 "Persona": "使用者角色",
6 "Delete": "刪除",6 "Delete": "刪除",
7 "AI Response Configuration": "設定 AI 回應",7 "AI Response Configuration": "AI 回應設定",
8 "AI Configuration panel will stay open": "上鎖 = AI 設定面板將保持開啟",8 "AI Configuration panel will stay open": "上鎖 = AI 設定面板將保持開啟",
9 "clickslidertips": "點選滑桿數字可手動輸入。",9 "clickslidertips": "點選滑桿旁的數字以手動輸入。",
10 "MAD LAB MODE ON": "瘋狂實驗室模式",10 "MAD LAB MODE ON": "瘋狂實驗室模式",
11 "Documentation on sampling parameters": "取樣參數的說明文件。",11 "Documentation on sampling parameters": "取樣參數的說明文件。",
12 "kobldpresets": "Kobold 預設設定檔",12 "kobldpresets": "Kobold 預設設定檔",
13 "guikoboldaisettings": "GUI KoboldAI 設定",13 "guikoboldaisettings": "GUI KoboldAI 設定",
14 "Update current preset": "更新預設",14 "Update current preset": "更新預設設定檔",
15 "Save preset as": "另存新預設",15 "Save preset as": "另存新預設設定檔",
16 "Import preset": "匯入預設",16 "Import preset": "匯入預設設定檔",
17 "Export preset": "匯出預設設定檔",17 "Export preset": "匯出預設設定檔",
18 "Restore current preset": "還原目前預設",18 "Restore current preset": "還原目前預設設定檔",
19 "Delete the preset": "刪除預設",19 "Delete the preset": "刪除預設設定檔",
20 "novelaipresets": "NovelAI 預設設定檔",20 "novelaipresets": "NovelAI 預設設定檔",
21 "Default": "預設",21 "Default": "預設",
22 "openaipresets": "OpenAI 預設設定檔",22 "openaipresets": "OpenAI 預設設定檔",
23 "Text Completion presets": "文本補全預設",23 "Text Completion presets": "文字補全預設設定檔",
24 "AI Module": "AI 模組",24 "AI Module": "AI 模組",
25 "Changes the style of the generated text.": "變更生成文字的樣式。",25 "Changes the style of the generated text.": "變更生成文字的樣式。",
26 "No Module": "無模組",26 "No Module": "無模組",
@@ -35,7 +35,7 @@
35 "Only enable this if your model supports context sizes greater than 8192 tokens": "僅在您的模型支援超過 8192 個符元的上下文長度時啟用此功能",35 "Only enable this if your model supports context sizes greater than 8192 tokens": "僅在您的模型支援超過 8192 個符元的上下文長度時啟用此功能",
36 "Max prompt cost:": "最大提示詞費用:",36 "Max prompt cost:": "最大提示詞費用:",
37 "Display the response bit by bit as it is generated.": "逐字顯示生成中的回應內容。",37 "Display the response bit by bit as it is generated.": "逐字顯示生成中的回應內容。",
38 "When this is off, responses will be displayed all at once when they are complete.": "關閉時,回應將在生成完成後一次性顯示。",38 "When this is off, responses will be displayed all at once when they are complete.": "關閉時,回應將在生成完成後一次全部顯示。",
39 "Temperature": "溫度",39 "Temperature": "溫度",
40 "rep.pen": "重複懲罰",40 "rep.pen": "重複懲罰",
41 "Rep. Pen. Range.": "重複懲罰範圍",41 "Rep. Pen. Range.": "重複懲罰範圍",
@@ -51,7 +51,7 @@
51 "Aggressive": "積極",51 "Aggressive": "積極",
52 "Very aggressive": "非常積極",52 "Very aggressive": "非常積極",
53 "Unlocked Context Size": "解鎖上下文長度",53 "Unlocked Context Size": "解鎖上下文長度",
54 "Unrestricted maximum value for the context slider": "不限制上下文滑桿最大值",54 "Unrestricted maximum value for the context slider": "不限制上下文長度的最大值",
55 "Context Size (tokens)": "上下文長度(符元數)",55 "Context Size (tokens)": "上下文長度(符元數)",
56 "Max Response Length (tokens)": "最大回應長度(符元數)",56 "Max Response Length (tokens)": "最大回應長度(符元數)",
57 "Multiple swipes per generation": "每次生成多次滑動",57 "Multiple swipes per generation": "每次生成多次滑動",
@@ -71,7 +71,7 @@
71 "Utility Prompts": "實用提示詞",71 "Utility Prompts": "實用提示詞",
72 "Impersonation prompt": "AI 扮演提示詞",72 "Impersonation prompt": "AI 扮演提示詞",
73 "Restore default prompt": "還原預設提示詞",73 "Restore default prompt": "還原預設提示詞",
74 "Prompt that is used for Impersonation function": "用於 AI 模仿功能的提示詞",74 "Prompt that is used for Impersonation function": "用於「AI 扮演使用者」功能的提示詞",
75 "World Info Format Template": "世界資訊格式",75 "World Info Format Template": "世界資訊格式",
76 "Restore default format": "還原預設格式",76 "Restore default format": "還原預設格式",
77 "Wraps activated World Info entries before inserting into the prompt.": "在插入提示詞前包裝已啟用的世界資訊條目。",77 "Wraps activated World Info entries before inserting into the prompt.": "在插入提示詞前包裝已啟用的世界資訊條目。",
@@ -79,8 +79,8 @@
79 "scenario_format_template_part_2": "來標示要插入內容的位置。",79 "scenario_format_template_part_2": "來標示要插入內容的位置。",
80 "Scenario Format Template": "場景格式",80 "Scenario Format Template": "場景格式",
81 "Personality Format Template": "個性格式",81 "Personality Format Template": "個性格式",
82 "Group Nudge Prompt Template": "群組推動提示詞範本",82 "Group Nudge Prompt Template": "群組聊天格式微調",
83 "Sent at the end of the group chat history to force reply from a specific character.": "在群組聊天歷史結束時發送以強制特定角色回覆",83 "Sent at the end of the group chat history to force reply from a specific character.": "在群組聊天歷史結束時傳送以強制特定角色回覆",
84 "New Chat": "新聊天",84 "New Chat": "新聊天",
85 "Restore new chat prompt": "還原新聊天的提示詞",85 "Restore new chat prompt": "還原新聊天的提示詞",
86 "Set at the beginning of the chat history to indicate that a new chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的聊天",86 "Set at the beginning of the chat history to indicate that a new chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的聊天",
@@ -89,17 +89,17 @@
89 "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的群組聊天",89 "Set at the beginning of the chat history to indicate that a new group chat is about to start.": "設定在聊天歷史的開頭以表明即將開始新的群組聊天",
90 "New Example Chat": "新範例聊天",90 "New Example Chat": "新範例聊天",
91 "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "設定在對話範例的開頭以表明即將開始新的範例聊天",91 "Set at the beginning of Dialogue examples to indicate that a new example chat is about to start.": "設定在對話範例的開頭以表明即將開始新的範例聊天",
92 "Continue nudge": "繼續輔助提示詞",92 "Continue nudge": "繼續輔助微調",
93 "Set at the end of the chat history when the continue button is pressed.": "按下繼續按鈕時設定在聊天歷史的末尾",93 "Set at the end of the chat history when the continue button is pressed.": "按下「繼續」按鈕時,插入於聊天歷史的結尾",
94 "Replace empty message": "取代空白訊息",94 "Replace empty message": "取代空白訊息",
95 "Send this text instead of nothing when the text box is empty.": "當文字方塊為空時,發送此字串而不是空白。",95 "Send this text instead of nothing when the text box is empty.": "當文字框為空時,傳送此文字以取代空白。",
96 "Seed": "種子",96 "Seed": "種子",
97 "Set to get deterministic results. Use -1 for random seed.": "設定以獲取確定性結果。使用 -1 作為隨機種子",97 "Set to get deterministic results. Use -1 for random seed.": "設定數值以取得可重現的結果。使用 -1 作為隨機種子",
98 "Temperature controls the randomness in token selection": "溫度控制符元選擇中的隨機性",98 "Temperature controls the randomness in token selection": "溫度(Temperature)控制符元選擇的隨機性。\n- 低溫(<1.0):產生更可預測且具邏輯性的文字,優先選擇機率較高的符元。\n- 高溫(>1.0):提升創造性與輸出的多樣性,更常選擇機率較低的符元。\n將值設為 1.0 可使用原始機率。",
99 "Top_K_desc": "Top K 設定可以選擇的最高符元數量。\n例如,Top K 為 20,這意味著只保留排名前 20 的符元(無論它們的機率是多樣還是有限的)。\n設定為 0 以停用。",99 "Top_K_desc": "Top K 設定可以選擇的最高符元數量。\n例如,Top K 為 20,這意味著只保留排名前 20 的符元(無論它們的機率是多樣還是有限的)。\n設定為 0 以停用。",
100 "Top_P_desc": "Top P(又名核心取樣) 會將所有頂級符元加總,直到達到目標百分比。\n例如,如果前兩個符元都是 25%,而 Top P 設為 0.5,那麼只有前兩個符元會被考慮。\n設定為 1.0 以停用。",100 "Top_P_desc": "Top P(又名核心取樣) 會將所有頂級符元加總,直到達到目標百分比。\n例如,如果前兩個符元都是 25%,而 Top P 設為 0.5,那麼只有前兩個符元會被考慮。\n設定為 1.0 以停用。",
101 "Typical P": "Typical P",101 "Typical P": "Typical P",
102 "Typical_P_desc": "Typical P 取樣根據符元偏離集合平均熵的程度進行優先排序。\n它會保留累積機率接近預設閾值(例如0.5)的符元,強調那些具有平均信息量的符元。\n設定為 1.0 以停用。",102 "Typical_P_desc": "Typical P 取樣根據符元偏離集合平均熵的程度進行優先排序。\n它會保留累積機率接近預設閾值 (例如 0.5) 的符元,強調那些具有平均資訊量的符元。\n設定為 1.0 以停用。",
103 "Min_P_desc": "Min P 設定基本最小機率。\n這個值會根據最高符元的機率進行調整。例如,如果最高符元機率為 80%,而 Min P 設為 0.1,那麼只有機率高於 8% 的符元會被考慮。\n設定為 0 以停用。",103 "Min_P_desc": "Min P 設定基本最小機率。\n這個值會根據最高符元的機率進行調整。例如,如果最高符元機率為 80%,而 Min P 設為 0.1,那麼只有機率高於 8% 的符元會被考慮。\n設定為 0 以停用。",
104 "Top_A_desc": "Top A 根據最高符元機率的平方設定符元選擇的門檻。\n例如,如果 Top A 值為 0.2,而最高符元機率為 50%,那麼低於 5%(0.2 * 0.5^2) 的符元機率就會被排除。\n設定為 0 以停用。",104 "Top_A_desc": "Top A 根據最高符元機率的平方設定符元選擇的門檻。\n例如,如果 Top A 值為 0.2,而最高符元機率為 50%,那麼低於 5%(0.2 * 0.5^2) 的符元機率就會被排除。\n設定為 0 以停用。",
105 "Tail_Free_Sampling_desc": "無尾取樣 (Tail-Free Sampling, TFS) 會透過分析符元機率的變化率 (使用導數) 來尋找分佈中的低機率符元尾部。\n它會根據標準化的二階導數,保留直到某個閾值 (例如 0.3) 的符元。\n數值越接近 0,表示會棄去越多符元。設定為 1.0 以停用。",105 "Tail_Free_Sampling_desc": "無尾取樣 (Tail-Free Sampling, TFS) 會透過分析符元機率的變化率 (使用導數) 來尋找分佈中的低機率符元尾部。\n它會根據標準化的二階導數,保留直到某個閾值 (例如 0.3) 的符元。\n數值越接近 0,表示會棄去越多符元。設定為 1.0 以停用。",
@@ -126,10 +126,10 @@
126 "Logit Bias": "Logit 偏差",126 "Logit Bias": "Logit 偏差",
127 "Add": "新增",127 "Add": "新增",
128 "Helps to ban or reenforce the usage of certain words": "有助於禁止或強化某些符元的使用",128 "Helps to ban or reenforce the usage of certain words": "有助於禁止或強化某些符元的使用",
129 "CFG Scale": "CFG 比例",129 "CFG Scale": "CFG 縮放比例",
130 "Negative Prompt": "負面提示詞",130 "Negative Prompt": "負面提示詞",
131 "Add text here that would make the AI generate things you don't want in your outputs.": "在這裡新增文字,使 AI 生成您不希望在輸出中出現的內容。",131 "Add text here that would make the AI generate things you don't want in your outputs.": "在此新增文字,以防止 AI 在輸出中生成您不希望出現的內容。",
132 "Used if CFG Scale is unset globally, per chat or character": "如果CFG Scale未在全域、每個聊天或角色中設定,則使用",132 "Used if CFG Scale is unset globally, per chat or character": "若 CFG 縮放比例未被全域設定,它將作用於所有聊天或角色",
133 "Mirostat Tau": "Tau",133 "Mirostat Tau": "Tau",
134 "Mirostat LR": "Mirostat 學習率",134 "Mirostat LR": "Mirostat 學習率",
135 "Min Length": "最小長度",135 "Min Length": "最小長度",
@@ -144,14 +144,14 @@
144 "Epsilon Cutoff": "Epsilon 截斷",144 "Epsilon Cutoff": "Epsilon 截斷",
145 "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon 截斷設定排除符元的機率下限",145 "Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled": "Epsilon 截斷設定排除符元的機率下限",
146 "Eta Cutoff": "Eta 截斷",146 "Eta Cutoff": "Eta 截斷",
147 "Eta_Cutoff_desc": "Eta 截斷是特殊 Eta 取樣技術的主要參數。\n單位為 1e-4;合理值為 3。\n設為 0 以停用。\n詳情請參見 Hewitt 等人於 2022 年撰寫的論文《Truncation Sampling as Language Model Desmoothing》。",147 "Eta_Cutoff_desc": "Eta 截斷是特殊 Eta 取樣技術的主要參數。\n單位為 1e-4;合理值為 3。\n設為 0 以停用。\n詳細資訊請參見 Hewitt 等人於 2022 年撰寫的論文《Truncation Sampling as Language Model Desmoothing》。",
148 "rep.pen decay": "重複懲罰衰減",148 "rep.pen decay": "重複懲罰衰減",
149 "Encoder Rep. Pen.": "編碼器重複懲罰",149 "Encoder Rep. Pen.": "編碼器重複懲罰",
150 "No Repeat Ngram Size": "無重複 Ngram 大小",150 "No Repeat Ngram Size": "無重複 Ngram 大小",
151 "Skew": "Skew",151 "Skew": "Skew",
152 "Max Tokens Second": "最大符元/秒",152 "Max Tokens Second": "最大符元/秒",
153 "Smooth Sampling": "平滑取樣",153 "Smooth Sampling": "平滑取樣",
154 "Smooth_Sampling_desc": "允許您使用二次/三次變換來調整分佈。較低的平滑因子值將更具創造性,通常在 0.2-0.3 之間是最佳點(假設曲線=1)。較高的平滑曲線值會使曲線更陡峭,這將更加激烈地懲罰低概率選擇。1.0 的曲線值相當於僅使用平滑因子。",154 "Smooth_Sampling_desc": "允許您使用二次/三次變換來調整分佈。較低的平滑因子值將更具創造性,通常在 0.2-0.3 之間是最佳點(假設曲線=1)。較高的平滑曲線值會使曲線更陡峭,這將更加激烈地懲罰低機率選擇。1.0 的曲線值相當於僅使用平滑因子。",
155 "Smoothing Factor": "平滑因子",155 "Smoothing Factor": "平滑因子",
156 "Smoothing Curve": "平滑曲線",156 "Smoothing Curve": "平滑曲線",
157 "DRY_Repetition_Penalty_desc": "DRY 會懲罰那些將輸入的結尾擴充為已在先前輸入中出現過序列的符元。將乘法器設為 0 以停用。",157 "DRY_Repetition_Penalty_desc": "DRY 會懲罰那些將輸入的結尾擴充為已在先前輸入中出現過序列的符元。將乘法器設為 0 以停用。",
@@ -183,7 +183,7 @@
183 "Length Penalty": "長度懲罰",183 "Length Penalty": "長度懲罰",
184 "Early Stopping": "提前停止",184 "Early Stopping": "提前停止",
185 "Contrastive search": "對比搜尋",185 "Contrastive search": "對比搜尋",
186 "Contrastive_search_txt": "一種取樣器,通過利用大多數 LLM 的表示空間的等向性,鼓勵多樣性的同時保持一致性。詳情請參閱 Su 等人於 2022 年發表的論文《A Contrastive Framework for Neural Text Generation》。",186 "Contrastive_search_txt": "一種取樣器,透過利用大多數 LLM 的表示空間的等向性,鼓勵多樣性的同時保持一致性。詳細資訊請參閱 Su 等人於 2022 年發表的論文《A Contrastive Framework for Neural Text Generation》。",
187 "Penalty Alpha": "懲罰 Alpha",187 "Penalty Alpha": "懲罰 Alpha",
188 "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "對比搜尋正則化項的強度。設定為 0 以停用 CS",188 "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "對比搜尋正則化項的強度。設定為 0 以停用 CS",
189 "Do Sample": "進行取樣",189 "Do Sample": "進行取樣",
@@ -194,7 +194,7 @@
194 "Ignore the EOS Token even if it generates.": "即使生成也忽略 EOS 符元",194 "Ignore the EOS Token even if it generates.": "即使生成也忽略 EOS 符元",
195 "Skip Special Tokens": "跳過特殊符元",195 "Skip Special Tokens": "跳過特殊符元",
196 "Temperature Last": "最後的溫度",196 "Temperature Last": "最後的溫度",
197 "Temperature_Last_desc": "使用最後應用溫度取樣器。這幾乎總是明智的做法。\n啟用時:首先取樣一組合理的符元,然後應用溫度來調整它們的相對機率(技術上講,是 logits)。\n停用時:首先應用溫度調整所有符元的相對機率,然後從中取樣合理的符元。\n停用「最後應用溫度取樣」會增加分佈尾部的概率,這傾向於放大獲得不連貫回應的機會。",197 "Temperature_Last_desc": "使用最後應用溫度取樣器。這幾乎總是明智的做法。\n啟用時:首先取樣一組合理的符元,然後應用溫度來調整它們的相對機率(技術上講,是 logits)。\n停用時:首先應用溫度調整所有符元的相對機率,然後從中取樣合理的符元。\n停用「最後應用溫度取樣」會增加分佈尾部的機率,這傾向於放大獲得不連貫回應的機會。",
198 "Speculative Ngram": "推測性 Ngram",198 "Speculative Ngram": "推測性 Ngram",
199 "Use a different speculative decoding method without a draft model": "使用不含草稿模型的不同推測性解碼方法。",199 "Use a different speculative decoding method without a draft model": "使用不含草稿模型的不同推測性解碼方法。",
200 "Spaces Between Special Tokens": "特殊符元之間的空格",200 "Spaces Between Special Tokens": "特殊符元之間的空格",
@@ -222,21 +222,21 @@
222 "Message Content": "訊息內容",222 "Message Content": "訊息內容",
223 "Prepend character names to message contents.": "在訊息內容前新增角色名稱",223 "Prepend character names to message contents.": "在訊息內容前新增角色名稱",
224 "Continue Postfix": "繼續後綴",224 "Continue Postfix": "繼續後綴",
225 "The next chunk of the continued message will be appended using this as a separator.": "繼續訊息的下一塊將使用此作為分隔符附加",225 "The next chunk of the continued message will be appended using this as a separator.": "繼續訊息的下一塊將使用此作為分隔符號附加",
226 "Space": "空格",226 "Space": "空格",
227 "Newline": "換行",227 "Newline": "換行",
228 "Double Newline": "雙換行",228 "Double Newline": "雙換行",
229 "Wrap user messages in quotes before sending": "發送前將使用者訊息用引號括起來",229 "Wrap user messages in quotes before sending": "傳送前將使用者訊息用引號括起來",
230 "Wrap in Quotes": "用引號包裹",230 "Wrap in Quotes": "用引號包裹",
231 "Wrap entire user message in quotes before sending.": "在發送之前將整個使用者訊息用引號包裹。",231 "Wrap entire user message in quotes before sending.": "在傳送之前將整個使用者訊息用引號包裹。",
232 "Leave off if you use quotes manually for speech.": "如果您手動使用引號進行發言,請關閉。",232 "Leave off if you use quotes manually for speech.": "如果您手動使用引號進行發言,請關閉。",
233 "Continue prefill": "繼續預先填充",233 "Continue prefill": "繼續預先填充",
234 "Continue sends the last message as assistant role instead of system message with instruction.": "繼續將最後的訊息作為助理角色發送,而不是帶有指令的系統訊息。",234 "Continue sends the last message as assistant role instead of system message with instruction.": "繼續將最後的訊息作為助理角色傳送,而不是帶有指令的系統訊息。",
235 "Squash system messages": "合併系統訊息",235 "Squash system messages": "合併系統訊息",
236 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括對話範例)。可能會提高某些模型的一致性。",236 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括對話範例)。可能會提高某些模型的一致性。",
237 "Enable function calling": "啟用函數調用",237 "Enable function calling": "啟用函式呼叫",
238 "Send inline images": "發送內嵌圖片",238 "Send inline images": "傳送內嵌圖片",
239 "image_inlining_hint_1": "如果模型支援(例如:GPT-4V、Claude 3 或 Llava 13B),則在提示詞中發送圖片。\n使用任何訊息上的",239 "image_inlining_hint_1": "如果模型支援(例如:GPT-4V、Claude 3 或 Llava 13B),則在提示詞中傳送圖片。\n使用任何訊息上的",
240 "image_inlining_hint_2": "動作或",240 "image_inlining_hint_2": "動作或",
241 "image_inlining_hint_3": "選單來附加圖片文件到聊天中。",241 "image_inlining_hint_3": "選單來附加圖片文件到聊天中。",
242 "Inline Image Quality": "內嵌圖片品質",242 "Inline Image Quality": "內嵌圖片品質",
@@ -246,31 +246,31 @@
246 "Use AI21 Tokenizer": "使用 AI21 分詞器",246 "Use AI21 Tokenizer": "使用 AI21 分詞器",
247 "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "對於 Jurassic 模型使用適當的分詞器,比 GPT 的更高效",247 "Use the appropriate tokenizer for Jurassic models, which is more efficient than GPT's.": "對於 Jurassic 模型使用適當的分詞器,比 GPT 的更高效",
248 "Use Google Tokenizer": "使用 Google 分詞器",248 "Use Google Tokenizer": "使用 Google 分詞器",
249 "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "通過 Google 模型的 API 使用適當的分詞器。提示詞處理速度較慢,但提供更準確的符元計數。",249 "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "透過 Google 模型的 API 使用適當的分詞器。提示詞處理速度較慢,但提供更準確的符元計數。",
250 "Use system prompt": "使用系統提示詞",250 "Use system prompt": "使用系統提示詞",
251 "(Gemini 1.5 Pro/Flash only)": "(僅限於 Gemini 1.5 Pro/Flash)",251 "(Gemini 1.5 Pro/Flash only)": "(僅限於 Gemini 1.5 Pro/Flash)",
252 "Merges_all_system_messages_desc_1": "合併所有系統訊息,直到第一則非系統角色的訊息,並通過 google 的",252 "Merges_all_system_messages_desc_1": "合併所有系統訊息,直到第一則非系統角色的訊息,並透過 google 的",
253 "Merges_all_system_messages_desc_2": "字段發送,而不是與其餘提示詞內容一起發送。",253 "Merges_all_system_messages_desc_2": "欄位傳送,而不是與其餘提示詞內容一起傳送。",
254 "Assistant Prefill": "預先填充助理訊息",254 "Assistant Prefill": "預先填充助理訊息",
255 "Start Claude's answer with...": "開始 Claude 的回答⋯",255 "Start Claude's answer with...": "開始 Claude 的回答⋯",
256 "Assistant Impersonation Prefill": "助理扮演時的預先填充",256 "Assistant Impersonation Prefill": "助理扮演時的預先填充",
257 "Use system prompt (Claude 2.1+ only)": "使用系統提示詞(僅限 Claude 2.1+)",257 "Use system prompt (Claude 2.1+ only)": "使用系統提示詞(僅限 Claude 2.1+)",
258 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "為支援的模型發送系統提示詞。停用時,使用者訊息將新增到提示詞的開頭。",258 "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "為支援的模型傳送系統提示詞。停用時,使用者訊息將新增到提示詞的開頭。",
259 "User first message": "使用者第一則訊息",259 "User first message": "使用者第一則訊息",
260 "Restore User first message": "還原使用者第一則訊息",260 "Restore User first message": "還原使用者第一則訊息",
261 "Human message": "人類訊息、指令等。\n當空白時不加入任何內容,也就是需要一個帶有使用者角色的新提示詞。",261 "Human message": "人類訊息、指令等。\n當空白時不加入任何內容,也就是需要一個帶有使用者角色的新提示詞。",
262 "New preset": "新預設",262 "New preset": "新預設設定檔",
263 "Delete preset": "刪除預設",263 "Delete preset": "刪除預設設定檔",
264 "View / Edit bias preset": "查看/編輯 Bias 預設",264 "View / Edit bias preset": "檢視/編輯 Bias 預設設定檔",
265 "Add bias entry": "新增 Bias 條目",265 "Add bias entry": "新增 Bias 條目",
266 "Most tokens have a leading space.": "大多數符元有前導空格",266 "Most tokens have a leading space.": "大多數符元有前導空格",
267 "API Connections": "API 連線",267 "API Connections": "API 連線",
268 "Text Completion": "文本補全",268 "Text Completion": "文字補全",
269 "Chat Completion": "聊天補全",269 "Chat Completion": "聊天補全",
270 "NovelAI": "NovelAI",270 "NovelAI": "NovelAI",
271 "AI Horde": "AI Horde",271 "AI Horde": "AI Horde",
272 "KoboldAI": "KoboldAI",272 "KoboldAI": "KoboldAI",
273 "Avoid sending sensitive information to the Horde.": "避免發送敏感資訊到 Horde。",273 "Avoid sending sensitive information to the Horde.": "避免傳送敏感資訊到 Horde。",
274 "Review the Privacy statement": "檢視隱私聲明",274 "Review the Privacy statement": "檢視隱私聲明",
275 "Register a Horde account for faster queue times": "註冊 Horde 帳號以縮短等待時間",275 "Register a Horde account for faster queue times": "註冊 Horde 帳號以縮短等待時間",
276 "Learn how to contribute your idle GPU cycles to the Horde": "了解如何將閒置的 GPU 週期貢獻給 Horde",276 "Learn how to contribute your idle GPU cycles to the Horde": "了解如何將閒置的 GPU 週期貢獻給 Horde",
@@ -279,7 +279,7 @@
279 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "僅將已批准的 worker 排隊,可以幫助處理不良回應。可能會延長回應時間。",279 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "僅將已批准的 worker 排隊,可以幫助處理不良回應。可能會延長回應時間。",
280 "Trusted workers only": "僅限受信任的 worker",280 "Trusted workers only": "僅限受信任的 worker",
281 "API key": "API 金鑰",281 "API key": "API 金鑰",
282 "Get it here:": "在這裡獲取:",282 "Get it here:": "在這裡取得:",
283 "Register": "註冊",283 "Register": "註冊",
284 "View my Kudos": "瀏覽我的讚賞記錄",284 "View my Kudos": "瀏覽我的讚賞記錄",
285 "Enter": "輸入",285 "Enter": "輸入",
@@ -346,18 +346,18 @@
346 "Save Proxy": "儲存代理伺服器",346 "Save Proxy": "儲存代理伺服器",
347 "Delete Proxy": "刪除代理伺服器",347 "Delete Proxy": "刪除代理伺服器",
348 "Proxy Name": "代理伺服器名稱",348 "Proxy Name": "代理伺服器名稱",
349 "This will show up as your saved preset.": "這將顯示為您儲存的預設",349 "This will show up as your saved preset.": "這將顯示為您儲存的預設設定檔",
350 "Proxy Server URL": "代理伺服器 URL",350 "Proxy Server URL": "代理伺服器 URL",
351 "Alternative server URL (leave empty to use the default value).": "替代伺服器 URL(留空以使用預設值)。",351 "Alternative server URL (leave empty to use the default value).": "替代伺服器 URL(留空以使用預設值)。",
352 "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "在此框中輸入任何內容之前,從 API 面板中刪除您的實際 OAI API 金鑰",352 "Remove your real OAI API Key from the API panel BEFORE typing anything into this box": "在此框中輸入任何內容之前,從 API 面板中刪除您的實際 OAI API 金鑰",
353 "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "我們無法為使用非官方 OpenAI 代理伺服器時遇到的問題提供支援",353 "We cannot provide support for problems encountered while using an unofficial OpenAI proxy": "我們無法為使用非官方 OpenAI 代理伺服器時遇到的問題提供支援",
354 "Doesn't work? Try adding": "不起作用?嘗試新增",354 "Doesn't work? Try adding": "不起作用?嘗試新增",
355 "at the end!": "在最後!",355 "at the end!": "在 URL 結尾!",
356 "Proxy Password": "代理伺服器密碼",356 "Proxy Password": "代理伺服器密碼",
357 "Will be used as a password for the proxy instead of API key.": "將用作代理的密碼,而不是 API 金鑰",357 "Will be used as a password for the proxy instead of API key.": "將用作代理的密碼,而不是 API 金鑰",
358 "Peek a password": "顯示密碼",358 "Peek a password": "顯示密碼",
359 "OpenAI API key": "OpenAI API 金鑰",359 "OpenAI API key": "OpenAI API 金鑰",
360 "View API Usage Metrics": "查看 API 使用指標",360 "View API Usage Metrics": "檢視 API 使用指標",
361 "Follow": "遵循",361 "Follow": "遵循",
362 "these directions": "這些指示",362 "these directions": "這些指示",
363 "to get your OpenAI API key.": "以取得您的 OpenAI API 金鑰。",363 "to get your OpenAI API key.": "以取得您的 OpenAI API 金鑰。",
@@ -397,16 +397,16 @@
397 "Available Models": "可用模型",397 "Available Models": "可用模型",
398 "Prompt Post-Processing": "提示詞後處理",398 "Prompt Post-Processing": "提示詞後處理",
399 "Applies additional processing to the prompt before sending it to the API.": "這個選項會在將提示詞送往 API 之前,對它進行額外的處理。",399 "Applies additional processing to the prompt before sending it to the API.": "這個選項會在將提示詞送往 API 之前,對它進行額外的處理。",
400 "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "透過發送簡短的測試訊息來驗證您的 API 連線。請注意,您將因此獲得榮譽!",400 "Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!": "透過傳送簡短的測試訊息來驗證您的 API 連線。請注意,您將因此獲得榮譽!",
401 "Test Message": "測試訊息",401 "Test Message": "測試訊息",
402 "Auto-connect to Last Server": "自動連線到上次伺服器",402 "Auto-connect to Last Server": "自動連接至上次使用的伺服器",
403 "Missing key": "❌ 鑰匙遺失",403 "Missing key": "❌ 鑰匙遺失",
404 "Key saved": "✔️ 金鑰已儲存",404 "Key saved": "✔️ 金鑰已儲存",
405 "View hidden API keys": "查看隱藏的 API 金鑰",405 "View hidden API keys": "檢視隱藏的 API 金鑰",
406 "AI Response Formatting": "AI 回應進階格式化",406 "AI Response Formatting": "AI 回應進階格式化",
407 "Advanced Formatting": "進階格式化",407 "Advanced Formatting": "進階格式化",
408 "Context Template": "上下文範本",408 "Context Template": "上下文範本",
409 "Auto-select this preset for Instruct Mode": "自動選擇此預設用於指令模式",409 "Auto-select this preset for Instruct Mode": "自動選擇此預設設定檔用於指令模式",
410 "Story String": "故事字串",410 "Story String": "故事字串",
411 "Example Separator": "分隔符號範例",411 "Example Separator": "分隔符號範例",
412 "Chat Start": "聊天開始符號",412 "Chat Start": "聊天開始符號",
@@ -458,7 +458,7 @@
458 "Inserted before the first Assistant's message.": "插入在第一則助理訊息之前。",458 "Inserted before the first Assistant's message.": "插入在第一則助理訊息之前。",
459 "First Assistant Prefix": "開頭助理前綴",459 "First Assistant Prefix": "開頭助理前綴",
460 "instruct_last_output_sequence": "插入在最後一則助理訊息之前,或在生成 AI 回覆時作為最後一行提示詞(除了中立/系統角色)。",460 "instruct_last_output_sequence": "插入在最後一則助理訊息之前,或在生成 AI 回覆時作為最後一行提示詞(除了中立/系統角色)。",
461 "Last Assistant Prefix": "末尾助理前綴",461 "Last Assistant Prefix": "結尾助理前綴",
462 "Will be inserted as a last prompt line when using system/neutral generation.": "在使用系統/中立生成時作為最後一行提示詞插入。",462 "Will be inserted as a last prompt line when using system/neutral generation.": "在使用系統/中立生成時作為最後一行提示詞插入。",
463 "System Instruction Prefix": "系統指令前綴",463 "System Instruction Prefix": "系統指令前綴",
464 "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "如果生成了停止序列,包括該序列以及之後的所有內容將從輸出中刪除。",464 "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "如果生成了停止序列,包括該序列以及之後的所有內容將從輸出中刪除。",
@@ -482,7 +482,7 @@
482 "Non-markdown strings": "非 Markdown 字串",482 "Non-markdown strings": "非 Markdown 字串",
483 "separate with commas w/o space between": "用逗號分隔,之間無空格",483 "separate with commas w/o space between": "用逗號分隔,之間無空格",
484 "Custom Stopping Strings": "自訂停止字串",484 "Custom Stopping Strings": "自訂停止字串",
485 "JSON serialized array of strings": "JSON 序列化字串數組",485 "JSON serialized array of strings": "JSON 序列化字串陣列",
486 "Replace Macro in Stop Strings": "取代自訂停止字串中的巨集",486 "Replace Macro in Stop Strings": "取代自訂停止字串中的巨集",
487 "Auto-Continue": "自動繼續",487 "Auto-Continue": "自動繼續",
488 "Allow for Chat Completion APIs": "允許聊天補全 API",488 "Allow for Chat Completion APIs": "允許聊天補全 API",
@@ -493,7 +493,7 @@
493 "Active World(s) for all chats": "所有聊天啟用中的世界書",493 "Active World(s) for all chats": "所有聊天啟用中的世界書",
494 "-- World Info not found --": "-- 未找到世界資訊 --",494 "-- World Info not found --": "-- 未找到世界資訊 --",
495 "Global World Info/Lorebook activation settings": "全域世界資訊/知識書啟動設定",495 "Global World Info/Lorebook activation settings": "全域世界資訊/知識書啟動設定",
496 "Click to expand": "點擊展開",496 "Click to expand": "點選展開",
497 "Scan Depth": "掃描深度",497 "Scan Depth": "掃描深度",
498 "Context %": "上下文百分比",498 "Context %": "上下文百分比",
499 "Budget Cap": "預算上限",499 "Budget Cap": "預算上限",
@@ -506,16 +506,16 @@
506 "Sorted Evenly": "均等排序",506 "Sorted Evenly": "均等排序",
507 "Character Lore First": "角色知識書優先",507 "Character Lore First": "角色知識書優先",
508 "Global Lore First": "全域知識書優先",508 "Global Lore First": "全域知識書優先",
509 "Entries can activate other entries by mentioning their keywords": "條目可以通過提及其關鍵字來啟用其他條目",509 "Entries can activate other entries by mentioning their keywords": "條目可以透過提及其關鍵字來啟用其他條目",
510 "Recursive Scan": "遞迴掃描",510 "Recursive Scan": "遞迴掃描",
511 "Lookup for the entry keys in the context will respect the case": "在上下文中查找條目鍵將區分大小寫",511 "Lookup for the entry keys in the context will respect the case": "在上下文中查詢條目鍵將區分大小寫",
512 "Case Sensitive": "區分大小寫",512 "Case Sensitive": "區分大小寫",
513 "If the entry key consists of only one word, it would not be matched as part of other words": "如果條目鍵僅包含一個詞,則不會作為其他詞的一部分進行配對",513 "If the entry key consists of only one word, it would not be matched as part of other words": "如果條目鍵僅包含一個詞,則不會作為其他詞的一部分進行配對",
514 "Match Whole Words": "完全配對",514 "Match Whole Words": "完全配對",
515 "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "只有符合最多鍵值數量的條目將被選中進行包含群組過濾",515 "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "只有符合最多鍵值數量的條目將被選中進行包含群組過濾",
516 "Use Group Scoring": "使用群組評分",516 "Use Group Scoring": "使用群組評分",
517 "Alert if your world info is greater than the allocated budget.": "如果您的世界資訊超過分配的預算則提醒",517 "Alert if your world info is greater than the allocated budget.": "如果您的世界資訊超過分配的預算則提醒",
518 "Alert On Overflow": "溢出時警告",518 "Alert On Overflow": "溢位時警告",
519 "New": "新增",519 "New": "新增",
520 "or": "或",520 "or": "或",
521 "--- Pick to Edit ---": "--- 選擇編輯 ---",521 "--- Pick to Edit ---": "--- 選擇編輯 ---",
@@ -548,7 +548,7 @@
548 "User Settings": "使用者設定",548 "User Settings": "使用者設定",
549 "Simple": "簡單",549 "Simple": "簡單",
550 "Advanced": "進階",550 "Advanced": "進階",
551 "UI Language": "介面語言:",551 "UI Language": "介面語言:",
552 "Account": "帳號",552 "Account": "帳號",
553 "Admin Panel": "管理面板",553 "Admin Panel": "管理面板",
554 "Logout": "登出",554 "Logout": "登出",
@@ -559,7 +559,7 @@
559 "Delete a theme": "刪除主題",559 "Delete a theme": "刪除主題",
560 "Update a theme file": "更新主題檔",560 "Update a theme file": "更新主題檔",
561 "Save as a new theme": "另存為新主題",561 "Save as a new theme": "另存為新主題",
562 "Avatar Style": "頭像樣式",562 "Avatar Style:": "頭像樣式",
563 "Circle": "圓形",563 "Circle": "圓形",
564 "Square": "方形",564 "Square": "方形",
565 "Rectangle": "矩形",565 "Rectangle": "矩形",
@@ -580,9 +580,9 @@
580 "User Message Blur Tint": "使用者訊息模糊色調",580 "User Message Blur Tint": "使用者訊息模糊色調",
581 "AI Message Blur Tint": "AI 訊息模糊色調",581 "AI Message Blur Tint": "AI 訊息模糊色調",
582 "Chat Width": "對話框寬度",582 "Chat Width": "對話框寬度",
583 "Width of the main chat window in % of screen width": "主聊天視窗寬度占螢幕寬度的百分比",583 "Width of the main chat window in % of screen width": "主聊天視窗寬度佔螢幕寬度的百分比",
584 "Font Scale": "字體比例",584 "Font Scale": "字型比例",
585 "Font size": "字體大小",585 "Font size": "字型大小",
586 "Blur Strength": "模糊強度",586 "Blur Strength": "模糊強度",
587 "Blur strength on UI panels.": "UI 面板上的模糊強度",587 "Blur strength on UI panels.": "UI 面板上的模糊強度",
588 "Text Shadow Width": "文字陰影寬度",588 "Text Shadow Width": "文字陰影寬度",
@@ -622,22 +622,22 @@
622 "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當你在聊天中點選頭像的圖片後,這會啟用滑鼠懸停時的放大效果。",622 "Enables a magnification effect on hover when you display the zoomed avatar after clicking an avatar's image in chat.": "當你在聊天中點選頭像的圖片後,這會啟用滑鼠懸停時的放大效果。",
623 "Show tagged character folders in the character list": "在角色列表中顯示標籤角色資料夾。",623 "Show tagged character folders in the character list": "在角色列表中顯示標籤角色資料夾。",
624 "Tags as Folders": "標籤作為資料夾",624 "Tags as Folders": "標籤作為資料夾",
625 "Tags_as_Folders_desc": "標籤必須在「標籤管理」選單中標記為資料夾才可適用。點擊這裡打開。",625 "Tags_as_Folders_desc": "標籤必須在「標籤管理」選單中標記為資料夾才可適用。點選這裡開啟。",
626 "Character Handling": "角色處理",626 "Character Handling": "角色處理",
627 "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在進階角色定義中設定,這個欄位將顯示在角色清單中。",627 "If set in the advanced character definitions, this field will be displayed in the characters list.": "如果在進階角色定義中設定,這個欄位將顯示在角色清單中。",
628 "Char List Subheader": "角色列表子標題",628 "Char List Subheader": "角色列表子標題",
629 "Character Version": "角色版本",629 "Character Version": "角色版本",
630 "Created by": "創作者",630 "Created by": "創作者",
631 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊配對,並通過所有資料欄位在列表中搜尋角色,而不僅僅是通過名稱子字串。",631 "Use fuzzy matching, and search characters in the list by all data fields, not just by a name substring": "使用模糊配對,並透過所有資料欄位在列表中搜尋角色,而不僅僅是透過名稱子字串。",
632 "Advanced Character Search": "進階角色搜尋",632 "Advanced Character Search": "進階角色搜尋",
633 "If checked and the character card contains a prompt override (System Prompt), use that instead": "如果選中並且角色卡包含提示詞覆寫(系統提示詞),則使用該提示詞。",633 "If checked and the character card contains a prompt override (System Prompt), use that instead": "如果選中並且角色卡包含提示詞覆寫(系統提示詞),則使用該提示詞。",
634 "Prefer Character Card Prompt": "角色卡主要提示詞優先",634 "Prefer Character Card Prompt": "角色卡主要提示詞優先",
635 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "如果選中並且角色卡包含越獄覆寫(聊天歷史後指示),則使用該提示詞。",635 "If checked and the character card contains a jailbreak override (Post History Instruction), use that instead": "如果選中並且角色卡包含越獄覆寫(聊天歷史後指示),則使用該提示詞。",
636 "Prefer Character Card Jailbreak": "角色卡越獄優先",636 "Prefer Character Card Jailbreak": "角色卡越獄優先",
637 "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "避免裁剪和調整匯入的角色圖像大小。未勾選時將會裁剪/調整大小到 512x768。",637 "never_resize_avatars_tooltip": "避免裁剪與調整匯入的角色頭像大小。未啟用此選項時,圖片將被裁剪/調整為 512x768。此設定會關閉上傳頭像時的裁剪彈出視窗。",
638 "Never resize avatars": "永不調整頭像大小",638 "Never resize avatars": "永不調整頭像大小",
639 "Show actual file names on the disk, in the characters list display only": "僅在角色列表顯示實際檔案名稱。",639 "Show actual file names on the disk, in the characters list display only": "僅在角色列表顯示實際檔案名稱。",
640 "Show avatar filenames": "顯示頭像檔案名",640 "Show avatar filenames": "顯示頭像檔案名稱",
641 "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "在角色匯入時提示詞匯入嵌入的卡片標籤。否則,嵌入的標籤將被忽略。",641 "Prompt to import embedded card tags on character import. Otherwise embedded tags are ignored": "在角色匯入時提示詞匯入嵌入的卡片標籤。否則,嵌入的標籤將被忽略。",
642 "Import Card Tags": "匯入卡片中的標籤",642 "Import Card Tags": "匯入卡片中的標籤",
643 "Hide character definitions from the editor panel behind a spoiler button": "在編輯器面板中將角色定義隱藏在劇透按鈕後面。",643 "Hide character definitions from the editor panel behind a spoiler button": "在編輯器面板中將角色定義隱藏在劇透按鈕後面。",
@@ -658,14 +658,14 @@
658 "Relaxed API URLS": "寬鬆的 API URL 格式",658 "Relaxed API URLS": "寬鬆的 API URL 格式",
659 "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "當新角色含有知識書時,詢問是否要匯入嵌入的世界資訊/知識書。如果未選中,則會顯示簡短的訊息。",659 "Ask to import the World Info/Lorebook for every new character with embedded lorebook. If unchecked, a brief message will be shown instead": "當新角色含有知識書時,詢問是否要匯入嵌入的世界資訊/知識書。如果未選中,則會顯示簡短的訊息。",
660 "Lorebook Import Dialog": "匯入知識書對話框",660 "Lorebook Import Dialog": "匯入知識書對話框",
661 "Restore unsaved user input on page refresh": "在頁面刷新時還原未儲存的使用者輸入。",661 "Restore unsaved user input on page refresh": "在頁面重新整理時還原未儲存的使用者輸入。",
662 "Restore User Input": "還原使用者輸入",662 "Restore User Input": "還原使用者輸入",
663 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允許通過拖動重新定位某些 UI 元素。僅適用於 PC 版。",663 "Allow repositioning certain UI elements by dragging them. PC only, no effect on mobile": "允許透過拖動重新定位某些 UI 元素。僅適用於 PC 版。",
664 "Movable UI Panels": "可拖動的 UI 模式",664 "Movable UI Panels": "可拖動的 UI 模式",
665 "MovingUI preset. Predefined/saved draggable positions": "MovingUI 預設。預先定義/儲存可拖動位置。",665 "MovingUI preset. Predefined/saved draggable positions": "MovingUI 預設設定檔。預先定義/儲存可拖動位置。",
666 "MUI Preset": "MovingUI 預設",666 "MUI Preset": "MovingUI 預設設定檔",
667 "Save movingUI changes to a new file": "另存 MovingUI 變更為新檔案",667 "Save movingUI changes to a new file": "另存 MovingUI 變更為新檔案",
668 "Reset MovingUI panel sizes/locations.": "重置 MovingUI 面板大小/位置",668 "Reset MovingUI panel sizes/locations.": "重設 MovingUI 面板大小/位置",
669 "Apply a custom CSS style to all of the ST GUI": "將自訂 CSS 樣式應用於所有 SillyTavern 介面",669 "Apply a custom CSS style to all of the ST GUI": "將自訂 CSS 樣式應用於所有 SillyTavern 介面",
670 "Custom CSS": "自訂 CSS 樣式",670 "Custom CSS": "自訂 CSS 樣式",
671 "Expand the editor": "展開編輯器",671 "Expand the editor": "展開編輯器",
@@ -679,7 +679,7 @@
679 "Gradual push-out": "逐步推出",679 "Gradual push-out": "逐步推出",
680 "Always include examples": "總是包含範例",680 "Always include examples": "總是包含範例",
681 "Never include examples": "永不包含範例",681 "Never include examples": "永不包含範例",
682 "Send on Enter": "按下 Enter 鍵發送:",682 "Send on Enter": "按下 Enter 鍵傳送:",
683 "Disabled": "停用",683 "Disabled": "停用",
684 "Automatic (PC)": "自動(PC)",684 "Automatic (PC)": "自動(PC)",
685 "Press Send to continue": "按下傳送繼續",685 "Press Send to continue": "按下傳送繼續",
@@ -699,22 +699,22 @@
699 "Forbid External Media": "禁止使用外部媒體",699 "Forbid External Media": "禁止使用外部媒體",
700 "Allow {{char}}: in bot messages": "允許機器人訊息中使用 {{char}}:",700 "Allow {{char}}: in bot messages": "允許機器人訊息中使用 {{char}}:",
701 "Allow {{user}}: in bot messages": "允許機器人訊息中使用 {{user}}:",701 "Allow {{user}}: in bot messages": "允許機器人訊息中使用 {{user}}:",
702 "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "跳過編碼訊息文字中的 < 和 > 字符,允許一部分 HTML 標記以及 Markdown",702 "Skip encoding and characters in message text, allowing a subset of HTML markup as well as Markdown": "跳過編碼訊息文字中的 < 和 > 字元,允許一部分 HTML 標記以及 Markdown",
703 "Show tags in responses": "在回應中顯示標籤",703 "Show tags in responses": "在回應中顯示標籤",
704 "Allow AI messages in groups to contain lines spoken by other group members": "允許群組中的 AI 訊息包含其他群組成員說的話",704 "Allow AI messages in groups to contain lines spoken by other group members": "允許群組中的 AI 訊息包含其他群組成員說的話",
705 "Relax message trim in Groups": "放寬群組中的訊息修剪",705 "Relax message trim in Groups": "放寬群組中的訊息修剪",
706 "Log prompts to console": "將提示詞記錄到控制台",706 "Log prompts to console": "將提示詞記錄到控制台",
707 "Requests logprobs from the API for the Token Probabilities feature": "從 API 請求 logprobs 用於符元機率功能。",707 "Requests logprobs from the API for the Token Probabilities feature": "從 API 請求 logprobs 用於符元機率功能。",
708 "Request token probabilities": "請求符元機率",708 "Request token probabilities": "請求符元機率",
709 "Automatically reject and re-generate AI message based on configurable criteria": "根據可配置標準自動拒絕並重新生成 AI 訊息。",709 "Automatically reject and re-generate AI message based on configurable criteria": "根據可設定標準自動拒絕並重新生成 AI 訊息。",
710 "Auto-swipe": "自動滑動",710 "Auto-swipe": "自動滑動",
711 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "啟用自動滑動功能。此部分的設定僅在啟用自動滑動時有效。",711 "Enable the auto-swipe function. Settings in this section only have an effect when auto-swipe is enabled": "啟用自動滑動功能。此部分的設定僅在啟用自動滑動時有效。",
712 "Minimum generated message length": "生成訊息的最小長度",712 "Minimum generated message length": "生成訊息的最小長度",
713 "If the generated message is shorter than this, trigger an auto-swipe": "如果生成的訊息比這個短,將觸發自動滑動。",713 "If the generated message is shorter than these many characters, trigger an auto-swipe": "如果生成的訊息比這個短,將觸發自動滑動。",
714 "Blacklisted words": "黑名單詞語",714 "Blacklisted words": "黑名單詞語",
715 "words you dont want generated separated by comma ','": "您不想生成的文字,使用逗號分隔",715 "words you dont want generated separated by comma ','": "您不想生成的文字,使用逗號分隔",
716 "Blacklisted word count to swipe": "滑動的黑名單詞語數量",716 "Blacklisted word count to swipe": "滑動的黑名單詞語數量",
717 "Minimum number of blacklisted words detected to trigger an auto-swipe": "檢測到的黑名單詞語數量觸發自動滑動的最小值。",717 "Minimum number of blacklisted words detected to trigger an auto-swipe": "偵測到的黑名單詞語數量觸發自動滑動的最小值。",
718 "AutoComplete Settings": "自動完成設定",718 "AutoComplete Settings": "自動完成設定",
719 "Automatically hide details": "自動隱藏詳細資訊",719 "Automatically hide details": "自動隱藏詳細資訊",
720 "Determines how entries are found for autocomplete.": "決定如何找到自動完成的條目",720 "Determines how entries are found for autocomplete.": "決定如何找到自動完成的條目",
@@ -726,18 +726,18 @@
726 "Autocomplete Style": "自動完成樣式",726 "Autocomplete Style": "自動完成樣式",
727 "Follow Theme": "沿用介面主題",727 "Follow Theme": "沿用介面主題",
728 "Dark": "深色",728 "Dark": "深色",
729 "Sets the font size of the autocomplete.": "設定自動完成的字體大小",729 "Sets the font size of the autocomplete.": "設定自動完成的字型大小",
730 "Sets the width of the autocomplete.": "設定自動完成的寬度",730 "Sets the width of the autocomplete.": "設定自動完成的寬度",
731 "Autocomplete Width": "自動完成寬度",731 "Autocomplete Width": "自動完成寬度",
732 "chat input box": "聊天輸入框",732 "chat input box": "聊天輸入框",
733 "entire chat width": "整個聊天寬度",733 "entire chat width": "整個聊天寬度",
734 "full window width": "全視窗寬度",734 "full window width": "全視窗寬度",
735 "STscript Settings": "STscript 設定",735 "STscript Settings": "STscript 設定",
736 "Sets default flags for the STscript parser.": "設定 STscript 解析器的預設標誌",736 "Sets default flags for the STscript parser.": "設定 STscript 解析器的預設象徵",
737 "Parser Flags": "解析器標誌",737 "Parser Flags": "解析器象徵",
738 "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "切換到更嚴格的字元跳脫,允許所有分隔符號使用反斜線跳脫,反斜線自己也可以跳脫。",738 "Switch to stricter escaping, allowing all delimiting characters to be escaped with a backslash, and backslashes to be escaped as well.": "切換到更嚴格的字元跳脫,允許所有分隔符號使用反斜線跳脫,反斜線自己也可以跳脫。",
739 "STRICT_ESCAPING": "STRICT_ESCAPING",739 "STRICT_ESCAPING": "STRICT_ESCAPING",
740 "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "將所有 {{getvar::}} 和 {{getglobalvar::}} 巨集取代為作用域變量以避免雙重巨集取代",740 "Replace all {{getvar::}} and {{getglobalvar::}} macros with scoped variables to avoid double macro substitution.": "將所有 {{getvar::}} 和 {{getglobalvar::}} 巨集取代為區域變數以避免雙重巨集取代",
741 "REPLACE_GETVAR": "REPLACE_GETVAR",741 "REPLACE_GETVAR": "REPLACE_GETVAR",
742 "Change Background Image": "變更背景圖片",742 "Change Background Image": "變更背景圖片",
743 "Filter": "篩選",743 "Filter": "篩選",
@@ -758,7 +758,7 @@
758 "Extras API key (optional)": "擴充功能 API 金鑰(選填)",758 "Extras API key (optional)": "擴充功能 API 金鑰(選填)",
759 "Persona Management": "使用者角色管理",759 "Persona Management": "使用者角色管理",
760 "How do I use this?": "我該如何使用這個?",760 "How do I use this?": "我該如何使用這個?",
761 "Click for stats!": "點擊以查看統計資料!",761 "Click for stats!": "點選以檢視統計資料!",
762 "Usage Stats": "統計資料",762 "Usage Stats": "統計資料",
763 "Backup your personas to a file": "備份您的使用者角色檔案",763 "Backup your personas to a file": "備份您的使用者角色檔案",
764 "Backup": "備份",764 "Backup": "備份",
@@ -766,20 +766,20 @@
766 "Restore": "還原",766 "Restore": "還原",
767 "Create a dummy persona": "建立一個虛構使用者角色",767 "Create a dummy persona": "建立一個虛構使用者角色",
768 "Create": "建立",768 "Create": "建立",
769 "Toggle grid view": "切換為網格視圖",769 "Toggle grid view": "切換為網格檢視",
770 "No persona description": "無使用者角色描述",770 "No persona description": "無使用者角色描述",
771 "Name": "名稱",771 "Name": "名稱",
772 "Enter your name": "輸入您的名字",772 "Enter your name": "輸入您的名字",
773 "Click to set a new User Name": "設定新的使用者名稱",773 "Click to set a new User Name": "設定新的使用者名稱",
774 "Click to lock your selected persona to the current chat. Click again to remove the lock.": "綁定目前所選的使用者角色至本次聊天。再次點擊則可移除綁定。",774 "Click to lock your selected persona to the current chat. Click again to remove the lock.": "綁定目前所選的使用者角色至本次聊天。再次點選則可移除綁定。",
775 "Click to set user name for all messages": "設定所有訊息的使用者名稱",775 "Click to set user name for all messages": "設定所有訊息的使用者名稱",
776 "Persona Description": "使用者角色描述",776 "Persona Description": "使用者角色描述",
777 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]",777 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "範例:[{{user}} 是一個 28 歲的羅馬尼亞貓娘。]",
778 "Tokens persona description": "角色描述符元數",778 "Tokens persona description": "角色描述符元數",
779 "Position:": "插入位置:",779 "Position:": "插入位置:",
780 "In Story String / Prompt Manager": "提示詞管理器/故事字串中",780 "In Story String / Prompt Manager": "提示詞管理器/故事字串中",
781 "Top of Author's Note": "作者備註的頂部",781 "Top of Author's Note": "作者備註的頂端",
782 "Bottom of Author's Note": "作者備註的底部",782 "Bottom of Author's Note": "作者備註的底端",
783 "In-chat @ Depth": "聊天中 @ 深度",783 "In-chat @ Depth": "聊天中 @ 深度",
784 "Depth:": "深度:",784 "Depth:": "深度:",
785 "Role:": "角色:",785 "Role:": "角色:",
@@ -820,7 +820,7 @@
820 "Replace / Update": "取代/更新",820 "Replace / Update": "取代/更新",
821 "Import Tags": "匯入標籤",821 "Import Tags": "匯入標籤",
822 "Search / Create Tags": "搜尋/建立標籤",822 "Search / Create Tags": "搜尋/建立標籤",
823 "View all tags": "查看所有標籤",823 "View all tags": "檢視所有標籤",
824 "Creator's Notes": "創作者備註",824 "Creator's Notes": "創作者備註",
825 "Show / Hide Description and First Message": "顯示/隱藏描述和第一則訊息",825 "Show / Hide Description and First Message": "顯示/隱藏描述和第一則訊息",
826 "Character Description": "角色描述",826 "Character Description": "角色描述",
@@ -830,7 +830,7 @@
830 "First message": "初始訊息",830 "First message": "初始訊息",
831 "Click to set additional greeting messages": "點選以設定額外的問候訊息",831 "Click to set additional greeting messages": "點選以設定額外的問候訊息",
832 "Alt. Greetings": "額外問候語",832 "Alt. Greetings": "額外問候語",
833 "This will be the first message from the character that starts every chat.": "這將是每次聊天開始時角色發送的第一則訊息。",833 "This will be the first message from the character that starts every chat.": "這將是每次聊天開始時角色傳送的第一則訊息。",
834 "Group Controls": "群組控制",834 "Group Controls": "群組控制",
835 "Chat Name (Optional)": "聊天名稱(選填)",835 "Chat Name (Optional)": "聊天名稱(選填)",
836 "Click to select a new avatar for this group": "點選以選擇此群組的新頭像",836 "Click to select a new avatar for this group": "點選以選擇此群組的新頭像",
@@ -843,7 +843,7 @@
843 "Join character cards (include muted)": "合併角色卡欄位(包括靜音)",843 "Join character cards (include muted)": "合併角色卡欄位(包括靜音)",
844 "Inserted before each part of the joined fields.": "插入在合併欄位的每一部分之前。",844 "Inserted before each part of the joined fields.": "插入在合併欄位的每一部分之前。",
845 "Join Prefix": "加入前綴",845 "Join Prefix": "加入前綴",
846 "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)": "選擇「合併角色卡欄位」時,所有角色的相關欄位將被合併。\r例如,在故事字串中,所有角色的描述將合併為一段大文本。\r若您希望這些欄位保持分隔,您可以在此定義前綴或後綴。\r\r此值支持常規巨集 {{macros}},並會將 {{char}} 替換為相關角色的名稱,可將 <FIELDNAME> 替換為欄位名稱(例如:角色描述、個性、場景等)。",846 "When 'Join character cards' is selected, all respective fields of the characters are being joined together.This means that in the story string for example all character descriptions will be joined to one big text.If you want those fields to be separated, you can define a prefix or suffix here.This value supports normal macros and will also replace {{char}} with the relevant char's name and <FIELDNAME> with the name of the part (e.g.: description, personality, scenario, etc.)": "選擇「合併角色卡欄位」時,所有角色的相關欄位將被合併。\r例如,在故事字串中,所有角色的描述將合併為一段大文字。\r若您希望這些欄位保持分隔,您可以在此定義前綴或後綴。\r\r此值支援常規巨集 {{macros}},並會將 {{char}} 替換為相關角色的名稱,可將 <FIELDNAME> 替換為欄位名稱(例如:角色描述、個性、場景等)。",
847 "Inserted after each part of the joined fields.": "插入在合併欄位的每一部分之後。",847 "Inserted after each part of the joined fields.": "插入在合併欄位的每一部分之後。",
848 "Join Suffix": "加入後綴",848 "Join Suffix": "加入後綴",
849 "Set a group chat scenario": "設定群組聊天場景",849 "Set a group chat scenario": "設定群組聊天場景",
@@ -855,10 +855,10 @@
855 "Hide Muted Member Sprites": "於群組拼貼頭像中隱藏靜音成員",855 "Hide Muted Member Sprites": "於群組拼貼頭像中隱藏靜音成員",
856 "Current Members": "目前成員",856 "Current Members": "目前成員",
857 "Add Members": "新增成員",857 "Add Members": "新增成員",
858 "Create New Character": "創建角色",858 "Create New Character": "建立角色",
859 "Import Character from File": "由本地檔案匯入角色",859 "Import Character from File": "由本機檔案匯入角色",
860 "Import content from external URL": "由外部 URL 匯入內容",860 "Import content from external URL": "由外部 URL 匯入內容",
861 "Create New Chat Group": "創建聊天群組",861 "Create New Chat Group": "建立聊天群組",
862 "Characters sorting order": "角色排序依據",862 "Characters sorting order": "角色排序依據",
863 "A-Z": "A-Z",863 "A-Z": "A-Z",
864 "Z-A": "Z-A",864 "Z-A": "Z-A",
@@ -871,8 +871,8 @@
871 "Most tokens": "最多符元",871 "Most tokens": "最多符元",
872 "Least tokens": "最少符元",872 "Least tokens": "最少符元",
873 "Random": "隨機",873 "Random": "隨機",
874 "Toggle character grid view": "切換為角色網格視圖",874 "Toggle character grid view": "切換為角色網格檢視",
875 "Bulk_edit_characters": "批次編輯角色\n\n點選以切換角色\n「Shift+點擊」可選擇/取消選擇範圍的角色\n右鍵以查看動作\n右鍵以查看動作",875 "Bulk_edit_characters": "批次編輯角色\n\n點選以切換角色\n「Shift+點選」可選擇/取消選擇範圍的角色\n右鍵以檢視動作\n右鍵以檢視動作",
876 "Bulk select all characters": "全選所有角色",876 "Bulk select all characters": "全選所有角色",
877 "Bulk delete characters": "批次刪除角色",877 "Bulk delete characters": "批次刪除角色",
878 "popup-button-save": "儲存",878 "popup-button-save": "儲存",
@@ -887,9 +887,9 @@
887 "Main Prompt": "主要提示詞",887 "Main Prompt": "主要提示詞",
888 "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "此處的任何內容將取代此角色使用的預設主要提示詞。(v2 規範:system_prompt)",888 "Any contents here will replace the default Main Prompt used for this character. (v2 spec: system_prompt)": "此處的任何內容將取代此角色使用的預設主要提示詞。(v2 規範:system_prompt)",
889 "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "此處的任何內容將取代此角色使用的預設越獄提示詞。(v2 規範:post_history_instructions)",889 "Any contents here will replace the default Jailbreak Prompt used for this character. (v2 spec: post_history_instructions)": "此處的任何內容將取代此角色使用的預設越獄提示詞。(v2 規範:post_history_instructions)",
890 "Creator's Metadata (Not sent with the AI prompt)": "創作者的中繼資料(不會與 AI 提示詞一起發送)",890 "Creator's Metadata (Not sent with the AI prompt)": "創作者的中繼資料(不會與 AI 提示詞一起傳送)",
891 "Creator's Metadata": "創作者的中繼資料",891 "Creator's Metadata": "創作者的中繼資料",
892 "(Not sent with the AI Prompt)": "(不與 AI 提示詞一起發送)",892 "(Not sent with the AI Prompt)": "(不與 AI 提示詞一起傳送)",
893 "Everything here is optional": "此處所有內容均為選填",893 "Everything here is optional": "此處所有內容均為選填",
894 "(Botmaker's name / Contact Info)": "(機器人創作者的名字/聯絡資訊)",894 "(Botmaker's name / Contact Info)": "(機器人創作者的名字/聯絡資訊)",
895 "(If you want to track character versions)": "(若您想追蹤角色版本)",895 "(If you want to track character versions)": "(若您想追蹤角色版本)",
@@ -901,7 +901,7 @@
901 "Scenario": "場景設想",901 "Scenario": "場景設想",
902 "(Circumstances and context of the interaction)": "(互動情形與聊天背景)",902 "(Circumstances and context of the interaction)": "(互動情形與聊天背景)",
903 "Character's Note": "角色備註",903 "Character's Note": "角色備註",
904 "(Text to be inserted in-chat @ designated depth and role)": "(在聊天中以指定角色於 @ 深度位置插入文本)",904 "(Text to be inserted in-chat @ designated depth and role)": "(在聊天中以指定角色於 @ 深度位置插入文字)",
905 "@ Depth": "@ 深度",905 "@ Depth": "@ 深度",
906 "Role": "角色",906 "Role": "角色",
907 "Talkativeness": "健談度",907 "Talkativeness": "健談度",
@@ -990,13 +990,13 @@
990 "Exclude from recursion": "不可遞迴(此條目不會被其他條目啟用)",990 "Exclude from recursion": "不可遞迴(此條目不會被其他條目啟用)",
991 "Prevent further recursion (this entry will not activate others)": "防止進一步遞迴(此條目不會啟用其他條目)",991 "Prevent further recursion (this entry will not activate others)": "防止進一步遞迴(此條目不會啟用其他條目)",
992 "Delay until recursion (this entry can only be activated on recursive checking)": "延遲遞迴(此條目只能在遞迴檢查時啟用)",992 "Delay until recursion (this entry can only be activated on recursive checking)": "延遲遞迴(此條目只能在遞迴檢查時啟用)",
993 "What this keyword should mean to the AI, sent verbatim": "這個關鍵字對 AI 應意味著什麼,逐字發送",993 "What this keyword should mean to the AI, sent verbatim": "這個關鍵字對 AI 應意味著什麼,逐字傳送",
994 "Filter to Character(s)": "角色篩選",994 "Filter to Character(s)": "角色篩選",
995 "Character Exclusion": "角色排除",995 "Character Exclusion": "角色排除",
996 "-- Characters not found --": "-- 未找到角色 --",996 "-- Characters not found --": "-- 未找到角色 --",
997 "Inclusion Group": "包含的群組",997 "Inclusion Group": "包含的群組",
998 "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "如果觸發多個條目,包含群組可確保一次僅啟動一組中的一個條目。\r支援多個以逗號分隔的群組。\r\r文件:世界資訊——包容性集團",998 "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "如果觸發多個條目,包含群組可確保一次僅啟動一組中的一個條目。\r支援多個以逗號分隔的群組。\r\r文件:世界資訊——包容性集團",
999 "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先考慮此條目:選取後,此條目將在所有選擇中優先。\r如果有多個優先級,則選擇「順序」最高的一個。",999 "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "優先考慮此條目:選取後,此條目將在所有選擇中優先。\r如果有多個優先順序,則選擇「順序」最高的一個。",
1000 "Only one entry with the same label will be activated": "僅會啟用具有相同標籤的一個條目",1000 "Only one entry with the same label will be activated": "僅會啟用具有相同標籤的一個條目",
1001 "A relative likelihood of entry activation within the group": "群組內條目啟用的相對可能性",1001 "A relative likelihood of entry activation within the group": "群組內條目啟用的相對可能性",
1002 "Group Weight": "群組權重",1002 "Group Weight": "群組權重",
@@ -1008,7 +1008,7 @@
1008 "prompt_manager_edit": "編輯",1008 "prompt_manager_edit": "編輯",
1009 "prompt_manager_name": "名稱",1009 "prompt_manager_name": "名稱",
1010 "A name for this prompt.": "這個提示詞的名稱。",1010 "A name for this prompt.": "這個提示詞的名稱。",
1011 "To whom this message will be attributed.": "此訊息將隸屬於誰。",1011 "To whom this message will be attributed.": "此訊息所屬的角色。",
1012 "AI Assistant": "人工智慧助手",1012 "AI Assistant": "人工智慧助手",
1013 "prompt_manager_position": "位置",1013 "prompt_manager_position": "位置",
1014 "Injection position. Next to other prompts (relative) or in-chat (absolute).": "注入位置。與其他提示詞相鄰(相對位置)或在聊天中(絕對位置)。",1014 "Injection position. Next to other prompts (relative) or in-chat (absolute).": "注入位置。與其他提示詞相鄰(相對位置)或在聊天中(絕對位置)。",
@@ -1016,7 +1016,7 @@
1016 "prompt_manager_depth": "深度",1016 "prompt_manager_depth": "深度",
1017 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最後一則訊息之後,1 = 在最後一則訊息之前,以此類推。",1017 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "注入深度。0 = 在最後一則訊息之後,1 = 在最後一則訊息之前,以此類推。",
1018 "Prompt": "提示詞",1018 "Prompt": "提示詞",
1019 "The prompt to be sent.": "要發送的提示詞。",1019 "The prompt to be sent.": "要傳送的提示詞。",
1020 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使啟用優先覆寫,此提示詞也不能被角色卡片覆寫。",1020 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "即使啟用優先覆寫,此提示詞也不能被角色卡片覆寫。",
1021 "prompt_manager_forbid_overrides": "禁止覆寫",1021 "prompt_manager_forbid_overrides": "禁止覆寫",
1022 "reset": "重設",1022 "reset": "重設",
@@ -1069,13 +1069,13 @@
1069 "Trigger a message from this character": "觸發此角色的訊息",1069 "Trigger a message from this character": "觸發此角色的訊息",
1070 "Move up": "上移",1070 "Move up": "上移",
1071 "Move down": "下移",1071 "Move down": "下移",
1072 "View character card": "查看角色卡",1072 "View character card": "檢視角色卡",
1073 "Remove from group": "從群組中移除",1073 "Remove from group": "從群組中移除",
1074 "Add to group": "新增到群組",1074 "Add to group": "新增到群組",
1075 "Alternate Greetings": "額外問候語",1075 "Alternate Greetings": "額外問候語",
1076 "Alternate_Greetings_desc": "這些將在開始新聊天時顯示為第一則訊息的滑動選項。\n群組成員可以選擇其中之一來開始對話。",1076 "Alternate_Greetings_desc": "這些將在開始新聊天時顯示為第一則訊息的滑動選項。\n群組成員可以選擇其中之一來開始對話。",
1077 "Alternate Greetings Hint": "額外問候語的提示訊息",1077 "Alternate Greetings Hint": "額外問候語的提示訊息",
1078 "(This will be the first message from the character that starts every chat)": "(這將是每次聊天開始時角色發送的第一則訊息)",1078 "(This will be the first message from the character that starts every chat)": "(這將是每次聊天開始時角色傳送的第一則訊息)",
1079 "Forbid Media Override explanation": "此角色/群組在聊天中使用外部媒體的能力。",1079 "Forbid Media Override explanation": "此角色/群組在聊天中使用外部媒體的能力。",
1080 "Forbid Media Override subtitle": "禁止媒體覆寫副標題",1080 "Forbid Media Override subtitle": "禁止媒體覆寫副標題",
1081 "Always forbidden": "總是禁止",1081 "Always forbidden": "總是禁止",
@@ -1089,7 +1089,7 @@
1089 "After Main Prompt / Story String": "在主要提示詞/故事字串之後",1089 "After Main Prompt / Story String": "在主要提示詞/故事字串之後",
1090 "as": "作為",1090 "as": "作為",
1091 "Insertion Frequency": "插入頻率",1091 "Insertion Frequency": "插入頻率",
1092 "(0 = Disable, 1 = Always)": "(0 = 停用, 1 = 永久)",1092 "(0 = Disable, 1 = Always)": "(0 = 停用,1 = 永久)",
1093 "User inputs until next insertion:": "使用者輸入直到下一次插入:",1093 "User inputs until next insertion:": "使用者輸入直到下一次插入:",
1094 "Character Author's Note (Private)": "角色作者備註(私人)",1094 "Character Author's Note (Private)": "角色作者備註(私人)",
1095 "Won't be shared with the character card on export.": "匯出時不與角色卡共享。",1095 "Won't be shared with the character card on export.": "匯出時不與角色卡共享。",
@@ -1114,7 +1114,7 @@
1114 "Chat Negatives": "聊天負面提示詞",1114 "Chat Negatives": "聊天負面提示詞",
1115 "Character Negatives": "角色負面提示詞",1115 "Character Negatives": "角色負面提示詞",
1116 "Global Negatives": "全域負面提示詞",1116 "Global Negatives": "全域負面提示詞",
1117 "Custom Separator:": "自訂分隔符:",1117 "Custom Separator:": "自訂分隔符號:",
1118 "Insertion Depth:": "插入深度:",1118 "Insertion Depth:": "插入深度:",
1119 "Token Probabilities": "符元機率",1119 "Token Probabilities": "符元機率",
1120 "Select a token to see alternatives considered by the AI.": "選擇一個符元以檢視 AI 考慮的替代方案",1120 "Select a token to see alternatives considered by the AI.": "選擇一個符元以檢視 AI 考慮的替代方案",
@@ -1125,7 +1125,7 @@
1125 "Abort script execution": "中止腳本執行",1125 "Abort script execution": "中止腳本執行",
1126 "Abort request": "中止請求",1126 "Abort request": "中止請求",
1127 "Continue the last message": "繼續生成最新訊息",1127 "Continue the last message": "繼續生成最新訊息",
1128 "Send a message": "發送訊息",1128 "Send a message": "傳送訊息",
1129 "Close chat": "關閉聊天",1129 "Close chat": "關閉聊天",
1130 "Toggle Panels": "切換面板",1130 "Toggle Panels": "切換面板",
1131 "Back to parent chat": "返回上層聊天",1131 "Back to parent chat": "返回上層聊天",
@@ -1156,7 +1156,7 @@
1156 "File per article": "每篇文章一個檔案",1156 "File per article": "每篇文章一個檔案",
1157 "Each article will be saved as a separate file.": "每篇文章將另存為一個檔案。",1157 "Each article will be saved as a separate file.": "每篇文章將另存為一個檔案。",
1158 "Data Bank": "資料庫",1158 "Data Bank": "資料庫",
1159 "These files will be available for extensions that support attachments (e.g. Vector Storage).": "這些檔案將可用於支援附件的擴充功能(例如向量存儲)。",1159 "These files will be available for extensions that support attachments (e.g. Vector Storage).": "這些檔案將可用於支援附件的擴充功能(例如向量儲存)。",
1160 "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支援的檔案類型:純文字,PDF,Markdown,HTML,EPUB。",1160 "Supported file types: Plain Text, PDF, Markdown, HTML, EPUB.": "支援的檔案類型:純文字,PDF,Markdown,HTML,EPUB。",
1161 "Drag and drop files here to upload.": "拖放檔案至此即可上傳。",1161 "Drag and drop files here to upload.": "拖放檔案至此即可上傳。",
1162 "Date (Newest First)": "日期(最新優先)",1162 "Date (Newest First)": "日期(最新優先)",
@@ -1172,7 +1172,7 @@
1172 "These files are available for all characters in all chats.": "適用於所有聊天、所有角色。",1172 "These files are available for all characters in all chats.": "適用於所有聊天、所有角色。",
1173 "Character Attachments": "角色附件",1173 "Character Attachments": "角色附件",
1174 "These files are available the current character in all chats they are in.": "適用於該角色參與的所有聊天。",1174 "These files are available the current character in all chats they are in.": "適用於該角色參與的所有聊天。",
1175 "Saved locally. Not exported.": "僅本地保存,不匯出。",1175 "Saved locally. Not exported.": "僅本機儲存,不匯出。",
1176 "Chat Attachments": "聊天附件",1176 "Chat Attachments": "聊天附件",
1177 "These files are available to all characters in the current chat.": "適用於本次聊天中的所有角色。",1177 "These files are available to all characters in the current chat.": "適用於本次聊天中的所有角色。",
1178 "Enter a base URL of the MediaWiki to scrape.": "輸入要抓取的 MediaWiki 的基礎 URL。",1178 "Enter a base URL of the MediaWiki to scrape.": "輸入要抓取的 MediaWiki 的基礎 URL。",
@@ -1189,7 +1189,7 @@
1189 "ext_sum_memory_placeholder": "將在此生成摘要⋯",1189 "ext_sum_memory_placeholder": "將在此生成摘要⋯",
1190 "Trigger a summary update right now.": "立即更新摘要內容。",1190 "Trigger a summary update right now.": "立即更新摘要內容。",
1191 "ext_sum_force_text": "重新摘要",1191 "ext_sum_force_text": "重新摘要",
1192 "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」)。",1192 "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」)。",
1193 "ext_sum_pause": "暫停",1193 "ext_sum_pause": "暫停",
1194 "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 始終自動省略世界資訊與作者備註。",1194 "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 始終自動省略世界資訊與作者備註。",
1195 "ext_sum_no_wi_an": "排除世界資訊及作者備註",1195 "ext_sum_no_wi_an": "排除世界資訊及作者備註",
@@ -1204,7 +1204,7 @@
1204 "ext_sum_prompt_builder_3": "經典、阻塞",1204 "ext_sum_prompt_builder_3": "經典、阻塞",
1205 "Summary Prompt": "摘要提示詞",1205 "Summary Prompt": "摘要提示詞",
1206 "ext_sum_restore_default_prompt_tip": "還原為預設提示詞",1206 "ext_sum_restore_default_prompt_tip": "還原為預設提示詞",
1207 "ext_sum_prompt_placeholder": "此提示詞將發送給 AI 以請求生成摘要。{{words}} 將解析為「字數」參數。",1207 "ext_sum_prompt_placeholder": "此提示詞將傳送給 AI 以請求生成摘要。{{words}} 將解析為「字數」參數。",
1208 "ext_sum_target_length_1": "目標摘要長度",1208 "ext_sum_target_length_1": "目標摘要長度",
1209 "ext_sum_target_length_2": "(",1209 "ext_sum_target_length_2": "(",
1210 "ext_sum_target_length_3": "字)",1210 "ext_sum_target_length_3": "字)",
@@ -1222,17 +1222,17 @@
1222 "ext_sum_update_every_words_1": "更新每",1222 "ext_sum_update_every_words_1": "更新每",
1223 "ext_sum_update_every_words_2": " 字",1223 "ext_sum_update_every_words_2": " 字",
1224 "ext_sum_both_sliders": "若兩個滑桿數值皆不為零,則將各自按照其時間間隔更新摘要。",1224 "ext_sum_both_sliders": "若兩個滑桿數值皆不為零,則將各自按照其時間間隔更新摘要。",
1225 "ext_sum_injection_template": "插入模板",1225 "ext_sum_injection_template": "插入範本",
1226 "ext_sum_memory_template_placeholder": "{{summary}} 會解析為目前的摘要內容。",1226 "ext_sum_memory_template_placeholder": "{{summary}} 會解析為目前的摘要內容。",
1227 "ext_sum_injection_position": "插入位置",1227 "ext_sum_injection_position": "插入位置",
1228 "How many messages before the current end of the chat.": "距離本次聊天結尾前的訊息數量。",1228 "How many messages before the current end of the chat.": "距離本次聊天結尾前的訊息數量。",
1229 "ext_regex_title": "正規表示式",1229 "ext_regex_title": "正規表示式",
1230 "ext_regex_new_global_script": "+ 全域",1230 "ext_regex_new_global_script": "+ 全域",
1231 "ext_regex_new_scoped_script": "+ 局部",1231 "ext_regex_new_scoped_script": "+ 區域",
1232 "ext_regex_import_script": "匯入腳本",1232 "ext_regex_import_script": "匯入腳本",
1233 "ext_regex_global_scripts": "全域腳本",1233 "ext_regex_global_scripts": "全域腳本",
1234 "ext_regex_global_scripts_desc": "適用於所有角色,資料將儲存到本地。",1234 "ext_regex_global_scripts_desc": "適用於所有角色,資料將儲存到本機。",
1235 "ext_regex_scoped_scripts": "局部腳本",1235 "ext_regex_scoped_scripts": "區域腳本",
1236 "ext_regex_scoped_scripts_desc": "僅適用於目前角色,資料將儲存到該角色卡中。",1236 "ext_regex_scoped_scripts_desc": "僅適用於目前角色,資料將儲存到該角色卡中。",
1237 "Regex Editor": "正規表示式編輯器",1237 "Regex Editor": "正規表示式編輯器",
1238 "Test Mode": "測試模式",1238 "Test Mode": "測試模式",
@@ -1247,17 +1247,17 @@
1247 "ext_regex_replace_string_placeholder": "使用 {{match}} 來包含來自尋找正規表示式的匹配文字或 $1、$2 等捕獲組。",1247 "ext_regex_replace_string_placeholder": "使用 {{match}} 來包含來自尋找正規表示式的匹配文字或 $1、$2 等捕獲組。",
1248 "Trim Out": "修剪掉",1248 "Trim Out": "修剪掉",
1249 "ext_regex_trim_placeholder": "在取代之前,全域修剪正規表示式匹配中的任何不需要的部分。每個元素用輸入鍵分隔。",1249 "ext_regex_trim_placeholder": "在取代之前,全域修剪正規表示式匹配中的任何不需要的部分。每個元素用輸入鍵分隔。",
1250 "ext_regex_affects": "影響對象",1250 "ext_regex_affects": "影響物件",
1251 "ext_regex_user_input": "使用者輸入",1251 "ext_regex_user_input": "使用者輸入",
1252 "ext_regex_ai_output": "AI 輸出",1252 "ext_regex_ai_output": "AI 輸出",
1253 "Slash Commands": "斜線命令",1253 "Slash Commands": "斜線命令",
1254 "ext_regex_min_depth_desc": "當應用於提示或顯示時,僅影響至少 N 層深的消息。 0 = 最後一則訊息,1 = 倒數第二個訊息等。",1254 "ext_regex_min_depth_desc": "當應用於提示或顯示時,僅影響至少 N 層深的訊息。0 = 最後一則訊息,1 = 倒數第二個訊息等。",
1255 "Min Depth": "最小深度",1255 "Min Depth": "最小深度",
1256 "ext_regex_min_depth_placeholder": "無限制",1256 "ext_regex_min_depth_placeholder": "無限制",
1257 "ext_regex_max_depth_desc": "當應用於提示或顯示時,僅影響不超過 N 層深度的訊息。0 = 最後一則訊息,1 = 倒數第二個訊息等。",1257 "ext_regex_max_depth_desc": "當應用於提示或顯示時,僅影響不超過 N 層深度的訊息。0 = 最後一則訊息,1 = 倒數第二個訊息等。",
1258 "ext_regex_other_options": "其他選項",1258 "ext_regex_other_options": "其他選項",
1259 "Only Format Display": "僅修改聊天顯示",1259 "Only Format Display": "僅修改聊天顯示",
1260 "ext_regex_only_format_prompt_desc": "不修改聊天記錄,僅修改發送訊息(請求文本生成時)時的系統提示詞。",1260 "ext_regex_only_format_prompt_desc": "不修改聊天記錄,僅修改傳送訊息(請求文字生成時)時的系統提示詞。",
1261 "Only Format Prompt (?)": "僅修改系統提示詞",1261 "Only Format Prompt (?)": "僅修改系統提示詞",
1262 "Run On Edit": "編輯時執行",1262 "Run On Edit": "編輯時執行",
1263 "ext_regex_substitute_regex_desc": "在執行「尋找正規表達式」前,將 {{macros}}(巨集)替換為對應內容",1263 "ext_regex_substitute_regex_desc": "在執行「尋找正規表達式」前,將 {{macros}}(巨集)替換為對應內容",
@@ -1267,7 +1267,7 @@
1267 "ext_regex_enable_script": "啟用腳本",1267 "ext_regex_enable_script": "啟用腳本",
1268 "ext_regex_edit_script": "編輯腳本",1268 "ext_regex_edit_script": "編輯腳本",
1269 "ext_regex_move_to_global": "移至全域腳本",1269 "ext_regex_move_to_global": "移至全域腳本",
1270 "ext_regex_move_to_scoped": "移至作用域腳本",1270 "ext_regex_move_to_scoped": "移至區域腳本",
1271 "ext_regex_export_script": "匯出腳本",1271 "ext_regex_export_script": "匯出腳本",
1272 "ext_regex_delete_script": "刪除腳本",1272 "ext_regex_delete_script": "刪除腳本",
1273 "Trigger Stable Diffusion": "觸發 Stable Diffusion",1273 "Trigger Stable Diffusion": "觸發 Stable Diffusion",
@@ -1281,24 +1281,24 @@
1281 "Image Generation": "圖片生成設定",1281 "Image Generation": "圖片生成設定",
1282 "sd_refine_mode": "允許在傳送至生成 API 前,手動編輯提示詞字串",1282 "sd_refine_mode": "允許在傳送至生成 API 前,手動編輯提示詞字串",
1283 "sd_refine_mode_txt": "生成前編輯提示詞",1283 "sd_refine_mode_txt": "生成前編輯提示詞",
1284 "sd_interactive_mode": "當發送「給我一張貓的圖片」這類訊息時,自動生成圖片。",1284 "sd_interactive_mode": "當傳送「給我一張貓的圖片」這類訊息時,自動生成圖片。",
1285 "sd_interactive_mode_txt": "互動模式",1285 "sd_interactive_mode_txt": "互動模式",
1286 "sd_multimodal_captioning": "根據使用者和角色的頭像,使用多模態模型描述生成肖像提示詞。",1286 "sd_multimodal_captioning": "根據使用者和角色的頭像,使用多模態模型描述生成肖像提示詞。",
1287 "sd_multimodal_captioning_txt": "對肖像使用多模態模型描述",1287 "sd_multimodal_captioning_txt": "對肖像使用多模態模型描述",
1288 "sd_expand": "使用文本生成模型自動擴寫提示詞。",1288 "sd_expand": "使用文字生成模型自動擴寫提示詞。",
1289 "sd_expand_txt": "自動潤色提示詞",1289 "sd_expand_txt": "自動潤飾提示詞",
1290 "sd_snap": "對於具有特定長寬比的生成請求(如肖像、背景),將其調整至最接近的已知解析度,同時儘量保持絕對像素數(建議用於 SDXL)。",1290 "sd_snap": "對於具有特定長寬比的生成請求(如肖像、背景),將其調整至最接近的已知解析度,同時儘量保持絕對像素數(建議用於 SDXL)。",
1291 "sd_snap_txt": "自動調整解析度",1291 "sd_snap_txt": "自動調整解析度",
1292 "Source": "來源",1292 "Source": "來源",
1293 "sd_auto_url": "範例: {{auto_url}}",1293 "sd_auto_url": "範例:{{auto_url}}",
1294 "Authentication (optional)": "授權驗證(選填)",1294 "Authentication (optional)": "授權驗證(選填)",
1295 "Example: username:password": "範例:帳號:密碼",1295 "Example: username:password": "範例:帳號:密碼",
1296 "Important:": "重要:",1296 "Important:": "重要:",
1297 "sd_auto_auth_warning_1": "使用",1297 "sd_auto_auth_warning_1": "使用",
1298 "sd_auto_auth_warning_2": "旗標執行 SD Web UI!伺服器必須能夠被 SillyTavern 主機存取。",1298 "sd_auto_auth_warning_2": "旗標執行 SD Web UI!伺服器必須能夠被 SillyTavern 主機存取。",
1299 "sd_drawthings_url": "範例: {{drawthings_url}}",1299 "sd_drawthings_url": "範例:{{drawthings_url}}",
1300 "sd_drawthings_auth_txt": "執行 DrawThings 應用程式並在介面中啟用 HTTP API 開關!伺服器必須能夠被 SillyTavern 主機存取。",1300 "sd_drawthings_auth_txt": "執行 DrawThings 應用程式並在介面中啟用 HTTP API 開關!伺服器必須能夠被 SillyTavern 主機存取。",
1301 "sd_vlad_url": "範例: {{vlad_url}}",1301 "sd_vlad_url": "範例:{{vlad_url}}",
1302 "The server must be accessible from the SillyTavern host machine.": "伺服器必須能夠被 SillyTavern 主機存取。",1302 "The server must be accessible from the SillyTavern host machine.": "伺服器必須能夠被 SillyTavern 主機存取。",
1303 "Hint: Save an API key in AI Horde API settings to use it here.": "提示訊息:在 AI Horde API 設定中儲存一個 API 金鑰,以便在此使用。",1303 "Hint: Save an API key in AI Horde API settings to use it here.": "提示訊息:在 AI Horde API 設定中儲存一個 API 金鑰,以便在此使用。",
1304 "Allow NSFW images from Horde": "允許來自 Horde 的 NSFW 圖片",1304 "Allow NSFW images from Horde": "允許來自 Horde 的 NSFW 圖片",
@@ -1312,7 +1312,7 @@
1312 "Image Quality": "圖片品質",1312 "Image Quality": "圖片品質",
1313 "Standard": "標準",1313 "Standard": "標準",
1314 "HD": "高畫質",1314 "HD": "高畫質",
1315 "sd_comfy_url": "範例: {{comfy_url}}",1315 "sd_comfy_url": "範例:{{comfy_url}}",
1316 "Open workflow editor": "開啟 workflow 編輯器",1316 "Open workflow editor": "開啟 workflow 編輯器",
1317 "Create new workflow": "建立新的 workflow",1317 "Create new workflow": "建立新的 workflow",
1318 "Delete workflow": "刪除 workflow",1318 "Delete workflow": "刪除 workflow",
@@ -1330,14 +1330,14 @@
1330 "SMEA": "SMEA",1330 "SMEA": "SMEA",
1331 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 取樣器的 DYN 變體通常會產生更多樣化的輸出,但在非常高的解析度下可能會失敗。",1331 "DYN variants of SMEA samplers often lead to more varied output, but may fail at very high resolutions.": "SMEA 取樣器的 DYN 變體通常會產生更多樣化的輸出,但在非常高的解析度下可能會失敗。",
1332 "DYN": "DYN",1332 "DYN": "DYN",
1333 "Scheduler": "調度器",1333 "Scheduler": "排程器",
1334 "Restore Faces": "修復臉部",1334 "Restore Faces": "修復臉部",
1335 "Hires. Fix": "高解析度修正",1335 "Hires. Fix": "高解析度修正",
1336 "Upscaler": "放大演算法",1336 "Upscaler": "放大演演算法",
1337 "Upscale by": "放大倍率",1337 "Upscale by": "放大倍率",
1338 "Denoising strength": "重繪幅度",1338 "Denoising strength": "重繪幅度",
1339 "Hires steps (2nd pass)": "高解析步驟(2nd pass)",1339 "Hires steps (2nd pass)": "高解析步驟(2nd pass)",
1340 "Preset for prompt prefix and negative prompt": "提示詞前綴和負面提示詞的預設設定",1340 "Preset for prompt prefix and negative prompt": "提示詞前綴和負面提示詞的預設設定檔",
1341 "Style": "樣式",1341 "Style": "樣式",
1342 "Save style": "儲存樣式",1342 "Save style": "儲存樣式",
1343 "Delete style": "刪除樣式",1343 "Delete style": "刪除樣式",
@@ -1346,9 +1346,9 @@
1346 "Negative common prompt prefix": "通用負面提示詞前綴",1346 "Negative common prompt prefix": "通用負面提示詞前綴",
1347 "Character-specific prompt prefix": "角色提示詞前綴",1347 "Character-specific prompt prefix": "角色提示詞前綴",
1348 "Won't be used in groups.": "群聊中無效",1348 "Won't be used in groups.": "群聊中無效",
1349 "sd_character_prompt_placeholder": "描述該角色的特徵。這些特徵將添加在通用提示詞前綴之後。例如:女性、綠色眼睛、棕色頭髮、粉紅色襯衫。",1349 "sd_character_prompt_placeholder": "描述該角色的特徵。這些特徵將新增在通用提示詞前綴之後。例如:女性、綠色眼睛、棕色頭髮、粉紅色襯衫。",
1350 "Character-specific negative prompt prefix": "角色負面提示詞前綴",1350 "Character-specific negative prompt prefix": "角色負面提示詞前綴",
1351 "sd_character_negative_prompt_placeholder": "不應出現在該角色上的任何特徵。這些特徵將添加在負面通用提示詞前綴之後。例如:珠寶、鞋子、眼鏡。",1351 "sd_character_negative_prompt_placeholder": "不應出現在該角色上的任何特徵。這些特徵將新增在負面通用提示詞前綴之後。例如:珠寶、鞋子、眼鏡。",
1352 "Shareable": "分享至角色卡",1352 "Shareable": "分享至角色卡",
1353 "Image Prompt Templates": "圖片生成提示詞",1353 "Image Prompt Templates": "圖片生成提示詞",
1354 "Vectors Model Warning": "向量模型警告",1354 "Vectors Model Warning": "向量模型警告",
@@ -1358,7 +1358,7 @@
1358 "Status:": "狀態:",1358 "Status:": "狀態:",
1359 "Created:": "建立於:",1359 "Created:": "建立於:",
1360 "Display Name:": "顯示名稱:",1360 "Display Name:": "顯示名稱:",
1361 "User Handle:": "使用者控制代碼:",1361 "User Handle:": "使用者控制程式碼:",
1362 "Password:": "密碼:",1362 "Password:": "密碼:",
1363 "Confirm Password:": "確認密碼:",1363 "Confirm Password:": "確認密碼:",
1364 "This will create a new subfolder...": "這將建立一個新的子資料夾⋯",1364 "This will create a new subfolder...": "這將建立一個新的子資料夾⋯",
@@ -1372,10 +1372,10 @@
1372 "Also wipe user data.": "同時清除使用者資料。",1372 "Also wipe user data.": "同時清除使用者資料。",
1373 "Warning:": "警告:",1373 "Warning:": "警告:",
1374 "This action is irreversible.": "此動作不可逆轉。",1374 "This action is irreversible.": "此動作不可逆轉。",
1375 "Type the user's handle below to confirm:": "在下方輸入使用者的控制代碼以確認:",1375 "Type the user's handle below to confirm:": "在下方輸入使用者的控制程式碼以確認:",
1376 "Import Characters": "匯入角色",1376 "Import Characters": "匯入角色",
1377 "Enter the URL of the content to import": "輸入要匯入的內容的 URL",1377 "Enter the URL of the content to import": "輸入要匯入的內容的 URL",
1378 "Supported sources:": "支持的來源:",1378 "Supported sources:": "支援的來源:",
1379 "char_import_1": "Chub 角色(直接連結或 ID)",1379 "char_import_1": "Chub 角色(直接連結或 ID)",
1380 "char_import_example": "例子:",1380 "char_import_example": "例子:",
1381 "char_import_2": "Chub Lorebook(直接連結或 ID)",1381 "char_import_2": "Chub Lorebook(直接連結或 ID)",
@@ -1387,7 +1387,7 @@
1387 "char_import_8": "RisuRealm 角色(直接連結)",1387 "char_import_8": "RisuRealm 角色(直接連結)",
1388 "Supports importing multiple characters.": "支援匯入多個字元。",1388 "Supports importing multiple characters.": "支援匯入多個字元。",
1389 "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。",1389 "Write each URL or ID into a new line.": "將每個 URL 或 ID 寫入新行。",
1390 "Export for character": "匯出字符",1390 "Export for character": "匯出字元",
1391 "Export prompts for this character, including their order.": "匯出該角色的提示,包括其順序。",1391 "Export prompts for this character, including their order.": "匯出該角色的提示,包括其順序。",
1392 "Export all": "全部匯出",1392 "Export all": "全部匯出",
1393 "Export all your prompts to a file": "將所有提示匯出到文件",1393 "Export all your prompts to a file": "將所有提示匯出到文件",
@@ -1395,7 +1395,7 @@
1395 "Delete prompt": "刪除提示",1395 "Delete prompt": "刪除提示",
1396 "Import a prompt list": "匯入提示列表",1396 "Import a prompt list": "匯入提示列表",
1397 "Export this prompt list": "匯出此提示列表",1397 "Export this prompt list": "匯出此提示列表",
1398 "Reset current character": "重置目前字符",1398 "Reset current character": "重設目前字元",
1399 "New prompt": "新提示",1399 "New prompt": "新提示",
1400 "Prompts": "提示",1400 "Prompts": "提示",
1401 "Total Tokens:": "代幣總數:",1401 "Total Tokens:": "代幣總數:",
@@ -1444,93 +1444,92 @@
1444 "Still have questions?": "仍有更多問題?",1444 "Still have questions?": "仍有更多問題?",
1445 "Join the SillyTavern Discord": "加入 SillyTavern Discord",1445 "Join the SillyTavern Discord": "加入 SillyTavern Discord",
1446 "Post a GitHub issue": "發布 GitHub 問題",1446 "Post a GitHub issue": "發布 GitHub 問題",
1447 "Contact the developers": "聯繫開發者",1447 "Contact the developers": "聯絡開發者",
1448 "(-1 for random)": "(-1 表示隨機)",1448 "(-1 for random)": "(-1 表示隨機)",
1449 "(Optional)": "(可選)",1449 "(Optional)": "(可選)",
1450 "(use _space": "(使用",1450 "(use _space": "(使用",
1451 "api_no_connection": "未連線⋯",1451 "api_no_connection": "未連線⋯",
1452 "No model description": "[無描述]",1452 "No model description": "[無描述]",
1453 "openai_logit_bias_no_items": "無項目",1453 "openai_logit_bias_no_items": "無項目",
1454 "Any contents here will replace the default Post-History Instructions used for this character. (v2 specpost_history_instructions)": "此處填入的內容將取代該角色的默認聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)",1454 "Any contents here will replace the default Post-History Instructions used for this character. (v2 specpost_history_instructions)": "此處填入的內容將取代該角色的預設聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)",
1455 "comma delimited,no spaces between": "逗號分割,無需空格",1455 "comma delimited,no spaces between": "逗號分割,無需空格",
1456 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",1456 "e.g. black-forest-labs/FLUX.1-dev": "例如:black-forest-labs/FLUX.1-dev",
1457 "Example: gpt-4o": "例如:gpt-4o",1457 "Example: gpt-4o": "例如:gpt-4o",
1458 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",1458 "Example: http://localhost:1234/v1": "例如:http://localhost:1234/v1",
1459 "popup-button-crop": "裁剪",1459 "popup-button-crop": "裁剪",
1460 "(disabled when max recursion steps are used)": "(當最大遞歸步驟數使用時將停用)",1460 "(disabled when max recursion steps are used)": "(當最大遞迴步驟數使用時將停用)",
1461 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\n(disabled when min activations are used)": "0 = 無限制,1 = 掃描一次且不遞歸,2 = 掃描一次並遞歸一次,以此類推\n(使用最小啟動設定時將停用)",1461 "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "一種用於 LLM 抽樣的貪婪演演算法,用於尋找最可能的單詞或標記序列。該方法會同時展開多個候選序列,並在每一步中保持固定數量的頂級序列(beam width)。",
1462 "A greedy, brute-force algorithm used in LLM sampling to find the most likely sequence of words or tokens. It expands multiple candidate sequences at once, maintaining a fixed number (beam width) of top sequences at each step.": "一種用於 LLM 抽樣的貪婪演算法,用於尋找最可能的單詞或標記序列。該方法會同時展開多個候選序列,並在每一步中保持固定數量的頂級序列(beam width)。",
1463 "A multiplicative factor to expand the overall area that the nodes take up.": "節點佔用該擴充功能區域的倍數。",1462 "A multiplicative factor to expand the overall area that the nodes take up.": "節點佔用該擴充功能區域的倍數。",
1464 "Abort current image generation task": "終止目前的圖片生成任務",1463 "Abort current image generation task": "終止目前的圖片生成任務",
1465 "Add Character and User names to a list of stopping strings.": "將角色和使用者角色名稱添加至停止字符列表。",1464 "Add Character and User names to a list of stopping strings.": "將角色和使用者角色名稱新增至停止字元列表。",
1466 "Alignment for rank nodes.": "對排名節點的對齊方式。",1465 "Alignment for rank nodes.": "對排名節點的對齊方式。",
1467 "Always show the node full info panel at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的完整資訊面板顯示在時間軸視圖的左下角。關閉時,將顯示在節點附近。",1466 "Always show the node full info panel at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的完整資訊面板顯示在時間軸檢視的左下角。關閉時,將顯示在節點附近。",
1468 "Always show the node tooltip at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的工具提示欄顯示在時間軸視圖的左下角。關閉時,將顯示在節點附近。",1467 "Always show the node tooltip at the bottom left of the timeline view. When off, show it near the node.": "始終將節點的工具提示欄顯示在時間軸檢視的左下角。關閉時,將顯示在節點附近。",
1469 "Apply current sorting as Order": "應用此排序為順序",1468 "Apply current sorting as Order": "應用此排序為順序",
1470 "Cap the number of entry activation recursions": "限制入口啟動的遞歸次數",1469 "Cap the number of entry activation recursions": "限制入口啟動的遞迴次數",
1471 "Caption": "標題",1470 "Caption": "標題",
1472 "Close popup": "關閉彈出視窗",1471 "Close popup": "關閉彈出視窗",
1473 "Color configuration for Timelines when 'Use UI Theme' in Style Settings is off.": "關閉「使用介面主題」的時間線顏色。",1472 "Color configuration for Timelines when 'Use UI Theme' in Style Settings is off.": "關閉「使用介面主題」的時間線顏色。",
1474 "context_allow_post_history_instructions": "在文本完成模式中包含聊天歷史後指示(Post-History Instructions),但可能導致不良輸出。",1473 "context_allow_post_history_instructions": "在文字完成模式中包含聊天歷史後指示(Post-History Instructions),但可能導致不良輸出。",
1475 "Create a new connection profile": "建立新的連線設定檔",1474 "Create a new connection profile": "建立新的連線設定檔",
1476 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定義匯入角色卡時應採取的動作。選擇「詢問」將始終顯示對話框。",1475 "Defines on importing cards which action should be chosen for importing its listed tags. 'Ask' will always display the dialog.": "定義匯入角色卡時應採取的動作。選擇「詢問」將始終顯示對話框。",
1477 "delay_until_recursion_level": "定義遞迴掃描的延遲層級。\r最初僅匹配第一層(數字最小的層級)。\r未找到匹配時,下一層將成為可匹配的層級。\r此過程會重複,直到所有層級都被檢查完畢。\r與「延遲至遞歸」設定相關聯。",1476 "delay_until_recursion_level": "定義遞迴掃描的延遲層級。\r最初僅匹配第一層(數字最小的層級)。\r未找到匹配時,下一層將成為可匹配的層級。\r此過程會重複,直到所有層級都被檢查完畢。\r與「延遲至遞迴」設定相關聯。",
1478 "Delete a connection profile": "刪除連線設定檔",1477 "Delete a connection profile": "刪除連線設定檔",
1479 "Delete template": "刪除模板",1478 "Delete template": "刪除範本",
1480 "Delete the template": "刪除此模板",1479 "Delete the template": "刪除此範本",
1481 "Disabling is not recommended.": "不建議禁用。",1480 "Disabling is not recommended.": "不建議停用。",
1482 "Display swipe numbers for all messages, not just the last.": "顯示所有訊息的滑動編號,而不僅是最後一條訊息。",1481 "Display swipe numbers for all messages, not just the last.": "顯示所有訊息的滑動編號,而不僅是最後一條訊息。",
1483 "Duplicate persona": "複製使用者角色",1482 "Duplicate persona": "複製使用者角色",
1484 "Edit a connection profile": "編輯連線設定檔",1483 "Edit a connection profile": "編輯連線設定檔",
1485 "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "啟用自動選擇輸入框中的文本,適用於彈出輸入框及其他自定義輸入框。",1484 "Enable auto-select of input text in some text fields when clicking/selecting them. Applies to popup input textboxes, and possible other custom input fields.": "啟用自動選擇輸入框中的文字,適用於彈出輸入框及其他自定義輸入框。",
1486 "Entries with a cooldown can't be activated N messages after being triggered.": "設有冷卻時間的條目於觸發後的 N 條訊息內無法再次啟用。",1485 "Entries with a cooldown can't be activated N messages after being triggered.": "設有冷卻時間的條目於觸發後的 N 條訊息內無法再次啟用。",
1487 "Entries with a delay can't be activated until there are N messages present in the chat.": "有延遲的條目需等待聊天中出現 N 條訊息後才能啟用。",1486 "Entries with a delay can't be activated until there are N messages present in the chat.": "有延遲的條目需等待聊天中出現 N 條訊息後才能啟用。",
1488 "Expand swipe nodes when the timeline view first opens, and whenever the graph is refreshed. When off, you can expand them by long-pressing a node, or by pressing the Toggle Swipes button.": "時間線視圖首次打開或刷新時展開滑動節點。關閉時可通過長按節點或點選「切換滑動」按鈕展開。",1487 "Expand swipe nodes when the timeline view first opens, and whenever the graph is refreshed. When off, you can expand them by long-pressing a node, or by pressing the Toggle Swipes button.": "時間線檢視首次開啟或重新整理時展開滑動節點。關閉時可透過長按節點或點選「切換滑動」按鈕展開。",
1489 "Export Advanced Formatting settings": "匯出進階格式設定",1488 "Export Advanced Formatting settings": "匯出進階格式設定",
1490 "Export template": "匯出模板",1489 "Export template": "匯出範本",
1491 "Find similar characters": "尋找相似角色",1490 "Find similar characters": "尋找相似角色",
1492 "Height of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時的節點像素高度。",1491 "Height of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時的節點像素高度。",
1493 "How the automatic graph builder assigns a rank (layout depth) to graph nodes.": "自動圖表生成器分配圖節點等級(佈局深度)的方式。",1492 "How the automatic graph builder assigns a rank (layout depth) to graph nodes.": "自動圖表生成器分配圖節點等級(配置深度)的方式。",
1494 "If checked and the character card contains a Post-History Instructions override, use that instead": "勾選後,將使用角色卡中的聊天歷史後指示(Post-History Instructions)覆蓋。",1493 "If checked and the character card contains a Post-History Instructions override, use that instead": "勾選後,將使用角色卡中的聊天歷史後指示(Post-History Instructions)覆蓋。",
1495 "Import Advanced Formatting settings": "匯入進階格式設定\n也可提供舊版檔案作為提示詞和上下文範本使用",1494 "Import Advanced Formatting settings": "匯入進階格式設定\n也可提供舊版檔案作為提示詞和上下文範本使用",
1496 "Import template": "匯入模板",1495 "Import template": "匯入範本",
1497 "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群組聊天中,突出顯示該生成回應的角色及順序。",1496 "In group chat, highlight the character(s) that are currently queued to generate responses and the order in which they will respond.": "在群組聊天中,突出顯示該生成回應的角色及順序。",
1498 "Include names with each message into the context for scanning": "將每條訊息的名稱納入掃描上下文",1497 "Include names with each message into the context for scanning": "將每條訊息的名稱納入掃描上下文",
1499 "Inserted before the first User's message": "插入到第一條使用者訊息前。",1498 "Inserted before the first User's message": "插入到第一條使用者訊息前。",
1500 "instruct_enabled": "啟用指令模式(Instruct Mode)",1499 "instruct_enabled": "啟用指令模式(Instruct Mode)",
1501 "instruct_last_input_sequence": "插入到最後一條使用者訊息之前。",1500 "instruct_last_input_sequence": "插入到最後一條使用者訊息之前。",
1502 "instruct_template_activation_regex_desc": "連線 API 或選擇模型時,若模型名稱符合所提供的正規表達式,則自動啟動該指令模板(Instruct Template)。",1501 "instruct_template_activation_regex_desc": "連線 API 或選擇模型時,若模型名稱符合所提供的正規表達式,則自動啟動該指令範本(Instruct Template)。",
1503 "Load Asset List": "載入資源列表",1502 "Load Asset List": "載入資源列表",
1504 "load_asset_list_desc": "根據資源列表文件載入擴充功能及資源。\n\n該字段中的默認資源 URL 指向官方擴充功能及資源列表。\n可在此插入您的自定義資源列表。\n\n若需安裝單個第三方擴充功能,請使用右上角的「安裝擴充功能」按鈕。",1503 "load_asset_list_desc": "根據資源列表文件載入擴充功能及資源。\n\n該欄位中的預設資源 URL 指向官方擴充功能及資源列表。\n可在此插入您的自定義資源列表。\n\n若需安裝單個第三方擴充功能,請使用右上角的「安裝擴充功能」按鈕。",
1505 "markdown_hotkeys_desc": "啟用快捷鍵以在某些文本輸入框中插入 Markdown 格式字符。詳見「/help hotkeys」。",1504 "markdown_hotkeys_desc": "啟用快捷鍵以在某些文字輸入框中插入 Markdown 格式字元。詳見「/help hotkeys」。",
1506 "Not all samplers supported.": "並非所有採樣器均受支援。",1505 "Not all samplers supported.": "並非所有取樣器均受支援。",
1507 "Open the timeline view. Same as the slash command '/tl'.": "打開時間線視圖,與斜線指令「/tl」相同。",1506 "Open the timeline view. Same as the slash command '/tl'.": "開啟時間線檢視,與斜線指令「/tl」相同。",
1508 "Penalize sequences based on their length.": "根據序列長度進行懲罰。",1507 "Penalize sequences based on their length.": "根據序列長度進行懲罰。",
1509 "Reload a connection profile": "重新載入連線設定檔",1508 "Reload a connection profile": "重新載入連線設定檔",
1510 "Rename current preset": "重新命名此預設",1509 "Rename current preset": "重新命名此預設設定檔",
1511 "Rename current prompt": "重新命名此提示詞",1510 "Rename current prompt": "重新命名此提示詞",
1512 "Rename current template": "重新命名此模板",1511 "Rename current template": "重新命名此範本",
1513 "Reset all Timelines settings to their default values.": "將所有時間軸設定重置為預設值。",1512 "Reset all Timelines settings to their default values.": "將所有時間軸設定重設為預設值。",
1514 "Restore current prompt": "還原目前的提示詞",1513 "Restore current prompt": "還原目前的提示詞",
1515 "Restore current template": "還原目前的模板",1514 "Restore current template": "還原目前的範本",
1516 "Save prompt as": "另存提示詞為",1515 "Save prompt as": "另存提示詞為",
1517 "Save template as": "另存模板為",1516 "Save template as": "另存範本為",
1518 "sd_adetailer_face": "在生成過程中使用 ADetailer 臉部模型。需在後端安裝 ADetailer 擴充功能。",1517 "sd_adetailer_face": "在生成過程中使用 ADetailer 臉部模型。需在後端安裝 ADetailer 擴充功能。",
1519 "sd_free_extend": "自動使用目前選定的 LLM 擴充功能的「自由模式」提示詞(不包括肖像或背景)。",1518 "sd_free_extend": "自動使用目前選定的 LLM 擴充功能的「自由模式」提示詞(不包括肖像或背景)。",
1520 "sd_function_tool": "使用功能工具自動檢測意圖以生成圖片。",1519 "sd_function_tool": "使用功能工具自動偵測意圖以生成圖片。",
1521 "Seed_desc": "用於生成確定性和可重現輸出的隨機種子。設定為 -1 時將使用隨機種子。",1520 "Seed_desc": "用於生成確定性和可重現輸出的隨機種子。設定為 -1 時將使用隨機種子。",
1522 "Select your current Context Template": "選擇您目前的上下文模板",1521 "Select your current Context Template": "選擇您目前的上下文範本",
1523 "Select your current Instruct Template": "選擇您目前的指令模板",1522 "Select your current Instruct Template": "選擇您目前的指令範本",
1524 "Select your current System Prompt": "選擇您目前的系統提示詞",1523 "Select your current System Prompt": "選擇您目前的系統提示詞",
1525 "Separation between adjacent edges in the same rank.": "同一層級中相鄰邊之間的間距。",1524 "Separation between adjacent edges in the same rank.": "同一層級中相鄰邊之間的間距。",
1526 "Separation between adjacent nodes in the same rank.": "同一層級中相鄰節點之間的間距。",1525 "Separation between adjacent nodes in the same rank.": "同一層級中相鄰節點之間的間距。",
1527 "Separation between each rank in the layout.": "佈局中各層級之間的間距。",1526 "Separation between each rank in the layout.": "配置中各層級之間的間距。",
1528 "Settings for the visual appearance of the Timelines graph.": "時間線圖形的視覺外觀設置。",1527 "Settings for the visual appearance of the Timelines graph.": "時間線圖形的視覺外觀設定。",
1529 "Show a button in the input area to ask the AI to impersonate your character for a single message": "於輸入框中添加按鈕,讓 AI 模仿您的角色發送一則訊息。",1528 "Show a button in the input area to ask the AI to impersonate your character for a single message": "於輸入框中新增按鈕,讓 AI 模仿您的角色傳送一則訊息。",
1530 "Show a legend for colors corresponding to different characters and chat checkpoints.": "顯示一個圖例,標註不同角色和對話檢查點對應的顏色。",1529 "Show a legend for colors corresponding to different characters and chat checkpoints.": "顯示一個圖例,標註不同角色和對話檢查點對應的顏色。",
1531 "Show the AI character's avatar as the graph root node. When off, the root node is blank.": "將 AI 角色的頭像作為圖形的根節點;關閉時,根節點為空。",1530 "Show the AI character's avatar as the graph root node. When off, the root node is blank.": "將 AI 角色的頭像作為圖形的根節點;關閉時,根節點為空。",
1532 "Sticky entries will stay active for N messages after being triggered.": "觸發後,置頂條目將在接下來的 N 條訊息中保持活躍。",1531 "Sticky entries will stay active for N messages after being triggered.": "觸發後,置頂條目將在接下來的 N 條訊息中保持活躍。",
1533 "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} 和 {{getglobalvar::}} 巨集的字面巨集樣值被自動解析。\n例如,{{newline}} 將保持為字面字串 {{newline}}。\n\n(此功能通過內部將 {{getvar::}} 和 {{getglobalvar::}} 巨集替換為局部變數來實現。)",1532 "stscript_parser_flag_replace_getvar_label": "防止 {{getvar::}} 和 {{getglobalvar::}} 巨集的字面巨集樣值被自動解析。\n例如,{{newline}} 將保持為字面字串 {{newline}}。\n\n(此功能透過內部將 {{getvar::}} 和 {{getglobalvar::}} 巨集替換為區域變數來實現。)",
1534 "Style and routing of graph edges.": "圖形邊的樣式和路徑。",1533 "Style and routing of graph edges.": "圖形邊的樣式和路徑。",
1535 "Swap width and height": "交換寬度與高度",1534 "Swap width and height": "交換寬度與高度",
1536 "Swipe left": "向左滑動",1535 "Swipe left": "向左滑動",
@@ -1541,14 +1540,14 @@
1541 "The visual appearance of a node in the graph.": "圖形中節點的視覺外觀。",1540 "The visual appearance of a node in the graph.": "圖形中節點的視覺外觀。",
1542 "Update a connection profile": "更新連線設定檔",1541 "Update a connection profile": "更新連線設定檔",
1543 "Update current prompt": "更新此提示詞",1542 "Update current prompt": "更新此提示詞",
1544 "Update current template": "更新此模板",1543 "Update current template": "更新此範本",
1545 "Use GPU acceleration for positioning the full info panel that appears when you click a node. If the tooltip arrow tends to disappear, turning this off may help.": "啟用 GPU 加速來定位點擊節點時出現的完整資訊面板。若發現工具提示箭頭經常消失,可考慮關閉此功能。",1544 "Use GPU acceleration for positioning the full info panel that appears when you click a node. If the tooltip arrow tends to disappear, turning this off may help.": "啟用 GPU 加速來定位點選節點時出現的完整資訊面板。若發現工具提示箭頭經常消失,可考慮關閉此功能。",
1546 "Use the colors of the ST GUI theme, instead of the colors configured in Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。",1545 "Use the colors of the ST GUI theme, instead of the colors configured in Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。",
1547 "View connection profile details": "查看連線設定檔詳情",1546 "View connection profile details": "檢視連線設定檔詳細資訊",
1548 "When enabled, nodes that have swipes splitting off of them will appear subtly larger, in addition to having the double border.": "啟用後,具分支滑動的節點將顯示雙重邊框,還會略微放大。",1547 "When enabled, nodes that have swipes splitting off of them will appear subtly larger, in addition to having the double border.": "啟用後,具分支滑動的節點將顯示雙重邊框,還會略微放大。",
1549 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界資訊條目狀態:\\r🔵 恆定\\r🟢 正常\\r🔗 向量化",1548 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "世界資訊條目狀態:\\r🔵 恆定\\r🟢 正常\\r🔗 向量化",
1550 "Width of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時,節點的像素寬度。",1549 "Width of a node, in pixels at zoom level 1.0.": "縮放等級為 1.0 時,節點的像素寬度。",
1551 "world_button_title": "角色背景設定\n「Shift+點擊」可開啟「連結至世界資訊」彈窗",1550 "world_button_title": "角色背景設定\n「Shift+點選」可開啟「連結至世界資訊」彈窗",
1552 "# of Beams": "# of Beams",1551 "# of Beams": "# of Beams",
1553 "01.AI API Key": "01.AI API 金鑰",1552 "01.AI API Key": "01.AI API 金鑰",
1554 "01.AI Model": "01.AI 模型",1553 "01.AI Model": "01.AI 模型",
@@ -1559,7 +1558,7 @@
1559 "Allow Post-History Instructions": "允許聊天歷史後指示",1558 "Allow Post-History Instructions": "允許聊天歷史後指示",
1560 "Allow reverse proxy": "允許反向代理",1559 "Allow reverse proxy": "允許反向代理",
1561 "Alternate Greeting #": "備選問候語 #",1560 "Alternate Greeting #": "備選問候語 #",
1562 "alternate_greetings_hint_1": "點擊",1561 "alternate_greetings_hint_1": "點選",
1563 "alternate_greetings_hint_2": "按鈕開始!",1562 "alternate_greetings_hint_2": "按鈕開始!",
1564 "Always": "總是",1563 "Always": "總是",
1565 "ANY support requests will be REFUSED if you are using a proxy.": "使用代理時,所有支援請求均不予受理。",1564 "ANY support requests will be REFUSED if you are using a proxy.": "使用代理時,所有支援請求均不予受理。",
@@ -1571,14 +1570,13 @@
1571 "Assistant Message Sequences": "助理訊息序列",1570 "Assistant Message Sequences": "助理訊息序列",
1572 "Assistant Prefix": "助理訊息前綴",1571 "Assistant Prefix": "助理訊息前綴",
1573 "Assistant Suffix": "助理訊息後綴",1572 "Assistant Suffix": "助理訊息後綴",
1574 "at the end of the URL!": "在 URL 末尾!",
1575 "Audio Playback Speed": "音檔播放速度",1573 "Audio Playback Speed": "音檔播放速度",
1576 "Auto-select Input Text": "自動選擇輸入文本",1574 "Auto-select Input Text": "自動選擇輸入文字",
1577 "Automatically caption images": "自動產生圖片註解",1575 "Automatically caption images": "自動產生圖片註解",
1578 "Auxiliary": "輔助提示詞",1576 "Auxiliary": "輔助提示詞",
1579 "Background Image": "背景圖片",1577 "Background Image": "背景圖片",
1580 "Block Entropy API Key": "Block Entropy API 金鑰",1578 "Block Entropy API Key": "Block Entropy API 金鑰",
1581 "Can be set manually or with an _space": "可以手動設置或使用 _space",1579 "Can be set manually or with an _space": "可以手動設定或使用 _space",
1582 "Caption Prompt": "註解功能提示詞",1580 "Caption Prompt": "註解功能提示詞",
1583 "category": "類別",1581 "category": "類別",
1584 "Character Expressions": "角色情緒立繪",1582 "Character Expressions": "角色情緒立繪",
@@ -1591,12 +1589,12 @@
1591 "Checkpoint Color": "檢查點節點邊框顏色",1589 "Checkpoint Color": "檢查點節點邊框顏色",
1592 "Chunk boundary": "Chunk 邊界",1590 "Chunk boundary": "Chunk 邊界",
1593 "Chunk overlap (%)": "Chunk 重疊(%)",1591 "Chunk overlap (%)": "Chunk 重疊(%)",
1594 "Chunk size (chars)": "Chunk 大小(字符數)",1592 "Chunk size (chars)": "Chunk 大小(字元數)",
1595 "class": "所有類別",1593 "class": "所有類別",
1596 "Classifier API": "分類器 API",1594 "Classifier API": "分類器 API",
1597 "Click to set": "點擊以設定",1595 "Click to set": "點選以設定",
1598 "CLIP Skip": "CLIP 跳過",1596 "CLIP Skip": "CLIP 跳過",
1599 "Completion Object": "完成對象",1597 "Completion Object": "完成物件",
1600 "Conf": "設定檔",1598 "Conf": "設定檔",
1601 "Connection Profile": "連線設定檔",1599 "Connection Profile": "連線設定檔",
1602 "Cooldown": "冷卻時間",1600 "Cooldown": "冷卻時間",
@@ -1605,13 +1603,13 @@
1605 "currently_selected": "[目前已選取]",1603 "currently_selected": "[目前已選取]",
1606 "Custom (OpenAI-compatible)": "自定義(相容 OpenAI)",1604 "Custom (OpenAI-compatible)": "自定義(相容 OpenAI)",
1607 "Custom Expressions": "自定義角色表情",1605 "Custom Expressions": "自定義角色表情",
1608 "Data Bank files": "數據庫文件",1606 "Data Bank files": "資料庫文件",
1609 "Default / Fallback Expression": "默認/回退表情",1607 "Default / Fallback Expression": "預設/回退表情",
1610 "Delay": "延遲",1608 "Delay": "延遲",
1611 "Delay until recursion (can only be activated on recursive checking)": "遞迴掃描延遲(僅在啟用遞迴掃描時可用)",1609 "Delay until recursion (can only be activated on recursive checking)": "遞迴掃描延遲(僅在啟用遞迴掃描時可用)",
1612 "Do not proceed if you do not agree to this!": "若不同意此條款,請勿繼續!",1610 "Do not proceed if you do not agree to this!": "若不同意此條款,請勿繼續!",
1613 "Edge Color": "邊緣顏色",1611 "Edge Color": "邊緣顏色",
1614 "Edit captions before saving": "在保存前編輯註解",1612 "Edit captions before saving": "在儲存前編輯註解",
1615 "Enable for files": "啟用文件檔案向量化",1613 "Enable for files": "啟用文件檔案向量化",
1616 "Enable for World Info": "啟用世界資訊向量化",1614 "Enable for World Info": "啟用世界資訊向量化",
1617 "enable_functions_desc_1": "允許使用",1615 "enable_functions_desc_1": "允許使用",
@@ -1623,8 +1621,8 @@
1623 "Enter a Model ID": "輸入模型 ID",1621 "Enter a Model ID": "輸入模型 ID",
1624 "Example: https://****.endpoints.huggingface.cloud": "例如:https://****.endpoints.huggingface.cloud",1622 "Example: https://****.endpoints.huggingface.cloud": "例如:https://****.endpoints.huggingface.cloud",
1625 "Exclude": "排除",1623 "Exclude": "排除",
1626 "Exclude Top Choices (XTC)": "排除頂部選項(XTC)",1624 "Exclude Top Choices (XTC)": "排除頂端選項(XTC)",
1627 "Existing": "現有項目",1625 "tag_import_existing": "現有項目",
1628 "expression_label_pattern": "[情緒名稱].[圖檔格式](例如:neutral.png)。",1626 "expression_label_pattern": "[情緒名稱].[圖檔格式](例如:neutral.png)。",
1629 "ext_translate_auto_mode": "自動翻譯模式",1627 "ext_translate_auto_mode": "自動翻譯模式",
1630 "ext_translate_btn_chat": "翻譯聊天內容",1628 "ext_translate_btn_chat": "翻譯聊天內容",
@@ -1644,16 +1642,15 @@
1644 "File vectorization settings": "檔案向量化設定",1642 "File vectorization settings": "檔案向量化設定",
1645 "Filter to Characters or Tags": "角色/標籤篩選",1643 "Filter to Characters or Tags": "角色/標籤篩選",
1646 "First User Prefix": "第一使用者前綴",1644 "First User Prefix": "第一使用者前綴",
1647 "folder of your user data directory and name it as the name of the character.": "」中新建資料夾,並將該資料夾命名為角色名稱(名稱需與使用者資料夾中的角色名稱一致)。",1645 "folder of your user data directory and name it as the name of the character.": "」中新增資料夾,並將該資料夾命名為角色名稱(名稱需與使用者資料夾中的角色名稱一致)。",
1648 "Group Scoring": "群組評分",1646 "Group Scoring": "群組評分",
1649 "Groups and Past Personas": "群組與過去的使用者角色設定",1647 "Groups and Past Personas": "群組與過去的使用者角色設定",
1650 "Hint:": "提示:",1648 "Hint:": "提示:",
1651 "Hint: Set the URL in the API connection settings.": "提示:在 API 連線設置中設定 URL。",1649 "Hint: Set the URL in the API connection settings.": "提示:在 API 連線設定中設定 URL。",
1652 "Horde": "Horde",1650 "Horde": "Horde",
1653 "HuggingFace Token": "HuggingFace 符元",1651 "HuggingFace Token": "HuggingFace 符元",
1654 "Image Captioning": "圖片註解",1652 "Image Captioning": "圖片註解",
1655 "Generate Caption": "產生圖片註解",1653 "Generate Caption": "產生圖片註解",
1656 "Image Type - talkinghead (extras)": "圖片類型 - talkinghead(額外選項)",
1657 "Injection Position": "插入位置",1654 "Injection Position": "插入位置",
1658 "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "插入位置(與提示詞管理器中的其他提示相比)或聊天中的深度位置。",1655 "Injection position. Relative (to other prompts in prompt manager) or In-chat @ Depth.": "插入位置(與提示詞管理器中的其他提示相比)或聊天中的深度位置。",
1659 "Injection Template": "插入範本",1656 "Injection Template": "插入範本",
@@ -1662,17 +1659,17 @@
1662 "Instruct Template": "指令範本",1659 "Instruct Template": "指令範本",
1663 "Interactive Mode": "互動模式",1660 "Interactive Mode": "互動模式",
1664 "Karras": "Karras",1661 "Karras": "Karras",
1665 "Keep model in memory": "將模型保存在記憶體中",1662 "Keep model in memory": "將模型儲存在記憶體中",
1666 "Keyboard": "鍵盤:",1663 "Keyboard": "鍵盤:",
1667 "AI Horde Website": "AI Horde 網站",1664 "AI Horde Website": "AI Horde 網站",
1668 "Last User Prefix": "最後用戶前綴",1665 "Last User Prefix": "最後使用者前綴",
1669 "Linear": "線性",1666 "Linear": "線性",
1670 "LLM": "LLM",1667 "LLM": "LLM",
1671 "LLM Prompt": "LLM 提示詞",1668 "LLM Prompt": "LLM 提示詞",
1672 "Load a custom asset list or select": "載入或選擇自定義資源列表",1669 "Load a custom asset list or select": "載入或選擇自定義資源列表",
1673 "Load an asset list": "載入資源列表",1670 "Load an asset list": "載入資源列表",
1674 "Local": "本地",1671 "Local": "本機",
1675 "Local (Transformers)": "本地(Transformers)",1672 "Local (Transformers)": "本機(Transformers)",
1676 "macro)": "巨集)",1673 "macro)": "巨集)",
1677 "Main API": "主要 API",1674 "Main API": "主要 API",
1678 "Markdown Hotkeys": "Markdown 快捷鍵",1675 "Markdown Hotkeys": "Markdown 快捷鍵",
@@ -1681,20 +1678,20 @@
1681 "Max Entries": "最大條目數",1678 "Max Entries": "最大條目數",
1682 "Max Recursion Steps": "最大遞迴步數",1679 "Max Recursion Steps": "最大遞迴步數",
1683 "Message attachments": "訊息附件",1680 "Message attachments": "訊息附件",
1684 "Message Template": "訊息模板",1681 "Message Template": "訊息範本",
1685 "Model ID": "模型 ID",1682 "Model ID": "模型 ID",
1686 "mui_reset": "重置",1683 "mui_reset": "重設",
1687 "Multimodal (OpenAI / Anthropic / llama / Google)": "多模態(OpenAI/Anthropic/llama/Google)",1684 "Multimodal (OpenAI / Anthropic / llama / Google)": "多模態(OpenAI/Anthropic/llama/Google)",
1688 "must be set in Tabby's config.yml to switch models.": "須在 Tabby's config.yml 中設置以切換模型。",1685 "must be set in Tabby's config.yml to switch models.": "須在 Tabby's config.yml 中設定以切換模型。",
1689 "Names as Stop Strings": "將名稱用作停止字串",1686 "Names as Stop Strings": "將名稱用作停止字串",
1690 "Never": "從不",1687 "Never": "從不",
1691 "NomicAI API Key": "NomicAI API 金鑰",1688 "NomicAI API Key": "NomicAI API 金鑰",
1692 "Non-recursable (will not be activated by another)": "不可遞迴(不會被其他條目啟動)",1689 "Non-recursable (will not be activated by another)": "不可遞迴(不會被其他條目啟動)",
1693 "None (disabled)": "無(已禁用)",1690 "None (disabled)": "無(已停用)",
1694 "OK": "確定",1691 "OK": "確定",
1695 "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "舊訊息會在聊天時逐步向量化。\n若要處理所有先前訊息,請點擊下方按鈕。",1692 "Old messages are vectorized gradually as you chat. To process all previous messages, click the button below.": "舊訊息會在聊天時逐步向量化。\n若要處理所有先前訊息,請點選下方按鈕。",
1696 "Only used when Main API or WebLLM Extension is selected.": "僅在選擇主要 API 或 WebLLM 擴充功能時使用。",1693 "Only used when Main API or WebLLM Extension is selected.": "僅在選擇主要 API 或 WebLLM 擴充功能時使用。",
1697 "Open a chat to see the character expressions.": "開啟聊天以查看角色表情。",1694 "Open a chat to see the character expressions.": "開啟聊天以檢視角色表情。",
1698 "Post-History Instructions": "聊天歷史後指示",1695 "Post-History Instructions": "聊天歷史後指示",
1699 "Prefer Character Card Instructions": "角色卡聊天歷史後指示優先",1696 "Prefer Character Card Instructions": "角色卡聊天歷史後指示優先",
1700 "Prioritize": "優先處理",1697 "Prioritize": "優先處理",
@@ -1708,7 +1705,7 @@
1708 "Quick Impersonate button": "快速模擬按鈕",1705 "Quick Impersonate button": "快速模擬按鈕",
1709 "Recursion Level": "遞迴層級",1706 "Recursion Level": "遞迴層級",
1710 "Remove all image overrides": "移除所有圖片覆蓋",1707 "Remove all image overrides": "移除所有圖片覆蓋",
1711 "Restore default": "",1708 "Restore default": "恢復預設",
1712 "Retain#": "保留#",1709 "Retain#": "保留#",
1713 "Retrieve chunks": "檢索 Chunks",1710 "Retrieve chunks": "檢索 Chunks",
1714 "Sampler Order": "取樣順序",1711 "Sampler Order": "取樣順序",
@@ -1716,7 +1713,7 @@
1716 "sd_free_extend_small": "(互動/指令)",1713 "sd_free_extend_small": "(互動/指令)",
1717 "sd_free_extend_txt": "使用「自由模式」。由 LLM 自動擴寫圖片生成提示",1714 "sd_free_extend_txt": "使用「自由模式」。由 LLM 自動擴寫圖片生成提示",
1718 "sd_function_tool_txt": "使用功能工具",1715 "sd_function_tool_txt": "使用功能工具",
1719 "sd_prompt_-1": "聊天訊息模板",1716 "sd_prompt_-1": "聊天訊息範本",
1720 "sd_prompt_-2": "功能工具提示詞",1717 "sd_prompt_-2": "功能工具提示詞",
1721 "sd_prompt_0": "角色(第二人稱,你)",1718 "sd_prompt_0": "角色(第二人稱,你)",
1722 "sd_prompt_1": "使用者(第一人稱,我)",1719 "sd_prompt_1": "使用者(第一人稱,我)",
@@ -1734,19 +1731,19 @@
1734 "Select with Enter": "按 Enter 選擇",1731 "Select with Enter": "按 Enter 選擇",
1735 "Select with Tab": "按 Tab 選擇",1732 "Select with Tab": "按 Tab 選擇",
1736 "Select with Tab or Enter": "按 Tab 或 Enter 選擇",1733 "Select with Tab or Enter": "按 Tab 或 Enter 選擇",
1737 "Separators as Stop Strings": "以分隔符作為停止字串",1734 "Separators as Stop Strings": "以分隔符號作為停止字串",
1738 "Set the default and fallback expression being used when no matching expression is found.": "設定在無法配對表情時所使用的預設表情和備用圖片。",1735 "Set the default and fallback expression being used when no matching expression is found.": "設定在無法配對表情時所使用的預設表情和備用圖片。",
1739 "Set your API keys and endpoints in the API Connections tab first.": "請先在「API 連線」頁面中設定您的 API 金鑰和端點。",1736 "Set your API keys and endpoints in the API Connections tab first.": "請先在「API 連線」頁面中設定您的 API 金鑰和端點。",
1740 "Show default images (emojis) if sprite missing": "無對應圖片時,顯示為預設表情符號(emoji)",1737 "Show default images (emojis) if sprite missing": "無對應圖片時,顯示為預設表情符號(emoji)",
1741 "Show group chat queue": "顯示群組聊天隊列",1738 "Show group chat queue": "顯示群組聊天佇列",
1742 "Size threshold (KB)": "大小閾值(KB)",1739 "Size threshold (KB)": "大小閾值(KB)",
1743 "Slash Command": "斜線命令",1740 "Slash Command": "斜線命令",
1744 "space_ slash command.": " 斜線命令。",1741 "space_ slash command.": " 斜線命令。",
1745 "Sprite Folder Override": "表情立繪資料夾覆蓋",1742 "Sprite Folder Override": "表情立繪資料夾覆蓋",
1746 "Sprite set:": "立繪組:",1743 "Sprite set:": "立繪組:",
1747 "Show Gallery": "查看圖庫",1744 "Show Gallery": "檢視相簿",
1748 "Sticky": "黏性",1745 "Sticky": "黏性",
1749 "Style Preset": "預設樣式",1746 "Style Preset": "樣式預設設定檔",
1750 "Summarize chat messages for vector generation": "摘要聊天訊息以進行向量化處理",1747 "Summarize chat messages for vector generation": "摘要聊天訊息以進行向量化處理",
1751 "Summarize chat messages when sending": "傳送時摘要聊天內容",1748 "Summarize chat messages when sending": "傳送時摘要聊天內容",
1752 "Swipe # for All Messages": "為所有訊息分配滑動編號 #",1749 "Swipe # for All Messages": "為所有訊息分配滑動編號 #",
@@ -1758,16 +1755,16 @@
1758 "tag_import_all": "全部匯入",1755 "tag_import_all": "全部匯入",
1759 "tag_import_none": "不匯入",1756 "tag_import_none": "不匯入",
1760 "Text Generation WebUI (oobabooga)": "文字生成 WebUI (oobabooga)",1757 "Text Generation WebUI (oobabooga)": "文字生成 WebUI (oobabooga)",
1761 "The server MUST be started with the --embedding flag to use this feature!": "若要使用此功能,伺服器必須啟動時加上 --embedding 標誌。",1758 "The server MUST be started with the --embedding flag to use this feature!": "若要使用此功能,伺服器必須啟動時加上 --embedding 象徵。",
1762 "Threshold": "閾值",1759 "Threshold": "閾值",
1763 "to install 3rd party extensions.": "用於安裝第三方擴充功能。",1760 "to install 3rd party extensions.": "用於安裝第三方擴充功能。",
1764 "Top": "頂部",1761 "Top": "頂端",
1765 "Translate text to English before classification": "在分類前將文本翻譯為英文。",1762 "Translate text to English before classification": "分類前,將訊息翻譯為英文",
1766 "Uncheck to hide the extensions messages in chat prompts.": "不勾選即可隱藏聊天提示詞中的擴充功能訊息。",1763 "Uncheck to hide the extensions messages in chat prompts.": "不勾選即可隱藏聊天提示詞中的擴充功能訊息。",
1767 "Unchecked: only entries with ❌ status can be activated.": "未勾選時:僅允許啟用狀態為 ❌ 的條目。",1764 "Unchecked: only entries with ❌ status can be activated.": "未勾選時:僅允許啟用狀態為 ❌ 的條目。",
1768 "Unified Sampling": "統一取樣(Unified Sampling)",1765 "Unified Sampling": "統一取樣(Unified Sampling)",
1769 "Upload sprite pack (ZIP)": "批次上傳立繪包(.ZIP)",1766 "Upload sprite pack (ZIP)": "批次上傳立繪包(.ZIP)",
1770 "Use a forward slash to specify a subfolder. Example: _space": "使用「/」來設置子目錄,例如:_space",1767 "Use a forward slash to specify a subfolder. Example: _space": "使用「/」來設定子目錄,例如:_space",
1771 "Use ADetailer (Face)": "使用 ADetailer 進行臉部處理。",1768 "Use ADetailer (Face)": "使用 ADetailer 進行臉部處理。",
1772 "Use an admin API key.": "使用管理員的 API 金鑰。",1769 "Use an admin API key.": "使用管理員的 API 金鑰。",
1773 "Use global": "啟用全域設定",1770 "Use global": "啟用全域設定",
@@ -1775,21 +1772,21 @@
1775 "User Node Color": "使用者節點顏色",1772 "User Node Color": "使用者節點顏色",
1776 "User Prefix": "使用者訊息前綴",1773 "User Prefix": "使用者訊息前綴",
1777 "User Suffix": "使用者訊息後綴",1774 "User Suffix": "使用者訊息後綴",
1778 "Using a proxy that youre not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務存在數據隱私洩漏風險。",1775 "Using a proxy that youre not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務存在資料隱私洩漏風險。",
1779 "Vector Storage": "向量存儲",1776 "Vector Storage": "向量儲存",
1780 "Vector Summarization": "向量摘要",1777 "Vector Summarization": "向量摘要",
1781 "Vectorization Model": "向量生成模型",1778 "Vectorization Model": "向量生成模型",
1782 "Vectorization Source": "向量化來源",1779 "Vectorization Source": "向量化來源",
1783 "Vectorize All": "向量化全部數據",1780 "Vectorize All": "向量化全部資料",
1784 "View Stats": "查看統計資料",1781 "View Stats": "檢視統計資料",
1785 "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:這可能會導致訊息處理速度變慢,並延長回應時間。",1782 "Warning: This might cause your sent messages to take a bit to process and slow down response time.": "警告:這可能會導致訊息處理速度變慢,並延長回應時間。",
1786 "WarningThis might cause your sent messages to take a bit to process and slow down response time.": "警告:這將顯著減緩向量生成速度,因為所有消息都需先進行摘要。",1783 "WarningThis might cause your sent messages to take a bit to process and slow down response time.": "警告:這將顯著減緩向量生成速度,因為所有訊息都需先進行摘要。",
1787 "WebLLM Extension": "WebLLM 擴充功能",1784 "WebLLM Extension": "WebLLM 擴充功能",
1788 "Whole Words": "匹配完整單字",1785 "Whole Words": "匹配完整單字",
1789 "Will be used if the API doesnt support JSON schemas or function calling.": "若 API 不支持 JSON 模式或函數調用,將使用此設定。",1786 "Will be used if the API doesnt support JSON schemas or function calling.": "若 API 不支援 JSON 模式或函式呼叫,將使用此設定。",
1790 "World Info settings": "世界資訊設定",1787 "World Info settings": "世界資訊設定",
1791 "You are in offline mode. Click on the image below to set the expression.": "您目前為離線狀態,請點擊下方圖片進行表情設定。",1788 "You are in offline mode. Click on the image below to set the expression.": "您目前為離線狀態,請點選下方圖片進行表情設定。",
1792 "You can find your API key in the Stability AI dashboard.": "API 金鑰可在 Stability AI 儀表板中查看。",1789 "You can find your API key in the Stability AI dashboard.": "API 金鑰可在 Stability AI 儀錶板中檢視。",
1793 "Stop Inspecting": "停止檢查",1790 "Stop Inspecting": "停止檢查",
1794 "Inspect Prompts": "檢查提示詞",1791 "Inspect Prompts": "檢查提示詞",
1795 "Toggle prompt inspection": "切換提示詞檢查",1792 "Toggle prompt inspection": "切換提示詞檢查",
@@ -1799,19 +1796,19 @@
1799 "KoboldAI Horde": "KoboldAI Horde",1796 "KoboldAI Horde": "KoboldAI Horde",
1800 "KoboldAI Horde Website": "KoboldAI Horde 網站",1797 "KoboldAI Horde Website": "KoboldAI Horde 網站",
1801 "Derive context size from backend": "從後端推導上下文大小",1798 "Derive context size from backend": "從後端推導上下文大小",
1802 "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務可能導致您的數據隱私外洩。",1799 "Using a proxy that you're not running yourself is a risk to your data privacy.": "使用非自行管理的代理服務可能導致您的資料隱私外洩。",
1803 "Claude API Key": "Claude API 金鑰",1800 "Claude API Key": "Claude API 金鑰",
1804 "NanoGPT API Key": "NanoGPT API 金鑰",1801 "NanoGPT API Key": "NanoGPT API 金鑰",
1805 "NanoGPT Model": "NanoGPT 模型",1802 "NanoGPT Model": "NanoGPT 模型",
1806 "context_derived": "若可能,根據模型元數據推導。",1803 "context_derived": "若可能,根據模型後設資料推導。",
1807 "instruct_derived": "若可能,根據模型元數據推導。",1804 "instruct_derived": "若可能,根據模型後設資料推導。",
1808 "Inserted before the first User's message.": "插入於第一則使用者訊息之前。",1805 "Inserted before the first User's message.": "插入於第一則使用者訊息之前。",
1809 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\\n(disabled when min activations are used)": "0 = 無限制,1 = 掃描一次不遞歸,2 = 掃描一次後遞歸一次 ⋯以此類推\n(啟用最小啟動次數時無效)",1806 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = 無限制,1 = 掃描一次不遞迴,2 = 掃描一次後遞迴一次 ⋯以此類推\n(啟用最小啟動次數時無效)",
1810 "Quick 'Impersonate' button": "快速「AI 扮演使用者」按鈕",1807 "Quick 'Impersonate' button": "快速「AI 扮演使用者」按鈕",
1811 "Manual": "手動",1808 "Manual": "手動",
1812 "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "此處填入的內容將取代該角色的默認聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)",1809 "Any contents here will replace the default Post-History Instructions used for this character. (v2 spec: post_history_instructions)": "此處填入的內容將取代該角色的預設聊天歷史後指示(Post-History Instructions)。\n(v2 格式:specpost_history_instructions)",
1813 "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示內容由其他地方提取,無法在此進行編輯。",1810 "The content of this prompt is pulled from elsewhere and cannot be edited here.": "此提示內容由其他地方提取,無法在此進行編輯。",
1814 "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "開啟檢查點聊天\n使用「Shift+點擊」將以新檢查點替換現有的。",1811 "Open checkpoint chat\nShift+Click to replace the existing checkpoint with a new one": "開啟檢查點聊天\n使用「Shift+點選」將以新檢查點替換現有的。",
1815 "Reroll with the entire prefix": "使用完整前綴重新生成",1812 "Reroll with the entire prefix": "使用完整前綴重新生成",
1816 "Disable": "停用",1813 "Disable": "停用",
1817 "Enable": "啟用",1814 "Enable": "啟用",
@@ -1823,17 +1820,17 @@
1823 "{{@key}}": "{{@key}}:",1820 "{{@key}}": "{{@key}}:",
1824 "Enter a name:": "輸入名稱:",1821 "Enter a name:": "輸入名稱:",
1825 "Omitted Settings:": "忽略的設定:",1822 "Omitted Settings:": "忽略的設定:",
1826 "Will be used if the API doesn't support JSON schemas or function calling.": "將於 API 不支援 JSON 結構或函數調用時使用。",1823 "Will be used if the API doesn't support JSON schemas or function calling.": "將於 API 不支援 JSON 結構或函式呼叫時使用。",
1827 "ext_sum_webllm": "WebLLM 擴充功能",1824 "ext_sum_webllm": "WebLLM 擴充功能",
1828 "ext_sum_restore_tip": "恢復先前的摘要;重複使用以清除此聊天的摘要狀態。",1825 "ext_sum_restore_tip": "恢復先前的摘要;重複使用以清除此聊天的摘要狀態。",
1829 "ext_sum_force_tip": "將立即更新摘要。",1826 "ext_sum_force_tip": "將立即更新摘要。",
1830 "ext_sum_include_wi_scan_desc": "於掃描世界資訊時包含最新摘要。",1827 "ext_sum_include_wi_scan_desc": "於掃描世界資訊時包含最新摘要。",
1831 "ext_sum_include_wi_scan": "包含世界資訊掃描",1828 "ext_sum_include_wi_scan": "包含世界資訊掃描",
1832 "None (not injected)": "無(不插入)",1829 "None (not injected)": "無(不插入)",
1833 "ext_sum_injection_position_none": "此摘要將不會插入提示詞中,但可通過 {{summary}} 巨集訪問。",1830 "ext_sum_injection_position_none": "此摘要將不會插入提示詞中,但可透過 {{summary}} 巨集存取。",
1834 "Labels and Message": "標籤與訊息",1831 "Labels and Message": "標籤與訊息",
1835 "Label": "標籤",1832 "Label": "標籤",
1836 "(label of the button, if no icon is chosen) ": "(若未選擇圖標,則為按鈕的標籤)",1833 "(label of the button, if no icon is chosen) ": "(若未選擇圖示,則為按鈕的標籤)",
1837 "Title": "名稱",1834 "Title": "名稱",
1838 "(tooltip, leave empty to show message or /command)": "(工具提示,留空以顯示訊息或 /command)",1835 "(tooltip, leave empty to show message or /command)": "(工具提示,留空以顯示訊息或 /command)",
1839 "Message / Command:": "訊息/指令:",1836 "Message / Command:": "訊息/指令:",
@@ -1848,7 +1845,7 @@
1848 "Execute on user message": "根據使用者訊息執行",1845 "Execute on user message": "根據使用者訊息執行",
1849 "Execute on AI message": "根據 AI 訊息執行",1846 "Execute on AI message": "根據 AI 訊息執行",
1850 "Execute on chat change": "聊天內容變更時執行",1847 "Execute on chat change": "聊天內容變更時執行",
1851 "Execute on new chat": "新建聊天時執行",1848 "Execute on new chat": "新增聊天時執行",
1852 "Execute on group member draft": "群組成員變更時執行",1849 "Execute on group member draft": "群組成員變更時執行",
1853 "Automation ID:": "自動化 ID:",1850 "Automation ID:": "自動化 ID:",
1854 "Testing": "測試",1851 "Testing": "測試",
@@ -1859,43 +1856,43 @@
1859 "Global Quick Reply Sets": "全域快速回覆",1856 "Global Quick Reply Sets": "全域快速回覆",
1860 "Chat Quick Reply Sets": "聊天快速回覆",1857 "Chat Quick Reply Sets": "聊天快速回覆",
1861 "Edit Quick Replies": "編輯快速回覆",1858 "Edit Quick Replies": "編輯快速回覆",
1862 "Disable Send (Insert Into Input Field)": "停用發送(插入到輸入字段)",1859 "Disable Send (Insert Into Input Field)": "停用傳送(插入到輸入欄位)",
1863 "Place Quick Reply Before Input": "在輸入前插入快速回覆",1860 "Place Quick Reply Before Input": "在輸入前插入快速回覆",
1864 "Inject user input automatically": "自動插入使用者輸入",1861 "Inject user input automatically": "自動插入使用者輸入",
1865 "(if disabled, use ": "(若停用,請使用",1862 "(if disabled, use ": "(若停用,請使用",
1866 "macro for manual injection)": "巨集進行手動插入)",1863 "macro for manual injection)": "巨集進行手動插入)",
1867 "Color": "顏色",1864 "Color": "顏色",
1868 "Only apply color as accent": "僅使用顏色作為強調",1865 "Only apply color as accent": "僅使用顏色作為強調",
1869 "ext_regex_new_global_script_desc": "新建「全域」正規表達式",1866 "ext_regex_new_global_script_desc": "新增「全域」正規表達式",
1870 "ext_regex_new_scoped_script_desc": "新建「作用域」正規表達式",1867 "ext_regex_new_scoped_script_desc": "新增「區域」正規表達式",
1871 "ext_regex_disallow_scoped": "不使用作用域正規表達式",1868 "ext_regex_disallow_scoped": "不使用區域正規表達式",
1872 "ext_regex_allow_scoped": "使用作用域正規表達式",1869 "ext_regex_allow_scoped": "使用區域正規表達式",
1873 "ext_regex_user_input_desc": "使用者發送的訊息。",1870 "ext_regex_user_input_desc": "使用者傳送的訊息。",
1874 "ext_regex_ai_input_desc": "從生成式 API 接收到的訊息。",1871 "ext_regex_ai_input_desc": "從生成式 API 接收到的訊息。",
1875 "ext_regex_slash_desc": "使用 STscript 指令發送的訊息。",1872 "ext_regex_slash_desc": "使用 STscript 指令傳送的訊息。",
1876 "ext_regex_wi_desc": "世界資訊/知識書條目內容。需要勾選「僅格式化提示詞」!",1873 "ext_regex_wi_desc": "世界資訊/知識書條目內容。需要勾選「僅格式化提示詞」!",
1877 "ext_regex_run_on_edit_desc": "當指定角色的訊息被編輯時執行正規腳本。",1874 "ext_regex_run_on_edit_desc": "當指定角色的訊息被編輯時執行正規腳本。",
1878 "Macro in Find Regex": "巨集替換模式",1875 "Macro in Find Regex": "巨集替換模式",
1879 "Don't substitute": "不替換(純文字匹配)",1876 "Don't substitute": "不替換(純文字匹配)",
1880 "Substitute (raw)": "原始替換(不處理 *、. 等特殊字符)",1877 "Substitute (raw)": "原始替換(不處理 *、. 等特殊字元)",
1881 "Substitute (escaped)": "轉義替換(將特殊字符 *、. 等當作普通文字處理)",1878 "Substitute (escaped)": "轉義替換(將特殊字元 *、. 等當作普通文字處理)",
1882 "Ephemerality": "暫時性",1879 "Ephemerality": "暫時性",
1883 "ext_regex_only_format_visual_desc": "僅改變聊天界面顯示的訊息,不修改聊天記錄檔案內容。",1880 "ext_regex_only_format_visual_desc": "僅改變聊天介面顯示的訊息,不修改聊天記錄檔案內容。",
1884 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "提示:請於 Horde KoboldAI API 設定中保存 API 金鑰以進行使用。",1881 "Hint: Save an API key in Horde KoboldAI API settings to use it here.": "提示:請於 Horde KoboldAI API 設定中儲存 API 金鑰以進行使用。",
1885 "Prompt Upsampling": "提示提升(Upsampling)",1882 "Prompt Upsampling": "提示提升(Upsampling)",
1886 "Uncheck to hide the extension's messages in chat prompts.": "取消選取可在聊天提示詞中隱藏擴充功能的訊息。",1883 "Uncheck to hide the extension's messages in chat prompts.": "取消選取可在聊天提示詞中隱藏擴充功能的訊息。",
1887 "ext_translate_delete_confirm_1": "確定要刪除嗎?",1884 "ext_translate_delete_confirm_1": "確定要刪除嗎?",
1888 "ext_translate_delete_confirm_2": "這將「永久刪除」本次聊天中所有訊息的翻譯文本,且無法復原。",1885 "ext_translate_delete_confirm_2": "這將「永久刪除」本次聊天中所有訊息的翻譯文字,且無法復原。",
1889 "Select TTS Provider": "選擇 TTS 提供者",1886 "Select TTS Provider": "選擇 TTS 提供者",
1890 "tts_enabled": "啟用",1887 "tts_enabled": "啟用",
1891 "Narrate user messages": "朗讀使用者訊息",1888 "Narrate user messages": "朗讀使用者訊息",
1892 "Auto Generation": "自動生成",1889 "Auto Generation": "自動生成",
1893 "Requires auto generation to be enabled.": "需要啟用自動生成功能。",1890 "Requires auto generation to be enabled.": "需要啟用自動生成功能。",
1894 "Narrate by paragraphs (when streaming)": "按段落朗讀(使用「串流」傳輸時)",1891 "Narrate by paragraphs (when streaming)": "按段落朗讀(使用「串流」時)",
1895 "Only narrate quotes": "僅朗讀「引號」中的文字",1892 "Only narrate quotes": "僅朗讀「引號」中的文字",
1896 "Ignore text, even quotes, inside asterisk": "忽略 *(星號)內的文字(包括「引號」)",1893 "Ignore text, even quotes, inside asterisk": "忽略 *(星號)內的文字(包括「引號」)",
1897 "Narrate only the translated text": "僅朗讀翻譯後的文本",1894 "Narrate only the translated text": "僅朗讀翻譯後的文字",
1898 "Skip codeblocks": "跳過代碼塊",1895 "Skip codeblocks": "跳過程式碼塊",
1899 "Skip tagged blocks": "跳過 <標記> 塊",1896 "Skip tagged blocks": "跳過 <標記> 塊",
1900 "Pass Asterisks to TTS Engine": "將 *(星號)視為普通文字傳送至 TTS 引擎(否則忽略)",1897 "Pass Asterisks to TTS Engine": "將 *(星號)視為普通文字傳送至 TTS 引擎(否則忽略)",
1901 "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:操作後將顯著降低向量生成速度,因為所有訊息都必須先進行摘要。",1898 "Warning: This will slow down vector generation drastically, as all messages have to be summarized first.": "警告:操作後將顯著降低向量生成速度,因為所有訊息都必須先進行摘要。",
@@ -1903,42 +1900,42 @@
1903 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天為臨時聊天,離開後將被刪除。",1900 "this chat is temporary and will be deleted as soon as you leave it.": "此聊天為臨時聊天,離開後將被刪除。",
1904 "Import Tags For _begin": "為",1901 "Import Tags For _begin": "為",
1905 "Import Tags For _end": "匯入標籤",1902 "Import Tags For _end": "匯入標籤",
1906 "Click remove on any tag to remove it from this import.<br />Select one of the import options to finish importing the tags.": "點擊任意標籤上的「移除」可將其於本次匯入中刪除。\n選擇一個匯入選項以完成標籤匯入。",1903 "Click remove on any tag to remove it from this import.<br />Select one of the import options to finish importing the tags.": "點選任意標籤上的「移除」可將其於本次匯入中刪除。\n選擇一個匯入選項以完成標籤匯入。",
1907 "Existing Tags": "現有標籤",1904 "Existing Tags": "現有標籤",
1908 "New Tags": "新標籤",1905 "New Tags": "新標籤",
1909 "Folder Tags": "資料夾標籤",1906 "Folder Tags": "資料夾標籤",
1910 "The following tags will be auto-imported based on the currently selected folders": "以下標籤將根據目前選擇的文件夾自動匯入",1907 "The following tags will be auto-imported based on the currently selected folders": "以下標籤將根據目前選擇的資料夾自動匯入",
1911 "Import None": "不匯入",1908 "Import None": "不匯入",
1912 "Import All": "全部匯入",1909 "Import All": "全部匯入",
1913 "Import Existing": "匯入現有標籤",1910 "Import Existing": "匯入現有標籤",
1914 "Import": "匯入",1911 "Import": "匯入",
1915 "chat_rename_1": "輸入此聊天檔案的新名稱:",1912 "chat_rename_1": "輸入此聊天檔案的新名稱:",
1916 "chat_rename_2": "!! 使用已存在的檔案名將導致錯誤 !!",1913 "chat_rename_2": "!! 使用已存在的檔案名稱將導致錯誤 !!",
1917 "chat_rename_3": "這將斷開各檢查點間的連結。",1914 "chat_rename_3": "這將斷開各檢查點間的連結。",
1918 "chat_rename_4": "無需在末尾加上 `.jsonl`。",1915 "chat_rename_4": "無需在結尾加上 `.jsonl`。",
1919 "Include Body Parameters": "包含請求主體參數",1916 "Include Body Parameters": "包含請求主體參數",
1920 "custom_include_body_desc": "包含在 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- top_k: 20\n- repetition_penalty: 1.1",1917 "custom_include_body_desc": "包含在 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- top_k: 20\n- repetition_penalty: 1.1",
1921 "Exclude Body Parameters": "排除請求主體參數",1918 "Exclude Body Parameters": "排除請求主體參數",
1922 "custom_exclude_body_desc": "排除於 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- frequency_penalty\n- presence_penalty",1919 "custom_exclude_body_desc": "排除於 Chat Completion 請求體中的參數(YAML 格式)\n\n範例:\n- frequency_penalty\n- presence_penalty",
1923 "Include Request Headers": "包含請求頭(Request Headers)",1920 "Include Request Headers": "包含請求標頭(Request Headers)",
1924 "custom_include_headers_desc": "添加於 Chat Completion 請求的自定義標頭(YAML 格式)\n\n範例:\n- CustomHeader: custom-value\n- AnotherHeader: custom-value",1921 "custom_include_headers_desc": "新增於 Chat Completion 請求的自定義標頭(YAML 格式)\n\n範例:\n- CustomHeader: custom-value\n- AnotherHeader: custom-value",
1925 "THIS IS PERMANENT!": "這是「永久性」的!",1922 "THIS IS PERMANENT!": "這是「永久性」的!",
1926 "Also delete the chat files": "同時刪除此聊天檔案",1923 "Also delete the chat files": "同時刪除此聊天檔案",
1927 "Are you sure you want to duplicate this character?": "您確定要複製該角色嗎?",1924 "Are you sure you want to duplicate this character?": "您確定要複製該角色嗎?",
1928 "If you just want to start a new chat with the same character...": "若您只是想與該角色開始新聊天,請使用左下角選單中的「開始新聊天」。",1925 "If you just want to start a new chat with the same character...": "若您只是想與該角色開始新聊天,請使用左下角選單中的「開始新聊天」。",
1929 "forbid_media_global_state_forbidden": "(禁止)",1926 "forbid_media_global_state_forbidden": "(禁止)",
1930 "forbid_media_global_state_allowed": "(允許)",1927 "forbid_media_global_state_allowed": "(允許)",
1931 "help_format_1": "文本格式化命令:",1928 "help_format_1": "文字格式化命令:",
1932 "help_format_2": "*文本*",1929 "help_format_2": "*文字*",
1933 "help_format_3": "顯示為",1930 "help_format_3": "顯示為",
1934 "help_format_4": "斜體",1931 "help_format_4": "斜體",
1935 "help_format_5": "**文本**",1932 "help_format_5": "**文字**",
1936 "help_format_6": "顯示為",1933 "help_format_6": "顯示為",
1937 "help_format_7": "粗體",1934 "help_format_7": "粗體",
1938 "help_format_8": "***text***",1935 "help_format_8": "***text***",
1939 "help_format_9": "顯示為",1936 "help_format_9": "顯示為",
1940 "help_format_10": "粗斜體",1937 "help_format_10": "粗斜體",
1941 "help_format_11": "__文本__",1938 "help_format_11": "__文字__",
1942 "help_format_12": "顯示為",1939 "help_format_12": "顯示為",
1943 "help_format_13": "底線",1940 "help_format_13": "底線",
1944 "help_format_14": "~~text~~",1941 "help_format_14": "~~text~~",
@@ -1969,8 +1966,8 @@
1969 "help_3": "格式化",1966 "help_3": "格式化",
1970 "help_4": "快捷鍵",1967 "help_4": "快捷鍵",
1971 "help_5": "{{macros}}(巨集)",1968 "help_5": "{{macros}}(巨集)",
1972 "help_6": "還有問題嗎?請查看",1969 "help_6": "還有問題嗎?請造訪",
1973 "help_7": "SillyTavern 官方文檔網站",1970 "help_7": "SillyTavern 官方文件網站",
1974 "help_8": " 了解更多資訊!",1971 "help_8": " 了解更多資訊!",
1975 "help_hotkeys_0": "聊天快捷鍵",1972 "help_hotkeys_0": "聊天快捷鍵",
1976 "help_hotkeys_1": "↑(方向鍵)",1973 "help_hotkeys_1": "↑(方向鍵)",
@@ -1980,21 +1977,21 @@
1980 "help_hotkeys_5": "←(方向鍵)",1977 "help_hotkeys_5": "←(方向鍵)",
1981 "help_hotkeys_6": "向左滑動",1978 "help_hotkeys_6": "向左滑動",
1982 "help_hotkeys_7": "→(方向鍵)",1979 "help_hotkeys_7": "→(方向鍵)",
1983 "help_hotkeys_8": "向右滑動(注意:若聊天框中已有輸入,滑動快捷鍵將被禁用)",1980 "help_hotkeys_8": "向右滑動(注意:若聊天框中已有輸入,滑動快捷鍵將被停用)",
1984 "help_hotkeys_9": "Enter",1981 "help_hotkeys_9": "Enter",
1985 "help_hotkeys_10": "(選中聊天框時)",1982 "help_hotkeys_10": "(選中聊天框時)",
1986 "help_hotkeys_10_1": "向 AI 發送您的訊息",1983 "help_hotkeys_10_1": "向 AI 傳送您的訊息",
1987 "help_hotkeys_11": "Ctrl+Enter",1984 "help_hotkeys_11": "Ctrl+Enter",
1988 "help_hotkeys_12": "重新生成最後一則 AI 回應",1985 "help_hotkeys_12": "重新生成最後一則 AI 回應",
1989 "help_hotkeys_13": "Alt+Enter",1986 "help_hotkeys_13": "Alt+Enter",
1990 "help_hotkeys_14": "繼續生成最後一則 AI 回應",1987 "help_hotkeys_14": "繼續生成最後一則 AI 回應",
1991 "help_hotkeys_15": "Esc 鍵",1988 "help_hotkeys_15": "Esc 鍵",
1992 "help_hotkeys_16": "停止 AI 回應生成,關閉使用者界面,取消訊息編輯",1989 "help_hotkeys_16": "停止 AI 回應生成,關閉使用者介面,取消訊息編輯",
1993 "help_hotkeys_17": "Ctrl+Shift+↑",1990 "help_hotkeys_17": "Ctrl+Shift+↑",
1994 "help_hotkeys_18": "滾動到上下文行",1991 "help_hotkeys_18": "滾動到上下文行",
1995 "help_hotkeys_19": "Ctrl+Shift+↓",1992 "help_hotkeys_19": "Ctrl+Shift+↓",
1996 "help_hotkeys_20": "Markdown 快捷鍵",1993 "help_hotkeys_20": "Markdown 快捷鍵",
1997 "help_hotkeys_21": "適用於聊天框和帶有此圖標的文本區域:",1994 "help_hotkeys_21": "適用於聊天框和帶有此圖示的文字區域:",
1998 "help_hotkeys_22": "**粗體**",1995 "help_hotkeys_22": "**粗體**",
1999 "help_hotkeys_23": "*斜體*",1996 "help_hotkeys_23": "*斜體*",
2000 "help_hotkeys_24": "__底線__",1997 "help_hotkeys_24": "__底線__",
@@ -2008,7 +2005,7 @@
2008 "help_macros_2": "插入一個換行符。",2005 "help_macros_2": "插入一個換行符。",
2009 "help_macros_3": "修剪巨集指令周圍的換行符。",2006 "help_macros_3": "修剪巨集指令周圍的換行符。",
2010 "help_macros_4": "無操作,僅返回空字串。",2007 "help_macros_4": "無操作,僅返回空字串。",
2011 "help_macros_5": "在 API 設定中定義的全域提示詞。僅在高級定義提示詞覆蓋中有效。",2008 "help_macros_5": "在 API 設定中定義的全域提示詞。僅在高階定義提示詞覆蓋中有效。",
2012 "help_macros_6": "使用者輸入",2009 "help_macros_6": "使用者輸入",
2013 "help_macros_7": "角色的主要提示詞覆蓋",2010 "help_macros_7": "角色的主要提示詞覆蓋",
2014 "help_macros_8": "角色的聊天歷史後指示覆蓋",2011 "help_macros_8": "角色的聊天歷史後指示覆蓋",
@@ -2025,11 +2022,11 @@
2025 "help_macros_17": "角色版本",2022 "help_macros_17": "角色版本",
2026 "help_macros_18": "以逗號分隔的群組成員名稱列表(包含靜音成員)或單人聊天中的角色名稱。別名:{{charIfNotGroup}}",2023 "help_macros_18": "以逗號分隔的群組成員名稱列表(包含靜音成員)或單人聊天中的角色名稱。別名:{{charIfNotGroup}}",
2027 "help_groupNotMuted": "與 {{group}} 相同,但不包含靜音成員",2024 "help_groupNotMuted": "與 {{group}} 相同,但不包含靜音成員",
2028 "help_macros_19": "目前所選之 API 的文本生成模型名稱。",2025 "help_macros_19": "目前所選之 API 的文字生成模型名稱。",
2029 "Can be inaccurate!": "可能不準確!",2026 "Can be inaccurate!": "可能不準確!",
2030 "help_macros_20": "最新聊天訊息的文本內容。",2027 "help_macros_20": "最新聊天訊息的文字內容。",
2031 "help_macros_lastUser": "最新使用者聊天訊息的文本內容。",2028 "help_macros_lastUser": "最新使用者聊天訊息的文字內容。",
2032 "help_macros_lastChar": "最新角色聊天訊息的文本內容。",2029 "help_macros_lastChar": "最新角色聊天訊息的文字內容。",
2033 "help_macros_21": "最新聊天訊息的索引 # 編號。適用於斜線命令批次處理。",2030 "help_macros_21": "最新聊天訊息的索引 # 編號。適用於斜線命令批次處理。",
2034 "help_macros_22": "包含在上下文中的第一條訊息的 ID。需在目前對話中至少進行一次生成。",2031 "help_macros_22": "包含在上下文中的第一條訊息的 ID。需在目前對話中至少進行一次生成。",
2035 "help_macros_23": "最新聊天訊息中所滑動的 ID(以 1 起始)。若最新訊息為使用者訊息或提示為隱藏,則為空字串。",2032 "help_macros_23": "最新聊天訊息中所滑動的 ID(以 1 起始)。若最新訊息為使用者訊息或提示為隱藏,則為空字串。",
@@ -2044,20 +2041,20 @@
2044 "help_macros_31": "指定格式的目前日期/時間,例如,德國日期/時間:",2041 "help_macros_31": "指定格式的目前日期/時間,例如,德國日期/時間:",
2045 "help_macros_32": "指定 UTC 時區偏移量的目前時間,例如 UTC-4 或 UTC+2",2042 "help_macros_32": "指定 UTC 時區偏移量的目前時間,例如 UTC-4 或 UTC+2",
2046 "help_macros_33": "計算 time1 和 time2 之間的時間差。接受時間和日期巨集。(例如:{{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})",2043 "help_macros_33": "計算 time1 和 time2 之間的時間差。接受時間和日期巨集。(例如:{{timeDiff::{{isodate}} {{time}}::2024/5/11 12:30:00}})",
2047 "help_macros_34": "上次使用者訊息發送後的時間",2044 "help_macros_34": "上次使用者訊息傳送後的時間",
2048 "help_macros_35": "設定 AI 的行為偏好,直到下一次使用者輸入。引號中的文本很重要。",2045 "help_macros_35": "設定 AI 的行為偏好,直到下一次使用者輸入。引號中的文字很重要。",
2049 "help_macros_36": "擲骰子。(例如:",2046 "help_macros_36": "擲骰子。(例如:",
2050 "space_ will roll a 6-sided dice and return a number between 1 and 6)": "將擲一個六面骰並回傳 1 到 6 間的數字)",2047 "space_ will roll a 6-sided dice and return a number between 1 and 6)": "將擲一個六面骰並回傳 1 到 6 間的數字)",
2051 "help_macros_37": "從列表中返回隨機一項。(例如:",2048 "help_macros_37": "從列表中返回隨機一項。(例如:",
2052 "space_ will return 1 of the 4 numbers at random. Works with text lists too.": "將隨機返回 4 個數字中的 1 個。也適用於文本列表。)",2049 "space_ will return 1 of the 4 numbers at random. Works with text lists too.": "將隨機返回 4 個數字中的 1 個。也適用於文字列表。)",
2053 "help_macros_38": "用於隨機的替代語法,允許在列表中使用逗號。",2050 "help_macros_38": "用於隨機的替代語法,允許在列表中使用逗號。",
2054 "help_macros_39": "從列表中選擇隨機一項。工作原理與 {{random}} 相同,但選擇結果將在本次聊天中保持一致,不會在後續消息或提示處理時重新滾動。",2051 "help_macros_39": "從列表中選擇隨機一項。工作原理與 {{random}} 相同,但選擇結果將在本次聊天中保持一致,不會在後續訊息或提示處理時重新滾動。",
2055 "help_macros_40": "若使用 Text Generation WebUI 後端,動態將引號中的文本添加到禁用單詞序列中。對其他後端無效。可在任何地方使用(角色描述、世界資訊、作者備註等)。引號內容很重要。",2052 "help_macros_40": "若使用 Text Generation WebUI 後端,動態將引號中的文字新增到停用單詞序列中。對其他後端無效。可在任何地方使用(角色描述、世界資訊、作者備註等)。引號內容很重要。",
2056 "Instruct Mode and Context Template Macros:": "指令模式與上下文模板巨集:",2053 "Instruct Mode and Context Template Macros:": "指令模式與上下文範本巨集:",
2057 "(enabled in the Advanced Formatting settings)": "(在高級格式化設定中啟用)",2054 "(enabled in the Advanced Formatting settings)": "(在高階格式化設定中啟用)",
2058 "help_macros_41": "允許的最大提示詞長度(以符元為單位)=(上下文大小 - 回應長度)",2055 "help_macros_41": "允許的最大提示詞長度(以符元為單位)=(上下文大小 - 回應長度)",
2059 "help_macros_42": "上下文模板對話範例分隔符",2056 "help_macros_42": "上下文範本對話範例分隔符號",
2060 "help_macros_43": "上下文模板聊天開始行",2057 "help_macros_43": "上下文範本聊天開始行",
2061 "help_macros_44": "主要提示詞(啟用後,將覆蓋角色提示詞或預設系統提示)",2058 "help_macros_44": "主要提示詞(啟用後,將覆蓋角色提示詞或預設系統提示)",
2062 "help_macros_45": "主要提示詞",2059 "help_macros_45": "主要提示詞",
2063 "help_macros_46": "指令系統提示詞前綴序列",2060 "help_macros_46": "指令系統提示詞前綴序列",
@@ -2076,21 +2073,21 @@
2076 "help_macros_first_user": "指令使用者開頭輸入序列",2073 "help_macros_first_user": "指令使用者開頭輸入序列",
2077 "help_macros_last_user": "指令使用者結尾輸入序列",2074 "help_macros_last_user": "指令使用者結尾輸入序列",
2078 "Chat variables Macros:": "聊天變數巨集:",2075 "Chat variables Macros:": "聊天變數巨集:",
2079 "Local variables = unique to the current chat": "局部變數 = 僅作用於本次聊天",2076 "Local variables = unique to the current chat": "區域變數 = 僅作用於本次聊天",
2080 "Global variables = works in any chat for any character": "全域變數 = 作用於所有聊天中的所有角色",2077 "Global variables = works in any chat for any character": "全域變數 = 作用於所有聊天中的所有角色",
2081 "Scoped variables = works in STscript": "局部變數 = 適用於 STscript",2078 "Scoped variables = works in STscript": "區域變數 = 適用於 STscript",
2082 "help_macros_59": "替換為局部變數 \"name\" 的值",2079 "help_macros_59": "替換為區域變數 \"name\" 的值",
2083 "help_macros_60": "替換為空字串,並將局部變數 \"name\" 設定為 \"value\"",2080 "help_macros_60": "替換為空字串,並將區域變數 \"name\" 設定為 \"value\"",
2084 "help_macros_61": "替換為空字串,並將 \"increment\" 數值添加到局部變數 \"name\"",2081 "help_macros_61": "替換為空字串,並將 \"increment\" 數值新增到區域變數 \"name\"",
2085 "help_macros_62": "替換為局部變數 \"name\" 的值增加 1 後的結果",2082 "help_macros_62": "替換為區域變數 \"name\" 的值增加 1 後的結果",
2086 "help_macros_63": "替換為局部變數 \"name\" 的值減少 1 後的結果",2083 "help_macros_63": "替換為區域變數 \"name\" 的值減少 1 後的結果",
2087 "help_macros_64": "替換為全域變數 \"name\" 的值",2084 "help_macros_64": "替換為全域變數 \"name\" 的值",
2088 "help_macros_65": "替換為空字串,並將全域變數 \"name\" 設定為 \"value\"",2085 "help_macros_65": "替換為空字串,並將全域變數 \"name\" 設定為 \"value\"",
2089 "help_macros_66": "替換為空字串,並將 \"increment\" 數值添加到全域變數 \"name\"",2086 "help_macros_66": "替換為空字串,並將 \"increment\" 數值新增到全域變數 \"name\"",
2090 "help_macros_67": "替換為全域變數 \"name\" 的值增加 1 後的結果",2087 "help_macros_67": "替換為全域變數 \"name\" 的值增加 1 後的結果",
2091 "help_macros_68": "替換為全域變數 \"name\" 的值減少 1 後的結果",2088 "help_macros_68": "替換為全域變數 \"name\" 的值減少 1 後的結果",
2092 "help_macros_69": "替換為局部變數 \"name\" 的值",2089 "help_macros_69": "替換為區域變數 \"name\" 的值",
2093 "help_macros_70": "替換為局部變數 \"name\" 中指定索引(適用於陣列/列表或對象/字典)的值",2090 "help_macros_70": "替換為區域變數 \"name\" 中指定索引(適用於陣列/列表或物件/字典)的值",
2094 "{{name}}": "{{name}}",2091 "{{name}}": "{{name}}",
2095 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可以稍後從 /backups 資料夾恢復此聊天檔案",2092 "If necessary, you can later restore this chat file from the /backups folder": "若需要,您可以稍後從 /backups 資料夾恢復此聊天檔案",
2096 "Also delete the current chat file": "同時刪除目前的聊天檔案",2093 "Also delete the current chat file": "同時刪除目前的聊天檔案",
@@ -2111,13 +2108,13 @@
2111 "Exclude Patterns": "排除模式",2108 "Exclude Patterns": "排除模式",
2112 "Glob patterns of files to exclude in the download.": "要排除於下載中的文件的全域模式。\r每行輸入一個模式。",2109 "Glob patterns of files to exclude in the download.": "要排除於下載中的文件的全域模式。\r每行輸入一個模式。",
2113 "Tag Management": "管理標籤",2110 "Tag Management": "管理標籤",
2114 "Save your tags to a file": "將標籤保存到文件",2111 "Save your tags to a file": "將標籤儲存到文件",
2115 "Restore tags from a file": "從文件中恢復標籤",2112 "Restore tags from a file": "從文件中恢復標籤",
2116 "Create a new tag": "創建新標籤",2113 "Create a new tag": "建立新標籤",
2117 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖動以重新排序。點擊名稱重新命名。點擊顏色更改顯示。",2114 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖動以重新排序。點選名稱重新命名。點選顏色更改顯示。",
2118 "Click on the folder icon to use this tag as a folder.": "點擊資料夾圖示以將此標籤作為資料夾。",2115 "Click on the folder icon to use this tag as a folder.": "點選資料夾圖示以將此標籤作為資料夾。",
2119 "Use alphabetical sorting": "按字母順序排序 ",2116 "Use alphabetical sorting": "按字母順序排序 ",
2120 "tags_sorting_desc": "啟用後,標籤將在創建或重命名時將自動按字母排序。\n禁用時,新標籤將附加到末尾。\n若標籤被手動拖動重新排序,則自動排序將被禁用。",2117 "tags_sorting_desc": "啟用後,標籤將在建立或重新命名時將自動按字母排序。\n停用時,新標籤將附加到結尾。\n若標籤被手動拖動重新排序,則自動排序將被停用。",
2121 "and connect to an": "並連線到",2118 "and connect to an": "並連線到",
2122 "You can add more": "您可加入更多",2119 "You can add more": "您可加入更多",
2123 "or_welcome": "或",2120 "or_welcome": "或",
@@ -2157,13 +2154,13 @@
2157 "Which elements to color.": "設定需要上色的元素。",2154 "Which elements to color.": "設定需要上色的元素。",
2158 "Open Chat History": "開啟聊天記錄",2155 "Open Chat History": "開啟聊天記錄",
2159 "Reset": "重設",2156 "Reset": "重設",
2160 "Save": "保存",2157 "Save": "儲存",
2161 " folder of your user directory (typically 'data/default-user'). Place your expressions there.": "資料夾內,放置您的角色立繪(通常為「data/default-user」)。",2158 " folder of your user directory (typically 'data/default-user'). Place your expressions there.": "資料夾內,放置您的角色立繪(通常為「data/default-user」)。",
2162 "Always show the node full info panel at the…e timeline view. When off, show it near the node.": "始終在時間軸視圖底部顯示節點的完整資訊面板。若關閉,則在節點附近顯示。",2159 "Always show the node full info panel at the…e timeline view. When off, show it near the node.": "始終在時間軸檢視底端顯示節點的完整資訊面板。若關閉,則在節點附近顯示。",
2163 "Always show the node tooltip at the bottom …e timeline view. When off, show it near the node.": "始終在時間軸視圖左下角顯示節點的提示框。若關閉,則在節點附近顯示。",2160 "Always show the node tooltip at the bottom …e timeline view. When off, show it near the node.": "始終在時間軸檢視左下角顯示節點的提示框。若關閉,則在節點附近顯示。",
2164 "Dialogue settings for user personas.": "Dialogue settings for user personas.",2161 "Dialogue settings for user personas.": "Dialogue settings for user personas.",
2165 "Expand swipe nodes when the timeline view f… a node, or by pressing the Toggle Swipes button.": "在時間軸視圖首次打開時展開滑動節點,或透過按下「切換滑動」按鈕來展開節點。",2162 "Expand swipe nodes when the timeline view f… a node, or by pressing the Toggle Swipes button.": "在時間軸檢視首次開啟時展開滑動節點,或透過按下「切換滑動」按鈕來展開節點。",
2166 "Send as a character": "以角色身份發送",2163 "Send as a character": "以角色身份傳送",
2167 "Use GPU acceleration for positioning the fu…ow tends to disappear, turning this off may help.": "使用 GPU 加速來定位完整資訊面板。若面板頻繁消失,建議關閉此選項以解決問題。",2164 "Use GPU acceleration for positioning the fu…ow tends to disappear, turning this off may help.": "使用 GPU 加速來定位完整資訊面板。若面板頻繁消失,建議關閉此選項以解決問題。",
2168 "Use the colors of the ST GUI theme, instead…n Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。",2165 "Use the colors of the ST GUI theme, instead…n Color Settings specifically for this extension.": "使用使用者設定中的介面主題顏色,取代下方「顏色設定」中額外設定的顏色。",
2169 "When enabled, nodes that have swipes splitt… larger, in addition to having the double border.": "啟用後,具有分支滑動的節點除了顯示雙重邊框外,還會顯示為更大的尺寸。",2166 "When enabled, nodes that have swipes splitt… larger, in addition to having the double border.": "啟用後,具有分支滑動的節點除了顯示雙重邊框外,還會顯示為更大的尺寸。",
@@ -2172,7 +2169,7 @@
2172 "Commands": "指令",2169 "Commands": "指令",
2173 "Contrast": "對比度",2170 "Contrast": "對比度",
2174 "Darken Unfocused Character Sprites": "暗化未聚焦的角色立繪",2171 "Darken Unfocused Character Sprites": "暗化未聚焦的角色立繪",
2175 "Delete tint": "保存色調",2172 "Delete tint": "儲存色調",
2176 "Ease": "平滑過渡",2173 "Ease": "平滑過渡",
2177 "Ease-In": "淡入",2174 "Ease-In": "淡入",
2178 "Ease-In-Out": "淡入 + 淡出",2175 "Ease-In-Out": "淡入 + 淡出",
@@ -2216,7 +2213,7 @@
2216 "Select the animation for focus mode.": "選擇聚焦模式的動畫效果。",2213 "Select the animation for focus mode.": "選擇聚焦模式的動畫效果。",
2217 "Select the color of the letterbox.": "選擇遮罩顏色。",2214 "Select the color of the letterbox.": "選擇遮罩顏色。",
2218 "Select the letterbox mode for the Prome VN UI.": "選擇 Prome 視覺小說介面的遮罩模式",2215 "Select the letterbox mode for the Prome VN UI.": "選擇 Prome 視覺小說介面的遮罩模式",
2219 "Select the tint preset to use for the Prome VN UI.": "選擇用於 Prome 視覺小說介面的色調預設。",2216 "Select the tint preset to use for the Prome VN UI.": "選擇用於 Prome 視覺小說介面的色調預設設定檔。",
2220 "Sepia": "復古",2217 "Sepia": "復古",
2221 "Set the blur of the character shadow.": "設定角色陰影模糊程度。",2218 "Set the blur of the character shadow.": "設定角色陰影模糊程度。",
2222 "Set the brightness of the character.": "設定角色亮度。",2219 "Set the brightness of the character.": "設定角色亮度。",
@@ -2240,7 +2237,7 @@
2240 "Sprite List": "角色立繪列表",2237 "Sprite List": "角色立繪列表",
2241 "Sprite Shadow Configuration": "設定角色立繪陰影",2238 "Sprite Shadow Configuration": "設定角色立繪陰影",
2242 "Tint Configuration": "設定色調",2239 "Tint Configuration": "設定色調",
2243 "Tint Presets": "預設色調",2240 "Tint Presets": "色調預設設定檔",
2244 "Type the name of the sprite set to use for your pe…rites in the 'characters' folder in SillyTavern).": "輸入您要使用的個人角色立繪集名稱(需將立繪存放於 SillyTavern 中的「characters」資料夾內)。",2241 "Type the name of the sprite set to use for your pe…rites in the 'characters' folder in SillyTavern).": "輸入您要使用的個人角色立繪集名稱(需將立繪存放於 SillyTavern 中的「characters」資料夾內)。",
2245 "User Sprite Configuration": "[測試版] 使用者立繪設定",2242 "User Sprite Configuration": "[測試版] 使用者立繪設定",
2246 "Vertical Letterbox": "垂直遮罩",2243 "Vertical Letterbox": "垂直遮罩",
@@ -2254,33 +2251,33 @@
2254 "Prome Commands": "Prome 指令",2251 "Prome Commands": "Prome 指令",
2255 "Show/Hide the letterbox (black bars) in the VN UI": "顯示/隱藏視覺小說模式中的黑邊(信箱模式)",2252 "Show/Hide the letterbox (black bars) in the VN UI": "顯示/隱藏視覺小說模式中的黑邊(信箱模式)",
2256 "Toggles focus mode on character sprites": "切換角色立繪的焦點模式",2253 "Toggles focus mode on character sprites": "切換角色立繪的焦點模式",
2257 "Sets the focus mode animation": "設置焦點模式動畫",2254 "Sets the focus mode animation": "設定焦點模式動畫",
2258 "Toggles the defocus tint on non-speaking character sprites": "切換非對話角色立繪的背景色",2255 "Toggles the defocus tint on non-speaking character sprites": "切換非對話角色立繪的背景色",
2259 "Toggles the shake animation when a character speaks on character sprites": "切換角色立繪對話時的震動動畫",2256 "Toggles the shake animation when a character speaks on character sprites": "切換角色立繪對話時的震動動畫",
2260 "Toggles sprite shadows on character sprites": "切換角色立繪的陰影效果",2257 "Toggles sprite shadows on character sprites": "切換角色立繪的陰影效果",
2261 "Toggles world/character tint on the VN UI": "切換視覺小說模式中的世界/角色色調",2258 "Toggles world/character tint on the VN UI": "切換視覺小說模式中的世界/角色色調",
2262 "Toggles world tint on the VN UI": "切換視覺小說模式中的世界色調",2259 "Toggles world tint on the VN UI": "切換視覺小說模式中的世界色調",
2263 "Toggles character tint on the VN UI": "切換視覺小說模式中的角色色調",2260 "Toggles character tint on the VN UI": "切換視覺小說模式中的角色色調",
2264 "Toggles sharing world tint with character sprites (This will override Character Tint)": "切換角色立繪是否與世界色調共享色調(此操作將覆蓋角色色調設置)",2261 "Toggles sharing world tint with character sprites (This will override Character Tint)": "切換角色立繪是否與世界色調共享色調(此操作將覆蓋角色色調設定)",
2265 "Sets the expression of the user sprite": "設定使用者立繪的表情",2262 "Sets the expression of the user sprite": "設定使用者立繪的表情",
2266 "Sets the user sprite set to use for the user sprite": "設定使用者立繪所使用的立繪集",2263 "Sets the user sprite set to use for the user sprite": "設定使用者立繪所使用的立繪集",
2267 "Toggles the user sprite on the VN UI": "切換視覺小說模式中使用者立繪的顯示狀態",2264 "Toggles the user sprite on the VN UI": "切換視覺小說模式中使用者立繪的顯示狀態",
2268 "Close": "關閉",2265 "Close": "關閉",
2269 "View this current chat's chat history.": "查看本次聊天的聊天記錄。",2266 "View this current chat's chat history.": "檢視本次聊天的聊天記錄。",
2270 "WARNING: Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "警告:此類功能僅適用於進階使用者。若您不確定使用後果,請勿點擊任何按鈕。",2267 "WARNING: Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "警告:此類功能僅適用於進階使用者。若您不確定使用後果,請勿點選任何按鈕。",
2271 "Enter a new display name:": "輸入新的顯示名稱:",2268 "Enter a new display name:": "輸入新的顯示名稱:",
2272 "Enter Checkpoint Name:": "輸入檢查點名稱:",2269 "Enter Checkpoint Name:": "輸入檢查點名稱:",
2273 "(Leave empty to auto-generate)": "(留空將自動命名)",2270 "(Leave empty to auto-generate)": "(留空將自動命名)",
2274 "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "此檢查點將取消連結並替換為新的檢查點,但仍可在「管理聊天檔案」中找到。",2271 "The currently existing checkpoint will be unlinked and replaced with the new checkpoint, but can still be found in the Chat Management.": "此檢查點將取消連結並替換為新的檢查點,但仍可在「管理聊天檔案」中找到。",
2275 "Enter the Git URL of the extension to install": "輸入欲安裝的擴充功能 Git URL",2272 "Enter the Git URL of the extension to install": "輸入欲安裝的擴充功能 Git URL",
2276 "Disclaimer:": "免責聲明:",2273 "Disclaimer:": "免責宣告:",
2277 "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "請注意,使用外部擴充功能可能會導致意想不到的副作用並存在安全風險。在匯入前,請務必確保您信任其來源。我們對於第三方擴充功能所引起的任何損害概不負責。",2274 "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "請注意,使用外部擴充功能可能會導致意想不到的副作用並存在安全風險。在匯入前,請務必確保您信任其來源。我們對於第三方擴充功能所引起的任何損害概不負責。",
2278 "Prompt Itemization": "提示詞項目化",2275 "Prompt Itemization": "提示詞項目化",
2279 "API/Model": "API/模型",2276 "API/Model": "API/模型",
2280 "Preset": "預設",2277 "Preset": "預設設定檔",
2281 "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "所有數字均為估算值,僅白色數字真正重要。灰色項目可能因提示詞格式設定未納入上下文。",2278 "Only the white numbers really matter. All numbers are estimates. Grey color items may not have been included in the context due to certain prompt format settings.": "所有數字均為估算值,僅白色數字真正重要。灰色項目可能因提示詞格式設定未納入上下文。",
2282 "System Info:": "系統資訊:",2279 "System Info:": "系統資訊:",
2283 "Bias:": "Bias:",2280 "Bias:": "Bias:",
2284 "World Info:": "世界資訊:",2281 "World Info:": "世界資訊:",
2285 "Chat History:": "聊天記錄:",2282 "Chat History:": "聊天記錄:",
2286 "Extensions:": "擴充功能:",2283 "Extensions:": "擴充功能:",
@@ -2289,48 +2286,48 @@
2289 "(Context Size - Response Length)": "(上下文長度 - 回應長度)",2286 "(Context Size - Response Length)": "(上下文長度 - 回應長度)",
2290 ":": ":",2287 ":": ":",
2291 "API/Model:": "API/模型:",2288 "API/Model:": "API/模型:",
2292 "Preset:": "預設:",2289 "Preset:": "預設設定檔:",
2293 "Tokenizer:": "分詞器:",2290 "Tokenizer:": "分詞器:",
2294 "Choose what to export": "選擇匯出內容",2291 "Choose what to export": "選擇匯出內容",
2295 "Text Completion Preset": "文本補全預設",2292 "Text Completion Preset": "文字補全預設設定檔",
2296 "Choose what to import": "選擇匯入內容",2293 "Choose what to import": "選擇匯入內容",
2297 "Enter your password below to confirm:": "請在下方輸入密碼以完成確認:",2294 "Enter your password below to confirm:": "請在下方輸入密碼以完成確認:",
2298 "Unique to this chat.": "此設定僅適用於本次聊天。",2295 "Unique to this chat.": "此設定僅適用於本次聊天。",
2299 "The following scenario text will be used instead of the value set in the character card.": "以下場景內容將覆蓋角色卡中的設定值。",2296 "The following scenario text will be used instead of the value set in the character card.": "以下場景內容將覆蓋角色卡中的設定值。",
2300 "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "檢查點將繼承父項的場景覆蓋值,但仍可獨立修改。",2297 "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "檢查點將繼承父項的場景覆蓋值,但仍可獨立修改。",
2301 "Are you sure you want to delete the theme?": "您確定要刪除介面主題嗎?",2298 "Are you sure you want to delete the theme?": "您確定要刪除介面主題嗎?",
2302 "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "此操作將刪除所有設定與數據,且無法還原。進行重設前請務必完成備份。",2299 "This will delete all your settings and data. There will be no undo button. Make sure you have a backup before proceeding.": "此操作將刪除所有設定與資料,且無法還原。進行重設前請務必完成備份。",
2303 "Account reset code has been posted to the server console.": "帳號重設驗證碼已發送至伺服器控制台。",2300 "Account reset code has been posted to the server console.": "帳號重設驗證碼已傳送至伺服器控制台。",
2304 "Prompt Tokens:": "提示詞符元數:",2301 "Prompt Tokens:": "提示詞符元數:",
2305 "All group members will use the following scenario text instead of what is specified in their character cards.": "所有群組聊天成員將使用以下場景內容,取代原有角色卡中指定的內容。",2302 "All group members will use the following scenario text instead of what is specified in their character cards.": "所有群組聊天成員將使用以下場景內容,取代原有角色卡中指定的內容。",
2306 "Toggle sidebar": "切換側邊欄",2303 "Toggle sidebar": "切換側邊欄",
2307 "Show connection profiles": "顯示連線設定檔",2304 "Show connection profiles": "顯示連線設定檔",
2308 "View chat files": "查看聊天檔案",2305 "View chat files": "檢視聊天檔案",
2309 "New chat": "新聊天",2306 "New chat": "新聊天",
2310 "Rename chat": "重新命名聊天",2307 "Rename chat": "重新命名聊天",
2311 "Delete chat": "刪除聊天",2308 "Delete chat": "刪除聊天",
2312 "Are you sure?": "你確定嗎?",2309 "Are you sure?": "你確定嗎?",
2313 "Enter new chat name": "輸入新的聊天名稱",2310 "Enter new chat name": "輸入新的聊天名稱",
2314 "No chat selected": "未選擇聊天",2311 "No chat selected": "未選擇聊天",
2315 "Draggable template not found. Side bar will not be added.": "未找到可拖動模板。側邊欄將不被添加。",2312 "Draggable template not found. Side bar will not be added.": "未找到可拖動範本。側邊欄將不被新增。",
2316 "Failed to find draggable or close button. Side bar will not be added.": "未找到可拖動項或關閉按鈕。側邊欄將不被添加。",2313 "Failed to find draggable or close button. Side bar will not be added.": "未找到可拖動項或關閉按鈕。側邊欄將不被新增。",
2317 "Sidebar or toggle button not found": "未找到側邊欄或切換按鈕",2314 "Sidebar or toggle button not found": "未找到側邊欄或切換按鈕",
2318 "Switch connection profile": "切換連線設定檔",2315 "Switch connection profile": "切換連線設定檔",
2319 "Failed to get current API": "獲取 API 失敗",2316 "Failed to get current API": "取得 API 失敗",
2320 "Failed to get current model": "獲取模型失敗",2317 "Failed to get current model": "取得模型失敗",
2321 "Aborting populateSideBar due to process id mismatch": "由於 populateSideBar ID 不匹配,中止填充側邊欄",2318 "Aborting populateSideBar due to process id mismatch": "由於 populateSideBar ID 不匹配,中止填充側邊欄",
2322 "Bronya Rand": "Bronya Rand(布洛妮婭·蘭德)",2319 "Bronya Rand": "Bronya Rand(布洛妮婭·蘭德)",
2323 "Toggles Prome, VN Mode and other Prome features.": "切換 Prome、視覺小說模式和其他 Prome 功能。",2320 "Toggles Prome, VN Mode and other Prome features.": "切換 Prome、視覺小說模式和其他 Prome 功能。",
2324 "Only Show Last Message in Chat (Requires Prome to be enabled).": "僅顯示聊天中的最後一條消息(需啟用 Prome)。",2321 "Only Show Last Message in Chat (Requires Prome to be enabled).": "僅顯示聊天中的最後一條訊息(需啟用 Prome)。",
2325 "Emulates the character card of a character to be a sprite. (Requires Prome to be enabled).": "將角色的角色卡圖片模擬為角色立繪(需啟用 Prome)。",2322 "Emulates the character card of a character to be a sprite. (Requires Prome to be enabled).": "將角色的角色卡圖片模擬為角色立繪(需啟用 Prome)。",
2326 "Shakes the character sprite when the character is speaking (Only works if Streaming is enabled in Preset Settings).": "當角色說話時,震動角色的立繪(僅在預設設定中啟用「串流」時有效)。",2323 "Shakes the character sprite when the character is speaking (Only works if Streaming is enabled in Preset Settings).": "當角色說話時,震動角色的立繪(僅在預設設定檔中啟用「串流」時有效)。",
2327 "Focuses the current speaking character in chat. (Requires Prome to be enabled).": "聚焦聊天中當前正在說話的角色(要啟用 Prome)。",2324 "Focuses the current speaking character in chat. (Requires Prome to be enabled).": "聚焦聊天中目前正在說話的角色(要啟用 Prome)。",
2328 "Darkens non-speaking (unfocused) characters. (Requires Prome to be enabled).": "使未說話(未聚焦)的角色變暗(需啟用 Prome)。",2325 "Darkens non-speaking (unfocused) characters. (Requires Prome to be enabled).": "使未說話(未聚焦)的角色變暗(需啟用 Prome)。",
2329 "Auto-hides characters from the screen that haven't been in the conversation for a while up to X characters. (Requires Prome to be enabled).": "自動隱藏未參與會話一段時間的角色,最多 X 個角色(需啟用 Prome)。",2326 "Auto-hides characters from the screen that haven't been in the conversation for a while up to X characters. (Requires Prome to be enabled).": "自動隱藏未參與會話一段時間的角色,最多 X 個角色(需啟用 Prome)。",
2330 "Enables the ability to use a user sprite for your persona.": "啟用後,將為使用者的角色使用角色立繪功能。",2327 "Enables the ability to use a user sprite for your persona.": "啟用後,將為使用者的角色使用角色立繪功能。",
2331 "Applies the world tint to character sprites (Requires Prome to be enabled. This will override your character tint settings).": "將世界色調應用於角色立繪(需啟用 Prome,這將覆蓋角色的色調設定)。",2328 "Applies the world tint to character sprites (Requires Prome to be enabled. This will override your character tint settings).": "將世界色調應用於角色立繪(需啟用 Prome,這將覆蓋角色的色調設定)。",
2332 "Tints the world background.": "為世界背景添加色調。",2329 "Tints the world background.": "為世界背景新增色調。",
2333 "Tints the character sprites.": "為角色立繪添加色調(需啟用 Prome)。",2330 "Tints the character sprites.": "為角色立繪新增色調(需啟用 Prome)。",
2334 "Auto-Hide Sprites": "自動隱藏立繪",2331 "Auto-Hide Sprites": "自動隱藏立繪",
2335 "Max Visible Sprites": "最大顯示數",2332 "Max Visible Sprites": "最大顯示數",
2336 "Set the maximum number of visible sprites that appears in the VN screen.": "設定視覺小說模式中,畫面可顯示的最大立繪數量。",2333 "Set the maximum number of visible sprites that appears in the VN screen.": "設定視覺小說模式中,畫面可顯示的最大立繪數量。",
@@ -2355,11 +2352,11 @@
2355 "Auto": "自動",2352 "Auto": "自動",
2356 "Allow": "允許",2353 "Allow": "允許",
2357 "Forbid": "禁止",2354 "Forbid": "禁止",
2358 "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "僅限 Aphrodite 使用。決定採樣器的順序。偏移總是在 softmax 後應用,因此不包括在此。",2355 "Aphrodite only. Determines the order of samplers. Skew is always applied post-softmax, so it's not included here.": "僅限 Aphrodite 使用。決定取樣器的順序。偏移總是在 softmax 後應用,因此不包括在此。",
2359 "Aphrodite only. Determines the order of samplers.": "僅限 Aphrodite 使用。決定採樣器的順序。",2356 "Aphrodite only. Determines the order of samplers.": "僅限 Aphrodite 使用。決定取樣器的順序。",
2360 "Request model reasoning": "請求模型思維鏈",2357 "Request model reasoning": "請求模型思維鏈",
2361 "Allows the model to return its thinking process.": "讓模型回傳其思考過程。",2358 "Allows the model to return its thinking process.": "讓模型回傳其思考過程。",
2362 "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(兼容 OpenAI)[LM Studio, LiteLLM 等]",2359 "Generic (OpenAI-compatible) [LM Studio, LiteLLM, etc.]": "通用(相容 OpenAI)[LM Studio, LiteLLM 等]",
2363 "Model ID (optional)": "模型 ID(可選)",2360 "Model ID (optional)": "模型 ID(可選)",
2364 "DeepSeek API Key": "DeepSeek API 金鑰",2361 "DeepSeek API Key": "DeepSeek API 金鑰",
2365 "DeepSeek Model": "DeepSeek 模型",2362 "DeepSeek Model": "DeepSeek 模型",
@@ -2372,31 +2369,31 @@
2372 "Contain": "自適應",2369 "Contain": "自適應",
2373 "Stretch": "拉伸",2370 "Stretch": "拉伸",
2374 "Center": "置中",2371 "Center": "置中",
2375 "Persona Lore Alt+Click to open the lorebook": "「Alt+點擊」可開啟角色知識書",2372 "Persona Lore Alt+Click to open the lorebook": "「Alt+點選」可開啟角色知識書",
2376 "Chat Lore Alt+Click to open the lorebook": "「Alt+點擊」可開啟聊天知識書",2373 "Chat Lore Alt+Click to open the lorebook": "「Alt+點選」可開啟聊天知識書",
2377 "Function Tool": "功能工具",2374 "Function Tool": "功能工具",
2378 "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此類功能僅供高級用戶使用。若不確定後果,請勿點擊任何內容。",2375 "Functions in this category are for advanced users only. Don't click anything if you're not sure about the consequences.": "此類功能僅供高階使用者使用。若不確定後果,請勿點選任何內容。",
2379 "Are you sure you want to delete this user?": "確定要刪除該使用者嗎?",2376 "Are you sure you want to delete this user?": "確定要刪除該使用者嗎?",
2380 "help_macros_isMobile": "目前是否在行動端使用:\"true\" 表示是,\"false\" 表示否",2377 "help_macros_isMobile": "目前是否在行動端使用:\"true\" 表示是,\"false\" 表示否",
2381 "Persona Lorebook for": "角色知識書適用於",2378 "Persona Lorebook for": "角色知識書適用於",
2382 "persona_world_template_txt": "選中的世界資訊將綁定到此角色。生成 AI 回覆時,會結合全域、角色及聊天知識書中的內容。",2379 "persona_world_template_txt": "選中的世界資訊將綁定到此角色。生成 AI 回覆時,會結合全域、角色及聊天知識書中的內容。",
2383 "Key saved; press \"Test Message\" to verify.": "金鑰已儲存;請點擊「測試訊息」進行驗證。",2380 "Key saved; press \"Test Message\" to verify.": "金鑰已儲存;請點選「測試訊息」進行驗證。",
2384 "Preset name:": "預設名稱:",2381 "Preset name:": "預設設定檔名稱:",
2385 "Hint: Use a character/group name to bind preset to a specific chat.": "提示:使用角色/群組名稱將綁定預設至特定對話。",2382 "Hint: Use a character/group name to bind preset to a specific chat.": "提示:使用角色/群組名稱將綁定預設設定檔至特定對話。",
2386 "Your preset contains proxy and/or custom endpoint settings.": "此預設包含代理和/或自訂端點設定。",2383 "Your preset contains proxy and/or custom endpoint settings.": "此預設設定檔包含代理和/或自訂端點設定。",
2387 "Do you want to remove these fields before exporting?": "是否要在匯出前移除這些欄位?",2384 "Do you want to remove these fields before exporting?": "是否要在匯出前移除這些欄位?",
2388 "Delete the preset? This action is irreversible and your current settings will be overwritten.": "確定刪除此預設?刪除後無法復原,且此設定將被覆蓋。",2385 "Delete the preset? This action is irreversible and your current settings will be overwritten.": "確定刪除此預設設定檔?刪除後無法復原,且此設定將被覆蓋。",
2389 "Update all": "全部更新",2386 "Update all": "全部更新",
2390 "Automatically chooses an alternative provider if chosen providers can't serve your request.": "當所選提供者無法滿足您的請求時,自動選擇替代提供者。",2387 "Automatically chooses an alternative provider if chosen providers can't serve your request.": "當所選提供者無法滿足您的請求時,自動選擇替代提供者。",
2391 "Use extension settings": "使用擴充功能設定",2388 "Use extension settings": "使用擴充功能設定",
2392 "To use instruct formatting, switch to OpenRouter under Text Completion API.": "若要使用指令格式,請在文本補全 API 下切換至 OpenRouter。",2389 "To use instruct formatting, switch to OpenRouter under Text Completion API.": "若要使用指令格式,請在文字補全 API 下切換至 OpenRouter。",
2393 "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "如果模型在達到一定數量的符元前停止,則自動繼續生成回應。",2390 "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "如果模型在達到一定數量的符元前停止,則自動繼續生成回應。",
2394 "Toggle entry's active state.": "切換條目的啟用狀態。",2391 "Toggle entry's active state.": "切換條目的啟用狀態。",
2395 "Non-sticky": "無黏性",2392 "Non-sticky": "無黏性",
2396 "No cooldown": "無冷卻時間",2393 "No cooldown": "無冷卻時間",
2397 "No delay": "無延遲",2394 "No delay": "無延遲",
2398 "Included settings:": "包含設定:",2395 "Included settings:": "包含設定:",
2399 "Click on the setting name to omit it from the profile.": "點擊設定名稱以從設定檔中省略。",2396 "Click on the setting name to omit it from the profile.": "點選設定名稱以從設定檔中省略。",
2400 "Tints the chat background and/or character sprites.": "調整聊天背景或角色圖片的色調。",2397 "Tints the chat background and/or character sprites.": "調整聊天背景或角色圖片的色調。",
2401 "Only chunk on custom boundary": "僅在自定邊界進行分塊(chunk)",2398 "Only chunk on custom boundary": "僅在自定邊界進行分塊(chunk)",
2402 "help_macros_firstDisplayedMessageId": "載入到可見聊天中的第一則訊息的 ID。",2399 "help_macros_firstDisplayedMessageId": "載入到可見聊天中的第一則訊息的 ID。",
@@ -2404,7 +2401,7 @@
2404 "Select providers. No selection = all providers.": "選擇供應商。未選擇=所有供應商。",2401 "Select providers. No selection = all providers.": "選擇供應商。未選擇=所有供應商。",
2405 "Select a model": "選擇模型",2402 "Select a model": "選擇模型",
2406 "Search models...": "搜尋模型⋯",2403 "Search models...": "搜尋模型⋯",
2407 "[Currently loaded]": "[當前加載]",2404 "[Currently loaded]": "[目前載入]",
2408 "Search providers...": "搜尋供應商⋯",2405 "Search providers...": "搜尋供應商⋯",
2409 "No-sticky": "無固定",2406 "No-sticky": "無固定",
2410 "Create a new World Info": "建立新世界資訊",2407 "Create a new World Info": "建立新世界資訊",
@@ -2429,15 +2426,15 @@
2429 "Loading third-party extensions... Please wait...": "正在載入第三方擴充功能,請稍候⋯",2426 "Loading third-party extensions... Please wait...": "正在載入第三方擴充功能,請稍候⋯",
2430 "The page will be reloaded shortly...": "頁面即將重新載入⋯",2427 "The page will be reloaded shortly...": "頁面即將重新載入⋯",
2431 "Extensions state changed": "擴充功能狀態已更改",2428 "Extensions state changed": "擴充功能狀態已更改",
2432 "Error loading extensions. See browser console for details.": "載入擴充功能時出現錯誤。詳情請查看瀏覽器控制台。",2429 "Error loading extensions. See browser console for details.": "載入擴充功能時出現錯誤。詳細資訊請檢視瀏覽器控制台。",
2433 "You don't have permission to update global extensions.": "您無權更新全域擴充功能。",2430 "You don't have permission to update global extensions.": "您無權更新全域擴充功能。",
2434 "Extension update failed": "擴充功能更新失敗",2431 "Extension update failed": "擴充功能更新失敗",
2435 "Extension ${0} updated to ${1}": "擴充功能 ${0} 已更新至 ${1}",2432 "Extension ${0} updated to ${1}": "擴充功能 ${0} 已更新至 ${1}",
2436 "Reload the page to apply updates": "重新加載頁面以使用更新",2433 "Reload the page to apply updates": "重新載入頁面以使用更新",
2437 "You don't have permission to delete global extensions.": "您無權刪除全域擴充功能。",2434 "You don't have permission to delete global extensions.": "您無權刪除全域擴充功能。",
2438 "Are you sure you want to delete ${0}?": "確定要刪除 ${0} 嗎?",2435 "Are you sure you want to delete ${0}?": "確定要刪除 ${0} 嗎?",
2439 "You don't have permission to move extensions.": "您無權移動擴充功能。",2436 "You don't have permission to move extensions.": "您無權移動擴充功能。",
2440 "Are you sure you want to move ${0} to your local extensions? This will make it available only for you.": "確定要將 ${0} 移至本地擴充功能嗎?此後僅您可使用。",2437 "Are you sure you want to move ${0} to your local extensions? This will make it available only for you.": "確定要將 ${0} 移至本機擴充功能嗎?此後僅您可使用。",
2441 "Are you sure you want to move ${0} to the global extensions? This will make it available for all users.": "確定要將 ${0} 移至全域擴充功能嗎?此後所有使用者皆可使用。",2438 "Are you sure you want to move ${0} to the global extensions? This will make it available for all users.": "確定要將 ${0} 移至全域擴充功能嗎?此後所有使用者皆可使用。",
2442 "Extension ${0} moved.": "擴充功能 ${0} 已移動。",2439 "Extension ${0} moved.": "擴充功能 ${0} 已移動。",
2443 "Extension ${0} deleted": "擴充功能 ${0} 已刪除。",2440 "Extension ${0} deleted": "擴充功能 ${0} 已刪除。",
@@ -2452,5 +2449,179 @@
2452 "Modules provided by your Extras API:": "由您的 Extras API 提供的模組:",2449 "Modules provided by your Extras API:": "由您的 Extras API 提供的模組:",
2453 "Not connected to the API!": "未連線到 API!",2450 "Not connected to the API!": "未連線到 API!",
2454 "ext_type_system": "這是內建的擴充功能,無法刪除,且會跟隨系統更新。",2451 "ext_type_system": "這是內建的擴充功能,無法刪除,且會跟隨系統更新。",
2455 "Valid": "已驗證"2452 "Valid": "已驗證",
2453 "Request Model Reasoning": "請求模型推理",
2454 "Global list": "全域列表",
2455 "Preset-specific list": "特定預設設定檔列表",
2456 "Constrains effort on reasoning for reasoning models.": "限制推理模型的推理耗費。\n目前支援的值為低、中和高。\n降低推理耗費可加快回應速度,並減少推理所使用的符元數量。",
2457 "Reasoning Effort": "推理耗費",
2458 "openai_reasoning_effort_low": "低",
2459 "openai_reasoning_effort_medium": "中",
2460 "openai_reasoning_effort_high": "高",
2461 "Reasoning": "推理 Reasoning",
2462 "reasoning_auto_parse": "自動解析主要內容中推理區塊,需定義且不為空的前綴與後綴欄位。",
2463 "Auto-Parse": "自動解析",
2464 "reasoning_auto_expand": "自動展開推理區塊。",
2465 "Auto-Expand": "自動展開",
2466 "reasoning_show_hidden": "顯示隱藏推理功能模型的推理時間",
2467 "Show Hidden": "顯示隱藏內容",
2468 "reasoning_add_to_prompts": "將現有推理區塊新增至提示詞中。若需新增推理區塊,請使用訊息編輯選單。",
2469 "Add to Prompts": "新增至提示詞",
2470 "reasoning_max_additions": "從最後一則訊息起算,每則提示詞中可新增的最大推理區塊數量。",
2471 "Max": "最大值",
2472 "Reasoning Formatting": "推理格式",
2473 "reasoning_prefix": "插入於推理內容之前。",
2474 "Prefix": "前綴",
2475 "reasoning_suffix": "插入於推理內容之後。",
2476 "Suffix": "後綴",
2477 "reasoning_separator": "插入於推理內容與訊息內容之間。",
2478 "Separator": "分隔符號",
2479 "Character details are hidden.": "角色詳細資訊已隱藏。",
2480 "Add a reasoning block": "新增推理區塊",
2481 "Thought for some time": "思考了一段時間",
2482 "Confirm Edit": "確認",
2483 "Remove reasoning": "移除推理",
2484 "Cancel edit": "取消編輯",
2485 "Copy reasoning": "複製推理",
2486 "Edit reasoning": "編輯推理",
2487 "extension_install_1": "若要從此頁面下載擴充功能,您需要安裝",
2488 "extension_install_2": "已安裝。",
2489 "extension_install_3": "點選",
2490 "extension_install_4": "圖示以存取擴充功能的儲存庫,檢視使用技巧。",
2491 "Use the selected API from Chat Translation extension settings.": "使用擴充功能設定中,「聊天翻譯」所選的翻譯提供者(API)。",
2492 "A single expression can have multiple sprites. Whenever the expression is chosen, a random sprite for this expression will be selected.": "單個同名表情可以有多張角色立繪。每次使用該表情時,會隨機擇一顯示。",
2493 "Allow multiple sprites per expression": "允許單一表情使用多張立繪",
2494 "If the same expression is used again, re-roll the sprite. This only applies to expressions that have multiple available sprites assigned.": "若再次使用相同的表情,將重新隨機選擇。此功能僅適用於分配了多張立繪的表情。",
2495 "Re-roll if same expression is used again": "重複使用同名表情時,隨機選用其他立繪",
2496 "upload_expression_request": "請輸入角色立繪名稱(不含副檔名)。",
2497 "upload_expression_naming_1": "角色立繪名稱必須符合所選表情的命名規則:{{expression}}",
2498 "upload_expression_naming_2": "對於多個表情,名稱必須包含表情名稱和有效的後綴,允許的分隔符號為「-」或「.」。",
2499 "upload_expression_replace": "點選「取代」以取代現有表情:",
2500 "ext_regex_reasoning_desc": "推理區塊內容。當「僅格式化提示詞」已勾選時,這也會影響新增至提示詞的推理內容。",
2501 "Token Counter": "符元計數器",
2502 "Type / paste in the box below to see the number of tokens in the text.": "在下框中輸入或貼上文字以檢視符元(Token)數量。",
2503 "Selected tokenizer:": "選擇的分詞器:",
2504 "Input:": "輸入:",
2505 "Tokens:": "符元數:",
2506 "Tokenized text:": "已符元化的文字:",
2507 "Token IDs:": "符元 ID:",
2508 "Narrate by paragraphs (when not streaming)": "按段落朗讀(不使用「串流」時)",
2509 " folder (typically in ": "資料夾(通常位於 ",
2510 "Copy to Clipboard": "複製到剪貼簿",
2511 "Reset to Defaults": "重設為預設值",
2512 "Toggles Guinevere features.": "切換 Guinevere 功能。",
2513 "Update customCSS": "更新 customCSS",
2514 "Apply Theme": "套用主題",
2515 "Enable Guinevere": "啟用 Guinevere",
2516 "Note: Themes can be made/applied by going to the ": "注意:主題可通過前往以下位置進行創建/應用",
2517 "Theme Name": "主題名稱",
2518 "An unknown error occurred while counting tokens. Further information may be available in console.": "計算符元時發生未知錯誤。更多資訊可能可在主控台(console)中查看。",
2519 "Qvink Memory": "Qvink Memory(進階聊天記憶)",
2520 "Toggle whether memory is enabled for this chat specifically (overrides all settings).": "切換是否為此聊天啟用記憶功能(將覆蓋所有設定)。",
2521 "Toggle Chat Memory": "切換聊天記憶",
2522 "Preview current memory state (the exact text that will be injected into your context).": "預覽目前記憶狀態(包含將嵌入上下文的具體內容)。",
2523 "Copy ALL memories to clipboard (all memories in the entire chat, not just those injected).": "將所有記憶複製到剪貼簿(包含整個聊天的所有記憶,而非僅限於注入的部分)。",
2524 "Just refreshes which memories are included and re-renders the memories under each message, doesn't change summaries. This is done automatically all the time, the button is here just in case.": "不影響摘要,僅更新已包含的聊天記憶,並重新顯示在每則訊息下方。此過程通常會自動執行,按鈕只是備用選項。",
2525 "Active Settings Profile ": "目前設定檔",
2526 "Create, edit, and save configuration profiles for this extension.": "建立、編輯及儲存此擴充功能的設定檔。",
2527 "The currently selected profile": "目前選取的設定檔",
2528 "Save current profile": "儲存此設定檔",
2529 "Rename current profile": "重新命名此設定檔",
2530 "Create new profile": "建立新設定檔",
2531 "Restore current profile": "還原此設定檔",
2532 "Delete current profile": "刪除此設定檔",
2533 "Set as default profile for current character": "設為目前角色的預設設定檔",
2534 "Summarization": "摘要",
2535 "Customize the prompt used to summarize a given message": "自訂用於摘要指定訊息的提示詞",
2536 "Edit the summary prompt": "編輯摘要提示",
2537 "Preview the filled-in summary prompt, using the last message as an example.": "以最後一則訊息為例,預覽填充完成的摘要提示",
2538 "Mass re-summarization. Brings up dialog to choose subsets of messages to summarize or re-summarize.": "批量重新摘要:開啟對話框以選擇訊息子集進行摘要或重新摘要。",
2539 "Stop all summarization immediately.": "立即停止所有摘要。",
2540 "New messages will be automatically summarized if they will be included in short-term memory.": "如果新訊息將被納入短期記憶,將自動進行摘要。",
2541 "Auto Summarize": "自動摘要",
2542 "Auto-summarization will be triggered before a new message is sent instead of after.": "自動摘要將在發送新訊息之前觸發。",
2543 "Auto Summarize Before Generation": "在生成內容前自動摘要",
2544 "Show the progress bar when auto-summarizing more than 1 message.": "在自動摘要多於 1 則訊息時顯示進度條。",
2545 "Auto Summarize Progress Bar": "自動摘要進度條",
2546 "Number of messages to delay summarization (0 = summarize up to the most recent message, 1 = lag behind by one message, etc.)": "延遲摘要的訊息數量(0 = 摘要至最新訊息,1 = 延遲摘要 1 則訊息,以此類推)。",
2547 "Auto Summarize Message Lag": "自動摘要訊息延遲",
2548 "Wait until this many messages before auto-summarizing them all in sequence (1 = summarize every message immediately, 2 = summarize when you have two ready, etc). Still summarizes one at a time.": "在訊息數量達到此設定值後,依序自動摘要(1 = 即時摘要每則訊息,2 = 等待 2 則訊息後再摘要,以此類推)。摘要將逐條執行。",
2549 "Auto Summarize Batch Size": "自動摘要批次大小",
2550 "The maximum number of messages back that auto-summarization will apply (-1 to disable).": "自動摘要可回溯的訊息最大數量(-1 表示禁用此功能)。",
2551 "Auto Summarize Message Limit": "自動摘要訊息上限",
2552 "Time in seconds to wait between summarizations. May be needed if you are using a external API with a rate limit.": "每次摘要的間隔時間(秒)。此設定適用於使用具有請求速率限制的外部 API。",
2553 "Summarization Time Delay": "摘要時間延遲",
2554 "The maximum token length a summary is allowed to be before cutting it off. Use the {{words}} macro in the summarization prompt to get this value.": "摘要在被截斷前允許的最大符元(token)長度。可在摘要提示中使用 {{words}} 巨集以取得此數值。",
2555 "Summary Max Token Length": "摘要允許的最大符元長度",
2556 "Editing a message will automatically trigger a re-summarization if it has already been summarized.": "編輯訊息時,若該訊息已被摘要,將自動觸發重新摘要。",
2557 "Re-summarize on Edit": "編輯後重新摘要",
2558 "Swiping a message will automatically trigger a re-summarization if it has already been summarized.": "滑動訊息後若已進行摘要,將自動觸發重新摘要。",
2559 "Re-summarize on Swipe": "滑動後重新摘要",
2560 "Block chat input while summarizing.": "在摘要進行時暫時禁用聊天訊息輸入。",
2561 "Block Chat": "訊息輸入鎖定",
2562 "Whether to use messages and/or summaries as context for summarization. You must use {{history}} in the summary prompt.": "決定是否在摘要中使用訊息及/或過往摘要作為背景資訊。需於摘要提示詞中,使用 {{history}}。",
2563 "Message History": "訊息歷史",
2564 "Messages": "僅訊息",
2565 "Summaries": "僅摘要",
2566 "Both": "訊息與摘要",
2567 "Preview what the message history will look like": "預覽訊息歷史的顯示效果",
2568 "How many previous messages to include in the summarization prompt as context.": "摘要提示中要包含多少先前訊息作為上下文。",
2569 "Number of Previous Messages": "先前訊息數量",
2570 "When including previous messages, also include user messages.": "包含先前訊息時,也包含使用者訊息。",
2571 "Include Previous User Messages": "包含先前使用者訊息",
2572 "The message to summarize will be inside the system instruct template itself. In unchecked (default), the message will instead be added separately after the prompt. Some models benefit from this, but it is not recommended.": "系統指令模板內將直接包含需要摘要的訊息。若未啟用此選項(預設設定),訊息會在提示後分開添加。儘管某些模型可能更適合此設定,但一般不建議使用。",
2573 "Nest Message in Summary Prompt": "在摘要提示中內嵌訊息",
2574 "WARNING: doesn't work great. Attempts to preserve context-shifting by including all the content that is sent in regular prompts (world info, description, personas, example messages, message history, etc). If your regular prompts are static, this can allow Context Shifting to work between summarizations, but it decreases the accuracy of summarization due to all the extra stuff in the prompt. It also can't be previewed as this injection is handled by ST, not the extension.": "警告:效果不佳。此功能嘗試透過在摘要時包含所有常規提示內容(如世界資訊、描述、角色設定、示範訊息、聊天歷史等)來保留上下文轉換。若您的常規提示為靜態內容,則可在摘要之間維持上下文轉換,但由於提示中包含大量額外資訊,將降低摘要的準確性。此外,此內容注入由 ST 處理,而非此擴充功能,因此無法進行預覽。",
2575 "Include All Context Content": "包含所有上下文內容",
2576 "Short-term Memory Injection": "短期記憶注入",
2577 "Determines which messages are included in the short-term memory injection and where. If you change this and include messages that weren't summarized previously, you can either manually trigger a re-summarization or just wait until automatic summarization triggers.": "設定短期記憶注入中所包含的訊息及其插入位置。若更改此設定並包含先前未摘要的訊息,您可手動觸發重新摘要,或等待自動摘要啟動。",
2578 "Edit the short-term memory prompt": "編輯短期記憶提示",
2579 "Include User Messages": "包含使用者訊息",
2580 "Include System Messages": "包含系統訊息",
2581 "Include Thought Message": "包含思考訊息",
2582 "Message Length Threshold": "訊息長度閾值",
2583 "The minimum token length a message has to be in order to get summarized.": "可被摘要的訊息最小符元長度。",
2584 "The max percent of the context that short-term memory can take up.": "短期記憶可佔用上下文的最大百分比。",
2585 "Short-Term Context %": "短期記憶上下文%",
2586 "Include short-term memory in the World Info Scan": "在世界資訊掃描中包含短期記憶",
2587 "Do not inject": "不注入",
2588 "Before main prompt": "主提示之前",
2589 "After main prompt": "主提示之後",
2590 "In chat at depth": "在對話中位於深度",
2591 "Long-Term Memory Injection": "長期記憶注入",
2592 "Determines where long-term messages are injected.": "決定長期訊息注入的位置。",
2593 "Edit the long-term memory prompt": "編輯長期記憶提示",
2594 "The max percent of the context that long-term memory can take up.": "長期記憶可佔用上下文的最大百分比。",
2595 "Long-Term Context %": "長期記憶上下文%",
2596 "Include long-term memory in the World Info Scan": "在世界資訊掃描中包含長期記憶",
2597 "Misc.": "其他",
2598 "Fill your console with debug messages": "將偵錯訊息填入主控台",
2599 "Debug Mode": "偵錯模式",
2600 "Display summarizations below each message": "在每則訊息下顯示摘要",
2601 "Display Memories": "顯示記憶",
2602 "Enable Memory in New Chats": "在新對話中啟用記憶",
2603 "Limit Message History": "限制訊息歷史",
2604 "Revert Settings": "還原設定",
2605 "Auto-summarize user messages and include summaries in memory.": "自動摘要使用者訊息,並將該摘要納入記憶。",
2606 "Auto-summarize system messages and include summaries in memory.": "自動摘要系統訊息,並將該摘要納入記憶。",
2607 "Auto-summarize thought messages and include summaries in memory (from the Stepped Thinking extension).": "自動摘要思考訊息並將摘要納入記憶(來自 Stepped Thinking 擴充功能)。",
2608 "Revert all settings to default (not the default profile, just the default that comes with the extension). Your other profiles won't be affected.": "將所有設定恢復為預設值(並非恢復至「預設設定檔」,而是擴充功能隨附的原始預設值)。其他設定檔將不受影響。",
2609 "Limit the number of messages to send in regular prompts to this number (-1 for no limit). Message memories will still be sent.": "限制常規提示中傳送的訊息數量至此數值(-1 表示無限制)。訊息記憶仍將一併傳送。",
2610 "Whether memory is enabled by default for new chats.": "是否在新對話中預設啟用記憶。",
2611 "Summarize Chat": "摘要對話",
2612 "Choose settings for the chat summarization. All message inclusion/exclusion settings from the main config profile are used, in addition to the following options.": "選擇聊天摘要的設定。摘要時將使用主要設定檔中的所有訊息包含/排除規則,並可額外設定以下選項。",
2613 "Currently preparing to summarize:": "目前正在準備摘要:",
2614 "Summarize messages with no existing summary": "摘要尚無摘要的訊息",
2615 "Re-summarize messages with existing short-term memories": "重新摘要具有現有短期記憶的訊息",
2616 "Re-summarize messages with existing long-term memories": "重新摘要具有現有長期記憶的訊息",
2617 "Re-summarize messages with existing memories, but which are currently excluded from short-term and long-term memory": "重新摘要具有現有記憶,但目前被排除在短期和長期記憶之外的訊息",
2618 "Re-summarize messages with existing memories that have been manually edited.": "重新摘要已手動編輯的訊息記憶",
2619 "Type the folder name of the theme you want to apply.": "輸入您想套用的主題資料夾名稱。",
2620 "Place your theme data in a folder.": "請將主題資料存於該資料夾內。",
2621 "Unsure where to start? Type ": "不確定如何開始?輸入:",
2622 " to apply the default Google Messages theme or click ": " 即可使用預設主題 Google Messages,或點擊",
2623 "here": "這裡",
2624 " to learn how to create your own theme.": " 以學習如何創建個人化主題。",
2625 "Guinevere (UI Theme Extension)": "Guinevere(進階自定義 UI 主題)",
2626 "and Guinaifen.": "和 Guinaifen(桂乃芬)呈獻。"
2456}2627}
public/script.js+520 -153
@@ -171,6 +171,7 @@ import {
171 isElementInViewport,171 isElementInViewport,
172 copyText,172 copyText,
173 escapeHtml,173 escapeHtml,
174 saveBase64AsFile,
174} from './scripts/utils.js';175} from './scripts/utils.js';
175import { debounce_timeout } from './scripts/constants.js';176import { debounce_timeout } from './scripts/constants.js';
176177
@@ -235,6 +236,8 @@ import {
235 initPersonas,236 initPersonas,
236 setPersonaDescription,237 setPersonaDescription,
237 initUserAvatar,238 initUserAvatar,
239 updatePersonaConnectionsAvatarList,
240 isPersonaPanelOpen,
238} from './scripts/personas.js';241} from './scripts/personas.js';
239import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';242import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_settings } from './scripts/backgrounds.js';
240import { hideLoader, showLoader } from './scripts/loader.js';243import { hideLoader, showLoader } from './scripts/loader.js';
@@ -269,7 +272,7 @@ import { initSettingsSearch } from './scripts/setting-search.js';
269import { initBulkEdit } from './scripts/bulk-edit.js';272import { initBulkEdit } from './scripts/bulk-edit.js';
270import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js';273import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js';
271import { getContext } from './scripts/st-context.js';274import { getContext } from './scripts/st-context.js';
272import { extractReasoningFromData, initReasoning, PromptReasoning, ReasoningHandler, removeReasoningFromString, updateReasoningUI } from './scripts/reasoning.js';275import { extractReasoningFromData, initReasoning, parseReasoningInSwipes, PromptReasoning, ReasoningHandler, removeReasoningFromString, updateReasoningUI } from './scripts/reasoning.js';
273import { accountStorage } from './scripts/util/AccountStorage.js';276import { accountStorage } from './scripts/util/AccountStorage.js';
274277
275// API OBJECT FOR EXTERNAL WIRING278// API OBJECT FOR EXTERNAL WIRING
@@ -366,6 +369,10 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => {
366 return;369 return;
367 }370 }
368371
372 if (!(node instanceof Element)) {
373 return;
374 }
375
369 let mediaBlocked = false;376 let mediaBlocked = false;
370377
371 switch (node.tagName) {378 switch (node.tagName) {
@@ -447,6 +454,8 @@ export const event_types = {
447 MESSAGE_DELETED: 'message_deleted',454 MESSAGE_DELETED: 'message_deleted',
448 MESSAGE_UPDATED: 'message_updated',455 MESSAGE_UPDATED: 'message_updated',
449 MESSAGE_FILE_EMBEDDED: 'message_file_embedded',456 MESSAGE_FILE_EMBEDDED: 'message_file_embedded',
457 MESSAGE_REASONING_EDITED: 'message_reasoning_edited',
458 MESSAGE_REASONING_DELETED: 'message_reasoning_deleted',
450 MORE_MESSAGES_LOADED: 'more_messages_loaded',459 MORE_MESSAGES_LOADED: 'more_messages_loaded',
451 IMPERSONATE_READY: 'impersonate_ready',460 IMPERSONATE_READY: 'impersonate_ready',
452 CHAT_CHANGED: 'chat_id_changed',461 CHAT_CHANGED: 'chat_id_changed',
@@ -493,6 +502,8 @@ export const event_types = {
493 // TODO: Naming convention is inconsistent with other events502 // TODO: Naming convention is inconsistent with other events
494 CHARACTER_DELETED: 'characterDeleted',503 CHARACTER_DELETED: 'characterDeleted',
495 CHARACTER_DUPLICATED: 'character_duplicated',504 CHARACTER_DUPLICATED: 'character_duplicated',
505 CHARACTER_RENAMED: 'character_renamed',
506 CHARACTER_RENAMED_IN_PAST_CHAT: 'character_renamed_in_past_chat',
496 /** @deprecated The event is aliased to STREAM_TOKEN_RECEIVED. */507 /** @deprecated The event is aliased to STREAM_TOKEN_RECEIVED. */
497 SMOOTH_STREAM_TOKEN_RECEIVED: 'stream_token_received',508 SMOOTH_STREAM_TOKEN_RECEIVED: 'stream_token_received',
498 STREAM_TOKEN_RECEIVED: 'stream_token_received',509 STREAM_TOKEN_RECEIVED: 'stream_token_received',
@@ -507,7 +518,7 @@ export const event_types = {
507 TOOL_CALLS_RENDERED: 'tool_calls_rendered',518 TOOL_CALLS_RENDERED: 'tool_calls_rendered',
508};519};
509520
510export const eventSource = new EventEmitter();521export const eventSource = new EventEmitter([event_types.APP_READY]);
511522
512eventSource.on(event_types.CHAT_CHANGED, processChatSlashCommands);523eventSource.on(event_types.CHAT_CHANGED, processChatSlashCommands);
513524
@@ -545,6 +556,10 @@ let generatedPromptCache = '';
545let generation_started = new Date();556let generation_started = new Date();
546/** @type {import('./scripts/char-data.js').v1CharData[]} */557/** @type {import('./scripts/char-data.js').v1CharData[]} */
547export let characters = [];558export let characters = [];
559/**
560 * Stringified index of a currently chosen entity in the characters array.
561 * @type {string|undefined} Yes, we hate it as much as you do.
562 */
548export let this_chid;563export let this_chid;
549let saveCharactersPage = 0;564let saveCharactersPage = 0;
550export const default_avatar = 'img/ai4.png';565export const default_avatar = 'img/ai4.png';
@@ -598,7 +613,6 @@ export const printCharactersDebounced = debounce(() => { printCharacters(false);
598export const system_message_types = {613export const system_message_types = {
599 HELP: 'help',614 HELP: 'help',
600 WELCOME: 'welcome',615 WELCOME: 'welcome',
601 GROUP: 'group',
602 EMPTY: 'empty',616 EMPTY: 'empty',
603 GENERIC: 'generic',617 GENERIC: 'generic',
604 NARRATOR: 'narrator',618 NARRATOR: 'narrator',
@@ -691,14 +705,6 @@ async function getSystemMessages() {
691 uses_system_ui: true,705 uses_system_ui: true,
692 mes: await renderTemplateAsync('welcome', { displayVersion }),706 mes: await renderTemplateAsync('welcome', { displayVersion }),
693 },707 },
694 group: {
695 name: systemUserName,
696 force_avatar: system_avatar,
697 is_user: false,
698 is_system: true,
699 is_group: true,
700 mes: 'Group chat created. Say \'Hi\' to lovely people!',
701 },
702 empty: {708 empty: {
703 name: systemUserName,709 name: systemUserName,
704 force_avatar: system_avatar,710 force_avatar: system_avatar,
@@ -978,7 +984,7 @@ async function firstLoadInit() {
978 await initTokenizers();984 await initTokenizers();
979 initBackgrounds();985 initBackgrounds();
980 initAuthorsNote();986 initAuthorsNote();
981 initPersonas();987 await initPersonas();
982 initRossMods();988 initRossMods();
983 initStats();989 initStats();
984 initCfg();990 initCfg();
@@ -1027,12 +1033,22 @@ export function setAnimationDuration(ms = null) {
1027 document.documentElement.style.setProperty('--animation-duration', `${animation_duration}ms`);1033 document.documentElement.style.setProperty('--animation-duration', `${animation_duration}ms`);
1028}1034}
10291035
1036/**
1037 * Sets the currently active character
1038 * @param {object|number|string} [entityOrKey] - An entity with id property (character, group, tag), or directly an id or tag key. If not provided, the active character is reset to `null`.
1039 */
1030export function setActiveCharacter(entityOrKey) {1040export function setActiveCharacter(entityOrKey) {
1031 active_character = getTagKeyForEntity(entityOrKey);1041 active_character = entityOrKey ? getTagKeyForEntity(entityOrKey) : null;
1042 if (active_character) active_group = null;
1032}1043}
10331044
1045/**
1046 * Sets the currently active group.
1047 * @param {object|number|string} [entityOrKey] - An entity with id property (character, group, tag), or directly an id or tag key. If not provided, the active group is reset to `null`.
1048 */
1034export function setActiveGroup(entityOrKey) {1049export function setActiveGroup(entityOrKey) {
1035 active_group = getTagKeyForEntity(entityOrKey);1050 active_group = entityOrKey ? getTagKeyForEntity(entityOrKey) : null;
1051 if (active_group) active_character = null;
1036}1052}
10371053
1038/**1054/**
@@ -1347,6 +1363,14 @@ export function resultCheckStatus() {
1347 stopStatusLoading();1363 stopStatusLoading();
1348}1364}
13491365
1366
1367/**
1368 * Switches the currently selected character to the one with the given ID. (character index, not the character key!)
1369 *
1370 * If the character ID doesn't exist, if the chat is being saved, or if a group is being generated, this function does nothing.
1371 * If the character is different from the currently selected one, it will clear the chat and reset any selected character or group.
1372 * @param {number} id The ID of the character to switch to.
1373 */
1350export async function selectCharacterById(id) {1374export async function selectCharacterById(id) {
1351 if (characters[id] === undefined) {1375 if (characters[id] === undefined) {
1352 return;1376 return;
@@ -1361,7 +1385,7 @@ export async function selectCharacterById(id) {
1361 return;1385 return;
1362 }1386 }
13631387
1364 if (selected_group || this_chid !== id) {1388 if (selected_group || String(this_chid) !== String(id)) {
1365 //if clicked on a different character from what was currently selected1389 //if clicked on a different character from what was currently selected
1366 if (!is_send_press) {1390 if (!is_send_press) {
1367 await clearChat();1391 await clearChat();
@@ -1369,7 +1393,7 @@ export async function selectCharacterById(id) {
1369 resetSelectedGroup();1393 resetSelectedGroup();
1370 this_edit_mes_id = undefined;1394 this_edit_mes_id = undefined;
1371 selected_button = 'character_edit';1395 selected_button = 'character_edit';
1372 this_chid = id;1396 setCharacterId(id);
1373 chat.length = 0;1397 chat.length = 0;
1374 chat_metadata = {};1398 chat_metadata = {};
1375 await getChat();1399 await getChat();
@@ -1377,6 +1401,7 @@ export async function selectCharacterById(id) {
1377 } else {1401 } else {
1378 //if clicked on character that was already selected1402 //if clicked on character that was already selected
1379 selected_button = 'character_edit';1403 selected_button = 'character_edit';
1404 await unshallowCharacter(this_chid);
1380 select_selected_character(this_chid);1405 select_selected_character(this_chid);
1381 }1406 }
1382}1407}
@@ -1420,7 +1445,7 @@ function getCharacterBlock(item, id) {
1420 }1445 }
1421 // Populate the template1446 // Populate the template
1422 const template = $('#character_template .character_select').clone();1447 const template = $('#character_template .character_select').clone();
1423 template.attr({ 'chid': id, 'id': `CharID${id}` });1448 template.attr({ 'data-chid': id, 'id': `CharID${id}` });
1424 template.find('img').attr('src', this_avatar).attr('alt', item.name);1449 template.find('img').attr('src', this_avatar).attr('alt', item.name);
1425 template.find('.avatar').attr('title', `[Character] ${item.name}\nFile: ${item.avatar}`);1450 template.find('.avatar').attr('title', `[Character] ${item.name}\nFile: ${item.avatar}`);
1426 template.find('.ch_name').text(item.name).attr('title', `[Character] ${item.name}`);1451 template.find('.ch_name').text(item.name).attr('title', `[Character] ${item.name}`);
@@ -1546,6 +1571,7 @@ export async function printCharacters(fullRefresh = false) {
1546 });1571 });
15471572
1548 favsToHotswap();1573 favsToHotswap();
1574 updatePersonaConnectionsAvatarList();
1549}1575}
15501576
1551/** Checks the state of the current search, and adds/removes the search sorting option accordingly */1577/** Checks the state of the current search, and adds/removes the search sorting option accordingly */
@@ -1758,9 +1784,7 @@ export async function getCharacters() {
1758 const response = await fetch('/api/characters/all', {1784 const response = await fetch('/api/characters/all', {
1759 method: 'POST',1785 method: 'POST',
1760 headers: getRequestHeaders(),1786 headers: getRequestHeaders(),
1761 body: JSON.stringify({1787 body: JSON.stringify({}),
1762 '': '',
1763 }),
1764 });1788 });
1765 if (response.ok === true) {1789 if (response.ok === true) {
1766 characters.splice(0, characters.length);1790 characters.splice(0, characters.length);
@@ -2455,7 +2479,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2455 timestamp: timestamp,2479 timestamp: timestamp,
2456 extra: mes.extra,2480 extra: mes.extra,
2457 tokenCount: mes.extra?.token_count ?? 0,2481 tokenCount: mes.extra?.token_count ?? 0,
2458 ...formatGenerationTimer(mes.gen_started, mes.gen_finished, mes.extra?.token_count, mes.extra?.reasoning_duration),2482 ...formatGenerationTimer(mes.gen_started, mes.gen_finished, mes.extra?.token_count, mes.extra?.reasoning_duration, mes.extra?.time_to_first_token),
2459 };2483 };
24602484
2461 const renderedMessage = getMessageFromTemplate(params);2485 const renderedMessage = getMessageFromTemplate(params);
@@ -2576,13 +2600,14 @@ export function formatCharacterAvatar(characterAvatar) {
2576 * @param {Date} gen_finished Date when generation was finished2600 * @param {Date} gen_finished Date when generation was finished
2577 * @param {number} tokenCount Number of tokens generated (0 if not available)2601 * @param {number} tokenCount Number of tokens generated (0 if not available)
2578 * @param {number?} [reasoningDuration=null] Reasoning duration (null if no reasoning was done)2602 * @param {number?} [reasoningDuration=null] Reasoning duration (null if no reasoning was done)
2603 * @param {number?} [timeToFirstToken=null] Time to first token
2579 * @returns {Object} Object containing the formatted timer value and title2604 * @returns {Object} Object containing the formatted timer value and title
2580 * @example2605 * @example
2581 * const { timerValue, timerTitle } = formatGenerationTimer(gen_started, gen_finished, tokenCount);2606 * const { timerValue, timerTitle } = formatGenerationTimer(gen_started, gen_finished, tokenCount);
2582 * console.log(timerValue); // 1.2s2607 * console.log(timerValue); // 1.2s
2583 * console.log(timerTitle); // Generation queued: 12:34:56 7 Jan 2021\nReply received: 12:34:57 7 Jan 2021\nTime to generate: 1.2 seconds\nToken rate: 5 t/s2608 * console.log(timerTitle); // Generation queued: 12:34:56 7 Jan 2021\nReply received: 12:34:57 7 Jan 2021\nTime to generate: 1.2 seconds\nToken rate: 5 t/s
2584 */2609 */
2585function formatGenerationTimer(gen_started, gen_finished, tokenCount, reasoningDuration = null) {2610function formatGenerationTimer(gen_started, gen_finished, tokenCount, reasoningDuration = null, timeToFirstToken = null) {
2586 if (!gen_started || !gen_finished) {2611 if (!gen_started || !gen_finished) {
2587 return {};2612 return {};
2588 }2613 }
@@ -2596,8 +2621,9 @@ function formatGenerationTimer(gen_started, gen_finished, tokenCount, reasoningD
2596 `Generation queued: ${start.format(dateFormat)}`,2621 `Generation queued: ${start.format(dateFormat)}`,
2597 `Reply received: ${finish.format(dateFormat)}`,2622 `Reply received: ${finish.format(dateFormat)}`,
2598 `Time to generate: ${seconds} seconds`,2623 `Time to generate: ${seconds} seconds`,
2624 timeToFirstToken ? `Time to first token: ${timeToFirstToken / 1000} seconds` : '',
2599 reasoningDuration > 0 ? `Time to think: ${reasoningDuration / 1000} seconds` : '',2625 reasoningDuration > 0 ? `Time to think: ${reasoningDuration / 1000} seconds` : '',
2600 tokenCount > 0 ? `Token rate: ${Number(tokenCount / seconds).toFixed(1)} t/s` : '',2626 tokenCount > 0 ? `Token rate: ${Number(tokenCount / seconds).toFixed(3)} t/s` : '',
2601 ].filter(x => x).join('\n').trim();2627 ].filter(x => x).join('\n').trim();
26022628
2603 if (isNaN(seconds) || seconds < 0) {2629 if (isNaN(seconds) || seconds < 0) {
@@ -2692,7 +2718,16 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re
2692 environment.personality = fields.personality || '';2718 environment.personality = fields.personality || '';
2693 environment.scenario = fields.scenario || '';2719 environment.scenario = fields.scenario || '';
2694 environment.persona = fields.persona || '';2720 environment.persona = fields.persona || '';
2695 environment.mesExamples = fields.mesExamples || '';2721 environment.mesExamples = () => {
2722 const isInstruct = power_user.instruct.enabled && main_api !== 'openai';
2723 const mesExamplesArray = parseMesExamples(fields.mesExamples, isInstruct);
2724 if (isInstruct) {
2725 const instructExamples = formatInstructModeExamples(mesExamplesArray, name1, name2);
2726 return instructExamples.join('');
2727 }
2728 return mesExamplesArray.join('');
2729 };
2730 environment.mesExamplesRaw = fields.mesExamples || '';
2696 environment.charVersion = fields.version || '';2731 environment.charVersion = fields.version || '';
2697 environment.char_version = fields.version || '';2732 environment.char_version = fields.version || '';
2698 }2733 }
@@ -3081,6 +3116,27 @@ export function getCharacterCardFields() {
3081 return result;3116 return result;
3082}3117}
30833118
3119/**
3120 * Parses an examples string.
3121 * @param {string} examplesStr
3122 * @returns {string[]} Examples array with block heading
3123 */
3124export function parseMesExamples(examplesStr, isInstruct) {
3125 if (!examplesStr || examplesStr.length === 0 || examplesStr === '<START>') {
3126 return [];
3127 }
3128
3129 if (!examplesStr.startsWith('<START>')) {
3130 examplesStr = '<START>\n' + examplesStr.trim();
3131 }
3132
3133 const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : '';
3134 const blockHeading = main_api === 'openai' ? '<START>\n' : (exampleSeparator || (isInstruct ? '<START>\n' : ''));
3135 const splitExamples = examplesStr.split(/<START>/gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`);
3136
3137 return splitExamples;
3138}
3139
3084export function isStreamingEnabled() {3140export function isStreamingEnabled() {
3085 const noStreamSources = [chat_completion_sources.SCALE];3141 const noStreamSources = [chat_completion_sources.SCALE];
3086 return (3142 return (
@@ -3113,8 +3169,9 @@ class StreamingProcessor {
3113 * @param {boolean} forceName2 If true, force the use of name23169 * @param {boolean} forceName2 If true, force the use of name2
3114 * @param {Date} timeStarted Date when generation was started3170 * @param {Date} timeStarted Date when generation was started
3115 * @param {string} continueMessage Previous message if the type is 'continue'3171 * @param {string} continueMessage Previous message if the type is 'continue'
3172 * @param {PromptReasoning} promptReasoning Prompt reasoning instance
3116 */3173 */
3117 constructor(type, forceName2, timeStarted, continueMessage) {3174 constructor(type, forceName2, timeStarted, continueMessage, promptReasoning) {
3118 this.result = '';3175 this.result = '';
3119 this.messageId = -1;3176 this.messageId = -1;
3120 /** @type {HTMLElement} */3177 /** @type {HTMLElement} */
@@ -3135,6 +3192,9 @@ class StreamingProcessor {
3135 this.abortController = new AbortController();3192 this.abortController = new AbortController();
3136 this.firstMessageText = '...';3193 this.firstMessageText = '...';
3137 this.timeStarted = timeStarted;3194 this.timeStarted = timeStarted;
3195 /** @type {number?} */
3196 this.timeToFirstToken = null;
3197 this.createdAt = new Date();
3138 this.continueMessage = type === 'continue' ? continueMessage : '';3198 this.continueMessage = type === 'continue' ? continueMessage : '';
3139 this.swipes = [];3199 this.swipes = [];
3140 /** @type {import('./scripts/logprobs.js').TokenLogprobs[]} */3200 /** @type {import('./scripts/logprobs.js').TokenLogprobs[]} */
@@ -3142,15 +3202,27 @@ class StreamingProcessor {
3142 this.toolCalls = [];3202 this.toolCalls = [];
3143 // Initialize reasoning in its own handler3203 // Initialize reasoning in its own handler
3144 this.reasoningHandler = new ReasoningHandler(timeStarted);3204 this.reasoningHandler = new ReasoningHandler(timeStarted);
3205 /** @type {PromptReasoning} */
3206 this.promptReasoning = promptReasoning;
3207 /** @type {string} */
3208 this.image = '';
3145 }3209 }
31463210
3147 #checkDomElements(messageId) {3211 /**
3212 * Initializes DOM elements for the current message.
3213 * @param {number} messageId Current message ID
3214 * @param {boolean?} continueOnReasoning If continuing on reasoning
3215 */
3216 async #checkDomElements(messageId, continueOnReasoning = null) {
3148 if (this.messageDom === null || this.messageTextDom === null) {3217 if (this.messageDom === null || this.messageTextDom === null) {
3149 this.messageDom = document.querySelector(`#chat .mes[mesid="${messageId}"]`);3218 this.messageDom = document.querySelector(`#chat .mes[mesid="${messageId}"]`);
3150 this.messageTextDom = this.messageDom?.querySelector('.mes_text');3219 this.messageTextDom = this.messageDom?.querySelector('.mes_text');
3151 this.messageTimerDom = this.messageDom?.querySelector('.mes_timer');3220 this.messageTimerDom = this.messageDom?.querySelector('.mes_timer');
3152 this.messageTokenCounterDom = this.messageDom?.querySelector('.tokenCounterDisplay');3221 this.messageTokenCounterDom = this.messageDom?.querySelector('.tokenCounterDisplay');
3153 }3222 }
3223 if (continueOnReasoning) {
3224 await this.reasoningHandler.process(messageId, false, this.promptReasoning);
3225 }
3154 this.reasoningHandler.updateDom(messageId);3226 this.reasoningHandler.updateDom(messageId);
3155 }3227 }
31563228
@@ -3170,15 +3242,20 @@ class StreamingProcessor {
3170 }3242 }
31713243
3172 async onStartStreaming(text) {3244 async onStartStreaming(text) {
3245 const continueOnReasoning = !!(this.type === 'continue' && this.promptReasoning.prefixReasoning);
3246 if (continueOnReasoning) {
3247 this.reasoningHandler.initContinue(this.promptReasoning);
3248 }
3249
3173 let messageId = -1;3250 let messageId = -1;
31743251
3175 if (this.type == 'impersonate') {3252 if (this.type == 'impersonate') {
3176 this.sendTextarea.value = '';3253 this.sendTextarea.value = '';
3177 this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true }));3254 this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true }));
3178 } else {3255 } else {
3179 await saveReply(this.type, text, true, '', [], '');3256 await saveReply({ type: this.type, getMessage: text, fromStreaming: true });
3180 messageId = chat.length - 1;3257 messageId = chat.length - 1;
3181 this.#checkDomElements(messageId);3258 await this.#checkDomElements(messageId, continueOnReasoning);
3182 this.markUIGenStarted();3259 this.markUIGenStarted();
3183 }3260 }
3184 hideSwipeButtons();3261 hideSwipeButtons();
@@ -3211,7 +3288,7 @@ class StreamingProcessor {
3211 this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true }));3288 this.sendTextarea.dispatchEvent(new Event('input', { bubbles: true }));
3212 } else {3289 } else {
3213 const mesChanged = chat[messageId]['mes'] !== processedText;3290 const mesChanged = chat[messageId]['mes'] !== processedText;
3214 this.#checkDomElements(messageId);3291 await this.#checkDomElements(messageId);
3215 this.#updateMessageBlockVisibility();3292 this.#updateMessageBlockVisibility();
3216 const currentTime = new Date();3293 const currentTime = new Date();
3217 chat[messageId]['mes'] = processedText;3294 chat[messageId]['mes'] = processedText;
@@ -3220,9 +3297,11 @@ class StreamingProcessor {
3220 if (!chat[messageId]['extra']) {3297 if (!chat[messageId]['extra']) {
3221 chat[messageId]['extra'] = {};3298 chat[messageId]['extra'] = {};
3222 }3299 }
3300 chat[messageId]['extra']['time_to_first_token'] = this.timeToFirstToken;
32233301
3224 // Update reasoning3302 // Update reasoning
3225 await this.reasoningHandler.process(messageId, mesChanged);3303 await this.reasoningHandler.process(messageId, mesChanged, this.promptReasoning);
3304 processedText = chat[messageId]['mes'];
32263305
3227 // Token count update.3306 // Token count update.
3228 const tokenCountText = this.reasoningHandler.reasoning + processedText;3307 const tokenCountText = this.reasoningHandler.reasoning + processedText;
@@ -3236,7 +3315,12 @@ class StreamingProcessor {
32363315
3237 if ((this.type == 'swipe' || this.type === 'continue') && Array.isArray(chat[messageId]['swipes'])) {3316 if ((this.type == 'swipe' || this.type === 'continue') && Array.isArray(chat[messageId]['swipes'])) {
3238 chat[messageId]['swipes'][chat[messageId]['swipe_id']] = processedText;3317 chat[messageId]['swipes'][chat[messageId]['swipe_id']] = processedText;
3239 chat[messageId]['swipe_info'][chat[messageId]['swipe_id']] = { 'send_date': chat[messageId]['send_date'], 'gen_started': chat[messageId]['gen_started'], 'gen_finished': chat[messageId]['gen_finished'], 'extra': JSON.parse(JSON.stringify(chat[messageId]['extra'])) };3318 chat[messageId]['swipe_info'][chat[messageId]['swipe_id']] = {
3319 'send_date': chat[messageId]['send_date'],
3320 'gen_started': chat[messageId]['gen_started'],
3321 'gen_finished': chat[messageId]['gen_finished'],
3322 'extra': JSON.parse(JSON.stringify(chat[messageId]['extra'])),
3323 };
3240 }3324 }
32413325
3242 const formattedText = messageFormatting(3326 const formattedText = messageFormatting(
@@ -3252,7 +3336,7 @@ class StreamingProcessor {
3252 this.messageTextDom.innerHTML = formattedText;3336 this.messageTextDom.innerHTML = formattedText;
3253 }3337 }
32543338
3255 const timePassed = formatGenerationTimer(this.timeStarted, currentTime, currentTokenCount, this.reasoningHandler.getDuration());3339 const timePassed = formatGenerationTimer(this.timeStarted, currentTime, currentTokenCount, this.reasoningHandler.getDuration(), this.timeToFirstToken);
3256 if (this.messageTimerDom instanceof HTMLElement) {3340 if (this.messageTimerDom instanceof HTMLElement) {
3257 this.messageTimerDom.textContent = timePassed.timerValue;3341 this.messageTimerDom.textContent = timePassed.timerValue;
3258 this.messageTimerDom.title = timePassed.timerTitle;3342 this.messageTimerDom.title = timePassed.timerTitle;
@@ -3275,26 +3359,35 @@ class StreamingProcessor {
32753359
3276 if (Array.isArray(this.swipes) && this.swipes.length > 0) {3360 if (Array.isArray(this.swipes) && this.swipes.length > 0) {
3277 const message = chat[messageId];3361 const message = chat[messageId];
3362 const swipeInfoExtra = structuredClone(message.extra ?? {});
3363 delete swipeInfoExtra.token_count;
3364 delete swipeInfoExtra.reasoning;
3365 delete swipeInfoExtra.reasoning_duration;
3278 const swipeInfo = {3366 const swipeInfo = {
3279 send_date: message.send_date,3367 send_date: message.send_date,
3280 gen_started: message.gen_started,3368 gen_started: message.gen_started,
3281 gen_finished: message.gen_finished,3369 gen_finished: message.gen_finished,
3282 extra: structuredClone(message.extra),3370 extra: swipeInfoExtra,
3283 };3371 };
3284 const swipeInfoArray = [];3372 const swipeInfoArray = Array(this.swipes.length).fill().map(() => structuredClone(swipeInfo));
3285 swipeInfoArray.length = this.swipes.length;3373 parseReasoningInSwipes(this.swipes, swipeInfoArray, message.extra?.reasoning_duration);
3286 swipeInfoArray.fill(swipeInfo);
3287 chat[messageId].swipes.push(...this.swipes);3374 chat[messageId].swipes.push(...this.swipes);
3288 chat[messageId].swipe_info.push(...swipeInfoArray);3375 chat[messageId].swipe_info.push(...swipeInfoArray);
3289 }3376 }
32903377
3378 if (this.image) {
3379 await processImageAttachment(chat[messageId], { imageUrl: this.image, parsedImage: null });
3380 appendMediaToMessage(chat[messageId], $(this.messageDom));
3381 }
3382
3291 if (this.type !== 'impersonate') {3383 if (this.type !== 'impersonate') {
3292 await eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId);3384 await eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId, this.type);
3293 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, this.messageId);3385 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, this.messageId, this.type);
3294 } else {3386 } else {
3295 await eventSource.emit(event_types.IMPERSONATE_READY, text);3387 await eventSource.emit(event_types.IMPERSONATE_READY, text);
3296 }3388 }
32973389
3390 syncMesToSwipe(messageId);
3298 saveLogprobsForActiveMessage(this.messageLogprobs.filter(Boolean), this.continueMessage);3391 saveLogprobsForActiveMessage(this.messageLogprobs.filter(Boolean), this.continueMessage);
3299 await saveChatConditional();3392 await saveChatConditional();
3300 unblockGeneration();3393 unblockGeneration();
@@ -3318,8 +3411,8 @@ class StreamingProcessor {
33183411
3319 const noEmitTypes = ['swipe', 'impersonate', 'continue'];3412 const noEmitTypes = ['swipe', 'impersonate', 'continue'];
3320 if (!noEmitTypes.includes(this.type)) {3413 if (!noEmitTypes.includes(this.type)) {
3321 eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId);3414 eventSource.emit(event_types.MESSAGE_RECEIVED, this.messageId, this.type);
3322 eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, this.messageId);3415 eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, this.messageId, this.type);
3323 }3416 }
3324 }3417 }
33253418
@@ -3327,7 +3420,12 @@ class StreamingProcessor {
3327 if (this.type !== 'swipe' && this.type !== 'impersonate') {3420 if (this.type !== 'swipe' && this.type !== 'impersonate') {
3328 if (Array.isArray(chat[messageId]['swipes']) && chat[messageId]['swipes'].length === 1 && chat[messageId]['swipe_id'] === 0) {3421 if (Array.isArray(chat[messageId]['swipes']) && chat[messageId]['swipes'].length === 1 && chat[messageId]['swipe_id'] === 0) {
3329 chat[messageId]['swipes'][0] = chat[messageId]['mes'];3422 chat[messageId]['swipes'][0] = chat[messageId]['mes'];
3330 chat[messageId]['swipe_info'][0] = { 'send_date': chat[messageId]['send_date'], 'gen_started': chat[messageId]['gen_started'], 'gen_finished': chat[messageId]['gen_finished'], 'extra': JSON.parse(JSON.stringify(chat[messageId]['extra'])) };3423 chat[messageId]['swipe_info'][0] = {
3424 'send_date': chat[messageId]['send_date'],
3425 'gen_started': chat[messageId]['gen_started'],
3426 'gen_finished': chat[messageId]['gen_finished'],
3427 'extra': JSON.parse(JSON.stringify(chat[messageId]['extra'])),
3428 };
3331 }3429 }
3332 }3430 }
3333 }3431 }
@@ -3361,7 +3459,11 @@ class StreamingProcessor {
3361 const sw = new Stopwatch(1000 / power_user.streaming_fps);3459 const sw = new Stopwatch(1000 / power_user.streaming_fps);
3362 const timestamps = [];3460 const timestamps = [];
3363 for await (const { text, swipes, logprobs, toolCalls, state } of this.generator()) {3461 for await (const { text, swipes, logprobs, toolCalls, state } of this.generator()) {
3364 timestamps.push(Date.now());3462 const now = Date.now();
3463 timestamps.push(now);
3464 if (!this.timeToFirstToken) {
3465 this.timeToFirstToken = now - this.createdAt.getTime();
3466 }
3365 if (this.isStopped || this.abortController.signal.aborted) {3467 if (this.isStopped || this.abortController.signal.aborted) {
3366 return this.result;3468 return this.result;
3367 }3469 }
@@ -3373,7 +3475,8 @@ class StreamingProcessor {
3373 this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs]));3475 this.messageLogprobs.push(...(Array.isArray(logprobs) ? logprobs : [logprobs]));
3374 }3476 }
3375 // Get the updated reasoning string into the handler3477 // Get the updated reasoning string into the handler
3376 this.reasoningHandler.updateReasoning(this.messageId, state?.reasoning ?? '');3478 this.reasoningHandler.updateReasoning(this.messageId, state?.reasoning);
3479 this.image = state?.image ?? '';
3377 await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);3480 await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);
3378 await sw.tick(async () => await this.onProgressStreaming(this.messageId, this.continueMessage + text));3481 await sw.tick(async () => await this.onProgressStreaming(this.messageId, this.continueMessage + text));
3379 }3482 }
@@ -3628,6 +3731,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3628 setGenerationProgress(0);3731 setGenerationProgress(0);
3629 generation_started = new Date();3732 generation_started = new Date();
36303733
3734 // Prevent generation from shallow characters
3735 await unshallowCharacter(this_chid);
3736
3631 // Occurs every time, even if the generation is aborted due to slash commands execution3737 // Occurs every time, even if the generation is aborted due to slash commands execution
3632 await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);3738 await eventSource.emit(event_types.GENERATION_STARTED, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
36333739
@@ -3843,7 +3949,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3843 coreChat = await Promise.all(coreChat.map(async (chatItem, index) => {3949 coreChat = await Promise.all(coreChat.map(async (chatItem, index) => {
3844 let message = chatItem.mes;3950 let message = chatItem.mes;
3845 let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT;3951 let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT;
3846 let options = { isPrompt: true, depth: (coreChat.length - index - 1) };3952 let options = { isPrompt: true, depth: (coreChat.length - index - (isContinue ? 2 : 1)) };
38473953
3848 let regexedMessage = getRegexedString(message, regexType, options);3954 let regexedMessage = getRegexedString(message, regexType, options);
3849 regexedMessage = await appendFileContent(chatItem, regexedMessage);3955 regexedMessage = await appendFileContent(chatItem, regexedMessage);
@@ -3859,13 +3965,13 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3859 };3965 };
3860 }));3966 }));
38613967
3862 const reasoning = new PromptReasoning();3968 const promptReasoning = new PromptReasoning();
3863 for (let i = coreChat.length - 1; i >= 0; i--) {3969 for (let i = coreChat.length - 1; i >= 0; i--) {
3864 const depth = coreChat.length - i - 1;3970 const depth = coreChat.length - i - (isContinue ? 2 : 1);
3865 const isPrefix = isContinue && i === coreChat.length - 1;3971 const isPrefix = isContinue && i === coreChat.length - 1;
3866 coreChat[i] = {3972 coreChat[i] = {
3867 ...coreChat[i],3973 ...coreChat[i],
3868 mes: reasoning.addToMessage(3974 mes: promptReasoning.addToMessage(
3869 coreChat[i].mes,3975 coreChat[i].mes,
3870 getRegexedString(3976 getRegexedString(
3871 String(coreChat[i].extra?.reasoning ?? ''),3977 String(coreChat[i].extra?.reasoning ?? ''),
@@ -3873,9 +3979,10 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3873 { isPrompt: true, depth: depth },3979 { isPrompt: true, depth: depth },
3874 ),3980 ),
3875 isPrefix,3981 isPrefix,
3982 coreChat[i].extra?.reasoning_duration,
3876 ),3983 ),
3877 };3984 };
3878 if (reasoning.isLimitReached()) {3985 if (promptReasoning.isLimitReached()) {
3879 break;3986 break;
3880 }3987 }
3881 }3988 }
@@ -3939,29 +4046,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3939 force_name2 = false;4046 force_name2 = false;
3940 }4047 }
39414048
3942 // TODO (kingbri): Migrate to a utility function4049 let mesExamplesArray = parseMesExamples(mesExamples, isInstruct);
3943 /**
3944 * Parses an examples string.
3945 * @param {string} examplesStr
3946 * @returns {string[]} Examples array with block heading
3947 */
3948 function parseMesExamples(examplesStr) {
3949 if (!examplesStr || examplesStr.length === 0 || examplesStr === '<START>') {
3950 return [];
3951 }
3952
3953 if (!examplesStr.startsWith('<START>')) {
3954 examplesStr = '<START>\n' + examplesStr.trim();
3955 }
3956
3957 const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : '';
3958 const blockHeading = main_api === 'openai' ? '<START>\n' : (exampleSeparator || (isInstruct ? '<START>\n' : ''));
3959 const splitExamples = examplesStr.split(/<START>/gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`);
3960
3961 return splitExamples;
3962 }
3963
3964 let mesExamplesArray = parseMesExamples(mesExamples);
39654050
3966 //////////////////////////////////4051 //////////////////////////////////
3967 // Extension added strings4052 // Extension added strings
@@ -3986,7 +4071,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3986 }4071 }
39874072
3988 const formattedExample = baseChatReplace(exampleMessage, name1, name2);4073 const formattedExample = baseChatReplace(exampleMessage, name1, name2);
3989 const cleanedExample = parseMesExamples(formattedExample);4074 const cleanedExample = parseMesExamples(formattedExample, isInstruct);
39904075
3991 // Insert depending on before or after position4076 // Insert depending on before or after position
3992 if (example.position === wi_anchor_position.before) {4077 if (example.position === wi_anchor_position.before) {
@@ -4700,7 +4785,8 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4700 console.debug(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`);4785 console.debug(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`);
47014786
4702 if (isStreamingEnabled() && type !== 'quiet') {4787 if (isStreamingEnabled() && type !== 'quiet') {
4703 streamingProcessor = new StreamingProcessor(type, force_name2, generation_started, continue_mag);4788 continue_mag = promptReasoning.removePrefix(continue_mag);
4789 streamingProcessor = new StreamingProcessor(type, force_name2, generation_started, continue_mag, promptReasoning);
4704 if (isContinue) {4790 if (isContinue) {
4705 // Save reply does add cycle text to the prompt, so it's not needed here4791 // Save reply does add cycle text to the prompt, so it's not needed here
4706 streamingProcessor.firstMessageText = '';4792 streamingProcessor.firstMessageText = '';
@@ -4789,6 +4875,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4789 let getMessage = extractMessageFromData(data);4875 let getMessage = extractMessageFromData(data);
4790 let title = extractTitleFromData(data);4876 let title = extractTitleFromData(data);
4791 let reasoning = extractReasoningFromData(data);4877 let reasoning = extractReasoningFromData(data);
4878 let imageUrl = extractImageFromData(data);
4792 kobold_horde_model = title;4879 kobold_horde_model = title;
47934880
4794 const swipes = extractMultiSwipes(data, type);4881 const swipes = extractMultiSwipes(data, type);
@@ -4801,6 +4888,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4801 }4888 }
48024889
4803 if (isContinue) {4890 if (isContinue) {
4891 continue_mag = promptReasoning.removePrefix(continue_mag);
4804 getMessage = continue_mag + getMessage;4892 getMessage = continue_mag + getMessage;
4805 }4893 }
48064894
@@ -4820,10 +4908,10 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4820 else {4908 else {
4821 // Without streaming we'll be having a full message on continuation. Treat it as a last chunk.4909 // Without streaming we'll be having a full message on continuation. Treat it as a last chunk.
4822 if (originalType !== 'continue') {4910 if (originalType !== 'continue') {
4823 ({ type, getMessage } = await saveReply(type, getMessage, false, title, swipes, reasoning));4911 ({ type, getMessage } = await saveReply({ type, getMessage, title, swipes, reasoning, imageUrl }));
4824 }4912 }
4825 else {4913 else {
4826 ({ type, getMessage } = await saveReply('appendFinal', getMessage, false, title, swipes, reasoning));4914 ({ type, getMessage } = await saveReply({ type: 'appendFinal', getMessage, title, swipes, reasoning, imageUrl }));
4827 }4915 }
48284916
4829 // This relies on `saveReply` having been called to add the message to the chat, so it must be last.4917 // This relies on `saveReply` having been called to add the message to the chat, so it must be last.
@@ -5290,7 +5378,7 @@ function addChatsSeparator(mesSendString) {
5290}5378}
52915379
5292async function duplicateCharacter() {5380async function duplicateCharacter() {
5293 if (!this_chid) {5381 if (this_chid === undefined || !characters[this_chid]) {
5294 toastr.warning(t`You must first select a character to duplicate!`);5382 toastr.warning(t`You must first select a character to duplicate!`);
5295 return '';5383 return '';
5296 }5384 }
@@ -5624,7 +5712,7 @@ export async function sendStreamingRequest(type, data) {
5624 * @returns {string} Generation URL5712 * @returns {string} Generation URL
5625 * @throws {Error} If the API is unknown5713 * @throws {Error} If the API is unknown
5626 */5714 */
5627function getGenerateUrl(api) {5715export function getGenerateUrl(api) {
5628 switch (api) {5716 switch (api) {
5629 case 'kobold':5717 case 'kobold':
5630 return '/api/backends/kobold/generate';5718 return '/api/backends/kobold/generate';
@@ -5648,6 +5736,32 @@ function extractTitleFromData(data) {
5648}5736}
56495737
5650/**5738/**
5739 * Extracts the image from the response data.
5740 * @param {object} data Response data
5741 * @param {object} [options] Extraction options
5742 * @param {string} [options.mainApi] Main API to use
5743 * @param {string} [options.chatCompletionSource] Chat completion source
5744 * @returns {string} Extracted image
5745 */
5746function extractImageFromData(data, { mainApi = null, chatCompletionSource = null } = {}) {
5747 switch (mainApi ?? main_api) {
5748 case 'openai': {
5749 switch (chatCompletionSource ?? oai_settings.chat_completion_source) {
5750 case chat_completion_sources.MAKERSUITE: {
5751 const inlineData = data?.responseContent?.parts?.find(x => x.inlineData)?.inlineData;
5752 if (inlineData) {
5753 return `data:${inlineData.mimeType};base64,${inlineData.data}`;
5754 }
5755 } break;
5756
5757 }
5758 } break;
5759 }
5760
5761 return undefined;
5762}
5763
5764/**
5651 * parseAndSaveLogprobs receives the full data response for a non-streaming5765 * parseAndSaveLogprobs receives the full data response for a non-streaming
5652 * generation, parses logprobs for all tokens in the message, and saves them5766 * generation, parses logprobs for all tokens in the message, and saves them
5653 * to the currently active message.5767 * to the currently active message.
@@ -5692,14 +5806,15 @@ function parseAndSaveLogprobs(data, continueFrom) {
5692/**5806/**
5693 * Extracts the message from the response data.5807 * Extracts the message from the response data.
5694 * @param {object} data Response data5808 * @param {object} data Response data
5809 * @param {string} activeApi If it's set, ignores active API
5695 * @returns {string} Extracted message5810 * @returns {string} Extracted message
5696 */5811 */
5697function extractMessageFromData(data) {5812export function extractMessageFromData(data, activeApi = null) {
5698 if (typeof data === 'string') {5813 if (typeof data === 'string') {
5699 return data;5814 return data;
5700 }5815 }
57015816
5702 switch (main_api) {5817 switch (activeApi ?? main_api) {
5703 case 'kobold':5818 case 'kobold':
5704 return data.results[0].text;5819 return data.results[0].text;
5705 case 'koboldhorde':5820 case 'koboldhorde':
@@ -5709,7 +5824,7 @@ function extractMessageFromData(data) {
5709 case 'novel':5824 case 'novel':
5710 return data.output;5825 return data.output;
5711 case 'openai':5826 case 'openai':
5712 return data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? '';5827 return data?.content?.find(p => p.type === 'text')?.text ?? data?.choices?.[0]?.message?.content ?? data?.choices?.[0]?.text ?? data?.text ?? data?.message?.content?.[0]?.text ?? data?.message?.tool_plan ?? '';
5713 default:5828 default:
5714 return '';5829 return '';
5715 }5830 }
@@ -5888,14 +6003,66 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc
5888 getMessage = trimToEndSentence(getMessage);6003 getMessage = trimToEndSentence(getMessage);
5889 }6004 }
58906005
5891 if (power_user.trim_spaces) {6006 if (power_user.trim_spaces && !PromptReasoning.getLatestPrefix()) {
5892 getMessage = getMessage.trim();6007 getMessage = getMessage.trim();
5893 }6008 }
58946009
5895 return getMessage;6010 return getMessage;
5896}6011}
58976012
5898export async function saveReply(type, getMessage, fromStreaming, title, swipes, reasoning) {6013/**
6014 * Adds an image to the message.
6015 * @param {object} message Message object
6016 * @param {object} sources Image sources
6017 * @param {ParsedImage} [sources.parsedImage] Parsed image
6018 * @param {string} [sources.imageUrl] Image URL
6019 *
6020 * @returns {Promise<void>}
6021 */
6022async function processImageAttachment(message, { parsedImage, imageUrl }) {
6023 if (parsedImage?.image) {
6024 saveImageToMessage(parsedImage, message);
6025 return;
6026 }
6027
6028 if (!imageUrl) {
6029 return;
6030 }
6031
6032 let url = imageUrl;
6033 if (isDataURL(url)) {
6034 const fileName = `inline_image_${Date.now().toString()}`;
6035 const [mime, base64] = /^data:(.*?);base64,(.*)$/.exec(imageUrl).slice(1);
6036 url = await saveBase64AsFile(base64, message.name, fileName, mime.split('/')[1]);
6037 }
6038 saveImageToMessage({ image: url, inline: true }, message);
6039}
6040
6041/**
6042 * Saves a resulting message to the chat.
6043 * @param {SaveReplyParams} params
6044 * @returns {Promise<SaveReplyResult>} Promise when the message is saved
6045 *
6046 * @typedef {object} SaveReplyParams
6047 * @property {string} type Type of generation
6048 * @property {string} getMessage Generated message
6049 * @property {boolean} [fromStreaming] If the message is from streaming
6050 * @property {string} [title] Message tooltip
6051 * @property {string[]} [swipes] Extra swipes
6052 * @property {string} [reasoning] Message reasoning
6053 * @property {string} [imageUrl] Link to an image
6054 *
6055 * @typedef {object} SaveReplyResult
6056 * @property {string} type Type of generation
6057 * @property {string} getMessage Generated message
6058 */
6059export async function saveReply({ type, getMessage, fromStreaming = false, title = '', swipes = [], reasoning = '', imageUrl = '' }) {
6060 // Backward compatibility
6061 if (arguments.length > 1 && typeof arguments[0] !== 'object') {
6062 console.trace('saveReply called with positional arguments. Please use an object instead.');
6063 [type, getMessage, fromStreaming, title, swipes, reasoning, imageUrl] = arguments;
6064 }
6065
5899 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||6066 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||
5900 chat[chat.length - 1]['is_user'])) {6067 chat[chat.length - 1]['is_user'])) {
5901 type = 'normal';6068 type = 'normal';
@@ -5916,8 +6083,8 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
59166083
5917 let oldMessage = '';6084 let oldMessage = '';
5918 const generationFinished = new Date();6085 const generationFinished = new Date();
5919 const img = extractImageFromMessage(getMessage);6086 const parsedImage = extractImageFromMessage(getMessage);
5920 getMessage = img.getMessage;6087 getMessage = parsedImage.getMessage;
5921 if (type === 'swipe') {6088 if (type === 'swipe') {
5922 oldMessage = chat[chat.length - 1]['mes'];6089 oldMessage = chat[chat.length - 1]['mes'];
5923 chat[chat.length - 1]['swipes'].length++;6090 chat[chat.length - 1]['swipes'].length++;
@@ -5931,14 +6098,15 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
5931 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();6098 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5932 chat[chat.length - 1]['extra']['reasoning'] = reasoning;6099 chat[chat.length - 1]['extra']['reasoning'] = reasoning;
5933 chat[chat.length - 1]['extra']['reasoning_duration'] = null;6100 chat[chat.length - 1]['extra']['reasoning_duration'] = null;
6101 await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl });
5934 if (power_user.message_token_count_enabled) {6102 if (power_user.message_token_count_enabled) {
5935 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];6103 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
5936 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);6104 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
5937 }6105 }
5938 const chat_id = (chat.length - 1);6106 const chat_id = (chat.length - 1);
5939 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id);6107 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
5940 addOneMessage(chat[chat_id], { type: 'swipe' });6108 addOneMessage(chat[chat_id], { type: 'swipe' });
5941 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id);6109 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
5942 } else {6110 } else {
5943 chat[chat.length - 1]['mes'] = getMessage;6111 chat[chat.length - 1]['mes'] = getMessage;
5944 }6112 }
@@ -5954,14 +6122,15 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
5954 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();6122 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5955 chat[chat.length - 1]['extra']['reasoning'] = reasoning;6123 chat[chat.length - 1]['extra']['reasoning'] = reasoning;
5956 chat[chat.length - 1]['extra']['reasoning_duration'] = null;6124 chat[chat.length - 1]['extra']['reasoning_duration'] = null;
6125 await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl });
5957 if (power_user.message_token_count_enabled) {6126 if (power_user.message_token_count_enabled) {
5958 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];6127 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
5959 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);6128 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
5960 }6129 }
5961 const chat_id = (chat.length - 1);6130 const chat_id = (chat.length - 1);
5962 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id);6131 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
5963 addOneMessage(chat[chat_id], { type: 'swipe' });6132 addOneMessage(chat[chat_id], { type: 'swipe' });
5964 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id);6133 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
5965 } else if (type === 'appendFinal') {6134 } else if (type === 'appendFinal') {
5966 oldMessage = chat[chat.length - 1]['mes'];6135 oldMessage = chat[chat.length - 1]['mes'];
5967 console.debug('Trying to appendFinal.');6136 console.debug('Trying to appendFinal.');
@@ -5973,15 +6142,16 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
5973 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();6142 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
5974 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();6143 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5975 chat[chat.length - 1]['extra']['reasoning'] += reasoning;6144 chat[chat.length - 1]['extra']['reasoning'] += reasoning;
6145 await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl });
5976 // We don't know if the reasoning duration extended, so we don't update it here on purpose.6146 // We don't know if the reasoning duration extended, so we don't update it here on purpose.
5977 if (power_user.message_token_count_enabled) {6147 if (power_user.message_token_count_enabled) {
5978 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];6148 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
5979 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);6149 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
5980 }6150 }
5981 const chat_id = (chat.length - 1);6151 const chat_id = (chat.length - 1);
5982 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id);6152 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
5983 addOneMessage(chat[chat_id], { type: 'swipe' });6153 addOneMessage(chat[chat_id], { type: 'swipe' });
5984 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id);6154 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
59856155
5986 } else {6156 } else {
5987 console.debug('entering chat update routine for non-swipe post');6157 console.debug('entering chat update routine for non-swipe post');
@@ -6018,12 +6188,12 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
6018 chat[chat.length - 1]['extra']['gen_id'] = group_generation_id;6188 chat[chat.length - 1]['extra']['gen_id'] = group_generation_id;
6019 }6189 }
60206190
6021 saveImageToMessage(img, chat[chat.length - 1]);6191 await processImageAttachment(chat[chat.length - 1], { parsedImage, imageUrl: imageUrl });
6022 const chat_id = (chat.length - 1);6192 const chat_id = (chat.length - 1);
60236193
6024 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id);6194 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
6025 addOneMessage(chat[chat_id]);6195 addOneMessage(chat[chat_id]);
6026 !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id);6196 !fromStreaming && await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, type);
6027 }6197 }
60286198
6029 const item = chat[chat.length - 1];6199 const item = chat[chat.length - 1];
@@ -6052,15 +6222,18 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
6052 }6222 }
60536223
6054 if (Array.isArray(swipes) && swipes.length > 0) {6224 if (Array.isArray(swipes) && swipes.length > 0) {
6225 const swipeInfoExtra = structuredClone(item.extra ?? {});
6226 delete swipeInfoExtra.token_count;
6227 delete swipeInfoExtra.reasoning;
6228 delete swipeInfoExtra.reasoning_duration;
6055 const swipeInfo = {6229 const swipeInfo = {
6056 send_date: item.send_date,6230 send_date: item.send_date,
6057 gen_started: item.gen_started,6231 gen_started: item.gen_started,
6058 gen_finished: item.gen_finished,6232 gen_finished: item.gen_finished,
6059 extra: structuredClone(item.extra),6233 extra: swipeInfoExtra,
6060 };6234 };
6061 const swipeInfoArray = [];6235 const swipeInfoArray = Array(swipes.length).fill().map(() => structuredClone(swipeInfo));
6062 swipeInfoArray.length = swipes.length;6236 parseReasoningInSwipes(swipes, swipeInfoArray, item.extra?.reasoning_duration);
6063 swipeInfoArray.fill(swipeInfo, 0, swipes.length);
6064 item.swipes.push(...swipes);6237 item.swipes.push(...swipes);
6065 item.swipe_info.push(...swipeInfoArray);6238 item.swipe_info.push(...swipeInfoArray);
6066 }6239 }
@@ -6069,19 +6242,64 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes,
6069 return { type, getMessage };6242 return { type, getMessage };
6070}6243}
60716244
6072export function syncCurrentSwipeInfoExtras() {6245/**
6246 * Syncs the current message and all its data into the swipe data at the given message ID (or the last message if no ID is given).
6247 *
6248 * If the swipe data is invalid in some way, this function will exit out without doing anything.
6249 * @param {number?} [messageId=null] - The ID of the message to sync with the swipe data. If no ID is given, the last message is used.
6250 * @returns {boolean} Whether the message was successfully synced
6251 */
6252export function syncMesToSwipe(messageId = null) {
6073 if (!chat.length) {6253 if (!chat.length) {
6074 return;6254 return false;
6255 }
6256
6257 const targetMessageId = messageId ?? chat.length - 1;
6258 if (targetMessageId >= chat.length || targetMessageId < 0) {
6259 console.warn(`[syncMesToSwipe] Invalid message ID: ${messageId}`);
6260 return false;
6075 }6261 }
6076 const currentMessage = chat[chat.length - 1];6262
6077 if (currentMessage && Array.isArray(currentMessage.swipe_info) && typeof currentMessage.swipe_id === 'number') {6263 const targetMessage = chat[targetMessageId];
6078 const swipeInfo = currentMessage.swipe_info[currentMessage.swipe_id];6264
6079 if (swipeInfo && typeof swipeInfo === 'object') {6265 if (!targetMessage) {
6080 swipeInfo.extra = structuredClone(currentMessage.extra);6266 return false;
6081 }6267 }
6268
6269 // No swipe data there yet, exit out
6270 if (typeof targetMessage.swipe_id !== 'number') {
6271 return false;
6272 }
6273 // If swipes structure is invalid, exit out (for now?)
6274 if (!Array.isArray(targetMessage.swipe_info) || !Array.isArray(targetMessage.swipes)) {
6275 return false;
6276 }
6277 // If the swipe is not present yet, exit out (will likely be copied later)
6278 if (!targetMessage.swipes[targetMessage.swipe_id] || !targetMessage.swipe_info[targetMessage.swipe_id]) {
6279 return false;
6280 }
6281
6282 const targetSwipeInfo = targetMessage.swipe_info[targetMessage.swipe_id];
6283 if (typeof targetSwipeInfo !== 'object') {
6284 return false;
6082 }6285 }
6286
6287 targetMessage.swipes[targetMessage.swipe_id] = targetMessage.mes;
6288
6289 targetSwipeInfo.send_date = targetMessage.send_date;
6290 targetSwipeInfo.gen_started = targetMessage.gen_started;
6291 targetSwipeInfo.gen_finished = targetMessage.gen_finished;
6292 targetSwipeInfo.extra = structuredClone(targetMessage.extra);
6293
6294 return true;
6083}6295}
60846296
6297/**
6298 * Saves the image to the message object.
6299 * @param {ParsedImage} img Image object
6300 * @param {object} mes Chat message object
6301 * @typedef {{ image?: string, title?: string, inline?: boolean }} ParsedImage
6302 */
6085function saveImageToMessage(img, mes) {6303function saveImageToMessage(img, mes) {
6086 if (mes && img.image) {6304 if (mes && img.image) {
6087 if (!mes.extra || typeof mes.extra !== 'object') {6305 if (!mes.extra || typeof mes.extra !== 'object') {
@@ -6089,6 +6307,7 @@ function saveImageToMessage(img, mes) {
6089 }6307 }
6090 mes.extra.image = img.image;6308 mes.extra.image = img.image;
6091 mes.extra.title = img.title;6309 mes.extra.title = img.title;
6310 mes.extra.inline_image = img.inline;
6092 }6311 }
6093}6312}
60946313
@@ -6131,7 +6350,7 @@ function extractImageFromMessage(getMessage) {
6131 const image = results ? results[1] : '';6350 const image = results ? results[1] : '';
6132 const title = results ? results[2] : '';6351 const title = results ? results[2] : '';
6133 getMessage = getMessage.replace(regex, '');6352 getMessage = getMessage.replace(regex, '');
6134 return { getMessage, image, title };6353 return { getMessage, image, title, inline: true };
6135}6354}
61366355
6137/**6356/**
@@ -6155,7 +6374,7 @@ export function resetChatState() {
6155 // replaces deleted charcter name with system user since it will be displayed next.6374 // replaces deleted charcter name with system user since it will be displayed next.
6156 name2 = (this_chid === undefined && neutralCharacterName) ? neutralCharacterName : systemUserName;6375 name2 = (this_chid === undefined && neutralCharacterName) ? neutralCharacterName : systemUserName;
6157 //unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays)6376 //unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays)
6158 this_chid = undefined;6377 setCharacterId(undefined);
6159 // sets up system user to tell user about having deleted a character6378 // sets up system user to tell user about having deleted a character
6160 chat.splice(0, chat.length, ...SAFETY_CHAT);6379 chat.splice(0, chat.length, ...SAFETY_CHAT);
6161 // resets chat metadata6380 // resets chat metadata
@@ -6178,8 +6397,29 @@ export function setExternalAbortController(controller) {
6178 abortController = controller;6397 abortController = controller;
6179}6398}
61806399
6400/**
6401 * Sets a character array index.
6402 * @param {number|string|undefined} value
6403 */
6181export function setCharacterId(value) {6404export function setCharacterId(value) {
6182 this_chid = value;6405 switch (typeof value) {
6406 case 'bigint':
6407 case 'number':
6408 this_chid = String(value);
6409 break;
6410 case 'string':
6411 this_chid = !isNaN(parseInt(value)) ? value : undefined;
6412 break;
6413 case 'object':
6414 this_chid = characters.indexOf(value) !== -1 ? String(characters.indexOf(value)) : undefined;
6415 break;
6416 case 'undefined':
6417 this_chid = undefined;
6418 break;
6419 default:
6420 console.error('Invalid character ID type:', value);
6421 break;
6422 }
6183}6423}
61846424
6185export function setCharacterName(value) {6425export function setCharacterName(value) {
@@ -6207,6 +6447,23 @@ export function setSendButtonState(value) {
6207 is_send_press = value;6447 is_send_press = value;
6208}6448}
62096449
6450/**
6451 * Renames the currently selected character, updating relevant references and optionally renaming past chats.
6452 *
6453 * If no name is provided, a popup prompts for a new name. If the new name matches the current name,
6454 * the renaming process is aborted. The function sends a request to the server to rename the character
6455 * and handles updates to other related fields such as tags, lore, and author notes.
6456 *
6457 * If the renaming is successful, the character list is reloaded and the renamed character is selected.
6458 * Optionally, past chats can be renamed to reflect the new character name.
6459 *
6460 * @param {string?} [name=null] - The new name for the character. If not provided, a popup will prompt for it.
6461 * @param {object} [options] - Additional options.
6462 * @param {boolean} [options.silent=false] - If true, suppresses popups and warnings.
6463 * @param {boolean?} [options.renameChats=null] - If true, renames past chats to reflect the new character name.
6464 * @returns {Promise<boolean>} - Returns true if the character was successfully renamed, false otherwise.
6465 */
6466
6210export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) {6467export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) {
6211 if (!name && silent) {6468 if (!name && silent) {
6212 toastr.warning(t`No character name provided.`, t`Rename Character`);6469 toastr.warning(t`No character name provided.`, t`Rename Character`);
@@ -6241,9 +6498,35 @@ export async function renameCharacter(name = null, { silent = false, renameChats
6241 const data = await response.json();6498 const data = await response.json();
6242 const newAvatar = data.avatar;6499 const newAvatar = data.avatar;
62436500
6244 // Replace tags list6501 const oldName = getCharaFilename(null, { manualAvatarKey: oldAvatar });
6502 const newName = getCharaFilename(null, { manualAvatarKey: newAvatar });
6503
6504 // Replace other auxillery fields where was referenced by avatar key
6505 // Tag List
6245 renameTagKey(oldAvatar, newAvatar);6506 renameTagKey(oldAvatar, newAvatar);
62466507
6508 // Addtional lore books
6509 const charLore = world_info.charLore?.find(x => x.name == oldName);
6510 if (charLore) {
6511 charLore.name = newName;
6512 saveSettingsDebounced();
6513 }
6514
6515 // Char-bound Author's Notes
6516 const charNote = extension_settings.note.chara?.find(x => x.name == oldName);
6517 if (charNote) {
6518 charNote.name = newName;
6519 saveSettingsDebounced();
6520 }
6521
6522 // Update active character, if the current one was the currently active one
6523 if (active_character === oldAvatar) {
6524 active_character = newAvatar;
6525 saveSettingsDebounced();
6526 }
6527
6528 await eventSource.emit(event_types.CHARACTER_RENAMED, oldAvatar, newAvatar);
6529
6247 // Reload characters list6530 // Reload characters list
6248 await getCharacters();6531 await getCharacters();
62496532
@@ -6252,25 +6535,30 @@ export async function renameCharacter(name = null, { silent = false, renameChats
62526535
6253 if (newChId !== -1) {6536 if (newChId !== -1) {
6254 // Select the character after the renaming6537 // Select the character after the renaming
6255 this_chid = -1;6538 setCharacterId(undefined);
6256 await selectCharacterById(String(newChId));6539 await selectCharacterById(newChId);
62576540
6258 // Async delay to update UI6541 // Async delay to update UI
6259 await delay(1);6542 await delay(1);
62606543
6261 if (this_chid === -1) {6544 if (this_chid === undefined) {
6262 throw new Error('New character not selected');6545 throw new Error('New character not selected');
6263 }6546 }
62646547
6265 // Also rename as a group member6548 // Also rename as a group member
6266 await renameGroupMember(oldAvatar, newAvatar, newValue);6549 await renameGroupMember(oldAvatar, newAvatar, newValue);
6267 const renamePastChatsConfirm = renameChats !== null ? renameChats6550 const renamePastChatsConfirm = renameChats !== null
6268 : silent ? false : await callPopup(`<h3>Character renamed!</h3>6551 ? renameChats
6269 <p>Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?</p>6552 : silent
6270 <i><b>Sprites folder (if any) should be renamed manually.</b></i>`, 'confirm');6553 ? false
6554 : await Popup.show.confirm(
6555 t`Character renamed!`,
6556 `<p>${t`Past chats will still contain the old character name. Would you like to update the character name in previous chats as well?`}</p>
6557 <i><b>${t`Sprites folder (if any) should be renamed manually.`}</b></i>`,
6558 ) == POPUP_RESULT.AFFIRMATIVE;
62716559
6272 if (renamePastChatsConfirm) {6560 if (renamePastChatsConfirm) {
6273 await renamePastChats(newAvatar, newValue);6561 await renamePastChats(oldAvatar, newAvatar, newValue);
6274 await reloadCurrentChat();6562 await reloadCurrentChat();
6275 toastr.success(t`Character renamed and past chats updated!`, t`Rename Character`);6563 toastr.success(t`Character renamed and past chats updated!`, t`Rename Character`);
6276 } else {6564 } else {
@@ -6287,7 +6575,7 @@ export async function renameCharacter(name = null, { silent = false, renameChats
6287 }6575 }
6288 catch (error) {6576 catch (error) {
6289 // Reloading to prevent data corruption6577 // Reloading to prevent data corruption
6290 if (!silent) await callPopup(t`Something went wrong. The page will be reloaded.`, 'text');6578 if (!silent) await Popup.show.text(t`Rename Character`, t`Something went wrong. The page will be reloaded.`);
6291 else toastr.error(t`Something went wrong. The page will be reloaded.`, t`Rename Character`);6579 else toastr.error(t`Something went wrong. The page will be reloaded.`, t`Rename Character`);
62926580
6293 console.log('Renaming character error:', error);6581 console.log('Renaming character error:', error);
@@ -6298,7 +6586,7 @@ export async function renameCharacter(name = null, { silent = false, renameChats
6298 return true;6586 return true;
6299}6587}
63006588
6301async function renamePastChats(newAvatar, newValue) {6589async function renamePastChats(oldAvatar, newAvatar, newName) {
6302 const pastChats = await getPastCharacterChats();6590 const pastChats = await getPastCharacterChats();
63036591
6304 for (const { file_name } of pastChats) {6592 for (const { file_name } of pastChats) {
@@ -6308,7 +6596,7 @@ async function renamePastChats(newAvatar, newValue) {
6308 method: 'POST',6596 method: 'POST',
6309 headers: getRequestHeaders(),6597 headers: getRequestHeaders(),
6310 body: JSON.stringify({6598 body: JSON.stringify({
6311 ch_name: newValue,6599 ch_name: newName,
6312 file_name: fileNameWithoutExtension,6600 file_name: fileNameWithoutExtension,
6313 avatar_url: newAvatar,6601 avatar_url: newAvatar,
6314 }),6602 }),
@@ -6324,15 +6612,17 @@ async function renamePastChats(newAvatar, newValue) {
6324 }6612 }
63256613
6326 if (message.name !== undefined) {6614 if (message.name !== undefined) {
6327 message.name = newValue;6615 message.name = newName;
6328 }6616 }
6329 }6617 }
63306618
6619 await eventSource.emit(event_types.CHARACTER_RENAMED_IN_PAST_CHAT, currentChat, oldAvatar, newAvatar);
6620
6331 const saveChatResponse = await fetch('/api/chats/save', {6621 const saveChatResponse = await fetch('/api/chats/save', {
6332 method: 'POST',6622 method: 'POST',
6333 headers: getRequestHeaders(),6623 headers: getRequestHeaders(),
6334 body: JSON.stringify({6624 body: JSON.stringify({
6335 ch_name: newValue,6625 ch_name: newName,
6336 file_name: fileNameWithoutExtension,6626 file_name: fileNameWithoutExtension,
6337 chat: currentChat,6627 chat: currentChat,
6338 avatar_url: newAvatar,6628 avatar_url: newAvatar,
@@ -6358,6 +6648,7 @@ export function saveChatDebounced() {
6358 if (chatSaveTimeout) {6648 if (chatSaveTimeout) {
6359 console.debug('Clearing chat save timeout');6649 console.debug('Clearing chat save timeout');
6360 clearTimeout(chatSaveTimeout);6650 clearTimeout(chatSaveTimeout);
6651 chatSaveTimeout = null;
6361 }6652 }
63626653
6363 chatSaveTimeout = setTimeout(async () => {6654 chatSaveTimeout = setTimeout(async () => {
@@ -6374,7 +6665,7 @@ export function saveChatDebounced() {
6374 console.debug('Chat save timeout triggered');6665 console.debug('Chat save timeout triggered');
6375 await saveChatConditional();6666 await saveChatConditional();
6376 console.debug('Chat saved');6667 console.debug('Chat saved');
6377 }, 1000);6668 }, DEFAULT_SAVE_EDIT_TIMEOUT);
6378}6669}
63796670
6380export async function saveChat(chatName, withMetadata, mesId) {6671export async function saveChat(chatName, withMetadata, mesId) {
@@ -6529,7 +6820,7 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t
6529 }6820 }
65306821
6531 avatarTemplate.attr('data-type', entity.type);6822 avatarTemplate.attr('data-type', entity.type);
6532 avatarTemplate.attr({ 'chid': id, 'id': `CharID${id}` });6823 avatarTemplate.attr('data-chid', id);
6533 avatarTemplate.find('img').attr('src', this_avatar).attr('alt', entity.item.name);6824 avatarTemplate.find('img').attr('src', this_avatar).attr('alt', entity.item.name);
6534 avatarTemplate.attr('title', `[Character] ${entity.item.name}\nFile: ${entity.item.avatar}`);6825 avatarTemplate.attr('title', `[Character] ${entity.item.name}\nFile: ${entity.item.avatar}`);
6535 if (highlightFavs) {6826 if (highlightFavs) {
@@ -6544,8 +6835,14 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t
6544 avatarTemplate.addClass(grpTemplate.attr('class'));6835 avatarTemplate.addClass(grpTemplate.attr('class'));
6545 avatarTemplate.empty();6836 avatarTemplate.empty();
6546 avatarTemplate.append(grpTemplate.children());6837 avatarTemplate.append(grpTemplate.children());
6838 avatarTemplate.attr({ 'data-grid': id, 'data-chid': null });
6547 avatarTemplate.attr('title', `[Group] ${entity.item.name}`);6839 avatarTemplate.attr('title', `[Group] ${entity.item.name}`);
6548 }6840 }
6841 else if (entity.type === 'persona') {
6842 avatarTemplate.attr({ 'data-pid': id, 'data-chid': null });
6843 avatarTemplate.find('img').attr('src', getUserAvatar(entity.item.avatar));
6844 avatarTemplate.attr('title', `[Persona] ${entity.item.name}\nFile: ${entity.item.avatar}`);
6845 }
65496846
6550 if (interactable) {6847 if (interactable) {
6551 avatarTemplate.addClass(INTERACTABLE_CONTROL_CLASS);6848 avatarTemplate.addClass(INTERACTABLE_CONTROL_CLASS);
@@ -6557,9 +6854,43 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t
6557 }6854 }
6558}6855}
65596856
6857/**
6858 * Loads all the data of a shallow character.
6859 * @param {string|undefined} characterId Array index
6860 * @returns {Promise<void>} Promise that resolves when the character is unshallowed
6861 */
6862export async function unshallowCharacter(characterId) {
6863 if (characterId === undefined) {
6864 console.warn('Undefined character cannot be unshallowed');
6865 return;
6866 }
6867
6868 /** @type {import('./scripts/char-data.js').v1CharData} */
6869 const character = characters[characterId];
6870 if (!character) {
6871 console.warn('Character not found:', characterId);
6872 return;
6873 }
6874
6875 // Character is not shallow
6876 if (!character.shallow) {
6877 return;
6878 }
6879
6880 const avatar = character.avatar;
6881 if (!avatar) {
6882 console.warn('Character has no avatar field:', characterId);
6883 return;
6884 }
6885
6886 await getOneCharacter(avatar);
6887}
6888
6560export async function getChat() {6889export async function getChat() {
6561 //console.log('/api/chats/get -- entered for -- ' + characters[this_chid].name);6890 //console.log('/api/chats/get -- entered for -- ' + characters[this_chid].name);
6562 try {6891 try {
6892 await unshallowCharacter(this_chid);
6893
6563 const response = await $.ajax({6894 const response = await $.ajax({
6564 type: 'POST',6895 type: 'POST',
6565 url: '/api/chats/get',6896 url: '/api/chats/get',
@@ -6617,8 +6948,8 @@ async function getChatResult() {
66176948
6618 if (chat.length === 1) {6949 if (chat.length === 1) {
6619 const chat_id = (chat.length - 1);6950 const chat_id = (chat.length - 1);
6620 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id);6951 await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, 'first_message');
6621 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id);6952 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, chat_id, 'first_message');
6622 }6953 }
6623}6954}
66246955
@@ -6782,14 +7113,14 @@ export function changeMainAPI() {
6782 forceCharacterEditorTokenize();7113 forceCharacterEditorTokenize();
6783}7114}
67847115
6785export function setUserName(value) {7116export function setUserName(value, { toastPersonaNameChange = true } = {}) {
6786 name1 = value;7117 name1 = value;
6787 if (name1 === undefined || name1 == '')7118 if (name1 === undefined || name1 == '')
6788 name1 = default_user_name;7119 name1 = default_user_name;
6789 console.log(`User name changed to ${name1}`);7120 console.log(`User name changed to ${name1}`);
6790 $('#your_name').val(name1);7121 $('#your_name').text(name1);
6791 if (power_user.persona_show_notifications) {7122 if (toastPersonaNameChange && power_user.persona_show_notifications && !isPersonaPanelOpen()) {
6792 toastr.success(t`Your messages will now be sent as ${name1}`, t`Current persona updated`);7123 toastr.success(t`Your messages will now be sent as ${name1}`, t`Persona Changed`);
6793 }7124 }
6794 saveSettingsDebounced();7125 saveSettingsDebounced();
6795}7126}
@@ -6841,7 +7172,7 @@ export async function getSettings() {
6841 settings = JSON.parse(data.settings);7172 settings = JSON.parse(data.settings);
6842 if (settings.username !== undefined && settings.username !== '') {7173 if (settings.username !== undefined && settings.username !== '') {
6843 name1 = settings.username;7174 name1 = settings.username;
6844 $('#your_name').val(name1);7175 $('#your_name').text(name1);
6845 }7176 }
68467177
6847 accountStorage.init(settings?.accountStorage);7178 accountStorage.init(settings?.accountStorage);
@@ -7546,7 +7877,7 @@ export function select_rm_info(type, charId, previousCharId = null) {
7546 if (previousCharId) {7877 if (previousCharId) {
7547 const newId = characters.findIndex((x) => x.avatar == previousCharId);7878 const newId = characters.findIndex((x) => x.avatar == previousCharId);
7548 if (newId >= 0) {7879 if (newId >= 0) {
7549 this_chid = newId;7880 setCharacterId(newId);
7550 }7881 }
7551 }7882 }
7552}7883}
@@ -7566,6 +7897,7 @@ export function select_selected_character(chid) {
7566 $('#create_button').attr('value', 'Save'); // what is the use case for this?7897 $('#create_button').attr('value', 'Save'); // what is the use case for this?
7567 $('#dupe_button').show();7898 $('#dupe_button').show();
7568 $('#create_button_label').css('display', 'none');7899 $('#create_button_label').css('display', 'none');
7900 $('#char_connections_button').show();
75697901
7570 // Hide the chat scenario button if we're peeking the group member defs7902 // Hide the chat scenario button if we're peeking the group member defs
7571 $('#set_chat_scenario').toggle(!selected_group);7903 $('#set_chat_scenario').toggle(!selected_group);
@@ -7650,6 +7982,7 @@ function select_rm_create() {
7650 $('#create_button_label').css('display', '');7982 $('#create_button_label').css('display', '');
7651 $('#create_button').attr('value', 'Create');7983 $('#create_button').attr('value', 'Create');
7652 $('#dupe_button').hide();7984 $('#dupe_button').hide();
7985 $('#char_connections_button').hide();
76537986
7654 //create text poles7987 //create text poles
7655 $('#rm_button_back').css('display', '');7988 $('#rm_button_back').css('display', '');
@@ -7679,8 +8012,8 @@ function select_rm_create() {
7679 $('#renameCharButton').css('display', 'none');8012 $('#renameCharButton').css('display', 'none');
7680 $('#name_div').removeClass('displayNone');8013 $('#name_div').removeClass('displayNone');
7681 $('#name_div').addClass('displayBlock');8014 $('#name_div').addClass('displayBlock');
7682 $('.open_alternate_greetings').data('chid', undefined);8015 $('.open_alternate_greetings').data('chid', -1);
7683 $('#set_character_world').data('chid', undefined);8016 $('#set_character_world').data('chid', -1);
7684 setWorldInfoButtonClass(undefined, !!create_save.world);8017 setWorldInfoButtonClass(undefined, !!create_save.world);
7685 updateFavButtonState(false);8018 updateFavButtonState(false);
7686 checkEmbeddedWorld();8019 checkEmbeddedWorld();
@@ -7771,7 +8104,7 @@ function updateFavButtonState(state) {
7771}8104}
77728105
7773export async function setScenarioOverride() {8106export async function setScenarioOverride() {
7774 if (!selected_group && !this_chid) {8107 if (!selected_group && (this_chid === undefined || !characters[this_chid])) {
7775 console.warn('setScenarioOverride() -- no selected group or character');8108 console.warn('setScenarioOverride() -- no selected group or character');
7776 return;8109 return;
7777 }8110 }
@@ -7989,6 +8322,12 @@ export async function saveChatConditional() {
7989 }8322 }
79908323
7991 try {8324 try {
8325 if (chatSaveTimeout) {
8326 console.debug('Debounced chat save canceled');
8327 clearTimeout(chatSaveTimeout);
8328 chatSaveTimeout = null;
8329 }
8330
7992 isChatSaving = true;8331 isChatSaving = true;
79938332
7994 if (selected_group) {8333 if (selected_group) {
@@ -8130,7 +8469,7 @@ function updateAlternateGreetingsHintVisibility(root) {
8130function openCharacterWorldPopup() {8469function openCharacterWorldPopup() {
8131 const chid = $('#set_character_world').data('chid');8470 const chid = $('#set_character_world').data('chid');
81328471
8133 if (menu_type != 'create' && chid == undefined) {8472 if (menu_type != 'create' && chid === undefined) {
8134 toastr.error('Does not have an Id for this character in world select menu.');8473 toastr.error('Does not have an Id for this character in world select menu.');
8135 return;8474 return;
8136 }8475 }
@@ -8262,7 +8601,7 @@ function openAlternateGreetings() {
8262 return;8601 return;
8263 } else {8602 } else {
8264 // If the character does not have alternate greetings, create an empty array8603 // If the character does not have alternate greetings, create an empty array
8265 if (chid && Array.isArray(characters[chid].data.alternate_greetings) == false) {8604 if (characters[chid] && !Array.isArray(characters[chid].data.alternate_greetings)) {
8266 characters[chid].data.alternate_greetings = [];8605 characters[chid].data.alternate_greetings = [];
8267 }8606 }
8268 }8607 }
@@ -8449,7 +8788,7 @@ async function createOrEditCharacter(e) {
84498788
8450 formData.delete('alternate_greetings');8789 formData.delete('alternate_greetings');
8451 const chid = $('.open_alternate_greetings').data('chid');8790 const chid = $('.open_alternate_greetings').data('chid');
8452 if (chid && Array.isArray(characters[chid]?.data?.alternate_greetings)) {8791 if (characters[chid] && Array.isArray(characters[chid]?.data?.alternate_greetings)) {
8453 for (const value of characters[chid].data.alternate_greetings) {8792 for (const value of characters[chid].data.alternate_greetings) {
8454 formData.append('alternate_greetings', value);8793 formData.append('alternate_greetings', value);
8455 }8794 }
@@ -8488,10 +8827,10 @@ async function createOrEditCharacter(e) {
8488 if (shouldRegenerateMessage) {8827 if (shouldRegenerateMessage) {
8489 chat.splice(0, chat.length, message);8828 chat.splice(0, chat.length, message);
8490 const messageId = (chat.length - 1);8829 const messageId = (chat.length - 1);
8491 await eventSource.emit(event_types.MESSAGE_RECEIVED, messageId);8830 await eventSource.emit(event_types.MESSAGE_RECEIVED, messageId, 'first_message');
8492 await clearChat();8831 await clearChat();
8493 await printMessages();8832 await printMessages();
8494 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId);8833 await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, messageId, 'first_message');
8495 await saveChatConditional();8834 await saveChatConditional();
8496 }8835 }
8497 } catch (error) {8836 } catch (error) {
@@ -8515,17 +8854,28 @@ function formatSwipeCounter(current, total) {
8515 return `${current}\u200b/\u200b${total}`;8854 return `${current}\u200b/\u200b${total}`;
8516}8855}
85178856
8518function swipe_left() { // when we swipe left..but no generation.8857/**
8858 * Handles the swipe to the left event.
8859 * @param {JQuery.Event} _event Event.
8860 * @param {object} params Additional parameters.
8861 * @param {string} [params.source] The source of the swipe event.
8862 * @param {boolean} [params.repeated] Is the swipe event repeated.
8863 */
8864function swipe_left(_event, { source, repeated } = {}) {
8519 if (chat.length - 1 === Number(this_edit_mes_id)) {8865 if (chat.length - 1 === Number(this_edit_mes_id)) {
8520 closeMessageEditor();8866 closeMessageEditor();
8521 }8867 }
8522
8523 if (isStreamingEnabled() && streamingProcessor) {8868 if (isStreamingEnabled() && streamingProcessor) {
8524 streamingProcessor.onStopStreaming();8869 streamingProcessor.onStopStreaming();
8525 }8870 }
85268871
8527 // Make sure ad-hoc changes to extras are saved before swiping away8872 // Make sure ad-hoc changes to extras are saved before swiping away
8528 syncCurrentSwipeInfoExtras();8873 syncMesToSwipe();
8874
8875 // If the user is holding down the key and we're at the first swipe, don't do anything
8876 if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === 0) {
8877 return;
8878 }
85298879
8530 const swipe_duration = 120;8880 const swipe_duration = 120;
8531 const swipe_range = '700px';8881 const swipe_range = '700px';
@@ -8652,8 +9002,14 @@ function swipe_left() { // when we swipe left..but no generation.
8652 }9002 }
8653}9003}
86549004
8655// when we click swipe right button9005/**
8656const swipe_right = () => {9006 * Handles the swipe to the right event.
9007 * @param {JQuery.Event} _event Event.
9008 * @param {object} params Additional parameters.
9009 * @param {string} [params.source] The source of the swipe event.
9010 * @param {boolean} [params.repeated] Is the swipe event repeated.
9011 */
9012function swipe_right(_event, { source, repeated } = {}) {
8657 if (chat.length - 1 === Number(this_edit_mes_id)) {9013 if (chat.length - 1 === Number(this_edit_mes_id)) {
8658 closeMessageEditor();9014 closeMessageEditor();
8659 }9015 }
@@ -8663,7 +9019,7 @@ const swipe_right = () => {
8663 }9019 }
86649020
8665 // Make sure ad-hoc changes to extras are saved before swiping away9021 // Make sure ad-hoc changes to extras are saved before swiping away
8666 syncCurrentSwipeInfoExtras();9022 syncMesToSwipe();
86679023
8668 const swipe_duration = 200;9024 const swipe_duration = 200;
8669 const swipe_range = 700;9025 const swipe_range = 700;
@@ -8675,12 +9031,21 @@ const swipe_right = () => {
8675 chat[chat.length - 1]['swipes'] = []; // empty the array9031 chat[chat.length - 1]['swipes'] = []; // empty the array
8676 chat[chat.length - 1]['swipe_info'] = [];9032 chat[chat.length - 1]['swipe_info'] = [];
8677 chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat9033 chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat
8678 chat[chat.length - 1]['swipe_info'][0] = { 'send_date': chat[chat.length - 1]['send_date'], 'gen_started': chat[chat.length - 1]['gen_started'], 'gen_finished': chat[chat.length - 1]['gen_finished'], 'extra': JSON.parse(JSON.stringify(chat[chat.length - 1]['extra'])) };9034 chat[chat.length - 1]['swipe_info'][0] = {
9035 'send_date': chat[chat.length - 1]['send_date'],
9036 'gen_started': chat[chat.length - 1]['gen_started'],
9037 'gen_finished': chat[chat.length - 1]['gen_finished'],
9038 'extra': JSON.parse(JSON.stringify(chat[chat.length - 1]['extra'])),
9039 };
8679 //assign swipe info array with last message from chat9040 //assign swipe info array with last message from chat
8680 }9041 }
8681 if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1) { // if swipe_right is called on the last alternate greeting, loop back around9042 if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1) { // if swipe_right is called on the last alternate greeting, loop back around
8682 chat[0]['swipe_id'] = 0;9043 chat[0]['swipe_id'] = 0;
8683 } else {9044 } else {
9045 // If the user is holding down the key and we're at the last swipe, don't do anything
9046 if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === chat[chat.length - 1].swipes.length - 1) {
9047 return;
9048 }
8684 chat[chat.length - 1]['swipe_id']++; // make new slot in array9049 chat[chat.length - 1]['swipe_id']++; // make new slot in array
8685 }9050 }
8686 if (chat[chat.length - 1].extra) {9051 if (chat[chat.length - 1].extra) {
@@ -8829,9 +9194,9 @@ const swipe_right = () => {
8829 },9194 },
8830 });9195 });
8831 }9196 }
8832};9197}
88339198
8834const CONNECT_API_MAP = {9199export const CONNECT_API_MAP = {
8835 // Default APIs not contined inside text gen / chat gen9200 // Default APIs not contined inside text gen / chat gen
8836 'kobold': {9201 'kobold': {
8837 selected: 'kobold',9202 selected: 'kobold',
@@ -9021,10 +9386,12 @@ async function connectAPISlash(args, text) {
9021 const toast = quiet ? jQuery() : toastr.info(t`API set to ${text}, trying to connect..`);9386 const toast = quiet ? jQuery() : toastr.info(t`API set to ${text}, trying to connect..`);
90229387
9023 try {9388 try {
9024 await waitUntilCondition(() => online_status !== 'no_connection', 10000, 100);9389 if (connectionRequired) {
9390 await waitUntilCondition(() => online_status !== 'no_connection', 5000, 100);
9391 }
9025 console.log('Connection successful');9392 console.log('Connection successful');
9026 } catch {9393 } catch {
9027 console.log('Could not connect after 10 seconds, skipping.');9394 console.log('Could not connect after 5 seconds, skipping.');
9028 }9395 }
90299396
9030 toastr.clear(toast);9397 toastr.clear(toast);
@@ -9969,7 +10336,7 @@ jQuery(async function () {
9969 });10336 });
997010337
9971 $(document).on('click', '.character_select', async function () {10338 $(document).on('click', '.character_select', async function () {
9972 const id = $(this).attr('chid');10339 const id = Number($(this).attr('data-chid'));
9973 await selectCharacterById(id);10340 await selectCharacterById(id);
9974 });10341 });
997510342
@@ -10165,7 +10532,7 @@ jQuery(async function () {
10165 $('#form_create').submit(createOrEditCharacter);10532 $('#form_create').submit(createOrEditCharacter);
1016610533
10167 $('#delete_button').on('click', async function () {10534 $('#delete_button').on('click', async function () {
10168 if (!this_chid) {10535 if (this_chid === undefined || !characters[this_chid]) {
10169 toastr.warning('No character selected.');10536 toastr.warning('No character selected.');
10170 return;10537 return;
10171 }10538 }
@@ -10947,7 +11314,7 @@ jQuery(async function () {
10947 });11314 });
1094811315
10949 $(document).on('click', '.mes_edit_copy', async function () {11316 $(document).on('click', '.mes_edit_copy', async function () {
10950 const confirmation = await callGenericPopup('Create a copy of this message?', POPUP_TYPE.CONFIRM);11317 const confirmation = await callGenericPopup(t`Create a copy of this message?`, POPUP_TYPE.CONFIRM);
10951 if (!confirmation) {11318 if (!confirmation) {
10952 return;11319 return;
10953 }11320 }
public/scripts/BulkEditOverlay.js+10 -10
@@ -395,7 +395,7 @@ class BulkEditOverlay {
395395
396 /**396 /**
397 * @typedef {object} LastSelected - An object noting the last selected character and its state.397 * @typedef {object} LastSelected - An object noting the last selected character and its state.
398 * @property {string} [characterId] - The character id of the last selected character.398 * @property {number} [characterId] - The character id of the last selected character.
399 * @property {boolean} [select] - The selected state of the last selected character. <c>true</c> if it was selected, <c>false</c> if it was deselected.399 * @property {boolean} [select] - The selected state of the last selected character. <c>true</c> if it was selected, <c>false</c> if it was deselected.
400 */400 */
401401
@@ -672,10 +672,10 @@ class BulkEditOverlay {
672 * @param {HTMLElement} currentCharacter - The html element of the currently toggled character672 * @param {HTMLElement} currentCharacter - The html element of the currently toggled character
673 */673 */
674 handleShiftClick = (currentCharacter) => {674 handleShiftClick = (currentCharacter) => {
675 const characterId = currentCharacter.getAttribute('chid');675 const characterId = Number(currentCharacter.getAttribute('data-chid'));
676 const select = !this.selectedCharacters.includes(characterId);676 const select = !this.selectedCharacters.includes(characterId);
677677
678 if (this.lastSelected.characterId && this.lastSelected.select !== undefined) {678 if (this.lastSelected.characterId >= 0 && this.lastSelected.select !== undefined) {
679 // Only if select state and the last select state match we execute the range select679 // Only if select state and the last select state match we execute the range select
680 if (select === this.lastSelected.select) {680 if (select === this.lastSelected.select) {
681 this.toggleCharactersInRange(currentCharacter, select);681 this.toggleCharactersInRange(currentCharacter, select);
@@ -691,7 +691,7 @@ class BulkEditOverlay {
691 * @param {boolean} [param1.markState] - Whether the toggle of this character should be remembered as the last done toggle691 * @param {boolean} [param1.markState] - Whether the toggle of this character should be remembered as the last done toggle
692 */692 */
693 toggleSingleCharacter = (character, { markState = true } = {}) => {693 toggleSingleCharacter = (character, { markState = true } = {}) => {
694 const characterId = character.getAttribute('chid');694 const characterId = Number(character.getAttribute('data-chid'));
695695
696 const select = !this.selectedCharacters.includes(characterId);696 const select = !this.selectedCharacters.includes(characterId);
697 const legacyBulkEditCheckbox = character.querySelector('.' + BulkEditOverlay.legacySelectedClass);697 const legacyBulkEditCheckbox = character.querySelector('.' + BulkEditOverlay.legacySelectedClass);
@@ -699,11 +699,11 @@ class BulkEditOverlay {
699 if (select) {699 if (select) {
700 character.classList.add(BulkEditOverlay.selectedClass);700 character.classList.add(BulkEditOverlay.selectedClass);
701 if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = true;701 if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = true;
702 this.#selectedCharacters.push(String(characterId));702 this.#selectedCharacters.push(characterId);
703 } else {703 } else {
704 character.classList.remove(BulkEditOverlay.selectedClass);704 character.classList.remove(BulkEditOverlay.selectedClass);
705 if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = false;705 if (legacyBulkEditCheckbox) legacyBulkEditCheckbox.checked = false;
706 this.#selectedCharacters = this.#selectedCharacters.filter(item => String(characterId) !== item);706 this.#selectedCharacters = this.#selectedCharacters.filter(item => characterId !== item);
707 }707 }
708708
709 this.updateSelectedCount();709 this.updateSelectedCount();
@@ -732,15 +732,15 @@ class BulkEditOverlay {
732 * @param {boolean} select - <c>true</c> if the characters in the range are to be selected, <c>false</c> if deselected732 * @param {boolean} select - <c>true</c> if the characters in the range are to be selected, <c>false</c> if deselected
733 */733 */
734 toggleCharactersInRange = (currentCharacter, select) => {734 toggleCharactersInRange = (currentCharacter, select) => {
735 const currentCharacterId = currentCharacter.getAttribute('chid');735 const currentCharacterId = Number(currentCharacter.getAttribute('data-chid'));
736 const characters = Array.from(document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.characterClass));736 const characters = Array.from(document.querySelectorAll('#' + BulkEditOverlay.containerId + ' .' + BulkEditOverlay.characterClass));
737737
738 const startIndex = characters.findIndex(c => c.getAttribute('chid') === this.lastSelected.characterId);738 const startIndex = characters.findIndex(c => Number(c.getAttribute('data-chid')) === Number(this.lastSelected.characterId));
739 const endIndex = characters.findIndex(c => c.getAttribute('chid') === currentCharacterId);739 const endIndex = characters.findIndex(c => Number(c.getAttribute('data-chid')) === currentCharacterId);
740740
741 for (let i = Math.min(startIndex, endIndex); i <= Math.max(startIndex, endIndex); i++) {741 for (let i = Math.min(startIndex, endIndex); i <= Math.max(startIndex, endIndex); i++) {
742 const character = characters[i];742 const character = characters[i];
743 const characterId = character.getAttribute('chid');743 const characterId = Number(character.getAttribute('data-chid'));
744 const isCharacterSelected = this.selectedCharacters.includes(characterId);744 const isCharacterSelected = this.selectedCharacters.includes(characterId);
745745
746 // Only toggle the character if it wasn't on the state we have are toggling towards.746 // Only toggle the character if it wasn't on the state we have are toggling towards.
public/scripts/RossAscends-mods.js+38 -10
@@ -280,17 +280,32 @@ async function RA_autoloadchat() {
280 // active character is the name, we should look it up in the character list and get the id280 // active character is the name, we should look it up in the character list and get the id
281 if (active_character !== null && active_character !== undefined) {281 if (active_character !== null && active_character !== undefined) {
282 const active_character_id = characters.findIndex(x => getTagKeyForEntity(x) === active_character);282 const active_character_id = characters.findIndex(x => getTagKeyForEntity(x) === active_character);
283 if (active_character_id !== null) {283 if (active_character_id !== -1) {
284 await selectCharacterById(String(active_character_id));284 await selectCharacterById(active_character_id);
285285
286 // Do a little tomfoolery to spoof the tag selector286 // Do a little tomfoolery to spoof the tag selector
287 const selectedCharElement = $(`#rm_print_characters_block .character_select[chid="${active_character_id}"]`);287 const selectedCharElement = $(`#rm_print_characters_block .character_select[chid="${active_character_id}"]`);
288 applyTagsOnCharacterSelect.call(selectedCharElement);288 applyTagsOnCharacterSelect.call(selectedCharElement);
289 } else {
290 setActiveCharacter(null);
291 saveSettingsDebounced();
292 console.warn(`Currently active character with ID ${active_character} not found. Resetting to no active character.`);
289 }293 }
290 }294 }
291295
292 if (active_group !== null && active_group !== undefined) {296 if (active_group !== null && active_group !== undefined) {
293 await openGroupById(String(active_group));297 if (active_character) {
298 console.warn('Active character and active group are both set. Only active character will be loaded. Resetting active group.');
299 setActiveGroup(null);
300 saveSettingsDebounced();
301 } else {
302 const result = await openGroupById(String(active_group));
303 if (!result) {
304 setActiveGroup(null);
305 saveSettingsDebounced();
306 console.warn(`Currently active group with ID ${active_group} not found. Resetting to no active group.`);
307 }
308 }
294 }309 }
295310
296 // if the character list hadn't been loaded yet, try again.311 // if the character list hadn't been loaded yet, try again.
@@ -301,7 +316,10 @@ export async function favsToHotswap() {
301 const entities = getEntitiesList({ doFilter: false });316 const entities = getEntitiesList({ doFilter: false });
302 const container = $('#right-nav-panel .hotswap');317 const container = $('#right-nav-panel .hotswap');
303318
304 const favs = entities.filter(x => x.item.fav || x.item.fav == 'true');319 // Hard limit is required because even if all hotswaps don't fit the screen, their images would still be loaded
320 // 25 is roughly calculated as the maximum number of favs that can fit an ultrawide monitor with the default theme
321 const FAVS_LIMIT = 25;
322 const favs = entities.filter(x => x.item.fav || x.item.fav == 'true').slice(0, FAVS_LIMIT);
305323
306 //helpful instruction message if no characters are favorited324 //helpful instruction message if no characters are favorited
307 if (favs.length == 0) {325 if (favs.length == 0) {
@@ -879,14 +897,14 @@ export function initRossMods() {
879897
880 // when a char is selected from the list, save their name as the auto-load character for next page load898 // when a char is selected from the list, save their name as the auto-load character for next page load
881 $(document).on('click', '.character_select', function () {899 $(document).on('click', '.character_select', function () {
882 const characterId = $(this).attr('chid') || $(this).data('id');900 const characterId = $(this).attr('data-chid');
883 setActiveCharacter(characterId);901 setActiveCharacter(characterId);
884 setActiveGroup(null);902 setActiveGroup(null);
885 saveSettingsDebounced();903 saveSettingsDebounced();
886 });904 });
887905
888 $(document).on('click', '.group_select', function () {906 $(document).on('click', '.group_select', function () {
889 const groupId = $(this).attr('chid') || $(this).attr('grid') || $(this).data('id');907 const groupId = $(this).attr('data-chid') || $(this).attr('data-grid');
890 setActiveCharacter(null);908 setActiveCharacter(null);
891 setActiveGroup(groupId);909 setActiveGroup(groupId);
892 saveSettingsDebounced();910 saveSettingsDebounced();
@@ -1000,6 +1018,14 @@ export function initRossMods() {
1000 return false;1018 return false;
1001 }1019 }
10021020
1021 function isModifiedKeyboardEvent(event) {
1022 return (event instanceof KeyboardEvent &&
1023 event.shiftKey ||
1024 event.ctrlKey ||
1025 event.altKey ||
1026 event.metaKey);
1027 }
1028
1003 $(document).on('keydown', async function (event) {1029 $(document).on('keydown', async function (event) {
1004 await processHotkeys(event.originalEvent);1030 await processHotkeys(event.originalEvent);
1005 });1031 });
@@ -1123,9 +1149,10 @@ export function initRossMods() {
1123 $('#send_textarea').val() === '' &&1149 $('#send_textarea').val() === '' &&
1124 $('#character_popup').css('display') === 'none' &&1150 $('#character_popup').css('display') === 'none' &&
1125 $('#shadow_select_chat_popup').css('display') === 'none' &&1151 $('#shadow_select_chat_popup').css('display') === 'none' &&
1126 !isInputElementInFocus()1152 !isInputElementInFocus() &&
1153 !isModifiedKeyboardEvent(event)
1127 ) {1154 ) {
1128 $('.swipe_left:last').click();1155 $('.swipe_left:last').trigger('click', { source: 'keyboard', repeated: event.repeat });
1129 return;1156 return;
1130 }1157 }
1131 }1158 }
@@ -1136,9 +1163,10 @@ export function initRossMods() {
1136 $('#send_textarea').val() === '' &&1163 $('#send_textarea').val() === '' &&
1137 $('#character_popup').css('display') === 'none' &&1164 $('#character_popup').css('display') === 'none' &&
1138 $('#shadow_select_chat_popup').css('display') === 'none' &&1165 $('#shadow_select_chat_popup').css('display') === 'none' &&
1139 !isInputElementInFocus()1166 !isInputElementInFocus() &&
1167 !isModifiedKeyboardEvent(event)
1140 ) {1168 ) {
1141 $('.swipe_right:last').click();1169 $('.swipe_right:last').trigger('click', { source: 'keyboard', repeated: event.repeat });
1142 return;1170 return;
1143 }1171 }
1144 }1172 }
public/scripts/authors-note.js+9 -9
@@ -299,7 +299,7 @@ function loadSettings() {
299 $('#extension_floating_role').val(chat_metadata[metadata_keys.role]);299 $('#extension_floating_role').val(chat_metadata[metadata_keys.role]);
300 $(`input[name="extension_floating_position"][value="${chat_metadata[metadata_keys.position]}"]`).prop('checked', true);300 $(`input[name="extension_floating_position"][value="${chat_metadata[metadata_keys.position]}"]`).prop('checked', true);
301301
302 if (extension_settings.note.chara && getContext().characterId) {302 if (extension_settings.note.chara && getContext().characterId !== undefined) {
303 const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());303 const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());
304304
305 $('#extension_floating_chara').val(charaNote ? charaNote.prompt : '');305 $('#extension_floating_chara').val(charaNote ? charaNote.prompt : '');
@@ -389,7 +389,11 @@ export function setFloatingPrompt() {
389}389}
390390
391function onANMenuItemClick() {391function onANMenuItemClick() {
392 if (selected_group || this_chid) {392 if (!selected_group && this_chid === undefined) {
393 toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 });
394 return;
395 }
396
393 //show AN if it's hidden397 //show AN if it's hidden
394 if ($('#floatingPrompt').css('display') !== 'flex') {398 if ($('#floatingPrompt').css('display') !== 'flex') {
395 $('#floatingPrompt').addClass('resizing');399 $('#floatingPrompt').addClass('resizing');
@@ -416,22 +420,18 @@ function onANMenuItemClick() {
416 $('#floatingPrompt').transition({420 $('#floatingPrompt').transition({
417 opacity: 0.0,421 opacity: 0.0,
418 duration: animation_duration,422 duration: animation_duration,
419 },423 }, async function () {
420 async function () {
421 await delay(50);424 await delay(50);
422 $('#floatingPrompt').removeClass('resizing');425 $('#floatingPrompt').removeClass('resizing');
423 });426 });
424 setTimeout(function () {427 setTimeout(function () {
425 $('#floatingPrompt').hide();428 $('#floatingPrompt').hide();
426 }, animation_duration);429 }, animation_duration);
427
428 }430 }
431
429 //duplicate options menu close handler from script.js432 //duplicate options menu close handler from script.js
430 //because this listener takes priority433 //because this listener takes priority
431 $('#options').stop().fadeOut(animation_duration);434 $('#options').stop().fadeOut(animation_duration);
432 } else {
433 toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 });
434 }
435}435}
436436
437async function onChatChanged() {437async function onChatChanged() {
@@ -446,7 +446,7 @@ async function onChatChanged() {
446 $('#extension_floating_prompt_token_counter').text(tokenCounter1);446 $('#extension_floating_prompt_token_counter').text(tokenCounter1);
447447
448 let tokenCounter2;448 let tokenCounter2;
449 if (extension_settings.note.chara && context.characterId) {449 if (extension_settings.note.chara && context.characterId !== undefined) {
450 const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());450 const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());
451451
452 if (charaNote) {452 if (charaNote) {
public/scripts/bookmarks.js+0 -10
@@ -318,16 +318,6 @@ export async function convertSoloToGroupChat() {
318 const groupChat = chat.slice();318 const groupChat = chat.slice();
319 const genIdFirst = Date.now();319 const genIdFirst = Date.now();
320320
321 // Add something if the chat is empty
322 if (groupChat.length === 0) {
323 const newMessage = {
324 ...system_messages[system_message_types.GROUP],
325 send_date: getMessageTimeStamp(),
326 extra: { type: system_message_types.GROUP },
327 };
328 groupChat.push(newMessage);
329 }
330
331 for (let index = 0; index < groupChat.length; index++) {321 for (let index = 0; index < groupChat.length; index++) {
332 const message = groupChat[index];322 const message = groupChat[index];
333323
public/scripts/cfg-scale.js+7 -8
@@ -69,8 +69,7 @@ function setCharCfg(tempValue, setting) {
69 if (!existingCharaCfg.useChara &&69 if (!existingCharaCfg.useChara &&
70 (tempAssign.guidance_scale ?? 1.00) === 1.00 &&70 (tempAssign.guidance_scale ?? 1.00) === 1.00 &&
71 (tempAssign.negative_prompt?.length ?? 0) === 0 &&71 (tempAssign.negative_prompt?.length ?? 0) === 0 &&
72 (tempAssign.positive_prompt?.length ?? 0) === 0)72 (tempAssign.positive_prompt?.length ?? 0) === 0) {
73 {
74 extension_settings.cfg.chara.splice(existingCharaCfgIndex, 1);73 extension_settings.cfg.chara.splice(existingCharaCfgIndex, 1);
75 }74 }
76 } else if (avatarName && tempValue.length > 0) {75 } else if (avatarName && tempValue.length > 0) {
@@ -113,7 +112,11 @@ function setChatCfg(tempValue, setting) {
113112
114// TODO: Only change CFG when character is selected113// TODO: Only change CFG when character is selected
115function onCfgMenuItemClick() {114function onCfgMenuItemClick() {
116 if (selected_group || this_chid) {115 if (!selected_group && this_chid === undefined) {
116 toastr.warning('Select a character before trying to configure CFG', '', { timeOut: 2000 });
117 return;
118 }
119
117 //show CFG config if it's hidden120 //show CFG config if it's hidden
118 if ($('#cfgConfig').css('display') !== 'flex') {121 if ($('#cfgConfig').css('display') !== 'flex') {
119 $('#cfgConfig').addClass('resizing');122 $('#cfgConfig').addClass('resizing');
@@ -140,8 +143,7 @@ function onCfgMenuItemClick() {
140 $('#cfgConfig').transition({143 $('#cfgConfig').transition({
141 opacity: 0.0,144 opacity: 0.0,
142 duration: animation_duration,145 duration: animation_duration,
143 },146 }, async function () {
144 async function () {
145 await delay(50);147 await delay(50);
146 $('#cfgConfig').removeClass('resizing');148 $('#cfgConfig').removeClass('resizing');
147 });149 });
@@ -153,9 +155,6 @@ function onCfgMenuItemClick() {
153 //duplicate options menu close handler from script.js155 //duplicate options menu close handler from script.js
154 //because this listener takes priority156 //because this listener takes priority
155 $('#options').stop().fadeOut(animation_duration);157 $('#options').stop().fadeOut(animation_duration);
156 } else {
157 toastr.warning('Select a character before trying to configure CFG', '', { timeOut: 2000 });
158 }
159}158}
160159
161async function onChatChanged() {160async function onChatChanged() {
public/scripts/char-data.js+1 -0
@@ -113,5 +113,6 @@
113 * @property {string} chat - name of the current chat file chat113 * @property {string} chat - name of the current chat file chat
114 * @property {string} avatar - file name of the avatar image (acts as a unique identifier)114 * @property {string} avatar - file name of the avatar image (acts as a unique identifier)
115 * @property {string} json_data - the full raw JSON data of the character115 * @property {string} json_data - the full raw JSON data of the character
116 * @property {boolean?} shallow - if the data is shallow (lazy-loaded)
116 */117 */
117export default 0;// now this file is a module118export default 0;// now this file is a module
public/scripts/chat-templates.js+4 -0
@@ -47,6 +47,10 @@ const hash_derivations = {
47 // gemma-2-2b-it47 // gemma-2-2b-it
48 'Gemma 2'48 'Gemma 2'
49 ,49 ,
50 '7de1c58e208eda46e9c7f86397df37ec49883aeece39fb961e0a6b24088dd3c4':
51 // gemma-3
52 'Gemma 2'
53 ,
5054
51 // Cohere55 // Cohere
52 '3b54f5c219ae1caa5c0bb2cdc7c001863ca6807cf888e4240e8739fa7eb9e02e':56 '3b54f5c219ae1caa5c0bb2cdc7c001863ca6807cf888e4240e8739fa7eb9e02e':
public/scripts/chats.js+6 -3
@@ -130,9 +130,10 @@ function getConverter(type) {
130 * @param {number} start Starting message ID130 * @param {number} start Starting message ID
131 * @param {number} end Ending message ID (inclusive)131 * @param {number} end Ending message ID (inclusive)
132 * @param {boolean} unhide If true, unhide the messages instead.132 * @param {boolean} unhide If true, unhide the messages instead.
133 * @param {string} nameFitler Optional name filter
133 * @returns {Promise<void>}134 * @returns {Promise<void>}
134 */135 */
135export async function hideChatMessageRange(start, end, unhide) {136export async function hideChatMessageRange(start, end, unhide, nameFitler = null) {
136 if (isNaN(start)) return;137 if (isNaN(start)) return;
137 if (!end) end = start;138 if (!end) end = start;
138 const hide = !unhide;139 const hide = !unhide;
@@ -140,6 +141,7 @@ export async function hideChatMessageRange(start, end, unhide) {
140 for (let messageId = start; messageId <= end; messageId++) {141 for (let messageId = start; messageId <= end; messageId++) {
141 const message = chat[messageId];142 const message = chat[messageId];
142 if (!message) continue;143 if (!message) continue;
144 if (nameFitler && message.name !== nameFitler) continue;
143145
144 message.is_system = hide;146 message.is_system = hide;
145147
@@ -1506,7 +1508,7 @@ jQuery(function () {
1506 embedMessageFile(messageId, messageBlock);1508 embedMessageFile(messageId, messageBlock);
1507 });1509 });
15081510
1509 $(document).on('click', '.editor_maximize', function () {1511 $(document).on('click', '.editor_maximize', async function () {
1510 const broId = $(this).attr('data-for');1512 const broId = $(this).attr('data-for');
1511 const bro = $(`#${broId}`);1513 const bro = $(`#${broId}`);
1512 const contentEditable = bro.is('[contenteditable]');1514 const contentEditable = bro.is('[contenteditable]');
@@ -1525,6 +1527,7 @@ jQuery(function () {
1525 textarea.value = String(contentEditable ? bro[0].innerText : bro.val());1527 textarea.value = String(contentEditable ? bro[0].innerText : bro.val());
1526 textarea.classList.add('height100p', 'wide100p', 'maximized_textarea');1528 textarea.classList.add('height100p', 'wide100p', 'maximized_textarea');
1527 bro.hasClass('monospace') && textarea.classList.add('monospace');1529 bro.hasClass('monospace') && textarea.classList.add('monospace');
1530 bro.hasClass('mdHotkeys') && textarea.classList.add('mdHotkeys');
1528 textarea.addEventListener('input', function () {1531 textarea.addEventListener('input', function () {
1529 if (contentEditable) {1532 if (contentEditable) {
1530 bro[0].innerText = textarea.value;1533 bro[0].innerText = textarea.value;
@@ -1565,7 +1568,7 @@ jQuery(function () {
1565 });1568 });
1566 }1569 }
15671570
1568 callGenericPopup(wrapper, POPUP_TYPE.TEXT, '', { wide: true, large: true });1571 await callGenericPopup(wrapper, POPUP_TYPE.TEXT, '', { wide: true, large: true });
1569 });1572 });
15701573
1571 $(document).on('click', 'body.documentstyle .mes .mes_text', function () {1574 $(document).on('click', 'body.documentstyle .mes .mes_text', function () {
public/scripts/custom-request.js+189 -0
@@ -0,0 +1,189 @@
1import { getPresetManager } from './preset-manager.js';
2import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js';
3import { getTextGenServer } from './textgen-settings.js';
4
5// #region Type Definitions
6/**
7 * @typedef {Object} TextCompletionRequestBase
8 * @property {string} prompt - The text prompt for completion
9 * @property {number} max_tokens - Maximum number of tokens to generate
10 * @property {string} [model] - Optional model name
11 * @property {string} api_type - Type of API to use
12 * @property {string} [api_server] - Optional API server URL
13 * @property {number} [temperature] - Optional temperature parameter
14 */
15
16/** @typedef {Record<string, any> & TextCompletionRequestBase} TextCompletionRequest */
17
18/**
19 * @typedef {Object} TextCompletionPayloadBase
20 * @property {string} prompt - The text prompt for completion
21 * @property {number} max_tokens - Maximum number of tokens to generate
22 * @property {number} max_new_tokens - Alias for max_tokens
23 * @property {string} [model] - Optional model name
24 * @property {string} api_type - Type of API to use
25 * @property {string} api_server - API server URL
26 * @property {number} [temperature] - Optional temperature parameter
27 */
28
29/** @typedef {Record<string, any> & TextCompletionPayloadBase} TextCompletionPayload */
30
31/**
32 * @typedef {Object} ChatCompletionMessage
33 * @property {string} role - The role of the message author (e.g., "user", "assistant", "system")
34 * @property {string} content - The content of the message
35 */
36
37/**
38 * @typedef {Object} ChatCompletionPayloadBase
39 * @property {ChatCompletionMessage[]} messages - Array of chat messages
40 * @property {string} [model] - Optional model name to use for completion
41 * @property {string} chat_completion_source - Source provider for chat completion
42 * @property {number} max_tokens - Maximum number of tokens to generate
43 * @property {number} [temperature] - Optional temperature parameter for response randomness
44 */
45
46/** @typedef {Record<string, any> & ChatCompletionPayloadBase} ChatCompletionPayload */
47// #endregion
48
49/**
50 * Creates & sends a text completion request. Streaming is not supported.
51 */
52export class TextCompletionService {
53 static TYPE = 'textgenerationwebui';
54
55 /**
56 * @param {TextCompletionRequest} custom
57 * @returns {TextCompletionPayload}
58 */
59 static createRequestData({ prompt, max_tokens, model, api_type, api_server, temperature, ...props }) {
60 return {
61 ...props,
62 prompt,
63 max_tokens,
64 max_new_tokens: max_tokens,
65 model,
66 api_type,
67 api_server: api_server ?? getTextGenServer(api_type),
68 temperature,
69 stream: false,
70 };
71 }
72
73 /**
74 * Sends a text completion request to the specified server
75 * @param {TextCompletionPayload} data Request data
76 * @param {boolean?} extractData Extract message from the response. Default true
77 * @returns {Promise<string | any>} Extracted data or the raw response
78 * @throws {Error}
79 */
80 static async sendRequest(data, extractData = true) {
81 const response = await fetch(getGenerateUrl(this.TYPE), {
82 method: 'POST',
83 headers: getRequestHeaders(),
84 cache: 'no-cache',
85 body: JSON.stringify(data),
86 signal: new AbortController().signal,
87 });
88
89 const json = await response.json();
90 if (!response.ok || json.error) {
91 throw json;
92 }
93
94 return extractData ? extractMessageFromData(json, this.TYPE) : json;
95 }
96
97 /**
98 * @param {string} presetName
99 * @param {TextCompletionRequest} custom
100 * @param {boolean?} extractData Extract message from the response. Default true
101 * @returns {Promise<string | any>} Extracted data or the raw response
102 * @throws {Error}
103 */
104 static async sendRequestWithPreset(presetName, custom, extractData = true) {
105 const presetManager = getPresetManager(this.TYPE);
106 if (!presetManager) {
107 throw new Error('Preset manager not found');
108 }
109
110 const preset = presetManager.getCompletionPresetByName(presetName);
111 if (!preset) {
112 throw new Error('Preset not found');
113 }
114
115 const data = this.createRequestData({ ...preset, ...custom });
116
117 return await this.sendRequest(data, extractData);
118 }
119}
120
121/**
122 * Creates & sends a chat completion request. Streaming is not supported.
123 */
124export class ChatCompletionService {
125 static TYPE = 'openai';
126
127 /**
128 * @param {ChatCompletionPayload} custom
129 * @returns {ChatCompletionPayload}
130 */
131 static createRequestData({ messages, model, chat_completion_source, max_tokens, temperature, ...props }) {
132 return {
133 ...props,
134 messages,
135 model,
136 chat_completion_source,
137 max_tokens,
138 temperature,
139 stream: false,
140 };
141 }
142
143 /**
144 * Sends a chat completion request
145 * @param {ChatCompletionPayload} data Request data
146 * @param {boolean?} extractData Extract message from the response. Default true
147 * @returns {Promise<string | any>} Extracted data or the raw response
148 * @throws {Error}
149 */
150 static async sendRequest(data, extractData = true) {
151 const response = await fetch('/api/backends/chat-completions/generate', {
152 method: 'POST',
153 headers: getRequestHeaders(),
154 cache: 'no-cache',
155 body: JSON.stringify(data),
156 signal: new AbortController().signal,
157 });
158
159 const json = await response.json();
160 if (!response.ok || json.error) {
161 throw json;
162 }
163
164 return extractData ? extractMessageFromData(json, this.TYPE) : json;
165 }
166
167 /**
168 * @param {string} presetName
169 * @param {ChatCompletionPayload} custom
170 * @param {boolean} extractData Extract message from the response. Default true
171 * @returns {Promise<string | any>} Extracted data or the raw response
172 * @throws {Error}
173 */
174 static async sendRequestWithPreset(presetName, custom, extractData = true) {
175 const presetManager = getPresetManager(this.TYPE);
176 if (!presetManager) {
177 throw new Error('Preset manager not found');
178 }
179
180 const preset = presetManager.getCompletionPresetByName(presetName);
181 if (!preset) {
182 throw new Error('Preset not found');
183 }
184
185 const data = this.createRequestData({ ...preset, ...custom });
186
187 return await this.sendRequest(data, extractData);
188 }
189}
public/scripts/extensions.js+59 -7
@@ -7,7 +7,7 @@ import { renderTemplate, renderTemplateAsync } from './templates.js';
7import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js';7import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js';
8import { getContext } from './st-context.js';8import { getContext } from './st-context.js';
9import { isAdmin } from './user.js';9import { isAdmin } from './user.js';
10import { t } from './i18n.js';10import { addLocaleData, getCurrentLocale, t } from './i18n.js';
11import { debounce_timeout } from './constants.js';11import { debounce_timeout } from './constants.js';
12import { accountStorage } from './util/AccountStorage.js';12import { accountStorage } from './util/AccountStorage.js';
1313
@@ -154,8 +154,18 @@ export const extension_settings = {
154 refine_mode: false,154 refine_mode: false,
155 },155 },
156 expressions: {156 expressions: {
157 /** @type {number} see `EXPRESSION_API` */
158 api: undefined,
157 /** @type {string[]} */159 /** @type {string[]} */
158 custom: [],160 custom: [],
161 showDefault: false,
162 translate: false,
163 /** @type {string} */
164 fallback_expression: undefined,
165 /** @type {string} */
166 llmPrompt: undefined,
167 allowMultiple: true,
168 rerollIfSame: false,
159 },169 },
160 connectionManager: {170 connectionManager: {
161 selectedProfile: '',171 selectedProfile: '',
@@ -200,6 +210,12 @@ export const extension_settings = {
200 * @type {string[]}210 * @type {string[]}
201 */211 */
202 disabled_attachments: [],212 disabled_attachments: [],
213 gallery: {
214 /** @type {{[characterKey: string]: string}} */
215 folders: {},
216 /** @type {string} */
217 sort: 'dateAsc',
218 },
203};219};
204220
205function showHideExtensionsMenu() {221function showHideExtensionsMenu() {
@@ -374,7 +390,7 @@ async function activateExtensions() {
374 if (meetsModuleRequirements && !isDisabled) {390 if (meetsModuleRequirements && !isDisabled) {
375 try {391 try {
376 console.debug('Activating extension', name);392 console.debug('Activating extension', name);
377 const promise = Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]);393 const promise = addExtensionLocale(name, manifest).finally(() => Promise.all([addExtensionScript(name, manifest), addExtensionStyle(name, manifest)]));
378 await promise394 await promise
379 .then(() => activeExtensions.add(name))395 .then(() => activeExtensions.add(name))
380 .catch(err => console.log('Could not activate extension', name, err));396 .catch(err => console.log('Could not activate extension', name, err));
@@ -567,6 +583,42 @@ function addExtensionScript(name, manifest) {
567}583}
568584
569/**585/**
586 * Adds a localization data for an extension.
587 * @param {string} name Extension name
588 * @param {object} manifest Manifest object
589 */
590function addExtensionLocale(name, manifest) {
591 // No i18n data in the manifest
592 if (!manifest.i18n || typeof manifest.i18n !== 'object') {
593 return Promise.resolve();
594 }
595
596 const currentLocale = getCurrentLocale();
597 const localeFile = manifest.i18n[currentLocale];
598
599 // Manifest doesn't provide a locale file for the current locale
600 if (!localeFile) {
601 return Promise.resolve();
602 }
603
604 return fetch(`/scripts/extensions/${name}/${localeFile}`)
605 .then(async response => {
606 if (!response.ok) {
607 throw new Error(`HTTP ${response.status}: ${response.statusText}`);
608 }
609
610 const data = await response.json();
611
612 if (data && typeof data === 'object') {
613 addLocaleData(currentLocale, data);
614 }
615 })
616 .catch(err => {
617 console.log('Could not load extension locale data for ' + name, err);
618 });
619}
620
621/**
570 * Generates HTML string for displaying an extension in the UI.622 * Generates HTML string for displaying an extension in the UI.
571 *623 *
572 * @param {string} name - The name of the extension.624 * @param {string} name - The name of the extension.
@@ -603,12 +655,12 @@ function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal,
603 }655 }
604656
605 let toggleElement = isActive || isDisabled ?657 let toggleElement = isActive || isDisabled ?
606 `<input type="checkbox" title="Click to toggle" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :658 '<input type="checkbox" title="' + t`Click to toggle` + `" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :
607 `<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;659 `<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;
608660
609 let deleteButton = isExternal ? `<button class="btn_delete menu_button" data-name="${externalId}" title="Delete"><i class="fa-fw fa-solid fa-trash-can"></i></button>` : '';661 let deleteButton = isExternal ? `<button class="btn_delete menu_button" data-name="${externalId}" data-i18n="[title]Delete" title="Delete"><i class="fa-fw fa-solid fa-trash-can"></i></button>` : '';
610 let updateButton = isExternal ? `<button class="btn_update menu_button displayNone" data-name="${externalId}" title="Update available"><i class="fa-solid fa-download fa-fw"></i></button>` : '';662 let updateButton = isExternal ? `<button class="btn_update menu_button displayNone" data-name="${externalId}" title="Update available"><i class="fa-solid fa-download fa-fw"></i></button>` : '';
611 let moveButton = isExternal && isUserAdmin ? `<button class="btn_move menu_button" data-name="${externalId}" title="Move"><i class="fa-solid fa-folder-tree fa-fw"></i></button>` : '';663 let moveButton = isExternal && isUserAdmin ? `<button class="btn_move menu_button" data-name="${externalId}" data-i18n="[title]Move" title="Move"><i class="fa-solid fa-folder-tree fa-fw"></i></button>` : '';
612 let modulesInfo = '';664 let modulesInfo = '';
613665
614 if (isActive && Array.isArray(manifest.optional)) {666 if (isActive && Array.isArray(manifest.optional)) {
@@ -616,7 +668,7 @@ function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal,
616 modules.forEach(x => optional.delete(x));668 modules.forEach(x => optional.delete(x));
617 if (optional.size > 0) {669 if (optional.size > 0) {
618 const optionalString = DOMPurify.sanitize([...optional].join(', '));670 const optionalString = DOMPurify.sanitize([...optional].join(', '));
619 modulesInfo = `<div class="extension_modules">Optional modules: <span class="optional">${optionalString}</span></div>`;671 modulesInfo = '<div class="extension_modules">' + t`Optional modules:` + ` <span class="optional">${optionalString}</span></div>`;
620 }672 }
621 } else if (!isDisabled) { // Neither active nor disabled673 } else if (!isDisabled) { // Neither active nor disabled
622 const requirements = new Set(manifest.requires);674 const requirements = new Set(manifest.requires);
@@ -1018,7 +1070,7 @@ export async function installExtension(url, global) {
1018 toastr.success(t`Extension '${response.display_name}' by ${response.author} (version ${response.version}) has been installed successfully!`, t`Extension installation successful`);1070 toastr.success(t`Extension '${response.display_name}' by ${response.author} (version ${response.version}) has been installed successfully!`, t`Extension installation successful`);
1019 console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`);1071 console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`);
1020 await loadExtensionSettings({}, false, false);1072 await loadExtensionSettings({}, false, false);
1021 await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED);1073 await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED, response);
1022}1074}
10231075
1024/**1076/**
public/scripts/extensions/assets/index.js+13 -15
@@ -10,6 +10,7 @@ import { POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js';
10import { executeSlashCommands } from '../../slash-commands.js';10import { executeSlashCommands } from '../../slash-commands.js';
11import { accountStorage } from '../../util/AccountStorage.js';11import { accountStorage } from '../../util/AccountStorage.js';
12import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js';12import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js';
13import { t } from '../../i18n.js';
13export { MODULE_NAME };14export { MODULE_NAME };
1415
15const MODULE_NAME = 'assets';16const MODULE_NAME = 'assets';
@@ -59,11 +60,11 @@ const KNOWN_TYPES = {
59 'blip': 'Blip sounds',60 'blip': 'Blip sounds',
60};61};
6162
62function downloadAssetsList(url) {63async function downloadAssetsList(url) {
63 updateCurrentAssets().then(function () {64 updateCurrentAssets().then(async function () {
64 fetch(url, { cache: 'no-cache' })65 fetch(url, { cache: 'no-cache' })
65 .then(response => response.json())66 .then(response => response.json())
66 .then(json => {67 .then(async function(json) {
6768
68 availableAssets = {};69 availableAssets = {};
69 $('#assets_menu').empty();70 $('#assets_menu').empty();
@@ -84,10 +85,10 @@ function downloadAssetsList(url) {
8485
85 $('#assets_type_select').empty();86 $('#assets_type_select').empty();
86 $('#assets_search').val('');87 $('#assets_search').val('');
87 $('#assets_type_select').append($('<option />', { value: '', text: 'All' }));88 $('#assets_type_select').append($('<option />', { value: '', text: t`All` }));
8889
89 for (const type of assetTypes) {90 for (const type of assetTypes) {
90 const option = $('<option />', { value: type, text: KNOWN_TYPES[type] || type });91 const option = $('<option />', { value: type, text: t([KNOWN_TYPES[type] || type]) });
91 $('#assets_type_select').append(option);92 $('#assets_type_select').append(option);
92 }93 }
9394
@@ -104,11 +105,7 @@ function downloadAssetsList(url) {
104 assetTypeMenu.append(`<h3>${KNOWN_TYPES[assetType] || assetType}</h3>`).hide();105 assetTypeMenu.append(`<h3>${KNOWN_TYPES[assetType] || assetType}</h3>`).hide();
105106
106 if (assetType == 'extension') {107 if (assetType == 'extension') {
107 assetTypeMenu.append(`108 assetTypeMenu.append(await renderExtensionTemplateAsync('assets', 'installation'));
108 <div class="assets-list-git">
109 To download extensions from this page, you need to have <a href="https://git-scm.com/downloads" target="_blank">Git</a> installed.<br>
110 Click the <i class="fa-solid fa-sm fa-arrow-up-right-from-square"></i> icon to visit the Extension's repo for tips on how to use it.
111 </div>`);
112 }109 }
113110
114 for (const i in availableAssets[assetType].sort((a, b) => a?.name && b?.name && a['name'].localeCompare(b['name']))) {111 for (const i in availableAssets[assetType].sort((a, b) => a?.name && b?.name && a['name'].localeCompare(b['name']))) {
@@ -184,7 +181,7 @@ function downloadAssetsList(url) {
184 const displayName = DOMPurify.sanitize(asset['name'] || asset['id']);181 const displayName = DOMPurify.sanitize(asset['name'] || asset['id']);
185 const description = DOMPurify.sanitize(asset['description'] || '');182 const description = DOMPurify.sanitize(asset['description'] || '');
186 const url = isValidUrl(asset['url']) ? asset['url'] : '';183 const url = isValidUrl(asset['url']) ? asset['url'] : '';
187 const title = assetType === 'extension' ? `Extension repo/guide: ${url}` : 'Preview in browser';184 const title = assetType === 'extension' ? t`Extension repo/guide:` + ` ${url}` : t`Preview in browser`;
188 const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';185 const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';
189 const toolTag = assetType === 'extension' && asset['tool'];186 const toolTag = assetType === 'extension' && asset['tool'];
190187
@@ -195,9 +192,10 @@ function downloadAssetsList(url) {
195 <b>${displayName}</b>192 <b>${displayName}</b>
196 <a class="asset_preview" href="${url}" target="_blank" title="${title}">193 <a class="asset_preview" href="${url}" target="_blank" title="${title}">
197 <i class="fa-solid fa-sm ${previewIcon}"></i>194 <i class="fa-solid fa-sm ${previewIcon}"></i>
198 </a>195 </a>` +
199 ${toolTag ? '<span class="tag" title="Adds a function tool"><i class="fa-solid fa-sm fa-wrench"></i> Tool</span>' : ''}196 (toolTag ? '<span class="tag" title="' + t`Adds a function tool` + '"><i class="fa-solid fa-sm fa-wrench"></i> ' +
200 </span>197 t`Tool` + '</span>' : '') +
198 `</span>
201 <small class="asset-description">199 <small class="asset-description">
202 ${description}200 ${description}
203 </small>201 </small>
@@ -435,7 +433,7 @@ jQuery(async () => {
435 const rememberKey = `Assets_SkipConfirm_${getStringHash(url)}`;433 const rememberKey = `Assets_SkipConfirm_${getStringHash(url)}`;
436 const skipConfirm = accountStorage.getItem(rememberKey) === 'true';434 const skipConfirm = accountStorage.getItem(rememberKey) === 'true';
437435
438 const confirmation = skipConfirm || await Popup.show.confirm('Loading Asset List', `<span>Are you sure you want to connect to the following url?</span><var>${url}</var>`, {436 const confirmation = skipConfirm || await Popup.show.confirm(t`Loading Asset List`, '<span>' + t`Are you sure you want to connect to the following url?` + `</span><var>${url}</var>`, {
439 customInputs: [{ id: 'assets-remember', label: 'Don\'t ask again for this URL' }],437 customInputs: [{ id: 'assets-remember', label: 'Don\'t ask again for this URL' }],
440 onClose: popup => {438 onClose: popup => {
441 if (popup.result) {439 if (popup.result) {
public/scripts/extensions/assets/installation.html+4 -0
@@ -0,0 +1,4 @@
1<div class="assets-list-git">
2 <span data-i18n="extension_install_1">To download extensions from this page, you need to have </span><a href="https://git-scm.com/downloads" target="_blank">Git</a><span data-i18n="extension_install_2"> installed.</span><br>
3 <span data-i18n="extension_install_3">Click the </span><i class="fa-solid fa-sm fa-arrow-up-right-from-square"></i><span data-i18n="extension_install_4"> icon to visit the Extension's repo for tips on how to use it.</span>
4</div>
\ No newline at end of file4 \ No newline at end of file
public/scripts/extensions/assets/window.html+1 -1
@@ -33,7 +33,7 @@ To install a single 3rd party extension, use the &quot;Install Extensions&quot;
33 <div id="assets_filters" class="flex-container">33 <div id="assets_filters" class="flex-container">
34 <select id="assets_type_select" class="text_pole flex1">34 <select id="assets_type_select" class="text_pole flex1">
35 </select>35 </select>
36 <input id="assets_search" class="text_pole flex1" placeholder="Search" type="search">36 <input id="assets_search" class="text_pole flex1" data-i18n="[placeholder]Search" placeholder="Search" type="search">
37 <div id="assets-characters-button" class="menu_button menu_button_icon">37 <div id="assets-characters-button" class="menu_button menu_button_icon">
38 <i class="fa-solid fa-image-portrait"></i>38 <i class="fa-solid fa-image-portrait"></i>
39 <span data-i18n="Characters">Characters</span>39 <span data-i18n="Characters">Characters</span>
public/scripts/extensions/caption/index.js+56 -17
@@ -398,23 +398,62 @@ jQuery(async function () {
398398
399 $('#caption_wand_container').append(sendButton);399 $('#caption_wand_container').append(sendButton);
400 $(sendButton).on('click', () => {400 $(sendButton).on('click', () => {
401 const hasCaptionModule =401 const hasCaptionModule = (() => {
402 (modules.includes('caption') && extension_settings.caption.source === 'extras') ||402 const settings = extension_settings.caption;
403 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openai' && (secret_state[SECRET_KEYS.OPENAI] || extension_settings.caption.allow_reverse_proxy)) ||403
404 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'openrouter' && secret_state[SECRET_KEYS.OPENROUTER]) ||404 // Handle non-multimodal sources
405 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'zerooneai' && secret_state[SECRET_KEYS.ZEROONEAI]) ||405 if (settings.source === 'extras' && modules.includes('caption')) return true;
406 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'groq' && secret_state[SECRET_KEYS.GROQ]) ||406 if (settings.source === 'local' || settings.source === 'horde') return true;
407 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'mistral' && (secret_state[SECRET_KEYS.MISTRALAI] || extension_settings.caption.allow_reverse_proxy)) ||407
408 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'google' && (secret_state[SECRET_KEYS.MAKERSUITE] || extension_settings.caption.allow_reverse_proxy)) ||408 // Handle multimodal sources
409 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'anthropic' && (secret_state[SECRET_KEYS.CLAUDE] || extension_settings.caption.allow_reverse_proxy)) ||409 if (settings.source === 'multimodal') {
410 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ollama' && textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) ||410 const api = settings.multimodal_api;
411 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'llamacpp' && textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) ||411
412 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'ooba' && textgenerationwebui_settings.server_urls[textgen_types.OOBA]) ||412 // APIs that support reverse proxy
413 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'koboldcpp' && textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP]) ||413 const reverseProxyApis = {
414 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'vllm' && textgenerationwebui_settings.server_urls[textgen_types.VLLM]) ||414 'openai': SECRET_KEYS.OPENAI,
415 (extension_settings.caption.source === 'multimodal' && extension_settings.caption.multimodal_api === 'custom') ||415 'mistral': SECRET_KEYS.MISTRALAI,
416 extension_settings.caption.source === 'local' ||416 'google': SECRET_KEYS.MAKERSUITE,
417 extension_settings.caption.source === 'horde';417 'anthropic': SECRET_KEYS.CLAUDE,
418 };
419
420 if (reverseProxyApis[api]) {
421 if (secret_state[reverseProxyApis[api]] || settings.allow_reverse_proxy) {
422 return true;
423 }
424 }
425
426 const chatCompletionApis = {
427 'openrouter': SECRET_KEYS.OPENROUTER,
428 'zerooneai': SECRET_KEYS.ZEROONEAI,
429 'groq': SECRET_KEYS.GROQ,
430 'cohere': SECRET_KEYS.COHERE,
431 };
432
433 if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) {
434 return true;
435 }
436
437 const textCompletionApis = {
438 'ollama': textgen_types.OLLAMA,
439 'llamacpp': textgen_types.LLAMACPP,
440 'ooba': textgen_types.OOBA,
441 'koboldcpp': textgen_types.KOBOLDCPP,
442 'vllm': textgen_types.VLLM,
443 };
444
445 if (textCompletionApis[api] && textgenerationwebui_settings.server_urls[textCompletionApis[api]]) {
446 return true;
447 }
448
449 // Custom API doesn't need additional checks
450 if (api === 'custom') {
451 return true;
452 }
453 }
454
455 return false;
456 })();
418457
419 if (!hasCaptionModule) {458 if (!hasCaptionModule) {
420 toastr.error('Choose other captioning source in the extension settings.', 'Captioning is not available');459 toastr.error('Choose other captioning source in the extension settings.', 'Captioning is not available');
public/scripts/extensions/caption/settings.html+10 -0
@@ -19,6 +19,7 @@
19 <select id="caption_multimodal_api" class="flex1 text_pole">19 <select id="caption_multimodal_api" class="flex1 text_pole">
20 <option value="zerooneai">01.AI (Yi)</option>20 <option value="zerooneai">01.AI (Yi)</option>
21 <option value="anthropic">Anthropic</option>21 <option value="anthropic">Anthropic</option>
22 <option value="cohere">Cohere</option>
22 <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>
23 <option value="google">Google AI Studio</option>24 <option value="google">Google AI Studio</option>
24 <option value="groq">Groq</option>25 <option value="groq">Groq</option>
@@ -35,6 +36,8 @@
35 <div class="flex1 flex-container flexFlowColumn flexNoGap">36 <div class="flex1 flex-container flexFlowColumn flexNoGap">
36 <label for="caption_multimodal_model" data-i18n="Model">Model</label>37 <label for="caption_multimodal_model" data-i18n="Model">Model</label>
37 <select id="caption_multimodal_model" class="flex1 text_pole">38 <select id="caption_multimodal_model" class="flex1 text_pole">
39 <option data-type="cohere" value="c4ai-aya-vision-8b">c4ai-aya-vision-8b</option>
40 <option data-type="cohere" value="c4ai-aya-vision-32b">c4ai-aya-vision-32b</option>
38 <option data-type="mistral" value="pixtral-12b-latest">pixtral-12b-latest</option>41 <option data-type="mistral" value="pixtral-12b-latest">pixtral-12b-latest</option>
39 <option data-type="mistral" value="pixtral-12b-2409">pixtral-12b-2409</option>42 <option data-type="mistral" value="pixtral-12b-2409">pixtral-12b-2409</option>
40 <option data-type="mistral" value="pixtral-large-latest">pixtral-large-latest</option>43 <option data-type="mistral" value="pixtral-large-latest">pixtral-large-latest</option>
@@ -45,6 +48,12 @@
45 <option data-type="openai" value="gpt-4o">gpt-4o</option>48 <option data-type="openai" value="gpt-4o">gpt-4o</option>
46 <option data-type="openai" value="gpt-4o-mini">gpt-4o-mini</option>49 <option data-type="openai" value="gpt-4o-mini">gpt-4o-mini</option>
47 <option data-type="openai" value="chatgpt-4o-latest">chatgpt-4o-latest</option>50 <option data-type="openai" value="chatgpt-4o-latest">chatgpt-4o-latest</option>
51 <option data-type="openai" value="o1">o1</option>
52 <option data-type="openai" value="o1-2024-12-17">o1-2024-12-17</option>
53 <option data-type="openai" value="gpt-4.5-preview">gpt-4.5-preview</option>
54 <option data-type="openai" value="gpt-4.5-preview-2025-02-27">gpt-4.5-preview-2025-02-27</option>
55 <option data-type="anthropic" value="claude-3-7-sonnet-latest">claude-3-7-sonnet-latest</option>
56 <option data-type="anthropic" value="claude-3-7-sonnet-20250219">claude-3-7-sonnet-20250219</option>
48 <option data-type="anthropic" value="claude-3-5-sonnet-latest">claude-3-5-sonnet-latest</option>57 <option data-type="anthropic" value="claude-3-5-sonnet-latest">claude-3-5-sonnet-latest</option>
49 <option data-type="anthropic" value="claude-3-5-sonnet-20241022">claude-3-5-sonnet-20241022</option>58 <option data-type="anthropic" value="claude-3-5-sonnet-20241022">claude-3-5-sonnet-20241022</option>
50 <option data-type="anthropic" value="claude-3-5-sonnet-20240620">claude-3-5-sonnet-20240620</option>59 <option data-type="anthropic" value="claude-3-5-sonnet-20240620">claude-3-5-sonnet-20240620</option>
@@ -60,6 +69,7 @@
60 <option data-type="google" value="gemini-2.0-flash">gemini-2.0-flash</option>69 <option data-type="google" value="gemini-2.0-flash">gemini-2.0-flash</option>
61 <option data-type="google" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option>70 <option data-type="google" value="gemini-2.0-flash-001">gemini-2.0-flash-001</option>
62 <option data-type="google" value="gemini-2.0-flash-exp">gemini-2.0-flash-exp</option>71 <option data-type="google" value="gemini-2.0-flash-exp">gemini-2.0-flash-exp</option>
72 <option data-type="google" value="gemini-2.0-flash-exp-image-generation">gemini-2.0-flash-exp-image-generation</option>
63 <option data-type="google" value="gemini-2.0-flash-thinking-exp">gemini-2.0-flash-thinking-exp</option>73 <option data-type="google" value="gemini-2.0-flash-thinking-exp">gemini-2.0-flash-thinking-exp</option>
64 <option data-type="google" value="gemini-2.0-flash-thinking-exp-01-21">gemini-2.0-flash-thinking-exp-01-21</option>74 <option data-type="google" value="gemini-2.0-flash-thinking-exp-01-21">gemini-2.0-flash-thinking-exp-01-21</option>
65 <option data-type="google" value="gemini-2.0-flash-thinking-exp-1219">gemini-2.0-flash-thinking-exp-1219</option>75 <option data-type="google" value="gemini-2.0-flash-thinking-exp-1219">gemini-2.0-flash-thinking-exp-1219</option>
public/scripts/extensions/connection-manager/index.js+26 -4
@@ -16,12 +16,19 @@ import { t } from '../../i18n.js';
1616
17const MODULE_NAME = 'connection-manager';17const MODULE_NAME = 'connection-manager';
18const NONE = '<None>';18const NONE = '<None>';
19const EMPTY = '<Empty>';
1920
20const DEFAULT_SETTINGS = {21const DEFAULT_SETTINGS = {
21 profiles: [],22 profiles: [],
22 selectedProfile: null,23 selectedProfile: null,
23};24};
2425
26// Commands that can record an empty value into the profile
27const ALLOW_EMPTY = [
28 'stop-strings',
29 'start-reply-with',
30];
31
25const CC_COMMANDS = [32const CC_COMMANDS = [
26 'api',33 'api',
27 'preset',34 'preset',
@@ -31,6 +38,7 @@ const CC_COMMANDS = [
31 'model',38 'model',
32 'proxy',39 'proxy',
33 'stop-strings',40 'stop-strings',
41 'start-reply-with',
34];42];
3543
36const TC_COMMANDS = [44const TC_COMMANDS = [
@@ -45,6 +53,7 @@ const TC_COMMANDS = [
45 'instruct-state',53 'instruct-state',
46 'tokenizer',54 'tokenizer',
47 'stop-strings',55 'stop-strings',
56 'start-reply-with',
48];57];
4958
50const FANCY_NAMES = {59const FANCY_NAMES = {
@@ -60,6 +69,7 @@ const FANCY_NAMES = {
60 'context': 'Context Template',69 'context': 'Context Template',
61 'tokenizer': 'Tokenizer',70 'tokenizer': 'Tokenizer',
62 'stop-strings': 'Custom Stopping Strings',71 'stop-strings': 'Custom Stopping Strings',
72 'start-reply-with': 'Start Reply With',
63};73};
6474
65/**75/**
@@ -107,6 +117,7 @@ class ConnectionManagerSpinner {
107/**117/**
108 * Get named arguments for the command callback.118 * Get named arguments for the command callback.
109 * @param {object} [args] Additional named arguments119 * @param {object} [args] Additional named arguments
120 * @param {string} [args.force] Whether to force setting the value
110 * @returns {object} Named arguments121 * @returns {object} Named arguments
111 */122 */
112function getNamedArguments(args = {}) {123function getNamedArguments(args = {}) {
@@ -142,6 +153,7 @@ const profilesProvider = () => [
142 * @property {string} [instruct-state] Instruct Mode153 * @property {string} [instruct-state] Instruct Mode
143 * @property {string} [tokenizer] Tokenizer154 * @property {string} [tokenizer] Tokenizer
144 * @property {string} [stop-strings] Custom Stopping Strings155 * @property {string} [stop-strings] Custom Stopping Strings
156 * @property {string} [start-reply-with] Start Reply With
145 * @property {string[]} [exclude] Commands to exclude157 * @property {string[]} [exclude] Commands to exclude
146 */158 */
147159
@@ -186,9 +198,10 @@ async function readProfileFromCommands(mode, profile, cleanUp = false) {
186 continue;198 continue;
187 }199 }
188200
201 const allowEmpty = ALLOW_EMPTY.includes(command);
189 const args = getNamedArguments();202 const args = getNamedArguments();
190 const result = await SlashCommandParser.commands[command].callback(args, '');203 const result = await SlashCommandParser.commands[command].callback(args, '');
191 if (result) {204 if (result || (allowEmpty && result === '')) {
192 profile[command] = result;205 profile[command] = result;
193 continue;206 continue;
194 }207 }
@@ -309,7 +322,14 @@ async function deleteConnectionProfile() {
309 */322 */
310function makeFancyProfile(profile) {323function makeFancyProfile(profile) {
311 return Object.entries(FANCY_NAMES).reduce((acc, [key, value]) => {324 return Object.entries(FANCY_NAMES).reduce((acc, [key, value]) => {
312 if (!profile[key]) return acc;325 const allowEmpty = ALLOW_EMPTY.includes(key);
326 if (!profile[key]) {
327 if (profile[key] === '' && allowEmpty) {
328 acc[value] = EMPTY;
329 }
330 return acc;
331 }
332
313 acc[value] = profile[key];333 acc[value] = profile[key];
314 return acc;334 return acc;
315 }, {});335 }, {});
@@ -339,11 +359,12 @@ async function applyConnectionProfile(profile) {
339 }359 }
340360
341 const argument = profile[command];361 const argument = profile[command];
342 if (!argument) {362 const allowEmpty = ALLOW_EMPTY.includes(command);
363 if (!argument && !(allowEmpty && argument === '')) {
343 continue;364 continue;
344 }365 }
345 try {366 try {
346 const args = getNamedArguments();367 const args = getNamedArguments(allowEmpty ? { force: 'true' } : {});
347 await SlashCommandParser.commands[command].callback(args, argument);368 await SlashCommandParser.commands[command].callback(args, argument);
348 } catch (error) {369 } catch (error) {
349 console.error(`Failed to execute command: ${command} ${argument}`, error);370 console.error(`Failed to execute command: ${command} ${argument}`, error);
@@ -539,6 +560,7 @@ async function renderDetailsContent(detailsContent) {
539 }, {});560 }, {});
540 const template = $(await renderExtensionTemplateAsync(MODULE_NAME, 'edit', { name: profile.name, settings }));561 const template = $(await renderExtensionTemplateAsync(MODULE_NAME, 'edit', { name: profile.name, settings }));
541 const newName = await callGenericPopup(template, POPUP_TYPE.INPUT, profile.name, {562 const newName = await callGenericPopup(template, POPUP_TYPE.INPUT, profile.name, {
563 rows: 2,
542 customButtons: [{564 customButtons: [{
543 text: t`Save and Update`,565 text: t`Save and Update`,
544 classes: ['popup-button-ok'],566 classes: ['popup-button-ok'],
public/scripts/extensions/expressions/index.js+144 -294
@@ -1,11 +1,11 @@
1import { Fuse } from '../../../lib.js';1import { Fuse } from '../../../lib.js';
22
3import { callPopup, eventSource, event_types, generateRaw, getRequestHeaders, main_api, online_status, saveSettingsDebounced, substituteParams, substituteParamsExtended, system_message_types } from '../../../script.js';3import { characters, eventSource, event_types, generateRaw, getRequestHeaders, main_api, online_status, saveSettingsDebounced, substituteParams, substituteParamsExtended, system_message_types, this_chid } from '../../../script.js';
4import { dragElement, isMobile } from '../../RossAscends-mods.js';4import { dragElement, isMobile } from '../../RossAscends-mods.js';
5import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';5import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js';
6import { loadMovingUIState, power_user } from '../../power-user.js';6import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js';
7import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar } from '../../utils.js';7import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar } from '../../utils.js';
8import { hideMutedSprites } from '../../group-chats.js';8import { hideMutedSprites, selected_group } from '../../group-chats.js';
9import { isJsonSchemaSupported } from '../../textgen-settings.js';9import { isJsonSchemaSupported } from '../../textgen-settings.js';
10import { debounce_timeout } from '../../constants.js';10import { debounce_timeout } from '../../constants.js';
11import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';11import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
@@ -15,16 +15,32 @@ import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashComm
15import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';15import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
16import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';16import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
17import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';17import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js';
18import { Popup, POPUP_RESULT } from '../../popup.js';
19import { t } from '../../i18n.js';
18export { MODULE_NAME };20export { MODULE_NAME };
1921
22/**
23* @typedef {object} Expression Expression definition with label and file path
24* @property {string} label The label of the expression
25* @property {ExpressionImage[]} files One or more images to represent this expression
26*/
27
28/**
29 * @typedef {object} ExpressionImage An expression image
30 * @property {string} expression - The expression
31 * @property {boolean} [isCustom=false] - If the expression is added by user
32 * @property {string} fileName - The filename with extension
33 * @property {string} title - The title for the image
34 * @property {string} imageSrc - The image source / full path
35 * @property {'success' | 'additional' | 'failure'} type - The type of the image
36 */
37
20const MODULE_NAME = 'expressions';38const MODULE_NAME = 'expressions';
21const UPDATE_INTERVAL = 2000;39const UPDATE_INTERVAL = 2000;
22const STREAMING_UPDATE_INTERVAL = 10000;40const STREAMING_UPDATE_INTERVAL = 10000;
23const TALKINGCHECK_UPDATE_INTERVAL = 500;
24const DEFAULT_FALLBACK_EXPRESSION = 'joy';41const DEFAULT_FALLBACK_EXPRESSION = 'joy';
25const DEFAULT_LLM_PROMPT = 'Ignore previous instructions. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}';42const DEFAULT_LLM_PROMPT = 'Ignore previous instructions. Classify the emotion of the last message. Output just one word, e.g. "joy" or "anger". Choose only one of the following labels: {{labels}}';
26const DEFAULT_EXPRESSIONS = [43const DEFAULT_EXPRESSIONS = [
27 'talkinghead',
28 'admiration',44 'admiration',
29 'amusement',45 'amusement',
30 'anger',46 'anger',
@@ -54,6 +70,12 @@ const DEFAULT_EXPRESSIONS = [
54 'surprise',70 'surprise',
55 'neutral',71 'neutral',
56];72];
73
74const OPTION_NO_FALLBACK = '#none';
75const OPTION_EMOJI_FALLBACK = '#emoji';
76const RESET_SPRITE_LABEL = '#reset';
77
78
57/** @enum {number} */79/** @enum {number} */
58const EXPRESSION_API = {80const EXPRESSION_API = {
59 local: 0,81 local: 0,
@@ -65,35 +87,29 @@ const EXPRESSION_API = {
65let expressionsList = null;87let expressionsList = null;
66let lastCharacter = undefined;88let lastCharacter = undefined;
67let lastMessage = null;89let lastMessage = null;
68let lastTalkingState = false;90/** @type {{[characterKey: string]: Expression[]}} */
69let lastTalkingStateMessage = null; // last message as seen by `updateTalkingState` (tracked separately, different timer)
70let spriteCache = {};91let spriteCache = {};
71let inApiCall = false;92let inApiCall = false;
72let lastServerResponseTime = 0;93let lastServerResponseTime = 0;
73export let lastExpression = {};
74
75function isTalkingHeadEnabled() {
76 return extension_settings.expressions.talkinghead && extension_settings.expressions.api == EXPRESSION_API.extras;
77}
7894
79/**95/** @type {{[characterName: string]: string}} */
80 * Returns the fallback expression if explicitly chosen, otherwise the default one96export let lastExpression = {};
81 * @returns {string} expression name
82 */
83function getFallbackExpression() {
84 return extension_settings.expressions.fallback_expression ?? DEFAULT_FALLBACK_EXPRESSION;
85}
8697
87/**98/**
88 * Toggles Talkinghead mode on/off.99 * Returns a placeholder image object for a given expression
89 *100 * @param {string} expression - The expression label
90 * Implements the `/th` slash command, which is meant to be bound to a Quick Reply button101 * @param {boolean} [isCustom=false] - Whether the expression is custom
91 * as a quick way to switch Talkinghead on or off (e.g. to conserve GPU resources when AFK102 * @returns {ExpressionImage} The placeholder image object
92 * for a long time).
93 */103 */
94function toggleTalkingHeadCommand(_) {104function getPlaceholderImage(expression, isCustom = false) {
95 setTalkingHeadState(!extension_settings.expressions.talkinghead);105 return {
96 return String(extension_settings.expressions.talkinghead);106 expression: expression,
107 isCustom: isCustom,
108 title: 'No Image',
109 type: 'failure',
110 fileName: 'No-Image-Placeholder.svg',
111 imageSrc: '/img/No-Image-Placeholder.svg',
112 };
97}113}
98114
99function isVisualNovelMode() {115function isVisualNovelMode() {
@@ -108,21 +124,21 @@ async function forceUpdateVisualNovelMode() {
108124
109const updateVisualNovelModeDebounced = debounce(forceUpdateVisualNovelMode, debounce_timeout.quick);125const updateVisualNovelModeDebounced = debounce(forceUpdateVisualNovelMode, debounce_timeout.quick);
110126
111async function updateVisualNovelMode(name, expression) {127async function updateVisualNovelMode(spriteFolderName, expression) {
112 const container = $('#visual-novel-wrapper');128 const vnContainer = $('#visual-novel-wrapper');
113129
114 await visualNovelRemoveInactive(container);130 await visualNovelRemoveInactive(vnContainer);
115131
116 const setSpritePromises = await visualNovelSetCharacterSprites(container, name, expression);132 const setSpritePromises = await visualNovelSetCharacterSprites(vnContainer, spriteFolderName, expression);
117133
118 // calculate layer indices based on recent messages134 // calculate layer indices based on recent messages
119 await visualNovelUpdateLayers(container);135 await visualNovelUpdateLayers(vnContainer);
120136
121 await Promise.allSettled(setSpritePromises);137 await Promise.allSettled(setSpritePromises);
122138
123 // update again based on new sprites139 // update again based on new sprites
124 if (setSpritePromises.length > 0) {140 if (setSpritePromises.length > 0) {
125 await visualNovelUpdateLayers(container);141 await visualNovelUpdateLayers(vnContainer);
126 }142 }
127}143}
128144
@@ -153,52 +169,60 @@ async function visualNovelRemoveInactive(container) {
153 await Promise.allSettled(removeInactiveCharactersPromises);169 await Promise.allSettled(removeInactiveCharactersPromises);
154}170}
155171
156async function visualNovelSetCharacterSprites(container, name, expression) {172/**
173 * Sets the character sprites for visual novel mode based on the provided container, name, and expression.
174 *
175 * @param {JQuery<HTMLElement>} vnContainer - The container element where the sprites will be set
176 * @param {string} spriteFolderName - The name of the sprite folder
177 * @param {string} expression - The expression to set for the characters
178 * @returns {Promise<Array>} - An array of promises that resolve when the sprites are set
179 */
180async function visualNovelSetCharacterSprites(vnContainer, spriteFolderName, expression) {
181 const originalExpression = expression;
157 const context = getContext();182 const context = getContext();
158 const group = context.groups.find(x => x.id == context.groupId);183 const group = context.groups.find(x => x.id == context.groupId);
159 const labels = await getExpressionsList();
160184
161 const createCharacterPromises = [];
162 const setSpritePromises = [];185 const setSpritePromises = [];
163186
164 for (const avatar of group.members) {187 for (const avatar of group.members) {
165 const isDisabled = group.disabled_members.includes(avatar);
166
167 // skip disabled characters188 // skip disabled characters
189 const isDisabled = group.disabled_members.includes(avatar);
168 if (isDisabled && hideMutedSprites) {190 if (isDisabled && hideMutedSprites) {
169 continue;191 continue;
170 }192 }
171193
172 const character = context.characters.find(x => x.avatar == avatar);194 const character = context.characters.find(x => x.avatar == avatar);
173
174 if (!character) {195 if (!character) {
175 continue;196 continue;
176 }197 }
177198
178 const spriteFolderName = getSpriteFolderName({ original_avatar: character.avatar }, character.name);199 const expressionImage = vnContainer.find(`.expression-holder[data-avatar="${avatar}"]`);
200 /** @type {JQuery<HTMLElement>} */
201 let img;
202
203 const memberSpriteFolderName = getSpriteFolderName({ original_avatar: character.avatar }, character.name);
179204
180 // download images if not downloaded yet205 // download images if not downloaded yet
181 if (spriteCache[spriteFolderName] === undefined) {206 if (spriteCache[memberSpriteFolderName] === undefined) {
182 spriteCache[spriteFolderName] = await getSpritesList(spriteFolderName);207 spriteCache[memberSpriteFolderName] = await getSpritesList(memberSpriteFolderName);
183 }208 }
184209
185 const sprites = spriteCache[spriteFolderName];210 const prevExpressionSrc = expressionImage.find('img').attr('src') || null;
186 const expressionImage = container.find(`.expression-holder[data-avatar="${avatar}"]`);
187 const defaultExpression = getFallbackExpression();
188 const defaultSpritePath = sprites.find(x => x.label === defaultExpression)?.path;
189 const noSprites = sprites.length === 0;
190211
191 if (expressionImage.length > 0) {212 if (!originalExpression && Array.isArray(spriteCache[memberSpriteFolderName]) && spriteCache[memberSpriteFolderName].length > 0) {
192 if (name == spriteFolderName) {213 expression = await getLastMessageSprite(avatar);
193 await validateImages(spriteFolderName, true);214 }
194 setExpressionOverrideHtml(true); // <= force clear expression override input
195 const currentSpritePath = labels.includes(expression) ? sprites.find(x => x.label === expression)?.path : '';
196215
197 const path = currentSpritePath || defaultSpritePath || '';216 const spriteFile = chooseSpriteForExpression(memberSpriteFolderName, expression, { prevExpressionSrc: prevExpressionSrc });
198 const img = expressionImage.find('img');217 if (expressionImage.length) {
218 if (!spriteFolderName || spriteFolderName == memberSpriteFolderName) {
219 await validateImages(memberSpriteFolderName, true);
220 setExpressionOverrideHtml(true); // <= force clear expression override input
221 const path = spriteFile?.imageSrc || '';
222 img = expressionImage.find('img');
199 await setImage(img, path);223 await setImage(img, path);
200 }224 }
201 expressionImage.toggleClass('hidden', noSprites);225 expressionImage.toggleClass('hidden', !spriteFile);
202 } else {226 } else {
203 const template = $('#expression-holder').clone();227 const template = $('#expression-holder').clone();
204 template.attr('id', `expression-${avatar}`);228 template.attr('id', `expression-${avatar}`);
@@ -206,21 +230,49 @@ async function visualNovelSetCharacterSprites(container, name, expression) {
206 template.find('.drag-grabber').attr('id', `expression-${avatar}header`);230 template.find('.drag-grabber').attr('id', `expression-${avatar}header`);
207 $('#visual-novel-wrapper').append(template);231 $('#visual-novel-wrapper').append(template);
208 dragElement($(template[0]));232 dragElement($(template[0]));
209 template.toggleClass('hidden', noSprites);233 template.toggleClass('hidden', !spriteFile);
210 await setImage(template.find('img'), defaultSpritePath || '');234 img = template.find('img');
235 await setImage(img, spriteFile?.imageSrc || '');
211 const fadeInPromise = new Promise(resolve => {236 const fadeInPromise = new Promise(resolve => {
212 template.fadeIn(250, () => resolve());237 template.fadeIn(250, () => resolve());
213 });238 });
214 createCharacterPromises.push(fadeInPromise);239 setSpritePromises.push(fadeInPromise);
215 const setSpritePromise = setLastMessageSprite(template.find('img'), avatar, labels);
216 setSpritePromises.push(setSpritePromise);
217 }240 }
241
242 if (!img) {
243 continue;
244 }
245
246 img.attr('data-sprite-folder-name', spriteFolderName);
247 img.attr('data-expression', expression);
248 img.attr('data-sprite-filename', spriteFile?.fileName || null);
249 img.attr('title', expression);
250
251 if (spriteFile) console.info(`Expression set for group member ${character.name}`, { expression: spriteFile.expression, file: spriteFile.fileName });
252 else if (expressionImage.length) console.info(`Expression unset for group member ${character.name} - No sprite found`, { expression: expression });
253 else console.info(`Expression not available for group member ${character.name}`, { expression: expression });
218 }254 }
219255
220 await Promise.allSettled(createCharacterPromises);
221 return setSpritePromises;256 return setSpritePromises;
222}257}
223258
259/**
260 * Classifies the text of the latest message and returns the expression label.
261 * @param {string} avatar - The avatar of the character to get the last message for
262 * @returns {Promise<string>} - The expression label
263 */
264async function getLastMessageSprite(avatar) {
265 const context = getContext();
266 const lastMessage = context.chat.slice().reverse().find(x => x.original_avatar == avatar || (x.force_avatar && x.force_avatar.includes(encodeURIComponent(avatar))));
267
268 if (lastMessage) {
269 const text = lastMessage.mes || '';
270 return await getExpressionLabel(text);
271 }
272
273 return null;
274}
275
224async function visualNovelUpdateLayers(container) {276async function visualNovelUpdateLayers(container) {
225 const context = getContext();277 const context = getContext();
226 const group = context.groups.find(x => x.id == context.groupId);278 const group = context.groups.find(x => x.id == context.groupId);
@@ -256,11 +308,17 @@ async function visualNovelUpdateLayers(container) {
256 const containerWidth = container.width();308 const containerWidth = container.width();
257 const pivotalPoint = containerWidth * 0.5;309 const pivotalPoint = containerWidth * 0.5;
258310
259 let images = $('#visual-novel-wrapper .expression-holder');311 let images = Array.from($('#visual-novel-wrapper .expression-holder')).sort(sortFunction);
260 let imagesWidth = [];312 let imagesWidth = [];
261313
262 images.sort(sortFunction).each(function () {314 for (const image of images) {
263 imagesWidth.push($(this).width());315 if (image instanceof HTMLImageElement && !image.complete) {
316 await new Promise(resolve => image.addEventListener('load', resolve, { once: true }));
317 }
318 }
319
320 images.forEach(image => {
321 imagesWidth.push($(image).width());
264 });322 });
265323
266 let totalWidth = imagesWidth.reduce((a, b) => a + b, 0);324 let totalWidth = imagesWidth.reduce((a, b) => a + b, 0);
@@ -274,7 +332,7 @@ async function visualNovelUpdateLayers(container) {
274 currentPosition = 0; // Reset the initial position to 0332 currentPosition = 0; // Reset the initial position to 0
275 }333 }
276334
277 images.sort(sortFunction).each((index, current) => {335 images.forEach((current, index) => {
278 const element = $(current);336 const element = $(current);
279 const elementID = element.attr('id');337 const elementID = element.attr('id');
280338
@@ -294,9 +352,15 @@ async function visualNovelUpdateLayers(container) {
294 element.show();352 element.show();
295353
296 const promise = new Promise(resolve => {354 const promise = new Promise(resolve => {
355 if (power_user.reduced_motion) {
356 element.css('left', currentPosition + 'px');
357 requestAnimationFrame(() => resolve());
358 }
359 else {
297 element.animate({ left: currentPosition + 'px' }, 500, () => {360 element.animate({ left: currentPosition + 'px' }, 500, () => {
298 resolve();361 resolve();
299 });362 });
363 }
300 });364 });
301365
302 currentPosition += imagesWidth[index];366 currentPosition += imagesWidth[index];
@@ -307,23 +371,12 @@ async function visualNovelUpdateLayers(container) {
307 await Promise.allSettled(setLayerIndicesPromises);371 await Promise.allSettled(setLayerIndicesPromises);
308}372}
309373
310async function setLastMessageSprite(img, avatar, labels) {374/**
311 const context = getContext();375 * Sets the expression for the given character image.
312 const lastMessage = context.chat.slice().reverse().find(x => x.original_avatar == avatar || (x.force_avatar && x.force_avatar.includes(encodeURIComponent(avatar))));376 * @param {JQuery<HTMLElement>} img - The image element to set the image on
313377 * @param {string} path - The path to the image
314 if (lastMessage) {378 * @returns {Promise<void>} - A promise that resolves when the image is set
315 const text = lastMessage.mes || '';379 */
316 const spriteFolderName = getSpriteFolderName(lastMessage, lastMessage.name);
317 const sprites = spriteCache[spriteFolderName] || [];
318 const label = await getExpressionLabel(text);
319 const path = labels.includes(label) ? sprites.find(x => x.label === label)?.path : '';
320
321 if (path) {
322 setImage(img, path);
323 }
324 }
325}
326
327async function setImage(img, path) {380async function setImage(img, path) {
328 // Cohee: If something goes wrong, uncomment this to return to the old behavior381 // Cohee: If something goes wrong, uncomment this to return to the old behavior
329 /*382 /*
@@ -340,7 +393,7 @@ async function setImage(img, path) {
340 return new Promise(resolve => {393 return new Promise(resolve => {
341 const prevExpressionSrc = img.attr('src');394 const prevExpressionSrc = img.attr('src');
342 const expressionClone = img.clone();395 const expressionClone = img.clone();
343 const originalId = img.attr('id');396 const originalId = img.data('filename');
344397
345 //only swap expressions when necessary398 //only swap expressions when necessary
346 if (prevExpressionSrc !== path && !img.hasClass('expression-animating')) {399 if (prevExpressionSrc !== path && !img.hasClass('expression-animating')) {
@@ -348,7 +401,7 @@ async function setImage(img, path) {
348 expressionClone.addClass('expression-clone');401 expressionClone.addClass('expression-clone');
349 //make invisible and remove id to prevent double ids402 //make invisible and remove id to prevent double ids
350 //must be made invisible to start because they share the same Z-index403 //must be made invisible to start because they share the same Z-index
351 expressionClone.attr('id', '').css({ opacity: 0 });404 expressionClone.data('filename', '').css({ opacity: 0 });
352 //add new sprite path to clone src405 //add new sprite path to clone src
353 expressionClone.attr('src', path);406 expressionClone.attr('src', path);
354 //add invisible clone to html407 //add invisible clone to html
@@ -384,14 +437,18 @@ async function setImage(img, path) {
384 //remove old expression437 //remove old expression
385 img.remove();438 img.remove();
386 //replace ID so it becomes the new 'original' expression for next change439 //replace ID so it becomes the new 'original' expression for next change
387 expressionClone.attr('id', originalId);440 expressionClone.data('filename', originalId);
388 expressionClone.removeClass('expression-animating');441 expressionClone.removeClass('expression-animating');
389442
390 // Reset the expression holder min height and width443 // Reset the expression holder min height and width
391 expressionHolder.css('min-width', 100);444 expressionHolder.css('min-width', 100);
392 expressionHolder.css('min-height', 100);445 expressionHolder.css('min-height', 100);
393446
447 if (expressionClone.prop('complete')) {
394 resolve();448 resolve();
449 } else {
450 expressionClone.one('load', () => resolve());
451 }
395 });452 });
396453
397 expressionClone.removeClass('expression-clone');454 expressionClone.removeClass('expression-clone');
@@ -410,216 +467,9 @@ async function setImage(img, path) {
410 });467 });
411}468}
412469
413function onExpressionsShowDefaultInput() {470async function moduleWorker({ newChat = false } = {}) {
414 const value = $(this).prop('checked');
415 extension_settings.expressions.showDefault = value;
416 saveSettingsDebounced();
417
418 const existingImageSrc = $('img.expression').prop('src');
419 if (existingImageSrc !== undefined) { //if we have an image in src
420 if (!value && existingImageSrc.includes('/img/default-expressions/')) { //and that image is from /img/ (default)
421 $('img.expression').prop('src', ''); //remove it
422 lastMessage = null;
423 }
424 if (value) {
425 lastMessage = null;
426 }
427 }
428}
429
430/**
431 * Stops animating Talkinghead.
432 */
433async function unloadTalkingHead() {
434 if (!modules.includes('talkinghead')) {
435 console.debug('talkinghead module is disabled');
436 return;
437 }
438 console.debug('expressions: Stopping Talkinghead');
439
440 try {
441 const url = new URL(getApiUrl());
442 url.pathname = '/api/talkinghead/unload';
443 const loadResponse = await doExtrasFetch(url);
444 if (!loadResponse.ok) {
445 throw new Error(loadResponse.statusText);
446 }
447 //console.log(`Response: ${loadResponseText}`);
448 } catch (error) {
449 //console.error(`Error unloading - ${error}`);
450 }
451}
452
453/**
454 * Posts `talkinghead.png` of the current character to the talkinghead module in SillyTavern-extras, to start animating it.
455 */
456async function loadTalkingHead() {
457 if (!modules.includes('talkinghead')) {
458 console.debug('talkinghead module is disabled');
459 return;
460 }
461 console.debug('expressions: Starting Talkinghead');
462
463 const spriteFolderName = getSpriteFolderName();
464
465 const talkingheadPath = `/characters/${encodeURIComponent(spriteFolderName)}/talkinghead.png`;
466 const emotionsSettingsPath = `/characters/${encodeURIComponent(spriteFolderName)}/_emotions.json`;
467 const animatorSettingsPath = `/characters/${encodeURIComponent(spriteFolderName)}/_animator.json`;
468
469 try {
470 const spriteResponse = await fetch(talkingheadPath);
471
472 if (!spriteResponse.ok) {
473 throw new Error(spriteResponse.statusText);
474 }
475
476 const spriteBlob = await spriteResponse.blob();
477 const spriteFile = new File([spriteBlob], 'talkinghead.png', { type: 'image/png' });
478 const formData = new FormData();
479 formData.append('file', spriteFile);
480
481 const url = new URL(getApiUrl());
482 url.pathname = '/api/talkinghead/load';
483
484 const loadResponse = await doExtrasFetch(url, {
485 method: 'POST',
486 body: formData,
487 });
488
489 if (!loadResponse.ok) {
490 throw new Error(loadResponse.statusText);
491 }
492
493 const loadResponseText = await loadResponse.text();
494 console.log(`Load talkinghead response: ${loadResponseText}`);
495
496 // Optional: per-character emotion templates
497 let emotionsSettings;
498 try {
499 const emotionsResponse = await fetch(emotionsSettingsPath);
500 if (emotionsResponse.ok) {
501 emotionsSettings = await emotionsResponse.json();
502 console.log(`Loaded ${emotionsSettingsPath}`);
503 } else {
504 throw new Error();
505 }
506 }
507 catch (error) {
508 emotionsSettings = {}; // blank -> use server defaults (to unload the previous character's customizations)
509 console.log(`No valid config at ${emotionsSettingsPath}, using server defaults`);
510 }
511 try {
512 const url = new URL(getApiUrl());
513 url.pathname = '/api/talkinghead/load_emotion_templates';
514 const apiResult = await doExtrasFetch(url, {
515 method: 'POST',
516 headers: {
517 'Content-Type': 'application/json',
518 'Bypass-Tunnel-Reminder': 'bypass',
519 },
520 body: JSON.stringify(emotionsSettings),
521 });
522
523 if (!apiResult.ok) {
524 throw new Error(apiResult.statusText);
525 }
526 }
527 catch (error) {
528 // it's ok if not supported
529 console.log('Failed to send _emotions.json (backend too old?), ignoring');
530 }
531
532 // Optional: per-character animator and postprocessor config
533 let animatorSettings;
534 try {
535 const animatorResponse = await fetch(animatorSettingsPath);
536 if (animatorResponse.ok) {
537 animatorSettings = await animatorResponse.json();
538 console.log(`Loaded ${animatorSettingsPath}`);
539 } else {
540 throw new Error();
541 }
542 }
543 catch (error) {
544 animatorSettings = {}; // blank -> use server defaults (to unload the previous character's customizations)
545 console.log(`No valid config at ${animatorSettingsPath}, using server defaults`);
546 }
547 try {
548 const url = new URL(getApiUrl());
549 url.pathname = '/api/talkinghead/load_animator_settings';
550 const apiResult = await doExtrasFetch(url, {
551 method: 'POST',
552 headers: {
553 'Content-Type': 'application/json',
554 'Bypass-Tunnel-Reminder': 'bypass',
555 },
556 body: JSON.stringify(animatorSettings),
557 });
558
559 if (!apiResult.ok) {
560 throw new Error(apiResult.statusText);
561 }
562 }
563 catch (error) {
564 // it's ok if not supported
565 console.log('Failed to send _animator.json (backend too old?), ignoring');
566 }
567 } catch (error) {
568 console.error(`Error loading talkinghead image: ${talkingheadPath} - ${error}`);
569 }
570}
571
572function handleImageChange() {
573 const imgElement = document.querySelector('img#expression-image.expression');
574
575 if (!imgElement || !(imgElement instanceof HTMLImageElement)) {
576 console.log('Cannot find addExpressionImage()');
577 return;
578 }
579
580 if (isTalkingHeadEnabled() && modules.includes('talkinghead')) {
581 const talkingheadResultFeedSrc = `${getApiUrl()}/api/talkinghead/result_feed`;
582 $('#expression-holder').css({ display: '' });
583 if (imgElement.src !== talkingheadResultFeedSrc) {
584 const expressionImageElement = document.querySelector('.expression_list_image');
585
586 if (expressionImageElement && expressionImageElement instanceof HTMLImageElement) {
587 doExtrasFetch(expressionImageElement.src, {
588 method: 'HEAD',
589 })
590 .then(response => {
591 if (response.ok) {
592 imgElement.src = talkingheadResultFeedSrc;
593 }
594 })
595 .catch(error => {
596 console.error(error);
597 });
598 }
599 }
600 } else {
601 imgElement.src = ''; // remove in case char doesn't have expressions
602
603 // When switching Talkinghead off, force-set the character to the last known expression, if any.
604 // This preserves the same expression Talkinghead had at the moment it was switched off.
605 const charName = getContext().name2;
606 const last = lastExpression[charName];
607 const targetExpression = last ? last : getFallbackExpression();
608 setExpression(charName, targetExpression, true);
609 }
610}
611
612async function moduleWorker() {
613 const context = getContext();471 const context = getContext();
614472
615 // Hide and disable Talkinghead while not in extras
616 $('#image_type_block').toggle(extension_settings.expressions.api == EXPRESSION_API.extras);
617
618 if (extension_settings.expressions.api != EXPRESSION_API.extras && extension_settings.expressions.talkinghead) {
619 $('#image_type_toggle').prop('checked', false);
620 setTalkingHeadState(false);
621 }
622
623 // non-characters not supported473 // non-characters not supported
624 if (!context.groupId && context.characterId === undefined) {474 if (!context.groupId && context.characterId === undefined) {
625 removeExpression();475 removeExpression();
@@ -646,7 +496,7 @@ async function moduleWorker() {
646 }496 }
647497
648 const currentLastMessage = getLastCharacterMessage();498 const currentLastMessage = getLastCharacterMessage();
649 let spriteFolderName = context.groupId ? getSpriteFolderName(currentLastMessage, currentLastMessage.name) : getSpriteFolderName();499 let spriteFolderName = getSpriteFolderName(currentLastMessage, currentLastMessage.name);
650500
651 // character has no expressions or it is not loaded501 // character has no expressions or it is not loaded
652 if (Object.keys(spriteCache).length === 0) {502 if (Object.keys(spriteCache).length === 0) {
@@ -686,6 +536,10 @@ async function moduleWorker() {
686 offlineMode.css('display', 'none');536 offlineMode.css('display', 'none');
687 }537 }
public/scripts/extensions/expressions/list-item.html+0 -0
public/scripts/extensions/expressions/settings.html+0 -0
public/scripts/extensions/expressions/style.css+0 -0
public/scripts/extensions/expressions/templates/upload-expression.html+0 -0
public/scripts/extensions/gallery/index.js+0 -0
public/scripts/extensions/gallery/style.css+0 -0
public/scripts/extensions/memory/index.js+0 -0
public/scripts/extensions/memory/settings.html+0 -0
public/scripts/extensions/memory/style.css+0 -0
public/scripts/extensions/quick-reply/index.js+0 -0
public/scripts/extensions/regex/editor.html+0 -0
public/scripts/extensions/regex/engine.js+0 -0
public/scripts/extensions/regex/index.js+0 -0
public/scripts/extensions/regex/style.css+0 -0
public/scripts/extensions/shared.js+0 -0
public/scripts/extensions/stable-diffusion/index.js+0 -0
public/scripts/extensions/token-counter/index.js+0 -0
public/scripts/extensions/token-counter/window.html+0 -0
public/scripts/extensions/translate/index.js+0 -0
public/scripts/extensions/tts/alltalk.js+0 -0
public/scripts/extensions/tts/index.js+0 -0
public/scripts/extensions/tts/kokoro-worker.js+0 -0
public/scripts/extensions/tts/kokoro.js+0 -0
public/scripts/extensions/tts/lib/README.md+0 -0
public/scripts/extensions/tts/lib/kokoro.web.js+0 -0
public/scripts/extensions/tts/openai-compatible.js+0 -0
public/scripts/extensions/tts/readme.md+0 -0
public/scripts/extensions/tts/system.js+0 -0
public/scripts/extensions/vectors/index.js+0 -0
public/scripts/extensions/vectors/settings.html+0 -0
public/scripts/extensions/vectors/webllm.js+0 -0
public/scripts/group-chats.js+0 -0
public/scripts/horde.js+0 -0
public/scripts/i18n.js+0 -0
public/scripts/instruct-mode.js+0 -0
public/scripts/logprobs.js+0 -0
public/scripts/openai.js+0 -0
public/scripts/personas.js+0 -0
public/scripts/power-user.js+0 -0
public/scripts/preset-manager.js+0 -0
public/scripts/reasoning.js+0 -0
public/scripts/slash-commands.js+0 -0
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js+0 -0
public/scripts/sse-stream.js+0 -0
public/scripts/st-context.js+0 -0
public/scripts/tags.js+0 -0
public/scripts/templates/hotkeys.html+0 -0
public/scripts/templates/macros.html+0 -0
public/scripts/textgen-models.js+0 -0
public/scripts/textgen-settings.js+0 -0
public/scripts/tokenizers.js+0 -0
public/scripts/tool-calling.js+0 -0
public/scripts/utils.js+0 -0
public/scripts/world-info.js+0 -0
public/style.css+0 -0
server.js+0 -0
src/command-line.js+0 -0
src/electron/Start.bat+0 -0
src/electron/index.js+0 -0
src/electron/package-lock.json+0 -0
src/electron/package.json+0 -0
src/electron/start.sh+0 -0
src/endpoints/anthropic.js+0 -0
src/endpoints/assets.js+0 -0
src/endpoints/avatars.js+0 -0
src/endpoints/azure.js+0 -0
src/endpoints/backends/chat-completions.js+0 -0
src/endpoints/backends/kobold.js+0 -0
src/endpoints/backends/scale-alt.js+0 -0
src/endpoints/backends/text-completions.js+0 -0
src/endpoints/backgrounds.js+0 -0
src/endpoints/caption.js+0 -0
src/endpoints/characters.js+0 -0
src/endpoints/chats.js+0 -0
src/endpoints/classify.js+0 -0
src/endpoints/content-manager.js+0 -0
src/endpoints/extensions.js+0 -0
src/endpoints/files.js+0 -0
src/endpoints/google.js+0 -0
src/endpoints/groups.js+0 -0
src/endpoints/horde.js+0 -0
src/endpoints/images.js+0 -0
src/endpoints/moving-ui.js+0 -0
src/endpoints/novelai.js+0 -0
src/endpoints/openai.js+0 -0
src/endpoints/openrouter.js+0 -0
src/endpoints/presets.js+0 -0
src/endpoints/quick-replies.js+0 -0
src/endpoints/search.js+0 -0
src/endpoints/secrets.js+0 -0
src/endpoints/settings.js+0 -0
src/endpoints/speech.js+0 -0
src/endpoints/sprites.js+0 -0
src/endpoints/stable-diffusion.js+0 -0
src/endpoints/stats.js+0 -0
src/endpoints/themes.js+0 -0
src/endpoints/thumbnails.js+0 -0
src/endpoints/tokenizers.js+0 -0
src/endpoints/translate.js+0 -0
src/endpoints/users-admin.js+0 -0
src/endpoints/users-private.js+0 -0
src/endpoints/users-public.js+0 -0
src/endpoints/vectors.js+0 -0
src/endpoints/worldinfo.js+0 -0
src/express-common.js+0 -0
src/middleware/accessLogWriter.js+0 -0
src/middleware/basicAuth.js+0 -0
src/middleware/corsProxy.js+0 -0
src/middleware/webpack-serve.js+0 -0
src/middleware/whitelist.js+0 -0
src/plugin-loader.js+0 -0
src/prompt-converters.js+0 -0
src/server-events.js+0 -0
src/server-startup.js+0 -0
src/transformers.js+0 -0
src/users.js+0 -0
src/util.js+0 -0
tests/package-lock.json+0 -0
webpack.config.js+0 -0
Diff truncated