Merge pull request #3891 from SillyTavern/staging Staging
Signed| @@ -3,6 +3,9 @@ module.exports = { | ||
| 3 | 3 | extends: [ |
| 4 | 4 | 'eslint:recommended', |
| 5 | 5 | ], |
| 6 | + plugins: [ | |
| 7 | + 'jsdoc', | |
| 8 | + ], | |
| 6 | 9 | env: { |
| 7 | 10 | es6: true, |
| 8 | 11 | }, |
| @@ -78,6 +81,7 @@ module.exports = { | ||
| 78 | 81 | 'public/scripts/extensions/tts/lib/**', |
| 79 | 82 | ], |
| 80 | 83 | rules: { |
| 84 | + 'jsdoc/no-undefined-types': ['warn', { disableReporting: true, markVariablesAsUsed: true }], | |
| 81 | 85 | 'no-unused-vars': ['error', { args: 'none' }], |
| 82 | 86 | 'no-control-regex': 'off', |
| 83 | 87 | 'no-constant-condition': ['error', { checkLoops: false }], |
| @@ -14,7 +14,7 @@ | ||
| 14 | 14 | - '(🐧 Linux)' |
| 15 | 15 | |
| 16 | 16 | 🦊 Firefox: |
| 17 | 17 | - '\b(firefox|mozilla)\b' |
| 18 | 18 | |
| 19 | 19 | 📱 Mobile: |
| 20 | 20 | - '\b(iphone|ios|android|📱 Termux)\b' |
| @@ -34,6 +34,9 @@ | ||
| 34 | 34 | 🦊 Firefox: |
| 35 | 35 | - head-branch: ['\bfirefox\b'] |
| 36 | 36 | |
| 37 | +🧑🤝🧑 Group Chat: | |
| 38 | +- head-branch: ['\bgroups?\b'] | |
| 39 | + | |
| 37 | 40 | 🖼️ Image Gen: |
| 38 | 41 | - head-branch: ['\bimage-gen\b'] |
| 39 | 42 | |
| @@ -58,6 +61,9 @@ | ||
| 58 | 61 | 📜 Prompt: |
| 59 | 62 | - head-branch: ['\bprompt\b'] |
| 60 | 63 | |
| 64 | +🧠 Reasoning: | |
| 65 | +- head-branch: ['\breasoning\b', '\breason\b', '\bthinking\b'] | |
| 66 | + | |
| 61 | 67 | 🚚 Refactor: |
| 62 | 68 | - head-branch: ['\brefactor(s|ed)?\b'] |
| 63 | 69 | |
| @@ -32,7 +32,7 @@ jobs: | ||
| 32 | 32 | with: |
| 33 | 33 | configuration-path: .github/issues-auto-labels.yml |
| 34 | 34 | enable-versioned-regex: 0 |
| 35 | 35 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 36 | 36 | |
| 37 | 37 | label-on-labels: |
| 38 | 38 | name: 🏷️ Label Issues by Labels |
| @@ -46,7 +46,7 @@ jobs: | ||
| 46 | 46 | uses: actions-cool/issues-helper@v3.6.0 |
| 47 | 47 | with: |
| 48 | 48 | actions: 'add-labels' |
| 49 | 49 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 50 | 50 | labels: '👍 Approved' |
| 51 | 51 | |
| 52 | 52 | - name: ❌ Remove progress labels when issue is marked done or stale |
| @@ -56,7 +56,7 @@ jobs: | ||
| 56 | 56 | uses: actions-cool/issues-helper@v3.6.0 |
| 57 | 57 | with: |
| 58 | 58 | actions: 'remove-labels' |
| 59 | 59 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 60 | 60 | labels: '🧑💻 In Progress,🤔 Unsure,🤔 Under Consideration' |
| 61 | 61 | |
| 62 | 62 | - name: ❌ Remove temporary labels when confirmed labels are added |
| @@ -66,7 +66,7 @@ jobs: | ||
| 66 | 66 | uses: actions-cool/issues-helper@v3.6.0 |
| 67 | 67 | with: |
| 68 | 68 | actions: 'remove-labels' |
| 69 | 69 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 70 | 70 | labels: '🤔 Unsure,🤔 Under Consideration' |
| 71 | 71 | |
| 72 | 72 | - name: ❌ Remove no bug labels when "🪲 Confirmed" is added |
| @@ -76,7 +76,7 @@ jobs: | ||
| 76 | 76 | uses: actions-cool/issues-helper@v3.6.0 |
| 77 | 77 | with: |
| 78 | 78 | actions: 'remove-labels' |
| 79 | 79 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 80 | 80 | labels: '✖️ Not Reproducible,✖️ Not A Bug' |
| 81 | 81 | |
| 82 | 82 | remove-stale-label: |
| @@ -92,7 +92,7 @@ jobs: | ||
| 92 | 92 | uses: actions-cool/issues-helper@v3.6.0 |
| 93 | 93 | with: |
| 94 | 94 | actions: 'remove-labels' |
| 95 | 95 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 96 | 96 | issue-number: ${{ github.event.issue.number }} |
| 97 | 97 | labels: '⚰️ Stale,🕸️ Inactive,🚏 Awaiting User Response,🛑 No Response' |
| 98 | 98 | |
| @@ -113,4 +113,4 @@ jobs: | ||
| 113 | 113 | uses: peaceiris/actions-label-commenter@v1.10.0 |
| 114 | 114 | with: |
| 115 | 115 | config_file: .github/issues-auto-comments.yml |
| 116 | 116 | github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| @@ -31,15 +31,15 @@ jobs: | ||
| 31 | 31 | - name: Label Linked Issues |
| 32 | 32 | id: label_linked_issues |
| 33 | 33 | env: |
| 34 | 34 | GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 35 | 35 | run: | |
| 36 | 36 | for ISSUE in $(echo $issues | jq -r '.[]'); do |
| 37 | 37 | if [ "${{ github.ref }}" == "refs/heads/staging" ]; then |
| 38 | 38 | LABEL="✅ Done (staging)" |
| 39 | 39 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" --remove-label "🧑💻 In Progress" |
| 40 | 40 | elif [ "${{ github.ref }}" == "refs/heads/release" ]; then |
| 41 | 41 | LABEL="✅ Done" |
| 42 | 42 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "$LABEL" --remove-label "🧑💻 In Progress" |
| 43 | 43 | fi |
| 44 | 44 | echo "Added label '$LABEL' to(and removed '🧑💻 In Progress' if present) in issue #$ISSUE" |
| 45 | 45 | done |
| @@ -22,7 +22,7 @@ jobs: | ||
| 22 | 22 | # https://github.com/marketplace/actions/close-stale-issues |
| 23 | 23 | uses: actions/stale@v9.1.0 |
| 24 | 24 | with: |
| 25 | 25 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 26 | 26 | days-before-stale: 183 |
| 27 | 27 | days-before-close: 7 |
| 28 | 28 | operations-per-run: 30 |
| @@ -56,7 +56,7 @@ jobs: | ||
| 56 | 56 | # https://github.com/marketplace/actions/close-stale-issues |
| 57 | 57 | uses: actions/stale@v9.1.0 |
| 58 | 58 | with: |
| 59 | 59 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 60 | 60 | days-before-stale: 7 |
| 61 | 61 | days-before-close: 7 |
| 62 | 62 | operations-per-run: 30 |
| @@ -83,7 +83,7 @@ jobs: | ||
| 83 | 83 | # https://github.com/marketplace/actions/close-stale-issues |
| 84 | 84 | uses: actions/stale@v9.1.0 |
| 85 | 85 | with: |
| 86 | 86 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 87 | 87 | days-before-stale: 7 |
| 88 | 88 | days-before-close: 7 |
| 89 | 89 | operations-per-run: 30 |
| @@ -23,6 +23,6 @@ jobs: | ||
| 23 | 23 | uses: actions-cool/issues-helper@v3.6.0 |
| 24 | 24 | with: |
| 25 | 25 | actions: remove-labels |
| 26 | 26 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 27 | 27 | issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} |
| 28 | 28 | labels: '🚏 Awaiting User Response,🧑💻 In Progress,📌 Keep Open,🚫 Merge Conflicts,🔬 Needs Testing,🔨 Needs Work,⚰️ Stale,⛔ Waiting For External/Upstream' |
| @@ -24,6 +24,6 @@ jobs: | ||
| 24 | 24 | uses: actions-cool/issues-helper@v3.6.0 |
| 25 | 25 | with: |
| 26 | 26 | actions: 'add-labels' |
| 27 | 27 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 28 | 28 | issue-number: ${{ github.event.issue.number || github.event.pull_request.number }} |
| 29 | 29 | labels: '👷 Maintainer' |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | name: 🔀 Pull Request Manager |
| 2 | 2 | |
| 3 | 3 | on: |
| 4 | + workflow_dispatch: # Allow to manually call this workflow | |
| 4 | 5 | pull_request_target: |
| 5 | 6 | types: [opened, synchronize, reopened, edited, labeled, unlabeled, closed] |
| 6 | 7 | pull_request_review_comment: |
| @@ -11,9 +12,63 @@ permissions: | ||
| 11 | 12 | pull-requests: write |
| 12 | 13 | |
| 13 | 14 | jobs: |
| 15 | + run-eslint: | |
| 16 | + name: ✅ Check ESLint on PR | |
| 17 | + runs-on: ubuntu-latest | |
| 18 | + # Only needs to run when code is changed | |
| 19 | + if: github.event.action == 'opened' || github.event.action == 'synchronize' | |
| 20 | + | |
| 21 | + # Override permissions, linter likely needs write access to issues | |
| 22 | + permissions: | |
| 23 | + contents: read | |
| 24 | + issues: write | |
| 25 | + pull-requests: write | |
| 26 | + | |
| 27 | + steps: | |
| 28 | + - name: Checkout Repository | |
| 29 | + # Checkout | |
| 30 | + # https://github.com/marketplace/actions/checkout | |
| 31 | + uses: actions/checkout@v4.2.2 | |
| 32 | + with: | |
| 33 | + ref: ${{ github.event.pull_request.head.sha }} | |
| 34 | + repository: ${{ github.event.pull_request.head.repo.full_name }} | |
| 35 | + | |
| 36 | + - name: Setup Node.js | |
| 37 | + # Setup Node.js environment | |
| 38 | + # https://github.com/marketplace/actions/setup-node-js-environment | |
| 39 | + uses: actions/setup-node@v4.3.0 | |
| 40 | + with: | |
| 41 | + node-version: 20 | |
| 42 | + | |
| 43 | + - name: Run npm install | |
| 44 | + run: npm ci | |
| 45 | + | |
| 46 | + - name: Run ESLint | |
| 47 | + # Action ESLint | |
| 48 | + # https://github.com/marketplace/actions/action-eslint | |
| 49 | + uses: sibiraj-s/action-eslint@v3.0.1 | |
| 50 | + with: | |
| 51 | + token: ${{ secrets.GITHUB_TOKEN }} | |
| 52 | + eslint-args: '--ignore-path=.gitignore --quiet' | |
| 53 | + extensions: 'js' | |
| 54 | + annotations: true | |
| 55 | + ignore-patterns: | | |
| 56 | + dist/ | |
| 57 | + lib/ | |
| 58 | + | |
| 14 | 59 | label-by-size: |
| 15 | 60 | name: 🏷️ Label PR by Size |
| 61 | + # This job should run after all others, to prevent possible concurrency issues | |
| 62 | + needs: [label-by-branches, label-by-files, remove-stale-label, check-merge-blocking-labels, write-auto-comments] | |
| 16 | 63 | runs-on: ubuntu-latest |
| 64 | + # Only needs to run when code is changed | |
| 65 | + if: always() && (github.event.action == 'opened' || github.event.action == 'synchronize') | |
| 66 | + | |
| 67 | + # Override permissions, the labeler needs issues write access | |
| 68 | + permissions: | |
| 69 | + contents: read | |
| 70 | + issues: write | |
| 71 | + pull-requests: write | |
| 17 | 72 | |
| 18 | 73 | steps: |
| 19 | 74 | - name: Label PR Size |
| @@ -21,7 +76,7 @@ jobs: | ||
| 21 | 76 | # https://github.com/marketplace/actions/pull-request-size-labeler |
| 22 | 77 | uses: codelytv/pr-size-labeler@v1.10.2 |
| 23 | 78 | with: |
| 24 | 79 | GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 25 | 80 | xs_label: '🟩 ⬤○○○○' |
| 26 | 81 | xs_max_size: '20' |
| 27 | 82 | s_label: '🟩 ⬤⬤○○○' |
| @@ -32,20 +87,15 @@ jobs: | ||
| 32 | 87 | l_max_size: '1000' |
| 33 | 88 | xl_label: '🟥 ⬤⬤⬤⬤⬤' |
| 34 | 89 | fail_if_xl: 'false' |
| 35 | - github_api_url: 'https://api.github.com' | |
| 36 | 90 | files_to_ignore: | |
| 37 | 91 | "package-lock.json" |
| 38 | 92 | "public/lib/*" |
| 39 | 93 | |
| 40 | 94 | label-by-branches: |
| 41 | 95 | name: 🏷️ Label PR by Branches |
| 42 | - needs: [label-by-size] | |
| 43 | 96 | runs-on: ubuntu-latest |
| 44 | - # Run, even if the previous jobs were skipped/failed | |
| 97 | + # Only label once when PR is created or when base branch is changed, to allow manual label removal | |
| 45 | - # Only label once when PR is created or branches are changed, to allow manual label removal | |
| 98 | + if: github.event.action == 'opened' || (github.event.action == 'synchronize' && github.event.changes.base) | |
| 46 | - if: | | |
| 47 | - always() | |
| 48 | - && github.event.action == 'opened' || (github.event.action == 'synchronize' && (github.event.changes.base || github.event.changes.head)) | |
| 49 | 99 | |
| 50 | 100 | steps: |
| 51 | 101 | - name: Checkout Repository |
| @@ -59,14 +109,13 @@ jobs: | ||
| 59 | 109 | uses: actions/labeler@v5.0.0 |
| 60 | 110 | with: |
| 61 | 111 | configuration-path: .github/pr-auto-labels-by-branch.yml |
| 62 | 112 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 63 | 113 | |
| 64 | 114 | label-by-files: |
| 65 | 115 | name: 🏷️ Label PR by Files |
| 66 | - needs: [label-by-branches] | |
| 67 | 116 | runs-on: ubuntu-latest |
| 68 | 117 | # Run,Only evenneeds ifto therun previouswhen jobscode wereis skipped/failedchanged |
| 69 | - if: always() | |
| 118 | + if: github.event.action == 'opened' || github.event.action == 'synchronize' | |
| 70 | 119 | |
| 71 | 120 | steps: |
| 72 | 121 | - name: Checkout Repository |
| @@ -80,16 +129,19 @@ jobs: | ||
| 80 | 129 | uses: actions/labeler@v5.0.0 |
| 81 | 130 | with: |
| 82 | 131 | configuration-path: .github/pr-auto-labels-by-files.yml |
| 83 | 132 | repo-token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 84 | 133 | |
| 85 | 134 | remove-stale-label: |
| 86 | 135 | name: 🗑️ Remove Stale Label on Comment |
| 87 | - needs: [label-by-files] | |
| 88 | 136 | runs-on: ubuntu-latest |
| 89 | 137 | # Only runs when thison iscomments not done by the github actions bot |
| 90 | - if: | | |
| 138 | + if: github.event_name == 'pull_request_review_comment' && github.actor != 'github-actions[bot]' | |
| 91 | - always() | |
| 139 | + | |
| 92 | - && github.event_name == 'pull_request_review_comment' && github.actor != 'github-actions[bot]' | |
| 140 | + # Override permissions, issue labeler needs issues write access | |
| 141 | + permissions: | |
| 142 | + contents: read | |
| 143 | + issues: write | |
| 144 | + pull-requests: write | |
| 93 | 145 | |
| 94 | 146 | steps: |
| 95 | 147 | - name: Remove Stale Label |
| @@ -98,13 +150,13 @@ jobs: | ||
| 98 | 150 | uses: actions-cool/issues-helper@v3.6.0 |
| 99 | 151 | with: |
| 100 | 152 | actions: 'remove-labels' |
| 101 | 153 | token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 102 | 154 | issue-number: ${{ github.event.pull_request.number }} |
| 103 | 155 | labels: '⚰️ Stale' |
| 104 | 156 | |
| 105 | 157 | check-merge-blocking-labels: |
| 106 | 158 | name: 🚫 Check Merge Blocking Labels |
| 107 | 159 | needs: [label-by-size, label-by-branches, label-by-files, remove-stale-label] |
| 108 | 160 | runs-on: ubuntu-latest |
| 109 | 161 | # Run, even if the previous jobs were skipped/failed |
| 110 | 162 | if: always() |
| @@ -154,7 +206,7 @@ jobs: | ||
| 154 | 206 | |
| 155 | 207 | write-auto-comments: |
| 156 | 208 | name: 💬 Post PR Comments Based on Labels |
| 157 | 209 | needs: [label-by-size, label-by-branches, label-by-files, remove-stale-label] |
| 158 | 210 | runs-on: ubuntu-latest |
| 159 | 211 | # Run, even if the previous jobs were skipped/failed |
| 160 | 212 | if: always() |
| @@ -171,7 +223,7 @@ jobs: | ||
| 171 | 223 | uses: peaceiris/actions-label-commenter@v1.10.0 |
| 172 | 224 | with: |
| 173 | 225 | config_file: .github/pr-auto-comments.yml |
| 174 | 226 | github_token: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 175 | 227 | |
| 176 | 228 | # 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. |
| 177 | 229 | update-linked-issues: |
| @@ -179,6 +231,12 @@ jobs: | ||
| 179 | 231 | runs-on: ubuntu-latest |
| 180 | 232 | if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'staging' |
| 181 | 233 | |
| 234 | + # Override permissions, We need to be able to write to issues | |
| 235 | + permissions: | |
| 236 | + contents: read | |
| 237 | + issues: write | |
| 238 | + pull-requests: write | |
| 239 | + | |
| 182 | 240 | steps: |
| 183 | 241 | - name: Extract Linked Issues From PR Description |
| 184 | 242 | id: extract_issues |
| @@ -192,7 +250,7 @@ jobs: | ||
| 192 | 250 | PR_NUMBER=${{ github.event.pull_request.number }} |
| 193 | 251 | REPO=${{ github.repository }} |
| 194 | 252 | API_URL="https://api.github.com/repos/$REPO/pulls/$PR_NUMBER/issues" |
| 195 | 253 | 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]') |
| 196 | 254 | echo "linked_issues=$ISSUES" >> $GITHUB_ENV |
| 197 | 255 | |
| 198 | 256 | - name: Merge Issue Lists |
| @@ -204,9 +262,9 @@ jobs: | ||
| 204 | 262 | - name: Label Linked Issues |
| 205 | 263 | id: label_linked_issues |
| 206 | 264 | env: |
| 207 | 265 | GH_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 208 | 266 | run: | |
| 209 | 267 | for ISSUE in $(echo $final_issues | jq -r '.[]'); do |
| 210 | 268 | gh issue edit $ISSUE -R ${{ github.repository }} --add-label "✅ Done (staging)" --remove-label "🧑💻 In Progress" |
| 211 | 269 | echo "Added label '✅ Done (staging)' to(and removed '🧑💻 In Progress' if present) in issue #$ISSUE" |
| 212 | 270 | done |
| @@ -23,6 +23,6 @@ jobs: | ||
| 23 | 23 | uses: eps1lon/actions-label-merge-conflict@v3.0.3 |
| 24 | 24 | with: |
| 25 | 25 | dirtyLabel: '🚫 Merge Conflicts' |
| 26 | 26 | repoToken: ${{ secrets.BOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} |
| 27 | 27 | commentOnDirty: > |
| 28 | 28 | ⚠️ This PR has conflicts that need to be resolved before it can be merged. |
| @@ -114,6 +114,8 @@ backups: | ||
| 114 | 114 | chat: |
| 115 | 115 | # Enable automatic chat backups |
| 116 | 116 | enabled: true |
| 117 | + # Verify integrity of chat files before saving | |
| 118 | + checkIntegrity: true | |
| 117 | 119 | # Maximum number of chat backups to keep per user (starting from the most recent). Set to -1 to keep all backups. |
| 118 | 120 | maxTotalBackups: -1 |
| 119 | 121 | # Interval in milliseconds to throttle chat backups per user |
| @@ -140,6 +142,8 @@ performance: | ||
| 140 | 142 | lazyLoadCharacters: false |
| 141 | 143 | # The maximum amount of memory that parsed character cards can use. Set to 0 to disable memory caching. |
| 142 | 144 | memoryCacheCapacity: '100mb' |
| 145 | + # Enables disk caching for character cards. Improves performances with large card libraries. | |
| 146 | + useDiskCache: true | |
| 143 | 147 | |
| 144 | 148 | # Allow secret keys exposure via API |
| 145 | 149 | allowKeysExposure: false |
| @@ -151,6 +155,7 @@ whitelistImportDomains: | ||
| 151 | 155 | - cdn.discordapp.com |
| 152 | 156 | - files.catbox.moe |
| 153 | 157 | - raw.githubusercontent.com |
| 158 | + - char-archive.evulid.cc | |
| 154 | 159 | # API request overrides (for KoboldAI and Text Completion APIs) |
| 155 | 160 | ## Note: host includes the port number if it's not the default (80 or 443) |
| 156 | 161 | ## Format is an array of objects: |
| @@ -564,6 +564,10 @@ | ||
| 564 | 564 | "type": "context" |
| 565 | 565 | }, |
| 566 | 566 | { |
| 567 | + "filename": "presets/context/Llama 4 Instruct.json", | |
| 568 | + "type": "context" | |
| 569 | + }, | |
| 570 | + { | |
| 567 | 571 | "filename": "presets/context/Phi.json", |
| 568 | 572 | "type": "context" |
| 569 | 573 | }, |
| @@ -664,6 +668,10 @@ | ||
| 664 | 668 | "type": "instruct" |
| 665 | 669 | }, |
| 666 | 670 | { |
| 671 | + "filename": "presets/instruct/Llama 4 Instruct.json", | |
| 672 | + "type": "instruct" | |
| 673 | + }, | |
| 674 | + { | |
| 667 | 675 | "filename": "presets/instruct/Phi.json", |
| 668 | 676 | "type": "instruct" |
| 669 | 677 | }, |
| @@ -786,5 +794,13 @@ | ||
| 786 | 794 | { |
| 787 | 795 | "filename": "presets/context/DeepSeek-V2.5.json", |
| 788 | 796 | "type": "context" |
| 797 | + }, | |
| 798 | + { | |
| 799 | + "filename": "presets/reasoning/DeepSeek.json", | |
| 800 | + "type": "reasoning" | |
| 801 | + }, | |
| 802 | + { | |
| 803 | + "filename": "presets/reasoning/Blank.json", | |
| 804 | + "type": "reasoning" | |
| 789 | 805 | } |
| 790 | 806 | ] |
| @@ -0,0 +1,11 @@ | ||
| 1 | +{ | |
| 2 | + "story_string": "<|begin_of_text|><|header_start|>system<|header_end|>\n\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}<|eot|>", | |
| 3 | + "example_separator": "", | |
| 4 | + "chat_start": "", | |
| 5 | + "use_stop_strings": false, | |
| 6 | + "allow_jailbreak": false, | |
| 7 | + "always_force_name2": true, | |
| 8 | + "trim_sentences": false, | |
| 9 | + "single_line": false, | |
| 10 | + "name": "Llama 4 Instruct" | |
| 11 | +} | |
| @@ -16,7 +16,7 @@ | ||
| 16 | 16 | "input_suffix": "<|eot_id|>", |
| 17 | 17 | "system_suffix": "<|eot_id|>", |
| 18 | 18 | "user_alignment_message": "", |
| 19 | 19 | "system_same_as_user": truefalse, |
| 20 | 20 | "last_system_sequence": "", |
| 21 | 21 | "name": "Llama 3 Instruct" |
| 22 | 22 | } |
| @@ -0,0 +1,22 @@ | ||
| 1 | +{ | |
| 2 | + "input_sequence": "<|header_start|>user<|header_end|>\n\n", | |
| 3 | + "output_sequence": "<|header_start|>assistant<|header_end|>\n\n", | |
| 4 | + "last_output_sequence": "", | |
| 5 | + "system_sequence": "<|header_start|>system<|header_end|>\n\n", | |
| 6 | + "stop_sequence": "<|eot|>", | |
| 7 | + "wrap": false, | |
| 8 | + "macro": true, | |
| 9 | + "names_behavior": "always", | |
| 10 | + "activation_regex": "", | |
| 11 | + "system_sequence_prefix": "", | |
| 12 | + "system_sequence_suffix": "", | |
| 13 | + "first_output_sequence": "", | |
| 14 | + "skip_examples": false, | |
| 15 | + "output_suffix": "<|eot|>", | |
| 16 | + "input_suffix": "<|eot|>", | |
| 17 | + "system_suffix": "<|eot|>", | |
| 18 | + "user_alignment_message": "", | |
| 19 | + "system_same_as_user": false, | |
| 20 | + "last_system_sequence": "", | |
| 21 | + "name": "Llama 4 Instruct" | |
| 22 | +} | |
| @@ -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 | +} | |
| @@ -2,7 +2,7 @@ | ||
| 2 | 2 | "compilerOptions": { |
| 3 | 3 | "module": "ESNext", |
| 4 | 4 | "target": "ES2023", |
| 5 | 5 | "moduleResolution": "NodeBundler", |
| 6 | 6 | "strictNullChecks": true, |
| 7 | 7 | "strictFunctionTypes": true, |
| 8 | 8 | "checkJs": true, |
| @@ -1,12 +1,12 @@ | ||
| 1 | 1 | { |
| 2 | 2 | "name": "sillytavern", |
| 3 | 3 | "version": "1.12.1314", |
| 4 | 4 | "lockfileVersion": 3, |
| 5 | 5 | "requires": true, |
| 6 | 6 | "packages": { |
| 7 | 7 | "": { |
| 8 | 8 | "name": "sillytavern", |
| 9 | 9 | "version": "1.12.1314", |
| 10 | 10 | "hasInstallScript": true, |
| 11 | 11 | "license": "AGPL-3.0", |
| 12 | 12 | "dependencies": { |
| @@ -14,6 +14,26 @@ | ||
| 14 | 14 | "@agnai/sentencepiece-js": "^1.1.1", |
| 15 | 15 | "@agnai/web-tokenizers": "^0.1.3", |
| 16 | 16 | "@iconfu/svg-inject": "^1.2.3", |
| 17 | + "@jimp/core": "^1.6.0", | |
| 18 | + "@jimp/js-bmp": "^1.6.0", | |
| 19 | + "@jimp/js-gif": "^1.6.0", | |
| 20 | + "@jimp/js-tiff": "^1.6.0", | |
| 21 | + "@jimp/plugin-circle": "^1.6.0", | |
| 22 | + "@jimp/plugin-color": "^1.6.0", | |
| 23 | + "@jimp/plugin-contain": "^1.6.0", | |
| 24 | + "@jimp/plugin-cover": "^1.6.0", | |
| 25 | + "@jimp/plugin-crop": "^1.6.0", | |
| 26 | + "@jimp/plugin-displace": "^1.6.0", | |
| 27 | + "@jimp/plugin-fisheye": "^1.6.0", | |
| 28 | + "@jimp/plugin-flip": "^1.6.0", | |
| 29 | + "@jimp/plugin-mask": "^1.6.0", | |
| 30 | + "@jimp/plugin-quantize": "^1.6.0", | |
| 31 | + "@jimp/plugin-rotate": "^1.6.0", | |
| 32 | + "@jimp/plugin-threshold": "^1.6.0", | |
| 33 | + "@jimp/wasm-avif": "^1.6.0", | |
| 34 | + "@jimp/wasm-jpeg": "^1.6.0", | |
| 35 | + "@jimp/wasm-png": "^1.6.0", | |
| 36 | + "@jimp/wasm-webp": "^1.6.0", | |
| 17 | 37 | "@mozilla/readability": "^0.6.0", |
| 18 | 38 | "@popperjs/core": "^2.11.8", |
| 19 | 39 | "@zeldafan0225/ai_horde": "^5.2.0", |
| @@ -28,6 +48,7 @@ | ||
| 28 | 48 | "cookie-parser": "^1.4.6", |
| 29 | 49 | "cookie-session": "^2.1.0", |
| 30 | 50 | "cors": "^2.8.5", |
| 51 | + "crc": "^4.3.2", | |
| 31 | 52 | "csrf-sync": "^4.0.3", |
| 32 | 53 | "diff-match-patch": "^1.0.5", |
| 33 | 54 | "dompurify": "^3.2.4", |
| @@ -46,7 +67,6 @@ | ||
| 46 | 67 | "ip-regex": "^5.0.0", |
| 47 | 68 | "ipaddr.js": "^2.2.0", |
| 48 | 69 | "is-docker": "^3.0.0", |
| 49 | - "jimp": "^0.22.10", | |
| 50 | 70 | "localforage": "^1.10.0", |
| 51 | 71 | "lodash": "^4.17.21", |
| 52 | 72 | "mime-types": "^2.1.35", |
| @@ -57,7 +77,6 @@ | ||
| 57 | 77 | "node-persist": "^4.0.4", |
| 58 | 78 | "open": "^8.4.2", |
| 59 | 79 | "png-chunk-text": "^1.0.0", |
| 60 | - "png-chunks-encode": "^1.0.0", | |
| 61 | 80 | "png-chunks-extract": "^1.0.0", |
| 62 | 81 | "proxy-agent": "^6.5.0", |
| 63 | 82 | "rate-limiter-flexible": "^5.0.5", |
| @@ -102,7 +121,6 @@ | ||
| 102 | 121 | "@types/node": "^18.19.80", |
| 103 | 122 | "@types/node-persist": "^3.1.8", |
| 104 | 123 | "@types/png-chunk-text": "^1.0.3", |
| 105 | - "@types/png-chunks-encode": "^1.0.2", | |
| 106 | 124 | "@types/png-chunks-extract": "^1.0.2", |
| 107 | 125 | "@types/response-time": "^2.3.8", |
| 108 | 126 | "@types/select2": "^4.0.63", |
| @@ -110,7 +128,8 @@ | ||
| 110 | 128 | "@types/write-file-atomic": "^4.0.3", |
| 111 | 129 | "@types/yargs": "^17.0.33", |
| 112 | 130 | "@types/yauzl": "^2.10.3", |
| 113 | 131 | "eslint": "^8.57.1", |
| 132 | + "eslint-plugin-jsdoc": "^48.10.0" | |
| 114 | 133 | }, |
| 115 | 134 | "engines": { |
| 116 | 135 | "node": ">= 18" |
| @@ -147,6 +166,21 @@ | ||
| 147 | 166 | "integrity": "sha512-KlmTftToTtmb6aLVdne4NluS+POWputPF5J8v25UN/EQS+K9vahWEIe1NPRSFqBQclObkqHaj7JOnFrmnSm5MA==", |
| 148 | 167 | "license": "Apache-2.0" |
| 149 | 168 | }, |
| 169 | + "node_modules/@es-joy/jsdoccomment": { | |
| 170 | + "version": "0.46.0", | |
| 171 | + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", | |
| 172 | + "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", | |
| 173 | + "dev": true, | |
| 174 | + "license": "MIT", | |
| 175 | + "dependencies": { | |
| 176 | + "comment-parser": "1.4.1", | |
| 177 | + "esquery": "^1.6.0", | |
| 178 | + "jsdoc-type-pratt-parser": "~4.0.0" | |
| 179 | + }, | |
| 180 | + "engines": { | |
| 181 | + "node": ">=16" | |
| 182 | + } | |
| 183 | + }, | |
| 150 | 184 | "node_modules/@eslint-community/eslint-utils": { |
| 151 | 185 | "version": "4.4.0", |
| 152 | 186 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", |
| @@ -412,7 +446,55 @@ | ||
| 412 | 446 | "@jimp/custom": ">=0.3.5" |
| 413 | 447 | } |
| 414 | 448 | }, |
| 449 | + "node_modules/@jimp/bmp/node_modules/@jimp/utils": { | |
| 450 | + "version": "0.22.12", | |
| 451 | + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", | |
| 452 | + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", | |
| 453 | + "license": "MIT", | |
| 454 | + "dependencies": { | |
| 455 | + "regenerator-runtime": "^0.13.3" | |
| 456 | + } | |
| 457 | + }, | |
| 415 | 458 | "node_modules/@jimp/core": { |
| 459 | + "version": "1.6.0", | |
| 460 | + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.6.0.tgz", | |
| 461 | + "integrity": "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w==", | |
| 462 | + "license": "MIT", | |
| 463 | + "dependencies": { | |
| 464 | + "@jimp/file-ops": "1.6.0", | |
| 465 | + "@jimp/types": "1.6.0", | |
| 466 | + "@jimp/utils": "1.6.0", | |
| 467 | + "await-to-js": "^3.0.0", | |
| 468 | + "exif-parser": "^0.1.12", | |
| 469 | + "file-type": "^16.0.0", | |
| 470 | + "mime": "3" | |
| 471 | + }, | |
| 472 | + "engines": { | |
| 473 | + "node": ">=18" | |
| 474 | + } | |
| 475 | + }, | |
| 476 | + "node_modules/@jimp/core/node_modules/mime": { | |
| 477 | + "version": "3.0.0", | |
| 478 | + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", | |
| 479 | + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", | |
| 480 | + "license": "MIT", | |
| 481 | + "bin": { | |
| 482 | + "mime": "cli.js" | |
| 483 | + }, | |
| 484 | + "engines": { | |
| 485 | + "node": ">=10.0.0" | |
| 486 | + } | |
| 487 | + }, | |
| 488 | + "node_modules/@jimp/custom": { | |
| 489 | + "version": "0.22.12", | |
| 490 | + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", | |
| 491 | + "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", | |
| 492 | + "license": "MIT", | |
| 493 | + "dependencies": { | |
| 494 | + "@jimp/core": "^0.22.12" | |
| 495 | + } | |
| 496 | + }, | |
| 497 | + "node_modules/@jimp/custom/node_modules/@jimp/core": { | |
| 416 | 498 | "version": "0.22.12", |
| 417 | 499 | "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", |
| 418 | 500 | "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", |
| @@ -428,13 +510,67 @@ | ||
| 428 | 510 | "tinycolor2": "^1.6.0" |
| 429 | 511 | } |
| 430 | 512 | }, |
| 431 | 513 | "node_modules/@jimp/custom/node_modules/@jimp/utils": { |
| 432 | 514 | "version": "0.22.12", |
| 433 | 515 | "resolved": "https://registry.npmjs.org/@jimp/customutils/-/customutils-0.22.12.tgz", |
| 434 | 516 | "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHVyJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1QnMKXk8TrSwAE71zt716Q==", |
| 435 | 517 | "license": "MIT", |
| 436 | 518 | "dependencies": { |
| 437 | 519 | "@jimp/coreregenerator-runtime": "^0.2213.123" |
| 520 | + } | |
| 521 | + }, | |
| 522 | + "node_modules/@jimp/custom/node_modules/buffer": { | |
| 523 | + "version": "5.7.1", | |
| 524 | + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", | |
| 525 | + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", | |
| 526 | + "funding": [ | |
| 527 | + { | |
| 528 | + "type": "github", | |
| 529 | + "url": "https://github.com/sponsors/feross" | |
| 530 | + }, | |
| 531 | + { | |
| 532 | + "type": "patreon", | |
| 533 | + "url": "https://www.patreon.com/feross" | |
| 534 | + }, | |
| 535 | + { | |
| 536 | + "type": "consulting", | |
| 537 | + "url": "https://feross.org/support" | |
| 538 | + } | |
| 539 | + ], | |
| 540 | + "license": "MIT", | |
| 541 | + "dependencies": { | |
| 542 | + "base64-js": "^1.3.1", | |
| 543 | + "ieee754": "^1.1.13" | |
| 544 | + } | |
| 545 | + }, | |
| 546 | + "node_modules/@jimp/custom/node_modules/pixelmatch": { | |
| 547 | + "version": "4.0.2", | |
| 548 | + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", | |
| 549 | + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", | |
| 550 | + "license": "ISC", | |
| 551 | + "dependencies": { | |
| 552 | + "pngjs": "^3.0.0" | |
| 553 | + }, | |
| 554 | + "bin": { | |
| 555 | + "pixelmatch": "bin/pixelmatch" | |
| 556 | + } | |
| 557 | + }, | |
| 558 | + "node_modules/@jimp/custom/node_modules/pngjs": { | |
| 559 | + "version": "3.4.0", | |
| 560 | + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", | |
| 561 | + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", | |
| 562 | + "license": "MIT", | |
| 563 | + "engines": { | |
| 564 | + "node": ">=4.0.0" | |
| 565 | + } | |
| 566 | + }, | |
| 567 | + "node_modules/@jimp/file-ops": { | |
| 568 | + "version": "1.6.0", | |
| 569 | + "resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.6.0.tgz", | |
| 570 | + "integrity": "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ==", | |
| 571 | + "license": "MIT", | |
| 572 | + "engines": { | |
| 573 | + "node": ">=18" | |
| 438 | 574 | } |
| 439 | 575 | }, |
| 440 | 576 | "node_modules/@jimp/gif": { |
| @@ -451,6 +587,15 @@ | ||
| 451 | 587 | "@jimp/custom": ">=0.3.5" |
| 452 | 588 | } |
| 453 | 589 | }, |
| 590 | + "node_modules/@jimp/gif/node_modules/@jimp/utils": { | |
| 591 | + "version": "0.22.12", | |
| 592 | + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", | |
| 593 | + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", | |
| 594 | + "license": "MIT", | |
| 595 | + "dependencies": { | |
| 596 | + "regenerator-runtime": "^0.13.3" | |
| 597 | + } | |
| 598 | + }, | |
| 454 | 599 | "node_modules/@jimp/jpeg": { |
| 455 | 600 | "version": "0.22.12", |
| 456 | 601 | "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", |
| @@ -464,10 +609,237 @@ | ||
| 464 | 609 | "@jimp/custom": ">=0.3.5" |
| 465 | 610 | } |
| 466 | 611 | }, |
| 612 | + "node_modules/@jimp/jpeg/node_modules/@jimp/utils": { | |
| 613 | + "version": "0.22.12", | |
| 614 | + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", | |
| 615 | + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", | |
| 616 | + "license": "MIT", | |
| 617 | + "dependencies": { | |
| 618 | + "regenerator-runtime": "^0.13.3" | |
| 619 | + } | |
| 620 | + }, | |
| 621 | + "node_modules/@jimp/js-bmp": { | |
| 622 | + "version": "1.6.0", | |
| 623 | + "resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.6.0.tgz", | |
| 624 | + "integrity": "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw==", | |
| 625 | + "license": "MIT", | |
| 626 | + "dependencies": { | |
| 627 | + "@jimp/core": "1.6.0", | |
| 628 | + "@jimp/types": "1.6.0", | |
| 629 | + "@jimp/utils": "1.6.0", | |
| 630 | + "bmp-ts": "^1.0.9" | |
| 631 | + }, | |
| 632 | + "engines": { | |
| 633 | + "node": ">=18" | |
| 634 | + } | |
| 635 | + }, | |
| 636 | + "node_modules/@jimp/js-gif": { | |
| 637 | + "version": "1.6.0", | |
| 638 | + "resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.6.0.tgz", | |
| 639 | + "integrity": "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g==", | |
| 640 | + "license": "MIT", | |
| 641 | + "dependencies": { | |
| 642 | + "@jimp/core": "1.6.0", | |
| 643 | + "@jimp/types": "1.6.0", | |
| 644 | + "gifwrap": "^0.10.1", | |
| 645 | + "omggif": "^1.0.10" | |
| 646 | + }, | |
| 647 | + "engines": { | |
| 648 | + "node": ">=18" | |
| 649 | + } | |
| 650 | + }, | |
| 651 | + "node_modules/@jimp/js-jpeg": { | |
| 652 | + "version": "1.6.0", | |
| 653 | + "resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.6.0.tgz", | |
| 654 | + "integrity": "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA==", | |
| 655 | + "license": "MIT", | |
| 656 | + "dependencies": { | |
| 657 | + "@jimp/core": "1.6.0", | |
| 658 | + "@jimp/types": "1.6.0", | |
| 659 | + "jpeg-js": "^0.4.4" | |
| 660 | + }, | |
| 661 | + "engines": { | |
| 662 | + "node": ">=18" | |
| 663 | + } | |
| 664 | + }, | |
| 665 | + "node_modules/@jimp/js-png": { | |
| 666 | + "version": "1.6.0", | |
| 667 | + "resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.6.0.tgz", | |
| 668 | + "integrity": "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg==", | |
| 669 | + "license": "MIT", | |
| 670 | + "dependencies": { | |
| 671 | + "@jimp/core": "1.6.0", | |
| 672 | + "@jimp/types": "1.6.0", | |
| 673 | + "pngjs": "^7.0.0" | |
| 674 | + }, | |
| 675 | + "engines": { | |
| 676 | + "node": ">=18" | |
| 677 | + } | |
| 678 | + }, | |
| 679 | + "node_modules/@jimp/js-tiff": { | |
| 680 | + "version": "1.6.0", | |
| 681 | + "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.6.0.tgz", | |
| 682 | + "integrity": "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw==", | |
| 683 | + "license": "MIT", | |
| 684 | + "dependencies": { | |
| 685 | + "@jimp/core": "1.6.0", | |
| 686 | + "@jimp/types": "1.6.0", | |
| 687 | + "utif2": "^4.1.0" | |
| 688 | + }, | |
| 689 | + "engines": { | |
| 690 | + "node": ">=18" | |
| 691 | + } | |
| 692 | + }, | |
| 467 | 693 | "node_modules/@jimp/plugin-blit": { |
| 694 | + "version": "1.6.0", | |
| 695 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.6.0.tgz", | |
| 696 | + "integrity": "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA==", | |
| 697 | + "license": "MIT", | |
| 698 | + "dependencies": { | |
| 699 | + "@jimp/types": "1.6.0", | |
| 700 | + "@jimp/utils": "1.6.0", | |
| 701 | + "zod": "^3.23.8" | |
| 702 | + }, | |
| 703 | + "engines": { | |
| 704 | + "node": ">=18" | |
| 705 | + } | |
| 706 | + }, | |
| 707 | + "node_modules/@jimp/plugin-blur": { | |
| 708 | + "version": "1.6.0", | |
| 709 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.6.0.tgz", | |
| 710 | + "integrity": "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw==", | |
| 711 | + "license": "MIT", | |
| 712 | + "peer": true, | |
| 713 | + "dependencies": { | |
| 714 | + "@jimp/core": "1.6.0", | |
| 715 | + "@jimp/utils": "1.6.0" | |
| 716 | + }, | |
| 717 | + "engines": { | |
| 718 | + "node": ">=18" | |
| 719 | + } | |
| 720 | + }, | |
| 721 | + "node_modules/@jimp/plugin-circle": { | |
| 722 | + "version": "1.6.0", | |
| 723 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.6.0.tgz", | |
| 724 | + "integrity": "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw==", | |
| 725 | + "license": "MIT", | |
| 726 | + "dependencies": { | |
| 727 | + "@jimp/types": "1.6.0", | |
| 728 | + "zod": "^3.23.8" | |
| 729 | + }, | |
| 730 | + "engines": { | |
| 731 | + "node": ">=18" | |
| 732 | + } | |
| 733 | + }, | |
| 734 | + "node_modules/@jimp/plugin-color": { | |
| 735 | + "version": "1.6.0", | |
| 736 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.6.0.tgz", | |
| 737 | + "integrity": "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA==", | |
| 738 | + "license": "MIT", | |
| 739 | + "dependencies": { | |
| 740 | + "@jimp/core": "1.6.0", | |
| 741 | + "@jimp/types": "1.6.0", | |
| 742 | + "@jimp/utils": "1.6.0", | |
| 743 | + "tinycolor2": "^1.6.0", | |
| 744 | + "zod": "^3.23.8" | |
| 745 | + }, | |
| 746 | + "engines": { | |
| 747 | + "node": ">=18" | |
| 748 | + } | |
| 749 | + }, | |
| 750 | + "node_modules/@jimp/plugin-contain": { | |
| 751 | + "version": "1.6.0", | |
| 752 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.6.0.tgz", | |
| 753 | + "integrity": "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ==", | |
| 754 | + "license": "MIT", | |
| 755 | + "dependencies": { | |
| 756 | + "@jimp/core": "1.6.0", | |
| 757 | + "@jimp/plugin-blit": "1.6.0", | |
| 758 | + "@jimp/plugin-resize": "1.6.0", | |
| 759 | + "@jimp/types": "1.6.0", | |
| 760 | + "@jimp/utils": "1.6.0", | |
| 761 | + "zod": "^3.23.8" | |
| 762 | + }, | |
| 763 | + "engines": { | |
| 764 | + "node": ">=18" | |
| 765 | + } | |
| 766 | + }, | |
| 767 | + "node_modules/@jimp/plugin-cover": { | |
| 768 | + "version": "1.6.0", | |
| 769 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.6.0.tgz", | |
| 770 | + "integrity": "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA==", | |
| 771 | + "license": "MIT", | |
| 772 | + "dependencies": { | |
| 773 | + "@jimp/core": "1.6.0", | |
| 774 | + "@jimp/plugin-crop": "1.6.0", | |
| 775 | + "@jimp/plugin-resize": "1.6.0", | |
| 776 | + "@jimp/types": "1.6.0", | |
| 777 | + "zod": "^3.23.8" | |
| 778 | + }, | |
| 779 | + "engines": { | |
| 780 | + "node": ">=18" | |
| 781 | + } | |
| 782 | + }, | |
| 783 | + "node_modules/@jimp/plugin-crop": { | |
| 784 | + "version": "1.6.0", | |
| 785 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.6.0.tgz", | |
| 786 | + "integrity": "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang==", | |
| 787 | + "license": "MIT", | |
| 788 | + "dependencies": { | |
| 789 | + "@jimp/core": "1.6.0", | |
| 790 | + "@jimp/types": "1.6.0", | |
| 791 | + "@jimp/utils": "1.6.0", | |
| 792 | + "zod": "^3.23.8" | |
| 793 | + }, | |
| 794 | + "engines": { | |
| 795 | + "node": ">=18" | |
| 796 | + } | |
| 797 | + }, | |
| 798 | + "node_modules/@jimp/plugin-displace": { | |
| 799 | + "version": "1.6.0", | |
| 800 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.6.0.tgz", | |
| 801 | + "integrity": "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q==", | |
| 802 | + "license": "MIT", | |
| 803 | + "dependencies": { | |
| 804 | + "@jimp/types": "1.6.0", | |
| 805 | + "@jimp/utils": "1.6.0", | |
| 806 | + "zod": "^3.23.8" | |
| 807 | + }, | |
| 808 | + "engines": { | |
| 809 | + "node": ">=18" | |
| 810 | + } | |
| 811 | + }, | |
| 812 | + "node_modules/@jimp/plugin-fisheye": { | |
| 813 | + "version": "1.6.0", | |
| 814 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.6.0.tgz", | |
| 815 | + "integrity": "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA==", | |
| 816 | + "license": "MIT", | |
| 817 | + "dependencies": { | |
| 818 | + "@jimp/types": "1.6.0", | |
| 819 | + "@jimp/utils": "1.6.0", | |
| 820 | + "zod": "^3.23.8" | |
| 821 | + }, | |
| 822 | + "engines": { | |
| 823 | + "node": ">=18" | |
| 824 | + } | |
| 825 | + }, | |
| 826 | + "node_modules/@jimp/plugin-flip": { | |
| 827 | + "version": "1.6.0", | |
| 828 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.6.0.tgz", | |
| 829 | + "integrity": "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg==", | |
| 830 | + "license": "MIT", | |
| 831 | + "dependencies": { | |
| 832 | + "@jimp/types": "1.6.0", | |
| 833 | + "zod": "^3.23.8" | |
| 834 | + }, | |
| 835 | + "engines": { | |
| 836 | + "node": ">=18" | |
| 837 | + } | |
| 838 | + }, | |
| 839 | + "node_modules/@jimp/plugin-gaussian": { | |
| 468 | 840 | "version": "0.22.12", |
| 469 | 841 | "resolved": "https://registry.npmjs.org/@jimp/plugin-blitgaussian/-/plugin-blitgaussian-0.22.12.tgz", |
| 470 | 842 | "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQsBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", |
| 471 | 843 | "license": "MIT", |
| 472 | 844 | "dependencies": { |
| 473 | 845 | "@jimp/utils": "^0.22.12" |
| @@ -476,10 +848,40 @@ | ||
| 476 | 848 | "@jimp/custom": ">=0.3.5" |
| 477 | 849 | } |
| 478 | 850 | }, |
| 479 | 851 | "node_modules/@jimp/plugin-blurgaussian/node_modules/@jimp/utils": { |
| 480 | 852 | "version": "0.22.12", |
| 481 | 853 | "resolved": "https://registry.npmjs.org/@jimp/plugin-blurutils/-/plugin-blurutils-0.22.12.tgz", |
| 482 | 854 | "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9tyJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uwnMKXk8TrSwAE71zt716Q==", |
| 855 | + "license": "MIT", | |
| 856 | + "dependencies": { | |
| 857 | + "regenerator-runtime": "^0.13.3" | |
| 858 | + } | |
| 859 | + }, | |
| 860 | + "node_modules/@jimp/plugin-hash": { | |
| 861 | + "version": "1.6.0", | |
| 862 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.6.0.tgz", | |
| 863 | + "integrity": "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q==", | |
| 864 | + "license": "MIT", | |
| 865 | + "dependencies": { | |
| 866 | + "@jimp/core": "1.6.0", | |
| 867 | + "@jimp/js-bmp": "1.6.0", | |
| 868 | + "@jimp/js-jpeg": "1.6.0", | |
| 869 | + "@jimp/js-png": "1.6.0", | |
| 870 | + "@jimp/js-tiff": "1.6.0", | |
| 871 | + "@jimp/plugin-color": "1.6.0", | |
| 872 | + "@jimp/plugin-resize": "1.6.0", | |
| 873 | + "@jimp/types": "1.6.0", | |
| 874 | + "@jimp/utils": "1.6.0", | |
| 875 | + "any-base": "^1.1.0" | |
| 876 | + }, | |
| 877 | + "engines": { | |
| 878 | + "node": ">=18" | |
| 879 | + } | |
| 880 | + }, | |
| 881 | + "node_modules/@jimp/plugin-invert": { | |
| 882 | + "version": "0.22.12", | |
| 883 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", | |
| 884 | + "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", | |
| 483 | 885 | "license": "MIT", |
| 484 | 886 | "dependencies": { |
| 485 | 887 | "@jimp/utils": "^0.22.12" |
| @@ -488,10 +890,32 @@ | ||
| 488 | 890 | "@jimp/custom": ">=0.3.5" |
| 489 | 891 | } |
| 490 | 892 | }, |
| 491 | 893 | "node_modules/@jimp/plugin-circleinvert/node_modules/@jimp/utils": { |
| 492 | 894 | "version": "0.22.12", |
| 493 | 895 | "resolved": "https://registry.npmjs.org/@jimp/plugin-circleutils/-/plugin-circleutils-0.22.12.tgz", |
| 494 | 896 | "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTgyJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", |
| 897 | + "license": "MIT", | |
| 898 | + "dependencies": { | |
| 899 | + "regenerator-runtime": "^0.13.3" | |
| 900 | + } | |
| 901 | + }, | |
| 902 | + "node_modules/@jimp/plugin-mask": { | |
| 903 | + "version": "1.6.0", | |
| 904 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.6.0.tgz", | |
| 905 | + "integrity": "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA==", | |
| 906 | + "license": "MIT", | |
| 907 | + "dependencies": { | |
| 908 | + "@jimp/types": "1.6.0", | |
| 909 | + "zod": "^3.23.8" | |
| 910 | + }, | |
| 911 | + "engines": { | |
| 912 | + "node": ">=18" | |
| 913 | + } | |
| 914 | + }, | |
| 915 | + "node_modules/@jimp/plugin-normalize": { | |
| 916 | + "version": "0.22.12", | |
| 917 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", | |
| 918 | + "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", | |
| 495 | 919 | "license": "MIT", |
| 496 | 920 | "dependencies": { |
| 497 | 921 | "@jimp/utils": "^0.22.12" |
| @@ -500,65 +924,158 @@ | ||
| 500 | 924 | "@jimp/custom": ">=0.3.5" |
| 501 | 925 | } |
| 502 | 926 | }, |
| 503 | 927 | "node_modules/@jimp/plugin-colornormalize/node_modules/@jimp/utils": { |
| 504 | 928 | "version": "0.22.12", |
| 505 | 929 | "resolved": "https://registry.npmjs.org/@jimp/plugin-colorutils/-/plugin-colorutils-0.22.12.tgz", |
| 506 | 930 | "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIAyJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", |
| 507 | 931 | "license": "MIT", |
| 508 | 932 | "dependencies": { |
| 509 | 933 | "@jimp/utilsregenerator-runtime": "^0.2213.123", |
| 510 | - "tinycolor2": "^1.6.0" | |
| 934 | + } | |
| 511 | 935 | }, |
| 512 | - "peerDependencies": { | |
| 936 | + "node_modules/@jimp/plugin-quantize": { | |
| 513 | 937 | "@jimp/customversion": ">=01.36.50", |
| 938 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-quantize/-/plugin-quantize-1.6.0.tgz", | |
| 939 | + "integrity": "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg==", | |
| 940 | + "license": "MIT", | |
| 941 | + "dependencies": { | |
| 942 | + "image-q": "^4.0.0", | |
| 943 | + "zod": "^3.23.8" | |
| 944 | + }, | |
| 945 | + "engines": { | |
| 946 | + "node": ">=18" | |
| 514 | 947 | } |
| 515 | 948 | }, |
| 516 | 949 | "node_modules/@jimp/plugin-containresize": { |
| 950 | + "version": "1.6.0", | |
| 951 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.6.0.tgz", | |
| 952 | + "integrity": "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==", | |
| 953 | + "license": "MIT", | |
| 954 | + "dependencies": { | |
| 955 | + "@jimp/core": "1.6.0", | |
| 956 | + "@jimp/types": "1.6.0", | |
| 957 | + "zod": "^3.23.8" | |
| 958 | + }, | |
| 959 | + "engines": { | |
| 960 | + "node": ">=18" | |
| 961 | + } | |
| 962 | + }, | |
| 963 | + "node_modules/@jimp/plugin-rotate": { | |
| 964 | + "version": "1.6.0", | |
| 965 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.6.0.tgz", | |
| 966 | + "integrity": "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw==", | |
| 967 | + "license": "MIT", | |
| 968 | + "dependencies": { | |
| 969 | + "@jimp/core": "1.6.0", | |
| 970 | + "@jimp/plugin-crop": "1.6.0", | |
| 971 | + "@jimp/plugin-resize": "1.6.0", | |
| 972 | + "@jimp/types": "1.6.0", | |
| 973 | + "@jimp/utils": "1.6.0", | |
| 974 | + "zod": "^3.23.8" | |
| 975 | + }, | |
| 976 | + "engines": { | |
| 977 | + "node": ">=18" | |
| 978 | + } | |
| 979 | + }, | |
| 980 | + "node_modules/@jimp/plugin-scale": { | |
| 517 | 981 | "version": "0.22.12", |
| 518 | 982 | "resolved": "https://registry.npmjs.org/@jimp/plugin-containscale/-/plugin-containscale-0.22.12.tgz", |
| 519 | 983 | "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQdghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", |
| 520 | 984 | "license": "MIT", |
| 521 | 985 | "dependencies": { |
| 522 | 986 | "@jimp/utils": "^0.22.12" |
| 523 | 987 | }, |
| 524 | 988 | "peerDependencies": { |
| 525 | 989 | "@jimp/custom": ">=0.3.5", |
| 526 | 990 | "@jimp/plugin-blitresize": ">=0.3.5", |
| 527 | - "@jimp/plugin-resize": ">=0.3.5", | |
| 528 | - "@jimp/plugin-scale": ">=0.3.5" | |
| 529 | 991 | } |
| 530 | 992 | }, |
| 531 | 993 | "node_modules/@jimp/plugin-coverscale/node_modules/@jimp/utils": { |
| 532 | 994 | "version": "0.22.12", |
| 533 | 995 | "resolved": "https://registry.npmjs.org/@jimp/plugin-coverutils/-/plugin-coverutils-0.22.12.tgz", |
| 534 | 996 | "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/W56+4nJ1brhSd233HBJCo01BXAnMKXk8TrSwAE71zt716Q==", |
| 997 | + "license": "MIT", | |
| 998 | + "dependencies": { | |
| 999 | + "regenerator-runtime": "^0.13.3" | |
| 1000 | + } | |
| 1001 | + }, | |
| 1002 | + "node_modules/@jimp/plugin-shadow": { | |
| 1003 | + "version": "0.22.12", | |
| 1004 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", | |
| 1005 | + "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", | |
| 535 | 1006 | "license": "MIT", |
| 536 | 1007 | "dependencies": { |
| 537 | 1008 | "@jimp/utils": "^0.22.12" |
| 538 | 1009 | }, |
| 539 | 1010 | "peerDependencies": { |
| 540 | 1011 | "@jimp/custom": ">=0.3.5", |
| 541 | 1012 | "@jimp/plugin-cropblur": ">=0.3.5", |
| 542 | 1013 | "@jimp/plugin-resize": ">=0.3.5", |
| 543 | - "@jimp/plugin-scale": ">=0.3.5" | |
| 544 | 1014 | } |
| 545 | 1015 | }, |
| 546 | 1016 | "node_modules/@jimp/plugin-cropshadow/node_modules/@jimp/utils": { |
| 547 | 1017 | "version": "0.22.12", |
| 548 | 1018 | "resolved": "https://registry.npmjs.org/@jimp/plugin-croputils/-/plugin-croputils-0.22.12.tgz", |
| 549 | 1019 | "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVwyJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", |
| 550 | 1020 | "license": "MIT", |
| 551 | 1021 | "dependencies": { |
| 552 | 1022 | "@jimp/utilsregenerator-runtime": "^0.2213.123" |
| 1023 | + } | |
| 1024 | + }, | |
| 1025 | + "node_modules/@jimp/plugin-threshold": { | |
| 1026 | + "version": "1.6.0", | |
| 1027 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.6.0.tgz", | |
| 1028 | + "integrity": "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w==", | |
| 1029 | + "license": "MIT", | |
| 1030 | + "dependencies": { | |
| 1031 | + "@jimp/core": "1.6.0", | |
| 1032 | + "@jimp/plugin-color": "1.6.0", | |
| 1033 | + "@jimp/plugin-hash": "1.6.0", | |
| 1034 | + "@jimp/types": "1.6.0", | |
| 1035 | + "@jimp/utils": "1.6.0", | |
| 1036 | + "zod": "^3.23.8" | |
| 1037 | + }, | |
| 1038 | + "engines": { | |
| 1039 | + "node": ">=18" | |
| 1040 | + } | |
| 1041 | + }, | |
| 1042 | + "node_modules/@jimp/plugins": { | |
| 1043 | + "version": "0.22.12", | |
| 1044 | + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", | |
| 1045 | + "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", | |
| 1046 | + "license": "MIT", | |
| 1047 | + "dependencies": { | |
| 1048 | + "@jimp/plugin-blit": "^0.22.12", | |
| 1049 | + "@jimp/plugin-blur": "^0.22.12", | |
| 1050 | + "@jimp/plugin-circle": "^0.22.12", | |
| 1051 | + "@jimp/plugin-color": "^0.22.12", | |
| 1052 | + "@jimp/plugin-contain": "^0.22.12", | |
| 1053 | + "@jimp/plugin-cover": "^0.22.12", | |
| 1054 | + "@jimp/plugin-crop": "^0.22.12", | |
| 1055 | + "@jimp/plugin-displace": "^0.22.12", | |
| 1056 | + "@jimp/plugin-dither": "^0.22.12", | |
| 1057 | + "@jimp/plugin-fisheye": "^0.22.12", | |
| 1058 | + "@jimp/plugin-flip": "^0.22.12", | |
| 1059 | + "@jimp/plugin-gaussian": "^0.22.12", | |
| 1060 | + "@jimp/plugin-invert": "^0.22.12", | |
| 1061 | + "@jimp/plugin-mask": "^0.22.12", | |
| 1062 | + "@jimp/plugin-normalize": "^0.22.12", | |
| 1063 | + "@jimp/plugin-print": "^0.22.12", | |
| 1064 | + "@jimp/plugin-resize": "^0.22.12", | |
| 1065 | + "@jimp/plugin-rotate": "^0.22.12", | |
| 1066 | + "@jimp/plugin-scale": "^0.22.12", | |
| 1067 | + "@jimp/plugin-shadow": "^0.22.12", | |
| 1068 | + "@jimp/plugin-threshold": "^0.22.12", | |
| 1069 | + "timm": "^1.6.1" | |
| 553 | 1070 | }, |
| 554 | 1071 | "peerDependencies": { |
| 555 | 1072 | "@jimp/custom": ">=0.3.5" |
| 556 | 1073 | } |
| 557 | 1074 | }, |
| 558 | 1075 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-displaceblit": { |
| 559 | 1076 | "version": "0.22.12", |
| 560 | 1077 | "resolved": "https://registry.npmjs.org/@jimp/plugin-displaceblit/-/plugin-displaceblit-0.22.12.tgz", |
| 561 | 1078 | "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CAxslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", |
| 562 | 1079 | "license": "MIT", |
| 563 | 1080 | "dependencies": { |
| 564 | 1081 | "@jimp/utils": "^0.22.12" |
| @@ -567,10 +1084,10 @@ | ||
| 567 | 1084 | "@jimp/custom": ">=0.3.5" |
| 568 | 1085 | } |
| 569 | 1086 | }, |
| 570 | 1087 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-ditherblur": { |
| 571 | 1088 | "version": "0.22.12", |
| 572 | 1089 | "resolved": "https://registry.npmjs.org/@jimp/plugin-ditherblur/-/plugin-ditherblur-0.22.12.tgz", |
| 573 | 1090 | "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89sS0vJADTuh1Q9F+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLwcXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", |
| 574 | 1091 | "license": "MIT", |
| 575 | 1092 | "dependencies": { |
| 576 | 1093 | "@jimp/utils": "^0.22.12" |
| @@ -579,10 +1096,10 @@ | ||
| 579 | 1096 | "@jimp/custom": ">=0.3.5" |
| 580 | 1097 | } |
| 581 | 1098 | }, |
| 582 | 1099 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-fisheyecircle": { |
| 583 | 1100 | "version": "0.22.12", |
| 584 | 1101 | "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheyecircle/-/plugin-fisheyecircle-0.22.12.tgz", |
| 585 | 1102 | "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+QSWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", |
| 586 | 1103 | "license": "MIT", |
| 587 | 1104 | "dependencies": { |
| 588 | 1105 | "@jimp/utils": "^0.22.12" |
| @@ -591,23 +1108,53 @@ | ||
| 591 | 1108 | "@jimp/custom": ">=0.3.5" |
| 592 | 1109 | } |
| 593 | 1110 | }, |
| 594 | 1111 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-flipcolor": { |
| 595 | 1112 | "version": "0.22.12", |
| 596 | 1113 | "resolved": "https://registry.npmjs.org/@jimp/plugin-flipcolor/-/plugin-flipcolor-0.22.12.tgz", |
| 597 | 1114 | "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxtxImhTE5BpS8xa+inBIb7nlaLLxnvHX8QmAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", |
| 1115 | + "license": "MIT", | |
| 1116 | + "dependencies": { | |
| 1117 | + "@jimp/utils": "^0.22.12", | |
| 1118 | + "tinycolor2": "^1.6.0" | |
| 1119 | + }, | |
| 1120 | + "peerDependencies": { | |
| 1121 | + "@jimp/custom": ">=0.3.5" | |
| 1122 | + } | |
| 1123 | + }, | |
| 1124 | + "node_modules/@jimp/plugins/node_modules/@jimp/plugin-contain": { | |
| 1125 | + "version": "0.22.12", | |
| 1126 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", | |
| 1127 | + "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", | |
| 598 | 1128 | "license": "MIT", |
| 599 | 1129 | "dependencies": { |
| 600 | 1130 | "@jimp/utils": "^0.22.12" |
| 601 | 1131 | }, |
| 602 | 1132 | "peerDependencies": { |
| 603 | 1133 | "@jimp/custom": ">=0.3.5", |
| 604 | 1134 | "@jimp/plugin-rotateblit": ">=0.3.5", |
| 1135 | + "@jimp/plugin-resize": ">=0.3.5", | |
| 1136 | + "@jimp/plugin-scale": ">=0.3.5" | |
| 605 | 1137 | } |
| 606 | 1138 | }, |
| 607 | 1139 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-gaussiancover": { |
| 608 | 1140 | "version": "0.22.12", |
| 609 | 1141 | "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussiancover/-/plugin-gaussiancover-0.22.12.tgz", |
| 610 | 1142 | "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53z0w/1xH/v/knZkpTNx+n3c8Y0P2HWlUjflEla2hE8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/vWShvhgW56+4nJ1brhSd233HBJCo01BXA==", |
| 1143 | + "license": "MIT", | |
| 1144 | + "dependencies": { | |
| 1145 | + "@jimp/utils": "^0.22.12" | |
| 1146 | + }, | |
| 1147 | + "peerDependencies": { | |
| 1148 | + "@jimp/custom": ">=0.3.5", | |
| 1149 | + "@jimp/plugin-crop": ">=0.3.5", | |
| 1150 | + "@jimp/plugin-resize": ">=0.3.5", | |
| 1151 | + "@jimp/plugin-scale": ">=0.3.5" | |
| 1152 | + } | |
| 1153 | + }, | |
| 1154 | + "node_modules/@jimp/plugins/node_modules/@jimp/plugin-crop": { | |
| 1155 | + "version": "0.22.12", | |
| 1156 | + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", | |
| 1157 | + "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", | |
| 611 | 1158 | "license": "MIT", |
| 612 | 1159 | "dependencies": { |
| 613 | 1160 | "@jimp/utils": "^0.22.12" |
| @@ -616,10 +1163,10 @@ | ||
| 616 | 1163 | "@jimp/custom": ">=0.3.5" |
| 617 | 1164 | } |
| 618 | 1165 | }, |
| 619 | 1166 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-invertdisplace": { |
| 620 | 1167 | "version": "0.22.12", |
| 621 | 1168 | "resolved": "https://registry.npmjs.org/@jimp/plugin-invertdisplace/-/plugin-invertdisplace-0.22.12.tgz", |
| 622 | 1169 | "integrity": "sha512-NqpRM8JRicxfK6aPPqKZA6+6rwxdBGzBwUIitiHaZw0QrJ64Ygd3+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6AsTc7BXr+xQ37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", |
| 623 | 1170 | "license": "MIT", |
| 624 | 1171 | "dependencies": { |
| 625 | 1172 | "@jimp/utils": "^0.22.12" |
| @@ -628,10 +1175,10 @@ | ||
| 628 | 1175 | "@jimp/custom": ">=0.3.5" |
| 629 | 1176 | } |
| 630 | 1177 | }, |
| 631 | 1178 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-maskdither": { |
| 632 | 1179 | "version": "0.22.12", |
| 633 | 1180 | "resolved": "https://registry.npmjs.org/@jimp/plugin-maskdither/-/plugin-maskdither-0.22.12.tgz", |
| 634 | 1181 | "integrity": "sha512-4AWZgjYgGdSdSKl1UUEanX8A85v4+DomtpUA099jRV8IEZUfn1wLv6QUm+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NAPE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", |
| 635 | 1182 | "license": "MIT", |
| 636 | 1183 | "dependencies": { |
| 637 | 1184 | "@jimp/utils": "^0.22.12" |
| @@ -640,10 +1187,10 @@ | ||
| 640 | 1187 | "@jimp/custom": ">=0.3.5" |
| 641 | 1188 | } |
| 642 | 1189 | }, |
| 643 | 1190 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-normalizefisheye": { |
| 644 | 1191 | "version": "0.22.12", |
| 645 | 1192 | "resolved": "https://registry.npmjs.org/@jimp/plugin-normalizefisheye/-/plugin-normalizefisheye-0.22.12.tgz", |
| 646 | 1193 | "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGCLGuUTsFg+As1FtAfOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", |
| 647 | 1194 | "license": "MIT", |
| 648 | 1195 | "dependencies": { |
| 649 | 1196 | "@jimp/utils": "^0.22.12" |
| @@ -652,24 +1199,23 @@ | ||
| 652 | 1199 | "@jimp/custom": ">=0.3.5" |
| 653 | 1200 | } |
| 654 | 1201 | }, |
| 655 | 1202 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-printflip": { |
| 656 | 1203 | "version": "0.22.12", |
| 657 | 1204 | "resolved": "https://registry.npmjs.org/@jimp/plugin-printflip/-/plugin-printflip-0.22.12.tgz", |
| 658 | 1205 | "integrity": "sha512-c7TnhHlxm87DJeSnwrm251Rop7GN8W0Yo/XOLjJUrF9LWk6kNclngyjIJs/whoiKYY7r21SbuJ5nuHVXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQinBIb7nlaLLxnvHX8Q==", |
| 659 | 1206 | "license": "MIT", |
| 660 | 1207 | "dependencies": { |
| 661 | 1208 | "@jimp/utils": "^0.22.12", |
| 662 | - "load-bmfont": "^1.4.1" | |
| 663 | 1209 | }, |
| 664 | 1210 | "peerDependencies": { |
| 665 | 1211 | "@jimp/custom": ">=0.3.5", |
| 666 | 1212 | "@jimp/plugin-blitrotate": ">=0.3.5" |
| 667 | 1213 | } |
| 668 | 1214 | }, |
| 669 | 1215 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-resizemask": { |
| 670 | 1216 | "version": "0.22.12", |
| 671 | 1217 | "resolved": "https://registry.npmjs.org/@jimp/plugin-resizemask/-/plugin-resizemask-0.22.12.tgz", |
| 672 | 1218 | "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX/4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/i82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/sXgNA==", |
| 673 | 1219 | "license": "MIT", |
| 674 | 1220 | "dependencies": { |
| 675 | 1221 | "@jimp/utils": "^0.22.12" |
| @@ -678,49 +1224,48 @@ | ||
| 678 | 1224 | "@jimp/custom": ">=0.3.5" |
| 679 | 1225 | } |
| 680 | 1226 | }, |
| 681 | 1227 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-rotateprint": { |
| 682 | 1228 | "version": "0.22.12", |
| 683 | 1229 | "resolved": "https://registry.npmjs.org/@jimp/plugin-rotateprint/-/plugin-rotateprint-0.22.12.tgz", |
| 684 | 1230 | "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvRc7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+emmmPPWGgaYNYt1gA7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", |
| 685 | 1231 | "license": "MIT", |
| 686 | 1232 | "dependencies": { |
| 687 | 1233 | "@jimp/utils": "^0.22.12", |
| 1234 | + "load-bmfont": "^1.4.1" | |
| 688 | 1235 | }, |
| 689 | 1236 | "peerDependencies": { |
| 690 | 1237 | "@jimp/custom": ">=0.3.5", |
| 691 | 1238 | "@jimp/plugin-blit": ">=0.3.5", |
| 692 | - "@jimp/plugin-crop": ">=0.3.5", | |
| 693 | - "@jimp/plugin-resize": ">=0.3.5" | |
| 694 | 1239 | } |
| 695 | 1240 | }, |
| 696 | 1241 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-scaleresize": { |
| 697 | 1242 | "version": "0.22.12", |
| 698 | 1243 | "resolved": "https://registry.npmjs.org/@jimp/plugin-scaleresize/-/plugin-scaleresize-0.22.12.tgz", |
| 699 | 1244 | "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", |
| 700 | 1245 | "license": "MIT", |
| 701 | 1246 | "dependencies": { |
| 702 | 1247 | "@jimp/utils": "^0.22.12" |
| 703 | 1248 | }, |
| 704 | 1249 | "peerDependencies": { |
| 705 | 1250 | "@jimp/custom": ">=0.3.5", |
| 706 | - "@jimp/plugin-resize": ">=0.3.5" | |
| 707 | 1251 | } |
| 708 | 1252 | }, |
| 709 | 1253 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-shadowrotate": { |
| 710 | 1254 | "version": "0.22.12", |
| 711 | 1255 | "resolved": "https://registry.npmjs.org/@jimp/plugin-shadowrotate/-/plugin-shadowrotate-0.22.12.tgz", |
| 712 | 1256 | "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV39YNEt7BPAFfTls2FGfKBVgwwLUuKqy+WWwTgE8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", |
| 713 | 1257 | "license": "MIT", |
| 714 | 1258 | "dependencies": { |
| 715 | 1259 | "@jimp/utils": "^0.22.12" |
| 716 | 1260 | }, |
| 717 | 1261 | "peerDependencies": { |
| 718 | 1262 | "@jimp/custom": ">=0.3.5", |
| 719 | 1263 | "@jimp/plugin-blurblit": ">=0.3.5", |
| 1264 | + "@jimp/plugin-crop": ">=0.3.5", | |
| 720 | 1265 | "@jimp/plugin-resize": ">=0.3.5" |
| 721 | 1266 | } |
| 722 | 1267 | }, |
| 723 | 1268 | "node_modules/@jimp/plugins/node_modules/@jimp/plugin-threshold": { |
| 724 | 1269 | "version": "0.22.12", |
| 725 | 1270 | "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", |
| 726 | 1271 | "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", |
| @@ -734,37 +1279,13 @@ | ||
| 734 | 1279 | "@jimp/plugin-resize": ">=0.8.0" |
| 735 | 1280 | } |
| 736 | 1281 | }, |
| 737 | 1282 | "node_modules/@jimp/plugins/node_modules/@jimp/utils": { |
| 738 | 1283 | "version": "0.22.12", |
| 739 | 1284 | "resolved": "https://registry.npmjs.org/@jimp/pluginsutils/-/pluginsutils-0.22.12.tgz", |
| 740 | 1285 | "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/XWILoTZsjTUASQcGoH0TuC0N7xm3wwnMKXk8TrSwAE71zt716Q==", |
| 741 | 1286 | "license": "MIT", |
| 742 | 1287 | "dependencies": { |
| 743 | 1288 | "@jimp/pluginregenerator-blitruntime": "^0.2213.123", |
| 744 | - "@jimp/plugin-blur": "^0.22.12", | |
| 745 | - "@jimp/plugin-circle": "^0.22.12", | |
| 746 | - "@jimp/plugin-color": "^0.22.12", | |
| 747 | - "@jimp/plugin-contain": "^0.22.12", | |
| 748 | - "@jimp/plugin-cover": "^0.22.12", | |
| 749 | - "@jimp/plugin-crop": "^0.22.12", | |
| 750 | - "@jimp/plugin-displace": "^0.22.12", | |
| 751 | - "@jimp/plugin-dither": "^0.22.12", | |
| 752 | - "@jimp/plugin-fisheye": "^0.22.12", | |
| 753 | - "@jimp/plugin-flip": "^0.22.12", | |
| 754 | - "@jimp/plugin-gaussian": "^0.22.12", | |
| 755 | - "@jimp/plugin-invert": "^0.22.12", | |
| 756 | - "@jimp/plugin-mask": "^0.22.12", | |
| 757 | - "@jimp/plugin-normalize": "^0.22.12", | |
| 758 | - "@jimp/plugin-print": "^0.22.12", | |
| 759 | - "@jimp/plugin-resize": "^0.22.12", | |
| 760 | - "@jimp/plugin-rotate": "^0.22.12", | |
| 761 | - "@jimp/plugin-scale": "^0.22.12", | |
| 762 | - "@jimp/plugin-shadow": "^0.22.12", | |
| 763 | - "@jimp/plugin-threshold": "^0.22.12", | |
| 764 | - "timm": "^1.6.1" | |
| 765 | - }, | |
| 766 | - "peerDependencies": { | |
| 767 | - "@jimp/custom": ">=0.3.5" | |
| 768 | 1289 | } |
| 769 | 1290 | }, |
| 770 | 1291 | "node_modules/@jimp/png": { |
| @@ -780,6 +1301,24 @@ | ||
| 780 | 1301 | "@jimp/custom": ">=0.3.5" |
| 781 | 1302 | } |
| 782 | 1303 | }, |
| 1304 | + "node_modules/@jimp/png/node_modules/@jimp/utils": { | |
| 1305 | + "version": "0.22.12", | |
| 1306 | + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", | |
| 1307 | + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", | |
| 1308 | + "license": "MIT", | |
| 1309 | + "dependencies": { | |
| 1310 | + "regenerator-runtime": "^0.13.3" | |
| 1311 | + } | |
| 1312 | + }, | |
| 1313 | + "node_modules/@jimp/png/node_modules/pngjs": { | |
| 1314 | + "version": "6.0.0", | |
| 1315 | + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", | |
| 1316 | + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", | |
| 1317 | + "license": "MIT", | |
| 1318 | + "engines": { | |
| 1319 | + "node": ">=12.13.0" | |
| 1320 | + } | |
| 1321 | + }, | |
| 783 | 1322 | "node_modules/@jimp/tiff": { |
| 784 | 1323 | "version": "0.22.12", |
| 785 | 1324 | "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", |
| @@ -793,29 +1332,81 @@ | ||
| 793 | 1332 | } |
| 794 | 1333 | }, |
| 795 | 1334 | "node_modules/@jimp/types": { |
| 796 | 1335 | "version": "01.226.120", |
| 797 | 1336 | "resolved": "https://registry.npmjs.org/@jimp/types/-/types-01.226.120.tgz", |
| 798 | 1337 | "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg==", |
| 799 | 1338 | "license": "MIT", |
| 800 | 1339 | "dependencies": { |
| 801 | 1340 | "@jimp/bmpzod": "^03.2223.128", |
| 802 | - "@jimp/gif": "^0.22.12", | |
| 803 | - "@jimp/jpeg": "^0.22.12", | |
| 804 | - "@jimp/png": "^0.22.12", | |
| 805 | - "@jimp/tiff": "^0.22.12", | |
| 806 | - "timm": "^1.6.1" | |
| 807 | 1341 | }, |
| 808 | 1342 | "peerDependenciesengines": { |
| 809 | 1343 | "@jimp/customnode": ">=0.3.518" |
| 810 | 1344 | } |
| 811 | 1345 | }, |
| 812 | 1346 | "node_modules/@jimp/utils": { |
| 813 | 1347 | "version": "01.226.120", |
| 814 | 1348 | "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-01.226.120.tgz", |
| 815 | 1349 | "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHWgqFTGEosKbOkYF/nMKXk8TrSwAE71zt716QWFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA==", |
| 816 | 1350 | "license": "MIT", |
| 817 | 1351 | "dependencies": { |
| 818 | 1352 | "regenerator-runtime@jimp/types": "^01.136.30", |
| 1353 | + "tinycolor2": "^1.6.0" | |
| 1354 | + }, | |
| 1355 | + "engines": { | |
| 1356 | + "node": ">=18" | |
| 1357 | + } | |
| 1358 | + }, | |
| 1359 | + "node_modules/@jimp/wasm-avif": { | |
| 1360 | + "version": "1.6.0", | |
| 1361 | + "resolved": "https://registry.npmjs.org/@jimp/wasm-avif/-/wasm-avif-1.6.0.tgz", | |
| 1362 | + "integrity": "sha512-OjiqqtD71MTLVQgB/oUOZ8PD+nxLQtl/Lyf/P/hhL56L6iCJbcciA3xO0Y9OJept7+R34ORY4f7RwWwt535DHg==", | |
| 1363 | + "license": "MIT", | |
| 1364 | + "dependencies": { | |
| 1365 | + "@jsquash/avif": "^1.3.0", | |
| 1366 | + "zod": "^3.23.8" | |
| 1367 | + }, | |
| 1368 | + "engines": { | |
| 1369 | + "node": ">=18" | |
| 1370 | + } | |
| 1371 | + }, | |
| 1372 | + "node_modules/@jimp/wasm-jpeg": { | |
| 1373 | + "version": "1.6.0", | |
| 1374 | + "resolved": "https://registry.npmjs.org/@jimp/wasm-jpeg/-/wasm-jpeg-1.6.0.tgz", | |
| 1375 | + "integrity": "sha512-zURjiESa79XXpMHzvvLMD3RC+wzFevS8lcTgyoZq4/y7qE5WrrUTWUBhr1UMFDueQ4gmOUf6EZ8L3/jkS/6nKQ==", | |
| 1376 | + "license": "MIT", | |
| 1377 | + "dependencies": { | |
| 1378 | + "@jsquash/jpeg": "^1.4.0", | |
| 1379 | + "zod": "^3.23.8" | |
| 1380 | + }, | |
| 1381 | + "engines": { | |
| 1382 | + "node": ">=18" | |
| 1383 | + } | |
| 1384 | + }, | |
| 1385 | + "node_modules/@jimp/wasm-png": { | |
| 1386 | + "version": "1.6.0", | |
| 1387 | + "resolved": "https://registry.npmjs.org/@jimp/wasm-png/-/wasm-png-1.6.0.tgz", | |
| 1388 | + "integrity": "sha512-D1xTVXpErApFH4YiOWZDoF8S8B6I3PgoCe38WsnTxDLfple8KGZMBdNjv3UO7vczsdlg5rATwWMBbNwxK03jNQ==", | |
| 1389 | + "license": "MIT", | |
| 1390 | + "dependencies": { | |
| 1391 | + "@jsquash/oxipng": "^2.3.0", | |
| 1392 | + "@jsquash/png": "^3.0.1", | |
| 1393 | + "zod": "^3.23.8" | |
| 1394 | + }, | |
| 1395 | + "engines": { | |
| 1396 | + "node": ">=18" | |
| 1397 | + } | |
| 1398 | + }, | |
| 1399 | + "node_modules/@jimp/wasm-webp": { | |
| 1400 | + "version": "1.6.0", | |
| 1401 | + "resolved": "https://registry.npmjs.org/@jimp/wasm-webp/-/wasm-webp-1.6.0.tgz", | |
| 1402 | + "integrity": "sha512-P0zUpK6n2XIAn8bt0F6rhSn1+FgteBTrL+TBb6Oqw8v5qEDJoNYkd6LlfZYN8YwtRBTBdZ8GFnWsg2Sar+qOkA==", | |
| 1403 | + "license": "MIT", | |
| 1404 | + "dependencies": { | |
| 1405 | + "@jsquash/webp": "^1.4.0", | |
| 1406 | + "zod": "^3.23.8" | |
| 1407 | + }, | |
| 1408 | + "engines": { | |
| 1409 | + "node": ">=18" | |
| 819 | 1410 | } |
| 820 | 1411 | }, |
| 821 | 1412 | "node_modules/@jridgewell/gen-mapping": { |
| @@ -876,6 +1467,45 @@ | ||
| 876 | 1467 | "@jridgewell/sourcemap-codec": "^1.4.14" |
| 877 | 1468 | } |
| 878 | 1469 | }, |
| 1470 | + "node_modules/@jsquash/avif": { | |
| 1471 | + "version": "1.3.0", | |
| 1472 | + "resolved": "https://registry.npmjs.org/@jsquash/avif/-/avif-1.3.0.tgz", | |
| 1473 | + "integrity": "sha512-N6zH27O/AioCPNGxaf33PYnUEQZmAjUz0JwwAf9eMHRdYItn+CxwxlsHSSOkFmZKW+v9uVX6c7ZPQ4RTXArL7A==", | |
| 1474 | + "license": "Apache-2.0", | |
| 1475 | + "dependencies": { | |
| 1476 | + "wasm-feature-detect": "^1.2.11" | |
| 1477 | + } | |
| 1478 | + }, | |
| 1479 | + "node_modules/@jsquash/jpeg": { | |
| 1480 | + "version": "1.5.0", | |
| 1481 | + "resolved": "https://registry.npmjs.org/@jsquash/jpeg/-/jpeg-1.5.0.tgz", | |
| 1482 | + "integrity": "sha512-Jam3X9BhbP1f+d58TfYobV/ZpYhCnawBF7YMS0Vt5Gi1v5Rk+xUdqYiZarAn0PwAzy2Zm2pPU/VzXHsLhwT9QQ==", | |
| 1483 | + "license": "Apache-2.0" | |
| 1484 | + }, | |
| 1485 | + "node_modules/@jsquash/oxipng": { | |
| 1486 | + "version": "2.3.0", | |
| 1487 | + "resolved": "https://registry.npmjs.org/@jsquash/oxipng/-/oxipng-2.3.0.tgz", | |
| 1488 | + "integrity": "sha512-aQ8wiEp6ztlTMXc+RMt/CG8crU3mEHDU+h+JYkIi6ctMhlh8+Ltj5XwQFfBuyzKYrp8NxaFW80Dp824bqjr+zA==", | |
| 1489 | + "license": "Apache-2.0", | |
| 1490 | + "dependencies": { | |
| 1491 | + "wasm-feature-detect": "^1.2.11" | |
| 1492 | + } | |
| 1493 | + }, | |
| 1494 | + "node_modules/@jsquash/png": { | |
| 1495 | + "version": "3.0.1", | |
| 1496 | + "resolved": "https://registry.npmjs.org/@jsquash/png/-/png-3.0.1.tgz", | |
| 1497 | + "integrity": "sha512-Bnvv93Y5LL92cuk2r2gpV+9JKuDo2/w7bOODw1iPxk8VARknky0sS1tSDgMosUdhNb4CdMlcCm3TMzTaqa3zZw==", | |
| 1498 | + "license": "Apache-2.0" | |
| 1499 | + }, | |
| 1500 | + "node_modules/@jsquash/webp": { | |
| 1501 | + "version": "1.4.0", | |
| 1502 | + "resolved": "https://registry.npmjs.org/@jsquash/webp/-/webp-1.4.0.tgz", | |
| 1503 | + "integrity": "sha512-yKJb6Hilq+qV/4C4qTDEalBobNwJO09LeHHtilmWg5mYHFUDwMunfeAap/r3cL5KsHkGOoI0IjY2nKbTaHq9Bw==", | |
| 1504 | + "license": "Apache-2.0", | |
| 1505 | + "dependencies": { | |
| 1506 | + "wasm-feature-detect": "^1.2.11" | |
| 1507 | + } | |
| 1508 | + }, | |
| 879 | 1509 | "node_modules/@kwsites/file-exists": { |
| 880 | 1510 | "version": "1.1.1", |
| 881 | 1511 | "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", |
| @@ -970,6 +1600,19 @@ | ||
| 970 | 1600 | "node": ">=14" |
| 971 | 1601 | } |
| 972 | 1602 | }, |
| 1603 | + "node_modules/@pkgr/core": { | |
| 1604 | + "version": "0.1.1", | |
| 1605 | + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", | |
| 1606 | + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", | |
| 1607 | + "dev": true, | |
| 1608 | + "license": "MIT", | |
| 1609 | + "engines": { | |
| 1610 | + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" | |
| 1611 | + }, | |
| 1612 | + "funding": { | |
| 1613 | + "url": "https://opencollective.com/unts" | |
| 1614 | + } | |
| 1615 | + }, | |
| 973 | 1616 | "node_modules/@popperjs/core": { |
| 974 | 1617 | "version": "2.11.8", |
| 975 | 1618 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", |
| @@ -1389,13 +2032,6 @@ | ||
| 1389 | 2032 | "dev": true, |
| 1390 | 2033 | "license": "MIT" |
| 1391 | 2034 | }, |
| 1392 | - "node_modules/@types/png-chunks-encode": { | |
| 1393 | - "version": "1.0.2", | |
| 1394 | - "resolved": "https://registry.npmjs.org/@types/png-chunks-encode/-/png-chunks-encode-1.0.2.tgz", | |
| 1395 | - "integrity": "sha512-Dxn0aXEcSg1wVeHjvNlygm/+fKBDzWMCdxJYhjGUTeefFW/jYxWcrg+W7ppLBfH44iJMqeVBHtHBwtYQUeYvgw==", | |
| 1396 | - "dev": true, | |
| 1397 | - "license": "MIT" | |
| 1398 | - }, | |
| 1399 | 2035 | "node_modules/@types/png-chunks-extract": { |
| 1400 | 2036 | "version": "1.0.2", |
| 1401 | 2037 | "resolved": "https://registry.npmjs.org/@types/png-chunks-extract/-/png-chunks-extract-1.0.2.tgz", |
| @@ -1926,29 +2562,6 @@ | ||
| 1926 | 2562 | "balanced-match": "^1.0.0" |
| 1927 | 2563 | } |
| 1928 | 2564 | }, |
| 1929 | - "node_modules/archiver-utils/node_modules/buffer": { | |
| 1930 | - "version": "6.0.3", | |
| 1931 | - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", | |
| 1932 | - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", | |
| 1933 | - "funding": [ | |
| 1934 | - { | |
| 1935 | - "type": "github", | |
| 1936 | - "url": "https://github.com/sponsors/feross" | |
| 1937 | - }, | |
| 1938 | - { | |
| 1939 | - "type": "patreon", | |
| 1940 | - "url": "https://www.patreon.com/feross" | |
| 1941 | - }, | |
| 1942 | - { | |
| 1943 | - "type": "consulting", | |
| 1944 | - "url": "https://feross.org/support" | |
| 1945 | - } | |
| 1946 | - ], | |
| 1947 | - "dependencies": { | |
| 1948 | - "base64-js": "^1.3.1", | |
| 1949 | - "ieee754": "^1.2.1" | |
| 1950 | - } | |
| 1951 | - }, | |
| 1952 | 2565 | "node_modules/archiver-utils/node_modules/glob": { |
| 1953 | 2566 | "version": "10.3.12", |
| 1954 | 2567 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", |
| @@ -2026,29 +2639,6 @@ | ||
| 2026 | 2639 | "safe-buffer": "~5.2.0" |
| 2027 | 2640 | } |
| 2028 | 2641 | }, |
| 2029 | - "node_modules/archiver/node_modules/buffer": { | |
| 2030 | - "version": "6.0.3", | |
| 2031 | - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", | |
| 2032 | - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", | |
| 2033 | - "funding": [ | |
| 2034 | - { | |
| 2035 | - "type": "github", | |
| 2036 | - "url": "https://github.com/sponsors/feross" | |
| 2037 | - }, | |
| 2038 | - { | |
| 2039 | - "type": "patreon", | |
| 2040 | - "url": "https://www.patreon.com/feross" | |
| 2041 | - }, | |
| 2042 | - { | |
| 2043 | - "type": "consulting", | |
| 2044 | - "url": "https://feross.org/support" | |
| 2045 | - } | |
| 2046 | - ], | |
| 2047 | - "dependencies": { | |
| 2048 | - "base64-js": "^1.3.1", | |
| 2049 | - "ieee754": "^1.2.1" | |
| 2050 | - } | |
| 2051 | - }, | |
| 2052 | 2642 | "node_modules/archiver/node_modules/buffer-crc32": { |
| 2053 | 2643 | "version": "1.0.0", |
| 2054 | 2644 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", |
| @@ -2099,6 +2689,16 @@ | ||
| 2099 | 2689 | "safe-buffer": "~5.2.0" |
| 2100 | 2690 | } |
| 2101 | 2691 | }, |
| 2692 | + "node_modules/are-docs-informative": { | |
| 2693 | + "version": "0.0.2", | |
| 2694 | + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", | |
| 2695 | + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", | |
| 2696 | + "dev": true, | |
| 2697 | + "license": "MIT", | |
| 2698 | + "engines": { | |
| 2699 | + "node": ">=14" | |
| 2700 | + } | |
| 2701 | + }, | |
| 2102 | 2702 | "node_modules/argparse": { |
| 2103 | 2703 | "version": "2.0.1", |
| 2104 | 2704 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", |
| @@ -2135,6 +2735,15 @@ | ||
| 2135 | 2735 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", |
| 2136 | 2736 | "license": "MIT" |
| 2137 | 2737 | }, |
| 2738 | + "node_modules/await-to-js": { | |
| 2739 | + "version": "3.0.0", | |
| 2740 | + "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", | |
| 2741 | + "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==", | |
| 2742 | + "license": "MIT", | |
| 2743 | + "engines": { | |
| 2744 | + "node": ">=6.0.0" | |
| 2745 | + } | |
| 2746 | + }, | |
| 2138 | 2747 | "node_modules/axios": { |
| 2139 | 2748 | "version": "1.8.3", |
| 2140 | 2749 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz", |
| @@ -2212,6 +2821,12 @@ | ||
| 2212 | 2821 | "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", |
| 2213 | 2822 | "license": "MIT" |
| 2214 | 2823 | }, |
| 2824 | + "node_modules/bmp-ts": { | |
| 2825 | + "version": "1.0.9", | |
| 2826 | + "resolved": "https://registry.npmjs.org/bmp-ts/-/bmp-ts-1.0.9.tgz", | |
| 2827 | + "integrity": "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==", | |
| 2828 | + "license": "MIT" | |
| 2829 | + }, | |
| 2215 | 2830 | "node_modules/body-parser": { |
| 2216 | 2831 | "version": "1.20.3", |
| 2217 | 2832 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", |
| @@ -2304,9 +2919,9 @@ | ||
| 2304 | 2919 | } |
| 2305 | 2920 | }, |
| 2306 | 2921 | "node_modules/buffer": { |
| 2307 | 2922 | "version": "56.70.13", |
| 2308 | 2923 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-56.70.13.tgz", |
| 2309 | 2924 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHYFTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQpDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", |
| 2310 | 2925 | "funding": [ |
| 2311 | 2926 | { |
| 2312 | 2927 | "type": "github", |
| @@ -2324,7 +2939,7 @@ | ||
| 2324 | 2939 | "license": "MIT", |
| 2325 | 2940 | "dependencies": { |
| 2326 | 2941 | "base64-js": "^1.3.1", |
| 2327 | 2942 | "ieee754": "^1.12.131" |
| 2328 | 2943 | } |
| 2329 | 2944 | }, |
| 2330 | 2945 | "node_modules/buffer-crc32": { |
| @@ -2614,6 +3229,16 @@ | ||
| 2614 | 3229 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", |
| 2615 | 3230 | "license": "MIT" |
| 2616 | 3231 | }, |
| 3232 | + "node_modules/comment-parser": { | |
| 3233 | + "version": "1.4.1", | |
| 3234 | + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", | |
| 3235 | + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", | |
| 3236 | + "dev": true, | |
| 3237 | + "license": "MIT", | |
| 3238 | + "engines": { | |
| 3239 | + "node": ">= 12.0.0" | |
| 3240 | + } | |
| 3241 | + }, | |
| 2617 | 3242 | "node_modules/compress-commons": { |
| 2618 | 3243 | "version": "6.0.2", |
| 2619 | 3244 | "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", |
| @@ -2629,29 +3254,6 @@ | ||
| 2629 | 3254 | "node": ">= 14" |
| 2630 | 3255 | } |
| 2631 | 3256 | }, |
| 2632 | - "node_modules/compress-commons/node_modules/buffer": { | |
| 2633 | - "version": "6.0.3", | |
| 2634 | - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", | |
| 2635 | - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", | |
| 2636 | - "funding": [ | |
| 2637 | - { | |
| 2638 | - "type": "github", | |
| 2639 | - "url": "https://github.com/sponsors/feross" | |
| 2640 | - }, | |
| 2641 | - { | |
| 2642 | - "type": "patreon", | |
| 2643 | - "url": "https://www.patreon.com/feross" | |
| 2644 | - }, | |
| 2645 | - { | |
| 2646 | - "type": "consulting", | |
| 2647 | - "url": "https://feross.org/support" | |
| 2648 | - } | |
| 2649 | - ], | |
| 2650 | - "dependencies": { | |
| 2651 | - "base64-js": "^1.3.1", | |
| 2652 | - "ieee754": "^1.2.1" | |
| 2653 | - } | |
| 2654 | - }, | |
| 2655 | 3257 | "node_modules/compress-commons/node_modules/crc-32": { |
| 2656 | 3258 | "version": "1.2.2", |
| 2657 | 3259 | "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", |
| @@ -2928,8 +3530,25 @@ | ||
| 2928 | 3530 | "object-assign": "^4", |
| 2929 | 3531 | "vary": "^1" |
| 2930 | 3532 | }, |
| 2931 | 3533 | "engines": { |
| 2932 | 3534 | "node": ">= 0.10" |
| 3535 | + } | |
| 3536 | + }, | |
| 3537 | + "node_modules/crc": { | |
| 3538 | + "version": "4.3.2", | |
| 3539 | + "resolved": "https://registry.npmjs.org/crc/-/crc-4.3.2.tgz", | |
| 3540 | + "integrity": "sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==", | |
| 3541 | + "license": "MIT", | |
| 3542 | + "engines": { | |
| 3543 | + "node": ">=12" | |
| 3544 | + }, | |
| 3545 | + "peerDependencies": { | |
| 3546 | + "buffer": ">=6.0.3" | |
| 3547 | + }, | |
| 3548 | + "peerDependenciesMeta": { | |
| 3549 | + "buffer": { | |
| 3550 | + "optional": true | |
| 3551 | + } | |
| 2933 | 3552 | } |
| 2934 | 3553 | }, |
| 2935 | 3554 | "node_modules/crc-32": { |
| @@ -2953,29 +3572,6 @@ | ||
| 2953 | 3572 | "node": ">= 14" |
| 2954 | 3573 | } |
| 2955 | 3574 | }, |
| 2956 | - "node_modules/crc32-stream/node_modules/buffer": { | |
| 2957 | - "version": "6.0.3", | |
| 2958 | - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", | |
| 2959 | - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", | |
| 2960 | - "funding": [ | |
| 2961 | - { | |
| 2962 | - "type": "github", | |
| 2963 | - "url": "https://github.com/sponsors/feross" | |
| 2964 | - }, | |
| 2965 | - { | |
| 2966 | - "type": "patreon", | |
| 2967 | - "url": "https://www.patreon.com/feross" | |
| 2968 | - }, | |
| 2969 | - { | |
| 2970 | - "type": "consulting", | |
| 2971 | - "url": "https://feross.org/support" | |
| 2972 | - } | |
| 2973 | - ], | |
| 2974 | - "dependencies": { | |
| 2975 | - "base64-js": "^1.3.1", | |
| 2976 | - "ieee754": "^1.2.1" | |
| 2977 | - } | |
| 2978 | - }, | |
| 2979 | 3575 | "node_modules/crc32-stream/node_modules/crc-32": { |
| 2980 | 3576 | "version": "1.2.2", |
| 2981 | 3577 | "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", |
| @@ -3560,6 +4156,69 @@ | ||
| 3560 | 4156 | "url": "https://opencollective.com/eslint" |
| 3561 | 4157 | } |
| 3562 | 4158 | }, |
| 4159 | + "node_modules/eslint-plugin-jsdoc": { | |
| 4160 | + "version": "48.10.0", | |
| 4161 | + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz", | |
| 4162 | + "integrity": "sha512-BEli0k8E0dzhJairAllwlkGnyYDZVKNn4WDmyKy+v6J5qGNuofjzxwNUi+55BOGmyO9mKBhqaidwGy+dxndn/Q==", | |
| 4163 | + "dev": true, | |
| 4164 | + "license": "BSD-3-Clause", | |
| 4165 | + "dependencies": { | |
| 4166 | + "@es-joy/jsdoccomment": "~0.46.0", | |
| 4167 | + "are-docs-informative": "^0.0.2", | |
| 4168 | + "comment-parser": "1.4.1", | |
| 4169 | + "debug": "^4.3.5", | |
| 4170 | + "escape-string-regexp": "^4.0.0", | |
| 4171 | + "esquery": "^1.6.0", | |
| 4172 | + "parse-imports": "^2.1.1", | |
| 4173 | + "semver": "^7.6.3", | |
| 4174 | + "spdx-expression-parse": "^4.0.0", | |
| 4175 | + "synckit": "^0.9.1" | |
| 4176 | + }, | |
| 4177 | + "engines": { | |
| 4178 | + "node": ">=18" | |
| 4179 | + }, | |
| 4180 | + "peerDependencies": { | |
| 4181 | + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" | |
| 4182 | + } | |
| 4183 | + }, | |
| 4184 | + "node_modules/eslint-plugin-jsdoc/node_modules/debug": { | |
| 4185 | + "version": "4.4.0", | |
| 4186 | + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", | |
| 4187 | + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", | |
| 4188 | + "dev": true, | |
| 4189 | + "license": "MIT", | |
| 4190 | + "dependencies": { | |
| 4191 | + "ms": "^2.1.3" | |
| 4192 | + }, | |
| 4193 | + "engines": { | |
| 4194 | + "node": ">=6.0" | |
| 4195 | + }, | |
| 4196 | + "peerDependenciesMeta": { | |
| 4197 | + "supports-color": { | |
| 4198 | + "optional": true | |
| 4199 | + } | |
| 4200 | + } | |
| 4201 | + }, | |
| 4202 | + "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { | |
| 4203 | + "version": "4.0.0", | |
| 4204 | + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", | |
| 4205 | + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", | |
| 4206 | + "dev": true, | |
| 4207 | + "license": "MIT", | |
| 4208 | + "engines": { | |
| 4209 | + "node": ">=10" | |
| 4210 | + }, | |
| 4211 | + "funding": { | |
| 4212 | + "url": "https://github.com/sponsors/sindresorhus" | |
| 4213 | + } | |
| 4214 | + }, | |
| 4215 | + "node_modules/eslint-plugin-jsdoc/node_modules/ms": { | |
| 4216 | + "version": "2.1.3", | |
| 4217 | + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | |
| 4218 | + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | |
| 4219 | + "dev": true, | |
| 4220 | + "license": "MIT" | |
| 4221 | + }, | |
| 3563 | 4222 | "node_modules/eslint-scope": { |
| 3564 | 4223 | "version": "7.2.2", |
| 3565 | 4224 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", |
| @@ -3690,9 +4349,9 @@ | ||
| 3690 | 4349 | } |
| 3691 | 4350 | }, |
| 3692 | 4351 | "node_modules/esquery": { |
| 3693 | 4352 | "version": "1.56.0", |
| 3694 | 4353 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.56.0.tgz", |
| 3695 | 4354 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idISca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/9fIU5GjG73IgjKMVg5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", |
| 3696 | 4355 | "dev": true, |
| 3697 | 4356 | "license": "BSD-3-Clause", |
| 3698 | 4357 | "dependencies": { |
| @@ -4978,18 +5637,6 @@ | ||
| 4978 | 5637 | "url": "https://github.com/chalk/supports-color?sponsor=1" |
| 4979 | 5638 | } |
| 4980 | 5639 | }, |
| 4981 | - "node_modules/jimp": { | |
| 4982 | - "version": "0.22.12", | |
| 4983 | - "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", | |
| 4984 | - "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", | |
| 4985 | - "license": "MIT", | |
| 4986 | - "dependencies": { | |
| 4987 | - "@jimp/custom": "^0.22.12", | |
| 4988 | - "@jimp/plugins": "^0.22.12", | |
| 4989 | - "@jimp/types": "^0.22.12", | |
| 4990 | - "regenerator-runtime": "^0.13.3" | |
| 4991 | - } | |
| 4992 | - }, | |
| 4993 | 5640 | "node_modules/jpeg-js": { |
| 4994 | 5641 | "version": "0.4.4", |
| 4995 | 5642 | "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", |
| @@ -5015,6 +5662,16 @@ | ||
| 5015 | 5662 | "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", |
| 5016 | 5663 | "license": "MIT" |
| 5017 | 5664 | }, |
| 5665 | + "node_modules/jsdoc-type-pratt-parser": { | |
| 5666 | + "version": "4.0.0", | |
| 5667 | + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", | |
| 5668 | + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", | |
| 5669 | + "dev": true, | |
| 5670 | + "license": "MIT", | |
| 5671 | + "engines": { | |
| 5672 | + "node": ">=12.0.0" | |
| 5673 | + } | |
| 5674 | + }, | |
| 5018 | 5675 | "node_modules/json-buffer": { |
| 5019 | 5676 | "version": "3.0.1", |
| 5020 | 5677 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", |
| @@ -5886,11 +6543,25 @@ | ||
| 5886 | 6543 | } |
| 5887 | 6544 | }, |
| 5888 | 6545 | "node_modules/parse-headers": { |
| 5889 | 6546 | "version": "2.0.56", |
| 5890 | 6547 | "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.56.tgz", |
| 5891 | 6548 | "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1ZauTz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/HwI75HA5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==", |
| 5892 | 6549 | "license": "MIT" |
| 5893 | 6550 | }, |
| 6551 | + "node_modules/parse-imports": { | |
| 6552 | + "version": "2.2.1", | |
| 6553 | + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", | |
| 6554 | + "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", | |
| 6555 | + "dev": true, | |
| 6556 | + "license": "Apache-2.0 AND MIT", | |
| 6557 | + "dependencies": { | |
| 6558 | + "es-module-lexer": "^1.5.3", | |
| 6559 | + "slashes": "^3.0.12" | |
| 6560 | + }, | |
| 6561 | + "engines": { | |
| 6562 | + "node": ">= 18" | |
| 6563 | + } | |
| 6564 | + }, | |
| 5894 | 6565 | "node_modules/parse5": { |
| 5895 | 6566 | "version": "7.1.2", |
| 5896 | 6567 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", |
| @@ -6012,27 +6683,6 @@ | ||
| 6012 | 6683 | "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", |
| 6013 | 6684 | "license": "ISC" |
| 6014 | 6685 | }, |
| 6015 | - "node_modules/pixelmatch": { | |
| 6016 | - "version": "4.0.2", | |
| 6017 | - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", | |
| 6018 | - "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", | |
| 6019 | - "license": "ISC", | |
| 6020 | - "dependencies": { | |
| 6021 | - "pngjs": "^3.0.0" | |
| 6022 | - }, | |
| 6023 | - "bin": { | |
| 6024 | - "pixelmatch": "bin/pixelmatch" | |
| 6025 | - } | |
| 6026 | - }, | |
| 6027 | - "node_modules/pixelmatch/node_modules/pngjs": { | |
| 6028 | - "version": "3.4.0", | |
| 6029 | - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", | |
| 6030 | - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", | |
| 6031 | - "license": "MIT", | |
| 6032 | - "engines": { | |
| 6033 | - "node": ">=4.0.0" | |
| 6034 | - } | |
| 6035 | - }, | |
| 6036 | 6686 | "node_modules/platform": { |
| 6037 | 6687 | "version": "1.3.6", |
| 6038 | 6688 | "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", |
| @@ -6045,16 +6695,6 @@ | ||
| 6045 | 6695 | "integrity": "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw==", |
| 6046 | 6696 | "license": "MIT" |
| 6047 | 6697 | }, |
| 6048 | - "node_modules/png-chunks-encode": { | |
| 6049 | - "version": "1.0.0", | |
| 6050 | - "resolved": "https://registry.npmjs.org/png-chunks-encode/-/png-chunks-encode-1.0.0.tgz", | |
| 6051 | - "integrity": "sha512-J1jcHgbQRsIIgx5wxW9UmCymV3wwn4qCCJl6KYgEU/yHCh/L2Mwq/nMOkRPtmV79TLxRZj5w3tH69pvygFkDqA==", | |
| 6052 | - "license": "MIT", | |
| 6053 | - "dependencies": { | |
| 6054 | - "crc-32": "^0.3.0", | |
| 6055 | - "sliced": "^1.0.1" | |
| 6056 | - } | |
| 6057 | - }, | |
| 6058 | 6698 | "node_modules/png-chunks-extract": { |
| 6059 | 6699 | "version": "1.0.0", |
| 6060 | 6700 | "resolved": "https://registry.npmjs.org/png-chunks-extract/-/png-chunks-extract-1.0.0.tgz", |
| @@ -6065,12 +6705,12 @@ | ||
| 6065 | 6705 | } |
| 6066 | 6706 | }, |
| 6067 | 6707 | "node_modules/pngjs": { |
| 6068 | 6708 | "version": "67.0.0", |
| 6069 | 6709 | "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-67.0.0.tgz", |
| 6070 | 6710 | "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28KLKWqWJRhstyYo9pGvgor/m5bjBWKsC29KyoMfHbypaygivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", |
| 6071 | 6711 | "license": "MIT", |
| 6072 | 6712 | "engines": { |
| 6073 | 6713 | "node": ">=1214.1319.0" |
| 6074 | 6714 | } |
| 6075 | 6715 | }, |
| 6076 | 6716 | "node_modules/prelude-ls": { |
| @@ -6342,12 +6982,12 @@ | ||
| 6342 | 6982 | } |
| 6343 | 6983 | }, |
| 6344 | 6984 | "node_modules/readable-web-to-node-stream": { |
| 6345 | 6985 | "version": "3.0.24", |
| 6346 | 6986 | "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.24.tgz", |
| 6347 | 6987 | "integrity": "sha512-ePeK6cc1EcKLEhJFt9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/AebMCLL+GgSKhuygrZCVPtb/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGwXHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==", |
| 6348 | 6988 | "license": "MIT", |
| 6349 | 6989 | "dependencies": { |
| 6350 | 6990 | "readable-stream": "^34.67.0" |
| 6351 | 6991 | }, |
| 6352 | 6992 | "engines": { |
| 6353 | 6993 | "node": ">=8" |
| @@ -6358,17 +6998,48 @@ | ||
| 6358 | 6998 | } |
| 6359 | 6999 | }, |
| 6360 | 7000 | "node_modules/readable-web-to-node-stream/node_modules/readable-stream": { |
| 6361 | 7001 | "version": "34.67.20", |
| 6362 | 7002 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-34.67.20.tgz", |
| 6363 | 7003 | "integrity": "sha512-9uoIGGmcpTLwPga8Bn6/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoAZ75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", |
| 6364 | 7004 | "license": "MIT", |
| 6365 | 7005 | "dependencies": { |
| 6366 | 7006 | "inheritsabort-controller": "^23.0.30", |
| 6367 | 7007 | "string_decoderbuffer": "^16.10.13", |
| 6368 | 7008 | "util-deprecateevents": "^13.03.10", |
| 7009 | + "process": "^0.11.10", | |
| 7010 | + "string_decoder": "^1.3.0" | |
| 6369 | 7011 | }, |
| 6370 | 7012 | "engines": { |
| 6371 | - "node": ">= 6" | |
| 7013 | + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" | |
| 7014 | + } | |
| 7015 | + }, | |
| 7016 | + "node_modules/readable-web-to-node-stream/node_modules/safe-buffer": { | |
| 7017 | + "version": "5.2.1", | |
| 7018 | + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | |
| 7019 | + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", | |
| 7020 | + "funding": [ | |
| 7021 | + { | |
| 7022 | + "type": "github", | |
| 7023 | + "url": "https://github.com/sponsors/feross" | |
| 7024 | + }, | |
| 7025 | + { | |
| 7026 | + "type": "patreon", | |
| 7027 | + "url": "https://www.patreon.com/feross" | |
| 7028 | + }, | |
| 7029 | + { | |
| 7030 | + "type": "consulting", | |
| 7031 | + "url": "https://feross.org/support" | |
| 7032 | + } | |
| 7033 | + ], | |
| 7034 | + "license": "MIT" | |
| 7035 | + }, | |
| 7036 | + "node_modules/readable-web-to-node-stream/node_modules/string_decoder": { | |
| 7037 | + "version": "1.3.0", | |
| 7038 | + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", | |
| 7039 | + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", | |
| 7040 | + "license": "MIT", | |
| 7041 | + "dependencies": { | |
| 7042 | + "safe-buffer": "~5.2.0" | |
| 6372 | 7043 | } |
| 6373 | 7044 | }, |
| 6374 | 7045 | "node_modules/readdir-glob": { |
| @@ -6600,6 +7271,19 @@ | ||
| 6600 | 7271 | "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", |
| 6601 | 7272 | "license": "MIT" |
| 6602 | 7273 | }, |
| 7274 | + "node_modules/semver": { | |
| 7275 | + "version": "7.7.1", | |
| 7276 | + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", | |
| 7277 | + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", | |
| 7278 | + "dev": true, | |
| 7279 | + "license": "ISC", | |
| 7280 | + "bin": { | |
| 7281 | + "semver": "bin/semver.js" | |
| 7282 | + }, | |
| 7283 | + "engines": { | |
| 7284 | + "node": ">=10" | |
| 7285 | + } | |
| 7286 | + }, | |
| 6603 | 7287 | "node_modules/send": { |
| 6604 | 7288 | "version": "0.19.0", |
| 6605 | 7289 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", |
| @@ -6773,6 +7457,35 @@ | ||
| 6773 | 7457 | "onnxruntime-web": "1.14.0" |
| 6774 | 7458 | } |
| 6775 | 7459 | }, |
| 7460 | + "node_modules/sillytavern-transformers/node_modules/@jimp/types": { | |
| 7461 | + "version": "0.22.12", | |
| 7462 | + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", | |
| 7463 | + "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", | |
| 7464 | + "license": "MIT", | |
| 7465 | + "dependencies": { | |
| 7466 | + "@jimp/bmp": "^0.22.12", | |
| 7467 | + "@jimp/gif": "^0.22.12", | |
| 7468 | + "@jimp/jpeg": "^0.22.12", | |
| 7469 | + "@jimp/png": "^0.22.12", | |
| 7470 | + "@jimp/tiff": "^0.22.12", | |
| 7471 | + "timm": "^1.6.1" | |
| 7472 | + }, | |
| 7473 | + "peerDependencies": { | |
| 7474 | + "@jimp/custom": ">=0.3.5" | |
| 7475 | + } | |
| 7476 | + }, | |
| 7477 | + "node_modules/sillytavern-transformers/node_modules/jimp": { | |
| 7478 | + "version": "0.22.12", | |
| 7479 | + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.12.tgz", | |
| 7480 | + "integrity": "sha512-R5jZaYDnfkxKJy1dwLpj/7cvyjxiclxU3F4TrI/J4j2rS0niq6YDUMoPn5hs8GDpO+OZGo7Ky057CRtWesyhfg==", | |
| 7481 | + "license": "MIT", | |
| 7482 | + "dependencies": { | |
| 7483 | + "@jimp/custom": "^0.22.12", | |
| 7484 | + "@jimp/plugins": "^0.22.12", | |
| 7485 | + "@jimp/types": "^0.22.12", | |
| 7486 | + "regenerator-runtime": "^0.13.3" | |
| 7487 | + } | |
| 7488 | + }, | |
| 6776 | 7489 | "node_modules/simple-git": { |
| 6777 | 7490 | "version": "3.27.0", |
| 6778 | 7491 | "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.27.0.tgz", |
| @@ -6811,11 +7524,12 @@ | ||
| 6811 | 7524 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", |
| 6812 | 7525 | "license": "MIT" |
| 6813 | 7526 | }, |
| 6814 | 7527 | "node_modules/slicedslashes": { |
| 6815 | 7528 | "version": "13.0.112", |
| 6816 | 7529 | "resolved": "https://registry.npmjs.org/slicedslashes/-/slicedslashes-13.0.112.tgz", |
| 6817 | 7530 | "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2XxzmQ9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yAkWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", |
| 6818 | 7531 | "licensedev": "MIT"true, |
| 7532 | + "license": "ISC" | |
| 6819 | 7533 | }, |
| 6820 | 7534 | "node_modules/slidetoggle": { |
| 6821 | 7535 | "version": "4.0.0", |
| @@ -6903,6 +7617,31 @@ | ||
| 6903 | 7617 | "source-map": "^0.6.0" |
| 6904 | 7618 | } |
| 6905 | 7619 | }, |
| 7620 | + "node_modules/spdx-exceptions": { | |
| 7621 | + "version": "2.5.0", | |
| 7622 | + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", | |
| 7623 | + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", | |
| 7624 | + "dev": true, | |
| 7625 | + "license": "CC-BY-3.0" | |
| 7626 | + }, | |
| 7627 | + "node_modules/spdx-expression-parse": { | |
| 7628 | + "version": "4.0.0", | |
| 7629 | + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", | |
| 7630 | + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", | |
| 7631 | + "dev": true, | |
| 7632 | + "license": "MIT", | |
| 7633 | + "dependencies": { | |
| 7634 | + "spdx-exceptions": "^2.1.0", | |
| 7635 | + "spdx-license-ids": "^3.0.0" | |
| 7636 | + } | |
| 7637 | + }, | |
| 7638 | + "node_modules/spdx-license-ids": { | |
| 7639 | + "version": "3.0.21", | |
| 7640 | + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", | |
| 7641 | + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", | |
| 7642 | + "dev": true, | |
| 7643 | + "license": "CC0-1.0" | |
| 7644 | + }, | |
| 6906 | 7645 | "node_modules/sprintf-js": { |
| 6907 | 7646 | "version": "1.1.3", |
| 6908 | 7647 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", |
| @@ -7042,6 +7781,23 @@ | ||
| 7042 | 7781 | "node": ">=8" |
| 7043 | 7782 | } |
| 7044 | 7783 | }, |
| 7784 | + "node_modules/synckit": { | |
| 7785 | + "version": "0.9.2", | |
| 7786 | + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", | |
| 7787 | + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", | |
| 7788 | + "dev": true, | |
| 7789 | + "license": "MIT", | |
| 7790 | + "dependencies": { | |
| 7791 | + "@pkgr/core": "^0.1.0", | |
| 7792 | + "tslib": "^2.6.2" | |
| 7793 | + }, | |
| 7794 | + "engines": { | |
| 7795 | + "node": "^14.18.0 || >=16.0.0" | |
| 7796 | + }, | |
| 7797 | + "funding": { | |
| 7798 | + "url": "https://opencollective.com/unts" | |
| 7799 | + } | |
| 7800 | + }, | |
| 7045 | 7801 | "node_modules/tapable": { |
| 7046 | 7802 | "version": "2.2.1", |
| 7047 | 7803 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", |
| @@ -7391,6 +8147,12 @@ | ||
| 7391 | 8147 | "vectra": "bin/vectra.js" |
| 7392 | 8148 | } |
| 7393 | 8149 | }, |
| 8150 | + "node_modules/wasm-feature-detect": { | |
| 8151 | + "version": "1.8.0", | |
| 8152 | + "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz", | |
| 8153 | + "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==", | |
| 8154 | + "license": "Apache-2.0" | |
| 8155 | + }, | |
| 7394 | 8156 | "node_modules/watchpack": { |
| 7395 | 8157 | "version": "2.4.2", |
| 7396 | 8158 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", |
| @@ -7757,29 +8519,6 @@ | ||
| 7757 | 8519 | "node": ">= 14" |
| 7758 | 8520 | } |
| 7759 | 8521 | }, |
| 7760 | - "node_modules/zip-stream/node_modules/buffer": { | |
| 7761 | - "version": "6.0.3", | |
| 7762 | - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", | |
| 7763 | - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", | |
| 7764 | - "funding": [ | |
| 7765 | - { | |
| 7766 | - "type": "github", | |
| 7767 | - "url": "https://github.com/sponsors/feross" | |
| 7768 | - }, | |
| 7769 | - { | |
| 7770 | - "type": "patreon", | |
| 7771 | - "url": "https://www.patreon.com/feross" | |
| 7772 | - }, | |
| 7773 | - { | |
| 7774 | - "type": "consulting", | |
| 7775 | - "url": "https://feross.org/support" | |
| 7776 | - } | |
| 7777 | - ], | |
| 7778 | - "dependencies": { | |
| 7779 | - "base64-js": "^1.3.1", | |
| 7780 | - "ieee754": "^1.2.1" | |
| 7781 | - } | |
| 7782 | - }, | |
| 7783 | 8522 | "node_modules/zip-stream/node_modules/readable-stream": { |
| 7784 | 8523 | "version": "4.5.2", |
| 7785 | 8524 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", |
| @@ -7821,6 +8560,15 @@ | ||
| 7821 | 8560 | "dependencies": { |
| 7822 | 8561 | "safe-buffer": "~5.2.0" |
| 7823 | 8562 | } |
| 8563 | + }, | |
| 8564 | + "node_modules/zod": { | |
| 8565 | + "version": "3.24.2", | |
| 8566 | + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", | |
| 8567 | + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", | |
| 8568 | + "license": "MIT", | |
| 8569 | + "funding": { | |
| 8570 | + "url": "https://github.com/sponsors/colinhacks" | |
| 8571 | + } | |
| 7824 | 8572 | } |
| 7825 | 8573 | } |
| 7826 | 8574 | } |
| @@ -4,6 +4,26 @@ | ||
| 4 | 4 | "@agnai/sentencepiece-js": "^1.1.1", |
| 5 | 5 | "@agnai/web-tokenizers": "^0.1.3", |
| 6 | 6 | "@iconfu/svg-inject": "^1.2.3", |
| 7 | + "@jimp/core": "^1.6.0", | |
| 8 | + "@jimp/js-bmp": "^1.6.0", | |
| 9 | + "@jimp/js-gif": "^1.6.0", | |
| 10 | + "@jimp/js-tiff": "^1.6.0", | |
| 11 | + "@jimp/plugin-circle": "^1.6.0", | |
| 12 | + "@jimp/plugin-color": "^1.6.0", | |
| 13 | + "@jimp/plugin-contain": "^1.6.0", | |
| 14 | + "@jimp/plugin-cover": "^1.6.0", | |
| 15 | + "@jimp/plugin-crop": "^1.6.0", | |
| 16 | + "@jimp/plugin-displace": "^1.6.0", | |
| 17 | + "@jimp/plugin-fisheye": "^1.6.0", | |
| 18 | + "@jimp/plugin-flip": "^1.6.0", | |
| 19 | + "@jimp/plugin-mask": "^1.6.0", | |
| 20 | + "@jimp/plugin-quantize": "^1.6.0", | |
| 21 | + "@jimp/plugin-rotate": "^1.6.0", | |
| 22 | + "@jimp/plugin-threshold": "^1.6.0", | |
| 23 | + "@jimp/wasm-avif": "^1.6.0", | |
| 24 | + "@jimp/wasm-jpeg": "^1.6.0", | |
| 25 | + "@jimp/wasm-png": "^1.6.0", | |
| 26 | + "@jimp/wasm-webp": "^1.6.0", | |
| 7 | 27 | "@mozilla/readability": "^0.6.0", |
| 8 | 28 | "@popperjs/core": "^2.11.8", |
| 9 | 29 | "@zeldafan0225/ai_horde": "^5.2.0", |
| @@ -18,6 +38,7 @@ | ||
| 18 | 38 | "cookie-parser": "^1.4.6", |
| 19 | 39 | "cookie-session": "^2.1.0", |
| 20 | 40 | "cors": "^2.8.5", |
| 41 | + "crc": "^4.3.2", | |
| 21 | 42 | "csrf-sync": "^4.0.3", |
| 22 | 43 | "diff-match-patch": "^1.0.5", |
| 23 | 44 | "dompurify": "^3.2.4", |
| @@ -36,7 +57,6 @@ | ||
| 36 | 57 | "ip-regex": "^5.0.0", |
| 37 | 58 | "ipaddr.js": "^2.2.0", |
| 38 | 59 | "is-docker": "^3.0.0", |
| 39 | - "jimp": "^0.22.10", | |
| 40 | 60 | "localforage": "^1.10.0", |
| 41 | 61 | "lodash": "^4.17.21", |
| 42 | 62 | "mime-types": "^2.1.35", |
| @@ -47,7 +67,6 @@ | ||
| 47 | 67 | "node-persist": "^4.0.4", |
| 48 | 68 | "open": "^8.4.2", |
| 49 | 69 | "png-chunk-text": "^1.0.0", |
| 50 | - "png-chunks-encode": "^1.0.0", | |
| 51 | 70 | "png-chunks-extract": "^1.0.0", |
| 52 | 71 | "proxy-agent": "^6.5.0", |
| 53 | 72 | "rate-limiter-flexible": "^5.0.5", |
| @@ -90,7 +109,7 @@ | ||
| 90 | 109 | "type": "git", |
| 91 | 110 | "url": "https://github.com/SillyTavern/SillyTavern.git" |
| 92 | 111 | }, |
| 93 | 112 | "version": "1.12.1314", |
| 94 | 113 | "scripts": { |
| 95 | 114 | "start": "node server.js", |
| 96 | 115 | "debug": "node --inspect server.js", |
| @@ -132,7 +151,6 @@ | ||
| 132 | 151 | "@types/node": "^18.19.80", |
| 133 | 152 | "@types/node-persist": "^3.1.8", |
| 134 | 153 | "@types/png-chunk-text": "^1.0.3", |
| 135 | - "@types/png-chunks-encode": "^1.0.2", | |
| 136 | 154 | "@types/png-chunks-extract": "^1.0.2", |
| 137 | 155 | "@types/response-time": "^2.3.8", |
| 138 | 156 | "@types/select2": "^4.0.63", |
| @@ -140,6 +158,7 @@ | ||
| 140 | 158 | "@types/write-file-atomic": "^4.0.3", |
| 141 | 159 | "@types/yargs": "^17.0.33", |
| 142 | 160 | "@types/yauzl": "^2.10.3", |
| 143 | 161 | "eslint": "^8.57.1", |
| 162 | + "eslint-plugin-jsdoc": "^48.10.0" | |
| 144 | 163 | } |
| 145 | 164 | } |
| @@ -101,15 +101,12 @@ const keyMigrationMap = [ | ||
| 101 | 101 | newKey: 'performance.memoryCacheCapacity', |
| 102 | 102 | migrate: (value) => `${value}mb`, |
| 103 | 103 | }, |
| 104 | - // uncomment one release after 1.12.13 | |
| 105 | - /* | |
| 106 | 104 | { |
| 107 | 105 | oldKey: 'cookieSecret', |
| 108 | 106 | newKey: 'cookieSecret', |
| 109 | 107 | migrate: () => void 0, |
| 110 | 108 | remove: true, |
| 111 | 109 | }, |
| 112 | - */ | |
| 113 | 110 | ]; |
| 114 | 111 | |
| 115 | 112 | /** |
| @@ -146,3 +146,15 @@ input.extension_missing[type="checkbox"] { | ||
| 146 | 146 | .extensions_info .extension_actions { |
| 147 | 147 | flex-wrap: nowrap; |
| 148 | 148 | } |
| 149 | + | |
| 150 | +.extensions_toolbar { | |
| 151 | + top: 0; | |
| 152 | + position: sticky; | |
| 153 | + display: flex; | |
| 154 | + flex-direction: row; | |
| 155 | + background-color: var(--SmartThemeBlurTintColor); | |
| 156 | + gap: 5px; | |
| 157 | + z-index: 1; | |
| 158 | + margin-bottom: 10px; | |
| 159 | + padding: 5px; | |
| 160 | +} | |
| @@ -13,6 +13,7 @@ | ||
| 13 | 13 | backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)*2)); |
| 14 | 14 | color: var(--SmartThemeBodyColor); |
| 15 | 15 | z-index: 40000; |
| 16 | + user-select: none; | |
| 16 | 17 | } |
| 17 | 18 | |
| 18 | 19 | .select2-container .select2-selection .select2-selection__clear { |
| @@ -1,7 +1,11 @@ | ||
| 1 | 1 | import libs from './lib'; |
| 2 | 2 | import getContext from './scripts/st-context'; |
| 3 | +import { power_user } from './scripts/power-user'; | |
| 3 | 4 | |
| 4 | 5 | declare global { |
| 6 | + // Custom types | |
| 7 | + declare type InstructSettings = typeof power_user.instruct; | |
| 8 | + | |
| 5 | 9 | // Global namespace modules |
| 6 | 10 | interface Window { |
| 7 | 11 | ai: any; |
| @@ -0,0 +1,46 @@ | ||
| 1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |
| 2 | +<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> | |
| 3 | + | |
| 4 | +<svg | |
| 5 | + version="1.1" | |
| 6 | + id="katman_1" | |
| 7 | + x="0px" | |
| 8 | + y="0px" | |
| 9 | + viewBox="0 0 438.67001 481.44999" | |
| 10 | + xml:space="preserve" | |
| 11 | + sodipodi:docname="XAI_Logo.svg" | |
| 12 | + width="438.67001" | |
| 13 | + height="481.45001" | |
| 14 | + inkscape:version="1.3 (0e150ed, 2023-07-21)" | |
| 15 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | |
| 16 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | |
| 17 | + xmlns="http://www.w3.org/2000/svg" | |
| 18 | + xmlns:svg="http://www.w3.org/2000/svg"><defs | |
| 19 | + id="defs4" /><sodipodi:namedview | |
| 20 | + id="namedview4" | |
| 21 | + pagecolor="#ffffff" | |
| 22 | + bordercolor="#000000" | |
| 23 | + borderopacity="0.25" | |
| 24 | + inkscape:showpageshadow="2" | |
| 25 | + inkscape:pageopacity="0.0" | |
| 26 | + inkscape:pagecheckerboard="0" | |
| 27 | + inkscape:deskcolor="#d1d1d1" | |
| 28 | + inkscape:zoom="0.39645207" | |
| 29 | + inkscape:cx="219.44645" | |
| 30 | + inkscape:cy="238.36425" | |
| 31 | + inkscape:window-width="1512" | |
| 32 | + inkscape:window-height="856" | |
| 33 | + inkscape:window-x="0" | |
| 34 | + inkscape:window-y="38" | |
| 35 | + inkscape:window-maximized="1" | |
| 36 | + inkscape:current-layer="katman_1" /> <g | |
| 37 | + id="g4" | |
| 38 | + transform="translate(-201.61,-56.91)"> <polygon | |
| 39 | + points="631.96,538.36 640.28,93.18 557.09,211.99 565.4,538.36 " | |
| 40 | + id="polygon1" /> <polygon | |
| 41 | + points="379.35,284.53 430.13,357.05 640.28,56.91 538.72,56.91 " | |
| 42 | + id="polygon2" /> <polygon | |
| 43 | + points="353.96,465.84 303.17,393.31 201.61,538.36 303.17,538.36 " | |
| 44 | + id="polygon3" /> <polygon | |
| 45 | + points="531.69,538.36 303.17,211.99 201.61,211.99 430.13,538.36 " | |
| 46 | + id="polygon4" /> </g> </svg> | |
| @@ -197,6 +197,9 @@ | ||
| 197 | 197 | <div id="update_oai_preset" class="menu_button menu_button_icon" title="Update current preset" data-i18n="[title]Update current preset"> |
| 198 | 198 | <i class="fa-fw fa-solid fa-save"></i> |
| 199 | 199 | </div> |
| 200 | + <div data-preset-manager-rename="openai" class="menu_button menu_button_icon" title="Rename current preset" data-i18n="[title]Rename current preset"> | |
| 201 | + <i class="fa-fw fa-solid fa-pencil"></i> | |
| 202 | + </div> | |
| 200 | 203 | <div id="new_oai_preset" class="menu_button menu_button_icon" title="Save preset as" data-i18n="[title]Save preset as"> |
| 201 | 204 | <i class="fa-fw fa-solid fa-file-circle-plus"></i> |
| 202 | 205 | </div> |
| @@ -643,7 +646,7 @@ | ||
| 643 | 646 | <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="65536"> |
| 644 | 647 | </div> |
| 645 | 648 | </div> |
| 646 | 649 | <div class="range-block" data-source="openai,custom,xai"> |
| 647 | 650 | <div class="range-block-title" data-i18n="Multiple swipes per generation"> |
| 648 | 651 | Multiple swipes per generation |
| 649 | 652 | </div> |
| @@ -682,7 +685,7 @@ | ||
| 682 | 685 | </span> |
| 683 | 686 | </div> |
| 684 | 687 | </div> |
| 685 | 688 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> |
| 686 | 689 | <div class="range-block-title" data-i18n="Temperature"> |
| 687 | 690 | Temperature |
| 688 | 691 | </div> |
| @@ -695,7 +698,7 @@ | ||
| 695 | 698 | </div> |
| 696 | 699 | </div> |
| 697 | 700 | </div> |
| 698 | 701 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai"> |
| 699 | 702 | <div class="range-block-title" data-i18n="Frequency Penalty"> |
| 700 | 703 | Frequency Penalty |
| 701 | 704 | </div> |
| @@ -708,7 +711,7 @@ | ||
| 708 | 711 | </div> |
| 709 | 712 | </div> |
| 710 | 713 | </div> |
| 711 | 714 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt,deepseek,xai"> |
| 712 | 715 | <div class="range-block-title" data-i18n="Presence Penalty"> |
| 713 | 716 | Presence Penalty |
| 714 | 717 | </div> |
| @@ -734,7 +737,7 @@ | ||
| 734 | 737 | </div> |
| 735 | 738 | </div> |
| 736 | 739 | </div> |
| 737 | 740 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt,deepseek,xai"> |
| 738 | 741 | <div class="range-block-title" data-i18n="Top P"> |
| 739 | 742 | Top P |
| 740 | 743 | </div> |
| @@ -971,7 +974,7 @@ | ||
| 971 | 974 | </div> |
| 972 | 975 | </div> |
| 973 | 976 | </div> |
| 974 | 977 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt,xai"> |
| 975 | 978 | <div class="range-block-title justifyLeft" data-i18n="Seed"> |
| 976 | 979 | Seed |
| 977 | 980 | </div> |
| @@ -1416,7 +1419,7 @@ | ||
| 1416 | 1419 | </div> |
| 1417 | 1420 | </div> |
| 1418 | 1421 | |
| 1419 | 1422 | <div data-tg-type="aphrodite, ooba, koboldcpp, tabby, llamacpp, dreamgen" id="dryBlock" class="wide100p"> |
| 1420 | 1423 | <h4 class="wide100p textAlignCenter" title="DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable." data-i18n="[title]DRY_Repetition_Penalty_desc"> |
| 1421 | 1424 | <label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label> |
| 1422 | 1425 | <a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank"> |
| @@ -1571,7 +1574,7 @@ | ||
| 1571 | 1574 | <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative" title="Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative."></div> |
| 1572 | 1575 | </label> |
| 1573 | 1576 | </label> |
| 1574 | 1577 | <label data-tg-type="ooba, llamacpp, tabby, koboldcpp, dreamgen" class="checkbox_label flexGrow flexShrink" for="ban_eos_token_textgenerationwebui"> |
| 1575 | 1578 | <input type="checkbox" id="ban_eos_token_textgenerationwebui" /> |
| 1576 | 1579 | <label> |
| 1577 | 1580 | <small data-i18n="Ban EOS Token">Ban EOS Token</small> |
| @@ -1957,12 +1960,15 @@ | ||
| 1957 | 1960 | <span data-i18n="Enable web search">Enable web search</span> |
| 1958 | 1961 | </label> |
| 1959 | 1962 | <div class="flexBasis100p toggle-description justifyLeft"> |
| 1960 | - <span> | |
| 1963 | + <span data-i18n="Use search capabilities provided by the backend."> | |
| 1961 | 1964 | Use search capabilities provided by the backend. |
| 1962 | 1965 | </span> |
| 1966 | + <b data-source="openrouter" data-i18n="openrouter_web_search_fee"> | |
| 1967 | + Not free, adds a $0.02 fee to each prompt. | |
| 1968 | + </b> | |
| 1963 | 1969 | </div> |
| 1964 | 1970 | </div> |
| 1965 | 1971 | <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,openrouter,groq,deepseek,makersuite,ai21,xai"> |
| 1966 | 1972 | <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand"> |
| 1967 | 1973 | <input id="openai_function_calling" type="checkbox" /> |
| 1968 | 1974 | <span data-i18n="Enable function calling">Enable function calling</span> |
| @@ -1972,7 +1978,7 @@ | ||
| 1972 | 1978 | <span data-i18n="enable_functions_desc_3">Can be utilized by various extensions to provide additional functionality.</span> |
| 1973 | 1979 | </div> |
| 1974 | 1980 | </div> |
| 1975 | 1981 | <div class="range-block" data-source="openai,openrouter,mistralai,makersuite,claude,custom,01ai,xai"> |
| 1976 | 1982 | <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand"> |
| 1977 | 1983 | <input id="openai_image_inlining" type="checkbox" /> |
| 1978 | 1984 | <span data-i18n="Send inline images">Send inline images</span> |
| @@ -1984,7 +1990,7 @@ | ||
| 1984 | 1990 | <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> |
| 1985 | 1991 | <span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span> |
| 1986 | 1992 | </div> |
| 1987 | 1993 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai"> |
| 1988 | 1994 | <div class="flex-container oneline-dropdown"> |
| 1989 | 1995 | <label for="openai_inline_image_quality" data-i18n="Inline Image Quality"> |
| 1990 | 1996 | Inline Image Quality |
| @@ -2028,7 +2034,7 @@ | ||
| 2028 | 2034 | </span> |
| 2029 | 2035 | </div> |
| 2030 | 2036 | </div> |
| 2031 | 2037 | <div class="range-block" data-source="deepseek,openrouter,custom,claude,xai"> |
| 2032 | 2038 | <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand"> |
| 2033 | 2039 | <input id="openai_show_thoughts" type="checkbox" /> |
| 2034 | 2040 | <span> |
| @@ -2042,7 +2048,7 @@ | ||
| 2042 | 2048 | </span> |
| 2043 | 2049 | </div> |
| 2044 | 2050 | </div> |
| 2045 | 2051 | <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai"> |
| 2046 | 2052 | <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models. Currently supported values are low, medium, and high. Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models."> |
| 2047 | 2053 | <label for="openai_reasoning_effort"> |
| 2048 | 2054 | <span data-i18n="Reasoning Effort">Reasoning Effort</span> |
| @@ -2188,7 +2194,7 @@ | ||
| 2188 | 2194 | <input id="horde_trusted_workers_only" type="checkbox" /> |
| 2189 | 2195 | <span data-i18n="Trusted workers only">Trusted workers only</span> |
| 2190 | 2196 | </label> |
| 2191 | 2197 | <small id="adjustedHordeParams"><span data-i18n="Context">Context</span>: --, <span data-i18n="Response">Response</span>: --</small> |
| 2192 | 2198 | <h4 data-i18n="API key">API key</h4> |
| 2193 | 2199 | <small> |
| 2194 | 2200 | <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> |
| @@ -2429,7 +2435,7 @@ | ||
| 2429 | 2435 | </div> |
| 2430 | 2436 | <div class="flex1"> |
| 2431 | 2437 | <h4 data-i18n="Server url">Server URL</h4> |
| 2432 | 2438 | <small data-i18n="Example: http://127.0.0.1:5000">Example: http://127.0.0.1:5000</small> |
| 2433 | 2439 | <input id="generic_api_url_text" name="generic_api_url" class="text_pole wide100p" value="" autocomplete="off" data-server-history="generic"> |
| 2434 | 2440 | </div> |
| 2435 | 2441 | <datalist id="generic_model_fill"></datalist> |
| @@ -2458,7 +2464,7 @@ | ||
| 2458 | 2464 | </div> |
| 2459 | 2465 | <div class="flex1"> |
| 2460 | 2466 | <h4 data-i18n="Server url">Server URL</h4> |
| 2461 | 2467 | <small data-i18n="Example: http://127.0.0.1:5000">Example: http://127.0.0.1:5000</small> |
| 2462 | 2468 | <input id="textgenerationwebui_api_url_text" name="textgenerationwebui_api_url" class="text_pole wide100p" value="" autocomplete="off" data-server-history="ooba_blocking"> |
| 2463 | 2469 | </div> |
| 2464 | 2470 | <input id="custom_model_textgenerationwebui" class="text_pole wide100p" placeholder="Custom model (optional)" data-i18n="[placeholder]Custom model (optional)" type="text"> |
| @@ -2531,7 +2537,7 @@ | ||
| 2531 | 2537 | </div> |
| 2532 | 2538 | <div class="flex1"> |
| 2533 | 2539 | <h4 data-i18n="API url">API URL</h4> |
| 2534 | 2540 | <small data-i18n="Example: http://127.0.0.1:8000">Example: http://127.0.0.1:8000</small> |
| 2535 | 2541 | <input id="vllm_api_url_text" class="text_pole wide100p" value="" autocomplete="off" data-server-history="vllm"> |
| 2536 | 2542 | </div> |
| 2537 | 2543 | <div> |
| @@ -2577,7 +2583,7 @@ | ||
| 2577 | 2583 | </div> |
| 2578 | 2584 | <div class="flex1"> |
| 2579 | 2585 | <h4 data-i18n="API url">API URL</h4> |
| 2580 | 2586 | <small data-i18n="Example: http://127.0.0.1:5000">Example: http://127.0.0.1:5000</small> |
| 2581 | 2587 | <input id="aphrodite_api_url_text" class="text_pole wide100p" value="" autocomplete="off" data-server-history="aphrodite"> |
| 2582 | 2588 | </div> |
| 2583 | 2589 | <div> |
| @@ -2606,7 +2612,7 @@ | ||
| 2606 | 2612 | </div> |
| 2607 | 2613 | <div class="flex1"> |
| 2608 | 2614 | <h4 data-i18n="API url">API URL</h4> |
| 2609 | 2615 | <small data-i18n="Example: http://127.0.0.1:8080">Example: http://127.0.0.1:8080</small> |
| 2610 | 2616 | <input id="llamacpp_api_url_text" class="text_pole wide100p" value="" autocomplete="off" data-server-history="llamacpp"> |
| 2611 | 2617 | </div> |
| 2612 | 2618 | </div> |
| @@ -2618,7 +2624,7 @@ | ||
| 2618 | 2624 | </div> |
| 2619 | 2625 | <div class="flex1"> |
| 2620 | 2626 | <h4 data-i18n="API url">API URL</h4> |
| 2621 | 2627 | <small data-i18n="Example: http://127.0.0.1:11434">Example: http://127.0.0.1:11434</small> |
| 2622 | 2628 | <input id="ollama_api_url_text" class="text_pole wide100p" value="" autocomplete="off" data-server-history="ollama"> |
| 2623 | 2629 | </div> |
| 2624 | 2630 | <div class="flex1"> |
| @@ -2653,7 +2659,7 @@ | ||
| 2653 | 2659 | </div> |
| 2654 | 2660 | <div class="flex1"> |
| 2655 | 2661 | <h4 data-i18n="API url">API URL</h4> |
| 2656 | 2662 | <small data-i18n="Example: http://127.0.0.1:5000">Example: http://127.0.0.1:5000</small> |
| 2657 | 2663 | <input id="tabby_api_url_text" class="text_pole wide100p" value="" autocomplete="off" data-server-history="tabby"> |
| 2658 | 2664 | </div> |
| 2659 | 2665 | <div class="flex1"> |
| @@ -2705,7 +2711,7 @@ | ||
| 2705 | 2711 | </div> |
| 2706 | 2712 | <div class="flex1"> |
| 2707 | 2713 | <h4 data-i18n="API url">API URL</h4> |
| 2708 | 2714 | <small data-i18n="Example: http://127.0.0.1:5001">Example: http://127.0.0.1:5001</small> |
| 2709 | 2715 | <input id="koboldcpp_api_url_text" class="text_pole wide100p" value="" autocomplete="off" data-server-history="koboldcpp"> |
| 2710 | 2716 | </div> |
| 2711 | 2717 | </div> |
| @@ -2742,7 +2748,6 @@ | ||
| 2742 | 2748 | <optgroup> |
| 2743 | 2749 | <option value="01ai">01.AI (Yi)</option> |
| 2744 | 2750 | <option value="ai21">AI21</option> |
| 2745 | - <option value="blockentropy">Block Entropy</option> | |
| 2746 | 2751 | <option value="claude">Claude</option> |
| 2747 | 2752 | <option value="cohere">Cohere</option> |
| 2748 | 2753 | <option value="deepseek">DeepSeek</option> |
| @@ -2754,9 +2759,10 @@ | ||
| 2754 | 2759 | <option value="perplexity">Perplexity</option> |
| 2755 | 2760 | <option value="scale">Scale</option> |
| 2756 | 2761 | <option value="windowai">Window AI</option> |
| 2762 | + <option value="xai">xAI (Grok)</option> | |
| 2757 | 2763 | </optgroup> |
| 2758 | 2764 | </select> |
| 2759 | 2765 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek,xai"> |
| 2760 | 2766 | <div class="inline-drawer-toggle inline-drawer-header"> |
| 2761 | 2767 | <b data-i18n="Reverse Proxy">Reverse Proxy</b> |
| 2762 | 2768 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| @@ -2819,7 +2825,7 @@ | ||
| 2819 | 2825 | </div> |
| 2820 | 2826 | </div> |
| 2821 | 2827 | </div> |
| 2822 | 2828 | <div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite,deepseek,xai"> |
| 2823 | 2829 | <div class="reverse_proxy_warning"> |
| 2824 | 2830 | <b> |
| 2825 | 2831 | <div data-i18n="Using a proxy that you're not running yourself is a risk to your data privacy."> |
| @@ -2883,7 +2889,15 @@ | ||
| 2883 | 2889 | <option value="gpt-4o-2024-05-13">gpt-4o-2024-05-13</option> |
| 2884 | 2890 | <option value="chatgpt-4o-latest">chatgpt-4o-latest</option> |
| 2885 | 2891 | </optgroup> |
| 2886 | 2892 | <optgroup label="o1 and o1GPT-mini4.1"> |
| 2893 | + <option value="gpt-4.1">gpt-4.1</option> | |
| 2894 | + <option value="gpt-4.1-2025-04-14">gpt-4.1-2025-04-14</option> | |
| 2895 | + <option value="gpt-4.1-mini">gpt-4.1-mini</option> | |
| 2896 | + <option value="gpt-4.1-mini-2025-04-14">gpt-4.1-mini-2025-04-14</option> | |
| 2897 | + <option value="gpt-4.1-nano">gpt-4.1-nano</option> | |
| 2898 | + <option value="gpt-4.1-nano-2025-04-14">gpt-4.1-nano-2025-04-14</option> | |
| 2899 | + </optgroup> | |
| 2900 | + <optgroup label="o1"> | |
| 2887 | 2901 | <option value="o1">o1</option> |
| 2888 | 2902 | <option value="o1-2024-12-17">o1-2024-12-17</option> |
| 2889 | 2903 | <option value="o1-mini">o1-mini</option> |
| @@ -2892,9 +2906,15 @@ | ||
| 2892 | 2906 | <option value="o1-preview-2024-09-12">o1-preview-2024-09-12</option> |
| 2893 | 2907 | </optgroup> |
| 2894 | 2908 | <optgroup label="o3"> |
| 2909 | + <option value="o3">o3</option> | |
| 2910 | + <option value="o3-2025-04-16">o3-2025-04-16</option> | |
| 2895 | 2911 | <option value="o3-mini">o3-mini</option> |
| 2896 | 2912 | <option value="o3-mini-2025-01-31">o3-mini-2025-01-31</option> |
| 2897 | 2913 | </optgroup> |
| 2914 | + <optgroup label="o4"> | |
| 2915 | + <option value="o4-mini">o4-mini</option> | |
| 2916 | + <option value="o4-mini-2025-04-16">o4-mini-2025-04-16</option> | |
| 2917 | + </optgroup> | |
| 2898 | 2918 | <optgroup label="GPT-4.5"> |
| 2899 | 2919 | <option value="gpt-4.5-preview">gpt-4.5-preview</option> |
| 2900 | 2920 | <option value="gpt-4.5-preview-2025-02-27">gpt-4.5-preview-2025-02-27</option> |
| @@ -3138,8 +3158,11 @@ | ||
| 3138 | 3158 | <option value="gemma-3-27b-it">Gemma 3 27B</option> |
| 3139 | 3159 | </optgroup> |
| 3140 | 3160 | <optgroup label="Subversions"> |
| 3161 | + <option value="gemini-2.5-pro-preview-03-25">Gemini 2.5 Pro Preview 2025-03-25</option> | |
| 3162 | + <option value="gemini-2.5-pro-exp-03-25">Gemini 2.5 Pro Experimental 2025-03-25</option> | |
| 3141 | 3163 | <option value="gemini-2.0-pro-exp">Gemini 2.0 Pro Experimental</option> |
| 3142 | 3164 | <option value="gemini-2.0-pro-exp-02-05">Gemini 2.0 Pro Experimental 2025-02-05</option> |
| 3165 | + <option value="gemini-2.5-flash-preview-04-17">Gemini 2.5 Flash Preview 2025-04-17</option> | |
| 3143 | 3166 | <option value="gemini-2.0-flash-lite-preview">Gemini 2.0 Flash-Lite Preview</option> |
| 3144 | 3167 | <option value="gemini-2.0-flash-lite-preview-02-05">Gemini 2.0 Flash-Lite Preview 2025-02-05</option> |
| 3145 | 3168 | <option value="gemini-2.0-flash-001">Gemini 2.0 Flash [001]</option> |
| @@ -3193,6 +3216,7 @@ | ||
| 3193 | 3216 | <option value="mistral-small-latest">mistral-small-latest</option> |
| 3194 | 3217 | <option value="mistral-medium-latest">mistral-medium-latest</option> |
| 3195 | 3218 | <option value="mistral-large-latest">mistral-large-latest</option> |
| 3219 | + <option value="mistral-saba-latest">mistral-saba-latest</option> | |
| 3196 | 3220 | <option value="codestral-latest">codestral-latest</option> |
| 3197 | 3221 | <option value="codestral-mamba-latest">codestral-mamba-latest</option> |
| 3198 | 3222 | <option value="pixtral-12b-latest">pixtral-12b-latest</option> |
| @@ -3208,13 +3232,20 @@ | ||
| 3208 | 3232 | <option value="mistral-small-2312">mistral-small-2312</option> |
| 3209 | 3233 | <option value="mistral-small-2402">mistral-small-2402</option> |
| 3210 | 3234 | <option value="mistral-small-2409">mistral-small-2409</option> |
| 3235 | + <option value="mistral-small-2501">mistral-small-2501</option> | |
| 3236 | + <option value="mistral-small-2503">mistral-small-2503</option> | |
| 3211 | 3237 | <option value="mistral-medium-2312">mistral-medium-2312</option> |
| 3212 | 3238 | <option value="mistral-large-2402">mistral-large-2402</option> |
| 3213 | 3239 | <option value="mistral-large-2407">mistral-large-2407</option> |
| 3214 | 3240 | <option value="mistral-large-2411">mistral-large-2411</option> |
| 3241 | + <option value="mistral-large-pixtral-2411">mistral-large-pixtral-2411</option> | |
| 3242 | + <option value="mistral-saba-2502">mistral-saba-2502</option> | |
| 3215 | 3243 | <option value="codestral-2405">codestral-2405</option> |
| 3216 | 3244 | <option value="codestral-2405-blue">codestral-2405-blue</option> |
| 3217 | 3245 | <option value="codestral-mamba-2407">codestral-mamba-2407</option> |
| 3246 | + <option value="codestral-2411-rc5">codestral-2411-rc5</option> | |
| 3247 | + <option value="codestral-2412">codestral-2412</option> | |
| 3248 | + <option value="codestral-2501">codestral-2501</option> | |
| 3218 | 3249 | <option value="pixtral-12b-2409">pixtral-12b-2409</option> |
| 3219 | 3250 | <option value="pixtral-large-2411">pixtral-large-2411</option> |
| 3220 | 3251 | </optgroup> |
| @@ -3237,16 +3268,16 @@ | ||
| 3237 | 3268 | <option value="qwen-2.5-32b">qwen-2.5-32b</option> |
| 3238 | 3269 | <option value="qwen-2.5-coder-32b">qwen-2.5-coder-32b</option> |
| 3239 | 3270 | </optgroup> |
| 3240 | 3271 | <optgroup label="DeepSeek / Alibaba Cloud"> |
| 3241 | 3272 | <option value="deepseek-r1-distill-qwen-32b">deepseek-r1-distill-qwen-32b</option> |
| 3242 | - </optgroup> | |
| 3243 | - <optgroup label="DeepSeek / Meta"> | |
| 3244 | 3273 | <option value="deepseek-r1-distill-llama-70b">deepseek-r1-distill-llama-70b</option> |
| 3245 | 3274 | </optgroup> |
| 3246 | 3275 | <optgroup label="Google"> |
| 3247 | 3276 | <option value="gemma2-9b-it">gemma2-9b-it</option> |
| 3248 | 3277 | </optgroup> |
| 3249 | 3278 | <optgroup label="Meta"> |
| 3279 | + <option value="meta-llama/llama-4-scout-17b-16e-instruct">meta-llama/llama-4-scout-17b-16e-instruct</option> | |
| 3280 | + <option value="meta-llama/llama-4-maverick-17b-128e-instruct">meta-llama/llama-4-maverick-17b-128e-instruct</option> | |
| 3250 | 3281 | <option value="llama-3.1-8b-instant">llama-3.1-8b-instant</option> |
| 3251 | 3282 | <option value="llama-3.2-11b-vision-preview">llama-3.2-11b-vision-preview </option> |
| 3252 | 3283 | <option value="llama-3.2-1b-preview">llama-3.2-1b-preview </option> |
| @@ -3259,6 +3290,7 @@ | ||
| 3259 | 3290 | <option value="llama3-8b-8192">llama3-8b-8192</option> |
| 3260 | 3291 | </optgroup> |
| 3261 | 3292 | <optgroup label="Mistral AI"> |
| 3293 | + <option value="mistral-saba-24b">mistral-saba-24b</option> | |
| 3262 | 3294 | <option value="mixtral-8x7b-32768">mixtral-8x7b-32768</option> |
| 3263 | 3295 | </optgroup> |
| 3264 | 3296 | </select> |
| @@ -3363,20 +3395,6 @@ | ||
| 3363 | 3395 | </select> |
| 3364 | 3396 | </div> |
| 3365 | 3397 | </form> |
| 3366 | - <form id="blockentropy_form" data-source="blockentropy"> | |
| 3367 | - <h4 data-i18n="Block Entropy API Key">Block Entropy API Key</h4> | |
| 3368 | - <div class="flex-container"> | |
| 3369 | - <input id="api_key_blockentropy" name="api_key_blockentropy" class="text_pole flex1" value="" type="text" autocomplete="off"> | |
| 3370 | - <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_blockentropy"></div> | |
| 3371 | - </div> | |
| 3372 | - <div data-for="api_key_blockentropy" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | |
| 3373 | - For privacy reasons, your API key will be hidden after you reload the page. | |
| 3374 | - </div> | |
| 3375 | - <h4 data-i18n="Select a Model">Select a Model</h4> | |
| 3376 | - <div class="flex-container"> | |
| 3377 | - <select id="model_blockentropy_select" class="text_pole"></select> | |
| 3378 | - </div> | |
| 3379 | - </form> | |
| 3380 | 3398 | <form id="custom_form" data-source="custom"> |
| 3381 | 3399 | <h4 data-i18n="Custom Endpoint (Base URL)">Custom Endpoint (Base URL)</h4> |
| 3382 | 3400 | <div class="flex-container"> |
| @@ -3407,17 +3425,10 @@ | ||
| 3407 | 3425 | <div class="flex-container"> |
| 3408 | 3426 | <select id="model_custom_select" class="text_pole model_custom_select"></select> |
| 3409 | 3427 | </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 | 3428 | </form> |
| 3418 | 3429 | <div id="01ai_form" data-source="01ai"> |
| 3419 | 3430 | <h4> |
| 3420 | 3431 | <a data-i18n="01.AI API Key" href="https://platform.01lingyiwanwu.aicom/" target="_blank" rel="noopener noreferrer"> |
| 3421 | 3432 | 01.AI API Key |
| 3422 | 3433 | </a> |
| 3423 | 3434 | </h4> |
| @@ -3432,6 +3443,40 @@ | ||
| 3432 | 3443 | <select id="model_01ai_select"> |
| 3433 | 3444 | </select> |
| 3434 | 3445 | </div> |
| 3446 | + <div id="xai_form" data-source="xai"> | |
| 3447 | + <h4> | |
| 3448 | + <a data-i18n="xAI API Key" href="https://console.x.ai/" target="_blank" rel="noopener noreferrer"> | |
| 3449 | + xAI API Key | |
| 3450 | + </a> | |
| 3451 | + </h4> | |
| 3452 | + <div class="flex-container"> | |
| 3453 | + <input id="api_key_xai" name="api_key_xai" class="text_pole flex1" value="" type="text" autocomplete="off"> | |
| 3454 | + <div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_xai"></div> | |
| 3455 | + </div> | |
| 3456 | + <div data-for="api_key_xai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page."> | |
| 3457 | + For privacy reasons, your API key will be hidden after you reload the page. | |
| 3458 | + </div> | |
| 3459 | + <h4 data-i18n="xAI Model">xAI Model</h4> | |
| 3460 | + <select id="model_xai_select"> | |
| 3461 | + <option value="grok-3-beta">grok-3-beta</option> | |
| 3462 | + <option value="grok-3-fast-beta">grok-3-fast-beta</option> | |
| 3463 | + <option value="grok-3-mini-beta">grok-3-mini-beta</option> | |
| 3464 | + <option value="grok-3-mini-fast-beta">grok-3-mini-fast-beta</option> | |
| 3465 | + <option value="grok-2-vision-1212">grok-2-vision-1212</option> | |
| 3466 | + <option value="grok-2-1212">grok-2-1212</option> | |
| 3467 | + <option value="grok-vision-beta">grok-vision-beta</option> | |
| 3468 | + <option value="grok-beta">grok-beta</option> | |
| 3469 | + </select> | |
| 3470 | + </div> | |
| 3471 | + <div id="prompt_post_porcessing_form" data-source="custom,openrouter"> | |
| 3472 | + <h4 data-i18n="Prompt Post-Processing">Prompt Post-Processing</h4> | |
| 3473 | + <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."> | |
| 3474 | + <option data-i18n="prompt_post_processing_none" value="">None</option> | |
| 3475 | + <option data-i18n="prompt_post_processing_merge" value="merge">Merge consecutive roles</option> | |
| 3476 | + <option data-i18n="prompt_post_processing_semi" value="semi">Semi-strict (alternating roles)</option> | |
| 3477 | + <option data-i18n="prompt_post_processing_strict" value="strict">Strict (user first, alternating roles)</option> | |
| 3478 | + </select> | |
| 3479 | + </div> | |
| 3435 | 3480 | <div class="flex-container flex"> |
| 3436 | 3481 | <div id="api_button_openai" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div> |
| 3437 | 3482 | <div class="api_loading menu_button menu_button_icon" data-i18n="Cancel">Cancel</div> |
| @@ -3917,6 +3962,19 @@ | ||
| 3917 | 3962 | <summary data-i18n="Reasoning Formatting"> |
| 3918 | 3963 | Reasoning Formatting |
| 3919 | 3964 | </summary> |
| 3965 | + <div class="flex-container" title="Select your current Reasoning Template" data-i18n="[title]Select your current Reasoning Template"> | |
| 3966 | + <select id="reasoning_select" data-preset-manager-for="reasoning" class="flex1 text_pole"></select> | |
| 3967 | + <div class="flex-container margin0 justifyCenter gap3px"> | |
| 3968 | + <input type="file" hidden data-preset-manager-file="reasoning" accept=".json, .settings"> | |
| 3969 | + <i data-preset-manager-update="reasoning" class="menu_button fa-solid fa-save" title="Update current template" data-i18n="[title]Update current template"></i> | |
| 3970 | + <i data-preset-manager-rename="reasoning" class="menu_button fa-pencil fa-solid" title="Rename current template" data-i18n="[title]Rename current template"></i> | |
| 3971 | + <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> | |
| 3972 | + <i data-preset-manager-import="reasoning" class="displayNone menu_button fa-solid fa-file-import" title="Import template" data-i18n="[title]Import template"></i> | |
| 3973 | + <i data-preset-manager-export="reasoning" class="displayNone menu_button fa-solid fa-file-export" title="Export template" data-i18n="[title]Export template"></i> | |
| 3974 | + <i data-preset-manager-restore="reasoning" class="menu_button fa-solid fa-recycle" title="Restore current template" data-i18n="[title]Restore current template"></i> | |
| 3975 | + <i data-preset-manager-delete="reasoning" class="menu_button fa-solid fa-trash-can" title="Delete template" data-i18n="[title]Delete template"></i> | |
| 3976 | + </div> | |
| 3977 | + </div> | |
| 3920 | 3978 | <div class="flex-container"> |
| 3921 | 3979 | <div class="flex1" title="Inserted before the reasoning content." data-i18n="[title]reasoning_prefix"> |
| 3922 | 3980 | <small data-i18n="Prefix">Prefix</small> |
| @@ -5099,7 +5157,7 @@ | ||
| 5099 | 5157 | <div id="persona_depth_position_settings" class="flex-container"> |
| 5100 | 5158 | <div class="flex1"> |
| 5101 | 5159 | <label for="persona_depth_value" data-i18n="Depth:">Depth:</label> |
| 5102 | 5160 | <input id="persona_depth_value" class="text_pole" type="number" min="0" max="9999999" step="1"> |
| 5103 | 5161 | </div> |
| 5104 | 5162 | <div class="flex1"> |
| 5105 | 5163 | <label for="persona_depth_role" data-i18n="Role:">Role:</label> |
| @@ -5752,7 +5810,7 @@ | ||
| 5752 | 5810 | @ Depth |
| 5753 | 5811 | </span> |
| 5754 | 5812 | </h4> |
| 5755 | 5813 | <input id="depth_prompt_depth" name="depth_prompt_depth" class="text_pole textarea_compact m-t-0" type="number" min="0" max="9999999" value="4" form="form_create" /> |
| 5756 | 5814 | <h4> |
| 5757 | 5815 | <span data-i18n="Role"> |
| 5758 | 5816 | Role |
| @@ -5973,11 +6031,11 @@ | ||
| 5973 | 6031 | </div> |
| 5974 | 6032 | <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap"> |
| 5975 | 6033 | <label for="depth" class="WIEntryHeaderTitleMobile" data-i18n="Depth:">Depth:</label> |
| 5976 | 6034 | <input title="Depth" class="text_pole wideMax100px margin0" type="number" name="depth" data-i18n="[title]Depth" placeholder="" min="0" max="9999999" /> |
| 5977 | 6035 | </div> |
| 5978 | 6036 | <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap"> |
| 5979 | 6037 | <label for="order" class="WIEntryHeaderTitleMobile" data-i18n="Order:">Order:</label> |
| 5980 | 6038 | <input title="Order" data-i18n="[title]Order" class="text_pole wideMax100px margin0" type="number" name="order" placeholder="" min="0" max="9999999" /> |
| 5981 | 6039 | </div> |
| 5982 | 6040 | <div class="world_entry_form_control wi-enter-footer-text flex-container flexNoGap probabilityContainer"> |
| 5983 | 6041 | <label for="order" class="WIEntryHeaderTitleMobile" data-i18n="Trigger %:">Trigger %:</label> |
| @@ -5986,6 +6044,7 @@ | ||
| 5986 | 6044 | </div> |
| 5987 | 6045 | </div> |
| 5988 | 6046 | </div> |
| 6047 | + <i class="menu_button move_entry_button fa-solid fa-right-left" title="Move Entry to Another Lorebook" data-i18n="[title]Move Entry to Another Lorebook"></i> | |
| 5989 | 6048 | <i class="menu_button duplicate_entry_button fa-solid fa-paste" title="Duplicate world info entry" data-i18n="[title]Duplicate world info entry" type="submit" value=""></i> |
| 5990 | 6049 | <i class="menu_button delete_entry_button fa-solid fa-trash-can" title="Delete world info entry" data-i18n="[title]Delete world info entry" type="submit" value=""></i> |
| 5991 | 6050 | </div> |
| @@ -6074,9 +6133,12 @@ | ||
| 6074 | 6133 | <label for="content "> |
| 6075 | 6134 | <small> |
| 6076 | 6135 | <span class="alignitemscenter flex-container flexnowrap wide100p justifySpaceBetween"> |
| 6077 | 6136 | <span data-i18n="Content" class="alignitemscenter flex-container flexNoGap mdhotkey_location"> |
| 6137 | + <span data-i18n="Content" class="mdhotkey_location"> | |
| 6078 | 6138 | Content |
| 6079 | 6139 | </span> |
| 6140 | + <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i> | |
| 6141 | + </span> | |
| 6080 | 6142 | <span> |
| 6081 | 6143 | (<span data-i18n="extension_token_counter">Tokens:</span> <span class="world_entry_form_token_counter" data-first-run="true">counting...</span>) |
| 6082 | 6144 | <span class="world_entry_form_uid_value" data-first-run="true"></span> |
| @@ -6335,7 +6397,7 @@ | ||
| 6335 | 6397 | <span data-i18n="prompt_manager_depth">Depth</span> |
| 6336 | 6398 | </label> |
| 6337 | 6399 | <div class="text_muted" data-i18n="Injection depth. 0 = after the last message, 1 = before the last message, etc.">Injection depth. 0 = after the last message, 1 = before the last message, etc.</div> |
| 6338 | 6400 | <input id="completion_prompt_manager_popup_entry_form_injection_depth" class="text_pole" type="number" name="injection_depth" min="0" max="9999999" value="4" /> |
| 6339 | 6401 | </div> |
| 6340 | 6402 | </div> |
| 6341 | 6403 | <div class="completion_prompt_manager_popup_entry_form_control"> |
| @@ -6434,7 +6496,7 @@ | ||
| 6434 | 6496 | <div class="mes_text"></div> |
| 6435 | 6497 | <div class="mes_img_container"> |
| 6436 | 6498 | <div class="mes_img_controls"> |
| 6437 | 6499 | <div title="EnlargeExpand and zoom" class="right_menu_button fa-lg fa-solid fa-magnifying-glass mes_img_enlarge" data-i18n="[title]EnlargeExpand and zoom"></div> |
| 6438 | 6500 | <div title="Caption" class="right_menu_button fa-lg fa-solid fa-envelope-open-text mes_img_caption" data-i18n="[title]Caption"></div> |
| 6439 | 6501 | <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_img_delete" data-i18n="[title]Delete"></div> |
| 6440 | 6502 | </div> |
| @@ -6563,7 +6625,7 @@ | ||
| 6563 | 6625 | <div class="ch_name"></div> |
| 6564 | 6626 | <small class="ch_additional_info group_select_counter"></small> |
| 6565 | 6627 | </div> |
| 6566 | 6628 | <small class="character_name_block_sub_line" data-i18n="in this group">in this group</small> |
| 6567 | 6629 | <i class='group_fav_icon fa-solid fa-star'></i> |
| 6568 | 6630 | <input class="ch_fav" value="" hidden /> |
| 6569 | 6631 | <div class="group_select_block_list ch_description"></div> |
| @@ -6695,7 +6757,7 @@ | ||
| 6695 | 6757 | <label class="checkbox_label alignItemsCenter" for="extension_floating_position_depth"> |
| 6696 | 6758 | <input type="radio" id="extension_floating_position_depth" name="extension_floating_position" value="1" /> |
| 6697 | 6759 | <span data-i18n="In-chat @ Depth">In-chat @ Depth</span> |
| 6698 | 6760 | <input id="extension_floating_depth" class="text_pole textarea_compact widthNatural" type="number" min="0" max="9999999" /> |
| 6699 | 6761 | <span data-i18n="as">as</span> |
| 6700 | 6762 | <select id="extension_floating_role" class="text_pole widthNatural"> |
| 6701 | 6763 | <option data-i18n="System" value="0">System</option> |
| @@ -6710,7 +6772,7 @@ | ||
| 6710 | 6772 | <span data-i18n="Insertion Frequency">Insertion Frequency</span> |
| 6711 | 6773 | <small data-i18n="(0 = Disable, 1 = Always)">(0 = Disable, 1 = Always)</small> |
| 6712 | 6774 | </label> |
| 6713 | 6775 | <input id="extension_floating_interval" class="text_pole widthUnset" type="number" min="0" max="9999999" /> |
| 6714 | 6776 | </div> |
| 6715 | 6777 | <br> |
| 6716 | 6778 | <span><span data-i18n="User inputs until next insertion:">User inputs until next insertion:</span> <span id="extension_floating_counter">(disabled)</span></span> |
| @@ -6780,7 +6842,7 @@ | ||
| 6780 | 6842 | <label class="checkbox_label alignItemsCenter" for="extension_default_position_depth"> |
| 6781 | 6843 | <input type="radio" id="extension_default_position_depth" name="extension_default_position" value="1" /> |
| 6782 | 6844 | <span data-i18n="In-chat @ Depth">In-chat @ Depth</span> |
| 6783 | 6845 | <input id="extension_default_depth" class="text_pole textarea_compact widthNatural" type="number" min="0" max="9999999" /> |
| 6784 | 6846 | <span data-i18n="as">as</span> |
| 6785 | 6847 | <select id="extension_default_role" class="text_pole widthNatural"> |
| 6786 | 6848 | <option data-i18n="System" value="0">System</option> |
| @@ -6794,7 +6856,7 @@ | ||
| 6794 | 6856 | <span data-i18n="Insertion Frequency">Insertion Frequency</span> |
| 6795 | 6857 | <small data-i18n="(0 = Disable, 1 = Always)">(0 = Disable, 1 = Always)</small> |
| 6796 | 6858 | </label> |
| 6797 | 6859 | <input id="extension_default_interval" class="text_pole widthUnset" type="number" min="0" max="9999999" /> |
| 6798 | 6860 | </div> |
| 6799 | 6861 | </div> |
| 6800 | 6862 | </div> |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "وضع علامة", |
| 319 | 319 | "API key (optional)": "مفتاح API (اختياري)", |
| 320 | 320 | "Server url": "رابط الخادم", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "مثال: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "نموذج مخصص (اختياري)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (وضع غلاف OpenAI API)", |
| 324 | 324 | "vLLM API key": "مفتاح واجهة برمجة التطبيقات vLLM", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "مثال: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "نموذج vLLM", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (وضع التغليف لواجهة برمجة التطبيقات OpenAI)", |
| 328 | 328 | "Aphrodite API key": "مفتاح واجهة برمجة التطبيقات Aphrodite", |
| 329 | 329 | "Aphrodite Model": "نموذج أفروديت", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (خادم إخراج)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "مثال: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "مثال: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "نموذج Ollama", |
| 334 | 334 | "Download": "تحميل", |
| 335 | 335 | "Tabby API key": "مفتاح API لـ Tabby", |
| 336 | 336 | "koboldcpp API key (optional)": "مفتاح koboldcpp API (اختياري)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "مثال: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "تفويض", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "احصل على رمز واجهة برمجة التطبيقات الخاص بك لموزع الاتصالات باستخدام تدفق OAuth. سيتم توجيهك إلى openrouter.ai", |
| 340 | 340 | "Bypass status check": "تجاوز فحص الحالة", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "Flagge", |
| 319 | 319 | "API key (optional)": "API-Schlüssel (optional)", |
| 320 | 320 | "Server url": "Server-URL", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Beispiel: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Benutzerdefiniertes Modell (optional)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API-Wrappermodus)", |
| 324 | 324 | "vLLM API key": "vLLM-API-Schlüssel", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Beispiel: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "vLLM-Modell", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Wrappermodus für OpenAI API)", |
| 328 | 328 | "Aphrodite API key": "Aphrodite API-Schlüssel", |
| 329 | 329 | "Aphrodite Model": "Aphrodite-Modell", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (Output-Server)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Beispiel: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Beispiel: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Ollama-Modell", |
| 334 | 334 | "Download": "Herunterladen", |
| 335 | 335 | "Tabby API key": "Tabby API-Schlüssel", |
| 336 | 336 | "koboldcpp API key (optional)": "koboldcpp API-Schlüssel (optional)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Beispiel: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Autorisieren", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Hole dein OpenRouter-API-Token mit OAuth-Fluss. Du wirst zu openrouter.ai weitergeleitet", |
| 340 | 340 | "Bypass status check": "Umgehe Statusüberprüfung", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "bandera", |
| 319 | 319 | "API key (optional)": "Clave API (opcional)", |
| 320 | 320 | "Server url": "URL del servidor", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Ejemplo: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Modelo personalizado (opcional)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (modo contenedor de API OpenAI)", |
| 324 | 324 | "vLLM API key": "Clave API vLLM", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Ejemplo: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "Modelo vLLM", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Modo envolvente para API de OpenAI)", |
| 328 | 328 | "Aphrodite API key": "Clave de API de Aphrodite", |
| 329 | 329 | "Aphrodite Model": "Modelo Afrodita", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (Servidor de salida)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Ejemplo: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Ejemplo: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Modelo Ollama", |
| 334 | 334 | "Download": "Descargar", |
| 335 | 335 | "Tabby API key": "Clave API de Tabby", |
| 336 | 336 | "koboldcpp API key (optional)": "Clave API de koboldcpp (opcional)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Ejemplo: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Autorizar", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenga su token de API de OpenRouter utilizando el flujo OAuth. Será redirigido a openrouter.ai", |
| 340 | 340 | "Bypass status check": "Saltar la verificación del estado", |
| @@ -301,23 +301,23 @@ | ||
| 301 | 301 | "flag": "fanion", |
| 302 | 302 | "API key (optional)": "Clé API (optionnelle)", |
| 303 | 303 | "Server url": "URL du serveur", |
| 304 | 304 | "Example: http://127.0.0.1:5000": "Exemple : http://127.0.0.1:5000", |
| 305 | 305 | "Custom model (optional)": "Modèle personnalisé (optionnel)", |
| 306 | 306 | "vllm-project/vllm": "vllm-project/vllm (mode wrapper de l'API OpenAI)", |
| 307 | 307 | "vLLM API key": "Clé API vLLM", |
| 308 | 308 | "Example: http://127.0.0.1:8000": "Exemple : http://127.0.0.1:8000", |
| 309 | 309 | "vLLM Model": "Modèle vLLM", |
| 310 | 310 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (mode wrapper pour l'API OpenAI)", |
| 311 | 311 | "Aphrodite API key": "Clé API Aphrodite", |
| 312 | 312 | "Aphrodite Model": "Modèle Aphrodite", |
| 313 | 313 | "ggerganov/llama.cpp": "ggerganov/llama.cpp", |
| 314 | 314 | "Example: http://127.0.0.1:8080": "Exemple : http://127.0.0.1:8080", |
| 315 | 315 | "Example: http://127.0.0.1:11434": "Exemple : http://127.0.0.1:11434", |
| 316 | 316 | "Ollama Model": "Modèle Ollama", |
| 317 | 317 | "Download": "Télécharger", |
| 318 | 318 | "Tabby API key": "Clé API de Tabby", |
| 319 | 319 | "koboldcpp API key (optional)": "Clé API koboldcpp (facultatif)", |
| 320 | 320 | "Example: http://127.0.0.1:5001": "Exemple : http://127.0.0.1:5001", |
| 321 | 321 | "Authorize": "Autoriser", |
| 322 | 322 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenez votre jeton API OpenRouter en utilisant le flux OAuth. Vous serez redirigé vers openrouter.ai", |
| 323 | 323 | "Bypass status check": "Contourner la vérification de l'état", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "merki", |
| 319 | 319 | "API key (optional)": "API lykill (valkvæmt)", |
| 320 | 320 | "Server url": "URL þjóns", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Dæmi: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Sérsniðið módel (valkvæmt)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API umbúðastilling)", |
| 324 | 324 | "vLLM API key": "vLLM API lykill", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Dæmi: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "vLLM líkan", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (OpenAI forritunargrensl)", |
| 328 | 328 | "Aphrodite API key": "Aphrodite API lykill", |
| 329 | 329 | "Aphrodite Model": "Afródíta fyrirmynd", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (úttak þjónn)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Dæmi: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Dæmi: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Ollama módel", |
| 334 | 334 | "Download": "Niðurhal", |
| 335 | 335 | "Tabby API key": "Tabby API lykill", |
| 336 | 336 | "koboldcpp API key (optional)": "koboldcpp API lykill (valfrjálst)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Dæmi: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Heimild", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Fáðu API lykilinn þinn fyrir OpenRouter með því að nota OAuth strauminn. Þú verður endurvísað(ð/ur) á openrouter.ai", |
| 340 | 340 | "Bypass status check": "Hlaupa framhjá stöðutík", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "bandiera", |
| 319 | 319 | "API key (optional)": "Chiave API (opzionale)", |
| 320 | 320 | "Server url": "URL del server", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Esempio: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Modello personalizzato (opzionale)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (modalità wrapper API OpenAI)", |
| 324 | 324 | "vLLM API key": "Chiave API vLLM", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Esempio: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "Modello vLLM", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Modalità wrapper per l'API OpenAI)", |
| 328 | 328 | "Aphrodite API key": "Chiave API di Aphrodite", |
| 329 | 329 | "Aphrodite Model": "Modello di Afrodite", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (Server di output)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Esempio: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Esempio: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Modello Ollama", |
| 334 | 334 | "Download": "Scarica", |
| 335 | 335 | "Tabby API key": "Chiave API di Tabby", |
| 336 | 336 | "koboldcpp API key (optional)": "Chiave API koboldcpp (opzionale)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Esempio: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Autorizzare", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Ottieni il tuo token API di OpenRouter utilizzando il flusso OAuth. Sarai reindirizzato su openrouter.ai", |
| 340 | 340 | "Bypass status check": "Ignora controllo stato", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "フラグ", |
| 319 | 319 | "API key (optional)": "APIキー(オプション)", |
| 320 | 320 | "Server url": "サーバーURL", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "例: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "カスタムモデル(オプション)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API ラッパーモード)", |
| 324 | 324 | "vLLM API key": "vLLM API キー", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "例: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "vLLM モデル", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine(OpenAI APIエンドポイントのパッケージングモード)", |
| 328 | 328 | "Aphrodite API key": "アフロディーテAPIキー", |
| 329 | 329 | "Aphrodite Model": "アフロディーテモデル", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp(出力サーバー)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "例: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "例: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Ollamaモデル", |
| 334 | 334 | "Download": "ダウンロード", |
| 335 | 335 | "Tabby API key": "TabbyのAPIキー", |
| 336 | 336 | "koboldcpp API key (optional)": "koboldcpp API キー (オプション)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "例: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "承認", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "OAuthフローを使用してOpenRouter APIトークンを取得します。 openrouter.aiにリダイレクトされます", |
| 340 | 340 | "Bypass status check": "ステータスのチェックをバイパスする", |
| @@ -320,23 +320,23 @@ | ||
| 320 | 320 | "flag": "깃발", |
| 321 | 321 | "API key (optional)": "API 키 (선택 사항)", |
| 322 | 322 | "Server url": "서버 URL", |
| 323 | 323 | "Example: http://127.0.0.1:5000": "예시: http://127.0.0.1:5000", |
| 324 | 324 | "Custom model (optional)": "사용자 정의 모델 (선택 사항)", |
| 325 | 325 | "vllm-project/vllm": "vllm-project/vllm(OpenAI API 래퍼 모드)", |
| 326 | 326 | "vLLM API key": "vLLM API 키", |
| 327 | 327 | "Example: http://127.0.0.1:8000": "예: http://127.0.0.1:8000", |
| 328 | 328 | "vLLM Model": "vLLM 모델", |
| 329 | 329 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (OpenAI API의 래퍼 모드)", |
| 330 | 330 | "Aphrodite API key": "Aphrodite API 키", |
| 331 | 331 | "Aphrodite Model": "Aphrodite 모델", |
| 332 | 332 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (출력 서버)", |
| 333 | 333 | "Example: http://127.0.0.1:8080": "예: http://127.0.0.1:8080", |
| 334 | 334 | "Example: http://127.0.0.1:11434": "예: http://127.0.0.1:11434", |
| 335 | 335 | "Ollama Model": "Ollama 모델", |
| 336 | 336 | "Download": "다운로드", |
| 337 | 337 | "Tabby API key": "Tabby API 키", |
| 338 | 338 | "koboldcpp API key (optional)": "koboldcpp API 키(선택사항)", |
| 339 | 339 | "Example: http://127.0.0.1:5001": "예: http://127.0.0.1:5001", |
| 340 | 340 | "Authorize": "승인하기", |
| 341 | 341 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "OAuth 플로우를 사용하여 OpenRouter API 토큰을 가져옵니다. openrouter.ai로 리디렉션됩니다.", |
| 342 | 342 | "Legacy API (pre-OAI, no streaming)": "레거시 API (OAI 이전, 스트리밍 없음)", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "vlag", |
| 319 | 319 | "API key (optional)": "API-sleutel (optioneel)", |
| 320 | 320 | "Server url": "Server-URL", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Voorbeeld: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Aangepast model (optioneel)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (OpenAI API-wrappermodus)", |
| 324 | 324 | "vLLM API key": "vLLM API-sleutel", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Voorbeeld: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "vLLM-model", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Wrappermodus voor OpenAI API)", |
| 328 | 328 | "Aphrodite API key": "Aphrodite API-sleutel", |
| 329 | 329 | "Aphrodite Model": "Aphrodite-model", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (Output-server)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Voorbeeld: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Voorbeeld: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Ollama-model", |
| 334 | 334 | "Download": "Downloaden", |
| 335 | 335 | "Tabby API key": "Tabby API-sleutel", |
| 336 | 336 | "koboldcpp API key (optional)": "koboldcpp API-sleutel (optioneel)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Voorbeeld: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Toestemming geven", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Haal uw OpenRouter API-token op met behulp van OAuth-flow. U wordt doorgestuurd naar openrouter.ai", |
| 340 | 340 | "Bypass status check": "Omzeil statuscontrole", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "bandeira", |
| 319 | 319 | "API key (optional)": "Chave da API (opcional)", |
| 320 | 320 | "Server url": "URL do servidor", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Exemplo: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Modelo personalizado (opcional)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (modo wrapper da API OpenAI)", |
| 324 | 324 | "vLLM API key": "Chave de API vLLM", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Exemplo: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "Modelo vLLM", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Modo Wrapper para API OpenAI)", |
| 328 | 328 | "Aphrodite API key": "Chave da API Aphrodite", |
| 329 | 329 | "Aphrodite Model": "Modelo Afrodite", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (Servidor de Saída)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Exemplo: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Exemplo: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Modelo Ollama", |
| 334 | 334 | "Download": "Baixar", |
| 335 | 335 | "Tabby API key": "Chave da API do Tabby", |
| 336 | 336 | "koboldcpp API key (optional)": "Chave API koboldcpp (opcional)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Exemplo: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Autorizar", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Obtenha seu token da API do OpenRouter usando o fluxo OAuth. Você será redirecionado para openrouter.ai", |
| 340 | 340 | "Bypass status check": "Ignorar verificação de status", |
| @@ -23,9 +23,8 @@ | ||
| 23 | 23 | "Mirostat Mode": "Режим", |
| 24 | 24 | "Mirostat Tau": "Tau", |
| 25 | 25 | "Mirostat Eta": "Eta", |
| 26 | 26 | "Variability parameter for Mirostat outputs": "Параметр изменчивостиВариативность для выходных данных Mirostat.", |
| 27 | 27 | "Learning rate of Mirostat": "Скорость обучения Mirostat.", |
| 28 | - "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Сила условия регуляризации контрастивного поиска. Установите значение 0, чтобы отключить CS.", | |
| 29 | 28 | "Temperature Last": "Температура последней", |
| 30 | 29 | "LLaMA / Mistral / Yi models only": "Только для моделей LLaMA / Mistral / Yi. Перед этим обязательно выберите подходящий токенизатор.\nПоследовательности, которых не должно быть на выходе.\nОдна на строку. Текст или [идентификаторы токенов].\nМногие токены имеют пробел впереди. Используйте счетчик токенов, если не уверены.", |
| 31 | 30 | "Example: some text [42, 69, 1337]": "Пример:\nкакой-то текст\n[42, 69, 1337]", |
| @@ -60,13 +59,11 @@ | ||
| 60 | 59 | "Add BOS Token": "Добавлять BOS-токен", |
| 61 | 60 | "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Добавлять BOS-токен в начале промпта. Если выключить, ответы могут стать более креативными.", |
| 62 | 61 | "Ban EOS Token": "Запретить EOS-токен", |
| 63 | 62 | "Ban the eos_token. This forces the model to never end the generation prematurely": "Запрет EOS-токена не позволит модели завершить генерацию преждевременносамостоятельно (только при достижении лимита токенов)", |
| 64 | 63 | "Skip Special Tokens": "Пропускать спец. токены", |
| 65 | 64 | "Beam search": "Поиск Beam Search", |
| 66 | - "Number of Beams": "Количество Beam", | |
| 67 | 65 | "Length Penalty": "Штраф за длину", |
| 68 | 66 | "Early Stopping": "ПреждевременнаяПрекращать остановкасразу", |
| 69 | - "Contrastive search": "Контрастный поиск", | |
| 70 | 67 | "Penalty Alpha": "Penalty Alpha", |
| 71 | 68 | "Seed": "Зерно", |
| 72 | 69 | "Epsilon Cutoff": "Epsilon Cutoff", |
| @@ -89,7 +86,7 @@ | ||
| 89 | 86 | "Text Completion presets": "Пресеты для Text Completion", |
| 90 | 87 | "Documentation on sampling parameters": "Документация по параметрам сэмплеров", |
| 91 | 88 | "Set all samplers to their neutral/disabled state.": "Установить все сэмплеры в нейтральное/отключенное состояние.", |
| 92 | 89 | "Only enable this if your model supports context sizes greater than 8192 tokens": "Включайте эту опцию, только если ваша модель поддерживает размер контекста более 8192 токенов.\nУвеличивайте только если вы знаетепонимаете, что делаете.", |
| 93 | 90 | "Wrap in Quotes": "Заключать в кавычки", |
| 94 | 91 | "Wrap entire user message in quotes before sending.": "Перед отправкой заключать всё сообщение пользователя в кавычки.", |
| 95 | 92 | "Leave off if you use quotes manually for speech.": "Оставьте выключенным, если вручную выставляете кавычки для прямой речи.", |
| @@ -109,13 +106,13 @@ | ||
| 109 | 106 | "Adjust response length to worker capabilities": "Подстраивать длину ответа под возможности рабочих машин", |
| 110 | 107 | "API key": "API-ключ", |
| 111 | 108 | "Tabby API key": "Tabby API-ключ", |
| 112 | 109 | "Get it here:": "ПолучитьПолучите здесь:", |
| 113 | 110 | "Register": "Зарегистрироваться", |
| 114 | 111 | "TogetherAI Model": "Модель TogetherAI", |
| 115 | 112 | "Example: http://127.0.0.1:5001": "Пример: http://127.0.0.1:5001", |
| 116 | 113 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (сервер вывода)", |
| 117 | 114 | "Example: http://127.0.0.1:8080": "Пример: http://127.0.0.1:8080", |
| 118 | 115 | "Example: http://127.0.0.1:11434": "Пример: http://127.0.0.1:11434", |
| 119 | 116 | "Ollama Model": "Модель Ollama", |
| 120 | 117 | "Download": "Скачать", |
| 121 | 118 | "TogetherAI API Key": "TogetherAI API-ключ", |
| @@ -136,7 +133,7 @@ | ||
| 136 | 133 | "Server url": "URL-адрес сервера", |
| 137 | 134 | "Custom model (optional)": "Пользовательская модель (необязательно)", |
| 138 | 135 | "Bypass API status check": "Обход проверки статуса API", |
| 139 | 136 | "Example: http://127.0.0.1:5000": "Пример: http://127.0.0.1:5000", |
| 140 | 137 | "Bypass status check": "Обход проверки статуса", |
| 141 | 138 | "Mancer API key": "Ключ от Mancer API", |
| 142 | 139 | "to get your OpenAI API key.": "для получения ключа от API OpenAI", |
| @@ -289,10 +286,10 @@ | ||
| 289 | 286 | "Author's Note": "Заметки автора", |
| 290 | 287 | "Replace empty message": "Заменять пустые сообщения", |
| 291 | 288 | "Send this text instead of nothing when the text box is empty.": "Этот текст будет отправлен в случае отсутствия текста на отправку.", |
| 292 | 289 | "Unrestricted maximum value for the context slider": "Убрать потолок для ползунка контекста. Включайте только если точно знаетепонимаете, что делаете", |
| 293 | 290 | "Chat Completion Source": "Источник для Chat Completion", |
| 294 | 291 | "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde.", |
| 295 | 292 | "Review the Privacy statement": "ОзнакомитьсяОзнакомьтесь с заявлением о конфиденциальности", |
| 296 | 293 | "Trusted workers only": "Только доверенные рабочие машины", |
| 297 | 294 | "For privacy reasons, your API key will be hidden after you reload the page.": "Из соображений безопасности ваш API-ключ будет скрыт после перезагрузки страницы.", |
| 298 | 295 | "-- Horde models not loaded --": "--Модель Horde не загружена--", |
| @@ -699,7 +696,7 @@ | ||
| 699 | 696 | "Aggressive": "Агрессивный", |
| 700 | 697 | "Very aggressive": "Очень агрессивный", |
| 701 | 698 | "Eta_Cutoff_desc": "Eta cutoff - основной параметр специальной техники сэмплинга под названием Eta Sampling. В единицах 1e-4; разумное значение - 3. Установите в 0, чтобы отключить. См. статью Truncation Sampling as Language Model Desmoothing от Хьюитт и др. (2022) для получения подробной информации.", |
| 702 | 699 | "Learn how to contribute your idle GPU cycles to the Horde": "Узнайте, как внести свой вкладиспользовать ввремя своипростоя свободныевашего GPU-циклы вдля ордупомощи Horde", |
| 703 | 700 | "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Используйте соответствующий токенизатор для моделей Google через их API. Медленная обработка подсказок, но предлагает намного более точный подсчет токенов.", |
| 704 | 701 | "Load koboldcpp order": "Загрузить порядок из koboldcpp", |
| 705 | 702 | "Use Google Tokenizer": "Использовать токенизатор Google", |
| @@ -744,7 +741,7 @@ | ||
| 744 | 741 | "Last Assistant Prefix": "Последний префикс ассистента", |
| 745 | 742 | "System Instruction Prefix": "Префикс системной инструкции", |
| 746 | 743 | "User Filler Message": "Принудительное сообщение пользователя", |
| 747 | 744 | "Permanent": "перманентныхпостоянных", |
| 748 | 745 | "Alt. Greetings": "Др. варианты", |
| 749 | 746 | "Smooth Streaming": "Плавный стриминг", |
| 750 | 747 | "Save checkpoint": "Сохранить чекпоинт", |
| @@ -1227,7 +1224,6 @@ | ||
| 1227 | 1224 | "JSON-serialized array of strings.": "Список строк в формате JSON.", |
| 1228 | 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 | 1226 | "Helpful tip coming soon.": "Подсказку скоро добавим.", |
| 1230 | - "Temperature_Last_desc": "Использовать Temperature сэмплер в последнюю очередь. Это почти всегда разумно.\nПри включении: сначала выборка набора правдоподобных токенов, затем применение Temperature для корректировки их относительных вероятностей (технически, логитов).\nПри отключении: сначала применение Temperature для корректировки относительных вероятностей ВСЕХ токенов, затем выборка правдоподобных токенов из этого.\nОтключение Temperature Last увеличивает вероятности в хвосте распределения, что увеличивает шансы получить несогласованный ответ.", | |
| 1231 | 1227 | "Speculative Ngram": "Speculative Ngram", |
| 1232 | 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 | 1229 | "Spaces Between Special Tokens": "Spaces Between Special Tokens", |
| @@ -1256,7 +1252,6 @@ | ||
| 1256 | 1252 | "DreamGen Model": "Модель DreamGen", |
| 1257 | 1253 | "vllm-project/vllm": "vllm-project/vllm (режим враппера OpenAI API)", |
| 1258 | 1254 | "vLLM API key": "Ключ от API vLLM", |
| 1259 | - "Example: 127.0.0.1:8000": "Example: http://127.0.0.1:8000", | |
| 1260 | 1255 | "vLLM Model": "Модель vLLM", |
| 1261 | 1256 | "Aphrodite Model": "Модель Aphrodite", |
| 1262 | 1257 | "Peek a password": "Посмотреть пароль", |
| @@ -1734,7 +1729,7 @@ | ||
| 1734 | 1729 | "markdown_hotkeys_desc": "Включить горячие клавиши для вставки символов разметки в некоторых полях ввода. См. '/help hotkeys'.", |
| 1735 | 1730 | "Save and Update": "Сохранить и обновить", |
| 1736 | 1731 | "Profile name:": "Название профиля:", |
| 1737 | 1732 | "API returned an error": "API вернулоответило ошибкуошибкой", |
| 1738 | 1733 | "Failed to save preset": "Не удалось сохранить пресет", |
| 1739 | 1734 | "Preset name should be unique.": "Название пресета должно быть уникальным.", |
| 1740 | 1735 | "Invalid file": "Невалидный файл", |
| @@ -1756,8 +1751,7 @@ | ||
| 1756 | 1751 | "dot quota_error": "имеется достаточно кредитов.", |
| 1757 | 1752 | "If you have sufficient credits, please try again later.": "Если кредитов достаточно, то повторите попытку позднее.", |
| 1758 | 1753 | "Proxy preset '${0}' not found": "Пресет '${0}' не найден", |
| 1759 | 1754 | "Window.ai returned an error": "Window.ai вернулответил ошибкуошибкой", |
| 1760 | - "Get it here:": "Загрузите здесь:", | |
| 1761 | 1755 | "Extension is not installed": "Расширение не установлено", |
| 1762 | 1756 | "Update or remove your reverse proxy settings.": "Измените или удалите ваши настройки прокси.", |
| 1763 | 1757 | "An error occurred while importing prompts. More info available in console.": "В процессе импорта произошла ошибка. Подробную информацию см. в консоли.", |
| @@ -1866,7 +1860,7 @@ | ||
| 1866 | 1860 | "Group Chat could not be saved": "Не удалось сохранить групповой чат", |
| 1867 | 1861 | "Deleted group member swiped. To get a reply, add them back to the group.": "Вы пытаетесь свайпнуть удалённого члена группы. Чтобы получить ответ, добавьте этого персонажа обратно в группу.", |
| 1868 | 1862 | "Currently no group selected.": "В данный момент не выбрано ни одной группы.", |
| 1869 | 1863 | "Not so fast! Wait for the characters to stop typing before deleting the group.": "Чуть помедленнее! Перед удалением группы дождитесь, пока персонажперсонажи закончитзакончат печатать.", |
| 1870 | 1864 | "Delete the group?": "Удалить группу?", |
| 1871 | 1865 | "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 | 1866 | "Can't peek a character while group reply is being generated": "Невозможно открыть карточку персонажа во время генерации ответа", |
| @@ -1997,7 +1991,7 @@ | ||
| 1997 | 1991 | "Default persona deleted": "Удалена персона по умолчанию", |
| 1998 | 1992 | "The locked persona was deleted. You will need to set a new persona for this chat.": "Удалена привязанная к чату персона. Вам будет необходимо выбрать новую фиксированную персону для этого чата.", |
| 1999 | 1993 | "Persona deleted": "Персона удалена", |
| 2000 | 1994 | "You must bind a name to this persona before you can set it as the default.": "Прежде чем установить эту персону в качестве персоны по умолчанию, ей необходимо задатьприсвоить имя.", |
| 2001 | 1995 | "Persona name not set": "У персоны отсутствует имя", |
| 2002 | 1996 | "Are you sure you want to remove the default persona?": "Вы точно хотите снять статус персоны по умолчанию?", |
| 2003 | 1997 | "This persona will no longer be used by default when you open a new chat.": "Эта персона больше не будет автоматически выбираться при старте нового чата", |
| @@ -2038,7 +2032,7 @@ | ||
| 2038 | 2032 | "[Currently loaded]": "[Загруженная сейчас]", |
| 2039 | 2033 | "Search providers...": "Искать по провайдерам...", |
| 2040 | 2034 | "Automatically chooses an alternative provider if chosen providers can't serve your request.": "Автоматически переключаться на другого провайдера, если текущий не может обслужить запрос.", |
| 2041 | 2035 | "Example: http://127.0.0.1:8000": "Пример: http://127.0.0.1:8000", |
| 2042 | 2036 | "Edit a connection profile": "Редактировать профиль соединения", |
| 2043 | 2037 | "System Prompt Name": "Название системного промпта", |
| 2044 | 2038 | "Use System Prompt": "Использовать системный промпт", |
| @@ -2203,5 +2197,146 @@ | ||
| 2203 | 2197 | "Input:": "Входные данные:", |
| 2204 | 2198 | "Tokenized text:": "Токенизированный текст:", |
| 2205 | 2199 | "Token IDs:": "Идентификаторы токенов:", |
| 2206 | 2200 | "Tokens:": "Токенов:", |
| 2201 | + "Max prompt cost:": "Макс. стоимость промпта:", | |
| 2202 | + "Reset custom sampler selection": "Сбросить подборку семплеров", | |
| 2203 | + "Here you can toggle the display of individual samplers. (WIP)": "Здесь можно включить или выключить отображение каждого из сэмплеров отдельно. (WIP)", | |
| 2204 | + "Request Model Reasoning": "Запрашивать цепочку рассуждений", | |
| 2205 | + "Reasoning": "Рассуждения / Reasoning", | |
| 2206 | + "Auto-Parse": "Авто-парсинг", | |
| 2207 | + "reasoning_auto_parse": "Автоматически считывать блоки рассуждений, расположенные между префиксом и суффиксом рассуждений. Для работы должно быть указано и то, и другое.", | |
| 2208 | + "Auto-Expand": "Разворачивать", | |
| 2209 | + "reasoning_auto_expand": "Автоматически разворачивать блоки рассуждений.", | |
| 2210 | + "Show Hidden": "Показывать время", | |
| 2211 | + "reasoning_show_hidden": "Отображать затраченное на рассуждения время для моделей со скрытой цепочкой рассуждений", | |
| 2212 | + "Add to Prompts": "Добавлять в промпт", | |
| 2213 | + "reasoning_add_to_prompts": "Добавлять существующие блоки рассуждений в промпт. Для добавления новых используйте меню редактирования сообщений.", | |
| 2214 | + "reasoning_max_additions": "Макс. кол-во блоков рассуждений в промпте, считается от последнего сообщения", | |
| 2215 | + "Max": "Макс.", | |
| 2216 | + "Reasoning Formatting": "Форматирование рассуждений", | |
| 2217 | + "Prefix": "Префикс", | |
| 2218 | + "Suffix": "Постфикс", | |
| 2219 | + "Separator": "Разделитель", | |
| 2220 | + "reasoning_separator": "Вставляется между рассуждениями и содержанием самого сообщения.", | |
| 2221 | + "reasoning_prefix": "Вставляется перед рассуждениями.", | |
| 2222 | + "reasoning_suffix": "Вставляется после рассуждений.", | |
| 2223 | + "Seed_desc": "Фиксированное значение зерна позволяет получать предсказуемые, одинаковые результаты на одинаковых настройках. Поставьте -1 для рандомного зерна.", | |
| 2224 | + "# of Beams": "Кол-во лучей", | |
| 2225 | + "The number of sequences generated at each step with Beam Search.": "Кол-во вариантов, генерируемых Beam Search на каждом шаге работы.", | |
| 2226 | + "Penalize sequences based on their length.": "Штрафует строки в зависимости от длины", | |
| 2227 | + "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. Поставив галочку, вы укажете поиску остановиться тогда, когда будет достигнуто кол-во лучей из соответствующего поля. Если галочку не отмечать, то генерация остановится тогда, когда сочтёт, что дальше найти лучших кандидатов слишком маловероятно.", | |
| 2228 | + "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-сэмплинга, подбирающий наиболее вероятную последовательность слов или токенов путём исследования и расширения сразу нескольких вариантов. На каждом шаге он удерживает фиксированное кол-во самых подходящих вариантов (ширина луча).", | |
| 2229 | + "Smooth_Sampling_desc": "Изменяет распределение с помощью квадратичных и кубических преобразований. Снижение Коэффициента сглаживания даёт более креативные ответы, обычно идеальное значение находится в диапазоне 0.2-0.3 (при кривой сглаживания=1.0). Повышение значения Кривой сглаживания сделает кривую круче, что приведёт к более агрессивной фильтрации маловероятных вариантов. Установив Кривую сглаживания = 1.0, вы фактически нейтрализуете этот параметр и будете работать только с Коэффициентом", | |
| 2230 | + "Temperature_Last_desc": "Применять сэмплер Температуры в последнюю очередь. Почти всегда оправдано.\nПри включении: сначала все токены семплируются, и затем температура регулирует распределение у оставшихся (технически, у оставшихся логитов).\nПри выключении: сначала температура настраивает распределение ВСЕХ токенов, и потом они семплируются уже с этим обновлённым распределением.\nПри отключении этой опции токены в хвосте получают больше шансов попасть в итоговую последовательность, что может привести к менее связным и логичным ответам.", | |
| 2231 | + "Swipe # for All Messages": "Номер свайпа на всех сообщениях", | |
| 2232 | + "Display swipe numbers for all messages, not just the last.": "Отображать номер свайпа для всех сообщений, а не только для последнего.", | |
| 2233 | + "Penalty Range": "Окно для штрафа", | |
| 2234 | + "Never": "Никогда", | |
| 2235 | + "Groups and Past Personas": "Для групп и прошлых персон", | |
| 2236 | + "Always": "Всегда", | |
| 2237 | + "Request model reasoning": "Запрашивать рассуждения", | |
| 2238 | + "Allows the model to return its thinking process.": "Позволяет модели высылать в ответе свою цепочку рассуждений.", | |
| 2239 | + "Rename Persona": "Переименовать персону", | |
| 2240 | + "Change Persona Image": "Изменить изображение персоны", | |
| 2241 | + "Duplicate Persona": "Клонировать персону", | |
| 2242 | + "Delete Persona": "Удалить персону", | |
| 2243 | + "Enter a new name for this persona:": "Введите новое имя персоны:", | |
| 2244 | + "Connections": "Связи", | |
| 2245 | + "Click to select this as default persona for the new chats. Click again to remove it.": "Нажмите, чтобы установить эту персону стандартной для всех новых чатов. Нажмите ещё раз, чтобы отключить.", | |
| 2246 | + "Character": "Персонаж", | |
| 2247 | + "Click to lock your selected persona to the current character. Click again to remove the lock.": "Нажмите, чтобы закрепить эту персону для текущего персонажа. Нажмите ещё раз, чтобы открепить.", | |
| 2248 | + "Chat": "Чат", | |
| 2249 | + "[No character connections. Click one of the buttons above to connect this persona.]": "[Связи отсутствуют. Нажмите на одну из кнопок выше, чтобы создать.]", | |
| 2250 | + "Global Settings": "Общие настройки", | |
| 2251 | + "Allow multiple persona connections per character": "Разрешить привязывать несколько персон к одному персонажу", | |
| 2252 | + "When multiple personas are connected to a character, a popup will appear to select which one to use": "При связывании нескольких персон с персонажем, будет появляться окошко с предложением выбрать нужную.", | |
| 2253 | + "Auto-lock a chosen persona to the chat": "Автоматически привязывать выбранную персону к чату", | |
| 2254 | + "Whenever a persona is selected, it will be locked to the current chat and automatically selected when the chat is opened.": "При выборе новой персоны она автоматически будет привязана к текущему чату, и будет выбираться при его открытии.", | |
| 2255 | + "Current Persona": "Текущая персона", | |
| 2256 | + "The chat has been successfully converted!": "Чат успешно преобразован!", | |
| 2257 | + "Manual": "Когда вы скажете", | |
| 2258 | + "Auto Mode delay": "Задержка авто-режима", | |
| 2259 | + "Use tag as folder": "Тег-папка", | |
| 2260 | + "All connections to ${0} have been removed.": "Все связи с персонажем ${0} были удалены.", | |
| 2261 | + "Personas Unlocked": "Персоны отвязаны", | |
| 2262 | + "Remove All Connections": "Удалить все связи", | |
| 2263 | + "Persona ${0} selected and auto-locked to current chat": "Персона ${0} выбрана и автоматически закреплена за этим чатом", | |
| 2264 | + "This persona is only temporarily chosen. Click for more info.": "Данная персона выбрана лишь временно. Нажмите, чтобы узнать больше.", | |
| 2265 | + "Temporary Persona": "Временная персона", | |
| 2266 | + "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.": "К этому чату уже привязана иная персона, либо у вас выбрана иная персона по-умолчанию. Выбранная в данный момент персона будет временной, и сбросится после перезагрузки. Если хотите всегда использовать её в этом чате, советуем её прикрепить.", | |
| 2267 | + "Current Persona: ${0}": "Выбранная персона: ${0}", | |
| 2268 | + "Chat persona: ${0}": "Персона для этого чата: ${0}", | |
| 2269 | + "Default persona: ${0}": "Персона по умолчанию (стандартная): ${0}", | |
| 2270 | + "Persona ${0} is now unlocked from this chat.": "Персона ${0} отвязана от этого чата.", | |
| 2271 | + "Persona Unlocked": "Персона отвязана", | |
| 2272 | + "Persona ${0} is now unlocked from character ${1}.": "Персона ${0} отвязана от персонажа ${1}.", | |
| 2273 | + "Persona Not Found": "Персона не найдена", | |
| 2274 | + "Persona Locked": "Персона закреплена", | |
| 2275 | + "User persona ${0} is locked to character ${1}${2}": "Персона ${0} прикреплена к персонажу ${1}${2}", | |
| 2276 | + "Persona Name Not Set": "У персоны отсутствует имя", | |
| 2277 | + "You must bind a name to this persona before you can set a lorebook.": "Перед привязкой лорбука персоне необходимо присвоить имя.", | |
| 2278 | + "Default Persona Removed": "Персона по умолчанию снята", | |
| 2279 | + "Persona is locked to the current character": "Персона закреплена за этим персонажем", | |
| 2280 | + "Persona is locked to the current chat": "Персона закреплена за этим чатом", | |
| 2281 | + "characters": "перс.", | |
| 2282 | + "character": "персонаж", | |
| 2283 | + "in this group": "в группе", | |
| 2284 | + "Chatting Since": "Первая беседа", | |
| 2285 | + "Context": "Контекст", | |
| 2286 | + "Response": "Ответ", | |
| 2287 | + "Connected": "Подключено", | |
| 2288 | + "Enter new background name:": "Введите новое название для фона:", | |
| 2289 | + "AI Horde Website": "Сайт AI Horde", | |
| 2290 | + "Enable web search": "Включить поиск в Интернете", | |
| 2291 | + "Use search capabilities provided by the backend.": "Разрешить использование предоставляемых бэкендом функций поиска.", | |
| 2292 | + "Request inline images": "Запрашивать inline-изображения", | |
| 2293 | + "Allows the model to return image attachments.": "Разрешить модели отправлять вложения в виде картинок.", | |
| 2294 | + "Request inline images_desc_2": "Не совместимо со следующим функционалом: вызов функций, поиск в Интернете, системный промпт.", | |
| 2295 | + "Connected Personas": "Связанные персоны", | |
| 2296 | + "[Currently no personas connected]": "[Связанных персон нет]", | |
| 2297 | + "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 + ЛКМ, чтобы её отвязать.", | |
| 2298 | + "Persona Connections": "Связи с персонами", | |
| 2299 | + "Pooled order": "Если уже давно не отвечали", | |
| 2300 | + "Attach a File": "Приложить файл", | |
| 2301 | + "Attach a file or image to a current chat.": "Приложить файл или изображение к текущему чату", | |
| 2302 | + "Remove the file": "Удалить файл", | |
| 2303 | + "Delete the Chat File?": "Удалить чат?", | |
| 2304 | + "Forbidden": "Доступ запрещён", | |
| 2305 | + "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.", | |
| 2306 | + "Invalid endpoint URL. Requests may fail.": "Некорректный адрес эндпоинта. Запросы могут не проходить.", | |
| 2307 | + "How to install extensions?": "Как устанавливать расширения?", | |
| 2308 | + "Click the flashing button to install extensions.": "Чтобы их установить, нажмите на мигающую кнопку.", | |
| 2309 | + "ext_regex_reasoning_desc": "Содержимое блоков рассуждений. При отмеченной галочке \"Только промпт\" будут также обработаны добавленные в промпт рассуждения.", | |
| 2310 | + "Macro in Find Regex": "Макросы в рег. выражении", | |
| 2311 | + "Don't substitute": "Не заменять", | |
| 2312 | + "Substitute (raw)": "Заменять в \"чистом\" виде", | |
| 2313 | + "Substitute (escaped)": "Заменять после экранирования", | |
| 2314 | + "ext_regex_other_options_desc": "По умолчанию, расширение вносит изменения в сам файл чата.\nПри включении одной из опций (или обеих), файл чата останется нетронутым, при этом сами изменения по-прежнему будут действовать.", | |
| 2315 | + "ext_regex_flags_help": "Нажмите, чтобы узнать больше о флагах в рег. выражениях.", | |
| 2316 | + "Applies to all matches": "Заменяет все вхождения", | |
| 2317 | + "Applies to the first match": "Заменяет первое вхождение", | |
| 2318 | + "Case insensitive": "Не чувствительно к регистру", | |
| 2319 | + "Case sensitive": "Чувствительно к регистру", | |
| 2320 | + "Find Regex is empty": "Рег. выражение не указано", | |
| 2321 | + "Click the button to save it as a file.": "Нажмите на кнопку справа, чтобы сохранить его в файл.", | |
| 2322 | + "Export as JSONL": "Экспорт в формате JSONL", | |
| 2323 | + "Thought for some time": "Какое-то время заняли размышления", | |
| 2324 | + "Thinking...": "В раздумьях...", | |
| 2325 | + "Thought for ${0}": "Размышления заняли ${0}", | |
| 2326 | + "Hidden reasoning - Add reasoning block": "Рассуждения скрыты - Добавить блок рассуждений", | |
| 2327 | + "Add reasoning block": "Добавить блок рассуждений", | |
| 2328 | + "Edit reasoning": "Редактировать рассуждения", | |
| 2329 | + "Copy reasoning": "Скопировать рассуждения", | |
| 2330 | + "Confirm Edit": "Подтвердить", | |
| 2331 | + "Remove reasoning": "Удалить рассуждения", | |
| 2332 | + "Cancel edit": "Отменить редактирование", | |
| 2333 | + "Remove Reasoning": "Удалить рассуждения", | |
| 2334 | + "Are you sure you want to clear the reasoning?<br />Visible message contents will stay intact.": "Вы точно хотите удалить блок рассуждений?<br />Основное сообщение останется на месте.", | |
| 2335 | + "Reasoning Parse": "Парсинг рассуждений", | |
| 2336 | + "Both prefix and suffix must be set in the Reasoning Formatting settings.": "В настройках форматирования рассуждений должны быть заданы префикс и суффикс.", | |
| 2337 | + "Invalid return type '${0}', defaulting to 'reasoning'.": "Некорректный возвращаемый тип, используем стандартный 'reasoning'.", | |
| 2338 | + "Reasoning already exists.": "Рассуждения уже присутствуют.", | |
| 2339 | + "Edit Message": "Редактирование", | |
| 2340 | + "Status check bypassed": "Проверка статуса отключена", | |
| 2341 | + "Valid": "Работает" | |
| 2207 | 2342 | } |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "прапорцем", |
| 319 | 319 | "API key (optional)": "Ключ API (необов'язково)", |
| 320 | 320 | "Server url": "URL-адреса сервера", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Приклад: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Власна модель (необов'язково)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (режим оболонки OpenAI API)", |
| 324 | 324 | "vLLM API key": "Ключ API vLLM", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Приклад: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "Модель vLLM", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (режим OpenAI API)", |
| 328 | 328 | "Aphrodite API key": "Ключ API для Aphrodite", |
| 329 | 329 | "Aphrodite Model": "Модель Афродіта", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp (сервер виведення)", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Приклад: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Приклад: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Модель Ollama", |
| 334 | 334 | "Download": "Завантажити", |
| 335 | 335 | "Tabby API key": "Ключ API для Tabby", |
| 336 | 336 | "koboldcpp API key (optional)": "API-ключ koboldcpp (необов’язково)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Приклад: http://127.0.0.1:5001", |
| 338 | 338 | "Authorize": "Авторизувати", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Отримайте свій токен API OpenRouter за допомогою OAuth. Вас буде перенаправлено на openrouter.ai", |
| 340 | 340 | "Bypass status check": "Обійти перевірку статусу", |
| @@ -318,23 +318,23 @@ | ||
| 318 | 318 | "flag": "cờ", |
| 319 | 319 | "API key (optional)": "Key API (tùy chọn)", |
| 320 | 320 | "Server url": "URL máy chủ", |
| 321 | 321 | "Example: http://127.0.0.1:5000": "Ví dụ: http://127.0.0.1:5000", |
| 322 | 322 | "Custom model (optional)": "Model tùy chỉnh (tùy chọn)", |
| 323 | 323 | "vllm-project/vllm": "vllm-project/vllm (Chế độ trình bao bọc API OpenAI)", |
| 324 | 324 | "vLLM API key": "Key API vLLM", |
| 325 | 325 | "Example: http://127.0.0.1:8000": "Ví dụ: http://127.0.0.1:8000", |
| 326 | 326 | "vLLM Model": "Model vLLM", |
| 327 | 327 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite-engine (Chế độ đóng gói cho Giao diện lập trình ứng dụng OpenAI)", |
| 328 | 328 | "Aphrodite API key": "Key API Aphrodite", |
| 329 | 329 | "Aphrodite Model": "Moddel cho Aphrodite", |
| 330 | 330 | "ggerganov/llama.cpp": "ggerganov/llama.cpp", |
| 331 | 331 | "Example: http://127.0.0.1:8080": "Ví dụ: http://127.0.0.1:8080", |
| 332 | 332 | "Example: http://127.0.0.1:11434": "Ví dụ: http://127.0.0.1:11434", |
| 333 | 333 | "Ollama Model": "Model Ollama", |
| 334 | 334 | "Download": "Tải xuống", |
| 335 | 335 | "Tabby API key": "Key API Tabby", |
| 336 | 336 | "koboldcpp API key (optional)": "Key API koboldcpp (tùy chọn)", |
| 337 | 337 | "Example: http://127.0.0.1:5001": "Ví dụ: http://127.0.0.1:5001", |
| 338 | 338 | "Cho phép": "Ủy quyền", |
| 339 | 339 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Nhận mã thông báo API OpenRouter của bạn bằng cách sử dụng luồng OAuth. Bạn sẽ được chuyển hướng đến openrouter.ai", |
| 340 | 340 | "Bypass status check": "Bỏ qua check trạng thái", |
| @@ -347,7 +347,7 @@ | ||
| 347 | 347 | "Mancer Model": "Mancer 模型", |
| 348 | 348 | "API key (optional)": "API密钥(可选)", |
| 349 | 349 | "Server url": "服务器URL", |
| 350 | 350 | "Example: http://127.0.0.1:5000": "示例:http://127.0.0.1:5000", |
| 351 | 351 | "Model ID (optional)": "模型 ID(可选)", |
| 352 | 352 | "Make sure you run it with": "确保您在运行时加上", |
| 353 | 353 | "flag": "标志", |
| @@ -364,7 +364,7 @@ | ||
| 364 | 364 | "No model description": "[无描述]", |
| 365 | 365 | "vllm-project/vllm": "vllm-project/vllm(OpenAI API 包装器模式)", |
| 366 | 366 | "vLLM API key": "vLLM API 密钥", |
| 367 | 367 | "Example: http://127.0.0.1:8000": "示例:http://127.0.0.1:8000", |
| 368 | 368 | "vLLM Model": "vLLM 模型", |
| 369 | 369 | "HuggingFace Token": "HuggingFace 代币", |
| 370 | 370 | "Endpoint URL": "端点 URL", |
| @@ -373,8 +373,8 @@ | ||
| 373 | 373 | "Aphrodite API key": "Aphrodite API 密钥", |
| 374 | 374 | "Aphrodite Model": "Aphrodite 模型", |
| 375 | 375 | "ggerganov/llama.cpp": "ggerganov/llama.cpp", |
| 376 | 376 | "Example: http://127.0.0.1:8080": "示例:http://127.0.0.1:8080", |
| 377 | 377 | "Example: http://127.0.0.1:11434": "示例:http://127.0.0.1:11434", |
| 378 | 378 | "Ollama Model": "Ollama 模型", |
| 379 | 379 | "Download": "下载", |
| 380 | 380 | "Tabby API key": "Tabby API 密钥", |
| @@ -382,7 +382,7 @@ | ||
| 382 | 382 | "must be set in Tabby's config.yml to switch models.": "必须在Tabby的config.yml内设置以切换模型", |
| 383 | 383 | "Use an admin API key.": "使用管理员API密钥。", |
| 384 | 384 | "koboldcpp API key (optional)": "koboldcpp API 密钥(可选)", |
| 385 | 385 | "Example: http://127.0.0.1:5001": "示例:http://127.0.0.1:5001", |
| 386 | 386 | "Bypass status check": "跳过状态检查", |
| 387 | 387 | "Derive context size from backend": "从后端获取上下文长度", |
| 388 | 388 | "Authorize": "授权", |
| @@ -319,23 +319,23 @@ | ||
| 319 | 319 | "flag": "旗標", |
| 320 | 320 | "API key (optional)": "API 金鑰(可選)", |
| 321 | 321 | "Server url": "伺服器 URL", |
| 322 | 322 | "Example: http://127.0.0.1:5000": "範例:http://127.0.0.1:5000", |
| 323 | 323 | "Custom model (optional)": "自訂模型(選填)", |
| 324 | 324 | "vllm-project/vllm": "vllm-project/vllm", |
| 325 | 325 | "vLLM API key": "vLLM API 金鑰", |
| 326 | 326 | "Example: http://127.0.0.1:8000": "範例:http://127.0.0.1:8000", |
| 327 | 327 | "vLLM Model": "vLLM 模型", |
| 328 | 328 | "PygmalionAI/aphrodite-engine": "PygmalionAI/aphrodite 引擎", |
| 329 | 329 | "Aphrodite API key": "Aphrodite API 金鑰", |
| 330 | 330 | "Aphrodite Model": "Aphrodite 模型", |
| 331 | 331 | "ggerganov/llama.cpp": "ggerganov/llama.cpp", |
| 332 | 332 | "Example: http://127.0.0.1:8080": "範例:http://127.0.0.1:8080", |
| 333 | 333 | "Example: http://127.0.0.1:11434": "範例:http://127.0.0.1:11434", |
| 334 | 334 | "Ollama Model": "Ollama 模型", |
| 335 | 335 | "Download": "下載", |
| 336 | 336 | "Tabby API key": "Tabby API 金鑰", |
| 337 | 337 | "koboldcpp API key (optional)": "KoboldCpp API 金鑰(可選)", |
| 338 | 338 | "Example: http://127.0.0.1:5001": "範例:http://127.0.0.1:5001", |
| 339 | 339 | "Authorize": "授權", |
| 340 | 340 | "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "使用 OAuth 流程取得您的 OpenRouter API 符元。您將被重新導向到 openrouter.ai", |
| 341 | 341 | "Bypass status check": "繞過狀態檢查", |
| @@ -172,8 +172,10 @@ import { | ||
| 172 | 172 | copyText, |
| 173 | 173 | escapeHtml, |
| 174 | 174 | saveBase64AsFile, |
| 175 | + uuidv4, | |
| 176 | + equalsIgnoreCaseAndAccents, | |
| 175 | 177 | } from './scripts/utils.js'; |
| 176 | 178 | import { debounce_timeout, IGNORE_SYMBOL } from './scripts/constants.js'; |
| 177 | 179 | |
| 178 | 180 | import { doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js'; |
| 179 | 181 | import { COMMENT_NAME_DEFAULT, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, stopScriptExecution } from './scripts/slash-commands.js'; |
| @@ -494,6 +496,8 @@ export const event_types = { | ||
| 494 | 496 | GENERATE_AFTER_COMBINE_PROMPTS: 'generate_after_combine_prompts', |
| 495 | 497 | GENERATE_AFTER_DATA: 'generate_after_data', |
| 496 | 498 | GROUP_MEMBER_DRAFTED: 'group_member_drafted', |
| 499 | + GROUP_WRAPPER_STARTED: 'group_wrapper_started', | |
| 500 | + GROUP_WRAPPER_FINISHED: 'group_wrapper_finished', | |
| 497 | 501 | WORLD_INFO_ACTIVATED: 'world_info_activated', |
| 498 | 502 | TEXT_COMPLETION_SETTINGS_READY: 'text_completion_settings_ready', |
| 499 | 503 | CHAT_COMPLETION_SETTINGS_READY: 'chat_completion_settings_ready', |
| @@ -514,6 +518,9 @@ export const event_types = { | ||
| 514 | 518 | ONLINE_STATUS_CHANGED: 'online_status_changed', |
| 515 | 519 | IMAGE_SWIPED: 'image_swiped', |
| 516 | 520 | CONNECTION_PROFILE_LOADED: 'connection_profile_loaded', |
| 521 | + CONNECTION_PROFILE_CREATED: 'connection_profile_created', | |
| 522 | + CONNECTION_PROFILE_DELETED: 'connection_profile_deleted', | |
| 523 | + CONNECTION_PROFILE_UPDATED: 'connection_profile_updated', | |
| 517 | 524 | TOOL_CALLS_PERFORMED: 'tool_calls_performed', |
| 518 | 525 | TOOL_CALLS_RENDERED: 'tool_calls_rendered', |
| 519 | 526 | }; |
| @@ -589,7 +596,7 @@ let is_delete_mode = false; | ||
| 589 | 596 | let fav_ch_checked = false; |
| 590 | 597 | let scrollLock = false; |
| 591 | 598 | export let abortStatusCheck = new AbortController(); |
| 592 | 599 | export let charDragDropHandler = null; |
| 593 | 600 | |
| 594 | 601 | /** @type {debounce_timeout} The debounce timeout used for chat/settings save. debounce_timeout.long: 1.000 ms */ |
| 595 | 602 | export const DEFAULT_SAVE_EDIT_TIMEOUT = debounce_timeout.relaxed; |
| @@ -644,7 +651,7 @@ export const extension_prompt_roles = { | ||
| 644 | 651 | ASSISTANT: 2, |
| 645 | 652 | }; |
| 646 | 653 | |
| 647 | 654 | export const MAX_INJECTION_DEPTH = 100010000; |
| 648 | 655 | |
| 649 | 656 | const SAFETY_CHAT = [ |
| 650 | 657 | { |
| @@ -1140,7 +1147,7 @@ export async function clearItemizedPrompts() { | ||
| 1140 | 1147 | async function getStatusHorde() { |
| 1141 | 1148 | try { |
| 1142 | 1149 | const hordeStatus = await checkHordeStatus(); |
| 1143 | 1150 | setOnlineStatus(hordeStatus ? 't`Connected'` : 'no_connection'); |
| 1144 | 1151 | } |
| 1145 | 1152 | catch { |
| 1146 | 1153 | setOnlineStatus('no_connection'); |
| @@ -1207,7 +1214,7 @@ async function getStatusTextgen() { | ||
| 1207 | 1214 | } |
| 1208 | 1215 | |
| 1209 | 1216 | if ([textgen_types.GENERIC, textgen_types.OOBA].includes(textgen_settings.type) && textgen_settings.bypass_status_check) { |
| 1210 | 1217 | setOnlineStatus('t`Status check bypassed'`); |
| 1211 | 1218 | return resultCheckStatus(); |
| 1212 | 1219 | } |
| 1213 | 1220 | |
| @@ -1232,7 +1239,7 @@ async function getStatusTextgen() { | ||
| 1232 | 1239 | setOnlineStatus(textgen_settings.togetherai_model); |
| 1233 | 1240 | } else if (textgen_settings.type === textgen_types.OLLAMA) { |
| 1234 | 1241 | loadOllamaModels(data?.data); |
| 1235 | 1242 | setOnlineStatus(textgen_settings.ollama_model || 't`Connected'`); |
| 1236 | 1243 | } else if (textgen_settings.type === textgen_types.INFERMATICAI) { |
| 1237 | 1244 | loadInfermaticAIModels(data?.data); |
| 1238 | 1245 | setOnlineStatus(textgen_settings.infermaticai_model); |
| @@ -1256,7 +1263,7 @@ async function getStatusTextgen() { | ||
| 1256 | 1263 | setOnlineStatus(textgen_settings.tabby_model || data?.result); |
| 1257 | 1264 | } else if (textgen_settings.type === textgen_types.GENERIC) { |
| 1258 | 1265 | loadGenericModels(data?.data); |
| 1259 | 1266 | setOnlineStatus(textgen_settings.generic_model || data?.result || 't`Connected'`); |
| 1260 | 1267 | } else { |
| 1261 | 1268 | setOnlineStatus(data?.result); |
| 1262 | 1269 | } |
| @@ -1370,8 +1377,11 @@ export function resultCheckStatus() { | ||
| 1370 | 1377 | * 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 | 1378 | * If the character is different from the currently selected one, it will clear the chat and reset any selected character or group. |
| 1372 | 1379 | * @param {number} id The ID of the character to switch to. |
| 1380 | + * @param {object} [options] Options for the switch. | |
| 1381 | + * @param {boolean} [options.switchMenu=true] Whether to switch the right menu to the character edit menu if the character is already selected. | |
| 1382 | + * @returns {Promise<void>} A promise that resolves when the character is switched. | |
| 1373 | 1383 | */ |
| 1374 | 1384 | export async function selectCharacterById(id, { switchMenu = true } = {}) { |
| 1375 | 1385 | if (characters[id] === undefined) { |
| 1376 | 1386 | return; |
| 1377 | 1387 | } |
| @@ -1400,9 +1410,9 @@ export async function selectCharacterById(id) { | ||
| 1400 | 1410 | } |
| 1401 | 1411 | } else { |
| 1402 | 1412 | //if clicked on character that was already selected |
| 1403 | 1413 | switchMenu && (selected_button = 'character_edit'); |
| 1404 | 1414 | await unshallowCharacter(this_chid); |
| 1405 | 1415 | select_selected_character(this_chid, { switchMenu }); |
| 1406 | 1416 | } |
| 1407 | 1417 | } |
| 1408 | 1418 | |
| @@ -1787,6 +1797,7 @@ export async function getCharacters() { | ||
| 1787 | 1797 | body: JSON.stringify({}), |
| 1788 | 1798 | }); |
| 1789 | 1799 | if (response.ok === true) { |
| 1800 | + const previousAvatar = this_chid !== undefined ? characters[this_chid]?.avatar : null; | |
| 1790 | 1801 | characters.splice(0, characters.length); |
| 1791 | 1802 | const getData = await response.json(); |
| 1792 | 1803 | for (let i = 0; i < getData.length; i++) { |
| @@ -1800,8 +1811,16 @@ export async function getCharacters() { | ||
| 1800 | 1811 | |
| 1801 | 1812 | characters[i]['chat'] = String(characters[i]['chat']); |
| 1802 | 1813 | } |
| 1803 | - if (this_chid !== undefined) { | |
| 1814 | + | |
| 1804 | - $('#avatar_url_pole').val(characters[this_chid].avatar); | |
| 1815 | + if (previousAvatar) { | |
| 1816 | + const newCharacterId = characters.findIndex(x => x.avatar === previousAvatar); | |
| 1817 | + if (newCharacterId >= 0) { | |
| 1818 | + setCharacterId(newCharacterId); | |
| 1819 | + await selectCharacterById(newCharacterId, { switchMenu: false }); | |
| 1820 | + } else { | |
| 1821 | + 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.`); | |
| 1822 | + return location.reload(); | |
| 1823 | + } | |
| 1805 | 1824 | } |
| 1806 | 1825 | |
| 1807 | 1826 | await getGroups(); |
| @@ -2051,8 +2070,9 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, san | ||
| 2051 | 2070 | } |
| 2052 | 2071 | |
| 2053 | 2072 | // Prompt bias replacement should be applied on the raw message |
| 2054 | - if (!power_user.show_user_prompt_bias && ch_name && !isUser && !isSystem) { | |
| 2073 | + const replacedPromptBias = power_user.user_prompt_bias && substituteParams(power_user.user_prompt_bias); | |
| 2055 | - mes = mes.replaceAll(substituteParams(power_user.user_prompt_bias), ''); | |
| 2074 | + if (!power_user.show_user_prompt_bias && ch_name && !isUser && !isSystem && replacedPromptBias && mes.startsWith(replacedPromptBias)) { | |
| 2075 | + mes = mes.slice(replacedPromptBias.length); | |
| 2056 | 2076 | } |
| 2057 | 2077 | |
| 2058 | 2078 | if (!isSystem) { |
| @@ -2114,7 +2134,7 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, san | ||
| 2114 | 2134 | } |
| 2115 | 2135 | |
| 2116 | 2136 | mes = mes.replace( |
| 2117 | 2137 | /<style>[\s\S]*?<\/style>|```[\s\S]*?```|~~~[\s\S]*?~~~|``[\s\S]*?``|`[\s\S]*?`|(".*?")|(\u201C.*?\u201D)|(\u00AB.*?\u00BB)|(\u300C.*?\u300D)|(\u300E.*?\u300F)|(\uFF02.*?\uFF02)/gmgim, |
| 2118 | 2138 | function (match, p1, p2, p3, p4, p5, p6) { |
| 2119 | 2139 | if (p1) { |
| 2120 | 2140 | // English double quotes |
| @@ -2730,6 +2750,7 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re | ||
| 2730 | 2750 | environment.mesExamplesRaw = fields.mesExamples || ''; |
| 2731 | 2751 | environment.charVersion = fields.version || ''; |
| 2732 | 2752 | environment.char_version = fields.version || ''; |
| 2753 | + environment.charDepthPrompt = fields.charDepthPrompt || ''; | |
| 2733 | 2754 | } |
| 2734 | 2755 | |
| 2735 | 2756 | // Must be substituted last so that they're replaced inside {{description}} |
| @@ -3026,6 +3047,20 @@ export async function getExtensionPromptByName(moduleName) { | ||
| 3026 | 3047 | } |
| 3027 | 3048 | |
| 3028 | 3049 | /** |
| 3050 | + * Gets the maximum depth of extension prompts. | |
| 3051 | + * @returns {number} Maximum depth of extension prompts | |
| 3052 | + */ | |
| 3053 | +export function getExtensionPromptMaxDepth() { | |
| 3054 | + return MAX_INJECTION_DEPTH; | |
| 3055 | + /* | |
| 3056 | + const prompts = Object.values(extension_prompts); | |
| 3057 | + const maxDepth = Math.max(...prompts.map(x => x.depth ?? 0)); | |
| 3058 | + // Clamp to 1 <= depth <= MAX_INJECTION_DEPTH | |
| 3059 | + return Math.max(Math.min(maxDepth, MAX_INJECTION_DEPTH), 1); | |
| 3060 | + */ | |
| 3061 | +} | |
| 3062 | + | |
| 3063 | +/** | |
| 3029 | 3064 | * Returns the extension prompt for the given position, depth, and role. |
| 3030 | 3065 | * If multiple prompts are found, they are joined with a separator. |
| 3031 | 3066 | * @param {number} [position] Position of the prompt |
| @@ -3081,13 +3116,38 @@ export function baseChatReplace(value, name1, name2) { | ||
| 3081 | 3116 | |
| 3082 | 3117 | /** |
| 3083 | 3118 | * 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}} | |
| 3119 | + * @param {object} [options] | |
| 3120 | + * @param {number} [options.chid] Optional character index | |
| 3121 | + * | |
| 3122 | + * @typedef {object} CharacterCardFields | |
| 3123 | + * @property {string} system System prompt | |
| 3124 | + * @property {string} mesExamples Message examples | |
| 3125 | + * @property {string} description Description | |
| 3126 | + * @property {string} personality Personality | |
| 3127 | + * @property {string} persona Persona | |
| 3128 | + * @property {string} scenario Scenario | |
| 3129 | + * @property {string} jailbreak Jailbreak instructions | |
| 3130 | + * @property {string} version Character version | |
| 3131 | + * @property {string} charDepthPrompt Character depth note | |
| 3132 | + * @returns {CharacterCardFields} Character card fields | |
| 3085 | 3133 | */ |
| 3086 | 3134 | export function getCharacterCardFields({ chid = null } = {}) { |
| 3087 | - const result = { system: '', mesExamples: '', description: '', personality: '', persona: '', scenario: '', jailbreak: '', version: '' }; | |
| 3135 | + const currentChid = chid ?? this_chid; | |
| 3136 | + | |
| 3137 | + const result = { | |
| 3138 | + system: '', | |
| 3139 | + mesExamples: '', | |
| 3140 | + description: '', | |
| 3141 | + personality: '', | |
| 3142 | + persona: '', | |
| 3143 | + scenario: '', | |
| 3144 | + jailbreak: '', | |
| 3145 | + version: '', | |
| 3146 | + charDepthPrompt: '', | |
| 3147 | + }; | |
| 3088 | 3148 | result.persona = baseChatReplace(power_user.persona_description?.trim(), name1, name2); |
| 3089 | 3149 | |
| 3090 | 3150 | const character = characters[this_chidcurrentChid]; |
| 3091 | 3151 | |
| 3092 | 3152 | if (!character) { |
| 3093 | 3153 | return result; |
| @@ -3101,9 +3161,10 @@ export function getCharacterCardFields() { | ||
| 3101 | 3161 | result.system = power_user.prefer_character_prompt ? baseChatReplace(character.data?.system_prompt?.trim(), name1, name2) : ''; |
| 3102 | 3162 | result.jailbreak = power_user.prefer_character_jailbreak ? baseChatReplace(character.data?.post_history_instructions?.trim(), name1, name2) : ''; |
| 3103 | 3163 | result.version = character.data?.character_version ?? ''; |
| 3164 | + result.charDepthPrompt = baseChatReplace(character.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2); | |
| 3104 | 3165 | |
| 3105 | 3166 | if (selected_group) { |
| 3106 | 3167 | const groupCards = getGroupCharacterCards(selected_group, Number(this_chidcurrentChid)); |
| 3107 | 3168 | |
| 3108 | 3169 | if (groupCards) { |
| 3109 | 3170 | result.description = groupCards.description; |
| @@ -3269,13 +3330,25 @@ class StreamingProcessor { | ||
| 3269 | 3330 | |
| 3270 | 3331 | if (!isImpersonate && !isContinue && Array.isArray(this.swipes) && this.swipes.length > 0) { |
| 3271 | 3332 | for (let i = 0; i < this.swipes.length; i++) { |
| 3272 | 3333 | this.swipes[i] = cleanUpMessage(this.swipes[i], false, false, true, this.stoppingStrings);{ |
| 3334 | + getMessage: this.swipes[i], | |
| 3335 | + isImpersonate: false, | |
| 3336 | + isContinue: false, | |
| 3337 | + displayIncompleteSentences: true, | |
| 3338 | + stoppingStrings: this.stoppingStrings, | |
| 3339 | + }); | |
| 3273 | 3340 | } |
| 3274 | 3341 | } |
| 3275 | 3342 | |
| 3276 | - let processedText = cleanUpMessage(text, isImpersonate, isContinue, !isFinal, this.stoppingStrings); | |
| 3343 | + let processedText = cleanUpMessage({ | |
| 3344 | + getMessage: text, | |
| 3345 | + isImpersonate: isImpersonate, | |
| 3346 | + isContinue: isContinue, | |
| 3347 | + displayIncompleteSentences: !isFinal, | |
| 3348 | + stoppingStrings: this.stoppingStrings, | |
| 3349 | + }); | |
| 3277 | 3350 | |
| 3278 | 3351 | const charsToBalance = ['*', '"', '```', '~~~']; |
| 3279 | 3352 | for (const char of charsToBalance) { |
| 3280 | 3353 | if (!isFinal && isOdd(countOccurrences(processedText, char))) { |
| 3281 | 3354 | const separator = char.length > 1 ? '\n' : ''; |
| @@ -3505,9 +3578,10 @@ class StreamingProcessor { | ||
| 3505 | 3578 | * @param {boolean} quietToLoud true to generate a message in system mode, false to generate a message in character mode |
| 3506 | 3579 | * @param {string} [systemPrompt] System prompt to use. Only Instruct mode or OpenAI. |
| 3507 | 3580 | * @param {number} [responseLength] Maximum response length. If unset, the global default value is used. |
| 3581 | + * @param {boolean} [trimNames] Whether to allow trimming "{{user}}:" and "{{char}}:" from the response. | |
| 3508 | 3582 | * @returns {Promise<string>} Generated message |
| 3509 | 3583 | */ |
| 3510 | 3584 | export async function generateRaw(prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, trimNames = true) { |
| 3511 | 3585 | if (!api) { |
| 3512 | 3586 | api = main_api; |
| 3513 | 3587 | } |
| @@ -3596,7 +3670,16 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | ||
| 3596 | 3670 | throw new Error(data.response); |
| 3597 | 3671 | } |
| 3598 | 3672 | |
| 3599 | - const message = cleanUpMessage(extractMessageFromData(data), false, false, true); | |
| 3673 | + // format result, exclude user prompt bias | |
| 3674 | + const message = cleanUpMessage({ | |
| 3675 | + getMessage: extractMessageFromData(data), | |
| 3676 | + isImpersonate: false, | |
| 3677 | + isContinue: false, | |
| 3678 | + displayIncompleteSentences: true, | |
| 3679 | + includeUserPromptBias: false, | |
| 3680 | + trimNames: trimNames, | |
| 3681 | + trimWrongNames: trimNames, | |
| 3682 | + }); | |
| 3600 | 3683 | |
| 3601 | 3684 | if (!message) { |
| 3602 | 3685 | throw new Error('No message generated'); |
| @@ -3905,6 +3988,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3905 | 3988 | mesExamples, |
| 3906 | 3989 | system, |
| 3907 | 3990 | jailbreak, |
| 3991 | + charDepthPrompt, | |
| 3908 | 3992 | } = getCharacterCardFields(); |
| 3909 | 3993 | |
| 3910 | 3994 | if (main_api !== 'openai') { |
| @@ -3927,7 +4011,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3927 | 4011 | setExtensionPrompt('DEPTH_PROMPT_' + index, value.text, extension_prompt_types.IN_CHAT, value.depth, extension_settings.note.allowWIScan, role); |
| 3928 | 4012 | }); |
| 3929 | 4013 | } else { |
| 3930 | - const depthPromptText = baseChatReplace(characters[this_chid]?.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || ''; | |
| 4014 | + const depthPromptText = charDepthPrompt || ''; | |
| 3931 | 4015 | const depthPromptDepth = characters[this_chid]?.data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default; |
| 3932 | 4016 | const depthPromptRole = getExtensionPromptRoleByName(characters[this_chid]?.data?.extensions?.depth_prompt?.role ?? depth_prompt_role_default); |
| 3933 | 4017 | setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole); |
| @@ -4796,7 +4880,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4796 | 4880 | |
| 4797 | 4881 | hideSwipeButtons(); |
| 4798 | 4882 | let getMessage = await streamingProcessor.generate(); |
| 4799 | 4883 | let messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false);{ |
| 4884 | + getMessage: getMessage, | |
| 4885 | + isImpersonate: isImpersonate, | |
| 4886 | + isContinue: isContinue, | |
| 4887 | + displayIncompleteSentences: false, | |
| 4888 | + }); | |
| 4800 | 4889 | |
| 4801 | 4890 | if (isContinue) { |
| 4802 | 4891 | getMessage = continue_mag + getMessage; |
| @@ -4880,7 +4969,14 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4880 | 4969 | |
| 4881 | 4970 | const swipes = extractMultiSwipes(data, type); |
| 4882 | 4971 | |
| 4883 | 4972 | messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false);{ |
| 4973 | + getMessage: getMessage, | |
| 4974 | + isImpersonate: isImpersonate, | |
| 4975 | + isContinue: isContinue, | |
| 4976 | + displayIncompleteSentences: false, | |
| 4977 | + }); | |
| 4978 | + | |
| 4979 | + | |
| 4884 | 4980 | reasoning = getRegexedString(reasoning, regex_placement.REASONING); |
| 4885 | 4981 | |
| 4886 | 4982 | if (power_user.trim_spaces) { |
| @@ -4894,7 +4990,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4894 | 4990 | |
| 4895 | 4991 | //Formating |
| 4896 | 4992 | const displayIncomplete = type === 'quiet' && !quietToLoud; |
| 4897 | 4993 | getMessage = cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncomplete);{ |
| 4994 | + getMessage: getMessage, | |
| 4995 | + isImpersonate: isImpersonate, | |
| 4996 | + isContinue: isContinue, | |
| 4997 | + displayIncompleteSentences: displayIncomplete, | |
| 4998 | + }); | |
| 4898 | 4999 | |
| 4899 | 5000 | if (isImpersonate) { |
| 4900 | 5001 | $('#send_textarea').val(getMessage)[0].dispatchEvent(new Event('input', { bubbles: true })); |
| @@ -5012,7 +5113,8 @@ async function doChatInject(messages, isContinue) { | ||
| 5012 | 5113 | let totalInsertedMessages = 0; |
| 5013 | 5114 | messages.reverse(); |
| 5014 | 5115 | |
| 5015 | - for (let i = 0; i <= MAX_INJECTION_DEPTH; i++) { | |
| 5116 | + const maxDepth = getExtensionPromptMaxDepth(); | |
| 5117 | + for (let i = 0; i <= maxDepth; i++) { | |
| 5016 | 5118 | // Order of priority (most important go lower) |
| 5017 | 5119 | const roles = [extension_prompt_roles.SYSTEM, extension_prompt_roles.USER, extension_prompt_roles.ASSISTANT]; |
| 5018 | 5120 | const names = { |
| @@ -5215,6 +5317,12 @@ function formatMessageHistoryItem(chatItem, isInstruct, forceOutputSequence) { | ||
| 5215 | 5317 | const itemName = chatItem.is_user ? chatItem['name'] : characterName; |
| 5216 | 5318 | const shouldPrependName = !isNarratorType; |
| 5217 | 5319 | |
| 5320 | + // If this symbol flag is set, completely ignore the message. | |
| 5321 | + // This can be used to hide messages without affecting the number of messages in the chat. | |
| 5322 | + if (chatItem.extra?.[IGNORE_SYMBOL]) { | |
| 5323 | + return ''; | |
| 5324 | + } | |
| 5325 | + | |
| 5218 | 5326 | // Don't include a name if it's empty |
| 5219 | 5327 | let textResult = chatItem?.name && shouldPrependName ? `${itemName}: ${chatItem.mes}\n` : `${chatItem.mes}\n`; |
| 5220 | 5328 | |
| @@ -5860,7 +5968,13 @@ function extractMultiSwipes(data, type) { | ||
| 5860 | 5968 | |
| 5861 | 5969 | for (let i = 1; i < data.choices.length; i++) { |
| 5862 | 5970 | const text = data?.choices[i]?.message?.content ?? data?.choices[i]?.text ?? ''; |
| 5863 | 5971 | const cleanedText = cleanUpMessage(text, false, false, false);{ |
| 5972 | + getMessage: text, | |
| 5973 | + isImpersonate: false, | |
| 5974 | + isContinue: false, | |
| 5975 | + displayIncompleteSentences: false, | |
| 5976 | + }); | |
| 5977 | + | |
| 5864 | 5978 | swipes.push(cleanedText); |
| 5865 | 5979 | } |
| 5866 | 5980 | } |
| @@ -5868,13 +5982,33 @@ function extractMultiSwipes(data, type) { | ||
| 5868 | 5982 | return swipes; |
| 5869 | 5983 | } |
| 5870 | 5984 | |
| 5871 | -export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null) { | |
| 5985 | +/** | |
| 5986 | + * Formats a message according to user settings | |
| 5987 | + * @param {object} [options] - Additional options. | |
| 5988 | + * @param {string} [options.getMessage] The message to clean up | |
| 5989 | + * @param {boolean} [options.isImpersonate] Whether this is an impersonated message | |
| 5990 | + * @param {boolean} [options.isContinue] Whether this is a continued message | |
| 5991 | + * @param {boolean} [options.displayIncompleteSentences] Whether to keep incomplete sentences at the end. | |
| 5992 | + * @param {array} [options.stoppingStrings] Array of stopping strings. | |
| 5993 | + * @param {boolean} [options.includeUserPromptBias] Whether to permit prepending the user prompt bias at the beginning. | |
| 5994 | + * @param {boolean} [options.trimNames] Whether to allow trimming "{{char}}:" or "{{user}}:" from the beginning. | |
| 5995 | + * @param {boolean} [options.trimWrongNames] Whether to allow deleting responses prefixed by the incorrect name, depending on isImpersonate | |
| 5996 | + * | |
| 5997 | + * @returns {string} The formatted message | |
| 5998 | + */ | |
| 5999 | +export function cleanUpMessage({ getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null, includeUserPromptBias = true, trimNames = true, trimWrongNames = true } = {}) { | |
| 6000 | + if (arguments.length > 0 && typeof arguments[0] !== 'object') { | |
| 6001 | + console.trace('cleanUpMessage called with positional arguments. Please use an object instead.'); | |
| 6002 | + [getMessage, isImpersonate, isContinue, displayIncompleteSentences, stoppingStrings, includeUserPromptBias, trimNames, trimWrongNames] = arguments; | |
| 6003 | + } | |
| 6004 | + | |
| 5872 | 6005 | if (!getMessage) { |
| 5873 | 6006 | return ''; |
| 5874 | 6007 | } |
| 5875 | 6008 | |
| 5876 | 6009 | // Add the prompt bias before anything else |
| 5877 | 6010 | if ( |
| 6011 | + includeUserPromptBias && | |
| 5878 | 6012 | power_user.user_prompt_bias && |
| 5879 | 6013 | !isImpersonate && |
| 5880 | 6014 | !isContinue && |
| @@ -5912,21 +6046,32 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc | ||
| 5912 | 6046 | // "trailing whitespace on newlines\nevery line of the string\nsample text" |
| 5913 | 6047 | getMessage = getMessage.replace(/[^\S\r\n]+$/gm, ''); |
| 5914 | 6048 | |
| 5915 | - let nameToTrim = isImpersonate ? name2 : name1; | |
| 6049 | + if (trimWrongNames) { | |
| 6050 | + // If this is an impersonation, delete the entire response if it starts with "{{char}}:" | |
| 6051 | + // If this isn't an impersonation, delete the entire response if it starts with "{{user}}:" | |
| 6052 | + // Also delete any trailing text that starts with the wrong name. | |
| 6053 | + // This only occurs if the corresponding "power_user.allow_nameX_display" is false. | |
| 5916 | 6054 | |
| 5917 | - if (isImpersonate) { | |
| 6055 | + let wrongName = isImpersonate | |
| 5918 | - nameToTrim = power_user.allow_name2_display ? '' : name2; | |
| 6056 | + ? (!power_user.allow_name2_display ? name2 : '') // char | |
| 5919 | - } | |
| 6057 | + : (!power_user.allow_name1_display ? name1 : ''); // user | |
| 5920 | - else { | |
| 6058 | + | |
| 5921 | - nameToTrim = power_user.allow_name1_display ? '' : name1; | |
| 6059 | + if (wrongName) { | |
| 6060 | + // If the message starts with the wrong name, delete the entire response | |
| 6061 | + let startIndex = getMessage.indexOf(`${wrongName}:`); | |
| 6062 | + if (startIndex === 0) { | |
| 6063 | + getMessage = ''; | |
| 6064 | + console.debug(`Message started with the wrong name: "${wrongName}" - response was deleted.`); | |
| 5922 | 6065 | } |
| 5923 | 6066 | |
| 5924 | - if (nameToTrim && getMessage.indexOf(`${nameToTrim}:`) == 0) { | |
| 6067 | + // If there is trailing text starting with the wrong name, trim it off. | |
| 5925 | 6068 | getMessage startIndex = getMessage.substring(0, getMessage.indexOf(`\n${nameToTrimwrongName}:`)); |
| 6069 | + if (startIndex >= 0) { | |
| 6070 | + getMessage = getMessage.substring(0, startIndex); | |
| 5926 | 6071 | } |
| 5927 | - if (nameToTrim && getMessage.indexOf(`\n${nameToTrim}:`) >= 0) { | |
| 5928 | - getMessage = getMessage.substring(0, getMessage.indexOf(`\n${nameToTrim}:`)); | |
| 5929 | 6072 | } |
| 6073 | + } | |
| 6074 | + | |
| 5930 | 6075 | if (getMessage.indexOf('<|endoftext|>') != -1) { |
| 5931 | 6076 | getMessage = getMessage.substring(0, getMessage.indexOf('<|endoftext|>')); |
| 5932 | 6077 | } |
| @@ -5986,14 +6131,19 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc | ||
| 5986 | 6131 | getMessage = fixMarkdown(getMessage, false); |
| 5987 | 6132 | } |
| 5988 | 6133 | |
| 6134 | + if (trimNames) { | |
| 6135 | + // If this is an impersonation, trim "{{user}}:" from the beginning | |
| 6136 | + // If this isn't an impersonation, trim "{{char}}:" from the beginning. | |
| 6137 | + // Only applied when the corresponding "power_user.allow_nameX_display" is false. | |
| 5989 | 6138 | const nameToTrim2 = isImpersonate |
| 5990 | 6139 | ? (!power_user.allow_name1_display ? name1 : '') // user |
| 5991 | 6140 | : (!power_user.allow_name2_display ? name2 : ''); // char |
| 5992 | 6141 | |
| 5993 | 6142 | if (nameToTrim2 && getMessage.startsWith(nameToTrim2 + ':')) { |
| 5994 | 6143 | getMessage = getMessage.replace(nameToTrim2 + ':', ''); |
| 5995 | 6144 | getMessage = getMessage.trimStart(); |
| 5996 | 6145 | } |
| 6146 | + } | |
| 5997 | 6147 | |
| 5998 | 6148 | if (isImpersonate) { |
| 5999 | 6149 | getMessage = getMessage.trim(); |
| @@ -6588,6 +6738,8 @@ export async function renameCharacter(name = null, { silent = false, renameChats | ||
| 6588 | 6738 | |
| 6589 | 6739 | await eventSource.emit(event_types.CHARACTER_RENAMED, oldAvatar, newAvatar); |
| 6590 | 6740 | |
| 6741 | + // Unload current character | |
| 6742 | + setCharacterId(undefined); | |
| 6591 | 6743 | // Reload characters list |
| 6592 | 6744 | await getCharacters(); |
| 6593 | 6745 | |
| @@ -6596,7 +6748,6 @@ export async function renameCharacter(name = null, { silent = false, renameChats | ||
| 6596 | 6748 | |
| 6597 | 6749 | if (newChId !== -1) { |
| 6598 | 6750 | // Select the character after the renaming |
| 6599 | - setCharacterId(undefined); | |
| 6600 | 6751 | await selectCharacterById(newChId); |
| 6601 | 6752 | |
| 6602 | 6753 | // Async delay to update UI |
| @@ -6729,7 +6880,22 @@ export function saveChatDebounced() { | ||
| 6729 | 6880 | }, DEFAULT_SAVE_EDIT_TIMEOUT); |
| 6730 | 6881 | } |
| 6731 | 6882 | |
| 6732 | -export async function saveChat(chatName, withMetadata, mesId) { | |
| 6883 | +/** | |
| 6884 | + * Saves the chat to the server. | |
| 6885 | + * @param {object} [options] - Additional options. | |
| 6886 | + * @param {string} [options.chatName] The name of the chat file to save to | |
| 6887 | + * @param {object} [options.withMetadata] Additional metadata to save with the chat | |
| 6888 | + * @param {number} [options.mesId] The message ID to save the chat up to | |
| 6889 | + * @param {boolean} [options.force] Force the saving despire the integrity check result | |
| 6890 | + * | |
| 6891 | + * @returns {Promise<void>} | |
| 6892 | + */ | |
| 6893 | +export async function saveChat({ chatName, withMetadata, mesId, force = false } = {}) { | |
| 6894 | + if (arguments.length > 0 && typeof arguments[0] !== 'object') { | |
| 6895 | + console.trace('saveChat called with positional arguments. Please use an object instead.'); | |
| 6896 | + [chatName, withMetadata, mesId, force] = arguments; | |
| 6897 | + } | |
| 6898 | + | |
| 6733 | 6899 | const metadata = { ...chat_metadata, ...(withMetadata || {}) }; |
| 6734 | 6900 | const fileName = chatName ?? characters[this_chid]?.chat; |
| 6735 | 6901 | |
| @@ -6749,53 +6915,59 @@ export async function saveChat(chatName, withMetadata, mesId) { | ||
| 6749 | 6915 | toastr.error(t`Trying to save group chat with regular saveChat function. Aborting to prevent corruption.`); |
| 6750 | 6916 | throw new Error('Group chat saved from saveChat'); |
| 6751 | 6917 | } |
| 6752 | - /* | |
| 6753 | - if (item.is_user) { | |
| 6754 | - //var str = item.mes.replace(`${name1}:`, `${name1}:`); | |
| 6755 | - //chat[i].mes = str; | |
| 6756 | - //chat[i].name = name1; | |
| 6757 | - } else if (i !== chat.length - 1 && chat[i].swipe_id !== undefined) { | |
| 6758 | - // delete chat[i].swipes; | |
| 6759 | - // delete chat[i].swipe_id; | |
| 6760 | - } | |
| 6761 | - */ | |
| 6762 | 6918 | }); |
| 6763 | 6919 | |
| 6764 | 6920 | const trimmed_chattrimmedChat = (mesId !== undefined && mesId >= 0 && mesId < chat.length) |
| 6765 | 6921 | ? chat.slice(0, parseIntNumber(mesId) + 1) |
| 6766 | 6922 | : chat.slice(); |
| 6767 | 6923 | |
| 6768 | 6924 | varconst save_chatchatToSave = [ |
| 6769 | 6925 | { |
| 6770 | 6926 | user_name: name1, |
| 6771 | 6927 | character_name: name2, |
| 6772 | 6928 | create_date: chat_create_date, |
| 6773 | 6929 | chat_metadata: metadata, |
| 6774 | 6930 | }, |
| 6775 | 6931 | ...trimmed_chattrimmedChat, |
| 6776 | 6932 | ]; |
| 6777 | - return jQuery.ajax({ | |
| 6933 | + | |
| 6778 | - type: 'POST', | |
| 6934 | + try { | |
| 6779 | 6935 | url:const result = await fetch('/api/chats/save', { |
| 6780 | - data: JSON.stringify({ | |
| 6936 | + method: 'POST', | |
| 6937 | + cache: 'no-cache', | |
| 6938 | + headers: getRequestHeaders(), | |
| 6939 | + body: JSON.stringify({ | |
| 6781 | 6940 | ch_name: characters[this_chid].name, |
| 6782 | 6941 | file_name: fileName, |
| 6783 | 6942 | chat: save_chatchatToSave, |
| 6784 | 6943 | avatar_url: characters[this_chid].avatar, |
| 6944 | + force: force, | |
| 6785 | 6945 | }), |
| 6786 | - beforeSend: function () { | |
| 6946 | + }); | |
| 6787 | 6947 | |
| 6788 | - }, | |
| 6948 | + if (result.ok) { | |
| 6789 | - cache: false, | |
| 6949 | + return; | |
| 6790 | - dataType: 'json', | |
| 6950 | + } | |
| 6791 | - contentType: 'application/json', | |
| 6951 | + | |
| 6792 | - success: function (data) { }, | |
| 6952 | + const errorData = await result.json(); | |
| 6793 | - error: function (jqXHR, exception) { | |
| 6953 | + const isIntegrityError = errorData?.error === 'integrity' && !force; | |
| 6954 | + if (!isIntegrityError) { | |
| 6955 | + throw new Error(result.statusText); | |
| 6956 | + } | |
| 6957 | + | |
| 6958 | + const forceSaveConfirmed = await Popup.show.confirm( | |
| 6959 | + t`ERROR: Chat integrity check failed.`, | |
| 6960 | + 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.`, | |
| 6961 | + { okButton: t`Yes, overwrite`, cancelButton: t`No, cancel` }, | |
| 6962 | + ) === POPUP_RESULT.AFFIRMATIVE; | |
| 6963 | + | |
| 6964 | + if (forceSaveConfirmed) { | |
| 6965 | + await saveChat({ chatName, withMetadata, mesId, force: true }); | |
| 6966 | + } | |
| 6967 | + } catch (error) { | |
| 6968 | + console.error(error); | |
| 6794 | 6969 | toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Chat could not be saved`); |
| 6795 | - console.log(exception); | |
| 6970 | + } | |
| 6796 | - console.log(jqXHR); | |
| 6797 | - }, | |
| 6798 | - }); | |
| 6799 | 6971 | } |
| 6800 | 6972 | |
| 6801 | 6973 | async function read_avatar_load(input) { |
| @@ -6972,6 +7144,9 @@ export async function getChat() { | ||
| 6972 | 7144 | } else { |
| 6973 | 7145 | chat_create_date = humanizedDateTime(); |
| 6974 | 7146 | } |
| 7147 | + if (!chat_metadata['integrity']) { | |
| 7148 | + chat_metadata['integrity'] = uuidv4(); | |
| 7149 | + } | |
| 6975 | 7150 | await getChatResult(); |
| 6976 | 7151 | eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } }); |
| 6977 | 7152 | |
| @@ -7943,14 +8118,19 @@ export function select_rm_info(type, charId, previousCharId = null) { | ||
| 7943 | 8118 | } |
| 7944 | 8119 | } |
| 7945 | 8120 | |
| 7946 | -export function select_selected_character(chid) { | |
| 8121 | +/** | |
| 8122 | + * Selects the right menu for displaying the character editor. | |
| 8123 | + * @param {number|string} chid Character array index | |
| 8124 | + * @param {object} [param1] Options for the switch | |
| 8125 | + * @param {boolean} [param1.switchMenu=true] Whether to switch the menu | |
| 8126 | + */ | |
| 8127 | +export function select_selected_character(chid, { switchMenu = true } = {}) { | |
| 7947 | 8128 | //character select |
| 7948 | 8129 | //console.log('select_selected_character() -- starting with input of -- ' + chid + ' (name:' + characters[chid].name + ')'); |
| 7949 | 8130 | select_rm_create({ switchMenu }); |
| 7950 | 8131 | switchMenu && setMenuType('character_edit'); |
| 7951 | 8132 | $('#delete_button').css('display', 'flex'); |
| 7952 | 8133 | $('#export_button').css('display', 'flex'); |
| 7953 | - var display_name = characters[chid].name; | |
| 7954 | 8134 | |
| 7955 | 8135 | //create text poles |
| 7956 | 8136 | $('#rm_button_back').css('display', 'none'); |
| @@ -7965,7 +8145,7 @@ export function select_selected_character(chid) { | ||
| 7965 | 8145 | |
| 7966 | 8146 | // Don't update the navbar name if we're peeking the group member defs |
| 7967 | 8147 | if (!selected_group) { |
| 7968 | 8148 | $('#rm_button_selected_ch').children('h2').text(display_namecharacters[chid].name); |
| 7969 | 8149 | } |
| 7970 | 8150 | |
| 7971 | 8151 | $('#add_avatar_button').val(''); |
| @@ -7996,22 +8176,20 @@ export function select_selected_character(chid) { | ||
| 7996 | 8176 | $('#chat_import_avatar_url').val(characters[chid].avatar); |
| 7997 | 8177 | $('#chat_import_character_name').val(characters[chid].name); |
| 7998 | 8178 | $('#character_json_data').val(characters[chid].json_data); |
| 7999 | - let this_avatar = default_avatar; | |
| 8000 | - if (characters[chid].avatar != 'none') { | |
| 8001 | - this_avatar = getThumbnailUrl('avatar', characters[chid].avatar); | |
| 8002 | - } | |
| 8003 | 8179 | |
| 8004 | 8180 | updateFavButtonState(characters[chid].fav || characters[chid].fav == 'true'); |
| 8005 | 8181 | |
| 8006 | - $('#avatar_load_preview').attr('src', this_avatar); | |
| 8182 | + const avatarUrl = characters[chid].avatar != 'none' ? getThumbnailUrl('avatar', characters[chid].avatar) : default_avatar; | |
| 8007 | 8183 | $('#name_divavatar_load_preview').removeClassattr('displayBlocksrc', avatarUrl); |
| 8008 | - $('#name_div').addClass('displayNone'); | |
| 8009 | - $('#renameCharButton').css('display', ''); | |
| 8010 | 8184 | $('.open_alternate_greetings').data('chid', chid); |
| 8011 | 8185 | $('#set_character_world').data('chid', chid); |
| 8012 | 8186 | setWorldInfoButtonClass(chid); |
| 8013 | 8187 | checkEmbeddedWorld(chid); |
| 8014 | 8188 | |
| 8189 | + $('#name_div').removeClass('displayBlock'); | |
| 8190 | + $('#name_div').addClass('displayNone'); | |
| 8191 | + $('#renameCharButton').css('display', ''); | |
| 8192 | + | |
| 8015 | 8193 | $('#form_create').attr('actiontype', 'editcharacter'); |
| 8016 | 8194 | $('.form_create_bottom_buttons_block .chat_lorebook_button').show(); |
| 8017 | 8195 | |
| @@ -8023,8 +8201,13 @@ export function select_selected_character(chid) { | ||
| 8023 | 8201 | saveSettingsDebounced(); |
| 8024 | 8202 | } |
| 8025 | 8203 | |
| 8026 | -function select_rm_create() { | |
| 8204 | +/** | |
| 8027 | - setMenuType('create'); | |
| 8205 | + * Selects the right menu for creating a new character. | |
| 8206 | + * @param {object} [options] Options for the switch | |
| 8207 | + * @param {boolean} [options.switchMenu=true] Whether to switch the menu | |
| 8208 | + */ | |
| 8209 | +function select_rm_create({ switchMenu = true } = {}) { | |
| 8210 | + switchMenu && setMenuType('create'); | |
| 8028 | 8211 | |
| 8029 | 8212 | //console.log('select_rm_Create() -- selected button: '+selected_button); |
| 8030 | 8213 | if (selected_button == 'create') { |
| @@ -8034,7 +8217,7 @@ function select_rm_create() { | ||
| 8034 | 8217 | } |
| 8035 | 8218 | } |
| 8036 | 8219 | |
| 8037 | 8220 | switchMenu && selectRightMenuWithAnimation('rm_ch_create_block'); |
| 8038 | 8221 | |
| 8039 | 8222 | $('#set_chat_scenario').hide(); |
| 8040 | 8223 | $('#delete_button_div').css('display', 'none'); |
| @@ -9256,6 +9439,17 @@ function swipe_right(_event, { source, repeated } = {}) { | ||
| 9256 | 9439 | } |
| 9257 | 9440 | } |
| 9258 | 9441 | |
| 9442 | +/** | |
| 9443 | + * @typedef {object} ConnectAPIMap | |
| 9444 | + * @property {string} selected - API name (e.g. "textgenerationwebui", "openai") | |
| 9445 | + * @property {string?} [button] - CSS selector for the API button | |
| 9446 | + * @property {string?} [type] - API type, mostly used by text completion. (e.g. "openrouter") | |
| 9447 | + * @property {string?} [source] - API source, mostly used by chat completion. (e.g. "openai") | |
| 9448 | + */ | |
| 9449 | + | |
| 9450 | +/** | |
| 9451 | + * @type {Record<string, ConnectAPIMap>} | |
| 9452 | + */ | |
| 9259 | 9453 | export const CONNECT_API_MAP = { |
| 9260 | 9454 | // Default APIs not contined inside text gen / chat gen |
| 9261 | 9455 | 'kobold': { |
| @@ -9700,6 +9894,15 @@ export async function renameChat(oldFileName, newName) { | ||
| 9700 | 9894 | renamed_file: `${newName.trim()}.jsonl`, |
| 9701 | 9895 | }; |
| 9702 | 9896 | |
| 9897 | + if (body.original_file === body.renamed_file) { | |
| 9898 | + console.debug('Chat rename cancelled, old and new names are the same'); | |
| 9899 | + return; | |
| 9900 | + } | |
| 9901 | + if (equalsIgnoreCaseAndAccents(body.original_file, body.renamed_file)) { | |
| 9902 | + toastr.warning(t`Name not accepted, as it is the same as before (ignoring case and accents).`, t`Rename Chat`); | |
| 9903 | + return; | |
| 9904 | + } | |
| 9905 | + | |
| 9703 | 9906 | try { |
| 9704 | 9907 | showLoader(); |
| 9705 | 9908 | const response = await fetch('/api/chats/rename', { |
| @@ -10477,7 +10680,7 @@ jQuery(async function () { | ||
| 10477 | 10680 | e.stopPropagation(); |
| 10478 | 10681 | chat_file_for_del = $(this).attr('file_name'); |
| 10479 | 10682 | console.debug('detected cross click for' + chat_file_for_del); |
| 10480 | 10683 | callPopup('<h3>' + t`Delete the Chat File?` + '</h3>', 'del_chat'); |
| 10481 | 10684 | }); |
| 10482 | 10685 | |
| 10483 | 10686 | $('#advanced_div').click(function () { |
| @@ -11644,8 +11847,8 @@ jQuery(async function () { | ||
| 11644 | 11847 | return; |
| 11645 | 11848 | } |
| 11646 | 11849 | const drawer = $(this).closest('.inline-drawer'); |
| 11647 | 11850 | const icon = drawer.find('>.inline-drawer-header .inline-drawer-icon'); |
| 11648 | 11851 | const drawerContent = drawer.find('>.inline-drawer-content'); |
| 11649 | 11852 | icon.toggleClass('down up'); |
| 11650 | 11853 | icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up'); |
| 11651 | 11854 | drawerContent.stop().slideToggle({ |
| @@ -12031,4 +12234,11 @@ jQuery(async function () { | ||
| 12031 | 12234 | }); |
| 12032 | 12235 | |
| 12033 | 12236 | initCustomSelectedSamplers(); |
| 12237 | + | |
| 12238 | + window.addEventListener('beforeunload', (e) => { | |
| 12239 | + if (isChatSaving) { | |
| 12240 | + e.preventDefault(); | |
| 12241 | + e.returnValue = true; | |
| 12242 | + } | |
| 12243 | + }); | |
| 12034 | 12244 | }); |
| @@ -1,10 +1,10 @@ | ||
| 1 | 1 | 'use strict'; |
| 2 | 2 | |
| 3 | 3 | import { DOMPurify, Popper } from '../lib.js'; |
| 4 | 4 | |
| 5 | 5 | import { event_types, eventSource, is_send_press, main_api, substituteParams } from '../script.js'; |
| 6 | 6 | import { is_group_generating } from './group-chats.js'; |
| 7 | 7 | import { Message, MessageCollection, TokenHandler } from './openai.js'; |
| 8 | 8 | import { power_user } from './power-user.js'; |
| 9 | 9 | import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; |
| 10 | 10 | import { debounce_timeout } from './constants.js'; |
| @@ -1440,36 +1440,8 @@ class PromptManager { | ||
| 1440 | 1440 | footerDiv.querySelector('select').selectedIndex = selectedPromptIndex; |
| 1441 | 1441 | |
| 1442 | 1442 | // Add prompt export dialogue and options |
| 1443 | - | |
| 1444 | - const exportForCharacter = await renderTemplateAsync('promptManagerExportForCharacter'); | |
| 1445 | - const exportPopup = await renderTemplateAsync('promptManagerExportPopup', { isGlobalStrategy: 'global' === this.configuration.promptOrder.strategy, exportForCharacter }); | |
| 1446 | - rangeBlockDiv.insertAdjacentHTML('beforeend', exportPopup); | |
| 1447 | - | |
| 1448 | - // Destroy previous popper instance if it exists | |
| 1449 | - if (this.exportPopper) { | |
| 1450 | - this.exportPopper.destroy(); | |
| 1451 | - } | |
| 1452 | - | |
| 1453 | - this.exportPopper = Popper.createPopper( | |
| 1454 | - document.getElementById('prompt-manager-export'), | |
| 1455 | - document.getElementById('prompt-manager-export-format-popup'), | |
| 1456 | - { placement: 'bottom' }, | |
| 1457 | - ); | |
| 1458 | - | |
| 1459 | - const showExportSelection = () => { | |
| 1460 | - const popup = document.getElementById('prompt-manager-export-format-popup'); | |
| 1461 | - const show = popup.hasAttribute('data-show'); | |
| 1462 | - | |
| 1463 | - if (show) popup.removeAttribute('data-show'); | |
| 1464 | - else popup.setAttribute('data-show', ''); | |
| 1465 | - | |
| 1466 | - this.exportPopper.update(); | |
| 1467 | - }; | |
| 1468 | - | |
| 1469 | 1443 | footerDiv.querySelector('#prompt-manager-import').addEventListener('click', this.handleImport); |
| 1470 | 1444 | footerDiv.querySelector('#prompt-manager-export').addEventListener('click', showExportSelectionthis.handleFullExport); |
| 1471 | - rangeBlockDiv.querySelector('.export-promptmanager-prompts-full').addEventListener('click', this.handleFullExport); | |
| 1472 | - rangeBlockDiv.querySelector('.export-promptmanager-prompts-character')?.addEventListener('click', this.handleCharacterExport); | |
| 1473 | 1445 | } |
| 1474 | 1446 | } |
| 1475 | 1447 | |
| @@ -407,9 +407,9 @@ function RA_autoconnect(PrevApi) { | ||
| 407 | 407 | || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY) |
| 408 | 408 | || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ) |
| 409 | 409 | || (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI) |
| 410 | - || (secret_state[SECRET_KEYS.BLOCKENTROPY] && oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) | |
| 411 | 410 | || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT) |
| 412 | 411 | || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) |
| 412 | + || (secret_state[SECRET_KEYS.XAI] && oai_settings.chat_completion_source == chat_completion_sources.XAI) | |
| 413 | 413 | || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) |
| 414 | 414 | ) { |
| 415 | 415 | $('#api_button_openai').trigger('click'); |
| @@ -17,6 +17,7 @@ import { SlashCommand } from './slash-commands/SlashCommand.js'; | ||
| 17 | 17 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; |
| 18 | 18 | export { MODULE_NAME as NOTE_MODULE_NAME }; |
| 19 | 19 | import { t } from './i18n.js'; |
| 20 | +import { MacrosParser } from './macros.js'; | |
| 20 | 21 | |
| 21 | 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 | 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 | 3 | import { AutoCompleteOption } from './AutoCompleteOption.js'; |
| 4 | 4 | import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; |
| 5 | 5 | import { BlankAutoCompleteOption } from './BlankAutoCompleteOption.js'; |
| 6 | -// eslint-disable-next-line no-unused-vars | |
| 7 | 6 | import { AutoCompleteNameResult } from './AutoCompleteNameResult.js'; |
| 8 | 7 | import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js'; |
| 9 | -import { Popup, getTopmostModalLayer } from '../popup.js'; | |
| 10 | 8 | |
| 11 | 9 | /**@readonly*/ |
| 12 | 10 | /**@enum {Number}*/ |
| @@ -1,4 +1,3 @@ | ||
| 1 | -import { SlashCommandNamedArgumentAutoCompleteOption } from '../slash-commands/SlashCommandNamedArgumentAutoCompleteOption.js'; | |
| 2 | 1 | import { AutoCompleteOption } from './AutoCompleteOption.js'; |
| 3 | 2 | |
| 4 | 3 | |
| @@ -1,4 +1,3 @@ | ||
| 1 | -import { SlashCommand } from '../slash-commands/SlashCommand.js'; | |
| 2 | 1 | import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js'; |
| 3 | 2 | |
| 4 | 3 | |
| @@ -5,6 +5,7 @@ import { saveMetadataDebounced } from './extensions.js'; | ||
| 5 | 5 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 6 | 6 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 7 | 7 | import { flashHighlight, stringFormat } from './utils.js'; |
| 8 | +import { t } from './i18n.js'; | |
| 8 | 9 | |
| 9 | 10 | const BG_METADATA_KEY = 'custom_background'; |
| 10 | 11 | const LIST_METADATA_KEY = 'chat_backgrounds'; |
| @@ -243,7 +244,7 @@ async function getNewBackgroundName(referenceElement) { | ||
| 243 | 244 | const fileExtension = oldBg.split('.').pop(); |
| 244 | 245 | const fileNameBase = isCustom ? oldBg.split('/').pop() : oldBg; |
| 245 | 246 | const oldBgExtensionless = fileNameBase.replace(`.${fileExtension}`, ''); |
| 246 | 247 | const newBgExtensionless = await callPopup('<h3>' + t`Enter new background name:` + '</h3>', 'input', oldBgExtensionless); |
| 247 | 248 | |
| 248 | 249 | if (!newBgExtensionless) { |
| 249 | 250 | console.debug('no new_bg_extensionless'); |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | import { |
| 2 | 2 | characters, |
| 3 | 3 | saveChat, |
| 4 | - system_messages, | |
| 5 | 4 | system_message_types, |
| 6 | 5 | this_chid, |
| 7 | 6 | openCharacterChat, |
| @@ -13,7 +12,7 @@ import { | ||
| 13 | 12 | saveChatConditional, |
| 14 | 13 | saveItemizedPrompts, |
| 15 | 14 | } from '../script.js'; |
| 16 | 15 | import { humanizedDateTime, getMessageTimeStamp } from './RossAscends-mods.js'; |
| 17 | 16 | import { |
| 18 | 17 | getGroupPastChats, |
| 19 | 18 | group_activation_strategy, |
| @@ -156,7 +155,7 @@ export async function createBranch(mesId) { | ||
| 156 | 155 | if (selected_group) { |
| 157 | 156 | await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); |
| 158 | 157 | } else { |
| 159 | 158 | await saveChat({ chatName: name, withMetadata: newMetadata, mesId }); |
| 160 | 159 | } |
| 161 | 160 | // append to branches list if it exists |
| 162 | 161 | // otherwise create it |
| @@ -212,7 +211,7 @@ export async function createNewBookmark(mesId, { forceName = null } = {}) { | ||
| 212 | 211 | if (selected_group) { |
| 213 | 212 | await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId); |
| 214 | 213 | } else { |
| 215 | 214 | await saveChat({ chatName: name, withMetadata: newMetadata, mesId }); |
| 216 | 215 | } |
| 217 | 216 | |
| 218 | 217 | lastMes.extra['bookmark_link'] = name; |
| @@ -358,7 +357,7 @@ export async function convertSoloToGroupChat() { | ||
| 358 | 357 | // Click on the freshly selected group to open it |
| 359 | 358 | await openGroupById(group.id); |
| 360 | 359 | |
| 361 | 360 | toastr.success('t`The chat has been successfully converted!'`); |
| 362 | 361 | } |
| 363 | 362 | |
| 364 | 363 | /** |
| @@ -459,7 +459,7 @@ export async function appendFileContent(message, messageText) { | ||
| 459 | 459 | * @copyright https://github.com/kwaroran/risuAI |
| 460 | 460 | */ |
| 461 | 461 | export function encodeStyleTags(text) { |
| 462 | 462 | const styleRegex = /<style>(.+?)<\/style>/gmsgims; |
| 463 | 463 | return text.replaceAll(styleRegex, (_, match) => { |
| 464 | 464 | return `<custom-style>${escape(match)}</custom-style>`; |
| 465 | 465 | }); |
| @@ -575,8 +575,8 @@ export function isExternalMediaAllowed() { | ||
| 575 | 575 | return !power_user.forbid_external_media; |
| 576 | 576 | } |
| 577 | 577 | |
| 578 | 578 | async function enlargeMessageImageexpandMessageImage(event) { |
| 579 | 579 | const mesBlock = $(thisevent.currentTarget).closest('.mes'); |
| 580 | 580 | const mesId = mesBlock.attr('mesid'); |
| 581 | 581 | const message = chat[mesId]; |
| 582 | 582 | const imgSrc = message?.extra?.image; |
| @@ -620,7 +620,12 @@ async function enlargeMessageImage() { | ||
| 620 | 620 | popup.completeCancelled(); |
| 621 | 621 | }); |
| 622 | 622 | |
| 623 | 623 | await popup.show(); |
| 624 | + return img; | |
| 625 | +} | |
| 626 | + | |
| 627 | +function expandAndZoomMessageImage(event) { | |
| 628 | + expandMessageImage(event).click(); | |
| 624 | 629 | } |
| 625 | 630 | |
| 626 | 631 | async function deleteMessageImage() { |
| @@ -1603,7 +1608,8 @@ jQuery(function () { | ||
| 1603 | 1608 | reloadCurrentChat(); |
| 1604 | 1609 | }); |
| 1605 | 1610 | |
| 1606 | 1611 | $(document).on('click', '.mes_img_enlargemes_img', enlargeMessageImageexpandMessageImage); |
| 1612 | + $(document).on('click', '.mes_img_enlarge', expandAndZoomMessageImage); | |
| 1607 | 1613 | $(document).on('click', '.mes_img_delete', deleteMessageImage); |
| 1608 | 1614 | |
| 1609 | 1615 | $('#file_form_input').on('change', async () => { |
| @@ -14,3 +14,11 @@ export const debounce_timeout = { | ||
| 14 | 14 | /** [5 sec] For delayed tasks, like auto-saving or completing batch operations that need a significant pause. */ |
| 15 | 15 | extended: 5000, |
| 16 | 16 | }; |
| 17 | + | |
| 18 | +/** | |
| 19 | + * Used as an ephemeral key in message extra metadata. | |
| 20 | + * When set, the message will be excluded from generation | |
| 21 | + * prompts without affecting the number of chat messages, | |
| 22 | + * which is needed to preserve world info timed effects. | |
| 23 | + */ | |
| 24 | +export const IGNORE_SYMBOL = Symbol.for('ignore'); | |
| @@ -1,22 +1,26 @@ | ||
| 1 | 1 | import { getPresetManager } from './preset-manager.js'; |
| 2 | 2 | import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js'; |
| 3 | 3 | import { getTextGenServer } from './textgen-settings.js'; |
| 4 | +import { extractReasoningFromData } from './reasoning.js'; | |
| 5 | +import { formatInstructModeChat, formatInstructModePrompt, getInstructStoppingSequences, names_behavior_types } from './instruct-mode.js'; | |
| 6 | +import { getStreamingReply, tryParseStreamingError } from './openai.js'; | |
| 7 | +import EventSourceStream from './sse-stream.js'; | |
| 4 | 8 | |
| 5 | 9 | // #region Type Definitions |
| 6 | 10 | /** |
| 7 | 11 | * @typedef {Object} TextCompletionRequestBase |
| 8 | 12 | * @property {stringboolean?} prompt[stream=false] - TheWhether textto promptstream forthe completionresponse |
| 9 | 13 | * @property {number} max_tokens - Maximum number of tokens to generate |
| 10 | 14 | * @property {string} [model] - Optional model name |
| 11 | 15 | * @property {string} api_type - Type of API to use |
| 12 | 16 | * @property {string} [api_server] - Optional API server URL |
| 13 | 17 | * @property {number} [temperature] - Optional temperature parameter |
| 18 | + * @property {number} [min_p] - Optional min_p parameter | |
| 14 | 19 | */ |
| 15 | 20 | |
| 16 | -/** @typedef {Record<string, any> & TextCompletionRequestBase} TextCompletionRequest */ | |
| 17 | - | |
| 18 | 21 | /** |
| 19 | 22 | * @typedef {Object} TextCompletionPayloadBase |
| 23 | + * @property {boolean?} [stream=false] - Whether to stream the response | |
| 20 | 24 | * @property {string} prompt - The text prompt for completion |
| 21 | 25 | * @property {number} max_tokens - Maximum number of tokens to generate |
| 22 | 26 | * @property {number} max_new_tokens - Alias for max_tokens |
| @@ -36,29 +40,49 @@ import { getTextGenServer } from './textgen-settings.js'; | ||
| 36 | 40 | |
| 37 | 41 | /** |
| 38 | 42 | * @typedef {Object} ChatCompletionPayloadBase |
| 43 | + * @property {boolean?} [stream=false] - Whether to stream the response | |
| 39 | 44 | * @property {ChatCompletionMessage[]} messages - Array of chat messages |
| 40 | 45 | * @property {string} [model] - Optional model name to use for completion |
| 41 | 46 | * @property {string} chat_completion_source - Source provider for chat completion |
| 42 | 47 | * @property {number} max_tokens - Maximum number of tokens to generate |
| 43 | 48 | * @property {number} [temperature] - Optional temperature parameter for response randomness |
| 49 | + * @property {string} [custom_url] - Optional custom URL | |
| 50 | + * @property {string} [reverse_proxy] - Optional reverse proxy URL | |
| 51 | + * @property {string} [proxy_password] - Optional proxy password | |
| 44 | 52 | */ |
| 45 | 53 | |
| 46 | 54 | /** @typedef {Record<string, any> & ChatCompletionPayloadBase} ChatCompletionPayload */ |
| 55 | + | |
| 56 | +/** | |
| 57 | + * @typedef {Object} ExtractedData | |
| 58 | + * @property {string} content - Extracted content. | |
| 59 | + * @property {string} reasoning - Extracted reasoning. | |
| 60 | + */ | |
| 61 | + | |
| 62 | +/** | |
| 63 | + * @typedef {Object} StreamResponse | |
| 64 | + * @property {string} text - Generated text. | |
| 65 | + * @property {string[]} swipes - Generated swipes | |
| 66 | + * @property {Object} state - Generated state | |
| 67 | + * @property {string?} [state.reasoning] - Generated reasoning | |
| 68 | + * @property {string?} [state.image] - Generated image | |
| 69 | + */ | |
| 70 | + | |
| 47 | 71 | // #endregion |
| 48 | 72 | |
| 49 | 73 | /** |
| 50 | 74 | * Creates & sends a text completion request. Streaming is not supported. |
| 51 | 75 | */ |
| 52 | 76 | export class TextCompletionService { |
| 53 | 77 | static TYPE = 'textgenerationwebui'; |
| 54 | 78 | |
| 55 | 79 | /** |
| 56 | - * @param {TextCompletionRequest} custom | |
| 80 | + * @param {Record<string, any> & TextCompletionRequestBase & {prompt: string}} custom | |
| 57 | 81 | * @returns {TextCompletionPayload} |
| 58 | 82 | */ |
| 59 | 83 | static createRequestData({ stream = false, prompt, max_tokens, model, api_type, api_server, temperature, min_p, ...props }) { |
| 60 | 84 | returnconst payload = { |
| 61 | - ...props, | |
| 85 | + stream, | |
| 62 | 86 | prompt, |
| 63 | 87 | max_tokens, |
| 64 | 88 | max_new_tokens: max_tokens, |
| @@ -66,24 +90,36 @@ export class TextCompletionService { | ||
| 66 | 90 | api_type, |
| 67 | 91 | api_server: api_server ?? getTextGenServer(api_type), |
| 68 | 92 | temperature, |
| 69 | - stream: false, | |
| 93 | + min_p, | |
| 94 | + ...props, | |
| 70 | 95 | }; |
| 96 | + | |
| 97 | + // Remove undefined values to avoid API errors | |
| 98 | + Object.keys(payload).forEach(key => { | |
| 99 | + if (payload[key] === undefined) { | |
| 100 | + delete payload[key]; | |
| 101 | + } | |
| 102 | + }); | |
| 103 | + | |
| 104 | + return payload; | |
| 71 | 105 | } |
| 72 | 106 | |
| 73 | 107 | /** |
| 74 | 108 | * Sends a text completion request to the specified server |
| 75 | 109 | * @param {TextCompletionPayload} data Request data |
| 76 | 110 | * @param {boolean?} extractData Extract message from the response. Default true |
| 77 | - * @returns {Promise<string | any>} Extracted data or the raw response | |
| 111 | + * @param {AbortSignal?} signal | |
| 112 | + * @returns {Promise<ExtractedData | (() => AsyncGenerator<StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator | |
| 78 | 113 | * @throws {Error} |
| 79 | 114 | */ |
| 80 | 115 | static async sendRequest(data, extractData = true, signal = null) { |
| 116 | + if (!data.stream) { | |
| 81 | 117 | const response = await fetch(getGenerateUrl(this.TYPE), { |
| 82 | 118 | method: 'POST', |
| 83 | 119 | headers: getRequestHeaders(), |
| 84 | 120 | cache: 'no-cache', |
| 85 | 121 | body: JSON.stringify(data), |
| 86 | 122 | signal: signal ?? new AbortController().signal, |
| 87 | 123 | }); |
| 88 | 124 | |
| 89 | 125 | const json = await response.json(); |
| @@ -91,35 +127,260 @@ export class TextCompletionService { | ||
| 91 | 127 | throw json; |
| 92 | 128 | } |
| 93 | 129 | |
| 94 | - return extractData ? extractMessageFromData(json, this.TYPE) : json; | |
| 130 | + if (!extractData) { | |
| 131 | + return json; | |
| 132 | + } | |
| 133 | + | |
| 134 | + return { | |
| 135 | + content: extractMessageFromData(json, this.TYPE), | |
| 136 | + reasoning: extractReasoningFromData(json, { | |
| 137 | + mainApi: this.TYPE, | |
| 138 | + textGenType: data.api_type, | |
| 139 | + ignoreShowThoughts: true, | |
| 140 | + }), | |
| 141 | + }; | |
| 142 | + } | |
| 143 | + | |
| 144 | + const response = await fetch('/api/backends/text-completions/generate', { | |
| 145 | + method: 'POST', | |
| 146 | + headers: getRequestHeaders(), | |
| 147 | + cache: 'no-cache', | |
| 148 | + body: JSON.stringify(data), | |
| 149 | + signal: signal ?? new AbortController().signal, | |
| 150 | + }); | |
| 151 | + | |
| 152 | + if (!response.ok) { | |
| 153 | + const text = await response.text(); | |
| 154 | + tryParseStreamingError(response, text, { quiet: true }); | |
| 155 | + | |
| 156 | + throw new Error(`Got response status ${response.status}`); | |
| 157 | + } | |
| 158 | + | |
| 159 | + const eventStream = new EventSourceStream(); | |
| 160 | + response.body.pipeThrough(eventStream); | |
| 161 | + const reader = eventStream.readable.getReader(); | |
| 162 | + return async function* streamData() { | |
| 163 | + let text = ''; | |
| 164 | + const swipes = []; | |
| 165 | + const state = { reasoning: '' }; | |
| 166 | + while (true) { | |
| 167 | + const { done, value } = await reader.read(); | |
| 168 | + if (done) return; | |
| 169 | + if (value.data === '[DONE]') return; | |
| 170 | + | |
| 171 | + tryParseStreamingError(response, value.data, { quiet: true }); | |
| 172 | + | |
| 173 | + let data = JSON.parse(value.data); | |
| 174 | + | |
| 175 | + if (data?.choices?.[0]?.index > 0) { | |
| 176 | + const swipeIndex = data.choices[0].index - 1; | |
| 177 | + swipes[swipeIndex] = (swipes[swipeIndex] || '') + data.choices[0].text; | |
| 178 | + } else { | |
| 179 | + const newText = data?.choices?.[0]?.text || data?.content || ''; | |
| 180 | + text += newText; | |
| 181 | + state.reasoning += data?.choices?.[0]?.reasoning ?? ''; | |
| 182 | + } | |
| 183 | + | |
| 184 | + yield { text, swipes, state }; | |
| 185 | + } | |
| 186 | + }; | |
| 95 | 187 | } |
| 96 | 188 | |
| 97 | 189 | /** |
| 98 | - * @param {string} presetName | |
| 190 | + * Process and send a text completion request with optional preset & instruct | |
| 99 | - * @param {TextCompletionRequest} custom | |
| 191 | + * @param {Record<string, any> & TextCompletionRequestBase & {prompt: (ChatCompletionMessage & {ignoreInstruct?: boolean})[] |string}} custom | |
| 100 | 192 | * @param {boolean?Object} extractData Extract message from theoptions response.- DefaultConfiguration trueoptions |
| 101 | - * @returns {Promise<string | any>} Extracted data or the raw response | |
| 193 | + * @param {string?} [options.presetName] - Name of the preset to use for generation settings | |
| 194 | + * @param {string?} [options.instructName] - Name of instruct preset for message formatting | |
| 195 | + * @param {Partial<InstructSettings>?} [options.instructSettings] - Override instruct settings | |
| 196 | + * @param {boolean} extractData - Whether to extract structured data from response | |
| 197 | + * @param {AbortSignal?} [signal] | |
| 198 | + * @returns {Promise<ExtractedData | (() => AsyncGenerator<StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator | |
| 102 | 199 | * @throws {Error} |
| 103 | 200 | */ |
| 104 | - static async sendRequestWithPreset(presetName, custom, extractData = true) { | |
| 201 | + static async processRequest( | |
| 202 | + custom, | |
| 203 | + options = {}, | |
| 204 | + extractData = true, | |
| 205 | + signal = null, | |
| 206 | + ) { | |
| 207 | + const { presetName, instructName } = options; | |
| 208 | + let requestData = { ...custom }; | |
| 209 | + const prompt = custom.prompt; | |
| 210 | + | |
| 211 | + // Apply generation preset if specified | |
| 212 | + if (presetName) { | |
| 105 | 213 | const presetManager = getPresetManager(this.TYPE); |
| 106 | 214 | if (!presetManager) { |
| 107 | - throw new Error('Preset manager not found'); | |
| 215 | + const preset = presetManager.getCompletionPresetByName(presetName); | |
| 216 | + if (preset) { | |
| 217 | + // Convert preset to payload and merge with custom parameters | |
| 218 | + const presetPayload = this.presetToGeneratePayload(preset, {}); | |
| 219 | + requestData = { ...presetPayload, ...requestData }; | |
| 220 | + } else { | |
| 221 | + console.warn(`Preset "${presetName}" not found, continuing with default settings`); | |
| 222 | + } | |
| 223 | + } else { | |
| 224 | + console.warn('Preset manager not found, continuing with default settings'); | |
| 225 | + } | |
| 108 | 226 | } |
| 109 | 227 | |
| 110 | - const preset = presetManager.getCompletionPresetByName(presetName); | |
| 228 | + | |
| 111 | - if (!preset) { | |
| 229 | + /** @type {InstructSettings | undefined} */ | |
| 112 | - throw new Error('Preset not found'); | |
| 230 | + let instructPreset; | |
| 231 | + // Handle instruct formatting if requested | |
| 232 | + if (Array.isArray(prompt) && instructName) { | |
| 233 | + const instructPresetManager = getPresetManager('instruct'); | |
| 234 | + instructPreset = instructPresetManager?.getCompletionPresetByName(instructName); | |
| 235 | + if (instructPreset) { | |
| 236 | + // Clone the preset to avoid modifying the original | |
| 237 | + instructPreset = structuredClone(instructPreset); | |
| 238 | + instructPreset.names_behavior = names_behavior_types.NONE; | |
| 239 | + if (options.instructSettings) { | |
| 240 | + Object.assign(instructPreset, options.instructSettings); | |
| 241 | + } | |
| 242 | + | |
| 243 | + // Format messages using instruct formatting | |
| 244 | + const formattedMessages = []; | |
| 245 | + for (const message of prompt) { | |
| 246 | + let messageContent = message.content; | |
| 247 | + if (!message.ignoreInstruct) { | |
| 248 | + messageContent = formatInstructModeChat( | |
| 249 | + message.role, | |
| 250 | + message.content, | |
| 251 | + message.role === 'user', | |
| 252 | + false, | |
| 253 | + undefined, | |
| 254 | + undefined, | |
| 255 | + undefined, | |
| 256 | + undefined, | |
| 257 | + instructPreset, | |
| 258 | + ); | |
| 259 | + | |
| 260 | + // Add prompt formatting for the last message | |
| 261 | + if (message === prompt[prompt.length - 1]) { | |
| 262 | + messageContent += formatInstructModePrompt( | |
| 263 | + undefined, | |
| 264 | + false, | |
| 265 | + undefined, | |
| 266 | + undefined, | |
| 267 | + undefined, | |
| 268 | + false, | |
| 269 | + false, | |
| 270 | + instructPreset, | |
| 271 | + ); | |
| 272 | + } | |
| 273 | + } | |
| 274 | + formattedMessages.push(messageContent); | |
| 113 | 275 | } |
| 276 | + requestData.prompt = formattedMessages.join(''); | |
| 277 | + const stoppingStrings = getInstructStoppingSequences({ customInstruct: instructPreset, useStopStrings: false }); | |
| 278 | + requestData.stop = stoppingStrings; | |
| 279 | + requestData.stopping_strings = stoppingStrings; | |
| 280 | + } else { | |
| 281 | + console.warn(`Instruct preset "${instructName}" not found, using basic formatting`); | |
| 282 | + requestData.prompt = prompt.map(x => x.content).join('\n\n'); | |
| 283 | + } | |
| 284 | + } else if (typeof prompt === 'string') { | |
| 285 | + requestData.prompt = prompt; | |
| 286 | + } else { | |
| 287 | + requestData.prompt = prompt.map(x => x.content).join('\n\n'); | |
| 288 | + } | |
| 289 | + | |
| 290 | + // @ts-ignore | |
| 291 | + const data = this.createRequestData(requestData); | |
| 292 | + | |
| 293 | + const response = await this.sendRequest(data, extractData, signal); | |
| 294 | + // Remove stopping strings from the end | |
| 295 | + if (!data.stream && extractData) { | |
| 296 | + /** @type {ExtractedData} */ | |
| 297 | + // @ts-ignore | |
| 298 | + const extractedData = response; | |
| 114 | 299 | |
| 115 | - const data = this.createRequestData({ ...preset, ...custom }); | |
| 300 | + let message = extractedData.content; | |
| 116 | 301 | |
| 117 | - return await this.sendRequest(data, extractData); | |
| 302 | + message = message.replace(/[^\S\r\n]+$/gm, ''); | |
| 303 | + | |
| 304 | + if (requestData.stopping_strings) { | |
| 305 | + for (const stoppingString of requestData.stopping_strings) { | |
| 306 | + if (stoppingString.length) { | |
| 307 | + for (let j = stoppingString.length; j > 0; j--) { | |
| 308 | + if (message.slice(-j) === stoppingString.slice(0, j)) { | |
| 309 | + message = message.slice(0, -j); | |
| 310 | + break; | |
| 311 | + } | |
| 312 | + } | |
| 313 | + } | |
| 314 | + } | |
| 315 | + } | |
| 316 | + | |
| 317 | + if (instructPreset) { | |
| 318 | + [ | |
| 319 | + instructPreset.stop_sequence, | |
| 320 | + instructPreset.input_sequence, | |
| 321 | + ].forEach(sequence => { | |
| 322 | + if (sequence?.trim()) { | |
| 323 | + const index = message.indexOf(sequence); | |
| 324 | + if (index !== -1) { | |
| 325 | + message = message.substring(0, index); | |
| 326 | + } | |
| 327 | + } | |
| 328 | + }); | |
| 329 | + | |
| 330 | + [ | |
| 331 | + instructPreset.output_sequence, | |
| 332 | + instructPreset.last_output_sequence, | |
| 333 | + ].forEach(sequences => { | |
| 334 | + if (sequences) { | |
| 335 | + sequences.split('\n') | |
| 336 | + .filter(line => line.trim() !== '') | |
| 337 | + .forEach(line => { | |
| 338 | + message = message.replaceAll(line, ''); | |
| 339 | + }); | |
| 340 | + } | |
| 341 | + }); | |
| 342 | + } | |
| 343 | + | |
| 344 | + extractedData.content = message; | |
| 345 | + } | |
| 346 | + | |
| 347 | + return response; | |
| 348 | + } | |
| 349 | + | |
| 350 | + /** | |
| 351 | + * Converts a preset to a valid text completion payload. | |
| 352 | + * Only supports temperature. | |
| 353 | + * @param {Object} preset - The preset configuration | |
| 354 | + * @param {Object} customPreset - Additional parameters to override preset values | |
| 355 | + * @returns {Object} - Formatted payload for text completion API | |
| 356 | + */ | |
| 357 | + static presetToGeneratePayload(preset, customPreset = {}) { | |
| 358 | + if (!preset || typeof preset !== 'object') { | |
| 359 | + throw new Error('Invalid preset: must be an object'); | |
| 360 | + } | |
| 361 | + | |
| 362 | + // Merge preset with custom parameters | |
| 363 | + const settings = { ...preset, ...customPreset }; | |
| 364 | + | |
| 365 | + // Initialize base payload with common parameters | |
| 366 | + let payload = { | |
| 367 | + 'temperature': settings.temp ? Number(settings.temp) : undefined, | |
| 368 | + 'min_p': settings.min_p ? Number(settings.min_p) : undefined, | |
| 369 | + }; | |
| 370 | + | |
| 371 | + // Remove undefined values to avoid API errors | |
| 372 | + Object.keys(payload).forEach(key => { | |
| 373 | + if (payload[key] === undefined) { | |
| 374 | + delete payload[key]; | |
| 375 | + } | |
| 376 | + }); | |
| 377 | + | |
| 378 | + return payload; | |
| 118 | 379 | } |
| 119 | 380 | } |
| 120 | 381 | |
| 121 | 382 | /** |
| 122 | 383 | * Creates & sends a chat completion request. Streaming is not supported. |
| 123 | 384 | */ |
| 124 | 385 | export class ChatCompletionService { |
| 125 | 386 | static TYPE = 'openai'; |
| @@ -128,62 +389,170 @@ export class ChatCompletionService { | ||
| 128 | 389 | * @param {ChatCompletionPayload} custom |
| 129 | 390 | * @returns {ChatCompletionPayload} |
| 130 | 391 | */ |
| 131 | 392 | static createRequestData({ stream = false, messages, model, chat_completion_source, max_tokens, temperature, custom_url, reverse_proxy, proxy_password, ...props }) { |
| 132 | 393 | returnconst payload = { |
| 133 | - ...props, | |
| 394 | + stream, | |
| 134 | 395 | messages, |
| 135 | 396 | model, |
| 136 | 397 | chat_completion_source, |
| 137 | 398 | max_tokens, |
| 138 | 399 | temperature, |
| 139 | - stream: false, | |
| 400 | + custom_url, | |
| 401 | + reverse_proxy, | |
| 402 | + proxy_password, | |
| 403 | + use_makersuite_sysprompt: true, | |
| 404 | + claude_use_sysprompt: true, | |
| 405 | + ...props, | |
| 140 | 406 | }; |
| 407 | + | |
| 408 | + // Remove undefined values to avoid API errors | |
| 409 | + Object.keys(payload).forEach(key => { | |
| 410 | + if (payload[key] === undefined) { | |
| 411 | + delete payload[key]; | |
| 412 | + } | |
| 413 | + }); | |
| 414 | + | |
| 415 | + return payload; | |
| 141 | 416 | } |
| 142 | 417 | |
| 143 | 418 | /** |
| 144 | 419 | * Sends a chat completion request |
| 145 | 420 | * @param {ChatCompletionPayload} data Request data |
| 146 | 421 | * @param {boolean?} extractData Extract message from the response. Default true |
| 147 | - * @returns {Promise<string | any>} Extracted data or the raw response | |
| 422 | + * @param {AbortSignal?} signal Abort signal | |
| 423 | + * @returns {Promise<ExtractedData | (() => AsyncGenerator<StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator | |
| 148 | 424 | * @throws {Error} |
| 149 | 425 | */ |
| 150 | 426 | static async sendRequest(data, extractData = true, signal = null) { |
| 151 | 427 | const response = await fetch('/api/backends/chat-completions/generate', { |
| 152 | 428 | method: 'POST', |
| 153 | 429 | headers: getRequestHeaders(), |
| 154 | 430 | cache: 'no-cache', |
| 155 | 431 | body: JSON.stringify(data), |
| 156 | 432 | signal: signal ?? new AbortController().signal, |
| 157 | 433 | }); |
| 158 | 434 | |
| 435 | + if (!data.stream) { | |
| 159 | 436 | const json = await response.json(); |
| 160 | 437 | if (!response.ok || json.error) { |
| 161 | 438 | throw json; |
| 162 | 439 | } |
| 163 | 440 | |
| 164 | - return extractData ? extractMessageFromData(json, this.TYPE) : json; | |
| 441 | + if (!extractData) { | |
| 442 | + return json; | |
| 443 | + } | |
| 444 | + | |
| 445 | + return { | |
| 446 | + content: extractMessageFromData(json, this.TYPE), | |
| 447 | + reasoning: extractReasoningFromData(json, { | |
| 448 | + mainApi: this.TYPE, | |
| 449 | + textGenType: data.chat_completion_source, | |
| 450 | + ignoreShowThoughts: true, | |
| 451 | + }), | |
| 452 | + }; | |
| 453 | + } | |
| 454 | + | |
| 455 | + if (!response.ok) { | |
| 456 | + const text = await response.text(); | |
| 457 | + tryParseStreamingError(response, text, { quiet: true }); | |
| 458 | + | |
| 459 | + throw new Error(`Got response status ${response.status}`); | |
| 460 | + } | |
| 461 | + | |
| 462 | + const eventStream = new EventSourceStream(); | |
| 463 | + response.body.pipeThrough(eventStream); | |
| 464 | + const reader = eventStream.readable.getReader(); | |
| 465 | + return async function* streamData() { | |
| 466 | + let text = ''; | |
| 467 | + const swipes = []; | |
| 468 | + const state = { reasoning: '', image: '' }; | |
| 469 | + while (true) { | |
| 470 | + const { done, value } = await reader.read(); | |
| 471 | + if (done) return; | |
| 472 | + const rawData = value.data; | |
| 473 | + if (rawData === '[DONE]') return; | |
| 474 | + tryParseStreamingError(response, rawData, { quiet: true }); | |
| 475 | + const parsed = JSON.parse(rawData); | |
| 476 | + | |
| 477 | + const reply = getStreamingReply(parsed, state, { | |
| 478 | + chatCompletionSource: data.chat_completion_source, | |
| 479 | + overrideShowThoughts: true, | |
| 480 | + }); | |
| 481 | + if (Array.isArray(parsed?.choices) && parsed?.choices?.[0]?.index > 0) { | |
| 482 | + const swipeIndex = parsed.choices[0].index - 1; | |
| 483 | + swipes[swipeIndex] = (swipes[swipeIndex] || '') + reply; | |
| 484 | + } else { | |
| 485 | + text += reply; | |
| 486 | + } | |
| 487 | + | |
| 488 | + yield { text, swipes: swipes, state }; | |
| 489 | + } | |
| 490 | + }; | |
| 165 | 491 | } |
| 166 | 492 | |
| 167 | 493 | /** |
| 168 | - * @param {string} presetName | |
| 494 | + * Process and send a chat completion request with optional preset | |
| 169 | 495 | * @param {ChatCompletionPayload} custom |
| 170 | 496 | * @param {booleanObject} extractData Extract message from theoptions response.- DefaultConfiguration trueoptions |
| 171 | - * @returns {Promise<string | any>} Extracted data or the raw response | |
| 497 | + * @param {string?} [options.presetName] - Name of the preset to use for generation settings | |
| 498 | + * @param {boolean} [extractData=true] - Whether to extract structured data from response | |
| 499 | + * @param {AbortSignal?} [signal] - Abort signal | |
| 500 | + * @returns {Promise<ExtractedData | (() => AsyncGenerator<StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator | |
| 172 | 501 | * @throws {Error} |
| 173 | 502 | */ |
| 174 | 503 | static async sendRequestWithPresetprocessRequest(presetNamecustom, customoptions, extractData = true, signal = null) { |
| 504 | + const { presetName } = options; | |
| 505 | + let requestData = { ...custom }; | |
| 506 | + | |
| 507 | + // Apply generation preset if specified | |
| 508 | + if (presetName) { | |
| 175 | 509 | const presetManager = getPresetManager(this.TYPE); |
| 176 | 510 | if (!presetManager) { |
| 177 | - throw new Error('Preset manager not found'); | |
| 511 | + const preset = presetManager.getCompletionPresetByName(presetName); | |
| 512 | + if (preset) { | |
| 513 | + // Convert preset to payload and merge with custom parameters | |
| 514 | + const presetPayload = this.presetToGeneratePayload(preset, {}); | |
| 515 | + requestData = { ...presetPayload, ...requestData }; | |
| 516 | + } else { | |
| 517 | + console.warn(`Preset "${presetName}" not found, continuing with default settings`); | |
| 518 | + } | |
| 519 | + } else { | |
| 520 | + console.warn('Preset manager not found, continuing with default settings'); | |
| 521 | + } | |
| 178 | 522 | } |
| 179 | 523 | |
| 180 | 524 | const presetdata = presetManagerthis.getCompletionPresetByNamecreateRequestData(presetNamerequestData); |
| 181 | - if (!preset) { | |
| 525 | + | |
| 182 | - throw new Error('Preset not found'); | |
| 526 | + return await this.sendRequest(data, extractData, signal); | |
| 183 | 527 | } |
| 184 | 528 | |
| 185 | - const data = this.createRequestData({ ...preset, ...custom }); | |
| 529 | + /** | |
| 530 | + * Converts a preset to a valid chat completion payload | |
| 531 | + * Only supports temperature. | |
| 532 | + * @param {Object} preset - The preset configuration | |
| 533 | + * @param {Object} customParams - Additional parameters to override preset values | |
| 534 | + * @returns {Object} - Formatted payload for chat completion API | |
| 535 | + */ | |
| 536 | + static presetToGeneratePayload(preset, customParams = {}) { | |
| 537 | + if (!preset || typeof preset !== 'object') { | |
| 538 | + throw new Error('Invalid preset: must be an object'); | |
| 539 | + } | |
| 540 | + | |
| 541 | + // Merge preset with custom parameters | |
| 542 | + const settings = { ...preset, ...customParams }; | |
| 543 | + | |
| 544 | + // Initialize base payload with common parameters | |
| 545 | + const payload = { | |
| 546 | + temperature: settings.temperature ? Number(settings.temperature) : undefined, | |
| 547 | + }; | |
| 548 | + | |
| 549 | + // Remove undefined values to avoid API errors | |
| 550 | + Object.keys(payload).forEach(key => { | |
| 551 | + if (payload[key] === undefined) { | |
| 552 | + delete payload[key]; | |
| 553 | + } | |
| 554 | + }); | |
| 186 | 555 | |
| 187 | - return await this.sendRequest(data, extractData); | |
| 556 | + return payload; | |
| 188 | 557 | } |
| 189 | 558 | } |
| @@ -783,25 +783,41 @@ async function showExtensionsDetails() { | ||
| 783 | 783 | .append(htmlExternal) |
| 784 | 784 | .append(getModuleInformation()); |
| 785 | 785 | |
| 786 | - /** @type {import('./popup.js').CustomPopupButton} */ | |
| 786 | + { | |
| 787 | - const updateAllButton = { | |
| 787 | + const updateAction = async (force) => { | |
| 788 | - text: t`Update all`, | |
| 789 | - action: async () => { | |
| 790 | 788 | requiresReload = true; |
| 791 | 789 | await autoUpdateExtensions(trueforce); |
| 792 | 790 | await popup.complete(POPUP_RESULT.AFFIRMATIVE); |
| 793 | - }, | |
| 794 | 791 | }; |
| 795 | 792 | |
| 796 | - /** @type {import('./popup.js').CustomPopupButton} */ | |
| 793 | + const toolbar = document.createElement('div'); | |
| 797 | - const sortOrderButton = { | |
| 794 | + toolbar.classList.add('extensions_toolbar'); | |
| 798 | - text: sortByName ? t`Sort: Display Name` : t`Sort: Loading Order`, | |
| 795 | + | |
| 799 | - action: async () => { | |
| 796 | + const updateAllButton = document.createElement('button'); | |
| 797 | + updateAllButton.classList.add('menu_button', 'menu_button_icon'); | |
| 798 | + updateAllButton.textContent = t`Update all`; | |
| 799 | + updateAllButton.addEventListener('click', () => updateAction(true)); | |
| 800 | + | |
| 801 | + const updateEnabledOnlyButton = document.createElement('button'); | |
| 802 | + updateEnabledOnlyButton.classList.add('menu_button', 'menu_button_icon'); | |
| 803 | + updateEnabledOnlyButton.textContent = t`Update enabled`; | |
| 804 | + updateEnabledOnlyButton.addEventListener('click', () => updateAction(false)); | |
| 805 | + | |
| 806 | + const flexExpander = document.createElement('div'); | |
| 807 | + flexExpander.classList.add('expander'); | |
| 808 | + | |
| 809 | + const sortOrderButton = document.createElement('button'); | |
| 810 | + sortOrderButton.classList.add('menu_button', 'menu_button_icon'); | |
| 811 | + sortOrderButton.textContent = sortByName ? t`Sort: Display Name` : t`Sort: Loading Order`; | |
| 812 | + sortOrderButton.addEventListener('click', async () => { | |
| 800 | 813 | abortController.abort(); |
| 801 | 814 | accountStorage.setItem(sortOrderKey, sortByName ? 'false' : 'true'); |
| 802 | 815 | await showExtensionsDetails(); |
| 803 | 816 | },); |
| 804 | - }; | |
| 817 | + | |
| 818 | + toolbar.append(updateAllButton, updateEnabledOnlyButton, flexExpander, sortOrderButton); | |
| 819 | + html.prepend(toolbar); | |
| 820 | + } | |
| 805 | 821 | |
| 806 | 822 | let waitingForSave = false; |
| 807 | 823 | |
| @@ -809,7 +825,7 @@ async function showExtensionsDetails() { | ||
| 809 | 825 | okButton: t`Close`, |
| 810 | 826 | wide: true, |
| 811 | 827 | large: true, |
| 812 | 828 | customButtons: [sortOrderButton, updateAllButton], |
| 813 | 829 | allowVerticalScrolling: true, |
| 814 | 830 | onClosing: async () => { |
| 815 | 831 | if (waitingForSave) { |
| @@ -1196,7 +1212,7 @@ async function checkForUpdatesManual(sortFn, abortSignal) { | ||
| 1196 | 1212 | } |
| 1197 | 1213 | |
| 1198 | 1214 | /** |
| 1199 | 1215 | * Checks if there are updates available for enabled 3rd-party extensions. |
| 1200 | 1216 | * @param {boolean} force Skip nag check |
| 1201 | 1217 | * @returns {Promise<any>} |
| 1202 | 1218 | */ |
| @@ -1218,6 +1234,11 @@ async function checkForExtensionUpdates(force) { | ||
| 1218 | 1234 | const promises = []; |
| 1219 | 1235 | |
| 1220 | 1236 | for (const [id, manifest] of Object.entries(manifests)) { |
| 1237 | + const isDisabled = extension_settings.disabledExtensions.includes(id); | |
| 1238 | + if (isDisabled) { | |
| 1239 | + console.debug(`Skipping extension: ${manifest.display_name} (${id}) for non-admin user`); | |
| 1240 | + continue; | |
| 1241 | + } | |
| 1221 | 1242 | const isGlobal = getExtensionType(id) === 'global'; |
| 1222 | 1243 | if (isGlobal && !isCurrentUserAdmin) { |
| 1223 | 1244 | console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`); |
| @@ -1247,8 +1268,8 @@ async function checkForExtensionUpdates(force) { | ||
| 1247 | 1268 | } |
| 1248 | 1269 | |
| 1249 | 1270 | /** |
| 1250 | 1271 | * Updates all enabled 3rd-party extensions that have auto-update enabled. |
| 1251 | 1272 | * @param {boolean} forceAll Force update allInclude evendisabled ifand not auto-updating |
| 1252 | 1273 | * @returns {Promise<void>} |
| 1253 | 1274 | */ |
| 1254 | 1275 | async function autoUpdateExtensions(forceAll) { |
| @@ -1260,6 +1281,11 @@ async function autoUpdateExtensions(forceAll) { | ||
| 1260 | 1281 | const isCurrentUserAdmin = isAdmin(); |
| 1261 | 1282 | const promises = []; |
| 1262 | 1283 | for (const [id, manifest] of Object.entries(manifests)) { |
| 1284 | + const isDisabled = extension_settings.disabledExtensions.includes(id); | |
| 1285 | + if (!forceAll && isDisabled) { | |
| 1286 | + console.debug(`Skipping extension: ${manifest.display_name} (${id}) for non-admin user`); | |
| 1287 | + continue; | |
| 1288 | + } | |
| 1263 | 1289 | const isGlobal = getExtensionType(id) === 'global'; |
| 1264 | 1290 | if (isGlobal && !isCurrentUserAdmin) { |
| 1265 | 1291 | console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`); |
| @@ -424,7 +424,7 @@ jQuery(async () => { | ||
| 424 | 424 | installHintButton.on('click', async function () { |
| 425 | 425 | const installButton = $('#third_party_extension_button'); |
| 426 | 426 | flashHighlight(installButton, 5000); |
| 427 | 427 | toastr.info('t`Click the flashing button to install extensions.'`, 't`How to install extensions?'`); |
| 428 | 428 | }); |
| 429 | 429 | |
| 430 | 430 | const connectButton = windowHtml.find('#assets-connect-button'); |
| @@ -39,7 +39,7 @@ To install a single 3rd party extension, use the "Install Extensions" | ||
| 39 | 39 | <span data-i18n="Characters">Characters</span> |
| 40 | 40 | </div> |
| 41 | 41 | </div> |
| 42 | 42 | <div class="inline-drawer-content" id="assets_menu"> |
| 43 | 43 | </div> |
| 44 | 44 | </div> |
| 45 | 45 | </div> |
| @@ -1,4 +1,4 @@ | ||
| 1 | 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 | 2 | <div class="fa-fw fa-solid fa-paperclip extensionsMenuExtensionButton"></div> |
| 3 | 3 | <span data-i18n="Attach a File">Attach a File</span> |
| 4 | 4 | </div> |
| @@ -428,6 +428,7 @@ jQuery(async function () { | ||
| 428 | 428 | 'zerooneai': SECRET_KEYS.ZEROONEAI, |
| 429 | 429 | 'groq': SECRET_KEYS.GROQ, |
| 430 | 430 | 'cohere': SECRET_KEYS.COHERE, |
| 431 | + 'xai': SECRET_KEYS.XAI, | |
| 431 | 432 | }; |
| 432 | 433 | |
| 433 | 434 | if (chatCompletionApis[api] && secret_state[chatCompletionApis[api]]) { |
| @@ -31,6 +31,7 @@ | ||
| 31 | 31 | <option value="openrouter">OpenRouter</option> |
| 32 | 32 | <option value="ooba" data-i18n="Text Generation WebUI (oobabooga)">Text Generation WebUI (oobabooga)</option> |
| 33 | 33 | <option value="vllm">vLLM</option> |
| 34 | + <option value="xai">xAI (Grok)</option> | |
| 34 | 35 | </select> |
| 35 | 36 | </div> |
| 36 | 37 | <div class="flex1 flex-container flexFlowColumn flexNoGap"> |
| @@ -42,7 +43,16 @@ | ||
| 42 | 43 | <option data-type="mistral" value="pixtral-12b-2409">pixtral-12b-2409</option> |
| 43 | 44 | <option data-type="mistral" value="pixtral-large-latest">pixtral-large-latest</option> |
| 44 | 45 | <option data-type="mistral" value="pixtral-large-2411">pixtral-large-2411</option> |
| 46 | + <option data-type="mistral" value="mistral-large-pixtral-2411">mistral-large-pixtral-2411</option> | |
| 47 | + <option data-type="mistral" value="mistral-small-2503">mistral-small-2503</option> | |
| 48 | + <option data-type="mistral" value="mistral-small-latest">mistral-small-latest</option> | |
| 45 | 49 | <option data-type="zerooneai" value="yi-vision">yi-vision</option> |
| 50 | + <option data-type="openai" value="gpt-4.1">gpt-4.1</option> | |
| 51 | + <option data-type="openai" value="gpt-4.1-2025-04-14">gpt-4.1-2025-04-14</option> | |
| 52 | + <option data-type="openai" value="gpt-4.1-mini">gpt-4.1-mini</option> | |
| 53 | + <option data-type="openai" value="gpt-4.1-mini-2025-04-14">gpt-4.1-mini-2025-04-14</option> | |
| 54 | + <option data-type="openai" value="gpt-4.1-nano">gpt-4.1-nano</option> | |
| 55 | + <option data-type="openai" value="gpt-4.1-nano-2025-04-14">gpt-4.1-nano-2025-04-14</option> | |
| 46 | 56 | <option data-type="openai" value="gpt-4-vision-preview">gpt-4-vision-preview</option> |
| 47 | 57 | <option data-type="openai" value="gpt-4-turbo">gpt-4-turbo</option> |
| 48 | 58 | <option data-type="openai" value="gpt-4o">gpt-4o</option> |
| @@ -50,6 +60,10 @@ | ||
| 50 | 60 | <option data-type="openai" value="chatgpt-4o-latest">chatgpt-4o-latest</option> |
| 51 | 61 | <option data-type="openai" value="o1">o1</option> |
| 52 | 62 | <option data-type="openai" value="o1-2024-12-17">o1-2024-12-17</option> |
| 63 | + <option data-type="openai" value="o3">o3</option> | |
| 64 | + <option data-type="openai" value="o3-2025-04-16">o3-2025-04-16</option> | |
| 65 | + <option data-type="openai" value="o4-mini">o4-mini</option> | |
| 66 | + <option data-type="openai" value="o4-mini-2025-04-16">o4-mini-2025-04-16</option> | |
| 53 | 67 | <option data-type="openai" value="gpt-4.5-preview">gpt-4.5-preview</option> |
| 54 | 68 | <option data-type="openai" value="gpt-4.5-preview-2025-02-27">gpt-4.5-preview-2025-02-27</option> |
| 55 | 69 | <option data-type="anthropic" value="claude-3-7-sonnet-latest">claude-3-7-sonnet-latest</option> |
| @@ -62,8 +76,11 @@ | ||
| 62 | 76 | <option data-type="anthropic" value="claude-3-opus-20240229">claude-3-opus-20240229</option> |
| 63 | 77 | <option data-type="anthropic" value="claude-3-sonnet-20240229">claude-3-sonnet-20240229</option> |
| 64 | 78 | <option data-type="anthropic" value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> |
| 79 | + <option data-type="google" value="gemini-2.5-pro-preview-03-25">gemini-2.5-pro-preview-03-25</option> | |
| 80 | + <option data-type="google" value="gemini-2.5-pro-exp-03-25">gemini-2.5-pro-exp-03-25</option> | |
| 65 | 81 | <option data-type="google" value="gemini-2.0-pro-exp">gemini-2.0-pro-exp</option> |
| 66 | 82 | <option data-type="google" value="gemini-2.0-pro-exp-02-05">gemini-2.0-pro-exp-02-05</option> |
| 83 | + <option data-type="google" value="gemini-2.5-flash-preview-04-17">gemini-2.5-flash-preview-04-17</option> | |
| 67 | 84 | <option data-type="google" value="gemini-2.0-flash-lite-preview">gemini-2.0-flash-lite-preview</option> |
| 68 | 85 | <option data-type="google" value="gemini-2.0-flash-lite-preview-02-05">gemini-2.0-flash-lite-preview-02-05</option> |
| 69 | 86 | <option data-type="google" value="gemini-2.0-flash">gemini-2.0-flash</option> |
| @@ -129,6 +146,8 @@ | ||
| 129 | 146 | <option data-type="koboldcpp" value="koboldcpp_current" data-i18n="currently_loaded">[Currently loaded]</option> |
| 130 | 147 | <option data-type="vllm" value="vllm_current" data-i18n="currently_selected">[Currently selected]</option> |
| 131 | 148 | <option data-type="custom" value="custom_current" data-i18n="currently_selected">[Currently selected]</option> |
| 149 | + <option data-type="xai" value="grok-2-vision-1212">grok-2-vision-1212</option> | |
| 150 | + <option data-type="xai" value="grok-vision-beta">grok-vision-beta</option> | |
| 132 | 151 | </select> |
| 133 | 152 | </div> |
| 134 | 153 | <div data-type="ollama"> |
| @@ -1,4 +1,4 @@ | ||
| 1 | 1 | import { DOMPurify, Fuse } from '../../../lib.js'; |
| 2 | 2 | |
| 3 | 3 | import { event_types, eventSource, main_api, saveSettingsDebounced } from '../../../script.js'; |
| 4 | 4 | import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js'; |
| @@ -39,6 +39,7 @@ const CC_COMMANDS = [ | ||
| 39 | 39 | 'proxy', |
| 40 | 40 | 'stop-strings', |
| 41 | 41 | 'start-reply-with', |
| 42 | + 'reasoning-template', | |
| 42 | 43 | ]; |
| 43 | 44 | |
| 44 | 45 | const TC_COMMANDS = [ |
| @@ -54,6 +55,7 @@ const TC_COMMANDS = [ | ||
| 54 | 55 | 'tokenizer', |
| 55 | 56 | 'stop-strings', |
| 56 | 57 | 'start-reply-with', |
| 58 | + 'reasoning-template', | |
| 57 | 59 | ]; |
| 58 | 60 | |
| 59 | 61 | const FANCY_NAMES = { |
| @@ -70,6 +72,7 @@ const FANCY_NAMES = { | ||
| 70 | 72 | 'tokenizer': 'Tokenizer', |
| 71 | 73 | 'stop-strings': 'Custom Stopping Strings', |
| 72 | 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 | 157 | * @property {string} [tokenizer] Tokenizer |
| 155 | 158 | * @property {string} [stop-strings] Custom Stopping Strings |
| 156 | 159 | * @property {string} [start-reply-with] Start Reply With |
| 160 | + * @property {string} [reasoning-template] Reasoning Template | |
| 157 | 161 | * @property {string[]} [exclude] Commands to exclude |
| 158 | 162 | */ |
| 159 | 163 | |
| @@ -267,9 +271,14 @@ async function createConnectionProfile(forceName = null) { | ||
| 267 | 271 | }); |
| 268 | 272 | const isNameTaken = (n) => extension_settings.connectionManager.profiles.some(p => p.name === n); |
| 269 | 273 | const suggestedName = getUniqueName(collapseSpaces(`${profile.api ?? ''} ${profile.model ?? ''} - ${profile.preset ?? ''}`), isNameTaken); |
| 270 | 274 | constlet 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 | 280 | if (!name) { |
| 281 | + toastr.error('Name cannot be empty.'); | |
| 273 | 282 | return null; |
| 274 | 283 | } |
| 275 | 284 | |
| @@ -303,7 +312,8 @@ async function deleteConnectionProfile() { | ||
| 303 | 312 | return; |
| 304 | 313 | } |
| 305 | 314 | |
| 306 | 315 | const nameprofile = extension_settings.connectionManager.profiles[index].name; |
| 316 | + const name = profile.name; | |
| 307 | 317 | const confirm = await Popup.show.confirm(t`Are you sure you want to delete the selected profile?`, name); |
| 308 | 318 | |
| 309 | 319 | if (!confirm) { |
| @@ -313,6 +323,8 @@ async function deleteConnectionProfile() { | ||
| 313 | 323 | extension_settings.connectionManager.profiles.splice(index, 1); |
| 314 | 324 | extension_settings.connectionManager.selectedProfile = null; |
| 315 | 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 | 524 | saveSettingsDebounced(); |
| 513 | 525 | renderConnectionProfiles(profiles); |
| 514 | 526 | await renderDetailsContent(detailsContent); |
| 527 | + await eventSource.emit(event_types.CONNECTION_PROFILE_CREATED, profile); | |
| 515 | 528 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); |
| 516 | 529 | }); |
| 517 | 530 | |
| @@ -523,9 +536,11 @@ async function renderDetailsContent(detailsContent) { | ||
| 523 | 536 | console.log('No profile selected'); |
| 524 | 537 | return; |
| 525 | 538 | } |
| 539 | + const oldProfile = structuredClone(profile); | |
| 526 | 540 | await updateConnectionProfile(profile); |
| 527 | 541 | await renderDetailsContent(detailsContent); |
| 528 | 542 | saveSettingsDebounced(); |
| 543 | + await eventSource.emit(event_types.CONNECTION_PROFILE_UPDATED, oldProfile, profile); | |
| 529 | 544 | await eventSource.emit(event_types.CONNECTION_PROFILE_LOADED, profile.name); |
| 530 | 545 | toastr.success('Connection profile updated', '', { timeOut: 1500 }); |
| 531 | 546 | }); |
| @@ -559,7 +574,7 @@ async function renderDetailsContent(detailsContent) { | ||
| 559 | 574 | return acc; |
| 560 | 575 | }, {}); |
| 561 | 576 | const template = $(await renderExtensionTemplateAsync(MODULE_NAME, 'edit', { name: profile.name, settings })); |
| 562 | 577 | constlet newName = await callGenericPopup(template, POPUP_TYPE.INPUT, profile.name, { |
| 563 | 578 | rows: 2, |
| 564 | 579 | customButtons: [{ |
| 565 | 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 | 594 | if (!newName) { |
| 595 | + toastr.error('Name cannot be empty.'); | |
| 575 | 596 | return; |
| 576 | 597 | } |
| 577 | 598 | |
| @@ -584,6 +605,7 @@ async function renderDetailsContent(detailsContent) { | ||
| 584 | 605 | return Object.entries(FANCY_NAMES).find(x => x[1] === String($(this).val()))?.[0]; |
| 585 | 606 | }).get(); |
| 586 | 607 | |
| 608 | + const oldProfile = structuredClone(profile); | |
| 587 | 609 | if (newExcludeList.length !== profile.exclude.length || !newExcludeList.every(e => profile.exclude.includes(e))) { |
| 588 | 610 | profile.exclude = newExcludeList; |
| 589 | 611 | for (const command of newExcludeList) { |
| @@ -598,10 +620,11 @@ async function renderDetailsContent(detailsContent) { | ||
| 598 | 620 | |
| 599 | 621 | if (profile.name !== newName) { |
| 600 | 622 | toastr.success('Connection profile renamed.'); |
| 601 | 623 | profile.name = String(newName); |
| 602 | 624 | } |
| 603 | 625 | |
| 604 | 626 | saveSettingsDebounced(); |
| 627 | + await eventSource.emit(event_types.CONNECTION_PROFILE_UPDATED, oldProfile, profile); | |
| 605 | 628 | renderConnectionProfiles(profiles); |
| 606 | 629 | await renderDetailsContent(detailsContent); |
| 607 | 630 | }); |
| @@ -704,6 +727,7 @@ async function renderDetailsContent(detailsContent) { | ||
| 704 | 727 | saveSettingsDebounced(); |
| 705 | 728 | renderConnectionProfiles(profiles); |
| 706 | 729 | await renderDetailsContent(detailsContent); |
| 730 | + await eventSource.emit(event_types.CONNECTION_PROFILE_CREATED, profile); | |
| 707 | 731 | return profile.name; |
| 708 | 732 | }, |
| 709 | 733 | })); |
| @@ -718,9 +742,11 @@ async function renderDetailsContent(detailsContent) { | ||
| 718 | 742 | toastr.warning('No profile selected.'); |
| 719 | 743 | return ''; |
| 720 | 744 | } |
| 745 | + const oldProfile = structuredClone(profile); | |
| 721 | 746 | await updateConnectionProfile(profile); |
| 722 | 747 | await renderDetailsContent(detailsContent); |
| 723 | 748 | saveSettingsDebounced(); |
| 749 | + await eventSource.emit(event_types.CONNECTION_PROFILE_UPDATED, oldProfile, profile); | |
| 724 | 750 | return profile.name; |
| 725 | 751 | }, |
| 726 | 752 | })); |
| @@ -4,7 +4,7 @@ import { characters, eventSource, event_types, generateRaw, getRequestHeaders, m | ||
| 4 | 4 | import { dragElement, isMobile } from '../../RossAscends-mods.js'; |
| 5 | 5 | import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 6 | 6 | import { loadMovingUIState, performFuzzySearch, power_user } from '../../power-user.js'; |
| 7 | 7 | import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, waitUntilCondition, findChar, isFalseBoolean } from '../../utils.js'; |
| 8 | 8 | import { hideMutedSprites, selected_group } from '../../group-chats.js'; |
| 9 | 9 | import { isJsonSchemaSupported } from '../../textgen-settings.js'; |
| 10 | 10 | import { debounce_timeout } from '../../constants.js'; |
| @@ -17,6 +17,7 @@ import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandRetur | ||
| 17 | 17 | import { generateWebLlmChatPrompt, isWebLlmSupported } from '../shared.js'; |
| 18 | 18 | import { Popup, POPUP_RESULT } from '../../popup.js'; |
| 19 | 19 | import { t } from '../../i18n.js'; |
| 20 | +import { removeReasoningFromString } from '../../reasoning.js'; | |
| 20 | 21 | export { MODULE_NAME }; |
| 21 | 22 | |
| 22 | 23 | /** |
| @@ -82,6 +83,7 @@ const EXPRESSION_API = { | ||
| 82 | 83 | extras: 1, |
| 83 | 84 | llm: 2, |
| 84 | 85 | webllm: 3, |
| 86 | + none: 99, | |
| 85 | 87 | }; |
| 86 | 88 | |
| 87 | 89 | let expressionsList = null; |
| @@ -273,7 +275,7 @@ async function getLastMessageSprite(avatar) { | ||
| 273 | 275 | return null; |
| 274 | 276 | } |
| 275 | 277 | |
| 276 | 278 | export async function visualNovelUpdateLayers(container) { |
| 277 | 279 | const context = getContext(); |
| 278 | 280 | const group = context.groups.find(x => x.id == context.groupId); |
| 279 | 281 | const recentMessages = context.chat.map(x => x.original_avatar).filter(x => x).reverse().filter(onlyUnique); |
| @@ -678,7 +680,7 @@ async function setSpriteFolderCommand(_, folder) { | ||
| 678 | 680 | return ''; |
| 679 | 681 | } |
| 680 | 682 | |
| 681 | 683 | async function classifyCallback(/** @type {{api: string?, filter: string?, prompt: string?}} */ { api = null, filter = null, prompt = null }, text) { |
| 682 | 684 | if (!text) { |
| 683 | 685 | toastr.error('No text provided'); |
| 684 | 686 | return ''; |
| @@ -689,13 +691,19 @@ async function classifyCallback(/** @type {{api: string?, prompt: string?}} */ { | ||
| 689 | 691 | } |
| 690 | 692 | |
| 691 | 693 | const expressionApi = EXPRESSION_API[api] || extension_settings.expressions.api; |
| 694 | + const filterAvailable = !isFalseBoolean(filter); | |
| 695 | + | |
| 696 | + if (expressionApi === EXPRESSION_API.none) { | |
| 697 | + toastr.warning('No classifier API selected'); | |
| 698 | + return ''; | |
| 699 | + } | |
| 692 | 700 | |
| 693 | 701 | if (!modules.includes('classify') && expressionApi == EXPRESSION_API.extras) { |
| 694 | 702 | toastr.warning('Text classification is disabled or not available'); |
| 695 | 703 | return ''; |
| 696 | 704 | } |
| 697 | 705 | |
| 698 | 706 | const label = await getExpressionLabel(text, expressionApi, { filterAvailable: filterAvailable, customPrompt: prompt }); |
| 699 | 707 | console.debug(`Classification result for "${text}": ${label}`); |
| 700 | 708 | return label; |
| 701 | 709 | } |
| @@ -928,6 +936,9 @@ function parseLlmResponse(emotionResponse, labels) { | ||
| 928 | 936 | |
| 929 | 937 | return response; |
| 930 | 938 | } catch { |
| 939 | + // Clean possible reasoning from response | |
| 940 | + emotionResponse = removeReasoningFromString(emotionResponse); | |
| 941 | + | |
| 931 | 942 | const fuse = new Fuse(labels, { includeScore: true }); |
| 932 | 943 | console.debug('Using fuzzy search in labels:', labels); |
| 933 | 944 | const result = fuse.search(emotionResponse); |
| @@ -988,10 +999,11 @@ function onTextGenSettingsReady(args) { | ||
| 988 | 999 | * @param {string} text - The text to classify and retrieve the expression label for. |
| 989 | 1000 | * @param {EXPRESSION_API} [expressionsApi=extension_settings.expressions.api] - The expressions API to use for classification. |
| 990 | 1001 | * @param {object} [options={}] - Optional arguments. |
| 1002 | + * @param {boolean?} [options.filterAvailable=null] - Whether to filter available expressions. If not specified, uses the extension setting. | |
| 991 | 1003 | * @param {string?} [options.customPrompt=null] - The custom prompt to use for classification. |
| 992 | 1004 | * @returns {Promise<string?>} - The label of the expression. |
| 993 | 1005 | */ |
| 994 | 1006 | export async function getExpressionLabel(text, expressionsApi = extension_settings.expressions.api, { filterAvailable = null, customPrompt = null } = {}) { |
| 995 | 1007 | // Return if text is undefined, saving a costly fetch request |
| 996 | 1008 | if ((!modules.includes('classify') && expressionsApi == EXPRESSION_API.extras) || !text) { |
| 997 | 1009 | return extension_settings.expressions.fallback_expression; |
| @@ -1003,6 +1015,11 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | ||
| 1003 | 1015 | |
| 1004 | 1016 | text = sampleClassifyText(text); |
| 1005 | 1017 | |
| 1018 | + filterAvailable ??= extension_settings.expressions.filterAvailable; | |
| 1019 | + if (filterAvailable && ![EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(expressionsApi)) { | |
| 1020 | + console.debug('Filter available is only supported for LLM and WebLLM expressions'); | |
| 1021 | + } | |
| 1022 | + | |
| 1006 | 1023 | try { |
| 1007 | 1024 | switch (expressionsApi) { |
| 1008 | 1025 | // Local BERT pipeline |
| @@ -1027,7 +1044,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | ||
| 1027 | 1044 | return extension_settings.expressions.fallback_expression; |
| 1028 | 1045 | } |
| 1029 | 1046 | |
| 1030 | 1047 | const expressionsList = await getExpressionsList({ filterAvailable: filterAvailable }); |
| 1031 | 1048 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); |
| 1032 | 1049 | eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); |
| 1033 | 1050 | const emotionResponse = await generateRaw(text, main_api, false, false, prompt); |
| @@ -1040,7 +1057,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | ||
| 1040 | 1057 | return extension_settings.expressions.fallback_expression; |
| 1041 | 1058 | } |
| 1042 | 1059 | |
| 1043 | 1060 | const expressionsList = await getExpressionsList({ filterAvailable: filterAvailable }); |
| 1044 | 1061 | const prompt = substituteParamsExtended(customPrompt, { labels: expressionsList }) || await getLlmPrompt(expressionsList); |
| 1045 | 1062 | const messages = [ |
| 1046 | 1063 | { role: 'user', content: text + '\n\n' + prompt }, |
| @@ -1050,7 +1067,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | ||
| 1050 | 1067 | return parseLlmResponse(emotionResponse, expressionsList); |
| 1051 | 1068 | } |
| 1052 | 1069 | // Extras |
| 1053 | 1070 | defaultcase EXPRESSION_API.extras: { |
| 1054 | 1071 | const url = new URL(getApiUrl()); |
| 1055 | 1072 | url.pathname = '/api/classify'; |
| 1056 | 1073 | |
| @@ -1068,6 +1085,15 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin | ||
| 1068 | 1085 | return data.classification[0].label; |
| 1069 | 1086 | } |
| 1070 | 1087 | } break; |
| 1088 | + // None | |
| 1089 | + case EXPRESSION_API.none: { | |
| 1090 | + // Return empty, the fallback expression will be used | |
| 1091 | + return ''; | |
| 1092 | + } | |
| 1093 | + default: { | |
| 1094 | + toastr.error('Invalid API selected'); | |
| 1095 | + return ''; | |
| 1096 | + } | |
| 1071 | 1097 | } |
| 1072 | 1098 | } catch (error) { |
| 1073 | 1099 | toastr.error('Could not classify expression. Check the console or your backend for more information.'); |
| @@ -1320,12 +1346,28 @@ function getCachedExpressions() { | ||
| 1320 | 1346 | return [...expressionsList, ...extension_settings.expressions.custom].filter(onlyUnique); |
| 1321 | 1347 | } |
| 1322 | 1348 | |
| 1323 | 1349 | export async function getExpressionsList({ filterAvailable = false } = {}) { |
| 1324 | 1350 | // ReturnIf there is no cached list, ifload availableand cache it |
| 1325 | 1351 | if (!Array.isArray(expressionsList)) { |
| 1326 | 1352 | returnexpressionsList getCachedExpressions= await resolveExpressionsList(); |
| 1327 | 1353 | } |
| 1328 | 1354 | |
| 1355 | + const expressions = getCachedExpressions(); | |
| 1356 | + | |
| 1357 | + // Filtering is only available for llm and webllm APIs | |
| 1358 | + if (!filterAvailable || ![EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api)) { | |
| 1359 | + return expressions; | |
| 1360 | + } | |
| 1361 | + | |
| 1362 | + // Get expressions with available sprites | |
| 1363 | + const currentLastMessage = selected_group ? getLastCharacterMessage() : null; | |
| 1364 | + const spriteFolderName = getSpriteFolderName(currentLastMessage, currentLastMessage?.name); | |
| 1365 | + | |
| 1366 | + return expressions.filter(label => { | |
| 1367 | + const expression = spriteCache[spriteFolderName]?.find(x => x.label === label); | |
| 1368 | + return (expression?.files.length ?? 0) > 0; | |
| 1369 | + }); | |
| 1370 | + | |
| 1329 | 1371 | /** |
| 1330 | 1372 | * Returns the list of expressions from the API or fallback in offline mode. |
| 1331 | 1373 | * @returns {Promise<string[]>} |
| @@ -1372,9 +1414,6 @@ export async function getExpressionsList() { | ||
| 1372 | 1414 | expressionsList = DEFAULT_EXPRESSIONS.slice(); |
| 1373 | 1415 | return expressionsList; |
| 1374 | 1416 | } |
| 1375 | - | |
| 1376 | - const result = await resolveExpressionsList(); | |
| 1377 | - return [...result, ...extension_settings.expressions.custom].filter(onlyUnique); | |
| 1378 | 1417 | } |
| 1379 | 1418 | |
| 1380 | 1419 | /** |
| @@ -2036,7 +2075,7 @@ async function fetchImagesNoCache() { | ||
| 2036 | 2075 | |
| 2037 | 2076 | function migrateSettings() { |
| 2038 | 2077 | if (extension_settings.expressions.api === undefined) { |
| 2039 | 2078 | extension_settings.expressions.api = EXPRESSION_API.extrasnone; |
| 2040 | 2079 | saveSettingsDebounced(); |
| 2041 | 2080 | } |
| 2042 | 2081 | |
| @@ -2102,6 +2141,10 @@ function migrateSettings() { | ||
| 2102 | 2141 | extension_settings.expressions.rerollIfSame = !!$(this).prop('checked'); |
| 2103 | 2142 | saveSettingsDebounced(); |
| 2104 | 2143 | }); |
| 2144 | + $('#expressions_filter_available').prop('checked', extension_settings.expressions.filterAvailable).on('input', function () { | |
| 2145 | + extension_settings.expressions.filterAvailable = !!$(this).prop('checked'); | |
| 2146 | + saveSettingsDebounced(); | |
| 2147 | + }); | |
| 2105 | 2148 | $('#expression_override_cleanup_button').on('click', onClickExpressionOverrideRemoveAllButton); |
| 2106 | 2149 | $(document).on('dragstart', '.expression', (e) => { |
| 2107 | 2150 | e.preventDefault(); |
| @@ -2114,7 +2157,7 @@ function migrateSettings() { | ||
| 2114 | 2157 | $('#open_chat_expressions').hide(); |
| 2115 | 2158 | |
| 2116 | 2159 | await renderAdditionalExpressionSettings(); |
| 2117 | 2160 | $('#expression_api').val(extension_settings.expressions.api ?? EXPRESSION_API.extrasnone); |
| 2118 | 2161 | $('.expression_llm_prompt_block').toggle([EXPRESSION_API.llm, EXPRESSION_API.webllm].includes(extension_settings.expressions.api)); |
| 2119 | 2162 | $('#expression_llm_prompt').val(extension_settings.expressions.llmPrompt ?? ''); |
| 2120 | 2163 | $('#expression_llm_prompt').on('input', function () { |
| @@ -2154,7 +2197,7 @@ function migrateSettings() { | ||
| 2154 | 2197 | imgElement.src = ''; |
| 2155 | 2198 | } |
| 2156 | 2199 | |
| 2157 | - setExpressionOverrideHtml(); | |
| 2200 | + setExpressionOverrideHtml(true); // force-clear, as the character might not have an override defined | |
| 2158 | 2201 | |
| 2159 | 2202 | if (isVisualNovelMode()) { |
| 2160 | 2203 | $('#visual-novel-wrapper').empty(); |
| @@ -2279,13 +2322,13 @@ function migrateSettings() { | ||
| 2279 | 2322 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 2280 | 2323 | name: 'expression-list', |
| 2281 | 2324 | aliases: ['expressions'], |
| 2282 | 2325 | /** @type {(args: {return: string, filter: string}) => Promise<string>} */ |
| 2283 | 2326 | callback: async (args) => { |
| 2284 | 2327 | let returnType = |
| 2285 | 2328 | /** @type {import('../../slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */ |
| 2286 | 2329 | (args.return); |
| 2287 | 2330 | |
| 2288 | 2331 | const list = await getExpressionsList({ filterAvailable: !isFalseBoolean(args.filter) }); |
| 2289 | 2332 | |
| 2290 | 2333 | return await slashCommandReturnHelper.doReturn(returnType ?? 'pipe', list, { objectToStringFunc: list => list.join(', ') }); |
| 2291 | 2334 | }, |
| @@ -2298,6 +2341,13 @@ function migrateSettings() { | ||
| 2298 | 2341 | enumList: slashCommandReturnHelper.enumList({ allowObject: true }), |
| 2299 | 2342 | forceEnum: true, |
| 2300 | 2343 | }), |
| 2344 | + SlashCommandNamedArgument.fromProps({ | |
| 2345 | + name: 'filter', | |
| 2346 | + description: 'Filter the list to only include expressions that have available sprites for the current character.', | |
| 2347 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 2348 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 2349 | + defaultValue: 'true', | |
| 2350 | + }), | |
| 2301 | 2351 | ], |
| 2302 | 2352 | returns: 'The comma-separated list of available expressions, including custom expressions.', |
| 2303 | 2353 | helpString: 'Returns a list of available expressions, including custom expressions.', |
| @@ -2314,6 +2364,13 @@ function migrateSettings() { | ||
| 2314 | 2364 | enumList: Object.keys(EXPRESSION_API).map(api => new SlashCommandEnumValue(api, null, enumTypes.enum)), |
| 2315 | 2365 | }), |
| 2316 | 2366 | SlashCommandNamedArgument.fromProps({ |
| 2367 | + name: 'filter', | |
| 2368 | + description: 'Filter the list to only include expressions that have available sprites for the current character.', | |
| 2369 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 2370 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 2371 | + defaultValue: 'true', | |
| 2372 | + }), | |
| 2373 | + SlashCommandNamedArgument.fromProps({ | |
| 2317 | 2374 | name: 'prompt', |
| 2318 | 2375 | description: 'Custom prompt for classification. Only relevant if Classifier API is set to LLM.', |
| 2319 | 2376 | typeList: [ARGUMENT_TYPE.STRING], |
| @@ -22,6 +22,7 @@ | ||
| 22 | 22 | <label for="expression_api" data-i18n="Classifier API">Classifier API</label> |
| 23 | 23 | <small data-i18n="Select the API for classifying expressions.">Select the API for classifying expressions.</small> |
| 24 | 24 | <select id="expression_api" class="flex1 margin0"> |
| 25 | + <option value="99" data-i18n="[ None ]">[ None ]</option> | |
| 25 | 26 | <option value="0" data-i18n="Local">Local</option> |
| 26 | 27 | <option value="1" data-i18n="Extras">Extras (deprecated)</option> |
| 27 | 28 | <option value="2" data-i18n="Main API">Main API</option> |
| @@ -29,7 +30,11 @@ | ||
| 29 | 30 | </select> |
| 30 | 31 | </div> |
| 31 | 32 | <div class="expression_llm_prompt_block m-b-1 m-t-1"> |
| 32 | - <label for="expression_llm_prompt" class="title_restorable"> | |
| 33 | + <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."> | |
| 34 | + <input id="expressions_filter_available" type="checkbox"> | |
| 35 | + <span data-i18n="Filter expressions for available sprites">Filter expressions for available sprites</span> | |
| 36 | + </label> | |
| 37 | + <label for="expression_llm_prompt" class="title_restorable m-t-1"> | |
| 33 | 38 | <span data-i18n="LLM Prompt">LLM Prompt</span> |
| 34 | 39 | <div id="expression_llm_prompt_restore" title="Restore default value" class="right_menu_button"> |
| 35 | 40 | <i class="fa-solid fa-clock-rotate-left fa-sm"></i> |
| @@ -132,7 +132,7 @@ | ||
| 132 | 132 | </label> |
| 133 | 133 | <label class="flex-container alignItemsCenter" title="How many messages before the current end of the chat." data-i18n="[title]How many messages before the current end of the chat."> |
| 134 | 134 | <input type="radio" name="memory_position" value="1" /> |
| 135 | 135 | <span data-i18n="In-chat @ Depth">In-chat @ Depth</span> <input id="memory_depth" class="text_pole widthUnset" type="number" min="0" max="9999999" /> |
| 136 | 136 | <span data-i18n="as">as</span> |
| 137 | 137 | <select id="memory_role" class="text_pole widthNatural"> |
| 138 | 138 | <option value="0" data-i18n="System">System</option> |
| @@ -1,10 +1,7 @@ | ||
| 1 | -// eslint-disable-next-line no-unused-vars | |
| 2 | 1 | import { QuickReply } from '../src/QuickReply.js'; |
| 3 | 2 | import { QuickReplyContextLink } from '../src/QuickReplyContextLink.js'; |
| 4 | 3 | import { QuickReplySet } from '../src/QuickReplySet.js'; |
| 5 | -// eslint-disable-next-line no-unused-vars | |
| 6 | 4 | import { QuickReplySettings } from '../src/QuickReplySettings.js'; |
| 7 | -// eslint-disable-next-line no-unused-vars | |
| 8 | 5 | import { SettingsUi } from '../src/ui/SettingsUi.js'; |
| 9 | 6 | import { onlyUnique } from '../../../utils.js'; |
| 10 | 7 | |
| @@ -1,7 +1,5 @@ | ||
| 1 | 1 | import { warn } from '../index.js'; |
| 2 | -// eslint-disable-next-line no-unused-vars | |
| 3 | 2 | import { QuickReply } from './QuickReply.js'; |
| 4 | -// eslint-disable-next-line no-unused-vars | |
| 5 | 3 | import { QuickReplySettings } from './QuickReplySettings.js'; |
| 6 | 4 | |
| 7 | 5 | export class AutoExecuteHandler { |
| @@ -635,7 +635,6 @@ export class QuickReply { | ||
| 635 | 635 | }, { passive:true }); |
| 636 | 636 | const getLineStart = ()=>{ |
| 637 | 637 | const start = message.selectionStart; |
| 638 | - const end = message.selectionEnd; | |
| 639 | 638 | let lineStart; |
| 640 | 639 | if (start == 0 || message.value[start - 1] == '\n') { |
| 641 | 640 | // cursor is already at beginning of line |
| @@ -701,7 +700,6 @@ export class QuickReply { | ||
| 701 | 700 | } else if (evt.key == 'Enter' && !evt.ctrlKey && !evt.shiftKey && !evt.altKey && !(ac.isReplaceable && ac.isActive)) { |
| 702 | 701 | // new line, keep indent |
| 703 | 702 | const start = message.selectionStart; |
| 704 | - const end = message.selectionEnd; | |
| 705 | 703 | let lineStart = getLineStart(); |
| 706 | 704 | const indent = /^([^\S\n]*)/.exec(message.value.slice(lineStart))[1] ?? ''; |
| 707 | 705 | if (indent.length) { |
| @@ -8,7 +8,6 @@ import { SlashCommandEnumValue, enumTypes } from '../../../slash-commands/SlashC | ||
| 8 | 8 | import { SlashCommandParser } from '../../../slash-commands/SlashCommandParser.js'; |
| 9 | 9 | import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js'; |
| 10 | 10 | import { isTrueBoolean } from '../../../utils.js'; |
| 11 | -// eslint-disable-next-line no-unused-vars | |
| 12 | 11 | import { QuickReplyApi } from '../api/QuickReplyApi.js'; |
| 13 | 12 | import { QuickReply } from './QuickReply.js'; |
| 14 | 13 | import { QuickReplySet } from './QuickReplySet.js'; |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | import { animation_duration } from '../../../../../script.js'; |
| 2 | 2 | import { dragElement } from '../../../../RossAscends-mods.js'; |
| 3 | 3 | import { loadMovingUIState } from '../../../../power-user.js'; |
| 4 | -// eslint-disable-next-line no-unused-vars | |
| 5 | 4 | import { QuickReplySettings } from '../QuickReplySettings.js'; |
| 6 | 5 | |
| 7 | 6 | export class ButtonUi { |
| @@ -3,7 +3,6 @@ import { getSortableDelay } from '../../../../utils.js'; | ||
| 3 | 3 | import { log, warn } from '../../index.js'; |
| 4 | 4 | import { QuickReply } from '../QuickReply.js'; |
| 5 | 5 | import { QuickReplySet } from '../QuickReplySet.js'; |
| 6 | -// eslint-disable-next-line no-unused-vars | |
| 7 | 6 | import { QuickReplySettings } from '../QuickReplySettings.js'; |
| 8 | 7 | |
| 9 | 8 | export class SettingsUi { |
| @@ -1,5 +1,4 @@ | ||
| 1 | 1 | import { QuickReply } from '../../QuickReply.js'; |
| 2 | -// eslint-disable-next-line no-unused-vars | |
| 3 | 2 | import { QuickReplySet } from '../../QuickReplySet.js'; |
| 4 | 3 | import { MenuHeader } from './MenuHeader.js'; |
| 5 | 4 | import { MenuItem } from './MenuItem.js'; |
| @@ -18,9 +18,8 @@ | ||
| 18 | 18 | |
| 19 | 19 | <div id="regex_info_block_wrapper"> |
| 20 | 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 | 23 | </a> |
| 25 | 24 | </div> |
| 26 | 25 | |
| @@ -114,14 +113,14 @@ | ||
| 114 | 113 | <span data-i18n="Min Depth">Min Depth</span> |
| 115 | 114 | <span class="fa-solid fa-circle-question note-link-span"></span> |
| 116 | 115 | </small> |
| 117 | 116 | <input name="min_depth" class="text_pole textarea_compact" type="number" min="-1" max="9999999" data-i18n="[placeholder]ext_regex_min_depth_placeholder" placeholder="Unlimited" /> |
| 118 | 117 | </div> |
| 119 | 118 | <div class="flex1 flex-container flexNoGap"> |
| 120 | 119 | <small data-i18n="[title]ext_regex_max_depth_desc" title="When applied to prompts or display, only affect messages no more than N levels deep. 0 = last message, 1 = penultimate message, etc. System prompt and utility prompts are not affected. Max must be greater than Min for regex to apply."> |
| 121 | 120 | <span data-i18n="Max Depth">Max Depth</span> |
| 122 | 121 | <span class="fa-solid fa-circle-question note-link-span"></span> |
| 123 | 122 | </small> |
| 124 | 123 | <input name="max_depth" class="text_pole textarea_compact" type="number" min="0" max="9999999" data-i18n="[placeholder]ext_regex_min_depth_placeholder" placeholder="Unlimited" /> |
| 125 | 124 | </div> |
| 126 | 125 | </div> |
| 127 | 126 | </div> |
| @@ -148,7 +147,7 @@ | ||
| 148 | 147 | </label> |
| 149 | 148 | <span> |
| 150 | 149 | <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small> |
| 151 | 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 | 151 | </span> |
| 153 | 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 | 153 | <input type="checkbox" name="only_format_display" /> |
| @@ -398,7 +398,7 @@ function runRegexCallback(args, value) { | ||
| 398 | 398 | for (const script of scripts) { |
| 399 | 399 | if (script.scriptName.toLowerCase() === scriptName.toLowerCase()) { |
| 400 | 400 | if (script.disabled) { |
| 401 | 401 | toastr.warning(t`Regex script "${scriptName}" is disabled.`); |
| 402 | 402 | return value; |
| 403 | 403 | } |
| 404 | 404 | |
| @@ -1,6 +1,7 @@ | ||
| 1 | 1 | import { CONNECT_API_MAP, getRequestHeaders } from '../../script.js'; |
| 2 | 2 | import { extension_settings, openThirdPartyExtensionMenu } from '../extensions.js'; |
| 3 | 3 | import { oai_settingst } from '../openaii18n.js'; |
| 4 | +import { oai_settings, proxies } from '../openai.js'; | |
| 4 | 5 | import { SECRET_KEYS, secret_state } from '../secrets.js'; |
| 5 | 6 | import { textgen_types, textgenerationwebui_settings } from '../textgen-settings.js'; |
| 6 | 7 | import { getTokenCountAsync } from '../tokenizers.js'; |
| @@ -152,6 +153,10 @@ function throwIfInvalidModel(useReverseProxy) { | ||
| 152 | 153 | throw new Error('Cohere API key is not set.'); |
| 153 | 154 | } |
| 154 | 155 | |
| 156 | + if (extension_settings.caption.multimodal_api === 'xai' && !secret_state[SECRET_KEYS.XAI]) { | |
| 157 | + throw new Error('xAI API key is not set.'); | |
| 158 | + } | |
| 159 | + | |
| 155 | 160 | if (extension_settings.caption.multimodal_api === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]) { |
| 156 | 161 | throw new Error('Ollama server URL is not set.'); |
| 157 | 162 | } |
| @@ -273,3 +278,329 @@ export async function getWebLlmContextSize() { | ||
| 273 | 278 | const model = await engine.getCurrentModelInfo(); |
| 274 | 279 | return model?.context_size; |
| 275 | 280 | } |
| 281 | + | |
| 282 | +/** | |
| 283 | + * It uses the profiles to send a generate request to the API. | |
| 284 | + */ | |
| 285 | +export class ConnectionManagerRequestService { | |
| 286 | + static defaultSendRequestParams = { | |
| 287 | + stream: false, | |
| 288 | + signal: null, | |
| 289 | + extractData: true, | |
| 290 | + includePreset: true, | |
| 291 | + includeInstruct: true, | |
| 292 | + instructSettings: {}, | |
| 293 | + }; | |
| 294 | + | |
| 295 | + static getAllowedTypes() { | |
| 296 | + return { | |
| 297 | + openai: t`Chat Completion`, | |
| 298 | + textgenerationwebui: t`Text Completion`, | |
| 299 | + }; | |
| 300 | + } | |
| 301 | + | |
| 302 | + /** | |
| 303 | + * @param {string} profileId | |
| 304 | + * @param {string | (import('../custom-request.js').ChatCompletionMessage & {ignoreInstruct?: boolean})[]} prompt | |
| 305 | + * @param {number} maxTokens | |
| 306 | + * @param {Object} custom | |
| 307 | + * @param {boolean?} [custom.stream=false] | |
| 308 | + * @param {AbortSignal?} [custom.signal] | |
| 309 | + * @param {boolean?} [custom.extractData=true] | |
| 310 | + * @param {boolean?} [custom.includePreset=true] | |
| 311 | + * @param {boolean?} [custom.includeInstruct=true] | |
| 312 | + * @param {Partial<InstructSettings>?} [custom.instructSettings] Override instruct settings | |
| 313 | + * @param {Record<string, any>} [overridePayload] - Override payload for the request | |
| 314 | + * @returns {Promise<import('../custom-request.js').ExtractedData | (() => AsyncGenerator<import('../custom-request.js').StreamResponse>)>} If not streaming, returns extracted data; if streaming, returns a function that creates an AsyncGenerator | |
| 315 | + */ | |
| 316 | + static async sendRequest(profileId, prompt, maxTokens, custom = this.defaultSendRequestParams, overridePayload = {}) { | |
| 317 | + const { stream, signal, extractData, includePreset, includeInstruct, instructSettings } = { ...this.defaultSendRequestParams, ...custom }; | |
| 318 | + | |
| 319 | + const context = SillyTavern.getContext(); | |
| 320 | + if (context.extensionSettings.disabledExtensions.includes('connection-manager')) { | |
| 321 | + throw new Error('Connection Manager is not available'); | |
| 322 | + } | |
| 323 | + | |
| 324 | + const profile = context.extensionSettings.connectionManager.profiles.find((p) => p.id === profileId); | |
| 325 | + const selectedApiMap = this.validateProfile(profile); | |
| 326 | + | |
| 327 | + try { | |
| 328 | + switch (selectedApiMap.selected) { | |
| 329 | + case 'openai': { | |
| 330 | + if (!selectedApiMap.source) { | |
| 331 | + throw new Error(`API type ${selectedApiMap.selected} does not support chat completions`); | |
| 332 | + } | |
| 333 | + | |
| 334 | + const proxyPreset = proxies.find((p) => p.name === profile.proxy); | |
| 335 | + | |
| 336 | + const messages = Array.isArray(prompt) ? prompt : [{ role: 'user', content: prompt }]; | |
| 337 | + return await context.ChatCompletionService.processRequest({ | |
| 338 | + stream, | |
| 339 | + messages, | |
| 340 | + max_tokens: maxTokens, | |
| 341 | + model: profile.model, | |
| 342 | + chat_completion_source: selectedApiMap.source, | |
| 343 | + custom_url: profile['api-url'], | |
| 344 | + reverse_proxy: proxyPreset?.url, | |
| 345 | + proxy_password: proxyPreset?.password, | |
| 346 | + ...overridePayload, | |
| 347 | + }, { | |
| 348 | + presetName: includePreset ? profile.preset : undefined, | |
| 349 | + }, extractData, signal); | |
| 350 | + } | |
| 351 | + case 'textgenerationwebui': { | |
| 352 | + if (!selectedApiMap.type) { | |
| 353 | + throw new Error(`API type ${selectedApiMap.selected} does not support text completions`); | |
| 354 | + } | |
| 355 | + | |
| 356 | + return await context.TextCompletionService.processRequest({ | |
| 357 | + stream, | |
| 358 | + prompt, | |
| 359 | + max_tokens: maxTokens, | |
| 360 | + model: profile.model, | |
| 361 | + api_type: selectedApiMap.type, | |
| 362 | + api_server: profile['api-url'], | |
| 363 | + ...overridePayload, | |
| 364 | + }, { | |
| 365 | + instructName: includeInstruct ? profile.instruct : undefined, | |
| 366 | + presetName: includePreset ? profile.preset : undefined, | |
| 367 | + instructSettings: includeInstruct ? instructSettings : undefined, | |
| 368 | + }, extractData, signal); | |
| 369 | + } | |
| 370 | + default: { | |
| 371 | + throw new Error(`Unknown API type ${selectedApiMap.selected}`); | |
| 372 | + } | |
| 373 | + } | |
| 374 | + } catch (error) { | |
| 375 | + throw new Error('API request failed', { cause: error }); | |
| 376 | + } | |
| 377 | + } | |
| 378 | + | |
| 379 | + /** | |
| 380 | + * Respects allowed types. | |
| 381 | + * @returns {import('./connection-manager/index.js').ConnectionProfile[]} | |
| 382 | + */ | |
| 383 | + static getSupportedProfiles() { | |
| 384 | + const context = SillyTavern.getContext(); | |
| 385 | + if (context.extensionSettings.disabledExtensions.includes('connection-manager')) { | |
| 386 | + throw new Error('Connection Manager is not available'); | |
| 387 | + } | |
| 388 | + | |
| 389 | + const profiles = context.extensionSettings.connectionManager.profiles; | |
| 390 | + return profiles.filter((p) => this.isProfileSupported(p)); | |
| 391 | + } | |
| 392 | + | |
| 393 | + /** | |
| 394 | + * @param {import('./connection-manager/index.js').ConnectionProfile?} [profile] | |
| 395 | + * @returns {boolean} | |
| 396 | + */ | |
| 397 | + static isProfileSupported(profile) { | |
| 398 | + if (!profile || !profile.api) { | |
| 399 | + return false; | |
| 400 | + } | |
| 401 | + | |
| 402 | + const apiMap = CONNECT_API_MAP[profile.api]; | |
| 403 | + if (!Object.hasOwn(this.getAllowedTypes(), apiMap.selected)) { | |
| 404 | + return false; | |
| 405 | + } | |
| 406 | + | |
| 407 | + // Some providers not need model, like koboldcpp. But I don't want to check by provider. | |
| 408 | + switch (apiMap.selected) { | |
| 409 | + case 'openai': | |
| 410 | + return !!apiMap.source; | |
| 411 | + case 'textgenerationwebui': | |
| 412 | + return !!apiMap.type; | |
| 413 | + } | |
| 414 | + | |
| 415 | + return false; | |
| 416 | + } | |
| 417 | + | |
| 418 | + /** | |
| 419 | + * @param {import('./connection-manager/index.js').ConnectionProfile?} [profile] | |
| 420 | + * @return {import('../../script.js').ConnectAPIMap} | |
| 421 | + * @throws {Error} | |
| 422 | + */ | |
| 423 | + static validateProfile(profile) { | |
| 424 | + if (!profile) { | |
| 425 | + throw new Error('Could not find profile.'); | |
| 426 | + } | |
| 427 | + if (!profile.api) { | |
| 428 | + throw new Error('Select a connection profile that has an API'); | |
| 429 | + } | |
| 430 | + | |
| 431 | + const context = SillyTavern.getContext(); | |
| 432 | + const selectedApiMap = context.CONNECT_API_MAP[profile.api]; | |
| 433 | + if (!selectedApiMap) { | |
| 434 | + throw new Error(`Unknown API type ${profile.api}`); | |
| 435 | + } | |
| 436 | + if (!Object.hasOwn(this.getAllowedTypes(), selectedApiMap.selected)) { | |
| 437 | + throw new Error(`API type ${selectedApiMap.selected} is not supported. Supported types: ${Object.values(this.getAllowedTypes()).join(', ')}`); | |
| 438 | + } | |
| 439 | + | |
| 440 | + return selectedApiMap; | |
| 441 | + } | |
| 442 | + | |
| 443 | + /** | |
| 444 | + * Create profiles dropdown and updates select element accordingly. Use onChange, onCreate, unUpdate, onDelete callbacks for custom behaviour. e.g updating extension settings. | |
| 445 | + * @param {string} selector | |
| 446 | + * @param {string} initialSelectedProfileId | |
| 447 | + * @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. | |
| 448 | + * @param {(profile: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} onCreate | |
| 449 | + * @param {(oldProfile: import('./connection-manager/index.js').ConnectionProfile, newProfile: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} unUpdate | |
| 450 | + * @param {(profile: import('./connection-manager/index.js').ConnectionProfile) => Promise<void> | void} onDelete | |
| 451 | + */ | |
| 452 | + static handleDropdown( | |
| 453 | + selector, | |
| 454 | + initialSelectedProfileId, | |
| 455 | + onChange = () => { }, | |
| 456 | + onCreate = () => { }, | |
| 457 | + unUpdate = () => { }, | |
| 458 | + onDelete = () => { }, | |
| 459 | + ) { | |
| 460 | + const context = SillyTavern.getContext(); | |
| 461 | + if (context.extensionSettings.disabledExtensions.includes('connection-manager')) { | |
| 462 | + throw new Error('Connection Manager is not available'); | |
| 463 | + } | |
| 464 | + | |
| 465 | + /** | |
| 466 | + * @type {JQuery<HTMLSelectElement>} | |
| 467 | + */ | |
| 468 | + const dropdown = $(selector); | |
| 469 | + | |
| 470 | + if (!dropdown || !dropdown.length) { | |
| 471 | + throw new Error(`Could not find dropdown with selector ${selector}`); | |
| 472 | + } | |
| 473 | + | |
| 474 | + dropdown.empty(); | |
| 475 | + | |
| 476 | + // Create default option using document.createElement | |
| 477 | + const defaultOption = document.createElement('option'); | |
| 478 | + defaultOption.value = ''; | |
| 479 | + defaultOption.textContent = 'Select a Connection Profile'; | |
| 480 | + defaultOption.dataset.i18n = 'Select a Connection Profile'; | |
| 481 | + dropdown.append(defaultOption); | |
| 482 | + | |
| 483 | + const profiles = context.extensionSettings.connectionManager.profiles; | |
| 484 | + | |
| 485 | + // Create optgroups using document.createElement | |
| 486 | + const groups = {}; | |
| 487 | + for (const [apiType, groupLabel] of Object.entries(this.getAllowedTypes())) { | |
| 488 | + const optgroup = document.createElement('optgroup'); | |
| 489 | + optgroup.label = groupLabel; | |
| 490 | + groups[apiType] = optgroup; | |
| 491 | + } | |
| 492 | + | |
| 493 | + const sortedProfilesByGroup = {}; | |
| 494 | + for (const apiType of Object.keys(this.getAllowedTypes())) { | |
| 495 | + sortedProfilesByGroup[apiType] = []; | |
| 496 | + } | |
| 497 | + | |
| 498 | + for (const profile of profiles) { | |
| 499 | + if (this.isProfileSupported(profile)) { | |
| 500 | + const apiMap = CONNECT_API_MAP[profile.api]; | |
| 501 | + if (sortedProfilesByGroup[apiMap.selected]) { | |
| 502 | + sortedProfilesByGroup[apiMap.selected].push(profile); | |
| 503 | + } | |
| 504 | + } | |
| 505 | + } | |
| 506 | + | |
| 507 | + // Sort each group alphabetically and add to dropdown | |
| 508 | + for (const [apiType, groupProfiles] of Object.entries(sortedProfilesByGroup)) { | |
| 509 | + if (groupProfiles.length === 0) continue; | |
| 510 | + | |
| 511 | + groupProfiles.sort((a, b) => a.name.localeCompare(b.name)); | |
| 512 | + | |
| 513 | + const group = groups[apiType]; | |
| 514 | + for (const profile of groupProfiles) { | |
| 515 | + const option = document.createElement('option'); | |
| 516 | + option.value = profile.id; | |
| 517 | + option.textContent = profile.name; | |
| 518 | + group.appendChild(option); | |
| 519 | + } | |
| 520 | + } | |
| 521 | + | |
| 522 | + for (const group of Object.values(groups)) { | |
| 523 | + if (group.children.length > 0) { | |
| 524 | + dropdown.append(group); | |
| 525 | + } | |
| 526 | + } | |
| 527 | + | |
| 528 | + const selectedProfile = profiles.find((p) => p.id === initialSelectedProfileId); | |
| 529 | + if (selectedProfile) { | |
| 530 | + dropdown.val(selectedProfile.id); | |
| 531 | + } | |
| 532 | + | |
| 533 | + context.eventSource.on(context.eventTypes.CONNECTION_PROFILE_CREATED, async (profile) => { | |
| 534 | + const isSupported = this.isProfileSupported(profile); | |
| 535 | + if (!isSupported) { | |
| 536 | + return; | |
| 537 | + } | |
| 538 | + | |
| 539 | + const group = groups[CONNECT_API_MAP[profile.api].selected]; | |
| 540 | + const option = document.createElement('option'); | |
| 541 | + option.value = profile.id; | |
| 542 | + option.textContent = profile.name; | |
| 543 | + group.appendChild(option); | |
| 544 | + | |
| 545 | + await onCreate(profile); | |
| 546 | + }); | |
| 547 | + | |
| 548 | + context.eventSource.on(context.eventTypes.CONNECTION_PROFILE_UPDATED, async (oldProfile, newProfile) => { | |
| 549 | + const currentSelected = dropdown.val(); | |
| 550 | + const isSelectedProfile = currentSelected === oldProfile.id; | |
| 551 | + await unUpdate(oldProfile, newProfile); | |
| 552 | + | |
| 553 | + if (!this.isProfileSupported(newProfile)) { | |
| 554 | + if (isSelectedProfile) { | |
| 555 | + dropdown.val(''); | |
| 556 | + dropdown.trigger('change'); | |
| 557 | + } | |
| 558 | + return; | |
| 559 | + } | |
| 560 | + | |
| 561 | + const group = groups[CONNECT_API_MAP[newProfile.api].selected]; | |
| 562 | + const oldOption = group.querySelector(`option[value="${oldProfile.id}"]`); | |
| 563 | + if (oldOption) { | |
| 564 | + oldOption.remove(); | |
| 565 | + } | |
| 566 | + | |
| 567 | + const option = document.createElement('option'); | |
| 568 | + option.value = newProfile.id; | |
| 569 | + option.textContent = newProfile.name; | |
| 570 | + group.appendChild(option); | |
| 571 | + | |
| 572 | + if (isSelectedProfile) { | |
| 573 | + // Ackchyually, we don't need to reselect but what if id changes? It is not possible for now I couldn't stop myself. | |
| 574 | + dropdown.val(newProfile.id); | |
| 575 | + dropdown.trigger('change'); | |
| 576 | + } | |
| 577 | + }); | |
| 578 | + | |
| 579 | + context.eventSource.on(context.eventTypes.CONNECTION_PROFILE_DELETED, async (profile) => { | |
| 580 | + const currentSelected = dropdown.val(); | |
| 581 | + const isSelectedProfile = currentSelected === profile.id; | |
| 582 | + if (!this.isProfileSupported(profile)) { | |
| 583 | + return; | |
| 584 | + } | |
| 585 | + | |
| 586 | + const group = groups[CONNECT_API_MAP[profile.api].selected]; | |
| 587 | + const optionToRemove = group.querySelector(`option[value="${profile.id}"]`); | |
| 588 | + if (optionToRemove) { | |
| 589 | + optionToRemove.remove(); | |
| 590 | + } | |
| 591 | + | |
| 592 | + if (isSelectedProfile) { | |
| 593 | + dropdown.val(''); | |
| 594 | + dropdown.trigger('change'); | |
| 595 | + } | |
| 596 | + | |
| 597 | + await onDelete(profile); | |
| 598 | + }); | |
| 599 | + | |
| 600 | + dropdown.on('change', async () => { | |
| 601 | + const profileId = dropdown.val(); | |
| 602 | + const profile = context.extensionSettings.connectionManager.profiles.find((p) => p.id === profileId); | |
| 603 | + await onChange(profile); | |
| 604 | + }); | |
| 605 | + } | |
| 606 | +} | |
| @@ -77,11 +77,11 @@ const sources = { | ||
| 77 | 77 | drawthings: 'drawthings', |
| 78 | 78 | pollinations: 'pollinations', |
| 79 | 79 | stability: 'stability', |
| 80 | - blockentropy: 'blockentropy', | |
| 81 | 80 | huggingface: 'huggingface', |
| 82 | 81 | nanogpt: 'nanogpt', |
| 83 | 82 | bfl: 'bfl', |
| 84 | 83 | falai: 'falai', |
| 84 | + xai: 'xai', | |
| 85 | 85 | }; |
| 86 | 86 | |
| 87 | 87 | const initiators = { |
| @@ -1300,11 +1300,11 @@ async function onModelChange() { | ||
| 1300 | 1300 | sources.togetherai, |
| 1301 | 1301 | sources.pollinations, |
| 1302 | 1302 | sources.stability, |
| 1303 | - sources.blockentropy, | |
| 1304 | 1303 | sources.huggingface, |
| 1305 | 1304 | sources.nanogpt, |
| 1306 | 1305 | sources.bfl, |
| 1307 | 1306 | sources.falai, |
| 1307 | + sources.xai, | |
| 1308 | 1308 | ]; |
| 1309 | 1309 | |
| 1310 | 1310 | if (cloudSources.includes(extension_settings.sd.source)) { |
| @@ -1511,9 +1511,6 @@ async function loadSamplers() { | ||
| 1511 | 1511 | case sources.stability: |
| 1512 | 1512 | samplers = ['N/A']; |
| 1513 | 1513 | break; |
| 1514 | - case sources.blockentropy: | |
| 1515 | - samplers = ['N/A']; | |
| 1516 | - break; | |
| 1517 | 1514 | case sources.huggingface: |
| 1518 | 1515 | samplers = ['N/A']; |
| 1519 | 1516 | break; |
| @@ -1523,6 +1520,9 @@ async function loadSamplers() { | ||
| 1523 | 1520 | case sources.bfl: |
| 1524 | 1521 | samplers = ['N/A']; |
| 1525 | 1522 | break; |
| 1523 | + case sources.xai: | |
| 1524 | + samplers = ['N/A']; | |
| 1525 | + break; | |
| 1526 | 1526 | } |
| 1527 | 1527 | |
| 1528 | 1528 | for (const sampler of samplers) { |
| @@ -1701,9 +1701,6 @@ async function loadModels() { | ||
| 1701 | 1701 | case sources.stability: |
| 1702 | 1702 | models = await loadStabilityModels(); |
| 1703 | 1703 | break; |
| 1704 | - case sources.blockentropy: | |
| 1705 | - models = await loadBlockEntropyModels(); | |
| 1706 | - break; | |
| 1707 | 1704 | case sources.huggingface: |
| 1708 | 1705 | models = [{ value: '', text: '<Enter Model ID above>' }]; |
| 1709 | 1706 | break; |
| @@ -1716,6 +1713,9 @@ async function loadModels() { | ||
| 1716 | 1713 | case sources.falai: |
| 1717 | 1714 | models = await loadFalaiModels(); |
| 1718 | 1715 | break; |
| 1716 | + case sources.xai: | |
| 1717 | + models = await loadXAIModels(); | |
| 1718 | + break; | |
| 1719 | 1719 | } |
| 1720 | 1720 | |
| 1721 | 1721 | for (const model of models) { |
| @@ -1768,6 +1768,12 @@ async function loadFalaiModels() { | ||
| 1768 | 1768 | return []; |
| 1769 | 1769 | } |
| 1770 | 1770 | |
| 1771 | +async function loadXAIModels() { | |
| 1772 | + return [ | |
| 1773 | + { value: 'grok-2-image-1212', text: 'grok-2-image-1212' }, | |
| 1774 | + ]; | |
| 1775 | +} | |
| 1776 | + | |
| 1771 | 1777 | async function loadPollinationsModels() { |
| 1772 | 1778 | const result = await fetch('/api/sd/pollinations/models', { |
| 1773 | 1779 | method: 'POST', |
| @@ -1799,26 +1805,6 @@ async function loadTogetherAIModels() { | ||
| 1799 | 1805 | return []; |
| 1800 | 1806 | } |
| 1801 | 1807 | |
| 1802 | -async function loadBlockEntropyModels() { | |
| 1803 | - if (!secret_state[SECRET_KEYS.BLOCKENTROPY]) { | |
| 1804 | - console.debug('Block Entropy API key is not set.'); | |
| 1805 | - return []; | |
| 1806 | - } | |
| 1807 | - | |
| 1808 | - const result = await fetch('/api/sd/blockentropy/models', { | |
| 1809 | - method: 'POST', | |
| 1810 | - headers: getRequestHeaders(), | |
| 1811 | - }); | |
| 1812 | - console.log(result); | |
| 1813 | - if (result.ok) { | |
| 1814 | - const data = await result.json(); | |
| 1815 | - console.log(data); | |
| 1816 | - return data; | |
| 1817 | - } | |
| 1818 | - | |
| 1819 | - return []; | |
| 1820 | -} | |
| 1821 | - | |
| 1822 | 1808 | async function loadNanoGPTModels() { |
| 1823 | 1809 | if (!secret_state[SECRET_KEYS.NANOGPT]) { |
| 1824 | 1810 | console.debug('NanoGPT API key is not set.'); |
| @@ -2097,9 +2083,6 @@ async function loadSchedulers() { | ||
| 2097 | 2083 | case sources.stability: |
| 2098 | 2084 | schedulers = ['N/A']; |
| 2099 | 2085 | break; |
| 2100 | - case sources.blockentropy: | |
| 2101 | - schedulers = ['N/A']; | |
| 2102 | - break; | |
| 2103 | 2086 | case sources.huggingface: |
| 2104 | 2087 | schedulers = ['N/A']; |
| 2105 | 2088 | break; |
| @@ -2112,6 +2095,9 @@ async function loadSchedulers() { | ||
| 2112 | 2095 | case sources.falai: |
| 2113 | 2096 | schedulers = ['N/A']; |
| 2114 | 2097 | break; |
| 2098 | + case sources.xai: | |
| 2099 | + schedulers = ['N/A']; | |
| 2100 | + break; | |
| 2115 | 2101 | } |
| 2116 | 2102 | |
| 2117 | 2103 | for (const scheduler of schedulers) { |
| @@ -2188,9 +2174,6 @@ async function loadVaes() { | ||
| 2188 | 2174 | case sources.stability: |
| 2189 | 2175 | vaes = ['N/A']; |
| 2190 | 2176 | break; |
| 2191 | - case sources.blockentropy: | |
| 2192 | - vaes = ['N/A']; | |
| 2193 | - break; | |
| 2194 | 2177 | case sources.huggingface: |
| 2195 | 2178 | vaes = ['N/A']; |
| 2196 | 2179 | break; |
| @@ -2200,6 +2183,12 @@ async function loadVaes() { | ||
| 2200 | 2183 | case sources.bfl: |
| 2201 | 2184 | vaes = ['N/A']; |
| 2202 | 2185 | break; |
| 2186 | + case sources.falai: | |
| 2187 | + vaes = ['N/A']; | |
| 2188 | + break; | |
| 2189 | + case sources.xai: | |
| 2190 | + vaes = ['N/A']; | |
| 2191 | + break; | |
| 2203 | 2192 | } |
| 2204 | 2193 | |
| 2205 | 2194 | for (const vae of vaes) { |
| @@ -2757,9 +2746,6 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | ||
| 2757 | 2746 | case sources.stability: |
| 2758 | 2747 | result = await generateStabilityImage(prefixedPrompt, negativePrompt, signal); |
| 2759 | 2748 | break; |
| 2760 | - case sources.blockentropy: | |
| 2761 | - result = await generateBlockEntropyImage(prefixedPrompt, negativePrompt, signal); | |
| 2762 | - break; | |
| 2763 | 2749 | case sources.huggingface: |
| 2764 | 2750 | result = await generateHuggingFaceImage(prefixedPrompt, signal); |
| 2765 | 2751 | break; |
| @@ -2772,6 +2758,9 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | ||
| 2772 | 2758 | case sources.falai: |
| 2773 | 2759 | result = await generateFalaiImage(prefixedPrompt, negativePrompt, signal); |
| 2774 | 2760 | break; |
| 2761 | + case sources.xai: | |
| 2762 | + result = await generateXAIImage(prefixedPrompt, negativePrompt, signal); | |
| 2763 | + break; | |
| 2775 | 2764 | } |
| 2776 | 2765 | |
| 2777 | 2766 | if (!result.data) { |
| @@ -2828,40 +2817,6 @@ async function generateTogetherAIImage(prompt, negativePrompt, signal) { | ||
| 2828 | 2817 | } |
| 2829 | 2818 | } |
| 2830 | 2819 | |
| 2831 | -async function generateBlockEntropyImage(prompt, negativePrompt, signal) { | |
| 2832 | - const result = await fetch('/api/sd/blockentropy/generate', { | |
| 2833 | - method: 'POST', | |
| 2834 | - headers: getRequestHeaders(), | |
| 2835 | - signal: signal, | |
| 2836 | - body: JSON.stringify({ | |
| 2837 | - prompt: prompt, | |
| 2838 | - negative_prompt: negativePrompt, | |
| 2839 | - model: extension_settings.sd.model, | |
| 2840 | - steps: extension_settings.sd.steps, | |
| 2841 | - width: extension_settings.sd.width, | |
| 2842 | - height: extension_settings.sd.height, | |
| 2843 | - seed: extension_settings.sd.seed >= 0 ? extension_settings.sd.seed : undefined, | |
| 2844 | - }), | |
| 2845 | - }); | |
| 2846 | - | |
| 2847 | - if (result.ok) { | |
| 2848 | - const data = await result.json(); | |
| 2849 | - | |
| 2850 | - // Default format is 'jpg' | |
| 2851 | - let format = 'jpg'; | |
| 2852 | - | |
| 2853 | - // Check if a format is specified in the result | |
| 2854 | - if (data.format) { | |
| 2855 | - format = data.format.toLowerCase(); | |
| 2856 | - } | |
| 2857 | - | |
| 2858 | - return { format: format, data: data.images[0] }; | |
| 2859 | - } else { | |
| 2860 | - const text = await result.text(); | |
| 2861 | - throw new Error(text); | |
| 2862 | - } | |
| 2863 | -} | |
| 2864 | - | |
| 2865 | 2820 | /** |
| 2866 | 2821 | * Generates an image using the Pollinations API. |
| 2867 | 2822 | * @param {string} prompt - The main instruction used to guide the image generation. |
| @@ -3535,6 +3490,33 @@ async function generateBflImage(prompt, signal) { | ||
| 3535 | 3490 | } |
| 3536 | 3491 | |
| 3537 | 3492 | /** |
| 3493 | + * Generates an image using the xAI API. | |
| 3494 | + * @param {string} prompt The main instruction used to guide the image generation. | |
| 3495 | + * @param {string} _negativePrompt Negative prompt is not used in this API | |
| 3496 | + * @param {AbortSignal} signal An AbortSignal object that can be used to cancel the request. | |
| 3497 | + * @returns {Promise<{format: string, data: string}>} A promise that resolves when the image generation and processing are complete. | |
| 3498 | + */ | |
| 3499 | +async function generateXAIImage(prompt, _negativePrompt, signal) { | |
| 3500 | + const result = await fetch('/api/sd/xai/generate', { | |
| 3501 | + method: 'POST', | |
| 3502 | + headers: getRequestHeaders(), | |
| 3503 | + signal: signal, | |
| 3504 | + body: JSON.stringify({ | |
| 3505 | + prompt: prompt, | |
| 3506 | + model: extension_settings.sd.model, | |
| 3507 | + }), | |
| 3508 | + }); | |
| 3509 | + | |
| 3510 | + if (result.ok) { | |
| 3511 | + const data = await result.json(); | |
| 3512 | + return { format: 'jpg', data: data.image }; | |
| 3513 | + } else { | |
| 3514 | + const text = await result.text(); | |
| 3515 | + throw new Error(text); | |
| 3516 | + } | |
| 3517 | +} | |
| 3518 | + | |
| 3519 | +/** | |
| 3538 | 3520 | * Generates an image using the FAL.AI API. |
| 3539 | 3521 | * @param {string} prompt - The main instruction used to guide the image generation. |
| 3540 | 3522 | * @param {string} negativePrompt - The negative prompt used to guide the image generation. |
| @@ -3772,7 +3754,6 @@ async function addSDGenButtons() { | ||
| 3772 | 3754 | $('#sd_wand_container').append(buttonHtml); |
| 3773 | 3755 | $(document.body).append(dropdownHtml); |
| 3774 | 3756 | |
| 3775 | - const messageButton = $('.sd_message_gen'); | |
| 3776 | 3757 | const button = $('#sd_gen'); |
| 3777 | 3758 | const dropdown = $('#sd_dropdown'); |
| 3778 | 3759 | dropdown.hide(); |
| @@ -3846,8 +3827,6 @@ function isValidState() { | ||
| 3846 | 3827 | return true; |
| 3847 | 3828 | case sources.stability: |
| 3848 | 3829 | return secret_state[SECRET_KEYS.STABILITY]; |
| 3849 | - case sources.blockentropy: | |
| 3850 | - return secret_state[SECRET_KEYS.BLOCKENTROPY]; | |
| 3851 | 3830 | case sources.huggingface: |
| 3852 | 3831 | return secret_state[SECRET_KEYS.HUGGINGFACE]; |
| 3853 | 3832 | case sources.nanogpt: |
| @@ -3856,6 +3835,8 @@ function isValidState() { | ||
| 3856 | 3835 | return secret_state[SECRET_KEYS.BFL]; |
| 3857 | 3836 | case sources.falai: |
| 3858 | 3837 | return secret_state[SECRET_KEYS.FALAI]; |
| 3838 | + case sources.xai: | |
| 3839 | + return secret_state[SECRET_KEYS.XAI]; | |
| 3859 | 3840 | } |
| 3860 | 3841 | } |
| 3861 | 3842 | |
| @@ -38,7 +38,6 @@ | ||
| 38 | 38 | <label for="sd_source" data-i18n="Source">Source</label> |
| 39 | 39 | <select id="sd_source"> |
| 40 | 40 | <option value="bfl">BFL (Black Forest Labs)</option> |
| 41 | - <option value="blockentropy">Block Entropy</option> | |
| 42 | 41 | <option value="comfy">ComfyUI</option> |
| 43 | 42 | <option value="drawthings">DrawThings HTTP API</option> |
| 44 | 43 | <option value="extras">Extras API (deprecated)</option> |
| @@ -53,6 +52,7 @@ | ||
| 53 | 52 | <option value="auto">Stable Diffusion Web UI (AUTOMATIC1111)</option> |
| 54 | 53 | <option value="horde">Stable Horde</option> |
| 55 | 54 | <option value="togetherai">TogetherAI</option> |
| 55 | + <option value="xai">xAI (Grok)</option> | |
| 56 | 56 | </select> |
| 57 | 57 | <div data-sd-source="auto"> |
| 58 | 58 | <label for="sd_auto_url">SD Web UI URL</label> |
| @@ -422,7 +422,7 @@ | ||
| 422 | 422 | </label> |
| 423 | 423 | </div> |
| 424 | 424 | |
| 425 | 425 | <div data-sd-source="novel,togetherai,pollinations,comfy,drawthings,vlad,auto,horde,extras,stability,blockentropy,bfl" class="marginTop5"> |
| 426 | 426 | <label for="sd_seed"> |
| 427 | 427 | <span data-i18n="Seed">Seed</span> |
| 428 | 428 | <small data-i18n="(-1 for random)">(-1 for random)</small> |
| @@ -183,8 +183,6 @@ class GptSovitsV2Provider { | ||
| 183 | 183 | |
| 184 | 184 | let prompt_text = replaceSpeaker(voiceId); |
| 185 | 185 | |
| 186 | - const streaming = this.settings.streaming; | |
| 187 | - | |
| 188 | 186 | const params = { |
| 189 | 187 | text: inputText, |
| 190 | 188 | prompt_text: prompt_text, |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | import { cancelTtsPlay, eventSource, event_types, getCurrentChatId, isStreamingEnabled, name2, saveSettingsDebounced, substituteParams } from '../../../script.js'; |
| 2 | 2 | import { ModuleWorkerWrapper, doExtrasFetch, extension_settings, getApiUrl, getContext, modules, renderExtensionTemplateAsync } from '../../extensions.js'; |
| 3 | 3 | import { delay, escapeRegex, getBase64Async, getStringHash, onlyUnique } from '../../utils.js'; |
| 4 | 4 | import { EdgeTtsProvider } from './edge.js'; |
| 5 | 5 | import { ElevenLabsTtsProvider } from './elevenlabs.js'; |
| @@ -471,6 +471,7 @@ async function processTtsQueue() { | ||
| 471 | 471 | if (extension_settings.tts.skip_codeblocks) { |
| 472 | 472 | text = text.replace(/^\s{4}.*$/gm, '').trim(); |
| 473 | 473 | text = text.replace(/```.*?```/gs, '').trim(); |
| 474 | + text = text.replace(/~~~.*?~~~/gs, '').trim(); | |
| 474 | 475 | } |
| 475 | 476 | |
| 476 | 477 | if (extension_settings.tts.skip_tags) { |
| @@ -76,7 +76,7 @@ | ||
| 76 | 76 | <div id="tts_voicemap_block"> |
| 77 | 77 | </div> |
| 78 | 78 | <hr> |
| 79 | 79 | <form id="tts_provider_settings" class="inline-drawer-content"> |
| 80 | 80 | </form> |
| 81 | 81 | <div class="tts_buttons"> |
| 82 | 82 | <input id="tts_voices" class="menu_button" type="submit" value="Available voices" /> |
| @@ -79,6 +79,10 @@ class SystemTtsProvider { | ||
| 79 | 79 | // Config // |
| 80 | 80 | //########// |
| 81 | 81 | |
| 82 | + // Static constants for the simulated default voice | |
| 83 | + static BROWSER_DEFAULT_VOICE_ID = '__browser_default__'; | |
| 84 | + static BROWSER_DEFAULT_VOICE_NAME = 'System Default Voice'; | |
| 85 | + | |
| 82 | 86 | settings; |
| 83 | 87 | ready = false; |
| 84 | 88 | voices = []; |
| @@ -168,51 +172,97 @@ class SystemTtsProvider { | ||
| 168 | 172 | //#################// |
| 169 | 173 | fetchTtsVoiceObjects() { |
| 170 | 174 | if (!('speechSynthesis' in window)) { |
| 171 | 175 | return Promise.resolve([]); |
| 172 | 176 | } |
| 173 | 177 | |
| 174 | 178 | return new Promise((resolve) => { |
| 175 | 179 | setTimeout(() => { |
| 176 | 180 | constlet voices = speechSynthesis.getVoices(); |
| 177 | - .getVoices() | |
| 181 | + | |
| 182 | + if (voices.length === 0) { | |
| 183 | + // Edge compat: Provide default when voices empty | |
| 184 | + console.warn('SystemTTS: getVoices() returned empty list. Providing browser default option.'); | |
| 185 | + const defaultVoice = { | |
| 186 | + name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME, | |
| 187 | + voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID, | |
| 188 | + preview_url: false, | |
| 189 | + lang: navigator.language || 'en-US', | |
| 190 | + }; | |
| 191 | + resolve([defaultVoice]); | |
| 192 | + } else { | |
| 193 | + const mappedVoices = voices | |
| 178 | 194 | .sort((a, b) => a.lang.localeCompare(b.lang) || a.name.localeCompare(b.name)) |
| 179 | 195 | .map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: false, lang: x.lang })); |
| 180 | - | |
| 196 | + resolve(mappedVoices); | |
| 181 | - resolve(voices); | |
| 197 | + } | |
| 182 | 198 | }, 150); |
| 183 | 199 | }); |
| 184 | 200 | } |
| 185 | 201 | |
| 186 | 202 | previewTtsVoice(voiceId) { |
| 187 | 203 | if (!('speechSynthesis' in window)) { |
| 188 | 204 | throw new Error('Speech synthesis API is not supported'); |
| 189 | 205 | } |
| 190 | 206 | |
| 191 | - const voice = speechSynthesis.getVoices().find(x => x.voiceURI === voiceId); | |
| 207 | + let voice = null; | |
| 208 | + if (voiceId !== SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID) { | |
| 209 | + const voices = speechSynthesis.getVoices(); | |
| 210 | + voice = voices.find(x => x.voiceURI === voiceId); | |
| 192 | 211 | |
| 193 | 212 | if (!voice && voices.length > 0) { |
| 194 | - throw `TTS Voice id ${voiceId} not found`; | |
| 213 | + console.warn(`SystemTTS Preview: Voice ID "${voiceId}" not found among available voices. Using browser default.`); | |
| 214 | + } else if (!voice && voices.length === 0) { | |
| 215 | + console.warn('SystemTTS Preview: Voice list is empty. Using browser default.'); | |
| 216 | + } | |
| 217 | + } else { | |
| 218 | + console.log('SystemTTS Preview: Using browser default voice as requested.'); | |
| 195 | 219 | } |
| 196 | 220 | |
| 197 | 221 | speechSynthesis.cancel(); |
| 198 | - const text = getPreviewString(voice.lang); | |
| 222 | + const langForPreview = voice ? voice.lang : (navigator.language || 'en-US'); | |
| 223 | + const text = getPreviewString(langForPreview); | |
| 199 | 224 | const utterance = new SpeechSynthesisUtterance(text); |
| 225 | + | |
| 226 | + if (voice) { | |
| 200 | 227 | utterance.voice = voice; |
| 228 | + } | |
| 229 | + | |
| 201 | 230 | utterance.rate = this.settings.rate || 1; |
| 202 | 231 | utterance.pitch = this.settings.pitch || 1; |
| 232 | + | |
| 233 | + utterance.onerror = (event) => { | |
| 234 | + console.error(`SystemTTS Preview Error: ${event.error}`, event); | |
| 235 | + }; | |
| 236 | + | |
| 203 | 237 | speechSynthesis.speak(utterance); |
| 204 | 238 | } |
| 205 | 239 | |
| 206 | 240 | async getVoice(voiceName) { |
| 207 | 241 | if (!('speechSynthesis' in window)) { |
| 208 | 242 | return { voice_id: null, name: 'API Not Supported' }; |
| 243 | + } | |
| 244 | + | |
| 245 | + if (voiceName === SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME) { | |
| 246 | + return { | |
| 247 | + voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID, | |
| 248 | + name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME, | |
| 249 | + }; | |
| 209 | 250 | } |
| 210 | 251 | |
| 211 | 252 | const voices = speechSynthesis.getVoices(); |
| 253 | + | |
| 254 | + if (voices.length === 0) { | |
| 255 | + console.warn('SystemTTS: Empty voice list, using default fallback'); | |
| 256 | + return { | |
| 257 | + voice_id: SystemTtsProvider.BROWSER_DEFAULT_VOICE_ID, | |
| 258 | + name: SystemTtsProvider.BROWSER_DEFAULT_VOICE_NAME, | |
| 259 | + }; | |
| 260 | + } | |
| 261 | + | |
| 212 | 262 | const match = voices.find(x => x.name == voiceName); |
| 213 | 263 | |
| 214 | 264 | if (!match) { |
| 215 | 265 | throw new Error(`SystemTTS getVoice: TTS Voice name "${voiceName}" not found`); |
| 216 | 266 | } |
| 217 | 267 | |
| 218 | 268 | return { voice_id: match.voiceURI, name: match.name }; |
| @@ -237,7 +287,6 @@ class SystemTtsProvider { | ||
| 237 | 287 | speechUtteranceChunker(utterance, { |
| 238 | 288 | chunkLength: 200, |
| 239 | 289 | }, function () { |
| 240 | - //some code to execute when done | |
| 241 | 290 | resolve(silence); |
| 242 | 291 | console.log('System TTS done'); |
| 243 | 292 | }); |
| @@ -55,6 +55,8 @@ const getBatchSize = () => ['transformers', 'palm', 'ollama'].includes(settings. | ||
| 55 | 55 | const settings = { |
| 56 | 56 | // For both |
| 57 | 57 | source: 'transformers', |
| 58 | + alt_endpoint_url: '', | |
| 59 | + use_alt_endpoint: false, | |
| 58 | 60 | include_wi: false, |
| 59 | 61 | togetherai_model: 'togethercomputer/m2-bert-80M-32k-retrieval', |
| 60 | 62 | openai_model: 'text-embedding-ada-002', |
| @@ -63,6 +65,7 @@ const settings = { | ||
| 63 | 65 | ollama_keep: false, |
| 64 | 66 | vllm_model: '', |
| 65 | 67 | webllm_model: '', |
| 68 | + google_model: 'text-embedding-004', | |
| 66 | 69 | summarize: false, |
| 67 | 70 | summarize_sent: false, |
| 68 | 71 | summary_source: 'main', |
| @@ -108,6 +111,7 @@ const settings = { | ||
| 108 | 111 | const moduleWorker = new ModuleWorkerWrapper(synchronizeChat); |
| 109 | 112 | const webllmProvider = new WebLlmVectorProvider(); |
| 110 | 113 | const cachedSummaries = new Map(); |
| 114 | +const vectorApiRequiresUrl = ['llamacpp', 'vllm', 'ollama', 'koboldcpp']; | |
| 111 | 115 | |
| 112 | 116 | /** |
| 113 | 117 | * Gets the Collection ID for a file embedded in the chat. |
| @@ -565,6 +569,8 @@ async function retrieveFileChunks(queryText, collectionId) { | ||
| 565 | 569 | * @returns {Promise<boolean>} True if successful, false if not |
| 566 | 570 | */ |
| 567 | 571 | async function vectorizeFile(fileText, fileName, collectionId, chunkSize, overlapPercent) { |
| 572 | + let toast = jQuery(); | |
| 573 | + | |
| 568 | 574 | try { |
| 569 | 575 | if (settings.translate_files && typeof globalThis.translate === 'function') { |
| 570 | 576 | console.log(`Vectors: Translating file ${fileName} to English...`); |
| @@ -574,7 +580,7 @@ async function vectorizeFile(fileText, fileName, collectionId, chunkSize, overla | ||
| 574 | 580 | |
| 575 | 581 | const batchSize = getBatchSize(); |
| 576 | 582 | const toastBody = $('<span>').text('This may take a while. Please wait...'); |
| 577 | 583 | const toast = toastr.info(toastBody, `Ingesting file ${escapeHtml(fileName)}`, { closeButton: false, escapeHtml: false, timeOut: 0, extendedTimeOut: 0 }); |
| 578 | 584 | const overlapSize = Math.round(chunkSize * overlapPercent / 100); |
| 579 | 585 | const delimiters = getChunkDelimiters(); |
| 580 | 586 | // Overlap should not be included in chunk size. It will be later compensated by overlapChunks |
| @@ -596,6 +602,7 @@ async function vectorizeFile(fileText, fileName, collectionId, chunkSize, overla | ||
| 596 | 602 | console.log(`Vectors: Inserted ${chunks.length} vector items for file ${fileName} into ${collectionId}`); |
| 597 | 603 | return true; |
| 598 | 604 | } catch (error) { |
| 605 | + toastr.clear(toast); | |
| 599 | 606 | toastr.error(String(error), 'Failed to vectorize file', { preventDuplicates: true }); |
| 600 | 607 | console.error('Vectors: Failed to vectorize file', error); |
| 601 | 608 | return false; |
| @@ -773,19 +780,22 @@ function getVectorsRequestBody(args = {}) { | ||
| 773 | 780 | break; |
| 774 | 781 | case 'ollama': |
| 775 | 782 | body.model = extension_settings.vectors.ollama_model; |
| 776 | 783 | body.apiUrl = settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.OLLAMA]; |
| 777 | 784 | body.keep = !!extension_settings.vectors.ollama_keep; |
| 778 | 785 | break; |
| 779 | 786 | case 'llamacpp': |
| 780 | 787 | body.apiUrl = settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]; |
| 781 | 788 | break; |
| 782 | 789 | case 'vllm': |
| 783 | 790 | body.apiUrl = settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.VLLM]; |
| 784 | 791 | body.model = extension_settings.vectors.vllm_model; |
| 785 | 792 | break; |
| 786 | 793 | case 'webllm': |
| 787 | 794 | body.model = extension_settings.vectors.webllm_model; |
| 788 | 795 | break; |
| 796 | + case 'palm': | |
| 797 | + body.model = extension_settings.vectors.google_model; | |
| 798 | + break; | |
| 789 | 799 | default: |
| 790 | 800 | break; |
| 791 | 801 | } |
| @@ -803,6 +813,12 @@ async function getAdditionalArgs(items) { | ||
| 803 | 813 | case 'webllm': |
| 804 | 814 | args.embeddings = await createWebLlmEmbeddings(items); |
| 805 | 815 | break; |
| 816 | + case 'koboldcpp': { | |
| 817 | + const { embeddings, model } = await createKoboldCppEmbeddings(items); | |
| 818 | + args.embeddings = embeddings; | |
| 819 | + args.model = model; | |
| 820 | + break; | |
| 821 | + } | |
| 806 | 822 | } |
| 807 | 823 | return args; |
| 808 | 824 | } |
| @@ -870,11 +886,19 @@ function throwIfSourceInvalid() { | ||
| 870 | 886 | throw new Error('Vectors: API key missing', { cause: 'api_key_missing' }); |
| 871 | 887 | } |
| 872 | 888 | |
| 889 | + if (vectorApiRequiresUrl.includes(settings.source) && settings.use_alt_endpoint) { | |
| 890 | + if (!settings.alt_endpoint_url) { | |
| 891 | + throw new Error('Vectors: API URL missing', { cause: 'api_url_missing' }); | |
| 892 | + } | |
| 893 | + } | |
| 894 | + else { | |
| 873 | 895 | if (settings.source === 'ollama' && !textgenerationwebui_settings.server_urls[textgen_types.OLLAMA] || |
| 874 | 896 | settings.source === 'vllm' && !textgenerationwebui_settings.server_urls[textgen_types.VLLM] || |
| 897 | + settings.source === 'koboldcpp' && !textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP] || | |
| 875 | 898 | settings.source === 'llamacpp' && !textgenerationwebui_settings.server_urls[textgen_types.LLAMACPP]) { |
| 876 | 899 | throw new Error('Vectors: API URL missing', { cause: 'api_url_missing' }); |
| 877 | 900 | } |
| 901 | + } | |
| 878 | 902 | |
| 879 | 903 | if (settings.source === 'ollama' && !settings.ollama_model || settings.source === 'vllm' && !settings.vllm_model) { |
| 880 | 904 | throw new Error('Vectors: API model missing', { cause: 'api_model_missing' }); |
| @@ -1071,6 +1095,9 @@ function toggleSettings() { | ||
| 1071 | 1095 | $('#vllm_vectorsModel').toggle(settings.source === 'vllm'); |
| 1072 | 1096 | $('#nomicai_apiKey').toggle(settings.source === 'nomicai'); |
| 1073 | 1097 | $('#webllm_vectorsModel').toggle(settings.source === 'webllm'); |
| 1098 | + $('#koboldcpp_vectorsModel').toggle(settings.source === 'koboldcpp'); | |
| 1099 | + $('#google_vectorsModel').toggle(settings.source === 'palm'); | |
| 1100 | + $('#vector_altEndpointUrl').toggle(vectorApiRequiresUrl.includes(settings.source)); | |
| 1074 | 1101 | if (settings.source === 'webllm') { |
| 1075 | 1102 | loadWebLlmModels(); |
| 1076 | 1103 | } |
| @@ -1138,6 +1165,45 @@ async function createWebLlmEmbeddings(items) { | ||
| 1138 | 1165 | }); |
| 1139 | 1166 | } |
| 1140 | 1167 | |
| 1168 | +/** | |
| 1169 | + * Creates KoboldCpp embeddings for a list of items. | |
| 1170 | + * @param {string[]} items Items to embed | |
| 1171 | + * @returns {Promise<{embeddings: Record<string, number[]>, model: string}>} Calculated embeddings | |
| 1172 | + */ | |
| 1173 | +async function createKoboldCppEmbeddings(items) { | |
| 1174 | + const response = await fetch('/api/backends/kobold/embed', { | |
| 1175 | + method: 'POST', | |
| 1176 | + headers: getRequestHeaders(), | |
| 1177 | + body: JSON.stringify({ | |
| 1178 | + items: items, | |
| 1179 | + server: settings.use_alt_endpoint ? settings.alt_endpoint_url : textgenerationwebui_settings.server_urls[textgen_types.KOBOLDCPP], | |
| 1180 | + }), | |
| 1181 | + }); | |
| 1182 | + | |
| 1183 | + if (!response.ok) { | |
| 1184 | + throw new Error('Failed to get KoboldCpp embeddings'); | |
| 1185 | + } | |
| 1186 | + | |
| 1187 | + const data = await response.json(); | |
| 1188 | + if (!Array.isArray(data.embeddings) || !data.model || data.embeddings.length !== items.length) { | |
| 1189 | + throw new Error('Invalid response from KoboldCpp embeddings'); | |
| 1190 | + } | |
| 1191 | + | |
| 1192 | + const embeddings = /** @type {Record<string, number[]>} */ ({}); | |
| 1193 | + for (let i = 0; i < data.embeddings.length; i++) { | |
| 1194 | + if (!Array.isArray(data.embeddings[i]) || data.embeddings[i].length === 0) { | |
| 1195 | + throw new Error('KoboldCpp returned an empty embedding. Reduce the chunk size and/or size threshold and try again.'); | |
| 1196 | + } | |
| 1197 | + | |
| 1198 | + embeddings[items[i]] = data.embeddings[i]; | |
| 1199 | + } | |
| 1200 | + | |
| 1201 | + return { | |
| 1202 | + embeddings: embeddings, | |
| 1203 | + model: data.model, | |
| 1204 | + }; | |
| 1205 | +} | |
| 1206 | + | |
| 1141 | 1207 | async function onPurgeClick() { |
| 1142 | 1208 | const chatId = getCurrentChatId(); |
| 1143 | 1209 | if (!chatId) { |
| @@ -1412,6 +1478,16 @@ jQuery(async () => { | ||
| 1412 | 1478 | saveSettingsDebounced(); |
| 1413 | 1479 | toggleSettings(); |
| 1414 | 1480 | }); |
| 1481 | + $('#vector_altEndpointUrl_enabled').prop('checked', settings.use_alt_endpoint).on('input', () => { | |
| 1482 | + settings.use_alt_endpoint = $('#vector_altEndpointUrl_enabled').prop('checked'); | |
| 1483 | + Object.assign(extension_settings.vectors, settings); | |
| 1484 | + saveSettingsDebounced(); | |
| 1485 | + }); | |
| 1486 | + $('#vector_altEndpoint_address').val(settings.alt_endpoint_url).on('change', () => { | |
| 1487 | + settings.alt_endpoint_url = String($('#vector_altEndpoint_address').val()); | |
| 1488 | + Object.assign(extension_settings.vectors, settings); | |
| 1489 | + saveSettingsDebounced(); | |
| 1490 | + }); | |
| 1415 | 1491 | $('#api_key_nomicai').on('click', async () => { |
| 1416 | 1492 | const popupText = 'NomicAI API Key:'; |
| 1417 | 1493 | const key = await callGenericPopup(popupText, POPUP_TYPE.INPUT, '', { |
| @@ -1688,6 +1764,12 @@ jQuery(async () => { | ||
| 1688 | 1764 | toastr.success('WebLLM model loaded'); |
| 1689 | 1765 | }); |
| 1690 | 1766 | |
| 1767 | + $('#vectors_google_model').val(settings.google_model).on('input', () => { | |
| 1768 | + settings.google_model = String($('#vectors_google_model').val()); | |
| 1769 | + Object.assign(extension_settings.vectors, settings); | |
| 1770 | + saveSettingsDebounced(); | |
| 1771 | + }); | |
| 1772 | + | |
| 1691 | 1773 | $('#api_key_nomicai').toggleClass('success', !!secret_state[SECRET_KEYS.NOMICAI]); |
| 1692 | 1774 | |
| 1693 | 1775 | toggleSettings(); |
| @@ -13,6 +13,7 @@ | ||
| 13 | 13 | <option value="cohere">Cohere</option> |
| 14 | 14 | <option value="extras">Extras (deprecated)</option> |
| 15 | 15 | <option value="palm">Google AI Studio</option> |
| 16 | + <option value="koboldcpp">KoboldCpp</option> | |
| 16 | 17 | <option value="llamacpp">llama.cpp</option> |
| 17 | 18 | <option value="transformers" data-i18n="Local (Transformers)">Local (Transformers)</option> |
| 18 | 19 | <option value="mistral">MistralAI</option> |
| @@ -24,6 +25,16 @@ | ||
| 24 | 25 | <option value="webllm" data-i18n="WebLLM Extension">WebLLM Extension</option> |
| 25 | 26 | </select> |
| 26 | 27 | </div> |
| 28 | + <div class="flex-container flexFlowColumn" id="vector_altEndpointUrl"> | |
| 29 | + <label class="checkbox_label" for="vector_altEndpointUrl_enabled" title="Enable secondary endpoint URL usage, instead of the main one."> | |
| 30 | + <input id="vector_altEndpointUrl_enabled" type="checkbox" class="checkbox"> | |
| 31 | + <span data-i18n="Use secondary URL">Use secondary URL</span> | |
| 32 | + </label> | |
| 33 | + <label for="vector_altEndpoint_address" data-i18n="Secondary Embedding endpoint URL"> | |
| 34 | + Secondary Embedding endpoint URL | |
| 35 | + </label> | |
| 36 | + <input id="vector_altEndpoint_address" class="text_pole" type="text" placeholder="e.g. http://localhost:5001" /> | |
| 37 | + </div> | |
| 27 | 38 | <div class="flex-container flexFlowColumn" id="webllm_vectorsModel"> |
| 28 | 39 | <label for="vectors_webllm_model" data-i18n="Vectorization Model"> |
| 29 | 40 | Vectorization Model |
| @@ -55,6 +66,14 @@ | ||
| 55 | 66 | Hint: Set the URL in the API connection settings. |
| 56 | 67 | </i> |
| 57 | 68 | </div> |
| 69 | + <div class="flex-container flexFlowColumn" id="koboldcpp_vectorsModel"> | |
| 70 | + <span> | |
| 71 | + Set the KoboldCpp URL in the Text Completion API connection settings. | |
| 72 | + </span> | |
| 73 | + <span> | |
| 74 | + Must use version 1.87 or higher and have an embedding model loaded. | |
| 75 | + </span> | |
| 76 | + </div> | |
| 58 | 77 | <div class="flex-container flexFlowColumn" id="llamacpp_vectorsModel"> |
| 59 | 78 | <span data-i18n="The server MUST be started with the --embedding flag to use this feature!"> |
| 60 | 79 | The server MUST be started with the <code>--embedding</code> flag to use this feature! |
| @@ -111,7 +130,16 @@ | ||
| 111 | 130 | Hint: Set the URL in the API connection settings. |
| 112 | 131 | </i> |
| 113 | 132 | </div> |
| 114 | - | |
| 133 | + <div class="flex-container flexFlowColumn" id="google_vectorsModel"> | |
| 134 | + <label for="vectors_google_model" data-i18n="Vectorization Model"> | |
| 135 | + Vectorization Model | |
| 136 | + </label> | |
| 137 | + <select id="vectors_google_model" class="text_pole"> | |
| 138 | + <option value="gemini-embedding-exp-03-07">gemini-embedding-exp-03-07</option> | |
| 139 | + <option value="text-embedding-004">text-embedding-004</option> | |
| 140 | + <option value="embedding-001">embedding-001</option> | |
| 141 | + </select> | |
| 142 | + </div> | |
| 115 | 143 | <div class="flex-container alignItemsCenter" id="nomicai_apiKey"> |
| 116 | 144 | <label for="api_key_nomicai" class="flex1"> |
| 117 | 145 | <span data-i18n="NomicAI API Key">NomicAI API Key</span> |
| @@ -292,7 +320,7 @@ | ||
| 292 | 320 | <label for="vectors_file_depth_db" title="How many messages before the current end of the chat." data-i18n="[title]How many messages before the current end of the chat."> |
| 293 | 321 | <input type="radio" name="vectors_file_position_db" value="1" /> |
| 294 | 322 | <span data-i18n="In-chat @ Depth">In-chat @ Depth</span> |
| 295 | 323 | <input id="vectors_file_depth_db" class="text_pole widthUnset" type="number" min="0" max="9999999" /> |
| 296 | 324 | <span>as</span> |
| 297 | 325 | <select id="vectors_file_depth_role_db" class="text_pole widthNatural"> |
| 298 | 326 | <option value="0" data-i18n="System">System</option> |
| @@ -344,7 +372,7 @@ | ||
| 344 | 372 | <label for="vectors_depth" title="How many messages before the current end of the chat." data-i18n="[title]How many messages before the current end of the chat."> |
| 345 | 373 | <input type="radio" name="vectors_position" value="1" /> |
| 346 | 374 | <span data-i18n="In-chat @ Depth">In-chat @ Depth </span> |
| 347 | 375 | <input id="vectors_depth" class="text_pole widthUnset" type="number" min="0" max="9999999" /> |
| 348 | 376 | </label> |
| 349 | 377 | </div> |
| 350 | 378 | <div class="flex-container"> |
| @@ -46,7 +46,6 @@ import { | ||
| 46 | 46 | hideSwipeButtons, |
| 47 | 47 | chat_metadata, |
| 48 | 48 | updateChatMetadata, |
| 49 | - isStreamingEnabled, | |
| 50 | 49 | getThumbnailUrl, |
| 51 | 50 | getRequestHeaders, |
| 52 | 51 | setMenuType, |
| @@ -435,16 +434,18 @@ export function getGroupCharacterCards(groupId, characterId) { | ||
| 435 | 434 | * @param {string} value Value to replace |
| 436 | 435 | * @param {string} fieldName Name of the field |
| 437 | 436 | * @param {string} characterName Name of the character |
| 437 | + * @param {boolean} trim Whether to trim the value | |
| 438 | 438 | * @returns {string} Replaced text |
| 439 | 439 | * */ |
| 440 | 440 | function customBaseChatReplace(value, fieldName, characterName, trim) { |
| 441 | 441 | if (!value) { |
| 442 | 442 | return ''; |
| 443 | 443 | } |
| 444 | 444 | |
| 445 | 445 | // We should do the custom field name replacement first, and then run it through the normal macro engine with provided names |
| 446 | 446 | value = value.replace(/<FIELDNAME>/gi, fieldName); |
| 447 | 447 | returnvalue baseChatReplace(= trim ? value.trim(), name1,: characterName)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 | 470 | // Prepare and replace prefixes |
| 470 | 471 | const prefix = customBaseChatReplace(group.generation_mode_join_prefix, fieldName, characterName, false); |
| 471 | 472 | const suffix = customBaseChatReplace(group.generation_mode_join_suffix, fieldName, characterName, false); |
| 472 | - const separator = power_user.instruct.wrap ? '\n' : ''; | |
| 473 | 473 | // Also run the macro replacement on the actual content |
| 474 | 474 | value = customBaseChatReplace(value, fieldName, characterName, true); |
| 475 | 475 | |
| 476 | 476 | return `${prefix ? prefix + separator : ''}${value}${suffix ? separator + suffix : ''}`; |
| 477 | 477 | } |
| 478 | 478 | |
| 479 | 479 | const scenarioOverride = chat_metadata['scenario']; |
| @@ -696,7 +696,7 @@ export function getGroupBlock(group) { | ||
| 696 | 696 | template.find('.group_fav_icon').css('display', 'none'); |
| 697 | 697 | template.addClass(group.fav ? 'is_fav' : ''); |
| 698 | 698 | template.find('.ch_fav').val(group.fav); |
| 699 | 699 | template.find('.group_select_counter').text(`${count} ${+ ' ' + (count != 1 ? 't`characters'` : 't`character'}`)); |
| 700 | 700 | template.find('.group_select_block_list').text(namesList.join(', ')); |
| 701 | 701 | |
| 702 | 702 | // Display inline tags |
| @@ -882,7 +882,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | ||
| 882 | 882 | activatedMembers = activateListOrder(enabledMembers); |
| 883 | 883 | } |
| 884 | 884 | else if (activationStrategy === group_activation_strategy.POOLED) { |
| 885 | 885 | activatedMembers = activatePooledOrder(enabledMembers, lastMessage, isUserInput); |
| 886 | 886 | } |
| 887 | 887 | else if (activationStrategy === group_activation_strategy.MANUAL && !isUserInput) { |
| 888 | 888 | activatedMembers = shuffle(enabledMembers).slice(0, 1).map(x => characters.findIndex(y => y.avatar === x)).filter(x => x !== -1); |
| @@ -904,6 +904,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | ||
| 904 | 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 | 908 | // now the real generation begins: cycle through every activated character |
| 908 | 909 | for (const chId of activatedMembers) { |
| 909 | 910 | throwIfAborted(); |
| @@ -942,6 +943,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | ||
| 942 | 943 | setCharacterName(''); |
| 943 | 944 | activateSendButtons(); |
| 944 | 945 | showSwipeButtons(); |
| 946 | + await eventSource.emit(event_types.GROUP_WRAPPER_FINISHED, { selected_group, type }); | |
| 945 | 947 | } |
| 946 | 948 | |
| 947 | 949 | return Promise.resolve(textResult); |
| @@ -1028,16 +1030,17 @@ function activateListOrder(members) { | ||
| 1028 | 1030 | * Activate group members based on the last message. |
| 1029 | 1031 | * @param {string[]} members List of member avatars |
| 1030 | 1032 | * @param {Object} lastMessage Last message |
| 1033 | + * @param {boolean} isUserInput Whether the user has input text | |
| 1031 | 1034 | * @returns {number[]} List of character ids |
| 1032 | 1035 | */ |
| 1033 | 1036 | function activatePooledOrder(members, lastMessage, isUserInput) { |
| 1034 | 1037 | /** @type {string} */ |
| 1035 | 1038 | let activatedMember = null; |
| 1036 | 1039 | /** @type {string[]} */ |
| 1037 | 1040 | const spokenSinceUser = []; |
| 1038 | 1041 | |
| 1039 | 1042 | for (const message of chat.slice().reverse()) { |
| 1040 | 1043 | if (message.is_user || isUserInput) { |
| 1041 | 1044 | break; |
| 1042 | 1045 | } |
| 1043 | 1046 | |
| @@ -10,6 +10,7 @@ import { SECRET_KEYS, writeSecret } from './secrets.js'; | ||
| 10 | 10 | import { delay } from './utils.js'; |
| 11 | 11 | import { isMobile } from './RossAscends-mods.js'; |
| 12 | 12 | import { autoSelectInstructPreset } from './instruct-mode.js'; |
| 13 | +import { t } from './i18n.js'; | |
| 13 | 14 | |
| 14 | 15 | export { |
| 15 | 16 | horde_settings, |
| @@ -169,7 +170,7 @@ async function adjustHordeGenerationParams(max_context_length, max_length) { | ||
| 169 | 170 | } |
| 170 | 171 | } |
| 171 | 172 | console.log(maxContextLength, maxLength); |
| 172 | 173 | $('#adjustedHordeParams').text(t`Context` + `: ${maxContextLength}, ` + t`Response` + `: ${maxLength}`); |
| 173 | 174 | return { maxContextLength, maxLength }; |
| 174 | 175 | } |
| 175 | 176 | |
| @@ -177,7 +178,7 @@ function setContextSizePreview() { | ||
| 177 | 178 | if (horde_settings.models.length) { |
| 178 | 179 | adjustHordeGenerationParams(max_context, amount_gen); |
| 179 | 180 | } else { |
| 180 | 181 | $('#adjustedHordeParams').text('t`Context` + ': --, ' + t`Response` + ': --'); |
| 181 | 182 | } |
| 182 | 183 | } |
| 183 | 184 | |
| @@ -404,7 +405,7 @@ jQuery(function () { | ||
| 404 | 405 | if (horde_settings.models.length) { |
| 405 | 406 | adjustHordeGenerationParams(max_context, amount_gen); |
| 406 | 407 | } else { |
| 407 | 408 | $('#adjustedHordeParams').text('t`Context` + ': --, ' + t`Response` + ': --'); |
| 408 | 409 | } |
| 409 | 410 | |
| 410 | 411 | saveSettingsDebounced(); |
| @@ -243,9 +243,14 @@ export function autoSelectInstructPreset(modelId) { | ||
| 243 | 243 | |
| 244 | 244 | /** |
| 245 | 245 | * Converts instruct mode sequences to an array of stopping strings. |
| 246 | + * @param {Object} options | |
| 247 | + * @param {InstructSettings?} [options.customInstruct=null] - Custom instruct settings. | |
| 248 | + * @param {boolean?} [options.useStopStrings] - Decides whether to use "Chat Start" and "Example Separator" | |
| 246 | 249 | * @returns {string[]} Array of instruct mode stopping strings. |
| 247 | 250 | */ |
| 248 | -export function getInstructStoppingSequences() { | |
| 251 | +export function getInstructStoppingSequences({ customInstruct = null, useStopStrings = null } = {}) { | |
| 252 | + const instruct = structuredClone(customInstruct ?? power_user.instruct); | |
| 253 | + | |
| 249 | 254 | /** |
| 250 | 255 | * Adds instruct mode sequence to the result array. |
| 251 | 256 | * @param {string} sequence Sequence string. |
| @@ -254,7 +259,7 @@ export function getInstructStoppingSequences() { | ||
| 254 | 259 | function addInstructSequence(sequence) { |
| 255 | 260 | // Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string |
| 256 | 261 | // But it's a problem for Metharme which doesn't use newlines to separate them. |
| 257 | 262 | const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s; |
| 258 | 263 | // Sequence must be a non-empty string |
| 259 | 264 | if (typeof sequence === 'string' && sequence.length > 0) { |
| 260 | 265 | // If sequence is just a whitespace or newline - we don't want to make it a stopping string |
| @@ -262,7 +267,7 @@ export function getInstructStoppingSequences() { | ||
| 262 | 267 | if (sequence.trim().length > 0) { |
| 263 | 268 | const wrappedSequence = wrap(sequence); |
| 264 | 269 | // Need to respect "insert macro" setting |
| 265 | 270 | const stopString = power_user.instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence; |
| 266 | 271 | result.push(stopString); |
| 267 | 272 | } |
| 268 | 273 | } |
| @@ -270,14 +275,15 @@ export function getInstructStoppingSequences() { | ||
| 270 | 275 | |
| 271 | 276 | const result = []; |
| 272 | 277 | |
| 273 | - if (power_user.instruct.enabled) { | |
| 278 | + // Since preset's don't have "enabled", we assume it's always enabled | |
| 274 | - const stop_sequence = power_user.instruct.stop_sequence || ''; | |
| 279 | + if (customInstruct ?? instruct.enabled) { | |
| 275 | 280 | const input_sequencestop_sequence = power_user.instruct.input_sequence?.replace(/{{name}}/gi, name1)stop_sequence || ''; |
| 276 | 281 | const output_sequenceinput_sequence = power_user.instruct.output_sequenceinput_sequence?.replace(/{{name}}/gi, name2name1) || ''; |
| 277 | 282 | const first_output_sequenceoutput_sequence = power_user.instruct.first_output_sequenceoutput_sequence?.replace(/{{name}}/gi, name2) || ''; |
| 278 | 283 | const last_output_sequencefirst_output_sequence = power_user.instruct.last_output_sequencefirst_output_sequence?.replace(/{{name}}/gi, name2) || ''; |
| 279 | 284 | const system_sequencelast_output_sequence = power_user.instruct.system_sequencelast_output_sequence?.replace(/{{name}}/gi, 'System'name2) || ''; |
| 280 | 285 | const last_system_sequencesystem_sequence = power_user.instruct.last_system_sequencesystem_sequence?.replace(/{{name}}/gi, 'System') || ''; |
| 286 | + const last_system_sequence = instruct.last_system_sequence?.replace(/{{name}}/gi, 'System') || ''; | |
| 281 | 287 | |
| 282 | 288 | const combined_sequence = [ |
| 283 | 289 | stop_sequence, |
| @@ -292,7 +298,7 @@ export function getInstructStoppingSequences() { | ||
| 292 | 298 | combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence); |
| 293 | 299 | } |
| 294 | 300 | |
| 295 | 301 | if (useStopStrings ?? power_user.context.use_stop_strings) { |
| 296 | 302 | if (power_user.context.chat_start) { |
| 297 | 303 | result.push(`\n${substituteParams(power_user.context.chat_start)}`); |
| 298 | 304 | } |
| @@ -320,59 +326,61 @@ export const force_output_sequence = { | ||
| 320 | 326 | * @param {string} name1 User name. |
| 321 | 327 | * @param {string} name2 Character name. |
| 322 | 328 | * @param {boolean|number} forceOutputSequence Force to use first/last output sequence (if configured). |
| 329 | + * @param {InstructSettings} customInstruct Custom instruct mode settings. | |
| 323 | 330 | * @returns {string} Formatted instruct mode chat message. |
| 324 | 331 | */ |
| 325 | 332 | export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceOutputSequence, customInstruct = null) { |
| 326 | 333 | letconst includeNamesinstruct = isNarratorstructuredClone(customInstruct ? false :? power_user.instruct.names_behavior === names_behavior_types.ALWAYS); |
| 334 | + let includeNames = isNarrator ? false : instruct.names_behavior === names_behavior_types.ALWAYS; | |
| 327 | 335 | |
| 328 | 336 | if (!isNarrator && power_user.instruct.names_behavior === names_behavior_types.FORCE && ((selected_group && name !== name1) || (forceAvatar && name !== name1))) { |
| 329 | 337 | includeNames = true; |
| 330 | 338 | } |
| 331 | 339 | |
| 332 | 340 | function getPrefix() { |
| 333 | 341 | if (isNarrator) { |
| 334 | 342 | return power_user.instruct.system_same_as_user ? power_user.instruct.input_sequence : power_user.instruct.system_sequence; |
| 335 | 343 | } |
| 336 | 344 | |
| 337 | 345 | if (isUser) { |
| 338 | 346 | if (forceOutputSequence === force_output_sequence.FIRST) { |
| 339 | 347 | return power_user.instruct.first_input_sequence || power_user.instruct.input_sequence; |
| 340 | 348 | } |
| 341 | 349 | |
| 342 | 350 | if (forceOutputSequence === force_output_sequence.LAST) { |
| 343 | 351 | return power_user.instruct.last_input_sequence || power_user.instruct.input_sequence; |
| 344 | 352 | } |
| 345 | 353 | |
| 346 | 354 | return power_user.instruct.input_sequence; |
| 347 | 355 | } |
| 348 | 356 | |
| 349 | 357 | if (forceOutputSequence === force_output_sequence.FIRST) { |
| 350 | 358 | return power_user.instruct.first_output_sequence || power_user.instruct.output_sequence; |
| 351 | 359 | } |
| 352 | 360 | |
| 353 | 361 | if (forceOutputSequence === force_output_sequence.LAST) { |
| 354 | 362 | return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence; |
| 355 | 363 | } |
| 356 | 364 | |
| 357 | 365 | return power_user.instruct.output_sequence; |
| 358 | 366 | } |
| 359 | 367 | |
| 360 | 368 | function getSuffix() { |
| 361 | 369 | if (isNarrator) { |
| 362 | 370 | return power_user.instruct.system_same_as_user ? power_user.instruct.input_suffix : power_user.instruct.system_suffix; |
| 363 | 371 | } |
| 364 | 372 | |
| 365 | 373 | if (isUser) { |
| 366 | 374 | return power_user.instruct.input_suffix; |
| 367 | 375 | } |
| 368 | 376 | |
| 369 | 377 | return power_user.instruct.output_suffix; |
| 370 | 378 | } |
| 371 | 379 | |
| 372 | 380 | let prefix = getPrefix() || ''; |
| 373 | 381 | let suffix = getSuffix() || ''; |
| 374 | 382 | |
| 375 | 383 | if (power_user.instruct.macro) { |
| 376 | 384 | prefix = substituteParams(prefix, name1, name2); |
| 377 | 385 | prefix = prefix.replace(/{{name}}/gi, name || 'System'); |
| 378 | 386 | |
| @@ -380,11 +388,11 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata | ||
| 380 | 388 | suffix = suffix.replace(/{{name}}/gi, name || 'System'); |
| 381 | 389 | } |
| 382 | 390 | |
| 383 | 391 | if (!suffix && power_user.instruct.wrap) { |
| 384 | 392 | suffix = '\n'; |
| 385 | 393 | } |
| 386 | 394 | |
| 387 | 395 | const separator = power_user.instruct.wrap ? '\n' : ''; |
| 388 | 396 | |
| 389 | 397 | // Don't include the name if it's empty |
| 390 | 398 | const textArray = includeNames && name ? [prefix, `${name}: ${mes}` + suffix] : [prefix, mes + suffix]; |
| @@ -396,23 +404,26 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata | ||
| 396 | 404 | /** |
| 397 | 405 | * Formats instruct mode system prompt. |
| 398 | 406 | * @param {string} systemPrompt System prompt string. |
| 407 | + * @param {InstructSettings} customInstruct Custom instruct mode settings. | |
| 399 | 408 | * @returns {string} Formatted instruct mode system prompt. |
| 400 | 409 | */ |
| 401 | 410 | export function formatInstructModeSystemPrompt(systemPrompt, customInstruct = null) { |
| 402 | 411 | if (!systemPrompt) { |
| 403 | 412 | return ''; |
| 404 | 413 | } |
| 405 | 414 | |
| 406 | - const separator = power_user.instruct.wrap ? '\n' : ''; | |
| 415 | + const instruct = structuredClone(customInstruct ?? power_user.instruct); | |
| 416 | + | |
| 417 | + const separator = instruct.wrap ? '\n' : ''; | |
| 407 | 418 | |
| 408 | 419 | if (power_user.instruct.system_sequence_prefix) { |
| 409 | 420 | // TODO: Replace with a proper 'System' prompt entity name input |
| 410 | 421 | const prefix = power_user.instruct.system_sequence_prefix.replace(/{{name}}/gi, 'System'); |
| 411 | 422 | systemPrompt = prefix + separator + systemPrompt; |
| 412 | 423 | } |
| 413 | 424 | |
| 414 | 425 | if (power_user.instruct.system_sequence_suffix) { |
| 415 | 426 | systemPrompt = systemPrompt + separator + power_user.instruct.system_sequence_suffix; |
| 416 | 427 | } |
| 417 | 428 | |
| 418 | 429 | return systemPrompt; |
| @@ -504,30 +515,32 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) { | ||
| 504 | 515 | * @param {string} name2 Character name. |
| 505 | 516 | * @param {boolean} isQuiet Is quiet mode generation. |
| 506 | 517 | * @param {boolean} isQuietToLoud Is quiet to loud generation. |
| 518 | + * @param {InstructSettings} customInstruct Custom instruct settings. | |
| 507 | 519 | * @returns {string} Formatted instruct mode last prompt line. |
| 508 | 520 | */ |
| 509 | 521 | 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); | |
| 522 | + const instruct = structuredClone(customInstruct ?? power_user.instruct); | |
| 523 | + const includeNames = name && (instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && instruct.names_behavior === names_behavior_types.FORCE)) && !(isQuiet && !isQuietToLoud); | |
| 511 | 524 | |
| 512 | 525 | function getSequence() { |
| 513 | 526 | // User impersonation prompt |
| 514 | 527 | if (isImpersonate) { |
| 515 | 528 | return power_user.instruct.input_sequence; |
| 516 | 529 | } |
| 517 | 530 | |
| 518 | 531 | // Neutral / system / quiet prompt |
| 519 | 532 | // Use a special quiet instruct sequence if defined, or assistant's output sequence otherwise |
| 520 | 533 | if (isQuiet && !isQuietToLoud) { |
| 521 | 534 | return power_user.instruct.last_system_sequence || power_user.instruct.output_sequence; |
| 522 | 535 | } |
| 523 | 536 | |
| 524 | 537 | // Quiet in-character prompt |
| 525 | 538 | if (isQuiet && isQuietToLoud) { |
| 526 | 539 | return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence; |
| 527 | 540 | } |
| 528 | 541 | |
| 529 | 542 | // Default AI response |
| 530 | 543 | return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence; |
| 531 | 544 | } |
| 532 | 545 | |
| 533 | 546 | let sequence = getSequence() || ''; |
| @@ -536,21 +549,21 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, | ||
| 536 | 549 | // A hack for Mistral's formatting that has a normal output sequence ending with a space |
| 537 | 550 | if ( |
| 538 | 551 | includeNames && |
| 539 | 552 | power_user.instruct.last_output_sequence && |
| 540 | 553 | power_user.instruct.output_sequence && |
| 541 | 554 | sequence === power_user.instruct.last_output_sequence && |
| 542 | 555 | /\s$/.test(power_user.instruct.output_sequence) && |
| 543 | 556 | !/\s$/.test(power_user.instruct.last_output_sequence) |
| 544 | 557 | ) { |
| 545 | 558 | nameFiller = power_user.instruct.output_sequence.slice(-1); |
| 546 | 559 | } |
| 547 | 560 | |
| 548 | 561 | if (power_user.instruct.macro) { |
| 549 | 562 | sequence = substituteParams(sequence, name1, name2); |
| 550 | 563 | sequence = sequence.replace(/{{name}}/gi, name || 'System'); |
| 551 | 564 | } |
| 552 | 565 | |
| 553 | 566 | const separator = power_user.instruct.wrap ? '\n' : ''; |
| 554 | 567 | let text = includeNames ? (separator + sequence + separator + nameFiller + `${name}:`) : (separator + sequence); |
| 555 | 568 | |
| 556 | 569 | // Quiet prompt already has a newline at the end |
| @@ -562,7 +575,7 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, | ||
| 562 | 575 | text += (includeNames ? promptBias : (separator + promptBias.trimStart())); |
| 563 | 576 | } |
| 564 | 577 | |
| 565 | 578 | return (power_user.instruct.wrap ? text.trimEnd() : text) + (includeNames ? '' : separator); |
| 566 | 579 | } |
| 567 | 580 | |
| 568 | 581 | /** |
| @@ -180,13 +180,18 @@ function displayError(message) { | ||
| 180 | 180 | * Preserves the query string. |
| 181 | 181 | */ |
| 182 | 182 | function redirectToHome() { |
| 183 | 183 | // AfterCreate a loginURL theresobject nobased needon tothe preservecurrent thelocation |
| 184 | - // noauto (if present) | |
| 184 | + const currentUrl = new URL(window.location.href); | |
| 185 | - const urlParams = new URLSearchParams(window.location.search); | |
| 186 | 185 | |
| 187 | - urlParams.delete('noauto'); | |
| 186 | + // After a login there's no need to preserve the | |
| 187 | + // noauto parameter (if present) | |
| 188 | + currentUrl.searchParams.delete('noauto'); | |
| 188 | 189 | |
| 189 | - window.location.href = '/' + urlParams.toString(); | |
| 190 | + // Set the pathname to root and keep the updated query string | |
| 191 | + currentUrl.pathname = '/'; | |
| 192 | + | |
| 193 | + // Redirect to the new URL | |
| 194 | + window.location.href = currentUrl.toString(); | |
| 190 | 195 | } |
| 191 | 196 | |
| 192 | 197 | /** |
| @@ -368,7 +368,12 @@ function onToggleLogprobsPanel() { | ||
| 368 | 368 | function createSwipe(messageId, prompt) { |
| 369 | 369 | // need to call `cleanUpMessage` on our new prompt, because we were working |
| 370 | 370 | // with raw model output and our new prompt is missing trimming/macro replacements |
| 371 | 371 | const cleanedPrompt = cleanUpMessage(prompt, false, false, true);{ |
| 372 | + getMessage: prompt, | |
| 373 | + isImpersonate: false, | |
| 374 | + isContinue: false, | |
| 375 | + displayIncompleteSentences: true, | |
| 376 | + }); | |
| 372 | 377 | |
| 373 | 378 | const msg = chat[messageId]; |
| 374 | 379 | const newSwipeInfo = { |
| @@ -795,6 +795,7 @@ export function parseNovelAILogprobs(data) { | ||
| 795 | 795 | |
| 796 | 796 | // Add the chosen token to `merged` if it's not already there. This can |
| 797 | 797 | // happen if the chosen token was not among the top 10 most likely ones. |
| 798 | + // eslint-disable-next-line no-unused-vars | |
| 798 | 799 | const [[chosenId], [_, chosenAfter]] = data.chosen[0]; |
| 799 | 800 | if (!merged.some(([id]) => id === chosenId)) { |
| 800 | 801 | merged.push([chosenId, chosenAfter]); |
| @@ -15,12 +15,12 @@ import { | ||
| 15 | 15 | extension_prompt_types, |
| 16 | 16 | Generate, |
| 17 | 17 | getExtensionPrompt, |
| 18 | + getExtensionPromptMaxDepth, | |
| 18 | 19 | getNextMessageId, |
| 19 | 20 | getRequestHeaders, |
| 20 | 21 | getStoppingStrings, |
| 21 | 22 | is_send_press, |
| 22 | 23 | main_api, |
| 23 | - MAX_INJECTION_DEPTH, | |
| 24 | 24 | name1, |
| 25 | 25 | name2, |
| 26 | 26 | replaceItemizedPromptText, |
| @@ -75,6 +75,7 @@ import { Popup, POPUP_RESULT } from './popup.js'; | ||
| 75 | 75 | import { t } from './i18n.js'; |
| 76 | 76 | import { ToolManager } from './tool-calling.js'; |
| 77 | 77 | import { accountStorage } from './util/AccountStorage.js'; |
| 78 | +import { IGNORE_SYMBOL } from './constants.js'; | |
| 78 | 79 | |
| 79 | 80 | export { |
| 80 | 81 | openai_messages_count, |
| @@ -119,7 +120,6 @@ const default_bias_presets = { | ||
| 119 | 120 | const max_2k = 2047; |
| 120 | 121 | const max_4k = 4095; |
| 121 | 122 | const max_8k = 8191; |
| 122 | -const max_12k = 12287; | |
| 123 | 123 | const max_16k = 16383; |
| 124 | 124 | const max_32k = 32767; |
| 125 | 125 | const max_64k = 65535; |
| @@ -182,9 +182,9 @@ export const chat_completion_sources = { | ||
| 182 | 182 | PERPLEXITY: 'perplexity', |
| 183 | 183 | GROQ: 'groq', |
| 184 | 184 | ZEROONEAI: '01ai', |
| 185 | - BLOCKENTROPY: 'blockentropy', | |
| 186 | 185 | NANOGPT: 'nanogpt', |
| 187 | 186 | DEEPSEEK: 'deepseek', |
| 187 | + XAI: 'xai', | |
| 188 | 188 | }; |
| 189 | 189 | |
| 190 | 190 | const character_names_behavior = { |
| @@ -258,7 +258,7 @@ export const settingsToUpdate = { | ||
| 258 | 258 | nanogpt_model: ['#model_nanogpt_select', 'nanogpt_model', false], |
| 259 | 259 | deepseek_model: ['#model_deepseek_select', 'deepseek_model', false], |
| 260 | 260 | zerooneai_model: ['#model_01ai_select', 'zerooneai_model', false], |
| 261 | 261 | blockentropy_modelxai_model: ['#model_blockentropy_selectmodel_xai_select', 'blockentropy_modelxai_model', false], |
| 262 | 262 | custom_model: ['#custom_model_id', 'custom_model', false], |
| 263 | 263 | custom_url: ['#custom_api_url_text', 'custom_url', false], |
| 264 | 264 | custom_include_body: ['#custom_include_body', 'custom_include_body', false], |
| @@ -346,8 +346,8 @@ const default_settings = { | ||
| 346 | 346 | groq_model: 'llama-3.3-70b-versatile', |
| 347 | 347 | nanogpt_model: 'gpt-4o-mini', |
| 348 | 348 | zerooneai_model: 'yi-large', |
| 349 | - blockentropy_model: 'be-70b-base-llama3.1', | |
| 350 | 349 | deepseek_model: 'deepseek-chat', |
| 350 | + xai_model: 'grok-3-beta', | |
| 351 | 351 | custom_model: '', |
| 352 | 352 | custom_url: '', |
| 353 | 353 | custom_include_body: '', |
| @@ -427,8 +427,8 @@ const oai_settings = { | ||
| 427 | 427 | groq_model: 'llama-3.1-70b-versatile', |
| 428 | 428 | nanogpt_model: 'gpt-4o-mini', |
| 429 | 429 | zerooneai_model: 'yi-large', |
| 430 | - blockentropy_model: 'be-70b-base-llama3.1', | |
| 431 | 430 | deepseek_model: 'deepseek-chat', |
| 431 | + xai_model: 'grok-3-beta', | |
| 432 | 432 | custom_model: '', |
| 433 | 433 | custom_url: '', |
| 434 | 434 | custom_include_body: '', |
| @@ -527,6 +527,13 @@ function setOpenAIMessages(chat) { | ||
| 527 | 527 | let role = chat[j]['is_user'] ? 'user' : 'assistant'; |
| 528 | 528 | let content = chat[j]['mes']; |
| 529 | 529 | |
| 530 | + // If this symbol flag is set, completely ignore the message. | |
| 531 | + // This can be used to hide messages without affecting the number of messages in the chat. | |
| 532 | + if (chat[j].extra?.[IGNORE_SYMBOL]) { | |
| 533 | + j++; | |
| 534 | + continue; | |
| 535 | + } | |
| 536 | + | |
| 530 | 537 | // 100% legal way to send a message as system |
| 531 | 538 | if (chat[j].extra?.type === system_message_types.NARRATOR) { |
| 532 | 539 | role = 'system'; |
| @@ -705,16 +712,18 @@ export function parseExampleIntoIndividual(messageExampleString, appendNamesForG | ||
| 705 | 712 | return result; |
| 706 | 713 | } |
| 707 | 714 | |
| 708 | -function formatWorldInfo(value) { | |
| 715 | +export function formatWorldInfo(value, { wiFormat = null } = {}) { | |
| 709 | 716 | if (!value) { |
| 710 | 717 | return ''; |
| 711 | 718 | } |
| 712 | 719 | |
| 713 | - if (!oai_settings.wi_format.trim()) { | |
| 720 | + const format = wiFormat ?? oai_settings.wi_format; | |
| 721 | + | |
| 722 | + if (!format.trim()) { | |
| 714 | 723 | return value; |
| 715 | 724 | } |
| 716 | 725 | |
| 717 | 726 | return stringFormat(oai_settings.wi_formatformat, value); |
| 718 | 727 | } |
| 719 | 728 | |
| 720 | 729 | /** |
| @@ -733,7 +742,8 @@ async function populationInjectionPrompts(prompts, messages) { | ||
| 733 | 742 | 'assistant': extension_prompt_roles.ASSISTANT, |
| 734 | 743 | }; |
| 735 | 744 | |
| 736 | - for (let i = 0; i <= MAX_INJECTION_DEPTH; i++) { | |
| 745 | + const maxDepth = getExtensionPromptMaxDepth(); | |
| 746 | + for (let i = 0; i <= maxDepth; i++) { | |
| 737 | 747 | // Get prompts for current depth |
| 738 | 748 | const depthPrompts = prompts.filter(prompt => prompt.injection_depth === i && prompt.content); |
| 739 | 749 | |
| @@ -952,7 +962,7 @@ async function populateDialogueExamples(prompts, chatCompletion, messageExamples | ||
| 952 | 962 | * @param {number} position - Prompt position in the extensions object. |
| 953 | 963 | * @returns {string|false} - The prompt position for prompt collection. |
| 954 | 964 | */ |
| 955 | 965 | export function getPromptPosition(position) { |
| 956 | 966 | if (position == extension_prompt_types.BEFORE_PROMPT) { |
| 957 | 967 | return 'start'; |
| 958 | 968 | } |
| @@ -969,7 +979,7 @@ function getPromptPosition(position) { | ||
| 969 | 979 | * @param {number} role Role of the prompt. |
| 970 | 980 | * @returns {string} Mapped role. |
| 971 | 981 | */ |
| 972 | 982 | export function getPromptRole(role) { |
| 973 | 983 | switch (role) { |
| 974 | 984 | case extension_prompt_roles.SYSTEM: |
| 975 | 985 | return 'system'; |
| @@ -1402,9 +1412,9 @@ export async function prepareOpenAIMessages({ | ||
| 1402 | 1412 | await populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples }); |
| 1403 | 1413 | } catch (error) { |
| 1404 | 1414 | if (error instanceof TokenBudgetExceededError) { |
| 1405 | 1415 | toastr.error(t`An error occurred whileMandatory countingprompts tokens:exceed Tokenthe budgetcontext exceededsize.`); |
| 1406 | 1416 | chatCompletion.log('TokenMandatory budgetprompts exceededexceed the context size.'); |
| 1407 | 1417 | promptManager.error = t`Not enough free tokens for mandatory prompts. Raise your token Limitlimit or disable custom prompts.`; |
| 1408 | 1418 | } else if (error instanceof InvalidCharacterNameError) { |
| 1409 | 1419 | toastr.warning(t`An error occurred while counting tokens: Invalid character name`); |
| 1410 | 1420 | chatCompletion.log('Invalid character name'); |
| @@ -1442,8 +1452,10 @@ export async function prepareOpenAIMessages({ | ||
| 1442 | 1452 | * Handles errors during streaming requests. |
| 1443 | 1453 | * @param {Response} response |
| 1444 | 1454 | * @param {string} decoded - response text or decoded stream data |
| 1455 | + * @param {object} [options] | |
| 1456 | + * @param {boolean?} [options.quiet=false] Suppress toast messages | |
| 1445 | 1457 | */ |
| 1446 | 1458 | export function tryParseStreamingError(response, decoded, { quiet = false } = {}) { |
| 1447 | 1459 | try { |
| 1448 | 1460 | const data = JSON.parse(decoded); |
| 1449 | 1461 | |
| @@ -1451,19 +1463,19 @@ function tryParseStreamingError(response, decoded) { | ||
| 1451 | 1463 | return; |
| 1452 | 1464 | } |
| 1453 | 1465 | |
| 1454 | 1466 | checkQuotaError(data, { quiet }); |
| 1455 | 1467 | checkModerationError(data, { quiet }); |
| 1456 | 1468 | |
| 1457 | 1469 | // these do not throw correctly (equiv to Error("[object Object]")) |
| 1458 | 1470 | // if trying to fix "[object Object]" displayed to users, start here |
| 1459 | 1471 | |
| 1460 | 1472 | if (data.error) { |
| 1461 | 1473 | !quiet && toastr.error(data.error.message || response.statusText, 'Chat Completion API'); |
| 1462 | 1474 | throw new Error(data); |
| 1463 | 1475 | } |
| 1464 | 1476 | |
| 1465 | 1477 | if (data.message) { |
| 1466 | 1478 | !quiet && toastr.error(data.message, 'Chat Completion API'); |
| 1467 | 1479 | throw new Error(data); |
| 1468 | 1480 | } |
| 1469 | 1481 | } |
| @@ -1475,16 +1487,18 @@ function tryParseStreamingError(response, decoded) { | ||
| 1475 | 1487 | /** |
| 1476 | 1488 | * Checks if the response contains a quota error and displays a popup if it does. |
| 1477 | 1489 | * @param data |
| 1490 | + * @param {object} [options] | |
| 1491 | + * @param {boolean?} [options.quiet=false] Suppress toast messages | |
| 1478 | 1492 | * @returns {void} |
| 1479 | 1493 | * @throws {object} - response JSON |
| 1480 | 1494 | */ |
| 1481 | 1495 | function checkQuotaError(data, { quiet = false } = {}) { |
| 1482 | 1496 | if (!data) { |
| 1483 | 1497 | return; |
| 1484 | 1498 | } |
| 1485 | 1499 | |
| 1486 | 1500 | if (data.quota_error) { |
| 1487 | 1501 | !quiet && renderTemplateAsync('quotaError').then((html) => Popup.show.text('Quota Error', html)); |
| 1488 | 1502 | |
| 1489 | 1503 | // this does not throw correctly (equiv to Error("[object Object]")) |
| 1490 | 1504 | // if trying to fix "[object Object]" displayed to users, start here |
| @@ -1492,9 +1506,14 @@ function checkQuotaError(data) { | ||
| 1492 | 1506 | } |
| 1493 | 1507 | } |
| 1494 | 1508 | |
| 1495 | -function checkModerationError(data) { | |
| 1509 | +/** | |
| 1510 | + * @param {any} data | |
| 1511 | + * @param {object} [options] | |
| 1512 | + * @param {boolean?} [options.quiet=false] Suppress toast messages | |
| 1513 | + */ | |
| 1514 | +function checkModerationError(data, { quiet = false } = {}) { | |
| 1496 | 1515 | const moderationError = data?.error?.message?.includes('requires moderation'); |
| 1497 | 1516 | if (moderationError && !quiet) { |
| 1498 | 1517 | const moderationReason = `Reasons: ${data?.error?.metadata?.reasons?.join(', ') ?? '(N/A)'}`; |
| 1499 | 1518 | const flaggedText = data?.error?.metadata?.flagged_input ?? '(N/A)'; |
| 1500 | 1519 | toastr.info(flaggedText, moderationReason, { timeOut: 10000 }); |
| @@ -1626,12 +1645,12 @@ export function getChatCompletionModel(source = null) { | ||
| 1626 | 1645 | return oai_settings.groq_model; |
| 1627 | 1646 | case chat_completion_sources.ZEROONEAI: |
| 1628 | 1647 | return oai_settings.zerooneai_model; |
| 1629 | - case chat_completion_sources.BLOCKENTROPY: | |
| 1630 | - return oai_settings.blockentropy_model; | |
| 1631 | 1648 | case chat_completion_sources.NANOGPT: |
| 1632 | 1649 | return oai_settings.nanogpt_model; |
| 1633 | 1650 | case chat_completion_sources.DEEPSEEK: |
| 1634 | 1651 | return oai_settings.deepseek_model; |
| 1652 | + case chat_completion_sources.XAI: | |
| 1653 | + return oai_settings.xai_model; | |
| 1635 | 1654 | default: |
| 1636 | 1655 | throw new Error(`Unknown chat completion source: ${activeSource}`); |
| 1637 | 1656 | } |
| @@ -1675,6 +1694,11 @@ function calculateOpenRouterCost() { | ||
| 1675 | 1694 | } |
| 1676 | 1695 | } |
| 1677 | 1696 | |
| 1697 | + if (oai_settings.enable_web_search) { | |
| 1698 | + const webSearchCost = (0.02).toFixed(2); | |
| 1699 | + cost = t`${cost} + $${webSearchCost}`; | |
| 1700 | + } | |
| 1701 | + | |
| 1678 | 1702 | $('#openrouter_max_prompt_cost').text(cost); |
| 1679 | 1703 | } |
| 1680 | 1704 | |
| @@ -1746,23 +1770,6 @@ function saveModelList(data) { | ||
| 1746 | 1770 | $('#model_01ai_select').val(oai_settings.zerooneai_model).trigger('change'); |
| 1747 | 1771 | } |
| 1748 | 1772 | |
| 1749 | - if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) { | |
| 1750 | - $('#model_blockentropy_select').empty(); | |
| 1751 | - model_list.forEach((model) => { | |
| 1752 | - $('#model_blockentropy_select').append( | |
| 1753 | - $('<option>', { | |
| 1754 | - value: model.id, | |
| 1755 | - text: model.id, | |
| 1756 | - })); | |
| 1757 | - }); | |
| 1758 | - | |
| 1759 | - if (!oai_settings.blockentropy_model && model_list.length > 0) { | |
| 1760 | - oai_settings.blockentropy_model = model_list[0].id; | |
| 1761 | - } | |
| 1762 | - | |
| 1763 | - $('#model_blockentropy_select').val(oai_settings.blockentropy_model).trigger('change'); | |
| 1764 | - } | |
| 1765 | - | |
| 1766 | 1773 | if (oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI) { |
| 1767 | 1774 | /** @type {HTMLSelectElement} */ |
| 1768 | 1775 | const mistralModelSelect = document.querySelector('#model_mistralai_select'); |
| @@ -1966,13 +1973,14 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 1966 | 1973 | const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI; |
| 1967 | 1974 | const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT; |
| 1968 | 1975 | const isDeepSeek = oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK; |
| 1976 | + const isXAI = oai_settings.chat_completion_source == chat_completion_sources.XAI; | |
| 1969 | 1977 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); |
| 1970 | 1978 | const isQuiet = type === 'quiet'; |
| 1971 | 1979 | const isImpersonate = type === 'impersonate'; |
| 1972 | 1980 | const isContinue = type === 'continue'; |
| 1973 | 1981 | const stream = oai_settings.stream_openai && !isQuiet && !isScale && !(isOAI && ['o1-2024-12-17', 'o1'].includes(oai_settings.openai_model)); |
| 1974 | 1982 | const useLogprobs = !!power_user.request_token_probabilities; |
| 1975 | 1983 | const canMultiSwipe = oai_settings.n > 1 && !isContinue && !isImpersonate && !isQuiet && (isOAI || isCustom || isXAI); |
| 1976 | 1984 | |
| 1977 | 1985 | // If we're using the window.ai extension, use that instead |
| 1978 | 1986 | // Doesn't support logit bias yet |
| @@ -2018,6 +2026,7 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2018 | 2026 | 'reasoning_effort': String(oai_settings.reasoning_effort), |
| 2019 | 2027 | 'enable_web_search': Boolean(oai_settings.enable_web_search), |
| 2020 | 2028 | 'request_images': Boolean(oai_settings.request_images), |
| 2029 | + 'custom_prompt_post_processing': oai_settings.custom_prompt_post_processing, | |
| 2021 | 2030 | }; |
| 2022 | 2031 | |
| 2023 | 2032 | if (!canMultiSwipe && ToolManager.canPerformToolCalls(type)) { |
| @@ -2030,14 +2039,14 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2030 | 2039 | } |
| 2031 | 2040 | |
| 2032 | 2041 | // Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite |
| 2033 | 2042 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) { |
| 2034 | 2043 | await validateReverseProxy(); |
| 2035 | 2044 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; |
| 2036 | 2045 | generate_data['proxy_password'] = oai_settings.proxy_password; |
| 2037 | 2046 | } |
| 2038 | 2047 | |
| 2039 | 2048 | // Add logprobs request (currently OpenAI only, max 5 on their side) |
| 2040 | 2049 | if (useLogprobs && (isOAI || isCustom || isDeepSeek || isXAI)) { |
| 2041 | 2050 | generate_data['logprobs'] = 5; |
| 2042 | 2051 | } |
| 2043 | 2052 | |
| @@ -2048,7 +2057,7 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2048 | 2057 | delete generate_data.stop; |
| 2049 | 2058 | delete generate_data.logprobs; |
| 2050 | 2059 | } |
| 2051 | 2060 | if (isOAI && oai_settings.openai_model.includes('gpt-4.5-preview') || isOpenRouter && oai_settings.openrouter_model.includes('gpt-4.5-preview')) { |
| 2052 | 2061 | delete generate_data.logprobs; |
| 2053 | 2062 | } |
| 2054 | 2063 | |
| @@ -2098,7 +2107,6 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2098 | 2107 | generate_data['custom_include_body'] = oai_settings.custom_include_body; |
| 2099 | 2108 | generate_data['custom_exclude_body'] = oai_settings.custom_exclude_body; |
| 2100 | 2109 | generate_data['custom_include_headers'] = oai_settings.custom_include_headers; |
| 2101 | - generate_data['custom_prompt_post_processing'] = oai_settings.custom_prompt_post_processing; | |
| 2102 | 2110 | } |
| 2103 | 2111 | |
| 2104 | 2112 | if (isCohere) { |
| @@ -2157,29 +2165,42 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2157 | 2165 | } |
| 2158 | 2166 | } |
| 2159 | 2167 | |
| 2160 | - if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) { | |
| 2168 | + if (isXAI) { | |
| 2161 | - generate_data['seed'] = oai_settings.seed; | |
| 2169 | + if (generate_data.model.includes('grok-3-mini')) { | |
| 2170 | + delete generate_data.presence_penalty; | |
| 2171 | + delete generate_data.frequency_penalty; | |
| 2172 | + } | |
| 2173 | + if (generate_data.model.includes('grok-vision')) { | |
| 2174 | + delete generate_data.tools; | |
| 2175 | + delete generate_data.tool_choice; | |
| 2176 | + } | |
| 2162 | 2177 | } |
| 2163 | 2178 | |
| 2164 | - if (isOAI && (oai_settings.openai_model.startsWith('o1') || oai_settings.openai_model.startsWith('o3'))) { | |
| 2179 | + if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano || isXAI) && oai_settings.seed >= 0) { | |
| 2165 | - generate_data.messages.forEach((msg) => { | |
| 2180 | + generate_data['seed'] = oai_settings.seed; | |
| 2166 | - if (msg.role === 'system') { | |
| 2167 | - msg.role = 'user'; | |
| 2168 | 2181 | } |
| 2169 | - }); | |
| 2182 | + | |
| 2183 | + if (isOAI && /^(o1|o3|o4)/.test(oai_settings.openai_model)) { | |
| 2170 | 2184 | generate_data.max_completion_tokens = generate_data.max_tokens; |
| 2171 | 2185 | delete generate_data.max_tokens; |
| 2172 | 2186 | delete generate_data.logprobs; |
| 2173 | 2187 | delete generate_data.top_logprobs; |
| 2174 | 2188 | delete generate_data.nstop; |
| 2189 | + delete generate_data.logit_bias; | |
| 2175 | 2190 | delete generate_data.temperature; |
| 2176 | 2191 | delete generate_data.top_p; |
| 2177 | 2192 | delete generate_data.frequency_penalty; |
| 2178 | 2193 | delete generate_data.presence_penalty; |
| 2194 | + if (oai_settings.openai_model.startsWith('o1')) { | |
| 2195 | + generate_data.messages.forEach((msg) => { | |
| 2196 | + if (msg.role === 'system') { | |
| 2197 | + msg.role = 'user'; | |
| 2198 | + } | |
| 2199 | + }); | |
| 2200 | + delete generate_data.n; | |
| 2179 | 2201 | delete generate_data.tools; |
| 2180 | 2202 | delete generate_data.tool_choice; |
| 2181 | - delete generate_data.stop; | |
| 2203 | + } | |
| 2182 | - delete generate_data.logit_bias; | |
| 2183 | 2204 | } |
| 2184 | 2205 | |
| 2185 | 2206 | await eventSource.emit(event_types.CHAT_COMPLETION_SETTINGS_READY, generate_data); |
| @@ -2215,7 +2236,8 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2215 | 2236 | |
| 2216 | 2237 | if (Array.isArray(parsed?.choices) && parsed?.choices?.[0]?.index > 0) { |
| 2217 | 2238 | const swipeIndex = parsed.choices[0].index - 1; |
| 2218 | - swipes[swipeIndex] = (swipes[swipeIndex] || '') + getStreamingReply(parsed, state); | |
| 2239 | + // FIXME: state.reasoning should be an array to support multi-swipe | |
| 2240 | + swipes[swipeIndex] = (swipes[swipeIndex] || '') + getStreamingReply(parsed, state, { overrideShowThoughts: false }); | |
| 2219 | 2241 | } else { |
| 2220 | 2242 | text += getStreamingReply(parsed, state); |
| 2221 | 2243 | } |
| @@ -2253,37 +2275,48 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 2253 | 2275 | * Extracts the reply from the response data from a chat completions-like source |
| 2254 | 2276 | * @param {object} data Response data from the chat completions-like source |
| 2255 | 2277 | * @param {object} state Additional state to keep track of |
| 2278 | + * @param {object} [options] Additional options | |
| 2279 | + * @param {string?} [options.chatCompletionSource] Chat completion source | |
| 2280 | + * @param {boolean?} [options.overrideShowThoughts] Override show thoughts | |
| 2256 | 2281 | * @returns {string} The reply extracted from the response data |
| 2257 | 2282 | */ |
| 2258 | -function getStreamingReply(data, state) { | |
| 2283 | +export function getStreamingReply(data, state, { chatCompletionSource = null, overrideShowThoughts = null } = {}) { | |
| 2259 | - if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) { | |
| 2284 | + const chat_completion_source = chatCompletionSource ?? oai_settings.chat_completion_source; | |
| 2260 | - if (oai_settings.show_thoughts) { | |
| 2285 | + const show_thoughts = overrideShowThoughts ?? oai_settings.show_thoughts; | |
| 2286 | + | |
| 2287 | + if (chat_completion_source === chat_completion_sources.CLAUDE) { | |
| 2288 | + if (show_thoughts) { | |
| 2261 | 2289 | state.reasoning += data?.delta?.thinking || ''; |
| 2262 | 2290 | } |
| 2263 | 2291 | return data?.delta?.text || ''; |
| 2264 | 2292 | } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) { |
| 2265 | 2293 | const inlineData = data?.candidates?.[0]?.content?.parts?.find(x => x.inlineData)?.inlineData; |
| 2266 | 2294 | if (inlineData) { |
| 2267 | 2295 | state.image = `data:${inlineData.mimeType};base64,${inlineData.data}`; |
| 2268 | 2296 | } |
| 2269 | 2297 | if (oai_settings.show_thoughts) { |
| 2270 | 2298 | state.reasoning += (data?.candidates?.[0]?.content?.parts?.filter(x => x.thought)?.map(x => x.text)?.[0] || ''); |
| 2271 | 2299 | } |
| 2272 | 2300 | return data?.candidates?.[0]?.content?.parts?.filter(x => !x.thought)?.map(x => x.text)?.[0] || ''; |
| 2273 | 2301 | } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) { |
| 2274 | 2302 | return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || ''; |
| 2275 | 2303 | } else if (oai_settings.chat_completion_source === chat_completion_sources.DEEPSEEK) { |
| 2276 | 2304 | if (oai_settings.show_thoughts) { |
| 2305 | + state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || ''); | |
| 2306 | + } | |
| 2307 | + return data.choices?.[0]?.delta?.content || ''; | |
| 2308 | + } else if (chat_completion_source === chat_completion_sources.XAI) { | |
| 2309 | + if (show_thoughts) { | |
| 2277 | 2310 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content || ''); |
| 2278 | 2311 | } |
| 2279 | 2312 | return data.choices?.[0]?.delta?.content || ''; |
| 2280 | 2313 | } else if (oai_settings.chat_completion_source === chat_completion_sources.OPENROUTER) { |
| 2281 | 2314 | if (oai_settings.show_thoughts) { |
| 2282 | 2315 | state.reasoning += (data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning || ''); |
| 2283 | 2316 | } |
| 2284 | 2317 | return data.choices?.[0]?.delta?.content ?? data.choices?.[0]?.message?.content ?? data.choices?.[0]?.text ?? ''; |
| 2285 | 2318 | } else if (oai_settings.chat_completion_source === chat_completion_sources.CUSTOM) { |
| 2286 | 2319 | if (oai_settings.show_thoughts) { |
| 2287 | 2320 | state.reasoning += |
| 2288 | 2321 | data.choices?.filter(x => x?.delta?.reasoning_content)?.[0]?.delta?.reasoning_content ?? |
| 2289 | 2322 | data.choices?.filter(x => x?.delta?.reasoning)?.[0]?.delta?.reasoning ?? |
| @@ -2309,6 +2342,7 @@ function parseChatCompletionLogprobs(data) { | ||
| 2309 | 2342 | switch (oai_settings.chat_completion_source) { |
| 2310 | 2343 | case chat_completion_sources.OPENAI: |
| 2311 | 2344 | case chat_completion_sources.DEEPSEEK: |
| 2345 | + case chat_completion_sources.XAI: | |
| 2312 | 2346 | case chat_completion_sources.CUSTOM: |
| 2313 | 2347 | if (!data.choices?.length) { |
| 2314 | 2348 | return null; |
| @@ -3229,8 +3263,8 @@ function loadOpenAISettings(data, settings) { | ||
| 3229 | 3263 | oai_settings.groq_model = settings.groq_model ?? default_settings.groq_model; |
| 3230 | 3264 | oai_settings.nanogpt_model = settings.nanogpt_model ?? default_settings.nanogpt_model; |
| 3231 | 3265 | oai_settings.deepseek_model = settings.deepseek_model ?? default_settings.deepseek_model; |
| 3232 | - oai_settings.blockentropy_model = settings.blockentropy_model ?? default_settings.blockentropy_model; | |
| 3233 | 3266 | oai_settings.zerooneai_model = settings.zerooneai_model ?? default_settings.zerooneai_model; |
| 3267 | + oai_settings.xai_model = settings.xai_model ?? default_settings.xai_model; | |
| 3234 | 3268 | oai_settings.custom_model = settings.custom_model ?? default_settings.custom_model; |
| 3235 | 3269 | oai_settings.custom_url = settings.custom_url ?? default_settings.custom_url; |
| 3236 | 3270 | oai_settings.custom_include_body = settings.custom_include_body ?? default_settings.custom_include_body; |
| @@ -3316,7 +3350,8 @@ function loadOpenAISettings(data, settings) { | ||
| 3316 | 3350 | $('#model_deepseek_select').val(oai_settings.deepseek_model); |
| 3317 | 3351 | $(`#model_deepseek_select option[value="${oai_settings.deepseek_model}"`).prop('selected', true); |
| 3318 | 3352 | $('#model_01ai_select').val(oai_settings.zerooneai_model); |
| 3319 | 3353 | $('#model_blockentropy_selectmodel_xai_select').val(oai_settings.blockentropy_modelxai_model); |
| 3354 | + $(`#model_xai_select option[value="${oai_settings.xai_model}"`).attr('selected', true); | |
| 3320 | 3355 | $('#custom_model_id').val(oai_settings.custom_model); |
| 3321 | 3356 | $('#custom_api_url_text').val(oai_settings.custom_url); |
| 3322 | 3357 | $('#openai_max_context').val(oai_settings.openai_max_context); |
| @@ -3476,7 +3511,7 @@ async function getStatusOpen() { | ||
| 3476 | 3511 | let status; |
| 3477 | 3512 | |
| 3478 | 3513 | if ('ai' in window) { |
| 3479 | 3514 | status = 't`Valid'`; |
| 3480 | 3515 | } |
| 3481 | 3516 | else { |
| 3482 | 3517 | showWindowExtensionError(); |
| @@ -3513,7 +3548,7 @@ async function getStatusOpen() { | ||
| 3513 | 3548 | chat_completion_source: oai_settings.chat_completion_source, |
| 3514 | 3549 | }; |
| 3515 | 3550 | |
| 3516 | 3551 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK, chat_completion_sources.XAI].includes(oai_settings.chat_completion_source)) { |
| 3517 | 3552 | await validateReverseProxy(); |
| 3518 | 3553 | } |
| 3519 | 3554 | |
| @@ -3525,7 +3560,7 @@ async function getStatusOpen() { | ||
| 3525 | 3560 | |
| 3526 | 3561 | 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 | 3562 | if (canBypass) { |
| 3528 | 3563 | setOnlineStatus('t`Status check bypassed'`); |
| 3529 | 3564 | } |
| 3530 | 3565 | |
| 3531 | 3566 | try { |
| @@ -3547,7 +3582,7 @@ async function getStatusOpen() { | ||
| 3547 | 3582 | saveModelList(responseData.data); |
| 3548 | 3583 | } |
| 3549 | 3584 | if (!('error' in responseData)) { |
| 3550 | 3585 | setOnlineStatus('t`Valid'`); |
| 3551 | 3586 | } |
| 3552 | 3587 | } catch (error) { |
| 3553 | 3588 | console.error(error); |
| @@ -3596,7 +3631,6 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | ||
| 3596 | 3631 | perplexity_model: settings.perplexity_model, |
| 3597 | 3632 | groq_model: settings.groq_model, |
| 3598 | 3633 | zerooneai_model: settings.zerooneai_model, |
| 3599 | - blockentropy_model: settings.blockentropy_model, | |
| 3600 | 3634 | custom_model: settings.custom_model, |
| 3601 | 3635 | custom_url: settings.custom_url, |
| 3602 | 3636 | custom_include_body: settings.custom_include_body, |
| @@ -4094,9 +4128,15 @@ function getMaxContextOpenAI(value) { | ||
| 4094 | 4128 | if (oai_settings.max_context_unlocked) { |
| 4095 | 4129 | return unlocked_max; |
| 4096 | 4130 | } |
| 4097 | 4131 | else if (value.startsWithincludes('o1') || valuegpt-4.startsWith('o31')) { |
| 4132 | + return max_1mil; | |
| 4133 | + } | |
| 4134 | + else if (value.startsWith('o1')) { | |
| 4098 | 4135 | return max_128k; |
| 4099 | 4136 | } |
| 4137 | + else if (value.startsWith('o4') || value.startsWith('o3')) { | |
| 4138 | + return max_200k; | |
| 4139 | + } | |
| 4100 | 4140 | else if (value.includes('chatgpt-4o-latest') || value.includes('gpt-4-turbo') || value.includes('gpt-4o') || value.includes('gpt-4-1106') || value.includes('gpt-4-0125') || value.includes('gpt-4-vision')) { |
| 4101 | 4141 | return max_128k; |
| 4102 | 4142 | } |
| @@ -4168,6 +4208,80 @@ function getMaxContextWindowAI(value) { | ||
| 4168 | 4208 | } |
| 4169 | 4209 | |
| 4170 | 4210 | /** |
| 4211 | + * Get the maximum context size for the Mistral model | |
| 4212 | + * @param {string} model Model identifier | |
| 4213 | + * @param {boolean} isUnlocked Whether context limits are unlocked | |
| 4214 | + * @returns {number} Maximum context size in tokens | |
| 4215 | + */ | |
| 4216 | +function getMistralMaxContext(model, isUnlocked) { | |
| 4217 | + if (isUnlocked) { | |
| 4218 | + return unlocked_max; | |
| 4219 | + } | |
| 4220 | + | |
| 4221 | + if (Array.isArray(model_list) && model_list.length > 0) { | |
| 4222 | + const contextLength = model_list.find((record) => record.id === model)?.max_context_length; | |
| 4223 | + if (contextLength) { | |
| 4224 | + return contextLength; | |
| 4225 | + } | |
| 4226 | + } | |
| 4227 | + | |
| 4228 | + const contextMap = { | |
| 4229 | + 'codestral-2411-rc5': 262144, | |
| 4230 | + 'codestral-2412': 262144, | |
| 4231 | + 'codestral-2501': 262144, | |
| 4232 | + 'codestral-latest': 262144, | |
| 4233 | + 'codestral-mamba-2407': 262144, | |
| 4234 | + 'codestral-mamba-latest': 262144, | |
| 4235 | + 'open-codestral-mamba': 262144, | |
| 4236 | + 'ministral-3b-2410': 131072, | |
| 4237 | + 'ministral-3b-latest': 131072, | |
| 4238 | + 'ministral-8b-2410': 131072, | |
| 4239 | + 'ministral-8b-latest': 131072, | |
| 4240 | + 'mistral-large-2407': 131072, | |
| 4241 | + 'mistral-large-2411': 131072, | |
| 4242 | + 'mistral-large-latest': 131072, | |
| 4243 | + 'mistral-large-pixtral-2411': 131072, | |
| 4244 | + 'mistral-tiny-2407': 131072, | |
| 4245 | + 'mistral-tiny-latest': 131072, | |
| 4246 | + 'open-mistral-nemo': 131072, | |
| 4247 | + 'open-mistral-nemo-2407': 131072, | |
| 4248 | + 'pixtral-12b': 131072, | |
| 4249 | + 'pixtral-12b-2409': 131072, | |
| 4250 | + 'pixtral-12b-latest': 131072, | |
| 4251 | + 'pixtral-large-2411': 131072, | |
| 4252 | + 'pixtral-large-latest': 131072, | |
| 4253 | + 'open-mixtral-8x22b': 65536, | |
| 4254 | + 'open-mixtral-8x22b-2404': 65536, | |
| 4255 | + 'codestral-2405': 32768, | |
| 4256 | + 'mistral-embed': 32768, | |
| 4257 | + 'mistral-large-2402': 32768, | |
| 4258 | + 'mistral-medium': 32768, | |
| 4259 | + 'mistral-medium-2312': 32768, | |
| 4260 | + 'mistral-medium-latest': 32768, | |
| 4261 | + 'mistral-moderation-2411': 32768, | |
| 4262 | + 'mistral-moderation-latest': 32768, | |
| 4263 | + 'mistral-ocr-2503': 32768, | |
| 4264 | + 'mistral-ocr-latest': 32768, | |
| 4265 | + 'mistral-saba-2502': 32768, | |
| 4266 | + 'mistral-saba-latest': 32768, | |
| 4267 | + 'mistral-small': 32768, | |
| 4268 | + 'mistral-small-2312': 32768, | |
| 4269 | + 'mistral-small-2402': 32768, | |
| 4270 | + 'mistral-small-2409': 32768, | |
| 4271 | + 'mistral-small-2501': 32768, | |
| 4272 | + 'mistral-small-2503': 32768, | |
| 4273 | + 'mistral-small-latest': 32768, | |
| 4274 | + 'mistral-tiny': 32768, | |
| 4275 | + 'mistral-tiny-2312': 32768, | |
| 4276 | + 'open-mistral-7b': 32768, | |
| 4277 | + 'open-mixtral-8x7b': 32768, | |
| 4278 | + }; | |
| 4279 | + | |
| 4280 | + // Return context size if model found, otherwise default to 32k | |
| 4281 | + return Object.entries(contextMap).find(([key]) => model.includes(key))?.[1] || 32768; | |
| 4282 | +} | |
| 4283 | + | |
| 4284 | +/** | |
| 4171 | 4285 | * Get the maximum context size for the Groq model |
| 4172 | 4286 | * @param {string} model Model identifier |
| 4173 | 4287 | * @param {boolean} isUnlocked Whether context limits are unlocked |
| @@ -4195,6 +4309,9 @@ function getGroqMaxContext(model, isUnlocked) { | ||
| 4195 | 4309 | 'qwen-2.5-32b': max_128k, |
| 4196 | 4310 | 'deepseek-r1-distill-qwen-32b': max_128k, |
| 4197 | 4311 | 'deepseek-r1-distill-llama-70b-specdec': max_128k, |
| 4312 | + 'mistral-saba-24b': max_32k, | |
| 4313 | + 'meta-llama/llama-4-scout-17b-16e-instruct': max_128k, | |
| 4314 | + 'meta-llama/llama-4-maverick-17b-128e-instruct': max_128k, | |
| 4198 | 4315 | }; |
| 4199 | 4316 | |
| 4200 | 4317 | // Return context size if model found, otherwise default to 128k |
| @@ -4305,18 +4422,17 @@ async function onModelChange() { | ||
| 4305 | 4422 | oai_settings.zerooneai_model = value; |
| 4306 | 4423 | } |
| 4307 | 4424 | |
| 4308 | - if (value && $(this).is('#model_blockentropy_select')) { | |
| 4309 | - console.log('Block Entropy model changed to', value); | |
| 4310 | - oai_settings.blockentropy_model = value; | |
| 4311 | - $('#blockentropy_model_id').val(value).trigger('input'); | |
| 4312 | - } | |
| 4313 | - | |
| 4314 | 4425 | if (value && $(this).is('#model_custom_select')) { |
| 4315 | 4426 | console.log('Custom model changed to', value); |
| 4316 | 4427 | oai_settings.custom_model = value; |
| 4317 | 4428 | $('#custom_model_id').val(value).trigger('input'); |
| 4318 | 4429 | } |
| 4319 | 4430 | |
| 4431 | + if ($(this).is('#model_xai_select')) { | |
| 4432 | + console.log('XAI model changed to', value); | |
| 4433 | + oai_settings.xai_model = value; | |
| 4434 | + } | |
| 4435 | + | |
| 4320 | 4436 | if (oai_settings.chat_completion_source == chat_completion_sources.SCALE) { |
| 4321 | 4437 | if (oai_settings.max_context_unlocked) { |
| 4322 | 4438 | $('#openai_max_context').attr('max', unlocked_max); |
| @@ -4335,7 +4451,7 @@ async function onModelChange() { | ||
| 4335 | 4451 | $('#openai_max_context').attr('max', max_32k); |
| 4336 | 4452 | } else if (value.includes('gemini-1.5-pro') || value.includes('gemini-exp-1206') || value.includes('gemini-2.0-pro')) { |
| 4337 | 4453 | $('#openai_max_context').attr('max', max_2mil); |
| 4338 | 4454 | } else if (value.includes('gemini-1.5-flash') || value.includes('gemini-2.0-flash') || value.includes('gemini-2.5-flash-preview-04-17') || value.includes('gemini-2.5-pro-exp-03-25') || value.includes('gemini-2.5-pro-preview-03-25')) { |
| 4339 | 4455 | $('#openai_max_context').attr('max', max_1mil); |
| 4340 | 4456 | } else if (value.includes('gemini-1.0-pro') || value === 'gemini-pro') { |
| 4341 | 4457 | $('#openai_max_context').attr('max', max_32k); |
| @@ -4433,27 +4549,10 @@ async function onModelChange() { | ||
| 4433 | 4549 | } |
| 4434 | 4550 | |
| 4435 | 4551 | if (oai_settings.chat_completion_source === chat_completion_sources.MISTRALAI) { |
| 4436 | - if (oai_settings.max_context_unlocked) { | |
| 4552 | + const maxContext = getMistralMaxContext(oai_settings.mistralai_model, oai_settings.max_context_unlocked); | |
| 4437 | 4553 | $('#openai_max_context').attr('max', unlocked_maxmaxContext); |
| 4438 | - } else if (oai_settings.mistralai_model.includes('codestral-mamba')) { | |
| 4439 | - $('#openai_max_context').attr('max', max_256k); | |
| 4440 | - } else if (['mistral-large-2407', 'mistral-large-2411', 'mistral-large-latest'].includes(oai_settings.mistralai_model)) { | |
| 4441 | - $('#openai_max_context').attr('max', max_128k); | |
| 4442 | - } else if (oai_settings.mistralai_model.includes('mistral-nemo')) { | |
| 4443 | - $('#openai_max_context').attr('max', max_128k); | |
| 4444 | - } else if (oai_settings.mistralai_model.includes('mixtral-8x22b')) { | |
| 4445 | - $('#openai_max_context').attr('max', max_64k); | |
| 4446 | - } else if (oai_settings.mistralai_model.includes('pixtral')) { | |
| 4447 | - $('#openai_max_context').attr('max', max_128k); | |
| 4448 | - } else if (oai_settings.mistralai_model.includes('ministral')) { | |
| 4449 | - $('#openai_max_context').attr('max', max_32k); | |
| 4450 | - } else { | |
| 4451 | - $('#openai_max_context').attr('max', max_32k); | |
| 4452 | - } | |
| 4453 | 4554 | oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max'))); |
| 4454 | 4555 | $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); |
| 4455 | - | |
| 4456 | - //mistral also caps temp at 1.0 | |
| 4457 | 4556 | oai_settings.temp_openai = Math.min(claude_max_temp, oai_settings.temp_openai); |
| 4458 | 4557 | $('#temp_openai').attr('max', claude_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4459 | 4558 | } |
| @@ -4560,29 +4659,6 @@ async function onModelChange() { | ||
| 4560 | 4659 | oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai); |
| 4561 | 4660 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4562 | 4661 | } |
| 4563 | - if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) { | |
| 4564 | - if (oai_settings.max_context_unlocked) { | |
| 4565 | - $('#openai_max_context').attr('max', unlocked_max); | |
| 4566 | - } | |
| 4567 | - else if (oai_settings.blockentropy_model.includes('llama3.1')) { | |
| 4568 | - $('#openai_max_context').attr('max', max_16k); | |
| 4569 | - } | |
| 4570 | - else if (oai_settings.blockentropy_model.includes('72b')) { | |
| 4571 | - $('#openai_max_context').attr('max', max_16k); | |
| 4572 | - } | |
| 4573 | - else if (oai_settings.blockentropy_model.includes('120b')) { | |
| 4574 | - $('#openai_max_context').attr('max', max_12k); | |
| 4575 | - } | |
| 4576 | - else { | |
| 4577 | - $('#openai_max_context').attr('max', max_8k); | |
| 4578 | - } | |
| 4579 | - | |
| 4580 | - oai_settings.openai_max_context = Math.min(oai_settings.openai_max_context, Number($('#openai_max_context').attr('max'))); | |
| 4581 | - $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | |
| 4582 | - | |
| 4583 | - oai_settings.temp_openai = Math.min(oai_max_temp, oai_settings.temp_openai); | |
| 4584 | - $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | |
| 4585 | - } | |
| 4586 | 4662 | |
| 4587 | 4663 | if (oai_settings.chat_completion_source === chat_completion_sources.NANOGPT) { |
| 4588 | 4664 | if (oai_settings.max_context_unlocked) { |
| @@ -4612,6 +4688,22 @@ async function onModelChange() { | ||
| 4612 | 4688 | $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); |
| 4613 | 4689 | } |
| 4614 | 4690 | |
| 4691 | + if (oai_settings.chat_completion_source === chat_completion_sources.XAI) { | |
| 4692 | + if (oai_settings.max_context_unlocked) { | |
| 4693 | + $('#openai_max_context').attr('max', unlocked_max); | |
| 4694 | + } else if (oai_settings.xai_model.includes('grok-2-vision')) { | |
| 4695 | + $('#openai_max_context').attr('max', max_32k); | |
| 4696 | + } else if (oai_settings.xai_model.includes('grok-vision')) { | |
| 4697 | + $('#openai_max_context').attr('max', max_8k); | |
| 4698 | + } else { | |
| 4699 | + $('#openai_max_context').attr('max', max_128k); | |
| 4700 | + } | |
| 4701 | + | |
| 4702 | + oai_settings.openai_max_context = Math.min(Number($('#openai_max_context').attr('max')), oai_settings.openai_max_context); | |
| 4703 | + $('#openai_max_context').val(oai_settings.openai_max_context).trigger('input'); | |
| 4704 | + $('#temp_openai').attr('max', oai_max_temp).val(oai_settings.temp_openai).trigger('input'); | |
| 4705 | + } | |
| 4706 | + | |
| 4615 | 4707 | if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) { |
| 4616 | 4708 | oai_settings.pres_pen_openai = Math.min(Math.max(0, oai_settings.pres_pen_openai), 1); |
| 4617 | 4709 | $('#pres_pen_openai').attr('max', 1).attr('min', 0).val(oai_settings.pres_pen_openai).trigger('input'); |
| @@ -4849,15 +4941,16 @@ async function onConnectButtonClick(e) { | ||
| 4849 | 4941 | return; |
| 4850 | 4942 | } |
| 4851 | 4943 | } |
| 4852 | - if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) { | |
| 4853 | - const api_key_blockentropy = String($('#api_key_blockentropy').val()).trim(); | |
| 4854 | 4944 | |
| 4855 | 4945 | if (api_key_blockentropyoai_settings.lengthchat_completion_source === chat_completion_sources.XAI) { |
| 4856 | - await writeSecret(SECRET_KEYS.BLOCKENTROPY, api_key_blockentropy); | |
| 4946 | + const api_key_xai = String($('#api_key_xai').val()).trim(); | |
| 4947 | + | |
| 4948 | + if (api_key_xai.length) { | |
| 4949 | + await writeSecret(SECRET_KEYS.XAI, api_key_xai); | |
| 4857 | 4950 | } |
| 4858 | 4951 | |
| 4859 | 4952 | if (!secret_state[SECRET_KEYS.BLOCKENTROPYXAI] && !oai_settings.reverse_proxy) { |
| 4860 | 4953 | console.log('No secret key saved for Block EntropyXAI'); |
| 4861 | 4954 | return; |
| 4862 | 4955 | } |
| 4863 | 4956 | } |
| @@ -4915,12 +5008,12 @@ function toggleChatCompletionForms() { | ||
| 4915 | 5008 | else if (oai_settings.chat_completion_source == chat_completion_sources.CUSTOM) { |
| 4916 | 5009 | $('#model_custom_select').trigger('change'); |
| 4917 | 5010 | } |
| 4918 | - else if (oai_settings.chat_completion_source == chat_completion_sources.BLOCKENTROPY) { | |
| 4919 | - $('#model_blockentropy_select').trigger('change'); | |
| 4920 | - } | |
| 4921 | 5011 | else if (oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK) { |
| 4922 | 5012 | $('#model_deepseek_select').trigger('change'); |
| 4923 | 5013 | } |
| 5014 | + else if (oai_settings.chat_completion_source == chat_completion_sources.XAI) { | |
| 5015 | + $('#model_xai_select').trigger('change'); | |
| 5016 | + } | |
| 4924 | 5017 | $('[data-source]').each(function () { |
| 4925 | 5018 | const validSources = $(this).data('source').split(','); |
| 4926 | 5019 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); |
| @@ -5006,8 +5099,11 @@ export function isImageInliningSupported() { | ||
| 5006 | 5099 | // gultra just isn't being offered as multimodal, thanks google. |
| 5007 | 5100 | const visionSupportedModels = [ |
| 5008 | 5101 | 'gpt-4-vision', |
| 5102 | + 'gemini-2.5-pro-exp-03-25', | |
| 5103 | + 'gemini-2.5-pro-preview-03-25', | |
| 5009 | 5104 | 'gemini-2.0-pro-exp', |
| 5010 | 5105 | 'gemini-2.0-pro-exp-02-05', |
| 5106 | + 'gemini-2.5-flash-preview-04-17', | |
| 5011 | 5107 | 'gemini-2.0-flash-lite-preview', |
| 5012 | 5108 | 'gemini-2.0-flash-lite-preview-02-05', |
| 5013 | 5109 | 'gemini-2.0-flash', |
| @@ -5047,7 +5143,9 @@ export function isImageInliningSupported() { | ||
| 5047 | 5143 | 'o1-2024-12-17', |
| 5048 | 5144 | 'chatgpt-4o-latest', |
| 5049 | 5145 | 'yi-vision', |
| 5050 | 5146 | 'mistral-large-pixtral-latest2411', |
| 5147 | + 'mistral-small-2503', | |
| 5148 | + 'mistral-small-latest', | |
| 5051 | 5149 | 'pixtral-12b-latest', |
| 5052 | 5150 | 'pixtral-12b', |
| 5053 | 5151 | 'pixtral-12b-2409', |
| @@ -5055,11 +5153,18 @@ export function isImageInliningSupported() { | ||
| 5055 | 5153 | 'pixtral-large-2411', |
| 5056 | 5154 | 'c4ai-aya-vision-8b', |
| 5057 | 5155 | 'c4ai-aya-vision-32b', |
| 5156 | + 'grok-2-vision', | |
| 5157 | + 'grok-vision', | |
| 5158 | + 'gpt-4.1', | |
| 5159 | + 'o3', | |
| 5160 | + 'o3-2025-04-16', | |
| 5161 | + 'o4-mini', | |
| 5162 | + 'o4-mini-2025-04-16', | |
| 5058 | 5163 | ]; |
| 5059 | 5164 | |
| 5060 | 5165 | switch (oai_settings.chat_completion_source) { |
| 5061 | 5166 | case chat_completion_sources.OPENAI: |
| 5062 | 5167 | return visionSupportedModels.some(model => oai_settings.openai_model.includes(model) && !oai_settings.openai_model.includes('gpt-4-turbo-preview') && !oai_settings.openai_model.includes('o3-mini')); |
| 5063 | 5168 | case chat_completion_sources.MAKERSUITE: |
| 5064 | 5169 | return visionSupportedModels.some(model => oai_settings.google_model.includes(model)); |
| 5065 | 5170 | case chat_completion_sources.CLAUDE: |
| @@ -5074,6 +5179,8 @@ export function isImageInliningSupported() { | ||
| 5074 | 5179 | return visionSupportedModels.some(model => oai_settings.mistralai_model.includes(model)); |
| 5075 | 5180 | case chat_completion_sources.COHERE: |
| 5076 | 5181 | return visionSupportedModels.some(model => oai_settings.cohere_model.includes(model)); |
| 5182 | + case chat_completion_sources.XAI: | |
| 5183 | + return visionSupportedModels.some(model => oai_settings.xai_model.includes(model)); | |
| 5077 | 5184 | default: |
| 5078 | 5185 | return false; |
| 5079 | 5186 | } |
| @@ -5614,6 +5721,7 @@ export function initOpenAI() { | ||
| 5614 | 5721 | |
| 5615 | 5722 | $('#openai_enable_web_search').on('input', function () { |
| 5616 | 5723 | oai_settings.enable_web_search = !!$(this).prop('checked'); |
| 5724 | + calculateOpenRouterCost(); | |
| 5617 | 5725 | saveSettingsDebounced(); |
| 5618 | 5726 | }); |
| 5619 | 5727 | |
| @@ -5669,8 +5777,8 @@ export function initOpenAI() { | ||
| 5669 | 5777 | $('#model_nanogpt_select').on('change', onModelChange); |
| 5670 | 5778 | $('#model_deepseek_select').on('change', onModelChange); |
| 5671 | 5779 | $('#model_01ai_select').on('change', onModelChange); |
| 5672 | - $('#model_blockentropy_select').on('change', onModelChange); | |
| 5673 | 5780 | $('#model_custom_select').on('change', onModelChange); |
| 5781 | + $('#model_xai_select').on('change', onModelChange); | |
| 5674 | 5782 | $('#settings_preset_openai').on('change', onSettingsPresetChange); |
| 5675 | 5783 | $('#new_oai_preset').on('click', onNewPresetClick); |
| 5676 | 5784 | $('#delete_oai_preset').on('click', onDeletePresetClick); |
| @@ -111,6 +111,7 @@ export function setUserAvatar(imgfile, { toastPersonaNameChange = true, navigate | ||
| 111 | 111 | reloadUserAvatar(); |
| 112 | 112 | updatePersonaUIStates({ navigateToCurrent: navigateToCurrent }); |
| 113 | 113 | selectCurrentPersona({ toastPersonaNameChange: toastPersonaNameChange }); |
| 114 | + retriggerFirstMessageOnEmptyChat(); | |
| 114 | 115 | saveSettingsDebounced(); |
| 115 | 116 | $('.zoomed_avatar[forchar]').remove(); |
| 116 | 117 | } |
| @@ -465,7 +466,7 @@ export function initPersona(avatarId, personaName, personaDescription) { | ||
| 465 | 466 | * @returns {Promise<boolean>} A promise that resolves to true if the character was converted, false otherwise. |
| 466 | 467 | */ |
| 467 | 468 | export async function convertCharacterToPersona(characterId = null) { |
| 468 | 469 | if (null === characterId) characterId = Number(this_chid); |
| 469 | 470 | |
| 470 | 471 | const avatarUrl = characters[characterId]?.avatar; |
| 471 | 472 | if (!avatarUrl) { |
| @@ -800,7 +801,7 @@ async function selectCurrentPersona({ toastPersonaNameChange = true } = {}) { | ||
| 800 | 801 | chat_metadata['persona'] = user_avatar; |
| 801 | 802 | console.log(`Auto locked persona to ${user_avatar}`); |
| 802 | 803 | if (toastPersonaNameChange && power_user.persona_show_notifications) { |
| 803 | 804 | toastr.success(t`Persona ${personaName} selected and auto-locked to current chat`, t`Persona Selected`); |
| 804 | 805 | } |
| 805 | 806 | saveMetadataDebounced(); |
| 806 | 807 | updatePersonaUIStates(); |
| @@ -1243,7 +1244,7 @@ function getPersonaStates(avatarId) { | ||
| 1243 | 1244 | /** @type {PersonaConnection[]} */ |
| 1244 | 1245 | const connections = power_user.persona_descriptions[avatarId]?.connections; |
| 1245 | 1246 | const hasCharLock = !!connections?.some(c => |
| 1246 | 1247 | (!selected_group && c.type === 'character' && c.id === characters[Number(this_chid)]?.avatar) |
| 1247 | 1248 | || (selected_group && c.type === 'group' && c.id === selected_group)); |
| 1248 | 1249 | |
| 1249 | 1250 | return { |
| @@ -1481,7 +1482,7 @@ async function loadPersonaForCurrentChat({ doRender = false } = {}) { | ||
| 1481 | 1482 | * @returns {string[]} - An array of persona keys that are connected to the given character key |
| 1482 | 1483 | */ |
| 1483 | 1484 | export function getConnectedPersonas(characterKey = undefined) { |
| 1484 | 1485 | characterKey ??= selected_group || characters[Number(this_chid)]?.avatar; |
| 1485 | 1486 | const connectedPersonas = Object.entries(power_user.persona_descriptions) |
| 1486 | 1487 | .filter(([_, desc]) => desc.connections?.some(conn => conn.type === 'character' && conn.id === characterKey)) |
| 1487 | 1488 | .map(([key, _]) => key); |
| @@ -1513,7 +1514,7 @@ export async function showCharConnections() { | ||
| 1513 | 1514 | console.log(`Unlocking persona ${personaId} from current character ${name2}`); |
| 1514 | 1515 | power_user.persona_descriptions[personaId].connections = connections.filter(c => { |
| 1515 | 1516 | if (menu_type == 'group_edit' && c.type == 'group' && c.id == selected_group) return false; |
| 1516 | 1517 | else if (c.type == 'character' && c.id == characters[Number(this_chid)]?.avatar) return false; |
| 1517 | 1518 | return true; |
| 1518 | 1519 | }); |
| 1519 | 1520 | saveSettingsDebounced(); |
| @@ -1545,8 +1546,8 @@ export async function showCharConnections() { | ||
| 1545 | 1546 | export function getCurrentConnectionObj() { |
| 1546 | 1547 | if (selected_group) |
| 1547 | 1548 | return { type: 'group', id: selected_group }; |
| 1548 | 1549 | if (characters[Number(this_chid)]?.avatar) |
| 1549 | 1550 | return { type: 'character', id: characters[Number(this_chid)]?.avatar }; |
| 1550 | 1551 | return null; |
| 1551 | 1552 | } |
| 1552 | 1553 | |
| @@ -1664,7 +1665,7 @@ async function syncUserNameToPersona() { | ||
| 1664 | 1665 | * Only works if only the first message is present, and not in group mode. |
| 1665 | 1666 | */ |
| 1666 | 1667 | export function retriggerFirstMessageOnEmptyChat() { |
| 1667 | 1668 | if (Number(this_chid) >= 0 && !selected_group && chat.length === 1) { |
| 1668 | 1669 | $('#firstmessage_textarea').trigger('input'); |
| 1669 | 1670 | } |
| 1670 | 1671 | } |
| @@ -1782,7 +1783,6 @@ function setNameCallback({ mode = 'all' }, name) { | ||
| 1782 | 1783 | if (!persona) persona = Object.entries(power_user.personas).find(([_, personaName]) => personaName.toLowerCase() === name.toLowerCase())?.[1]; |
| 1783 | 1784 | if (persona) { |
| 1784 | 1785 | autoSelectPersona(persona); |
| 1785 | - retriggerFirstMessageOnEmptyChat(); | |
| 1786 | 1786 | return ''; |
| 1787 | 1787 | } else if (mode === 'lookup') { |
| 1788 | 1788 | toastr.warning(`Persona ${name} not found`); |
| @@ -1793,7 +1793,6 @@ function setNameCallback({ mode = 'all' }, name) { | ||
| 1793 | 1793 | if (['temp', 'all'].includes(mode)) { |
| 1794 | 1794 | // Otherwise, set just the name |
| 1795 | 1795 | setUserName(name); //this prevented quickReply usage |
| 1796 | - retriggerFirstMessageOnEmptyChat(); | |
| 1797 | 1796 | } |
| 1798 | 1797 | |
| 1799 | 1798 | return ''; |
| @@ -1944,9 +1943,6 @@ export async function initPersonas() { | ||
| 1944 | 1943 | $(document).on('click', '#user_avatar_block .avatar-container', function () { |
| 1945 | 1944 | const imgfile = $(this).attr('data-avatar-id'); |
| 1946 | 1945 | setUserAvatar(imgfile); |
| 1947 | - | |
| 1948 | - // force firstMes {{user}} update on persona switch | |
| 1949 | - retriggerFirstMessageOnEmptyChat(); | |
| 1950 | 1946 | }); |
| 1951 | 1947 | |
| 1952 | 1948 | $('#persona_rename_button').on('click', () => renamePersona(user_avatar)); |
| @@ -1979,4 +1975,3 @@ export async function initPersonas() { | ||
| 1979 | 1975 | eventSource.on(event_types.CHAT_CHANGED, loadPersonaForCurrentChat); |
| 1980 | 1976 | switchPersonaGridView(); |
| 1981 | 1977 | } |
| 1982 | - | |
| @@ -55,6 +55,7 @@ import { POPUP_TYPE, callGenericPopup } from './popup.js'; | ||
| 55 | 55 | import { loadSystemPrompts } from './sysprompt.js'; |
| 56 | 56 | import { fuzzySearchCategories } from './filters.js'; |
| 57 | 57 | import { accountStorage } from './util/AccountStorage.js'; |
| 58 | +import { DEFAULT_REASONING_TEMPLATE, loadReasoningTemplates } from './reasoning.js'; | |
| 58 | 59 | |
| 59 | 60 | export { |
| 60 | 61 | loadPowerUserSettings, |
| @@ -70,8 +71,8 @@ export { | ||
| 70 | 71 | |
| 71 | 72 | export const MAX_CONTEXT_DEFAULT = 8192; |
| 72 | 73 | export const MAX_RESPONSE_DEFAULT = 2048; |
| 73 | 74 | const MAX_CONTEXT_UNLOCKED = 200512 * 1024; |
| 74 | 75 | const MAX_RESPONSE_UNLOCKED = 3264 * 1024; |
| 75 | 76 | const unlockedMaxContextStep = 512; |
| 76 | 77 | const maxContextMin = 512; |
| 77 | 78 | const maxContextStep = 64; |
| @@ -218,7 +219,9 @@ let power_user = { | ||
| 218 | 219 | system_sequence: '', |
| 219 | 220 | system_suffix: '', |
| 220 | 221 | last_system_sequence: '', |
| 222 | + first_input_sequence: '', | |
| 221 | 223 | first_output_sequence: '', |
| 224 | + last_input_sequence: '', | |
| 222 | 225 | last_output_sequence: '', |
| 223 | 226 | system_sequence_prefix: '', |
| 224 | 227 | system_sequence_suffix: '', |
| @@ -255,6 +258,7 @@ let power_user = { | ||
| 255 | 258 | }, |
| 256 | 259 | |
| 257 | 260 | reasoning: { |
| 261 | + name: DEFAULT_REASONING_TEMPLATE, | |
| 258 | 262 | auto_parse: false, |
| 259 | 263 | add_to_prompts: false, |
| 260 | 264 | auto_expand: false, |
| @@ -1622,6 +1626,7 @@ async function loadPowerUserSettings(settings, data) { | ||
| 1622 | 1626 | await loadInstructMode(data); |
| 1623 | 1627 | await loadContextSettings(); |
| 1624 | 1628 | await loadSystemPrompts(data); |
| 1629 | + await loadReasoningTemplates(data); | |
| 1625 | 1630 | loadMaxContextUnlocked(); |
| 1626 | 1631 | switchWaifuMode(); |
| 1627 | 1632 | switchSpoilerMode(); |
| @@ -1983,15 +1988,21 @@ export function fuzzySearchGroups(searchValue, fuzzySearchCaches = null) { | ||
| 1983 | 1988 | /** |
| 1984 | 1989 | * Renders a story string template with the given parameters. |
| 1985 | 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 | 1994 | * @returns {string} The rendered story string. |
| 1987 | 1995 | */ |
| 1988 | -export function renderStoryString(params) { | |
| 1996 | +export function renderStoryString(params, { customStoryString = null, customInstructSettings = null } = {}) { | |
| 1989 | 1997 | try { |
| 1998 | + const storyString = customStoryString ?? power_user.context.story_string; | |
| 1999 | + const instructSettings = structuredClone(customInstructSettings ?? power_user.instruct); | |
| 2000 | + | |
| 1990 | 2001 | // Validate and log possible warnings/errors |
| 1991 | 2002 | validateStoryString(power_user.context.story_stringstoryString, params); |
| 1992 | 2003 | |
| 1993 | 2004 | // compile the story string template into a function, with no HTML escaping |
| 1994 | 2005 | const compiledTemplate = Handlebars.compile(power_user.context.story_stringstoryString, { noEscape: true }); |
| 1995 | 2006 | |
| 1996 | 2007 | // render the story string template with the given params |
| 1997 | 2008 | let output = compiledTemplate(params); |
| @@ -2004,7 +2015,7 @@ export function renderStoryString(params) { | ||
| 2004 | 2015 | |
| 2005 | 2016 | // add a newline to the end of the story string if it doesn't have one |
| 2006 | 2017 | if (output.length > 0 && !output.endsWith('\n')) { |
| 2007 | 2018 | if (!power_user.instructinstructSettings.enabled || power_user.instructinstructSettings.wrap) { |
| 2008 | 2019 | output += '\n'; |
| 2009 | 2020 | } |
| 2010 | 2021 | } |
| @@ -21,7 +21,7 @@ import { groups, selected_group } from './group-chats.js'; | ||
| 21 | 21 | import { instruct_presets } from './instruct-mode.js'; |
| 22 | 22 | import { kai_settings } from './kai-settings.js'; |
| 23 | 23 | import { convertNovelPreset } from './nai-settings.js'; |
| 24 | 24 | import { openai_settings, openai_setting_names, oai_settings } from './openai.js'; |
| 25 | 25 | import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; |
| 26 | 26 | import { context_presets, getContextSettings, power_user } from './power-user.js'; |
| 27 | 27 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| @@ -36,8 +36,9 @@ import { | ||
| 36 | 36 | textgenerationwebui_presets, |
| 37 | 37 | textgenerationwebui_settings as textgen_settings, |
| 38 | 38 | } from './textgen-settings.js'; |
| 39 | 39 | import { download, equalsIgnoreCaseAndAccents, parseJsonFile, waitUntilCondition } from './utils.js'; |
| 40 | 40 | import { t } from './i18n.js'; |
| 41 | +import { reasoning_templates } from './reasoning.js'; | |
| 41 | 42 | |
| 42 | 43 | const presetManagers = {}; |
| 43 | 44 | |
| @@ -168,6 +169,20 @@ class PresetManager { | ||
| 168 | 169 | }, |
| 169 | 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 | 188 | static isPossiblyInstructData(data) { |
| @@ -190,6 +205,11 @@ class PresetManager { | ||
| 190 | 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 | 214 | * Imports master settings from JSON data. |
| 195 | 215 | * @param {object} data Data to import |
| @@ -227,6 +247,12 @@ class PresetManager { | ||
| 227 | 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 | 256 | const validSections = []; |
| 231 | 257 | for (const [key, section] of Object.entries(this.masterSections)) { |
| 232 | 258 | if (key in data && section.isValid(data[key])) { |
| @@ -428,6 +454,9 @@ class PresetManager { | ||
| 428 | 454 | |
| 429 | 455 | async renamePreset(newName) { |
| 430 | 456 | const oldName = this.getSelectedPresetName(); |
| 457 | + if (equalsIgnoreCaseAndAccents(oldName, newName)) { | |
| 458 | + throw new Error('New name must be different from old name'); | |
| 459 | + } | |
| 431 | 460 | try { |
| 432 | 461 | await this.savePreset(newName); |
| 433 | 462 | await this.deletePreset(oldName); |
| @@ -478,6 +507,10 @@ class PresetManager { | ||
| 478 | 507 | presets = system_prompts; |
| 479 | 508 | preset_names = system_prompts.map(x => x.name); |
| 480 | 509 | break; |
| 510 | + case 'reasoning': | |
| 511 | + presets = reasoning_templates; | |
| 512 | + preset_names = reasoning_templates.map(x => x.name); | |
| 513 | + break; | |
| 481 | 514 | default: |
| 482 | 515 | console.warn(`Unknown API ID ${api}`); |
| 483 | 516 | } |
| @@ -490,7 +523,7 @@ class PresetManager { | ||
| 490 | 523 | } |
| 491 | 524 | |
| 492 | 525 | isAdvancedFormatting() { |
| 493 | - return this.apiId == 'context' || this.apiId == 'instruct' || this.apiId == 'sysprompt'; | |
| 526 | + return ['context', 'instruct', 'sysprompt', 'reasoning'].includes(this.apiId); | |
| 494 | 527 | } |
| 495 | 528 | |
| 496 | 529 | updateList(name, preset) { |
| @@ -553,6 +586,11 @@ class PresetManager { | ||
| 553 | 586 | sysprompt_preset['name'] = name || power_user.sysprompt.preset; |
| 554 | 587 | return sysprompt_preset; |
| 555 | 588 | } |
| 589 | + case 'reasoning': { | |
| 590 | + const reasoning_preset = structuredClone(power_user.reasoning); | |
| 591 | + reasoning_preset['name'] = name || power_user.reasoning.preset; | |
| 592 | + return reasoning_preset; | |
| 593 | + } | |
| 556 | 594 | default: |
| 557 | 595 | console.warn(`Unknown API ID ${apiId}`); |
| 558 | 596 | return {}; |
| @@ -599,6 +637,13 @@ class PresetManager { | ||
| 599 | 637 | 'include_reasoning', |
| 600 | 638 | 'global_banned_tokens', |
| 601 | 639 | 'send_banned_tokens', |
| 640 | + | |
| 641 | + // Reasoning exclusions | |
| 642 | + 'auto_parse', | |
| 643 | + 'add_to_prompts', | |
| 644 | + 'auto_expand', | |
| 645 | + 'show_hidden', | |
| 646 | + 'max_additions', | |
| 602 | 647 | ]; |
| 603 | 648 | const settings = Object.assign({}, getSettingsByApiId(this.apiId)); |
| 604 | 649 | |
| @@ -850,9 +895,19 @@ export async function initPresetManager() { | ||
| 850 | 895 | console.debug(!presetManager.isAdvancedFormatting() ? 'Preset rename cancelled' : 'Template rename cancelled'); |
| 851 | 896 | return; |
| 852 | 897 | } |
| 898 | + if (equalsIgnoreCaseAndAccents(oldName, newName)) { | |
| 899 | + toastr.warning(t`Name not accepted, as it is the same as before (ignoring case and accents).`, t`Rename Preset`); | |
| 900 | + return; | |
| 901 | + } | |
| 853 | 902 | |
| 854 | 903 | await presetManager.renamePreset(newName); |
| 855 | 904 | |
| 905 | + if (apiId === 'openai') { | |
| 906 | + // This is a horrible mess, but prevents the renamed preset from being corrupted. | |
| 907 | + $('#update_oai_preset').trigger('click'); | |
| 908 | + return; | |
| 909 | + } | |
| 910 | + | |
| 856 | 911 | const successToast = !presetManager.isAdvancedFormatting() ? t`Preset renamed` : t`Template renamed`; |
| 857 | 912 | toastr.success(successToast); |
| 858 | 913 | }); |
| @@ -7,14 +7,46 @@ import { getCurrentLocale, t, translate } from './i18n.js'; | ||
| 7 | 7 | import { MacrosParser } from './macros.js'; |
| 8 | 8 | import { chat_completion_sources, getChatCompletionModel, oai_settings } from './openai.js'; |
| 9 | 9 | import { Popup } from './popup.js'; |
| 10 | 10 | import { performFuzzySearch, power_user } from './power-user.js'; |
| 11 | +import { getPresetManager } from './preset-manager.js'; | |
| 11 | 12 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 12 | 13 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; |
| 13 | 14 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 14 | 15 | import { enumTypes, SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js'; |
| 15 | 16 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 16 | 17 | import { textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; |
| 17 | 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 | 52 | * Enum representing the type of the reasoning for a message (where it came from) |
| @@ -57,21 +89,28 @@ function toggleReasoningAutoExpand() { | ||
| 57 | 89 | * @param {object} data Response data |
| 58 | 90 | * @returns {string} Extracted reasoning |
| 59 | 91 | */ |
| 60 | 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 | 99 | case 'textgenerationwebui': |
| 63 | 100 | switch (textGenType ?? textgenerationwebui_settings.type) { |
| 64 | 101 | case textgen_types.OPENROUTER: |
| 65 | 102 | return data?.choices?.[0]?.reasoning ?? ''; |
| 66 | 103 | } |
| 67 | 104 | break; |
| 68 | 105 | |
| 69 | 106 | case 'openai': |
| 70 | 107 | if (!ignoreShowThoughts && !oai_settings.show_thoughts) break; |
| 71 | 108 | |
| 72 | 109 | switch (chatCompletionSource ?? oai_settings.chat_completion_source) { |
| 73 | 110 | case chat_completion_sources.DEEPSEEK: |
| 74 | 111 | return data?.choices?.[0]?.message?.reasoning_content ?? ''; |
| 112 | + case chat_completion_sources.XAI: | |
| 113 | + return data?.choices?.[0]?.message?.reasoning_content ?? ''; | |
| 75 | 114 | case chat_completion_sources.OPENROUTER: |
| 76 | 115 | return data?.choices?.[0]?.message?.reasoning ?? ''; |
| 77 | 116 | case chat_completion_sources.MAKERSUITE: |
| @@ -664,57 +703,102 @@ export class PromptReasoning { | ||
| 664 | 703 | } |
| 665 | 704 | |
| 666 | 705 | function loadReasoningSettings() { |
| 667 | 706 | UI.$('#reasoning_add_to_prompts')addToPrompts.prop('checked', power_user.reasoning.add_to_prompts); |
| 668 | 707 | UI.$('#reasoning_add_to_prompts')addToPrompts.on('change', function () { |
| 669 | 708 | power_user.reasoning.add_to_prompts = !!$(this).prop('checked'); |
| 670 | 709 | saveSettingsDebounced(); |
| 671 | 710 | }); |
| 672 | 711 | |
| 673 | 712 | UI.$('#reasoning_prefix')prefix.val(power_user.reasoning.prefix); |
| 674 | 713 | UI.$('#reasoning_prefix')prefix.on('input', function () { |
| 675 | 714 | power_user.reasoning.prefix = String($(this).val()); |
| 676 | 715 | saveSettingsDebounced(); |
| 677 | 716 | }); |
| 678 | 717 | |
| 679 | 718 | UI.$('#reasoning_suffix')suffix.val(power_user.reasoning.suffix); |
| 680 | 719 | UI.$('#reasoning_suffix')suffix.on('input', function () { |
| 681 | 720 | power_user.reasoning.suffix = String($(this).val()); |
| 682 | 721 | saveSettingsDebounced(); |
| 683 | 722 | }); |
| 684 | 723 | |
| 685 | 724 | UI.$('#reasoning_separator')separator.val(power_user.reasoning.separator); |
| 686 | 725 | UI.$('#reasoning_separator')separator.on('input', function () { |
| 687 | 726 | power_user.reasoning.separator = String($(this).val()); |
| 688 | 727 | saveSettingsDebounced(); |
| 689 | 728 | }); |
| 690 | 729 | |
| 691 | 730 | UI.$('#reasoning_max_additions')maxAdditions.val(power_user.reasoning.max_additions); |
| 692 | 731 | UI.$('#reasoning_max_additions')maxAdditions.on('input', function () { |
| 693 | 732 | power_user.reasoning.max_additions = Number($(this).val()); |
| 694 | 733 | saveSettingsDebounced(); |
| 695 | 734 | }); |
| 696 | 735 | |
| 697 | 736 | UI.$('#reasoning_auto_parse')autoParse.prop('checked', power_user.reasoning.auto_parse); |
| 698 | 737 | UI.$('#reasoning_auto_parse')autoParse.on('change', function () { |
| 699 | 738 | power_user.reasoning.auto_parse = !!$(this).prop('checked'); |
| 700 | 739 | saveSettingsDebounced(); |
| 701 | 740 | }); |
| 702 | 741 | |
| 703 | 742 | UI.$('#reasoning_auto_expand')autoExpand.prop('checked', power_user.reasoning.auto_expand); |
| 704 | 743 | UI.$('#reasoning_auto_expand')autoExpand.on('change', function () { |
| 705 | 744 | power_user.reasoning.auto_expand = !!$(this).prop('checked'); |
| 706 | 745 | toggleReasoningAutoExpand(); |
| 707 | 746 | saveSettingsDebounced(); |
| 708 | 747 | }); |
| 709 | 748 | toggleReasoningAutoExpand(); |
| 710 | 749 | |
| 711 | 750 | UI.$('#reasoning_show_hidden')showHidden.prop('checked', power_user.reasoning.show_hidden); |
| 712 | 751 | UI.$('#reasoning_show_hidden')showHidden.on('change', function () { |
| 713 | 752 | power_user.reasoning.show_hidden = !!$(this).prop('checked'); |
| 714 | 753 | $('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null); |
| 715 | 754 | saveSettingsDebounced(); |
| 716 | 755 | }); |
| 717 | 756 | $('#chat').attr('data-show-hidden-reasoning', power_user.reasoning.show_hidden ? 'true' : null); |
| 757 | + | |
| 758 | + UI.$select.on('change', async function () { | |
| 759 | + const name = String($(this).val()); | |
| 760 | + const template = reasoning_templates.find(p => p.name === name); | |
| 761 | + if (!template) { | |
| 762 | + return; | |
| 763 | + } | |
| 764 | + | |
| 765 | + UI.$prefix.val(template.prefix); | |
| 766 | + UI.$suffix.val(template.suffix); | |
| 767 | + UI.$separator.val(template.separator); | |
| 768 | + | |
| 769 | + power_user.reasoning.name = name; | |
| 770 | + power_user.reasoning.prefix = template.prefix; | |
| 771 | + power_user.reasoning.suffix = template.suffix; | |
| 772 | + power_user.reasoning.separator = template.separator; | |
| 773 | + | |
| 774 | + saveSettingsDebounced(); | |
| 775 | + }); | |
| 776 | +} | |
| 777 | + | |
| 778 | +function selectReasoningTemplateCallback(args, name) { | |
| 779 | + if (!name) { | |
| 780 | + return power_user.reasoning.name ?? ''; | |
| 781 | + } | |
| 782 | + | |
| 783 | + const quiet = isTrueBoolean(args?.quiet); | |
| 784 | + const templateNames = reasoning_templates.map(preset => preset.name); | |
| 785 | + let foundName = templateNames.find(x => x.toLowerCase() === name.toLowerCase()); | |
| 786 | + | |
| 787 | + if (!foundName) { | |
| 788 | + const result = performFuzzySearch('reasoning-templates', templateNames, [], name); | |
| 789 | + | |
| 790 | + if (result.length === 0) { | |
| 791 | + !quiet && toastr.warning(`Reasoning template "${name}" not found`); | |
| 792 | + return ''; | |
| 793 | + } | |
| 794 | + | |
| 795 | + foundName = result[0].item; | |
| 796 | + } | |
| 797 | + | |
| 798 | + UI.$select.val(foundName).trigger('change'); | |
| 799 | + !quiet && toastr.success(`Reasoning template "${foundName}" selected`); | |
| 800 | + return foundName; | |
| 801 | + | |
| 718 | 802 | } |
| 719 | 803 | |
| 720 | 804 | function registerReasoningSlashCommands() { |
| @@ -750,6 +834,12 @@ function registerReasoningSlashCommands() { | ||
| 750 | 834 | typeList: ARGUMENT_TYPE.NUMBER, |
| 751 | 835 | enumProvider: commonEnumProviders.messages(), |
| 752 | 836 | }), |
| 837 | + SlashCommandNamedArgument.fromProps({ | |
| 838 | + name: 'collapse', | |
| 839 | + description: 'Whether to collapse the reasoning block. (If not provided, uses the default expand setting)', | |
| 840 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 841 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 842 | + }), | |
| 753 | 843 | ], |
| 754 | 844 | unnamedArgumentList: [ |
| 755 | 845 | SlashCommandArgument.fromProps({ |
| @@ -774,6 +864,9 @@ function registerReasoningSlashCommands() { | ||
| 774 | 864 | |
| 775 | 865 | closeMessageEditor('reasoning'); |
| 776 | 866 | updateMessageBlock(messageId, message); |
| 867 | + | |
| 868 | + if (isTrueBoolean(String(args.collapse))) $(`#chat [mesid="${messageId}"] .mes_reasoning_details`).removeAttr('open'); | |
| 869 | + if (isFalseBoolean(String(args.collapse))) $(`#chat [mesid="${messageId}"] .mes_reasoning_details`).attr('open', ''); | |
| 777 | 870 | return message.extra.reasoning; |
| 778 | 871 | }, |
| 779 | 872 | })); |
| @@ -848,6 +941,42 @@ function registerReasoningSlashCommands() { | ||
| 848 | 941 | : parsedReasoning.reasoning; |
| 849 | 942 | }, |
| 850 | 943 | })); |
| 944 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 945 | + name: 'reasoning-template', | |
| 946 | + aliases: ['reasoning-formatting', 'reasoning-preset'], | |
| 947 | + callback: selectReasoningTemplateCallback, | |
| 948 | + returns: 'template name', | |
| 949 | + namedArgumentList: [ | |
| 950 | + SlashCommandNamedArgument.fromProps({ | |
| 951 | + name: 'quiet', | |
| 952 | + description: 'Suppress the toast message on template change', | |
| 953 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 954 | + defaultValue: 'false', | |
| 955 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 956 | + }), | |
| 957 | + ], | |
| 958 | + unnamedArgumentList: [ | |
| 959 | + SlashCommandArgument.fromProps({ | |
| 960 | + description: 'reasoning template name', | |
| 961 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 962 | + enumProvider: () => reasoning_templates.map(x => new SlashCommandEnumValue(x.name, null, enumTypes.enum, enumIcons.preset)), | |
| 963 | + }), | |
| 964 | + ], | |
| 965 | + helpString: ` | |
| 966 | + <div> | |
| 967 | + Selects a reasoning template by name, using fuzzy search to find the closest match. | |
| 968 | + Gets the current template if no name is provided. | |
| 969 | + </div> | |
| 970 | + <div> | |
| 971 | + <strong>Example:</strong> | |
| 972 | + <ul> | |
| 973 | + <li> | |
| 974 | + <pre><code class="language-stscript">/reasoning-template DeepSeek</code></pre> | |
| 975 | + </li> | |
| 976 | + </ul> | |
| 977 | + </div> | |
| 978 | + `, | |
| 979 | + })); | |
| 851 | 980 | } |
| 852 | 981 | |
| 853 | 982 | function registerReasoningMacros() { |
| @@ -1207,6 +1336,53 @@ function registerReasoningAppEvents() { | ||
| 1207 | 1336 | } |
| 1208 | 1337 | } |
| 1209 | 1338 | |
| 1339 | +/** | |
| 1340 | + * Loads reasoning templates from the settings data. | |
| 1341 | + * @param {object} data Settings data | |
| 1342 | + * @param {ReasoningTemplate[]} data.reasoning Reasoning templates | |
| 1343 | + * @returns {Promise<void>} | |
| 1344 | + */ | |
| 1345 | +export async function loadReasoningTemplates(data) { | |
| 1346 | + if (data.reasoning !== undefined) { | |
| 1347 | + reasoning_templates.splice(0, reasoning_templates.length, ...data.reasoning); | |
| 1348 | + } | |
| 1349 | + | |
| 1350 | + for (const template of reasoning_templates) { | |
| 1351 | + $('<option>').val(template.name).text(template.name).appendTo(UI.$select); | |
| 1352 | + } | |
| 1353 | + | |
| 1354 | + // No template name, need to migrate | |
| 1355 | + if (power_user.reasoning.name === undefined) { | |
| 1356 | + const defaultTemplate = reasoning_templates.find(p => p.name === DEFAULT_REASONING_TEMPLATE); | |
| 1357 | + if (defaultTemplate) { | |
| 1358 | + // If the reasoning settings were modified - migrate them to a custom template | |
| 1359 | + if (power_user.reasoning.prefix !== defaultTemplate.prefix || power_user.reasoning.suffix !== defaultTemplate.suffix || power_user.reasoning.separator !== defaultTemplate.separator) { | |
| 1360 | + /** @type {ReasoningTemplate} */ | |
| 1361 | + const data = { | |
| 1362 | + name: '[Migrated] Custom', | |
| 1363 | + prefix: power_user.reasoning.prefix, | |
| 1364 | + suffix: power_user.reasoning.suffix, | |
| 1365 | + separator: power_user.reasoning.separator, | |
| 1366 | + }; | |
| 1367 | + await getPresetManager('reasoning')?.savePreset(data.name, data); | |
| 1368 | + power_user.reasoning.name = data.name; | |
| 1369 | + } else { | |
| 1370 | + power_user.reasoning.name = defaultTemplate.name; | |
| 1371 | + } | |
| 1372 | + } else { | |
| 1373 | + // Template not found (deleted or content check skipped - leave blank) | |
| 1374 | + power_user.reasoning.name = ''; | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + saveSettingsDebounced(); | |
| 1378 | + } | |
| 1379 | + | |
| 1380 | + UI.$select.val(power_user.reasoning.name); | |
| 1381 | +} | |
| 1382 | + | |
| 1383 | +/** | |
| 1384 | + * Initializes reasoning settings and event handlers. | |
| 1385 | + */ | |
| 1210 | 1386 | export function initReasoning() { |
| 1211 | 1387 | loadReasoningSettings(); |
| 1212 | 1388 | setReasoningEventHandlers(); |
| @@ -9,6 +9,7 @@ import { power_user } from './power-user.js'; | ||
| 9 | 9 | //import { getSortableDelay, onlyUnique } from './utils.js'; |
| 10 | 10 | //import { getCfgPrompt } from './cfg-scale.js'; |
| 11 | 11 | import { setting_names } from './textgen-settings.js'; |
| 12 | +import { renderTemplateAsync } from './templates.js'; | |
| 12 | 13 | |
| 13 | 14 | |
| 14 | 15 | const TGsamplerNames = setting_names; |
| @@ -25,25 +26,7 @@ async function showSamplerSelectPopup() { | ||
| 25 | 26 | const html = $(document.createElement('div')); |
| 26 | 27 | html.attr('id', 'sampler_view_list') |
| 27 | 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 | 31 | const listContainer = $('<div id="apiSamplersList" class="flex-container flexNoGap"></div>'); |
| 49 | 32 | const APISamplers = await listSamplers(main_api); |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | import { DOMPurify } from '../lib.js'; |
| 2 | 2 | import { callPopup, getRequestHeaders } from '../script.js'; |
| 3 | +import { t } from './i18n.js'; | |
| 3 | 4 | |
| 4 | 5 | export const SECRET_KEYS = { |
| 5 | 6 | HORDE: 'api_key_horde', |
| @@ -33,7 +34,6 @@ export const SECRET_KEYS = { | ||
| 33 | 34 | ZEROONEAI: 'api_key_01ai', |
| 34 | 35 | HUGGINGFACE: 'api_key_huggingface', |
| 35 | 36 | STABILITY: 'api_key_stability', |
| 36 | - BLOCKENTROPY: 'api_key_blockentropy', | |
| 37 | 37 | CUSTOM_OPENAI_TTS: 'api_key_custom_openai_tts', |
| 38 | 38 | NANOGPT: 'api_key_nanogpt', |
| 39 | 39 | TAVILY: 'api_key_tavily', |
| @@ -42,6 +42,7 @@ export const SECRET_KEYS = { | ||
| 42 | 42 | DEEPSEEK: 'api_key_deepseek', |
| 43 | 43 | SERPER: 'api_key_serper', |
| 44 | 44 | FALAI: 'api_key_falai', |
| 45 | + XAI: 'api_key_xai', | |
| 45 | 46 | }; |
| 46 | 47 | |
| 47 | 48 | const INPUT_MAP = { |
| @@ -73,10 +74,10 @@ const INPUT_MAP = { | ||
| 73 | 74 | [SECRET_KEYS.FEATHERLESS]: '#api_key_featherless', |
| 74 | 75 | [SECRET_KEYS.ZEROONEAI]: '#api_key_01ai', |
| 75 | 76 | [SECRET_KEYS.HUGGINGFACE]: '#api_key_huggingface', |
| 76 | - [SECRET_KEYS.BLOCKENTROPY]: '#api_key_blockentropy', | |
| 77 | 77 | [SECRET_KEYS.NANOGPT]: '#api_key_nanogpt', |
| 78 | 78 | [SECRET_KEYS.GENERIC]: '#api_key_generic', |
| 79 | 79 | [SECRET_KEYS.DEEPSEEK]: '#api_key_deepseek', |
| 80 | + [SECRET_KEYS.XAI]: '#api_key_xai', | |
| 80 | 81 | }; |
| 81 | 82 | |
| 82 | 83 | async function clearSecret() { |
| @@ -104,7 +105,7 @@ async function viewSecrets() { | ||
| 104 | 105 | }); |
| 105 | 106 | |
| 106 | 107 | if (response.status == 403) { |
| 107 | 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 | 109 | return; |
| 109 | 110 | } |
| 110 | 111 | |
| @@ -188,14 +189,17 @@ export async function findSecret(key) { | ||
| 188 | 189 | } |
| 189 | 190 | |
| 190 | 191 | function authorizeOpenRouter() { |
| 191 | 192 | const openRouterUrlredirectUrl = `https:new URL('/callback/openrouter', window.ai/auth?callback_url=${encodeURIComponent(location.origin)}`; |
| 193 | + const openRouterUrl = `https://openrouter.ai/auth?callback_url=${encodeURIComponent(redirectUrl.toString())}`; | |
| 192 | 194 | location.href = openRouterUrl; |
| 193 | 195 | } |
| 194 | 196 | |
| 195 | 197 | async function checkOpenRouterAuth() { |
| 196 | 198 | const params = new URLSearchParams(location.search); |
| 197 | 199 | ifconst (source = params.hasget('codesource')) {; |
| 198 | - const code = params.get('code'); | |
| 200 | + if (source === 'openrouter') { | |
| 201 | + const query = new URLSearchParams(params.get('query')); | |
| 202 | + const code = query.get('code'); | |
| 199 | 203 | try { |
| 200 | 204 | const response = await fetch('https://openrouter.ai/api/v1/auth/keys', { |
| 201 | 205 | method: 'POST', |
| @@ -8,10 +8,10 @@ export const markdownUnderscoreExt = () => { | ||
| 8 | 8 | |
| 9 | 9 | return [{ |
| 10 | 10 | type: 'output', |
| 11 | 11 | regex: new RegExp('(<code(?:\\s+[^>]*)?>[\\s\\S]*?<\\/code>|<style(?:\\s+[^>]*)?>[\\s\\S]*?<\\/style>)|\\b(?<!_)_(?!_)(.*?)(?<!_)_(?!_)\\b', 'ggi'), |
| 12 | 12 | replace: function(match, codeContenttagContent, italicContent) { |
| 13 | 13 | if (codeContenttagContent) { |
| 14 | 14 | // If it's inside <code> or <style> tags, return unchanged |
| 15 | 15 | return match; |
| 16 | 16 | } else if (italicContent) { |
| 17 | 17 | // If it's an italic group, apply the replacement |
| @@ -75,6 +75,9 @@ import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakC | ||
| 75 | 75 | import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js'; |
| 76 | 76 | import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; |
| 77 | 77 | import { accountStorage } from './util/AccountStorage.js'; |
| 78 | +import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js'; | |
| 79 | +import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; | |
| 80 | +import { t } from './i18n.js'; | |
| 78 | 81 | export { |
| 79 | 82 | executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand, |
| 80 | 83 | }; |
| @@ -224,6 +227,7 @@ export function initDefaultSlashCommands() { | ||
| 224 | 227 | })); |
| 225 | 228 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 226 | 229 | name: 'sendas', |
| 230 | + rawQuotes: true, | |
| 227 | 231 | callback: sendMessageAs, |
| 228 | 232 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', |
| 229 | 233 | namedArgumentList: [ |
| @@ -290,6 +294,7 @@ export function initDefaultSlashCommands() { | ||
| 290 | 294 | })); |
| 291 | 295 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 292 | 296 | name: 'sys', |
| 297 | + rawQuotes: true, | |
| 293 | 298 | callback: sendNarratorMessage, |
| 294 | 299 | aliases: ['nar'], |
| 295 | 300 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', |
| @@ -354,6 +359,7 @@ export function initDefaultSlashCommands() { | ||
| 354 | 359 | })); |
| 355 | 360 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 356 | 361 | name: 'comment', |
| 362 | + rawQuotes: true, | |
| 357 | 363 | callback: sendCommentMessage, |
| 358 | 364 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', |
| 359 | 365 | namedArgumentList: [ |
| @@ -571,6 +577,7 @@ export function initDefaultSlashCommands() { | ||
| 571 | 577 | })); |
| 572 | 578 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 573 | 579 | name: 'send', |
| 580 | + rawQuotes: true, | |
| 574 | 581 | callback: sendUserMessageCallback, |
| 575 | 582 | returns: 'Optionally the text of the sent message, if specified in the "return" argument', |
| 576 | 583 | namedArgumentList: [ |
| @@ -933,6 +940,7 @@ export function initDefaultSlashCommands() { | ||
| 933 | 940 | })); |
| 934 | 941 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 935 | 942 | name: 'echo', |
| 943 | + rawQuotes: true, | |
| 936 | 944 | callback: echoCallback, |
| 937 | 945 | returns: 'the text', |
| 938 | 946 | namedArgumentList: [ |
| @@ -1554,16 +1562,28 @@ export function initDefaultSlashCommands() { | ||
| 1554 | 1562 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1555 | 1563 | name: 'buttons', |
| 1556 | 1564 | callback: buttonsCallback, |
| 1557 | 1565 | returns: 'clicked button label (or array of labels if multiple is enabled)', |
| 1558 | 1566 | namedArgumentList: [ |
| 1559 | 1567 | new SlashCommandNamedArgument.fromProps({ |
| 1560 | - 'labels', 'button labels', [ARGUMENT_TYPE.LIST], true, | |
| 1568 | + name: 'labels', | |
| 1561 | - ), | |
| 1569 | + description: 'button labels', | |
| 1570 | + typeList: [ARGUMENT_TYPE.LIST], | |
| 1571 | + isRequired: true, | |
| 1572 | + }), | |
| 1573 | + SlashCommandNamedArgument.fromProps({ | |
| 1574 | + name: 'multiple', | |
| 1575 | + description: 'if enabled multiple buttons can be clicked/toggled, and all clicked buttons are returned as an array', | |
| 1576 | + typeList: [ARGUMENT_TYPE.BOOLEAN], | |
| 1577 | + enumList: commonEnumProviders.boolean('trueFalse')(), | |
| 1578 | + defaultValue: 'false', | |
| 1579 | + }), | |
| 1562 | 1580 | ], |
| 1563 | 1581 | unnamedArgumentList: [ |
| 1564 | 1582 | new SlashCommandArgument.fromProps({ |
| 1565 | - 'text', [ARGUMENT_TYPE.STRING], true, | |
| 1583 | + description: 'text', | |
| 1566 | - ), | |
| 1584 | + typeList: [ARGUMENT_TYPE.STRING], | |
| 1585 | + isRequired: true, | |
| 1586 | + }), | |
| 1567 | 1587 | ], |
| 1568 | 1588 | helpString: ` |
| 1569 | 1589 | <div> |
| @@ -2375,6 +2395,18 @@ async function trimTokensCallback(arg, value) { | ||
| 2375 | 2395 | } |
| 2376 | 2396 | } |
| 2377 | 2397 | |
| 2398 | +/** | |
| 2399 | + * Displays a popup with buttons based on provided labels and handles button interactions. | |
| 2400 | + * | |
| 2401 | + * @param {object} args - Named arguments for the command | |
| 2402 | + * @param {string} args.labels - JSON string of an array of button labels | |
| 2403 | + * @param {string} [args.multiple=false] - Flag indicating if multiple buttons can be toggled | |
| 2404 | + * @param {string} text - The text content to be displayed within the popup | |
| 2405 | + * | |
| 2406 | + * @returns {Promise<string>} - A promise that resolves to a string of the button labels selected | |
| 2407 | + * If 'multiple' is true, returns a JSON string array of labels. | |
| 2408 | + * If 'multiple' is false, returns a single label string. | |
| 2409 | + */ | |
| 2378 | 2410 | async function buttonsCallback(args, text) { |
| 2379 | 2411 | try { |
| 2380 | 2412 | /** @type {string[]} */ |
| @@ -2385,6 +2417,10 @@ async function buttonsCallback(args, text) { | ||
| 2385 | 2417 | return ''; |
| 2386 | 2418 | } |
| 2387 | 2419 | |
| 2420 | + /** @type {Set<number>} */ | |
| 2421 | + const multipleToggledState = new Set(); | |
| 2422 | + const multiple = isTrueBoolean(args?.multiple); | |
| 2423 | + | |
| 2388 | 2424 | // Map custom buttons to results. Start at 2 because 1 and 0 are reserved for ok and cancel |
| 2389 | 2425 | const resultToButtonMap = new Map(buttons.map((button, index) => [index + 2, button])); |
| 2390 | 2426 | |
| @@ -2402,11 +2438,24 @@ async function buttonsCallback(args, text) { | ||
| 2402 | 2438 | |
| 2403 | 2439 | for (const [result, button] of resultToButtonMap) { |
| 2404 | 2440 | const buttonElement = document.createElement('div'); |
| 2405 | 2441 | buttonElement.classList.add('menu_button', 'result-control', 'wide100p'); |
| 2406 | - buttonElement.dataset.result = String(result); | |
| 2442 | + | |
| 2443 | + if (multiple) { | |
| 2444 | + buttonElement.classList.add('toggleable'); | |
| 2445 | + buttonElement.dataset.toggleValue = String(result); | |
| 2407 | 2446 | buttonElement.addEventListener('click', async () => { |
| 2408 | - await popup.complete(result); | |
| 2447 | + buttonElement.classList.toggle('toggled'); | |
| 2448 | + if (buttonElement.classList.contains('toggled')) { | |
| 2449 | + multipleToggledState.add(result); | |
| 2450 | + } else { | |
| 2451 | + multipleToggledState.delete(result); | |
| 2452 | + } | |
| 2409 | 2453 | }); |
| 2454 | + } else { | |
| 2455 | + buttonElement.classList.add('result-control'); | |
| 2456 | + buttonElement.dataset.result = String(result); | |
| 2457 | + } | |
| 2458 | + | |
| 2410 | 2459 | buttonElement.innerText = button; |
| 2411 | 2460 | buttonContainer.appendChild(buttonElement); |
| 2412 | 2461 | } |
| @@ -2422,10 +2471,19 @@ async function buttonsCallback(args, text) { | ||
| 2422 | 2471 | popupContainer.style.flexDirection = 'column'; |
| 2423 | 2472 | popupContainer.style.maxHeight = '80vh'; // Limit the overall height of the popup |
| 2424 | 2473 | |
| 2425 | 2474 | popup = new Popup(popupContainer, POPUP_TYPE.TEXT, '', { okButton: 'multiple ? t`Ok` : t`Cancel'`, allowVerticalScrolling: true }); |
| 2426 | 2475 | popup.show() |
| 2427 | 2476 | .then((result => resolve(typeof result === 'number' ? resultToButtonMap.getgetResult(result) ?? '' : ''))) |
| 2428 | 2477 | .catch(() => resolve('')); |
| 2478 | + | |
| 2479 | + /** @returns {string} @param {string|number|boolean} result */ | |
| 2480 | + function getResult(result) { | |
| 2481 | + if (multiple) { | |
| 2482 | + const array = result === POPUP_RESULT.AFFIRMATIVE ? Array.from(multipleToggledState).map(r => resultToButtonMap.get(r) ?? '') : []; | |
| 2483 | + return JSON.stringify(array); | |
| 2484 | + } | |
| 2485 | + return typeof result === 'number' ? resultToButtonMap.get(result) ?? '' : ''; | |
| 2486 | + } | |
| 2429 | 2487 | }); |
| 2430 | 2488 | } catch { |
| 2431 | 2489 | return ''; |
| @@ -3883,8 +3941,8 @@ function getModelOptions(quiet) { | ||
| 3883 | 3941 | { id: 'model_groq_select', api: 'openai', type: chat_completion_sources.GROQ }, |
| 3884 | 3942 | { id: 'model_nanogpt_select', api: 'openai', type: chat_completion_sources.NANOGPT }, |
| 3885 | 3943 | { id: 'model_01ai_select', api: 'openai', type: chat_completion_sources.ZEROONEAI }, |
| 3886 | - { id: 'model_blockentropy_select', api: 'openai', type: chat_completion_sources.BLOCKENTROPY }, | |
| 3887 | 3944 | { id: 'model_deepseek_select', api: 'openai', type: chat_completion_sources.DEEPSEEK }, |
| 3945 | + { id: 'model_xai_select', api: 'openai', type: chat_completion_sources.XAI }, | |
| 3888 | 3946 | { id: 'model_novel_select', api: 'novel', type: null }, |
| 3889 | 3947 | { id: 'horde_model', api: 'koboldhorde', type: null }, |
| 3890 | 3948 | ]; |
| @@ -4345,7 +4403,7 @@ const clearCommandProgressDebounced = debounce(clearCommandProgress); | ||
| 4345 | 4403 | * @prop {boolean} [handleParserErrors] (true) Whether to handle parser errors (show toast on error) or throw. |
| 4346 | 4404 | * @prop {SlashCommandScope} [scope] (null) The scope to be used when executing the commands. |
| 4347 | 4405 | * @prop {boolean} [handleExecutionErrors] (false) Whether to handle execution errors (show toast on error) or throw |
| 4348 | 4406 | * @prop {{[id:PARSER_FLAG]:boolean}import('./slash-commands/SlashCommandParser.js').ParserFlags} [parserFlags] (null) Parser flags to apply |
| 4349 | 4407 | * @prop {SlashCommandAbortController} [abortController] (null) Controller used to abort or pause command execution |
| 4350 | 4408 | * @prop {SlashCommandDebugController} [debugController] (null) Controller used to control debug execution |
| 4351 | 4409 | * @prop {(done:number, total:number)=>void} [onProgress] (null) Callback to handle progress events |
| @@ -4355,7 +4413,7 @@ const clearCommandProgressDebounced = debounce(clearCommandProgress); | ||
| 4355 | 4413 | /** |
| 4356 | 4414 | * @typedef ExecuteSlashCommandsOnChatInputOptions |
| 4357 | 4415 | * @prop {SlashCommandScope} [scope] (null) The scope to be used when executing the commands. |
| 4358 | 4416 | * @prop {{[id:PARSER_FLAG]:boolean}import('./slash-commands/SlashCommandParser.js').ParserFlags} [parserFlags] (null) Parser flags to apply |
| 4359 | 4417 | * @prop {boolean} [clearChatInput] (false) Whether to clear the chat input textarea |
| 4360 | 4418 | * @prop {string} [source] (null) String indicating where the code come from (e.g., QR name) |
| 4361 | 4419 | */ |
| @@ -1,18 +1,15 @@ | ||
| 1 | 1 | import { hljs } from '../../lib.js'; |
| 2 | +import { t } from '../i18n.js'; | |
| 2 | 3 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; |
| 3 | 4 | import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js'; |
| 4 | 5 | import { SlashCommandClosure } from './SlashCommandClosure.js'; |
| 5 | 6 | import { SlashCommandDebugController } from './SlashCommandDebugController.js'; |
| 6 | -import { PARSER_FLAG } from './SlashCommandParser.js'; | |
| 7 | 7 | import { SlashCommandScope } from './SlashCommandScope.js'; |
| 8 | 8 | |
| 9 | - | |
| 10 | - | |
| 11 | - | |
| 12 | 9 | /** |
| 13 | 10 | * @typedef {{ |
| 14 | 11 | * _scope:SlashCommandScope, |
| 15 | - * _parserFlags:{[id:PARSER_FLAG]:boolean}, | |
| 12 | + * _parserFlags:import('./SlashCommandParser.js').ParserFlags, | |
| 16 | 13 | * _abortController:SlashCommandAbortController, |
| 17 | 14 | * _debugController:SlashCommandDebugController, |
| 18 | 15 | * _hasUnnamedArgument:boolean, |
| @@ -40,6 +37,7 @@ export class SlashCommand { | ||
| 40 | 37 | * @param {string} [props.helpString] |
| 41 | 38 | * @param {boolean} [props.splitUnnamedArgument] |
| 42 | 39 | * @param {Number} [props.splitUnnamedArgumentCount] |
| 40 | + * @param {boolean} [props.rawQuotes] If set to true, does not remove wrapping quotes from the unnamed argument. | |
| 43 | 41 | * @param {string[]} [props.aliases] |
| 44 | 42 | * @param {string} [props.returns] |
| 45 | 43 | * @param {SlashCommandNamedArgument[]} [props.namedArgumentList] |
| @@ -58,6 +56,7 @@ export class SlashCommand { | ||
| 58 | 56 | /**@type {string}*/ helpString; |
| 59 | 57 | /**@type {boolean}*/ splitUnnamedArgument = false; |
| 60 | 58 | /**@type {Number}*/ splitUnnamedArgumentCount; |
| 59 | + /** @type {boolean} */ rawQuotes = false; | |
| 61 | 60 | /**@type {string[]}*/ aliases = []; |
| 62 | 61 | /**@type {string}*/ returns; |
| 63 | 62 | /**@type {SlashCommandNamedArgument[]}*/ namedArgumentList = []; |
| @@ -262,6 +261,15 @@ export class SlashCommand { | ||
| 262 | 261 | ].filter(it=>it).join('\n'); |
| 263 | 262 | head.append(src); |
| 264 | 263 | } |
| 264 | + if (this.rawQuotes) { | |
| 265 | + const rawQuotes = document.createElement('div'); { | |
| 266 | + rawQuotes.classList.add('rawQuotes'); | |
| 267 | + rawQuotes.classList.add('fa-solid'); | |
| 268 | + rawQuotes.classList.add('fa-quote-left'); | |
| 269 | + rawQuotes.title = t`Does not alter quoted literal unnamed arguments`; | |
| 270 | + head.append(rawQuotes); | |
| 271 | + } | |
| 272 | + } | |
| 265 | 273 | specs.append(head); |
| 266 | 274 | } |
| 267 | 275 | const body = document.createElement('div'); { |
| @@ -1,9 +1,6 @@ | ||
| 1 | 1 | import { AutoCompleteNameResult } from '../autocomplete/AutoCompleteNameResult.js'; |
| 2 | -import { AutoCompleteOption } from '../autocomplete/AutoCompleteOption.js'; | |
| 3 | 2 | import { AutoCompleteSecondaryNameResult } from '../autocomplete/AutoCompleteSecondaryNameResult.js'; |
| 4 | 3 | import { SlashCommand } from './SlashCommand.js'; |
| 5 | -import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; | |
| 6 | -import { SlashCommandClosure } from './SlashCommandClosure.js'; | |
| 7 | 4 | import { SlashCommandCommandAutoCompleteOption } from './SlashCommandCommandAutoCompleteOption.js'; |
| 8 | 5 | import { SlashCommandEnumAutoCompleteOption } from './SlashCommandEnumAutoCompleteOption.js'; |
| 9 | 6 | import { SlashCommandExecutor } from './SlashCommandExecutor.js'; |
| @@ -2,7 +2,6 @@ import { substituteParams } from '../../script.js'; | ||
| 2 | 2 | import { delay, escapeRegex, uuidv4 } from '../utils.js'; |
| 3 | 3 | import { SlashCommand } from './SlashCommand.js'; |
| 4 | 4 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; |
| 5 | -import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; | |
| 6 | 5 | import { SlashCommandBreak } from './SlashCommandBreak.js'; |
| 7 | 6 | import { SlashCommandBreakController } from './SlashCommandBreakController.js'; |
| 8 | 7 | import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js'; |
| @@ -16,9 +15,7 @@ import { SlashCommandScope } from './SlashCommandScope.js'; | ||
| 16 | 15 | export class SlashCommandClosure { |
| 17 | 16 | /** @type {SlashCommandScope} */ scope; |
| 18 | 17 | /** @type {boolean} */ executeNow = false; |
| 19 | - // @ts-ignore | |
| 20 | 18 | /** @type {SlashCommandNamedArgumentAssignment[]} */ argumentList = []; |
| 21 | - // @ts-ignore | |
| 22 | 19 | /** @type {SlashCommandNamedArgumentAssignment[]} */ providedArgumentList = []; |
| 23 | 20 | /** @type {SlashCommandExecutor[]} */ executorList = []; |
| 24 | 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 | 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 | 1 | import { uuidv4 } from '../utils.js'; |
| 3 | 2 | import { SlashCommand } from './SlashCommand.js'; |
| 4 | -// eslint-disable-next-line no-unused-vars | |
| 5 | 3 | import { SlashCommandClosure } from './SlashCommandClosure.js'; |
| 6 | 4 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; |
| 7 | -// eslint-disable-next-line no-unused-vars | |
| 8 | -import { PARSER_FLAG } from './SlashCommandParser.js'; | |
| 9 | 5 | import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js'; |
| 10 | 6 | |
| 11 | 7 | export class SlashCommandExecutor { |
| @@ -29,10 +25,9 @@ export class SlashCommandExecutor { | ||
| 29 | 25 | } |
| 30 | 26 | } |
| 31 | 27 | /** @type {SlashCommand} */ command; |
| 32 | - // @ts-ignore | |
| 33 | 28 | /** @type {SlashCommandNamedArgumentAssignment[]} */ namedArgumentList = []; |
| 34 | 29 | /** @type {SlashCommandUnnamedArgumentAssignment[]} */ unnamedArgumentList = []; |
| 35 | 30 | /** @type {{[id:PARSER_FLAG]:boolean}import('./SlashCommandParser.js').ParserFlags} */ parserFlags; |
| 36 | 31 | |
| 37 | 32 | get commandCount() { |
| 38 | 33 | return 1 |
| @@ -1,7 +1,6 @@ | ||
| 1 | 1 | import { AutoCompleteOption } from '../autocomplete/AutoCompleteOption.js'; |
| 2 | 2 | import { SlashCommand } from './SlashCommand.js'; |
| 3 | 3 | import { SlashCommandNamedArgument } from './SlashCommandArgument.js'; |
| 4 | -import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; | |
| 5 | 4 | |
| 6 | 5 | export class SlashCommandNamedArgumentAutoCompleteOption extends AutoCompleteOption { |
| 7 | 6 | /** @type {SlashCommandNamedArgument} */ arg; |
| @@ -8,11 +8,9 @@ import { SlashCommandExecutor } from './SlashCommandExecutor.js'; | ||
| 8 | 8 | import { SlashCommandParserError } from './SlashCommandParserError.js'; |
| 9 | 9 | import { AutoCompleteNameResult } from '../autocomplete/AutoCompleteNameResult.js'; |
| 10 | 10 | import { SlashCommandQuickReplyAutoCompleteOption } from './SlashCommandQuickReplyAutoCompleteOption.js'; |
| 11 | -// eslint-disable-next-line no-unused-vars | |
| 12 | 11 | import { SlashCommandScope } from './SlashCommandScope.js'; |
| 13 | 12 | import { SlashCommandVariableAutoCompleteOption } from './SlashCommandVariableAutoCompleteOption.js'; |
| 14 | 13 | import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js'; |
| 15 | -// eslint-disable-next-line no-unused-vars | |
| 16 | 14 | import { SlashCommandAbortController } from './SlashCommandAbortController.js'; |
| 17 | 15 | import { SlashCommandAutoCompleteNameResult } from './SlashCommandAutoCompleteNameResult.js'; |
| 18 | 16 | import { SlashCommandUnnamedArgumentAssignment } from './SlashCommandUnnamedArgumentAssignment.js'; |
| @@ -28,15 +26,17 @@ import { t } from '../i18n.js'; | ||
| 28 | 26 | /** @typedef {import('./SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture */ |
| 29 | 27 | /** @typedef {import('./SlashCommand.js').NamedArguments} NamedArguments */ |
| 30 | 28 | |
| 31 | 29 | /**@readonly*/ |
| 32 | 30 | /* * @enum {Number}*/ |
| 31 | + * @readonly | |
| 32 | + * @typedef {{[id:PARSER_FLAG]:boolean}} ParserFlags | |
| 33 | + */ | |
| 33 | 34 | export const PARSER_FLAG = { |
| 34 | 35 | 'STRICT_ESCAPING': 1, |
| 35 | 36 | 'REPLACE_GETVAR': 2, |
| 36 | 37 | }; |
| 37 | 38 | |
| 38 | 39 | export class SlashCommandParser { |
| 39 | - // @ts-ignore | |
| 40 | 40 | /** @type {Object.<string, SlashCommand>} */ static commands = {}; |
| 41 | 41 | |
| 42 | 42 | /** |
| @@ -101,7 +101,6 @@ export class SlashCommandParser { | ||
| 101 | 101 | get commands() { |
| 102 | 102 | return SlashCommandParser.commands; |
| 103 | 103 | } |
| 104 | - // @ts-ignore | |
| 105 | 104 | /** @type {Object.<string, string>} */ helpStrings = {}; |
| 106 | 105 | /** @type {boolean} */ verifyCommandNames = true; |
| 107 | 106 | /** @type {string} */ text; |
| @@ -976,7 +975,7 @@ export class SlashCommandParser { | ||
| 976 | 975 | cmd.startUnnamedArgs = this.index - (/\s(\s*)$/s.exec(this.behind)?.[1]?.length ?? 0); |
| 977 | 976 | cmd.endUnnamedArgs = this.index; |
| 978 | 977 | if (this.testUnnamedArgument()) { |
| 979 | 978 | cmd.unnamedArgumentList = this.parseUnnamedArgument(cmd.command?.unnamedArgumentList?.length && cmd?.command?.splitUnnamedArgument, cmd?.command?.splitUnnamedArgumentCount, cmd?.command?.rawQuotes); |
| 980 | 979 | cmd.endUnnamedArgs = this.index; |
| 981 | 980 | if (cmd.name == 'let') { |
| 982 | 981 | const keyArg = cmd.namedArgumentList.find(it=>it.name == 'key'); |
| @@ -1036,7 +1035,7 @@ export class SlashCommandParser { | ||
| 1036 | 1035 | testUnnamedArgumentEnd() { |
| 1037 | 1036 | return this.testCommandEnd(); |
| 1038 | 1037 | } |
| 1039 | 1038 | parseUnnamedArgument(split, splitCount = null, rawQuotes = false) { |
| 1040 | 1039 | const wasSplit = split; |
| 1041 | 1040 | /**@type {SlashCommandClosure|String}*/ |
| 1042 | 1041 | let value = this.jumpedEscapeSequence ? this.take() : ''; // take the first, already tested, char if it is an escaped one |
| @@ -1046,7 +1045,7 @@ export class SlashCommandParser { | ||
| 1046 | 1045 | /**@type {SlashCommandUnnamedArgumentAssignment}*/ |
| 1047 | 1046 | let assignment = new SlashCommandUnnamedArgumentAssignment(); |
| 1048 | 1047 | assignment.start = this.index; |
| 1049 | 1048 | if (!split && !rawQuotes && this.testQuotedValue()) { |
| 1050 | 1049 | // if the next bit is a quoted value, take the whole value and gather contents as a list |
| 1051 | 1050 | assignment.value = this.parseQuotedValue(); |
| 1052 | 1051 | assignment.end = this.index; |
| @@ -49,6 +49,7 @@ import { | ||
| 49 | 49 | clearChat, |
| 50 | 50 | unshallowCharacter, |
| 51 | 51 | deleteLastMessage, |
| 52 | + getCharacterCardFields, | |
| 52 | 53 | } from '../script.js'; |
| 53 | 54 | import { |
| 54 | 55 | extension_settings, |
| @@ -78,9 +79,11 @@ import { ToolManager } from './tool-calling.js'; | ||
| 78 | 79 | import { accountStorage } from './util/AccountStorage.js'; |
| 79 | 80 | import { timestampToMoment, uuidv4 } from './utils.js'; |
| 80 | 81 | import { getGlobalVariable, getLocalVariable, setGlobalVariable, setLocalVariable } from './variables.js'; |
| 81 | 82 | import { convertCharacterBook, getWorldInfoPrompt, loadWorldInfo, reloadEditor, saveWorldInfo, updateWorldInfoList } from './world-info.js'; |
| 82 | 83 | import { ChatCompletionService, TextCompletionService } from './custom-request.js'; |
| 84 | +import { ConnectionManagerRequestService } from './extensions/shared.js'; | |
| 83 | 85 | import { updateReasoningUI, parseReasoningFromString } from './reasoning.js'; |
| 86 | +import { IGNORE_SYMBOL } from './constants.js'; | |
| 84 | 87 | |
| 85 | 88 | export function getContext() { |
| 86 | 89 | return { |
| @@ -188,6 +191,7 @@ export function getContext() { | ||
| 188 | 191 | textCompletionSettings: textgenerationwebui_settings, |
| 189 | 192 | powerUserSettings: power_user, |
| 190 | 193 | getCharacters, |
| 194 | + getCharacterCardFields, | |
| 191 | 195 | uuidv4, |
| 192 | 196 | humanizedDateTime, |
| 193 | 197 | updateMessageBlock, |
| @@ -204,8 +208,10 @@ export function getContext() { | ||
| 204 | 208 | }, |
| 205 | 209 | loadWorldInfo, |
| 206 | 210 | saveWorldInfo, |
| 211 | + reloadWorldInfoEditor: reloadEditor, | |
| 207 | 212 | updateWorldInfoList, |
| 208 | 213 | convertCharacterBook, |
| 214 | + getWorldInfoPrompt, | |
| 209 | 215 | CONNECT_API_MAP, |
| 210 | 216 | getTextGenServer, |
| 211 | 217 | extractMessageFromData, |
| @@ -215,10 +221,14 @@ export function getContext() { | ||
| 215 | 221 | clearChat, |
| 216 | 222 | ChatCompletionService, |
| 217 | 223 | TextCompletionService, |
| 224 | + ConnectionManagerRequestService, | |
| 218 | 225 | updateReasoningUI, |
| 219 | 226 | parseReasoningFromString, |
| 220 | 227 | unshallowCharacter, |
| 221 | 228 | unshallowGroupMembers, |
| 229 | + symbols: { | |
| 230 | + ignore: IGNORE_SYMBOL, | |
| 231 | + }, | |
| 222 | 232 | }; |
| 223 | 233 | } |
| 224 | 234 | |
| @@ -13,7 +13,6 @@ import { | ||
| 13 | 13 | DEFAULT_PRINT_TIMEOUT, |
| 14 | 14 | printCharacters, |
| 15 | 15 | } from '../script.js'; |
| 16 | -// eslint-disable-next-line no-unused-vars | |
| 17 | 16 | import { FILTER_TYPES, FILTER_STATES, DEFAULT_FILTER_STATE, isFilterState, FilterHelper } from './filters.js'; |
| 18 | 17 | |
| 19 | 18 | import { groupCandidatesFilter, groups, selected_group } from './group-chats.js'; |
| @@ -1,9 +1,9 @@ | ||
| 1 | 1 | <div data-type="assistant_note"> |
| 2 | 2 | <div> |
| 3 | 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 | 4 | <span data-i18n="Click the button to save it as a file.">Click the button to save it as a file.</span> |
| 5 | 5 | </div> |
| 6 | 6 | <div class="assistant_note_export menu_button menu_button_icon" data-i18n="[title]Export as JSONL" title="Export as JSONL"> |
| 7 | 7 | <i class="fa-solid fa-file-export"></i> |
| 8 | 8 | </div> |
| 9 | 9 | </div> |
| @@ -20,7 +20,8 @@ | ||
| 20 | 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 | 21 | <li><tt>{{user}}</tt> – <span data-i18n="help_macros_15">your current Persona username</span></li> |
| 22 | 22 | <li><tt>{{char}}</tt> – <span data-i18n="help_macros_16">the Character's name</span></li> |
| 23 | 23 | <li><tt>{{char_versionversion}}</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 | 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 | 26 | <li><tt>{{groupNotMuted}}</tt> – <span data-i18n="help_groupNotMuted">the same as {{group}}, but excludes muted members</span></li> |
| 26 | 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> |
| @@ -1,4 +0,0 @@ | ||
| 1 | -<div class="row"> | |
| 2 | - <a class="export-promptmanager-prompts-character list-group-item" data-i18n="Export for character">Export for character</a> | |
| 3 | - <span class="tooltip fa-solid fa-info-circle" data-i18n="[title]Export prompts for this character, including their order." title="Export prompts for this character, including their order."></span> | |
| 4 | -</div> | |
| @@ -1,12 +0,0 @@ | ||
| 1 | -<div id="prompt-manager-export-format-popup" class="list-group"> | |
| 2 | - <div class="prompt-manager-export-format-popup-flex"> | |
| 3 | - <div class="row"> | |
| 4 | - <a class="export-promptmanager-prompts-full list-group-item" data-i18n="Export all">Export all</a> | |
| 5 | - <span class="tooltip fa-solid fa-info-circle" data-i18n="[title]Export all your prompts to a file" title="Export all your prompts to a file"></span> | |
| 6 | - </div> | |
| 7 | - {{#if isGlobalStrategy}} | |
| 8 | - {{else}} | |
| 9 | - {{{exportForCharacter}}} | |
| 10 | - {{/if}} | |
| 11 | - </div> | |
| 12 | -</div> | |
| @@ -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> | |
| 18 | \ No newline at end of file | |
| @@ -1,4 +1,4 @@ | ||
| 1 | 1 | <div id="WIEntryHeaderTitlesPC" class="flex-container wide100p spaceBetween justifyCenter textAlignCenter" style="padding:0 47.5em0em;"> |
| 2 | 2 | <small class="flex1" data-i18n="Title/Memo">Title/Memo</small> |
| 3 | 3 | <small style="width: calc(3.5em + 10px)" data-i18n="Strategy">Strategy</small> |
| 4 | 4 | <small style="width: calc(3.5em + 20px)" data-i18n="Position">Position</small> |
| @@ -58,6 +58,8 @@ const OPENROUTER_PROVIDERS = [ | ||
| 58 | 58 | 'Minimax', |
| 59 | 59 | 'Nineteen', |
| 60 | 60 | 'Liquid', |
| 61 | + 'Stealth', | |
| 62 | + 'NCompass', | |
| 61 | 63 | 'InferenceNet', |
| 62 | 64 | 'Friendli', |
| 63 | 65 | 'AionLabs', |
| @@ -69,6 +71,9 @@ const OPENROUTER_PROVIDERS = [ | ||
| 69 | 71 | 'Targon', |
| 70 | 72 | 'Ubicloud', |
| 71 | 73 | 'Parasail', |
| 74 | + 'Phala', | |
| 75 | + 'Cent-ML', | |
| 76 | + 'Venice', | |
| 72 | 77 | '01.AI', |
| 73 | 78 | 'HuggingFace', |
| 74 | 79 | 'Mancer', |
| @@ -923,6 +928,10 @@ export function getCurrentDreamGenModelTokenizer() { | ||
| 923 | 928 | return tokenizers.YI; |
| 924 | 929 | } else if (model.id.startsWith('opus-v1-xl')) { |
| 925 | 930 | return tokenizers.LLAMA; |
| 931 | + } else if (model.id.startsWith('lucid-v1-medium')) { | |
| 932 | + return tokenizers.NEMO; | |
| 933 | + } else if (model.id.startsWith('lucid-v1-extra-large')) { | |
| 934 | + return tokenizers.LLAMA3; | |
| 926 | 935 | } else { |
| 927 | 936 | return tokenizers.MISTRAL; |
| 928 | 937 | } |
| @@ -86,7 +86,7 @@ const OOBA_DEFAULT_ORDER = [ | ||
| 86 | 86 | 'encoder_repetition_penalty', |
| 87 | 87 | 'no_repeat_ngram', |
| 88 | 88 | ]; |
| 89 | 89 | export const APHRODITE_DEFAULT_ORDER = [ |
| 90 | 90 | 'dry', |
| 91 | 91 | 'penalties', |
| 92 | 92 | 'no_repeat_ngram', |
| @@ -729,15 +729,6 @@ export function getTokenizerModel() { | ||
| 729 | 729 | return yiTokenizer; |
| 730 | 730 | } |
| 731 | 731 | |
| 732 | - if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) { | |
| 733 | - if (oai_settings.blockentropy_model.includes('llama3')) { | |
| 734 | - return llama3Tokenizer; | |
| 735 | - } | |
| 736 | - if (oai_settings.blockentropy_model.includes('miqu') || oai_settings.blockentropy_model.includes('mixtral')) { | |
| 737 | - return mistralTokenizer; | |
| 738 | - } | |
| 739 | - } | |
| 740 | - | |
| 741 | 732 | // Default to Turbo 3.5 |
| 742 | 733 | return turboTokenizer; |
| 743 | 734 | } |
| @@ -586,6 +586,7 @@ export class ToolManager { | ||
| 586 | 586 | chat_completion_sources.DEEPSEEK, |
| 587 | 587 | chat_completion_sources.MAKERSUITE, |
| 588 | 588 | chat_completion_sources.AI21, |
| 589 | + chat_completion_sources.XAI, | |
| 589 | 590 | ]; |
| 590 | 591 | return supportedSources.includes(oai_settings.chat_completion_source); |
| 591 | 592 | } |
| @@ -9,8 +9,8 @@ import { ensureImageFormatSupported, getBase64Async, humanFileSize } from './uti | ||
| 9 | 9 | export let currentUser = null; |
| 10 | 10 | export let accountsEnabled = false; |
| 11 | 11 | |
| 12 | 12 | // Extend the session every 3010 minutes |
| 13 | 13 | const SESSION_EXTEND_INTERVAL = 3010 * 60 * 1000; |
| 14 | 14 | |
| 15 | 15 | /** |
| 16 | 16 | * Enable or disable user account controls in the UI. |
| @@ -1437,6 +1437,8 @@ export async function ensureImageFormatSupported(file) { | ||
| 1437 | 1437 | 'image/tiff', |
| 1438 | 1438 | 'image/gif', |
| 1439 | 1439 | 'image/apng', |
| 1440 | + 'image/webp', | |
| 1441 | + 'image/avif', | |
| 1440 | 1442 | ]; |
| 1441 | 1443 | |
| 1442 | 1444 | if (supportedTypes.includes(file.type) || !file.type.startsWith('image/')) { |
| @@ -9,7 +9,7 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; | ||
| 9 | 9 | import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js'; |
| 10 | 10 | import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 11 | 11 | import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js'; |
| 12 | 12 | import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js'; |
| 13 | 13 | import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js'; |
| 14 | 14 | import { SlashCommandScope } from './slash-commands/SlashCommandScope.js'; |
| 15 | 15 | import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js'; |
| @@ -583,7 +583,7 @@ export function evalBoolean(rule, a, b) { | ||
| 583 | 583 | * Executes a slash command from a string (may be enclosed in quotes) and returns the result. |
| 584 | 584 | * @param {string} command Command to execute. May contain escaped macro and batch separators. |
| 585 | 585 | * @param {SlashCommandScope} [scope] The scope to use. |
| 586 | 586 | * @param {{[id:PARSER_FLAG]:boolean}import('./slash-commands/SlashCommandParser.js').ParserFlags} [parserFlags] The parser flags to use. |
| 587 | 587 | * @param {SlashCommandAbortController} [abortController] The abort controller to use. |
| 588 | 588 | * @returns {Promise<SlashCommandClosureResult>} Closure execution result |
| 589 | 589 | */ |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import { Fuse } from '../lib.js'; |
| 2 | 2 | |
| 3 | 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'; |
| 4 | 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, equalsIgnoreCaseAndAccents } from './utils.js'; |
| 5 | 5 | import { extension_settings, getContext } from './extensions.js'; |
| 6 | 6 | import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js'; |
| 7 | 7 | import { isMobile } from './RossAscends-mods.js'; |
| @@ -753,10 +753,17 @@ export const worldInfoCache = new StructuredCloneMap({ cloneOnGet: true, cloneOn | ||
| 753 | 753 | |
| 754 | 754 | /** |
| 755 | 755 | * Gets the world info based on chat messages. |
| 756 | 756 | * @param {string[]} chat - The chat messages to scan, in reverse order. |
| 757 | 757 | * @param {number} maxContext - The maximum context size of the generation. |
| 758 | 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 | 767 | * @returns {Promise<WIPromptResult>} The world info string and depth. |
| 761 | 768 | */ |
| 762 | 769 | export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { |
| @@ -778,6 +785,8 @@ export async function getWorldInfoPrompt(chat, maxContext, isDryRun) { | ||
| 778 | 785 | worldInfoAfter, |
| 779 | 786 | worldInfoExamples: activatedWorldInfo.EMEntries ?? [], |
| 780 | 787 | worldInfoDepth: activatedWorldInfo.WIDepthEntries ?? [], |
| 788 | + anBefore: activatedWorldInfo.ANBeforeEntries ?? [], | |
| 789 | + anAfter: activatedWorldInfo.ANAfterEntries ?? [], | |
| 781 | 790 | }; |
| 782 | 791 | } |
| 783 | 792 | |
| @@ -899,13 +908,12 @@ export function setWorldInfoSettings(settings, data) { | ||
| 899 | 908 | registerWorldInfoSlashCommands(); |
| 900 | 909 | } |
| 901 | 910 | |
| 902 | -function registerWorldInfoSlashCommands() { | |
| 903 | 911 | /** |
| 904 | 912 | * Reloads the editor with the specified world info file |
| 905 | 913 | * @param {string} file - The file to load in the editor |
| 906 | 914 | * @param {boolean} [loadIfNotSelected=false] - Indicates whether to load the file even if it's not currently selected |
| 907 | 915 | */ |
| 908 | 916 | export function reloadEditor(file, loadIfNotSelected = false) { |
| 909 | 917 | const currentIndex = Number($('#world_editor_select').val()); |
| 910 | 918 | const selectedIndex = world_names.indexOf(file); |
| 911 | 919 | if (selectedIndex !== -1 && (loadIfNotSelected || currentIndex === selectedIndex)) { |
| @@ -913,6 +921,7 @@ function registerWorldInfoSlashCommands() { | ||
| 913 | 921 | } |
| 914 | 922 | } |
| 915 | 923 | |
| 924 | +function registerWorldInfoSlashCommands() { | |
| 916 | 925 | /** |
| 917 | 926 | * Gets a *rough* approximation of the current chat context. |
| 918 | 927 | * Normally, it is provided externally by the prompt builder. |
| @@ -1329,6 +1338,18 @@ function registerWorldInfoSlashCommands() { | ||
| 1329 | 1338 | } |
| 1330 | 1339 | } |
| 1331 | 1340 | |
| 1341 | + async function getGlobalBooksCallback() { | |
| 1342 | + if (!selected_world_info?.length) { | |
| 1343 | + return JSON.stringify([]); | |
| 1344 | + } | |
| 1345 | + | |
| 1346 | + let entries = selected_world_info.slice(); | |
| 1347 | + | |
| 1348 | + console.debug(`[WI] Selected global world info has ${entries.length} entries`, selected_world_info); | |
| 1349 | + | |
| 1350 | + return JSON.stringify(entries); | |
| 1351 | + } | |
| 1352 | + | |
| 1332 | 1353 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1333 | 1354 | name: 'world', |
| 1334 | 1355 | callback: onWorldInfoChange, |
| @@ -1371,6 +1392,13 @@ function registerWorldInfoSlashCommands() { | ||
| 1371 | 1392 | aliases: ['getchatlore', 'getchatwi'], |
| 1372 | 1393 | })); |
| 1373 | 1394 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1395 | + name: 'getglobalbooks', | |
| 1396 | + callback: getGlobalBooksCallback, | |
| 1397 | + returns: 'list of selected lorebook names', | |
| 1398 | + helpString: 'Get a list of names of the selected global lorebooks and pass it down the pipe.', | |
| 1399 | + aliases: ['getgloballore', 'getglobalwi'], | |
| 1400 | + })); | |
| 1401 | + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | |
| 1374 | 1402 | name: 'getpersonabook', |
| 1375 | 1403 | callback: getPersonaBookCallback, |
| 1376 | 1404 | returns: 'lorebook name', |
| @@ -2199,7 +2227,7 @@ function verifyWorldInfoSearchSortRule() { | ||
| 2199 | 2227 | * Use `originalWIDataKeyMap` to find the correct value to be set. |
| 2200 | 2228 | * |
| 2201 | 2229 | * @param {object} data - The data object containing the original data entries. |
| 2202 | 2230 | * @param {stringnumber} uid - The unique identifier of the data entry. |
| 2203 | 2231 | * @param {string} key - The key of the value to be set. |
| 2204 | 2232 | * @param {any} value - The value to be set. |
| 2205 | 2233 | */ |
| @@ -2223,7 +2251,9 @@ export function setWIOriginalDataValue(data, uid, key, value) { | ||
| 2223 | 2251 | */ |
| 2224 | 2252 | export function deleteWIOriginalDataValue(data, uid) { |
| 2225 | 2253 | if (data.originalData && Array.isArray(data.originalData.entries)) { |
| 2226 | - const originalIndex = data.originalData.entries.findIndex(x => x.uid === uid); | |
| 2254 | + // Non-strict equality is used here to allow for both string and number comparisons | |
| 2255 | + // @eslint-disable-next-line eqeqeq | |
| 2256 | + const originalIndex = data.originalData.entries.findIndex(x => x.uid == uid); | |
| 2227 | 2257 | |
| 2228 | 2258 | if (originalIndex >= 0) { |
| 2229 | 2259 | data.originalData.entries.splice(originalIndex, 1); |
| @@ -2671,8 +2701,10 @@ export async function getWorldEntry(name, data, entry) { | ||
| 2671 | 2701 | $(counter).text(numberOfTokens); |
| 2672 | 2702 | }, debounce_timeout.relaxed); |
| 2673 | 2703 | |
| 2704 | + const contentInputId = `world_entry_content_${entry.uid}`; | |
| 2674 | 2705 | const contentInput = template.find('textarea[name="content"]'); |
| 2675 | 2706 | contentInput.data('uid', entry.uid); |
| 2707 | + contentInput.attr('id', contentInputId); | |
| 2676 | 2708 | contentInput.on('input', async function (_, { skipCount } = {}) { |
| 2677 | 2709 | const uid = $(this).data('uid'); |
| 2678 | 2710 | const value = $(this).val(); |
| @@ -2689,7 +2721,9 @@ export async function getWorldEntry(name, data, entry) { | ||
| 2689 | 2721 | countTokensDebounced(counter, value); |
| 2690 | 2722 | }); |
| 2691 | 2723 | contentInput.val(entry.content).trigger('input', { skipCount: true }); |
| 2692 | - //initScrollHeight(contentInput); | |
| 2724 | + | |
| 2725 | + const contentExpandButton = template.find('.editor_maximize'); | |
| 2726 | + contentExpandButton.attr('data-for', contentInputId); | |
| 2693 | 2727 | |
| 2694 | 2728 | template.find('.inline-drawer-toggle').on('click', function () { |
| 2695 | 2729 | if (counter.data('first-run')) { |
| @@ -3130,6 +3164,84 @@ export async function getWorldEntry(name, data, entry) { | ||
| 3130 | 3164 | updateEditor(navigation_option.previous); |
| 3131 | 3165 | }); |
| 3132 | 3166 | |
| 3167 | + // move button | |
| 3168 | + const moveButton = template.find('.move_entry_button'); | |
| 3169 | + moveButton.attr('data-uid', entry.uid); | |
| 3170 | + moveButton.attr('data-current-world', name); | |
| 3171 | + moveButton.on('click', async function (e) { | |
| 3172 | + e.stopPropagation(); | |
| 3173 | + const sourceUid = $(this).attr('data-uid'); | |
| 3174 | + const sourceWorld = $(this).attr('data-current-world'); | |
| 3175 | + const sourceWorldInfo = await loadWorldInfo(sourceWorld); | |
| 3176 | + if (!sourceWorldInfo) { | |
| 3177 | + return; | |
| 3178 | + } | |
| 3179 | + const sourceName = sourceWorldInfo.entries[sourceUid]?.comment; | |
| 3180 | + if (sourceName === undefined) { | |
| 3181 | + return; | |
| 3182 | + } | |
| 3183 | + | |
| 3184 | + const select = document.createElement('select'); | |
| 3185 | + select.id = 'move_entry_target_select'; | |
| 3186 | + select.classList.add('text_pole', 'wide100p', 'marginTop10'); | |
| 3187 | + | |
| 3188 | + const defaultOption = document.createElement('option'); | |
| 3189 | + defaultOption.value = ''; | |
| 3190 | + defaultOption.textContent = `-- ${t`Select Target Lorebook`} --`; | |
| 3191 | + select.appendChild(defaultOption); | |
| 3192 | + | |
| 3193 | + let selectableWorldCount = 0; | |
| 3194 | + world_names.forEach(worldName => { | |
| 3195 | + if (worldName !== sourceWorld) { // Exclude current world | |
| 3196 | + const option = document.createElement('option'); | |
| 3197 | + option.value = world_names.indexOf(worldName).toString(); | |
| 3198 | + option.textContent = worldName; | |
| 3199 | + select.appendChild(option); | |
| 3200 | + selectableWorldCount++; | |
| 3201 | + } | |
| 3202 | + }); | |
| 3203 | + | |
| 3204 | + if (selectableWorldCount === 0) { | |
| 3205 | + toastr.warning(t`There are no other lorebooks to move to.`); | |
| 3206 | + return; | |
| 3207 | + } | |
| 3208 | + | |
| 3209 | + // Create wrapper div | |
| 3210 | + const wrapper = document.createElement('div'); | |
| 3211 | + wrapper.textContent = t`Move "${sourceName}" to:`; | |
| 3212 | + | |
| 3213 | + // Create container and append elements | |
| 3214 | + const container = document.createElement('div'); | |
| 3215 | + container.appendChild(wrapper); | |
| 3216 | + container.appendChild(select); | |
| 3217 | + | |
| 3218 | + let selectedWorldIndex = -1; | |
| 3219 | + select.addEventListener('change', function() { | |
| 3220 | + selectedWorldIndex = this.value === '' ? -1 : Number(this.value); | |
| 3221 | + }); | |
| 3222 | + | |
| 3223 | + const popupConfirm = await callGenericPopup(container, POPUP_TYPE.CONFIRM, '', { | |
| 3224 | + okButton: t`Move`, | |
| 3225 | + cancelButton: t`Cancel`, | |
| 3226 | + }); | |
| 3227 | + if (!popupConfirm) { | |
| 3228 | + return; | |
| 3229 | + } | |
| 3230 | + | |
| 3231 | + if (selectedWorldIndex === -1) { | |
| 3232 | + return; | |
| 3233 | + } | |
| 3234 | + | |
| 3235 | + const selectedValue = world_names[selectedWorldIndex]; | |
| 3236 | + | |
| 3237 | + if (!selectedValue) { | |
| 3238 | + toastr.warning(t`Please select a target lorebook.`); | |
| 3239 | + return; | |
| 3240 | + } | |
| 3241 | + | |
| 3242 | + await moveWorldInfoEntry(sourceWorld, selectedValue, sourceUid); | |
| 3243 | + }); | |
| 3244 | + | |
| 3133 | 3245 | // scan depth |
| 3134 | 3246 | const scanDepthInput = template.find('input[name="scanDepth"]'); |
| 3135 | 3247 | scanDepthInput.data('uid', entry.uid); |
| @@ -3493,6 +3605,10 @@ async function renameWorldInfo(name, data) { | ||
| 3493 | 3605 | console.debug('World info rename cancelled'); |
| 3494 | 3606 | return; |
| 3495 | 3607 | } |
| 3608 | + if (equalsIgnoreCaseAndAccents(oldName, newName)) { | |
| 3609 | + toastr.warning(t`Name not accepted, as it is the same as before (ignoring case and accents).`, t`Rename World Info`); | |
| 3610 | + return; | |
| 3611 | + } | |
| 3496 | 3612 | |
| 3497 | 3613 | const entryPreviouslySelected = selected_world_info.findIndex((e) => e === oldName); |
| 3498 | 3614 | |
| @@ -3862,7 +3978,14 @@ function parseDecorators(content) { | ||
| 3862 | 3978 | * @param {string[]} chat The chat messages to scan, in reverse order. |
| 3863 | 3979 | * @param {number} maxContext The maximum context size of the generation. |
| 3864 | 3980 | * @param {boolean} isDryRun Whether to perform a dry run. |
| 3865 | - * @typedef {{ worldInfoBefore: string, worldInfoAfter: string, EMEntries: any[], WIDepthEntries: any[], allActivatedEntries: Set<any> }} WIActivated | |
| 3981 | + * @typedef {object} WIActivated | |
| 3982 | + * @property {string} worldInfoBefore The world info before the chat. | |
| 3983 | + * @property {string} worldInfoAfter The world info after the chat. | |
| 3984 | + * @property {any[]} EMEntries The entries for examples. | |
| 3985 | + * @property {any[]} WIDepthEntries The depth entries. | |
| 3986 | + * @property {any[]} ANBeforeEntries The entries before Author's Note. | |
| 3987 | + * @property {any[]} ANAfterEntries The entries after Author's Note. | |
| 3988 | + * @property {Set<any>} allActivatedEntries All entries. | |
| 3866 | 3989 | * @returns {Promise<WIActivated>} The world info activated. |
| 3867 | 3990 | */ |
| 3868 | 3991 | export async function checkWorldInfo(chat, maxContext, isDryRun) { |
| @@ -3906,7 +4029,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | ||
| 3906 | 4029 | timedEffects.checkTimedEffects(); |
| 3907 | 4030 | |
| 3908 | 4031 | if (sortedEntries.length === 0) { |
| 3909 | 4032 | return { worldInfoBefore: '', worldInfoAfter: '', WIDepthEntries: [], EMEntries: [], ANBeforeEntries: [], ANAfterEntries: [], allActivatedEntries: new Set() }; |
| 3910 | 4033 | } |
| 3911 | 4034 | |
| 3912 | 4035 | /** @type {number[]} Represents the delay levels for entries that are delayed until recursion */ |
| @@ -4355,7 +4478,7 @@ export async function checkWorldInfo(chat, maxContext, isDryRun) { | ||
| 4355 | 4478 | console.log(`[WI] ${isDryRun ? 'Hypothetically adding' : 'Adding'} ${allActivatedEntries.size} entries to prompt`, Array.from(allActivatedEntries.values())); |
| 4356 | 4479 | console.debug(`[WI] --- DONE${isDryRun ? ' (DRY RUN)' : ''} ---`); |
| 4357 | 4480 | |
| 4358 | 4481 | return { worldInfoBefore, worldInfoAfter, EMEntries, WIDepthEntries, ANBeforeEntries: ANTopEntries, ANAfterEntries: ANBottomEntries, allActivatedEntries: new Set(allActivatedEntries.values()) }; |
| 4359 | 4482 | } |
| 4360 | 4483 | |
| 4361 | 4484 | /** |
| @@ -5251,3 +5374,99 @@ jQuery(() => { | ||
| 5251 | 5374 | }); |
| 5252 | 5375 | }); |
| 5253 | 5376 | }); |
| 5377 | + | |
| 5378 | +/** | |
| 5379 | + * Moves a World Info entry from a source lorebook to a target lorebook. | |
| 5380 | + * | |
| 5381 | + * @param {string} sourceName - The name of the source lorebook file. | |
| 5382 | + * @param {string} targetName - The name of the target lorebook file. | |
| 5383 | + * @param {string|number} uid - The UID of the entry to move from the source lorebook. | |
| 5384 | + * @returns {Promise<boolean>} True if the move was successful, false otherwise. | |
| 5385 | + */ | |
| 5386 | +export async function moveWorldInfoEntry(sourceName, targetName, uid) { | |
| 5387 | + if (sourceName === targetName) { | |
| 5388 | + return false; | |
| 5389 | + } | |
| 5390 | + | |
| 5391 | + if (!world_names.includes(sourceName)) { | |
| 5392 | + toastr.error(t`Source lorebook '${sourceName}' not found.`); | |
| 5393 | + console.error(`[WI Move] Source lorebook '${sourceName}' does not exist.`); | |
| 5394 | + return false; | |
| 5395 | + } | |
| 5396 | + | |
| 5397 | + if (!world_names.includes(targetName)) { | |
| 5398 | + toastr.error(t`Target lorebook '${targetName}' not found.`); | |
| 5399 | + console.error(`[WI Move] Target lorebook '${targetName}' does not exist.`); | |
| 5400 | + return false; | |
| 5401 | + } | |
| 5402 | + | |
| 5403 | + const entryUidString = String(uid); | |
| 5404 | + | |
| 5405 | + try { | |
| 5406 | + const sourceData = await loadWorldInfo(sourceName); | |
| 5407 | + const targetData = await loadWorldInfo(targetName); | |
| 5408 | + | |
| 5409 | + if (!sourceData || !sourceData.entries) { | |
| 5410 | + toastr.error(t`Failed to load data for source lorebook '${sourceName}'.`); | |
| 5411 | + console.error(`[WI Move] Could not load source data for '${sourceName}'.`); | |
| 5412 | + return false; | |
| 5413 | + } | |
| 5414 | + if (!targetData || !targetData.entries) { | |
| 5415 | + toastr.error(t`Failed to load data for target lorebook '${targetName}'.`); | |
| 5416 | + console.error(`[WI Move] Could not load target data for '${targetName}'.`); | |
| 5417 | + return false; | |
| 5418 | + } | |
| 5419 | + | |
| 5420 | + if (!sourceData.entries[entryUidString]) { | |
| 5421 | + toastr.error(t`Entry not found in source lorebook '${sourceName}'.`); | |
| 5422 | + console.error(`[WI Move] Entry UID ${entryUidString} not found in '${sourceName}'.`); | |
| 5423 | + return false; | |
| 5424 | + } | |
| 5425 | + | |
| 5426 | + const entryToMove = structuredClone(sourceData.entries[entryUidString]); | |
| 5427 | + | |
| 5428 | + | |
| 5429 | + const newUid = getFreeWorldEntryUid(targetData); | |
| 5430 | + if (newUid === null) { | |
| 5431 | + console.error(`[WI Move] Failed to get a free UID in '${targetName}'.`); | |
| 5432 | + return false; | |
| 5433 | + } | |
| 5434 | + | |
| 5435 | + entryToMove.uid = newUid; | |
| 5436 | + // Place the entry at the end of the target lorebook | |
| 5437 | + const maxDisplayIndex = Object.values(targetData.entries).reduce((max, entry) => Math.max(max, entry.displayIndex ?? -1), -1); | |
| 5438 | + entryToMove.displayIndex = maxDisplayIndex + 1; | |
| 5439 | + | |
| 5440 | + targetData.entries[newUid] = entryToMove; | |
| 5441 | + | |
| 5442 | + delete sourceData.entries[entryUidString]; | |
| 5443 | + // Remove from originalData if it exists | |
| 5444 | + deleteWIOriginalDataValue(sourceData, entryUidString); | |
| 5445 | + // TODO: setWIOriginalDataValue | |
| 5446 | + console.debug(`[WI Move] Removed entry UID ${entryUidString} from source '${sourceName}'.`); | |
| 5447 | + | |
| 5448 | + | |
| 5449 | + await saveWorldInfo(targetName, targetData, true); | |
| 5450 | + console.debug(`[WI Move] Saved target lorebook '${targetName}'.`); | |
| 5451 | + await saveWorldInfo(sourceName, sourceData, true); | |
| 5452 | + console.debug(`[WI Move] Saved source lorebook '${sourceName}'.`); | |
| 5453 | + | |
| 5454 | + | |
| 5455 | + console.log(`[WI Move] ${entryToMove.comment} moved successfully to '${targetName}'.`); | |
| 5456 | + | |
| 5457 | + // Check if the currently viewed book in the editor is the source or target and reload it | |
| 5458 | + const currentEditorBookIndex = Number($('#world_editor_select').val()); | |
| 5459 | + if (!isNaN(currentEditorBookIndex)) { | |
| 5460 | + const currentEditorBookName = world_names[currentEditorBookIndex]; | |
| 5461 | + if (currentEditorBookName === sourceName || currentEditorBookName === targetName) { | |
| 5462 | + reloadEditor(currentEditorBookName); | |
| 5463 | + } | |
| 5464 | + } | |
| 5465 | + | |
| 5466 | + return true; | |
| 5467 | + } catch (error) { | |
| 5468 | + toastr.error(t`An unexpected error occurred while moving the entry: ${error.message}`); | |
| 5469 | + console.error('[WI Move] Unexpected error:', error); | |
| 5470 | + return false; | |
| 5471 | + } | |
| 5472 | +} | |
| @@ -2086,6 +2086,15 @@ body[data-stscript-style] .hljs.language-stscript { | ||
| 2086 | 2086 | } |
| 2087 | 2087 | } |
| 2088 | 2088 | |
| 2089 | + >.head>.rawQuotes { | |
| 2090 | + padding: 0 0.5em; | |
| 2091 | + cursor: help; | |
| 2092 | + | |
| 2093 | + &:hover { | |
| 2094 | + text-decoration: 1px dotted underline; | |
| 2095 | + } | |
| 2096 | + } | |
| 2097 | + | |
| 2089 | 2098 | >.head>.source { |
| 2090 | 2099 | padding: 0 0.5em; |
| 2091 | 2100 | cursor: help; |
| @@ -2911,6 +2920,35 @@ select option:not(:checked) { | ||
| 2911 | 2920 | pointer-events: none; |
| 2912 | 2921 | } |
| 2913 | 2922 | |
| 2923 | +.menu_button.toggleable { | |
| 2924 | + padding-left: 20px; | |
| 2925 | +} | |
| 2926 | + | |
| 2927 | +.menu_button.toggleable.toggled { | |
| 2928 | + border-color: var(--active); | |
| 2929 | +} | |
| 2930 | + | |
| 2931 | +.menu_button.toggleable:not(.toggled) { | |
| 2932 | + filter: brightness(80%); | |
| 2933 | +} | |
| 2934 | + | |
| 2935 | +.menu_button.toggleable::before { | |
| 2936 | + font-family: "Font Awesome 6 Free"; | |
| 2937 | + margin-left: 10px; | |
| 2938 | + position: absolute; | |
| 2939 | + left: 0; | |
| 2940 | +} | |
| 2941 | + | |
| 2942 | +.menu_button.toggleable.toggled::before { | |
| 2943 | + content: "\f00c"; | |
| 2944 | + color: var(--active); | |
| 2945 | +} | |
| 2946 | + | |
| 2947 | +.menu_button.toggleable:not(.toggled)::before { | |
| 2948 | + content: "\f00d"; | |
| 2949 | + color: var(--fullred); | |
| 2950 | +} | |
| 2951 | + | |
| 2914 | 2952 | .fav_on { |
| 2915 | 2953 | color: var(--golden) !important; |
| 2916 | 2954 | } |
| @@ -2921,7 +2959,7 @@ select option:not(:checked) { | ||
| 2921 | 2959 | } |
| 2922 | 2960 | |
| 2923 | 2961 | .menu_button.togglable:not(.toggleEnabled) { |
| 2924 | 2962 | color: redvar(--fullred); |
| 2925 | 2963 | } |
| 2926 | 2964 | |
| 2927 | 2965 | .displayBlock { |
| @@ -4957,6 +4995,7 @@ a:hover { | ||
| 4957 | 4995 | max-width: 100%; |
| 4958 | 4996 | max-height: 40vh; |
| 4959 | 4997 | image-rendering: -webkit-optimize-contrast; |
| 4998 | + cursor: pointer; | |
| 4960 | 4999 | } |
| 4961 | 5000 | |
| 4962 | 5001 | .mes_img_swipes, |
| @@ -20,6 +20,7 @@ import bodyParser from 'body-parser'; | ||
| 20 | 20 | import open from 'open'; |
| 21 | 21 | |
| 22 | 22 | // local library imports |
| 23 | +import './src/fetch-patch.js'; | |
| 23 | 24 | import { serverEvents, EVENT_NAMES } from './src/server-events.js'; |
| 24 | 25 | import { CommandLineParser } from './src/command-line.js'; |
| 25 | 26 | import { loadPlugins } from './src/plugin-loader.js'; |
| @@ -66,6 +67,7 @@ import { init as statsInit, onExit as statsOnExit } from './src/endpoints/stats. | ||
| 66 | 67 | import { checkForNewContent } from './src/endpoints/content-manager.js'; |
| 67 | 68 | import { init as settingsInit } from './src/endpoints/settings.js'; |
| 68 | 69 | import { redirectDeprecatedEndpoints, ServerStartup, setupPrivateEndpoints } from './src/server-startup.js'; |
| 70 | +import { diskCache } from './src/endpoints/characters.js'; | |
| 69 | 71 | |
| 70 | 72 | // Unrestrict console logs display limit |
| 71 | 73 | util.inspect.defaultOptions.maxArrayLength = null; |
| @@ -149,7 +151,7 @@ if (cliArgs.enableCorsProxy) { | ||
| 149 | 151 | |
| 150 | 152 | app.use(cookieSession({ |
| 151 | 153 | name: getCookieSessionName(), |
| 152 | 154 | sameSite: 'strictlax', |
| 153 | 155 | httpOnly: true, |
| 154 | 156 | maxAge: getSessionCookieAge(), |
| 155 | 157 | secret: getCookieSecret(globalThis.DATA_ROOT), |
| @@ -212,6 +214,17 @@ app.get('/', getCacheBusterMiddleware(), (request, response) => { | ||
| 212 | 214 | return response.sendFile('index.html', { root: path.join(process.cwd(), 'public') }); |
| 213 | 215 | }); |
| 214 | 216 | |
| 217 | +// Callback endpoint for OAuth PKCE flows (e.g. OpenRouter) | |
| 218 | +app.get('/callback/:source?', (request, response) => { | |
| 219 | + const source = request.params.source; | |
| 220 | + const query = request.url.split('?')[1]; | |
| 221 | + const searchParams = new URLSearchParams(); | |
| 222 | + source && searchParams.set('source', source); | |
| 223 | + query && searchParams.set('query', query); | |
| 224 | + const path = `/?${searchParams.toString()}`; | |
| 225 | + return response.redirect(307, path); | |
| 226 | +}); | |
| 227 | + | |
| 215 | 228 | // Host login page |
| 216 | 229 | app.get('/login', loginPageMiddleware); |
| 217 | 230 | |
| @@ -267,7 +280,8 @@ async function preSetupTasks() { | ||
| 267 | 280 | |
| 268 | 281 | const directories = await getUserDirectoriesList(); |
| 269 | 282 | await checkForNewContent(directories); |
| 270 | 283 | await ensureThumbnailCache(directories); |
| 284 | + await diskCache.verify(directories); | |
| 271 | 285 | cleanUploads(); |
| 272 | 286 | migrateAccessLog(); |
| 273 | 287 | |
| @@ -286,6 +300,7 @@ async function preSetupTasks() { | ||
| 286 | 300 | if (typeof cleanupPlugins === 'function') { |
| 287 | 301 | await cleanupPlugins(); |
| 288 | 302 | } |
| 303 | + diskCache.dispose(); | |
| 289 | 304 | setWindowTitle(consoleTitle); |
| 290 | 305 | process.exit(); |
| 291 | 306 | }; |
| @@ -315,8 +330,12 @@ async function postSetupTasks(result) { | ||
| 315 | 330 | const autorunUrl = cliArgs.getAutorunUrl(autorunHostname); |
| 316 | 331 | |
| 317 | 332 | if (cliArgs.autorun) { |
| 333 | + try { | |
| 318 | 334 | console.log('Launching in a browser...'); |
| 319 | 335 | await open(autorunUrl.toString()); |
| 336 | + } catch (error) { | |
| 337 | + console.error('Failed to launch the browser. Open the URL manually.'); | |
| 338 | + } | |
| 320 | 339 | } |
| 321 | 340 | |
| 322 | 341 | setWindowTitle('SillyTavern WebServer'); |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | import fs from 'node:fs'; |
| 2 | 2 | import { Buffer } from 'node:buffer'; |
| 3 | 3 | |
| 4 | 4 | import encode from './png-chunks-/encode.js'; |
| 5 | 5 | import extract from 'png-chunks-extract'; |
| 6 | 6 | import PNGtext from 'png-chunk-text'; |
| 7 | 7 | |
| @@ -81,9 +81,9 @@ export const read = (image) => { | ||
| 81 | 81 | * Parses a card image and returns the character metadata. |
| 82 | 82 | * @param {string} cardUrl Path to the card image |
| 83 | 83 | * @param {string} format File format |
| 84 | 84 | * @returns {Promise<string>} Character data |
| 85 | 85 | */ |
| 86 | 86 | export const parse = async (cardUrl, format) => { |
| 87 | 87 | let fileFormat = format === undefined ? 'png' : format; |
| 88 | 88 | |
| 89 | 89 | switch (fileFormat) { |
| @@ -43,6 +43,7 @@ export const USER_DIRECTORY_TEMPLATE = Object.freeze({ | ||
| 43 | 43 | vectors: 'vectors', |
| 44 | 44 | backups: 'backups', |
| 45 | 45 | sysprompt: 'sysprompt', |
| 46 | + reasoning: 'reasoning', | |
| 46 | 47 | }); |
| 47 | 48 | |
Diff truncated