Merge branch 'staging' into disk-cache
| @@ -3,6 +3,9 @@ module.exports = { | |||
| 3 | extends: [ | 3 | extends: [ |
| 4 | 'eslint:recommended', | 4 | 'eslint:recommended', |
| 5 | ], | 5 | ], |
| 6 | plugins: [ | ||
| 7 | 'jsdoc', | ||
| 8 | ], | ||
| 6 | env: { | 9 | env: { |
| 7 | es6: true, | 10 | es6: true, |
| 8 | }, | 11 | }, |
| @@ -78,6 +81,7 @@ module.exports = { | |||
| 78 | 'public/scripts/extensions/tts/lib/**', | 81 | 'public/scripts/extensions/tts/lib/**', |
| 79 | ], | 82 | ], |
| 80 | rules: { | 83 | rules: { |
| 84 | 'jsdoc/no-undefined-types': ['warn', { disableReporting: true, markVariablesAsUsed: true }], | ||
| 81 | 'no-unused-vars': ['error', { args: 'none' }], | 85 | 'no-unused-vars': ['error', { args: 'none' }], |
| 82 | 'no-control-regex': 'off', | 86 | 'no-control-regex': 'off', |
| 83 | 'no-constant-condition': ['error', { checkLoops: false }], | 87 | 'no-constant-condition': ['error', { checkLoops: false }], |
| @@ -14,7 +14,7 @@ | |||
| 14 | - '(π§ Linux)' | 14 | - '(π§ Linux)' |
| 15 | 15 | ||
| 16 | π¦ Firefox: | 16 | π¦ Firefox: |
| 17 | - '(firefox|mozilla)' | 17 | - '\b(firefox|mozilla)\b' |
| 18 | 18 | ||
| 19 | π± Mobile: | 19 | π± Mobile: |
| 20 | - '(iphone|ios|android|π± Termux)' | 20 | - '\b(iphone|ios|android|π± Termux)\b' |
| @@ -34,6 +34,9 @@ | |||
| 34 | π¦ Firefox: | 34 | π¦ Firefox: |
| 35 | - head-branch: ['\bfirefox\b'] | 35 | - head-branch: ['\bfirefox\b'] |
| 36 | 36 | ||
| 37 | π§βπ€βπ§ Group Chat: | ||
| 38 | - head-branch: ['\bgroups?\b'] | ||
| 39 | |||
| 37 | πΌοΈ Image Gen: | 40 | πΌοΈ Image Gen: |
| 38 | - head-branch: ['\bimage-gen\b'] | 41 | - head-branch: ['\bimage-gen\b'] |
| 39 | 42 | ||
| @@ -58,6 +61,9 @@ | |||
| 58 | π Prompt: | 61 | π Prompt: |
| 59 | - head-branch: ['\bprompt\b'] | 62 | - head-branch: ['\bprompt\b'] |
| 60 | 63 | ||
| 64 | π§ Reasoning: | ||
| 65 | - head-branch: ['\breasoning\b', '\breason\b', '\bthinking\b'] | ||
| 66 | |||
| 61 | π Refactor: | 67 | π Refactor: |
| 62 | - head-branch: ['\brefactor(s|ed)?\b'] | 68 | - head-branch: ['\brefactor(s|ed)?\b'] |
| 63 | 69 | ||
| @@ -23,7 +23,7 @@ We have a [Documentation website](https://docs.sillytavern.app/) to answer most | |||
| 23 | 23 | ||
| 24 | SillyTavern (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. | 24 | SillyTavern (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. |
| 25 | 25 | ||
| 26 | Beginning in February 2023 as a fork of TavernAI 1.2.8, SillyTavern now has over 200 contributors and 3 years of independent development under its belt, and continues to serve as a leading software for savvy AI hobbyists. | 26 | Beginning 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. |
| 27 | 27 | ||
| 28 | ## Our Vision | 28 | ## Our Vision |
| 29 | 29 | ||
| @@ -192,28 +192,43 @@ You will need two mandatory directory mappings and a port mapping to allow Silly | |||
| 192 | 192 | ||
| 193 | ##### Volume Mappings | 193 | ##### Volume Mappings |
| 194 | 194 | ||
| 195 | * [config] - The directory where SillyTavern configuration files will be stored on your host machine | 195 | * `CONFIG_PATH` - 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 | 196 | * `DATA_PATH` - 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 | 197 | * `PLUGINS_PATH` - (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 | 198 | * `EXTENSIONS_PATH` - (optional) The directory where global UI extensions will be stored on your host machine |
| 199 | 199 | ||
| 200 | ##### Port Mappings | 200 | ##### Port Mappings |
| 201 | 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. | 202 | * `PUBLIC_PORT` - 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 | 203 | ||
| 204 | ##### Additional Settings | 204 | ##### Additional Settings |
| 205 | 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/). | 206 | * `SILLYTAVERN_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" that points to the nightly image the respective branch. |
| 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 | 207 | ||
| 209 | #### Install command | 208 | #### Running the container |
| 210 | 209 | ||
| 211 | 1. Open your Command Line | 210 | 1. Open your Command Line |
| 212 | 2. Run the following command | 211 | 2. Run the following command in a folder where you want to store the configuration and data files: |
| 213 | 212 | ||
| 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]'` | 213 | ```bash |
| 214 | SILLYTAVERN_VERSION="latest" | ||
| 215 | PUBLIC_PORT="8000" | ||
| 216 | CONFIG_PATH="./config" | ||
| 217 | DATA_PATH="./data" | ||
| 218 | PLUGINS_PATH="./plugins" | ||
| 219 | EXTENSIONS_PATH="./extensions" | ||
| 220 | |||
| 221 | docker run \ | ||
| 222 | --name="sillytavern" \ | ||
| 223 | -p "$PUBLIC_PORT:8000/tcp" \ | ||
| 224 | -v "$CONFIG_PATH:/home/node/app/config:rw" \ | ||
| 225 | -v "$DATA_PATH:/home/node/app/data:rw" \ | ||
| 226 | -v "$EXTENSIONS_PATH:/home/node/app/public/scripts/extensions/third-party:rw" \ | ||
| 227 | -v "$PLUGINS_PATH:/home/node/app/plugins:rw" \ | ||
| 228 | ghcr.io/sillytavern/sillytavern:"$SILLYTAVERN_VERSION" | ||
| 229 | ``` | ||
| 215 | 230 | ||
| 216 | > Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config. | 231 | > By default the container will run in the foreground. If you want to run it in the background, add the `-d` flag to the `docker run` command. |
| 217 | 232 | ||
| 218 | ### Building the image yourself | 233 | ### Building the image yourself |
| 219 | 234 | ||
| @@ -7,6 +7,10 @@ on: | |||
| 7 | issue_comment: | 7 | issue_comment: |
| 8 | types: [created] | 8 | types: [created] |
| 9 | 9 | ||
| 10 | permissions: | ||
| 11 | contents: read | ||
| 12 | issues: write | ||
| 13 | |||
| 10 | jobs: | 14 | jobs: |
| 11 | label-on-content: | 15 | label-on-content: |
| 12 | name: π·οΈ Label Issues by Content | 16 | name: π·οΈ Label Issues by Content |
| @@ -16,7 +20,7 @@ jobs: | |||
| 16 | - name: Checkout Repository | 20 | - name: Checkout Repository |
| 17 | # Checkout | 21 | # Checkout |
| 18 | # https://github.com/marketplace/actions/checkout | 22 | # https://github.com/marketplace/actions/checkout |
| 19 | uses: actions/checkout@v4 | 23 | uses: actions/checkout@v4.2.2 |
| 20 | 24 | ||
| 21 | - name: Auto-Label Issues (Based on Issue Content) | 25 | - 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) | 26 | # only auto label based on issue content once, on open (to prevent re-labeling removed labels) |
| @@ -24,11 +28,11 @@ jobs: | |||
| 24 | 28 | ||
| 25 | # Issue Labeler | 29 | # Issue Labeler |
| 26 | # https://github.com/marketplace/actions/regex-issue-labeler | 30 | # https://github.com/marketplace/actions/regex-issue-labeler |
| 27 | uses: github/issue-labeler@v3 | 31 | uses: github/issue-labeler@v3.4 |
| 28 | with: | 32 | with: |
| 29 | configuration-path: .github/issues-auto-labels.yml | 33 | configuration-path: .github/issues-auto-labels.yml |
| 30 | enable-versioned-regex: 0 | 34 | enable-versioned-regex: 0 |
| 31 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 35 | repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 32 | 36 | ||
| 33 | label-on-labels: | 37 | label-on-labels: |
| 34 | name: π·οΈ Label Issues by Labels | 38 | name: π·οΈ Label Issues by Labels |
| @@ -39,40 +43,40 @@ jobs: | |||
| 39 | if: contains(fromJSON('["π©βπ» Good First Issue", "π Help Wanted", "πͺ² Confirmed", "β οΈ High Priority", "β Medium Priority", "π€ Low Priority"]'), github.event.label.name) | 43 | if: contains(fromJSON('["π©βπ» Good First Issue", "π Help Wanted", "πͺ² Confirmed", "β οΈ High Priority", "β Medium Priority", "π€ Low Priority"]'), github.event.label.name) |
| 40 | # π€ Issues Helper | 44 | # π€ Issues Helper |
| 41 | # https://github.com/marketplace/actions/issues-helper | 45 | # https://github.com/marketplace/actions/issues-helper |
| 42 | uses: actions-cool/issues-helper@v3 | 46 | uses: actions-cool/issues-helper@v3.6.0 |
| 43 | with: | 47 | with: |
| 44 | actions: 'add-labels' | 48 | actions: 'add-labels' |
| 45 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 49 | token: ${{ secrets.GITHUB_TOKEN }} |
| 46 | labels: 'π Approved' | 50 | labels: 'π Approved' |
| 47 | 51 | ||
| 48 | - name: β Remove progress labels when issue is marked done or stale | 52 | - name: β Remove progress labels when issue is marked done or stale |
| 49 | if: contains(fromJSON('["β Done", "β Done (staging)", "β°οΈ Stale", "β wontfix"]'), github.event.label.name) | 53 | if: contains(fromJSON('["β Done", "β Done (staging)", "β°οΈ Stale", "β wontfix"]'), github.event.label.name) |
| 50 | # π€ Issues Helper | 54 | # π€ Issues Helper |
| 51 | # https://github.com/marketplace/actions/issues-helper | 55 | # https://github.com/marketplace/actions/issues-helper |
| 52 | uses: actions-cool/issues-helper@v3 | 56 | uses: actions-cool/issues-helper@v3.6.0 |
| 53 | with: | 57 | with: |
| 54 | actions: 'remove-labels' | 58 | actions: 'remove-labels' |
| 55 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 59 | token: ${{ secrets.GITHUB_TOKEN }} |
| 56 | labels: 'π§βπ» In Progress,π€ Unsure,π€ Under Consideration' | 60 | labels: 'π§βπ» In Progress,π€ Unsure,π€ Under Consideration' |
| 57 | 61 | ||
| 58 | - name: β Remove temporary labels when confirmed labels are added | 62 | - name: β Remove temporary labels when confirmed labels are added |
| 59 | if: contains(fromJSON('["β wontfix","π Approved","π©βπ» Good First Issue"]'), github.event.label.name) | 63 | if: contains(fromJSON('["β wontfix","π Approved","π©βπ» Good First Issue"]'), github.event.label.name) |
| 60 | # π€ Issues Helper | 64 | # π€ Issues Helper |
| 61 | # https://github.com/marketplace/actions/issues-helper | 65 | # https://github.com/marketplace/actions/issues-helper |
| 62 | uses: actions-cool/issues-helper@v3 | 66 | uses: actions-cool/issues-helper@v3.6.0 |
| 63 | with: | 67 | with: |
| 64 | actions: 'remove-labels' | 68 | actions: 'remove-labels' |
| 65 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 69 | token: ${{ secrets.GITHUB_TOKEN }} |
| 66 | labels: 'π€ Unsure,π€ Under Consideration' | 70 | labels: 'π€ Unsure,π€ Under Consideration' |
| 67 | 71 | ||
| 68 | - name: β Remove no bug labels when "πͺ² Confirmed" is added | 72 | - name: β Remove no bug labels when "πͺ² Confirmed" is added |
| 69 | if: github.event.label.name == 'πͺ² Confirmed' | 73 | if: github.event.label.name == 'πͺ² Confirmed' |
| 70 | # π€ Issues Helper | 74 | # π€ Issues Helper |
| 71 | # https://github.com/marketplace/actions/issues-helper | 75 | # https://github.com/marketplace/actions/issues-helper |
| 72 | uses: actions-cool/issues-helper@v3 | 76 | uses: actions-cool/issues-helper@v3.6.0 |
| 73 | with: | 77 | with: |
| 74 | actions: 'remove-labels' | 78 | actions: 'remove-labels' |
| 75 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 79 | token: ${{ secrets.GITHUB_TOKEN }} |
| 76 | labels: 'βοΈ Not Reproducible,βοΈ Not A Bug' | 80 | labels: 'βοΈ Not Reproducible,βοΈ Not A Bug' |
| 77 | 81 | ||
| 78 | remove-stale-label: | 82 | remove-stale-label: |
| @@ -85,10 +89,10 @@ jobs: | |||
| 85 | - name: Remove Stale Label | 89 | - name: Remove Stale Label |
| 86 | # π€ Issues Helper | 90 | # π€ Issues Helper |
| 87 | # https://github.com/marketplace/actions/issues-helper | 91 | # https://github.com/marketplace/actions/issues-helper |
| 88 | uses: actions-cool/issues-helper@v3 | 92 | uses: actions-cool/issues-helper@v3.6.0 |
| 89 | with: | 93 | with: |
| 90 | actions: 'remove-labels' | 94 | actions: 'remove-labels' |
| 91 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 95 | token: ${{ secrets.GITHUB_TOKEN }} |
| 92 | issue-number: ${{ github.event.issue.number }} | 96 | issue-number: ${{ github.event.issue.number }} |
| 93 | labels: 'β°οΈ Stale,πΈοΈ Inactive,π Awaiting User Response,π No Response' | 97 | labels: 'β°οΈ Stale,πΈοΈ Inactive,π Awaiting User Response,π No Response' |
| 94 | 98 | ||
| @@ -101,12 +105,12 @@ jobs: | |||
| 101 | - name: Checkout Repository | 105 | - name: Checkout Repository |
| 102 | # Checkout | 106 | # Checkout |
| 103 | # https://github.com/marketplace/actions/checkout | 107 | # https://github.com/marketplace/actions/checkout |
| 104 | uses: actions/checkout@v4 | 108 | uses: actions/checkout@v4.2.2 |
| 105 | 109 | ||
| 106 | - name: Post Issue Comments Based on Labels | 110 | - name: Post Issue Comments Based on Labels |
| 107 | # Label Commenter | 111 | # Label Commenter |
| 108 | # https://github.com/marketplace/actions/label-commenter | 112 | # https://github.com/marketplace/actions/label-commenter |
| 109 | uses: peaceiris/actions-label-commenter@v1 | 113 | uses: peaceiris/actions-label-commenter@v1.10.0 |
| 110 | with: | 114 | with: |
| 111 | config_file: .github/issues-auto-comments.yml | 115 | config_file: .github/issues-auto-comments.yml |
| 112 | github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 116 | github_token: ${{ secrets.GITHUB_TOKEN }} |
| @@ -6,6 +6,10 @@ on: | |||
| 6 | - staging | 6 | - staging |
| 7 | - release | 7 | - release |
| 8 | 8 | ||
| 9 | permissions: | ||
| 10 | contents: read | ||
| 11 | issues: write | ||
| 12 | |||
| 9 | jobs: | 13 | jobs: |
| 10 | # This runs commits to staging/release, reading the commit messages. Check `pr-auto-manager.yml`:`update-linked-issues` for PR-linked updates. | 14 | # 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: | 15 | update-linked-issues: |
| @@ -16,18 +20,18 @@ jobs: | |||
| 16 | - name: Checkout Repository | 20 | - name: Checkout Repository |
| 17 | # Checkout | 21 | # Checkout |
| 18 | # https://github.com/marketplace/actions/checkout | 22 | # https://github.com/marketplace/actions/checkout |
| 19 | uses: actions/checkout@v4 | 23 | uses: actions/checkout@v4.2.2 |
| 20 | 24 | ||
| 21 | - name: Extract Linked Issues from Commit Message | 25 | - name: Extract Linked Issues from Commit Message |
| 22 | id: extract_issues | 26 | id: extract_issues |
| 23 | run: | | 27 | 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]') | 28 | ISSUES=$(git log ${{ github.event.before }}..${{ github.event.after }} --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 | 29 | echo "issues=$ISSUES" >> $GITHUB_ENV |
| 26 | 30 | ||
| 27 | - name: Label Linked Issues | 31 | - name: Label Linked Issues |
| 28 | id: label_linked_issues | 32 | id: label_linked_issues |
| 29 | env: | 33 | env: |
| 30 | GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 34 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 31 | run: | | 35 | run: | |
| 32 | for ISSUE in $(echo $issues | jq -r '.[]'); do | 36 | for ISSUE in $(echo $issues | jq -r '.[]'); do |
| 33 | if [ "${{ github.ref }}" == "refs/heads/staging" ]; then | 37 | if [ "${{ github.ref }}" == "refs/heads/staging" ]; then |
| @@ -6,6 +6,11 @@ on: | |||
| 6 | schedule: | 6 | schedule: |
| 7 | - cron: '0 0 * * *' # Runs every day at midnight UTC | 7 | - cron: '0 0 * * *' # Runs every day at midnight UTC |
| 8 | 8 | ||
| 9 | permissions: | ||
| 10 | contents: read | ||
| 11 | issues: write | ||
| 12 | pull-requests: write | ||
| 13 | |||
| 9 | jobs: | 14 | jobs: |
| 10 | mark-inactivity: | 15 | mark-inactivity: |
| 11 | name: β³ Mark Issues/PRs without Activity | 16 | name: β³ Mark Issues/PRs without Activity |
| @@ -15,9 +20,9 @@ jobs: | |||
| 15 | - name: Mark Issues/PRs without Activity | 20 | - name: Mark Issues/PRs without Activity |
| 16 | # Close Stale Issues and PRs | 21 | # Close Stale Issues and PRs |
| 17 | # https://github.com/marketplace/actions/close-stale-issues | 22 | # https://github.com/marketplace/actions/close-stale-issues |
| 18 | uses: actions/stale@v9 | 23 | uses: actions/stale@v9.1.0 |
| 19 | with: | 24 | with: |
| 20 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 25 | repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 21 | days-before-stale: 183 | 26 | days-before-stale: 183 |
| 22 | days-before-close: 7 | 27 | days-before-close: 7 |
| 23 | operations-per-run: 30 | 28 | operations-per-run: 30 |
| @@ -49,9 +54,9 @@ jobs: | |||
| 49 | - name: Mark Issues/PRs Awaiting User Response | 54 | - name: Mark Issues/PRs Awaiting User Response |
| 50 | # Close Stale Issues and PRs | 55 | # Close Stale Issues and PRs |
| 51 | # https://github.com/marketplace/actions/close-stale-issues | 56 | # https://github.com/marketplace/actions/close-stale-issues |
| 52 | uses: actions/stale@v9 | 57 | uses: actions/stale@v9.1.0 |
| 53 | with: | 58 | with: |
| 54 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 59 | repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 55 | days-before-stale: 7 | 60 | days-before-stale: 7 |
| 56 | days-before-close: 7 | 61 | days-before-close: 7 |
| 57 | operations-per-run: 30 | 62 | operations-per-run: 30 |
| @@ -76,9 +81,9 @@ jobs: | |||
| 76 | - name: Mark Issues with Alternative Exists | 81 | - name: Mark Issues with Alternative Exists |
| 77 | # Close Stale Issues and PRs | 82 | # Close Stale Issues and PRs |
| 78 | # https://github.com/marketplace/actions/close-stale-issues | 83 | # https://github.com/marketplace/actions/close-stale-issues |
| 79 | uses: actions/stale@v9 | 84 | uses: actions/stale@v9.1.0 |
| 80 | with: | 85 | with: |
| 81 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 86 | repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 82 | days-before-stale: 7 | 87 | days-before-stale: 7 |
| 83 | days-before-close: 7 | 88 | days-before-close: 7 |
| 84 | operations-per-run: 30 | 89 | operations-per-run: 30 |
| @@ -6,6 +6,11 @@ on: | |||
| 6 | pull_request_target: | 6 | pull_request_target: |
| 7 | types: [closed] | 7 | types: [closed] |
| 8 | 8 | ||
| 9 | permissions: | ||
| 10 | contents: read | ||
| 11 | issues: write | ||
| 12 | pull-requests: write | ||
| 13 | |||
| 9 | jobs: | 14 | jobs: |
| 10 | remove-labels: | 15 | remove-labels: |
| 11 | name: ποΈ Remove Pending Labels on Close | 16 | name: ποΈ Remove Pending Labels on Close |
| @@ -15,9 +20,9 @@ jobs: | |||
| 15 | - name: Remove Pending Labels on Close | 20 | - name: Remove Pending Labels on Close |
| 16 | # π€ Issues Helper | 21 | # π€ Issues Helper |
| 17 | # https://github.com/marketplace/actions/issues-helper | 22 | # https://github.com/marketplace/actions/issues-helper |
| 18 | uses: actions-cool/issues-helper@v3 | 23 | uses: actions-cool/issues-helper@v3.6.0 |
| 19 | with: | 24 | with: |
| 20 | actions: remove-labels | 25 | actions: remove-labels |
| 21 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 26 | token: ${{ secrets.GITHUB_TOKEN }} |
| 22 | issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} | 27 | 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' | 28 | labels: 'π Awaiting User Response,π§βπ» In Progress,π Keep Open,π« Merge Conflicts,π¬ Needs Testing,π¨ Needs Work,β°οΈ Stale,β Waiting For External/Upstream' |
| @@ -6,6 +6,11 @@ on: | |||
| 6 | pull_request_target: | 6 | pull_request_target: |
| 7 | types: [opened] | 7 | types: [opened] |
| 8 | 8 | ||
| 9 | permissions: | ||
| 10 | contents: read | ||
| 11 | issues: write | ||
| 12 | pull-requests: write | ||
| 13 | |||
| 9 | jobs: | 14 | jobs: |
| 10 | label-maintainer: | 15 | label-maintainer: |
| 11 | name: π·οΈ Label if Author is a Repo Maintainer | 16 | name: π·οΈ Label if Author is a Repo Maintainer |
| @@ -16,9 +21,9 @@ jobs: | |||
| 16 | - name: Label if Author is a Repo Maintainer | 21 | - name: Label if Author is a Repo Maintainer |
| 17 | # π€ Issues Helper | 22 | # π€ Issues Helper |
| 18 | # https://github.com/marketplace/actions/issues-helper | 23 | # https://github.com/marketplace/actions/issues-helper |
| 19 | uses: actions-cool/issues-helper@v3 | 24 | uses: actions-cool/issues-helper@v3.6.0 |
| 20 | with: | 25 | with: |
| 21 | actions: 'add-labels' | 26 | actions: 'add-labels' |
| 22 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 27 | token: ${{ secrets.GITHUB_TOKEN }} |
| 23 | issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} | 28 | issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} |
| 24 | labels: 'π· Maintainer' | 29 | labels: 'π· Maintainer' |
| @@ -6,18 +6,67 @@ on: | |||
| 6 | pull_request_review_comment: | 6 | pull_request_review_comment: |
| 7 | types: [created] | 7 | types: [created] |
| 8 | 8 | ||
| 9 | permissions: | ||
| 10 | contents: read | ||
| 11 | pull-requests: write | ||
| 12 | |||
| 9 | jobs: | 13 | jobs: |
| 14 | run-eslint: | ||
| 15 | name: β Check ESLint on PR | ||
| 16 | runs-on: ubuntu-latest | ||
| 17 | # Only needs to run when code is changed | ||
| 18 | if: github.event.action == 'opened' || github.event.action == 'synchronize' | ||
| 19 | |||
| 20 | steps: | ||
| 21 | - name: Checkout Repository | ||
| 22 | # Checkout | ||
| 23 | # https://github.com/marketplace/actions/checkout | ||
| 24 | uses: actions/checkout@v4.2.2 | ||
| 25 | |||
| 26 | - name: Setup Node.js | ||
| 27 | # Setup Node.js environment | ||
| 28 | # https://github.com/marketplace/actions/setup-node-js-environment | ||
| 29 | uses: actions/setup-node@v4.3.0 | ||
| 30 | with: | ||
| 31 | node-version: 20 | ||
| 32 | |||
| 33 | - name: Run npm install | ||
| 34 | run: npm ci | ||
| 35 | |||
| 36 | - name: Run ESLint | ||
| 37 | # Action ESLint | ||
| 38 | # https://github.com/marketplace/actions/action-eslint | ||
| 39 | uses: sibiraj-s/action-eslint@v3.0.1 | ||
| 40 | with: | ||
| 41 | token: ${{ secrets.GITHUB_TOKEN }} | ||
| 42 | eslint-args: '--ignore-path=.gitignore --quiet' | ||
| 43 | extensions: 'js,ts' | ||
| 44 | annotations: true | ||
| 45 | ignore-patterns: | | ||
| 46 | dist/ | ||
| 47 | lib/ | ||
| 48 | |||
| 10 | label-by-size: | 49 | label-by-size: |
| 11 | name: π·οΈ Label PR by Size | 50 | name: π·οΈ Label PR by Size |
| 51 | # This job should run after all others, to prevent possible concurrency issues | ||
| 52 | needs: [label-by-branches, label-by-files, remove-stale-label, check-merge-blocking-labels, write-auto-comments] | ||
| 12 | runs-on: ubuntu-latest | 53 | runs-on: ubuntu-latest |
| 54 | # Only needs to run when code is changed | ||
| 55 | if: always() && (github.event.action == 'opened' || github.event.action == 'synchronize') | ||
| 56 | |||
| 57 | # Override permissions, the labeler needs issues write access | ||
| 58 | permissions: | ||
| 59 | contents: read | ||
| 60 | issues: write | ||
| 61 | pull-requests: write | ||
| 13 | 62 | ||
| 14 | steps: | 63 | steps: |
| 15 | - name: Label PR Size | 64 | - name: Label PR Size |
| 16 | # Pull Request Size Labeler | 65 | # Pull Request Size Labeler |
| 17 | # https://github.com/marketplace/actions/pull-request-size-labeler | 66 | # https://github.com/marketplace/actions/pull-request-size-labeler |
| 18 | uses: codelytv/pr-size-labeler@v1 | 67 | uses: codelytv/pr-size-labeler@v1.10.2 |
| 19 | with: | 68 | with: |
| 20 | GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 21 | xs_label: 'π© ⬀ββββ' | 70 | xs_label: 'π© ⬀ββββ' |
| 22 | xs_max_size: '20' | 71 | xs_max_size: '20' |
| 23 | s_label: 'π© ⬀⬀βββ' | 72 | s_label: 'π© ⬀⬀βββ' |
| @@ -28,7 +77,6 @@ jobs: | |||
| 28 | l_max_size: '1000' | 77 | l_max_size: '1000' |
| 29 | xl_label: 'π₯ ⬀⬀⬀⬀⬀' | 78 | xl_label: 'π₯ ⬀⬀⬀⬀⬀' |
| 30 | fail_if_xl: 'false' | 79 | fail_if_xl: 'false' |
| 31 | github_api_url: 'https://api.github.com' | ||
| 32 | files_to_ignore: | | 80 | files_to_ignore: | |
| 33 | "package-lock.json" | 81 | "package-lock.json" |
| 34 | "public/lib/*" | 82 | "public/lib/*" |
| @@ -36,55 +84,63 @@ jobs: | |||
| 36 | label-by-branches: | 84 | label-by-branches: |
| 37 | name: π·οΈ Label PR by Branches | 85 | name: π·οΈ Label PR by Branches |
| 38 | runs-on: ubuntu-latest | 86 | runs-on: ubuntu-latest |
| 39 | # Only label once when PR is created or branches are changed, to allow manual label removal | 87 | # Only label once when PR is created or when base branch is changed, to allow manual label removal |
| 40 | if: github.event.action == 'opened' || (github.event.action == 'synchronize' && (github.event.changes.base || github.event.changes.head)) | 88 | if: github.event.action == 'opened' || (github.event.action == 'synchronize' && github.event.changes.base) |
| 41 | 89 | ||
| 42 | steps: | 90 | steps: |
| 43 | - name: Checkout Repository | 91 | - name: Checkout Repository |
| 44 | # Checkout | 92 | # Checkout |
| 45 | # https://github.com/marketplace/actions/checkout | 93 | # https://github.com/marketplace/actions/checkout |
| 46 | uses: actions/checkout@v4 | 94 | uses: actions/checkout@v4.2.2 |
| 47 | 95 | ||
| 48 | - name: Apply Labels Based on Branch Name and Target Branch | 96 | - name: Apply Labels Based on Branch Name and Target Branch |
| 49 | # Pull Request Labeler | 97 | # Pull Request Labeler |
| 50 | # https://github.com/marketplace/actions/labeler | 98 | # https://github.com/marketplace/actions/labeler |
| 51 | uses: actions/labeler@v5 | 99 | uses: actions/labeler@v5.0.0 |
| 52 | with: | 100 | with: |
| 53 | configuration-path: .github/pr-auto-labels-by-branch.yml | 101 | configuration-path: .github/pr-auto-labels-by-branch.yml |
| 54 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 102 | repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 55 | 103 | ||
| 56 | label-by-files: | 104 | label-by-files: |
| 57 | name: π·οΈ Label PR by Files | 105 | name: π·οΈ Label PR by Files |
| 58 | runs-on: ubuntu-latest | 106 | runs-on: ubuntu-latest |
| 107 | # Only needs to run when code is changed | ||
| 108 | if: github.event.action == 'opened' || github.event.action == 'synchronize' | ||
| 59 | 109 | ||
| 60 | steps: | 110 | steps: |
| 61 | - name: Checkout Repository | 111 | - name: Checkout Repository |
| 62 | # Checkout | 112 | # Checkout |
| 63 | # https://github.com/marketplace/actions/checkout | 113 | # https://github.com/marketplace/actions/checkout |
| 64 | uses: actions/checkout@v4 | 114 | uses: actions/checkout@v4.2.2 |
| 65 | 115 | ||
| 66 | - name: Apply Labels Based on Changed Files | 116 | - name: Apply Labels Based on Changed Files |
| 67 | # Pull Request Labeler | 117 | # Pull Request Labeler |
| 68 | # https://github.com/marketplace/actions/labeler | 118 | # https://github.com/marketplace/actions/labeler |
| 69 | uses: actions/labeler@v5 | 119 | uses: actions/labeler@v5.0.0 |
| 70 | with: | 120 | with: |
| 71 | configuration-path: .github/pr-auto-labels-by-files.yml | 121 | configuration-path: .github/pr-auto-labels-by-files.yml |
| 72 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 122 | repo-token: ${{ secrets.GITHUB_TOKEN }} |
| 73 | 123 | ||
| 74 | remove-stale-label: | 124 | remove-stale-label: |
| 75 | name: ποΈ Remove Stale Label on Comment | 125 | name: ποΈ Remove Stale Label on Comment |
| 76 | runs-on: ubuntu-latest | 126 | runs-on: ubuntu-latest |
| 77 | # Only runs when this is not done by the github actions bot | 127 | # Only runs on comments not done by the github actions bot |
| 78 | if: github.actor != 'github-actions[bot]' | 128 | if: github.event_name == 'pull_request_review_comment' && github.actor != 'github-actions[bot]' |
| 129 | |||
| 130 | # Override permissions, issue labeler needs issues write access | ||
| 131 | permissions: | ||
| 132 | contents: read | ||
| 133 | issues: write | ||
| 134 | pull-requests: write | ||
| 79 | 135 | ||
| 80 | steps: | 136 | steps: |
| 81 | - name: Remove Stale Label | 137 | - name: Remove Stale Label |
| 82 | # π€ Issues Helper | 138 | # π€ Issues Helper |
| 83 | # https://github.com/marketplace/actions/issues-helper | 139 | # https://github.com/marketplace/actions/issues-helper |
| 84 | uses: actions-cool/issues-helper@v3 | 140 | uses: actions-cool/issues-helper@v3.6.0 |
| 85 | with: | 141 | with: |
| 86 | actions: 'remove-labels' | 142 | actions: 'remove-labels' |
| 87 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 143 | token: ${{ secrets.GITHUB_TOKEN }} |
| 88 | issue-number: ${{ github.event.pull_request.number }} | 144 | issue-number: ${{ github.event.pull_request.number }} |
| 89 | labels: 'β°οΈ Stale' | 145 | labels: 'β°οΈ Stale' |
| 90 | 146 | ||
| @@ -95,12 +151,18 @@ jobs: | |||
| 95 | # Run, even if the previous jobs were skipped/failed | 151 | # Run, even if the previous jobs were skipped/failed |
| 96 | if: always() | 152 | if: always() |
| 97 | 153 | ||
| 154 | # Override permissions, as this needs to write a check | ||
| 155 | permissions: | ||
| 156 | checks: write | ||
| 157 | contents: read | ||
| 158 | pull-requests: read | ||
| 159 | |||
| 98 | steps: | 160 | steps: |
| 99 | - name: Check Merge Blocking | 161 | - name: Check Merge Blocking |
| 100 | # GitHub Script | 162 | # GitHub Script |
| 101 | # https://github.com/marketplace/actions/github-scriptLabels | 163 | # https://github.com/marketplace/actions/github-script |
| 102 | id: label-check | 164 | id: label-check |
| 103 | uses: actions/github-script@v7 | 165 | uses: actions/github-script@v7.0.1 |
| 104 | with: | 166 | with: |
| 105 | script: | | 167 | script: | |
| 106 | const prLabels = context.payload.pull_request.labels.map(label => label.name); | 168 | const prLabels = context.payload.pull_request.labels.map(label => label.name); |
| @@ -134,7 +196,7 @@ jobs: | |||
| 134 | 196 | ||
| 135 | write-auto-comments: | 197 | write-auto-comments: |
| 136 | name: π¬ Post PR Comments Based on Labels | 198 | name: π¬ Post PR Comments Based on Labels |
| 137 | needs: [label-by-size, label-by-branches, label-by-files] | 199 | needs: [label-by-branches, label-by-files] |
| 138 | runs-on: ubuntu-latest | 200 | runs-on: ubuntu-latest |
| 139 | # Run, even if the previous jobs were skipped/failed | 201 | # Run, even if the previous jobs were skipped/failed |
| 140 | if: always() | 202 | if: always() |
| @@ -143,15 +205,15 @@ jobs: | |||
| 143 | - name: Checkout Repository | 205 | - name: Checkout Repository |
| 144 | # Checkout | 206 | # Checkout |
| 145 | # https://github.com/marketplace/actions/checkout | 207 | # https://github.com/marketplace/actions/checkout |
| 146 | uses: actions/checkout@v4 | 208 | uses: actions/checkout@v4.2.2 |
| 147 | 209 | ||
| 148 | - name: Post PR Comments Based on Labels | 210 | - name: Post PR Comments Based on Labels |
| 149 | # Label Commenter for PRs | 211 | # Label Commenter for PRs |
| 150 | # https://github.com/marketplace/actions/label-commenter | 212 | # https://github.com/marketplace/actions/label-commenter |
| 151 | uses: peaceiris/actions-label-commenter@v1 | 213 | uses: peaceiris/actions-label-commenter@v1.10.0 |
| 152 | with: | 214 | with: |
| 153 | config_file: .github/pr-auto-comments.yml | 215 | config_file: .github/pr-auto-comments.yml |
| 154 | github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 216 | github_token: ${{ secrets.GITHUB_TOKEN }} |
| 155 | 217 | ||
| 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. | 218 | # 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: | 219 | update-linked-issues: |
| @@ -159,6 +221,12 @@ jobs: | |||
| 159 | runs-on: ubuntu-latest | 221 | runs-on: ubuntu-latest |
| 160 | if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'staging' | 222 | if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'staging' |
| 161 | 223 | ||
| 224 | # Override permissions, We need to be able to write to issues | ||
| 225 | permissions: | ||
| 226 | contents: read | ||
| 227 | issues: write | ||
| 228 | pull-requests: write | ||
| 229 | |||
| 162 | steps: | 230 | steps: |
| 163 | - name: Extract Linked Issues From PR Description | 231 | - name: Extract Linked Issues From PR Description |
| 164 | id: extract_issues | 232 | id: extract_issues |
| @@ -172,7 +240,7 @@ jobs: | |||
| 172 | PR_NUMBER=${{ github.event.pull_request.number }} | 240 | PR_NUMBER=${{ github.event.pull_request.number }} |
| 173 | REPO=${{ github.repository }} | 241 | REPO=${{ github.repository }} |
| 174 | API_URL="https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/issues" | 242 | 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]') | 243 | ISSUES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" "$API_URL" | jq -r '.[].number' | jq -R -s -c 'split("\n")[:-1]') |
| 176 | echo "linked_issues=$ISSUES" >> $GITHUB_ENV | 244 | echo "linked_issues=$ISSUES" >> $GITHUB_ENV |
| 177 | 245 | ||
| 178 | - name: Merge Issue Lists | 246 | - name: Merge Issue Lists |
| @@ -184,7 +252,7 @@ jobs: | |||
| 184 | - name: Label Linked Issues | 252 | - name: Label Linked Issues |
| 185 | id: label_linked_issues | 253 | id: label_linked_issues |
| 186 | env: | 254 | env: |
| 187 | GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 255 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 188 | run: | | 256 | run: | |
| 189 | for ISSUE in $(echo $final_issues | jq -r '.[]'); do | 257 | for ISSUE in $(echo $final_issues | jq -r '.[]'); do |
| 190 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "β Done (staging)" | 258 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "β Done (staging)" |
| @@ -7,6 +7,10 @@ on: | |||
| 7 | pull_request_target: | 7 | pull_request_target: |
| 8 | types: [synchronize] | 8 | types: [synchronize] |
| 9 | 9 | ||
| 10 | permissions: | ||
| 11 | contents: read | ||
| 12 | pull-requests: write | ||
| 13 | |||
| 10 | jobs: | 14 | jobs: |
| 11 | check-merge-conflicts: | 15 | check-merge-conflicts: |
| 12 | name: βοΈ Check Merge Conflicts | 16 | name: βοΈ Check Merge Conflicts |
| @@ -16,9 +20,9 @@ jobs: | |||
| 16 | - name: Check Merge Conflicts | 20 | - name: Check Merge Conflicts |
| 17 | # Label Conflicting Pull Requests | 21 | # Label Conflicting Pull Requests |
| 18 | # https://github.com/marketplace/actions/label-conflicting-pull-requests | 22 | # https://github.com/marketplace/actions/label-conflicting-pull-requests |
| 19 | uses: eps1lon/actions-label-merge-conflict@v3 | 23 | uses: eps1lon/actions-label-merge-conflict@v3.0.3 |
| 20 | with: | 24 | with: |
| 21 | dirtyLabel: 'π« Merge Conflicts' | 25 | dirtyLabel: 'π« Merge Conflicts' |
| 22 | repoToken: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | 26 | repoToken: ${{ secrets.GITHUB_TOKEN }} |
| 23 | commentOnDirty: > | 27 | commentOnDirty: > |
| 24 | β οΈ This PR has conflicts that need to be resolved before it can be merged. | 28 | β οΈ This PR has conflicts that need to be resolved before it can be merged. |
| @@ -114,6 +114,8 @@ backups: | |||
| 114 | chat: | 114 | chat: |
| 115 | # Enable automatic chat backups | 115 | # Enable automatic chat backups |
| 116 | enabled: true | 116 | enabled: true |
| 117 | # Verify integrity of chat files before saving | ||
| 118 | checkIntegrity: true | ||
| 117 | # Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups. | 119 | # Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups. |
| 118 | maxTotalBackups: -1 | 120 | maxTotalBackups: -1 |
| 119 | # Interval in milliseconds to throttle chat backups per user | 121 | # Interval in milliseconds to throttle chat backups per user |
| @@ -786,5 +786,13 @@ | |||
| 786 | { | 786 | { |
| 787 | "filename": "presets/context/DeepSeek-V2.5.json", | 787 | "filename": "presets/context/DeepSeek-V2.5.json", |
| 788 | "type": "context" | 788 | "type": "context" |
| 789 | }, | ||
| 790 | { | ||
| 791 | "filename": "presets/reasoning/DeepSeek.json", | ||
| 792 | "type": "reasoning" | ||
| 793 | }, | ||
| 794 | { | ||
| 795 | "filename": "presets/reasoning/Blank.json", | ||
| 796 | "type": "reasoning" | ||
| 789 | } | 797 | } |
| 790 | ] | 798 | ] |
| @@ -0,0 +1,6 @@ | |||
| 1 | { | ||
| 2 | "name": "Blank", | ||
| 3 | "prefix": "", | ||
| 4 | "suffix": "", | ||
| 5 | "separator": "" | ||
| 6 | } | ||
| @@ -0,0 +1,6 @@ | |||
| 1 | { | ||
| 2 | "name": "DeepSeek", | ||
| 3 | "prefix": "<think>\n", | ||
| 4 | "suffix": "\n</think>", | ||
| 5 | "separator": "\n\n" | ||
| 6 | } | ||
| @@ -110,7 +110,8 @@ | |||
| 110 | "@types/write-file-atomic": "^4.0.3", | 110 | "@types/write-file-atomic": "^4.0.3", |
| 111 | "@types/yargs": "^17.0.33", | 111 | "@types/yargs": "^17.0.33", |
| 112 | "@types/yauzl": "^2.10.3", | 112 | "@types/yauzl": "^2.10.3", |
| 113 | "eslint": "^8.57.1" | 113 | "eslint": "^8.57.1", |
| 114 | "eslint-plugin-jsdoc": "^48.10.0" | ||
| 114 | }, | 115 | }, |
| 115 | "engines": { | 116 | "engines": { |
| 116 | "node": ">= 18" | 117 | "node": ">= 18" |
| @@ -147,6 +148,21 @@ | |||
| 147 | "integrity": "sha512-KlmTftToTtmb6aLVdne4NluS+POWputPF5J8v25UN/EQS+K9vahWEIe1NPRSFqBQclObkqHaj7JOnFrmnSm5MA==", | 148 | "integrity": "sha512-KlmTftToTtmb6aLVdne4NluS+POWputPF5J8v25UN/EQS+K9vahWEIe1NPRSFqBQclObkqHaj7JOnFrmnSm5MA==", |
| 148 | "license": "Apache-2.0" | 149 | "license": "Apache-2.0" |
| 149 | }, | 150 | }, |
| 151 | "node_modules/@es-joy/jsdoccomment": { | ||
| 152 | "version": "0.46.0", | ||
| 153 | "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", | ||
| 154 | "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", | ||
| 155 | "dev": true, | ||
| 156 | "license": "MIT", | ||
| 157 | "dependencies": { | ||
| 158 | "comment-parser": "1.4.1", | ||
| 159 | "esquery": "^1.6.0", | ||
| 160 | "jsdoc-type-pratt-parser": "~4.0.0" | ||
| 161 | }, | ||
| 162 | "engines": { | ||
| 163 | "node": ">=16" | ||
| 164 | } | ||
| 165 | }, | ||
| 150 | "node_modules/@eslint-community/eslint-utils": { | 166 | "node_modules/@eslint-community/eslint-utils": { |
| 151 | "version": "4.4.0", | 167 | "version": "4.4.0", |
| 152 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", | 168 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", |
| @@ -970,6 +986,19 @@ | |||
| 970 | "node": ">=14" | 986 | "node": ">=14" |
| 971 | } | 987 | } |
| 972 | }, | 988 | }, |
| 989 | "node_modules/@pkgr/core": { | ||
| 990 | "version": "0.1.1", | ||
| 991 | "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", | ||
| 992 | "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", | ||
| 993 | "dev": true, | ||
| 994 | "license": "MIT", | ||
| 995 | "engines": { | ||
| 996 | "node": "^12.20.0 || ^14.18.0 || >=16.0.0" | ||
| 997 | }, | ||
| 998 | "funding": { | ||
| 999 | "url": "https://opencollective.com/unts" | ||
| 1000 | } | ||
| 1001 | }, | ||
| 973 | "node_modules/@popperjs/core": { | 1002 | "node_modules/@popperjs/core": { |
| 974 | "version": "2.11.8", | 1003 | "version": "2.11.8", |
| 975 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", | 1004 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", |
| @@ -2099,6 +2128,16 @@ | |||
| 2099 | "safe-buffer": "~5.2.0" | 2128 | "safe-buffer": "~5.2.0" |
| 2100 | } | 2129 | } |
| 2101 | }, | 2130 | }, |
| 2131 | "node_modules/are-docs-informative": { | ||
| 2132 | "version": "0.0.2", | ||
| 2133 | "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", | ||
| 2134 | "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", | ||
| 2135 | "dev": true, | ||
| 2136 | "license": "MIT", | ||
| 2137 | "engines": { | ||
| 2138 | "node": ">=14" | ||
| 2139 | } | ||
| 2140 | }, | ||
| 2102 | "node_modules/argparse": { | 2141 | "node_modules/argparse": { |
| 2103 | "version": "2.0.1", | 2142 | "version": "2.0.1", |
| 2104 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", | 2143 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", |
| @@ -2614,6 +2653,16 @@ | |||
| 2614 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", | 2653 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", |
| 2615 | "license": "MIT" | 2654 | "license": "MIT" |
| 2616 | }, | 2655 | }, |
| 2656 | "node_modules/comment-parser": { | ||
| 2657 | "version": "1.4.1", | ||
| 2658 | "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", | ||
| 2659 | "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", | ||
| 2660 | "dev": true, | ||
| 2661 | "license": "MIT", | ||
| 2662 | "engines": { | ||
| 2663 | "node": ">= 12.0.0" | ||
| 2664 | } | ||
| 2665 | }, | ||
| 2617 | "node_modules/compress-commons": { | 2666 | "node_modules/compress-commons": { |
| 2618 | "version": "6.0.2", | 2667 | "version": "6.0.2", |
| 2619 | "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", | 2668 | "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", |
| @@ -3560,6 +3609,69 @@ | |||
| 3560 | "url": "https://opencollective.com/eslint" | 3609 | "url": "https://opencollective.com/eslint" |
| 3561 | } | 3610 | } |
| 3562 | }, | 3611 | }, |
| 3612 | "node_modules/eslint-plugin-jsdoc": { | ||
| 3613 | "version": "48.10.0", | ||
| 3614 | "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz", | ||
| 3615 | "integrity": "sha512-BEli0k8E0dzhJairAllwlkGnyYDZVKNn4WDmyKy+v6J5qGNuofjzxwNUi+55BOGmyO9mKBhqaidwGy+dxndn/Q==", | ||
| 3616 | "dev": true, | ||
| 3617 | "license": "BSD-3-Clause", | ||
| 3618 | "dependencies": { | ||
| 3619 | "@es-joy/jsdoccomment": "~0.46.0", | ||
| 3620 | "are-docs-informative": "^0.0.2", | ||
| 3621 | "comment-parser": "1.4.1", | ||
| 3622 | "debug": "^4.3.5", | ||
| 3623 | "escape-string-regexp": "^4.0.0", | ||
| 3624 | "esquery": "^1.6.0", | ||
| 3625 | "parse-imports": "^2.1.1", | ||
| 3626 | "semver": "^7.6.3", | ||
| 3627 | "spdx-expression-parse": "^4.0.0", | ||
| 3628 | "synckit": "^0.9.1" | ||
| 3629 | }, | ||
| 3630 | "engines": { | ||
| 3631 | "node": ">=18" | ||
| 3632 | }, | ||
| 3633 | "peerDependencies": { | ||
| 3634 | "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" | ||
| 3635 | } | ||
| 3636 | }, | ||
| 3637 | "node_modules/eslint-plugin-jsdoc/node_modules/debug": { | ||
| 3638 | "version": "4.4.0", | ||
| 3639 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", | ||
| 3640 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", | ||
| 3641 | "dev": true, | ||
| 3642 | "license": "MIT", | ||
| 3643 | "dependencies": { | ||
| 3644 | "ms": "^2.1.3" | ||
| 3645 | }, | ||
| 3646 | "engines": { | ||
| 3647 | "node": ">=6.0" | ||
| 3648 | }, | ||
| 3649 | "peerDependenciesMeta": { | ||
| 3650 | "supports-color": { | ||
| 3651 | "optional": true | ||
| 3652 | } | ||
| 3653 | } | ||
| 3654 | }, | ||
| 3655 | "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { | ||
| 3656 | "version": "4.0.0", | ||
| 3657 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", | ||
| 3658 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", | ||
| 3659 | "dev": true, | ||
| 3660 | "license": "MIT", | ||
| 3661 | "engines": { | ||
| 3662 | "node": ">=10" | ||
| 3663 | }, | ||
| 3664 | "funding": { | ||
| 3665 | "url": "https://github.com/sponsors/sindresorhus" | ||
| 3666 | } | ||
| 3667 | }, | ||
| 3668 | "node_modules/eslint-plugin-jsdoc/node_modules/ms": { | ||
| 3669 | "version": "2.1.3", | ||
| 3670 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | ||
| 3671 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | ||
| 3672 | "dev": true, | ||
| 3673 | "license": "MIT" | ||
| 3674 | }, | ||
| 3563 | "node_modules/eslint-scope": { | 3675 | "node_modules/eslint-scope": { |
| 3564 | "version": "7.2.2", | 3676 | "version": "7.2.2", |
| 3565 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", | 3677 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", |
| @@ -3690,9 +3802,9 @@ | |||
| 3690 | } | 3802 | } |
| 3691 | }, | 3803 | }, |
| 3692 | "node_modules/esquery": { | 3804 | "node_modules/esquery": { |
| 3693 | "version": "1.5.0", | 3805 | "version": "1.6.0", |
| 3694 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", | 3806 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", |
| 3695 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", | 3807 | "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", |
| 3696 | "dev": true, | 3808 | "dev": true, |
| 3697 | "license": "BSD-3-Clause", | 3809 | "license": "BSD-3-Clause", |
| 3698 | "dependencies": { | 3810 | "dependencies": { |
| @@ -5015,6 +5127,16 @@ | |||
| 5015 | "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", | 5127 | "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", |
| 5016 | "license": "MIT" | 5128 | "license": "MIT" |
| 5017 | }, | 5129 | }, |
| 5130 | "node_modules/jsdoc-type-pratt-parser": { | ||
| 5131 | "version": "4.0.0", | ||
| 5132 | "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", | ||
| 5133 | "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", | ||
| 5134 | "dev": true, | ||
| 5135 | "license": "MIT", | ||
| 5136 | "engines": { | ||
| 5137 | "node": ">=12.0.0" | ||
| 5138 | } | ||
| 5139 | }, | ||
| 5018 | "node_modules/json-buffer": { | 5140 | "node_modules/json-buffer": { |
| 5019 | "version": "3.0.1", | 5141 | "version": "3.0.1", |
| 5020 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", | 5142 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", |
| @@ -5891,6 +6013,20 @@ | |||
| 5891 | "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", | 6013 | "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", |
| 5892 | "license": "MIT" | 6014 | "license": "MIT" |
| 5893 | }, | 6015 | }, |
| 6016 | "node_modules/parse-imports": { | ||
| 6017 | "version": "2.2.1", | ||
| 6018 | "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", | ||
| 6019 | "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", | ||
| 6020 | "dev": true, | ||
| 6021 | "license": "Apache-2.0 AND MIT", | ||
| 6022 | "dependencies": { | ||
| 6023 | "es-module-lexer": "^1.5.3", | ||
| 6024 | "slashes": "^3.0.12" | ||
| 6025 | }, | ||
| 6026 | "engines": { | ||
| 6027 | "node": ">= 18" | ||
| 6028 | } | ||
| 6029 | }, | ||
| 5894 | "node_modules/parse5": { | 6030 | "node_modules/parse5": { |
| 5895 | "version": "7.1.2", | 6031 | "version": "7.1.2", |
| 5896 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", | 6032 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", |
| @@ -6600,6 +6736,19 @@ | |||
| 6600 | "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", | 6736 | "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", |
| 6601 | "license": "MIT" | 6737 | "license": "MIT" |
| 6602 | }, | 6738 | }, |
| 6739 | "node_modules/semver": { | ||
| 6740 | "version": "7.7.1", | ||
| 6741 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", | ||
| 6742 | "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", | ||
| 6743 | "dev": true, | ||
| 6744 | "license": "ISC", | ||
| 6745 | "bin": { | ||
| 6746 | "semver": "bin/semver.js" | ||
| 6747 | }, | ||
| 6748 | "engines": { | ||
| 6749 | "node": ">=10" | ||
| 6750 | } | ||
| 6751 | }, | ||
| 6603 | "node_modules/send": { | 6752 | "node_modules/send": { |
| 6604 | "version": "0.19.0", | 6753 | "version": "0.19.0", |
| 6605 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", | 6754 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", |
| @@ -6811,6 +6960,13 @@ | |||
| 6811 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | 6960 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", |
| 6812 | "license": "MIT" | 6961 | "license": "MIT" |
| 6813 | }, | 6962 | }, |
| 6963 | "node_modules/slashes": { | ||
| 6964 | "version": "3.0.12", | ||
| 6965 | "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", | ||
| 6966 | "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", | ||
| 6967 | "dev": true, | ||
| 6968 | "license": "ISC" | ||
| 6969 | }, | ||
| 6814 | "node_modules/sliced": { | 6970 | "node_modules/sliced": { |
| 6815 | "version": "1.0.1", | 6971 | "version": "1.0.1", |
| 6816 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", | 6972 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", |
| @@ -6903,6 +7059,31 @@ | |||
| 6903 | "source-map": "^0.6.0" | 7059 | "source-map": "^0.6.0" |
| 6904 | } | 7060 | } |
| 6905 | }, | 7061 | }, |
| 7062 | "node_modules/spdx-exceptions": { | ||
| 7063 | "version": "2.5.0", | ||
| 7064 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", | ||
| 7065 | "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", | ||
| 7066 | "dev": true, | ||
| 7067 | "license": "CC-BY-3.0" | ||
| 7068 | }, | ||
| 7069 | "node_modules/spdx-expression-parse": { | ||
| 7070 | "version": "4.0.0", | ||
| 7071 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", | ||
| 7072 | "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", | ||
| 7073 | "dev": true, | ||
| 7074 | "license": "MIT", | ||
| 7075 | "dependencies": { | ||
| 7076 | "spdx-exceptions": "^2.1.0", | ||
| 7077 | "spdx-license-ids": "^3.0.0" | ||
| 7078 | } | ||
| 7079 | }, | ||
| 7080 | "node_modules/spdx-license-ids": { | ||
| 7081 | "version": "3.0.21", | ||
| 7082 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", | ||
| 7083 | "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", | ||
| 7084 | "dev": true, | ||
| 7085 | "license": "CC0-1.0" | ||
| 7086 | }, | ||
| 6906 | "node_modules/sprintf-js": { | 7087 | "node_modules/sprintf-js": { |
| 6907 | "version": "1.1.3", | 7088 | "version": "1.1.3", |
| 6908 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", | 7089 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", |
| @@ -7042,6 +7223,23 @@ | |||
| 7042 | "node": ">=8" | 7223 | "node": ">=8" |
| 7043 | } | 7224 | } |
| 7044 | }, | 7225 | }, |
| 7226 | "node_modules/synckit": { | ||
| 7227 | "version": "0.9.2", | ||
| 7228 | "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", | ||
| 7229 | "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", | ||
| 7230 | "dev": true, | ||
| 7231 | "license": "MIT", | ||
| 7232 | "dependencies": { | ||
| 7233 | "@pkgr/core": "^0.1.0", | ||
| 7234 | "tslib": "^2.6.2" | ||
| 7235 | }, | ||
| 7236 | "engines": { | ||
| 7237 | "node": "^14.18.0 || >=16.0.0" | ||
| 7238 | }, | ||
| 7239 | "funding": { | ||
| 7240 | "url": "https://opencollective.com/unts" | ||
| 7241 | } | ||
| 7242 | }, | ||
| 7045 | "node_modules/tapable": { | 7243 | "node_modules/tapable": { |
| 7046 | "version": "2.2.1", | 7244 | "version": "2.2.1", |
| 7047 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", | 7245 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", |
| @@ -140,6 +140,7 @@ | |||
| 140 | "@types/write-file-atomic": "^4.0.3", | 140 | "@types/write-file-atomic": "^4.0.3", |
| 141 | "@types/yargs": "^17.0.33", | 141 | "@types/yargs": "^17.0.33", |
| 142 | "@types/yauzl": "^2.10.3", | 142 | "@types/yauzl": "^2.10.3", |
| 143 | "eslint": "^8.57.1" | 143 | "eslint": "^8.57.1", |
| 144 | "eslint-plugin-jsdoc": "^48.10.0" | ||
| 144 | } | 145 | } |
| 145 | } | 146 | } |
| @@ -101,15 +101,12 @@ const keyMigrationMap = [ | |||
| 101 | newKey: 'performance.memoryCacheCapacity', | 101 | newKey: 'performance.memoryCacheCapacity', |
| 102 | migrate: (value) => `${value}mb`, | 102 | migrate: (value) => `${value}mb`, |
| 103 | }, | 103 | }, |
| 104 | // uncomment one release after 1.12.13 | ||
| 105 | /* | ||
| 106 | { | 104 | { |
| 107 | oldKey: 'cookieSecret', | 105 | oldKey: 'cookieSecret', |
| 108 | newKey: 'cookieSecret', | 106 | newKey: 'cookieSecret', |
| 109 | migrate: () => void 0, | 107 | migrate: () => void 0, |
| 110 | remove: true, | 108 | remove: true, |
| 111 | }, | 109 | }, |
| 112 | */ | ||
| 113 | ]; | 110 | ]; |
| 114 | 111 | ||
| 115 | /** | 112 | /** |
| @@ -1,7 +1,11 @@ | |||
| 1 | import libs from './lib'; | 1 | import libs from './lib'; |
| 2 | import getContext from './scripts/st-context'; | 2 | import getContext from './scripts/st-context'; |
| 3 | import { power_user } from './scripts/power-user'; | ||
| 3 | 4 | ||
| 4 | declare global { | 5 | declare global { |
| 6 | // Custom types | ||
| 7 | declare type InstructSettings = typeof power_user.instruct; | ||
| 8 | |||
| 5 | // Global namespace modules | 9 | // Global namespace modules |
| 6 | interface Window { | 10 | interface Window { |
| 7 | ai: any; | 11 | ai: any; |
| @@ -1957,7 +1957,7 @@ | |||
| 1957 | <span data-i18n="Enable web search">Enable web search</span> | 1957 | <span data-i18n="Enable web search">Enable web search</span> |
| 1958 | </label> | 1958 | </label> |
| 1959 | <div class="flexBasis100p toggle-description justifyLeft"> | 1959 | <div class="flexBasis100p toggle-description justifyLeft"> |
| 1960 | <span> | 1960 | <span data-i18n="Use search capabilities provided by the backend."> |
| 1961 | Use search capabilities provided by the backend. | 1961 | Use search capabilities provided by the backend. |
| 1962 | </span> | 1962 | </span> |
| 1963 | </div> | 1963 | </div> |
| @@ -2188,7 +2188,7 @@ | |||
| 2188 | <input id="horde_trusted_workers_only" type="checkbox" /> | 2188 | <input id="horde_trusted_workers_only" type="checkbox" /> |
| 2189 | <span data-i18n="Trusted workers only">Trusted workers only</span> | 2189 | <span data-i18n="Trusted workers only">Trusted workers only</span> |
| 2190 | </label> | 2190 | </label> |
| 2191 | <small id="adjustedHordeParams">Context: --, Response: --</small> | 2191 | <small id="adjustedHordeParams"><span data-i18n="Context">Context</span>: --, <span data-i18n="Response">Response</span>: --</small> |
| 2192 | <h4 data-i18n="API key">API key</h4> | 2192 | <h4 data-i18n="API key">API key</h4> |
| 2193 | <small> | 2193 | <small> |
| 2194 | <span data-i18n="Get it here:">Get it here: </span> <a target="_blank" href="https://aihorde.net/register" data-i18n="Register">Register</a> (<a id="horde_kudos" href="javascript:void(0);" data-i18n="View my Kudos">View my Kudos</a>)<br> | 2194 | <span data-i18n="Get it here:">Get it here: </span> <a target="_blank" href="https://aihorde.net/register" data-i18n="Register">Register</a> (<a id="horde_kudos" href="javascript:void(0);" data-i18n="View my Kudos">View my Kudos</a>)<br> |
| @@ -3193,6 +3193,7 @@ | |||
| 3193 | <option value="mistral-small-latest">mistral-small-latest</option> | 3193 | <option value="mistral-small-latest">mistral-small-latest</option> |
| 3194 | <option value="mistral-medium-latest">mistral-medium-latest</option> | 3194 | <option value="mistral-medium-latest">mistral-medium-latest</option> |
| 3195 | <option value="mistral-large-latest">mistral-large-latest</option> | 3195 | <option value="mistral-large-latest">mistral-large-latest</option> |
| 3196 | <option value="mistral-saba-latest">mistral-saba-latest</option> | ||
| 3196 | <option value="codestral-latest">codestral-latest</option> | 3197 | <option value="codestral-latest">codestral-latest</option> |
| 3197 | <option value="codestral-mamba-latest">codestral-mamba-latest</option> | 3198 | <option value="codestral-mamba-latest">codestral-mamba-latest</option> |
| 3198 | <option value="pixtral-12b-latest">pixtral-12b-latest</option> | 3199 | <option value="pixtral-12b-latest">pixtral-12b-latest</option> |
| @@ -3208,13 +3209,20 @@ | |||
| 3208 | <option value="mistral-small-2312">mistral-small-2312</option> | 3209 | <option value="mistral-small-2312">mistral-small-2312</option> |
| 3209 | <option value="mistral-small-2402">mistral-small-2402</option> | 3210 | <option value="mistral-small-2402">mistral-small-2402</option> |
| 3210 | <option value="mistral-small-2409">mistral-small-2409</option> | 3211 | <option value="mistral-small-2409">mistral-small-2409</option> |
| 3212 | <option value="mistral-small-2501">mistral-small-2501</option> | ||
| 3213 | <option value="mistral-small-2503">mistral-small-2503</option> | ||
| 3211 | <option value="mistral-medium-2312">mistral-medium-2312</option> | 3214 | <option value="mistral-medium-2312">mistral-medium-2312</option> |
| 3212 | <option value="mistral-large-2402">mistral-large-2402</option> | 3215 | <option value="mistral-large-2402">mistral-large-2402</option> |
| 3213 | <option value="mistral-large-2407">mistral-large-2407</option> | 3216 | <option value="mistral-large-2407">mistral-large-2407</option> |
| 3214 | <option value="mistral-large-2411">mistral-large-2411</option> | 3217 | <option value="mistral-large-2411">mistral-large-2411</option> |
| 3218 | <option value="mistral-large-pixtral-2411">mistral-large-pixtral-2411</option> | ||
| 3219 | <option value="mistral-saba-2502">mistral-saba-2502</option> | ||
| 3215 | <option value="codestral-2405">codestral-2405</option> | 3220 | <option value="codestral-2405">codestral-2405</option> |
| 3216 | <option value="codestral-2405-blue">codestral-2405-blue</option> | 3221 | <option value="codestral-2405-blue">codestral-2405-blue</option> |
| 3217 | <option value="codestral-mamba-2407">codestral-mamba-2407</option> | 3222 | <option value="codestral-mamba-2407">codestral-mamba-2407</option> |
| 3223 | <option value="codestral-2411-rc5">codestral-2411-rc5</option> | ||
| 3224 | <option value="codestral-2412">codestral-2412</option> | ||
| 3225 | <option value="codestral-2501">codestral-2501</option> | ||
| 3218 | <option value="pixtral-12b-2409">pixtral-12b-2409</option> | 3226 | <option value="pixtral-12b-2409">pixtral-12b-2409</option> |
| 3219 | <option value="pixtral-large-2411">pixtral-large-2411</option> | 3227 | <option value="pixtral-large-2411">pixtral-large-2411</option> |
| 3220 | </optgroup> | 3228 | </optgroup> |
| @@ -3407,17 +3415,10 @@ | |||
| 3407 | <div class="flex-container"> | 3415 | <div class="flex-container"> |
| 3408 | <select id="model_custom_select" class="text_pole model_custom_select"></select> | 3416 | <select id="model_custom_select" class="text_pole model_custom_select"></select> |
| 3409 | </div> | 3417 | </div> |
| 3410 | <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4> | ||
| 3411 | <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API."> | ||
| 3412 | <option data-i18n="prompt_post_processing_none" value="">None</option> | ||
| 3413 | <option data-i18n="prompt_post_processing_merge" value="merge">Merge consecutive roles</option> | ||
| 3414 | <option data-i18n="prompt_post_processing_semi" value="semi">Semi-strict (alternating roles)</option> | ||
| 3415 | <option data-i18n="prompt_post_processing_strict" value="strict">Strict (user first, alternating roles)</option> | ||
| 3416 | </select> | ||
| 3417 | </form> | 3418 | </form> |
| 3418 | <div id="01ai_form" data-source="01ai"> | 3419 | <div id="01ai_form" data-source="01ai"> |
| 3419 | <h4> | 3420 | <h4> |
| 3420 | <a data-i18n="01.AI API Key" href="https://platform.01.ai/" target="_blank" rel="noopener noreferrer"> | 3421 | <a data-i18n="01.AI API Key" href="https://platform.lingyiwanwu.com/" target="_blank" rel="noopener noreferrer"> |
| 3421 | 01.AI API Key | 3422 | 01.AI API Key |
| 3422 | </a> | 3423 | </a> |
| 3423 | </h4> | 3424 | </h4> |
| @@ -3432,6 +3433,15 @@ | |||
| 3432 | <select id="model_01ai_select"> | 3433 | <select id="model_01ai_select"> |
| 3433 | </select> | 3434 | </select> |
| 3434 | </div> | 3435 | </div> |
| 3436 | <div id="prompt_post_porcessing_form" data-source="custom,openrouter"> | ||
| 3437 | <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4> | ||
| 3438 | <select id="custom_prompt_post_processing" class="text_pole" title="Applies additional processing to the prompt before sending it to the API." data-i18n="[title]Applies additional processing to the prompt before sending it to the API."> | ||
| 3439 | <option data-i18n="prompt_post_processing_none" value="">None</option> | ||
| 3440 | <option data-i18n="prompt_post_processing_merge" value="merge">Merge consecutive roles</option> | ||
| 3441 | <option data-i18n="prompt_post_processing_semi" value="semi">Semi-strict (alternating roles)</option> | ||
| 3442 | <option data-i18n="prompt_post_processing_strict" value="strict">Strict (user first, alternating roles)</option> | ||
| 3443 | </select> | ||
| 3444 | </div> | ||
| 3435 | <div class="flex-container flex"> | 3445 | <div class="flex-container flex"> |
| 3436 | <div id="api_button_openai" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div> | 3446 | <div id="api_button_openai" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div> |
| 3437 | <div class="api_loading menu_button menu_button_icon" data-i18n="Cancel">Cancel</div> | 3447 | <div class="api_loading menu_button menu_button_icon" data-i18n="Cancel">Cancel</div> |
| @@ -3917,6 +3927,19 @@ | |||
| 3917 | <summary data-i18n="Reasoning Formatting"> | 3927 | <summary data-i18n="Reasoning Formatting"> |
| 3918 | Reasoning Formatting | 3928 | Reasoning Formatting |
| 3919 | </summary> | 3929 | </summary> |
| 3930 | <div class="flex-container" title="Select your current Reasoning Template" data-i18n="[title]Select your current Reasoning Template"> | ||
| 3931 | <select id="reasoning_select" data-preset-manager-for="reasoning" class="flex1 text_pole"></select> | ||
| 3932 | <div class="flex-container margin0 justifyCenter gap3px"> | ||
| 3933 | <input type="file" hidden data-preset-manager-file="reasoning" accept=".json, .settings"> | ||
| 3934 | <i data-preset-manager-update="reasoning" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i> | ||
| 3935 | <i data-preset-manager-rename="reasoning" class="menu_button fa-pencil fa-solid" title="Rename current template" data-i18n="[title]Rename current template"></i> | ||
| 3936 | <i data-preset-manager-new="reasoning" class="menu_button fa-solid fa-file-circle-plus" title="Save template as" data-i18n="[title]Save template as"></i> | ||
| 3937 | <i data-preset-manager-import="reasoning" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | ||
| 3938 | <i data-preset-manager-export="reasoning" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | ||
| 3939 | <i data-preset-manager-restore="reasoning" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i> | ||
| 3940 | <i data-preset-manager-delete="reasoning" class="menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i> | ||
| 3941 | </div> | ||
| 3942 | </div> | ||
| 3920 | <div class="flex-container"> | 3943 | <div class="flex-container"> |
| 3921 | <div class="flex1" title="Inserted before the reasoning content." data-i18n="[title]reasoning_prefix"> | 3944 | <div class="flex1" title="Inserted before the reasoning content." data-i18n="[title]reasoning_prefix"> |
| 3922 | <small data-i18n="Prefix">Prefix</small> | 3945 | <small data-i18n="Prefix">Prefix</small> |
| @@ -6563,7 +6586,7 @@ | |||
| 6563 | <div class="ch_name"></div> | 6586 | <div class="ch_name"></div> |
| 6564 | <small class="ch_additional_info group_select_counter"></small> | 6587 | <small class="ch_additional_info group_select_counter"></small> |
| 6565 | </div> | 6588 | </div> |
| 6566 | <small class="character_name_block_sub_line">in this group</small> | 6589 | <small class="character_name_block_sub_line" data-i18n="in this group">in this group</small> |
| 6567 | <i class='group_fav_icon fa-solid fa-star'></i> | 6590 | <i class='group_fav_icon fa-solid fa-star'></i> |
| 6568 | <input class="ch_fav" value="" hidden /> | 6591 | <input class="ch_fav" value="" hidden /> |
| 6569 | <div class="group_select_block_list ch_description"></div> | 6592 | <div class="group_select_block_list ch_description"></div> |
| @@ -23,9 +23,8 @@ | |||
| 23 | "Mirostat Mode": "Π Π΅ΠΆΠΈΠΌ", | 23 | "Mirostat Mode": "Π Π΅ΠΆΠΈΠΌ", |
| 24 | "Mirostat Tau": "Tau", | 24 | "Mirostat Tau": "Tau", |
| 25 | "Mirostat Eta": "Eta", | 25 | "Mirostat Eta": "Eta", |
| 26 | "Variability parameter for Mirostat outputs": "ΠΠ°ΡΠ°ΠΌΠ΅ΡΡ ΠΈΠ·ΠΌΠ΅Π½ΡΠΈΠ²ΠΎΡΡΠΈ Π΄Π»Ρ Π²ΡΡ ΠΎΠ΄Π½ΡΡ Π΄Π°Π½Π½ΡΡ Mirostat.", | 26 | "Variability parameter for Mirostat outputs": "ΠΠ°ΡΠΈΠ°ΡΠΈΠ²Π½ΠΎΡΡΡ Π΄Π»Ρ Π²ΡΡ ΠΎΠ΄Π½ΡΡ Π΄Π°Π½Π½ΡΡ Mirostat.", |
| 27 | "Learning rate of Mirostat": "Π‘ΠΊΠΎΡΠΎΡΡΡ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ Mirostat.", | 27 | "Learning rate of Mirostat": "Π‘ΠΊΠΎΡΠΎΡΡΡ ΠΎΠ±ΡΡΠ΅Π½ΠΈΡ Mirostat.", |
| 28 | "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Π‘ΠΈΠ»Π° ΡΡΠ»ΠΎΠ²ΠΈΡ ΡΠ΅Π³ΡΠ»ΡΡΠΈΠ·Π°ΡΠΈΠΈ ΠΊΠΎΠ½ΡΡΠ°ΡΡΠΈΠ²Π½ΠΎΠ³ΠΎ ΠΏΠΎΠΈΡΠΊΠ°. Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ 0, ΡΡΠΎΠ±Ρ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ CS.", | ||
| 29 | "Temperature Last": "Π’Π΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΠ° ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅ΠΉ", | 28 | "Temperature Last": "Π’Π΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΠ° ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅ΠΉ", |
| 30 | "LLaMA / Mistral / Yi models only": "Π’ΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ LLaMA / Mistral / Yi. ΠΠ΅ΡΠ΅Π΄ ΡΡΠΈΠΌ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎ Π²ΡΠ±Π΅ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΡΡΠΈΠΉ ΡΠΎΠΊΠ΅Π½ΠΈΠ·Π°ΡΠΎΡ.\nΠΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ, ΠΊΠΎΡΠΎΡΡΡ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ Π½Π° Π²ΡΡ ΠΎΠ΄Π΅.\nΠΠ΄Π½Π° Π½Π° ΡΡΡΠΎΠΊΡ. Π’Π΅ΠΊΡΡ ΠΈΠ»ΠΈ [ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ²].\nΠΠ½ΠΎΠ³ΠΈΠ΅ ΡΠΎΠΊΠ΅Π½Ρ ΠΈΠΌΠ΅ΡΡ ΠΏΡΠΎΠ±Π΅Π» Π²ΠΏΠ΅ΡΠ΅Π΄ΠΈ. ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΡΠ΅ΡΡΠΈΠΊ ΡΠΎΠΊΠ΅Π½ΠΎΠ², Π΅ΡΠ»ΠΈ Π½Π΅ ΡΠ²Π΅ΡΠ΅Π½Ρ.", | 29 | "LLaMA / Mistral / Yi models only": "Π’ΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ LLaMA / Mistral / Yi. ΠΠ΅ΡΠ΅Π΄ ΡΡΠΈΠΌ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎ Π²ΡΠ±Π΅ΡΠΈΡΠ΅ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΡΡΠΈΠΉ ΡΠΎΠΊΠ΅Π½ΠΈΠ·Π°ΡΠΎΡ.\nΠΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ, ΠΊΠΎΡΠΎΡΡΡ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ Π½Π° Π²ΡΡ ΠΎΠ΄Π΅.\nΠΠ΄Π½Π° Π½Π° ΡΡΡΠΎΠΊΡ. Π’Π΅ΠΊΡΡ ΠΈΠ»ΠΈ [ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ²].\nΠΠ½ΠΎΠ³ΠΈΠ΅ ΡΠΎΠΊΠ΅Π½Ρ ΠΈΠΌΠ΅ΡΡ ΠΏΡΠΎΠ±Π΅Π» Π²ΠΏΠ΅ΡΠ΅Π΄ΠΈ. ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΡΠ΅ΡΡΠΈΠΊ ΡΠΎΠΊΠ΅Π½ΠΎΠ², Π΅ΡΠ»ΠΈ Π½Π΅ ΡΠ²Π΅ΡΠ΅Π½Ρ.", |
| 31 | "Example: some text [42, 69, 1337]": "ΠΡΠΈΠΌΠ΅Ρ:\nΠΊΠ°ΠΊΠΎΠΉ-ΡΠΎ ΡΠ΅ΠΊΡΡ\n[42, 69, 1337]", | 30 | "Example: some text [42, 69, 1337]": "ΠΡΠΈΠΌΠ΅Ρ:\nΠΊΠ°ΠΊΠΎΠΉ-ΡΠΎ ΡΠ΅ΠΊΡΡ\n[42, 69, 1337]", |
| @@ -60,13 +59,11 @@ | |||
| 60 | "Add BOS Token": "ΠΠΎΠ±Π°Π²Π»ΡΡΡ BOS-ΡΠΎΠΊΠ΅Π½", | 59 | "Add BOS Token": "ΠΠΎΠ±Π°Π²Π»ΡΡΡ BOS-ΡΠΎΠΊΠ΅Π½", |
| 61 | "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "ΠΠΎΠ±Π°Π²Π»ΡΡΡ BOS-ΡΠΎΠΊΠ΅Π½ Π² Π½Π°ΡΠ°Π»Π΅ ΠΏΡΠΎΠΌΠΏΡΠ°. ΠΡΠ»ΠΈ Π²ΡΠΊΠ»ΡΡΠΈΡΡ, ΠΎΡΠ²Π΅ΡΡ ΠΌΠΎΠ³ΡΡ ΡΡΠ°ΡΡ Π±ΠΎΠ»Π΅Π΅ ΠΊΡΠ΅Π°ΡΠΈΠ²Π½ΡΠΌΠΈ.", | 60 | "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "ΠΠΎΠ±Π°Π²Π»ΡΡΡ BOS-ΡΠΎΠΊΠ΅Π½ Π² Π½Π°ΡΠ°Π»Π΅ ΠΏΡΠΎΠΌΠΏΡΠ°. ΠΡΠ»ΠΈ Π²ΡΠΊΠ»ΡΡΠΈΡΡ, ΠΎΡΠ²Π΅ΡΡ ΠΌΠΎΠ³ΡΡ ΡΡΠ°ΡΡ Π±ΠΎΠ»Π΅Π΅ ΠΊΡΠ΅Π°ΡΠΈΠ²Π½ΡΠΌΠΈ.", |
| 62 | "Ban EOS Token": "ΠΠ°ΠΏΡΠ΅ΡΠΈΡΡ EOS-ΡΠΎΠΊΠ΅Π½", | 61 | "Ban EOS Token": "ΠΠ°ΠΏΡΠ΅ΡΠΈΡΡ EOS-ΡΠΎΠΊΠ΅Π½", |
| 63 | "Ban the eos_token. This forces the model to never end the generation prematurely": "ΠΠ°ΠΏΡΠ΅Ρ EOS-ΡΠΎΠΊΠ΅Π½Π° Π½Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π·Π°Π²Π΅ΡΡΠΈΡΡ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΏΡΠ΅ΠΆΠ΄Π΅Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ", | 62 | "Ban the eos_token. This forces the model to never end the generation prematurely": "ΠΠ°ΠΏΡΠ΅Ρ EOS-ΡΠΎΠΊΠ΅Π½Π° Π½Π΅ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π·Π°Π²Π΅ΡΡΠΈΡΡ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΡΠ°ΠΌΠΎΡΡΠΎΡΡΠ΅Π»ΡΠ½ΠΎ (ΡΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΈ Π΄ΠΎΡΡΠΈΠΆΠ΅Π½ΠΈΠΈ Π»ΠΈΠΌΠΈΡΠ° ΡΠΎΠΊΠ΅Π½ΠΎΠ²)", |
| 64 | "Skip Special Tokens": "ΠΡΠΎΠΏΡΡΠΊΠ°ΡΡ ΡΠΏΠ΅Ρ. ΡΠΎΠΊΠ΅Π½Ρ", | 63 | "Skip Special Tokens": "ΠΡΠΎΠΏΡΡΠΊΠ°ΡΡ ΡΠΏΠ΅Ρ. ΡΠΎΠΊΠ΅Π½Ρ", |
| 65 | "Beam search": "ΠΠΎΠΈΡΠΊ Beam", | 64 | "Beam search": "Beam Search", |
| 66 | "Number of Beams": "ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Beam", | ||
| 67 | "Length Penalty": "Π¨ΡΡΠ°Ρ Π·Π° Π΄Π»ΠΈΠ½Ρ", | 65 | "Length Penalty": "Π¨ΡΡΠ°Ρ Π·Π° Π΄Π»ΠΈΠ½Ρ", |
| 68 | "Early Stopping": "ΠΡΠ΅ΠΆΠ΄Π΅Π²ΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ ΠΎΡΡΠ°Π½ΠΎΠ²ΠΊΠ°", | 66 | "Early Stopping": "ΠΡΠ΅ΠΊΡΠ°ΡΠ°ΡΡ ΡΡΠ°Π·Ρ", |
| 69 | "Contrastive search": "ΠΠΎΠ½ΡΡΠ°ΡΡΠ½ΡΠΉ ΠΏΠΎΠΈΡΠΊ", | ||
| 70 | "Penalty Alpha": "Penalty Alpha", | 67 | "Penalty Alpha": "Penalty Alpha", |
| 71 | "Seed": "ΠΠ΅ΡΠ½ΠΎ", | 68 | "Seed": "ΠΠ΅ΡΠ½ΠΎ", |
| 72 | "Epsilon Cutoff": "Epsilon Cutoff", | 69 | "Epsilon Cutoff": "Epsilon Cutoff", |
| @@ -89,7 +86,7 @@ | |||
| 89 | "Text Completion presets": "ΠΡΠ΅ΡΠ΅ΡΡ Π΄Π»Ρ Text Completion", | 86 | "Text Completion presets": "ΠΡΠ΅ΡΠ΅ΡΡ Π΄Π»Ρ Text Completion", |
| 90 | "Documentation on sampling parameters": "ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ ΠΏΠΎ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠ°ΠΌ ΡΡΠΌΠΏΠ»Π΅ΡΠΎΠ²", | 87 | "Documentation on sampling parameters": "ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ ΠΏΠΎ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠ°ΠΌ ΡΡΠΌΠΏΠ»Π΅ΡΠΎΠ²", |
| 91 | "Set all samplers to their neutral/disabled state.": "Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ Π²ΡΠ΅ ΡΡΠΌΠΏΠ»Π΅ΡΡ Π² Π½Π΅ΠΉΡΡΠ°Π»ΡΠ½ΠΎΠ΅/ΠΎΡΠΊΠ»ΡΡΠ΅Π½Π½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅.", | 88 | "Set all samplers to their neutral/disabled state.": "Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ Π²ΡΠ΅ ΡΡΠΌΠΏΠ»Π΅ΡΡ Π² Π½Π΅ΠΉΡΡΠ°Π»ΡΠ½ΠΎΠ΅/ΠΎΡΠΊΠ»ΡΡΠ΅Π½Π½ΠΎΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΠ΅.", |
| 92 | "Only enable this if your model supports context sizes greater than 8192 tokens": "ΠΠΊΠ»ΡΡΠ°ΠΉΡΠ΅ ΡΡΡ ΠΎΠΏΡΠΈΡ, ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ Π²Π°ΡΠ° ΠΌΠΎΠ΄Π΅Π»Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΡΠ°Π·ΠΌΠ΅Ρ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° Π±ΠΎΠ»Π΅Π΅ 8192 ΡΠΎΠΊΠ΅Π½ΠΎΠ².\nΠ£Π²Π΅Π»ΠΈΡΠΈΠ²Π°ΠΉΡΠ΅ ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ Π²Ρ Π·Π½Π°Π΅ΡΠ΅, ΡΡΠΎ Π΄Π΅Π»Π°Π΅ΡΠ΅.", | 89 | "Only enable this if your model supports context sizes greater than 8192 tokens": "ΠΠΊΠ»ΡΡΠ°ΠΉΡΠ΅ ΡΡΡ ΠΎΠΏΡΠΈΡ, ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ Π²Π°ΡΠ° ΠΌΠΎΠ΄Π΅Π»Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΡΠ°Π·ΠΌΠ΅Ρ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ° Π±ΠΎΠ»Π΅Π΅ 8192 ΡΠΎΠΊΠ΅Π½ΠΎΠ².\nΠ£Π²Π΅Π»ΠΈΡΠΈΠ²Π°ΠΉΡΠ΅ ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ Π²Ρ ΠΏΠΎΠ½ΠΈΠΌΠ°Π΅ΡΠ΅, ΡΡΠΎ Π΄Π΅Π»Π°Π΅ΡΠ΅.", |
| 93 | "Wrap in Quotes": "ΠΠ°ΠΊΠ»ΡΡΠ°ΡΡ Π² ΠΊΠ°Π²ΡΡΠΊΠΈ", | 90 | "Wrap in Quotes": "ΠΠ°ΠΊΠ»ΡΡΠ°ΡΡ Π² ΠΊΠ°Π²ΡΡΠΊΠΈ", |
| 94 | "Wrap entire user message in quotes before sending.": "ΠΠ΅ΡΠ΅Π΄ ΠΎΡΠΏΡΠ°Π²ΠΊΠΎΠΉ Π·Π°ΠΊΠ»ΡΡΠ°ΡΡ Π²ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π² ΠΊΠ°Π²ΡΡΠΊΠΈ.", | 91 | "Wrap entire user message in quotes before sending.": "ΠΠ΅ΡΠ΅Π΄ ΠΎΡΠΏΡΠ°Π²ΠΊΠΎΠΉ Π·Π°ΠΊΠ»ΡΡΠ°ΡΡ Π²ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ Π² ΠΊΠ°Π²ΡΡΠΊΠΈ.", |
| 95 | "Leave off if you use quotes manually for speech.": "ΠΡΡΠ°Π²ΡΡΠ΅ Π²ΡΠΊΠ»ΡΡΠ΅Π½Π½ΡΠΌ, Π΅ΡΠ»ΠΈ Π²ΡΡΡΠ½ΡΡ Π²ΡΡΡΠ°Π²Π»ΡΠ΅ΡΠ΅ ΠΊΠ°Π²ΡΡΠΊΠΈ Π΄Π»Ρ ΠΏΡΡΠΌΠΎΠΉ ΡΠ΅ΡΠΈ.", | 92 | "Leave off if you use quotes manually for speech.": "ΠΡΡΠ°Π²ΡΡΠ΅ Π²ΡΠΊΠ»ΡΡΠ΅Π½Π½ΡΠΌ, Π΅ΡΠ»ΠΈ Π²ΡΡΡΠ½ΡΡ Π²ΡΡΡΠ°Π²Π»ΡΠ΅ΡΠ΅ ΠΊΠ°Π²ΡΡΠΊΠΈ Π΄Π»Ρ ΠΏΡΡΠΌΠΎΠΉ ΡΠ΅ΡΠΈ.", |
| @@ -109,7 +106,7 @@ | |||
| 109 | "Adjust response length to worker capabilities": "ΠΠΎΠ΄ΡΡΡΠ°ΠΈΠ²Π°ΡΡ Π΄Π»ΠΈΠ½Ρ ΠΎΡΠ²Π΅ΡΠ° ΠΏΠΎΠ΄ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΡΠ°Π±ΠΎΡΠΈΡ ΠΌΠ°ΡΠΈΠ½", | 106 | "Adjust response length to worker capabilities": "ΠΠΎΠ΄ΡΡΡΠ°ΠΈΠ²Π°ΡΡ Π΄Π»ΠΈΠ½Ρ ΠΎΡΠ²Π΅ΡΠ° ΠΏΠΎΠ΄ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΡΠ°Π±ΠΎΡΠΈΡ ΠΌΠ°ΡΠΈΠ½", |
| 110 | "API key": "API-ΠΊΠ»ΡΡ", | 107 | "API key": "API-ΠΊΠ»ΡΡ", |
| 111 | "Tabby API key": "Tabby API-ΠΊΠ»ΡΡ", | 108 | "Tabby API key": "Tabby API-ΠΊΠ»ΡΡ", |
| 112 | "Get it here:": "ΠΠΎΠ»ΡΡΠΈΡΡ Π·Π΄Π΅ΡΡ:", | 109 | "Get it here:": "ΠΠΎΠ»ΡΡΠΈΡΠ΅ Π·Π΄Π΅ΡΡ:", |
| 113 | "Register": "ΠΠ°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°ΡΡΡΡ", | 110 | "Register": "ΠΠ°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°ΡΡΡΡ", |
| 114 | "TogetherAI Model": "ΠΠΎΠ΄Π΅Π»Ρ TogetherAI", | 111 | "TogetherAI Model": "ΠΠΎΠ΄Π΅Π»Ρ TogetherAI", |
| 115 | "Example: 127.0.0.1:5001": "ΠΡΠΈΠΌΠ΅Ρ: http://127.0.0.1:5001", | 112 | "Example: 127.0.0.1:5001": "ΠΡΠΈΠΌΠ΅Ρ: http://127.0.0.1:5001", |
| @@ -289,10 +286,10 @@ | |||
| 289 | "Author's Note": "ΠΠ°ΠΌΠ΅ΡΠΊΠΈ Π°Π²ΡΠΎΡΠ°", | 286 | "Author's Note": "ΠΠ°ΠΌΠ΅ΡΠΊΠΈ Π°Π²ΡΠΎΡΠ°", |
| 290 | "Replace empty message": "ΠΠ°ΠΌΠ΅Π½ΡΡΡ ΠΏΡΡΡΡΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ", | 287 | "Replace empty message": "ΠΠ°ΠΌΠ΅Π½ΡΡΡ ΠΏΡΡΡΡΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ", |
| 291 | "Send this text instead of nothing when the text box is empty.": "ΠΡΠΎΡ ΡΠ΅ΠΊΡΡ Π±ΡΠ΄Π΅Ρ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ Π² ΡΠ»ΡΡΠ°Π΅ ΠΎΡΡΡΡΡΡΠ²ΠΈΡ ΡΠ΅ΠΊΡΡΠ° Π½Π° ΠΎΡΠΏΡΠ°Π²ΠΊΡ.", | 288 | "Send this text instead of nothing when the text box is empty.": "ΠΡΠΎΡ ΡΠ΅ΠΊΡΡ Π±ΡΠ΄Π΅Ρ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ Π² ΡΠ»ΡΡΠ°Π΅ ΠΎΡΡΡΡΡΡΠ²ΠΈΡ ΡΠ΅ΠΊΡΡΠ° Π½Π° ΠΎΡΠΏΡΠ°Π²ΠΊΡ.", |
| 292 | "Unrestricted maximum value for the context slider": "Π£Π±ΡΠ°ΡΡ ΠΏΠΎΡΠΎΠ»ΠΎΠΊ Π΄Π»Ρ ΠΏΠΎΠ»Π·ΡΠ½ΠΊΠ° ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ°. ΠΠΊΠ»ΡΡΠ°ΠΉΡΠ΅ ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ ΡΠΎΡΠ½ΠΎ Π·Π½Π°Π΅ΡΠ΅, ΡΡΠΎ Π΄Π΅Π»Π°Π΅ΡΠ΅", | 289 | "Unrestricted maximum value for the context slider": "Π£Π±ΡΠ°ΡΡ ΠΏΠΎΡΠΎΠ»ΠΎΠΊ Π΄Π»Ρ ΠΏΠΎΠ»Π·ΡΠ½ΠΊΠ° ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ°. ΠΠΊΠ»ΡΡΠ°ΠΉΡΠ΅ ΡΠΎΠ»ΡΠΊΠΎ Π΅ΡΠ»ΠΈ ΡΠΎΡΠ½ΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°Π΅ΡΠ΅, ΡΡΠΎ Π΄Π΅Π»Π°Π΅ΡΠ΅", |
| 293 | "Chat Completion Source": "ΠΡΡΠΎΡΠ½ΠΈΠΊ Π΄Π»Ρ Chat Completion", | 290 | "Chat Completion Source": "ΠΡΡΠΎΡΠ½ΠΈΠΊ Π΄Π»Ρ Chat Completion", |
| 294 | "Avoid sending sensitive information to the Horde.": "ΠΠ·Π±Π΅Π³Π°ΠΉΡΠ΅ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ Π»ΠΈΡΠ½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ Horde", | 291 | "Avoid sending sensitive information to the Horde.": "ΠΠ·Π±Π΅Π³Π°ΠΉΡΠ΅ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ Π»ΠΈΡΠ½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ Horde.", |
| 295 | "Review the Privacy statement": "ΠΠ·Π½Π°ΠΊΠΎΠΌΠΈΡΡΡΡ Ρ Π·Π°ΡΠ²Π»Π΅Π½ΠΈΠ΅ΠΌ ΠΎ ΠΊΠΎΠ½ΡΠΈΠ΄Π΅Π½ΡΠΈΠ°Π»ΡΠ½ΠΎΡΡΠΈ", | 292 | "Review the Privacy statement": "ΠΠ·Π½Π°ΠΊΠΎΠΌΡΡΠ΅ΡΡ Ρ Π·Π°ΡΠ²Π»Π΅Π½ΠΈΠ΅ΠΌ ΠΎ ΠΊΠΎΠ½ΡΠΈΠ΄Π΅Π½ΡΠΈΠ°Π»ΡΠ½ΠΎΡΡΠΈ", |
| 296 | "Trusted workers only": "Π’ΠΎΠ»ΡΠΊΠΎ Π΄ΠΎΠ²Π΅ΡΠ΅Π½Π½ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈΠ΅ ΠΌΠ°ΡΠΈΠ½Ρ", | 293 | "Trusted workers only": "Π’ΠΎΠ»ΡΠΊΠΎ Π΄ΠΎΠ²Π΅ΡΠ΅Π½Π½ΡΠ΅ ΡΠ°Π±ΠΎΡΠΈΠ΅ ΠΌΠ°ΡΠΈΠ½Ρ", |
| 297 | "For privacy reasons, your API key will be hidden after you reload the page.": "ΠΠ· ΡΠΎΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ Π²Π°Ρ API-ΠΊΠ»ΡΡ Π±ΡΠ΄Π΅Ρ ΡΠΊΡΡΡ ΠΏΠΎΡΠ»Π΅ ΠΏΠ΅ΡΠ΅Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΡΡΡΠ°Π½ΠΈΡΡ.", | 294 | "For privacy reasons, your API key will be hidden after you reload the page.": "ΠΠ· ΡΠΎΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ Π²Π°Ρ API-ΠΊΠ»ΡΡ Π±ΡΠ΄Π΅Ρ ΡΠΊΡΡΡ ΠΏΠΎΡΠ»Π΅ ΠΏΠ΅ΡΠ΅Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΡΡΡΠ°Π½ΠΈΡΡ.", |
| 298 | "-- Horde models not loaded --": "--ΠΠΎΠ΄Π΅Π»Ρ Horde Π½Π΅ Π·Π°Π³ΡΡΠΆΠ΅Π½Π°--", | 295 | "-- Horde models not loaded --": "--ΠΠΎΠ΄Π΅Π»Ρ Horde Π½Π΅ Π·Π°Π³ΡΡΠΆΠ΅Π½Π°--", |
| @@ -699,7 +696,7 @@ | |||
| 699 | "Aggressive": "ΠΠ³ΡΠ΅ΡΡΠΈΠ²Π½ΡΠΉ", | 696 | "Aggressive": "ΠΠ³ΡΠ΅ΡΡΠΈΠ²Π½ΡΠΉ", |
| 700 | "Very aggressive": "ΠΡΠ΅Π½Ρ Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½ΡΠΉ", | 697 | "Very aggressive": "ΠΡΠ΅Π½Ρ Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½ΡΠΉ", |
| 701 | "Eta_Cutoff_desc": "Eta cutoff - ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΠΎΠΉ ΡΠ΅Ρ Π½ΠΈΠΊΠΈ ΡΡΠΌΠΏΠ»ΠΈΠ½Π³Π° ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Eta Sampling. Π Π΅Π΄ΠΈΠ½ΠΈΡΠ°Ρ 1e-4; ΡΠ°Π·ΡΠΌΠ½ΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ - 3. Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ Π² 0, ΡΡΠΎΠ±Ρ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ. Π‘ΠΌ. ΡΡΠ°ΡΡΡ Truncation Sampling as Language Model Desmoothing ΠΎΡ Π₯ΡΡΠΈΡΡ ΠΈ Π΄Ρ. (2022) Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ.", | 698 | "Eta_Cutoff_desc": "Eta cutoff - ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΠΎΠΉ ΡΠ΅Ρ Π½ΠΈΠΊΠΈ ΡΡΠΌΠΏΠ»ΠΈΠ½Π³Π° ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Eta Sampling. Π Π΅Π΄ΠΈΠ½ΠΈΡΠ°Ρ 1e-4; ΡΠ°Π·ΡΠΌΠ½ΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ - 3. Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ Π² 0, ΡΡΠΎΠ±Ρ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ. Π‘ΠΌ. ΡΡΠ°ΡΡΡ Truncation Sampling as Language Model Desmoothing ΠΎΡ Π₯ΡΡΠΈΡΡ ΠΈ Π΄Ρ. (2022) Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΠΉ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ.", |
| 702 | "Learn how to contribute your idle GPU cycles to the Horde": "Π£Π·Π½Π°ΠΉΡΠ΅, ΠΊΠ°ΠΊ Π²Π½Π΅ΡΡΠΈ ΡΠ²ΠΎΠΉ Π²ΠΊΠ»Π°Π΄ Π² ΡΠ²ΠΎΠΈ ΡΠ²ΠΎΠ±ΠΎΠ΄Π½ΡΠ΅ GPU-ΡΠΈΠΊΠ»Ρ Π² ΠΎΡΠ΄Ρ", | 699 | "Learn how to contribute your idle GPU cycles to the Horde": "Π£Π·Π½Π°ΠΉΡΠ΅, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π²ΡΠ΅ΠΌΡ ΠΏΡΠΎΡΡΠΎΡ Π²Π°ΡΠ΅Π³ΠΎ GPU Π΄Π»Ρ ΠΏΠΎΠΌΠΎΡΠΈ Horde", |
| 703 | "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠΈΠΉ ΡΠΎΠΊΠ΅Π½ΠΈΠ·Π°ΡΠΎΡ Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Google ΡΠ΅ΡΠ΅Π· ΠΈΡ API. ΠΠ΅Π΄Π»Π΅Π½Π½Π°Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΏΠΎΠ΄ΡΠΊΠ°Π·ΠΎΠΊ, Π½ΠΎ ΠΏΡΠ΅Π΄Π»Π°Π³Π°Π΅Ρ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ Π±ΠΎΠ»Π΅Π΅ ΡΠΎΡΠ½ΡΠΉ ΠΏΠΎΠ΄ΡΡΠ΅Ρ ΡΠΎΠΊΠ΅Π½ΠΎΠ².", | 700 | "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠΈΠΉ ΡΠΎΠΊΠ΅Π½ΠΈΠ·Π°ΡΠΎΡ Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ Google ΡΠ΅ΡΠ΅Π· ΠΈΡ API. ΠΠ΅Π΄Π»Π΅Π½Π½Π°Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΏΠΎΠ΄ΡΠΊΠ°Π·ΠΎΠΊ, Π½ΠΎ ΠΏΡΠ΅Π΄Π»Π°Π³Π°Π΅Ρ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ Π±ΠΎΠ»Π΅Π΅ ΡΠΎΡΠ½ΡΠΉ ΠΏΠΎΠ΄ΡΡΠ΅Ρ ΡΠΎΠΊΠ΅Π½ΠΎΠ².", |
| 704 | "Load koboldcpp order": "ΠΠ°Π³ΡΡΠ·ΠΈΡΡ ΠΏΠΎΡΡΠ΄ΠΎΠΊ ΠΈΠ· koboldcpp", | 701 | "Load koboldcpp order": "ΠΠ°Π³ΡΡΠ·ΠΈΡΡ ΠΏΠΎΡΡΠ΄ΠΎΠΊ ΠΈΠ· koboldcpp", |
| 705 | "Use Google Tokenizer": "ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠΎΠΊΠ΅Π½ΠΈΠ·Π°ΡΠΎΡ Google", | 702 | "Use Google Tokenizer": "ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠΎΠΊΠ΅Π½ΠΈΠ·Π°ΡΠΎΡ Google", |
| @@ -744,7 +741,7 @@ | |||
| 744 | "Last Assistant Prefix": "ΠΠΎΡΠ»Π΅Π΄Π½ΠΈΠΉ ΠΏΡΠ΅ΡΠΈΠΊΡ Π°ΡΡΠΈΡΡΠ΅Π½ΡΠ°", | 741 | "Last Assistant Prefix": "ΠΠΎΡΠ»Π΅Π΄Π½ΠΈΠΉ ΠΏΡΠ΅ΡΠΈΠΊΡ Π°ΡΡΠΈΡΡΠ΅Π½ΡΠ°", |
| 745 | "System Instruction Prefix": "ΠΡΠ΅ΡΠΈΠΊΡ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎΠΉ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΈ", | 742 | "System Instruction Prefix": "ΠΡΠ΅ΡΠΈΠΊΡ ΡΠΈΡΡΠ΅ΠΌΠ½ΠΎΠΉ ΠΈΠ½ΡΡΡΡΠΊΡΠΈΠΈ", |
| 746 | "User Filler Message": "ΠΡΠΈΠ½ΡΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ", | 743 | "User Filler Message": "ΠΡΠΈΠ½ΡΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ", |
| 747 | "Permanent": "ΠΏΠ΅ΡΠΌΠ°Π½Π΅Π½ΡΠ½ΡΡ ", | 744 | "Permanent": "ΠΏΠΎΡΡΠΎΡΠ½Π½ΡΡ ", |
| 748 | "Alt. Greetings": "ΠΡ. Π²Π°ΡΠΈΠ°Π½ΡΡ", | 745 | "Alt. Greetings": "ΠΡ. Π²Π°ΡΠΈΠ°Π½ΡΡ", |
| 749 | "Smooth Streaming": "ΠΠ»Π°Π²Π½ΡΠΉ ΡΡΡΠΈΠΌΠΈΠ½Π³", | 746 | "Smooth Streaming": "ΠΠ»Π°Π²Π½ΡΠΉ ΡΡΡΠΈΠΌΠΈΠ½Π³", |
| 750 | "Save checkpoint": "Π‘ΠΎΡ ΡΠ°Π½ΠΈΡΡ ΡΠ΅ΠΊΠΏΠΎΠΈΠ½Ρ", | 747 | "Save checkpoint": "Π‘ΠΎΡ ΡΠ°Π½ΠΈΡΡ ΡΠ΅ΠΊΠΏΠΎΠΈΠ½Ρ", |
| @@ -1227,7 +1224,6 @@ | |||
| 1227 | "JSON-serialized array of strings.": "Π‘ΠΏΠΈΡΠΎΠΊ ΡΡΡΠΎΠΊ Π² ΡΠΎΡΠΌΠ°ΡΠ΅ JSON.", | 1224 | "JSON-serialized array of strings.": "Π‘ΠΏΠΈΡΠΎΠΊ ΡΡΡΠΎΠΊ Π² ΡΠΎΡΠΌΠ°ΡΠ΅ JSON.", |
| 1228 | "Mirostat_desc": "Mirostat - ΡΠ²ΠΎΠ΅Π³ΠΎ ΡΠΎΠ΄Π° ΡΠ΅ΡΠΌΠΎΠΌΠ΅ΡΡ, ΠΈΠ·ΠΌΠ΅ΡΡΡΡΠΈΠΉ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π΄Π»Ρ Π²ΡΠ²ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ°.\nMirostat ΠΏΠΎΠ΄Π³ΠΎΠ½ΡΠ΅Ρ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅ΠΌΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ° ΠΊ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΠΈ Π²Ρ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ°, ΡΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΈΠ·Π±Π΅ΠΆΠ°ΡΡ ΠΏΠΎΠ²ΡΠΎΡΠΎΠ².\n(ΠΊΠΎΠ³Π΄Π° ΠΏΠΎ ΠΌΠ΅ΡΠ΅ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΡΠ΅ΠΊΡΡΠ° Π°Π²ΡΠΎΡΠ΅Π³ΡΠ΅ΡΡΠΈΠΎΠ½Π½ΡΠΌ ΠΈΠ½ΡΠ΅ΡΠ΅Π½ΡΠΎΠΌ, ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π²ΡΡ Π±ΠΎΠ»ΡΡΠ΅ ΠΏΡΠΈΠ±Π»ΠΈΠΆΠ°Π΅ΡΡΡ ΠΊ Π½ΡΠ»Ρ)\n Π° ΡΠ°ΠΊΠΆΠ΅ Π»ΠΎΠ²ΡΡΠΊΠΈ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΠΈ (ΠΊΠΎΠ³Π΄Π° ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π½Π°ΡΠΈΠ½Π°Π΅Ρ ΡΡ ΠΎΠ΄ΠΈΡΡ Π² ΡΡΠΎΡΠΎΠ½Ρ)\nΠΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΠ΅ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π² ΡΡΠ°ΡΡΠ΅ Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity by Basu et al. (2020).\nΠ Π΅ΠΆΠΈΠΌ Π²ΡΠ±ΠΈΡΠ°Π΅Ρ Π²Π΅ΡΡΠΈΡ Mirostat. 0=ΠΎΡΠΊΠ»ΡΡΠΈΡΡ, 1=Mirostat 1.0 (ΡΠΎΠ»ΡΠΊΠΎ llama.cpp), 2=Mirostat 2.0.", | 1225 | "Mirostat_desc": "Mirostat - ΡΠ²ΠΎΠ΅Π³ΠΎ ΡΠΎΠ΄Π° ΡΠ΅ΡΠΌΠΎΠΌΠ΅ΡΡ, ΠΈΠ·ΠΌΠ΅ΡΡΡΡΠΈΠΉ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π΄Π»Ρ Π²ΡΠ²ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ°.\nMirostat ΠΏΠΎΠ΄Π³ΠΎΠ½ΡΠ΅Ρ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅ΠΌΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ° ΠΊ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΠΈ Π²Ρ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΡΠ΅ΠΊΡΡΠ°, ΡΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΈΠ·Π±Π΅ΠΆΠ°ΡΡ ΠΏΠΎΠ²ΡΠΎΡΠΎΠ².\n(ΠΊΠΎΠ³Π΄Π° ΠΏΠΎ ΠΌΠ΅ΡΠ΅ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΡΠ΅ΠΊΡΡΠ° Π°Π²ΡΠΎΡΠ΅Π³ΡΠ΅ΡΡΠΈΠΎΠ½Π½ΡΠΌ ΠΈΠ½ΡΠ΅ΡΠ΅Π½ΡΠΎΠΌ, ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π²ΡΡ Π±ΠΎΠ»ΡΡΠ΅ ΠΏΡΠΈΠ±Π»ΠΈΠΆΠ°Π΅ΡΡΡ ΠΊ Π½ΡΠ»Ρ)\n Π° ΡΠ°ΠΊΠΆΠ΅ Π»ΠΎΠ²ΡΡΠΊΠΈ ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΠΈ (ΠΊΠΎΠ³Π΄Π° ΠΏΠ΅ΡΠΏΠ»Π΅ΠΊΡΠΈΡ Π½Π°ΡΠΈΠ½Π°Π΅Ρ ΡΡ ΠΎΠ΄ΠΈΡΡ Π² ΡΡΠΎΡΠΎΠ½Ρ)\nΠΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΠ΅ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π² ΡΡΠ°ΡΡΠ΅ Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity by Basu et al. (2020).\nΠ Π΅ΠΆΠΈΠΌ Π²ΡΠ±ΠΈΡΠ°Π΅Ρ Π²Π΅ΡΡΠΈΡ Mirostat. 0=ΠΎΡΠΊΠ»ΡΡΠΈΡΡ, 1=Mirostat 1.0 (ΡΠΎΠ»ΡΠΊΠΎ llama.cpp), 2=Mirostat 2.0.", |
| 1229 | "Helpful tip coming soon.": "ΠΠΎΠ΄ΡΠΊΠ°Π·ΠΊΡ ΡΠΊΠΎΡΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ.", | 1226 | "Helpful tip coming soon.": "ΠΠΎΠ΄ΡΠΊΠ°Π·ΠΊΡ ΡΠΊΠΎΡΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ.", |
| 1230 | "Temperature_Last_desc": "ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Temperature ΡΡΠΌΠΏΠ»Π΅Ρ Π² ΠΏΠΎΡΠ»Π΅Π΄Π½ΡΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ. ΠΡΠΎ ΠΏΠΎΡΡΠΈ Π²ΡΠ΅Π³Π΄Π° ΡΠ°Π·ΡΠΌΠ½ΠΎ.\nΠΡΠΈ Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ: ΡΠ½Π°ΡΠ°Π»Π° Π²ΡΠ±ΠΎΡΠΊΠ° Π½Π°Π±ΠΎΡΠ° ΠΏΡΠ°Π²Π΄ΠΎΠΏΠΎΠ΄ΠΎΠ±Π½ΡΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ², Π·Π°ΡΠ΅ΠΌ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Temperature Π΄Π»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠΈΡΠΎΠ²ΠΊΠΈ ΠΈΡ ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»ΡΠ½ΡΡ Π²Π΅ΡΠΎΡΡΠ½ΠΎΡΡΠ΅ΠΉ (ΡΠ΅Ρ Π½ΠΈΡΠ΅ΡΠΊΠΈ, Π»ΠΎΠ³ΠΈΡΠΎΠ²).\nΠΡΠΈ ΠΎΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ: ΡΠ½Π°ΡΠ°Π»Π° ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Temperature Π΄Π»Ρ ΠΊΠΎΡΡΠ΅ΠΊΡΠΈΡΠΎΠ²ΠΊΠΈ ΠΎΡΠ½ΠΎΡΠΈΡΠ΅Π»ΡΠ½ΡΡ Π²Π΅ΡΠΎΡΡΠ½ΠΎΡΡΠ΅ΠΉ ΠΠ‘ΠΠ₯ ΡΠΎΠΊΠ΅Π½ΠΎΠ², Π·Π°ΡΠ΅ΠΌ Π²ΡΠ±ΠΎΡΠΊΠ° ΠΏΡΠ°Π²Π΄ΠΎΠΏΠΎΠ΄ΠΎΠ±Π½ΡΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ² ΠΈΠ· ΡΡΠΎΠ³ΠΎ.\nΠΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Temperature Last ΡΠ²Π΅Π»ΠΈΡΠΈΠ²Π°Π΅Ρ Π²Π΅ΡΠΎΡΡΠ½ΠΎΡΡΠΈ Π² Ρ Π²ΠΎΡΡΠ΅ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΡ, ΡΡΠΎ ΡΠ²Π΅Π»ΠΈΡΠΈΠ²Π°Π΅Ρ ΡΠ°Π½ΡΡ ΠΏΠΎΠ»ΡΡΠΈΡΡ Π½Π΅ΡΠΎΠ³Π»Π°ΡΠΎΠ²Π°Π½Π½ΡΠΉ ΠΎΡΠ²Π΅Ρ.", | ||
| 1231 | "Speculative Ngram": "Speculative Ngram", | 1227 | "Speculative Ngram": "Speculative Ngram", |
| 1232 | "Use a different speculative decoding method without a draft model": "Use a different speculative decoding method without a draft model.\rUsing a draft model is preferred. Speculative ngram is not as effective.", | 1228 | "Use a different speculative decoding method without a draft model": "Use a different speculative decoding method without a draft model.\rUsing a draft model is preferred. Speculative ngram is not as effective.", |
| 1233 | "Spaces Between Special Tokens": "Spaces Between Special Tokens", | 1229 | "Spaces Between Special Tokens": "Spaces Between Special Tokens", |
| @@ -1734,7 +1730,7 @@ | |||
| 1734 | "markdown_hotkeys_desc": "ΠΠΊΠ»ΡΡΠΈΡΡ Π³ΠΎΡΡΡΠΈΠ΅ ΠΊΠ»Π°Π²ΠΈΡΠΈ Π΄Π»Ρ Π²ΡΡΠ°Π²ΠΊΠΈ ΡΠΈΠΌΠ²ΠΎΠ»ΠΎΠ² ΡΠ°Π·ΠΌΠ΅ΡΠΊΠΈ Π² Π½Π΅ΠΊΠΎΡΠΎΡΡΡ ΠΏΠΎΠ»ΡΡ Π²Π²ΠΎΠ΄Π°. Π‘ΠΌ. '/help hotkeys'.", | 1730 | "markdown_hotkeys_desc": "ΠΠΊΠ»ΡΡΠΈΡΡ Π³ΠΎΡΡΡΠΈΠ΅ ΠΊΠ»Π°Π²ΠΈΡΠΈ Π΄Π»Ρ Π²ΡΡΠ°Π²ΠΊΠΈ ΡΠΈΠΌΠ²ΠΎΠ»ΠΎΠ² ΡΠ°Π·ΠΌΠ΅ΡΠΊΠΈ Π² Π½Π΅ΠΊΠΎΡΠΎΡΡΡ ΠΏΠΎΠ»ΡΡ Π²Π²ΠΎΠ΄Π°. Π‘ΠΌ. '/help hotkeys'.", |
| 1735 | "Save and Update": "Π‘ΠΎΡ ΡΠ°Π½ΠΈΡΡ ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡΡ", | 1731 | "Save and Update": "Π‘ΠΎΡ ΡΠ°Π½ΠΈΡΡ ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡΡ", |
| 1736 | "Profile name:": "ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΏΡΠΎΡΠΈΠ»Ρ:", | 1732 | "Profile name:": "ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΏΡΠΎΡΠΈΠ»Ρ:", |
| 1737 | "API returned an error": "API Π²Π΅ΡΠ½ΡΠ»ΠΎ ΠΎΡΠΈΠ±ΠΊΡ", | 1733 | "API returned an error": "API ΠΎΡΠ²Π΅ΡΠΈΠ»ΠΎ ΠΎΡΠΈΠ±ΠΊΠΎΠΉ", |
| 1738 | "Failed to save preset": "ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΎΡ ΡΠ°Π½ΠΈΡΡ ΠΏΡΠ΅ΡΠ΅Ρ", | 1734 | "Failed to save preset": "ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΎΡ ΡΠ°Π½ΠΈΡΡ ΠΏΡΠ΅ΡΠ΅Ρ", |
| 1739 | "Preset name should be unique.": "ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΏΡΠ΅ΡΠ΅ΡΠ° Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΌ.", | 1735 | "Preset name should be unique.": "ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΏΡΠ΅ΡΠ΅ΡΠ° Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΌ.", |
| 1740 | "Invalid file": "ΠΠ΅Π²Π°Π»ΠΈΠ΄Π½ΡΠΉ ΡΠ°ΠΉΠ»", | 1736 | "Invalid file": "ΠΠ΅Π²Π°Π»ΠΈΠ΄Π½ΡΠΉ ΡΠ°ΠΉΠ»", |
| @@ -1756,8 +1752,7 @@ | |||
| 1756 | "dot quota_error": "ΠΈΠΌΠ΅Π΅ΡΡΡ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΊΡΠ΅Π΄ΠΈΡΠΎΠ².", | 1752 | "dot quota_error": "ΠΈΠΌΠ΅Π΅ΡΡΡ Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΠΊΡΠ΅Π΄ΠΈΡΠΎΠ².", |
| 1757 | "If you have sufficient credits, please try again later.": "ΠΡΠ»ΠΈ ΠΊΡΠ΅Π΄ΠΈΡΠΎΠ² Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ, ΡΠΎ ΠΏΠΎΠ²ΡΠΎΡΠΈΡΠ΅ ΠΏΠΎΠΏΡΡΠΊΡ ΠΏΠΎΠ·Π΄Π½Π΅Π΅.", | 1753 | "If you have sufficient credits, please try again later.": "ΠΡΠ»ΠΈ ΠΊΡΠ΅Π΄ΠΈΡΠΎΠ² Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ, ΡΠΎ ΠΏΠΎΠ²ΡΠΎΡΠΈΡΠ΅ ΠΏΠΎΠΏΡΡΠΊΡ ΠΏΠΎΠ·Π΄Π½Π΅Π΅.", |
| 1758 | "Proxy preset '${0}' not found": "ΠΡΠ΅ΡΠ΅Ρ '${0}' Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½", | 1754 | "Proxy preset '${0}' not found": "ΠΡΠ΅ΡΠ΅Ρ '${0}' Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½", |
| 1759 | "Window.ai returned an error": "Window.ai Π²Π΅ΡΠ½ΡΠ» ΠΎΡΠΈΠ±ΠΊΡ", | 1755 | "Window.ai returned an error": "Window.ai ΠΎΡΠ²Π΅ΡΠΈΠ» ΠΎΡΠΈΠ±ΠΊΠΎΠΉ", |
| 1760 | "Get it here:": "ΠΠ°Π³ΡΡΠ·ΠΈΡΠ΅ Π·Π΄Π΅ΡΡ:", | ||
| 1761 | "Extension is not installed": "Π Π°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅ Π½Π΅ ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΎ", | 1756 | "Extension is not installed": "Π Π°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅ Π½Π΅ ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½ΠΎ", |
| 1762 | "Update or remove your reverse proxy settings.": "ΠΠ·ΠΌΠ΅Π½ΠΈΡΠ΅ ΠΈΠ»ΠΈ ΡΠ΄Π°Π»ΠΈΡΠ΅ Π²Π°ΡΠΈ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΡΠΎΠΊΡΠΈ.", | 1757 | "Update or remove your reverse proxy settings.": "ΠΠ·ΠΌΠ΅Π½ΠΈΡΠ΅ ΠΈΠ»ΠΈ ΡΠ΄Π°Π»ΠΈΡΠ΅ Π²Π°ΡΠΈ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΡΠΎΠΊΡΠΈ.", |
| 1763 | "An error occurred while importing prompts. More info available in console.": "Π ΠΏΡΠΎΡΠ΅ΡΡΠ΅ ΠΈΠΌΠΏΠΎΡΡΠ° ΠΏΡΠΎΠΈΠ·ΠΎΡΠ»Π° ΠΎΡΠΈΠ±ΠΊΠ°. ΠΠΎΠ΄ΡΠΎΠ±Π½ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΡΠΌ. Π² ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ.", | 1758 | "An error occurred while importing prompts. More info available in console.": "Π ΠΏΡΠΎΡΠ΅ΡΡΠ΅ ΠΈΠΌΠΏΠΎΡΡΠ° ΠΏΡΠΎΠΈΠ·ΠΎΡΠ»Π° ΠΎΡΠΈΠ±ΠΊΠ°. ΠΠΎΠ΄ΡΠΎΠ±Π½ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΡΠΌ. Π² ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ.", |
| @@ -1866,7 +1861,7 @@ | |||
| 1866 | "Group Chat could not be saved": "ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΎΡ ΡΠ°Π½ΠΈΡΡ Π³ΡΡΠΏΠΏΠΎΠ²ΠΎΠΉ ΡΠ°Ρ", | 1861 | "Group Chat could not be saved": "ΠΠ΅ ΡΠ΄Π°Π»ΠΎΡΡ ΡΠΎΡ ΡΠ°Π½ΠΈΡΡ Π³ΡΡΠΏΠΏΠΎΠ²ΠΎΠΉ ΡΠ°Ρ", |
| 1867 | "Deleted group member swiped. To get a reply, add them back to the group.": "ΠΡ ΠΏΡΡΠ°Π΅ΡΠ΅ΡΡ ΡΠ²Π°ΠΉΠΏΠ½ΡΡΡ ΡΠ΄Π°Π»ΡΠ½Π½ΠΎΠ³ΠΎ ΡΠ»Π΅Π½Π° Π³ΡΡΠΏΠΏΡ. Π§ΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΎΡΠ²Π΅Ρ, Π΄ΠΎΠ±Π°Π²ΡΡΠ΅ ΡΡΠΎΠ³ΠΎ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ° ΠΎΠ±ΡΠ°ΡΠ½ΠΎ Π² Π³ΡΡΠΏΠΏΡ.", | 1862 | "Deleted group member swiped. To get a reply, add them back to the group.": "ΠΡ ΠΏΡΡΠ°Π΅ΡΠ΅ΡΡ ΡΠ²Π°ΠΉΠΏΠ½ΡΡΡ ΡΠ΄Π°Π»ΡΠ½Π½ΠΎΠ³ΠΎ ΡΠ»Π΅Π½Π° Π³ΡΡΠΏΠΏΡ. Π§ΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΎΡΠ²Π΅Ρ, Π΄ΠΎΠ±Π°Π²ΡΡΠ΅ ΡΡΠΎΠ³ΠΎ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ° ΠΎΠ±ΡΠ°ΡΠ½ΠΎ Π² Π³ΡΡΠΏΠΏΡ.", |
| 1868 | "Currently no group selected.": "Π Π΄Π°Π½Π½ΡΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ Π½Π΅ Π²ΡΠ±ΡΠ°Π½ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎΠΉ Π³ΡΡΠΏΠΏΡ.", | 1863 | "Currently no group selected.": "Π Π΄Π°Π½Π½ΡΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ Π½Π΅ Π²ΡΠ±ΡΠ°Π½ΠΎ Π½ΠΈ ΠΎΠ΄Π½ΠΎΠΉ Π³ΡΡΠΏΠΏΡ.", |
| 1869 | "Not so fast! Wait for the characters to stop typing before deleting the group.": "Π§ΡΡΡ ΠΏΠΎΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅! ΠΠ΅ΡΠ΅Π΄ ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ΠΌ Π³ΡΡΠΏΠΏΡ Π΄ΠΎΠΆΠ΄ΠΈΡΠ΅ΡΡ, ΠΏΠΎΠΊΠ° ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆ Π·Π°ΠΊΠΎΠ½ΡΠΈΡ ΠΏΠ΅ΡΠ°ΡΠ°ΡΡ.", | 1864 | "Not so fast! Wait for the characters to stop typing before deleting the group.": "Π§ΡΡΡ ΠΏΠΎΠΌΠ΅Π΄Π»Π΅Π½Π½Π΅Π΅! ΠΠ΅ΡΠ΅Π΄ ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ΠΌ Π³ΡΡΠΏΠΏΡ Π΄ΠΎΠΆΠ΄ΠΈΡΠ΅ΡΡ, ΠΏΠΎΠΊΠ° ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠΈ Π·Π°ΠΊΠΎΠ½ΡΠ°Ρ ΠΏΠ΅ΡΠ°ΡΠ°ΡΡ.", |
| 1870 | "Delete the group?": "Π£Π΄Π°Π»ΠΈΡΡ Π³ΡΡΠΏΠΏΡ?", | 1865 | "Delete the group?": "Π£Π΄Π°Π»ΠΈΡΡ Π³ΡΡΠΏΠΏΡ?", |
| 1871 | "This will also delete all your chats with that group. If you want to delete a single conversation, select a \"View past chats\" option in the lower left menu.": "ΠΠΌΠ΅ΡΡΠ΅ Ρ Π½Π΅ΠΉ Π±ΡΠ΄ΡΡ ΡΠ΄Π°Π»Π΅Π½Ρ ΠΈ Π²ΡΠ΅ Π΅Ρ ΡΠ°ΡΡ. ΠΡΠ»ΠΈ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΡΠ΄Π°Π»ΠΈΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΎΠ΄ΠΈΠ½ ΡΠ°Ρ, Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ΡΡ ΠΊΠ½ΠΎΠΏΠΊΠΎΠΉ \"ΠΡΠ΅ ΡΠ°ΡΡ\" Π² ΠΌΠ΅Π½Ρ Π² Π»Π΅Π²ΠΎΠΌ Π½ΠΈΠΆΠ½Π΅ΠΌ ΡΠ³Π»Ρ.", | 1866 | "This will also delete all your chats with that group. If you want to delete a single conversation, select a \"View past chats\" option in the lower left menu.": "ΠΠΌΠ΅ΡΡΠ΅ Ρ Π½Π΅ΠΉ Π±ΡΠ΄ΡΡ ΡΠ΄Π°Π»Π΅Π½Ρ ΠΈ Π²ΡΠ΅ Π΅Ρ ΡΠ°ΡΡ. ΠΡΠ»ΠΈ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΡΠ΄Π°Π»ΠΈΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΎΠ΄ΠΈΠ½ ΡΠ°Ρ, Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ΡΡ ΠΊΠ½ΠΎΠΏΠΊΠΎΠΉ \"ΠΡΠ΅ ΡΠ°ΡΡ\" Π² ΠΌΠ΅Π½Ρ Π² Π»Π΅Π²ΠΎΠΌ Π½ΠΈΠΆΠ½Π΅ΠΌ ΡΠ³Π»Ρ.", |
| 1872 | "Can't peek a character while group reply is being generated": "ΠΠ΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡΠΊΡΡΡΡ ΠΊΠ°ΡΡΠΎΡΠΊΡ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ° Π²ΠΎ Π²ΡΠ΅ΠΌΡ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΠΎΡΠ²Π΅ΡΠ°", | 1867 | "Can't peek a character while group reply is being generated": "ΠΠ΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡΠΊΡΡΡΡ ΠΊΠ°ΡΡΠΎΡΠΊΡ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ° Π²ΠΎ Π²ΡΠ΅ΠΌΡ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΠΈ ΠΎΡΠ²Π΅ΡΠ°", |
| @@ -1997,7 +1992,7 @@ | |||
| 1997 | "Default persona deleted": "Π£Π΄Π°Π»Π΅Π½Π° ΠΏΠ΅ΡΡΠΎΠ½Π° ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ", | 1992 | "Default persona deleted": "Π£Π΄Π°Π»Π΅Π½Π° ΠΏΠ΅ΡΡΠΎΠ½Π° ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ", |
| 1998 | "The locked persona was deleted. You will need to set a new persona for this chat.": "Π£Π΄Π°Π»Π΅Π½Π° ΠΏΡΠΈΠ²ΡΠ·Π°Π½Π½Π°Ρ ΠΊ ΡΠ°ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Π°. ΠΠ°ΠΌ Π±ΡΠ΄Π΅Ρ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π²ΡΠ±ΡΠ°ΡΡ Π½ΠΎΠ²ΡΡ ΡΠΈΠΊΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΡΠ°ΡΠ°.", | 1993 | "The locked persona was deleted. You will need to set a new persona for this chat.": "Π£Π΄Π°Π»Π΅Π½Π° ΠΏΡΠΈΠ²ΡΠ·Π°Π½Π½Π°Ρ ΠΊ ΡΠ°ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Π°. ΠΠ°ΠΌ Π±ΡΠ΄Π΅Ρ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π²ΡΠ±ΡΠ°ΡΡ Π½ΠΎΠ²ΡΡ ΡΠΈΠΊΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΡΠ°ΡΠ°.", |
| 1999 | "Persona deleted": "ΠΠ΅ΡΡΠΎΠ½Π° ΡΠ΄Π°Π»Π΅Π½Π°", | 1994 | "Persona deleted": "ΠΠ΅ΡΡΠΎΠ½Π° ΡΠ΄Π°Π»Π΅Π½Π°", |
| 2000 | "You must bind a name to this persona before you can set it as the default.": "ΠΡΠ΅ΠΆΠ΄Π΅ ΡΠ΅ΠΌ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ, Π΅ΠΉ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π·Π°Π΄Π°ΡΡ ΠΈΠΌΡ.", | 1995 | "You must bind a name to this persona before you can set it as the default.": "ΠΡΠ΅ΠΆΠ΄Π΅ ΡΠ΅ΠΌ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ, Π΅ΠΉ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΡΠΈΡΠ²ΠΎΠΈΡΡ ΠΈΠΌΡ.", |
| 2001 | "Persona name not set": "Π£ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΎΡΡΡΡΡΡΠ²ΡΠ΅Ρ ΠΈΠΌΡ", | 1996 | "Persona name not set": "Π£ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΎΡΡΡΡΡΡΠ²ΡΠ΅Ρ ΠΈΠΌΡ", |
| 2002 | "Are you sure you want to remove the default persona?": "ΠΡ ΡΠΎΡΠ½ΠΎ Ρ ΠΎΡΠΈΡΠ΅ ΡΠ½ΡΡΡ ΡΡΠ°ΡΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ?", | 1997 | "Are you sure you want to remove the default persona?": "ΠΡ ΡΠΎΡΠ½ΠΎ Ρ ΠΎΡΠΈΡΠ΅ ΡΠ½ΡΡΡ ΡΡΠ°ΡΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ?", |
| 2003 | "This persona will no longer be used by default when you open a new chat.": "ΠΡΠ° ΠΏΠ΅ΡΡΠΎΠ½Π° Π±ΠΎΠ»ΡΡΠ΅ Π½Π΅ Π±ΡΠ΄Π΅Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π²ΡΠ±ΠΈΡΠ°ΡΡΡΡ ΠΏΡΠΈ ΡΡΠ°ΡΡΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΡΠ°ΡΠ°", | 1998 | "This persona will no longer be used by default when you open a new chat.": "ΠΡΠ° ΠΏΠ΅ΡΡΠΎΠ½Π° Π±ΠΎΠ»ΡΡΠ΅ Π½Π΅ Π±ΡΠ΄Π΅Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π²ΡΠ±ΠΈΡΠ°ΡΡΡΡ ΠΏΡΠΈ ΡΡΠ°ΡΡΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΡΠ°ΡΠ°", |
| @@ -2203,5 +2198,146 @@ | |||
| 2203 | "Input:": "ΠΡ ΠΎΠ΄Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅:", | 2198 | "Input:": "ΠΡ ΠΎΠ΄Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅:", |
| 2204 | "Tokenized text:": "Π’ΠΎΠΊΠ΅Π½ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΡΠ΅ΠΊΡΡ:", | 2199 | "Tokenized text:": "Π’ΠΎΠΊΠ΅Π½ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ ΡΠ΅ΠΊΡΡ:", |
| 2205 | "Token IDs:": "ΠΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ²:", | 2200 | "Token IDs:": "ΠΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡ ΡΠΎΠΊΠ΅Π½ΠΎΠ²:", |
| 2206 | "Tokens:": "Π’ΠΎΠΊΠ΅Π½ΠΎΠ²:" | 2201 | "Tokens:": "Π’ΠΎΠΊΠ΅Π½ΠΎΠ²:", |
| 2202 | "Max prompt cost:": "ΠΠ°ΠΊΡ. ΡΡΠΎΠΈΠΌΠΎΡΡΡ ΠΏΡΠΎΠΌΠΏΡΠ°:", | ||
| 2203 | "Reset custom sampler selection": "Π‘Π±ΡΠΎΡΠΈΡΡ ΠΏΠΎΠ΄Π±ΠΎΡΠΊΡ ΡΠ΅ΠΌΠΏΠ»Π΅ΡΠΎΠ²", | ||
| 2204 | "Here you can toggle the display of individual samplers. (WIP)": "ΠΠ΄Π΅ΡΡ ΠΌΠΎΠΆΠ½ΠΎ Π²ΠΊΠ»ΡΡΠΈΡΡ ΠΈΠ»ΠΈ Π²ΡΠΊΠ»ΡΡΠΈΡΡ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΈΠ· ΡΡΠΌΠΏΠ»Π΅ΡΠΎΠ² ΠΎΡΠ΄Π΅Π»ΡΠ½ΠΎ. (WIP)", | ||
| 2205 | "Request Model Reasoning": "ΠΠ°ΠΏΡΠ°ΡΠΈΠ²Π°ΡΡ ΡΠ΅ΠΏΠΎΡΠΊΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ", | ||
| 2206 | "Reasoning": "Π Π°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ / Reasoning", | ||
| 2207 | "Auto-Parse": "ΠΠ²ΡΠΎ-ΠΏΠ°ΡΡΠΈΠ½Π³", | ||
| 2208 | "reasoning_auto_parse": "ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΡΠΈΡΡΠ²Π°ΡΡ Π±Π»ΠΎΠΊΠΈ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ, ΡΠ°ΡΠΏΠΎΠ»ΠΎΠΆΠ΅Π½Π½ΡΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠ΅ΡΠΈΠΊΡΠΎΠΌ ΠΈ ΡΡΡΡΠΈΠΊΡΠΎΠΌ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ. ΠΠ»Ρ ΡΠ°Π±ΠΎΡΡ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ ΡΠΊΠ°Π·Π°Π½ΠΎ ΠΈ ΡΠΎ, ΠΈ Π΄ΡΡΠ³ΠΎΠ΅.", | ||
| 2209 | "Auto-Expand": "Π Π°Π·Π²ΠΎΡΠ°ΡΠΈΠ²Π°ΡΡ", | ||
| 2210 | "reasoning_auto_expand": "ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠ°Π·Π²ΠΎΡΠ°ΡΠΈΠ²Π°ΡΡ Π±Π»ΠΎΠΊΠΈ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ.", | ||
| 2211 | "Show Hidden": "ΠΠΎΠΊΠ°Π·ΡΠ²Π°ΡΡ Π²ΡΠ΅ΠΌΡ", | ||
| 2212 | "reasoning_show_hidden": "ΠΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡ Π·Π°ΡΡΠ°ΡΠ΅Π½Π½ΠΎΠ΅ Π½Π° ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ Π²ΡΠ΅ΠΌΡ Π΄Π»Ρ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ ΡΠΎ ΡΠΊΡΡΡΠΎΠΉ ΡΠ΅ΠΏΠΎΡΠΊΠΎΠΉ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ", | ||
| 2213 | "Add to Prompts": "ΠΠΎΠ±Π°Π²Π»ΡΡΡ Π² ΠΏΡΠΎΠΌΠΏΡ", | ||
| 2214 | "reasoning_add_to_prompts": "ΠΠΎΠ±Π°Π²Π»ΡΡΡ ΡΡΡΠ΅ΡΡΠ²ΡΡΡΠΈΠ΅ Π±Π»ΠΎΠΊΠΈ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ Π² ΠΏΡΠΎΠΌΠΏΡ. ΠΠ»Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ Π½ΠΎΠ²ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ ΠΌΠ΅Π½Ρ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ.", | ||
| 2215 | "reasoning_max_additions": "ΠΠ°ΠΊΡ. ΠΊΠΎΠ»-Π²ΠΎ Π±Π»ΠΎΠΊΠΎΠ² ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ Π² ΠΏΡΠΎΠΌΠΏΡΠ΅, ΡΡΠΈΡΠ°Π΅ΡΡΡ ΠΎΡ ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅Π³ΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ", | ||
| 2216 | "Max": "ΠΠ°ΠΊΡ.", | ||
| 2217 | "Reasoning Formatting": "Π€ΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ", | ||
| 2218 | "Prefix": "ΠΡΠ΅ΡΠΈΠΊΡ", | ||
| 2219 | "Suffix": "ΠΠΎΡΡΡΠΈΠΊΡ", | ||
| 2220 | "Separator": "Π Π°Π·Π΄Π΅Π»ΠΈΡΠ΅Π»Ρ", | ||
| 2221 | "reasoning_separator": "ΠΡΡΠ°Π²Π»ΡΠ΅ΡΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡΠΌΠΈ ΠΈ ΡΠΎΠ΄Π΅ΡΠΆΠ°Π½ΠΈΠ΅ΠΌ ΡΠ°ΠΌΠΎΠ³ΠΎ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ.", | ||
| 2222 | "reasoning_prefix": "ΠΡΡΠ°Π²Π»ΡΠ΅ΡΡΡ ΠΏΠ΅ΡΠ΅Π΄ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡΠΌΠΈ.", | ||
| 2223 | "reasoning_suffix": "ΠΡΡΠ°Π²Π»ΡΠ΅ΡΡΡ ΠΏΠΎΡΠ»Π΅ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ.", | ||
| 2224 | "Seed_desc": "Π€ΠΈΠΊΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ Π·Π΅ΡΠ½Π° ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΏΠΎΠ»ΡΡΠ°ΡΡ ΠΏΡΠ΅Π΄ΡΠΊΠ°Π·ΡΠ΅ΠΌΡΠ΅, ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΡΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ Π½Π° ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΡΡ Π½Π°ΡΡΡΠΎΠΉΠΊΠ°Ρ . ΠΠΎΡΡΠ°Π²ΡΡΠ΅ -1 Π΄Π»Ρ ΡΠ°Π½Π΄ΠΎΠΌΠ½ΠΎΠ³ΠΎ Π·Π΅ΡΠ½Π°.", | ||
| 2225 | "# of Beams": "ΠΠΎΠ»-Π²ΠΎ Π»ΡΡΠ΅ΠΉ", | ||
| 2226 | "The number of sequences generated at each step with Beam Search.": "ΠΠΎΠ»-Π²ΠΎ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ², Π³Π΅Π½Π΅ΡΠΈΡΡΠ΅ΠΌΡΡ Beam Search Π½Π° ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΡΠ°Π³Π΅ ΡΠ°Π±ΠΎΡΡ.", | ||
| 2227 | "Penalize sequences based on their length.": "Π¨ΡΡΠ°ΡΡΠ΅Ρ ΡΡΡΠΎΠΊΠΈ Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ Π΄Π»ΠΈΠ½Ρ", | ||
| 2228 | "Controls the stopping condition for beam search. If checked, the generation stops as soon as there are '# of Beams' sequences. If not checked, a heuristic is applied and the generation is stopped when it's very unlikely to find better candidates.": "ΠΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ, ΠΊΠΎΠ³Π΄Π° ΠΎΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°ΡΡ ΡΠ°Π±ΠΎΡΡ Beam Search. ΠΠΎΡΡΠ°Π²ΠΈΠ² Π³Π°Π»ΠΎΡΠΊΡ, Π²Ρ ΡΠΊΠ°ΠΆΠ΅ΡΠ΅ ΠΏΠΎΠΈΡΠΊΡ ΠΎΡΡΠ°Π½ΠΎΠ²ΠΈΡΡΡΡ ΡΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° Π±ΡΠ΄Π΅Ρ Π΄ΠΎΡΡΠΈΠ³Π½ΡΡΠΎ ΠΊΠΎΠ»-Π²ΠΎ Π»ΡΡΠ΅ΠΉ ΠΈΠ· ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅Π³ΠΎ ΠΏΠΎΠ»Ρ. ΠΡΠ»ΠΈ Π³Π°Π»ΠΎΡΠΊΡ Π½Π΅ ΠΎΡΠΌΠ΅ΡΠ°ΡΡ, ΡΠΎ Π³Π΅Π½Π΅ΡΠ°ΡΠΈΡ ΠΎΡΡΠ°Π½ΠΎΠ²ΠΈΡΡΡ ΡΠΎΠ³Π΄Π°, ΠΊΠΎΠ³Π΄Π° ΡΠΎΡΡΡΡ, ΡΡΠΎ Π΄Π°Π»ΡΡΠ΅ Π½Π°ΠΉΡΠΈ Π»ΡΡΡΠΈΡ ΠΊΠ°Π½Π΄ΠΈΠ΄Π°ΡΠΎΠ² ΡΠ»ΠΈΡΠΊΠΎΠΌ ΠΌΠ°Π»ΠΎΠ²Π΅ΡΠΎΡΡΠ½ΠΎ.", | ||
| 2229 | "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-ΡΡΠΌΠΏΠ»ΠΈΠ½Π³Π°, ΠΏΠΎΠ΄Π±ΠΈΡΠ°ΡΡΠΈΠΉ Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ Π²Π΅ΡΠΎΡΡΠ½ΡΡ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»ΡΠ½ΠΎΡΡΡ ΡΠ»ΠΎΠ² ΠΈΠ»ΠΈ ΡΠΎΠΊΠ΅Π½ΠΎΠ² ΠΏΡΡΡΠΌ ΠΈΡΡΠ»Π΅Π΄ΠΎΠ²Π°Π½ΠΈΡ ΠΈ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ ΡΡΠ°Π·Ρ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΈΡ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ². ΠΠ° ΠΊΠ°ΠΆΠ΄ΠΎΠΌ ΡΠ°Π³Π΅ ΠΎΠ½ ΡΠ΄Π΅ΡΠΆΠΈΠ²Π°Π΅Ρ ΡΠΈΠΊΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΠΊΠΎΠ»-Π²ΠΎ ΡΠ°ΠΌΡΡ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ΡΡΠΈΡ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ² (ΡΠΈΡΠΈΠ½Π° Π»ΡΡΠ°).", | ||
| 2230 | "Smooth_Sampling_desc": "ΠΠ·ΠΌΠ΅Π½ΡΠ΅Ρ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΊΠ²Π°Π΄ΡΠ°ΡΠΈΡΠ½ΡΡ ΠΈ ΠΊΡΠ±ΠΈΡΠ΅ΡΠΊΠΈΡ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½ΠΈΠΉ. Π‘Π½ΠΈΠΆΠ΅Π½ΠΈΠ΅ ΠΠΎΡΡΡΠΈΡΠΈΠ΅Π½ΡΠ° ΡΠ³Π»Π°ΠΆΠΈΠ²Π°Π½ΠΈΡ Π΄Π°ΡΡ Π±ΠΎΠ»Π΅Π΅ ΠΊΡΠ΅Π°ΡΠΈΠ²Π½ΡΠ΅ ΠΎΡΠ²Π΅ΡΡ, ΠΎΠ±ΡΡΠ½ΠΎ ΠΈΠ΄Π΅Π°Π»ΡΠ½ΠΎΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ Π² Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π΅ 0.2-0.3 (ΠΏΡΠΈ ΠΊΡΠΈΠ²ΠΎΠΉ ΡΠ³Π»Π°ΠΆΠΈΠ²Π°Π½ΠΈΡ=1.0). ΠΠΎΠ²ΡΡΠ΅Π½ΠΈΠ΅ Π·Π½Π°ΡΠ΅Π½ΠΈΡ ΠΡΠΈΠ²ΠΎΠΉ ΡΠ³Π»Π°ΠΆΠΈΠ²Π°Π½ΠΈΡ ΡΠ΄Π΅Π»Π°Π΅Ρ ΠΊΡΠΈΠ²ΡΡ ΠΊΡΡΡΠ΅, ΡΡΠΎ ΠΏΡΠΈΠ²Π΅Π΄ΡΡ ΠΊ Π±ΠΎΠ»Π΅Π΅ Π°Π³ΡΠ΅ΡΡΠΈΠ²Π½ΠΎΠΉ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠΈ ΠΌΠ°Π»ΠΎΠ²Π΅ΡΠΎΡΡΠ½ΡΡ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ². Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΠ² ΠΡΠΈΠ²ΡΡ ΡΠ³Π»Π°ΠΆΠΈΠ²Π°Π½ΠΈΡ = 1.0, Π²Ρ ΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ Π½Π΅ΠΉΡΡΠ°Π»ΠΈΠ·ΡΠ΅ΡΠ΅ ΡΡΠΎΡ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ ΠΈ Π±ΡΠ΄Π΅ΡΠ΅ ΡΠ°Π±ΠΎΡΠ°ΡΡ ΡΠΎΠ»ΡΠΊΠΎ Ρ ΠΠΎΡΡΡΠΈΡΠΈΠ΅Π½ΡΠΎΠΌ", | ||
| 2231 | "Temperature_Last_desc": "ΠΡΠΈΠΌΠ΅Π½ΡΡΡ ΡΡΠΌΠΏΠ»Π΅Ρ Π’Π΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΡ Π² ΠΏΠΎΡΠ»Π΅Π΄Π½ΡΡ ΠΎΡΠ΅ΡΠ΅Π΄Ρ. ΠΠΎΡΡΠΈ Π²ΡΠ΅Π³Π΄Π° ΠΎΠΏΡΠ°Π²Π΄Π°Π½ΠΎ.\nΠΡΠΈ Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ: ΡΠ½Π°ΡΠ°Π»Π° Π²ΡΠ΅ ΡΠΎΠΊΠ΅Π½Ρ ΡΠ΅ΠΌΠΏΠ»ΠΈΡΡΡΡΡΡ, ΠΈ Π·Π°ΡΠ΅ΠΌ ΡΠ΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΠ° ΡΠ΅Π³ΡΠ»ΠΈΡΡΠ΅Ρ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ Ρ ΠΎΡΡΠ°Π²ΡΠΈΡ ΡΡ (ΡΠ΅Ρ Π½ΠΈΡΠ΅ΡΠΊΠΈ, Ρ ΠΎΡΡΠ°Π²ΡΠΈΡ ΡΡ Π»ΠΎΠ³ΠΈΡΠΎΠ²).\nΠΡΠΈ Π²ΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ: ΡΠ½Π°ΡΠ°Π»Π° ΡΠ΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΠ° Π½Π°ΡΡΡΠ°ΠΈΠ²Π°Π΅Ρ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΠ‘ΠΠ₯ ΡΠΎΠΊΠ΅Π½ΠΎΠ², ΠΈ ΠΏΠΎΡΠΎΠΌ ΠΎΠ½ΠΈ ΡΠ΅ΠΌΠΏΠ»ΠΈΡΡΡΡΡΡ ΡΠΆΠ΅ Ρ ΡΡΠΈΠΌ ΠΎΠ±Π½ΠΎΠ²Π»ΡΠ½Π½ΡΠΌ ΡΠ°ΡΠΏΡΠ΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ΠΌ.\nΠΡΠΈ ΠΎΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ ΡΡΠΎΠΉ ΠΎΠΏΡΠΈΠΈ ΡΠΎΠΊΠ΅Π½Ρ Π² Ρ Π²ΠΎΡΡΠ΅ ΠΏΠΎΠ»ΡΡΠ°ΡΡ Π±ΠΎΠ»ΡΡΠ΅ ΡΠ°Π½ΡΠΎΠ² ΠΏΠΎΠΏΠ°ΡΡΡ Π² ΠΈΡΠΎΠ³ΠΎΠ²ΡΡ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»ΡΠ½ΠΎΡΡΡ, ΡΡΠΎ ΠΌΠΎΠΆΠ΅Ρ ΠΏΡΠΈΠ²Π΅ΡΡΠΈ ΠΊ ΠΌΠ΅Π½Π΅Π΅ ΡΠ²ΡΠ·Π½ΡΠΌ ΠΈ Π»ΠΎΠ³ΠΈΡΠ½ΡΠΌ ΠΎΡΠ²Π΅ΡΠ°ΠΌ.", | ||
| 2232 | "Swipe # for All Messages": "ΠΠΎΠΌΠ΅Ρ ΡΠ²Π°ΠΉΠΏΠ° Π½Π° Π²ΡΠ΅Ρ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡΡ ", | ||
| 2233 | "Display swipe numbers for all messages, not just the last.": "ΠΡΠΎΠ±ΡΠ°ΠΆΠ°ΡΡ Π½ΠΎΠΌΠ΅Ρ ΡΠ²Π°ΠΉΠΏΠ° Π΄Π»Ρ Π²ΡΠ΅Ρ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ, Π° Π½Π΅ ΡΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅Π³ΠΎ.", | ||
| 2234 | "Penalty Range": "ΠΠΊΠ½ΠΎ Π΄Π»Ρ ΡΡΡΠ°ΡΠ°", | ||
| 2235 | "Never": "ΠΠΈΠΊΠΎΠ³Π΄Π°", | ||
| 2236 | "Groups and Past Personas": "ΠΠ»Ρ Π³ΡΡΠΏΠΏ ΠΈ ΠΏΡΠΎΡΠ»ΡΡ ΠΏΠ΅ΡΡΠΎΠ½", | ||
| 2237 | "Always": "ΠΡΠ΅Π³Π΄Π°", | ||
| 2238 | "Request model reasoning": "ΠΠ°ΠΏΡΠ°ΡΠΈΠ²Π°ΡΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ", | ||
| 2239 | "Allows the model to return its thinking process.": "ΠΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΌΠΎΠ΄Π΅Π»ΠΈ Π²ΡΡΡΠ»Π°ΡΡ Π² ΠΎΡΠ²Π΅ΡΠ΅ ΡΠ²ΠΎΡ ΡΠ΅ΠΏΠΎΡΠΊΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ.", | ||
| 2240 | "Rename Persona": "ΠΠ΅ΡΠ΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ", | ||
| 2241 | "Change Persona Image": "ΠΠ·ΠΌΠ΅Π½ΠΈΡΡ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠ΅ΡΡΠΎΠ½Ρ", | ||
| 2242 | "Duplicate Persona": "ΠΠ»ΠΎΠ½ΠΈΡΠΎΠ²Π°ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ", | ||
| 2243 | "Delete Persona": "Π£Π΄Π°Π»ΠΈΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ", | ||
| 2244 | "Enter a new name for this persona:": "ΠΠ²Π΅Π΄ΠΈΡΠ΅ Π½ΠΎΠ²ΠΎΠ΅ ΠΈΠΌΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ:", | ||
| 2245 | "Connections": "Π‘Π²ΡΠ·ΠΈ", | ||
| 2246 | "Click to select this as default persona for the new chats. Click again to remove it.": "ΠΠ°ΠΆΠΌΠΈΡΠ΅, ΡΡΠΎΠ±Ρ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ ΡΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΡΡΠ°Π½Π΄Π°ΡΡΠ½ΠΎΠΉ Π΄Π»Ρ Π²ΡΠ΅Ρ Π½ΠΎΠ²ΡΡ ΡΠ°ΡΠΎΠ². ΠΠ°ΠΆΠΌΠΈΡΠ΅ Π΅ΡΡ ΡΠ°Π·, ΡΡΠΎΠ±Ρ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ.", | ||
| 2247 | "Character": "ΠΠ΅ΡΡΠΎΠ½Π°ΠΆ", | ||
| 2248 | "Click to lock your selected persona to the current character. Click again to remove the lock.": "ΠΠ°ΠΆΠΌΠΈΡΠ΅, ΡΡΠΎΠ±Ρ Π·Π°ΠΊΡΠ΅ΠΏΠΈΡΡ ΡΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ Π΄Π»Ρ ΡΠ΅ΠΊΡΡΠ΅Π³ΠΎ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ°. ΠΠ°ΠΆΠΌΠΈΡΠ΅ Π΅ΡΡ ΡΠ°Π·, ΡΡΠΎΠ±Ρ ΠΎΡΠΊΡΠ΅ΠΏΠΈΡΡ.", | ||
| 2249 | "Chat": "Π§Π°Ρ", | ||
| 2250 | "[No character connections. Click one of the buttons above to connect this persona.]": "[Π‘Π²ΡΠ·ΠΈ ΠΎΡΡΡΡΡΡΠ²ΡΡΡ. ΠΠ°ΠΆΠΌΠΈΡΠ΅ Π½Π° ΠΎΠ΄Π½Ρ ΠΈΠ· ΠΊΠ½ΠΎΠΏΠΎΠΊ Π²ΡΡΠ΅, ΡΡΠΎΠ±Ρ ΡΠΎΠ·Π΄Π°ΡΡ.]", | ||
| 2251 | "Global Settings": "ΠΠ±ΡΠΈΠ΅ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ", | ||
| 2252 | "Allow multiple persona connections per character": "Π Π°Π·ΡΠ΅ΡΠΈΡΡ ΠΏΡΠΈΠ²ΡΠ·ΡΠ²Π°ΡΡ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΠ΅ΡΡΠΎΠ½ ΠΊ ΠΎΠ΄Π½ΠΎΠΌΡ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΡ", | ||
| 2253 | "When multiple personas are connected to a character, a popup will appear to select which one to use": "ΠΡΠΈ ΡΠ²ΡΠ·ΡΠ²Π°Π½ΠΈΠΈ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΈΡ ΠΏΠ΅ΡΡΠΎΠ½ Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ΅ΠΌ, Π±ΡΠ΄Π΅Ρ ΠΏΠΎΡΠ²Π»ΡΡΡΡΡ ΠΎΠΊΠΎΡΠΊΠΎ Ρ ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Π²ΡΠ±ΡΠ°ΡΡ Π½ΡΠΆΠ½ΡΡ.", | ||
| 2254 | "Auto-lock a chosen persona to the chat": "ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΠΏΡΠΈΠ²ΡΠ·ΡΠ²Π°ΡΡ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΊ ΡΠ°ΡΡ", | ||
| 2255 | "Whenever a persona is selected, it will be locked to the current chat and automatically selected when the chat is opened.": "ΠΡΠΈ Π²ΡΠ±ΠΎΡΠ΅ Π½ΠΎΠ²ΠΎΠΉ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΎΠ½Π° Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π±ΡΠ΄Π΅Ρ ΠΏΡΠΈΠ²ΡΠ·Π°Π½Π° ΠΊ ΡΠ΅ΠΊΡΡΠ΅ΠΌΡ ΡΠ°ΡΡ, ΠΈ Π±ΡΠ΄Π΅Ρ Π²ΡΠ±ΠΈΡΠ°ΡΡΡΡ ΠΏΡΠΈ Π΅Π³ΠΎ ΠΎΡΠΊΡΡΡΠΈΠΈ.", | ||
| 2256 | "Current Persona": "Π’Π΅ΠΊΡΡΠ°Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°", | ||
| 2257 | "The chat has been successfully converted!": "Π§Π°Ρ ΡΡΠΏΠ΅ΡΠ½ΠΎ ΠΏΡΠ΅ΠΎΠ±ΡΠ°Π·ΠΎΠ²Π°Π½!", | ||
| 2258 | "Manual": "ΠΠΎΠ³Π΄Π° Π²Ρ ΡΠΊΠ°ΠΆΠ΅ΡΠ΅", | ||
| 2259 | "Auto Mode delay": "ΠΠ°Π΄Π΅ΡΠΆΠΊΠ° Π°Π²ΡΠΎ-ΡΠ΅ΠΆΠΈΠΌΠ°", | ||
| 2260 | "Use tag as folder": "Π’Π΅Π³-ΠΏΠ°ΠΏΠΊΠ°", | ||
| 2261 | "All connections to ${0} have been removed.": "ΠΡΠ΅ ΡΠ²ΡΠ·ΠΈ Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ΅ΠΌ ${0} Π±ΡΠ»ΠΈ ΡΠ΄Π°Π»Π΅Π½Ρ.", | ||
| 2262 | "Personas Unlocked": "ΠΠ΅ΡΡΠΎΠ½Ρ ΠΎΡΠ²ΡΠ·Π°Π½Ρ", | ||
| 2263 | "Remove All Connections": "Π£Π΄Π°Π»ΠΈΡΡ Π²ΡΠ΅ ΡΠ²ΡΠ·ΠΈ", | ||
| 2264 | "Persona ${0} selected and auto-locked to current chat": "ΠΠ΅ΡΡΠΎΠ½Π° ${0} Π²ΡΠ±ΡΠ°Π½Π° ΠΈ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π·Π°ΠΊΡΠ΅ΠΏΠ»Π΅Π½Π° Π·Π° ΡΡΠΈΠΌ ΡΠ°ΡΠΎΠΌ", | ||
| 2265 | "This persona is only temporarily chosen. Click for more info.": "ΠΠ°Π½Π½Π°Ρ ΠΏΠ΅ΡΡΠΎΠ½Π° Π²ΡΠ±ΡΠ°Π½Π° Π»ΠΈΡΡ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎ. ΠΠ°ΠΆΠΌΠΈΡΠ΅, ΡΡΠΎΠ±Ρ ΡΠ·Π½Π°ΡΡ Π±ΠΎΠ»ΡΡΠ΅.", | ||
| 2266 | "Temporary Persona": "ΠΡΠ΅ΠΌΠ΅Π½Π½Π°Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°", | ||
| 2267 | "A different persona is locked to this chat, or you have a different default persona set. The currently selected persona will only be temporary, and resets on reload. Consider locking this persona to the chat if you want to permanently use it.": "Π ΡΡΠΎΠΌΡ ΡΠ°ΡΡ ΡΠΆΠ΅ ΠΏΡΠΈΠ²ΡΠ·Π°Π½Π° ΠΈΠ½Π°Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°, Π»ΠΈΠ±ΠΎ Ρ Π²Π°Ρ Π²ΡΠ±ΡΠ°Π½Π° ΠΈΠ½Π°Ρ ΠΏΠ΅ΡΡΠΎΠ½Π° ΠΏΠΎ-ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ. ΠΡΠ±ΡΠ°Π½Π½Π°Ρ Π² Π΄Π°Π½Π½ΡΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ ΠΏΠ΅ΡΡΠΎΠ½Π° Π±ΡΠ΄Π΅Ρ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ, ΠΈ ΡΠ±ΡΠΎΡΠΈΡΡΡ ΠΏΠΎΡΠ»Π΅ ΠΏΠ΅ΡΠ΅Π·Π°Π³ΡΡΠ·ΠΊΠΈ. ΠΡΠ»ΠΈ Ρ ΠΎΡΠΈΡΠ΅ Π²ΡΠ΅Π³Π΄Π° ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΅Ρ Π² ΡΡΠΎΠΌ ΡΠ°ΡΠ΅, ΡΠΎΠ²Π΅ΡΡΠ΅ΠΌ Π΅Ρ ΠΏΡΠΈΠΊΡΠ΅ΠΏΠΈΡΡ.", | ||
| 2268 | "Current Persona: ${0}": "ΠΡΠ±ΡΠ°Π½Π½Π°Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°: ${0}", | ||
| 2269 | "Chat persona: ${0}": "ΠΠ΅ΡΡΠΎΠ½Π° Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΡΠ°ΡΠ°: ${0}", | ||
| 2270 | "Default persona: ${0}": "ΠΠ΅ΡΡΠΎΠ½Π° ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ (ΡΡΠ°Π½Π΄Π°ΡΡΠ½Π°Ρ): ${0}", | ||
| 2271 | "Persona ${0} is now unlocked from this chat.": "ΠΠ΅ΡΡΠΎΠ½Π° ${0} ΠΎΡΠ²ΡΠ·Π°Π½Π° ΠΎΡ ΡΡΠΎΠ³ΠΎ ΡΠ°ΡΠ°.", | ||
| 2272 | "Persona Unlocked": "ΠΠ΅ΡΡΠΎΠ½Π° ΠΎΡΠ²ΡΠ·Π°Π½Π°", | ||
| 2273 | "Persona ${0} is now unlocked from character ${1}.": "ΠΠ΅ΡΡΠΎΠ½Π° ${0} ΠΎΡΠ²ΡΠ·Π°Π½Π° ΠΎΡ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ° ${1}.", | ||
| 2274 | "Persona Not Found": "ΠΠ΅ΡΡΠΎΠ½Π° Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½Π°", | ||
| 2275 | "Persona Locked": "ΠΠ΅ΡΡΠΎΠ½Π° Π·Π°ΠΊΡΠ΅ΠΏΠ»Π΅Π½Π°", | ||
| 2276 | "User persona ${0} is locked to character ${1}${2}": "ΠΠ΅ΡΡΠΎΠ½Π° ${0} ΠΏΡΠΈΠΊΡΠ΅ΠΏΠ»Π΅Π½Π° ΠΊ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΡ ${1}${2}", | ||
| 2277 | "Persona Name Not Set": "Π£ ΠΏΠ΅ΡΡΠΎΠ½Ρ ΠΎΡΡΡΡΡΡΠ²ΡΠ΅Ρ ΠΈΠΌΡ", | ||
| 2278 | "You must bind a name to this persona before you can set a lorebook.": "ΠΠ΅ΡΠ΅Π΄ ΠΏΡΠΈΠ²ΡΠ·ΠΊΠΎΠΉ Π»ΠΎΡΠ±ΡΠΊΠ° ΠΏΠ΅ΡΡΠΎΠ½Π΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΡΠΈΡΠ²ΠΎΠΈΡΡ ΠΈΠΌΡ.", | ||
| 2279 | "Default Persona Removed": "ΠΠ΅ΡΡΠΎΠ½Π° ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ ΡΠ½ΡΡΠ°", | ||
| 2280 | "Persona is locked to the current character": "ΠΠ΅ΡΡΠΎΠ½Π° Π·Π°ΠΊΡΠ΅ΠΏΠ»Π΅Π½Π° Π·Π° ΡΡΠΈΠΌ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ΅ΠΌ", | ||
| 2281 | "Persona is locked to the current chat": "ΠΠ΅ΡΡΠΎΠ½Π° Π·Π°ΠΊΡΠ΅ΠΏΠ»Π΅Π½Π° Π·Π° ΡΡΠΈΠΌ ΡΠ°ΡΠΎΠΌ", | ||
| 2282 | "characters": "ΠΏΠ΅ΡΡ.", | ||
| 2283 | "character": "ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆ", | ||
| 2284 | "in this group": "Π² Π³ΡΡΠΏΠΏΠ΅", | ||
| 2285 | "Chatting Since": "ΠΠ΅ΡΠ²Π°Ρ Π±Π΅ΡΠ΅Π΄Π°", | ||
| 2286 | "Context": "ΠΠΎΠ½ΡΠ΅ΠΊΡΡ", | ||
| 2287 | "Response": "ΠΡΠ²Π΅Ρ", | ||
| 2288 | "Connected": "ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΎ", | ||
| 2289 | "Enter new background name:": "ΠΠ²Π΅Π΄ΠΈΡΠ΅ Π½ΠΎΠ²ΠΎΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ Π΄Π»Ρ ΡΠΎΠ½Π°:", | ||
| 2290 | "AI Horde Website": "Π‘Π°ΠΉΡ AI Horde", | ||
| 2291 | "Enable web search": "ΠΠΊΠ»ΡΡΠΈΡΡ ΠΏΠΎΠΈΡΠΊ Π² ΠΠ½ΡΠ΅ΡΠ½Π΅ΡΠ΅", | ||
| 2292 | "Use search capabilities provided by the backend.": "Π Π°Π·ΡΠ΅ΡΠΈΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅ΠΌΡΡ Π±ΡΠΊΠ΅Π½Π΄ΠΎΠΌ ΡΡΠ½ΠΊΡΠΈΠΉ ΠΏΠΎΠΈΡΠΊΠ°.", | ||
| 2293 | "Request inline images": "ΠΠ°ΠΏΡΠ°ΡΠΈΠ²Π°ΡΡ inline-ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ", | ||
| 2294 | "Allows the model to return image attachments.": "Π Π°Π·ΡΠ΅ΡΠΈΡΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΠΎΡΠΏΡΠ°Π²Π»ΡΡΡ Π²Π»ΠΎΠΆΠ΅Π½ΠΈΡ Π² Π²ΠΈΠ΄Π΅ ΠΊΠ°ΡΡΠΈΠ½ΠΎΠΊ.", | ||
| 2295 | "Request inline images_desc_2": "ΠΠ΅ ΡΠΎΠ²ΠΌΠ΅ΡΡΠΈΠΌΠΎ ΡΠΎ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΠΎΠΌ: Π²ΡΠ·ΠΎΠ² ΡΡΠ½ΠΊΡΠΈΠΉ, ΠΏΠΎΠΈΡΠΊ Π² ΠΠ½ΡΠ΅ΡΠ½Π΅ΡΠ΅, ΡΠΈΡΡΠ΅ΠΌΠ½ΡΠΉ ΠΏΡΠΎΠΌΠΏΡ.", | ||
| 2296 | "Connected Personas": "Π‘Π²ΡΠ·Π°Π½Π½ΡΠ΅ ΠΏΠ΅ΡΡΠΎΠ½Ρ", | ||
| 2297 | "[Currently no personas connected]": "[Π‘Π²ΡΠ·Π°Π½Π½ΡΡ ΠΏΠ΅ΡΡΠΎΠ½ Π½Π΅Ρ]", | ||
| 2298 | "The following personas are connected to the current character.\n\nClick on a persona to select it for the current character.\nShift + Click to unlink the persona from the character.": "Π‘ ΡΡΠΈΠΌ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ΅ΠΌ ΡΠ²ΡΠ·Π°Π½Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ ΠΏΠ΅ΡΡΠΎΠ½Ρ.\n\nΠΠ°ΠΆΠΌΠΈΡΠ΅ Π½Π° ΠΏΠ΅ΡΡΠΎΠ½Ρ, ΡΡΠΎΠ±Ρ Π²ΡΠ±ΡΠ°ΡΡ Π΅Ρ Π΄Π»Ρ Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΆΠ°.\nShift + ΠΠΠ, ΡΡΠΎΠ±Ρ Π΅Ρ ΠΎΡΠ²ΡΠ·Π°ΡΡ.", | ||
| 2299 | "Persona Connections": "Π‘Π²ΡΠ·ΠΈ Ρ ΠΏΠ΅ΡΡΠΎΠ½Π°ΠΌΠΈ", | ||
| 2300 | "Pooled order": "ΠΡΠ»ΠΈ ΡΠΆΠ΅ Π΄Π°Π²Π½ΠΎ Π½Π΅ ΠΎΡΠ²Π΅ΡΠ°Π»ΠΈ", | ||
| 2301 | "Attach a File": "ΠΡΠΈΠ»ΠΎΠΆΠΈΡΡ ΡΠ°ΠΉΠ»", | ||
| 2302 | "Attach a file or image to a current chat.": "ΠΡΠΈΠ»ΠΎΠΆΠΈΡΡ ΡΠ°ΠΉΠ» ΠΈΠ»ΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ ΠΊ ΡΠ΅ΠΊΡΡΠ΅ΠΌΡ ΡΠ°ΡΡ", | ||
| 2303 | "Remove the file": "Π£Π΄Π°Π»ΠΈΡΡ ΡΠ°ΠΉΠ»", | ||
| 2304 | "Delete the Chat File?": "Π£Π΄Π°Π»ΠΈΡΡ ΡΠ°Ρ?", | ||
| 2305 | "Forbidden": "ΠΠΎΡΡΡΠΏ Π·Π°ΠΏΡΠ΅ΡΡΠ½", | ||
| 2306 | "To view your API keys here, set the value of allowKeysExposure to true in config.yaml file and restart the SillyTavern server.": "Π§ΡΠΎΠ±Ρ Π²ΠΈΠ΄Π΅ΡΡ Π·Π΄Π΅ΡΡ Π²Π°ΡΠΈ API-ΠΊΠ»ΡΡΠΈ, ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡ allowKeysExposure Π² config.yaml Π² ΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ true, ΠΏΠΎΡΠ»Π΅ ΡΠ΅Π³ΠΎ ΠΏΠ΅ΡΠ΅Π·Π°ΠΏΡΡΡΠΈΡΠ΅ ΡΠ΅ΡΠ²Π΅Ρ SillyTavern.", | ||
| 2307 | "Invalid endpoint URL. Requests may fail.": "ΠΠ΅ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΡΠΉ Π°Π΄ΡΠ΅Ρ ΡΠ½Π΄ΠΏΠΎΠΈΠ½ΡΠ°. ΠΠ°ΠΏΡΠΎΡΡ ΠΌΠΎΠ³ΡΡ Π½Π΅ ΠΏΡΠΎΡ ΠΎΠ΄ΠΈΡΡ.", | ||
| 2308 | "How to install extensions?": "ΠΠ°ΠΊ ΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°ΡΡ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΡ?", | ||
| 2309 | "Click the flashing button to install extensions.": "Π§ΡΠΎΠ±Ρ ΠΈΡ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ, Π½Π°ΠΆΠΌΠΈΡΠ΅ Π½Π° ΠΌΠΈΠ³Π°ΡΡΡΡ ΠΊΠ½ΠΎΠΏΠΊΡ.", | ||
| 2310 | "ext_regex_reasoning_desc": "Π‘ΠΎΠ΄Π΅ΡΠΆΠΈΠΌΠΎΠ΅ Π±Π»ΠΎΠΊΠΎΠ² ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ. ΠΡΠΈ ΠΎΡΠΌΠ΅ΡΠ΅Π½Π½ΠΎΠΉ Π³Π°Π»ΠΎΡΠΊΠ΅ \"Π’ΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΎΠΌΠΏΡ\" Π±ΡΠ΄ΡΡ ΡΠ°ΠΊΠΆΠ΅ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π½ΡΠ΅ Π² ΠΏΡΠΎΠΌΠΏΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ.", | ||
| 2311 | "Macro in Find Regex": "ΠΠ°ΠΊΡΠΎΡΡ Π² ΡΠ΅Π³. Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΠΈ", | ||
| 2312 | "Don't substitute": "ΠΠ΅ Π·Π°ΠΌΠ΅Π½ΡΡΡ", | ||
| 2313 | "Substitute (raw)": "ΠΠ°ΠΌΠ΅Π½ΡΡΡ Π² \"ΡΠΈΡΡΠΎΠΌ\" Π²ΠΈΠ΄Π΅", | ||
| 2314 | "Substitute (escaped)": "ΠΠ°ΠΌΠ΅Π½ΡΡΡ ΠΏΠΎΡΠ»Π΅ ΡΠΊΡΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ", | ||
| 2315 | "ext_regex_other_options_desc": "ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ, ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅ Π²Π½ΠΎΡΠΈΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² ΡΠ°ΠΌ ΡΠ°ΠΉΠ» ΡΠ°ΡΠ°.\nΠΡΠΈ Π²ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ ΠΎΠ΄Π½ΠΎΠΉ ΠΈΠ· ΠΎΠΏΡΠΈΠΉ (ΠΈΠ»ΠΈ ΠΎΠ±Π΅ΠΈΡ ), ΡΠ°ΠΉΠ» ΡΠ°ΡΠ° ΠΎΡΡΠ°Π½Π΅ΡΡΡ Π½Π΅ΡΡΠΎΠ½ΡΡΡΠΌ, ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΠ°ΠΌΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΠΏΠΎ-ΠΏΡΠ΅ΠΆΠ½Π΅ΠΌΡ Π±ΡΠ΄ΡΡ Π΄Π΅ΠΉΡΡΠ²ΠΎΠ²Π°ΡΡ.", | ||
| 2316 | "ext_regex_flags_help": "ΠΠ°ΠΆΠΌΠΈΡΠ΅, ΡΡΠΎΠ±Ρ ΡΠ·Π½Π°ΡΡ Π±ΠΎΠ»ΡΡΠ΅ ΠΎ ΡΠ»Π°Π³Π°Ρ Π² ΡΠ΅Π³. Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΡΡ .", | ||
| 2317 | "Applies to all matches": "ΠΠ°ΠΌΠ΅Π½ΡΠ΅Ρ Π²ΡΠ΅ Π²Ρ ΠΎΠΆΠ΄Π΅Π½ΠΈΡ", | ||
| 2318 | "Applies to the first match": "ΠΠ°ΠΌΠ΅Π½ΡΠ΅Ρ ΠΏΠ΅ΡΠ²ΠΎΠ΅ Π²Ρ ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅", | ||
| 2319 | "Case insensitive": "ΠΠ΅ ΡΡΠ²ΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΊ ΡΠ΅Π³ΠΈΡΡΡΡ", | ||
| 2320 | "Case sensitive": "Π§ΡΠ²ΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΊ ΡΠ΅Π³ΠΈΡΡΡΡ", | ||
| 2321 | "Find Regex is empty": "Π Π΅Π³. Π²ΡΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π΅ ΡΠΊΠ°Π·Π°Π½ΠΎ", | ||
| 2322 | "Click the button to save it as a file.": "ΠΠ°ΠΆΠΌΠΈΡΠ΅ Π½Π° ΠΊΠ½ΠΎΠΏΠΊΡ ΡΠΏΡΠ°Π²Π°, ΡΡΠΎΠ±Ρ ΡΠΎΡ ΡΠ°Π½ΠΈΡΡ Π΅Π³ΠΎ Π² ΡΠ°ΠΉΠ».", | ||
| 2323 | "Export as JSONL": "ΠΠΊΡΠΏΠΎΡΡ Π² ΡΠΎΡΠΌΠ°ΡΠ΅ JSONL", | ||
| 2324 | "Thought for some time": "ΠΠ°ΠΊΠΎΠ΅-ΡΠΎ Π²ΡΠ΅ΠΌΡ Π·Π°Π½ΡΠ»ΠΈ ΡΠ°Π·ΠΌΡΡΠ»Π΅Π½ΠΈΡ", | ||
| 2325 | "Thinking...": "Π ΡΠ°Π·Π΄ΡΠΌΡΡΡ ...", | ||
| 2326 | "Thought for ${0}": "Π Π°Π·ΠΌΡΡΠ»Π΅Π½ΠΈΡ Π·Π°Π½ΡΠ»ΠΈ ${0}", | ||
| 2327 | "Hidden reasoning - Add reasoning block": "Π Π°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ ΡΠΊΡΡΡΡ - ΠΠΎΠ±Π°Π²ΠΈΡΡ Π±Π»ΠΎΠΊ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ", | ||
| 2328 | "Add reasoning block": "ΠΠΎΠ±Π°Π²ΠΈΡΡ Π±Π»ΠΎΠΊ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ", | ||
| 2329 | "Edit reasoning": "Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ", | ||
| 2330 | "Copy reasoning": "Π‘ΠΊΠΎΠΏΠΈΡΠΎΠ²Π°ΡΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ", | ||
| 2331 | "Confirm Edit": "ΠΠΎΠ΄ΡΠ²Π΅ΡΠ΄ΠΈΡΡ", | ||
| 2332 | "Remove reasoning": "Π£Π΄Π°Π»ΠΈΡΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ", | ||
| 2333 | "Cancel edit": "ΠΡΠΌΠ΅Π½ΠΈΡΡ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅", | ||
| 2334 | "Remove Reasoning": "Π£Π΄Π°Π»ΠΈΡΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ", | ||
| 2335 | "Are you sure you want to clear the reasoning?<br />Visible message contents will stay intact.": "ΠΡ ΡΠΎΡΠ½ΠΎ Ρ ΠΎΡΠΈΡΠ΅ ΡΠ΄Π°Π»ΠΈΡΡ Π±Π»ΠΎΠΊ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ?<br />ΠΡΠ½ΠΎΠ²Π½ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ ΠΎΡΡΠ°Π½Π΅ΡΡΡ Π½Π° ΠΌΠ΅ΡΡΠ΅.", | ||
| 2336 | "Reasoning Parse": "ΠΠ°ΡΡΠΈΠ½Π³ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ", | ||
| 2337 | "Both prefix and suffix must be set in the Reasoning Formatting settings.": "Π Π½Π°ΡΡΡΠΎΠΉΠΊΠ°Ρ ΡΠΎΡΠΌΠ°ΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΡΠ°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΠΉ Π΄ΠΎΠ»ΠΆΠ½Ρ Π±ΡΡΡ Π·Π°Π΄Π°Π½Ρ ΠΏΡΠ΅ΡΠΈΠΊΡ ΠΈ ΡΡΡΡΠΈΠΊΡ.", | ||
| 2338 | "Invalid return type '${0}', defaulting to 'reasoning'.": "ΠΠ΅ΠΊΠΎΡΡΠ΅ΠΊΡΠ½ΡΠΉ Π²ΠΎΠ·Π²ΡΠ°ΡΠ°Π΅ΠΌΡΠΉ ΡΠΈΠΏ, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌ ΡΡΠ°Π½Π΄Π°ΡΡΠ½ΡΠΉ 'reasoning'.", | ||
| 2339 | "Reasoning already exists.": "Π Π°ΡΡΡΠΆΠ΄Π΅Π½ΠΈΡ ΡΠΆΠ΅ ΠΏΡΠΈΡΡΡΡΡΠ²ΡΡΡ.", | ||
| 2340 | "Edit Message": "Π Π΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅", | ||
| 2341 | "Status check bypassed": "ΠΡΠΎΠ²Π΅ΡΠΊΠ° ΡΡΠ°ΡΡΡΠ° ΠΎΡΠΊΠ»ΡΡΠ΅Π½Π°", | ||
| 2342 | "Valid": "Π Π°Π±ΠΎΡΠ°Π΅Ρ" | ||
| 2207 | } | 2343 | } |
| @@ -172,6 +172,7 @@ import { | |||
| 172 | copyText, | 172 | copyText, |
| 173 | escapeHtml, | 173 | escapeHtml, |
| 174 | saveBase64AsFile, | 174 | saveBase64AsFile, |
| 175 | uuidv4, | ||
| 175 | } from './scripts/utils.js'; | 176 | } from './scripts/utils.js'; |
| 176 | import { debounce_timeout } from './scripts/constants.js'; | 177 | import { debounce_timeout } from './scripts/constants.js'; |
| 177 | 178 | ||
| @@ -494,6 +495,8 @@ export const event_types = { | |||
| 494 | GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts', | 495 | GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts', |
| 495 | GENERATE_AFTER_DATA: 'generate_after_data', | 496 | GENERATE_AFTER_DATA: 'generate_after_data', |
| 496 | GROUP_MEMBER_DRAFTED: 'group_member_drafted', | 497 | GROUP_MEMBER_DRAFTED: 'group_member_drafted', |
| 498 | GROUP_WRAPPER_STARTED: 'group_wrapper_started', | ||
| 499 | GROUP_WRAPPER_FINISHED: 'group_wrapper_finished', | ||
| 497 | WORLD_INFO_ACTIVATED: 'world_info_activated', | 500 | WORLD_INFO_ACTIVATED: 'world_info_activated', |
| 498 | TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready', | 501 | TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready', |
| 499 | CHAT_COMPLETION_SETTINGS_READY: 'chat_completion_settings_ready', | 502 | CHAT_COMPLETION_SETTINGS_READY: 'chat_completion_settings_ready', |
| @@ -514,6 +517,9 @@ export const event_types = { | |||
| 514 | ONLINE_STATUS_CHANGED: 'online_status_changed', | 517 | ONLINE_STATUS_CHANGED: 'online_status_changed', |
| 515 | IMAGE_SWIPED: 'image_swiped', | 518 | IMAGE_SWIPED: 'image_swiped', |
| 516 | CONNECTION_PROFILE_LOADED: 'connection_profile_loaded', | 519 | CONNECTION_PROFILE_LOADED: 'connection_profile_loaded', |
| 520 | CONNECTION_PROFILE_CREATED: 'connection_profile_created', | ||
| 521 | CONNECTION_PROFILE_DELETED: 'connection_profile_deleted', | ||
| 522 | CONNECTION_PROFILE_UPDATED: 'connection_profile_updated', | ||
| 517 | TOOL_CALLS_PERFORMED: 'tool_calls_performed', | 523 | TOOL_CALLS_PERFORMED: 'tool_calls_performed', |
| 518 | TOOL_CALLS_RENDERED: 'tool_calls_rendered', | 524 | TOOL_CALLS_RENDERED: 'tool_calls_rendered', |
| 519 | }; | 525 | }; |
| @@ -589,7 +595,7 @@ let is_delete_mode = false; | |||
| 589 | let fav_ch_checked = false; | 595 | let fav_ch_checked = false; |
| 590 | let scrollLock = false; | 596 | let scrollLock = false; |
| 591 | export let abortStatusCheck = new AbortController(); | 597 | export let abortStatusCheck = new AbortController(); |
| 592 | let charDragDropHandler = null; | 598 | export let charDragDropHandler = null; |
| 593 | 599 | ||
| 594 | /** @type {debounce_timeout} The debounce timeout used for chat/settings save. debounce_timeout.long: 1.000 ms */ | 600 | /** @type {debounce_timeout} The debounce timeout used for chat/settings save. debounce_timeout.long: 1.000 ms */ |
| 595 | export const DEFAULT_SAVE_EDIT_TIMEOUT = debounce_timeout.relaxed; | 601 | export const DEFAULT_SAVE_EDIT_TIMEOUT = debounce_timeout.relaxed; |
| @@ -1140,7 +1146,7 @@ export async function clearItemizedPrompts() { | |||
| 1140 | async function getStatusHorde() { | 1146 | async function getStatusHorde() { |
| 1141 | try { | 1147 | try { |
| 1142 | const hordeStatus = await checkHordeStatus(); | 1148 | const hordeStatus = await checkHordeStatus(); |
| 1143 | setOnlineStatus(hordeStatus ? 'Connected' : 'no_connection'); | 1149 | setOnlineStatus(hordeStatus ? t`Connected` : 'no_connection'); |
| 1144 | } | 1150 | } |
| 1145 | catch { | 1151 | catch { |
| 1146 | setOnlineStatus('no_connection'); | 1152 | setOnlineStatus('no_connection'); |
| @@ -1207,7 +1213,7 @@ async function getStatusTextgen() { | |||
| 1207 | } | 1213 | } |
| 1208 | 1214 | ||
| 1209 | if ([textgen_types.GENERIC, textgen_types.OOBA].includes(textgen_settings.type) && textgen_settings.bypass_status_check) { | 1215 | if ([textgen_types.GENERIC, textgen_types.OOBA].includes(textgen_settings.type) && textgen_settings.bypass_status_check) { |
| 1210 | setOnlineStatus('Status check bypassed'); | 1216 | setOnlineStatus(t`Status check bypassed`); |
| 1211 | return resultCheckStatus(); | 1217 | return resultCheckStatus(); |
| 1212 | } | 1218 | } |
| 1213 | 1219 | ||
| @@ -1232,7 +1238,7 @@ async function getStatusTextgen() { | |||
| 1232 | setOnlineStatus(textgen_settings.togetherai_model); | 1238 | setOnlineStatus(textgen_settings.togetherai_model); |
| 1233 | } else if (textgen_settings.type === textgen_types.OLLAMA) { | 1239 | } else if (textgen_settings.type === textgen_types.OLLAMA) { |
| 1234 | loadOllamaModels(data?.data); | 1240 | loadOllamaModels(data?.data); |
| 1235 | setOnlineStatus(textgen_settings.ollama_model || 'Connected'); | 1241 | setOnlineStatus(textgen_settings.ollama_model || t`Connected`); |
| 1236 | } else if (textgen_settings.type === textgen_types.INFERMATICAI) { | 1242 | } else if (textgen_settings.type === textgen_types.INFERMATICAI) { |
| 1237 | loadInfermaticAIModels(data?.data); | 1243 | loadInfermaticAIModels(data?.data); |
| 1238 | setOnlineStatus(textgen_settings.infermaticai_model); | 1244 | setOnlineStatus(textgen_settings.infermaticai_model); |
| @@ -1256,7 +1262,7 @@ async function getStatusTextgen() { | |||
| 1256 | setOnlineStatus(textgen_settings.tabby_model || data?.result); | 1262 | setOnlineStatus(textgen_settings.tabby_model || data?.result); |
| 1257 | } else if (textgen_settings.type === textgen_types.GENERIC) { | 1263 | } else if (textgen_settings.type === textgen_types.GENERIC) { |
| 1258 | loadGenericModels(data?.data); | 1264 | loadGenericModels(data?.data); |
| 1259 | setOnlineStatus(textgen_settings.generic_model || data?.result || 'Connected'); | 1265 | setOnlineStatus(textgen_settings.generic_model || data?.result || t`Connected`); |
| 1260 | } else { | 1266 | } else { |
| 1261 | setOnlineStatus(data?.result); | 1267 | setOnlineStatus(data?.result); |
| 1262 | } | 1268 | } |
| @@ -1370,8 +1376,11 @@ export function resultCheckStatus() { | |||
| 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. | 1376 | * 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. | 1377 | * 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. | 1378 | * @param {number} id The ID of the character to switch to. |
| 1379 | * @param {object} [options] Options for the switch. | ||
| 1380 | * @param {boolean} [options.switchMenu=true] Whether to switch the right menu to the character edit menu if the character is already selected. | ||
| 1381 | * @returns {Promise<void>} A promise that resolves when the character is switched. | ||
| 1373 | */ | 1382 | */ |
| 1374 | export async function selectCharacterById(id) { | 1383 | export async function selectCharacterById(id, { switchMenu = true } = {}) { |
| 1375 | if (characters[id] === undefined) { | 1384 | if (characters[id] === undefined) { |
| 1376 | return; | 1385 | return; |
| 1377 | } | 1386 | } |
| @@ -1400,9 +1409,9 @@ export async function selectCharacterById(id) { | |||
| 1400 | } | 1409 | } |
| 1401 | } else { | 1410 | } else { |
| 1402 | //if clicked on character that was already selected | 1411 | //if clicked on character that was already selected |
| 1403 | selected_button = 'character_edit'; | 1412 | switchMenu && (selected_button = 'character_edit'); |
| 1404 | await unshallowCharacter(this_chid); | 1413 | await unshallowCharacter(this_chid); |
| 1405 | select_selected_character(this_chid); | 1414 | select_selected_character(this_chid, { switchMenu }); |
| 1406 | } | 1415 | } |
| 1407 | } | 1416 | } |
| 1408 | 1417 | ||
| @@ -1787,6 +1796,7 @@ export async function getCharacters() { | |||
| 1787 | body: JSON.stringify({}), | 1796 | body: JSON.stringify({}), |
| 1788 | }); | 1797 | }); |
| 1789 | if (response.ok === true) { | 1798 | if (response.ok === true) { |
| 1799 | const previousAvatar = this_chid !== undefined ? characters[this_chid]?.avatar : null; | ||
| 1790 | characters.splice(0, characters.length); | 1800 | characters.splice(0, characters.length); |
| 1791 | const getData = await response.json(); | 1801 | const getData = await response.json(); |
| 1792 | for (let i = 0; i < getData.length; i++) { | 1802 | for (let i = 0; i < getData.length; i++) { |
| @@ -1800,8 +1810,16 @@ export async function getCharacters() { | |||
| 1800 | 1810 | ||
| 1801 | characters[i]['chat'] = String(characters[i]['chat']); | 1811 | characters[i]['chat'] = String(characters[i]['chat']); |
| 1802 | } | 1812 | } |
| 1803 | if (this_chid !== undefined) { | 1813 | |
| 1804 | $('#avatar_url_pole').val(characters[this_chid].avatar); | 1814 | if (previousAvatar) { |
| 1815 | const newCharacterId = characters.findIndex(x => x.avatar === previousAvatar); | ||
| 1816 | if (newCharacterId >= 0) { | ||
| 1817 | setCharacterId(newCharacterId); | ||
| 1818 | await selectCharacterById(newCharacterId, { switchMenu: false }); | ||
| 1819 | } else { | ||
| 1820 | await Popup.show.text(t`ERROR: The active character is no longer available.`, t`The page will be refreshed to prevent data loss. Press "OK" to continue.`); | ||
| 1821 | return location.reload(); | ||
| 1822 | } | ||
| 1805 | } | 1823 | } |
| 1806 | 1824 | ||
| 1807 | await getGroups(); | 1825 | await getGroups(); |
| @@ -2730,6 +2748,7 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re | |||
| 2730 | environment.mesExamplesRaw = fields.mesExamples || ''; | 2748 | environment.mesExamplesRaw = fields.mesExamples || ''; |
| 2731 | environment.charVersion = fields.version || ''; | 2749 | environment.charVersion = fields.version || ''; |
| 2732 | environment.char_version = fields.version || ''; | 2750 | environment.char_version = fields.version || ''; |
| 2751 | environment.charDepthPrompt = fields.charDepthPrompt || ''; | ||
| 2733 | } | 2752 | } |
| 2734 | 2753 | ||
| 2735 | // Must be substituted last so that they're replaced inside {{description}} | 2754 | // Must be substituted last so that they're replaced inside {{description}} |
| @@ -3081,13 +3100,38 @@ export function baseChatReplace(value, name1, name2) { | |||
| 3081 | 3100 | ||
| 3082 | /** | 3101 | /** |
| 3083 | * Returns the character card fields for the current character. | 3102 | * Returns the character card fields for the current character. |
| 3084 | * @returns {{system: string, mesExamples: string, description: string, personality: string, persona: string, scenario: string, jailbreak: string, version: string}} | 3103 | * @param {object} [options] |
| 3104 | * @param {number} [options.chid] Optional character index | ||
| 3105 | * | ||
| 3106 | * @typedef {object} CharacterCardFields | ||
| 3107 | * @property {string} system System prompt | ||
| 3108 | * @property {string} mesExamples Message examples | ||
| 3109 | * @property {string} description Description | ||
| 3110 | * @property {string} personality Personality | ||
| 3111 | * @property {string} persona Persona | ||
| 3112 | * @property {string} scenario Scenario | ||
| 3113 | * @property {string} jailbreak Jailbreak instructions | ||
| 3114 | * @property {string} version Character version | ||
| 3115 | * @property {string} charDepthPrompt Character depth note | ||
| 3116 | * @returns {CharacterCardFields} Character card fields | ||
| 3085 | */ | 3117 | */ |
| 3086 | export function getCharacterCardFields() { | 3118 | export function getCharacterCardFields({ chid = null } = {}) { |
| 3087 | const result = { system: '', mesExamples: '', description: '', personality: '', persona: '', scenario: '', jailbreak: '', version: '' }; | 3119 | const currentChid = chid ?? this_chid; |
| 3120 | |||
| 3121 | const result = { | ||
| 3122 | system: '', | ||
| 3123 | mesExamples: '', | ||
| 3124 | description: '', | ||
| 3125 | personality: '', | ||
| 3126 | persona: '', | ||
| 3127 | scenario: '', | ||
| 3128 | jailbreak: '', | ||
| 3129 | version: '', | ||
| 3130 | charDepthPrompt: '', | ||
| 3131 | }; | ||
| 3088 | result.persona = baseChatReplace(power_user.persona_description?.trim(), name1, name2); | 3132 | result.persona = baseChatReplace(power_user.persona_description?.trim(), name1, name2); |
| 3089 | 3133 | ||
| 3090 | const character = characters[this_chid]; | 3134 | const character = characters[currentChid]; |
| 3091 | 3135 | ||
| 3092 | if (!character) { | 3136 | if (!character) { |
| 3093 | return result; | 3137 | return result; |
| @@ -3101,9 +3145,10 @@ export function getCharacterCardFields() { | |||
| 3101 | result.system = power_user.prefer_character_prompt ? baseChatReplace(character.data?.system_prompt?.trim(), name1, name2) : ''; | 3145 | result.system = power_user.prefer_character_prompt ? baseChatReplace(character.data?.system_prompt?.trim(), name1, name2) : ''; |
| 3102 | result.jailbreak = power_user.prefer_character_jailbreak ? baseChatReplace(character.data?.post_history_instructions?.trim(), name1, name2) : ''; | 3146 | result.jailbreak = power_user.prefer_character_jailbreak ? baseChatReplace(character.data?.post_history_instructions?.trim(), name1, name2) : ''; |
| 3103 | result.version = character.data?.character_version ?? ''; | 3147 | result.version = character.data?.character_version ?? ''; |
| 3148 | result.charDepthPrompt = baseChatReplace(character.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2); | ||
| 3104 | 3149 | ||
| 3105 | if (selected_group) { | 3150 | if (selected_group) { |
| 3106 | const groupCards = getGroupCharacterCards(selected_group, Number(this_chid)); | 3151 | const groupCards = getGroupCharacterCards(selected_group, Number(currentChid)); |
| 3107 | 3152 | ||
| 3108 | if (groupCards) { | 3153 | if (groupCards) { |
| 3109 | result.description = groupCards.description; | 3154 | result.description = groupCards.description; |
| @@ -3596,7 +3641,8 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3596 | throw new Error(data.response); | 3641 | throw new Error(data.response); |
| 3597 | } | 3642 | } |
| 3598 | 3643 | ||
| 3599 | const message = cleanUpMessage(extractMessageFromData(data), false, false, true); | 3644 | // format result, exclude user prompt bias |
| 3645 | const message = cleanUpMessage(extractMessageFromData(data), false, false, true, null, false); | ||
| 3600 | 3646 | ||
| 3601 | if (!message) { | 3647 | if (!message) { |
| 3602 | throw new Error('No message generated'); | 3648 | throw new Error('No message generated'); |
| @@ -3905,6 +3951,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3905 | mesExamples, | 3951 | mesExamples, |
| 3906 | system, | 3952 | system, |
| 3907 | jailbreak, | 3953 | jailbreak, |
| 3954 | charDepthPrompt, | ||
| 3908 | } = getCharacterCardFields(); | 3955 | } = getCharacterCardFields(); |
| 3909 | 3956 | ||
| 3910 | if (main_api !== 'openai') { | 3957 | if (main_api !== 'openai') { |
| @@ -3927,7 +3974,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 3927 | setExtensionPrompt('DEPTH_PROMPT_' + index, value.text, extension_prompt_types.IN_CHAT, value.depth, extension_settings.note.allowWIScan, role); | 3974 | setExtensionPrompt('DEPTH_PROMPT_' + index, value.text, extension_prompt_types.IN_CHAT, value.depth, extension_settings.note.allowWIScan, role); |
| 3928 | }); | 3975 | }); |
| 3929 | } else { | 3976 | } else { |
| 3930 | const depthPromptText = baseChatReplace(characters[this_chid]?.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || ''; | 3977 | const depthPromptText = charDepthPrompt || ''; |
| 3931 | const depthPromptDepth = characters[this_chid]?.data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default; | 3978 | const depthPromptDepth = characters[this_chid]?.data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default; |
| 3932 | const depthPromptRole = getExtensionPromptRoleByName(characters[this_chid]?.data?.extensions?.depth_prompt?.role ?? depth_prompt_role_default); | 3979 | const depthPromptRole = getExtensionPromptRoleByName(characters[this_chid]?.data?.extensions?.depth_prompt?.role ?? depth_prompt_role_default); |
| 3933 | setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole); | 3980 | setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole); |
| @@ -5868,13 +5915,14 @@ function extractMultiSwipes(data, type) { | |||
| 5868 | return swipes; | 5915 | return swipes; |
| 5869 | } | 5916 | } |
| 5870 | 5917 | ||
| 5871 | export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null) { | 5918 | export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null, includeUserPromptBias = true) { |
| 5872 | if (!getMessage) { | 5919 | if (!getMessage) { |
| 5873 | return ''; | 5920 | return ''; |
| 5874 | } | 5921 | } |
| 5875 | 5922 | ||
| 5876 | // Add the prompt bias before anything else | 5923 | // Add the prompt bias before anything else |
| 5877 | if ( | 5924 | if ( |
| 5925 | includeUserPromptBias && | ||
| 5878 | power_user.user_prompt_bias && | 5926 | power_user.user_prompt_bias && |
| 5879 | !isImpersonate && | 5927 | !isImpersonate && |
| 5880 | !isContinue && | 5928 | !isContinue && |
| @@ -6261,7 +6309,6 @@ export function syncMesToSwipe(messageId = null) { | |||
| 6261 | } | 6309 | } |
| 6262 | 6310 | ||
| 6263 | const targetMessage = chat[targetMessageId]; | 6311 | const targetMessage = chat[targetMessageId]; |
| 6264 | |||
| 6265 | if (!targetMessage) { | 6312 | if (!targetMessage) { |
| 6266 | return false; | 6313 | return false; |
| 6267 | } | 6314 | } |
| @@ -6295,6 +6342,68 @@ export function syncMesToSwipe(messageId = null) { | |||
| 6295 | } | 6342 | } |
| 6296 | 6343 | ||
| 6297 | /** | 6344 | /** |
| 6345 | * Syncs swipe data back to the message data at the given message ID (or the last message if no ID is given). | ||
| 6346 | * If the swipe ID is not provided, the current swipe ID in the message object is used. | ||
| 6347 | * | ||
| 6348 | * If the swipe data is invalid in some way, this function will exit out without doing anything. | ||
| 6349 | * @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. | ||
| 6350 | * @param {number?} [swipeId=null] - The ID of the swipe to sync. If no ID is given, the current swipe ID in the message object is used. | ||
| 6351 | * @returns {boolean} Whether the swipe data was successfully synced to the message | ||
| 6352 | */ | ||
| 6353 | export function syncSwipeToMes(messageId = null, swipeId = null) { | ||
| 6354 | if (!chat.length) { | ||
| 6355 | return false; | ||
| 6356 | } | ||
| 6357 | |||
| 6358 | const targetMessageId = messageId ?? chat.length - 1; | ||
| 6359 | if (targetMessageId >= chat.length || targetMessageId < 0) { | ||
| 6360 | console.warn(`[syncSwipeToMes] Invalid message ID: ${messageId}`); | ||
| 6361 | return false; | ||
| 6362 | } | ||
| 6363 | |||
| 6364 | const targetMessage = chat[targetMessageId]; | ||
| 6365 | if (!targetMessage) { | ||
| 6366 | return false; | ||
| 6367 | } | ||
| 6368 | |||
| 6369 | if (swipeId !== null) { | ||
| 6370 | if (isNaN(swipeId) || swipeId < 0) { | ||
| 6371 | console.warn(`[syncSwipeToMes] Invalid swipe ID: ${swipeId}`); | ||
| 6372 | return false; | ||
| 6373 | } | ||
| 6374 | targetMessage.swipe_id = swipeId; | ||
| 6375 | } | ||
| 6376 | |||
| 6377 | // No swipe data there yet, exit out | ||
| 6378 | if (typeof targetMessage.swipe_id !== 'number') { | ||
| 6379 | return false; | ||
| 6380 | } | ||
| 6381 | // If swipes structure is invalid, exit out | ||
| 6382 | if (!Array.isArray(targetMessage.swipe_info) || !Array.isArray(targetMessage.swipes)) { | ||
| 6383 | return false; | ||
| 6384 | } | ||
| 6385 | |||
| 6386 | const targetSwipeId = targetMessage.swipe_id; | ||
| 6387 | if (!targetMessage.swipes[targetSwipeId] || !targetMessage.swipe_info[targetSwipeId]) { | ||
| 6388 | console.warn(`[syncSwipeToMes] Invalid swipe ID: ${targetSwipeId}`); | ||
| 6389 | return false; | ||
| 6390 | } | ||
| 6391 | |||
| 6392 | const targetSwipeInfo = targetMessage.swipe_info[targetSwipeId]; | ||
| 6393 | if (typeof targetSwipeInfo !== 'object') { | ||
| 6394 | return false; | ||
| 6395 | } | ||
| 6396 | |||
| 6397 | targetMessage.mes = targetMessage.swipes[targetSwipeId]; | ||
| 6398 | targetMessage.send_date = targetSwipeInfo.send_date; | ||
| 6399 | targetMessage.gen_started = targetSwipeInfo.gen_started; | ||
| 6400 | targetMessage.gen_finished = targetSwipeInfo.gen_finished; | ||
| 6401 | targetMessage.extra = structuredClone(targetSwipeInfo.extra); | ||
| 6402 | |||
| 6403 | return true; | ||
| 6404 | } | ||
| 6405 | |||
| 6406 | /** | ||
| 6298 | * Saves the image to the message object. | 6407 | * Saves the image to the message object. |
| 6299 | * @param {ParsedImage} img Image object | 6408 | * @param {ParsedImage} img Image object |
| 6300 | * @param {object} mes Chat message object | 6409 | * @param {object} mes Chat message object |
| @@ -6527,6 +6636,8 @@ export async function renameCharacter(name = null, { silent = false, renameChats | |||
| 6527 | 6636 | ||
| 6528 | await eventSource.emit(event_types.CHARACTER_RENAMED, oldAvatar, newAvatar); | 6637 | await eventSource.emit(event_types.CHARACTER_RENAMED, oldAvatar, newAvatar); |
| 6529 | 6638 | ||
| 6639 | // Unload current character | ||
| 6640 | setCharacterId(undefined); | ||
| 6530 | // Reload characters list | 6641 | // Reload characters list |
| 6531 | await getCharacters(); | 6642 | await getCharacters(); |
| 6532 | 6643 | ||
| @@ -6535,7 +6646,6 @@ export async function renameCharacter(name = null, { silent = false, renameChats | |||
| 6535 | 6646 | ||
| 6536 | if (newChId !== -1) { | 6647 | if (newChId !== -1) { |
| 6537 | // Select the character after the renaming | 6648 | // Select the character after the renaming |
| 6538 | setCharacterId(undefined); | ||
| 6539 | await selectCharacterById(newChId); | 6649 | await selectCharacterById(newChId); |
| 6540 | 6650 | ||
| 6541 | // Async delay to update UI | 6651 | // Async delay to update UI |
| @@ -6668,7 +6778,22 @@ export function saveChatDebounced() { | |||
| 6668 | }, DEFAULT_SAVE_EDIT_TIMEOUT); | 6778 | }, DEFAULT_SAVE_EDIT_TIMEOUT); |
| 6669 | } | 6779 | } |
| 6670 | 6780 | ||
| 6671 | export async function saveChat(chatName, withMetadata, mesId) { | 6781 | /** |
| 6782 | * Saves the chat to the server. | ||
| 6783 | * @param {object} [options] - Additional options. | ||
| 6784 | * @param {string} [options.chatName] The name of the chat file to save to | ||
| 6785 | * @param {object} [options.withMetadata] Additional metadata to save with the chat | ||
| 6786 | * @param {number} [options.mesId] The message ID to save the chat up to | ||
| 6787 | * @param {boolean} [options.force] Force the saving despire the integrity check result | ||
| 6788 | * | ||
| 6789 | * @returns {Promise<void>} | ||
| 6790 | */ | ||
| 6791 | export async function saveChat({ chatName, withMetadata, mesId, force = false } = {}) { | ||
| 6792 | if (arguments.length > 0 && typeof arguments[0] !== 'object') { | ||
| 6793 | console.trace('saveChat called with positional arguments. Please use an object instead.'); | ||
| 6794 | [chatName, withMetadata, mesId, force] = arguments; | ||
| 6795 | } | ||
| 6796 | |||
| 6672 | const metadata = { ...chat_metadata, ...(withMetadata || {}) }; | 6797 | const metadata = { ...chat_metadata, ...(withMetadata || {}) }; |
| 6673 | const fileName = chatName ?? characters[this_chid]?.chat; | 6798 | const fileName = chatName ?? characters[this_chid]?.chat; |
| 6674 | 6799 | ||
| @@ -6688,53 +6813,59 @@ export async function saveChat(chatName, withMetadata, mesId) { | |||
| 6688 | toastr.error(t`Trying to save group chat with regular saveChat function. Aborting to prevent corruption.`); | 6813 | toastr.error(t`Trying to save group chat with regular saveChat function. Aborting to prevent corruption.`); |
| 6689 | throw new Error('Group chat saved from saveChat'); | 6814 | throw new Error('Group chat saved from saveChat'); |
| 6690 | } | 6815 | } |
| 6691 | /* | ||
| 6692 | if (item.is_user) { | ||
| 6693 | //var str = item.mes.replace(`${name1}:`, `${name1}:`); | ||
| 6694 | //chat[i].mes = str; | ||
| 6695 | //chat[i].name = name1; | ||
| 6696 | } else if (i !== chat.length - 1 && chat[i].swipe_id !== undefined) { | ||
| 6697 | // delete chat[i].swipes; | ||
| 6698 | // delete chat[i].swipe_id; | ||
| 6699 | } | ||
| 6700 | */ | ||
| 6701 | }); | 6816 | }); |
| 6702 | 6817 | ||
| 6703 | const trimmed_chat = (mesId !== undefined && mesId >= 0 && mesId < chat.length) | 6818 | const trimmedChat = (mesId !== undefined && mesId >= 0 && mesId < chat.length) |
| 6704 | ? chat.slice(0, parseInt(mesId) + 1) | 6819 | ? chat.slice(0, Number(mesId) + 1) |
| 6705 | : chat; | 6820 | : chat.slice(); |
| 6706 | 6821 | ||
| 6707 | var save_chat = [ | 6822 | const chatToSave = [ |
| 6708 | { | 6823 | { |
| 6709 | user_name: name1, | 6824 | user_name: name1, |
| 6710 | character_name: name2, | 6825 | character_name: name2, |
| 6711 | create_date: chat_create_date, | 6826 | create_date: chat_create_date, |
| 6712 | chat_metadata: metadata, | 6827 | chat_metadata: metadata, |
| 6713 | }, | 6828 | }, |
| 6714 | ...trimmed_chat, | 6829 | ...trimmedChat, |
| 6715 | ]; | 6830 | ]; |
| 6716 | return jQuery.ajax({ | 6831 | |
| 6717 | type: 'POST', | 6832 | try { |
| 6718 | url: '/api/chats/save', | 6833 | const result = await fetch('/api/chats/save', { |
| 6719 | data: JSON.stringify({ | 6834 | method: 'POST', |
| 6835 | cache: 'no-cache', | ||
| 6836 | headers: getRequestHeaders(), | ||
| 6837 | body: JSON.stringify({ | ||
| 6720 | ch_name: characters[this_chid].name, | 6838 | ch_name: characters[this_chid].name, |
| 6721 | file_name: fileName, | 6839 | file_name: fileName, |
| 6722 | chat: save_chat, | 6840 | chat: chatToSave, |
| 6723 | avatar_url: characters[this_chid].avatar, | 6841 | avatar_url: characters[this_chid].avatar, |
| 6842 | force: force, | ||
| 6724 | }), | 6843 | }), |
| 6725 | beforeSend: function () { | 6844 | }); |
| 6726 | 6845 | ||
| 6727 | }, | 6846 | if (result.ok) { |
| 6728 | cache: false, | 6847 | return; |
| 6729 | dataType: 'json', | 6848 | } |
| 6730 | contentType: 'application/json', | 6849 | |
| 6731 | success: function (data) { }, | 6850 | const errorData = await result.json(); |
| 6732 | error: function (jqXHR, exception) { | 6851 | const isIntegrityError = errorData?.error === 'integrity' && !force; |
| 6852 | if (!isIntegrityError) { | ||
| 6853 | throw new Error(result.statusText); | ||
| 6854 | } | ||
| 6855 | |||
| 6856 | const forceSaveConfirmed = await Popup.show.confirm( | ||
| 6857 | t`ERROR: Chat integrity check failed.`, | ||
| 6858 | t`Continuing the operation may result in data loss. Would you like to overwrite the chat file anyway? Pressing "NO" will cancel the save operation.`, | ||
| 6859 | { okButton: t`Yes, overwrite`, cancelButton: t`No, cancel` }, | ||
| 6860 | ) === POPUP_RESULT.AFFIRMATIVE; | ||
| 6861 | |||
| 6862 | if (forceSaveConfirmed) { | ||
| 6863 | await saveChat({ chatName, withMetadata, mesId, force: true }); | ||
| 6864 | } | ||
| 6865 | } catch (error) { | ||
| 6866 | console.error(error); | ||
| 6733 | toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Chat could not be saved`); | 6867 | toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Chat could not be saved`); |
| 6734 | console.log(exception); | 6868 | } |
| 6735 | console.log(jqXHR); | ||
| 6736 | }, | ||
| 6737 | }); | ||
| 6738 | } | 6869 | } |
| 6739 | 6870 | ||
| 6740 | async function read_avatar_load(input) { | 6871 | async function read_avatar_load(input) { |
| @@ -6861,14 +6992,14 @@ export function buildAvatarList(block, entities, { templateId = 'inline_avatar_t | |||
| 6861 | */ | 6992 | */ |
| 6862 | export async function unshallowCharacter(characterId) { | 6993 | export async function unshallowCharacter(characterId) { |
| 6863 | if (characterId === undefined) { | 6994 | if (characterId === undefined) { |
| 6864 | console.warn('Undefined character cannot be unshallowed'); | 6995 | console.debug('Undefined character cannot be unshallowed'); |
| 6865 | return; | 6996 | return; |
| 6866 | } | 6997 | } |
| 6867 | 6998 | ||
| 6868 | /** @type {import('./scripts/char-data.js').v1CharData} */ | 6999 | /** @type {import('./scripts/char-data.js').v1CharData} */ |
| 6869 | const character = characters[characterId]; | 7000 | const character = characters[characterId]; |
| 6870 | if (!character) { | 7001 | if (!character) { |
| 6871 | console.warn('Character not found:', characterId); | 7002 | console.debug('Character not found:', characterId); |
| 6872 | return; | 7003 | return; |
| 6873 | } | 7004 | } |
| 6874 | 7005 | ||
| @@ -6879,7 +7010,7 @@ export async function unshallowCharacter(characterId) { | |||
| 6879 | 7010 | ||
| 6880 | const avatar = character.avatar; | 7011 | const avatar = character.avatar; |
| 6881 | if (!avatar) { | 7012 | if (!avatar) { |
| 6882 | console.warn('Character has no avatar field:', characterId); | 7013 | console.debug('Character has no avatar field:', characterId); |
| 6883 | return; | 7014 | return; |
| 6884 | } | 7015 | } |
| 6885 | 7016 | ||
| @@ -6911,6 +7042,9 @@ export async function getChat() { | |||
| 6911 | } else { | 7042 | } else { |
| 6912 | chat_create_date = humanizedDateTime(); | 7043 | chat_create_date = humanizedDateTime(); |
| 6913 | } | 7044 | } |
| 7045 | if (!chat_metadata['integrity']) { | ||
| 7046 | chat_metadata['integrity'] = uuidv4(); | ||
| 7047 | } | ||
| 6914 | await getChatResult(); | 7048 | await getChatResult(); |
| 6915 | eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } }); | 7049 | eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } }); |
| 6916 | 7050 | ||
| @@ -7882,14 +8016,19 @@ export function select_rm_info(type, charId, previousCharId = null) { | |||
| 7882 | } | 8016 | } |
| 7883 | } | 8017 | } |
| 7884 | 8018 | ||
| 7885 | export function select_selected_character(chid) { | 8019 | /** |
| 8020 | * Selects the right menu for displaying the character editor. | ||
| 8021 | * @param {number|string} chid Character array index | ||
| 8022 | * @param {object} [param1] Options for the switch | ||
| 8023 | * @param {boolean} [param1.switchMenu=true] Whether to switch the menu | ||
| 8024 | */ | ||
| 8025 | export function select_selected_character(chid, { switchMenu = true } = {}) { | ||
| 7886 | //character select | 8026 | //character select |
| 7887 | //console.log('select_selected_character() -- starting with input of -- ' + chid + ' (name:' + characters[chid].name + ')'); | 8027 | //console.log('select_selected_character() -- starting with input of -- ' + chid + ' (name:' + characters[chid].name + ')'); |
| 7888 | select_rm_create(); | 8028 | select_rm_create({ switchMenu }); |
| 7889 | setMenuType('character_edit'); | 8029 | switchMenu && setMenuType('character_edit'); |
| 7890 | $('#delete_button').css('display', 'flex'); | 8030 | $('#delete_button').css('display', 'flex'); |
| 7891 | $('#export_button').css('display', 'flex'); | 8031 | $('#export_button').css('display', 'flex'); |
| 7892 | var display_name = characters[chid].name; | ||
| 7893 | 8032 | ||
| 7894 | //create text poles | 8033 | //create text poles |
| 7895 | $('#rm_button_back').css('display', 'none'); | 8034 | $('#rm_button_back').css('display', 'none'); |
| @@ -7904,7 +8043,7 @@ export function select_selected_character(chid) { | |||
| 7904 | 8043 | ||
| 7905 | // Don't update the navbar name if we're peeking the group member defs | 8044 | // Don't update the navbar name if we're peeking the group member defs |
| 7906 | if (!selected_group) { | 8045 | if (!selected_group) { |
| 7907 | $('#rm_button_selected_ch').children('h2').text(display_name); | 8046 | $('#rm_button_selected_ch').children('h2').text(characters[chid].name); |
| 7908 | } | 8047 | } |
| 7909 | 8048 | ||
| 7910 | $('#add_avatar_button').val(''); | 8049 | $('#add_avatar_button').val(''); |
| @@ -7935,22 +8074,20 @@ export function select_selected_character(chid) { | |||
| 7935 | $('#chat_import_avatar_url').val(characters[chid].avatar); | 8074 | $('#chat_import_avatar_url').val(characters[chid].avatar); |
| 7936 | $('#chat_import_character_name').val(characters[chid].name); | 8075 | $('#chat_import_character_name').val(characters[chid].name); |
| 7937 | $('#character_json_data').val(characters[chid].json_data); | 8076 | $('#character_json_data').val(characters[chid].json_data); |
| 7938 | let this_avatar = default_avatar; | ||
| 7939 | if (characters[chid].avatar != 'none') { | ||
| 7940 | this_avatar = getThumbnailUrl('avatar', characters[chid].avatar); | ||
| 7941 | } | ||
| 7942 | 8077 | ||
| 7943 | updateFavButtonState(characters[chid].fav || characters[chid].fav == 'true'); | 8078 | updateFavButtonState(characters[chid].fav || characters[chid].fav == 'true'); |
| 7944 | 8079 | ||
| 7945 | $('#avatar_load_preview').attr('src', this_avatar); | 8080 | const avatarUrl = characters[chid].avatar != 'none' ? getThumbnailUrl('avatar', characters[chid].avatar) : default_avatar; |
| 7946 | $('#name_div').removeClass('displayBlock'); | 8081 | $('#avatar_load_preview').attr('src', avatarUrl); |
| 7947 | $('#name_div').addClass('displayNone'); | ||
| 7948 | $('#renameCharButton').css('display', ''); | ||
| 7949 | $('.open_alternate_greetings').data('chid', chid); | 8082 | $('.open_alternate_greetings').data('chid', chid); |
| 7950 | $('#set_character_world').data('chid', chid); | 8083 | $('#set_character_world').data('chid', chid); |
| 7951 | setWorldInfoButtonClass(chid); | 8084 | setWorldInfoButtonClass(chid); |
| 7952 | checkEmbeddedWorld(chid); | 8085 | checkEmbeddedWorld(chid); |
| 7953 | 8086 | ||
| 8087 | $('#name_div').removeClass('displayBlock'); | ||
| 8088 | $('#name_div').addClass('displayNone'); | ||
| 8089 | $('#renameCharButton').css('display', ''); | ||
| 8090 | |||
| 7954 | $('#form_create').attr('actiontype', 'editcharacter'); | 8091 | $('#form_create').attr('actiontype', 'editcharacter'); |
| 7955 | $('.form_create_bottom_buttons_block .chat_lorebook_button').show(); | 8092 | $('.form_create_bottom_buttons_block .chat_lorebook_button').show(); |
| 7956 | 8093 | ||
| @@ -7962,8 +8099,13 @@ export function select_selected_character(chid) { | |||
| 7962 | saveSettingsDebounced(); | 8099 | saveSettingsDebounced(); |
| 7963 | } | 8100 | } |
| 7964 | 8101 | ||
| 7965 | function select_rm_create() { | 8102 | /** |
| 7966 | setMenuType('create'); | 8103 | * Selects the right menu for creating a new character. |
| 8104 | * @param {object} [options] Options for the switch | ||
| 8105 | * @param {boolean} [options.switchMenu=true] Whether to switch the menu | ||
| 8106 | */ | ||
| 8107 | function select_rm_create({ switchMenu = true } = {}) { | ||
| 8108 | switchMenu && setMenuType('create'); | ||
| 7967 | 8109 | ||
| 7968 | //console.log('select_rm_Create() -- selected button: '+selected_button); | 8110 | //console.log('select_rm_Create() -- selected button: '+selected_button); |
| 7969 | if (selected_button == 'create') { | 8111 | if (selected_button == 'create') { |
| @@ -7973,7 +8115,7 @@ function select_rm_create() { | |||
| 7973 | } | 8115 | } |
| 7974 | } | 8116 | } |
| 7975 | 8117 | ||
| 7976 | selectRightMenuWithAnimation('rm_ch_create_block'); | 8118 | switchMenu && selectRightMenuWithAnimation('rm_ch_create_block'); |
| 7977 | 8119 | ||
| 7978 | $('#set_chat_scenario').hide(); | 8120 | $('#set_chat_scenario').hide(); |
| 7979 | $('#delete_button_div').css('display', 'none'); | 8121 | $('#delete_button_div').css('display', 'none'); |
| @@ -8293,10 +8435,9 @@ export async function deleteSwipe(swipeId = null) { | |||
| 8293 | lastMessage.swipe_info.splice(swipeId, 1); | 8435 | lastMessage.swipe_info.splice(swipeId, 1); |
| 8294 | } | 8436 | } |
| 8295 | 8437 | ||
| 8296 | // Select the next swip, or the one before if it was the last one | 8438 | // Select the next swipe, or the one before if it was the last one |
| 8297 | const newSwipeId = Math.min(swipeId, lastMessage.swipes.length - 1); | 8439 | const newSwipeId = Math.min(swipeId, lastMessage.swipes.length - 1); |
| 8298 | lastMessage.swipe_id = newSwipeId; | 8440 | syncSwipeToMes(null, newSwipeId); |
| 8299 | lastMessage.mes = lastMessage.swipes[newSwipeId]; | ||
| 8300 | 8441 | ||
| 8301 | await saveChatConditional(); | 8442 | await saveChatConditional(); |
| 8302 | await reloadCurrentChat(); | 8443 | await reloadCurrentChat(); |
| @@ -9196,6 +9337,17 @@ function swipe_right(_event, { source, repeated } = {}) { | |||
| 9196 | } | 9337 | } |
| 9197 | } | 9338 | } |
| 9198 | 9339 | ||
| 9340 | /** | ||
| 9341 | * @typedef {object} ConnectAPIMap | ||
| 9342 | * @property {string} selected - API name (e.g. "textgenerationwebui", "openai") | ||
| 9343 | * @property {string?} [button] - CSS selector for the API button | ||
| 9344 | * @property {string?} [type] - API type, mostly used by text completion. (e.g. "openrouter") | ||
| 9345 | * @property {string?} [source] - API source, mostly used by chat completion. (e.g. "openai") | ||
| 9346 | */ | ||
| 9347 | |||
| 9348 | /** | ||
| 9349 | * @type {Record<string, ConnectAPIMap>} | ||
| 9350 | */ | ||
| 9199 | export const CONNECT_API_MAP = { | 9351 | export const CONNECT_API_MAP = { |
| 9200 | // Default APIs not contined inside text gen / chat gen | 9352 | // Default APIs not contined inside text gen / chat gen |
| 9201 | 'kobold': { | 9353 | 'kobold': { |
| @@ -10417,7 +10569,7 @@ jQuery(async function () { | |||
| 10417 | e.stopPropagation(); | 10569 | e.stopPropagation(); |
| 10418 | chat_file_for_del = $(this).attr('file_name'); | 10570 | chat_file_for_del = $(this).attr('file_name'); |
| 10419 | console.debug('detected cross click for' + chat_file_for_del); | 10571 | console.debug('detected cross click for' + chat_file_for_del); |
| 10420 | callPopup('<h3>Delete the Chat File?</h3>', 'del_chat'); | 10572 | callPopup('<h3>' + t`Delete the Chat File?` + '</h3>', 'del_chat'); |
| 10421 | }); | 10573 | }); |
| 10422 | 10574 | ||
| 10423 | $('#advanced_div').click(function () { | 10575 | $('#advanced_div').click(function () { |
| @@ -4,7 +4,7 @@ import { DOMPurify, Popper } from '../lib.js'; | |||
| 4 | 4 | ||
| 5 | import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; | 5 | import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; |
| 6 | import { is_group_generating } from './group-chats.js'; | 6 | import { is_group_generating } from './group-chats.js'; |
| 7 | import { Message, TokenHandler } from './openai.js'; | 7 | import { Message, MessageCollection, TokenHandler } from './openai.js'; |
| 8 | import { power_user } from './power-user.js'; | 8 | import { power_user } from './power-user.js'; |
| 9 | import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; | 9 | import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; |
| 10 | import { debounce_timeout } from './constants.js'; | 10 | import { debounce_timeout } from './constants.js'; |
| @@ -17,6 +17,7 @@ import { SlashCommand } from './slash-commands/SlashCommand.js'; | |||
| 17 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; | 17 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; |
| 18 | export { MODULE_NAME as NOTE_MODULE_NAME }; | 18 | export { MODULE_NAME as NOTE_MODULE_NAME }; |
| 19 | import { t } from './i18n.js'; | 19 | import { t } from './i18n.js'; |
| 20 | import { MacrosParser } from './macros.js'; | ||
| 20 | 21 | ||
| 21 | const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory | 22 | const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory |
| 22 | 23 | ||
| @@ -576,4 +577,8 @@ export function initAuthorsNote() { | |||
| 576 | `, | 577 | `, |
| 577 | })); | 578 | })); |
| 578 | eventSource.on(event_types.CHAT_CHANGED, onChatChanged); | 579 | eventSource.on(event_types.CHAT_CHANGED, onChatChanged); |
| 580 | |||
| 581 | MacrosParser.registerMacro('authorsNote', () => chat_metadata[metadata_keys.prompt] ?? '', t`The contents of the Author's Note`); | ||
| 582 | MacrosParser.registerMacro('charAuthorsNote', () => this_chid !== undefined ? (extension_settings.note.chara.find((e) => e.name === getCharaFilename())?.prompt ?? '') : '', t`The contents of the Character Author's Note`); | ||
| 583 | MacrosParser.registerMacro('defaultAuthorsNote', () => extension_settings.note.default ?? '', t`The contents of the Default Author's Note`); | ||
| 579 | } | 584 | } |
| @@ -3,10 +3,8 @@ import { debounce, escapeRegex } from '../utils.js'; | |||
| 3 | import { AutoCompleteOption } from './AutoCompleteOption.js'; | 3 | import { AutoCompleteOption } from './AutoCompleteOption.js'; |
| 4 | import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; | 4 | import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; |
| 5 | import { BlankAutoCompleteOption } from './BlankAutoCompleteOption.js'; | 5 | import { BlankAutoCompleteOption } from './BlankAutoCompleteOption.js'; |
| 6 | // eslint-disable-next-line no-unused-vars | ||
| 7 | import { AutoCompleteNameResult } from './AutoCompleteNameResult.js'; | 6 | import { AutoCompleteNameResult } from './AutoCompleteNameResult.js'; |
| 8 | import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js'; | 7 | import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js'; |
| 9 | import { Popup, getTopmostModalLayer } from '../popup.js'; | ||
| 10 | 8 | ||
| 11 | /**@readonly*/ | 9 | /**@readonly*/ |
| 12 | /**@enum {Number}*/ | 10 | /**@enum {Number}*/ |
| @@ -1,4 +1,3 @@ | |||
| 1 | import { SlashCommandNamedArgumentAutoCompleteOption } from '../slash-commands/SlashCommandNamedArgumentAutoCompleteOption.js'; | ||
| 2 | import { AutoCompleteOption } from './AutoCompleteOption.js'; | 1 | import { AutoCompleteOption } from './AutoCompleteOption.js'; |
| 3 | 2 | ||
| 4 | 3 | ||
| @@ -1,4 +1,3 @@ | |||
| 1 | import { SlashCommand } from '../slash-commands/SlashCommand.js'; | ||
| 2 | import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; | 1 | import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; |
| 3 | 2 | ||
| 4 | 3 | ||
| @@ -5,6 +5,7 @@ import { saveMetadataDebounced } from './extensions.js'; | |||
| 5 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 5 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 6 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 6 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 7 | import { flashHighlight, stringFormat } from './utils.js'; | 7 | import { flashHighlight, stringFormat } from './utils.js'; |
| 8 | import { t } from './i18n.js'; | ||
| 8 | 9 | ||
| 9 | const BG_METADATA_KEY = 'custom_background'; | 10 | const BG_METADATA_KEY = 'custom_background'; |
| 10 | const LIST_METADATA_KEY = 'chat_backgrounds'; | 11 | const LIST_METADATA_KEY = 'chat_backgrounds'; |
| @@ -243,7 +244,7 @@ async function getNewBackgroundName(referenceElement) { | |||
| 243 | const fileExtension = oldBg.split('.').pop(); | 244 | const fileExtension = oldBg.split('.').pop(); |
| 244 | const fileNameBase = isCustom ? oldBg.split('/').pop() : oldBg; | 245 | const fileNameBase = isCustom ? oldBg.split('/').pop() : oldBg; |
| 245 | const oldBgExtensionless = fileNameBase.replace(`.${fileExtension}`, ''); | 246 | const oldBgExtensionless = fileNameBase.replace(`.${fileExtension}`, ''); |
| 246 | const newBgExtensionless = await callPopup('<h3>Enter new background name:</h3>', 'input', oldBgExtensionless); | 247 | const newBgExtensionless = await callPopup('<h3>' + t`Enter new background name:` + '</h3>', 'input', oldBgExtensionless); |
| 247 | 248 | ||
| 248 | if (!newBgExtensionless) { | 249 | if (!newBgExtensionless) { |
| 249 | console.debug('no new_bg_extensionless'); | 250 | console.debug('no new_bg_extensionless'); |
| @@ -1,7 +1,6 @@ | |||
| 1 | import { | 1 | import { |
| 2 | characters, | 2 | characters, |
| 3 | saveChat, | 3 | saveChat, |
| 4 | system_messages, | ||
| 5 | system_message_types, | 4 | system_message_types, |
| 6 | this_chid, | 5 | this_chid, |
| 7 | openCharacterChat, | 6 | openCharacterChat, |
| @@ -13,7 +12,7 @@ import { | |||
| 13 | saveChatConditional, | 12 | saveChatConditional, |
| 14 | saveItemizedPrompts, | 13 | saveItemizedPrompts, |
| 15 | } from '../script.js'; | 14 | } from '../script.js'; |
| 16 | import { humanizedDateTime, getMessageTimeStamp } from './RossAscends-mods.js'; | 15 | import { humanizedDateTime } from './RossAscends-mods.js'; |
| 17 | import { | 16 | import { |
| 18 | getGroupPastChats, | 17 | getGroupPastChats, |
| 19 | group_activation_strategy, | 18 | group_activation_strategy, |
| @@ -156,7 +155,7 @@ export async function createBranch(mesId) { | |||
| 156 | if (selected_group) { | 155 | if (selected_group) { |
| 157 | await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); | 156 | await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); |
| 158 | } else { | 157 | } else { |
| 159 | await saveChat(name, newMetadata, mesId); | 158 | await saveChat({ chatName: name, withMetadata: newMetadata, mesId }); |
| 160 | } | 159 | } |
| 161 | // append to branches list if it exists | 160 | // append to branches list if it exists |
| 162 | // otherwise create it | 161 | // otherwise create it |
| @@ -212,7 +211,7 @@ export async function createNewBookmark(mesId, { forceName = null } = {}) { | |||
| 212 | if (selected_group) { | 211 | if (selected_group) { |
| 213 | await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); | 212 | await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); |
| 214 | } else { | 213 | } else { |
| 215 | await saveChat(name, newMetadata, mesId); | 214 | await saveChat({ chatName: name, withMetadata: newMetadata, mesId }); |
| 216 | } | 215 | } |
| 217 | 216 | ||
| 218 | lastMes.extra['bookmark_link'] = name; | 217 | lastMes.extra['bookmark_link'] = name; |
| @@ -358,7 +357,7 @@ export async function convertSoloToGroupChat() { | |||
| 358 | // Click on the freshly selected group to open it | 357 | // Click on the freshly selected group to open it |
| 359 | await openGroupById(group.id); | 358 | await openGroupById(group.id); |
| 360 | 359 | ||
| 361 | toastr.success('The chat has been successfully converted!'); | 360 | toastr.success(t`The chat has been successfully converted!`); |
| 362 | } | 361 | } |
| 363 | 362 | ||
| 364 | /** | 363 | /** |
| @@ -1,20 +1,20 @@ | |||
| 1 | import { getPresetManager } from './preset-manager.js'; | 1 | import { getPresetManager } from './preset-manager.js'; |
| 2 | import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js'; | 2 | import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js'; |
| 3 | import { getTextGenServer } from './textgen-settings.js'; | 3 | import { getTextGenServer } from './textgen-settings.js'; |
| 4 | import { extractReasoningFromData } from './reasoning.js'; | ||
| 5 | import { formatInstructModeChat, formatInstructModePrompt, names_behavior_types } from './instruct-mode.js'; | ||
| 4 | 6 | ||
| 5 | // #region Type Definitions | 7 | // #region Type Definitions |
| 6 | /** | 8 | /** |
| 7 | * @typedef {Object} TextCompletionRequestBase | 9 | * @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 {number} max_tokens - Maximum number of tokens to generate |
| 10 | * @property {string} [model] - Optional model name | 11 | * @property {string} [model] - Optional model name |
| 11 | * @property {string} api_type - Type of API to use | 12 | * @property {string} api_type - Type of API to use |
| 12 | * @property {string} [api_server] - Optional API server URL | 13 | * @property {string} [api_server] - Optional API server URL |
| 13 | * @property {number} [temperature] - Optional temperature parameter | 14 | * @property {number} [temperature] - Optional temperature parameter |
| 15 | * @property {number} [min_p] - Optional min_p parameter | ||
| 14 | */ | 16 | */ |
| 15 | 17 | ||
| 16 | /** @typedef {Record<string, any> & TextCompletionRequestBase} TextCompletionRequest */ | ||
| 17 | |||
| 18 | /** | 18 | /** |
| 19 | * @typedef {Object} TextCompletionPayloadBase | 19 | * @typedef {Object} TextCompletionPayloadBase |
| 20 | * @property {string} prompt - The text prompt for completion | 20 | * @property {string} prompt - The text prompt for completion |
| @@ -41,9 +41,17 @@ import { getTextGenServer } from './textgen-settings.js'; | |||
| 41 | * @property {string} chat_completion_source - Source provider for chat completion | 41 | * @property {string} chat_completion_source - Source provider for chat completion |
| 42 | * @property {number} max_tokens - Maximum number of tokens to generate | 42 | * @property {number} max_tokens - Maximum number of tokens to generate |
| 43 | * @property {number} [temperature] - Optional temperature parameter for response randomness | 43 | * @property {number} [temperature] - Optional temperature parameter for response randomness |
| 44 | * @property {string} [custom_url] - Optional custom URL for chat completion | ||
| 44 | */ | 45 | */ |
| 45 | 46 | ||
| 46 | /** @typedef {Record<string, any> & ChatCompletionPayloadBase} ChatCompletionPayload */ | 47 | /** @typedef {Record<string, any> & ChatCompletionPayloadBase} ChatCompletionPayload */ |
| 48 | |||
| 49 | /** | ||
| 50 | * @typedef {Object} ExtractedData | ||
| 51 | * @property {string} content - Extracted content. | ||
| 52 | * @property {string} reasoning - Extracted reasoning. | ||
| 53 | */ | ||
| 54 | |||
| 47 | // #endregion | 55 | // #endregion |
| 48 | 56 | ||
| 49 | /** | 57 | /** |
| @@ -53,11 +61,11 @@ export class TextCompletionService { | |||
| 53 | static TYPE = 'textgenerationwebui'; | 61 | static TYPE = 'textgenerationwebui'; |
| 54 | 62 | ||
| 55 | /** | 63 | /** |
| 56 | * @param {TextCompletionRequest} custom | 64 | * @param {Record<string, any> & TextCompletionRequestBase & {prompt: string}} custom |
| 57 | * @returns {TextCompletionPayload} | 65 | * @returns {TextCompletionPayload} |
| 58 | */ | 66 | */ |
| 59 | static createRequestData({ prompt, max_tokens, model, api_type, api_server, temperature, ...props }) { | 67 | static createRequestData({ prompt, max_tokens, model, api_type, api_server, temperature, min_p, ...props }) { |
| 60 | return { | 68 | const payload = { |
| 61 | ...props, | 69 | ...props, |
| 62 | prompt, | 70 | prompt, |
| 63 | max_tokens, | 71 | max_tokens, |
| @@ -66,15 +74,25 @@ export class TextCompletionService { | |||
| 66 | api_type, | 74 | api_type, |
| 67 | api_server: api_server ?? getTextGenServer(api_type), | 75 | api_server: api_server ?? getTextGenServer(api_type), |
| 68 | temperature, | 76 | temperature, |
| 77 | min_p, | ||
| 69 | stream: false, | 78 | stream: false, |
| 70 | }; | 79 | }; |
| 80 | |||
| 81 | // Remove undefined values to avoid API errors | ||
| 82 | Object.keys(payload).forEach(key => { | ||
| 83 | if (payload[key] === undefined) { | ||
| 84 | delete payload[key]; | ||
| 85 | } | ||
| 86 | }); | ||
| 87 | |||
| 88 | return payload; | ||
| 71 | } | 89 | } |
| 72 | 90 | ||
| 73 | /** | 91 | /** |
| 74 | * Sends a text completion request to the specified server | 92 | * Sends a text completion request to the specified server |
| 75 | * @param {TextCompletionPayload} data Request data | 93 | * @param {TextCompletionPayload} data Request data |
| 76 | * @param {boolean?} extractData Extract message from the response. Default true | 94 | * @param {boolean?} extractData Extract message from the response. Default true |
| 77 | * @returns {Promise<string | any>} Extracted data or the raw response | 95 | * @returns {Promise<ExtractedData | any>} Extracted data or the raw response |
| 78 | * @throws {Error} | 96 | * @throws {Error} |
| 79 | */ | 97 | */ |
| 80 | static async sendRequest(data, extractData = true) { | 98 | static async sendRequest(data, extractData = true) { |
| @@ -91,31 +109,150 @@ export class TextCompletionService { | |||
| 91 | throw json; | 109 | throw json; |
| 92 | } | 110 | } |
| 93 | 111 | ||
| 94 | return extractData ? extractMessageFromData(json, this.TYPE) : json; | 112 | if (!extractData) { |
| 113 | return json; | ||
| 114 | } | ||
| 115 | |||
| 116 | return { | ||
| 117 | content: extractMessageFromData(json, this.TYPE), | ||
| 118 | reasoning: extractReasoningFromData(json, { | ||
| 119 | mainApi: this.TYPE, | ||
| 120 | textGenType: data.api_type, | ||
| 121 | ignoreShowThoughts: true, | ||
| 122 | }), | ||
| 123 | }; | ||
| 95 | } | 124 | } |
| 96 | 125 | ||
| 97 | /** | 126 | /** |
| 98 | * @param {string} presetName | 127 | * Process and send a text completion request with optional preset & instruct |
| 99 | * @param {TextCompletionRequest} custom | 128 | * @param {Record<string, any> & TextCompletionRequestBase & {prompt: (ChatCompletionMessage & {ignoreInstruct?: boolean})[] |string}} custom |
| 100 | * @param {boolean?} extractData Extract message from the response. Default true | 129 | * @param {Object} options - Configuration options |
| 101 | * @returns {Promise<string | any>} Extracted data or the raw response | 130 | * @param {string?} [options.presetName] - Name of the preset to use for generation settings |
| 131 | * @param {string?} [options.instructName] - Name of instruct preset for message formatting | ||
| 132 | * @param {boolean} extractData - Whether to extract structured data from response | ||
| 133 | * @returns {Promise<ExtractedData | any>} Extracted data or the raw response | ||
| 102 | * @throws {Error} | 134 | * @throws {Error} |
| 103 | */ | 135 | */ |
| 104 | static async sendRequestWithPreset(presetName, custom, extractData = true) { | 136 | static async processRequest( |
| 137 | custom, | ||
| 138 | options = {}, | ||
| 139 | extractData = true, | ||
| 140 | ) { | ||
| 141 | const { presetName, instructName } = options; | ||
| 142 | let requestData = { ...custom }; | ||
| 143 | const prompt = custom.prompt; | ||
| 144 | |||
| 145 | // Apply generation preset if specified | ||
| 146 | if (presetName) { | ||
| 105 | const presetManager = getPresetManager(this.TYPE); | 147 | const presetManager = getPresetManager(this.TYPE); |
| 106 | if (!presetManager) { | 148 | if (presetManager) { |
| 107 | throw new Error('Preset manager not found'); | 149 | const preset = presetManager.getCompletionPresetByName(presetName); |
| 150 | if (preset) { | ||
| 151 | // Convert preset to payload and merge with custom parameters | ||
| 152 | const presetPayload = this.presetToGeneratePayload(preset, {}); | ||
| 153 | requestData = { ...presetPayload, ...requestData }; | ||
| 154 | } else { | ||
| 155 | console.warn(`Preset "${presetName}" not found, continuing with default settings`); | ||
| 156 | } | ||
| 157 | } else { | ||
| 158 | console.warn('Preset manager not found, continuing with default settings'); | ||
| 159 | } | ||
| 108 | } | 160 | } |
| 109 | 161 | ||
| 110 | const preset = presetManager.getCompletionPresetByName(presetName); | 162 | // Handle instruct formatting if requested |
| 111 | if (!preset) { | 163 | if (Array.isArray(prompt) && instructName) { |
| 112 | throw new Error('Preset not found'); | 164 | const instructPresetManager = getPresetManager('instruct'); |
| 165 | let instructPreset = instructPresetManager?.getCompletionPresetByName(instructName); | ||
| 166 | if (instructPreset) { | ||
| 167 | // Clone the preset to avoid modifying the original | ||
| 168 | instructPreset = structuredClone(instructPreset); | ||
| 169 | instructPreset.macro = false; | ||
| 170 | instructPreset.names_behavior = names_behavior_types.NONE; | ||
| 171 | |||
| 172 | // Format messages using instruct formatting | ||
| 173 | const formattedMessages = []; | ||
| 174 | for (const message of prompt) { | ||
| 175 | let messageContent = message.content; | ||
| 176 | if (!message.ignoreInstruct) { | ||
| 177 | messageContent = formatInstructModeChat( | ||
| 178 | message.role, | ||
| 179 | message.content, | ||
| 180 | message.role === 'user', | ||
| 181 | false, | ||
| 182 | undefined, | ||
| 183 | undefined, | ||
| 184 | undefined, | ||
| 185 | undefined, | ||
| 186 | instructPreset, | ||
| 187 | ); | ||
| 188 | |||
| 189 | // Add prompt formatting for the last message | ||
| 190 | if (message === prompt[prompt.length - 1]) { | ||
| 191 | messageContent += formatInstructModePrompt( | ||
| 192 | undefined, | ||
| 193 | false, | ||
| 194 | undefined, | ||
| 195 | undefined, | ||
| 196 | undefined, | ||
| 197 | false, | ||
| 198 | false, | ||
| 199 | instructPreset, | ||
| 200 | ); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | formattedMessages.push(messageContent); | ||
| 204 | } | ||
| 205 | requestData.prompt = formattedMessages.join(''); | ||
| 206 | if (instructPreset.output_suffix) { | ||
| 207 | requestData.stop = [instructPreset.output_suffix]; | ||
| 208 | requestData.stopping_strings = [instructPreset.output_suffix]; | ||
| 209 | } | ||
| 210 | } else { | ||
| 211 | console.warn(`Instruct preset "${instructName}" not found, using basic formatting`); | ||
| 212 | requestData.prompt = prompt.map(x => x.content).join('\n\n'); | ||
| 213 | } | ||
| 214 | } else if (typeof prompt === 'string') { | ||
| 215 | requestData.prompt = prompt; | ||
| 216 | } else { | ||
| 217 | requestData.prompt = prompt.map(x => x.content).join('\n\n'); | ||
| 113 | } | 218 | } |
| 114 | 219 | ||
| 115 | const data = this.createRequestData({ ...preset, ...custom }); | 220 | // @ts-ignore |
| 221 | const data = this.createRequestData(requestData); | ||
| 116 | 222 | ||
| 117 | return await this.sendRequest(data, extractData); | 223 | return await this.sendRequest(data, extractData); |
| 118 | } | 224 | } |
| 225 | |||
| 226 | /** | ||
| 227 | * Converts a preset to a valid text completion payload. | ||
| 228 | * Only supports temperature. | ||
| 229 | * @param {Object} preset - The preset configuration | ||
| 230 | * @param {Object} customPreset - Additional parameters to override preset values | ||
| 231 | * @returns {Object} - Formatted payload for text completion API | ||
| 232 | */ | ||
| 233 | static presetToGeneratePayload(preset, customPreset = {}) { | ||
| 234 | if (!preset || typeof preset !== 'object') { | ||
| 235 | throw new Error('Invalid preset: must be an object'); | ||
| 236 | } | ||
| 237 | |||
| 238 | // Merge preset with custom parameters | ||
| 239 | const settings = { ...preset, ...customPreset }; | ||
| 240 | |||
| 241 | // Initialize base payload with common parameters | ||
| 242 | let payload = { | ||
| 243 | 'temperature': settings.temp ? Number(settings.temp) : undefined, | ||
| 244 | 'min_p': settings.min_p ? Number(settings.min_p) : undefined, | ||
| 245 | }; | ||
| 246 | |||
| 247 | // Remove undefined values to avoid API errors | ||
| 248 | Object.keys(payload).forEach(key => { | ||
| 249 | if (payload[key] === undefined) { | ||
| 250 | delete payload[key]; | ||
| 251 | } | ||
| 252 | }); | ||
| 253 | |||
| 254 | return payload; | ||
| 255 | } | ||
| 119 | } | 256 | } |
| 120 | 257 | ||
| 121 | /** | 258 | /** |
| @@ -128,23 +265,33 @@ export class ChatCompletionService { | |||
| 128 | * @param {ChatCompletionPayload} custom | 265 | * @param {ChatCompletionPayload} custom |
| 129 | * @returns {ChatCompletionPayload} | 266 | * @returns {ChatCompletionPayload} |
| 130 | */ | 267 | */ |
| 131 | static createRequestData({ messages, model, chat_completion_source, max_tokens, temperature, ...props }) { | 268 | static createRequestData({ messages, model, chat_completion_source, max_tokens, temperature, custom_url, ...props }) { |
| 132 | return { | 269 | const payload = { |
| 133 | ...props, | 270 | ...props, |
| 134 | messages, | 271 | messages, |
| 135 | model, | 272 | model, |
| 136 | chat_completion_source, | 273 | chat_completion_source, |
| 137 | max_tokens, | 274 | max_tokens, |
| 138 | temperature, | 275 | temperature, |
| 276 | custom_url, | ||
| 139 | stream: false, | 277 | stream: false, |
| 140 | }; | 278 | }; |
| 279 | |||
| 280 | // Remove undefined values to avoid API errors | ||
| 281 | Object.keys(payload).forEach(key => { | ||
| 282 | if (payload[key] === undefined) { | ||
| 283 | delete payload[key]; | ||
| 284 | } | ||
| 285 | }); | ||
| 286 | |||
| 287 | return payload; | ||
| 141 | } | 288 | } |
| 142 | 289 | ||
| 143 | /** | 290 | /** |
| 144 | * Sends a chat completion request | 291 | * Sends a chat completion request |
| 145 | * @param {ChatCompletionPayload} data Request data | 292 | * @param {ChatCompletionPayload} data Request data |
| 146 | * @param {boolean?} extractData Extract message from the response. Default true | 293 | * @param {boolean?} extractData Extract message from the response. Default true |
| 147 | * @returns {Promise<string | any>} Extracted data or the raw response | 294 | * @returns {Promise<ExtractedData | any>} Extracted data or the raw response |
| 148 | * @throws {Error} | 295 | * @throws {Error} |
| 149 | */ | 296 | */ |
| 150 | static async sendRequest(data, extractData = true) { | 297 | static async sendRequest(data, extractData = true) { |
| @@ -161,29 +308,82 @@ export class ChatCompletionService { | |||
| 161 | throw json; | 308 | throw json; |
| 162 | } | 309 | } |
| 163 | 310 | ||
| 164 | return extractData ? extractMessageFromData(json, this.TYPE) : json; | 311 | if (!extractData) { |
| 312 | return json; | ||
| 313 | } | ||
| 314 | |||
| 315 | return { | ||
| 316 | content: extractMessageFromData(json, this.TYPE), | ||
| 317 | reasoning: extractReasoningFromData(json, { | ||
| 318 | mainApi: this.TYPE, | ||
| 319 | textGenType: data.chat_completion_source, | ||
| 320 | ignoreShowThoughts: true, | ||
| 321 | }), | ||
| 322 | }; | ||
| 165 | } | 323 | } |
| 166 | 324 | ||
| 167 | /** | 325 | /** |
| 168 | * @param {string} presetName | 326 | * Process and send a chat completion request with optional preset |
| 169 | * @param {ChatCompletionPayload} custom | 327 | * @param {ChatCompletionPayload} custom |
| 170 | * @param {boolean} extractData Extract message from the response. Default true | 328 | * @param {Object} options - Configuration options |
| 171 | * @returns {Promise<string | any>} Extracted data or the raw response | 329 | * @param {string?} [options.presetName] - Name of the preset to use for generation settings |
| 330 | * @param {boolean} extractData - Whether to extract structured data from response | ||
| 331 | * @returns {Promise<ExtractedData | any>} Extracted data or the raw response | ||
| 172 | * @throws {Error} | 332 | * @throws {Error} |
| 173 | */ | 333 | */ |
| 174 | static async sendRequestWithPreset(presetName, custom, extractData = true) { | 334 | static async processRequest(custom, options, extractData = true) { |
| 175 | const presetManager = getPresetManager(this.TYPE); | 335 | const { presetName } = options; |
| 176 | if (!presetManager) { | 336 | let requestData = { ...custom }; |
| 177 | throw new Error('Preset manager not found'); | ||
| 178 | } | ||
| 179 | 337 | ||
| 338 | // Apply generation preset if specified | ||
| 339 | if (presetName) { | ||
| 340 | const presetManager = getPresetManager(this.TYPE); | ||
| 341 | if (presetManager) { | ||
| 180 | const preset = presetManager.getCompletionPresetByName(presetName); | 342 | const preset = presetManager.getCompletionPresetByName(presetName); |
| 181 | if (!preset) { | 343 | if (preset) { |
| 182 | throw new Error('Preset not found'); | 344 | // Convert preset to payload and merge with custom parameters |
| 345 | const presetPayload = this.presetToGeneratePayload(preset, {}); | ||
| 346 | requestData = { ...presetPayload, ...requestData }; | ||
| 347 | } else { | ||
| 348 | console.warn(`Preset "${presetName}" not found, continuing with default settings`); | ||
| 349 | } | ||
| 350 | } else { | ||
| 351 | console.warn('Preset manager not found, continuing with default settings'); | ||
| 352 | } | ||
| 183 | } | 353 | } |
| 184 | 354 | ||
| 185 | const data = this.createRequestData({ ...preset, ...custom }); | 355 | const data = this.createRequestData(requestData); |
| 186 | 356 | ||
| 187 | return await this.sendRequest(data, extractData); | 357 | return await this.sendRequest(data, extractData); |
| 188 | } | 358 | } |
| 359 | |||
| 360 | /** | ||
| 361 | * Converts a preset to a valid chat completion payload | ||
| 362 | * Only supports temperature. | ||
| 363 | * @param {Object} preset - The preset configuration | ||
| 364 | * @param {Object} customParams - Additional parameters to override preset values | ||
| 365 | * @returns {Object} - Formatted payload for chat completion API | ||
| 366 | */ | ||
| 367 | static presetToGeneratePayload(preset, customParams = {}) { | ||
| 368 | if (!preset || typeof preset !== 'object') { | ||
| 369 | throw new Error('Invalid preset: must be an object'); | ||
| 370 | } | ||
| 371 | |||
| 372 | // Merge preset with custom parameters | ||
| 373 | const settings = { ...preset, ...customParams }; | ||
| 374 | |||
| 375 | // Initialize base payload with common parameters | ||
| 376 | const payload = { | ||
| 377 | temperature: settings.temperature ? Number(settings.temperature) : undefined, | ||
| 378 | }; | ||
| 379 | |||
| 380 | // Remove undefined values to avoid API errors | ||
| 381 | Object.keys(payload).forEach(key => { | ||
| 382 | if (payload[key] === undefined) { | ||
| 383 | delete payload[key]; | ||
| 384 | } | ||
| 385 | }); | ||
| 386 | |||
| 387 | return payload; | ||
| 388 | } | ||
| 189 | } | 389 | } |
| @@ -424,7 +424,7 @@ jQuery(async () => { | |||
| 424 | installHintButton.on('click', async function () { | 424 | installHintButton.on('click', async function () { |
| 425 | const installButton = $('#third_party_extension_button'); | 425 | const installButton = $('#third_party_extension_button'); |
| 426 | flashHighlight(installButton, 5000); | 426 | flashHighlight(installButton, 5000); |
| 427 | toastr.info('Click the flashing button to install extensions.', 'How to install extensions?'); | 427 | toastr.info(t`Click the flashing button to install extensions.`, t`How to install extensions?`); |
| 428 | }); | 428 | }); |
| 429 | 429 | ||
| 430 | const connectButton = windowHtml.find('#assets-connect-button'); | 430 | const connectButton = windowHtml.find('#assets-connect-button'); |
| @@ -1,4 +1,4 @@ | |||
| 1 | <div id="attachFile" class="list-group-item flex-container flexGap5" title="Attach a file or image to a current chat."> | 1 | <div id="attachFile" class="list-group-item flex-container flexGap5" data-i18n="[title]Attach a file or image to a current chat." title="Attach a file or image to a current chat."> |
| 2 | <div class="fa-fw fa-solid fa-paperclip extensionsMenuExtensionButton"></div> | 2 | <div class="fa-fw fa-solid fa-paperclip extensionsMenuExtensionButton"></div> |
| 3 | <span data-i18n="Attach a File">Attach a File</span> | 3 | <span data-i18n="Attach a File">Attach a File</span> |
| 4 | </div> | 4 | </div> |
| @@ -42,6 +42,9 @@ | |||
| 42 | <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> |
| 43 | <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> |
| 44 | <option data-type="mistral" value="pixtral-large-2411">pixtral-large-2411</option> | 44 | <option data-type="mistral" value="pixtral-large-2411">pixtral-large-2411</option> |
| 45 | <option data-type="mistral" value="mistral-large-pixtral-2411">mistral-large-pixtral-2411</option> | ||
| 46 | <option data-type="mistral" value="mistral-small-2503">mistral-small-2503</option> | ||
| 47 | <option data-type="mistral" value="mistral-small-latest">mistral-small-latest</option> | ||
| 45 | <option data-type="zerooneai" value="yi-vision">yi-vision</option> | 48 | <option data-type="zerooneai" value="yi-vision">yi-vision</option> |
| 46 | <option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option> | 49 | <option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option> |
| 47 | <option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option> | 50 | <option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option> |
| @@ -1,4 +1,4 @@ | |||
| 1 | import { Fuse } from '../../../lib.js'; | 1 | import { DOMPurify, Fuse } from '../../../lib.js'; |
| 2 | 2 | ||
| 3 | import { event_types, eventSource, main_api, saveSettingsDebounced } from '../../../script.js'; | 3 | import { event_types, eventSource, main_api, saveSettingsDebounced } from '../../../script.js'; |
| 4 | import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js'; | 4 | import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js'; |
| @@ -39,6 +39,7 @@ const CC_COMMANDS = [ | |||
| 39 | 'proxy', | 39 | 'proxy', |
| 40 | 'stop-strings', | 40 | 'stop-strings', |
| 41 | 'start-reply-with', | 41 | 'start-reply-with', |
| 42 | 'reasoning-template', | ||
| 42 | ]; | 43 | ]; |
| 43 | 44 | ||
| 44 | const TC_COMMANDS = [ | 45 | const TC_COMMANDS = [ |
| @@ -54,6 +55,7 @@ const TC_COMMANDS = [ | |||
| 54 | 'tokenizer', | 55 | 'tokenizer', |
| 55 | 'stop-strings', | 56 | 'stop-strings', |
| 56 | 'start-reply-with', | 57 | 'start-reply-with', |
| 58 | 'reasoning-template', | ||
| 57 | ]; | 59 | ]; |
| 58 | 60 | ||
| 59 | const FANCY_NAMES = { | 61 | const FANCY_NAMES = { |
| @@ -70,6 +72,7 @@ const FANCY_NAMES = { | |||
| 70 | 'tokenizer': 'Tokenizer', | 72 | 'tokenizer': 'Tokenizer', |
| 71 | 'stop-strings': 'Custom Stopping Strings', | 73 | 'stop-strings': 'Custom Stopping Strings', |
| 72 | 'start-reply-with': 'Start Reply With', | 74 | 'start-reply-with': 'Start Reply With', |
| 75 | 'reasoning-template': 'Reasoning Template', | ||
| 73 | }; | 76 | }; |
| 74 | 77 | ||
| 75 | /** | 78 | /** |
| @@ -154,6 +157,7 @@ const profilesProvider = () => [ | |||
| 154 | * @property {string} [tokenizer] Tokenizer | 157 | * @property {string} [tokenizer] Tokenizer |
| 155 | * @property {string} [stop-strings] Custom Stopping Strings | 158 | * @property {string} [stop-strings] Custom Stopping Strings |
| 156 | * @property {string} [start-reply-with] Start Reply With | 159 | * @property {string} [start-reply-with] Start Reply With |
| 160 | * @property {string} [reasoning-template] Reasoning Template | ||
| 157 | * @property {string[]} [exclude] Commands to exclude | 161 | * @property {string[]} [exclude] Commands to exclude |
| 158 | */ | 162 | */ |
| 159 | 163 | ||
| @@ -267,9 +271,14 @@ async function createConnectionProfile(forceName = null) { | |||
| 267 | }); | 271 | }); |
| 268 | const isNameTaken = (n) => extension_settings.connectionManager.profiles.some(p => p.name === n); | 272 | const isNameTaken = (n) => extension_settings.connectionManager.profiles.some(p => p.name === n); |
| 269 | const suggestedName = getUniqueName(collapseSpaces(`${profile.api ?? ''} ${profile.model ?? ''} - ${profile.preset ?? ''}`), isNameTaken); | 273 | const suggestedName = getUniqueName(collapseSpaces(`${profile.api ?? ''} ${profile.model ?? ''} - ${profile.preset ?? ''}`), isNameTaken); |
| 270 | const name = forceName ?? await callGenericPopup(template, POPUP_TYPE.INPUT, suggestedName, { rows: 2 }); | 274 | let name = forceName ?? await callGenericPopup(template, POPUP_TYPE.INPUT, suggestedName, { rows: 2 }); |
| 271 | 275 | // If it's cancelled, it will be false | |
| 276 | if (!name) { | ||
| 277 | return null; | ||
| 278 | } | ||
| 279 | name = DOMPurify.sanitize(String(name)); | ||
| 272 | if (!name) { | 280 | if (!name) { |
| 281 | toastr.error('Name cannot be empty.'); | ||
| 273 | return null; | 282 | return null; |
| 274 | } | 283 | } |
| 275 | 284 | ||
| @@ -303,7 +312,8 @@ async function deleteConnectionProfile() { | |||
| 303 | return; | 312 | return; |
| 304 | } | 313 | } |
| 305 | 314 | ||
| 306 | const name = extension_settings.connectionManager.profiles[index].name; | 315 | const profile = extension_settings.connectionManager.profiles[index]; |
| 316 | const name = profile.name; | ||
| 307 | const confirm = await Popup.show.confirm(t`Are you sure you want to delete the selected profile?`, name); | 317 | const confirm = await Popup.show.confirm(t`Are you sure you want to delete the selected profile?`, name); |
| 308 | 318 | ||
| 309 | if (!confirm) { | 319 | if (!confirm) { |
| @@ -313,6 +323,8 @@ async function deleteConnectionProfile() { | |||
| 313 | extension_settings.connectionManager.profiles.splice(index, 1); | 323 | extension_settings.connectionManager.profiles.splice(index, 1); |
| 314 | extension_settings.connectionManager.selectedProfile = null; | 324 | extension_settings.connectionManager.selectedProfile = null; |
| 315 | saveSettingsDebounced(); | 325 | saveSettingsDebounced(); |
| 326 | |||
| 327 | await eventSource.emit(event_types.CONNECTION_PROFILE_DELETED, profile); | ||
| 316 | } | 328 | } |
| 317 | 329 | ||
| 318 | /** | 330 | /** |
| @@ -512,6 +524,7 @@ async function renderDetailsContent(detailsContent) { | |||
| 512 | saveSettingsDebounced(); | 524 | saveSettingsDebounced(); |
| 513 | renderConnectionProfiles(profiles); | 525 | renderConnectionProfiles(profiles); |
| 514 | await renderDetailsContent(detailsContent); | 526 | await renderDetailsContent(detailsContent); |
| 527 | await eventSource.emit(event_types.CONNECTION_PROFILE_CREATED, profile); | ||
| 515 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); | 528 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); |
| 516 | }); | 529 | }); |
| 517 | 530 | ||
| @@ -523,9 +536,11 @@ async function renderDetailsContent(detailsContent) { | |||
| 523 | console.log('No profile selected'); | 536 | console.log('No profile selected'); |
| 524 | return; | 537 | return; |
| 525 | } | 538 | } |
| 539 | const oldProfile = structuredClone(profile); | ||
| 526 | await updateConnectionProfile(profile); | 540 | await updateConnectionProfile(profile); |
| 527 | await renderDetailsContent(detailsContent); | 541 | await renderDetailsContent(detailsContent); |
| 528 | saveSettingsDebounced(); | 542 | saveSettingsDebounced(); |
| 543 | await eventSource.emit(event_types.CONNECTION_PROFILE_UPDATED, oldProfile, profile); | ||
| 529 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); | 544 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); |
| 530 | toastr.success('Connection profile updated', '', { timeOut: 1500 }); | 545 | toastr.success('Connection profile updated', '', { timeOut: 1500 }); |
| 531 | }); | 546 | }); |
| @@ -559,7 +574,7 @@ async function renderDetailsContent(detailsContent) { | |||
| 559 | return acc; | 574 | return acc; |
| 560 | }, {}); | 575 | }, {}); |
| 561 | const template = $(await renderExtensionTemplateAsync(MODULE_NAME, 'edit', { name: profile.name, settings })); | 576 | const template = $(await renderExtensionTemplateAsync(MODULE_NAME, 'edit', { name: profile.name, settings })); |
| 562 | const newName = await callGenericPopup(template, POPUP_TYPE.INPUT, profile.name, { | 577 | let newName = await callGenericPopup(template, POPUP_TYPE.INPUT, profile.name, { |
| 563 | rows: 2, | 578 | rows: 2, |
| 564 | customButtons: [{ | 579 | customButtons: [{ |
| 565 | text: t`Save and Update`, | 580 | text: t`Save and Update`, |
| @@ -571,7 +586,13 @@ async function renderDetailsContent(detailsContent) { | |||
| 571 | }], | 586 | }], |
| 572 | }); | 587 | }); |
| 573 | 588 | ||
| 589 | // If it's cancelled, it will be false | ||
| 590 | if (!newName) { | ||
| 591 | return; | ||
| 592 | } | ||
| 593 | newName = DOMPurify.sanitize(String(newName)); | ||
| 574 | if (!newName) { | 594 | if (!newName) { |
| 595 | toastr.error('Name cannot be empty.'); | ||
| 575 | return; | 596 | return; |
| 576 | } | 597 | } |
| 577 | 598 | ||
| @@ -584,6 +605,7 @@ async function renderDetailsContent(detailsContent) { | |||
| 584 | return Object.entries(FANCY_NAMES).find(x => x[1] === String($(this).val()))?.[0]; | 605 | return Object.entries(FANCY_NAMES).find(x => x[1] === String($(this).val()))?.[0]; |
| 585 | }).get(); | 606 | }).get(); |
| 586 | 607 | ||
| 608 | const oldProfile = structuredClone(profile); | ||
| 587 | if (newExcludeList.length !== profile.exclude.length || !newExcludeList.every(e => profile.exclude.includes(e))) { | 609 | if (newExcludeList.length !== profile.exclude.length || !newExcludeList.every(e => profile.exclude.includes(e))) { |
| 588 | profile.exclude = newExcludeList; | 610 | profile.exclude = newExcludeList; |
| 589 | for (const command of newExcludeList) { | 611 | for (const command of newExcludeList) { |
| @@ -598,10 +620,11 @@ async function renderDetailsContent(detailsContent) { | |||
| 598 | 620 | ||
| 599 | if (profile.name !== newName) { | 621 | if (profile.name !== newName) { |
| 600 | toastr.success('Connection profile renamed.'); | 622 | toastr.success('Connection profile renamed.'); |
| 601 | profile.name = String(newName); | 623 | profile.name = newName; |
| 602 | } | 624 | } |
| 603 | 625 | ||
| 604 | saveSettingsDebounced(); | 626 | saveSettingsDebounced(); |
| 627 | await eventSource.emit(event_types.CONNECTION_PROFILE_UPDATED, oldProfile, profile); | ||
| 605 | renderConnectionProfiles(profiles); | 628 | renderConnectionProfiles(profiles); |
| 606 | await renderDetailsContent(detailsContent); | 629 | await renderDetailsContent(detailsContent); |
| 607 | }); | 630 | }); |
| @@ -704,6 +727,7 @@ async function renderDetailsContent(detailsContent) { | |||
| 704 | saveSettingsDebounced(); | 727 | saveSettingsDebounced(); |
| 705 | renderConnectionProfiles(profiles); | 728 | renderConnectionProfiles(profiles); |
| 706 | await renderDetailsContent(detailsContent); | 729 | await renderDetailsContent(detailsContent); |
| 730 | await eventSource.emit(event_types.CONNECTION_PROFILE_CREATED, profile); | ||
| 707 | return profile.name; | 731 | return profile.name; |
| 708 | }, | 732 | }, |
| 709 | })); | 733 | })); |
| @@ -718,9 +742,11 @@ async function renderDetailsContent(detailsContent) { | |||
| 718 | toastr.warning('No profile selected.'); | 742 | toastr.warning('No profile selected.'); |
| 719 | return ''; | 743 | return ''; |
| 720 | } | 744 | } |
| 745 | const oldProfile = structuredClone(profile); | ||
| 721 | await updateConnectionProfile(profile); | 746 | await updateConnectionProfile(profile); |
| 722 | await renderDetailsContent(detailsContent); | 747 | await renderDetailsContent(detailsContent); |
| 723 | saveSettingsDebounced(); | 748 | saveSettingsDebounced(); |
| 749 | await eventSource.emit(event_types.CONNECTION_PROFILE_UPDATED, oldProfile, profile); | ||
| 724 | return profile.name; | 750 | return profile.name; |
| 725 | }, | 751 | }, |
| 726 | })); | 752 | })); |
| @@ -4,7 +4,7 @@ import { characters, eventSource, event_types, generateRaw, getRequestHeaders, m | |||
| 4 | import { dragElement, isMobile } from '../../RossAscends-mods.js'; | 4 | import { dragElement, isMobile } from '../../RossAscends-mods.js'; |
| 5 | import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; | 5 | import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 6 | import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js'; | 6 | import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js'; |
| 7 | import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar } from '../../utils.js'; | 7 | import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar, isFalseBoolean } from '../../utils.js'; |
| 8 | import { hideMutedSprites, selected_group } from '../../group-chats.js'; | 8 | import { hideMutedSprites, selected_group } from '../../group-chats.js'; |
| 9 | import { isJsonSchemaSupported } from '../../textgen-settings.js'; | 9 | import { isJsonSchemaSupported } from '../../textgen-settings.js'; |
| 10 | import { debounce_timeout } from '../../constants.js'; | 10 | import { debounce_timeout } from '../../constants.js'; |
| @@ -17,6 +17,7 @@ import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandRetur | |||
| 17 | import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js'; | 17 | import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js'; |
| 18 | import { Popup, POPUP_RESULT } from '../../popup.js'; | 18 | import { Popup, POPUP_RESULT } from '../../popup.js'; |
| 19 | import { t } from '../../i18n.js'; | 19 | import { t } from '../../i18n.js'; |
| 20 | import { removeReasoningFromString } from '../../reasoning.js'; | ||
| 20 | export { MODULE_NAME }; | 21 | export { MODULE_NAME }; |
| 21 | 22 | ||
| 22 | /** | 23 | /** |
| @@ -678,7 +679,7 @@ async function setSpriteFolderCommand(_, folder) { | |||
| 678 | return ''; | 679 | return ''; |
| 679 | } | 680 | } |
| 680 | 681 | ||
| 681 | async function classifyCallback(/** @type {{api: string?, prompt: string?}} */ { api = null, prompt = null }, text) { | 682 | async function classifyCallback(/** @type {{api: string?, filter: string?, prompt: string?}} */ { api = null, filter = null, prompt = null }, text) { |
| 682 | if (!text) { | 683 | if (!text) { |
| 683 | toastr.error('No text provided'); | 684 | toastr.error('No text provided'); |
| 684 | return ''; | 685 | return ''; |
| @@ -689,13 +690,14 @@ async function classifyCallback(/** @type {{api: string?, prompt: string?}} */ { | |||
| 689 | } | 690 | } |
| 690 | 691 | ||
| 691 | const expressionApi = EXPRESSION_API[api] || extension_settings.expressions.api; | 692 | const expressionApi = EXPRESSION_API[api] || extension_settings.expressions.api; |
| 693 | const filterAvailable = !isFalseBoolean(filter); | ||
| 692 | 694 | ||
| 693 | if (!modules.includes('classify') && expressionApi == EXPRESSION_API.extras) { | 695 | if (!modules.includes('classify') && expressionApi == EXPRESSION_API.extras) { |
| 694 | toastr.warning('Text classification is disabled or not available'); | 696 | toastr.warning('Text classification is disabled or not available'); |
| 695 | return ''; | 697 | return ''; |
| 696 | } | 698 | } |
| 697 | 699 | ||
| 698 | const label = await getExpressionLabel(text, expressionApi, { customPrompt: prompt }); | 700 | const label = await getExpressionLabel(text, expressionApi, { filterAvailable: filterAvailable, customPrompt: prompt }); |
| 699 | console.debug(`Classification result for "${text}": ${label}`); | 701 | console.debug(`Classification result for "${text}": ${label}`); |
| 700 | return label; | 702 | return label; |
| 701 | } | 703 | } |
| @@ -928,6 +930,9 @@ function parseLlmResponse(emotionResponse, labels) { | |||
| 928 | 930 | ||
| 929 | return response; | 931 | return response; |
| 930 | } catch { | 932 | } catch { |
| 933 | // Clean possible reasoning from response | ||
| 934 | emotionResponse = removeReasoningFromString(emotionResponse); | ||
| 935 | |||
| 931 | const fuse = new Fuse(labels, { includeScore: true }); | 936 | const fuse = new Fuse(labels, { includeScore: true }); |
| 932 | console.debug('Using fuzzy search in labels:', labels); | 937 | console.debug('Using fuzzy search in labels:', labels); |
| 933 | const result = fuse.search(emotionResponse); | 938 | const result = fuse.search(emotionResponse); |
| @@ -988,10 +993,11 @@ function onTextGenSettingsReady(args) { | |||
| 988 | * @param {string} text - The text to classify and retrieve the expression label for. | 993 | * @param {string} text - The text to classify and retrieve the expression label for. |
| 989 | * @param {EXPRESSION_API} [expressionsApi=extension_settings.expressions.api] - The expressions API to use for classification. | 994 | * @param {EXPRESSION_API} [expressionsApi=extension_settings.expressions.api] - The expressions API to use for classification. |
| 990 | * @param {object} [options={}] - Optional arguments. | 995 | * @param {object} [options={}] - Optional arguments. |
| 996 | * @param {boolean?} [options.filterAvailable=null] - Whether to filter available expressions. If not specified, uses the extension setting. | ||
| 991 | * @param {string?} [options.customPrompt=null] - The custom prompt to use for classification. | 997 | * @param {string?} [options.customPrompt=null] - The custom prompt to use for classification. |
| 992 | * @returns {Promise<string?>} - The label of the expression. | 998 | * @returns {Promise<string?>} - The label of the expression. |
| 993 | */ | 999 | */ |
| 994 | export async function getExpressionLabel(text, expressionsApi = extension_settings.expressions.api, { customPrompt = null } = {}) { | 1000 | export async function getExpressionLabel(text, expressionsApi = extension_settings.expressions.api, { filterAvailable = null, customPrompt = null } = {}) { |
| 995 | // Return if text is undefined, saving a costly fetch request | 1001 | // Return if text is undefined, saving a costly fetch request |
| 996 | if ((!modules.includes('classify') && expressionsApi == EXPRESSION_API.extras) || !text) { | 1002 | if ((!modules.includes('classify') && expressionsApi == EXPRESSION_API.extras) || !text) { |
| 997 | return extension_settings.expressions.fallback_expression; | 1003 | return extension_settings.expressions.fallback_expression; |
| @@ -1003,6 +1009,11 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | |||
| 1003 | 1009 | ||
| 1004 | text = sampleClassifyText(text); | 1010 | text = sampleClassifyText(text); |
| 1005 | 1011 | ||
| 1012 | filterAvailable ??= extension_settings.expressions.filterAvailable; | ||
| 1013 | if (filterAvailable && ![EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(expressionsApi)) { | ||
| 1014 | console.debug('Filter available is only supported for LLM and WebLLM expressions'); | ||
| 1015 | } | ||
| 1016 | |||
| 1006 | try { | 1017 | try { |
| 1007 | switch (expressionsApi) { | 1018 | switch (expressionsApi) { |
| 1008 | // Local BERT pipeline | 1019 | // Local BERT pipeline |
| @@ -1027,7 +1038,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | |||
| 1027 | return extension_settings.expressions.fallback_expression; | 1038 | return extension_settings.expressions.fallback_expression; |
| 1028 | } | 1039 | } |
| 1029 | 1040 | ||
| 1030 | const expressionsList = await getExpressionsList(); | 1041 | const expressionsList = await getExpressionsList({ filterAvailable: filterAvailable }); |
| 1031 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); | 1042 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); |
| 1032 | eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); | 1043 | eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); |
| 1033 | const emotionResponse = await generateRaw(text, main_api, false, false, prompt); | 1044 | const emotionResponse = await generateRaw(text, main_api, false, false, prompt); |
| @@ -1040,7 +1051,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | |||
| 1040 | return extension_settings.expressions.fallback_expression; | 1051 | return extension_settings.expressions.fallback_expression; |
| 1041 | } | 1052 | } |
| 1042 | 1053 | ||
| 1043 | const expressionsList = await getExpressionsList(); | 1054 | const expressionsList = await getExpressionsList({ filterAvailable: filterAvailable }); |
| 1044 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); | 1055 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); |
| 1045 | const messages = [ | 1056 | const messages = [ |
| 1046 | { role: 'user', content: text + '\n\n' + prompt }, | 1057 | { role: 'user', content: text + '\n\n' + prompt }, |
| @@ -1320,12 +1331,28 @@ function getCachedExpressions() { | |||
| 1320 | return [...expressionsList, ...extension_settings.expressions.custom].filter(onlyUnique); | 1331 | return [...expressionsList, ...extension_settings.expressions.custom].filter(onlyUnique); |
| 1321 | } | 1332 | } |
| 1322 | 1333 | ||
| 1323 | export async function getExpressionsList() { | 1334 | export async function getExpressionsList({ filterAvailable = false } = {}) { |
| 1324 | // Return cached list if available | 1335 | // If there is no cached list, load and cache it |
| 1325 | if (Array.isArray(expressionsList)) { | 1336 | if (!Array.isArray(expressionsList)) { |
| 1326 | return getCachedExpressions(); | 1337 | expressionsList = await resolveExpressionsList(); |
| 1327 | } | 1338 | } |
| 1328 | 1339 | ||
| 1340 | const expressions = getCachedExpressions(); | ||
| 1341 | |||
| 1342 | // Filtering is only available for llm and webllm APIs | ||
| 1343 | if (!filterAvailable || ![EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api)) { | ||
| 1344 | return expressions; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | // Get expressions with available sprites | ||
| 1348 | const currentLastMessage = selected_group ? getLastCharacterMessage() : null; | ||
| 1349 | const spriteFolderName = getSpriteFolderName(currentLastMessage, currentLastMessage?.name); | ||
| 1350 | |||
| 1351 | return expressions.filter(label => { | ||
| 1352 | const expression = spriteCache[spriteFolderName]?.find(x => x.label === label); | ||
| 1353 | return (expression?.files.length ?? 0) > 0; | ||
| 1354 | }); | ||
| 1355 | |||
| 1329 | /** | 1356 | /** |
| 1330 | * Returns the list of expressions from the API or fallback in offline mode. | 1357 | * Returns the list of expressions from the API or fallback in offline mode. |
| 1331 | * @returns {Promise<string[]>} | 1358 | * @returns {Promise<string[]>} |
| @@ -1372,9 +1399,6 @@ export async function getExpressionsList() { | |||
| 1372 | expressionsList = DEFAULT_EXPRESSIONS.slice(); | 1399 | expressionsList = DEFAULT_EXPRESSIONS.slice(); |
| 1373 | return expressionsList; | 1400 | return expressionsList; |
| 1374 | } | 1401 | } |
| 1375 | |||
| 1376 | const result = await resolveExpressionsList(); | ||
| 1377 | return [...result, ...extension_settings.expressions.custom].filter(onlyUnique); | ||
| 1378 | } | 1402 | } |
| 1379 | 1403 | ||
| 1380 | /** | 1404 | /** |
| @@ -1810,7 +1834,7 @@ async function onClickExpressionUpload(event) { | |||
| 1810 | } | 1834 | } |
| 1811 | } | 1835 | } |
| 1812 | } else { | 1836 | } else { |
| 1813 | spriteName = withoutExtension(clickedFileName); | 1837 | spriteName = withoutExtension(expression); |
| 1814 | } | 1838 | } |
| 1815 | 1839 | ||
| 1816 | if (!spriteName) { | 1840 | if (!spriteName) { |
| @@ -2102,6 +2126,10 @@ function migrateSettings() { | |||
| 2102 | extension_settings.expressions.rerollIfSame = !!$(this).prop('checked'); | 2126 | extension_settings.expressions.rerollIfSame = !!$(this).prop('checked'); |
| 2103 | saveSettingsDebounced(); | 2127 | saveSettingsDebounced(); |
| 2104 | }); | 2128 | }); |
| 2129 | $('#expressions_filter_available').prop('checked', extension_settings.expressions.filterAvailable).on('input', function () { | ||
| 2130 | extension_settings.expressions.filterAvailable = !!$(this).prop('checked'); | ||
| 2131 | saveSettingsDebounced(); | ||
| 2132 | }); | ||
| 2105 | $('#expression_override_cleanup_button').on('click', onClickExpressionOverrideRemoveAllButton); | 2133 | $('#expression_override_cleanup_button').on('click', onClickExpressionOverrideRemoveAllButton); |
| 2106 | $(document).on('dragstart', '.expression', (e) => { | 2134 | $(document).on('dragstart', '.expression', (e) => { |
| 2107 | e.preventDefault(); | 2135 | e.preventDefault(); |
| @@ -2154,7 +2182,7 @@ function migrateSettings() { | |||
| 2154 | imgElement.src = ''; | 2182 | imgElement.src = ''; |
| 2155 | } | 2183 | } |
| 2156 | 2184 | ||
| 2157 | setExpressionOverrideHtml(); | 2185 | setExpressionOverrideHtml(true); // force-clear, as the character might not have an override defined |
| 2158 | 2186 | ||
| 2159 | if (isVisualNovelMode()) { | 2187 | if (isVisualNovelMode()) { |
| 2160 | $('#visual-novel-wrapper').empty(); | 2188 | $('#visual-novel-wrapper').empty(); |
| @@ -2279,13 +2307,13 @@ function migrateSettings() { | |||
| 2279 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 2307 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2280 | name: 'expression-list', | 2308 | name: 'expression-list', |
| 2281 | aliases: ['expressions'], | 2309 | aliases: ['expressions'], |
| 2282 | /** @type {(args: {return: string}) => Promise<string>} */ | 2310 | /** @type {(args: {return: string, filter: string}) => Promise<string>} */ |
| 2283 | callback: async (args) => { | 2311 | callback: async (args) => { |
| 2284 | let returnType = | 2312 | let returnType = |
| 2285 | /** @type {import('../../slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */ | 2313 | /** @type {import('../../slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */ |
| 2286 | (args.return); | 2314 | (args.return); |
| 2287 | 2315 | ||
| 2288 | const list = await getExpressionsList(); | 2316 | const list = await getExpressionsList({ filterAvailable: !isFalseBoolean(args.filter) }); |
| 2289 | 2317 | ||
| 2290 | return await slashCommandReturnHelper.doReturn(returnType ?? 'pipe', list, { objectToStringFunc: list => list.join(', ') }); | 2318 | return await slashCommandReturnHelper.doReturn(returnType ?? 'pipe', list, { objectToStringFunc: list => list.join(', ') }); |
| 2291 | }, | 2319 | }, |
| @@ -2298,6 +2326,13 @@ function migrateSettings() { | |||
| 2298 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), | 2326 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| 2299 | forceEnum: true, | 2327 | forceEnum: true, |
| 2300 | }), | 2328 | }), |
| 2329 | SlashCommandNamedArgument.fromProps({ | ||
| 2330 | name: 'filter', | ||
| 2331 | description: 'Filter the list to only include expressions that have available sprites for the current character.', | ||
| 2332 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 2333 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 2334 | defaultValue: 'true', | ||
| 2335 | }), | ||
| 2301 | ], | 2336 | ], |
| 2302 | returns: 'The comma-separated list of available expressions, including custom expressions.', | 2337 | returns: 'The comma-separated list of available expressions, including custom expressions.', |
| 2303 | helpString: 'Returns a list of available expressions, including custom expressions.', | 2338 | helpString: 'Returns a list of available expressions, including custom expressions.', |
| @@ -2314,6 +2349,13 @@ function migrateSettings() { | |||
| 2314 | enumList: Object.keys(EXPRESSION_API).map(api => new SlashCommandEnumValue(api, null, enumTypes.enum)), | 2349 | enumList: Object.keys(EXPRESSION_API).map(api => new SlashCommandEnumValue(api, null, enumTypes.enum)), |
| 2315 | }), | 2350 | }), |
| 2316 | SlashCommandNamedArgument.fromProps({ | 2351 | SlashCommandNamedArgument.fromProps({ |
| 2352 | name: 'filter', | ||
| 2353 | description: 'Filter the list to only include expressions that have available sprites for the current character.', | ||
| 2354 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 2355 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 2356 | defaultValue: 'true', | ||
| 2357 | }), | ||
| 2358 | SlashCommandNamedArgument.fromProps({ | ||
| 2317 | name: 'prompt', | 2359 | name: 'prompt', |
| 2318 | description: 'Custom prompt for classification. Only relevant if Classifier API is set to LLM.', | 2360 | description: 'Custom prompt for classification. Only relevant if Classifier API is set to LLM.', |
| 2319 | typeList: [ARGUMENT_TYPE.STRING], | 2361 | typeList: [ARGUMENT_TYPE.STRING], |
| @@ -29,7 +29,11 @@ | |||
| 29 | </select> | 29 | </select> |
| 30 | </div> | 30 | </div> |
| 31 | <div class="expression_llm_prompt_block m-b-1 m-t-1"> | 31 | <div class="expression_llm_prompt_block m-b-1 m-t-1"> |
| 32 | <label for="expression_llm_prompt" class="title_restorable"> | 32 | <label class="checkbox_label" for="expressions_filter_available" title="When using LLM or WebLLM classifier, only show and use expressions that have sprites assigned to them." data-i18n="[title]When using LLM or WebLLM classifier, only show and use expressions that have sprites assigned to them."> |
| 33 | <input id="expressions_filter_available" type="checkbox"> | ||
| 34 | <span data-i18n="Filter expressions for available sprites">Filter expressions for available sprites</span> | ||
| 35 | </label> | ||
| 36 | <label for="expression_llm_prompt" class="title_restorable m-t-1"> | ||
| 33 | <span data-i18n="LLM Prompt">LLM Prompt</span> | 37 | <span data-i18n="LLM Prompt">LLM Prompt</span> |
| 34 | <div id="expression_llm_prompt_restore" title="Restore default value" class="right_menu_button"> | 38 | <div id="expression_llm_prompt_restore" title="Restore default value" class="right_menu_button"> |
| 35 | <i class="fa-solid fa-clock-rotate-left fa-sm"></i> | 39 | <i class="fa-solid fa-clock-rotate-left fa-sm"></i> |
| @@ -1,10 +1,7 @@ | |||
| 1 | // eslint-disable-next-line no-unused-vars | ||
| 2 | import { QuickReply } from '../src/QuickReply.js'; | 1 | import { QuickReply } from '../src/QuickReply.js'; |
| 3 | import { QuickReplyContextLink } from '../src/QuickReplyContextLink.js'; | 2 | import { QuickReplyContextLink } from '../src/QuickReplyContextLink.js'; |
| 4 | import { QuickReplySet } from '../src/QuickReplySet.js'; | 3 | import { QuickReplySet } from '../src/QuickReplySet.js'; |
| 5 | // eslint-disable-next-line no-unused-vars | ||
| 6 | import { QuickReplySettings } from '../src/QuickReplySettings.js'; | 4 | import { QuickReplySettings } from '../src/QuickReplySettings.js'; |
| 7 | // eslint-disable-next-line no-unused-vars | ||
| 8 | import { SettingsUi } from '../src/ui/SettingsUi.js'; | 5 | import { SettingsUi } from '../src/ui/SettingsUi.js'; |
| 9 | import { onlyUnique } from '../../../utils.js'; | 6 | import { onlyUnique } from '../../../utils.js'; |
| 10 | 7 | ||
| @@ -1,7 +1,5 @@ | |||
| 1 | import { warn } from '../index.js'; | 1 | import { warn } from '../index.js'; |
| 2 | // eslint-disable-next-line no-unused-vars | ||
| 3 | import { QuickReply } from './QuickReply.js'; | 2 | import { QuickReply } from './QuickReply.js'; |
| 4 | // eslint-disable-next-line no-unused-vars | ||
| 5 | import { QuickReplySettings } from './QuickReplySettings.js'; | 3 | import { QuickReplySettings } from './QuickReplySettings.js'; |
| 6 | 4 | ||
| 7 | export class AutoExecuteHandler { | 5 | export class AutoExecuteHandler { |
| @@ -635,7 +635,6 @@ export class QuickReply { | |||
| 635 | }, { passive:true }); | 635 | }, { passive:true }); |
| 636 | const getLineStart = ()=>{ | 636 | const getLineStart = ()=>{ |
| 637 | const start = message.selectionStart; | 637 | const start = message.selectionStart; |
| 638 | const end = message.selectionEnd; | ||
| 639 | let lineStart; | 638 | let lineStart; |
| 640 | if (start == 0 || message.value[start - 1] == '\n') { | 639 | if (start == 0 || message.value[start - 1] == '\n') { |
| 641 | // cursor is already at beginning of line | 640 | // cursor is already at beginning of line |
| @@ -701,7 +700,6 @@ export class QuickReply { | |||
| 701 | } else if (evt.key == 'Enter' && !evt.ctrlKey && !evt.shiftKey && !evt.altKey && !(ac.isReplaceable && ac.isActive)) { | 700 | } else if (evt.key == 'Enter' && !evt.ctrlKey && !evt.shiftKey && !evt.altKey && !(ac.isReplaceable && ac.isActive)) { |
| 702 | // new line, keep indent | 701 | // new line, keep indent |
| 703 | const start = message.selectionStart; | 702 | const start = message.selectionStart; |
| 704 | const end = message.selectionEnd; | ||
| 705 | let lineStart = getLineStart(); | 703 | let lineStart = getLineStart(); |
| 706 | const indent = /^([^\S\n]*)/.exec(message.value.slice(lineStart))[1] ?? ''; | 704 | const indent = /^([^\S\n]*)/.exec(message.value.slice(lineStart))[1] ?? ''; |
| 707 | if (indent.length) { | 705 | if (indent.length) { |
| @@ -8,7 +8,6 @@ import { SlashCommandEnumValue, enumTypes } from '../../../slash-commands/SlashC | |||
| 8 | import { SlashCommandParser } from '../../../slash-commands/SlashCommandParser.js'; | 8 | import { SlashCommandParser } from '../../../slash-commands/SlashCommandParser.js'; |
| 9 | import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js'; | 9 | import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js'; |
| 10 | import { isTrueBoolean } from '../../../utils.js'; | 10 | import { isTrueBoolean } from '../../../utils.js'; |
| 11 | // eslint-disable-next-line no-unused-vars | ||
| 12 | import { QuickReplyApi } from '../api/QuickReplyApi.js'; | 11 | import { QuickReplyApi } from '../api/QuickReplyApi.js'; |
| 13 | import { QuickReply } from './QuickReply.js'; | 12 | import { QuickReply } from './QuickReply.js'; |
| 14 | import { QuickReplySet } from './QuickReplySet.js'; | 13 | import { QuickReplySet } from './QuickReplySet.js'; |
| @@ -1,7 +1,6 @@ | |||
| 1 | import { animation_duration } from '../../../../../script.js'; | 1 | import { animation_duration } from '../../../../../script.js'; |
| 2 | import { dragElement } from '../../../../RossAscends-mods.js'; | 2 | import { dragElement } from '../../../../RossAscends-mods.js'; |
| 3 | import { loadMovingUIState } from '../../../../power-user.js'; | 3 | import { loadMovingUIState } from '../../../../power-user.js'; |
| 4 | // eslint-disable-next-line no-unused-vars | ||
| 5 | import { QuickReplySettings } from '../QuickReplySettings.js'; | 4 | import { QuickReplySettings } from '../QuickReplySettings.js'; |
| 6 | 5 | ||
| 7 | export class ButtonUi { | 6 | export class ButtonUi { |
| @@ -3,7 +3,6 @@ import { getSortableDelay } from '../../../../utils.js'; | |||
| 3 | import { log, warn } from '../../index.js'; | 3 | import { log, warn } from '../../index.js'; |
| 4 | import { QuickReply } from '../QuickReply.js'; | 4 | import { QuickReply } from '../QuickReply.js'; |
| 5 | import { QuickReplySet } from '../QuickReplySet.js'; | 5 | import { QuickReplySet } from '../QuickReplySet.js'; |
| 6 | // eslint-disable-next-line no-unused-vars | ||
| 7 | import { QuickReplySettings } from '../QuickReplySettings.js'; | 6 | import { QuickReplySettings } from '../QuickReplySettings.js'; |
| 8 | 7 | ||
| 9 | export class SettingsUi { | 8 | export class SettingsUi { |
| @@ -1,5 +1,4 @@ | |||
| 1 | import { QuickReply } from '../../QuickReply.js'; | 1 | import { QuickReply } from '../../QuickReply.js'; |
| 2 | // eslint-disable-next-line no-unused-vars | ||
| 3 | import { QuickReplySet } from '../../QuickReplySet.js'; | 2 | import { QuickReplySet } from '../../QuickReplySet.js'; |
| 4 | import { MenuHeader } from './MenuHeader.js'; | 3 | import { MenuHeader } from './MenuHeader.js'; |
| 5 | import { MenuItem } from './MenuItem.js'; | 4 | import { MenuItem } from './MenuItem.js'; |
| @@ -18,9 +18,8 @@ | |||
| 18 | 18 | ||
| 19 | <div id="regex_info_block_wrapper"> | 19 | <div id="regex_info_block_wrapper"> |
| 20 | <div id="regex_info_block" class="info-block"></div> | 20 | <div id="regex_info_block" class="info-block"></div> |
| 21 | <!-- TODO replace 3rd-party link with our own docs when it's done --> | 21 | <a id="regex_info_block_flags_hint" href="https://docs.sillytavern.app/extensions/regex/#flags" target="_blank" rel="noopener noreferrer"> |
| 22 | <a id="regex_info_block_flags_hint" href="http://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#advanced_searching_with_flags" target="_blank" rel="noopener noreferrer"> | 22 | <i class="fa-solid fa-circle-info" data-i18n="[title]ext_regex_flags_help" title="Click here to learn more about regex flags."></i> |
| 23 | <i class="fa-solid fa-circle-info" title="Click here to learn more about regex flags."></i> | ||
| 24 | </a> | 23 | </a> |
| 25 | </div> | 24 | </div> |
| 26 | 25 | ||
| @@ -148,7 +147,7 @@ | |||
| 148 | </label> | 147 | </label> |
| 149 | <span> | 148 | <span> |
| 150 | <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small> | 149 | <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small> |
| 151 | <span class="fa-solid fa-circle-question note-link-span" title="By default, regex scripts alter the chat file directly and irreversibly. Enabling either (or both) of the options below will prevent chat file alteration, while still altering the specified item(s)."></span> | 150 | <span class="fa-solid fa-circle-question note-link-span" data-i18n="[title]ext_regex_other_options_desc" title="By default, regex scripts alter the chat file directly and irreversibly. Enabling either (or both) of the options below will prevent chat file alteration, while still altering the specified item(s)."></span> |
| 152 | </span> | 151 | </span> |
| 153 | <label class="checkbox flex-container" data-i18n="[title]ext_regex_only_format_visual_desc" title="Chat history file contents won't change, but regex will be applied to the messages displayed in the Chat UI."> | 152 | <label class="checkbox flex-container" data-i18n="[title]ext_regex_only_format_visual_desc" title="Chat history file contents won't change, but regex will be applied to the messages displayed in the Chat UI."> |
| 154 | <input type="checkbox" name="only_format_display" /> | 153 | <input type="checkbox" name="only_format_display" /> |
| @@ -398,7 +398,7 @@ function runRegexCallback(args, value) { | |||
| 398 | for (const script of scripts) { | 398 | for (const script of scripts) { |
| 399 | if (script.scriptName.toLowerCase() === scriptName.toLowerCase()) { | 399 | if (script.scriptName.toLowerCase() === scriptName.toLowerCase()) { |
| 400 | if (script.disabled) { | 400 | if (script.disabled) { |
| 401 | toastr.warning(`Regex script "${scriptName}" is disabled.`); | 401 | toastr.warning(t`Regex script "${scriptName}" is disabled.`); |
| 402 | return value; | 402 | return value; |
| 403 | } | 403 | } |
| 404 | 404 | ||
| @@ -1,5 +1,6 @@ | |||
| 1 | import { getRequestHeaders } from '../../script.js'; | 1 | import { CONNECT_API_MAP, getRequestHeaders } from '../../script.js'; |
| 2 | import { extension_settings, openThirdPartyExtensionMenu } from '../extensions.js'; | 2 | import { extension_settings, openThirdPartyExtensionMenu } from '../extensions.js'; |
| 3 | import { t } from '../i18n.js'; | ||
| 3 | import { oai_settings } from '../openai.js'; | 4 | import { oai_settings } from '../openai.js'; |
| 4 | import { SECRET_KEYS, secret_state } from '../secrets.js'; | 5 | import { SECRET_KEYS, secret_state } from '../secrets.js'; |
| 5 | import { textgen_types, textgenerationwebui_settings } from '../textgen-settings.js'; | 6 | import { textgen_types, textgenerationwebui_settings } from '../textgen-settings.js'; |
| @@ -273,3 +274,310 @@ export async function getWebLlmContextSize() { | |||
| 273 | const model = await engine.getCurrentModelInfo(); | 274 | const model = await engine.getCurrentModelInfo(); |
| 274 | return model?.context_size; | 275 | return model?.context_size; |
| 275 | } | 276 | } |
| 277 | |||
| 278 | /** | ||
| 279 | * It uses the profiles to send a generate request to the API. Doesn't support streaming. | ||
| 280 | */ | ||
| 281 | export class ConnectionManagerRequestService { | ||
| 282 | static defaultSendRequestParams = { | ||
| 283 | extractData: true, | ||
| 284 | includePreset: true, | ||
| 285 | includeInstruct: true, | ||
| 286 | }; | ||
| 287 | |||
| 288 | static getAllowedTypes() { | ||
| 289 | return { | ||
| 290 | openai: t`Chat Completion`, | ||
| 291 | textgenerationwebui: t`Text Completion`, | ||
| 292 | }; | ||
| 293 | } | ||
| 294 | |||
| 295 | /** | ||
| 296 | * @param {string} profileId | ||
| 297 | * @param {string | (import('../custom-request.js').ChatCompletionMessage & {ignoreInstruct?: boolean})[]} prompt | ||
| 298 | * @param {number} maxTokens | ||
| 299 | * @param {{extractData?: boolean, includePreset?: boolean, includeInstruct?: boolean}} custom - default values are true | ||
| 300 | * @returns {Promise<import('../custom-request.js').ExtractedData | any>} Extracted data or the raw response | ||
| 301 | */ | ||
| 302 | static async sendRequest(profileId, prompt, maxTokens, custom = this.defaultSendRequestParams) { | ||
| 303 | const { extractData, includePreset, includeInstruct } = { ...this.defaultSendRequestParams, ...custom }; | ||
| 304 | |||
| 305 | const context = SillyTavern.getContext(); | ||
| 306 | if (context.extensionSettings.disabledExtensions.includes('connection-manager')) { | ||
| 307 | throw new Error('Connection Manager is not available'); | ||
| 308 | } | ||
| 309 | |||
| 310 | const profile = context.extensionSettings.connectionManager.profiles.find((p) => p.id === profileId); | ||
| 311 | const selectedApiMap = this.validateProfile(profile); | ||
| 312 | |||
| 313 | try { | ||
| 314 | switch (selectedApiMap.selected) { | ||
| 315 | case 'openai': { | ||
| 316 | if (!selectedApiMap.source) { | ||
| 317 | throw new Error(`API type ${selectedApiMap.selected} does not support chat completions`); | ||
| 318 | } | ||
| 319 | |||
| 320 | const messages = Array.isArray(prompt) ? prompt : [{ role: 'user', content: prompt }]; | ||
| 321 | return await context.ChatCompletionService.processRequest({ | ||
| 322 | messages, | ||
| 323 | max_tokens: maxTokens, | ||
| 324 | model: profile.model, | ||
| 325 | chat_completion_source: selectedApiMap.source, | ||
| 326 | custom_url: profile['api-url'], | ||
| 327 | }, { | ||
| 328 | presetName: includePreset ? profile.preset : undefined, | ||
| 329 | }, extractData); | ||
| 330 | } | ||
| 331 | case 'textgenerationwebui': { | ||
| 332 | if (!selectedApiMap.type) { | ||
| 333 | throw new Error(`API type ${selectedApiMap.selected} does not support text completions`); | ||
| 334 | } | ||
| 335 | |||
| 336 | return await context.TextCompletionService.processRequest({ | ||
| 337 | prompt, | ||
| 338 | max_tokens: maxTokens, | ||
| 339 | model: profile.model, | ||
| 340 | api_type: selectedApiMap.type, | ||
| 341 | api_server: profile['api-url'], | ||
| 342 | }, { | ||
| 343 | instructName: includeInstruct ? profile.instruct : undefined, | ||
| 344 | presetName: includePreset ? profile.preset : undefined, | ||
| 345 | }, extractData); | ||
| 346 | } | ||
| 347 | default: { | ||
| 348 | throw new Error(`Unknown API type ${selectedApiMap.selected}`); | ||
| 349 | } | ||
| 350 | } | ||
| 351 | } catch (error) { | ||
| 352 | throw new Error('API request failed', { cause: error }); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | /** | ||
| 357 | * Respects allowed types. | ||
| 358 | * @returns {import('./connection-manager/index.js').ConnectionProfile[]} | ||
| 359 | */ | ||
| 360 | static getSupportedProfiles() { | ||
| 361 | const context = SillyTavern.getContext(); | ||
| 362 | if (context.extensionSettings.disabledExtensions.includes('connection-manager')) { | ||
| 363 | throw new Error('Connection Manager is not available'); | ||
| 364 | } | ||
| 365 | |||
| 366 | const profiles = context.extensionSettings.connectionManager.profiles; | ||
| 367 | return profiles.filter((p) => this.isProfileSupported(p)); | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * @param {import('./connection-manager/index.js').ConnectionProfile?} [profile] | ||
| 372 | * @returns {boolean} | ||
| 373 | */ | ||
| 374 | static isProfileSupported(profile) { | ||
| 375 | if (!profile) { | ||
| 376 | return false; | ||
| 377 | } | ||
| 378 | |||
| 379 | const apiMap = CONNECT_API_MAP[profile.api]; | ||
| 380 | if (!Object.hasOwn(this.getAllowedTypes(), apiMap.selected)) { | ||
| 381 | return false; | ||
| 382 | } | ||
| 383 | |||
| 384 | // Some providers not need model, like koboldcpp. But I don't want to check by provider. | ||
| 385 | switch (apiMap.selected) { | ||
| 386 | case 'openai': | ||
| 387 | return !!apiMap.source; | ||
| 388 | case 'textgenerationwebui': | ||
| 389 | return !!apiMap.type; | ||
| 390 | } | ||
| 391 | |||
| 392 | return false; | ||
| 393 | } | ||
| 394 | |||
| 395 | /** | ||
| 396 | * @param {import('./connection-manager/index.js').ConnectionProfile?} [profile] | ||
| 397 | * @return {import('../../script.js').ConnectAPIMap} | ||
| 398 | * @throws {Error} | ||
| 399 | */ | ||
| 400 | static validateProfile(profile) { | ||
| 401 | if (!profile) { | ||
| 402 | throw new Error('Could not find profile.'); | ||
| 403 | } | ||
| 404 | if (!profile.api) { | ||
| 405 | throw new Error('Select a connection profile that has an API'); | ||
| 406 | } | ||
| 407 | |||
| 408 | const context = SillyTavern.getContext(); | ||
| 409 | const selectedApiMap = context.CONNECT_API_MAP[profile.api]; | ||
| 410 | if (!selectedApiMap) { | ||
| 411 | throw new Error(`Unknown API type ${profile.api}`); | ||
| 412 | } | ||
| 413 | if (!Object.hasOwn(this.getAllowedTypes(), selectedApiMap.selected)) { | ||
| 414 | throw new Error(`API type ${selectedApiMap.selected} is not supported. Supported types: ${Object.values(this.getAllowedTypes()).join(', ')}`); | ||
| 415 | } | ||
| 416 | |||
| 417 | return selectedApiMap; | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 421 | * Create profiles dropdown and updates select element accordingly. Use onChange, onCreate, unUpdate, onDelete callbacks for custom behaviour. e.g updating extension settings. | ||
| 422 | * @param {string} selector | ||
| 423 | * @param {string} initialSelectedProfileId | ||
| 424 | * @param {(profile?: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} onChange - 3 cases. 1- When user selects new profile. 2- When user deletes selected profile. 3- When user updates selected profile. | ||
| 425 | * @param {(profile: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} onCreate | ||
| 426 | * @param {(oldProfile: import('./connection-manager/index.js').ConnectionProfile, newProfile: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} unUpdate | ||
| 427 | * @param {(profile: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} onDelete | ||
| 428 | */ | ||
| 429 | static handleDropdown( | ||
| 430 | selector, | ||
| 431 | initialSelectedProfileId, | ||
| 432 | onChange = () => { }, | ||
| 433 | onCreate = () => { }, | ||
| 434 | unUpdate = () => { }, | ||
| 435 | onDelete = () => { }, | ||
| 436 | ) { | ||
| 437 | const context = SillyTavern.getContext(); | ||
| 438 | if (context.extensionSettings.disabledExtensions.includes('connection-manager')) { | ||
| 439 | throw new Error('Connection Manager is not available'); | ||
| 440 | } | ||
| 441 | |||
| 442 | /** | ||
| 443 | * @type {JQuery<HTMLSelectElement>} | ||
| 444 | */ | ||
| 445 | const dropdown = $(selector); | ||
| 446 | |||
| 447 | if (!dropdown || !dropdown.length) { | ||
| 448 | throw new Error(`Could not find dropdown with selector ${selector}`); | ||
| 449 | } | ||
| 450 | |||
| 451 | dropdown.empty(); | ||
| 452 | |||
| 453 | // Create default option using document.createElement | ||
| 454 | const defaultOption = document.createElement('option'); | ||
| 455 | defaultOption.value = ''; | ||
| 456 | defaultOption.textContent = 'Select a Connection Profile'; | ||
| 457 | defaultOption.dataset.i18n = 'Select a Connection Profile'; | ||
| 458 | dropdown.append(defaultOption); | ||
| 459 | |||
| 460 | const profiles = context.extensionSettings.connectionManager.profiles; | ||
| 461 | |||
| 462 | // Create optgroups using document.createElement | ||
| 463 | const groups = {}; | ||
| 464 | for (const [apiType, groupLabel] of Object.entries(this.getAllowedTypes())) { | ||
| 465 | const optgroup = document.createElement('optgroup'); | ||
| 466 | optgroup.label = groupLabel; | ||
| 467 | groups[apiType] = optgroup; | ||
| 468 | } | ||
| 469 | |||
| 470 | const sortedProfilesByGroup = {}; | ||
| 471 | for (const apiType of Object.keys(this.getAllowedTypes())) { | ||
| 472 | sortedProfilesByGroup[apiType] = []; | ||
| 473 | } | ||
| 474 | |||
| 475 | for (const profile of profiles) { | ||
| 476 | if (this.isProfileSupported(profile)) { | ||
| 477 | const apiMap = CONNECT_API_MAP[profile.api]; | ||
| 478 | if (sortedProfilesByGroup[apiMap.selected]) { | ||
| 479 | sortedProfilesByGroup[apiMap.selected].push(profile); | ||
| 480 | } | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | // Sort each group alphabetically and add to dropdown | ||
| 485 | for (const [apiType, groupProfiles] of Object.entries(sortedProfilesByGroup)) { | ||
| 486 | if (groupProfiles.length === 0) continue; | ||
| 487 | |||
| 488 | groupProfiles.sort((a, b) => a.name.localeCompare(b.name)); | ||
| 489 | |||
| 490 | const group = groups[apiType]; | ||
| 491 | for (const profile of groupProfiles) { | ||
| 492 | const option = document.createElement('option'); | ||
| 493 | option.value = profile.id; | ||
| 494 | option.textContent = profile.name; | ||
| 495 | group.appendChild(option); | ||
| 496 | } | ||
| 497 | } | ||
| 498 | |||
| 499 | for (const group of Object.values(groups)) { | ||
| 500 | if (group.children.length > 0) { | ||
| 501 | dropdown.append(group); | ||
| 502 | } | ||
| 503 | } | ||
| 504 | |||
| 505 | const selectedProfile = profiles.find((p) => p.id === initialSelectedProfileId); | ||
| 506 | if (selectedProfile) { | ||
| 507 | dropdown.val(selectedProfile.id); | ||
| 508 | } | ||
| 509 | |||
| 510 | context.eventSource.on(context.eventTypes.CONNECTION_PROFILE_CREATED, async (profile) => { | ||
| 511 | const isSupported = this.isProfileSupported(profile); | ||
| 512 | if (!isSupported) { | ||
| 513 | return; | ||
| 514 | } | ||
| 515 | |||
| 516 | const group = groups[CONNECT_API_MAP[profile.api].selected]; | ||
| 517 | const option = document.createElement('option'); | ||
| 518 | option.value = profile.id; | ||
| 519 | option.textContent = profile.name; | ||
| 520 | group.appendChild(option); | ||
| 521 | |||
| 522 | await onCreate(profile); | ||
| 523 | }); | ||
| 524 | |||
| 525 | context.eventSource.on(context.eventTypes.CONNECTION_PROFILE_UPDATED, async (oldProfile, newProfile) => { | ||
| 526 | const currentSelected = dropdown.val(); | ||
| 527 | const isSelectedProfile = currentSelected === oldProfile.id; | ||
| 528 | await unUpdate(oldProfile, newProfile); | ||
| 529 | |||
| 530 | if (!this.isProfileSupported(newProfile)) { | ||
| 531 | if (isSelectedProfile) { | ||
| 532 | dropdown.val(''); | ||
| 533 | dropdown.trigger('change'); | ||
| 534 | } | ||
| 535 | return; | ||
| 536 | } | ||
| 537 | |||
| 538 | const group = groups[CONNECT_API_MAP[newProfile.api].selected]; | ||
| 539 | const oldOption = group.querySelector(`option[value="${oldProfile.id}"]`); | ||
| 540 | if (oldOption) { | ||
| 541 | oldOption.remove(); | ||
| 542 | } | ||
| 543 | |||
| 544 | const option = document.createElement('option'); | ||
| 545 | option.value = newProfile.id; | ||
| 546 | option.textContent = newProfile.name; | ||
| 547 | group.appendChild(option); | ||
| 548 | |||
| 549 | if (isSelectedProfile) { | ||
| 550 | // Ackchyually, we don't need to reselect but what if id changes? It is not possible for now I couldn't stop myself. | ||
| 551 | dropdown.val(newProfile.id); | ||
| 552 | dropdown.trigger('change'); | ||
| 553 | } | ||
| 554 | }); | ||
| 555 | |||
| 556 | context.eventSource.on(context.eventTypes.CONNECTION_PROFILE_DELETED, async (profile) => { | ||
| 557 | const currentSelected = dropdown.val(); | ||
| 558 | const isSelectedProfile = currentSelected === profile.id; | ||
| 559 | if (!this.isProfileSupported(profile)) { | ||
| 560 | return; | ||
| 561 | } | ||
| 562 | |||
| 563 | const group = groups[CONNECT_API_MAP[profile.api].selected]; | ||
| 564 | const optionToRemove = group.querySelector(`option[value="${profile.id}"]`); | ||
| 565 | if (optionToRemove) { | ||
| 566 | optionToRemove.remove(); | ||
| 567 | } | ||
| 568 | |||
| 569 | if (isSelectedProfile) { | ||
| 570 | dropdown.val(''); | ||
| 571 | dropdown.trigger('change'); | ||
| 572 | } | ||
| 573 | |||
| 574 | await onDelete(profile); | ||
| 575 | }); | ||
| 576 | |||
| 577 | dropdown.on('change', async () => { | ||
| 578 | const profileId = dropdown.val(); | ||
| 579 | const profile = context.extensionSettings.connectionManager.profiles.find((p) => p.id === profileId); | ||
| 580 | await onChange(profile); | ||
| 581 | }); | ||
| 582 | } | ||
| 583 | } | ||
| @@ -3772,7 +3772,6 @@ async function addSDGenButtons() { | |||
| 3772 | $('#sd_wand_container').append(buttonHtml); | 3772 | $('#sd_wand_container').append(buttonHtml); |
| 3773 | $(document.body).append(dropdownHtml); | 3773 | $(document.body).append(dropdownHtml); |
| 3774 | 3774 | ||
| 3775 | const messageButton = $('.sd_message_gen'); | ||
| 3776 | const button = $('#sd_gen'); | 3775 | const button = $('#sd_gen'); |
| 3777 | const dropdown = $('#sd_dropdown'); | 3776 | const dropdown = $('#sd_dropdown'); |
| 3778 | dropdown.hide(); | 3777 | dropdown.hide(); |
| @@ -183,8 +183,6 @@ class GptSovitsV2Provider { | |||
| 183 | 183 | ||
| 184 | let prompt_text = replaceSpeaker(voiceId); | 184 | let prompt_text = replaceSpeaker(voiceId); |
| 185 | 185 | ||
| 186 | const streaming = this.settings.streaming; | ||
| 187 | |||
| 188 | const params = { | 186 | const params = { |
| 189 | text: inputText, | 187 | text: inputText, |
| 190 | prompt_text: prompt_text, | 188 | prompt_text: prompt_text, |
| @@ -1,5 +1,5 @@ | |||
| 1 | import { cancelTtsPlay, eventSource, event_types, getCurrentChatId, isStreamingEnabled, name2, saveSettingsDebounced, substituteParams } from '../../../script.js'; | 1 | import { cancelTtsPlay, eventSource, event_types, getCurrentChatId, isStreamingEnabled, name2, saveSettingsDebounced, substituteParams } from '../../../script.js'; |
| 2 | import { ModuleWorkerWrapper, doExtrasFetch, extension_settings, getApiUrl, getContext, modules, renderExtensionTemplateAsync } from '../../extensions.js'; | 2 | import { ModuleWorkerWrapper, extension_settings, getContext, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 3 | import { delay, escapeRegex, getBase64Async, getStringHash, onlyUnique } from '../../utils.js'; | 3 | import { delay, escapeRegex, getBase64Async, getStringHash, onlyUnique } from '../../utils.js'; |
| 4 | import { EdgeTtsProvider } from './edge.js'; | 4 | import { EdgeTtsProvider } from './edge.js'; |
| 5 | import { ElevenLabsTtsProvider } from './elevenlabs.js'; | 5 | import { ElevenLabsTtsProvider } from './elevenlabs.js'; |
| @@ -1207,8 +1207,8 @@ jQuery(async function () { | |||
| 1207 | eventSource.on(event_types.GROUP_UPDATED, onChatChanged); | 1207 | eventSource.on(event_types.GROUP_UPDATED, onChatChanged); |
| 1208 | eventSource.on(event_types.GENERATION_STARTED, onGenerationStarted); | 1208 | eventSource.on(event_types.GENERATION_STARTED, onGenerationStarted); |
| 1209 | eventSource.on(event_types.GENERATION_ENDED, onGenerationEnded); | 1209 | eventSource.on(event_types.GENERATION_ENDED, onGenerationEnded); |
| 1210 | eventSource.makeLast(event_types.CHARACTER_MESSAGE_RENDERED, onMessageEvent); | 1210 | eventSource.makeLast(event_types.CHARACTER_MESSAGE_RENDERED, (messageId) => onMessageEvent(messageId)); |
| 1211 | eventSource.makeLast(event_types.USER_MESSAGE_RENDERED, onMessageEvent); | 1211 | eventSource.makeLast(event_types.USER_MESSAGE_RENDERED, (messageId) => onMessageEvent(messageId)); |
| 1212 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1212 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1213 | name: 'speak', | 1213 | name: 'speak', |
| 1214 | callback: async (args, value) => { | 1214 | callback: async (args, value) => { |
| @@ -46,7 +46,6 @@ import { | |||
| 46 | hideSwipeButtons, | 46 | hideSwipeButtons, |
| 47 | chat_metadata, | 47 | chat_metadata, |
| 48 | updateChatMetadata, | 48 | updateChatMetadata, |
| 49 | isStreamingEnabled, | ||
| 50 | getThumbnailUrl, | 49 | getThumbnailUrl, |
| 51 | getRequestHeaders, | 50 | getRequestHeaders, |
| 52 | setMenuType, | 51 | setMenuType, |
| @@ -435,16 +434,18 @@ export function getGroupCharacterCards(groupId, characterId) { | |||
| 435 | * @param {string} value Value to replace | 434 | * @param {string} value Value to replace |
| 436 | * @param {string} fieldName Name of the field | 435 | * @param {string} fieldName Name of the field |
| 437 | * @param {string} characterName Name of the character | 436 | * @param {string} characterName Name of the character |
| 437 | * @param {boolean} trim Whether to trim the value | ||
| 438 | * @returns {string} Replaced text | 438 | * @returns {string} Replaced text |
| 439 | * */ | 439 | * */ |
| 440 | function customBaseChatReplace(value, fieldName, characterName) { | 440 | function customBaseChatReplace(value, fieldName, characterName, trim) { |
| 441 | if (!value) { | 441 | if (!value) { |
| 442 | return ''; | 442 | return ''; |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | // We should do the custom field name replacement first, and then run it through the normal macro engine with provided names | 445 | // We should do the custom field name replacement first, and then run it through the normal macro engine with provided names |
| 446 | value = value.replace(/<FIELDNAME>/gi, fieldName); | 446 | value = value.replace(/<FIELDNAME>/gi, fieldName); |
| 447 | return baseChatReplace(value.trim(), name1, characterName); | 447 | value = trim ? value.trim() : value; |
| 448 | return baseChatReplace(value, name1, characterName); | ||
| 448 | } | 449 | } |
| 449 | 450 | ||
| 450 | /** | 451 | /** |
| @@ -467,13 +468,12 @@ export function getGroupCharacterCards(groupId, characterId) { | |||
| 467 | } | 468 | } |
| 468 | 469 | ||
| 469 | // Prepare and replace prefixes | 470 | // Prepare and replace prefixes |
| 470 | const prefix = customBaseChatReplace(group.generation_mode_join_prefix, fieldName, characterName); | 471 | const prefix = customBaseChatReplace(group.generation_mode_join_prefix, fieldName, characterName, false); |
| 471 | const suffix = customBaseChatReplace(group.generation_mode_join_suffix, fieldName, characterName); | 472 | const suffix = customBaseChatReplace(group.generation_mode_join_suffix, fieldName, characterName, false); |
| 472 | const separator = power_user.instruct.wrap ? '\n' : ''; | ||
| 473 | // Also run the macro replacement on the actual content | 473 | // Also run the macro replacement on the actual content |
| 474 | value = customBaseChatReplace(value, fieldName, characterName); | 474 | value = customBaseChatReplace(value, fieldName, characterName, true); |
| 475 | 475 | ||
| 476 | return `${prefix ? prefix + separator : ''}${value}${suffix ? separator + suffix : ''}`; | 476 | return `${prefix}${value}${suffix}`; |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | const scenarioOverride = chat_metadata['scenario']; | 479 | const scenarioOverride = chat_metadata['scenario']; |
| @@ -696,7 +696,7 @@ export function getGroupBlock(group) { | |||
| 696 | template.find('.group_fav_icon').css('display', 'none'); | 696 | template.find('.group_fav_icon').css('display', 'none'); |
| 697 | template.addClass(group.fav ? 'is_fav' : ''); | 697 | template.addClass(group.fav ? 'is_fav' : ''); |
| 698 | template.find('.ch_fav').val(group.fav); | 698 | template.find('.ch_fav').val(group.fav); |
| 699 | template.find('.group_select_counter').text(`${count} ${count != 1 ? 'characters' : 'character'}`); | 699 | template.find('.group_select_counter').text(count + ' ' + (count != 1 ? t`characters` : t`character`)); |
| 700 | template.find('.group_select_block_list').text(namesList.join(', ')); | 700 | template.find('.group_select_block_list').text(namesList.join(', ')); |
| 701 | 701 | ||
| 702 | // Display inline tags | 702 | // Display inline tags |
| @@ -904,6 +904,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | |||
| 904 | groupChatQueueOrder.set(characters[activatedMembers[i]].avatar, i + 1); | 904 | groupChatQueueOrder.set(characters[activatedMembers[i]].avatar, i + 1); |
| 905 | } | 905 | } |
| 906 | } | 906 | } |
| 907 | await eventSource.emit(event_types.GROUP_WRAPPER_STARTED, { selected_group, type }); | ||
| 907 | // now the real generation begins: cycle through every activated character | 908 | // now the real generation begins: cycle through every activated character |
| 908 | for (const chId of activatedMembers) { | 909 | for (const chId of activatedMembers) { |
| 909 | throwIfAborted(); | 910 | throwIfAborted(); |
| @@ -942,6 +943,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | |||
| 942 | setCharacterName(''); | 943 | setCharacterName(''); |
| 943 | activateSendButtons(); | 944 | activateSendButtons(); |
| 944 | showSwipeButtons(); | 945 | showSwipeButtons(); |
| 946 | await eventSource.emit(event_types.GROUP_WRAPPER_FINISHED, { selected_group, type }); | ||
| 945 | } | 947 | } |
| 946 | 948 | ||
| 947 | return Promise.resolve(textResult); | 949 | return Promise.resolve(textResult); |
| @@ -10,6 +10,7 @@ import { SECRET_KEYS, writeSecret } from './secrets.js'; | |||
| 10 | import { delay } from './utils.js'; | 10 | import { delay } from './utils.js'; |
| 11 | import { isMobile } from './RossAscends-mods.js'; | 11 | import { isMobile } from './RossAscends-mods.js'; |
| 12 | import { autoSelectInstructPreset } from './instruct-mode.js'; | 12 | import { autoSelectInstructPreset } from './instruct-mode.js'; |
| 13 | import { t } from './i18n.js'; | ||
| 13 | 14 | ||
| 14 | export { | 15 | export { |
| 15 | horde_settings, | 16 | horde_settings, |
| @@ -169,7 +170,7 @@ async function adjustHordeGenerationParams(max_context_length, max_length) { | |||
| 169 | } | 170 | } |
| 170 | } | 171 | } |
| 171 | console.log(maxContextLength, maxLength); | 172 | console.log(maxContextLength, maxLength); |
| 172 | $('#adjustedHordeParams').text(`Context: ${maxContextLength}, Response: ${maxLength}`); | 173 | $('#adjustedHordeParams').text(t`Context` + `: ${maxContextLength}, ` + t`Response` + `: ${maxLength}`); |
| 173 | return { maxContextLength, maxLength }; | 174 | return { maxContextLength, maxLength }; |
| 174 | } | 175 | } |
| 175 | 176 | ||
| @@ -177,7 +178,7 @@ function setContextSizePreview() { | |||
| 177 | if (horde_settings.models.length) { | 178 | if (horde_settings.models.length) { |
| 178 | adjustHordeGenerationParams(max_context, amount_gen); | 179 | adjustHordeGenerationParams(max_context, amount_gen); |
| 179 | } else { | 180 | } else { |
| 180 | $('#adjustedHordeParams').text('Context: --, Response: --'); | 181 | $('#adjustedHordeParams').text(t`Context` + ': --, ' + t`Response` + ': --'); |
| 181 | } | 182 | } |
| 182 | } | 183 | } |
| 183 | 184 | ||
| @@ -404,7 +405,7 @@ jQuery(function () { | |||
| 404 | if (horde_settings.models.length) { | 405 | if (horde_settings.models.length) { |
| 405 | adjustHordeGenerationParams(max_context, amount_gen); | 406 | adjustHordeGenerationParams(max_context, amount_gen); |
| 406 | } else { | 407 | } else { |
| 407 | $('#adjustedHordeParams').text('Context: --, Response: --'); | 408 | $('#adjustedHordeParams').text(t`Context` + ': --, ' + t`Response` + ': --'); |
| 408 | } | 409 | } |
| 409 | 410 | ||
| 410 | saveSettingsDebounced(); | 411 | saveSettingsDebounced(); |
| @@ -320,59 +320,61 @@ export const force_output_sequence = { | |||
| 320 | * @param {string} name1 User name. | 320 | * @param {string} name1 User name. |
| 321 | * @param {string} name2 Character name. | 321 | * @param {string} name2 Character name. |
| 322 | * @param {boolean|number} forceOutputSequence Force to use first/last output sequence (if configured). | 322 | * @param {boolean|number} forceOutputSequence Force to use first/last output sequence (if configured). |
| 323 | * @param {InstructSettings} customInstruct Custom instruct mode settings. | ||
| 323 | * @returns {string} Formatted instruct mode chat message. | 324 | * @returns {string} Formatted instruct mode chat message. |
| 324 | */ | 325 | */ |
| 325 | export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceOutputSequence) { | 326 | export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceOutputSequence, customInstruct = null) { |
| 326 | let includeNames = isNarrator ? false : power_user.instruct.names_behavior === names_behavior_types.ALWAYS; | 327 | const instruct = structuredClone(customInstruct ?? power_user.instruct); |
| 328 | let includeNames = isNarrator ? false : instruct.names_behavior === names_behavior_types.ALWAYS; | ||
| 327 | 329 | ||
| 328 | if (!isNarrator && power_user.instruct.names_behavior === names_behavior_types.FORCE && ((selected_group && name !== name1) || (forceAvatar && name !== name1))) { | 330 | if (!isNarrator && instruct.names_behavior === names_behavior_types.FORCE && ((selected_group && name !== name1) || (forceAvatar && name !== name1))) { |
| 329 | includeNames = true; | 331 | includeNames = true; |
| 330 | } | 332 | } |
| 331 | 333 | ||
| 332 | function getPrefix() { | 334 | function getPrefix() { |
| 333 | if (isNarrator) { | 335 | if (isNarrator) { |
| 334 | return power_user.instruct.system_same_as_user ? power_user.instruct.input_sequence : power_user.instruct.system_sequence; | 336 | return instruct.system_same_as_user ? instruct.input_sequence : instruct.system_sequence; |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | if (isUser) { | 339 | if (isUser) { |
| 338 | if (forceOutputSequence === force_output_sequence.FIRST) { | 340 | if (forceOutputSequence === force_output_sequence.FIRST) { |
| 339 | return power_user.instruct.first_input_sequence || power_user.instruct.input_sequence; | 341 | return instruct.first_input_sequence || instruct.input_sequence; |
| 340 | } | 342 | } |
| 341 | 343 | ||
| 342 | if (forceOutputSequence === force_output_sequence.LAST) { | 344 | if (forceOutputSequence === force_output_sequence.LAST) { |
| 343 | return power_user.instruct.last_input_sequence || power_user.instruct.input_sequence; | 345 | return instruct.last_input_sequence || instruct.input_sequence; |
| 344 | } | 346 | } |
| 345 | 347 | ||
| 346 | return power_user.instruct.input_sequence; | 348 | return instruct.input_sequence; |
| 347 | } | 349 | } |
| 348 | 350 | ||
| 349 | if (forceOutputSequence === force_output_sequence.FIRST) { | 351 | if (forceOutputSequence === force_output_sequence.FIRST) { |
| 350 | return power_user.instruct.first_output_sequence || power_user.instruct.output_sequence; | 352 | return instruct.first_output_sequence || instruct.output_sequence; |
| 351 | } | 353 | } |
| 352 | 354 | ||
| 353 | if (forceOutputSequence === force_output_sequence.LAST) { | 355 | if (forceOutputSequence === force_output_sequence.LAST) { |
| 354 | return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence; | 356 | return instruct.last_output_sequence || instruct.output_sequence; |
| 355 | } | 357 | } |
| 356 | 358 | ||
| 357 | return power_user.instruct.output_sequence; | 359 | return instruct.output_sequence; |
| 358 | } | 360 | } |
| 359 | 361 | ||
| 360 | function getSuffix() { | 362 | function getSuffix() { |
| 361 | if (isNarrator) { | 363 | if (isNarrator) { |
| 362 | return power_user.instruct.system_same_as_user ? power_user.instruct.input_suffix : power_user.instruct.system_suffix; | 364 | return instruct.system_same_as_user ? instruct.input_suffix : instruct.system_suffix; |
| 363 | } | 365 | } |
| 364 | 366 | ||
| 365 | if (isUser) { | 367 | if (isUser) { |
| 366 | return power_user.instruct.input_suffix; | 368 | return instruct.input_suffix; |
| 367 | } | 369 | } |
| 368 | 370 | ||
| 369 | return power_user.instruct.output_suffix; | 371 | return instruct.output_suffix; |
| 370 | } | 372 | } |
| 371 | 373 | ||
| 372 | let prefix = getPrefix() || ''; | 374 | let prefix = getPrefix() || ''; |
| 373 | let suffix = getSuffix() || ''; | 375 | let suffix = getSuffix() || ''; |
| 374 | 376 | ||
| 375 | if (power_user.instruct.macro) { | 377 | if (instruct.macro) { |
| 376 | prefix = substituteParams(prefix, name1, name2); | 378 | prefix = substituteParams(prefix, name1, name2); |
| 377 | prefix = prefix.replace(/{{name}}/gi, name || 'System'); | 379 | prefix = prefix.replace(/{{name}}/gi, name || 'System'); |
| 378 | 380 | ||
| @@ -380,11 +382,11 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata | |||
| 380 | suffix = suffix.replace(/{{name}}/gi, name || 'System'); | 382 | suffix = suffix.replace(/{{name}}/gi, name || 'System'); |
| 381 | } | 383 | } |
| 382 | 384 | ||
| 383 | if (!suffix && power_user.instruct.wrap) { | 385 | if (!suffix && instruct.wrap) { |
| 384 | suffix = '\n'; | 386 | suffix = '\n'; |
| 385 | } | 387 | } |
| 386 | 388 | ||
| 387 | const separator = power_user.instruct.wrap ? '\n' : ''; | 389 | const separator = instruct.wrap ? '\n' : ''; |
| 388 | 390 | ||
| 389 | // Don't include the name if it's empty | 391 | // Don't include the name if it's empty |
| 390 | const textArray = includeNames && name ? [prefix, `${name}: ${mes}` + suffix] : [prefix, mes + suffix]; | 392 | const textArray = includeNames && name ? [prefix, `${name}: ${mes}` + suffix] : [prefix, mes + suffix]; |
| @@ -396,23 +398,26 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata | |||
| 396 | /** | 398 | /** |
| 397 | * Formats instruct mode system prompt. | 399 | * Formats instruct mode system prompt. |
| 398 | * @param {string} systemPrompt System prompt string. | 400 | * @param {string} systemPrompt System prompt string. |
| 401 | * @param {InstructSettings} customInstruct Custom instruct mode settings. | ||
| 399 | * @returns {string} Formatted instruct mode system prompt. | 402 | * @returns {string} Formatted instruct mode system prompt. |
| 400 | */ | 403 | */ |
| 401 | export function formatInstructModeSystemPrompt(systemPrompt) { | 404 | export function formatInstructModeSystemPrompt(systemPrompt, customInstruct = null) { |
| 402 | if (!systemPrompt) { | 405 | if (!systemPrompt) { |
| 403 | return ''; | 406 | return ''; |
| 404 | } | 407 | } |
| 405 | 408 | ||
| 406 | const separator = power_user.instruct.wrap ? '\n' : ''; | 409 | const instruct = structuredClone(customInstruct ?? power_user.instruct); |
| 407 | 410 | ||
| 408 | if (power_user.instruct.system_sequence_prefix) { | 411 | const separator = instruct.wrap ? '\n' : ''; |
| 412 | |||
| 413 | if (instruct.system_sequence_prefix) { | ||
| 409 | // TODO: Replace with a proper 'System' prompt entity name input | 414 | // TODO: Replace with a proper 'System' prompt entity name input |
| 410 | const prefix = power_user.instruct.system_sequence_prefix.replace(/{{name}}/gi, 'System'); | 415 | const prefix = instruct.system_sequence_prefix.replace(/{{name}}/gi, 'System'); |
| 411 | systemPrompt = prefix + separator + systemPrompt; | 416 | systemPrompt = prefix + separator + systemPrompt; |
| 412 | } | 417 | } |
| 413 | 418 | ||
| 414 | if (power_user.instruct.system_sequence_suffix) { | 419 | if (instruct.system_sequence_suffix) { |
| 415 | systemPrompt = systemPrompt + separator + power_user.instruct.system_sequence_suffix; | 420 | systemPrompt = systemPrompt + separator + instruct.system_sequence_suffix; |
| 416 | } | 421 | } |
| 417 | 422 | ||
| 418 | return systemPrompt; | 423 | return systemPrompt; |
| @@ -504,30 +509,32 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) { | |||
| 504 | * @param {string} name2 Character name. | 509 | * @param {string} name2 Character name. |
| 505 | * @param {boolean} isQuiet Is quiet mode generation. | 510 | * @param {boolean} isQuiet Is quiet mode generation. |
| 506 | * @param {boolean} isQuietToLoud Is quiet to loud generation. | 511 | * @param {boolean} isQuietToLoud Is quiet to loud generation. |
| 512 | * @param {InstructSettings} customInstruct Custom instruct settings. | ||
| 507 | * @returns {string} Formatted instruct mode last prompt line. | 513 | * @returns {string} Formatted instruct mode last prompt line. |
| 508 | */ | 514 | */ |
| 509 | export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, isQuietToLoud) { | 515 | export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, isQuietToLoud, customInstruct = null) { |
| 510 | const includeNames = name && (power_user.instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && power_user.instruct.names_behavior === names_behavior_types.FORCE)) && !(isQuiet && !isQuietToLoud); | 516 | const instruct = structuredClone(customInstruct ?? power_user.instruct); |
| 517 | const includeNames = name && (instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && instruct.names_behavior === names_behavior_types.FORCE)) && !(isQuiet && !isQuietToLoud); | ||
| 511 | 518 | ||
| 512 | function getSequence() { | 519 | function getSequence() { |
| 513 | // User impersonation prompt | 520 | // User impersonation prompt |
| 514 | if (isImpersonate) { | 521 | if (isImpersonate) { |
| 515 | return power_user.instruct.input_sequence; | 522 | return instruct.input_sequence; |
| 516 | } | 523 | } |
| 517 | 524 | ||
| 518 | // Neutral / system / quiet prompt | 525 | // Neutral / system / quiet prompt |
| 519 | // Use a special quiet instruct sequence if defined, or assistant's output sequence otherwise | 526 | // Use a special quiet instruct sequence if defined, or assistant's output sequence otherwise |
| 520 | if (isQuiet && !isQuietToLoud) { | 527 | if (isQuiet && !isQuietToLoud) { |
| 521 | return power_user.instruct.last_system_sequence || power_user.instruct.output_sequence; | 528 | return instruct.last_system_sequence || instruct.output_sequence; |
| 522 | } | 529 | } |
| 523 | 530 | ||
| 524 | // Quiet in-character prompt | 531 | // Quiet in-character prompt |
| 525 | if (isQuiet && isQuietToLoud) { | 532 | if (isQuiet && isQuietToLoud) { |
| 526 | return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence; | 533 | return instruct.last_output_sequence || instruct.output_sequence; |
| 527 | } | 534 | } |
| 528 | 535 | ||
| 529 | // Default AI response | 536 | // Default AI response |
| 530 | return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence; | 537 | return instruct.last_output_sequence || instruct.output_sequence; |
| 531 | } | 538 | } |
| 532 | 539 | ||
| 533 | let sequence = getSequence() || ''; | 540 | let sequence = getSequence() || ''; |
| @@ -536,21 +543,21 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, | |||
| 536 | // A hack for Mistral's formatting that has a normal output sequence ending with a space | 543 | // A hack for Mistral's formatting that has a normal output sequence ending with a space |
| 537 | if ( | 544 | if ( |
| 538 | includeNames && | 545 | includeNames && |
| 539 | power_user.instruct.last_output_sequence && | 546 | instruct.last_output_sequence && |
| 540 | power_user.instruct.output_sequence && | 547 | instruct.output_sequence && |
| 541 | sequence === power_user.instruct.last_output_sequence && | 548 | sequence === instruct.last_output_sequence && |
| 542 | /\s$/.test(power_user.instruct.output_sequence) && | 549 | /\s$/.test(instruct.output_sequence) && |
| 543 | !/\s$/.test(power_user.instruct.last_output_sequence) | 550 | !/\s$/.test(instruct.last_output_sequence) |
| 544 | ) { | 551 | ) { |
| 545 | nameFiller = power_user.instruct.output_sequence.slice(-1); | 552 | nameFiller = instruct.output_sequence.slice(-1); |
| 546 | } | 553 | } |
| 547 | 554 | ||
| 548 | if (power_user.instruct.macro) { | 555 | if (instruct.macro) { |
| 549 | sequence = substituteParams(sequence, name1, name2); | 556 | sequence = substituteParams(sequence, name1, name2); |
| 550 | sequence = sequence.replace(/{{name}}/gi, name || 'System'); | 557 | sequence = sequence.replace(/{{name}}/gi, name || 'System'); |
| 551 | } | 558 | } |
| 552 | 559 | ||
| 553 | const separator = power_user.instruct.wrap ? '\n' : ''; | 560 | const separator = instruct.wrap ? '\n' : ''; |
| 554 | let text = includeNames ? (separator + sequence + separator + nameFiller + `${name}:`) : (separator + sequence); | 561 | let text = includeNames ? (separator + sequence + separator + nameFiller + `${name}:`) : (separator + sequence); |
| 555 | 562 | ||
| 556 | // Quiet prompt already has a newline at the end | 563 | // Quiet prompt already has a newline at the end |
| @@ -562,7 +569,7 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, | |||
| 562 | text += (includeNames ? promptBias : (separator + promptBias.trimStart())); | 569 | text += (includeNames ? promptBias : (separator + promptBias.trimStart())); |
| 563 | } | 570 | } |
| 564 | 571 | ||
| 565 | return (power_user.instruct.wrap ? text.trimEnd() : text) + (includeNames ? '' : separator); | 572 | return (instruct.wrap ? text.trimEnd() : text) + (includeNames ? '' : separator); |
| 566 | } | 573 | } |
| 567 | 574 | ||
| 568 | /** | 575 | /** |
| @@ -795,6 +795,7 @@ export function parseNovelAILogprobs(data) { | |||
| 795 | 795 | ||
| 796 | // Add the chosen token to `merged` if it's not already there. This can | 796 | // Add the chosen token to `merged` if it's not already there. This can |
| 797 | // happen if the chosen token was not among the top 10 most likely ones. | 797 | // happen if the chosen token was not among the top 10 most likely ones. |
| 798 | // eslint-disable-next-line no-unused-vars | ||
| 798 | const [[chosenId], [_, chosenAfter]] = data.chosen[0]; | 799 | const [[chosenId], [_, chosenAfter]] = data.chosen[0]; |
| 799 | if (!merged.some(([id]) => id === chosenId)) { | 800 | if (!merged.some(([id]) => id === chosenId)) { |
| 800 | merged.push([chosenId, chosenAfter]); | 801 | merged.push([chosenId, chosenAfter]); |
| @@ -705,16 +705,18 @@ export function parseExampleIntoIndividual(messageExampleString, appendNamesForG | |||
| 705 | return result; | 705 | return result; |
| 706 | } | 706 | } |
| 707 | 707 | ||
| 708 | function formatWorldInfo(value) { | 708 | export function formatWorldInfo(value, { wiFormat = null } = {}) { |
| 709 | if (!value) { | 709 | if (!value) { |
| 710 | return ''; | 710 | return ''; |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | if (!oai_settings.wi_format.trim()) { | 713 | const format = wiFormat ?? oai_settings.wi_format; |
| 714 | |||
| 715 | if (!format.trim()) { | ||
| 714 | return value; | 716 | return value; |
| 715 | } | 717 | } |
| 716 | 718 | ||
| 717 | return stringFormat(oai_settings.wi_format, value); | 719 | return stringFormat(format, value); |
| 718 | } | 720 | } |
| 719 | 721 | ||
| 720 | /** | 722 | /** |
| @@ -952,7 +954,7 @@ async function populateDialogueExamples(prompts, chatCompletion, messageExamples | |||
| 952 | * @param {number} position - Prompt position in the extensions object. | 954 | * @param {number} position - Prompt position in the extensions object. |
| 953 | * @returns {string|false} - The prompt position for prompt collection. | 955 | * @returns {string|false} - The prompt position for prompt collection. |
| 954 | */ | 956 | */ |
| 955 | function getPromptPosition(position) { | 957 | export function getPromptPosition(position) { |
| 956 | if (position == extension_prompt_types.BEFORE_PROMPT) { | 958 | if (position == extension_prompt_types.BEFORE_PROMPT) { |
| 957 | return 'start'; | 959 | return 'start'; |
| 958 | } | 960 | } |
| @@ -969,7 +971,7 @@ function getPromptPosition(position) { | |||
| 969 | * @param {number} role Role of the prompt. | 971 | * @param {number} role Role of the prompt. |
| 970 | * @returns {string} Mapped role. | 972 | * @returns {string} Mapped role. |
| 971 | */ | 973 | */ |
| 972 | function getPromptRole(role) { | 974 | export function getPromptRole(role) { |
| 973 | switch (role) { | 975 | switch (role) { |
| 974 | case extension_prompt_roles.SYSTEM: | 976 | case extension_prompt_roles.SYSTEM: |
| 975 | return 'system'; | 977 | return 'system'; |
| @@ -2018,6 +2020,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2018 | 'reasoning_effort': String(oai_settings.reasoning_effort), | 2020 | 'reasoning_effort': String(oai_settings.reasoning_effort), |
| 2019 | 'enable_web_search': Boolean(oai_settings.enable_web_search), | 2021 | 'enable_web_search': Boolean(oai_settings.enable_web_search), |
| 2020 | 'request_images': Boolean(oai_settings.request_images), | 2022 | 'request_images': Boolean(oai_settings.request_images), |
| 2023 | 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing, | ||
| 2021 | }; | 2024 | }; |
| 2022 | 2025 | ||
| 2023 | if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) { | 2026 | if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) { |
| @@ -2048,7 +2051,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2048 | delete generate_data.stop; | 2051 | delete generate_data.stop; |
| 2049 | delete generate_data.logprobs; | 2052 | delete generate_data.logprobs; |
| 2050 | } | 2053 | } |
| 2051 | if (isOAI && oai_settings.openai_model.includes('gpt-4.5-preview') || isOpenRouter && oai_settings.openrouter_model.includes('gpt-4.5-preview')) { | 2054 | if (isOAI && oai_settings.openai_model.includes('gpt-4.5') || isOpenRouter && oai_settings.openrouter_model.includes('gpt-4.5')) { |
| 2052 | delete generate_data.logprobs; | 2055 | delete generate_data.logprobs; |
| 2053 | } | 2056 | } |
| 2054 | 2057 | ||
| @@ -2098,7 +2101,6 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2098 | generate_data['custom_include_body'] = oai_settings.custom_include_body; | 2101 | generate_data['custom_include_body'] = oai_settings.custom_include_body; |
| 2099 | generate_data['custom_exclude_body'] = oai_settings.custom_exclude_body; | 2102 | generate_data['custom_exclude_body'] = oai_settings.custom_exclude_body; |
| 2100 | generate_data['custom_include_headers'] = oai_settings.custom_include_headers; | 2103 | generate_data['custom_include_headers'] = oai_settings.custom_include_headers; |
| 2101 | generate_data['custom_prompt_post_processing'] = oai_settings.custom_prompt_post_processing; | ||
| 2102 | } | 2104 | } |
| 2103 | 2105 | ||
| 2104 | if (isCohere) { | 2106 | if (isCohere) { |
| @@ -3476,7 +3478,7 @@ async function getStatusOpen() { | |||
| 3476 | let status; | 3478 | let status; |
| 3477 | 3479 | ||
| 3478 | if ('ai' in window) { | 3480 | if ('ai' in window) { |
| 3479 | status = 'Valid'; | 3481 | status = t`Valid`; |
| 3480 | } | 3482 | } |
| 3481 | else { | 3483 | else { |
| 3482 | showWindowExtensionError(); | 3484 | showWindowExtensionError(); |
| @@ -3525,7 +3527,7 @@ async function getStatusOpen() { | |||
| 3525 | 3527 | ||
| 3526 | const canBypass = (oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check) || oai_settings.chat_completion_source === chat_completion_sources.CUSTOM; | 3528 | const canBypass = (oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check) || oai_settings.chat_completion_source === chat_completion_sources.CUSTOM; |
| 3527 | if (canBypass) { | 3529 | if (canBypass) { |
| 3528 | setOnlineStatus('Status check bypassed'); | 3530 | setOnlineStatus(t`Status check bypassed`); |
| 3529 | } | 3531 | } |
| 3530 | 3532 | ||
| 3531 | try { | 3533 | try { |
| @@ -3547,7 +3549,7 @@ async function getStatusOpen() { | |||
| 3547 | saveModelList(responseData.data); | 3549 | saveModelList(responseData.data); |
| 3548 | } | 3550 | } |
| 3549 | if (!('error' in responseData)) { | 3551 | if (!('error' in responseData)) { |
| 3550 | setOnlineStatus('Valid'); | 3552 | setOnlineStatus(t`Valid`); |
| 3551 | } | 3553 | } |
| 3552 | } catch (error) { | 3554 | } catch (error) { |
| 3553 | console.error(error); | 3555 | console.error(error); |
| @@ -4435,9 +4437,9 @@ async function onModelChange() { | |||
| 4435 | if (oai_settings.chat_completion_source === chat_completion_sources.MISTRALAI) { | 4437 | if (oai_settings.chat_completion_source === chat_completion_sources.MISTRALAI) { |
| 4436 | if (oai_settings.max_context_unlocked) { | 4438 | if (oai_settings.max_context_unlocked) { |
| 4437 | $('#openai_max_context').attr('max', unlocked_max); | 4439 | $('#openai_max_context').attr('max', unlocked_max); |
| 4438 | } else if (oai_settings.mistralai_model.includes('codestral-mamba')) { | 4440 | } else if (['codestral-latest', 'codestral-mamba-2407', 'codestral-2411-rc5', 'codestral-2412', 'codestral-2501'].includes(oai_settings.mistralai_model)) { |
| 4439 | $('#openai_max_context').attr('max', max_256k); | 4441 | $('#openai_max_context').attr('max', max_256k); |
| 4440 | } else if (['mistral-large-2407', 'mistral-large-2411', 'mistral-large-latest'].includes(oai_settings.mistralai_model)) { | 4442 | } else if (['mistral-large-2407', 'mistral-large-2411', 'mistral-large-pixtral-2411', 'mistral-large-latest'].includes(oai_settings.mistralai_model)) { |
| 4441 | $('#openai_max_context').attr('max', max_128k); | 4443 | $('#openai_max_context').attr('max', max_128k); |
| 4442 | } else if (oai_settings.mistralai_model.includes('mistral-nemo')) { | 4444 | } else if (oai_settings.mistralai_model.includes('mistral-nemo')) { |
| 4443 | $('#openai_max_context').attr('max', max_128k); | 4445 | $('#openai_max_context').attr('max', max_128k); |
| @@ -800,7 +800,7 @@ async function selectCurrentPersona({ toastPersonaNameChange = true } = {}) { | |||
| 800 | chat_metadata['persona'] = user_avatar; | 800 | chat_metadata['persona'] = user_avatar; |
| 801 | console.log(`Auto locked persona to ${user_avatar}`); | 801 | console.log(`Auto locked persona to ${user_avatar}`); |
| 802 | if (toastPersonaNameChange && power_user.persona_show_notifications) { | 802 | if (toastPersonaNameChange && power_user.persona_show_notifications) { |
| 803 | toastr.success(`Persona ${personaName} selected and auto-locked to current chat`, t`Persona Selected`); | 803 | toastr.success(t`Persona ${personaName} selected and auto-locked to current chat`, t`Persona Selected`); |
| 804 | } | 804 | } |
| 805 | saveMetadataDebounced(); | 805 | saveMetadataDebounced(); |
| 806 | updatePersonaUIStates(); | 806 | updatePersonaUIStates(); |
| @@ -55,6 +55,7 @@ import { POPUP_TYPE, callGenericPopup } from './popup.js'; | |||
| 55 | import { loadSystemPrompts } from './sysprompt.js'; | 55 | import { loadSystemPrompts } from './sysprompt.js'; |
| 56 | import { fuzzySearchCategories } from './filters.js'; | 56 | import { fuzzySearchCategories } from './filters.js'; |
| 57 | import { accountStorage } from './util/AccountStorage.js'; | 57 | import { accountStorage } from './util/AccountStorage.js'; |
| 58 | import { DEFAULT_REASONING_TEMPLATE, loadReasoningTemplates } from './reasoning.js'; | ||
| 58 | 59 | ||
| 59 | export { | 60 | export { |
| 60 | loadPowerUserSettings, | 61 | loadPowerUserSettings, |
| @@ -218,7 +219,9 @@ let power_user = { | |||
| 218 | system_sequence: '', | 219 | system_sequence: '', |
| 219 | system_suffix: '', | 220 | system_suffix: '', |
| 220 | last_system_sequence: '', | 221 | last_system_sequence: '', |
| 222 | first_input_sequence: '', | ||
| 221 | first_output_sequence: '', | 223 | first_output_sequence: '', |
| 224 | last_input_sequence: '', | ||
| 222 | last_output_sequence: '', | 225 | last_output_sequence: '', |
| 223 | system_sequence_prefix: '', | 226 | system_sequence_prefix: '', |
| 224 | system_sequence_suffix: '', | 227 | system_sequence_suffix: '', |
| @@ -255,6 +258,7 @@ let power_user = { | |||
| 255 | }, | 258 | }, |
| 256 | 259 | ||
| 257 | reasoning: { | 260 | reasoning: { |
| 261 | name: DEFAULT_REASONING_TEMPLATE, | ||
| 258 | auto_parse: false, | 262 | auto_parse: false, |
| 259 | add_to_prompts: false, | 263 | add_to_prompts: false, |
| 260 | auto_expand: false, | 264 | auto_expand: false, |
| @@ -1622,6 +1626,7 @@ async function loadPowerUserSettings(settings, data) { | |||
| 1622 | await loadInstructMode(data); | 1626 | await loadInstructMode(data); |
| 1623 | await loadContextSettings(); | 1627 | await loadContextSettings(); |
| 1624 | await loadSystemPrompts(data); | 1628 | await loadSystemPrompts(data); |
| 1629 | await loadReasoningTemplates(data); | ||
| 1625 | loadMaxContextUnlocked(); | 1630 | loadMaxContextUnlocked(); |
| 1626 | switchWaifuMode(); | 1631 | switchWaifuMode(); |
| 1627 | switchSpoilerMode(); | 1632 | switchSpoilerMode(); |
| @@ -1983,15 +1988,21 @@ export function fuzzySearchGroups(searchValue, fuzzySearchCaches = null) { | |||
| 1983 | /** | 1988 | /** |
| 1984 | * Renders a story string template with the given parameters. | 1989 | * Renders a story string template with the given parameters. |
| 1985 | * @param {object} params Template parameters. | 1990 | * @param {object} params Template parameters. |
| 1991 | * @param {object} [options] Additional options. | ||
| 1992 | * @param {string} [options.customStoryString] Custom story string template. | ||
| 1993 | * @param {InstructSettings} [options.customInstructSettings] Custom instruct settings. | ||
| 1986 | * @returns {string} The rendered story string. | 1994 | * @returns {string} The rendered story string. |
| 1987 | */ | 1995 | */ |
| 1988 | export function renderStoryString(params) { | 1996 | export function renderStoryString(params, { customStoryString = null, customInstructSettings = null } = {}) { |
| 1989 | try { | 1997 | try { |
| 1998 | const storyString = customStoryString ?? power_user.context.story_string; | ||
| 1999 | const instructSettings = structuredClone(customInstructSettings ?? power_user.instruct); | ||
| 2000 | |||
| 1990 | // Validate and log possible warnings/errors | 2001 | // Validate and log possible warnings/errors |
| 1991 | validateStoryString(power_user.context.story_string, params); | 2002 | validateStoryString(storyString, params); |
| 1992 | 2003 | ||
| 1993 | // compile the story string template into a function, with no HTML escaping | 2004 | // compile the story string template into a function, with no HTML escaping |
| 1994 | const compiledTemplate = Handlebars.compile(power_user.context.story_string, { noEscape: true }); | 2005 | const compiledTemplate = Handlebars.compile(storyString, { noEscape: true }); |
| 1995 | 2006 | ||
| 1996 | // render the story string template with the given params | 2007 | // render the story string template with the given params |
| 1997 | let output = compiledTemplate(params); | 2008 | let output = compiledTemplate(params); |
| @@ -2004,7 +2015,7 @@ export function renderStoryString(params) { | |||
| 2004 | 2015 | ||
| 2005 | // add a newline to the end of the story string if it doesn't have one | 2016 | // add a newline to the end of the story string if it doesn't have one |
| 2006 | if (output.length > 0 && !output.endsWith('\n')) { | 2017 | if (output.length > 0 && !output.endsWith('\n')) { |
| 2007 | if (!power_user.instruct.enabled || power_user.instruct.wrap) { | 2018 | if (!instructSettings.enabled || instructSettings.wrap) { |
| 2008 | output += '\n'; | 2019 | output += '\n'; |
| 2009 | } | 2020 | } |
| 2010 | } | 2021 | } |
| @@ -4227,14 +4238,13 @@ $(document).ready(() => { | |||
| 4227 | ], | 4238 | ], |
| 4228 | callback: (args, value) => { | 4239 | callback: (args, value) => { |
| 4229 | const force = isTrueBoolean(String(args?.force ?? false)); | 4240 | const force = isTrueBoolean(String(args?.force ?? false)); |
| 4230 | value = String(value ?? '').trim(); | ||
| 4231 | 4241 | ||
| 4232 | // Skip processing if no value and not forced | 4242 | // Skip processing if no value and not forced |
| 4233 | if (!force && !value) { | 4243 | if (!force && !value) { |
| 4234 | return power_user.user_prompt_bias; | 4244 | return power_user.user_prompt_bias; |
| 4235 | } | 4245 | } |
| 4236 | 4246 | ||
| 4237 | power_user.user_prompt_bias = value; | 4247 | power_user.user_prompt_bias = String(value ?? ''); |
| 4238 | $('#start_reply_with').val(power_user.user_prompt_bias); | 4248 | $('#start_reply_with').val(power_user.user_prompt_bias); |
| 4239 | saveSettingsDebounced(); | 4249 | saveSettingsDebounced(); |
| 4240 | 4250 | ||
| @@ -21,7 +21,7 @@ import { groups, selected_group } from './group-chats.js'; | |||
| 21 | import { instruct_presets } from './instruct-mode.js'; | 21 | import { instruct_presets } from './instruct-mode.js'; |
| 22 | import { kai_settings } from './kai-settings.js'; | 22 | import { kai_settings } from './kai-settings.js'; |
| 23 | import { convertNovelPreset } from './nai-settings.js'; | 23 | import { convertNovelPreset } from './nai-settings.js'; |
| 24 | import { openai_settings, openai_setting_names, oai_settings } from './openai.js'; | 24 | import { openai_settings, openai_setting_names } from './openai.js'; |
| 25 | import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; | 25 | import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; |
| 26 | import { context_presets, getContextSettings, power_user } from './power-user.js'; | 26 | import { context_presets, getContextSettings, power_user } from './power-user.js'; |
| 27 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 27 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| @@ -38,6 +38,7 @@ import { | |||
| 38 | } from './textgen-settings.js'; | 38 | } from './textgen-settings.js'; |
| 39 | import { download, parseJsonFile, waitUntilCondition } from './utils.js'; | 39 | import { download, parseJsonFile, waitUntilCondition } from './utils.js'; |
| 40 | import { t } from './i18n.js'; | 40 | import { t } from './i18n.js'; |
| 41 | import { reasoning_templates } from './reasoning.js'; | ||
| 41 | 42 | ||
| 42 | const presetManagers = {}; | 43 | const presetManagers = {}; |
| 43 | 44 | ||
| @@ -168,6 +169,20 @@ class PresetManager { | |||
| 168 | }, | 169 | }, |
| 169 | isValid: (data) => PresetManager.isPossiblyTextCompletionData(data), | 170 | isValid: (data) => PresetManager.isPossiblyTextCompletionData(data), |
| 170 | }, | 171 | }, |
| 172 | 'reasoning': { | ||
| 173 | name: 'Reasoning Formatting', | ||
| 174 | getData: () => { | ||
| 175 | const manager = getPresetManager('reasoning'); | ||
| 176 | const name = manager.getSelectedPresetName(); | ||
| 177 | return manager.getPresetSettings(name); | ||
| 178 | }, | ||
| 179 | setData: (data) => { | ||
| 180 | const manager = getPresetManager('reasoning'); | ||
| 181 | const name = data.name; | ||
| 182 | return manager.savePreset(name, data); | ||
| 183 | }, | ||
| 184 | isValid: (data) => PresetManager.isPossiblyReasoningData(data), | ||
| 185 | }, | ||
| 171 | }; | 186 | }; |
| 172 | 187 | ||
| 173 | static isPossiblyInstructData(data) { | 188 | static isPossiblyInstructData(data) { |
| @@ -190,6 +205,11 @@ class PresetManager { | |||
| 190 | return data && textCompletionProps.every(prop => Object.keys(data).includes(prop)); | 205 | return data && textCompletionProps.every(prop => Object.keys(data).includes(prop)); |
| 191 | } | 206 | } |
| 192 | 207 | ||
| 208 | static isPossiblyReasoningData(data) { | ||
| 209 | const reasoningProps = ['name', 'prefix', 'suffix', 'separator']; | ||
| 210 | return data && reasoningProps.every(prop => Object.keys(data).includes(prop)); | ||
| 211 | } | ||
| 212 | |||
| 193 | /** | 213 | /** |
| 194 | * Imports master settings from JSON data. | 214 | * Imports master settings from JSON data. |
| 195 | * @param {object} data Data to import | 215 | * @param {object} data Data to import |
| @@ -227,6 +247,12 @@ class PresetManager { | |||
| 227 | return await getPresetManager('textgenerationwebui').savePreset(fileName, data); | 247 | return await getPresetManager('textgenerationwebui').savePreset(fileName, data); |
| 228 | } | 248 | } |
| 229 | 249 | ||
| 250 | // 5. Reasoning Template | ||
| 251 | if (this.isPossiblyReasoningData(data)) { | ||
| 252 | toastr.info(t`Importing as reasoning template...`, t`Reasoning template detected`); | ||
| 253 | return await getPresetManager('reasoning').savePreset(data.name, data); | ||
| 254 | } | ||
| 255 | |||
| 230 | const validSections = []; | 256 | const validSections = []; |
| 231 | for (const [key, section] of Object.entries(this.masterSections)) { | 257 | for (const [key, section] of Object.entries(this.masterSections)) { |
| 232 | if (key in data && section.isValid(data[key])) { | 258 | if (key in data && section.isValid(data[key])) { |
| @@ -478,6 +504,10 @@ class PresetManager { | |||
| 478 | presets = system_prompts; | 504 | presets = system_prompts; |
| 479 | preset_names = system_prompts.map(x => x.name); | 505 | preset_names = system_prompts.map(x => x.name); |
| 480 | break; | 506 | break; |
| 507 | case 'reasoning': | ||
| 508 | presets = reasoning_templates; | ||
| 509 | preset_names = reasoning_templates.map(x => x.name); | ||
| 510 | break; | ||
| 481 | default: | 511 | default: |
| 482 | console.warn(`Unknown API ID ${api}`); | 512 | console.warn(`Unknown API ID ${api}`); |
| 483 | } | 513 | } |
| @@ -490,7 +520,7 @@ class PresetManager { | |||
| 490 | } | 520 | } |
| 491 | 521 | ||
| 492 | isAdvancedFormatting() { | 522 | isAdvancedFormatting() { |
| 493 | return this.apiId == 'context' || this.apiId == 'instruct' || this.apiId == 'sysprompt'; | 523 | return ['context', 'instruct', 'sysprompt', 'reasoning'].includes(this.apiId); |
| 494 | } | 524 | } |
| 495 | 525 | ||
| 496 | updateList(name, preset) { | 526 | updateList(name, preset) { |
| @@ -553,6 +583,11 @@ class PresetManager { | |||
| 553 | sysprompt_preset['name'] = name || power_user.sysprompt.preset; | 583 | sysprompt_preset['name'] = name || power_user.sysprompt.preset; |
| 554 | return sysprompt_preset; | 584 | return sysprompt_preset; |
| 555 | } | 585 | } |
| 586 | case 'reasoning': { | ||
| 587 | const reasoning_preset = structuredClone(power_user.reasoning); | ||
| 588 | reasoning_preset['name'] = name || power_user.reasoning.preset; | ||
| 589 | return reasoning_preset; | ||
| 590 | } | ||
| 556 | default: | 591 | default: |
| 557 | console.warn(`Unknown API ID ${apiId}`); | 592 | console.warn(`Unknown API ID ${apiId}`); |
| 558 | return {}; | 593 | return {}; |
| @@ -599,6 +634,13 @@ class PresetManager { | |||
| 599 | 'include_reasoning', | 634 | 'include_reasoning', |
| 600 | 'global_banned_tokens', | 635 | 'global_banned_tokens', |
| 601 | 'send_banned_tokens', | 636 | 'send_banned_tokens', |
| 637 | |||
| 638 | // Reasoning exclusions | ||
| 639 | 'auto_parse', | ||
| 640 | 'add_to_prompts', | ||
| 641 | 'auto_expand', | ||
| 642 | 'show_hidden', | ||
| 643 | 'max_additions', | ||
| 602 | ]; | 644 | ]; |
| 603 | const settings = Object.assign({}, getSettingsByApiId(this.apiId)); | 645 | const settings = Object.assign({}, getSettingsByApiId(this.apiId)); |
| 604 | 646 | ||
| @@ -7,14 +7,46 @@ import { getCurrentLocale, t, translate } from './i18n.js'; | |||
| 7 | import { MacrosParser } from './macros.js'; | 7 | import { MacrosParser } from './macros.js'; |
| 8 | import { chat_completion_sources, getChatCompletionModel, oai_settings } from './openai.js'; | 8 | import { chat_completion_sources, getChatCompletionModel, oai_settings } from './openai.js'; |
| 9 | import { Popup } from './popup.js'; | 9 | import { Popup } from './popup.js'; |
| 10 | import { power_user } from './power-user.js'; | 10 | import { performFuzzySearch, power_user } from './power-user.js'; |
| 11 | import { getPresetManager } from './preset-manager.js'; | ||
| 11 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | 12 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 12 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; | 13 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; |
| 13 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 14 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 14 | import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; | 15 | import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; |
| 15 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 16 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 16 | import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; | 17 | import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; |
| 17 | import { copyText, escapeRegex, isFalseBoolean, setDatasetProperty, trimSpaces } from './utils.js'; | 18 | import { copyText, escapeRegex, isFalseBoolean, isTrueBoolean, setDatasetProperty, trimSpaces } from './utils.js'; |
| 19 | |||
| 20 | /** | ||
| 21 | * @typedef {object} ReasoningTemplate | ||
| 22 | * @property {string} name - The name of the template | ||
| 23 | * @property {string} prefix - Reasoning prefix | ||
| 24 | * @property {string} suffix - Reasoning suffix | ||
| 25 | * @property {string} separator - Reasoning separator | ||
| 26 | */ | ||
| 27 | |||
| 28 | /** | ||
| 29 | * @type {ReasoningTemplate[]} List of reasoning templates | ||
| 30 | */ | ||
| 31 | export const reasoning_templates = []; | ||
| 32 | |||
| 33 | export const DEFAULT_REASONING_TEMPLATE = 'DeepSeek'; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * @type {Record<string, JQuery<HTMLElement>>} List of UI elements for reasoning settings | ||
| 37 | * @readonly | ||
| 38 | */ | ||
| 39 | const UI = { | ||
| 40 | $select: $('#reasoning_select'), | ||
| 41 | $suffix: $('#reasoning_suffix'), | ||
| 42 | $prefix: $('#reasoning_prefix'), | ||
| 43 | $separator: $('#reasoning_separator'), | ||
| 44 | $autoParse: $('#reasoning_auto_parse'), | ||
| 45 | $autoExpand: $('#reasoning_auto_expand'), | ||
| 46 | $showHidden: $('#reasoning_show_hidden'), | ||
| 47 | $addToPrompts: $('#reasoning_add_to_prompts'), | ||
| 48 | $maxAdditions: $('#reasoning_max_additions'), | ||
| 49 | }; | ||
| 18 | 50 | ||
| 19 | /** | 51 | /** |
| 20 | * Enum representing the type of the reasoning for a message (where it came from) | 52 | * Enum representing the type of the reasoning for a message (where it came from) |
| @@ -57,19 +89,24 @@ function toggleReasoningAutoExpand() { | |||
| 57 | * @param {object} data Response data | 89 | * @param {object} data Response data |
| 58 | * @returns {string} Extracted reasoning | 90 | * @returns {string} Extracted reasoning |
| 59 | */ | 91 | */ |
| 60 | export function extractReasoningFromData(data) { | 92 | export function extractReasoningFromData(data, { |
| 61 | switch (main_api) { | 93 | mainApi = null, |
| 94 | ignoreShowThoughts = false, | ||
| 95 | textGenType = null, | ||
| 96 | chatCompletionSource = null, | ||
| 97 | } = {}) { | ||
| 98 | switch (mainApi ?? main_api) { | ||
| 62 | case 'textgenerationwebui': | 99 | case 'textgenerationwebui': |
| 63 | switch (textgenerationwebui_settings.type) { | 100 | switch (textGenType ?? textgenerationwebui_settings.type) { |
| 64 | case textgen_types.OPENROUTER: | 101 | case textgen_types.OPENROUTER: |
| 65 | return data?.choices?.[0]?.reasoning ?? ''; | 102 | return data?.choices?.[0]?.reasoning ?? ''; |
| 66 | } | 103 | } |
| 67 | break; | 104 | break; |
| 68 | 105 | ||
| 69 | case 'openai': | 106 | case 'openai': |
| 70 | if (!oai_settings.show_thoughts) break; | 107 | if (!ignoreShowThoughts && !oai_settings.show_thoughts) break; |
| 71 | 108 | ||
| 72 | switch (oai_settings.chat_completion_source) { | 109 | switch (chatCompletionSource ?? oai_settings.chat_completion_source) { |
| 73 | case chat_completion_sources.DEEPSEEK: | 110 | case chat_completion_sources.DEEPSEEK: |
| 74 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; | 111 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; |
| 75 | case chat_completion_sources.OPENROUTER: | 112 | case chat_completion_sources.OPENROUTER: |
| @@ -664,57 +701,102 @@ export class PromptReasoning { | |||
| 664 | } | 701 | } |
| 665 | 702 | ||
| 666 | function loadReasoningSettings() { | 703 | function loadReasoningSettings() { |
| 667 | $('#reasoning_add_to_prompts').prop('checked', power_user.reasoning.add_to_prompts); | 704 | UI.$addToPrompts.prop('checked', power_user.reasoning.add_to_prompts); |
| 668 | $('#reasoning_add_to_prompts').on('change', function () { | 705 | UI.$addToPrompts.on('change', function () { |
| 669 | power_user.reasoning.add_to_prompts = !!$(this).prop('checked'); | 706 | power_user.reasoning.add_to_prompts = !!$(this).prop('checked'); |
| 670 | saveSettingsDebounced(); | 707 | saveSettingsDebounced(); |
| 671 | }); | 708 | }); |
| 672 | 709 | ||
| 673 | $('#reasoning_prefix').val(power_user.reasoning.prefix); | 710 | UI.$prefix.val(power_user.reasoning.prefix); |
| 674 | $('#reasoning_prefix').on('input', function () { | 711 | UI.$prefix.on('input', function () { |
| 675 | power_user.reasoning.prefix = String($(this).val()); | 712 | power_user.reasoning.prefix = String($(this).val()); |
| 676 | saveSettingsDebounced(); | 713 | saveSettingsDebounced(); |
| 677 | }); | 714 | }); |
| 678 | 715 | ||
| 679 | $('#reasoning_suffix').val(power_user.reasoning.suffix); | 716 | UI.$suffix.val(power_user.reasoning.suffix); |
| 680 | $('#reasoning_suffix').on('input', function () { | 717 | UI.$suffix.on('input', function () { |
| 681 | power_user.reasoning.suffix = String($(this).val()); | 718 | power_user.reasoning.suffix = String($(this).val()); |
| 682 | saveSettingsDebounced(); | 719 | saveSettingsDebounced(); |
| 683 | }); | 720 | }); |
| 684 | 721 | ||
| 685 | $('#reasoning_separator').val(power_user.reasoning.separator); | 722 | UI.$separator.val(power_user.reasoning.separator); |
| 686 | $('#reasoning_separator').on('input', function () { | 723 | UI.$separator.on('input', function () { |
| 687 | power_user.reasoning.separator = String($(this).val()); | 724 | power_user.reasoning.separator = String($(this).val()); |
| 688 | saveSettingsDebounced(); | 725 | saveSettingsDebounced(); |
| 689 | }); | 726 | }); |
| 690 | 727 | ||
| 691 | $('#reasoning_max_additions').val(power_user.reasoning.max_additions); | 728 | UI.$maxAdditions.val(power_user.reasoning.max_additions); |
| 692 | $('#reasoning_max_additions').on('input', function () { | 729 | UI.$maxAdditions.on('input', function () { |
| 693 | power_user.reasoning.max_additions = Number($(this).val()); | 730 | power_user.reasoning.max_additions = Number($(this).val()); |
| 694 | saveSettingsDebounced(); | 731 | saveSettingsDebounced(); |
| 695 | }); | 732 | }); |
| 696 | 733 | ||
| 697 | $('#reasoning_auto_parse').prop('checked', power_user.reasoning.auto_parse); | 734 | UI.$autoParse.prop('checked', power_user.reasoning.auto_parse); |
| 698 | $('#reasoning_auto_parse').on('change', function () { | 735 | UI.$autoParse.on('change', function () { |
| 699 | power_user.reasoning.auto_parse = !!$(this).prop('checked'); | 736 | power_user.reasoning.auto_parse = !!$(this).prop('checked'); |
| 700 | saveSettingsDebounced(); | 737 | saveSettingsDebounced(); |
| 701 | }); | 738 | }); |
| 702 | 739 | ||
| 703 | $('#reasoning_auto_expand').prop('checked', power_user.reasoning.auto_expand); | 740 | UI.$autoExpand.prop('checked', power_user.reasoning.auto_expand); |
| 704 | $('#reasoning_auto_expand').on('change', function () { | 741 | UI.$autoExpand.on('change', function () { |
| 705 | power_user.reasoning.auto_expand = !!$(this).prop('checked'); | 742 | power_user.reasoning.auto_expand = !!$(this).prop('checked'); |
| 706 | toggleReasoningAutoExpand(); | 743 | toggleReasoningAutoExpand(); |
| 707 | saveSettingsDebounced(); | 744 | saveSettingsDebounced(); |
| 708 | }); | 745 | }); |
| 709 | toggleReasoningAutoExpand(); | 746 | toggleReasoningAutoExpand(); |
| 710 | 747 | ||
| 711 | $('#reasoning_show_hidden').prop('checked', power_user.reasoning.show_hidden); | 748 | UI.$showHidden.prop('checked', power_user.reasoning.show_hidden); |
| 712 | $('#reasoning_show_hidden').on('change', function () { | 749 | UI.$showHidden.on('change', function () { |
| 713 | power_user.reasoning.show_hidden = !!$(this).prop('checked'); | 750 | power_user.reasoning.show_hidden = !!$(this).prop('checked'); |
| 714 | $('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null); | 751 | $('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null); |
| 715 | saveSettingsDebounced(); | 752 | saveSettingsDebounced(); |
| 716 | }); | 753 | }); |
| 717 | $('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null); | 754 | $('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null); |
| 755 | |||
| 756 | UI.$select.on('change', async function () { | ||
| 757 | const name = String($(this).val()); | ||
| 758 | const template = reasoning_templates.find(p => p.name === name); | ||
| 759 | if (!template) { | ||
| 760 | return; | ||
| 761 | } | ||
| 762 | |||
| 763 | UI.$prefix.val(template.prefix); | ||
| 764 | UI.$suffix.val(template.suffix); | ||
| 765 | UI.$separator.val(template.separator); | ||
| 766 | |||
| 767 | power_user.reasoning.name = name; | ||
| 768 | power_user.reasoning.prefix = template.prefix; | ||
| 769 | power_user.reasoning.suffix = template.suffix; | ||
| 770 | power_user.reasoning.separator = template.separator; | ||
| 771 | |||
| 772 | saveSettingsDebounced(); | ||
| 773 | }); | ||
| 774 | } | ||
| 775 | |||
| 776 | function selectReasoningTemplateCallback(args, name) { | ||
| 777 | if (!name) { | ||
| 778 | return power_user.reasoning.name ?? ''; | ||
| 779 | } | ||
| 780 | |||
| 781 | const quiet = isTrueBoolean(args?.quiet); | ||
| 782 | const templateNames = reasoning_templates.map(preset => preset.name); | ||
| 783 | let foundName = templateNames.find(x => x.toLowerCase() === name.toLowerCase()); | ||
| 784 | |||
| 785 | if (!foundName) { | ||
| 786 | const result = performFuzzySearch('reasoning-templates', templateNames, [], name); | ||
| 787 | |||
| 788 | if (result.length === 0) { | ||
| 789 | !quiet && toastr.warning(`Reasoning template "${name}" not found`); | ||
| 790 | return ''; | ||
| 791 | } | ||
| 792 | |||
| 793 | foundName = result[0].item; | ||
| 794 | } | ||
| 795 | |||
| 796 | UI.$select.val(foundName).trigger('change'); | ||
| 797 | !quiet && toastr.success(`Reasoning template "${foundName}" selected`); | ||
| 798 | return foundName; | ||
| 799 | |||
| 718 | } | 800 | } |
| 719 | 801 | ||
| 720 | function registerReasoningSlashCommands() { | 802 | function registerReasoningSlashCommands() { |
| @@ -848,6 +930,42 @@ function registerReasoningSlashCommands() { | |||
| 848 | : parsedReasoning.reasoning; | 930 | : parsedReasoning.reasoning; |
| 849 | }, | 931 | }, |
| 850 | })); | 932 | })); |
| 933 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 934 | name: 'reasoning-template', | ||
| 935 | aliases: ['reasoning-formatting', 'reasoning-preset'], | ||
| 936 | callback: selectReasoningTemplateCallback, | ||
| 937 | returns: 'template name', | ||
| 938 | namedArgumentList: [ | ||
| 939 | SlashCommandNamedArgument.fromProps({ | ||
| 940 | name: 'quiet', | ||
| 941 | description: 'Suppress the toast message on template change', | ||
| 942 | typeList: [ARGUMENT_TYPE.BOOLEAN], | ||
| 943 | defaultValue: 'false', | ||
| 944 | enumList: commonEnumProviders.boolean('trueFalse')(), | ||
| 945 | }), | ||
| 946 | ], | ||
| 947 | unnamedArgumentList: [ | ||
| 948 | SlashCommandArgument.fromProps({ | ||
| 949 | description: 'reasoning template name', | ||
| 950 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 951 | enumProvider: () => reasoning_templates.map(x => new SlashCommandEnumValue(x.name, null, enumTypes.enum, enumIcons.preset)), | ||
| 952 | }), | ||
| 953 | ], | ||
| 954 | helpString: ` | ||
| 955 | <div> | ||
| 956 | Selects a reasoning template by name, using fuzzy search to find the closest match. | ||
| 957 | Gets the current template if no name is provided. | ||
| 958 | </div> | ||
| 959 | <div> | ||
| 960 | <strong>Example:</strong> | ||
| 961 | <ul> | ||
| 962 | <li> | ||
| 963 | <pre><code class="language-stscript">/reasoning-template DeepSeek</code></pre> | ||
| 964 | </li> | ||
| 965 | </ul> | ||
| 966 | </div> | ||
| 967 | `, | ||
| 968 | })); | ||
| 851 | } | 969 | } |
| 852 | 970 | ||
| 853 | function registerReasoningMacros() { | 971 | function registerReasoningMacros() { |
| @@ -1207,6 +1325,53 @@ function registerReasoningAppEvents() { | |||
| 1207 | } | 1325 | } |
| 1208 | } | 1326 | } |
| 1209 | 1327 | ||
| 1328 | /** | ||
| 1329 | * Loads reasoning templates from the settings data. | ||
| 1330 | * @param {object} data Settings data | ||
| 1331 | * @param {ReasoningTemplate[]} data.reasoning Reasoning templates | ||
| 1332 | * @returns {Promise<void>} | ||
| 1333 | */ | ||
| 1334 | export async function loadReasoningTemplates(data) { | ||
| 1335 | if (data.reasoning !== undefined) { | ||
| 1336 | reasoning_templates.splice(0, reasoning_templates.length, ...data.reasoning); | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | for (const template of reasoning_templates) { | ||
| 1340 | $('<option>').val(template.name).text(template.name).appendTo(UI.$select); | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | // No template name, need to migrate | ||
| 1344 | if (power_user.reasoning.name === undefined) { | ||
| 1345 | const defaultTemplate = reasoning_templates.find(p => p.name === DEFAULT_REASONING_TEMPLATE); | ||
| 1346 | if (defaultTemplate) { | ||
| 1347 | // If the reasoning settings were modified - migrate them to a custom template | ||
| 1348 | if (power_user.reasoning.prefix !== defaultTemplate.prefix || power_user.reasoning.suffix !== defaultTemplate.suffix || power_user.reasoning.separator !== defaultTemplate.separator) { | ||
| 1349 | /** @type {ReasoningTemplate} */ | ||
| 1350 | const data = { | ||
| 1351 | name: '[Migrated] Custom', | ||
| 1352 | prefix: power_user.reasoning.prefix, | ||
| 1353 | suffix: power_user.reasoning.suffix, | ||
| 1354 | separator: power_user.reasoning.separator, | ||
| 1355 | }; | ||
| 1356 | await getPresetManager('reasoning')?.savePreset(data.name, data); | ||
| 1357 | power_user.reasoning.name = data.name; | ||
| 1358 | } else { | ||
| 1359 | power_user.reasoning.name = defaultTemplate.name; | ||
| 1360 | } | ||
| 1361 | } else { | ||
| 1362 | // Template not found (deleted or content check skipped - leave blank) | ||
| 1363 | power_user.reasoning.name = ''; | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | saveSettingsDebounced(); | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | UI.$select.val(power_user.reasoning.name); | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | /** | ||
| 1373 | * Initializes reasoning settings and event handlers. | ||
| 1374 | */ | ||
| 1210 | export function initReasoning() { | 1375 | export function initReasoning() { |
| 1211 | loadReasoningSettings(); | 1376 | loadReasoningSettings(); |
| 1212 | setReasoningEventHandlers(); | 1377 | setReasoningEventHandlers(); |
| @@ -9,6 +9,7 @@ import { power_user } from './power-user.js'; | |||
| 9 | //import { getSortableDelay, onlyUnique } from './utils.js'; | 9 | //import { getSortableDelay, onlyUnique } from './utils.js'; |
| 10 | //import { getCfgPrompt } from './cfg-scale.js'; | 10 | //import { getCfgPrompt } from './cfg-scale.js'; |
| 11 | import { setting_names } from './textgen-settings.js'; | 11 | import { setting_names } from './textgen-settings.js'; |
| 12 | import { renderTemplateAsync } from './templates.js'; | ||
| 12 | 13 | ||
| 13 | 14 | ||
| 14 | const TGsamplerNames = setting_names; | 15 | const TGsamplerNames = setting_names; |
| @@ -25,25 +26,7 @@ async function showSamplerSelectPopup() { | |||
| 25 | const html = $(document.createElement('div')); | 26 | const html = $(document.createElement('div')); |
| 26 | html.attr('id', 'sampler_view_list') | 27 | html.attr('id', 'sampler_view_list') |
| 27 | .addClass('flex-container flexFlowColumn'); | 28 | .addClass('flex-container flexFlowColumn'); |
| 28 | html.append(` | 29 | html.append(await renderTemplateAsync('samplerSelector')); |
| 29 | <div class="title_restorable flexFlowColumn alignItemsBaseline"> | ||
| 30 | <div class="flex-container justifyCenter"> | ||
| 31 | <h3>Sampler Select</h3> | ||
| 32 | <div class="flex-container alignItemsBaseline"> | ||
| 33 | <div id="resetSelectedSamplers" class="menu_button menu_button_icon" title="Reset custom sampler selection"> | ||
| 34 | <i class="fa-solid fa-recycle"></i> | ||
| 35 | </div> | ||
| 36 | </div> | ||
| 37 | <!--<div class="flex-container alignItemsBaseline"> | ||
| 38 | <div class="menu_button menu_button_icon" title="Create a new sampler"> | ||
| 39 | <i class="fa-solid fa-plus"></i> | ||
| 40 | <span data-i18n="Create">Create</span> | ||
| 41 | </div> | ||
| 42 | </div>--> | ||
| 43 | </div> | ||
| 44 | <small>Here you can toggle the display of individual samplers. (WIP)</small> | ||
| 45 | </div> | ||
| 46 | <hr>`); | ||
| 47 | 30 | ||
| 48 | const listContainer = $('<div id="apiSamplersList" class="flex-container flexNoGap"></div>'); | 31 | const listContainer = $('<div id="apiSamplersList" class="flex-container flexNoGap"></div>'); |
| 49 | const APISamplers = await listSamplers(main_api); | 32 | const APISamplers = await listSamplers(main_api); |
| @@ -1,5 +1,6 @@ | |||
| 1 | import { DOMPurify } from '../lib.js'; | 1 | import { DOMPurify } from '../lib.js'; |
| 2 | import { callPopup, getRequestHeaders } from '../script.js'; | 2 | import { callPopup, getRequestHeaders } from '../script.js'; |
| 3 | import { t } from './i18n.js'; | ||
| 3 | 4 | ||
| 4 | export const SECRET_KEYS = { | 5 | export const SECRET_KEYS = { |
| 5 | HORDE: 'api_key_horde', | 6 | HORDE: 'api_key_horde', |
| @@ -104,7 +105,7 @@ async function viewSecrets() { | |||
| 104 | }); | 105 | }); |
| 105 | 106 | ||
| 106 | if (response.status == 403) { | 107 | if (response.status == 403) { |
| 107 | callPopup('<h3>Forbidden</h3><p>To view your API keys here, set the value of allowKeysExposure to true in config.yaml file and restart the SillyTavern server.</p>', 'text'); | 108 | callPopup('<h3>' + t`Forbidden` + '</h3><p>' + t`To view your API keys here, set the value of allowKeysExposure to true in config.yaml file and restart the SillyTavern server.` + '</p>', 'text'); |
| 108 | return; | 109 | return; |
| 109 | } | 110 | } |
| 110 | 111 | ||
| @@ -69,12 +69,14 @@ import { SlashCommand } from './slash-commands/SlashCommand.js'; | |||
| 69 | import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js'; | 69 | import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js'; |
| 70 | import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js'; | 70 | import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js'; |
| 71 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; | 71 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; |
| 72 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; | 72 | import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; |
| 73 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 73 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 74 | import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js'; | 74 | import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js'; |
| 75 | import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js'; | 75 | import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js'; |
| 76 | import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; | 76 | import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; |
| 77 | import { accountStorage } from './util/AccountStorage.js'; | 77 | import { accountStorage } from './util/AccountStorage.js'; |
| 78 | import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js'; | ||
| 79 | import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; | ||
| 78 | export { | 80 | export { |
| 79 | executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand, | 81 | executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand, |
| 80 | }; | 82 | }; |
| @@ -4345,7 +4347,7 @@ const clearCommandProgressDebounced = debounce(clearCommandProgress); | |||
| 4345 | * @prop {boolean} [handleParserErrors] (true) Whether to handle parser errors (show toast on error) or throw. | 4347 | * @prop {boolean} [handleParserErrors] (true) Whether to handle parser errors (show toast on error) or throw. |
| 4346 | * @prop {SlashCommandScope} [scope] (null) The scope to be used when executing the commands. | 4348 | * @prop {SlashCommandScope} [scope] (null) The scope to be used when executing the commands. |
| 4347 | * @prop {boolean} [handleExecutionErrors] (false) Whether to handle execution errors (show toast on error) or throw | 4349 | * @prop {boolean} [handleExecutionErrors] (false) Whether to handle execution errors (show toast on error) or throw |
| 4348 | * @prop {{[id:PARSER_FLAG]:boolean}} [parserFlags] (null) Parser flags to apply | 4350 | * @prop {import('./slash-commands/SlashCommandParser.js').ParserFlags} [parserFlags] (null) Parser flags to apply |
| 4349 | * @prop {SlashCommandAbortController} [abortController] (null) Controller used to abort or pause command execution | 4351 | * @prop {SlashCommandAbortController} [abortController] (null) Controller used to abort or pause command execution |
| 4350 | * @prop {SlashCommandDebugController} [debugController] (null) Controller used to control debug execution | 4352 | * @prop {SlashCommandDebugController} [debugController] (null) Controller used to control debug execution |
| 4351 | * @prop {(done:number, total:number)=>void} [onProgress] (null) Callback to handle progress events | 4353 | * @prop {(done:number, total:number)=>void} [onProgress] (null) Callback to handle progress events |
| @@ -4355,7 +4357,7 @@ const clearCommandProgressDebounced = debounce(clearCommandProgress); | |||
| 4355 | /** | 4357 | /** |
| 4356 | * @typedef ExecuteSlashCommandsOnChatInputOptions | 4358 | * @typedef ExecuteSlashCommandsOnChatInputOptions |
| 4357 | * @prop {SlashCommandScope} [scope] (null) The scope to be used when executing the commands. | 4359 | * @prop {SlashCommandScope} [scope] (null) The scope to be used when executing the commands. |
| 4358 | * @prop {{[id:PARSER_FLAG]:boolean}} [parserFlags] (null) Parser flags to apply | 4360 | * @prop {import('./slash-commands/SlashCommandParser.js').ParserFlags} [parserFlags] (null) Parser flags to apply |
| 4359 | * @prop {boolean} [clearChatInput] (false) Whether to clear the chat input textarea | 4361 | * @prop {boolean} [clearChatInput] (false) Whether to clear the chat input textarea |
| 4360 | * @prop {string} [source] (null) String indicating where the code come from (e.g., QR name) | 4362 | * @prop {string} [source] (null) String indicating where the code come from (e.g., QR name) |
| 4361 | */ | 4363 | */ |
| @@ -3,16 +3,12 @@ import { SlashCommandAbortController } from './SlashCommandAbortController.js'; | |||
| 3 | import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js'; | 3 | import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js'; |
| 4 | import { SlashCommandClosure } from './SlashCommandClosure.js'; | 4 | import { SlashCommandClosure } from './SlashCommandClosure.js'; |
| 5 | import { SlashCommandDebugController } from './SlashCommandDebugController.js'; | 5 | import { SlashCommandDebugController } from './SlashCommandDebugController.js'; |
| 6 | import { PARSER_FLAG } from './SlashCommandParser.js'; | ||
| 7 | import { SlashCommandScope } from './SlashCommandScope.js'; | 6 | import { SlashCommandScope } from './SlashCommandScope.js'; |
| 8 | 7 | ||
| 9 | |||
| 10 | |||
| 11 | |||
| 12 | /** | 8 | /** |
| 13 | * @typedef {{ | 9 | * @typedef {{ |
| 14 | * _scope:SlashCommandScope, | 10 | * _scope:SlashCommandScope, |
| 15 | * _parserFlags:{[id:PARSER_FLAG]:boolean}, | 11 | * _parserFlags:import('./SlashCommandParser.js').ParserFlags, |
| 16 | * _abortController:SlashCommandAbortController, | 12 | * _abortController:SlashCommandAbortController, |
| 17 | * _debugController:SlashCommandDebugController, | 13 | * _debugController:SlashCommandDebugController, |
| 18 | * _hasUnnamedArgument:boolean, | 14 | * _hasUnnamedArgument:boolean, |
| @@ -1,9 +1,6 @@ | |||
| 1 | import { AutoCompleteNameResult } from '../autocomplete/AutoCompleteNameResult.js'; | 1 | import { AutoCompleteNameResult } from '../autocomplete/AutoCompleteNameResult.js'; |
| 2 | import { AutoCompleteOption } from '../autocomplete/AutoCompleteOption.js'; | ||
| 3 | import { AutoCompleteSecondaryNameResult } from '../autocomplete/AutoCompleteSecondaryNameResult.js'; | 2 | import { AutoCompleteSecondaryNameResult } from '../autocomplete/AutoCompleteSecondaryNameResult.js'; |
| 4 | import { SlashCommand } from './SlashCommand.js'; | 3 | import { SlashCommand } from './SlashCommand.js'; |
| 5 | import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; | ||
| 6 | import { SlashCommandClosure } from './SlashCommandClosure.js'; | ||
| 7 | import { SlashCommandCommandAutoCompleteOption } from './SlashCommandCommandAutoCompleteOption.js'; | 4 | import { SlashCommandCommandAutoCompleteOption } from './SlashCommandCommandAutoCompleteOption.js'; |
| 8 | import { SlashCommandEnumAutoCompleteOption } from './SlashCommandEnumAutoCompleteOption.js'; | 5 | import { SlashCommandEnumAutoCompleteOption } from './SlashCommandEnumAutoCompleteOption.js'; |
| 9 | import { SlashCommandExecutor } from './SlashCommandExecutor.js'; | 6 | import { SlashCommandExecutor } from './SlashCommandExecutor.js'; |
| @@ -2,7 +2,6 @@ import { substituteParams } from '../../script.js'; | |||
| 2 | import { delay, escapeRegex, uuidv4 } from '../utils.js'; | 2 | import { delay, escapeRegex, uuidv4 } from '../utils.js'; |
| 3 | import { SlashCommand } from './SlashCommand.js'; | 3 | import { SlashCommand } from './SlashCommand.js'; |
| 4 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; | 4 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; |
| 5 | import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; | ||
| 6 | import { SlashCommandBreak } from './SlashCommandBreak.js'; | 5 | import { SlashCommandBreak } from './SlashCommandBreak.js'; |
| 7 | import { SlashCommandBreakController } from './SlashCommandBreakController.js'; | 6 | import { SlashCommandBreakController } from './SlashCommandBreakController.js'; |
| 8 | import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js'; | 7 | import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js'; |
| @@ -16,9 +15,7 @@ import { SlashCommandScope } from './SlashCommandScope.js'; | |||
| 16 | export class SlashCommandClosure { | 15 | export class SlashCommandClosure { |
| 17 | /** @type {SlashCommandScope} */ scope; | 16 | /** @type {SlashCommandScope} */ scope; |
| 18 | /** @type {boolean} */ executeNow = false; | 17 | /** @type {boolean} */ executeNow = false; |
| 19 | // @ts-ignore | ||
| 20 | /** @type {SlashCommandNamedArgumentAssignment[]} */ argumentList = []; | 18 | /** @type {SlashCommandNamedArgumentAssignment[]} */ argumentList = []; |
| 21 | // @ts-ignore | ||
| 22 | /** @type {SlashCommandNamedArgumentAssignment[]} */ providedArgumentList = []; | 19 | /** @type {SlashCommandNamedArgumentAssignment[]} */ providedArgumentList = []; |
| 23 | /** @type {SlashCommandExecutor[]} */ executorList = []; | 20 | /** @type {SlashCommandExecutor[]} */ executorList = []; |
| 24 | /** @type {SlashCommandAbortController} */ abortController; | 21 | /** @type {SlashCommandAbortController} */ abortController; |
| @@ -1,7 +1,3 @@ | |||
| 1 | import { SlashCommandExecutor } from './SlashCommandExecutor.js'; | ||
| 2 | import { SlashCommandScope } from './SlashCommandScope.js'; | ||
| 3 | |||
| 4 | |||
| 5 | /** | 1 | /** |
| 6 | * @typedef {'enum' | 'command' | 'namedArgument' | 'variable' | 'qr' | 'macro' | 'number' | 'name'} EnumType | 2 | * @typedef {'enum' | 'command' | 'namedArgument' | 'variable' | 'qr' | 'macro' | 'number' | 'name'} EnumType |
| 7 | */ | 3 | */ |
| @@ -1,11 +1,7 @@ | |||
| 1 | // eslint-disable-next-line no-unused-vars | ||
| 2 | import { uuidv4 } from '../utils.js'; | 1 | import { uuidv4 } from '../utils.js'; |
| 3 | import { SlashCommand } from './SlashCommand.js'; | 2 | import { SlashCommand } from './SlashCommand.js'; |
| 4 | // eslint-disable-next-line no-unused-vars | ||
| 5 | import { SlashCommandClosure } from './SlashCommandClosure.js'; | 3 | import { SlashCommandClosure } from './SlashCommandClosure.js'; |
| 6 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; | 4 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; |
| 7 | // eslint-disable-next-line no-unused-vars | ||
| 8 | import { PARSER_FLAG } from './SlashCommandParser.js'; | ||
| 9 | import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js'; | 5 | import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js'; |
| 10 | 6 | ||
| 11 | export class SlashCommandExecutor { | 7 | export class SlashCommandExecutor { |
| @@ -29,10 +25,9 @@ export class SlashCommandExecutor { | |||
| 29 | } | 25 | } |
| 30 | } | 26 | } |
| 31 | /** @type {SlashCommand} */ command; | 27 | /** @type {SlashCommand} */ command; |
| 32 | // @ts-ignore | ||
| 33 | /** @type {SlashCommandNamedArgumentAssignment[]} */ namedArgumentList = []; | 28 | /** @type {SlashCommandNamedArgumentAssignment[]} */ namedArgumentList = []; |
| 34 | /** @type {SlashCommandUnnamedArgumentAssignment[]} */ unnamedArgumentList = []; | 29 | /** @type {SlashCommandUnnamedArgumentAssignment[]} */ unnamedArgumentList = []; |
| 35 | /**@type {{[id:PARSER_FLAG]:boolean}} */ parserFlags; | 30 | /** @type {import('./SlashCommandParser.js').ParserFlags} */ parserFlags; |
| 36 | 31 | ||
| 37 | get commandCount() { | 32 | get commandCount() { |
| 38 | return 1 | 33 | return 1 |
| @@ -1,7 +1,6 @@ | |||
| 1 | import { AutoCompleteOption } from '../autocomplete/AutoCompleteOption.js'; | 1 | import { AutoCompleteOption } from '../autocomplete/AutoCompleteOption.js'; |
| 2 | import { SlashCommand } from './SlashCommand.js'; | 2 | import { SlashCommand } from './SlashCommand.js'; |
| 3 | import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; | 3 | import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; |
| 4 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; | ||
| 5 | 4 | ||
| 6 | export class SlashCommandNamedArgumentAutoCompleteOption extends AutoCompleteOption { | 5 | export class SlashCommandNamedArgumentAutoCompleteOption extends AutoCompleteOption { |
| 7 | /** @type {SlashCommandNamedArgument} */ arg; | 6 | /** @type {SlashCommandNamedArgument} */ arg; |
| @@ -8,11 +8,9 @@ import { SlashCommandExecutor } from './SlashCommandExecutor.js'; | |||
| 8 | import { SlashCommandParserError } from './SlashCommandParserError.js'; | 8 | import { SlashCommandParserError } from './SlashCommandParserError.js'; |
| 9 | import { AutoCompleteNameResult } from '../autocomplete/AutoCompleteNameResult.js'; | 9 | import { AutoCompleteNameResult } from '../autocomplete/AutoCompleteNameResult.js'; |
| 10 | import { SlashCommandQuickReplyAutoCompleteOption } from './SlashCommandQuickReplyAutoCompleteOption.js'; | 10 | import { SlashCommandQuickReplyAutoCompleteOption } from './SlashCommandQuickReplyAutoCompleteOption.js'; |
| 11 | // eslint-disable-next-line no-unused-vars | ||
| 12 | import { SlashCommandScope } from './SlashCommandScope.js'; | 11 | import { SlashCommandScope } from './SlashCommandScope.js'; |
| 13 | import { SlashCommandVariableAutoCompleteOption } from './SlashCommandVariableAutoCompleteOption.js'; | 12 | import { SlashCommandVariableAutoCompleteOption } from './SlashCommandVariableAutoCompleteOption.js'; |
| 14 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; | 13 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; |
| 15 | // eslint-disable-next-line no-unused-vars | ||
| 16 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; | 14 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; |
| 17 | import { SlashCommandAutoCompleteNameResult } from './SlashCommandAutoCompleteNameResult.js'; | 15 | import { SlashCommandAutoCompleteNameResult } from './SlashCommandAutoCompleteNameResult.js'; |
| 18 | import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js'; | 16 | import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js'; |
| @@ -28,15 +26,17 @@ import { t } from '../i18n.js'; | |||
| 28 | /** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */ | 26 | /** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */ |
| 29 | /** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */ | 27 | /** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */ |
| 30 | 28 | ||
| 31 | /**@readonly*/ | 29 | /** |
| 32 | /**@enum {Number}*/ | 30 | * @enum {Number} |
| 31 | * @readonly | ||
| 32 | * @typedef {{[id:PARSER_FLAG]:boolean}} ParserFlags | ||
| 33 | */ | ||
| 33 | export const PARSER_FLAG = { | 34 | export const PARSER_FLAG = { |
| 34 | 'STRICT_ESCAPING': 1, | 35 | 'STRICT_ESCAPING': 1, |
| 35 | 'REPLACE_GETVAR': 2, | 36 | 'REPLACE_GETVAR': 2, |
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 38 | export class SlashCommandParser { | 39 | export class SlashCommandParser { |
| 39 | // @ts-ignore | ||
| 40 | /** @type {Object.<string, SlashCommand>} */ static commands = {}; | 40 | /** @type {Object.<string, SlashCommand>} */ static commands = {}; |
| 41 | 41 | ||
| 42 | /** | 42 | /** |
| @@ -101,7 +101,6 @@ export class SlashCommandParser { | |||
| 101 | get commands() { | 101 | get commands() { |
| 102 | return SlashCommandParser.commands; | 102 | return SlashCommandParser.commands; |
| 103 | } | 103 | } |
| 104 | // @ts-ignore | ||
| 105 | /** @type {Object.<string, string>} */ helpStrings = {}; | 104 | /** @type {Object.<string, string>} */ helpStrings = {}; |
| 106 | /** @type {boolean} */ verifyCommandNames = true; | 105 | /** @type {boolean} */ verifyCommandNames = true; |
| 107 | /** @type {string} */ text; | 106 | /** @type {string} */ text; |
| @@ -49,6 +49,7 @@ import { | |||
| 49 | clearChat, | 49 | clearChat, |
| 50 | unshallowCharacter, | 50 | unshallowCharacter, |
| 51 | deleteLastMessage, | 51 | deleteLastMessage, |
| 52 | getCharacterCardFields, | ||
| 52 | } from '../script.js'; | 53 | } from '../script.js'; |
| 53 | import { | 54 | import { |
| 54 | extension_settings, | 55 | extension_settings, |
| @@ -78,8 +79,9 @@ import { ToolManager } from './tool-calling.js'; | |||
| 78 | import { accountStorage } from './util/AccountStorage.js'; | 79 | import { accountStorage } from './util/AccountStorage.js'; |
| 79 | import { timestampToMoment, uuidv4 } from './utils.js'; | 80 | import { timestampToMoment, uuidv4 } from './utils.js'; |
| 80 | import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js'; | 81 | import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js'; |
| 81 | import { convertCharacterBook, loadWorldInfo, saveWorldInfo, updateWorldInfoList } from './world-info.js'; | 82 | import { convertCharacterBook, getWorldInfoPrompt, loadWorldInfo, saveWorldInfo, updateWorldInfoList } from './world-info.js'; |
| 82 | import { ChatCompletionService, TextCompletionService } from './custom-request.js'; | 83 | import { ChatCompletionService, TextCompletionService } from './custom-request.js'; |
| 84 | import { ConnectionManagerRequestService } from './extensions/shared.js'; | ||
| 83 | import { updateReasoningUI, parseReasoningFromString } from './reasoning.js'; | 85 | import { updateReasoningUI, parseReasoningFromString } from './reasoning.js'; |
| 84 | 86 | ||
| 85 | export function getContext() { | 87 | export function getContext() { |
| @@ -188,6 +190,7 @@ export function getContext() { | |||
| 188 | textCompletionSettings: textgenerationwebui_settings, | 190 | textCompletionSettings: textgenerationwebui_settings, |
| 189 | powerUserSettings: power_user, | 191 | powerUserSettings: power_user, |
| 190 | getCharacters, | 192 | getCharacters, |
| 193 | getCharacterCardFields, | ||
| 191 | uuidv4, | 194 | uuidv4, |
| 192 | humanizedDateTime, | 195 | humanizedDateTime, |
| 193 | updateMessageBlock, | 196 | updateMessageBlock, |
| @@ -206,6 +209,7 @@ export function getContext() { | |||
| 206 | saveWorldInfo, | 209 | saveWorldInfo, |
| 207 | updateWorldInfoList, | 210 | updateWorldInfoList, |
| 208 | convertCharacterBook, | 211 | convertCharacterBook, |
| 212 | getWorldInfoPrompt, | ||
| 209 | CONNECT_API_MAP, | 213 | CONNECT_API_MAP, |
| 210 | getTextGenServer, | 214 | getTextGenServer, |
| 211 | extractMessageFromData, | 215 | extractMessageFromData, |
| @@ -215,6 +219,7 @@ export function getContext() { | |||
| 215 | clearChat, | 219 | clearChat, |
| 216 | ChatCompletionService, | 220 | ChatCompletionService, |
| 217 | TextCompletionService, | 221 | TextCompletionService, |
| 222 | ConnectionManagerRequestService, | ||
| 218 | updateReasoningUI, | 223 | updateReasoningUI, |
| 219 | parseReasoningFromString, | 224 | parseReasoningFromString, |
| 220 | unshallowCharacter, | 225 | unshallowCharacter, |
| @@ -13,7 +13,6 @@ import { | |||
| 13 | DEFAULT_PRINT_TIMEOUT, | 13 | DEFAULT_PRINT_TIMEOUT, |
| 14 | printCharacters, | 14 | printCharacters, |
| 15 | } from '../script.js'; | 15 | } from '../script.js'; |
| 16 | // eslint-disable-next-line no-unused-vars | ||
| 17 | import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js'; | 16 | import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js'; |
| 18 | 17 | ||
| 19 | import { groupCandidatesFilter, groups, selected_group } from './group-chats.js'; | 18 | import { groupCandidatesFilter, groups, selected_group } from './group-chats.js'; |
| @@ -1,9 +1,9 @@ | |||
| 1 | <div data-type="assistant_note"> | 1 | <div data-type="assistant_note"> |
| 2 | <div> | 2 | <div> |
| 3 | <b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span> | 3 | <b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span> |
| 4 | <span>Click the button to save it as a file.</span> | 4 | <span data-i18n="Click the button to save it as a file.">Click the button to save it as a file.</span> |
| 5 | </div> | 5 | </div> |
| 6 | <div class="assistant_note_export menu_button menu_button_icon" title="Export as JSONL"> | 6 | <div class="assistant_note_export menu_button menu_button_icon" data-i18n="[title]Export as JSONL" title="Export as JSONL"> |
| 7 | <i class="fa-solid fa-file-export"></i> | 7 | <i class="fa-solid fa-file-export"></i> |
| 8 | </div> | 8 | </div> |
| 9 | </div> | 9 | </div> |
| @@ -20,7 +20,8 @@ | |||
| 20 | <li><tt>{{summary}}</tt> β <span data-i18n="help_macros_summary">the latest chat summary generated by the "Summarize" extension (if available).</span></li> | 20 | <li><tt>{{summary}}</tt> β <span data-i18n="help_macros_summary">the latest chat summary generated by the "Summarize" extension (if available).</span></li> |
| 21 | <li><tt>{{user}}</tt> β <span data-i18n="help_macros_15">your current Persona username</span></li> | 21 | <li><tt>{{user}}</tt> β <span data-i18n="help_macros_15">your current Persona username</span></li> |
| 22 | <li><tt>{{char}}</tt> β <span data-i18n="help_macros_16">the Character's name</span></li> | 22 | <li><tt>{{char}}</tt> β <span data-i18n="help_macros_16">the Character's name</span></li> |
| 23 | <li><tt>{{char_version}}</tt> β <span data-i18n="help_macros_17">the Character's version number</span></li> | 23 | <li><tt>{{version}}</tt> β <span data-i18n="help_macros_17">the Character's version number</span></li> |
| 24 | <li><tt>{{charDepthPrompt}}</tt> β <span data-i18n="help_macros_charDepthPrompt">the Character's @ Depth Note</span></li> | ||
| 24 | <li><tt>{{group}}</tt> β <span data-i18n="help_macros_18">a comma-separated list of group member names (including muted) or the character name in solo chats. Alias: {{charIfNotGroup}}</span></li> | 25 | <li><tt>{{group}}</tt> β <span data-i18n="help_macros_18">a comma-separated list of group member names (including muted) or the character name in solo chats. Alias: {{charIfNotGroup}}</span></li> |
| 25 | <li><tt>{{groupNotMuted}}</tt> β <span data-i18n="help_groupNotMuted">the same as {{group}}, but excludes muted members</span></li> | 26 | <li><tt>{{groupNotMuted}}</tt> β <span data-i18n="help_groupNotMuted">the same as {{group}}, but excludes muted members</span></li> |
| 26 | <li><tt>{{model}}</tt> β <span data-i18n="help_macros_19">a text generation model name for the currently selected API. </span><b data-i18n="Can be inaccurate!">Can be inaccurate!</b></li> | 27 | <li><tt>{{model}}</tt> β <span data-i18n="help_macros_19">a text generation model name for the currently selected API. </span><b data-i18n="Can be inaccurate!">Can be inaccurate!</b></li> |
| @@ -0,0 +1,18 @@ | |||
| 1 | <div class="title_restorable flexFlowColumn alignItemsBaseline"> | ||
| 2 | <div class="flex-container justifyCenter"> | ||
| 3 | <h3 data-i18n="Sampler Select">Sampler Select</h3> | ||
| 4 | <div class="flex-container alignItemsBaseline"> | ||
| 5 | <div id="resetSelectedSamplers" class="menu_button menu_button_icon" data-i18n="[title]Reset custom sampler selection" title="Reset custom sampler selection"> | ||
| 6 | <i class="fa-solid fa-recycle"></i> | ||
| 7 | </div> | ||
| 8 | </div> | ||
| 9 | <!--<div class="flex-container alignItemsBaseline"> | ||
| 10 | <div class="menu_button menu_button_icon" title="Create a new sampler"> | ||
| 11 | <i class="fa-solid fa-plus"></i> | ||
| 12 | <span data-i18n="Create">Create</span> | ||
| 13 | </div> | ||
| 14 | </div>--> | ||
| 15 | </div> | ||
| 16 | <small data-i18n="Here you can toggle the display of individual samplers. (WIP)">Here you can toggle the display of individual samplers. (WIP)</small> | ||
| 17 | </div> | ||
| 18 | <hr> | ||
| \ No newline at end of file | 18 | \ No newline at end of file | |
| @@ -86,7 +86,7 @@ const OOBA_DEFAULT_ORDER = [ | |||
| 86 | 'encoder_repetition_penalty', | 86 | 'encoder_repetition_penalty', |
| 87 | 'no_repeat_ngram', | 87 | 'no_repeat_ngram', |
| 88 | ]; | 88 | ]; |
| 89 | const APHRODITE_DEFAULT_ORDER = [ | 89 | export const APHRODITE_DEFAULT_ORDER = [ |
| 90 | 'dry', | 90 | 'dry', |
| 91 | 'penalties', | 91 | 'penalties', |
| 92 | 'no_repeat_ngram', | 92 | 'no_repeat_ngram', |
| @@ -9,7 +9,7 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; | |||
| 9 | import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js'; | 9 | import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js'; |
| 10 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; | 10 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 11 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; | 11 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; |
| 12 | import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | 12 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 13 | import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; | 13 | import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; |
| 14 | import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; | 14 | import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; |
| 15 | import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js'; | 15 | import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js'; |
| @@ -583,7 +583,7 @@ export function evalBoolean(rule, a, b) { | |||
| 583 | * Executes a slash command from a string (may be enclosed in quotes) and returns the result. | 583 | * Executes a slash command from a string (may be enclosed in quotes) and returns the result. |
| 584 | * @param {string} command Command to execute. May contain escaped macro and batch separators. | 584 | * @param {string} command Command to execute. May contain escaped macro and batch separators. |
| 585 | * @param {SlashCommandScope} [scope] The scope to use. | 585 | * @param {SlashCommandScope} [scope] The scope to use. |
| 586 | * @param {{[id:PARSER_FLAG]:boolean}} [parserFlags] The parser flags to use. | 586 | * @param {import('./slash-commands/SlashCommandParser.js').ParserFlags} [parserFlags] The parser flags to use. |
| 587 | * @param {SlashCommandAbortController} [abortController] The abort controller to use. | 587 | * @param {SlashCommandAbortController} [abortController] The abort controller to use. |
| 588 | * @returns {Promise<SlashCommandClosureResult>} Closure execution result | 588 | * @returns {Promise<SlashCommandClosureResult>} Closure execution result |
| 589 | */ | 589 | */ |
| @@ -1,6 +1,6 @@ | |||
| 1 | import { Fuse } from '../lib.js'; | 1 | import { Fuse } from '../lib.js'; |
| 2 | 2 | ||
| 3 | import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js'; | 3 | import { saveSettings, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js'; |
| 4 | import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, getSanitizedFilename, checkOverwriteExistingData, getStringHash, parseStringArray, cancelDebounce, findChar, onlyUnique } from './utils.js'; | 4 | import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, select2ModifyOptions, getSelect2OptionId, dynamicSelect2DataViaAjax, highlightRegex, select2ChoiceClickSubscribe, isFalseBoolean, getSanitizedFilename, checkOverwriteExistingData, getStringHash, parseStringArray, cancelDebounce, findChar, onlyUnique } from './utils.js'; |
| 5 | import { extension_settings, getContext } from './extensions.js'; | 5 | import { extension_settings, getContext } from './extensions.js'; |
| 6 | import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js'; | 6 | import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js'; |
| @@ -753,10 +753,17 @@ export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOn | |||
| 753 | 753 | ||
| 754 | /** | 754 | /** |
| 755 | * Gets the world info based on chat messages. | 755 | * Gets the world info based on chat messages. |
| 756 | * @param {string[]} chat The chat messages to scan, in reverse order. | 756 | * @param {string[]} chat - The chat messages to scan, in reverse order. |
| 757 | * @param {number} maxContext The maximum context size of the generation. | 757 | * @param {number} maxContext - The maximum context size of the generation. |
| 758 | * @param {boolean} isDryRun If true, the function will not emit any events. | 758 | * @param {boolean} isDryRun - If true, the function will not emit any events. |
| 759 | * @typedef {{worldInfoString: string, worldInfoBefore: string, worldInfoAfter: string, worldInfoExamples: any[], worldInfoDepth: any[]}} WIPromptResult | 759 | * @typedef {object} WIPromptResult |
| 760 | * @property {string} worldInfoString - Complete world info string | ||
| 761 | * @property {string} worldInfoBefore - World info that goes before the prompt | ||
| 762 | * @property {string} worldInfoAfter - World info that goes after the prompt | ||
| 763 | * @property {Array} worldInfoExamples - Array of example entries | ||
| 764 | * @property {Array} worldInfoDepth - Array of depth entries | ||
| 765 | * @property {Array} anBefore - Array of entries before Author's Note | ||
| 766 | * @property {Array} anAfter - Array of entries after Author's Note | ||
| 760 | * @returns {Promise<WIPromptResult>} The world info string and depth. | 767 | * @returns {Promise<WIPromptResult>} The world info string and depth. |
| 761 | */ | 768 | */ |
| 762 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { | 769 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { |
| @@ -778,6 +785,8 @@ export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { | |||
| 778 | worldInfoAfter, | 785 | worldInfoAfter, |
| 779 | worldInfoExamples: activatedWorldInfo.EMEntries ?? [], | 786 | worldInfoExamples: activatedWorldInfo.EMEntries ?? [], |
| 780 | worldInfoDepth: activatedWorldInfo.WIDepthEntries ?? [], | 787 | worldInfoDepth: activatedWorldInfo.WIDepthEntries ?? [], |
| 788 | anBefore: activatedWorldInfo.ANBeforeEntries ?? [], | ||
| 789 | anAfter: activatedWorldInfo.ANAfterEntries ?? [], | ||
| 781 | }; | 790 | }; |
| 782 | } | 791 | } |
| 783 | 792 | ||
| @@ -3862,7 +3871,14 @@ function parseDecorators(content) { | |||
| 3862 | * @param {string[]} chat The chat messages to scan, in reverse order. | 3871 | * @param {string[]} chat The chat messages to scan, in reverse order. |
| 3863 | * @param {number} maxContext The maximum context size of the generation. | 3872 | * @param {number} maxContext The maximum context size of the generation. |
| 3864 | * @param {boolean} isDryRun Whether to perform a dry run. | 3873 | * @param {boolean} isDryRun Whether to perform a dry run. |
| 3865 | * @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated | 3874 | * @typedef {object} WIActivated |
| 3875 | * @property {string} worldInfoBefore The world info before the chat. | ||
| 3876 | * @property {string} worldInfoAfter The world info after the chat. | ||
| 3877 | * @property {any[]} EMEntries The entries for examples. | ||
| 3878 | * @property {any[]} WIDepthEntries The depth entries. | ||
| 3879 | * @property {any[]} ANBeforeEntries The entries before Author's Note. | ||
| 3880 | * @property {any[]} ANAfterEntries The entries after Author's Note. | ||
| 3881 | * @property {Set<any>} allActivatedEntries All entries. | ||
| 3866 | * @returns {Promise<WIActivated>} The world info activated. | 3882 | * @returns {Promise<WIActivated>} The world info activated. |
| 3867 | */ | 3883 | */ |
| 3868 | export async function checkWorldInfo(chat, maxContext, isDryRun) { | 3884 | export async function checkWorldInfo(chat, maxContext, isDryRun) { |
| @@ -3906,7 +3922,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 3906 | timedEffects.checkTimedEffects(); | 3922 | timedEffects.checkTimedEffects(); |
| 3907 | 3923 | ||
| 3908 | if (sortedEntries.length === 0) { | 3924 | if (sortedEntries.length === 0) { |
| 3909 | return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], EMEntries: [], allActivatedEntries: new Set() }; | 3925 | return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], EMEntries: [], ANBeforeEntries: [], ANAfterEntries: [], allActivatedEntries: new Set() }; |
| 3910 | } | 3926 | } |
| 3911 | 3927 | ||
| 3912 | /** @type {number[]} Represents the delay levels for entries that are delayed until recursion */ | 3928 | /** @type {number[]} Represents the delay levels for entries that are delayed until recursion */ |
| @@ -4355,7 +4371,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | |||
| 4355 | console.log(`[WI] ${isDryRun ? 'Hypothetically adding' : 'Adding'} ${allActivatedEntries.size} entries to prompt`, Array.from(allActivatedEntries.values())); | 4371 | console.log(`[WI] ${isDryRun ? 'Hypothetically adding' : 'Adding'} ${allActivatedEntries.size} entries to prompt`, Array.from(allActivatedEntries.values())); |
| 4356 | console.debug(`[WI] --- DONE${isDryRun ? ' (DRY RUN)' : ''} ---`); | 4372 | console.debug(`[WI] --- DONE${isDryRun ? ' (DRY RUN)' : ''} ---`); |
| 4357 | 4373 | ||
| 4358 | return { worldInfoBefore, worldInfoAfter, EMEntries, WIDepthEntries, allActivatedEntries: new Set(allActivatedEntries.values()) }; | 4374 | return { worldInfoBefore, worldInfoAfter, EMEntries, WIDepthEntries, ANBeforeEntries: ANTopEntries, ANAfterEntries: ANBottomEntries, allActivatedEntries: new Set(allActivatedEntries.values()) }; |
| 4359 | } | 4375 | } |
| 4360 | 4376 | ||
| 4361 | /** | 4377 | /** |
| @@ -43,6 +43,7 @@ export const USER_DIRECTORY_TEMPLATE = Object.freeze({ | |||
| 43 | vectors: 'vectors', | 43 | vectors: 'vectors', |
| 44 | backups: 'backups', | 44 | backups: 'backups', |
| 45 | sysprompt: 'sysprompt', | 45 | sysprompt: 'sysprompt', |
| 46 | reasoning: 'reasoning', | ||
| 46 | }); | 47 | }); |
| 47 | 48 | ||
| 48 | /** | 49 | /** |
| @@ -49,7 +49,7 @@ const API_COHERE_V2 = 'https://api.cohere.ai/v2'; | |||
| 49 | const API_PERPLEXITY = 'https://api.perplexity.ai'; | 49 | const API_PERPLEXITY = 'https://api.perplexity.ai'; |
| 50 | const API_GROQ = 'https://api.groq.com/openai/v1'; | 50 | const API_GROQ = 'https://api.groq.com/openai/v1'; |
| 51 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; | 51 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; |
| 52 | const API_01AI = 'https://api.01.ai/v1'; | 52 | const API_01AI = 'https://api.lingyiwanwu.com/v1'; |
| 53 | const API_BLOCKENTROPY = 'https://api.blockentropy.ai/v1'; | 53 | const API_BLOCKENTROPY = 'https://api.blockentropy.ai/v1'; |
| 54 | const API_AI21 = 'https://api.ai21.com/studio/v1'; | 54 | const API_AI21 = 'https://api.ai21.com/studio/v1'; |
| 55 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; | 55 | const API_NANOGPT = 'https://nano-gpt.com/api/v1'; |
| @@ -1048,6 +1048,15 @@ router.post('/generate', function (request, response) { | |||
| 1048 | let bodyParams; | 1048 | let bodyParams; |
| 1049 | const isTextCompletion = Boolean(request.body.model && TEXT_COMPLETION_MODELS.includes(request.body.model)) || typeof request.body.messages === 'string'; | 1049 | const isTextCompletion = Boolean(request.body.model && TEXT_COMPLETION_MODELS.includes(request.body.model)) || typeof request.body.messages === 'string'; |
| 1050 | 1050 | ||
| 1051 | const postProcessTypes = [CHAT_COMPLETION_SOURCES.CUSTOM, CHAT_COMPLETION_SOURCES.OPENROUTER]; | ||
| 1052 | if (Array.isArray(request.body.messages) && postProcessTypes.includes(request.body.chat_completion_source) && request.body.custom_prompt_post_processing) { | ||
| 1053 | console.info('Applying custom prompt post-processing of type', request.body.custom_prompt_post_processing); | ||
| 1054 | request.body.messages = postProcessPrompt( | ||
| 1055 | request.body.messages, | ||
| 1056 | request.body.custom_prompt_post_processing, | ||
| 1057 | getPromptNames(request)); | ||
| 1058 | } | ||
| 1059 | |||
| 1051 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { | 1060 | if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.OPENAI) { |
| 1052 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); | 1061 | apiUrl = new URL(request.body.reverse_proxy || API_OPENAI).toString(); |
| 1053 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI); | 1062 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.OPENAI); |
| @@ -1121,14 +1130,6 @@ router.post('/generate', function (request, response) { | |||
| 1121 | 1130 | ||
| 1122 | mergeObjectWithYaml(bodyParams, request.body.custom_include_body); | 1131 | mergeObjectWithYaml(bodyParams, request.body.custom_include_body); |
| 1123 | mergeObjectWithYaml(headers, request.body.custom_include_headers); | 1132 | mergeObjectWithYaml(headers, request.body.custom_include_headers); |
| 1124 | |||
| 1125 | if (request.body.custom_prompt_post_processing) { | ||
| 1126 | console.info('Applying custom prompt post-processing of type', request.body.custom_prompt_post_processing); | ||
| 1127 | request.body.messages = postProcessPrompt( | ||
| 1128 | request.body.messages, | ||
| 1129 | request.body.custom_prompt_post_processing, | ||
| 1130 | getPromptNames(request)); | ||
| 1131 | } | ||
| 1132 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.PERPLEXITY) { | 1133 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.PERPLEXITY) { |
| 1133 | apiUrl = API_PERPLEXITY; | 1134 | apiUrl = API_PERPLEXITY; |
| 1134 | apiKey = readSecret(request.user.directories, SECRET_KEYS.PERPLEXITY); | 1135 | apiKey = readSecret(request.user.directories, SECRET_KEYS.PERPLEXITY); |
| @@ -21,6 +21,7 @@ import { | |||
| 21 | const isBackupEnabled = !!getConfigValue('backups.chat.enabled', true, 'boolean'); | 21 | const isBackupEnabled = !!getConfigValue('backups.chat.enabled', true, 'boolean'); |
| 22 | const maxTotalChatBackups = Number(getConfigValue('backups.chat.maxTotalBackups', -1, 'number')); | 22 | const maxTotalChatBackups = Number(getConfigValue('backups.chat.maxTotalBackups', -1, 'number')); |
| 23 | const throttleInterval = Number(getConfigValue('backups.chat.throttleInterval', 10_000, 'number')); | 23 | const throttleInterval = Number(getConfigValue('backups.chat.throttleInterval', 10_000, 'number')); |
| 24 | const checkIntegrity = !!getConfigValue('backups.chat.checkIntegrity', true, 'boolean'); | ||
| 24 | 25 | ||
| 25 | /** | 26 | /** |
| 26 | * Saves a chat to the backups directory. | 27 | * Saves a chat to the backups directory. |
| @@ -292,15 +293,81 @@ function importRisuChat(userName, characterName, jsonData) { | |||
| 292 | return chat.map(obj => JSON.stringify(obj)).join('\n'); | 293 | return chat.map(obj => JSON.stringify(obj)).join('\n'); |
| 293 | } | 294 | } |
| 294 | 295 | ||
| 296 | /** | ||
| 297 | * Reads the first line of a file asynchronously. | ||
| 298 | * @param {string} filePath Path to the file | ||
| 299 | * @returns {Promise<string>} The first line of the file | ||
| 300 | */ | ||
| 301 | function readFirstLine(filePath) { | ||
| 302 | const stream = fs.createReadStream(filePath, { encoding: 'utf8' }); | ||
| 303 | const rl = readline.createInterface({ input: stream }); | ||
| 304 | return new Promise((resolve, reject) => { | ||
| 305 | let resolved = false; | ||
| 306 | rl.on('line', line => { | ||
| 307 | resolved = true; | ||
| 308 | rl.close(); | ||
| 309 | stream.close(); | ||
| 310 | resolve(line); | ||
| 311 | }); | ||
| 312 | |||
| 313 | rl.on('error', error => { | ||
| 314 | resolved = true; | ||
| 315 | reject(error); | ||
| 316 | }); | ||
| 317 | |||
| 318 | // Handle empty files | ||
| 319 | stream.on('end', () => { | ||
| 320 | if (!resolved) { | ||
| 321 | resolved = true; | ||
| 322 | resolve(''); | ||
| 323 | } | ||
| 324 | }); | ||
| 325 | }); | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * Checks if the chat being saved has the same integrity as the one being loaded. | ||
| 330 | * @param {string} filePath Path to the chat file | ||
| 331 | * @param {string} integritySlug Integrity slug | ||
| 332 | * @returns {Promise<boolean>} Whether the chat is intact | ||
| 333 | */ | ||
| 334 | async function checkChatIntegrity(filePath, integritySlug) { | ||
| 335 | // If the chat file doesn't exist, assume it's intact | ||
| 336 | if (!fs.existsSync(filePath)) { | ||
| 337 | return true; | ||
| 338 | } | ||
| 339 | |||
| 340 | // Parse the first line of the chat file as JSON | ||
| 341 | const firstLine = await readFirstLine(filePath); | ||
| 342 | const jsonData = tryParse(firstLine); | ||
| 343 | const chatIntegrity = jsonData?.chat_metadata?.integrity; | ||
| 344 | |||
| 345 | // If the chat has no integrity metadata, assume it's intact | ||
| 346 | if (!chatIntegrity) { | ||
| 347 | return true; | ||
| 348 | } | ||
| 349 | |||
| 350 | // Check if the integrity matches | ||
| 351 | return chatIntegrity === integritySlug; | ||
| 352 | } | ||
| 353 | |||
| 295 | export const router = express.Router(); | 354 | export const router = express.Router(); |
| 296 | 355 | ||
| 297 | router.post('/save', validateAvatarUrlMiddleware, function (request, response) { | 356 | router.post('/save', validateAvatarUrlMiddleware, async function (request, response) { |
| 298 | try { | 357 | try { |
| 299 | const directoryName = String(request.body.avatar_url).replace('.png', ''); | 358 | const directoryName = String(request.body.avatar_url).replace('.png', ''); |
| 300 | const chatData = request.body.chat; | 359 | const chatData = request.body.chat; |
| 301 | const jsonlData = chatData.map(JSON.stringify).join('\n'); | 360 | const jsonlData = chatData.map(JSON.stringify).join('\n'); |
| 302 | const fileName = `${String(request.body.file_name)}.jsonl`; | 361 | const fileName = `${String(request.body.file_name)}.jsonl`; |
| 303 | const filePath = path.join(request.user.directories.chats, directoryName, sanitize(fileName)); | 362 | const filePath = path.join(request.user.directories.chats, directoryName, sanitize(fileName)); |
| 363 | if (checkIntegrity && !request.body.force) { | ||
| 364 | const integritySlug = chatData?.[0]?.chat_metadata?.integrity; | ||
| 365 | const isIntact = await checkChatIntegrity(filePath, integritySlug); | ||
| 366 | if (!isIntact) { | ||
| 367 | console.error(`Chat integrity check failed for ${filePath}`); | ||
| 368 | return response.status(400).send({ error: 'integrity' }); | ||
| 369 | } | ||
| 370 | } | ||
| 304 | writeFileAtomicSync(filePath, jsonlData, 'utf8'); | 371 | writeFileAtomicSync(filePath, jsonlData, 'utf8'); |
| 305 | getBackupFunction(request.user.profile.handle)(request.user.directories.backups, directoryName, jsonlData); | 372 | getBackupFunction(request.user.profile.handle)(request.user.directories.backups, directoryName, jsonlData); |
| 306 | return response.send({ result: 'ok' }); | 373 | return response.send({ result: 'ok' }); |
| @@ -716,12 +783,11 @@ router.post('/search', validateAvatarUrlMiddleware, function (request, response) | |||
| 716 | continue; | 783 | continue; |
| 717 | } | 784 | } |
| 718 | 785 | ||
| 719 | // Search through messages | 786 | // Search through title and messages of the chat |
| 720 | const fragments = query.trim().toLowerCase().split(/\s+/).filter(x => x); | 787 | const fragments = query.trim().toLowerCase().split(/\s+/).filter(x => x); |
| 721 | const hasMatch = messages.some(message => { | 788 | const text = [path.parse(chatFile.path).name, |
| 722 | const text = message?.mes?.toLowerCase(); | 789 | ...messages.map(message => message?.mes)].join('\n').toLowerCase(); |
| 723 | return text && fragments.every(fragment => text.includes(fragment)); | 790 | const hasMatch = fragments.every(fragment => text.includes(fragment)); |
| 724 | }); | ||
| 725 | 791 | ||
| 726 | if (hasMatch) { | 792 | if (hasMatch) { |
| 727 | results.push({ | 793 | results.push({ |
| @@ -48,6 +48,7 @@ export const CONTENT_TYPES = { | |||
| 48 | MOVING_UI: 'moving_ui', | 48 | MOVING_UI: 'moving_ui', |
| 49 | QUICK_REPLIES: 'quick_replies', | 49 | QUICK_REPLIES: 'quick_replies', |
| 50 | SYSPROMPT: 'sysprompt', | 50 | SYSPROMPT: 'sysprompt', |
| 51 | REASONING: 'reasoning', | ||
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | /** | 54 | /** |
| @@ -61,7 +62,7 @@ export function getDefaultPresets(directories) { | |||
| 61 | const presets = []; | 62 | const presets = []; |
| 62 | 63 | ||
| 63 | for (const contentItem of contentIndex) { | 64 | for (const contentItem of contentIndex) { |
| 64 | if (contentItem.type.endsWith('_preset') || contentItem.type === 'instruct' || contentItem.type === 'context' || contentItem.type === 'sysprompt') { | 65 | if (contentItem.type.endsWith('_preset') || ['instruct', 'context', 'sysprompt', 'reasoning'].includes(contentItem.type)) { |
| 65 | contentItem.name = path.parse(contentItem.filename).name; | 66 | contentItem.name = path.parse(contentItem.filename).name; |
| 66 | contentItem.folder = getTargetByType(contentItem.type, directories); | 67 | contentItem.folder = getTargetByType(contentItem.type, directories); |
| 67 | presets.push(contentItem); | 68 | presets.push(contentItem); |
| @@ -299,6 +300,8 @@ function getTargetByType(type, directories) { | |||
| 299 | return directories.quickreplies; | 300 | return directories.quickreplies; |
| 300 | case CONTENT_TYPES.SYSPROMPT: | 301 | case CONTENT_TYPES.SYSPROMPT: |
| 301 | return directories.sysprompt; | 302 | return directories.sysprompt; |
| 303 | case CONTENT_TYPES.REASONING: | ||
| 304 | return directories.reasoning; | ||
| 302 | default: | 305 | default: |
| 303 | return null; | 306 | return null; |
| 304 | } | 307 | } |
| @@ -116,7 +116,7 @@ router.post('/caption-image', async (request, response) => { | |||
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | if (request.body.api === 'zerooneai') { | 118 | if (request.body.api === 'zerooneai') { |
| 119 | apiUrl = 'https://api.01.ai/v1/chat/completions'; | 119 | apiUrl = 'https://api.lingyiwanwu.com/v1/chat/completions'; |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | if (request.body.api === 'groq') { | 122 | if (request.body.api === 'groq') { |
| @@ -30,6 +30,8 @@ function getPresetSettingsByAPI(apiId, directories) { | |||
| 30 | return { folder: directories.context, extension: '.json' }; | 30 | return { folder: directories.context, extension: '.json' }; |
| 31 | case 'sysprompt': | 31 | case 'sysprompt': |
| 32 | return { folder: directories.sysprompt, extension: '.json' }; | 32 | return { folder: directories.sysprompt, extension: '.json' }; |
| 33 | case 'reasoning': | ||
| 34 | return { folder: directories.reasoning, extension: '.json' }; | ||
| 33 | default: | 35 | default: |
| 34 | return { folder: null, extension: null }; | 36 | return { folder: null, extension: null }; |
| 35 | } | 37 | } |
| @@ -254,6 +254,7 @@ router.post('/get', (request, response) => { | |||
| 254 | const instruct = readAndParseFromDirectory(request.user.directories.instruct); | 254 | const instruct = readAndParseFromDirectory(request.user.directories.instruct); |
| 255 | const context = readAndParseFromDirectory(request.user.directories.context); | 255 | const context = readAndParseFromDirectory(request.user.directories.context); |
| 256 | const sysprompt = readAndParseFromDirectory(request.user.directories.sysprompt); | 256 | const sysprompt = readAndParseFromDirectory(request.user.directories.sysprompt); |
| 257 | const reasoning = readAndParseFromDirectory(request.user.directories.reasoning); | ||
| 257 | 258 | ||
| 258 | response.send({ | 259 | response.send({ |
| 259 | settings, | 260 | settings, |
| @@ -272,6 +273,7 @@ router.post('/get', (request, response) => { | |||
| 272 | instruct, | 273 | instruct, |
| 273 | context, | 274 | context, |
| 274 | sysprompt, | 275 | sysprompt, |
| 276 | reasoning, | ||
| 275 | enable_extensions: ENABLE_EXTENSIONS, | 277 | enable_extensions: ENABLE_EXTENSIONS, |
| 276 | enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE, | 278 | enable_extensions_auto_update: ENABLE_EXTENSIONS_AUTO_UPDATE, |
| 277 | enable_accounts: ENABLE_ACCOUNTS, | 279 | enable_accounts: ENABLE_ACCOUNTS, |
| @@ -411,7 +411,7 @@ export function getTokenizerModel(requestModel) { | |||
| 411 | return 'gpt-4o'; | 411 | return 'gpt-4o'; |
| 412 | } | 412 | } |
| 413 | 413 | ||
| 414 | if (requestModel.includes('gpt-4.5-preview')) { | 414 | if (requestModel.includes('gpt-4.5')) { |
| 415 | return 'gpt-4o'; | 415 | return 'gpt-4o'; |
| 416 | } | 416 | } |
| 417 | 417 | ||
| @@ -95,6 +95,7 @@ const STORAGE_KEYS = { | |||
| 95 | * @property {string} vectors - The directory where the vectors are stored | 95 | * @property {string} vectors - The directory where the vectors are stored |
| 96 | * @property {string} backups - The directory where the backups are stored | 96 | * @property {string} backups - The directory where the backups are stored |
| 97 | * @property {string} sysprompt - The directory where the system prompt data is stored | 97 | * @property {string} sysprompt - The directory where the system prompt data is stored |
| 98 | * @property {string} reasoning - The directory where the reasoning templates are stored | ||
| 98 | */ | 99 | */ |
| 99 | 100 | ||
| 100 | /** | 101 | /** |