Merge pull request #4794 from SillyTavern/staging Staging

9c9be90821ffd6132b40b5f04982522a61d7ad30

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

Signed
175 files changed, +3462 -4378Ignore whitespace
.github/workflows/pr-auto-manager.yml+32 -0
@@ -56,6 +56,38 @@ jobs:
56 dist/56 dist/
57 lib/57 lib/
5858
59 run-tests:
60 name: ✅ Run Unit Tests on PR
61 runs-on: ubuntu-latest
62 # Only needs to run when code is changed
63 if: always() && (github.event.action == 'opened' || github.event.action == 'synchronize')
64
65 steps:
66 - name: Checkout Repository
67 # Checkout
68 # https://github.com/marketplace/actions/checkout
69 uses: actions/checkout@v4.2.2
70 with:
71 ref: ${{ github.event.pull_request.head.sha }}
72 repository: ${{ github.event.pull_request.head.repo.full_name }}
73
74 - name: Setup Node.js
75 # Setup Node.js environment
76 # https://github.com/marketplace/actions/setup-node-js-environment
77 uses: actions/setup-node@v4.3.0
78 with:
79 node-version: 20
80 cache: 'npm'
81
82 - name: Install root dependencies
83 run: npm ci
84
85 - name: Install test dependencies
86 run: npm ci --prefix tests
87
88 - name: Run unit tests
89 run: npm run test:unit --prefix tests
90
59 label-by-size:91 label-by-size:
60 name: 🏷️ Label PR by Size92 name: 🏷️ Label PR by Size
61 # This job should run after all others, to prevent possible concurrency issues93 # This job should run after all others, to prevent possible concurrency issues
.gitignore+2 -1
@@ -55,4 +55,5 @@ public/scripts/extensions/third-party
55.env55.env
56/StartDev.bat56/StartDev.bat
57yarn.lock57yarn.lock
58*.code-workspace
58 \ No newline at end of file \ No newline at end of file
58*.code-workspace
59test-results/
default/content/index.json+2 -218
@@ -140,75 +140,11 @@
140 "type": "workflow"140 "type": "workflow"
141 },141 },
142 {142 {
143 "filename": "presets/kobold/Ace of Spades.json",
144 "type": "kobold_preset"
145 },
146 {
147 "filename": "presets/kobold/Basic Coherence.json",
148 "type": "kobold_preset"
149 },
150 {
151 "filename": "presets/kobold/Best Guess.json",
152 "type": "kobold_preset"
153 },
154 {
155 "filename": "presets/kobold/Coherent Creativity.json",
156 "type": "kobold_preset"
157 },
158 {
159 "filename": "presets/kobold/Deterministic.json",143 "filename": "presets/kobold/Deterministic.json",
160 "type": "kobold_preset"144 "type": "kobold_preset"
161 },145 },
162 {146 {
163 "filename": "presets/kobold/Genesis.json",147 "filename": "presets/kobold/Neutral.json",
164 "type": "kobold_preset"
165 },
166 {
167 "filename": "presets/kobold/Godlike.json",
168 "type": "kobold_preset"
169 },
170 {
171 "filename": "presets/kobold/Good Winds.json",
172 "type": "kobold_preset"
173 },
174 {
175 "filename": "presets/kobold/Liminal Drift.json",
176 "type": "kobold_preset"
177 },
178 {
179 "filename": "presets/kobold/Low Rider.json",
180 "type": "kobold_preset"
181 },
182 {
183 "filename": "presets/kobold/Luna Moth.json",
184 "type": "kobold_preset"
185 },
186 {
187 "filename": "presets/kobold/Mayday.json",
188 "type": "kobold_preset"
189 },
190 {
191 "filename": "presets/kobold/Miro Bronze.json",
192 "type": "kobold_preset"
193 },
194 {
195 "filename": "presets/kobold/Miro Gold.json",
196 "type": "kobold_preset"
197 },
198 {
199 "filename": "presets/kobold/Miro Silver.json",
200 "type": "kobold_preset"
201 },
202 {
203 "filename": "presets/kobold/Ouroboros.json",
204 "type": "kobold_preset"
205 },
206 {
207 "filename": "presets/kobold/Pleasing Results.json",
208 "type": "kobold_preset"
209 },
210 {
211 "filename": "presets/kobold/Pro Writer.json",
212 "type": "kobold_preset"148 "type": "kobold_preset"
213 },149 },
214 {150 {
@@ -216,22 +152,6 @@
216 "type": "kobold_preset"152 "type": "kobold_preset"
217 },153 },
218 {154 {
219 "filename": "presets/kobold/Space Alien.json",
220 "type": "kobold_preset"
221 },
222 {
223 "filename": "presets/kobold/Storywriter.json",
224 "type": "kobold_preset"
225 },
226 {
227 "filename": "presets/kobold/TFS-with-Top-A.json",
228 "type": "kobold_preset"
229 },
230 {
231 "filename": "presets/kobold/Titanic.json",
232 "type": "kobold_preset"
233 },
234 {
235 "filename": "presets/kobold/Universal-Creative.json",155 "filename": "presets/kobold/Universal-Creative.json",
236 "type": "kobold_preset"156 "type": "kobold_preset"
237 },157 },
@@ -244,10 +164,6 @@
244 "type": "kobold_preset"164 "type": "kobold_preset"
245 },165 },
246 {166 {
247 "filename": "presets/kobold/simple-proxy-for-tavern.json",
248 "type": "kobold_preset"
249 },
250 {
251 "filename": "presets/novel/Asper-Kayra.json",167 "filename": "presets/novel/Asper-Kayra.json",
252 "type": "novel_preset"168 "type": "novel_preset"
253 },169 },
@@ -344,22 +260,6 @@
344 "type": "novel_preset"260 "type": "novel_preset"
345 },261 },
346 {262 {
347 "filename": "presets/textgen/Asterism.json",
348 "type": "textgen_preset"
349 },
350 {
351 "filename": "presets/textgen/Beam Search.json",
352 "type": "textgen_preset"
353 },
354 {
355 "filename": "presets/textgen/Big O.json",
356 "type": "textgen_preset"
357 },
358 {
359 "filename": "presets/textgen/Contrastive Search.json",
360 "type": "textgen_preset"
361 },
362 {
363 "filename": "presets/textgen/Default.json",263 "filename": "presets/textgen/Default.json",
364 "type": "textgen_preset"264 "type": "textgen_preset"
365 },265 },
@@ -368,99 +268,7 @@
368 "type": "textgen_preset"268 "type": "textgen_preset"
369 },269 },
370 {270 {
371 "filename": "presets/textgen/Divine Intellect.json",271 "filename": "presets/textgen/Neutral.json",
372 "type": "textgen_preset"
373 },
374 {
375 "filename": "presets/textgen/Kobold (Godlike).json",
376 "type": "textgen_preset"
377 },
378 {
379 "filename": "presets/textgen/Kobold (Liminal Drift).json",
380 "type": "textgen_preset"
381 },
382 {
383 "filename": "presets/textgen/LLaMa-Precise.json",
384 "type": "textgen_preset"
385 },
386 {
387 "filename": "presets/textgen/Midnight Enigma.json",
388 "type": "textgen_preset"
389 },
390 {
391 "filename": "presets/textgen/Miro Bronze.json",
392 "type": "textgen_preset"
393 },
394 {
395 "filename": "presets/textgen/Miro Gold.json",
396 "type": "textgen_preset"
397 },
398 {
399 "filename": "presets/textgen/Miro Silver.json",
400 "type": "textgen_preset"
401 },
402 {
403 "filename": "presets/textgen/Mirostat.json",
404 "type": "textgen_preset"
405 },
406 {
407 "filename": "presets/textgen/Naive.json",
408 "type": "textgen_preset"
409 },
410 {
411 "filename": "presets/textgen/NovelAI (Best Guess).json",
412 "type": "textgen_preset"
413 },
414 {
415 "filename": "presets/textgen/NovelAI (Decadence).json",
416 "type": "textgen_preset"
417 },
418 {
419 "filename": "presets/textgen/NovelAI (Genesis).json",
420 "type": "textgen_preset"
421 },
422 {
423 "filename": "presets/textgen/NovelAI (Lycaenidae).json",
424 "type": "textgen_preset"
425 },
426 {
427 "filename": "presets/textgen/NovelAI (Ouroboros).json",
428 "type": "textgen_preset"
429 },
430 {
431 "filename": "presets/textgen/NovelAI (Pleasing Results).json",
432 "type": "textgen_preset"
433 },
434 {
435 "filename": "presets/textgen/NovelAI (Sphinx Moth).json",
436 "type": "textgen_preset"
437 },
438 {
439 "filename": "presets/textgen/NovelAI (Storywriter).json",
440 "type": "textgen_preset"
441 },
442 {
443 "filename": "presets/textgen/Shortwave.json",
444 "type": "textgen_preset"
445 },
446 {
447 "filename": "presets/textgen/Simple-1.json",
448 "type": "textgen_preset"
449 },
450 {
451 "filename": "presets/textgen/Space Alien.json",
452 "type": "textgen_preset"
453 },
454 {
455 "filename": "presets/textgen/StarChat.json",
456 "type": "textgen_preset"
457 },
458 {
459 "filename": "presets/textgen/TFS-with-Top-A.json",
460 "type": "textgen_preset"
461 },
462 {
463 "filename": "presets/textgen/Titanic.json",
464 "type": "textgen_preset"272 "type": "textgen_preset"
465 },273 },
466 {274 {
@@ -476,14 +284,6 @@
476 "type": "textgen_preset"284 "type": "textgen_preset"
477 },285 },
478 {286 {
479 "filename": "presets/textgen/Yara.json",
480 "type": "textgen_preset"
481 },
482 {
483 "filename": "presets/textgen/simple-proxy-for-tavern.json",
484 "type": "textgen_preset"
485 },
486 {
487 "filename": "presets/openai/Default.json",287 "filename": "presets/openai/Default.json",
488 "type": "openai_preset"288 "type": "openai_preset"
489 },289 },
@@ -508,14 +308,6 @@
508 "type": "context"308 "type": "context"
509 },309 },
510 {310 {
511 "filename": "presets/context/DreamGen Role-Play V1 ChatML.json",
512 "type": "context"
513 },
514 {
515 "filename": "presets/context/DreamGen Role-Play V1 Llama3.json",
516 "type": "context"
517 },
518 {
519 "filename": "presets/context/Libra-32B.json",311 "filename": "presets/context/Libra-32B.json",
520 "type": "context"312 "type": "context"
521 },313 },
@@ -588,14 +380,6 @@
588 "type": "instruct"380 "type": "instruct"
589 },381 },
590 {382 {
591 "filename": "presets/instruct/DreamGen Role-Play V1 ChatML.json",
592 "type": "instruct"
593 },
594 {
595 "filename": "presets/instruct/DreamGen Role-Play V1 Llama3.json",
596 "type": "instruct"
597 },
598 {
599 "filename": "presets/instruct/Koala.json",383 "filename": "presets/instruct/Koala.json",
600 "type": "instruct"384 "type": "instruct"
601 },385 },
default/content/presets/context/DreamGen Role-Play V1 ChatML.json+0 -14
@@ -1,14 +0,0 @@
1{
2 "story_string": "{{#if anchorBefore}}{{anchorBefore}}\n{{/if}}{{#if system}}{{system}}\n\n\n{{/if}}## Overall plot description:\n\n{{#if scenario}}{{scenario}}{{else}}Conversation between {{char}} and {{user}}.{{/if}}{{#if wiBefore}}\n\n{{wiBefore}}{{/if}}\n\n\n## Characters:\n\n### {{char}}\n\n{{#if description}}{{description}}\n\n{{/if}}{{#if personality}}{{personality}}\n\n{{/if}}### {{user}}\n\n{{#if persona}}{{persona}}{{else}}{{user}} is the protagonist of the role-play.{{/if}}{{#if wiAfter}}\n\n{{wiAfter}}{{/if}}{{#if mesExamples}}\n\n{{mesExamples}}{{/if}}{{#if anchorAfter}}{{anchorAfter}}\n{{/if}}{{trim}}",
3 "example_separator": "",
4 "chat_start": "",
5 "use_stop_strings": false,
6 "names_as_stop_strings": true,
7 "story_string_position": 0,
8 "story_string_depth": 1,
9 "story_string_role": 0,
10 "always_force_name2": false,
11 "trim_sentences": true,
12 "single_line": false,
13 "name": "DreamGen Role-Play V1 ChatML"
14}
default/content/presets/context/DreamGen Role-Play V1 Llama3.json+0 -14
@@ -1,14 +0,0 @@
1{
2 "story_string": "{{#if anchorBefore}}{{anchorBefore}}\n{{/if}}{{#if system}}{{system}}\n\n\n{{/if}}## Overall plot description:\n\n{{#if scenario}}{{scenario}}{{else}}Conversation between {{char}} and {{user}}.{{/if}}{{#if wiBefore}}\n\n{{wiBefore}}{{/if}}\n\n\n## Characters:\n\n### {{char}}\n\n{{#if description}}{{description}}\n\n{{/if}}{{#if personality}}{{personality}}\n\n{{/if}}### {{user}}\n\n{{#if persona}}{{persona}}{{else}}{{user}} is the protagonist of the role-play.{{/if}}{{#if wiAfter}}\n\n{{wiAfter}}{{/if}}{{#if mesExamples}}\n\n{{mesExamples}}{{/if}}{{#if anchorAfter}}{{anchorAfter}}\n{{/if}}{{trim}}",
3 "example_separator": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nWrite an example narrative / conversation that is not part of the main story.",
4 "chat_start": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nStart the role-play between {{char}} and {{user}}.",
5 "use_stop_strings": false,
6 "names_as_stop_strings": true,
7 "story_string_position": 0,
8 "story_string_depth": 1,
9 "story_string_role": 0,
10 "always_force_name2": false,
11 "trim_sentences": true,
12 "single_line": false,
13 "name": "DreamGen Role-Play V1 Llama3"
14}
default/content/presets/instruct/DreamGen Role-Play V1 ChatML.json+0 -25
@@ -1,25 +0,0 @@
1{
2 "input_sequence": "\n<|im_start|>text names= {{name}}\n",
3 "output_sequence": "\n<|im_start|>text names= {{name}}\n",
4 "last_output_sequence": "",
5 "system_sequence": "",
6 "stop_sequence": "\n<|im_start|>",
7 "wrap": false,
8 "macro": true,
9 "names_behavior": "none",
10 "activation_regex": "",
11 "first_output_sequence": "",
12 "skip_examples": false,
13 "output_suffix": "<|im_end|>",
14 "input_suffix": "<|im_end|>",
15 "system_suffix": "",
16 "user_alignment_message": "",
17 "system_same_as_user": true,
18 "last_system_sequence": "",
19 "first_input_sequence": "",
20 "last_input_sequence": "",
21 "sequences_as_stop_strings": true,
22 "story_string_prefix": "<|im_start|>system\n",
23 "story_string_suffix": "<|im_end|>",
24 "name": "DreamGen Role-Play V1 ChatML"
25}
default/content/presets/instruct/DreamGen Role-Play V1 Llama3.json+0 -25
@@ -1,25 +0,0 @@
1{
2 "input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n",
3 "output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n",
4 "last_output_sequence": "",
5 "system_sequence": "",
6 "stop_sequence": "",
7 "wrap": false,
8 "macro": true,
9 "names_behavior": "none",
10 "activation_regex": "",
11 "first_output_sequence": "",
12 "skip_examples": false,
13 "output_suffix": "",
14 "input_suffix": "",
15 "system_suffix": "",
16 "user_alignment_message": "",
17 "system_same_as_user": false,
18 "last_system_sequence": "",
19 "first_input_sequence": "",
20 "last_input_sequence": "",
21 "sequences_as_stop_strings": true,
22 "story_string_prefix": "<|start_header_id|>system<|end_header_id|>\n",
23 "story_string_suffix": "",
24 "name": "DreamGen Role-Play V1 Llama3"
25}
default/content/presets/kobold/Ace of Spades.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.15,
3 "rep_pen": 1.05,
4 "rep_pen_range": 2048,
5 "top_p": 0.95,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.8,
10 "rep_pen_slope": 7,
11 "sampler_order": [
12 6,
13 3,
14 2,
15 0,
16 5,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Basic Coherence.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.59,
3 "rep_pen": 1.1,
4 "rep_pen_range": 2048,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.87,
10 "rep_pen_slope": 0.3,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Best Guess.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.8,
3 "rep_pen": 1.15,
4 "rep_pen_range": 2048,
5 "top_p": 0.9,
6 "top_a": 0,
7 "top_k": 100,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 3.4,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Coherent Creativity.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.51,
3 "rep_pen": 1.2,
4 "rep_pen_range": 2048,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.99,
10 "rep_pen_slope": 0,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Deterministic.json+5 -3
@@ -1,8 +1,9 @@
1{1{
2 "temp": 0,2 "temp": 0,
3 "rep_pen": 1.18,3 "rep_pen": 1,
4 "rep_pen_range": 2048,4 "rep_pen_range": 0,
5 "top_p": 0,5 "top_p": 0,
6 "min_p": 0,
6 "top_a": 0,7 "top_a": 0,
7 "top_k": 1,8 "top_k": 1,
8 "typical": 1,9 "typical": 1,
@@ -20,5 +21,6 @@
20 "mirostat": 0,21 "mirostat": 0,
21 "mirostat_tau": 5,22 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,23 "mirostat_eta": 0.1,
24 "use_default_badwordsids": false,
23 "grammar": ""25 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
26}
default/content/presets/kobold/Genesis.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.63,
3 "rep_pen": 1.05,
4 "rep_pen_range": 2048,
5 "top_p": 0.98,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.98,
10 "rep_pen_slope": 0.1,
11 "sampler_order": [
12 6,
13 2,
14 0,
15 3,
16 5,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Godlike.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.7,
3 "rep_pen": 1.1,
4 "rep_pen_range": 1024,
5 "top_p": 0.5,
6 "top_a": 0.75,
7 "top_k": 0,
8 "typical": 0.19,
9 "tfs": 0.97,
10 "rep_pen_slope": 0.7,
11 "sampler_order": [
12 6,
13 5,
14 4,
15 3,
16 2,
17 1,
18 0
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Liminal Drift.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.66,
3 "rep_pen": 1.1,
4 "rep_pen_range": 1024,
5 "top_p": 1,
6 "top_a": 0.96,
7 "top_k": 0,
8 "typical": 0.6,
9 "tfs": 1,
10 "rep_pen_slope": 0.7,
11 "sampler_order": [
12 6,
13 4,
14 5,
15 1,
16 0,
17 2,
18 3
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Low Rider.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.94,
3 "rep_pen": 1.05,
4 "rep_pen_range": 2048,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 12,
8 "typical": 1,
9 "tfs": 0.94,
10 "rep_pen_slope": 0.2,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Luna Moth.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.5,
3 "rep_pen": 1.1,
4 "rep_pen_range": 2048,
5 "top_p": 0.24,
6 "top_a": 0,
7 "top_k": 85,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Mayday.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.05,
3 "rep_pen": 1.1,
4 "rep_pen_range": 1024,
5 "top_p": 0.95,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0.7,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 2,
16 3,
17 4,
18 5
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Miro Bronze.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.06,
3 "rep_pen": 1,
4 "rep_pen_range": 0,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0.9,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 2,
21 "mirostat_tau": 9.61,
22 "mirostat_eta": 1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Miro Gold.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.17,
3 "rep_pen": 1,
4 "rep_pen_range": 0,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0.9,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 2,
21 "mirostat_tau": 9.91,
22 "mirostat_eta": 1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Miro Silver.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.17,
3 "rep_pen": 1,
4 "rep_pen_range": 0,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0.9,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 2,
21 "mirostat_tau": 9.62,
22 "mirostat_eta": 1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Good Winds.json → default/content/presets/kobold/Neutral.json+9 -7
@@ -1,24 +1,26 @@
1{1{
2 "temp": 0.7,2 "temp": 1,
3 "rep_pen": 1.1,3 "rep_pen": 1,
4 "rep_pen_range": 1024,4 "rep_pen_range": 0,
5 "top_p": 1,5 "top_p": 1,
6 "min_p": 0,
6 "top_a": 0,7 "top_a": 0,
7 "top_k": 0,8 "top_k": 0,
8 "typical": 1,9 "typical": 1,
9 "tfs": 0.9,10 "tfs": 1,
10 "rep_pen_slope": 0.7,11 "rep_pen_slope": 0,
11 "sampler_order": [12 "sampler_order": [
12 6,13 6,
13 0,14 0,
14 1,15 1,
15 2,
16 3,16 3,
17 4,17 4,
18 2,
18 519 5
19 ],20 ],
20 "mirostat": 0,21 "mirostat": 0,
21 "mirostat_tau": 5,22 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,23 "mirostat_eta": 0.1,
24 "use_default_badwordsids": false,
23 "grammar": ""25 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
26}
default/content/presets/kobold/Ouroboros.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.07,
3 "rep_pen": 1.05,
4 "rep_pen_range": 404,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 100,
8 "typical": 1,
9 "tfs": 0.93,
10 "rep_pen_slope": 0.8,
11 "sampler_order": [
12 6,
13 0,
14 5,
15 3,
16 2,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Pleasing Results.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.44,
3 "rep_pen": 1.15,
4 "rep_pen_range": 2048,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.9,
10 "rep_pen_slope": 6.8,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Pro Writer.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.35,
3 "rep_pen": 1.15,
4 "rep_pen_range": 2048,
5 "top_p": 1,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.69,
10 "rep_pen_slope": 0.1,
11 "sampler_order": [
12 6,
13 3,
14 2,
15 5,
16 0,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/RecoveredRuins.json+3 -1
@@ -3,6 +3,7 @@
3 "rep_pen": 1.1,3 "rep_pen": 1.1,
4 "rep_pen_range": 600,4 "rep_pen_range": 600,
5 "top_p": 0.95,5 "top_p": 0.95,
6 "min_p": 0.01,
6 "top_a": 0,7 "top_a": 0,
7 "top_k": 0,8 "top_k": 0,
8 "typical": 1,9 "typical": 1,
@@ -20,5 +21,6 @@
20 "mirostat": 0,21 "mirostat": 0,
21 "mirostat_tau": 5,22 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,23 "mirostat_eta": 0.1,
24 "use_default_badwordsids": false,
23 "grammar": ""25 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
26}
default/content/presets/kobold/Space Alien.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.31,
3 "rep_pen": 1.09,
4 "rep_pen_range": 2048,
5 "top_p": 0.29,
6 "top_a": 0,
7 "top_k": 72,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Storywriter.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.72,
3 "rep_pen": 1.1,
4 "rep_pen_range": 2048,
5 "top_p": 0.73,
6 "top_a": 0,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0.2,
11 "sampler_order": [
12 6,
13 5,
14 0,
15 2,
16 3,
17 1,
18 4
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/TFS-with-Top-A.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.7,
3 "rep_pen": 1.15,
4 "rep_pen_range": 2048,
5 "top_p": 1,
6 "top_a": 0.2,
7 "top_k": 0,
8 "typical": 1,
9 "tfs": 0.95,
10 "rep_pen_slope": 0,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Titanic.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 1.01,
3 "rep_pen": 1.21,
4 "rep_pen_range": 2048,
5 "top_p": 0.21,
6 "top_a": 0.75,
7 "top_k": 91,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/kobold/Universal-Creative.json+1 -1
@@ -1,7 +1,7 @@
1{1{
2 "temp": 1.5,2 "temp": 1.5,
3 "rep_pen": 1,3 "rep_pen": 1,
4 "rep_pen_range": 600,4 "rep_pen_range": 0,
5 "top_p": 1,5 "top_p": 1,
6 "min_p": 0.1,6 "min_p": 0.1,
7 "top_a": 0,7 "top_a": 0,
default/content/presets/kobold/Universal-Light.json+1 -1
@@ -1,7 +1,7 @@
1{1{
2 "temp": 1.25,2 "temp": 1.25,
3 "rep_pen": 1,3 "rep_pen": 1,
4 "rep_pen_range": 600,4 "rep_pen_range": 0,
5 "top_p": 1,5 "top_p": 1,
6 "min_p": 0.1,6 "min_p": 0.1,
7 "top_a": 0,7 "top_a": 0,
default/content/presets/kobold/Universal-Super-Creative.json+1 -1
@@ -1,7 +1,7 @@
1{1{
2 "temp": 2,2 "temp": 2,
3 "rep_pen": 1,3 "rep_pen": 1,
4 "rep_pen_range": 600,4 "rep_pen_range": 0,
5 "top_p": 1,5 "top_p": 1,
6 "min_p": 0.1,6 "min_p": 0.1,
7 "top_a": 0,7 "top_a": 0,
default/content/presets/kobold/simple-proxy-for-tavern.json+0 -24
@@ -1,24 +0,0 @@
1{
2 "temp": 0.65,
3 "rep_pen": 1.18,
4 "rep_pen_range": 2048,
5 "top_p": 0.47,
6 "top_a": 0,
7 "top_k": 42,
8 "typical": 1,
9 "tfs": 1,
10 "rep_pen_slope": 0,
11 "sampler_order": [
12 6,
13 0,
14 1,
15 3,
16 4,
17 2,
18 5
19 ],
20 "mirostat": 0,
21 "mirostat_tau": 5,
22 "mirostat_eta": 0.1,
23 "grammar": ""
24}
24 \ No newline at end of file \ No newline at end of file
default/content/presets/textgen/Asterism.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.68,
3 "temperature_last": true,
4 "top_p": 0.17,
5 "top_k": 77,
6 "top_a": 0.42,
7 "tfs": 0.97,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.02,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Beam Search.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.7,
3 "temperature_last": true,
4 "top_p": 0.92,
5 "top_k": 150,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 3,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 2,
17 "penalty_alpha": 0,
18 "num_beams": 10,
19 "length_penalty": 1.4,
20 "min_length": 200,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": true,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Big O.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.87,
3 "temperature_last": true,
4 "top_p": 0.99,
5 "top_k": 85,
6 "top_a": 0,
7 "tfs": 0.68,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 0.68,
11 "min_p": 0,
12 "rep_pen": 1.01,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Contrastive Search.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 4,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0.6,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": false,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Default.json+40 -7
@@ -1,15 +1,15 @@
1{1{
2 "temp": 0.7,2 "temp": 1,
3 "temperature_last": true,3 "temperature_last": true,
4 "top_p": 0.5,4 "top_p": 0.95,
5 "top_k": 40,5 "top_k": 0,
6 "top_a": 0,6 "top_a": 0,
7 "tfs": 1,7 "tfs": 1,
8 "epsilon_cutoff": 0,8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,9 "eta_cutoff": 0,
10 "typical_p": 1,10 "typical_p": 1,
11 "min_p": 0,11 "min_p": 0.01,
12 "rep_pen": 1.2,12 "rep_pen": 1.1,
13 "rep_pen_range": 0,13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,15 "rep_pen_slope": 1,
@@ -44,12 +44,17 @@
44 "guidance_scale": 1,44 "guidance_scale": 1,
45 "negative_prompt": "",45 "negative_prompt": "",
46 "grammar_string": "",46 "grammar_string": "",
47 "json_schema": {},47 "json_schema": null,
48 "banned_tokens": "",48 "banned_tokens": "",
49 "sampler_priority": [49 "sampler_priority": [
50 "repetition_penalty",
51 "presence_penalty",
52 "frequency_penalty",
53 "dry",
50 "temperature",54 "temperature",
51 "dynamic_temperature",55 "dynamic_temperature",
52 "quadratic_sampling",56 "quadratic_sampling",
57 "top_n_sigma",
53 "top_k",58 "top_k",
54 "top_p",59 "top_p",
55 "typical_p",60 "typical_p",
@@ -58,16 +63,40 @@
58 "tfs",63 "tfs",
59 "top_a",64 "top_a",
60 "min_p",65 "min_p",
61 "mirostat"66 "mirostat",
67 "xtc",
68 "encoder_repetition_penalty",
69 "no_repeat_ngram"
62 ],70 ],
63 "samplers": [71 "samplers": [
72 "penalties",
73 "dry",
74 "top_n_sigma",
64 "top_k",75 "top_k",
76 "typ_p",
65 "tfs_z",77 "tfs_z",
66 "typical_p",78 "typical_p",
79 "xtc",
67 "top_p",80 "top_p",
68 "min_p",81 "min_p",
69 "temperature"82 "temperature"
70 ],83 ],
84 "samplers_priorities": [
85 "dry",
86 "penalties",
87 "no_repeat_ngram",
88 "temperature",
89 "top_nsigma",
90 "top_p_top_k",
91 "top_a",
92 "min_p",
93 "tfs",
94 "eta_cutoff",
95 "epsilon_cutoff",
96 "typical_p",
97 "quadratic",
98 "xtc"
99 ],
71 "ignore_eos_token": false,100 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,101 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,102 "speculative_ngram": false,
@@ -81,5 +110,9 @@
81 5110 5
82 ],111 ],
83 "logit_bias": [],112 "logit_bias": [],
113 "xtc_threshold": 0.1,
114 "xtc_probability": 0,
115 "nsigma": 0,
116 "min_keep": 0,
84 "rep_pen_size": 0117 "rep_pen_size": 0
85}118}
default/content/presets/textgen/Deterministic.json+36 -3
@@ -9,7 +9,7 @@
9 "eta_cutoff": 0,9 "eta_cutoff": 0,
10 "typical_p": 1,10 "typical_p": 1,
11 "min_p": 0,11 "min_p": 0,
12 "rep_pen": 1.18,12 "rep_pen": 1,
13 "rep_pen_range": 0,13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,15 "rep_pen_slope": 1,
@@ -44,12 +44,17 @@
44 "guidance_scale": 1,44 "guidance_scale": 1,
45 "negative_prompt": "",45 "negative_prompt": "",
46 "grammar_string": "",46 "grammar_string": "",
47 "json_schema": {},47 "json_schema": null,
48 "banned_tokens": "",48 "banned_tokens": "",
49 "sampler_priority": [49 "sampler_priority": [
50 "repetition_penalty",
51 "presence_penalty",
52 "frequency_penalty",
53 "dry",
50 "temperature",54 "temperature",
51 "dynamic_temperature",55 "dynamic_temperature",
52 "quadratic_sampling",56 "quadratic_sampling",
57 "top_n_sigma",
53 "top_k",58 "top_k",
54 "top_p",59 "top_p",
55 "typical_p",60 "typical_p",
@@ -58,16 +63,40 @@
58 "tfs",63 "tfs",
59 "top_a",64 "top_a",
60 "min_p",65 "min_p",
61 "mirostat"66 "mirostat",
67 "xtc",
68 "encoder_repetition_penalty",
69 "no_repeat_ngram"
62 ],70 ],
63 "samplers": [71 "samplers": [
72 "penalties",
73 "dry",
74 "top_n_sigma",
64 "top_k",75 "top_k",
76 "typ_p",
65 "tfs_z",77 "tfs_z",
66 "typical_p",78 "typical_p",
79 "xtc",
67 "top_p",80 "top_p",
68 "min_p",81 "min_p",
69 "temperature"82 "temperature"
70 ],83 ],
84 "samplers_priorities": [
85 "dry",
86 "penalties",
87 "no_repeat_ngram",
88 "temperature",
89 "top_nsigma",
90 "top_p_top_k",
91 "top_a",
92 "min_p",
93 "tfs",
94 "eta_cutoff",
95 "epsilon_cutoff",
96 "typical_p",
97 "quadratic",
98 "xtc"
99 ],
71 "ignore_eos_token": false,100 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,101 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,102 "speculative_ngram": false,
@@ -81,5 +110,9 @@
81 5110 5
82 ],111 ],
83 "logit_bias": [],112 "logit_bias": [],
113 "xtc_threshold": 0.1,
114 "xtc_probability": 0,
115 "nsigma": 0,
116 "min_keep": 0,
84 "rep_pen_size": 0117 "rep_pen_size": 0
85}118}
default/content/presets/textgen/Divine Intellect.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.31,
3 "temperature_last": true,
4 "top_p": 0.14,
5 "top_k": 49,
6 "top_a": 0.52,
7 "tfs": 1,
8 "epsilon_cutoff": 1.49,
9 "eta_cutoff": 10.42,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.17,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Kobold (Godlike).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.7,
3 "temperature_last": true,
4 "top_p": 0.5,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 0.19,
11 "min_p": 0,
12 "rep_pen": 1.1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Kobold (Liminal Drift).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.66,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 0.6,
11 "min_p": 0,
12 "rep_pen": 1.1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/LLaMa-Precise.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.7,
3 "temperature_last": true,
4 "top_p": 0.1,
5 "top_k": 40,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.18,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 200,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Midnight Enigma.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.98,
3 "temperature_last": true,
4 "top_p": 0.37,
5 "top_k": 100,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.18,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Miro Bronze.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.06,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 2,
42 "mirostat_tau": 9.61,
43 "mirostat_eta": 1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Miro Gold.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.17,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 2,
42 "mirostat_tau": 9.91,
43 "mirostat_eta": 1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Miro Silver.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.17,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 2,
42 "mirostat_tau": 9.62,
43 "mirostat_eta": 1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Naive.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.7,
3 "temperature_last": true,
4 "top_p": 0.85,
5 "top_k": 50,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Mirostat.json → default/content/presets/textgen/Neutral.json+37 -4
@@ -38,18 +38,23 @@
38 "add_bos_token": true,38 "add_bos_token": true,
39 "ban_eos_token": false,39 "ban_eos_token": false,
40 "skip_special_tokens": true,40 "skip_special_tokens": true,
41 "mirostat_mode": 2,41 "mirostat_mode": 0,
42 "mirostat_tau": 8,42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,44 "guidance_scale": 1,
45 "negative_prompt": "",45 "negative_prompt": "",
46 "grammar_string": "",46 "grammar_string": "",
47 "json_schema": {},47 "json_schema": null,
48 "banned_tokens": "",48 "banned_tokens": "",
49 "sampler_priority": [49 "sampler_priority": [
50 "repetition_penalty",
51 "presence_penalty",
52 "frequency_penalty",
53 "dry",
50 "temperature",54 "temperature",
51 "dynamic_temperature",55 "dynamic_temperature",
52 "quadratic_sampling",56 "quadratic_sampling",
57 "top_n_sigma",
53 "top_k",58 "top_k",
54 "top_p",59 "top_p",
55 "typical_p",60 "typical_p",
@@ -58,16 +63,40 @@
58 "tfs",63 "tfs",
59 "top_a",64 "top_a",
60 "min_p",65 "min_p",
61 "mirostat"66 "mirostat",
67 "xtc",
68 "encoder_repetition_penalty",
69 "no_repeat_ngram"
62 ],70 ],
63 "samplers": [71 "samplers": [
72 "penalties",
73 "dry",
74 "top_n_sigma",
64 "top_k",75 "top_k",
76 "typ_p",
65 "tfs_z",77 "tfs_z",
66 "typical_p",78 "typical_p",
79 "xtc",
67 "top_p",80 "top_p",
68 "min_p",81 "min_p",
69 "temperature"82 "temperature"
70 ],83 ],
84 "samplers_priorities": [
85 "dry",
86 "penalties",
87 "no_repeat_ngram",
88 "temperature",
89 "top_nsigma",
90 "top_p_top_k",
91 "top_a",
92 "min_p",
93 "tfs",
94 "eta_cutoff",
95 "epsilon_cutoff",
96 "typical_p",
97 "quadratic",
98 "xtc"
99 ],
71 "ignore_eos_token": false,100 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,101 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,102 "speculative_ngram": false,
@@ -81,5 +110,9 @@
81 5110 5
82 ],111 ],
83 "logit_bias": [],112 "logit_bias": [],
113 "xtc_threshold": 0.1,
114 "xtc_probability": 0,
115 "nsigma": 0,
116 "min_keep": 0,
84 "rep_pen_size": 0117 "rep_pen_size": 0
85}118}
default/content/presets/textgen/NovelAI (Best Guess).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.8,
3 "temperature_last": true,
4 "top_p": 0.9,
5 "top_k": 100,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.15,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Decadence).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.99,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 100,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 0.97,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Genesis).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.63,
3 "temperature_last": true,
4 "top_p": 0.98,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.05,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Lycaenidae).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.99,
3 "temperature_last": true,
4 "top_p": 0.85,
5 "top_k": 12,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.15,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Ouroboros).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.07,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 100,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.05,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Pleasing Results).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.44,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.15,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Sphinx Moth).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.99,
3 "temperature_last": true,
4 "top_p": 0.18,
5 "top_k": 30,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.15,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/NovelAI (Storywriter).json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.72,
3 "temperature_last": true,
4 "top_p": 0.73,
5 "top_k": 0,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Shortwave.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.53,
3 "temperature_last": true,
4 "top_p": 0.64,
5 "top_k": 33,
6 "top_a": 0.04,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.07,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Simple-1.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.7,
3 "temperature_last": true,
4 "top_p": 0.9,
5 "top_k": 20,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.15,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Space Alien.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.31,
3 "temperature_last": true,
4 "top_p": 0.29,
5 "top_k": 72,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.09,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/StarChat.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.02,
3 "temperature_last": true,
4 "top_p": 0.95,
5 "top_k": 50,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/TFS-with-Top-A.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.7,
3 "temperature_last": true,
4 "top_p": 1,
5 "top_k": 0,
6 "top_a": 0.2,
7 "tfs": 0.95,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.15,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Titanic.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 1.01,
3 "temperature_last": true,
4 "top_p": 0.21,
5 "top_k": 91,
6 "top_a": 0.75,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 10.78,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.21,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1.07,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/Universal-Creative.json+35 -2
@@ -44,12 +44,17 @@
44 "guidance_scale": 1,44 "guidance_scale": 1,
45 "negative_prompt": "",45 "negative_prompt": "",
46 "grammar_string": "",46 "grammar_string": "",
47 "json_schema": {},47 "json_schema": null,
48 "banned_tokens": "",48 "banned_tokens": "",
49 "sampler_priority": [49 "sampler_priority": [
50 "repetition_penalty",
51 "presence_penalty",
52 "frequency_penalty",
53 "dry",
50 "temperature",54 "temperature",
51 "dynamic_temperature",55 "dynamic_temperature",
52 "quadratic_sampling",56 "quadratic_sampling",
57 "top_n_sigma",
53 "top_k",58 "top_k",
54 "top_p",59 "top_p",
55 "typical_p",60 "typical_p",
@@ -58,16 +63,40 @@
58 "tfs",63 "tfs",
59 "top_a",64 "top_a",
60 "min_p",65 "min_p",
61 "mirostat"66 "mirostat",
67 "xtc",
68 "encoder_repetition_penalty",
69 "no_repeat_ngram"
62 ],70 ],
63 "samplers": [71 "samplers": [
72 "penalties",
73 "dry",
74 "top_n_sigma",
64 "top_k",75 "top_k",
76 "typ_p",
65 "tfs_z",77 "tfs_z",
66 "typical_p",78 "typical_p",
79 "xtc",
67 "top_p",80 "top_p",
68 "min_p",81 "min_p",
69 "temperature"82 "temperature"
70 ],83 ],
84 "samplers_priorities": [
85 "dry",
86 "penalties",
87 "no_repeat_ngram",
88 "temperature",
89 "top_nsigma",
90 "top_p_top_k",
91 "top_a",
92 "min_p",
93 "tfs",
94 "eta_cutoff",
95 "epsilon_cutoff",
96 "typical_p",
97 "quadratic",
98 "xtc"
99 ],
71 "ignore_eos_token": false,100 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,101 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,102 "speculative_ngram": false,
@@ -81,5 +110,9 @@
81 4110 4
82 ],111 ],
83 "logit_bias": [],112 "logit_bias": [],
113 "xtc_threshold": 0.1,
114 "xtc_probability": 0,
115 "nsigma": 0,
116 "min_keep": 0,
84 "rep_pen_size": 0117 "rep_pen_size": 0
85}118}
default/content/presets/textgen/Universal-Light.json+35 -2
@@ -44,12 +44,17 @@
44 "guidance_scale": 1,44 "guidance_scale": 1,
45 "negative_prompt": "",45 "negative_prompt": "",
46 "grammar_string": "",46 "grammar_string": "",
47 "json_schema": {},47 "json_schema": null,
48 "banned_tokens": "",48 "banned_tokens": "",
49 "sampler_priority": [49 "sampler_priority": [
50 "repetition_penalty",
51 "presence_penalty",
52 "frequency_penalty",
53 "dry",
50 "temperature",54 "temperature",
51 "dynamic_temperature",55 "dynamic_temperature",
52 "quadratic_sampling",56 "quadratic_sampling",
57 "top_n_sigma",
53 "top_k",58 "top_k",
54 "top_p",59 "top_p",
55 "typical_p",60 "typical_p",
@@ -58,16 +63,40 @@
58 "tfs",63 "tfs",
59 "top_a",64 "top_a",
60 "min_p",65 "min_p",
61 "mirostat"66 "mirostat",
67 "xtc",
68 "encoder_repetition_penalty",
69 "no_repeat_ngram"
62 ],70 ],
63 "samplers": [71 "samplers": [
72 "penalties",
73 "dry",
74 "top_n_sigma",
64 "top_k",75 "top_k",
76 "typ_p",
65 "tfs_z",77 "tfs_z",
66 "typical_p",78 "typical_p",
79 "xtc",
67 "top_p",80 "top_p",
68 "min_p",81 "min_p",
69 "temperature"82 "temperature"
70 ],83 ],
84 "samplers_priorities": [
85 "dry",
86 "penalties",
87 "no_repeat_ngram",
88 "temperature",
89 "top_nsigma",
90 "top_p_top_k",
91 "top_a",
92 "min_p",
93 "tfs",
94 "eta_cutoff",
95 "epsilon_cutoff",
96 "typical_p",
97 "quadratic",
98 "xtc"
99 ],
71 "ignore_eos_token": false,100 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,101 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,102 "speculative_ngram": false,
@@ -81,5 +110,9 @@
81 4110 4
82 ],111 ],
83 "logit_bias": [],112 "logit_bias": [],
113 "xtc_threshold": 0.1,
114 "xtc_probability": 0,
115 "nsigma": 0,
116 "min_keep": 0,
84 "rep_pen_size": 0117 "rep_pen_size": 0
85}118}
default/content/presets/textgen/Universal-Super-Creative.json+35 -2
@@ -44,12 +44,17 @@
44 "guidance_scale": 1,44 "guidance_scale": 1,
45 "negative_prompt": "",45 "negative_prompt": "",
46 "grammar_string": "",46 "grammar_string": "",
47 "json_schema": {},47 "json_schema": null,
48 "banned_tokens": "",48 "banned_tokens": "",
49 "sampler_priority": [49 "sampler_priority": [
50 "repetition_penalty",
51 "presence_penalty",
52 "frequency_penalty",
53 "dry",
50 "temperature",54 "temperature",
51 "dynamic_temperature",55 "dynamic_temperature",
52 "quadratic_sampling",56 "quadratic_sampling",
57 "top_n_sigma",
53 "top_k",58 "top_k",
54 "top_p",59 "top_p",
55 "typical_p",60 "typical_p",
@@ -58,16 +63,40 @@
58 "tfs",63 "tfs",
59 "top_a",64 "top_a",
60 "min_p",65 "min_p",
61 "mirostat"66 "mirostat",
67 "xtc",
68 "encoder_repetition_penalty",
69 "no_repeat_ngram"
62 ],70 ],
63 "samplers": [71 "samplers": [
72 "penalties",
73 "dry",
74 "top_n_sigma",
64 "top_k",75 "top_k",
76 "typ_p",
65 "tfs_z",77 "tfs_z",
66 "typical_p",78 "typical_p",
79 "xtc",
67 "top_p",80 "top_p",
68 "min_p",81 "min_p",
69 "temperature"82 "temperature"
70 ],83 ],
84 "samplers_priorities": [
85 "dry",
86 "penalties",
87 "no_repeat_ngram",
88 "temperature",
89 "top_nsigma",
90 "top_p_top_k",
91 "top_a",
92 "min_p",
93 "tfs",
94 "eta_cutoff",
95 "epsilon_cutoff",
96 "typical_p",
97 "quadratic",
98 "xtc"
99 ],
71 "ignore_eos_token": false,100 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,101 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,102 "speculative_ngram": false,
@@ -81,5 +110,9 @@
81 4110 4
82 ],111 ],
83 "logit_bias": [],112 "logit_bias": [],
113 "xtc_threshold": 0.1,
114 "xtc_probability": 0,
115 "nsigma": 0,
116 "min_keep": 0,
84 "rep_pen_size": 0117 "rep_pen_size": 0
85}118}
default/content/presets/textgen/Yara.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.82,
3 "temperature_last": true,
4 "top_p": 0.21,
5 "top_k": 72,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.19,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 5,
76 6,
77 0,
78 1,
79 2,
80 3,
81 4
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/presets/textgen/simple-proxy-for-tavern.json+0 -85
@@ -1,85 +0,0 @@
1{
2 "temp": 0.65,
3 "temperature_last": true,
4 "top_p": 0.47,
5 "top_k": 42,
6 "top_a": 0,
7 "tfs": 1,
8 "epsilon_cutoff": 0,
9 "eta_cutoff": 0,
10 "typical_p": 1,
11 "min_p": 0,
12 "rep_pen": 1.18,
13 "rep_pen_range": 0,
14 "rep_pen_decay": 0,
15 "rep_pen_slope": 1,
16 "no_repeat_ngram_size": 0,
17 "penalty_alpha": 0,
18 "num_beams": 1,
19 "length_penalty": 1,
20 "min_length": 0,
21 "encoder_rep_pen": 1,
22 "freq_pen": 0,
23 "presence_pen": 0,
24 "skew": 0,
25 "do_sample": true,
26 "early_stopping": false,
27 "dynatemp": false,
28 "min_temp": 0,
29 "max_temp": 2,
30 "dynatemp_exponent": 1,
31 "smoothing_factor": 0,
32 "smoothing_curve": 1,
33 "dry_allowed_length": 2,
34 "dry_multiplier": 0,
35 "dry_base": 1.75,
36 "dry_sequence_breakers": "[\"\\n\", \":\", \"\\\"\", \"*\"]",
37 "dry_penalty_last_n": 0,
38 "add_bos_token": true,
39 "ban_eos_token": false,
40 "skip_special_tokens": true,
41 "mirostat_mode": 0,
42 "mirostat_tau": 5,
43 "mirostat_eta": 0.1,
44 "guidance_scale": 1,
45 "negative_prompt": "",
46 "grammar_string": "",
47 "json_schema": {},
48 "banned_tokens": "",
49 "sampler_priority": [
50 "temperature",
51 "dynamic_temperature",
52 "quadratic_sampling",
53 "top_k",
54 "top_p",
55 "typical_p",
56 "epsilon_cutoff",
57 "eta_cutoff",
58 "tfs",
59 "top_a",
60 "min_p",
61 "mirostat"
62 ],
63 "samplers": [
64 "top_k",
65 "tfs_z",
66 "typical_p",
67 "top_p",
68 "min_p",
69 "temperature"
70 ],
71 "ignore_eos_token": false,
72 "spaces_between_special_tokens": true,
73 "speculative_ngram": false,
74 "sampler_order": [
75 6,
76 0,
77 1,
78 3,
79 4,
80 2,
81 5
82 ],
83 "logit_bias": [],
84 "rep_pen_size": 0
85}
default/content/settings.json+4 -2
@@ -22,14 +22,15 @@
22 "world_info_budget_cap": 022 "world_info_budget_cap": 0
23 },23 },
24 "textgenerationwebui_settings": {24 "textgenerationwebui_settings": {
25 "temp": 0.5,25 "temp": 1,
26 "top_p": 0.9,26 "top_p": 0.95,
27 "top_k": 0,27 "top_k": 0,
28 "top_a": 0,28 "top_a": 0,
29 "tfs": 1,29 "tfs": 1,
30 "epsilon_cutoff": 0,30 "epsilon_cutoff": 0,
31 "eta_cutoff": 0,31 "eta_cutoff": 0,
32 "typical_p": 1,32 "typical_p": 1,
33 "min_p": 0.01,
33 "rep_pen": 1.1,34 "rep_pen": 1.1,
34 "rep_pen_range": 0,35 "rep_pen_range": 0,
35 "no_repeat_ngram_size": 0,36 "no_repeat_ngram_size": 0,
@@ -430,6 +431,7 @@
430 "rep_pen": 1.1,431 "rep_pen": 1.1,
431 "rep_pen_range": 600,432 "rep_pen_range": 600,
432 "top_p": 0.95,433 "top_p": 0.95,
434 "min_p": 0.01,
433 "top_a": 0,435 "top_a": 0,
434 "top_k": 0,436 "top_k": 0,
435 "typical": 1,437 "typical": 1,
package-lock.json+425 -15
@@ -1,12 +1,12 @@
1{1{
2 "name": "sillytavern",2 "name": "sillytavern",
3 "version": "1.13.5",3 "version": "1.14.0",
4 "lockfileVersion": 3,4 "lockfileVersion": 3,
5 "requires": true,5 "requires": true,
6 "packages": {6 "packages": {
7 "": {7 "": {
8 "name": "sillytavern",8 "name": "sillytavern",
9 "version": "1.13.5",9 "version": "1.14.0",
10 "hasInstallScript": true,10 "hasInstallScript": true,
11 "license": "AGPL-3.0",11 "license": "AGPL-3.0",
12 "dependencies": {12 "dependencies": {
@@ -133,6 +133,7 @@
133 "@types/yargs": "^17.0.33",133 "@types/yargs": "^17.0.33",
134 "@types/yauzl": "^2.10.3",134 "@types/yauzl": "^2.10.3",
135 "eslint": "^8.57.1",135 "eslint": "^8.57.1",
136 "eslint-plugin-jest": "^27.9.0",
136 "eslint-plugin-jsdoc": "^48.10.0"137 "eslint-plugin-jsdoc": "^48.10.0"
137 },138 },
138 "engines": {139 "engines": {
@@ -186,17 +187,20 @@
186 }187 }
187 },188 },
188 "node_modules/@eslint-community/eslint-utils": {189 "node_modules/@eslint-community/eslint-utils": {
189 "version": "4.4.0",190 "version": "4.9.0",
190 "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",191 "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
191 "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",192 "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
192 "dev": true,193 "dev": true,
193 "license": "MIT",194 "license": "MIT",
194 "dependencies": {195 "dependencies": {
195 "eslint-visitor-keys": "^3.3.0"196 "eslint-visitor-keys": "^3.4.3"
196 },197 },
197 "engines": {198 "engines": {
198 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"199 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
199 },200 },
201 "funding": {
202 "url": "https://opencollective.com/eslint"
203 },
200 "peerDependencies": {204 "peerDependencies": {
201 "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"205 "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
202 }206 }
@@ -2105,6 +2109,13 @@
2105 "@types/jquery": "*"2109 "@types/jquery": "*"
2106 }2110 }
2107 },2111 },
2112 "node_modules/@types/semver": {
2113 "version": "7.7.1",
2114 "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
2115 "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
2116 "dev": true,
2117 "license": "MIT"
2118 },
2108 "node_modules/@types/send": {2119 "node_modules/@types/send": {
2109 "version": "0.17.4",2120 "version": "0.17.4",
2110 "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",2121 "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
@@ -2188,6 +2199,160 @@
2188 "@types/node": "*"2199 "@types/node": "*"
2189 }2200 }
2190 },2201 },
2202 "node_modules/@typescript-eslint/scope-manager": {
2203 "version": "5.62.0",
2204 "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
2205 "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==",
2206 "dev": true,
2207 "license": "MIT",
2208 "dependencies": {
2209 "@typescript-eslint/types": "5.62.0",
2210 "@typescript-eslint/visitor-keys": "5.62.0"
2211 },
2212 "engines": {
2213 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
2214 },
2215 "funding": {
2216 "type": "opencollective",
2217 "url": "https://opencollective.com/typescript-eslint"
2218 }
2219 },
2220 "node_modules/@typescript-eslint/types": {
2221 "version": "5.62.0",
2222 "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz",
2223 "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==",
2224 "dev": true,
2225 "license": "MIT",
2226 "engines": {
2227 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
2228 },
2229 "funding": {
2230 "type": "opencollective",
2231 "url": "https://opencollective.com/typescript-eslint"
2232 }
2233 },
2234 "node_modules/@typescript-eslint/typescript-estree": {
2235 "version": "5.62.0",
2236 "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz",
2237 "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==",
2238 "dev": true,
2239 "license": "BSD-2-Clause",
2240 "dependencies": {
2241 "@typescript-eslint/types": "5.62.0",
2242 "@typescript-eslint/visitor-keys": "5.62.0",
2243 "debug": "^4.3.4",
2244 "globby": "^11.1.0",
2245 "is-glob": "^4.0.3",
2246 "semver": "^7.3.7",
2247 "tsutils": "^3.21.0"
2248 },
2249 "engines": {
2250 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
2251 },
2252 "funding": {
2253 "type": "opencollective",
2254 "url": "https://opencollective.com/typescript-eslint"
2255 },
2256 "peerDependenciesMeta": {
2257 "typescript": {
2258 "optional": true
2259 }
2260 }
2261 },
2262 "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
2263 "version": "4.4.3",
2264 "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
2265 "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
2266 "dev": true,
2267 "license": "MIT",
2268 "dependencies": {
2269 "ms": "^2.1.3"
2270 },
2271 "engines": {
2272 "node": ">=6.0"
2273 },
2274 "peerDependenciesMeta": {
2275 "supports-color": {
2276 "optional": true
2277 }
2278 }
2279 },
2280 "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": {
2281 "version": "2.1.3",
2282 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
2283 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
2284 "dev": true,
2285 "license": "MIT"
2286 },
2287 "node_modules/@typescript-eslint/utils": {
2288 "version": "5.62.0",
2289 "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz",
2290 "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==",
2291 "dev": true,
2292 "license": "MIT",
2293 "dependencies": {
2294 "@eslint-community/eslint-utils": "^4.2.0",
2295 "@types/json-schema": "^7.0.9",
2296 "@types/semver": "^7.3.12",
2297 "@typescript-eslint/scope-manager": "5.62.0",
2298 "@typescript-eslint/types": "5.62.0",
2299 "@typescript-eslint/typescript-estree": "5.62.0",
2300 "eslint-scope": "^5.1.1",
2301 "semver": "^7.3.7"
2302 },
2303 "engines": {
2304 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
2305 },
2306 "funding": {
2307 "type": "opencollective",
2308 "url": "https://opencollective.com/typescript-eslint"
2309 },
2310 "peerDependencies": {
2311 "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
2312 }
2313 },
2314 "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": {
2315 "version": "5.1.1",
2316 "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
2317 "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
2318 "dev": true,
2319 "license": "BSD-2-Clause",
2320 "dependencies": {
2321 "esrecurse": "^4.3.0",
2322 "estraverse": "^4.1.1"
2323 },
2324 "engines": {
2325 "node": ">=8.0.0"
2326 }
2327 },
2328 "node_modules/@typescript-eslint/utils/node_modules/estraverse": {
2329 "version": "4.3.0",
2330 "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
2331 "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
2332 "dev": true,
2333 "license": "BSD-2-Clause",
2334 "engines": {
2335 "node": ">=4.0"
2336 }
2337 },
2338 "node_modules/@typescript-eslint/visitor-keys": {
2339 "version": "5.62.0",
2340 "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
2341 "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==",
2342 "dev": true,
2343 "license": "MIT",
2344 "dependencies": {
2345 "@typescript-eslint/types": "5.62.0",
2346 "eslint-visitor-keys": "^3.3.0"
2347 },
2348 "engines": {
2349 "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
2350 },
2351 "funding": {
2352 "type": "opencollective",
2353 "url": "https://opencollective.com/typescript-eslint"
2354 }
2355 },
2191 "node_modules/@ungap/structured-clone": {2356 "node_modules/@ungap/structured-clone": {
2192 "version": "1.2.0",2357 "version": "1.2.0",
2193 "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",2358 "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@@ -2590,9 +2755,9 @@
2590 }2755 }
2591 },2756 },
2592 "node_modules/archiver-utils/node_modules/glob": {2757 "node_modules/archiver-utils/node_modules/glob": {
2593 "version": "10.4.5",2758 "version": "10.5.0",
2594 "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",2759 "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
2595 "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",2760 "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
2596 "license": "ISC",2761 "license": "ISC",
2597 "dependencies": {2762 "dependencies": {
2598 "foreground-child": "^3.1.0",2763 "foreground-child": "^3.1.0",
@@ -2739,6 +2904,16 @@
2739 "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",2904 "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
2740 "license": "MIT"2905 "license": "MIT"
2741 },2906 },
2907 "node_modules/array-union": {
2908 "version": "2.1.0",
2909 "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
2910 "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
2911 "dev": true,
2912 "license": "MIT",
2913 "engines": {
2914 "node": ">=8"
2915 }
2916 },
2742 "node_modules/ast-types": {2917 "node_modules/ast-types": {
2743 "version": "0.13.4",2918 "version": "0.13.4",
2744 "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",2919 "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
@@ -2913,6 +3088,19 @@
2913 "concat-map": "0.0.1"3088 "concat-map": "0.0.1"
2914 }3089 }
2915 },3090 },
3091 "node_modules/braces": {
3092 "version": "3.0.3",
3093 "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
3094 "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
3095 "dev": true,
3096 "license": "MIT",
3097 "dependencies": {
3098 "fill-range": "^7.1.1"
3099 },
3100 "engines": {
3101 "node": ">=8"
3102 }
3103 },
2916 "node_modules/browserslist": {3104 "node_modules/browserslist": {
2917 "version": "4.24.0",3105 "version": "4.24.0",
2918 "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",3106 "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz",
@@ -3906,6 +4094,19 @@
3906 "md5": "^2.3.0"4094 "md5": "^2.3.0"
3907 }4095 }
3908 },4096 },
4097 "node_modules/dir-glob": {
4098 "version": "3.0.1",
4099 "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
4100 "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
4101 "dev": true,
4102 "license": "MIT",
4103 "dependencies": {
4104 "path-type": "^4.0.0"
4105 },
4106 "engines": {
4107 "node": ">=8"
4108 }
4109 },
3909 "node_modules/doctrine": {4110 "node_modules/doctrine": {
3910 "version": "3.0.0",4111 "version": "3.0.0",
3911 "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",4112 "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -4257,6 +4458,32 @@
4257 "url": "https://opencollective.com/eslint"4458 "url": "https://opencollective.com/eslint"
4258 }4459 }
4259 },4460 },
4461 "node_modules/eslint-plugin-jest": {
4462 "version": "27.9.0",
4463 "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz",
4464 "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==",
4465 "dev": true,
4466 "license": "MIT",
4467 "dependencies": {
4468 "@typescript-eslint/utils": "^5.10.0"
4469 },
4470 "engines": {
4471 "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
4472 },
4473 "peerDependencies": {
4474 "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0",
4475 "eslint": "^7.0.0 || ^8.0.0",
4476 "jest": "*"
4477 },
4478 "peerDependenciesMeta": {
4479 "@typescript-eslint/eslint-plugin": {
4480 "optional": true
4481 },
4482 "jest": {
4483 "optional": true
4484 }
4485 }
4486 },
4260 "node_modules/eslint-plugin-jsdoc": {4487 "node_modules/eslint-plugin-jsdoc": {
4261 "version": "48.10.0",4488 "version": "48.10.0",
4262 "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz",4489 "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.10.0.tgz",
@@ -4609,6 +4836,23 @@
4609 "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",4836 "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
4610 "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="4837 "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
4611 },4838 },
4839 "node_modules/fast-glob": {
4840 "version": "3.3.3",
4841 "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
4842 "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
4843 "dev": true,
4844 "license": "MIT",
4845 "dependencies": {
4846 "@nodelib/fs.stat": "^2.0.2",
4847 "@nodelib/fs.walk": "^1.2.3",
4848 "glob-parent": "^5.1.2",
4849 "merge2": "^1.3.0",
4850 "micromatch": "^4.0.8"
4851 },
4852 "engines": {
4853 "node": ">=8.6.0"
4854 }
4855 },
4612 "node_modules/fast-json-stable-stringify": {4856 "node_modules/fast-json-stable-stringify": {
4613 "version": "2.1.0",4857 "version": "2.1.0",
4614 "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",4858 "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -4702,6 +4946,19 @@
4702 "url": "https://github.com/sindresorhus/file-type?sponsor=1"4946 "url": "https://github.com/sindresorhus/file-type?sponsor=1"
4703 }4947 }
4704 },4948 },
4949 "node_modules/fill-range": {
4950 "version": "7.1.1",
4951 "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
4952 "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
4953 "dev": true,
4954 "license": "MIT",
4955 "dependencies": {
4956 "to-regex-range": "^5.0.1"
4957 },
4958 "engines": {
4959 "node": ">=8"
4960 }
4961 },
4705 "node_modules/finalhandler": {4962 "node_modules/finalhandler": {
4706 "version": "1.3.1",4963 "version": "1.3.1",
4707 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",4964 "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
@@ -5039,6 +5296,19 @@
5039 "url": "https://github.com/sponsors/isaacs"5296 "url": "https://github.com/sponsors/isaacs"
5040 }5297 }
5041 },5298 },
5299 "node_modules/glob-parent": {
5300 "version": "5.1.2",
5301 "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
5302 "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
5303 "dev": true,
5304 "license": "ISC",
5305 "dependencies": {
5306 "is-glob": "^4.0.1"
5307 },
5308 "engines": {
5309 "node": ">= 6"
5310 }
5311 },
5042 "node_modules/glob-to-regexp": {5312 "node_modules/glob-to-regexp": {
5043 "version": "0.4.1",5313 "version": "0.4.1",
5044 "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",5314 "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
@@ -5071,6 +5341,27 @@
5071 "url": "https://github.com/sponsors/sindresorhus"5341 "url": "https://github.com/sponsors/sindresorhus"
5072 }5342 }
5073 },5343 },
5344 "node_modules/globby": {
5345 "version": "11.1.0",
5346 "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
5347 "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
5348 "dev": true,
5349 "license": "MIT",
5350 "dependencies": {
5351 "array-union": "^2.1.0",
5352 "dir-glob": "^3.0.1",
5353 "fast-glob": "^3.2.9",
5354 "ignore": "^5.2.0",
5355 "merge2": "^1.4.1",
5356 "slash": "^3.0.0"
5357 },
5358 "engines": {
5359 "node": ">=10"
5360 },
5361 "funding": {
5362 "url": "https://github.com/sponsors/sindresorhus"
5363 }
5364 },
5074 "node_modules/google-translate-api-browser": {5365 "node_modules/google-translate-api-browser": {
5075 "version": "3.0.1",5366 "version": "3.0.1",
5076 "resolved": "https://registry.npmjs.org/google-translate-api-browser/-/google-translate-api-browser-3.0.1.tgz",5367 "resolved": "https://registry.npmjs.org/google-translate-api-browser/-/google-translate-api-browser-3.0.1.tgz",
@@ -5633,6 +5924,16 @@
5633 "url": "https://github.com/sponsors/sindresorhus"5924 "url": "https://github.com/sponsors/sindresorhus"
5634 }5925 }
5635 },5926 },
5927 "node_modules/is-number": {
5928 "version": "7.0.0",
5929 "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
5930 "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
5931 "dev": true,
5932 "license": "MIT",
5933 "engines": {
5934 "node": ">=0.12.0"
5935 }
5936 },
5636 "node_modules/is-path-inside": {5937 "node_modules/is-path-inside": {
5637 "version": "3.0.3",5938 "version": "3.0.3",
5638 "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",5939 "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@@ -5762,9 +6063,9 @@
5762 "license": "BSD-3-Clause"6063 "license": "BSD-3-Clause"
5763 },6064 },
5764 "node_modules/js-yaml": {6065 "node_modules/js-yaml": {
5765 "version": "4.1.0",6066 "version": "4.1.1",
5766 "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",6067 "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
5767 "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",6068 "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
5768 "dev": true,6069 "dev": true,
5769 "license": "MIT",6070 "license": "MIT",
5770 "dependencies": {6071 "dependencies": {
@@ -6076,6 +6377,16 @@
6076 "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",6377 "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
6077 "license": "MIT"6378 "license": "MIT"
6078 },6379 },
6380 "node_modules/merge2": {
6381 "version": "1.4.1",
6382 "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
6383 "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
6384 "dev": true,
6385 "license": "MIT",
6386 "engines": {
6387 "node": ">= 8"
6388 }
6389 },
6079 "node_modules/methods": {6390 "node_modules/methods": {
6080 "version": "1.1.2",6391 "version": "1.1.2",
6081 "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",6392 "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@@ -6085,6 +6396,20 @@
6085 "node": ">= 0.6"6396 "node": ">= 0.6"
6086 }6397 }
6087 },6398 },
6399 "node_modules/micromatch": {
6400 "version": "4.0.8",
6401 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
6402 "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
6403 "dev": true,
6404 "license": "MIT",
6405 "dependencies": {
6406 "braces": "^3.0.3",
6407 "picomatch": "^2.3.1"
6408 },
6409 "engines": {
6410 "node": ">=8.6"
6411 }
6412 },
6088 "node_modules/mime": {6413 "node_modules/mime": {
6089 "version": "1.6.0",6414 "version": "1.6.0",
6090 "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",6415 "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
@@ -6140,9 +6465,10 @@
6140 }6465 }
6141 },6466 },
6142 "node_modules/min-document": {6467 "node_modules/min-document": {
6143 "version": "2.19.0",6468 "version": "2.19.2",
6144 "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",6469 "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz",
6145 "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==",6470 "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==",
6471 "license": "MIT",
6146 "dependencies": {6472 "dependencies": {
6147 "dom-walk": "^0.1.0"6473 "dom-walk": "^0.1.0"
6148 }6474 }
@@ -6765,6 +7091,16 @@
6765 "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",7091 "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
6766 "license": "MIT"7092 "license": "MIT"
6767 },7093 },
7094 "node_modules/path-type": {
7095 "version": "4.0.0",
7096 "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
7097 "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
7098 "dev": true,
7099 "license": "MIT",
7100 "engines": {
7101 "node": ">=8"
7102 }
7103 },
6768 "node_modules/peek-readable": {7104 "node_modules/peek-readable": {
6769 "version": "4.1.0",7105 "version": "4.1.0",
6770 "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",7106 "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
@@ -6802,6 +7138,19 @@
6802 "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",7138 "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
6803 "license": "ISC"7139 "license": "ISC"
6804 },7140 },
7141 "node_modules/picomatch": {
7142 "version": "2.3.1",
7143 "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
7144 "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
7145 "dev": true,
7146 "license": "MIT",
7147 "engines": {
7148 "node": ">=8.6"
7149 },
7150 "funding": {
7151 "url": "https://github.com/sponsors/jonschlinkert"
7152 }
7153 },
6805 "node_modules/platform": {7154 "node_modules/platform": {
6806 "version": "1.3.6",7155 "version": "1.3.6",
6807 "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",7156 "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
@@ -7656,6 +8005,16 @@
7656 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",8005 "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
7657 "license": "MIT"8006 "license": "MIT"
7658 },8007 },
8008 "node_modules/slash": {
8009 "version": "3.0.0",
8010 "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
8011 "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
8012 "dev": true,
8013 "license": "MIT",
8014 "engines": {
8015 "node": ">=8"
8016 }
8017 },
7659 "node_modules/slashes": {8018 "node_modules/slashes": {
7660 "version": "3.0.12",8019 "version": "3.0.12",
7661 "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz",8020 "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz",
@@ -8028,6 +8387,19 @@
8028 "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",8387 "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
8029 "license": "MIT"8388 "license": "MIT"
8030 },8389 },
8390 "node_modules/to-regex-range": {
8391 "version": "5.0.1",
8392 "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
8393 "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
8394 "dev": true,
8395 "license": "MIT",
8396 "dependencies": {
8397 "is-number": "^7.0.0"
8398 },
8399 "engines": {
8400 "node": ">=8.0"
8401 }
8402 },
8031 "node_modules/toidentifier": {8403 "node_modules/toidentifier": {
8032 "version": "1.0.1",8404 "version": "1.0.1",
8033 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",8405 "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -8089,6 +8461,29 @@
8089 "node": ">=0.6.x"8461 "node": ">=0.6.x"
8090 }8462 }
8091 },8463 },
8464 "node_modules/tsutils": {
8465 "version": "3.21.0",
8466 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
8467 "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
8468 "dev": true,
8469 "license": "MIT",
8470 "dependencies": {
8471 "tslib": "^1.8.1"
8472 },
8473 "engines": {
8474 "node": ">= 6"
8475 },
8476 "peerDependencies": {
8477 "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
8478 }
8479 },
8480 "node_modules/tsutils/node_modules/tslib": {
8481 "version": "1.14.1",
8482 "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
8483 "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
8484 "dev": true,
8485 "license": "0BSD"
8486 },
8092 "node_modules/type-check": {8487 "node_modules/type-check": {
8093 "version": "0.4.0",8488 "version": "0.4.0",
8094 "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",8489 "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -8146,6 +8541,21 @@
8146 "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",8541 "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
8147 "license": "MIT"8542 "license": "MIT"
8148 },8543 },
8544 "node_modules/typescript": {
8545 "version": "5.9.3",
8546 "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
8547 "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
8548 "dev": true,
8549 "license": "Apache-2.0",
8550 "peer": true,
8551 "bin": {
8552 "tsc": "bin/tsc",
8553 "tsserver": "bin/tsserver"
8554 },
8555 "engines": {
8556 "node": ">=14.17"
8557 }
8558 },
8149 "node_modules/uglify-js": {8559 "node_modules/uglify-js": {
8150 "version": "3.19.3",8560 "version": "3.19.3",
8151 "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",8561 "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
package.json+3 -2
@@ -113,7 +113,7 @@
113 "type": "git",113 "type": "git",
114 "url": "https://github.com/SillyTavern/SillyTavern.git"114 "url": "https://github.com/SillyTavern/SillyTavern.git"
115 },115 },
116 "version": "1.13.5",116 "version": "1.14.0",
117 "scripts": {117 "scripts": {
118 "start": "node server.js",118 "start": "node server.js",
119 "debug": "node --inspect server.js",119 "debug": "node --inspect server.js",
@@ -164,6 +164,7 @@
164 "@types/yargs": "^17.0.33",164 "@types/yargs": "^17.0.33",
165 "@types/yauzl": "^2.10.3",165 "@types/yauzl": "^2.10.3",
166 "eslint": "^8.57.1",166 "eslint": "^8.57.1",
167 "eslint-plugin-jsdoc": "^48.10.0"167 "eslint-plugin-jsdoc": "^48.10.0",
168 "eslint-plugin-jest": "^27.9.0"
168 }169 }
169}170}
public/css/file-form.css+103 -0
@@ -25,6 +25,16 @@
25 border-radius: 15px;25 border-radius: 15px;
26}26}
2727
28.mes .mes_file_wrapper:empty {
29 display: none;
30}
31
32.mes .mes_file_wrapper {
33 display: flex;
34 flex-direction: column;
35 gap: 0.5em;
36}
37
28.mes_file_container .right_menu_button {38.mes_file_container .right_menu_button {
29 padding-right: 0;39 padding-right: 0;
30}40}
@@ -55,3 +65,96 @@
55 display: flex;65 display: flex;
56 text-align: left;66 text-align: left;
57}67}
68
69/* Audio Player Styles */
70.mes_audio_container {
71 cursor: default;
72 display: flex;
73 width: fit-content;
74 min-width: min(350px, 100%);
75 max-width: 100%;
76 background-color: var(--white20a);
77 border: 2px solid var(--SmartThemeBorderColor);
78 padding: 0.5em 1em;
79 border-radius: 15px;
80}
81
82.mes_audio_container .mes_img_swipes {
83 position: unset;
84 opacity: unset;
85 background: none;
86 padding: 0;
87}
88
89.mes_audio_container .mes_img_swipes .right_menu_button {
90 filter: brightness(75%);
91 text-shadow: none;
92}
93
94.mes_audio_container .mes_img_swipes .mes_img_swipe_counter {
95 filter: none;
96 text-shadow: none;
97}
98
99.audio-player {
100 display: flex;
101 flex-direction: column;
102 gap: 5px;
103}
104
105.audio-player-header {
106 display: flex;
107 flex-direction: row;
108 gap: 15px;
109 align-items: center;
110 justify-content: space-between;
111}
112
113.audio-player-title {
114 overflow: hidden;
115 text-overflow: ellipsis;
116 white-space: nowrap;
117}
118
119.audio-player-controls {
120 display: flex;
121 align-items: center;
122 gap: 10px;
123}
124
125.audio-player-play-pause,
126.audio-player-volume {
127 background: none;
128 border: none;
129}
130
131.audio-player-time-separator {
132 font-size: 0.9em;
133 text-align: center;
134}
135
136.audio-player-current-time,
137.audio-player-total-time {
138 font-size: 0.9em;
139 color: var(--SmartThemeQuoteColor);
140 min-width: 40px;
141 text-align: center;
142}
143
144.audio-player-progress {
145 flex: 1;
146 height: 6px;
147 background-color: var(--black30a);
148 border-radius: 3px;
149 cursor: pointer;
150 position: relative;
151 overflow: hidden;
152}
153
154.audio-player-progress-bar {
155 height: 100%;
156 background-color: var(--SmartThemeEmColor);
157 border-radius: 3px;
158 transition: width 0.1s linear;
159 width: 0%;
160}
public/css/toggle-dependent.css+18 -0
@@ -544,3 +544,21 @@ label[for="bind_preset_to_connection"]:has(input:checked) {
544#openai_settings [data-cc-toggle="false"]>.icon-unsupported {544#openai_settings [data-cc-toggle="false"]>.icon-unsupported {
545 color: var(--golden);545 color: var(--golden);
546}546}
547
548#advanced-formatting-cc-notice {
549 display: none;
550 gap: 5px;
551 align-items: baseline;
552 margin: 5px 0;
553 padding: 5px 10px;
554}
555
556#top-settings-holder:has(#main_api option[value="openai"]:checked) #advanced-formatting-cc-notice {
557 display: flex;
558}
559
560#top-settings-holder:has(#main_api option[value="openai"]:checked) #AdvancedFormatting [data-cc-null] {
561 opacity: 0.5;
562 filter: grayscale(0.5);
563 cursor: not-allowed;
564}
public/css/world-info.css+8 -0
@@ -237,6 +237,14 @@
237 display: none;237 display: none;
238}238}
239239
240.world_entry .select2-selection--multiple,
241.world_entry textarea.keyprimarytextpole,
242.world_entry textarea.keysecondarytextpole {
243 max-height: 160px;
244 overflow-y: auto;
245 overflow-x: hidden;
246}
247
240span.select2-container .select2-selection__choice__display:has(> .regex_item),248span.select2-container .select2-selection__choice__display:has(> .regex_item),
241span.select2-container .select2-results__option:has(> .result_block .regex_item) {249span.select2-container .select2-results__option:has(> .result_block .regex_item) {
242 background-color: #D27D2D30;250 background-color: #D27D2D30;
public/global.d.ts+84 -0
@@ -2,12 +2,96 @@ import libs from './lib';
2import getContext from './scripts/st-context';2import getContext from './scripts/st-context';
3import { power_user } from './scripts/power-user';3import { power_user } from './scripts/power-user';
4import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi';4import { QuickReplyApi } from './scripts/extensions/quick-reply/api/QuickReplyApi';
5import { oai_settings } from './scripts/openai';
6import { textgenerationwebui_settings } from './scripts/textgen-settings';
7import { FileAttachment } from './scripts/chats';
8import { ReasoningMessageExtra } from './scripts/reasoning';
59
6declare global {10declare global {
7 // Custom types11 // Custom types
8 type InstructSettings = typeof power_user.instruct;12 type InstructSettings = typeof power_user.instruct;
9 type ContextSettings = typeof power_user.context;13 type ContextSettings = typeof power_user.context;
10 type ReasoningSettings = typeof power_user.reasoning;14 type ReasoningSettings = typeof power_user.reasoning;
15 type ChatCompletionSettings = typeof oai_settings;
16 type TextCompletionSettings = typeof textgenerationwebui_settings;
17 type MessageTimestamp = string | number | Date;
18
19 interface ChatMessage {
20 name?: string;
21 mes?: string;
22 title?: string;
23 gen_started?: MessageTimestamp;
24 gen_finished?: MessageTimestamp;
25 send_date?: MessageTimestamp;
26 is_user?: boolean;
27 is_system?: boolean;
28 force_avatar?: string;
29 original_avatar?: string;
30 swipes?: string[];
31 swipe_info?: Record<string, any>;
32 swipe_id?: number;
33 extra?: ChatMessageExtra & Partial<ReasoningMessageExtra> & Record<string, any>;
34 };
35
36 interface ChatMessageExtra {
37 bias?: string;
38 uses_system_ui?: boolean;
39 memory?: string;
40 display_text?: string;
41 reasoning_display_text?: string;
42 tool_invocations?: any[];
43 title?: string;
44 isSmallSys?: boolean;
45 token_count?: number;
46 files?: FileAttachment[];
47 inline_image?: boolean;
48 media_display?: string;
49 media_index?: number;
50 media?: MediaAttachment[],
51 /** @deprecated Use `files` instead */
52 file?: FileAttachment;
53 /** @deprecated Use `media` instead */
54 image?: string;
55 /** @deprecated Use `media` instead */
56 video?: string;
57 /** @deprecated Use `media` with `media_display = 'gallery'` instead */
58 image_swipes?: string[];
59 /** @deprecated Use `MediaAttachment.append_title` instead */
60 append_title?: boolean;
61 /** @deprecated Use `MediaAttachment.generation_type` instead */
62 generationType?: number;
63 /** @deprecated Use `MediaAttachment.negative` instead */
64 negative?: string;
65 }
66
67 type MediaAttachment = MediaAttachmentProps & ImageGenerationAttachmentProps & ImageCaptionAttachmentProps;
68
69 interface MediaAttachmentProps {
70 url: string;
71 title?: string;
72 type: string;
73 source?: string;
74 }
75
76 interface ImageGenerationAttachmentProps {
77 generation_type?: number;
78 negative?: string;
79 }
80
81 interface ImageCaptionAttachmentProps {
82 /** Append title to the message text in case of non-inline captions. */
83 append_title?: boolean;
84 /** Marker for captioned images to prevent auto-caption from firing again. */
85 captioned?: boolean;
86 }
87
88 /** Media playback state */
89 interface MediaState {
90 /** Current playback time */
91 currentTime: number;
92 /** Whether the media is paused */
93 paused: boolean;
94 }
1195
12 // Global namespace modules96 // Global namespace modules
13 interface Window {97 interface Window {
public/img/siliconflow.svg+4 -0
@@ -0,0 +1,4 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<svg width="142.22" height="68.010002" viewBox="0 0 142.22 68.010002" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
3 <path d="M 136.05,0 H 74.21 c -3.42,0 -6.18,2.77 -6.18,6.18 v 18.55 c 0,3.42 -2.77,6.18 -6.18,6.18 H 6.18 C 2.76,30.91 0,33.68 0,37.09 v 24.74 c 0,3.42 2.77,6.18 6.18,6.18 h 61.84 c 3.42,0 6.18,-2.77 6.18,-6.18 V 43.28 c 0,-3.42 2.77,-6.18 6.18,-6.18 h 55.66 c 3.42,0 6.18,-2.77 6.18,-6.18 V 6.18 C 142.22,2.76 139.45,0 136.04,0 Z" />
4</svg>
public/img/zai.svg+3 -0
@@ -0,0 +1,3 @@
1<svg version="1.1" x="0" y="0" xml:space="preserve" id="svg6" width="18.60156" height="15.82031" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.60156 15.82031">
2 <path id="path2" d="M.4707 0v2.33008h7.09961c.36 0 .7004-.1807.9004-.4707L9.77147.00977S.4607.01.4707 0zm10.68946.00977L0 15.8203h7.4414L18.60157.00977Zm-.11914 13.48046c-.36 0-.7004.1807-.9004.4707l-1.31054 1.85938h9.30078v-2.33008z"/>
3</svg>
public/index.html+266 -133
@@ -648,7 +648,7 @@
648 Max Response Length (tokens)648 Max Response Length (tokens)
649 </div>649 </div>
650 <div class="wide100p">650 <div class="wide100p">
651 <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="65536" step="1">651 <input type="number" id="openai_max_tokens" name="openai_max_tokens" class="text_pole" min="1" max="128000" step="1">
652 </div>652 </div>
653 </div>653 </div>
654 <div class="range-block" data-source="openai,custom,xai,aimlapi,moonshot,azure_openai">654 <div class="range-block" data-source="openai,custom,xai,aimlapi,moonshot,azure_openai">
@@ -693,7 +693,7 @@
693 </span>693 </span>
694 </div>694 </div>
695 </div>695 </div>
696 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">696 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,siliconflow,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai">
697 <div class="range-block-title" data-i18n="Temperature">697 <div class="range-block-title" data-i18n="Temperature">
698 Temperature698 Temperature
699 </div>699 </div>
@@ -706,7 +706,7 @@
706 </div>706 </div>
707 </div>707 </div>
708 </div>708 </div>
709 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">709 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,siliconflow,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">
710 <div class="range-block-title" data-i18n="Frequency Penalty">710 <div class="range-block-title" data-i18n="Frequency Penalty">
711 Frequency Penalty711 Frequency Penalty
712 </div>712 </div>
@@ -719,7 +719,7 @@
719 </div>719 </div>
720 </div>720 </div>
721 </div>721 </div>
722 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">722 <div class="range-block" data-source="openai,aimlapi,openrouter,custom,cohere,perplexity,groq,siliconflow,mistralai,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">
723 <div class="range-block-title" data-i18n="Presence Penalty">723 <div class="range-block-title" data-i18n="Presence Penalty">
724 Presence Penalty724 Presence Penalty
725 </div>725 </div>
@@ -745,7 +745,7 @@
745 </div>745 </div>
746 </div>746 </div>
747 </div>747 </div>
748 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai">748 <div class="range-block" data-source="openai,claude,aimlapi,openrouter,ai21,makersuite,vertexai,mistralai,custom,cohere,perplexity,groq,siliconflow,electronhub,nanogpt,deepseek,xai,pollinations,moonshot,fireworks,cometapi,azure_openai,zai">
749 <div class="range-block-title" data-i18n="Top P">749 <div class="range-block-title" data-i18n="Top P">
750 Top P750 Top P
751 </div>751 </div>
@@ -1246,12 +1246,12 @@
1246 <div class="fa-solid fa-circle-info opacity50p" title="Customize displayed samplers or add custom samplers." data-i18n="[title]Customize displayed samplers or add custom samplers."></div>1246 <div class="fa-solid fa-circle-info opacity50p" title="Customize displayed samplers or add custom samplers." data-i18n="[title]Customize displayed samplers or add custom samplers."></div>
1247 </small>1247 </small>
1248 </div>1248 </div>
1249 <div data-tg-type="mancer, vllm, aphrodite, tabby, infermaticai" class="flex-container flexFlowColumn alignitemscenter flexBasis100p flexGrow flexShrink gap0">1249 <div data-tg-type="mancer, vllm, aphrodite, tabby, infermaticai" data-tg-samplers="n" class="flex-container flexFlowColumn alignitemscenter flexBasis100p flexGrow flexShrink gap0">
1250 <small data-i18n="Multiple swipes per generation">Multiple swipes per generation</small>1250 <small data-i18n="Multiple swipes per generation">Multiple swipes per generation</small>
1251 <input type="number" id="n_textgenerationwebui" class="text_pole textAlignCenter" min="1" value="1" step="1" />1251 <input type="number" id="n_textgenerationwebui" class="text_pole textAlignCenter" min="1" value="1" step="1" />
1252 </div>1252 </div>
1253 <div class="flex-container gap10h5v justifyCenter">1253 <div class="flex-container gap10h5v justifyCenter">
1254 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1254 <div data-tg-samplers="temp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1255 <small>1255 <small>
1256 <span data-i18n="Temperature">Temperature</span>1256 <span data-i18n="Temperature">Temperature</span>
1257 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Temperature controls the randomness in token selection" title="Temperature controls the randomness in token selection:&#13;- low temperature (<1.0) leads to more predictable text, favoring higher probability tokens.&#13;- high temperature (>1.0) increases creativity and diversity in the output by giving lower probability tokens a better chance.&#13;Set to 1.0 for the original probabilities."></div>1257 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Temperature controls the randomness in token selection" title="Temperature controls the randomness in token selection:&#13;- low temperature (<1.0) leads to more predictable text, favoring higher probability tokens.&#13;- high temperature (>1.0) increases creativity and diversity in the output by giving lower probability tokens a better chance.&#13;Set to 1.0 for the original probabilities."></div>
@@ -1260,7 +1260,7 @@
1260 <input class="neo-range-input" type="number" min="0.0" max="5.0" step="0.01" data-for="temp_textgenerationwebui" id="temp_counter_textgenerationwebui">1260 <input class="neo-range-input" type="number" min="0.0" max="5.0" step="0.01" data-for="temp_textgenerationwebui" id="temp_counter_textgenerationwebui">
1261 </div>1261 </div>
1262 <!-- Note: "except" mode = show for all BUT types in data-tg-type -->1262 <!-- Note: "except" mode = show for all BUT types in data-tg-type -->
1263 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1263 <div data-tg-type-mode="except" data-tg-type="generic" data-tg-samplers="top_k" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1264 <small>1264 <small>
1265 <span data-i18n="Top K">Top K</span>1265 <span data-i18n="Top K">Top K</span>
1266 <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from.&#13;E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited).&#13;Set to 0 (or -1, depending on your backend) to disable." data-i18n="[title]Top_K_desc"></div>1266 <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from.&#13;E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited).&#13;Set to 0 (or -1, depending on your backend) to disable." data-i18n="[title]Top_K_desc"></div>
@@ -1268,7 +1268,7 @@
1268 <input class="neo-range-slider" type="range" id="top_k_textgenerationwebui" name="volume" min="-1" max="200" step="1">1268 <input class="neo-range-slider" type="range" id="top_k_textgenerationwebui" name="volume" min="-1" max="200" step="1">
1269 <input class="neo-range-input" type="number" min="-1" max="200" step="1" data-for="top_k_textgenerationwebui" id="top_k_counter_textgenerationwebui">1269 <input class="neo-range-input" type="number" min="-1" max="200" step="1" data-for="top_k_textgenerationwebui" id="top_k_counter_textgenerationwebui">
1270 </div>1270 </div>
1271 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1271 <div data-tg-samplers="top_p" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1272 <small>1272 <small>
1273 <span data-i18n="Top P">Top P</span>1273 <span data-i18n="Top P">Top P</span>
1274 <div class="fa-solid fa-circle-info opacity50p" title="Top P (a.k.a. nucleus sampling) adds up all the top tokens required to add up to the target percentage.&#13;E.g If the Top 2 tokens are both 25%, and Top P is 0.50, only the Top 2 tokens are considered.&#13;Set to 1.0 to disable." data-i18n="[title]Top_P_desc"></div>1274 <div class="fa-solid fa-circle-info opacity50p" title="Top P (a.k.a. nucleus sampling) adds up all the top tokens required to add up to the target percentage.&#13;E.g If the Top 2 tokens are both 25%, and Top P is 0.50, only the Top 2 tokens are considered.&#13;Set to 1.0 to disable." data-i18n="[title]Top_P_desc"></div>
@@ -1276,7 +1276,7 @@
1276 <input class="neo-range-slider" type="range" id="top_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1276 <input class="neo-range-slider" type="range" id="top_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1277 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p_textgenerationwebui" id="top_p_counter_textgenerationwebui">1277 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p_textgenerationwebui" id="top_p_counter_textgenerationwebui">
1278 </div>1278 </div>
1279 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1279 <div data-tg-type-mode="except" data-tg-type="generic" data-tg-samplers="typical_p" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1280 <small>1280 <small>
1281 <span data-i18n="Typical P">Typical P</span>1281 <span data-i18n="Typical P">Typical P</span>
1282 <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set.&#13;It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content.&#13;Set to 1.0 to disable." data-i18n="[title]Typical_P_desc"></div>1282 <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set.&#13;It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content.&#13;Set to 1.0 to disable." data-i18n="[title]Typical_P_desc"></div>
@@ -1284,7 +1284,7 @@
1284 <input class="neo-range-slider" type="range" id="typical_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1284 <input class="neo-range-slider" type="range" id="typical_p_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1285 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="typical_p_textgenerationwebui" id="typical_p_counter_textgenerationwebui">1285 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="typical_p_textgenerationwebui" id="typical_p_counter_textgenerationwebui">
1286 </div>1286 </div>
1287 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1287 <div data-tg-type-mode="except" data-tg-type="generic" data-tg-samplers="min_p" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1288 <small>1288 <small>
1289 <span data-i18n="Min P">Min P</span>1289 <span data-i18n="Min P">Min P</span>
1290 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min_P_desc" title="Min P sets a base minimum probability. This is scaled according to the top token's probability.&#13;E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered.&#13;Set to 0 to disable."></div>1290 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min_P_desc" title="Min P sets a base minimum probability. This is scaled according to the top token's probability.&#13;E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered.&#13;Set to 0 to disable."></div>
@@ -1292,7 +1292,7 @@
1292 <input class="neo-range-slider" type="range" id="min_p_textgenerationwebui" name="volume" min="0" max="1" step="0.001">1292 <input class="neo-range-slider" type="range" id="min_p_textgenerationwebui" name="volume" min="0" max="1" step="0.001">
1293 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p_textgenerationwebui" id="min_p_counter_textgenerationwebui">1293 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p_textgenerationwebui" id="min_p_counter_textgenerationwebui">
1294 </div>1294 </div>
1295 <div data-tg-type-mode="except" data-tg-type="generic,llamacpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1295 <div data-tg-type-mode="except" data-tg-type="generic,llamacpp" data-tg-samplers="top_a" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1296 <small>1296 <small>
1297 <span data-i18n="Top A">Top A</span>1297 <span data-i18n="Top A">Top A</span>
1298 <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability.&#13;E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded.&#13;Set to 0 to disable." data-i18n="[title]Top_A_desc"></div>1298 <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability.&#13;E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded.&#13;Set to 0 to disable." data-i18n="[title]Top_A_desc"></div>
@@ -1300,7 +1300,7 @@
1300 <input class="neo-range-slider" type="range" id="top_a_textgenerationwebui" name="volume" min="0" max="1" step="0.01">1300 <input class="neo-range-slider" type="range" id="top_a_textgenerationwebui" name="volume" min="0" max="1" step="0.01">
1301 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_a_textgenerationwebui" id="top_a_counter_textgenerationwebui">1301 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_a_textgenerationwebui" id="top_a_counter_textgenerationwebui">
1302 </div>1302 </div>
1303 <div data-tg-type-mode="except" data-tg-type="generic,llamacpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1303 <div data-tg-type-mode="except" data-tg-type="generic,llamacpp" data-tg-samplers="tfs" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1304 <small>1304 <small>
1305 <span data-i18n="TFS">TFS</span>1305 <span data-i18n="TFS">TFS</span>
1306 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>1306 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail_Free_Sampling_desc" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution,&#13;by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative.&#13;The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div>
@@ -1308,7 +1308,7 @@
1308 <input class="neo-range-slider" type="range" id="tfs_textgenerationwebui" name="volume" min="0" max="1" step="0.001">1308 <input class="neo-range-slider" type="range" id="tfs_textgenerationwebui" name="volume" min="0" max="1" step="0.001">
1309 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="tfs_textgenerationwebui" id="tfs_counter_textgenerationwebui">1309 <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="tfs_textgenerationwebui" id="tfs_counter_textgenerationwebui">
1310 </div>1310 </div>
1311 <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1311 <div data-tg-type="ooba,mancer,aphrodite" data-tg-samplers="epsilon_cutoff" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1312 <small>1312 <small>
1313 <span data-i18n="Epsilon Cutoff">Epsilon Cutoff</span>1313 <span data-i18n="Epsilon Cutoff">Epsilon Cutoff</span>
1314 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled" title="Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled.&#13;In units of 1e-4; a reasonable value is 3.&#13;Set to 0 to disable."></div>1314 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled" title="Epsilon cutoff sets a probability floor below which tokens are excluded from being sampled.&#13;In units of 1e-4; a reasonable value is 3.&#13;Set to 0 to disable."></div>
@@ -1316,7 +1316,7 @@
1316 <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01">1316 <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01">
1317 <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui">1317 <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui">
1318 </div>1318 </div>
1319 <div data-tg-type="ooba,aphrodite,koboldcpp,llamacpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1319 <div data-tg-type="ooba,aphrodite,koboldcpp,llamacpp" data-tg-samplers="nsigma" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1320 <small>1320 <small>
1321 <span data-i18n="Top nsigma">Top nsigma</span>1321 <span data-i18n="Top nsigma">Top nsigma</span>
1322 <div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div>1322 <div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div>
@@ -1324,7 +1324,7 @@
1324 <input class="neo-range-slider" type="range" id="nsigma_textgenerationwebui" name="volume" min="0" max="5" step="0.01">1324 <input class="neo-range-slider" type="range" id="nsigma_textgenerationwebui" name="volume" min="0" max="5" step="0.01">
1325 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="nsigma_textgenerationwebui" id="nsigma_counter_textgenerationwebui">1325 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="nsigma_textgenerationwebui" id="nsigma_counter_textgenerationwebui">
1326 </div>1326 </div>
1327 <div data-tg-type="llamacpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1327 <div data-tg-type="llamacpp" data-tg-samplers="min_keep" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1328 <small>1328 <small>
1329 <span data-i18n="Min Keep">Min Keep</span>1329 <span data-i18n="Min Keep">Min Keep</span>
1330 <div class="fa-solid fa-circle-info opacity50p" title="A sampling modifier that ensures that truncation samplers such as top-p, min-p, typical-p, and xtc return at least this many tokens. Set to 0 to disable."></div>1330 <div class="fa-solid fa-circle-info opacity50p" title="A sampling modifier that ensures that truncation samplers such as top-p, min-p, typical-p, and xtc return at least this many tokens. Set to 0 to disable."></div>
@@ -1332,7 +1332,7 @@
1332 <input class="neo-range-slider" type="range" id="min_keep_textgenerationwebui" name="volume" min="0" max="50" step="1">1332 <input class="neo-range-slider" type="range" id="min_keep_textgenerationwebui" name="volume" min="0" max="50" step="1">
1333 <input class="neo-range-input" type="number" min="0" max="50" step="1" data-for="min_keep_textgenerationwebui" id="min_keep_counter_textgenerationwebui">1333 <input class="neo-range-input" type="number" min="0" max="50" step="1" data-for="min_keep_textgenerationwebui" id="min_keep_counter_textgenerationwebui">
1334 </div>1334 </div>
1335 <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1335 <div data-tg-type="ooba,mancer,aphrodite" data-tg-samplers="eta_cutoff" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1336 <small>1336 <small>
1337 <span data-i18n="Eta Cutoff">Eta Cutoff</span>1337 <span data-i18n="Eta Cutoff">Eta Cutoff</span>
1338 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Eta_Cutoff_desc" title="Eta cutoff is the main parameter of the special Eta Sampling technique.&#13;In units of 1e-4; a reasonable value is 3.&#13;Set to 0 to disable.&#13;See the paper Truncation Sampling as Language Model Desmoothing by Hewitt et al. (2022) for details."></div>1338 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Eta_Cutoff_desc" title="Eta cutoff is the main parameter of the special Eta Sampling technique.&#13;In units of 1e-4; a reasonable value is 3.&#13;Set to 0 to disable.&#13;See the paper Truncation Sampling as Language Model Desmoothing by Hewitt et al. (2022) for details."></div>
@@ -1340,62 +1340,62 @@
1340 <input class="neo-range-slider" type="range" id="eta_cutoff_textgenerationwebui" name="volume" min="0" max="20" step="0.01">1340 <input class="neo-range-slider" type="range" id="eta_cutoff_textgenerationwebui" name="volume" min="0" max="20" step="0.01">
1341 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="eta_cutoff_textgenerationwebui" id="eta_cutoff_counter_textgenerationwebui">1341 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="eta_cutoff_textgenerationwebui" id="eta_cutoff_counter_textgenerationwebui">
1342 </div>1342 </div>
1343 <div data-tg-type-mode="except" data-tg-type="generic" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1343 <div data-tg-type-mode="except" data-tg-type="generic" data-tg-samplers="rep_pen" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1344 <small data-i18n="rep.pen">Repetition Penalty</small>1344 <small data-i18n="rep.pen">Repetition Penalty</small>
1345 <input class="neo-range-slider" type="range" id="rep_pen_textgenerationwebui" name="volume" min="1" max="3" step="0.01">1345 <input class="neo-range-slider" type="range" id="rep_pen_textgenerationwebui" name="volume" min="1" max="3" step="0.01">
1346 <input class="neo-range-input" type="number" min="1" max="3" step="0.01" data-for="rep_pen_textgenerationwebui" id="rep_pen_counter_textgenerationwebui">1346 <input class="neo-range-input" type="number" min="1" max="3" step="0.01" data-for="rep_pen_textgenerationwebui" id="rep_pen_counter_textgenerationwebui">
1347 </div>1347 </div>
1348 <div data-tg-type="ooba, koboldcpp, tabby, ollama, llamacpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1348 <div data-tg-type="ooba, koboldcpp, tabby, ollama, llamacpp" data-tg-samplers="rep_pen_range" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1349 <small data-i18n="rep.pen range">Rep Pen Range</small>1349 <small data-i18n="rep.pen range">Rep Pen Range</small>
1350 <input class="neo-range-slider" type="range" id="rep_pen_range_textgenerationwebui" name="volume" min="-1" max="8192" step="1">1350 <input class="neo-range-slider" type="range" id="rep_pen_range_textgenerationwebui" name="volume" min="-1" max="8192" step="1">
1351 <input class="neo-range-input" type="number" min="-1" max="8192" step="1" data-for="rep_pen_range_textgenerationwebui" id="rep_pen_range_counter_textgenerationwebui">1351 <input class="neo-range-input" type="number" min="-1" max="8192" step="1" data-for="rep_pen_range_textgenerationwebui" id="rep_pen_range_counter_textgenerationwebui">
1352 </div>1352 </div>
1353 <div data-tg-type="koboldcpp" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1353 <div data-tg-type="koboldcpp" data-tg-samplers="rep_pen_slope" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1354 <small data-i18n="Rep. Pen. Slope">Rep Pen Slope</small>1354 <small data-i18n="Rep. Pen. Slope">Rep Pen Slope</small>
1355 <input class="neo-range-slider" type="range" id="rep_pen_slope_textgenerationwebui" name="volume" min="0" max="10" step="0.01">1355 <input class="neo-range-slider" type="range" id="rep_pen_slope_textgenerationwebui" name="volume" min="0" max="10" step="0.01">
1356 <input class="neo-range-input" type="number" min="0" max="10" step="0.01" data-for="rep_pen_slope_textgenerationwebui" id="rep_pen_slope_counter_textgenerationwebui">1356 <input class="neo-range-input" type="number" min="0" max="10" step="0.01" data-for="rep_pen_slope_textgenerationwebui" id="rep_pen_slope_counter_textgenerationwebui">
1357 </div>1357 </div>
1358 <div data-tg-type="tabby" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1358 <div data-tg-type="tabby" data-tg-samplers="rep_pen_decay" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1359 <small data-i18n="rep.pen decay">Rep Pen Decay</small>1359 <small data-i18n="rep.pen decay">Rep Pen Decay</small>
1360 <input class="neo-range-slider" type="range" id="rep_pen_decay_textgenerationwebui" name="volume" min="-1" max="8192" step="1">1360 <input class="neo-range-slider" type="range" id="rep_pen_decay_textgenerationwebui" name="volume" min="-1" max="8192" step="1">
1361 <input class="neo-range-input" type="number" min="-1" max="8192" step="1" data-for="rep_pen_decay_textgenerationwebui" id="rep_pen_decay_counter_textgenerationwebui">1361 <input class="neo-range-input" type="number" min="-1" max="8192" step="1" data-for="rep_pen_decay_textgenerationwebui" id="rep_pen_decay_counter_textgenerationwebui">
1362 </div>1362 </div>
1363 <div data-tg-type="ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1363 <div data-tg-type="ooba" data-tg-samplers="encoder_rep_pen" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1364 <small data-i18n="Encoder Rep. Pen.">Encoder Penalty</small>1364 <small data-i18n="Encoder Rep. Pen.">Encoder Penalty</small>
1365 <input class="neo-range-slider" type="range" id="encoder_rep_pen_textgenerationwebui" name="volume" min="0.8" max="1.5" step="0.01" />1365 <input class="neo-range-slider" type="range" id="encoder_rep_pen_textgenerationwebui" name="volume" min="0.8" max="1.5" step="0.01" />
1366 <input class="neo-range-input" type="number" min="0.8" max="1.5" step="0.01" data-for="encoder_rep_pen_textgenerationwebui" id="encoder_rep_pen_counter_textgenerationwebui">1366 <input class="neo-range-input" type="number" min="0.8" max="1.5" step="0.01" data-for="encoder_rep_pen_textgenerationwebui" id="encoder_rep_pen_counter_textgenerationwebui">
1367 </div>1367 </div>
1368 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1368 <div data-tg-samplers="freq_pen" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1369 <small data-i18n="Frequency Penalty">Frequency Penalty</small>1369 <small data-i18n="Frequency Penalty">Frequency Penalty</small>
1370 <input class="neo-range-slider" type="range" id="freq_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" />1370 <input class="neo-range-slider" type="range" id="freq_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" />
1371 <input class="neo-range-input" type="number" data-for="freq_pen_textgenerationwebui" min="-2" max="2" step="0.01" id="freq_pen_counter_textgenerationwebui">1371 <input class="neo-range-input" type="number" data-for="freq_pen_textgenerationwebui" min="-2" max="2" step="0.01" id="freq_pen_counter_textgenerationwebui">
1372 </div>1372 </div>
1373 <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1373 <div data-tg-samplers="presence_pen" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1374 <small data-i18n="Presence Penalty">Presence Penalty</small>1374 <small data-i18n="Presence Penalty">Presence Penalty</small>
1375 <input class="neo-range-slider" type="range" id="presence_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" />1375 <input class="neo-range-slider" type="range" id="presence_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" />
1376 <input class="neo-range-input" type="number" min="-2" max="2" step="0.01" data-for="presence_pen_textgenerationwebui" id="presence_pen_counter_textgenerationwebui">1376 <input class="neo-range-input" type="number" min="-2" max="2" step="0.01" data-for="presence_pen_textgenerationwebui" id="presence_pen_counter_textgenerationwebui">
1377 </div>1377 </div>
1378 <div data-tg-type="aphrodite, ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1378 <div data-tg-type="aphrodite, ooba" data-tg-samplers="no_repeat_ngram_size" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1379 <small data-i18n="No Repeat Ngram Size">No Repeat Ngram Size</small>1379 <small data-i18n="No Repeat Ngram Size">No Repeat Ngram Size</small>
1380 <input class="neo-range-slider" type="range" id="no_repeat_ngram_size_textgenerationwebui" name="volume" min="0" max="20" step="1">1380 <input class="neo-range-slider" type="range" id="no_repeat_ngram_size_textgenerationwebui" name="volume" min="0" max="20" step="1">
1381 <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="no_repeat_ngram_size_textgenerationwebui" id="no_repeat_ngram_size_counter_textgenerationwebui">1381 <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="no_repeat_ngram_size_textgenerationwebui" id="no_repeat_ngram_size_counter_textgenerationwebui">
1382 </div>1382 </div>
1383 <div data-tg-type="tabby, aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1383 <div data-tg-type="tabby, aphrodite" data-tg-samplers="skew" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1384 <small data-i18n="Skew">Skew</small>1384 <small data-i18n="Skew">Skew</small>
1385 <input class="neo-range-slider" type="range" id="skew_textgenerationwebui" name="volume" min="-5" max="5" step="0.01" />1385 <input class="neo-range-slider" type="range" id="skew_textgenerationwebui" name="volume" min="-5" max="5" step="0.01" />
1386 <input class="neo-range-input" type="number" min="-5" max="5" step="0.01" data-for="skew_textgenerationwebui" id="skew_counter_textgenerationwebui">1386 <input class="neo-range-input" type="number" min="-5" max="5" step="0.01" data-for="skew_textgenerationwebui" id="skew_counter_textgenerationwebui">
1387 </div>1387 </div>
1388 <div data-tg-type="mancer, ooba, tabby, dreamgen, infermaticai, aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1388 <div data-tg-type="mancer, ooba, tabby, dreamgen, infermaticai, aphrodite" data-tg-samplers="min_length" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1389 <small data-i18n="Min Length">Min Length</small>1389 <small data-i18n="Min Length">Min Length</small>
1390 <input class="neo-range-slider" type="range" id="min_length_textgenerationwebui" name="volume" min="0" max="2000" step="1" />1390 <input class="neo-range-slider" type="range" id="min_length_textgenerationwebui" name="volume" min="0" max="2000" step="1" />
1391 <input class="neo-range-input" type="number" min="0" max="2000" step="1" data-for="min_length_textgenerationwebui" id="min_length_counter_textgenerationwebui">1391 <input class="neo-range-input" type="number" min="0" max="2000" step="1" data-for="min_length_textgenerationwebui" id="min_length_counter_textgenerationwebui">
1392 </div>1392 </div>
1393 <div data-tg-type="ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">1393 <div data-tg-type="ooba" data-tg-samplers="max_tokens_second" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0">
1394 <small data-i18n="Max Tokens Second">Maximum tokens/second</small>1394 <small data-i18n="Max Tokens Second">Maximum tokens/second</small>
1395 <input class="neo-range-slider" type="range" id="max_tokens_second_textgenerationwebui" name="volume" min="0" max="20" step="1" />1395 <input class="neo-range-slider" type="range" id="max_tokens_second_textgenerationwebui" name="volume" min="0" max="20" step="1" />
1396 <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="max_tokens_second_textgenerationwebui" id="max_tokens_second_counter_textgenerationwebui">1396 <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="max_tokens_second_textgenerationwebui" id="max_tokens_second_counter_textgenerationwebui">
1397 </div>1397 </div>
1398 <div data-tg-type="mancer, ooba, koboldcpp, aphrodite, tabby" id="smoothingBlock" name="smoothingBlock" class="wide100p">1398 <div data-tg-type="mancer, ooba, koboldcpp, aphrodite, tabby" data-tg-samplers="smoothing_factor" id="smoothingBlock" name="smoothingBlock" class="wide100p">
1399 <h4 class="wide100p textAlignCenter">1399 <h4 class="wide100p textAlignCenter">
1400 <label data-i18n="Smooth Sampling">Smooth Sampling</label>1400 <label data-i18n="Smooth Sampling">Smooth Sampling</label>
1401 <div class=" fa-solid fa-circle-info opacity50p " data-i18n="[title]Smooth_Sampling_desc" title="Allows you to use quadratic/cubic transformations to adjust the distribution. Lower Smoothing Factor values will be more creative, usually between 0.2-0.3 is the sweetspot (assuming the curve = 1). Higher Smoothing Curve values will make the curve steeper, which will punish low probability choices more aggressively. 1.0 curve is equivalent to only using Smoothing Factor."></div>1401 <div class=" fa-solid fa-circle-info opacity50p " data-i18n="[title]Smooth_Sampling_desc" title="Allows you to use quadratic/cubic transformations to adjust the distribution. Lower Smoothing Factor values will be more creative, usually between 0.2-0.3 is the sweetspot (assuming the curve = 1). Higher Smoothing Curve values will make the curve steeper, which will punish low probability choices more aggressively. 1.0 curve is equivalent to only using Smoothing Factor."></div>
@@ -1406,7 +1406,7 @@
1406 <input class="neo-range-slider" type="range" id="smoothing_factor_textgenerationwebui" name="volume" min="0" max="10" step="0.01" />1406 <input class="neo-range-slider" type="range" id="smoothing_factor_textgenerationwebui" name="volume" min="0" max="10" step="0.01" />
1407 <input class="neo-range-input" type="number" min="0" max="10" step="0.01" data-for="smoothing_factor_textgenerationwebui" id="smoothing_factor_counter_textgenerationwebui">1407 <input class="neo-range-input" type="number" min="0" max="10" step="0.01" data-for="smoothing_factor_textgenerationwebui" id="smoothing_factor_counter_textgenerationwebui">
1408 </div>1408 </div>
1409 <div data-tg-type="mancer, ooba, koboldcpp, aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">1409 <div data-tg-type="mancer, ooba, koboldcpp, aphrodite" data-tg-samplers="smoothing_curve" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
1410 <small data-i18n="Smoothing Curve">Smoothing Curve</small>1410 <small data-i18n="Smoothing Curve">Smoothing Curve</small>
1411 <input class="neo-range-slider" type="range" id="smoothing_curve_textgenerationwebui" name="volume" min="1" max="10" step="0.01" />1411 <input class="neo-range-slider" type="range" id="smoothing_curve_textgenerationwebui" name="volume" min="1" max="10" step="0.01" />
1412 <input class="neo-range-input" type="number" min="1" max="10" step="0.01" data-for="smoothing_curve_textgenerationwebui" id="smoothing_curve_counter_textgenerationwebui">1412 <input class="neo-range-input" type="number" min="1" max="10" step="0.01" data-for="smoothing_curve_textgenerationwebui" id="smoothing_curve_counter_textgenerationwebui">
@@ -1414,7 +1414,7 @@
1414 </div>1414 </div>
1415 </div>1415 </div>
14161416
1417 <div data-tg-type="koboldcpp, aphrodite, mancer, tabby, ooba, llamacpp" id="xtc_block" class="wide100p">1417 <div data-tg-type="koboldcpp, aphrodite, mancer, tabby, ooba, llamacpp" data-tg-samplers="xtc_probability" id="xtc_block" class="wide100p">
1418 <h4 class="wide100p textAlignCenter">1418 <h4 class="wide100p textAlignCenter">
1419 <label data-i18n="Exclude Top Choices (XTC)">Exclude Top Choices (XTC)</label>1419 <label data-i18n="Exclude Top Choices (XTC)">Exclude Top Choices (XTC)</label>
1420 <a href="https://github.com/oobabooga/text-generation-webui/pull/6335" target="_blank">1420 <a href="https://github.com/oobabooga/text-generation-webui/pull/6335" target="_blank">
@@ -1422,7 +1422,7 @@
1422 </a>1422 </a>
1423 </h4>1423 </h4>
1424 <div class="flex-container flexFlowRow gap10px flexShrink">1424 <div class="flex-container flexFlowRow gap10px flexShrink">
1425 <div class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">1425 <div data-tg-samplers="xtc_threshold" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
1426 <small data-i18n="Threshold">Threshold</small>1426 <small data-i18n="Threshold">Threshold</small>
1427 <input class="neo-range-slider" type="range" id="xtc_threshold_textgenerationwebui" name="volume" min="0" max="0.5" step="0.01" />1427 <input class="neo-range-slider" type="range" id="xtc_threshold_textgenerationwebui" name="volume" min="0" max="0.5" step="0.01" />
1428 <input class="neo-range-input" type="number" min="0" max="0.5" step="0.01" data-for="xtc_threshold_textgenerationwebui" id="xtc_threshold_counter_textgenerationwebui">1428 <input class="neo-range-input" type="number" min="0" max="0.5" step="0.01" data-for="xtc_threshold_textgenerationwebui" id="xtc_threshold_counter_textgenerationwebui">
@@ -1435,7 +1435,7 @@
1435 </div>1435 </div>
1436 </div>1436 </div>
14371437
1438 <div data-tg-type="aphrodite, mancer, ooba, koboldcpp, tabby, llamacpp, dreamgen" id="dryBlock" class="wide100p">1438 <div data-tg-type="aphrodite, mancer, ooba, koboldcpp, tabby, llamacpp, dreamgen" data-tg-samplers="dry_multiplier" id="dryBlock" class="wide100p">
1439 <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">1439 <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">
1440 <label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label>1440 <label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label>
1441 <a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank">1441 <a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank">
@@ -1448,30 +1448,30 @@
1448 <input class="neo-range-slider" type="range" id="dry_multiplier_textgenerationwebui" min="0" max="5" step="0.01" />1448 <input class="neo-range-slider" type="range" id="dry_multiplier_textgenerationwebui" min="0" max="5" step="0.01" />
1449 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="dry_multiplier_textgenerationwebui" id="dry_multiplier_counter_textgenerationwebui">1449 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="dry_multiplier_textgenerationwebui" id="dry_multiplier_counter_textgenerationwebui">
1450 </div>1450 </div>
1451 <div class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" title="Controls how fast the penalty grows with increasing sequence length." data-i18n="[title]DRY_Base_desc">1451 <div data-tg-samplers="dry_base" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" title="Controls how fast the penalty grows with increasing sequence length." data-i18n="[title]DRY_Base_desc">
1452 <small data-i18n="Base">Base</small>1452 <small data-i18n="Base">Base</small>
1453 <input class="neo-range-slider" type="range" id="dry_base_textgenerationwebui" min="1" max="4" step="0.01" />1453 <input class="neo-range-slider" type="range" id="dry_base_textgenerationwebui" min="1" max="4" step="0.01" />
1454 <input class="neo-range-input" type="number" min="1" max="4" step="0.01" data-for="dry_base_textgenerationwebui" id="dry_base_counter_textgenerationwebui">1454 <input class="neo-range-input" type="number" min="1" max="4" step="0.01" data-for="dry_base_textgenerationwebui" id="dry_base_counter_textgenerationwebui">
1455 </div>1455 </div>
1456 <div class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" title="Longest sequence that can be repeated without being penalized." data-i18n="[title]DRY_Allowed_Length_desc">1456 <div data-tg-samplers="dry_allowed_length" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" title="Longest sequence that can be repeated without being penalized." data-i18n="[title]DRY_Allowed_Length_desc">
1457 <small data-i18n="Allowed Length">Allowed Length</small>1457 <small data-i18n="Allowed Length">Allowed Length</small>
1458 <input class="neo-range-slider" type="range" id="dry_allowed_length_textgenerationwebui" min="1" max="20" step="1" />1458 <input class="neo-range-slider" type="range" id="dry_allowed_length_textgenerationwebui" min="1" max="20" step="1" />
1459 <input class="neo-range-input" type="number" min="1" max="20" step="1" data-for="dry_allowed_length_textgenerationwebui" id="dry_allowed_length_counter_textgenerationwebui">1459 <input class="neo-range-input" type="number" min="1" max="20" step="1" data-for="dry_allowed_length_textgenerationwebui" id="dry_allowed_length_counter_textgenerationwebui">
1460 </div>1460 </div>
1461 <div class="alignItemsCenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" data-tg-type="llamacpp, koboldcpp, tabby, aphrodite">1461 <div data-tg-samplers="dry_penalty_last_n" class="alignItemsCenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0" data-tg-type="llamacpp, koboldcpp, tabby, aphrodite">
1462 <small data-i18n="Penalty Range">Penalty Range</small>1462 <small data-i18n="Penalty Range">Penalty Range</small>
1463 <input class="neo-range-slider" type="range" id="dry_penalty_last_n_textgenerationwebui" min="0" max="8192" step="1" />1463 <input class="neo-range-slider" type="range" id="dry_penalty_last_n_textgenerationwebui" min="0" max="8192" step="1" />
1464 <input class="neo-range-input" type="number" min="0" max="8192" step="1" data-for="dry_penalty_last_n_textgenerationwebui" id="dry_penalty_last_n_counter_textgenerationwebui">1464 <input class="neo-range-input" type="number" min="0" max="8192" step="1" data-for="dry_penalty_last_n_textgenerationwebui" id="dry_penalty_last_n_counter_textgenerationwebui">
1465 </div>1465 </div>
1466 </div>1466 </div>
1467 <div class="range-block marginTop5" title="Tokens across which sequence matching is not continued. Specified as a comma-separated list of quoted strings." data-i18n="[title]DRY_Sequence_Breakers_desc">1467 <div data-tg-samplers="dry_sequence_breakers" class="range-block marginTop5" title="Tokens across which sequence matching is not continued. Specified as a comma-separated list of quoted strings." data-i18n="[title]DRY_Sequence_Breakers_desc">
1468 <div class="range-block-title textAlignCenter flex-container justifyCenter alignitemscenter">1468 <div class="range-block-title textAlignCenter flex-container justifyCenter alignitemscenter">
1469 <small data-i18n="Sequence Breakers">Sequence Breakers</small>1469 <small data-i18n="Sequence Breakers">Sequence Breakers</small>
1470 </div>1470 </div>
1471 <textarea id="dry_sequence_breakers_textgenerationwebui" class="text_pole textarea_compact" name="sequence_breakers" rows="3" data-i18n="[placeholder]JSON-serialized array of strings." placeholder="JSON-serialized array of strings."></textarea>1471 <textarea id="dry_sequence_breakers_textgenerationwebui" class="text_pole textarea_compact" name="sequence_breakers" rows="3" data-i18n="[placeholder]JSON-serialized array of strings." placeholder="JSON-serialized array of strings."></textarea>
1472 </div>1472 </div>
1473 </div>1473 </div>
1474 <div data-tg-type="ooba, mancer, koboldcpp, tabby, llamacpp, aphrodite" id="dynatemp_block_ooba" class="wide100p">1474 <div data-tg-type="ooba, mancer, koboldcpp, tabby, llamacpp, aphrodite" data-tg-samplers="dynatemp" id="dynatemp_block_ooba" class="wide100p">
1475 <h4 class="wide100p textAlignCenter">1475 <h4 class="wide100p textAlignCenter">
1476 <div class="flex-container alignitemscenter justifyCenter">1476 <div class="flex-container alignitemscenter justifyCenter">
1477 <div class="checkbox_label" for="dynatemp_textgenerationwebui">1477 <div class="checkbox_label" for="dynatemp_textgenerationwebui">
@@ -1482,24 +1482,24 @@
1482 </div>1482 </div>
1483 </h4>1483 </h4>
1484 <div class="flex-container flexFlowRow alignitemscenter gap10px flexShrink">1484 <div class="flex-container flexFlowRow alignitemscenter gap10px flexShrink">
1485 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1485 <div data-tg-samplers="min_temp" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1486 <small data-i18n="Minimum Temp">Minimum Temp</small>1486 <small data-i18n="Minimum Temp">Minimum Temp</small>
1487 <input class="neo-range-slider" type="range" id="min_temp_textgenerationwebui" name="volume" min="0" max="5" step="0.01" />1487 <input class="neo-range-slider" type="range" id="min_temp_textgenerationwebui" name="volume" min="0" max="5" step="0.01" />
1488 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="min_temp_textgenerationwebui" id="min_temp_counter_textgenerationwebui">1488 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="min_temp_textgenerationwebui" id="min_temp_counter_textgenerationwebui">
1489 </div>1489 </div>
1490 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1490 <div data-tg-samplers="max_temp" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1491 <small data-i18n="Maximum Temp">Maximum Temp</small>1491 <small data-i18n="Maximum Temp">Maximum Temp</small>
1492 <input class="neo-range-slider" type="range" id="max_temp_textgenerationwebui" name="volume" min="0" max="5" step="0.01" />1492 <input class="neo-range-slider" type="range" id="max_temp_textgenerationwebui" name="volume" min="0" max="5" step="0.01" />
1493 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="max_temp_textgenerationwebui" id="max_temp_counter_textgenerationwebui">1493 <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="max_temp_textgenerationwebui" id="max_temp_counter_textgenerationwebui">
1494 </div>1494 </div>
1495 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1495 <div data-tg-samplers="dynatemp_exponent" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1496 <small data-i18n="Exponent">Exponent</small>1496 <small data-i18n="Exponent">Exponent</small>
1497 <input class="neo-range-slider" type="range" id="dynatemp_exponent_textgenerationwebui" name="volume" min="0.001" max="10" step="0.001" />1497 <input class="neo-range-slider" type="range" id="dynatemp_exponent_textgenerationwebui" name="volume" min="0.001" max="10" step="0.001" />
1498 <input class="neo-range-input" type="number" min="0.001" max="10" step="0.001" data-for="dynatemp_exponent_textgenerationwebui" id="dynatemp_exponent_counter_textgenerationwebui">1498 <input class="neo-range-input" type="number" min="0.001" max="10" step="0.001" data-for="dynatemp_exponent_textgenerationwebui" id="dynatemp_exponent_counter_textgenerationwebui">
1499 </div>1499 </div>
1500 </div>1500 </div>
1501 </div>1501 </div>
1502 <div data-tg-type="ooba,infermaticai,koboldcpp,llamacpp,tabby" id="mirostat_block_ooba" class="wide100p">1502 <div data-tg-type="ooba,infermaticai,koboldcpp,llamacpp,tabby" data-tg-samplers="mirostat_mode" id="mirostat_block_ooba" class="wide100p">
1503 <h4 class="wide100p textAlignCenter">1503 <h4 class="wide100p textAlignCenter">
1504 <label data-i18n="Mirostat (mode=1 is only for llama.cpp)">Mirostat</label>1504 <label data-i18n="Mirostat (mode=1 is only for llama.cpp)">Mirostat</label>
1505 <div class=" fa-solid fa-circle-info opacity50p " data-i18n="[title]Mirostat_desc" title="Mirostat is a thermostat for output perplexity.&#13;Mirostat matches the output perplexity to that of the input, thus avoiding the repetition trap&#13;(where, as the autoregressive inference produces text, the perplexity of the output tends toward zero)&#13;and the confusion trap (where the perplexity diverges).&#13;For details, see the paper Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity by Basu et al. (2020).&#13;Mode chooses the Mirostat version. 0=disable, 1=Mirostat 1.0 (llama.cpp only), 2=Mirostat 2.0.&#13;Tau = Variability parameter for Mirostat outputs.&#13;Eta = Learning rate of Mirostat."></div>1505 <div class=" fa-solid fa-circle-info opacity50p " data-i18n="[title]Mirostat_desc" title="Mirostat is a thermostat for output perplexity.&#13;Mirostat matches the output perplexity to that of the input, thus avoiding the repetition trap&#13;(where, as the autoregressive inference produces text, the perplexity of the output tends toward zero)&#13;and the confusion trap (where the perplexity diverges).&#13;For details, see the paper Mirostat: A Neural Text Decoding Algorithm that Directly Controls Perplexity by Basu et al. (2020).&#13;Mode chooses the Mirostat version. 0=disable, 1=Mirostat 1.0 (llama.cpp only), 2=Mirostat 2.0.&#13;Tau = Variability parameter for Mirostat outputs.&#13;Eta = Learning rate of Mirostat."></div>
@@ -1510,19 +1510,19 @@
1510 <input class="neo-range-slider" type="range" id="mirostat_mode_textgenerationwebui" name="volume" min="0" max="2" step="1" />1510 <input class="neo-range-slider" type="range" id="mirostat_mode_textgenerationwebui" name="volume" min="0" max="2" step="1" />
1511 <input class="neo-range-input" type="number" min="0" max="2" step="1" data-for="mirostat_mode_textgenerationwebui" id="mirostat_mode_counter_textgenerationwebui">1511 <input class="neo-range-input" type="number" min="0" max="2" step="1" data-for="mirostat_mode_textgenerationwebui" id="mirostat_mode_counter_textgenerationwebui">
1512 </div>1512 </div>
1513 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1513 <div data-tg-samplers="mirostat_tau" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1514 <small data-i18n="Mirostat Tau">Tau</small>1514 <small data-i18n="Mirostat Tau">Tau</small>
1515 <input class="neo-range-slider" type="range" id="mirostat_tau_textgenerationwebui" name="volume" min="0" max="20" step="0.01" />1515 <input class="neo-range-slider" type="range" id="mirostat_tau_textgenerationwebui" name="volume" min="0" max="20" step="0.01" />
1516 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="mirostat_tau_textgenerationwebui" id="mirostat_tau_counter_textgenerationwebui">1516 <input class="neo-range-input" type="number" min="0" max="20" step="0.01" data-for="mirostat_tau_textgenerationwebui" id="mirostat_tau_counter_textgenerationwebui">
1517 </div>1517 </div>
1518 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1518 <div data-tg-samplers="mirostat_eta" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1519 <small data-i18n="Mirostat Eta">Eta</small>1519 <small data-i18n="Mirostat Eta">Eta</small>
1520 <input class="neo-range-slider" type="range" id="mirostat_eta_textgenerationwebui" name="volume" min="0" max="1" step="0.01" />1520 <input class="neo-range-slider" type="range" id="mirostat_eta_textgenerationwebui" name="volume" min="0" max="1" step="0.01" />
1521 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="mirostat_eta_textgenerationwebui" id="mirostat_eta_counter_textgenerationwebui">1521 <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="mirostat_eta_textgenerationwebui" id="mirostat_eta_counter_textgenerationwebui">
1522 </div>1522 </div>
1523 </div>1523 </div>
1524 </div>1524 </div>
1525 <div data-tg-type="ooba" id="beamSearchBlock" name="beamSearchBlock" class="wide100p">1525 <div data-tg-type="ooba" data-tg-samplers="num_beams" id="beamSearchBlock" name="beamSearchBlock" class="wide100p">
1526 <h4 class="wide100p textAlignCenter">1526 <h4 class="wide100p textAlignCenter">
1527 <label>1527 <label>
1528 <span data-i18n="Beam search">Beam Search</span>1528 <span data-i18n="Beam search">Beam Search</span>
@@ -1538,7 +1538,7 @@
1538 <input class="neo-range-slider" type="range" id="num_beams_textgenerationwebui" name="volume" min="1" max="20" step="1" />1538 <input class="neo-range-slider" type="range" id="num_beams_textgenerationwebui" name="volume" min="1" max="20" step="1" />
1539 <input class="neo-range-input" type="number" min="1" max="20" step="1" data-for="num_beams_textgenerationwebui" id="num_beams_counter_textgenerationwebui">1539 <input class="neo-range-input" type="number" min="1" max="20" step="1" data-for="num_beams_textgenerationwebui" id="num_beams_counter_textgenerationwebui">
1540 </div>1540 </div>
1541 <div class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">1541 <div data-tg-samplers="length_penalty" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexGrow flexShrink gap0">
1542 <label>1542 <label>
1543 <small data-i18n="Length Penalty">Length Penalty</small>1543 <small data-i18n="Length Penalty">Length Penalty</small>
1544 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Penalize sequences based on their length." title="Penalize sequences based on their length."></div>1544 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Penalize sequences based on their length." title="Penalize sequences based on their length."></div>
@@ -1546,7 +1546,7 @@
1546 <input class="neo-range-slider" type="range" id="length_penalty_textgenerationwebui" name="volume" min="-5" max="5" step="0.1" />1546 <input class="neo-range-slider" type="range" id="length_penalty_textgenerationwebui" name="volume" min="-5" max="5" step="0.1" />
1547 <input class="neo-range-input" type="number" min="-5" max="5" step="0.1" data-for="length_penalty_textgenerationwebui" id="length_penalty_counter_textgenerationwebui">1547 <input class="neo-range-input" type="number" min="-5" max="5" step="0.1" data-for="length_penalty_textgenerationwebui" id="length_penalty_counter_textgenerationwebui">
1548 </div>1548 </div>
1549 <div class="">1549 <div data-tg-samplers="early_stopping" class="">
1550 <label class="checkbox_label" for="early_stopping_textgenerationwebui">1550 <label class="checkbox_label" for="early_stopping_textgenerationwebui">
1551 <input type="checkbox" id="early_stopping_textgenerationwebui" />1551 <input type="checkbox" id="early_stopping_textgenerationwebui" />
1552 <small data-i18n="Early Stopping">Early Stopping</small>1552 <small data-i18n="Early Stopping">Early Stopping</small>
@@ -1555,7 +1555,7 @@
1555 </div>1555 </div>
1556 </div>1556 </div>
1557 </div>1557 </div>
1558 <div data-tg-type="ooba" id="contrastiveSearchBlock" name="contrastiveSearchBlock" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">1558 <div data-tg-type="ooba" data-tg-samplers="penalty_alpha" id="contrastiveSearchBlock" name="contrastiveSearchBlock" class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
1559 <h4 class="textAlignCenter">1559 <h4 class="textAlignCenter">
1560 <span data-i18n="Contrastive search">Contrastive Search</span>1560 <span data-i18n="Contrastive search">Contrastive Search</span>
1561 <div class=" fa-solid fa-circle-info opacity50p " data-i18n="Contrastive_search_txt" title="A sampler that encourages diversity while maintaining coherence, by exploiting the isotropicity of the representation space of most LLMs. For details, see the paper A Contrastive Framework for Neural Text Generation by Su et al. (2022)."></div>1561 <div class=" fa-solid fa-circle-info opacity50p " data-i18n="Contrastive_search_txt" title="A sampler that encourages diversity while maintaining coherence, by exploiting the isotropicity of the representation space of most LLMs. For details, see the paper A Contrastive Framework for Neural Text Generation by Su et al. (2022)."></div>
@@ -1571,64 +1571,64 @@
1571 </div>1571 </div>
1572 <div name="checkboxes" class="flex-container flexBasis48p justifyCenter flexGrow flexShrink ">1572 <div name="checkboxes" class="flex-container flexBasis48p justifyCenter flexGrow flexShrink ">
1573 <div class="flex-container flexFlowColumn marginTop5">1573 <div class="flex-container flexFlowColumn marginTop5">
1574 <label data-tg-type="ooba" class="checkbox_label flexGrow flexShrink" for="do_sample_textgenerationwebui">1574 <label data-tg-type="ooba" data-tg-samplers="do_sample" class="checkbox_label flexGrow flexShrink" for="do_sample_textgenerationwebui">
1575 <input type="checkbox" id="do_sample_textgenerationwebui" />1575 <input type="checkbox" id="do_sample_textgenerationwebui" />
1576 <small data-i18n="Do Sample">Do Sample</small>1576 <small data-i18n="Do Sample">Do Sample</small>
1577 </label>1577 </label>
1578 <label data-tg-type="ooba, tabby" class="checkbox_label flexGrow flexShrink" for="add_bos_token_textgenerationwebui">1578 <label data-tg-type="ooba, tabby" data-tg-samplers="add_bos_token" class="checkbox_label flexGrow flexShrink" for="add_bos_token_textgenerationwebui">
1579 <input type="checkbox" id="add_bos_token_textgenerationwebui" />1579 <input type="checkbox" id="add_bos_token_textgenerationwebui" />
1580 <small data-i18n="Add BOS Token">Add BOS Token</small>1580 <small data-i18n="Add BOS Token">Add BOS Token</small>
1581 <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>1581 <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>
1582 </label>1582 </label>
1583 <label data-tg-type="ooba, llamacpp, tabby, koboldcpp, dreamgen" class="checkbox_label flexGrow flexShrink" for="ban_eos_token_textgenerationwebui">1583 <label data-tg-type="ooba, llamacpp, tabby, koboldcpp, dreamgen" data-tg-samplers="ban_eos_token" class="checkbox_label flexGrow flexShrink" for="ban_eos_token_textgenerationwebui">
1584 <input type="checkbox" id="ban_eos_token_textgenerationwebui" />1584 <input type="checkbox" id="ban_eos_token_textgenerationwebui" />
1585 <small data-i18n="Ban EOS Token">Ban EOS Token</small>1585 <small data-i18n="Ban EOS Token">Ban EOS Token</small>
1586 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ban the eos_token. This forces the model to never end the generation prematurely" title="Ban the eos_token. This forces the model to never end the generation prematurely."></div>1586 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ban the eos_token. This forces the model to never end the generation prematurely" title="Ban the eos_token. This forces the model to never end the generation prematurely."></div>
1587 </label>1587 </label>
1588 <label data-tg-type="vllm, aphrodite, infermaticai" class="checkbox_label" for="ignore_eos_token_textgenerationwebui">1588 <label data-tg-type="vllm, aphrodite, infermaticai" data-tg-samplers="ignore_eos_token" class="checkbox_label" for="ignore_eos_token_textgenerationwebui">
1589 <input type="checkbox" id="ignore_eos_token_textgenerationwebui" />1589 <input type="checkbox" id="ignore_eos_token_textgenerationwebui" />
1590 <small data-i18n="Ignore EOS Token">Ignore EOS Token</small>1590 <small data-i18n="Ignore EOS Token">Ignore EOS Token</small>
1591 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ignore the EOS Token even if it generates." title="Ignore the EOS Token even if it generates."></div>1591 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Ignore the EOS Token even if it generates." title="Ignore the EOS Token even if it generates."></div>
1592 </label>1592 </label>
1593 <label data-tg-type-mode="except" data-tg-type="generic" class="checkbox_label flexGrow flexShrink" for="skip_special_tokens_textgenerationwebui">1593 <label data-tg-type-mode="except" data-tg-type="generic" data-tg-samplers="skip_special_tokens" class="checkbox_label flexGrow flexShrink" for="skip_special_tokens_textgenerationwebui">
1594 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />1594 <input type="checkbox" id="skip_special_tokens_textgenerationwebui" />
1595 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>1595 <small data-i18n="Skip Special Tokens">Skip Special Tokens</small>
1596 </label>1596 </label>
1597 <label data-tg-type="openrouter" class="checkbox_label flexGrow flexShrink" for="include_reasoning_textgenerationwebui">1597 <label data-tg-type="openrouter" data-tg-samplers="include_reasoning" class="checkbox_label flexGrow flexShrink" for="include_reasoning_textgenerationwebui">
1598 <input type="checkbox" id="include_reasoning_textgenerationwebui" />1598 <input type="checkbox" id="include_reasoning_textgenerationwebui" />
1599 <small data-i18n="Request Model Reasoning">Request Model Reasoning</small>1599 <small data-i18n="Request Model Reasoning">Request Model Reasoning</small>
1600 </label>1600 </label>
1601 <label data-tg-type="ooba, aphrodite, tabby" class="checkbox_label flexGrow flexShrink" for="temperature_last_textgenerationwebui">1601 <label data-tg-type="ooba, aphrodite, tabby" data-tg-samplers="temperature_last" class="checkbox_label flexGrow flexShrink" for="temperature_last_textgenerationwebui">
1602 <input type="checkbox" id="temperature_last_textgenerationwebui" />1602 <input type="checkbox" id="temperature_last_textgenerationwebui" />
1603 <small data-i18n="Temperature Last">Temperature Last</small>1603 <small data-i18n="Temperature Last">Temperature Last</small>
1604 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Temperature_Last_desc" title="Use the temperature sampler last. This is almost always the sensible thing to do.&#13;When enabled: sample the set of plausible tokens first, then apply temperature to adjust their relative probabilities (technically, logits).&#13;When disabled: apply temperature to adjust the relative probabilities of ALL tokens first, then sample plausible tokens from that.&#13;Disabling Temperature Last boosts the probabilities in the tail of the distribution, which tends to amplify the chances of getting an incoherent response."></div>1604 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Temperature_Last_desc" title="Use the temperature sampler last. This is almost always the sensible thing to do.&#13;When enabled: sample the set of plausible tokens first, then apply temperature to adjust their relative probabilities (technically, logits).&#13;When disabled: apply temperature to adjust the relative probabilities of ALL tokens first, then sample plausible tokens from that.&#13;Disabling Temperature Last boosts the probabilities in the tail of the distribution, which tends to amplify the chances of getting an incoherent response."></div>
1605 </label>1605 </label>
1606 <label data-tg-type="tabby" class="checkbox_label flexGrow flexShrink" for="speculative_ngram_textgenerationwebui">1606 <label data-tg-type="tabby" data-tg-samplers="speculative_ngram" class="checkbox_label flexGrow flexShrink" for="speculative_ngram_textgenerationwebui">
1607 <input type="checkbox" id="speculative_ngram_textgenerationwebui" />1607 <input type="checkbox" id="speculative_ngram_textgenerationwebui" />
1608 <small data-i18n="Speculative Ngram">Speculative Ngram</small>1608 <small data-i18n="Speculative Ngram">Speculative Ngram</small>
1609 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Use a different speculative decoding method without a draft model" title="Use a different speculative decoding method without a draft model.&#13;Using a draft model is preferred. Speculative ngram is not as effective."></div>1609 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Use a different speculative decoding method without a draft model" title="Use a different speculative decoding method without a draft model.&#13;Using a draft model is preferred. Speculative ngram is not as effective."></div>
1610 </label>1610 </label>
1611 <label data-tg-type="vllm, aphrodite, infermaticai" class="checkbox_label" for="spaces_between_special_tokens_textgenerationwebui">1611 <label data-tg-type="vllm, aphrodite, infermaticai" data-tg-samplers="spaces_between_special_tokens" class="checkbox_label" for="spaces_between_special_tokens_textgenerationwebui">
1612 <input type="checkbox" id="spaces_between_special_tokens_textgenerationwebui" />1612 <input type="checkbox" id="spaces_between_special_tokens_textgenerationwebui" />
1613 <small data-i18n="Spaces Between Special Tokens">Spaces Between Special Tokens</small>1613 <small data-i18n="Spaces Between Special Tokens">Spaces Between Special Tokens</small>
1614 </label>1614 </label>
1615 </div>1615 </div>
1616 </div>1616 </div>
1617 <div data-tg-type="mancer, ooba, koboldcpp, vllm, aphrodite, llamacpp, ollama, infermaticai, huggingface, generic" class="flex-container flexFlowColumn alignitemscenter flexBasis48p flexGrow flexShrink gap0">1617 <div data-tg-type="mancer, ooba, koboldcpp, vllm, aphrodite, llamacpp, ollama, infermaticai, huggingface, generic" data-tg-samplers="seed" class="flex-container flexFlowColumn alignitemscenter flexBasis48p flexGrow flexShrink gap0">
1618 <label>1618 <label>
1619 <small data-i18n="Seed">Seed</small>1619 <small data-i18n="Seed">Seed</small>
1620 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Seed_desc" title="A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed."></div>1620 <div class="fa-solid fa-circle-info opacity50p " data-i18n="[title]Seed_desc" title="A random seed to use for deterministic and reproducable outputs. Set to -1 to use a random seed."></div>
1621 </label>1621 </label>
1622 <input type="number" id="seed_textgenerationwebui" class="text_pole textAlignCenter" min="-1" value="-1" />1622 <input type="number" id="seed_textgenerationwebui" class="text_pole textAlignCenter" min="-1" value="-1" />
1623 </div>1623 </div>
1624 <div data-tg-type-mode="except" data-tg-type="generic" id="banned_tokens_block_ooba" class="wide100p">1624 <div data-tg-type-mode="except" data-tg-type="generic" data-tg-samplers="banned_tokens" id="banned_tokens_block_ooba" class="wide100p">
1625 <hr class="width100p">1625 <hr class="width100p">
1626 <div class="range-block-title title_restorable">1626 <div class="range-block-title title_restorable">
1627 <div>1627 <div>
1628 <strong data-i18n="Banned Tokens">Banned Tokens/Strings</strong>1628 <strong data-i18n="Banned Tokens">Banned Tokens/Strings</strong>
1629 <div class="margin5 fa-solid fa-circle-info opacity50p " data-i18n="[title]LLaMA / Mistral / Yi models only" title="Enter sequences you don't want to appear in the output.&#13;Unquoted text will be tokenized in the back end and banned as tokens.&#13;[token ids] will be banned as-is.&#13;Most tokens have a leading space. Use token counter (with the correct tokenizer selected first!) if you are unsure.&#13;Enclose text in double quotes to ban the entire string as a set.&#13;Quoted Strings and [Token ids] must be on their own line."></div>1629 <div class="margin5 fa-solid fa-circle-info opacity50p " data-i18n="[title]LLaMA / Mistral / Yi models only" title="Enter sequences you don't want to appear in the output.&#13;Unquoted text will be tokenized in the back end and banned as tokens.&#13;[token ids] will be banned as-is.&#13;Most tokens have a leading space. Use token counter (with the correct tokenizer selected first!) if you are unsure.&#13;Enclose text in double quotes to ban the entire string as a set.&#13;Quoted Strings and [Token ids] must be on their own line."></div>
1630 </div>1630 </div>
1631 <label id="send_banned_tokens_label" for="send_banned_tokens_textgenerationwebui" class="checkbox_label">1631 <label data-tg-samplers="send_banned_tokens" id="send_banned_tokens_label" for="send_banned_tokens_textgenerationwebui" class="checkbox_label">
1632 <input id="send_banned_tokens_textgenerationwebui" type="checkbox" style="display:none;" />1632 <input id="send_banned_tokens_textgenerationwebui" type="checkbox" style="display:none;" />
1633 <small><i class="fa-solid fa-power-off menu_button togglable margin0"></i></small>1633 <small><i class="fa-solid fa-power-off menu_button togglable margin0"></i></small>
1634 </label>1634 </label>
@@ -1637,7 +1637,7 @@
1637 <div class="textAlignCenter">1637 <div class="textAlignCenter">
1638 <small data-i18n="Global list">Global list</small>1638 <small data-i18n="Global list">Global list</small>
1639 </div>1639 </div>
1640 <div class="wide100p marginBot10">1640 <div data-tg-samplers="global_banned_tokens" class="wide100p marginBot10">
1641 <textarea id="global_banned_tokens_textgenerationwebui" class="text_pole textarea_compact" name="global_banned_tokens_textgenerationwebui" rows="3" data-i18n="[placeholder]Example: some text [42, 69, 1337]" placeholder='some text as tokens&#10;[420, 69, 1337]&#10;"Some verbatim string"'></textarea>1641 <textarea id="global_banned_tokens_textgenerationwebui" class="text_pole textarea_compact" name="global_banned_tokens_textgenerationwebui" rows="3" data-i18n="[placeholder]Example: some text [42, 69, 1337]" placeholder='some text as tokens&#10;[420, 69, 1337]&#10;"Some verbatim string"'></textarea>
1642 </div>1642 </div>
1643 <div class="textAlignCenter">1643 <div class="textAlignCenter">
@@ -1648,7 +1648,7 @@
1648 </div>1648 </div>
1649 </div>1649 </div>
1650 </div>1650 </div>
1651 <div class="range-block wide100p" id="logit_bias_block_ooba">1651 <div data-tg-samplers="logit_bias" class="range-block wide100p" id="logit_bias_block_ooba">
1652 <div id="logit_bias_textgenerationwebui" class="range-block-title title_restorable">1652 <div id="logit_bias_textgenerationwebui" class="range-block-title title_restorable">
1653 <h4>1653 <h4>
1654 <span data-i18n="Logit Bias">Logit Bias</span>1654 <span data-i18n="Logit Bias">Logit Bias</span>
@@ -1665,7 +1665,7 @@
1665 <div class="logit_bias_list"></div>1665 <div class="logit_bias_list"></div>
1666 </div>1666 </div>
1667 </div>1667 </div>
1668 <div id="cfg_block_ooba" data-tg-type="ooba, tabby" class="flex-container flexFlowColumn wide100p">1668 <div id="cfg_block_ooba" data-tg-type="ooba, tabby" data-tg-samplers="guidance_scale" class="flex-container flexFlowColumn wide100p">
1669 <hr class="width100p">1669 <hr class="width100p">
1670 <h4 class="textAlignCenter">1670 <h4 class="textAlignCenter">
1671 <span data-i18n="CFG">CFG</span>1671 <span data-i18n="CFG">CFG</span>
@@ -1676,7 +1676,7 @@
1676 <input class="neo-range-slider" type="range" id="guidance_scale_textgenerationwebui" name="volume" min="0.1" max="4" step="0.05">1676 <input class="neo-range-slider" type="range" id="guidance_scale_textgenerationwebui" name="volume" min="0.1" max="4" step="0.05">
1677 <input class="neo-range-input" type="number" min="0.1" max="4" step="0.05" data-for="guidance_scale_textgenerationwebui" id="guidance_scale_counter_textgenerationwebui">1677 <input class="neo-range-input" type="number" min="0.1" max="4" step="0.05" data-for="guidance_scale_textgenerationwebui" id="guidance_scale_counter_textgenerationwebui">
1678 </div>1678 </div>
1679 <div class="range-block">1679 <div data-tg-samplers="negative_prompt" class="range-block">
1680 <div class="alignitemscenter justifyCenter flex-container flexShrink">1680 <div class="alignitemscenter justifyCenter flex-container flexShrink">
1681 <small data-i18n="Negative Prompt">Negative Prompt</small>1681 <small data-i18n="Negative Prompt">Negative Prompt</small>
1682 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Used if CFG Scale is unset globally, per chat or character" title="Used if CFG Scale is unset globally, per chat or character"></div>1682 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Used if CFG Scale is unset globally, per chat or character" title="Used if CFG Scale is unset globally, per chat or character"></div>
@@ -1684,7 +1684,7 @@
1684 <textarea id="negative_prompt_textgenerationwebui" class="wide100p text_pole textarea_compact" name="negative_prompt" rows="3" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>1684 <textarea id="negative_prompt_textgenerationwebui" class="wide100p text_pole textarea_compact" name="negative_prompt" rows="3" data-i18n="[placeholder]Add text here that would make the AI generate things you don't want in your outputs." placeholder="Add text here that would make the AI generate things you don't want in your outputs."></textarea>
1685 </div>1685 </div>
1686 </div>1686 </div>
1687 <div id="grammar_block_ooba" data-tg-type="ooba,aphrodite,tabby" class="wide100p">1687 <div id="grammar_block_ooba" data-tg-type="ooba,aphrodite,tabby" data-tg-samplers="grammar_string" class="wide100p">
1688 <hr class="wide100p">1688 <hr class="wide100p">
1689 <h4 class="wide100p textAlignCenter">1689 <h4 class="wide100p textAlignCenter">
1690 <div class="flex-container justifyCenter alignitemscenter">1690 <div class="flex-container justifyCenter alignitemscenter">
@@ -1697,7 +1697,7 @@
1697 </h4>1697 </h4>
1698 <textarea id="grammar_string_textgenerationwebui" rows="4" class="text_pole textarea_compact monospace" data-i18n="[placeholder]Type in the desired custom grammar" placeholder="Type in the desired custom grammar"></textarea>1698 <textarea id="grammar_string_textgenerationwebui" rows="4" class="text_pole textarea_compact monospace" data-i18n="[placeholder]Type in the desired custom grammar" placeholder="Type in the desired custom grammar"></textarea>
1699 </div>1699 </div>
1700 <div id="json_schema_block" data-tg-type="tabby, llamacpp, aphrodite" class="wide100p">1700 <div id="json_schema_block" data-tg-type="tabby, llamacpp, aphrodite" data-tg-samplers="json_schema" class="wide100p">
1701 <hr class="wide100p">1701 <hr class="wide100p">
1702 <h4 class="wide100p textAlignCenter"><span data-i18n="JSON Schema">JSON Schema</span>1702 <h4 class="wide100p textAlignCenter"><span data-i18n="JSON Schema">JSON Schema</span>
1703 <a href="https://json-schema.org/learn/getting-started-step-by-step" target="_blank">1703 <a href="https://json-schema.org/learn/getting-started-step-by-step" target="_blank">
@@ -1708,7 +1708,7 @@
1708 </h4>1708 </h4>
1709 <textarea id="tabby_json_schema" rows="4" class="text_pole textarea_compact monospace" data-i18n="[placeholder]Type in the desired JSON schema" placeholder="Type in the desired JSON schema"></textarea>1709 <textarea id="tabby_json_schema" rows="4" class="text_pole textarea_compact monospace" data-i18n="[placeholder]Type in the desired JSON schema" placeholder="Type in the desired JSON schema"></textarea>
1710 </div>1710 </div>
1711 <div id="sampler_order_block_kcpp" data-tg-type="koboldcpp" class="range-block flexFlowColumn wide100p">1711 <div id="sampler_order_block_kcpp" data-tg-type="koboldcpp" data-tg-samplers="sampler_order" class="range-block flexFlowColumn wide100p">
1712 <hr class="wide100p">1712 <hr class="wide100p">
1713 <div class="range-block-title">1713 <div class="range-block-title">
1714 <span data-i18n="Samplers Order">Samplers Order</span>1714 <span data-i18n="Samplers Order">Samplers Order</span>
@@ -1751,7 +1751,7 @@
1751 <span data-i18n="Load default order">Load default order</span>1751 <span data-i18n="Load default order">Load default order</span>
1752 </div>1752 </div>
1753 </div>1753 </div>
1754 <div id="sampler_order_block_lcpp" data-tg-type="llamacpp" class="range-block flexFlowColumn wide100p">1754 <div id="sampler_order_block_lcpp" data-tg-type="llamacpp" data-tg-samplers="samplers" class="range-block flexFlowColumn wide100p">
1755 <hr class="wide100p">1755 <hr class="wide100p">
1756 <h4 class="range-block-title justifyCenter">1756 <h4 class="range-block-title justifyCenter">
1757 <span data-i18n="Sampler Order">Sampler Order</span>1757 <span data-i18n="Sampler Order">Sampler Order</span>
@@ -1775,7 +1775,7 @@
1775 <span data-i18n="Load default order">Load default order</span>1775 <span data-i18n="Load default order">Load default order</span>
1776 </div>1776 </div>
1777 </div>1777 </div>
1778 <div id="sampler_priority_block_ooba" data-tg-type="ooba" class="range-block flexFlowColumn wide100p">1778 <div id="sampler_priority_block_ooba" data-tg-type="ooba" data-tg-samplers="sampler_priority" class="range-block flexFlowColumn wide100p">
1779 <hr class="wide100p">1779 <hr class="wide100p">
1780 <h4 class="range-block-title justifyCenter">1780 <h4 class="range-block-title justifyCenter">
1781 <span data-i18n="Sampler Priority">Sampler Priority</span>1781 <span data-i18n="Sampler Priority">Sampler Priority</span>
@@ -1810,7 +1810,7 @@
1810 <span data-i18n="Load default order">Load default order</span>1810 <span data-i18n="Load default order">Load default order</span>
1811 </div>1811 </div>
1812 </div>1812 </div>
1813 <div id="sampler_priority_block_aphrodite" data-tg-type="aphrodite" class="range-block flexFlowColumn wide100p">1813 <div id="sampler_priority_block_aphrodite" data-tg-type="aphrodite" data-tg-samplers="samplers_priorities" class="range-block flexFlowColumn wide100p">
1814 <hr class="wide100p">1814 <hr class="wide100p">
1815 <h4 class="range-block-title justifyCenter">1815 <h4 class="range-block-title justifyCenter">
1816 <span data-i18n="Sampler Order">Sampler Order</span>1816 <span data-i18n="Sampler Order">Sampler Order</span>
@@ -1965,7 +1965,7 @@
1965 </b>1965 </b>
1966 </div>1966 </div>
1967 </div>1967 </div>
1968 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi,electronhub,azure_openai">1968 <div class="range-block" data-source="openai,cohere,mistralai,custom,claude,aimlapi,openrouter,groq,siliconflow,deepseek,makersuite,vertexai,ai21,xai,pollinations,moonshot,fireworks,cometapi,electronhub,azure_openai,zai">
1969 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">1969 <label for="openai_function_calling" class="checkbox_label flexWrap widthFreeExpand">
1970 <input id="openai_function_calling" type="checkbox" />1970 <input id="openai_function_calling" type="checkbox" />
1971 <span data-i18n="Enable function calling">Enable function calling</span>1971 <span data-i18n="Enable function calling">Enable function calling</span>
@@ -1980,7 +1980,7 @@
1980 <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong>1980 <strong data-i18n="enable_functions_desc_4">Not supported when Prompt Post-Processing with "no tools" is used!</strong>
1981 </div>1981 </div>
1982 </div>1982 </div>
1983 <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt,electronhub,azure_openai">1983 <div class="range-block" data-source="openai,aimlapi,openrouter,mistralai,makersuite,vertexai,claude,custom,xai,pollinations,moonshot,cohere,cometapi,nanogpt,electronhub,azure_openai,zai,siliconflow">
1984 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">1984 <label for="openai_image_inlining" class="checkbox_label flexWrap widthFreeExpand">
1985 <input id="openai_image_inlining" type="checkbox" />1985 <input id="openai_image_inlining" type="checkbox" />
1986 <span data-i18n="Send inline images">Send inline images</span>1986 <span data-i18n="Send inline images">Send inline images</span>
@@ -1990,13 +1990,9 @@
1990 </div>1990 </div>
1991 </label>1991 </label>
1992 <div id="image_inlining_hint" class="flexBasis100p toggle-description justifyLeft">1992 <div id="image_inlining_hint" class="flexBasis100p toggle-description justifyLeft">
1993 <span data-i18n="image_inlining_hint_1">Sends images in prompts if the model supports it. Use the</span>1993 <span data-i18n="image_inlining_hint_1">Sends images in prompts if the model supports it.</span>
1994 <code><i class="fa-solid fa-paperclip"></i></code>
1995 <span data-i18n="image_inlining_hint_2">action on any message or the</span>
1996 <code><i class="fa-solid fa-wand-magic-sparkles"></i></code>
1997 <span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span>
1998 </div>1994 </div>
1999 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere,cometapi,nanogpt,moonshot,aimlapi,openrouter,mistralai,electronhub,azure_openai">1995 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,xai,pollinations,cohere,cometapi,nanogpt,moonshot,aimlapi,openrouter,mistralai,electronhub,azure_openai,zai,siliconflow">
2000 <div class="flex-container oneline-dropdown">1996 <div class="flex-container oneline-dropdown">
2001 <label for="openai_inline_image_quality" data-i18n="Inline Image Quality">1997 <label for="openai_inline_image_quality" data-i18n="Inline Image Quality">
2002 Inline Image Quality1998 Inline Image Quality
@@ -2009,7 +2005,7 @@
2009 </div>2005 </div>
2010 </div>2006 </div>
2011 </div>2007 </div>
2012 <div class="range-block" data-source="makersuite,vertexai">2008 <div class="range-block" data-source="makersuite,vertexai,openrouter">
2013 <label for="openai_video_inlining" class="checkbox_label flexWrap widthFreeExpand">2009 <label for="openai_video_inlining" class="checkbox_label flexWrap widthFreeExpand">
2014 <input id="openai_video_inlining" type="checkbox" />2010 <input id="openai_video_inlining" type="checkbox" />
2015 <span data-i18n="Send inline videos">Send inline videos</span>2011 <span data-i18n="Send inline videos">Send inline videos</span>
@@ -2019,12 +2015,22 @@
2019 </div>2015 </div>
2020 </label>2016 </label>
2021 <div id="video_inlining_hint" class="flexBasis100p toggle-description justifyLeft">2017 <div id="video_inlining_hint" class="flexBasis100p toggle-description justifyLeft">
2022 <span data-i18n="video_inlining_hint_1">Sends videos in prompts if the model supports it. Use the</span>2018 <span data-i18n="video_inlining_hint_1">Sends videos in prompts if the model supports it.</span>
2023 <code><i class="fa-solid fa-paperclip"></i></code>2019 <strong data-source="makersuite,vertexai" data-i18n="video_inlining_hint_4">Videos must be less than 20 MB and under 1 minute long</strong>
2024 <span data-i18n="video_inlining_hint_2">action on any message or the</span>2020 </div>
2025 <code><i class="fa-solid fa-wand-magic-sparkles"></i></code>2021 </div>
2026 <span data-i18n="video_inlining_hint_3">menu to attach a video file to the chat.</span>2022 <div class="range-block" data-source="makersuite,vertexai,openrouter">
2027 <strong data-i18n="video_inlining_hint_4">Videos must be less than 20 MB and under 1 minute long</strong>2023 <label for="openai_audio_inlining" class="checkbox_label flexWrap widthFreeExpand">
2024 <input id="openai_audio_inlining" type="checkbox" />
2025 <span data-i18n="Send inline audio">Send inline audio</span>
2026 <div id="openai_audio_inlining_supported" data-cc-toggle="false">
2027 <i class="icon-supported fa-solid fa-circle-check" title="Supported by the current model" data-i18n="[title]Supported by the current model"></i>
2028 <i class="icon-unsupported fa-solid fa-circle-exclamation" title="Unsupported by the current model" data-i18n="[title]Unsupported by the current model"></i>
2029 </div>
2030 </label>
2031 <div id="audio_inlining_hint" class="flexBasis100p toggle-description justifyLeft">
2032 <span data-i18n="audio_inlining_hint_1">Sends audio in prompts if the model supports it.</span>
2033 <strong data-source="makersuite,vertexai" data-i18n="audio_inlining_hint_2">Audio must be less than 20 MB</strong>
2028 </div>2034 </div>
2029 </div>2035 </div>
2030 <div class="range-block" data-source="makersuite,vertexai">2036 <div class="range-block" data-source="makersuite,vertexai">
@@ -2058,7 +2064,7 @@
2058 </span>2064 </span>
2059 </div>2065 </div>
2060 </div>2066 </div>
2061 <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi,electronhub,azure_openai,nanogpt">2067 <div class="range-block" data-source="deepseek,aimlapi,openrouter,custom,claude,xai,makersuite,vertexai,pollinations,moonshot,mistralai,fireworks,cometapi,electronhub,azure_openai,nanogpt,zai">
2062 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">2068 <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
2063 <input id="openai_show_thoughts" type="checkbox" />2069 <input id="openai_show_thoughts" type="checkbox" />
2064 <span data-i18n="Request model reasoning">Request model reasoning</span>2070 <span data-i18n="Request model reasoning">Request model reasoning</span>
@@ -2067,9 +2073,9 @@
2067 <span data-i18n="Allows the model to return its thinking process.">2073 <span data-i18n="Allows the model to return its thinking process.">
2068 Allows the model to return its thinking process.2074 Allows the model to return its thinking process.
2069 </span>2075 </span>
2070 <span data-i18n="This setting affects visibility only.">2076 <strong data-i18n="This setting affects visibility only." data-source-mode="except" data-source="zai">
2071 This setting affects visibility only.2077 This setting affects visibility only.
2072 </span>2078 </strong>
2073 </div>2079 </div>
2074 </div>2080 </div>
2075 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity,cometapi,electronhub,azure_openai">2081 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom,claude,xai,makersuite,vertexai,aimlapi,openrouter,pollinations,perplexity,cometapi,electronhub,azure_openai">
@@ -2800,7 +2806,9 @@
2800 <option value="openrouter">OpenRouter</option>2806 <option value="openrouter">OpenRouter</option>
2801 <option value="perplexity">Perplexity</option>2807 <option value="perplexity">Perplexity</option>
2802 <option value="pollinations">Pollinations</option>2808 <option value="pollinations">Pollinations</option>
2809 <option value="siliconflow">SiliconFlow</option>
2803 <option value="xai">xAI (Grok)</option>2810 <option value="xai">xAI (Grok)</option>
2811 <option value="zai">Z.AI (GLM)</option>
2804 </optgroup>2812 </optgroup>
2805 </select>2813 </select>
2806 <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,vertexai,deepseek,xai">2814 <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,vertexai,deepseek,xai">
@@ -2917,6 +2925,11 @@
2917 <div>2925 <div>
2918 <h4 data-i18n="OpenAI Model">OpenAI Model</h4>2926 <h4 data-i18n="OpenAI Model">OpenAI Model</h4>
2919 <select id="model_openai_select">2927 <select id="model_openai_select">
2928 <optgroup label="GPT-5.1">
2929 <option value="gpt-5.1">gpt-5.1</option>
2930 <option value="gpt-5.1-2025-11-13">gpt-5.1-2025-11-13</option>
2931 <option value="gpt-5.1-chat-latest">gpt-5.1-chat-latest</option>
2932 </optgroup>
2920 <optgroup label="GPT-5">2933 <optgroup label="GPT-5">
2921 <option value="gpt-5">gpt-5</option>2934 <option value="gpt-5">gpt-5</option>
2922 <option value="gpt-5-2025-08-07">gpt-5-2025-08-07</option>2935 <option value="gpt-5-2025-08-07">gpt-5-2025-08-07</option>
@@ -3154,6 +3167,10 @@
3154 <div>3167 <div>
3155 <h4 data-i18n="Google Model">Google Model</h4>3168 <h4 data-i18n="Google Model">Google Model</h4>
3156 <select id="model_google_select">3169 <select id="model_google_select">
3170 <optgroup label="Gemini 3.0">
3171 <option value="gemini-3-pro-preview">gemini-3-pro-preview</option>
3172 <option value="gemini-3-pro-image-preview">gemini-3-pro-image-preview</option>
3173 </optgroup>
3157 <optgroup label="Gemini 2.5">3174 <optgroup label="Gemini 2.5">
3158 <option value="gemini-2.5-pro">gemini-2.5-pro</option>3175 <option value="gemini-2.5-pro">gemini-2.5-pro</option>
3159 <option value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option>3176 <option value="gemini-2.5-pro-preview-06-05">gemini-2.5-pro-preview-06-05</option>
@@ -3322,6 +3339,10 @@
3322 <h4 data-i18n="Google Model">Google Model</h4>3339 <h4 data-i18n="Google Model">Google Model</h4>
3323 <select id="model_vertexai_select">3340 <select id="model_vertexai_select">
3324 <!-- data-mode="full" is for models that require a service account -->3341 <!-- data-mode="full" is for models that require a service account -->
3342 <optgroup label="Gemini 3.0">
3343 <option value="gemini-3-pro-preview">gemini-3-pro-preview</option>
3344 <option value="gemini-3-pro-image-preview">gemini-3-pro-image-preview</option>
3345 </optgroup>
3325 <optgroup label="Gemini 2.5">3346 <optgroup label="Gemini 2.5">
3326 <option value="gemini-2.5-pro">gemini-2.5-pro</option>3347 <option value="gemini-2.5-pro">gemini-2.5-pro</option>
3327 <option value="gemini-2.5-flash">gemini-2.5-flash</option>3348 <option value="gemini-2.5-flash">gemini-2.5-flash</option>
@@ -3379,6 +3400,20 @@
3379 <option value="mistral-saba-24b">mistral-saba-24b</option>3400 <option value="mistral-saba-24b">mistral-saba-24b</option>
3380 </select>3401 </select>
3381 </div>3402 </div>
3403 <div id="siliconflow_form" data-source="siliconflow">
3404 <h4>SiliconFlow API Key</h4>
3405 <div class="flex-container">
3406 <input id="api_key_siliconflow" name="api_key_siliconflow" class="text_pole flex1" value="" type="text" autocomplete="off">
3407 <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_siliconflow"></div>
3408 </div>
3409 <div data-for="api_key_siliconflow" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'.">
3410 For privacy reasons, your API key will be hidden after you click 'Connect'.
3411 </div>
3412 <h4>SiliconFlow Model</h4>
3413 <select id="model_siliconflow_select">
3414 <option value="" data-i18n="-- Connect to the API --">-- Connect to the API --</option>
3415 </select>
3416 </div>
3382 <div id="electronhub_form" data-source="electronhub">3417 <div id="electronhub_form" data-source="electronhub">
3383 <h4 data-i18n="Electron Hub API Key">Electron Hub API Key</h4>3418 <h4 data-i18n="Electron Hub API Key">Electron Hub API Key</h4>
3384 <div>3419 <div>
@@ -3674,6 +3709,36 @@
3674 <option value="kimi-thinking-preview">kimi-thinking-preview</option>3709 <option value="kimi-thinking-preview">kimi-thinking-preview</option>
3675 </select>3710 </select>
3676 </div>3711 </div>
3712 <div id="zai_form" data-source="zai">
3713 <h4>
3714 <a data-i18n="Z.AI API Key" href="https://z.ai/manage-apikey/apikey-list" target="_blank" rel="noopener noreferrer">
3715 Z.AI API Key
3716 </a>
3717 </h4>
3718 <div class="flex-container">
3719 <input id="api_key_zai" name="api_key_zai" class="text_pole flex1" value="" type="text" autocomplete="off">
3720 <div title="Manage API keys" data-i18n="[title]Manage API keys" class="menu_button fa-solid fa-key fa-fw manage-api-keys" data-key="api_key_zai"></div>
3721 </div>
3722 <div data-for="api_key_zai" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you click 'Connect'.">
3723 For privacy reasons, your API key will be hidden after you click 'Connect'.
3724 </div>
3725 <h4 data-i18n="Z.AI Endpoint">Z.AI Endpoint</h4>
3726 <select id="zai_endpoint">
3727 <option value="common" data-i18n="Common API">Common API</option>
3728 <option value="coding" data-i18n="Coding API">Coding API</option>
3729 </select>
3730 <h4 data-i18n="Z.AI Model">Z.AI Model</h4>
3731 <select id="model_zai_select">
3732 <option value="glm-4.6">glm-4.6</option>
3733 <option value="glm-4.5v">glm-4.5v</option>
3734 <option value="glm-4.5">glm-4.5</option>
3735 <option value="glm-4.5-air">glm-4.5-air</option>
3736 <option value="glm-4.5-x">glm-4.5-x</option>
3737 <option value="glm-4.5-airx">glm-4.5-airx</option>
3738 <option value="glm-4.5-flash">glm-4.5-flash</option>
3739 <option value="glm-4-32b-0414-128k">glm-4-32b-0414-128k</option>
3740 </select>
3741 </div>
3677 <div id="azure_openai_settings" data-source="azure_openai">3742 <div id="azure_openai_settings" data-source="azure_openai">
3678 <!-- Azure Base URL -->3743 <!-- Azure Base URL -->
3679 <h4><span data-i18n="Azure Base URL">Azure Base URL</span></h4>3744 <h4><span data-i18n="Azure Base URL">Azure Base URL</span></h4>
@@ -3779,7 +3844,7 @@
3779 <span class="fa-solid fa-circle-question note-link-span"></span>3844 <span class="fa-solid fa-circle-question note-link-span"></span>
3780 </a>3845 </a>
3781 </h3>3846 </h3>
3782 <div class="flex-container">3847 <div class="flex-container" data-cc-null>
3783 <input id="af_master_import_file" type="file" hidden accept=".json" class="displayNone">3848 <input id="af_master_import_file" type="file" hidden accept=".json" class="displayNone">
3784 <div id="af_master_import" class="menu_button menu_button_icon" title="Import Advanced Formatting settings&#10;&#10;You can also provide legacy files for Instruct and Context templates." data-i18n="[title]Import Advanced Formatting settings">3849 <div id="af_master_import" class="menu_button menu_button_icon" title="Import Advanced Formatting settings&#10;&#10;You can also provide legacy files for Instruct and Context templates." data-i18n="[title]Import Advanced Formatting settings">
3785 <i class="fa-solid fa-file-import"></i>3850 <i class="fa-solid fa-file-import"></i>
@@ -3791,10 +3856,16 @@
3791 </div>3856 </div>
3792 </div>3857 </div>
3793 </div>3858 </div>
3859 <div id="advanced-formatting-cc-notice" class="info-block warning">
3860 <i class="fa-solid fa-triangle-exclamation"></i>
3861 <span data-i18n="Grayed-out options have no effect when Chat Completion API is used.">
3862 Grayed-out options have no effect when Chat Completion API is used.
3863 </span>
3864 </div>
3794 <div class="flex-container spaceEvenly">3865 <div class="flex-container spaceEvenly">
3795 <div id="ContextSettings" class="flex-container flexNoGap flexFlowColumn flex1">3866 <div id="ContextSettings" class="flex-container flexNoGap flexFlowColumn flex1">
3796 <div>3867 <div>
3797 <h4 class="standoutHeader title_restorable">3868 <h4 class="standoutHeader title_restorable" data-cc-null>
3798 <div>3869 <div>
3799 <span data-i18n="Context Template">Context Template</span>3870 <span data-i18n="Context Template">Context Template</span>
3800 </div>3871 </div>
@@ -3805,7 +3876,7 @@
3805 </label>3876 </label>
3806 </div>3877 </div>
3807 </h4>3878 </h4>
3808 <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template">3879 <div class="flex-container" title="Select your current Context Template" data-i18n="[title]Select your current Context Template" data-cc-null>
3809 <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select>3880 <select id="context_presets" data-preset-manager-for="context" class="flex1 text_pole"></select>
3810 <div class="flex-container justifyCenter gap3px">3881 <div class="flex-container justifyCenter gap3px">
3811 <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings">3882 <input type="file" hidden data-preset-manager-file="context" accept=".json, .settings">
@@ -3819,12 +3890,14 @@
3819 </div>3890 </div>
3820 </div>3891 </div>
3821 <div>3892 <div>
3822 <label for="context_story_string" class="flex-container">3893 <div data-cc-null>
3823 <small data-i18n="Story String">Story String</small>3894 <label for="context_story_string" class="flex-container">
3824 <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="context_story_string" title="Expand the editor" data-i18n="[title]Expand the editor"></i>3895 <small data-i18n="Story String">Story String</small>
3825 </label>3896 <i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="context_story_string" title="Expand the editor" data-i18n="[title]Expand the editor"></i>
3826 <textarea id="context_story_string" class="text_pole textarea_compact autoSetHeight"></textarea>3897 </label>
3827 <div class="flex-container flexFlowColumn">3898 <textarea id="context_story_string" class="text_pole textarea_compact autoSetHeight"></textarea>
3899 </div>
3900 <div class="flex-container flexFlowColumn" data-cc-null>
3828 <div id="context_story_string_position_block">3901 <div id="context_story_string_position_block">
3829 <label for="context_story_string_position">3902 <label for="context_story_string_position">
3830 <small data-i18n="Position:">Position:</small>3903 <small data-i18n="Position:">Position:</small>
@@ -3853,7 +3926,7 @@
3853 </div>3926 </div>
3854 </div>3927 </div>
3855 </div>3928 </div>
3856 <div class="flex-container">3929 <div class="flex-container" data-cc-null>
3857 <div class="flex1">3930 <div class="flex1">
3858 <label for="context_example_separator">3931 <label for="context_example_separator">
3859 <small data-i18n="Example Separator">Example Separator</small>3932 <small data-i18n="Example Separator">Example Separator</small>
@@ -3878,13 +3951,13 @@
3878 </span>3951 </span>
3879 </h4>3952 </h4>
38803953
3881 <label class="checkbox_label" for="always-force-name2-checkbox">3954 <label class="checkbox_label" for="always-force-name2-checkbox" data-cc-null>
3882 <input id="always-force-name2-checkbox" type="checkbox" />3955 <input id="always-force-name2-checkbox" type="checkbox" />
3883 <small data-i18n="Always add character's name to prompt">3956 <small data-i18n="Always add character's name to prompt">
3884 Always add character's name to prompt3957 Always add character's name to prompt
3885 </small>3958 </small>
3886 </label>3959 </label>
3887 <label class="checkbox_label" for="single_line">3960 <label class="checkbox_label" for="single_line" data-cc-null>
3888 <input id="single_line" type="checkbox" />3961 <input id="single_line" type="checkbox" />
3889 <small data-i18n="Generate only one line per request">3962 <small data-i18n="Generate only one line per request">
3890 Generate only one line per request3963 Generate only one line per request
@@ -3907,11 +3980,11 @@
3907 Trim Incomplete Sentences3980 Trim Incomplete Sentences
3908 </small>3981 </small>
3909 </label>3982 </label>
3910 <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings.">3983 <label class="checkbox_label" title="Add Chat Start and Example Separator to a list of stopping strings." data-i18n="[title]Add Chat Start and Example Separator to a list of stopping strings." data-cc-null>
3911 <input id="context_use_stop_strings" type="checkbox" />3984 <input id="context_use_stop_strings" type="checkbox" />
3912 <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small>3985 <small data-i18n="Separators as Stop Strings">Separators as Stop Strings</small>
3913 </label>3986 </label>
3914 <label class="checkbox_label" title="Add Character and User names to a list of stopping strings." data-i18n="[title]Add Character and User names to a list of stopping strings.">3987 <label class="checkbox_label" title="Add Character and User names to a list of stopping strings." data-i18n="[title]Add Character and User names to a list of stopping strings." data-cc-null>
3915 <input id="context_names_as_stop_strings" type="checkbox" />3988 <input id="context_names_as_stop_strings" type="checkbox" />
3916 <small data-i18n="Names as Stop Strings">Names as Stop Strings</small>3989 <small data-i18n="Names as Stop Strings">Names as Stop Strings</small>
3917 </label>3990 </label>
@@ -3919,7 +3992,7 @@
3919 </div>3992 </div>
3920 </div>3993 </div>
3921 </div>3994 </div>
3922 <div id="InstructSettingsColumn" class="flex-container flexNoGap flexFlowColumn flex1">3995 <div id="InstructSettingsColumn" class="flex-container flexNoGap flexFlowColumn flex1" data-cc-null>
3923 <h4 class="standoutHeader title_restorable justifySpaceBetween">3996 <h4 class="standoutHeader title_restorable justifySpaceBetween">
3924 <div class="flex-container">3997 <div class="flex-container">
3925 <span data-i18n="Instruct Template">Instruct Template</span>3998 <span data-i18n="Instruct Template">Instruct Template</span>
@@ -4113,7 +4186,7 @@
4113 </div>4186 </div>
4114 </div>4187 </div>
4115 <div id="SystemPromptColumn" class="flex-container flexNoGap flexFlowColumn flex1">4188 <div id="SystemPromptColumn" class="flex-container flexNoGap flexFlowColumn flex1">
4116 <h4 class="standoutHeader title_restorable justifySpaceBetween">4189 <h4 class="standoutHeader title_restorable justifySpaceBetween" data-cc-null>
4117 <div class="flex-container">4190 <div class="flex-container">
4118 <span data-i18n="System Prompt">System Prompt</span>4191 <span data-i18n="System Prompt">System Prompt</span>
4119 </div>4192 </div>
@@ -4124,7 +4197,7 @@
4124 </label>4197 </label>
4125 </div>4198 </div>
4126 </h4>4199 </h4>
4127 <div id="SystemPromptBlock" class="marginBot10">4200 <div id="SystemPromptBlock" class="marginBot10" data-cc-null>
4128 <div class="flex-container" title="Select your current System Prompt" data-i18n="[title]Select your current System Prompt">4201 <div class="flex-container" title="Select your current System Prompt" data-i18n="[title]Select your current System Prompt">
4129 <select id="sysprompt_select" data-preset-manager-for="sysprompt" class="flex1 text_pole"></select>4202 <select id="sysprompt_select" data-preset-manager-for="sysprompt" class="flex1 text_pole"></select>
4130 <div class="flex-container margin0 justifyCenter gap3px">4203 <div class="flex-container margin0 justifyCenter gap3px">
@@ -4182,7 +4255,7 @@
4182 </label>4255 </label>
4183 </div>4256 </div>
41844257
4185 <div name="tokenizerSettingsBlock">4258 <div name="tokenizerSettingsBlock" data-cc-null>
4186 <div name="tokenizerSelectorBlock">4259 <div name="tokenizerSelectorBlock">
4187 <h4 class="standoutHeader"><span data-i18n="Tokenizer">Tokenizer</span>4260 <h4 class="standoutHeader"><span data-i18n="Tokenizer">Tokenizer</span>
4188 <a href="https://docs.sillytavern.app/usage/prompts/tokenizer/" class="notes-link" target="_blank">4261 <a href="https://docs.sillytavern.app/usage/prompts/tokenizer/" class="notes-link" target="_blank">
@@ -4295,7 +4368,7 @@
4295 </div>4368 </div>
4296 <div>4369 <div>
4297 <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4>4370 <h4 class="standoutHeader" data-i18n="Miscellaneous">Miscellaneous</h4>
4298 <div name="bindModelPresetBlock">4371 <div name="bindModelPresetBlock" data-cc-null>
4299 <label for="bind_model_templates" class="checkbox_label">4372 <label for="bind_model_templates" class="checkbox_label">
4300 <input id="bind_model_templates" type="checkbox" />4373 <input id="bind_model_templates" type="checkbox" />
4301 <small data-i18n="Bind Model to Templates">Bind Model to Templates</small>4374 <small data-i18n="Bind Model to Templates">Bind Model to Templates</small>
@@ -4637,6 +4710,13 @@
4637 <option value="2" data-i18n="Document">Document</option>4710 <option value="2" data-i18n="Document">Document</option>
4638 </select>4711 </select>
4639 </div>4712 </div>
4713 <div class="flex-container alignitemscenter" title="Default display style for media attachments in chat messages. Extensions can override this setting." data-i18n="[title]Default display style for media attachments in chat messages. Extensions can override this setting.">
4714 <span data-i18n="Media Style:">Media Style:</span>
4715 <select id="media_display" class="widthNatural flex1 margin0 text_pole">
4716 <option value="list" data-i18n="List">List</option>
4717 <option value="gallery" data-i18n="Gallery">Gallery</option>
4718 </select>
4719 </div>
4640 <div class="flex-container alignItemsBaseline">4720 <div class="flex-container alignItemsBaseline">
4641 <span data-i18n="Notifications:">Notifications:</span>4721 <span data-i18n="Notifications:">Notifications:</span>
4642 <select id="toastr_position" class="widthNatural flex1 margin0 text_pole">4722 <select id="toastr_position" class="widthNatural flex1 margin0 text_pole">
@@ -5010,7 +5090,7 @@
5010 </div>5090 </div>
5011 </div>5091 </div>
5012 <div id="examples-behavior-block">5092 <div id="examples-behavior-block">
5013 <label>5093 <label for="example_messages_behavior">
5014 <small data-i18n="Example Messages Behavior">5094 <small data-i18n="Example Messages Behavior">
5015 Example Messages Behavior:5095 Example Messages Behavior:
5016 </small>5096 </small>
@@ -5021,6 +5101,17 @@
5021 <option value="strip" data-i18n="Never include examples">Never include examples</option>5101 <option value="strip" data-i18n="Never include examples">Never include examples</option>
5022 </select>5102 </select>
5023 </div>5103 </div>
5104 <div>
5105 <label for="image_overswipe">
5106 <small data-i18n="Image Swipe Behavior:">
5107 Image Swipe Behavior:
5108 </small>
5109 </label>
5110 <select id="image_overswipe">
5111 <option value="generate" data-i18n="Generate new">Generate new</option>
5112 <option value="rollover" data-i18n="Roll over">Roll over</option>
5113 </select>
5114 </div>
5024 <div class="flex-container alignitemscenter">5115 <div class="flex-container alignitemscenter">
5025 <small data-i18n="Send on Enter">5116 <small data-i18n="Send on Enter">
5026 Enter to Send:5117 Enter to Send:
@@ -5664,7 +5755,7 @@
5664 <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div>5755 <div class="chat_lorebook_button menu_button fa-solid fa-passport" title="Chat Lore&#10;Alt+Click to open the lorebook" data-i18n="[title]Chat Lore Alt+Click to open the lorebook"></div>
5665 <div id="char_connections_button" class="menu_button fa-solid fa-face-smile" title="Connected Personas" data-i18n="[title]Connected Personas"></div>5756 <div id="char_connections_button" class="menu_button fa-solid fa-face-smile" title="Connected Personas" data-i18n="[title]Connected Personas"></div>
5666 <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>5757 <div id="export_button" class="menu_button fa-solid fa-file-export " title="Export and Download" data-i18n="[title]Export and Download"></div>
5667 <!-- <div id="set_chat_scenario" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->5758 <!-- <div id="set_chat_character_settings" class="menu_button fa-solid fa-scroll" title="Set a chat scenario override"></div> -->
5668 <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->5759 <!-- <div id="set_character_world" class="menu_button fa-solid fa-globe" title="Set a character World Info / Lorebook"></div> -->
5669 <div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character" data-i18n="[title]Duplicate Character"></div>5760 <div id="dupe_button" class="menu_button fa-solid fa-clone " title="Duplicate Character" data-i18n="[title]Duplicate Character"></div>
5670 <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character" data-i18n="[title]Create Character">5761 <label for="create_button" id="create_button_label" class="menu_button fa-solid fa-user-check" title="Create Character" data-i18n="[title]Create Character">
@@ -5681,8 +5772,8 @@
5681 <option id="import_character_info" data-i18n="Import Card Lore">5772 <option id="import_character_info" data-i18n="Import Card Lore">
5682 Import Card Lore5773 Import Card Lore
5683 </option>5774 </option>
5684 <option id="set_chat_scenario" data-i18n="Scenario Override">5775 <option id="set_chat_character_settings" data-i18n="Character Settings Overrides">
5685 Scenario Override5776 Character Settings Overrides
5686 </option>5777 </option>
5687 <option id="convert_to_persona" data-i18n="Convert to Persona">5778 <option id="convert_to_persona" data-i18n="Convert to Persona">
5688 Convert to Persona5779 Convert to Persona
@@ -5873,7 +5964,7 @@
5873 </div>5964 </div>
5874 <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1">5965 <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1">
5875 <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-left-long"></div>5966 <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-left-long"></div>
5876 <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div>5967 <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-scroll" title="Set group chat character settings overrides" data-i18n="[title]Set group chat character settings overrides"></div>
5877 <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>5968 <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>
5878 <input id="rm_group_fav" type="hidden" />5969 <input id="rm_group_fav" type="hidden" />
5879 <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group.">5970 <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group.">
@@ -6971,6 +7062,8 @@
6971 <div title="Prompt" class="mes_button mes_prompt fa-solid fa-square-poll-horizontal " data-i18n="[title]Prompt" style="display: none;"></div>7062 <div title="Prompt" class="mes_button mes_prompt fa-solid fa-square-poll-horizontal " data-i18n="[title]Prompt" style="display: none;"></div>
6972 <div title="Exclude message from prompts" class="mes_button mes_hide fa-solid fa-eye" data-i18n="[title]Exclude message from prompts"></div>7063 <div title="Exclude message from prompts" class="mes_button mes_hide fa-solid fa-eye" data-i18n="[title]Exclude message from prompts"></div>
6973 <div title="Include message in prompts" class="mes_button mes_unhide fa-solid fa-eye-slash" data-i18n="[title]Include message in prompts"></div>7064 <div title="Include message in prompts" class="mes_button mes_unhide fa-solid fa-eye-slash" data-i18n="[title]Include message in prompts"></div>
7065 <div title="Toggle media display style" class="mes_button mes_media_gallery fa-solid fa-photo-film" data-i18n="[title]Toggle media display style"></div>
7066 <div title="Toggle media display style" class="mes_button mes_media_list fa-solid fa-table-cells-large" data-i18n="[title]Toggle media display style"></div>
6974 <div title="Embed file or image" class="mes_button mes_embed fa-solid fa-paperclip" data-i18n="[title]Embed file or image"></div>7067 <div title="Embed file or image" class="mes_button mes_embed fa-solid fa-paperclip" data-i18n="[title]Embed file or image"></div>
6975 <div title="Create checkpoint" class="mes_button mes_create_bookmark fa-regular fa-solid fa-flag-checkered" data-i18n="[title]Create checkpoint"></div>7068 <div title="Create checkpoint" class="mes_button mes_create_bookmark fa-regular fa-solid fa-flag-checkered" data-i18n="[title]Create checkpoint"></div>
6976 <div title="Create branch" class="mes_button mes_create_branch fa-regular fa-code-branch" data-i18n="[title]Create Branch"></div>7069 <div title="Create branch" class="mes_button mes_create_branch fa-regular fa-code-branch" data-i18n="[title]Create Branch"></div>
@@ -7009,19 +7102,8 @@
7009 <div class="mes_reasoning"></div>7102 <div class="mes_reasoning"></div>
7010 </details>7103 </details>
7011 <div class="mes_text"></div>7104 <div class="mes_text"></div>
7012 <div class="mes_img_container">7105 <div class="mes_media_wrapper"></div>
7013 <div class="mes_img_controls">7106 <div class="mes_file_wrapper"></div>
7014 <div title="Expand and zoom" class="right_menu_button fa-lg fa-solid fa-magnifying-glass mes_img_enlarge" data-i18n="[title]Expand and zoom"></div>
7015 <div title="Caption" class="right_menu_button fa-lg fa-solid fa-envelope-open-text mes_img_caption" data-i18n="[title]Caption"></div>
7016 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_img_delete" data-i18n="[title]Delete"></div>
7017 </div>
7018 <div class="mes_img_swipes">
7019 <div title="Swipe left" class="right_menu_button fa-lg fa-solid fa-chevron-left mes_img_swipe_left" data-i18n="[title]Swipe left"></div>
7020 <div class="mes_img_swipe_counter">1/1</div>
7021 <div title="Swipe right" class="right_menu_button fa-lg fa-solid fa-chevron-right mes_img_swipe_right" data-i18n="[title]Swipe right"></div>
7022 </div>
7023 <img class="mes_img" src="" />
7024 </div>
7025 <div class="mes_bias"></div>7107 <div class="mes_bias"></div>
7026 </div>7108 </div>
7027 <div class="flex-container swipeRightBlock flexFlowColumn flexNoGap">7109 <div class="flex-container swipeRightBlock flexFlowColumn flexNoGap">
@@ -7208,11 +7290,18 @@
7208 <div class="alternate_greeting">7290 <div class="alternate_greeting">
7209 <details open>7291 <details open>
7210 <summary>7292 <summary>
7211 <div class="title_restorable">7293 <div class="title_restorable gap5px">
7212 <div class="flex-container alignItemsCenter">7294 <div class="flex-container alignItemsCenter">
7213 <strong><span data-i18n="Alternate Greeting #">Alternate Greeting #</span><span class="greeting_index"></span></strong>7295 <strong><span data-i18n="Alternate Greeting #">Alternate Greeting #</span><span class="greeting_index"></span></strong>
7214 <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i>7296 <i class="editor_maximize fa-solid fa-maximize right_menu_button" title="Expand the editor" data-i18n="[title]Expand the editor"></i>
7215 </div>7297 </div>
7298 <span class="expander"></span>
7299 <div class="menu_button menu_button_icon move_up_alternate_greeting" title="Move up" data-i18n="[title]Move up">
7300 <i class="fa-solid fa-chevron-up"></i>
7301 </div>
7302 <div class="menu_button menu_button_icon move_down_alternate_greeting" title="Move down" data-i18n="[title]Move down">
7303 <i class="fa-solid fa-chevron-down"></i>
7304 </div>
7216 <div class="menu_button menu_button_icon delete_alternate_greeting">7305 <div class="menu_button menu_button_icon delete_alternate_greeting">
7217 <i class="fa-solid fa-trash-alt"></i>7306 <i class="fa-solid fa-trash-alt"></i>
7218 <span data-i18n="Delete">Delete</span>7307 <span data-i18n="Delete">Delete</span>
@@ -7224,9 +7313,9 @@
7224 </div>7313 </div>
7225 </div>7314 </div>
72267315
7227 <!-- chat and input bar -->7316 <!-- Media Templates -->
7228 <div id="message_file_template" class="template_element">7317 <div id="message_file_template" class="template_element">
7229 <div class="mes_file_container">7318 <div class="mes_media_container mes_file_container">
7230 <div class="fa-lg fa-solid fa-file-alt mes_file_icon"></div>7319 <div class="fa-lg fa-solid fa-file-alt mes_file_icon"></div>
7231 <div class="mes_file_name"></div>7320 <div class="mes_file_name"></div>
7232 <div class="mes_file_size"></div>7321 <div class="mes_file_size"></div>
@@ -7235,15 +7324,59 @@
7235 </div>7324 </div>
7236 </div>7325 </div>
72377326
7327 <div id="message_image_template" class="template_element">
7328 <div class="mes_media_container mes_img_container">
7329 <div class="mes_img_controls">
7330 <div title="Expand and zoom" class="right_menu_button fa-lg fa-solid fa-magnifying-glass mes_media_enlarge" data-i18n="[title]Expand and zoom"></div>
7331 <div title="Caption" class="right_menu_button fa-lg fa-solid fa-envelope-open-text mes_img_caption" data-i18n="[title]Caption"></div>
7332 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_media_delete" data-i18n="[title]Delete"></div>
7333 </div>
7334 <img class="mes_img" src="" />
7335 </div>
7336 </div>
7337
7238 <div id="message_video_template" class="template_element">7338 <div id="message_video_template" class="template_element">
7239 <div class="mes_video_container">7339 <div class="mes_media_container mes_video_container">
7240 <div class="mes_video_controls">7340 <div class="mes_video_controls">
7241 <div><!-- Placeholder --></div>7341 <div title="Expand and zoom" class="right_menu_button fa-lg fa-solid fa-magnifying-glass mes_media_enlarge" data-i18n="[title]Expand and zoom"></div>
7242 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_video_delete" data-i18n="[title]Delete"></div>7342 <div title="Caption" class="right_menu_button fa-lg fa-solid fa-envelope-open-text mes_img_caption" data-i18n="[title]Caption"></div>
7343 <div title="Delete" class="right_menu_button fa-lg fa-solid fa-trash-can mes_media_delete" data-i18n="[title]Delete"></div>
7243 </div>7344 </div>
7244 <video class="mes_video" controls preload="metadata"></video>7345 <video class="mes_video" controls preload="metadata"></video>
7245 </div>7346 </div>
7246 </div>7347 </div>
7348
7349 <div id="message_gallery_controls" class="template_element">
7350 <div class="mes_img_swipes">
7351 <div title="Swipe left" class="right_menu_button fa-lg fa-solid fa-chevron-left mes_img_swipe_left" data-i18n="[title]Swipe left"></div>
7352 <div class="mes_img_swipe_counter">1/1</div>
7353 <div title="Swipe right" class="right_menu_button fa-lg fa-solid fa-chevron-right mes_img_swipe_right" data-i18n="[title]Swipe right"></div>
7354 </div>
7355 </div>
7356
7357 <div id="message_audio_template" class="template_element">
7358 <div class="mes_media_container mes_audio_container audio-player">
7359 <audio class="mes_audio" preload="auto" hidden></audio>
7360 <div class="audio-player-header">
7361 <div class="audio-player-title">Audio</div>
7362 <div class="right_menu_button mes_media_delete fa-fw fa-solid fa-trash-can" title="Delete" data-i18n="[title]Delete"></div>
7363 </div>
7364 <div class="audio-player-controls">
7365 <button class="audio-player-play-pause right_menu_button fa-fw fa-solid fa-play" title="Play" data-i18n="[title]Play"></button>
7366 <div class="audio-player-time">
7367 <span class="audio-player-current-time">0:00</span>
7368 <span class="audio-player-time-separator">/</span>
7369 <span class="audio-player-total-time">0:00</span>
7370 </div>
7371 <div class="audio-player-progress">
7372 <div class="audio-player-progress-bar"></div>
7373 </div>
7374 <div class="audio-player-volume-control">
7375 <button class="audio-player-volume right_menu_button fa-fw fa-solid fa-volume-high" title="Mute" data-i18n="[title]Mute"></button>
7376 </div>
7377 </div>
7378 </div>
7379 </div>
7247 </div>7380 </div>
7248 <div id="movingDivs">7381 <div id="movingDivs">
7249 <div id="floatingPrompt" class="drawer-content flexGap5">7382 <div id="floatingPrompt" class="drawer-content flexGap5">
@@ -7600,8 +7733,8 @@
7600 <div id="send_form" class="no-connection">7733 <div id="send_form" class="no-connection">
7601 <form id="file_form" class="wide100p displayNone">7734 <form id="file_form" class="wide100p displayNone">
7602 <div class="file_attached">7735 <div class="file_attached">
7603 <input id="file_form_input" type="file" hidden>7736 <input id="file_form_input" type="file" multiple hidden>
7604 <input id="embed_file_input" type="file" hidden>7737 <input id="embed_file_input" type="file" multiple hidden>
7605 <i class="fa-solid fa-file-alt"></i>7738 <i class="fa-solid fa-file-alt"></i>
7606 <span class="file_name">File Name</span>7739 <span class="file_name">File Name</span>
7607 <span class="file_size">File Size</span>7740 <span class="file_size">File Size</span>
public/locales/ar-sa.json+1 -1
@@ -235,7 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "يجمع الرسائل المتتالية للنظام في رسالة واحدة (باستثناء الحوارات المثالية). قد يحسن التتابع لبعض النماذج.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "يجمع الرسائل المتتالية للنظام في رسالة واحدة (باستثناء الحوارات المثالية). قد يحسن التتابع لبعض النماذج.",
236 "Enable function calling": "تمكين استدعاء الوظيفة",236 "Enable function calling": "تمكين استدعاء الوظيفة",
237 "Send inline images": "إرسال الصور المضمنة",237 "Send inline images": "إرسال الصور المضمنة",
238 "image_inlining_hint_1": "يرسل الصور في المطالبات إذا كان النموذج يدعمها .\n استخدم ال",238 "image_inlining_hint_1": "يرسل الصور في المطالبات إذا كان النموذج يدعمها .",
239 "image_inlining_hint_2": "الإجراء على أي رسالة أو",239 "image_inlining_hint_2": "الإجراء على أي رسالة أو",
240 "image_inlining_hint_3": "القائمة لإرفاق ملف صورة للدردشة.",240 "image_inlining_hint_3": "القائمة لإرفاق ملف صورة للدردشة.",
241 "Inline Image Quality": "جودة الصورة المضمنة",241 "Inline Image Quality": "جودة الصورة المضمنة",
public/locales/de-de.json+1 -1
@@ -235,7 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Kombiniert aufeinanderfolgende Systemnachrichten zu einer (ausschließlich Beispiel-Dialoge ausgeschlossen). Kann die Kohärenz für einige Modelle verbessern.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Kombiniert aufeinanderfolgende Systemnachrichten zu einer (ausschließlich Beispiel-Dialoge ausgeschlossen). Kann die Kohärenz für einige Modelle verbessern.",
236 "Enable function calling": "Funktionsaufruf aktivieren",236 "Enable function calling": "Funktionsaufruf aktivieren",
237 "Send inline images": "Inline-Bilder senden",237 "Send inline images": "Inline-Bilder senden",
238 "image_inlining_hint_1": "Sendet Bilder in Eingabeaufforderungen, wenn das Modell dies unterstützt.\nVerwenden Sie die",238 "image_inlining_hint_1": "Sendet Bilder in Eingabeaufforderungen, wenn das Modell dies unterstützt.",
239 "image_inlining_hint_2": "Aktion auf eine Nachricht oder die",239 "image_inlining_hint_2": "Aktion auf eine Nachricht oder die",
240 "image_inlining_hint_3": "Menü, um eine Bilddatei an den Chat anzuhängen.",240 "image_inlining_hint_3": "Menü, um eine Bilddatei an den Chat anzuhängen.",
241 "Inline Image Quality": "Inline-Bildqualität",241 "Inline Image Quality": "Inline-Bildqualität",
public/locales/es-es.json+1 -1
@@ -235,7 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina mensajes del sistema consecutivos en uno solo (excluyendo diálogos de ejemplo). Puede mejorar la coherencia para algunos modelos.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina mensajes del sistema consecutivos en uno solo (excluyendo diálogos de ejemplo). Puede mejorar la coherencia para algunos modelos.",
236 "Enable function calling": "Habilitar llamada a función",236 "Enable function calling": "Habilitar llamada a función",
237 "Send inline images": "Enviar imágenes en línea",237 "Send inline images": "Enviar imágenes en línea",
238 "image_inlining_hint_1": "Envía imágenes en mensajes si el modelo lo admite.\n Utilizar el",238 "image_inlining_hint_1": "Envía imágenes en mensajes si el modelo lo admite.",
239 "image_inlining_hint_2": "acción sobre cualquier mensaje o el",239 "image_inlining_hint_2": "acción sobre cualquier mensaje o el",
240 "image_inlining_hint_3": "menú para adjuntar un archivo de imagen al chat.",240 "image_inlining_hint_3": "menú para adjuntar un archivo de imagen al chat.",
241 "Inline Image Quality": "Calidad de imagen en línea",241 "Inline Image Quality": "Calidad de imagen en línea",
public/locales/fr-fr.json+1 -1
@@ -227,7 +227,7 @@
227 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combine les messages système consécutifs en un seul (à l'exclusion des dialogues d'exemple). Peut améliorer la cohérence pour certains modèles.",227 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combine les messages système consécutifs en un seul (à l'exclusion des dialogues d'exemple). Peut améliorer la cohérence pour certains modèles.",
228 "Enable function calling": "Activer l'appel de fonction",228 "Enable function calling": "Activer l'appel de fonction",
229 "Send inline images": "Envoyer des images en ligne",229 "Send inline images": "Envoyer des images en ligne",
230 "image_inlining_hint_1": "Envoie des images dans les prompts si le modèle le prend en charge.\nUtilisez le",230 "image_inlining_hint_1": "Envoie des images dans les prompts si le modèle le prend en charge.",
231 "image_inlining_hint_2": "action sur n'importe quel message ou le",231 "image_inlining_hint_2": "action sur n'importe quel message ou le",
232 "image_inlining_hint_3": "menu pour joindre un fichier image au chat.",232 "image_inlining_hint_3": "menu pour joindre un fichier image au chat.",
233 "Inline Image Quality": "Qualité d'image en ligne",233 "Inline Image Quality": "Qualité d'image en ligne",
public/locales/is-is.json+1 -1
@@ -235,7 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Sameinar samhliða kerfisskilaboð í eitt (sem er utan umsagna dæmum). Getur bætt samfelldni fyrir sumar módel.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Sameinar samhliða kerfisskilaboð í eitt (sem er utan umsagna dæmum). Getur bætt samfelldni fyrir sumar módel.",
236 "Enable function calling": "Virkja aðgerðarkall",236 "Enable function calling": "Virkja aðgerðarkall",
237 "Send inline images": "Senda myndir í línu",237 "Send inline images": "Senda myndir í línu",
238 "image_inlining_hint_1": "Sendir myndir í skilaboðum ef líkanið styður það.\n Nota",238 "image_inlining_hint_1": "Sendir myndir í skilaboðum ef líkanið styður það.",
239 "image_inlining_hint_2": "aðgerð á hvaða skilaboðum sem er eða",239 "image_inlining_hint_2": "aðgerð á hvaða skilaboðum sem er eða",
240 "image_inlining_hint_3": "valmynd til að hengja myndskrá við spjallið.",240 "image_inlining_hint_3": "valmynd til að hengja myndskrá við spjallið.",
241 "Inline Image Quality": "Innbyggð myndgæði",241 "Inline Image Quality": "Innbyggð myndgæði",
public/locales/it-it.json+1 -1
@@ -235,7 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina i messaggi di sistema consecutivi in uno solo (escludendo i dialoghi di esempio). Potrebbe migliorare la coerenza per alcuni modelli.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina i messaggi di sistema consecutivi in uno solo (escludendo i dialoghi di esempio). Potrebbe migliorare la coerenza per alcuni modelli.",
236 "Enable function calling": "Abilita la chiamata alla funzione",236 "Enable function calling": "Abilita la chiamata alla funzione",
237 "Send inline images": "Invia immagini inline",237 "Send inline images": "Invia immagini inline",
238 "image_inlining_hint_1": "Invia immagini nei prompt se il modello lo supporta.\n Usa il",238 "image_inlining_hint_1": "Invia immagini nei prompt se il modello lo supporta.",
239 "image_inlining_hint_2": "azione su qualsiasi messaggio o il",239 "image_inlining_hint_2": "azione su qualsiasi messaggio o il",
240 "image_inlining_hint_3": "menu per allegare un file immagine alla chat.",240 "image_inlining_hint_3": "menu per allegare un file immagine alla chat.",
241 "Inline Image Quality": "Qualità dell'immagine in linea",241 "Inline Image Quality": "Qualità dell'immagine in linea",
public/locales/ko-kr.json+1 -3
@@ -237,9 +237,7 @@
237 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "연속된 시스템 메시지를 하나로 결합합니다(예제 대화 제외). 일부 모델의 일관성을 향상시킬 수 있습니다.",237 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "연속된 시스템 메시지를 하나로 결합합니다(예제 대화 제외). 일부 모델의 일관성을 향상시킬 수 있습니다.",
238 "Enable function calling": "함수 호출 활성화",238 "Enable function calling": "함수 호출 활성화",
239 "Send inline images": "인라인 이미지 전송",239 "Send inline images": "인라인 이미지 전송",
240 "image_inlining_hint_1": "모델이 지원하는 경우 메시지로 이미지를 보냅니다.\n 사용",240 "image_inlining_hint_1": "모델이 지원하는 경우 메시지로 이미지를 보냅니다.",
241 "image_inlining_hint_2": "메시지에 대한 조치 또는",
242 "image_inlining_hint_3": "채팅에 이미지 파일을 첨부하는 메뉴입니다.",
243 "Inline Image Quality": "인라인 이미지 품질",241 "Inline Image Quality": "인라인 이미지 품질",
244 "openai_inline_image_quality_auto": "자동",242 "openai_inline_image_quality_auto": "자동",
245 "openai_inline_image_quality_low": "낮은",243 "openai_inline_image_quality_low": "낮은",
public/locales/nl-nl.json+1 -3
@@ -235,9 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combineert opeenvolgende systeemberichten tot één (exclusief voorbeeld dialogen). Kan de coherentie verbeteren voor sommige modellen.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combineert opeenvolgende systeemberichten tot één (exclusief voorbeeld dialogen). Kan de coherentie verbeteren voor sommige modellen.",
236 "Enable function calling": "Schakel functieaanroepen in",236 "Enable function calling": "Schakel functieaanroepen in",
237 "Send inline images": "Inline afbeeldingen verzenden",237 "Send inline images": "Inline afbeeldingen verzenden",
238 "image_inlining_hint_1": "Verzendt afbeeldingen in prompts als het model dit ondersteunt.\n Gebruik de",238 "image_inlining_hint_1": "Verzendt afbeeldingen in prompts als het model dit ondersteunt.",
239 "image_inlining_hint_2": "actie op elk bericht of de",
240 "image_inlining_hint_3": "menu om een ​​afbeeldingsbestand aan de chat toe te voegen.",
241 "Inline Image Quality": "Inline-beeldkwaliteit",239 "Inline Image Quality": "Inline-beeldkwaliteit",
242 "openai_inline_image_quality_auto": "Auto",240 "openai_inline_image_quality_auto": "Auto",
243 "openai_inline_image_quality_low": "Laag",241 "openai_inline_image_quality_low": "Laag",
public/locales/pt-pt.json+1 -3
@@ -235,9 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina mensagens do sistema consecutivas em uma (excluindo diálogos de exemplo). Pode melhorar a coerência para alguns modelos.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Combina mensagens do sistema consecutivas em uma (excluindo diálogos de exemplo). Pode melhorar a coerência para alguns modelos.",
236 "Enable function calling": "Habilitar chamada de função",236 "Enable function calling": "Habilitar chamada de função",
237 "Send inline images": "Enviar imagens inline",237 "Send inline images": "Enviar imagens inline",
238 "image_inlining_hint_1": "Envia imagens em prompts se o modelo suportar.\n Use o",238 "image_inlining_hint_1": "Envia imagens em prompts se o modelo suportar.",
239 "image_inlining_hint_2": "ação em qualquer mensagem ou",
240 "image_inlining_hint_3": "menu para anexar um arquivo de imagem ao chat.",
241 "Inline Image Quality": "Qualidade de imagem embutida",239 "Inline Image Quality": "Qualidade de imagem embutida",
242 "openai_inline_image_quality_auto": "Auto",240 "openai_inline_image_quality_auto": "Auto",
243 "openai_inline_image_quality_low": "Baixo",241 "openai_inline_image_quality_low": "Baixo",
public/locales/ru-ru.json+2 -6
@@ -1020,9 +1020,7 @@
1020 "The prompt to be sent.": "Текст промпта.",1020 "The prompt to be sent.": "Текст промпта.",
1021 "prompt_manager_forbid_overrides": "Запретить перезапись",1021 "prompt_manager_forbid_overrides": "Запретить перезапись",
1022 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Карточка персонажа не сможет перезаписать этот промпт, даже если настройки отдают приоритет именно ей.",1022 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Карточка персонажа не сможет перезаписать этот промпт, даже если настройки отдают приоритет именно ей.",
1023 "image_inlining_hint_1": "Отправлять картинки как часть промпта, если позволяет модель. Чтобы добавить в чат изображение, используйте на нужном сообщении действие",1023 "image_inlining_hint_1": "Отправлять картинки как часть промпта, если позволяет модель.",
1024 "image_inlining_hint_2": ". Также это можно сделать через меню",
1025 "image_inlining_hint_3": ".",
1026 "Contest Winners": "Победители конкурса",1024 "Contest Winners": "Победители конкурса",
1027 "Rename Background": "Переименовать фон",1025 "Rename Background": "Переименовать фон",
1028 "Lock": "Закрепить",1026 "Lock": "Закрепить",
@@ -2445,9 +2443,7 @@
2445 "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "Отводит часть ответа под рассуждения (Минимальные: 10%, Обычные: 25%, Подробные: 50%, Максимальные: 95%), но минимум 1024 токена. При выборе значение Авто рассуждения не запрашиваются.",2443 "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "Отводит часть ответа под рассуждения (Минимальные: 10%, Обычные: 25%, Подробные: 50%, Максимальные: 95%), но минимум 1024 токена. При выборе значение Авто рассуждения не запрашиваются.",
2446 "Use system prompt": "Включить системный промпт",2444 "Use system prompt": "Включить системный промпт",
2447 "Send inline videos": "Отправлять inline-видео",2445 "Send inline videos": "Отправлять inline-видео",
2448 "video_inlining_hint_1": "Отправляет модели видео, если она поддерживает такую возможность. Чтобы прикрепить видео к чату, используйте на любом сообщении кнопку",2446 "video_inlining_hint_1": "Отправляет модели видео, если она поддерживает такую возможность.",
2449 "video_inlining_hint_2": "либо меню",
2450 "video_inlining_hint_3": ".",
2451 "video_inlining_hint_4": "Видео должно весить не более 20 Мб и длиться не дольше 1 минуты.",2447 "video_inlining_hint_4": "Видео должно весить не более 20 Мб и длиться не дольше 1 минуты.",
2452 "Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide.": "Отводит часть ответа под рассуждения (Flash 2.5/Pro 2.5) (Минимальные: 0/128 токенов, Поверхностные: 10%, Обычные: 25%, Подробные: 50%, Максимальные: 24576/32768 токенов). При выборе значения Авто модель определяет объём самостоятельно.",2448 "Allocates a portion of the response length for thinking (Flash 2.5/Pro 2.5) (min: 0/128 tokens, low: 10%, medium: 25%, high: 50%, max: 24576/32768 tokens). Auto lets the model decide.": "Отводит часть ответа под рассуждения (Flash 2.5/Pro 2.5) (Минимальные: 0/128 токенов, Поверхностные: 10%, Обычные: 25%, Подробные: 50%, Максимальные: 24576/32768 токенов). При выборе значения Авто модель определяет объём самостоятельно.",
2453 "Google Vertex AI Configuration": "Настройки Google Vertex AI",2449 "Google Vertex AI Configuration": "Настройки Google Vertex AI",
public/locales/th-th.json+2 -4
@@ -241,9 +241,7 @@
241 "Allows the model to return its thinking process.": "อนุญาตให้โมเดลส่งคืนกระบวนการคิดของตัวเอง",241 "Allows the model to return its thinking process.": "อนุญาตให้โมเดลส่งคืนกระบวนการคิดของตัวเอง",
242 "This setting affects visibility only.": "การตั้งค่านี้มีผลต่อการมองเห็นเท่านั้น",242 "This setting affects visibility only.": "การตั้งค่านี้มีผลต่อการมองเห็นเท่านั้น",
243 "Send inline images": "ส่งรูปภาพแบบ inline",243 "Send inline images": "ส่งรูปภาพแบบ inline",
244 "image_inlining_hint_1": "ส่งรูปภาพในพรอมต์หากโมเดลรองรับ โดยใช้",244 "image_inlining_hint_1": "ส่งรูปภาพในพรอมต์หากโมเดลรองรับ",
245 "image_inlining_hint_2": "เพื่อดำเนินการในข้อความนั้นๆ หรือใช้ตัวเลือก",
246 "image_inlining_hint_3": "เพื่อแนบไฟล์รูปภาพลงในแชท",
247 "Inline Image Quality": "คุณภาพรูปภาพ Inline",245 "Inline Image Quality": "คุณภาพรูปภาพ Inline",
248 "openai_inline_image_quality_auto": "อัตโนมัติ",246 "openai_inline_image_quality_auto": "อัตโนมัติ",
249 "openai_inline_image_quality_low": "ต่ำ",247 "openai_inline_image_quality_low": "ต่ำ",
@@ -1458,4 +1456,4 @@
1458 "Stop Inspecting": "Stop Inspecting",1456 "Stop Inspecting": "Stop Inspecting",
1459 "Inspect Prompts": "ตรวจสอบ Prompt",1457 "Inspect Prompts": "ตรวจสอบ Prompt",
1460 "Toggle prompt inspection": "สลับการตรวจสอบ Prompt"1458 "Toggle prompt inspection": "สลับการตรวจสอบ Prompt"
1461}
1461 \ No newline at end of file \ No newline at end of file
1459}
public/locales/uk-ua.json+1 -3
@@ -235,9 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Об'єднує послідовні системні повідомлення в одне (крім прикладів діалогів). Може покращити співпрацю для деяких моделей.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Об'єднує послідовні системні повідомлення в одне (крім прикладів діалогів). Може покращити співпрацю для деяких моделей.",
236 "Enable function calling": "Увімкнути виклик функцій",236 "Enable function calling": "Увімкнути виклик функцій",
237 "Send inline images": "Надсилати вбудовані зображення",237 "Send inline images": "Надсилати вбудовані зображення",
238 "image_inlining_hint_1": "Надсилає зображення у підказках, якщо модель це підтримує.\n Використовувати",238 "image_inlining_hint_1": "Надсилає зображення у підказках, якщо модель це підтримує.",
239 "image_inlining_hint_2": "дії з будь-яким повідомленням або",
240 "image_inlining_hint_3": "меню, щоб прикріпити файл зображення до чату.",
241 "Inline Image Quality": "Якість вбудованого зображення",239 "Inline Image Quality": "Якість вбудованого зображення",
242 "openai_inline_image_quality_auto": "Авто",240 "openai_inline_image_quality_auto": "Авто",
243 "openai_inline_image_quality_low": "Низький",241 "openai_inline_image_quality_low": "Низький",
public/locales/vi-vn.json+1 -3
@@ -235,9 +235,7 @@
235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Kết hợp các tin nhắn hệ thống liên tiếp thành một (loại bỏ các đoạn hội thoại mẫu). Có thể cải thiện tính nhất quán cho một số model.",235 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Kết hợp các tin nhắn hệ thống liên tiếp thành một (loại bỏ các đoạn hội thoại mẫu). Có thể cải thiện tính nhất quán cho một số model.",
236 "Enable function calling": "Sử dụng tính năng gọi hàm (function calling)",236 "Enable function calling": "Sử dụng tính năng gọi hàm (function calling)",
237 "Send inline images": "Gửi hình ảnh nội bộ",237 "Send inline images": "Gửi hình ảnh nội bộ",
238 "image_inlining_hint_1": "Gửi hình ảnh theo Prompt nếu kiểu máy hỗ trợ.\n Sử dụng",238 "image_inlining_hint_1": "Gửi hình ảnh theo Prompt nếu kiểu máy hỗ trợ.",
239 "image_inlining_hint_2": "hành động đối với bất kỳ tin nhắn nào hoặc",
240 "image_inlining_hint_3": "menu để đính kèm tệp hình ảnh vào cuộc trò chuyện.",
241 "Inline Image Quality": "Chất lượng hình ảnh nội tuyến",239 "Inline Image Quality": "Chất lượng hình ảnh nội tuyến",
242 "openai_inline_image_quality_auto": "Tự động",240 "openai_inline_image_quality_auto": "Tự động",
243 "openai_inline_image_quality_low": "Thấp",241 "openai_inline_image_quality_low": "Thấp",
public/locales/zh-cn.json+6 -6
@@ -269,17 +269,13 @@
269 "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。",269 "enable_functions_desc_3": "可以被各种扩展利用来提供附加功能。",
270 "enable_functions_desc_4": "当提示词后处理没有选择工具时不支持。",270 "enable_functions_desc_4": "当提示词后处理没有选择工具时不支持。",
271 "Send inline images": "发送图片",271 "Send inline images": "发送图片",
272 "image_inlining_hint_1": "如果模型支持,就可以在提示词中发送图片。\n发送消息时,点击",272 "image_inlining_hint_1": "如果模型支持,就可以在提示词中发送图片。",
273 "image_inlining_hint_2": "在这里(",
274 "image_inlining_hint_3": ")将图片添加到消息中。",
275 "Inline Image Quality": "图片画质",273 "Inline Image Quality": "图片画质",
276 "openai_inline_image_quality_auto": "自动",274 "openai_inline_image_quality_auto": "自动",
277 "openai_inline_image_quality_low": "低",275 "openai_inline_image_quality_low": "低",
278 "openai_inline_image_quality_high": "高",276 "openai_inline_image_quality_high": "高",
279 "Send inline videos": "发送视频",277 "Send inline videos": "发送视频",
280 "video_inlining_hint_1": "当模型支持时,将视频发送给模型。使用",278 "video_inlining_hint_1": "当模型支持时,将视频发送给模型。",
281 "video_inlining_hint_2": "在任意消息上添加视频,或",
282 "video_inlining_hint_3": "菜单来添加视频。",
283 "video_inlining_hint_4": "视频必须在 20MB 以下且时长不超过1分钟。",279 "video_inlining_hint_4": "视频必须在 20MB 以下且时长不超过1分钟。",
284 "Request inline images": "请求图片返回",280 "Request inline images": "请求图片返回",
285 "Allows the model to return image attachments.": "允许模型返回图片附件。",281 "Allows the model to return image attachments.": "允许模型返回图片附件。",
@@ -2276,6 +2272,10 @@
2276 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖拽左侧三条横线以排序,点击名字以重命名,点击调色盘以切换颜色。",2272 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖拽左侧三条横线以排序,点击名字以重命名,点击调色盘以切换颜色。",
2277 "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。",2273 "Click on the folder icon to use this tag as a folder.": "点击文件夹图标来将此标签作为一个文件夹。",
2278 "Use alphabetical sorting": "按字母顺序排列",2274 "Use alphabetical sorting": "按字母顺序排列",
2275 "Sort mode": "排序模式",
2276 "Manual (Drag & Drop)": "手动 (拖放)",
2277 "Alphabetical (A-Z)": "按字母 (A-Z)",
2278 "Most Used (By Count)": "按使用次数",
2279 "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。",2279 "tags_sorting_desc": "启用后,标签在创建或重命名时会自动按字母顺序排序。\n禁用后,新标签会追加到末尾。\n\n如果通过拖动手动重新排列标签,则自动排序将被禁用。",
2280 "Are you sure you want to delete the theme?": "你确定要删除这个主题吗?",2280 "Are you sure you want to delete the theme?": "你确定要删除这个主题吗?",
2281 "Hi,": "嗨,",2281 "Hi,": "嗨,",
public/locales/zh-tw.json+6 -6
@@ -236,9 +236,7 @@
236 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括對話範例)。可能會提高某些模型的一致性。",236 "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "將連續的系統訊息合併為一個(不包括對話範例)。可能會提高某些模型的一致性。",
237 "Enable function calling": "啟用函式呼叫",237 "Enable function calling": "啟用函式呼叫",
238 "Send inline images": "傳送內嵌圖片",238 "Send inline images": "傳送內嵌圖片",
239 "image_inlining_hint_1": "如果模型支援,則在提示詞中傳送圖片。\n使用任何訊息上的",239 "image_inlining_hint_1": "如果模型支援,則在提示詞中傳送圖片。",
240 "image_inlining_hint_2": "動作或",
241 "image_inlining_hint_3": "選單來附加圖片文件到聊天中。",
242 "Inline Image Quality": "內嵌圖片品質",240 "Inline Image Quality": "內嵌圖片品質",
243 "openai_inline_image_quality_auto": "自動",241 "openai_inline_image_quality_auto": "自動",
244 "openai_inline_image_quality_low": "低",242 "openai_inline_image_quality_low": "低",
@@ -2109,6 +2107,10 @@
2109 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖動以重新排序。點選名稱重新命名。點選顏色更改顯示。",2107 "Drag handle to reorder. Click name to rename. Click color to change display.": "拖動以重新排序。點選名稱重新命名。點選顏色更改顯示。",
2110 "Click on the folder icon to use this tag as a folder.": "點選資料夾圖示以將此標籤作為資料夾。",2108 "Click on the folder icon to use this tag as a folder.": "點選資料夾圖示以將此標籤作為資料夾。",
2111 "Use alphabetical sorting": "按字母順序排序 ",2109 "Use alphabetical sorting": "按字母順序排序 ",
2110 "Sort mode": "排序模式",
2111 "Manual (Drag & Drop)": "手動(拖放)",
2112 "Alphabetical (A-Z)": "按字母(A-Z)",
2113 "Most Used (By Count)": "按使用次數",
2112 "tags_sorting_desc": "啟用後,標籤將在建立或重新命名時將自動按字母排序。\n停用時,新標籤將附加到結尾。\n若標籤被手動拖動重新排序,則自動排序將被停用。",2114 "tags_sorting_desc": "啟用後,標籤將在建立或重新命名時將自動按字母排序。\n停用時,新標籤將附加到結尾。\n若標籤被手動拖動重新排序,則自動排序將被停用。",
2113 "and connect to an": "並連線到",2115 "and connect to an": "並連線到",
2114 "You can add more": "您可加入更多",2116 "You can add more": "您可加入更多",
@@ -2646,9 +2648,7 @@
2646 "Min Keep": "最小保留",2648 "Min Keep": "最小保留",
2647 "enable_functions_desc_4": "當使用「無工具」提示後處理時不支援!",2649 "enable_functions_desc_4": "當使用「無工具」提示後處理時不支援!",
2648 "Send inline videos": "傳送內嵌影片",2650 "Send inline videos": "傳送內嵌影片",
2649 "video_inlining_hint_1": "若模型支援,則在提示中傳送影片。使用",2651 "video_inlining_hint_1": "若模型支援,則在提示中傳送影片。",
2650 "video_inlining_hint_2": "操作於任何訊息或使用",
2651 "video_inlining_hint_3": "選單以上傳影片檔案到聊天中。",
2652 "video_inlining_hint_4": "影片大小必須小於 20 MB 且長度低於 1 分鐘",2652 "video_inlining_hint_4": "影片大小必須小於 20 MB 且長度低於 1 分鐘",
2653 "This setting affects visibility only.": "此設定僅影響可見性。",2653 "This setting affects visibility only.": "此設定僅影響可見性。",
2654 "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "為推理部分分配回應長度(最大回應長度至少需 1024 符元,低:10%、中:25%、高:50%、最高:95%)。選擇「自動」將不請求推理。",2654 "Allocates a portion of the response length for thinking (min: 1024 tokens, low: 10%, medium: 25%, high: 50%, max: 95%), but minimum 1024 tokens. Auto does not request thinking.": "為推理部分分配回應長度(最大回應長度至少需 1024 符元,低:10%、中:25%、高:50%、最高:95%)。選擇「自動」將不請求推理。",
public/script.js+1382 -757
@@ -179,8 +179,11 @@ import {
179 importFromExternalUrl,179 importFromExternalUrl,
180 shiftUpByOne,180 shiftUpByOne,
181 shiftDownByOne,181 shiftDownByOne,
182 canUseNegativeLookbehind,
183 trimSpaces,
184 clamp,
182} from './scripts/utils.js';185} from './scripts/utils.js';
183import { debounce_timeout, GENERATION_TYPE_TRIGGERS, IGNORE_SYMBOL, inject_ids } from './scripts/constants.js';186import { debounce_timeout, GENERATION_TYPE_TRIGGERS, IGNORE_SYMBOL, inject_ids, MEDIA_DISPLAY, MEDIA_SOURCE, MEDIA_TYPE, SCROLL_BEHAVIOR, SWIPE_DIRECTION } from './scripts/constants.js';
184187
185import { cancelDebouncedMetadataSave, doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';188import { cancelDebouncedMetadataSave, doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js';
186import { COMMENT_NAME_DEFAULT, CONNECT_API_MAP, executeSlashCommandsOnChatInput, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, stopScriptExecution, UNIQUE_APIS } from './scripts/slash-commands.js';189import { COMMENT_NAME_DEFAULT, CONNECT_API_MAP, executeSlashCommandsOnChatInput, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, stopScriptExecution, UNIQUE_APIS } from './scripts/slash-commands.js';
@@ -273,6 +276,8 @@ import { event_types, eventSource } from './scripts/events.js';
273import { initAccessibility } from './scripts/a11y.js';276import { initAccessibility } from './scripts/a11y.js';
274import { applyStreamFadeIn } from './scripts/util/stream-fadein.js';277import { applyStreamFadeIn } from './scripts/util/stream-fadein.js';
275import { initDomHandlers } from './scripts/dom-handlers.js';278import { initDomHandlers } from './scripts/dom-handlers.js';
279import { SimpleMutex } from './scripts/util/SimpleMutex.js';
280import { AudioPlayer } from './scripts/audio-player.js';
276281
277// API OBJECT FOR EXTERNAL WIRING282// API OBJECT FOR EXTERNAL WIRING
278globalThis.SillyTavern = {283globalThis.SillyTavern = {
@@ -310,6 +315,10 @@ export {
310 getSystemMessageByType,315 getSystemMessageByType,
311 event_types,316 event_types,
312 eventSource,317 eventSource,
318 /** @deprecated Use setCharacterSettingsOverrides instead. */
319 setCharacterSettingsOverrides as setScenarioOverride,
320 /** @deprecated Use appendMediaToMessage instead. */
321 appendMediaToMessage as appendImageToMessage,
313};322};
314323
315/**324/**
@@ -362,7 +371,9 @@ export const neutralCharacterName = 'Assistant';
362let default_user_name = 'User';371let default_user_name = 'User';
363export let name1 = default_user_name;372export let name1 = default_user_name;
364export let name2 = systemUserName;373export let name2 = systemUserName;
374/** @type {ChatMessage[]} */
365export let chat = [];375export let chat = [];
376export let isSwipingAllowed = true; //false when a swipe is in progress, or swiping is blocked.
366let chatSaveTimeout;377let chatSaveTimeout;
367let importFlashTimeout;378let importFlashTimeout;
368export let isChatSaving = false;379export let isChatSaving = false;
@@ -554,9 +565,10 @@ export let is_send_press = false; //Send generation
554565
555let this_del_mes = -1;566let this_del_mes = -1;
556567
557//message editing568/** @type {string} */
558var this_edit_mes_chname = '';569let this_edit_mes_chname = '';
559var this_edit_mes_id;570/** @type {number|undefined} */
571let this_edit_mes_id = undefined;
560572
561//settings573//settings
562export let settings;574export let settings;
@@ -1400,32 +1412,46 @@ export async function printMessages() {
1400 addOneMessage(item, { scroll: false, forceId: i, showSwipes: false });1412 addOneMessage(item, { scroll: false, forceId: i, showSwipes: false });
1401 }1413 }
14021414
1403 // Scroll to bottom when all images are loaded1415 chatElement.find('.mes').removeClass('last_mes');
1404 const images = document.querySelectorAll('#chat .mes img');1416 chatElement.find('.mes').last().addClass('last_mes');
1405 let imagesLoaded = 0;1417 refreshSwipeButtons();
1418 applyStylePins();
1419 scrollChatToBottom();
1420 delay(debounce_timeout.short).then(() => scrollOnMediaLoad());
1421}
1422
1423function scrollOnMediaLoad() {
1424 const started = Date.now();
1425 const media = chatElement.find('.mes_block img, .mes_block video, .mes_block audio').toArray();
1426 let mediaLoaded = 0;
14061427
1407 for (let i = 0; i < images.length; i++) {1428 for (const currentElement of media) {
1408 const image = images[i];1429 if (currentElement instanceof HTMLImageElement) {
1409 if (image instanceof HTMLImageElement) {1430 if (currentElement.complete) {
1410 if (image.complete) {1431 incrementAndCheck();
1432 } else {
1433 currentElement.addEventListener('load', incrementAndCheck);
1434 currentElement.addEventListener('error', incrementAndCheck);
1435 }
1436 }
1437 if (currentElement instanceof HTMLMediaElement) {
1438 if (currentElement.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) {
1411 incrementAndCheck();1439 incrementAndCheck();
1412 } else {1440 } else {
1413 image.addEventListener('load', incrementAndCheck);1441 currentElement.addEventListener('loadeddata', incrementAndCheck);
1442 currentElement.addEventListener('error', incrementAndCheck);
1414 }1443 }
1415 }1444 }
1416 }1445 }
14171446
1418 chatElement.find('.mes').removeClass('last_mes');
1419 chatElement.find('.mes').last().addClass('last_mes');
1420 hideSwipeButtons();
1421 showSwipeButtons();
1422 scrollChatToBottom();
1423 applyStylePins();
1424
1425 function incrementAndCheck() {1447 function incrementAndCheck() {
1426 imagesLoaded++;1448 const MAX_DELAY = 1000; // 1 second
1427 if (imagesLoaded === images.length) {1449 if ((Date.now() - started) > MAX_DELAY) {
1428 scrollChatToBottom();1450 return;
1451 }
1452 mediaLoaded++;
1453 if (mediaLoaded === media.length) {
1454 scrollChatToBottom({ waitForFrame: true });
1429 }1455 }
1430 }1456 }
1431}1457}
@@ -1465,6 +1491,68 @@ export async function deleteLastMessage() {
1465 await eventSource.emit(event_types.MESSAGE_DELETED, chat.length);1491 await eventSource.emit(event_types.MESSAGE_DELETED, chat.length);
1466}1492}
14671493
1494/**
1495 * Deletes a message from the chat by its ID, optionally asking for confirmation.
1496 * @param {number} id The ID of the message to delete.
1497 * @param {number} [swipeDeletionIndex] Deletes the swipe with that index.
1498 * @param {boolean} [askConfirmation=false] Whether to ask for confirmation before deleting.
1499 */
1500export async function deleteMessage(id, swipeDeletionIndex = undefined, askConfirmation = false) {
1501 const canDeleteSwipe = swipeDeletionIndex !== undefined && swipeDeletionIndex !== null;
1502 if (canDeleteSwipe) {
1503 if (swipeDeletionIndex < 0) {
1504 throw new Error('Swipe index cannot be negative');
1505 }
1506 if (!Array.isArray(chat[id].swipes)) {
1507 throw new Error('Message has no swipes to delete');
1508 }
1509 if (chat[id].swipes.length <= swipeDeletionIndex) {
1510 throw new Error('Swipe index out of bounds');
1511 }
1512 }
1513
1514 const minId = getFirstDisplayedMessageId();
1515 const messageElement = chatElement.find(`.mes[mesid="${id}"]`);
1516 if (messageElement.length === 0) {
1517 return;
1518 }
1519
1520 let deleteOnlySwipe = canDeleteSwipe;
1521 if (askConfirmation) {
1522 const result = await callGenericPopup(t`Are you sure you want to delete this message?`, POPUP_TYPE.CONFIRM, null, {
1523 okButton: canDeleteSwipe ? t`Delete Swipe` : t`Delete Message`,
1524 cancelButton: 'Cancel',
1525 customButtons: canDeleteSwipe ? [t`Delete Message`] : null,
1526 });
1527 if (!result) {
1528 return;
1529 }
1530 deleteOnlySwipe = canDeleteSwipe && result === POPUP_RESULT.AFFIRMATIVE; // Default button, not the custom one
1531 }
1532
1533 if (deleteOnlySwipe) {
1534 await deleteSwipe(swipeDeletionIndex, id);
1535 return;
1536 }
1537
1538 chat.splice(id, 1);
1539 messageElement.remove();
1540
1541 chat_metadata['tainted'] = true;
1542
1543 const startIndex = [0, minId].includes(id) ? id : null;
1544 updateViewMessageIds(startIndex);
1545 saveChatDebounced();
1546
1547 if (this_edit_mes_id === id) {
1548 this_edit_mes_id = undefined;
1549 }
1550
1551 refreshSwipeButtons();
1552
1553 await eventSource.emit(event_types.MESSAGE_DELETED, chat.length);
1554}
1555
1468export async function reloadCurrentChat() {1556export async function reloadCurrentChat() {
1469 preserveNeutralChat();1557 preserveNeutralChat();
1470 await clearChat();1558 await clearChat();
@@ -1484,8 +1572,7 @@ export async function reloadCurrentChat() {
1484 await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId());1572 await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId());
1485 }1573 }
14861574
1487 hideSwipeButtons();1575 refreshSwipeButtons();
1488 showSwipeButtons();
1489}1576}
14901577
1491/**1578/**
@@ -1494,9 +1581,8 @@ export async function reloadCurrentChat() {
1494export async function sendTextareaMessage() {1581export async function sendTextareaMessage() {
1495 if (is_send_press) return;1582 if (is_send_press) return;
1496 if (isExecutingCommandsFromChatInput) return;1583 if (isExecutingCommandsFromChatInput) return;
1497 if (this_edit_mes_id) return; // don't proceed if editing a message
14981584
1499 let generateType;1585 let generateType = 'normal';
1500 // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last1586 // "Continue on send" is activated when the user hits "send" (or presses enter) on an empty chat box, and the last
1501 // message was sent from a character (not the user or the system).1587 // message was sent from a character (not the user or the system).
1502 const textareaText = String($('#send_textarea').val());1588 const textareaText = String($('#send_textarea').val());
@@ -1515,7 +1601,7 @@ export async function sendTextareaMessage() {
1515 await newAssistantChat({ temporary: false });1601 await newAssistantChat({ temporary: false });
1516 }1602 }
15171603
1518 Generate(generateType);1604 return await Generate(generateType);
1519}1605}
15201606
1521/**1607/**
@@ -1597,7 +1683,9 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId, san
1597 }1683 }
15981684
1599 if (!isSystem && power_user.encode_tags) {1685 if (!isSystem && power_user.encode_tags) {
1600 mes = mes.replaceAll('<', '&lt;').replaceAll('>', '&gt;');1686 mes = canUseNegativeLookbehind()
1687 ? mes.replaceAll('<', '&lt;').replace(new RegExp('(?<!^|\\n\\s*)>', 'g'), '&gt;')
1688 : mes.replaceAll('<', '&lt;').replaceAll('>', '&gt;');
1601 }1689 }
16021690
1603 // Make sure reasoning strings are always shown, even if they include "<" or ">"1691 // Make sure reasoning strings are always shown, even if they include "<" or ">"
@@ -1817,110 +1905,436 @@ export function updateMessageBlock(messageId, message, { rerenderMessage = true
1817}1905}
18181906
1819/**1907/**
1820 * Appends image or file to the message element.1908 * Ensures that the message media properties are arrays, adding getters/setters for single media items.
1821 * @param {object} mes Message object1909 * @param {ChatMessage} mes Message object
1822 * @param {JQuery<HTMLElement>} messageElement Message element
1823 * @param {boolean} [adjustScroll=true] Whether to adjust the scroll position after appending the media
1824 */1910 */
1825export function appendMediaToMessage(mes, messageElement, adjustScroll = true) {1911export function ensureMessageMediaIsArray(mes) {
1826 // Add image to message1912 /**
1827 if (mes.extra?.image) {1913 * Determines if a property of an object is a plain property (not a getter/setter or non-enumerable).
1828 const container = messageElement.find('.mes_img_container');1914 * @param {object} obj Object to check
1829 const chatHeight = chatElement.prop('scrollHeight');1915 * @param {string} name Property name
1830 const image = messageElement.find('.mes_img');1916 * @returns {boolean} True if the property is a plain property, false otherwise
1831 const text = messageElement.find('.mes_text');1917 */
1832 const isInline = !!mes.extra?.inline_image;1918 function isPlainObjectProperty(obj, name) {
1833 const doAdjustScroll = () => {1919 const hasProperty = Object.hasOwn(obj, name);
1834 if (!adjustScroll) {1920 if (hasProperty) {
1835 return;1921 const descriptor = Object.getOwnPropertyDescriptor(obj, name);
1836 }1922 return descriptor && descriptor.enumerable && descriptor.configurable && descriptor.writable;
1837 const scrollPosition = chatElement.scrollTop();1923 }
1838 const newChatHeight = chatElement.prop('scrollHeight');1924 return false;
1839 const diff = newChatHeight - chatHeight;1925 }
1840 chatElement.scrollTop(scrollPosition + diff);1926
1841 };1927 /**
1842 image.off('load').on('load', function () {1928 * Determines if a property of an object is a getter (not a plain property).
1843 image.removeAttr('alt');1929 * @param {object} obj Object to check
1844 image.removeClass('error');1930 * @param {string} name Property name
1845 doAdjustScroll();1931 * @returns {boolean} True if the property is a getter, false otherwise
1846 });1932 */
1847 image.off('error').on('error', function () {1933 function isGetterObjectProperty(obj, name) {
1848 image.attr('alt', '');1934 const hasProperty = Object.hasOwn(obj, name);
1849 image.addClass('error');1935 if (hasProperty) {
1850 doAdjustScroll();1936 const descriptor = Object.getOwnPropertyDescriptor(obj, name);
1937 return descriptor && typeof descriptor.get === 'function';
1938 }
1939 return false;
1940 }
1941
1942 /**
1943 * Adds a plain property to an object that wraps around an array property.
1944 * @param {object} obj Object to add property to
1945 * @param {string} plainProperty Plain property name
1946 * @param {string} arrayProperty Array property to back the plain property
1947 * @param {(value: any) => boolean} [filterFn] Optional filter function to apply when getting/setting the plain property
1948 * @param {(value: any) => any} [mapFn] Optional map function to apply when getting/setting the plain property
1949 */
1950 function addArrayAutoWrapper(obj, plainProperty, arrayProperty, filterFn = () => true, mapFn = (t) => t) {
1951 // If the plain property is already a getter, do nothing.
1952 const hasGetterProperty = isGetterObjectProperty(obj, plainProperty);
1953 if (hasGetterProperty) {
1954 return;
1955 }
1956
1957 // Define the plain property as a getter/setter that wraps around the array property.
1958 Object.defineProperty(obj, plainProperty, {
1959 // Getting the plain property returns the first item in the array property, or undefined if the array is empty.
1960 get: function () {
1961 console.trace(`Attempting to GET an array-wrapped property '${plainProperty}'. Use the array property '${arrayProperty}' instead.`);
1962 const array = Array.isArray(this[arrayProperty]) ? this[arrayProperty].filter(filterFn).map(mapFn) : [];
1963 return array.length > 0 ? array[0] : void 0;
1964 },
1965 // Setting the plain property is not supported, as it would be ambiguous.
1966 set: function () {
1967 console.trace(`Attempting to SET an array-wrapped property '${plainProperty}'. Use the array property '${arrayProperty}' instead.`);
1968 },
1969 // Exclude the property from JSON serialization and from being listed in for...in loops.
1970 enumerable: false,
1971 // Make the property non-configurable to prevent deletion or redefinition.
1972 configurable: false,
1851 });1973 });
1852 image.attr('src', mes.extra?.image);1974 }
1853 image.attr('title', mes.extra?.title || mes.title || '');
1854 container.addClass('img_extra');
1855 image.toggleClass('img_inline', isInline);
1856 text.toggleClass('displayNone', !isInline);
1857
1858 const imageSwipes = mes.extra.image_swipes;
1859 if (Array.isArray(imageSwipes) && imageSwipes.length > 0) {
1860 container.addClass('img_swipes');
1861 const counter = container.find('.mes_img_swipe_counter');
1862 const currentImage = imageSwipes.indexOf(mes.extra.image) + 1;
1863 counter.text(`${currentImage}/${imageSwipes.length}`);
1864
1865 const swipeLeft = container.find('.mes_img_swipe_left');
1866 swipeLeft.off('click').on('click', function () {
1867 eventSource.emit(event_types.IMAGE_SWIPED, { message: mes, element: messageElement, direction: 'left' });
1868 });
18691975
1870 const swipeRight = container.find('.mes_img_swipe_right');1976 /**
1871 swipeRight.off('click').on('click', function () {1977 * Migrates image swipes from a single image property to an array.
1872 eventSource.emit(event_types.IMAGE_SWIPED, { message: mes, element: messageElement, direction: 'right' });1978 * @param {ChatMessageExtra} obj
1873 });1979 */
1980 function migrateMediaToArray(obj) {
1981 if (isPlainObjectProperty(obj, 'file')) {
1982 if (!Array.isArray(obj.files)) {
1983 obj.files = [];
1984 }
1985 const fileValue = obj.file;
1986 delete obj.file;
1987 if (fileValue) {
1988 obj.files.push(fileValue);
1989 }
1874 }1990 }
1875 } else {1991
1876 const container = messageElement.find('.mes_img_container');1992 if (Array.isArray(obj.image_swipes)) {
1877 container.removeClass('img_extra img_swipes');1993 if (!Array.isArray(obj.media)) {
1878 const text = messageElement.find('.mes_text');1994 obj.media = [];
1879 text.removeClass('displayNone');
1880 }
1881
1882 // Add video to message
1883 if (mes.extra?.video) {
1884 const container = $('#message_video_template .mes_video_container').clone();
1885 messageElement.find('.mes_video_container').remove();
1886 messageElement.find('.mes_block').append(container);
1887 const chatHeight = chatElement.prop('scrollHeight');
1888 const video = container.find('.mes_video');
1889 video.off('loadedmetadata').on('loadedmetadata', function () {
1890 if (!adjustScroll) {
1891 return;
1892 }1995 }
1893 const scrollPosition = chatElement.scrollTop();1996 for (const swipe of obj.image_swipes) {
1894 const newChatHeight = chatElement.prop('scrollHeight');1997 if (swipe && typeof swipe === 'string') {
1895 const diff = newChatHeight - chatHeight;1998 obj.media_display = MEDIA_DISPLAY.GALLERY;
1896 chatElement.scrollTop(scrollPosition + diff);1999 obj.media.push({ type: MEDIA_TYPE.IMAGE, url: swipe });
1897 });2000 }
2001 }
2002 delete obj.image_swipes;
2003 }
18982004
1899 video.attr('src', mes.extra?.video);2005 if (isPlainObjectProperty(obj, 'image')) {
1900 } else {2006 if (!Array.isArray(obj.media)) {
1901 messageElement.find('.mes_video_container').remove();2007 obj.media = [];
1902 }2008 }
19032009 const imageValue = obj.image;
1904 // Add file to message2010 delete obj.image;
1905 if (mes.extra?.file) {2011 if (imageValue && typeof imageValue === 'string') {
1906 messageElement.find('.mes_file_container').remove();2012 obj.media.push({ type: MEDIA_TYPE.IMAGE, url: imageValue });
1907 const messageId = messageElement.attr('mesid');2013 }
1908 const template = $('#message_file_template .mes_file_container').clone();2014 if (obj.media_display === MEDIA_DISPLAY.GALLERY) {
1909 template.find('.mes_file_name').text(mes.extra.file.name);2015 const selectedIndex = obj.media.findIndex(t => t.url === imageValue);
1910 template.find('.mes_file_size').text(humanFileSize(mes.extra.file.size));2016 if (selectedIndex > -1) {
1911 template.find('.mes_file_download').attr('mesid', messageId);2017 obj.media_index = selectedIndex;
1912 template.find('.mes_file_delete').attr('mesid', messageId);2018 }
1913 messageElement.find('.mes_block').append(template);2019 }
1914 } else {2020 obj.media = obj.media.filter((v, i, a) => i === a.findIndex(t => t.url === v.url));
1915 messageElement.find('.mes_file_container').remove();2021 }
2022
2023 if (isPlainObjectProperty(obj, 'video')) {
2024 if (!Array.isArray(obj.media)) {
2025 obj.media = [];
2026 }
2027 const videoValue = obj.video;
2028 delete obj.video;
2029 if (videoValue && typeof videoValue === 'string') {
2030 obj.media.push({ type: MEDIA_TYPE.VIDEO, url: videoValue });
2031 }
2032 }
2033 }
2034
2035 if (!mes || !mes.extra || typeof mes.extra !== 'object') {
2036 return;
2037 }
2038
2039 migrateMediaToArray(mes.extra);
2040 addArrayAutoWrapper(mes.extra, 'file', 'files');
2041 addArrayAutoWrapper(mes.extra, 'image', 'media', (t) => t.type === MEDIA_TYPE.IMAGE, (t) => t.url);
2042 addArrayAutoWrapper(mes.extra, 'video', 'media', (t) => t.type === MEDIA_TYPE.VIDEO, (t) => t.url);
2043}
2044
2045/**
2046 * Gets the media display setting for a message.
2047 * @param {ChatMessage} mes Message object
2048 * @returns {MEDIA_DISPLAY} Media display setting
2049 */
2050export function getMediaDisplay(mes) {
2051 const value = mes?.extra?.media_display || power_user.media_display || MEDIA_DISPLAY.LIST;
2052 return Object.values(MEDIA_DISPLAY).includes(value) ? value : MEDIA_DISPLAY.LIST;
2053}
2054
2055/**
2056 * Gets the media index for a message.
2057 * @param {ChatMessage} mes Message object
2058 * @returns {number} Media index
2059 */
2060export function getMediaIndex(mes) {
2061 if (!Array.isArray(mes?.extra?.media)) {
2062 return 0;
1916 }2063 }
2064 const value = mes.extra?.media_index;
2065 if (isNaN(value) || value < 0 || value >= mes.extra.media.length) {
2066 return 0;
2067 }
2068 return value;
1917}2069}
19182070
1919/**2071/**
1920 * @deprecated Use appendMediaToMessage instead.2072 * Appends image or file to the message element.
2073 * @param {ChatMessage} mes Message object
2074 * @param {JQuery<HTMLElement>} messageElement Message element
2075 * @param {string} [scrollBehavior] Scroll behavior when adjusting scroll position
1921 */2076 */
1922export function appendImageToMessage(mes, messageElement) {2077export function appendMediaToMessage(mes, messageElement, scrollBehavior = SCROLL_BEHAVIOR.ADJUST) {
1923 appendMediaToMessage(mes, messageElement);2078 ensureMessageMediaIsArray(mes);
2079
2080 const fileWrapper = messageElement.find('.mes_file_wrapper');
2081 const mediaWrapper = messageElement.find('.mes_media_wrapper');
2082
2083 const hasMedia = Array.isArray(mes?.extra?.media) && mes.extra.media.length > 0;
2084 const hasFiles = Array.isArray(mes?.extra?.files) && mes.extra.files.length > 0;
2085 const mediaDisplay = hasMedia ? getMediaDisplay(mes) : null;
2086 const hideMessageText = hasMedia && mes?.extra?.inline_image === false;
2087
2088 const mediaBlocks = [];
2089 const mediaPromises = [];
2090
2091 const chatHeight = (hasMedia || hasFiles) ? chatElement.prop('scrollHeight') : 0;
2092 const scrollPosition = (hasMedia || hasFiles) ? chatElement.scrollTop() : 0;
2093 const doAdjustScroll = () => {
2094 if (!hasMedia && !hasFiles) {
2095 return;
2096 }
2097 if (scrollBehavior === SCROLL_BEHAVIOR.NONE) {
2098 return;
2099 }
2100 if (scrollBehavior === SCROLL_BEHAVIOR.KEEP) {
2101 chatElement.scrollTop(scrollPosition);
2102 return;
2103 }
2104 const newChatHeight = chatElement.prop('scrollHeight');
2105 const diff = newChatHeight - chatHeight;
2106 chatElement.scrollTop(scrollPosition + diff);
2107 };
2108
2109 // Set media display attribute
2110 messageElement.attr('data-media-display', mediaDisplay);
2111 // Toggle text visibility
2112 messageElement.find('.mes_text').toggleClass('displayNone', hideMessageText);
2113
2114 /**
2115 * Appends a single image attachment to the message element.
2116 * @param {MediaAttachment} attachment Image attachment object
2117 * @param {number} index Index of the image attachment
2118 * @returns {JQuery<HTMLElement>} The appended image container element
2119 */
2120 function appendImageAttachment(attachment, index) {
2121 const template = $('#message_image_template .mes_img_container').clone();
2122 template.attr('data-index', index);
2123
2124 const image = template.find('.mes_img');
2125 image.attr('src', attachment.url);
2126 image.attr('title', attachment.title || mes.extra.title || '');
2127 mediaPromises.push(new Promise((resolve) => {
2128 function onLoad() {
2129 image.removeAttr('alt');
2130 image.removeClass('error');
2131 resolve();
2132 }
2133 function onError() {
2134 image.attr('alt', '');
2135 image.addClass('error');
2136 resolve();
2137 }
2138 if (image.prop('complete')) {
2139 onLoad();
2140 } else {
2141 image.off('load').on('load', onLoad);
2142 image.off('error').on('error', onError);
2143 }
2144 }));
2145
2146 mediaBlocks.push(template);
2147 return template;
2148 }
2149
2150 /**
2151 * Appends a single video attachment to the message element.
2152 * @param {MediaAttachment} attachment Video attachment object
2153 * @param {number} index Index of the video attachment
2154 * @returns {JQuery<HTMLElement>} The appended video container element
2155 */
2156 function appendVideoAttachment(attachment, index) {
2157 const template = $('#message_video_template .mes_video_container').clone();
2158 template.attr('data-index', index);
2159
2160 const video = template.find('.mes_video');
2161 video.attr('src', attachment.url);
2162 video.attr('title', attachment.title || mes.extra.title || '');
2163 mediaPromises.push(new Promise((resolve) => {
2164 function onLoad() {
2165 resolve();
2166 }
2167 function onError() {
2168 video.addClass('error');
2169 resolve();
2170 }
2171 if (video.prop('readyState') >= HTMLMediaElement.HAVE_CURRENT_DATA) {
2172 onLoad();
2173 } else {
2174 video.off('loadeddata').on('loadeddata', onLoad);
2175 video.off('error').on('error', onError);
2176 }
2177 }));
2178
2179 mediaBlocks.push(template);
2180 return template;
2181 }
2182
2183 /**
2184 * Appends a single audio attachment to the message element.
2185 * @param {MediaAttachment} attachment Audio attachment object
2186 * @param {number} index Index of the audio attachment
2187 * @returns {JQuery<HTMLElement>} The appended audio container element
2188 */
2189 function appendAudioAttachment(attachment, index) {
2190 const template = $('#message_audio_template .mes_audio_container').clone();
2191 template.attr('data-index', index);
2192 const audio = template.find('.mes_audio');
2193 audio.attr('src', attachment.url);
2194 audio.attr('title', attachment.title || mes.extra.title || '');
2195
2196 mediaPromises.push(new Promise((resolve) => {
2197 function onLoad() {
2198 resolve();
2199 }
2200 function onError() {
2201 audio.addClass('error');
2202 resolve();
2203 }
2204 if (audio.prop('readyState') >= HTMLMediaElement.HAVE_CURRENT_DATA) {
2205 onLoad();
2206 } else {
2207 audio.off('loadeddata').on('loadeddata', onLoad);
2208 audio.off('error').on('error', onError);
2209 }
2210 }));
2211
2212 new AudioPlayer(audio.get(0), template.get(0));
2213
2214 mediaBlocks.push(template);
2215 return template;
2216 }
2217
2218 /**
2219 * Appends a media attachment to the message element.
2220 * @param {MediaAttachment} attachment Media attachment object
2221 * @param {number} index Index of the media attachment
2222 * @returns {JQuery<HTMLElement>} The appended media container element
2223 */
2224 function appendMediaAttachment(attachment, index) {
2225 if (!attachment.type) {
2226 attachment.type = MEDIA_TYPE.IMAGE;
2227 }
2228 switch (attachment.type) {
2229 case MEDIA_TYPE.IMAGE:
2230 return appendImageAttachment(attachment, index);
2231 case MEDIA_TYPE.VIDEO:
2232 return appendVideoAttachment(attachment, index);
2233 case MEDIA_TYPE.AUDIO:
2234 return appendAudioAttachment(attachment, index);
2235 }
2236
2237 console.warn(`Unknown media type: ${attachment.type}, defaulting to image.`, attachment);
2238 return appendImageAttachment(attachment, index);
2239 }
2240
2241 /**
2242 * Saves the current playback times of media elements in the message.
2243 * @returns {Map<string, MediaState>} Media playback times by source URL
2244 */
2245 function saveMediaStates() {
2246 const states = new Map();
2247 const media = mediaWrapper.find('video, audio');
2248 media.each((_, element) => {
2249 if (element instanceof HTMLMediaElement) {
2250 if (!element.currentSrc || element.readyState === HTMLMediaElement.HAVE_NOTHING) {
2251 return;
2252 }
2253 const state = { currentTime: element.currentTime, paused: element.paused };
2254 states.set(element.currentSrc, state);
2255 }
2256 });
2257 return states;
2258 }
2259
2260 /**
2261 * Restores the playback times of media elements in the message.
2262 * @param {Map<string, MediaState>} states Media playback times by source URL
2263 */
2264 function restoreMediaStates(states) {
2265 const media = mediaWrapper.find('video, audio');
2266 media.each((_, element) => {
2267 if (element instanceof HTMLMediaElement) {
2268 const restoreState = () => {
2269 if (!states.has(element.currentSrc)) {
2270 return;
2271 }
2272 const state = states.get(element.currentSrc);
2273 element.currentTime = state.currentTime;
2274 if (!state.paused) {
2275 element.play();
2276 }
2277 };
2278 if (element.readyState < HTMLMediaElement.HAVE_METADATA) {
2279 element.addEventListener('loadedmetadata', () => restoreState(), { once: true });
2280 } else {
2281 restoreState();
2282 }
2283 }
2284 });
2285 }
2286
2287 // Add media gallery to message
2288 if (hasMedia && mediaDisplay === MEDIA_DISPLAY.GALLERY) {
2289 const mediaIndex = getMediaIndex(mes);
2290 const selectedMedia = mes.extra.media[mediaIndex];
2291
2292 const galleryControls = $('#message_gallery_controls .mes_img_swipes').clone();
2293 const counter = galleryControls.find('.mes_img_swipe_counter');
2294 counter.text(`${mediaIndex + 1}/${mes.extra.media.length}`);
2295
2296 const template = appendMediaAttachment(selectedMedia, mediaIndex);
2297 template.addClass('img_swipes');
2298 template.append(galleryControls);
2299 }
2300
2301 // Add media as a list to message
2302 if (hasMedia && mediaDisplay === MEDIA_DISPLAY.LIST) {
2303 for (let index = 0; index < mes.extra.media.length; index++) {
2304 const attachment = mes.extra.media[index];
2305 appendMediaAttachment(attachment, index);
2306 }
2307 }
2308
2309 // Remove existing file containers
2310 fileWrapper.empty();
2311
2312 // Add files to message
2313 if (hasFiles) {
2314 for (let index = 0; index < mes.extra.files.length; index++) {
2315 const file = mes.extra.files[index];
2316 const template = $('#message_file_template .mes_file_container').clone();
2317 template.attr('data-index', index);
2318 template.find('.mes_file_name').text(file.name).attr('title', file.name);
2319 template.find('.mes_file_size').text(humanFileSize(file.size)).attr('title', file.size);
2320 fileWrapper.append(template);
2321 }
2322 }
2323
2324 // Early return if no media
2325 if (!hasMedia) {
2326 mediaWrapper.empty();
2327 doAdjustScroll();
2328 return;
2329 }
2330
2331 // TODO: Consider making this awaitable
2332 Promise.race([Promise.all(mediaPromises), delay(debounce_timeout.short)]).then(() => {
2333 const states = saveMediaStates();
2334 mediaWrapper.empty().append(mediaBlocks);
2335 restoreMediaStates(states);
2336 doAdjustScroll();
2337 });
1924}2338}
19252339
1926export function addCopyToCodeBlocks(messageElement) {2340export function addCopyToCodeBlocks(messageElement) {
@@ -1945,7 +2359,7 @@ export function addCopyToCodeBlocks(messageElement) {
19452359
1946/**2360/**
1947 * Adds a single message to the chat.2361 * Adds a single message to the chat.
1948 * @param {object} mes Message object2362 * @param {ChatMessage} mes Message object
1949 * @param {object} [options] Options2363 * @param {object} [options] Options
1950 * @param {string} [options.type='normal'] Message type2364 * @param {string} [options.type='normal'] Message type
1951 * @param {number} [options.insertAfter=null] Message ID to insert the new message after2365 * @param {number} [options.insertAfter=null] Message ID to insert the new message after
@@ -1997,8 +2411,8 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
1997 avatarImg = mes['force_avatar'];2411 avatarImg = mes['force_avatar'];
1998 }2412 }
19992413
2000 // if mes.uses_system_ui is true, set an override on the sanitizer options2414 // if mes.extra.uses_system_ui is true, set an override on the sanitizer options
2001 const sanitizerOverrides = mes.uses_system_ui ? { MESSAGE_ALLOW_SYSTEM_UI: true } : {};2415 const sanitizerOverrides = mes.extra?.uses_system_ui ? { MESSAGE_ALLOW_SYSTEM_UI: true } : {};
20022416
2003 messageText = messageFormatting(2417 messageText = messageFormatting(
2004 messageText,2418 messageText,
@@ -2076,12 +2490,13 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2076 });2490 });
20772491
2078 if (type === 'swipe') {2492 if (type === 'swipe') {
2079 const swipeMessage = chatElement.find(`[mesid="${chat.length - 1}"]`);2493 const messageId = forceId ?? chat.length - 1;
2494 const swipeMessage = chatElement.find(`[mesid="${messageId}"]`);
2080 swipeMessage.attr('swipeid', params.swipeId);2495 swipeMessage.attr('swipeid', params.swipeId);
2081 swipeMessage.find('.mes_text').html(messageText).attr('title', title);2496 swipeMessage.find('.mes_text').html(messageText).attr('title', title);
2082 swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);2497 swipeMessage.find('.timestamp').text(timestamp).attr('title', `${params.extra.api} - ${params.extra.model}`);
2083 updateReasoningUI(swipeMessage);2498 updateReasoningUI(swipeMessage);
2084 appendMediaToMessage(mes, swipeMessage);2499 appendMediaToMessage(mes, swipeMessage, scroll ? SCROLL_BEHAVIOR.ADJUST : SCROLL_BEHAVIOR.NONE);
2085 if (power_user.timestamp_model_icon && params.extra?.api) {2500 if (power_user.timestamp_model_icon && params.extra?.api) {
2086 insertSVGIcon(swipeMessage, params.extra);2501 insertSVGIcon(swipeMessage, params.extra);
2087 }2502 }
@@ -2096,7 +2511,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2096 } else {2511 } else {
2097 const messageId = forceId ?? chat.length - 1;2512 const messageId = forceId ?? chat.length - 1;
2098 chatElement.find(`[mesid="${messageId}"] .mes_text`).append(messageText);2513 chatElement.find(`[mesid="${messageId}"] .mes_text`).append(messageText);
2099 appendMediaToMessage(mes, newMessage);2514 appendMediaToMessage(mes, newMessage, scroll ? SCROLL_BEHAVIOR.ADJUST : SCROLL_BEHAVIOR.NONE);
2100 showSwipes && hideSwipeButtons();2515 showSwipes && hideSwipeButtons();
2101 }2516 }
21022517
@@ -2112,8 +2527,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2112 if (showSwipes) {2527 if (showSwipes) {
2113 chatElement.find('.mes').last().addClass('last_mes');2528 chatElement.find('.mes').last().addClass('last_mes');
2114 chatElement.find('.mes').eq(-2).removeClass('last_mes');2529 chatElement.find('.mes').eq(-2).removeClass('last_mes');
2115 hideSwipeButtons();2530 refreshSwipeButtons();
2116 showSwipeButtons();
2117 }2531 }
21182532
2119 // Don't scroll if not inserting last2533 // Don't scroll if not inserting last
@@ -2122,6 +2536,7 @@ export function addOneMessage(mes, { type = 'normal', insertAfter = null, scroll
2122 }2536 }
21232537
2124 applyCharacterTagsToMessageDivs({ mesIds: newMessageId });2538 applyCharacterTagsToMessageDivs({ mesIds: newMessageId });
2539 updateEditArrowClasses();
2125}2540}
21262541
2127/**2542/**
@@ -2146,8 +2561,8 @@ export function formatCharacterAvatar(characterAvatar) {
21462561
2147/**2562/**
2148 * Formats the title for the generation timer.2563 * Formats the title for the generation timer.
2149 * @param {Date} gen_started Date when generation was started2564 * @param {MessageTimestamp} gen_started Date when generation was started
2150 * @param {Date} gen_finished Date when generation was finished2565 * @param {MessageTimestamp} gen_finished Date when generation was finished
2151 * @param {number} tokenCount Number of tokens generated (0 if not available)2566 * @param {number} tokenCount Number of tokens generated (0 if not available)
2152 * @param {number?} [reasoningDuration=null] Reasoning duration (null if no reasoning was done)2567 * @param {number?} [reasoningDuration=null] Reasoning duration (null if no reasoning was done)
2153 * @param {number?} [timeToFirstToken=null] Time to first token2568 * @param {number?} [timeToFirstToken=null] Time to first token
@@ -2183,8 +2598,19 @@ function formatGenerationTimer(gen_started, gen_finished, tokenCount, reasoningD
2183 return { timerValue, timerTitle };2598 return { timerValue, timerTitle };
2184}2599}
21852600
2186export function scrollChatToBottom() {2601let requestId = null;
2187 if (power_user.auto_scroll_chat_to_bottom) {2602
2603/**
2604 * Scrolls the chat to the bottom if configured to do so.
2605 * @param {object} [options] Options
2606 * @param {boolean} [options.waitForFrame] If true, waits for the animation frame before scrolling
2607 */
2608export function scrollChatToBottom({ waitForFrame } = {}) {
2609 if (!power_user.auto_scroll_chat_to_bottom) {
2610 return;
2611 }
2612
2613 const doScroll = () => {
2188 let position = chatElement[0].scrollHeight;2614 let position = chatElement[0].scrollHeight;
21892615
2190 if (power_user.waifuMode) {2616 if (power_user.waifuMode) {
@@ -2196,7 +2622,23 @@ export function scrollChatToBottom() {
2196 }2622 }
21972623
2198 chatElement.scrollTop(position);2624 chatElement.scrollTop(position);
2625 requestId = null;
2626 };
2627
2628 // Do not check truthiness. requestId can loop to zero.
2629 if (requestId !== null) {
2630 cancelAnimationFrame(requestId);
2631 }
2632
2633 if (!waitForFrame) {
2634 doScroll();
2635 return;
2199 }2636 }
2637
2638 // This prevents layout thrashing.
2639 // https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame#return_value
2640 // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#file-what-forces-layout-md
2641 requestId = requestAnimationFrame(() => doScroll());
2200}2642}
22012643
2202/**2644/**
@@ -2690,11 +3132,14 @@ export function getCharacterCardFields({ chid = null } = {}) {
2690 }3132 }
26913133
2692 const scenarioText = chat_metadata['scenario'] || character.scenario || '';3134 const scenarioText = chat_metadata['scenario'] || character.scenario || '';
3135 const exampleDialog = chat_metadata['mes_example'] || character.mes_example || '';
3136 const systemPrompt = chat_metadata['system_prompt'] || character.data?.system_prompt || '';
3137
2693 result.description = baseChatReplace(character.description?.trim(), name1, name2);3138 result.description = baseChatReplace(character.description?.trim(), name1, name2);
2694 result.personality = baseChatReplace(character.personality?.trim(), name1, name2);3139 result.personality = baseChatReplace(character.personality?.trim(), name1, name2);
2695 result.scenario = baseChatReplace(scenarioText.trim(), name1, name2);3140 result.scenario = baseChatReplace(scenarioText.trim(), name1, name2);
2696 result.mesExamples = baseChatReplace(character.mes_example?.trim(), name1, name2);3141 result.mesExamples = baseChatReplace(exampleDialog.trim(), name1, name2);
2697 result.system = power_user.prefer_character_prompt ? baseChatReplace(character.data?.system_prompt?.trim(), name1, name2) : '';3142 result.system = power_user.prefer_character_prompt ? baseChatReplace(systemPrompt.trim(), name1, name2) : '';
2698 result.jailbreak = power_user.prefer_character_jailbreak ? baseChatReplace(character.data?.post_history_instructions?.trim(), name1, name2) : '';3143 result.jailbreak = power_user.prefer_character_jailbreak ? baseChatReplace(character.data?.post_history_instructions?.trim(), name1, name2) : '';
2699 result.version = character.data?.character_version ?? '';3144 result.version = character.data?.character_version ?? '';
2700 result.charDepthPrompt = baseChatReplace(character.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2);3145 result.charDepthPrompt = baseChatReplace(character.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2);
@@ -2800,8 +3245,8 @@ class StreamingProcessor {
2800 this.reasoningHandler = new ReasoningHandler(timeStarted);3245 this.reasoningHandler = new ReasoningHandler(timeStarted);
2801 /** @type {PromptReasoning} */3246 /** @type {PromptReasoning} */
2802 this.promptReasoning = promptReasoning;3247 this.promptReasoning = promptReasoning;
2803 /** @type {string} */3248 /** @type {string[]} */
2804 this.image = '';3249 this.images = [];
2805 }3250 }
28063251
2807 /**3252 /**
@@ -2854,8 +3299,8 @@ class StreamingProcessor {
2854 await this.#checkDomElements(messageId, continueOnReasoning);3299 await this.#checkDomElements(messageId, continueOnReasoning);
2855 this.markUIGenStarted();3300 this.markUIGenStarted();
2856 }3301 }
2857 hideSwipeButtons();3302 hideSwipeButtons({ hideCounters: true });
2858 scrollChatToBottom();3303 scrollChatToBottom({ waitForFrame: true });
2859 return messageId;3304 return messageId;
2860 }3305 }
28613306
@@ -2958,7 +3403,7 @@ class StreamingProcessor {
2958 }3403 }
29593404
2960 if (!scrollLock) {3405 if (!scrollLock) {
2961 scrollChatToBottom();3406 scrollChatToBottom({ waitForFrame: true });
2962 }3407 }
2963 }3408 }
29643409
@@ -2987,8 +3432,8 @@ class StreamingProcessor {
2987 chat[messageId].swipe_info.push(...swipeInfoArray);3432 chat[messageId].swipe_info.push(...swipeInfoArray);
2988 }3433 }
29893434
2990 if (this.image) {3435 if (Array.isArray(this.images) && this.images.length > 0) {
2991 await processImageAttachment(chat[messageId], { imageUrl: this.image });3436 await processImageAttachment(chat[messageId], { imageUrls: this.images });
2992 appendMediaToMessage(chat[messageId], $(this.messageDom));3437 appendMediaToMessage(chat[messageId], $(this.messageDom));
2993 }3438 }
29943439
@@ -3086,7 +3531,7 @@ class StreamingProcessor {
3086 }3531 }
3087 // Get the updated reasoning string into the handler3532 // Get the updated reasoning string into the handler
3088 this.reasoningHandler.updateReasoning(this.messageId, state?.reasoning);3533 this.reasoningHandler.updateReasoning(this.messageId, state?.reasoning);
3089 this.image = state?.image ?? '';3534 this.images = state?.images ?? [];
3090 await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);3535 await eventSource.emit(event_types.STREAM_TOKEN_RECEIVED, text);
3091 await sw.tick(async () => await this.onProgressStreaming(this.messageId, this.continueMessage + text));3536 await sw.tick(async () => await this.onProgressStreaming(this.messageId, this.continueMessage + text));
3092 }3537 }
@@ -3587,7 +4032,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3587 const prevStarted = chat[chat.length - 1]['gen_started'];4032 const prevStarted = chat[chat.length - 1]['gen_started'];
35884033
3589 if (prevFinished && prevStarted) {4034 if (prevFinished && prevStarted) {
3590 const timePassed = prevFinished - prevStarted;4035 const timePassed = Number(prevFinished) - Number(prevStarted);
3591 generation_started = new Date(Date.now() - timePassed);4036 generation_started = new Date(Date.now() - timePassed);
3592 chat[chat.length - 1]['gen_started'] = generation_started;4037 chat[chat.length - 1]['gen_started'] = generation_started;
3593 }4038 }
@@ -3667,7 +4112,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3667 coreChat.pop();4112 coreChat.pop();
3668 }4113 }
36694114
3670 coreChat = await Promise.all(coreChat.map(async (chatItem, index) => {4115 coreChat = await Promise.all(coreChat.map(async (/** @type {ChatMessage} */ chatItem, index) => {
3671 let message = chatItem.mes;4116 let message = chatItem.mes;
3672 let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT;4117 let regexType = chatItem.is_user ? regex_placement.USER_INPUT : regex_placement.AI_OUTPUT;
3673 let options = { isPrompt: true, depth: (coreChat.length - index - (isContinue ? 2 : 1)) };4118 let options = { isPrompt: true, depth: (coreChat.length - index - (isContinue ? 2 : 1)) };
@@ -3675,8 +4120,19 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
3675 let regexedMessage = getRegexedString(message, regexType, options);4120 let regexedMessage = getRegexedString(message, regexType, options);
3676 regexedMessage = await appendFileContent(chatItem, regexedMessage);4121 regexedMessage = await appendFileContent(chatItem, regexedMessage);
36774122
4123 const titles = [];
3678 if (chatItem?.extra?.append_title && chatItem?.extra?.title) {4124 if (chatItem?.extra?.append_title && chatItem?.extra?.title) {
3679 regexedMessage = `${regexedMessage}\n\n${chatItem.extra.title}`;4125 titles.push(chatItem.extra.title);
4126 }
4127 if (Array.isArray(chatItem?.extra?.media)) {
4128 for (const mediaItem of chatItem.extra.media) {
4129 if (mediaItem?.title && mediaItem?.append_title) {
4130 titles.push(mediaItem.title);
4131 }
4132 }
4133 }
4134 if (titles.length > 0) {
4135 regexedMessage = `${regexedMessage}\n\n${titles.join('\n\n')}`;
3680 }4136 }
36814137
3682 return {4138 return {
@@ -4637,7 +5093,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4637 let getMessage = extractMessageFromData(data);5093 let getMessage = extractMessageFromData(data);
4638 let title = extractTitleFromData(data);5094 let title = extractTitleFromData(data);
4639 let reasoning = extractReasoningFromData(data);5095 let reasoning = extractReasoningFromData(data);
4640 let imageUrl = extractImageFromData(data);5096 let imageUrls = extractImagesFromData(data);
4641 kobold_horde_model = title;5097 kobold_horde_model = title;
46425098
4643 const swipes = extractMultiSwipes(data, type);5099 const swipes = extractMultiSwipes(data, type);
@@ -4681,10 +5137,10 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
4681 else {5137 else {
4682 // Without streaming we'll be having a full message on continuation. Treat it as a last chunk.5138 // Without streaming we'll be having a full message on continuation. Treat it as a last chunk.
4683 if (originalType !== 'continue') {5139 if (originalType !== 'continue') {
4684 ({ type, getMessage } = await saveReply({ type, getMessage, title, swipes, reasoning, imageUrl }));5140 ({ type, getMessage } = await saveReply({ type, getMessage, title, swipes, reasoning, imageUrls }));
4685 }5141 }
4686 else {5142 else {
4687 ({ type, getMessage } = await saveReply({ type: 'appendFinal', getMessage, title, swipes, reasoning, imageUrl }));5143 ({ type, getMessage } = await saveReply({ type: 'appendFinal', getMessage, title, swipes, reasoning, imageUrls }));
4688 }5144 }
46895145
4690 // This relies on `saveReply` having been called to add the message to the chat, so it must be last.5146 // This relies on `saveReply` having been called to add the message to the chat, so it must be last.
@@ -5197,7 +5653,7 @@ function setInContextMessages(msgInContextCount, type) {
5197 msgInContextCount++;5653 msgInContextCount++;
5198 }5654 }
51995655
5200 const lastMessageBlock = chatElement.find('.mes:not([is_system="true"])').eq(-msgInContextCount);5656 const lastMessageBlock = chatElement.find('.mes:not([is_system="true"]), .mes.toolCall').eq(-msgInContextCount);
5201 lastMessageBlock.addClass('lastInContext');5657 lastMessageBlock.addClass('lastInContext');
52025658
5203 if (lastMessageBlock.length === 0) {5659 if (lastMessageBlock.length === 0) {
@@ -5308,23 +5764,23 @@ function extractTitleFromData(data) {
5308 * @param {object} [options] Extraction options5764 * @param {object} [options] Extraction options
5309 * @param {string} [options.mainApi] Main API to use5765 * @param {string} [options.mainApi] Main API to use
5310 * @param {string} [options.chatCompletionSource] Chat completion source5766 * @param {string} [options.chatCompletionSource] Chat completion source
5311 * @returns {string} Extracted image5767 * @returns {string[]} Extracted images or empty array
5312 */5768 */
5313function extractImageFromData(data, { mainApi = null, chatCompletionSource = null } = {}) {5769function extractImagesFromData(data, { mainApi = null, chatCompletionSource = null } = {}) {
5314 switch (mainApi ?? main_api) {5770 switch (mainApi ?? main_api) {
5315 case 'openai': {5771 case 'openai': {
5316 switch (chatCompletionSource ?? oai_settings.chat_completion_source) {5772 switch (chatCompletionSource ?? oai_settings.chat_completion_source) {
5317 case chat_completion_sources.VERTEXAI:5773 case chat_completion_sources.VERTEXAI:
5318 case chat_completion_sources.MAKERSUITE: {5774 case chat_completion_sources.MAKERSUITE: {
5319 const inlineData = data?.responseContent?.parts?.find(x => x.inlineData)?.inlineData;5775 const inlineData = data?.responseContent?.parts?.filter(x => x.inlineData && !x.thought)?.map(x => x.inlineData);
5320 if (inlineData) {5776 if (Array.isArray(inlineData) && inlineData.length > 0) {
5321 return `data:${inlineData.mimeType};base64,${inlineData.data}`;5777 return inlineData.map(x => `data:${x.mimeType};base64,${x.data}`).filter(isDataURL);
5322 }5778 }
5323 } break;5779 } break;
5324 case chat_completion_sources.OPENROUTER: {5780 case chat_completion_sources.OPENROUTER: {
5325 const imageUrl = data?.choices[0]?.message?.images?.find(x => x.type === 'image_url')?.image_url?.url;5781 const imageUrl = data?.choices[0]?.message?.images?.filter(x => x.type === 'image_url')?.map(x => x?.image_url?.url);
5326 if (isDataURL(imageUrl)) {5782 if (Array.isArray(imageUrl) && imageUrl.length > 0) {
5327 return imageUrl;5783 return imageUrl.filter(isDataURL);
5328 }5784 }
5329 // TODO: Handle remote URLs5785 // TODO: Handle remote URLs
5330 }5786 }
@@ -5332,7 +5788,7 @@ function extractImageFromData(data, { mainApi = null, chatCompletionSource = nul
5332 } break;5788 } break;
5333 }5789 }
53345790
5335 return undefined;5791 return [];
5336}5792}
53375793
5338/**5794/**
@@ -5453,6 +5909,7 @@ export function extractJsonFromData(data, { mainApi = null, chatCompletionSource
5453 case chat_completion_sources.XAI:5909 case chat_completion_sources.XAI:
5454 case chat_completion_sources.ELECTRONHUB:5910 case chat_completion_sources.ELECTRONHUB:
5455 case chat_completion_sources.AZURE_OPENAI:5911 case chat_completion_sources.AZURE_OPENAI:
5912 case chat_completion_sources.ZAI:
5456 default:5913 default:
5457 result = tryParse(text);5914 result = tryParse(text);
5458 break;5915 break;
@@ -5678,22 +6135,28 @@ export function cleanUpMessage({ getMessage, isImpersonate, isContinue, displayI
5678 * Adds an image to the message.6135 * Adds an image to the message.
5679 * @param {object} message Message object6136 * @param {object} message Message object
5680 * @param {object} sources Image sources6137 * @param {object} sources Image sources
5681 * @param {string} [sources.imageUrl] Image URL6138 * @param {string[]} [sources.imageUrls] Image URLs
5682 *6139 *
5683 * @returns {Promise<void>}6140 * @returns {Promise<void>}
5684 */6141 */
5685async function processImageAttachment(message, { imageUrl }) {6142async function processImageAttachment(message, { imageUrls }) {
5686 if (!imageUrl) {6143 if (!Array.isArray(imageUrls) || imageUrls.length === 0) {
5687 return;6144 return;
5688 }6145 }
56896146
5690 let url = imageUrl;6147 for (const [index, imageUrl] of imageUrls.filter(onlyUnique).entries()) {
5691 if (isDataURL(url)) {6148 if (!imageUrl) {
5692 const fileName = `inline_image_${Date.now().toString()}`;6149 continue;
5693 const [mime, base64] = /^data:(.*?);base64,(.*)$/.exec(imageUrl).slice(1);6150 }
5694 url = await saveBase64AsFile(base64, message.name, fileName, mime.split('/')[1]);6151
6152 let url = imageUrl;
6153 if (isDataURL(url)) {
6154 const fileName = `inline_image_${Date.now().toString()}_${index}`;
6155 const [mime, base64] = /^data:(.*?);base64,(.*)$/.exec(imageUrl).slice(1);
6156 url = await saveBase64AsFile(base64, message.name, fileName, mime.split('/')[1]);
6157 }
6158 saveImageToMessage({ image: url, inline: true }, message);
5695 }6159 }
5696 saveImageToMessage({ image: url, inline: true }, message);
5697}6160}
56986161
5699/**6162/**
@@ -5708,17 +6171,17 @@ async function processImageAttachment(message, { imageUrl }) {
5708 * @property {string} [title] Message tooltip6171 * @property {string} [title] Message tooltip
5709 * @property {string[]} [swipes] Extra swipes6172 * @property {string[]} [swipes] Extra swipes
5710 * @property {string} [reasoning] Message reasoning6173 * @property {string} [reasoning] Message reasoning
5711 * @property {string} [imageUrl] Link to an image6174 * @property {string[]} [imageUrls] Links to images
5712 *6175 *
5713 * @typedef {object} SaveReplyResult6176 * @typedef {object} SaveReplyResult
5714 * @property {string} type Type of generation6177 * @property {string} type Type of generation
5715 * @property {string} getMessage Generated message6178 * @property {string} getMessage Generated message
5716 */6179 */
5717export async function saveReply({ type, getMessage, fromStreaming = false, title = '', swipes = [], reasoning = '', imageUrl = '' }) {6180export async function saveReply({ type, getMessage, fromStreaming = false, title = '', swipes = [], reasoning = '', imageUrls = [] }) {
5718 // Backward compatibility6181 // Backward compatibility
5719 if (arguments.length > 1 && typeof arguments[0] !== 'object') {6182 if (arguments.length > 1 && typeof arguments[0] !== 'object') {
5720 console.trace('saveReply called with positional arguments. Please use an object instead.');6183 console.trace('saveReply called with positional arguments. Please use an object instead.');
5721 [type, getMessage, fromStreaming, title, swipes, reasoning, imageUrl] = arguments;6184 [type, getMessage, fromStreaming, title, swipes, reasoning, imageUrls] = arguments;
5722 }6185 }
57236186
5724 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||6187 if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||
@@ -5754,7 +6217,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
5754 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();6217 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5755 chat[chat.length - 1]['extra']['reasoning'] = reasoning;6218 chat[chat.length - 1]['extra']['reasoning'] = reasoning;
5756 chat[chat.length - 1]['extra']['reasoning_duration'] = null;6219 chat[chat.length - 1]['extra']['reasoning_duration'] = null;
5757 await processImageAttachment(chat[chat.length - 1], { imageUrl });6220 await processImageAttachment(chat[chat.length - 1], { imageUrls });
5758 if (power_user.message_token_count_enabled) {6221 if (power_user.message_token_count_enabled) {
5759 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];6222 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
5760 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);6223 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
@@ -5778,7 +6241,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
5778 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();6241 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5779 chat[chat.length - 1]['extra']['reasoning'] = reasoning;6242 chat[chat.length - 1]['extra']['reasoning'] = reasoning;
5780 chat[chat.length - 1]['extra']['reasoning_duration'] = null;6243 chat[chat.length - 1]['extra']['reasoning_duration'] = null;
5781 await processImageAttachment(chat[chat.length - 1], { imageUrl });6244 await processImageAttachment(chat[chat.length - 1], { imageUrls });
5782 if (power_user.message_token_count_enabled) {6245 if (power_user.message_token_count_enabled) {
5783 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];6246 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
5784 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);6247 chat[chat.length - 1]['extra']['token_count'] = await getTokenCountAsync(tokenCountText, 0);
@@ -5798,7 +6261,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
5798 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();6261 chat[chat.length - 1]['extra']['api'] = getGeneratingApi();
5799 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();6262 chat[chat.length - 1]['extra']['model'] = getGeneratingModel();
5800 chat[chat.length - 1]['extra']['reasoning'] += reasoning;6263 chat[chat.length - 1]['extra']['reasoning'] += reasoning;
5801 await processImageAttachment(chat[chat.length - 1], { imageUrl });6264 await processImageAttachment(chat[chat.length - 1], { imageUrls });
5802 // We don't know if the reasoning duration extended, so we don't update it here on purpose.6265 // We don't know if the reasoning duration extended, so we don't update it here on purpose.
5803 if (power_user.message_token_count_enabled) {6266 if (power_user.message_token_count_enabled) {
5804 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];6267 const tokenCountText = (reasoning || '') + chat[chat.length - 1]['mes'];
@@ -5844,7 +6307,7 @@ export async function saveReply({ type, getMessage, fromStreaming = false, title
5844 chat[chat.length - 1]['extra']['gen_id'] = group_generation_id;6307 chat[chat.length - 1]['extra']['gen_id'] = group_generation_id;
5845 }6308 }
58466309
5847 await processImageAttachment(chat[chat.length - 1], { imageUrl });6310 await processImageAttachment(chat[chat.length - 1], { imageUrls });
5848 const chat_id = (chat.length - 1);6311 const chat_id = (chat.length - 1);
58496312
5850 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);6313 !fromStreaming && await eventSource.emit(event_types.MESSAGE_RECEIVED, chat_id, type);
@@ -5930,7 +6393,8 @@ export function syncMesToSwipe(messageId = null) {
5930 return false;6393 return false;
5931 }6394 }
5932 // If the swipe is not present yet, exit out (will likely be copied later)6395 // If the swipe is not present yet, exit out (will likely be copied later)
5933 if (!targetMessage.swipes[targetMessage.swipe_id] || !targetMessage.swipe_info[targetMessage.swipe_id]) {6396 // "" is falsy. An empty string is a valid message.
6397 if (typeof targetMessage.swipes[targetMessage.swipe_id] !== 'string' || !targetMessage.swipe_info[targetMessage.swipe_id]) {
5934 return false;6398 return false;
5935 }6399 }
59366400
@@ -5987,26 +6451,36 @@ export function syncSwipeToMes(messageId = null, swipeId = null) {
5987 return false;6451 return false;
5988 }6452 }
5989 // If swipes structure is invalid, exit out6453 // If swipes structure is invalid, exit out
5990 if (!Array.isArray(targetMessage.swipe_info) || !Array.isArray(targetMessage.swipes)) {6454 if (!Array.isArray(targetMessage.swipes)) {
5991 return false;6455 return false;
5992 }6456 }
59936457
6458 // Backfill swipe_info if missing.
6459 if (!Array.isArray(targetMessage.swipe_info)) {
6460 targetMessage.swipe_info = targetMessage.swipes.map(_ => ({
6461 send_date: targetMessage.send_date,
6462 gen_started: void 0,
6463 gen_finished: void 0,
6464 extra: {},
6465 }));
6466 }
6467
5994 const targetSwipeId = targetMessage.swipe_id;6468 const targetSwipeId = targetMessage.swipe_id;
5995 if (!targetMessage.swipes[targetSwipeId] || !targetMessage.swipe_info[targetSwipeId]) {6469 if (typeof targetMessage.swipes[targetSwipeId] !== 'string') {
5996 console.warn(`[syncSwipeToMes] Invalid swipe ID: ${targetSwipeId}`);6470 console.warn(`[syncSwipeToMes] Invalid swipe ID: ${targetSwipeId}`);
5997 return false;6471 return false;
5998 }6472 }
59996473
6000 const targetSwipeInfo = targetMessage.swipe_info[targetSwipeId];6474 const targetSwipeInfo = targetMessage?.swipe_info?.[targetSwipeId];
6001 if (typeof targetSwipeInfo !== 'object') {6475 if (typeof targetSwipeInfo !== 'object') {
6002 return false;6476 console.warn(`[syncSwipeToMes] Invalid swipe info: ${targetSwipeId}`);
6003 }6477 }
60046478
6005 targetMessage.mes = targetMessage.swipes[targetSwipeId];6479 targetMessage.mes = targetMessage.swipes[targetSwipeId];
6006 targetMessage.send_date = targetSwipeInfo.send_date;6480 targetMessage.send_date = targetSwipeInfo?.send_date;
6007 targetMessage.gen_started = targetSwipeInfo.gen_started;6481 targetMessage.gen_started = targetSwipeInfo?.gen_started;
6008 targetMessage.gen_finished = targetSwipeInfo.gen_finished;6482 targetMessage.gen_finished = targetSwipeInfo?.gen_finished;
6009 targetMessage.extra = structuredClone(targetSwipeInfo.extra);6483 targetMessage.extra = structuredClone(targetSwipeInfo?.extra) ?? {};
60106484
6011 return true;6485 return true;
6012}6486}
@@ -6014,7 +6488,7 @@ export function syncSwipeToMes(messageId = null, swipeId = null) {
6014/**6488/**
6015 * Saves the image to the message object.6489 * Saves the image to the message object.
6016 * @param {ParsedImage} img Image object6490 * @param {ParsedImage} img Image object
6017 * @param {object} mes Chat message object6491 * @param {ChatMessage} mes Chat message object
6018 * @typedef {{ image?: string, title?: string, inline?: boolean }} ParsedImage6492 * @typedef {{ image?: string, title?: string, inline?: boolean }} ParsedImage
6019 */6493 */
6020function saveImageToMessage(img, mes) {6494function saveImageToMessage(img, mes) {
@@ -6022,8 +6496,10 @@ function saveImageToMessage(img, mes) {
6022 if (!mes.extra || typeof mes.extra !== 'object') {6496 if (!mes.extra || typeof mes.extra !== 'object') {
6023 mes.extra = {};6497 mes.extra = {};
6024 }6498 }
6025 mes.extra.image = img.image;6499 if (!Array.isArray(mes.extra.media)) {
6026 mes.extra.title = img.title;6500 mes.extra.media = [];
6501 }
6502 mes.extra.media.push({ url: img.image, type: MEDIA_TYPE.IMAGE, title: img.title, source: MEDIA_SOURCE.API });
6027 mes.extra.inline_image = img.inline;6503 mes.extra.inline_image = img.inline;
6028 }6504 }
6029}6505}
@@ -6209,11 +6685,11 @@ export async function renameCharacter(name = null, { silent = false, renameChats
6209 const oldName = getCharaFilename(null, { manualAvatarKey: oldAvatar });6685 const oldName = getCharaFilename(null, { manualAvatarKey: oldAvatar });
6210 const newName = getCharaFilename(null, { manualAvatarKey: newAvatar });6686 const newName = getCharaFilename(null, { manualAvatarKey: newAvatar });
62116687
6212 // Replace other auxillery fields where was referenced by avatar key6688 // Replace other auxiliary fields where was referenced by avatar key
6213 // Tag List6689 // Tag List
6214 renameTagKey(oldAvatar, newAvatar);6690 renameTagKey(oldAvatar, newAvatar);
62156691
6216 // Addtional lore books6692 // Additional lore books
6217 const charLore = world_info.charLore?.find(x => x.name == oldName);6693 const charLore = world_info.charLore?.find(x => x.name == oldName);
6218 if (charLore) {6694 if (charLore) {
6219 charLore.name = newName;6695 charLore.name = newName;
@@ -6379,7 +6855,7 @@ export function saveChatDebounced() {
6379 * @param {string} [options.chatName] The name of the chat file to save to6855 * @param {string} [options.chatName] The name of the chat file to save to
6380 * @param {object} [options.withMetadata] Additional metadata to save with the chat6856 * @param {object} [options.withMetadata] Additional metadata to save with the chat
6381 * @param {number} [options.mesId] The message ID to save the chat up to6857 * @param {number} [options.mesId] The message ID to save the chat up to
6382 * @param {boolean} [options.force] Force the saving despire the integrity check result6858 * @param {boolean} [options.force] Force the saving despite the integrity check result
6383 *6859 *
6384 * @returns {Promise<void>}6860 * @returns {Promise<void>}
6385 */6861 */
@@ -6649,6 +7125,7 @@ export async function getChat() {
6649 chat_metadata = chat[0]['chat_metadata'] ?? {};7125 chat_metadata = chat[0]['chat_metadata'] ?? {};
66507126
6651 chat.shift();7127 chat.shift();
7128 chat.forEach(ensureMessageMediaIsArray);
6652 } else {7129 } else {
6653 chat_create_date = humanizedDateTime();7130 chat_create_date = humanizedDateTime();
6654 }7131 }
@@ -6875,7 +7352,7 @@ export function setUserName(value, { toastPersonaNameChange = true } = {}) {
68757352
6876async function doOnboarding(avatarId) {7353async function doOnboarding(avatarId) {
6877 const template = $('#onboarding_template .onboarding');7354 const template = $('#onboarding_template .onboarding');
6878 let userName = await callGenericPopup(template, POPUP_TYPE.INPUT, currentUser?.name || name1, { rows: 2, wider: true, cancelButton: false });7355 let userName = await callGenericPopup(template, POPUP_TYPE.INPUT, currentUser?.name || name1, { wider: true, cancelButton: false });
68797356
6880 if (userName) {7357 if (userName) {
6881 userName = String(userName).replace('\n', ' ');7358 userName = String(userName).replace('\n', ' ');
@@ -6936,8 +7413,7 @@ export async function getSettings() {
69367413
6937 swipes = settings.swipes !== undefined ? !!settings.swipes : true; // enable swipes by default7414 swipes = settings.swipes !== undefined ? !!settings.swipes : true; // enable swipes by default
6938 $('#swipes-checkbox').prop('checked', swipes); /// swipecode7415 $('#swipes-checkbox').prop('checked', swipes); /// swipecode
6939 hideSwipeButtons();7416 refreshSwipeButtons();
6940 showSwipeButtons();
69417417
6942 // Kobold7418 // Kobold
6943 loadKoboldSettings(data, settings.kai_settings ?? settings, settings);7419 loadKoboldSettings(data, settings.kai_settings ?? settings, settings);
@@ -6946,7 +7422,7 @@ export async function getSettings() {
6946 loadNovelSettings(data, settings.nai_settings ?? settings);7422 loadNovelSettings(data, settings.nai_settings ?? settings);
69477423
6948 // TextGen7424 // TextGen
6949 loadTextGenSettings(data, settings);7425 await loadTextGenSettings(data, settings);
69507426
6951 // OpenAI7427 // OpenAI
6952 loadOpenAISettings(data, settings.oai_settings ?? settings);7428 loadOpenAISettings(data, settings.oai_settings ?? settings);
@@ -7210,22 +7686,183 @@ function messageEditAuto(div) {
7210 saveChatDebounced();7686 saveChatDebounced();
7211}7687}
72127688
7213async function messageEditDone(div) {7689/**
7214 let { mesBlock, text, mes, bias } = updateMessage(div);7690 * Create the message edit UI.
7215 if (this_edit_mes_id == 0) {7691 * @param {number} editMessageId The ID of the message to edit
7216 text = substituteParams(text);7692 */
7693export async function messageEdit(editMessageId) {
7694 const editMessage = chat[editMessageId];
7695 if (!editMessage) {
7696 console.warn(`Message with id ${editMessageId} not found in chat array.`);
7697 return;
7217 }7698 }
72187699
7219 await eventSource.emit(event_types.MESSAGE_EDITED, this_edit_mes_id);7700 const messageElement = chatElement.find(`.mes[mesid="${editMessageId}"]`);
7220 text = chat[this_edit_mes_id]?.mes ?? text;7701 if (messageElement.length === 0) {
7221 mesBlock.find('.mes_text').empty();7702 console.warn(`Message element with id ${editMessageId} not found in DOM.`);
7222 mesBlock.find('.mes_edit_buttons').css('display', 'none');7703 return;
7223 mesBlock.find('.mes_buttons').css('display', '');7704 }
7224 mesBlock.find('.mes_text').append(7705
7225 messageFormatting(7706 this_edit_mes_id = editMessageId;
7226 text,7707 this_edit_mes_chname = editMessage.name || (editMessage.is_user ? name1 : name2);
7227 this_edit_mes_chname,7708
7228 mes.is_system,7709 const hideCounters = editMessageId < chat.length - 1;
7710 hideSwipeButtons({ hideCounters });
7711
7712 const chatScrollPosition = chatElement.scrollTop();
7713 const messageBlock = messageElement.find('.mes_block');
7714 const messageText = messageBlock.find('.mes_text');
7715
7716 messageText.empty();
7717 messageBlock.find('.mes_buttons').css('display', 'none');
7718 messageBlock.find('.mes_edit_buttons').css('display', 'inline-flex');
7719
7720 // Also edit reasoning, if it exists
7721 const reasoningEdit = messageBlock.find('.mes_reasoning_edit:visible');
7722 if (reasoningEdit.length > 0) {
7723 reasoningEdit.trigger('click');
7724 }
7725
7726 const editTextArea = document.createElement('textarea');
7727 editTextArea.id = 'curEditTextarea';
7728 editTextArea.className = 'edit_textarea mdHotkeys';
7729 messageText.append(editTextArea);
7730
7731 const text = trimSpaces(editMessage.mes || '');
7732 const $editTextArea = $(editTextArea);
7733 $editTextArea.val(text);
7734
7735 const cssAutofit = CSS.supports('field-sizing', 'content');
7736 if (!cssAutofit) {
7737 $editTextArea.height(0);
7738 $editTextArea.height(editTextArea.scrollHeight);
7739 }
7740
7741 $editTextArea.trigger('focus');
7742
7743 // Sets the cursor at the end of the text
7744 editTextArea.setSelectionRange(text.length, text.length);
7745
7746 if (Number(this_edit_mes_id) === chat.length - 1) {
7747 chatElement.scrollTop(chatScrollPosition);
7748 }
7749
7750 updateEditArrowClasses();
7751}
7752
7753/**
7754 * Close the open message editor.
7755 * This deletes the user's unsaved changes.
7756 * @param {number} [messageId=this_edit_mes_id]
7757 */
7758async function messageEditCancel(messageId = this_edit_mes_id) {
7759 let text = chat[messageId]['mes'];
7760 let thisMesDiv;
7761 // If this is the button then select it's parent. Otherwise, select by messageId.
7762 if (this?.classList?.contains('mes_edit_cancel')) {
7763 thisMesDiv = $(this).closest('.mes');
7764 } else {
7765 thisMesDiv = chatElement.children().filter(`[mesid="${messageId}"]`);
7766 }
7767
7768 const thisMesBlock = thisMesDiv.find('.mes_block');
7769 thisMesBlock.find('.mes_text').empty();
7770 thisMesDiv.find('.mes_edit_buttons').css('display', 'none');
7771 thisMesBlock.find('.mes_buttons').css('display', '');
7772 thisMesBlock.find('.mes_text')
7773 .append(messageFormatting(
7774 text,
7775 this_edit_mes_chname,
7776 chat[messageId].is_system,
7777 chat[messageId].is_user,
7778 messageId,
7779 {},
7780 false,
7781 ));
7782 appendMediaToMessage(chat[messageId], thisMesDiv);
7783 addCopyToCodeBlocks(thisMesDiv);
7784
7785 const reasoningEditDone = thisMesBlock.find('.mes_reasoning_edit_cancel:visible');
7786 if (reasoningEditDone.length > 0) {
7787 reasoningEditDone.trigger('click');
7788 }
7789
7790 await eventSource.emit(event_types.MESSAGE_UPDATED, messageId);
7791 if (messageId == this_edit_mes_id) {
7792 this_edit_mes_id = undefined;
7793 }
7794 else {
7795 console.warn(`The message editor was closed on message #${messageId} while #${this_edit_mes_id} is being edited.`);
7796 }
7797
7798 showSwipeButtons();
7799}
7800
7801/**
7802 * Swaps chat[sourceId] with chat[targetId]. They must be adjacent.
7803 * @param {number} sourceId Index of the message to move
7804 * @param {number} targetId Index of the target message
7805 * @returns {Promise<boolean>} True if the messages were moved, false otherwise
7806 */
7807async function messageEditMove(sourceId, targetId) {
7808 if (is_send_press) {
7809 console.warn(`The message #${sourceId} was not moved to #${targetId} because a generation is in progress.`);
7810 return false;
7811 }
7812
7813 if (Math.abs(sourceId - targetId) !== 1) {
7814 console.error(`Message #${sourceId} and #${targetId} are not adjacent.`);
7815 return false;
7816 }
7817
7818 const targetMessageDiv = chatElement.find(`.mes[mesid="${targetId}"]`);
7819 const sourceMessageDiv = chatElement.find(`.mes[mesid="${sourceId}"]`);
7820
7821 if (sourceMessageDiv.length === 0 || targetMessageDiv.length === 0) {
7822 console.error(`Message #${sourceId} or #${targetId} were not found.`);
7823 return false;
7824 }
7825
7826 if (sourceId <= targetId) {
7827 sourceMessageDiv.insertAfter(targetMessageDiv);
7828 }
7829 else {
7830 sourceMessageDiv.insertBefore(targetMessageDiv);
7831 }
7832
7833 //Swap Ids.
7834 targetMessageDiv.attr('mesid', sourceId);
7835 sourceMessageDiv.attr('mesid', targetId);
7836
7837 // Swap chat array entries.
7838 [chat[sourceId], chat[targetId]] = [chat[targetId], chat[sourceId]];
7839
7840 // Update edited message id
7841 if (this_edit_mes_id === sourceId) {
7842 this_edit_mes_id = targetId;
7843 }
7844
7845 updateViewMessageIds();
7846 await saveChatConditional();
7847 return true;
7848}
7849
7850async function messageEditDone(div) {
7851 let { mesBlock, text, mes, bias } = updateMessage(div);
7852 if (this_edit_mes_id == 0) {
7853 text = substituteParams(text);
7854 }
7855
7856 await eventSource.emit(event_types.MESSAGE_EDITED, this_edit_mes_id);
7857 text = chat[this_edit_mes_id]?.mes ?? text;
7858 mesBlock.find('.mes_text').empty();
7859 mesBlock.find('.mes_edit_buttons').css('display', 'none');
7860 mesBlock.find('.mes_buttons').css('display', '');
7861 mesBlock.find('.mes_text').append(
7862 messageFormatting(
7863 text,
7864 this_edit_mes_chname,
7865 mes.is_system,
7229 mes.is_user,7866 mes.is_user,
7230 this_edit_mes_id,7867 this_edit_mes_id,
7231 {},7868 {},
@@ -7245,6 +7882,7 @@ async function messageEditDone(div) {
7245 await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id);7882 await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id);
7246 this_edit_mes_id = undefined;7883 this_edit_mes_id = undefined;
7247 await saveChatConditional();7884 await saveChatConditional();
7885 showSwipeButtons();
7248}7886}
72497887
7250/**7888/**
@@ -7590,7 +8228,7 @@ export function select_selected_character(chid, { switchMenu = true } = {}) {
7590 $('#char_connections_button').show();8228 $('#char_connections_button').show();
75918229
7592 // Hide the chat scenario button if we're peeking the group member defs8230 // Hide the chat scenario button if we're peeking the group member defs
7593 $('#set_chat_scenario').toggle(!selected_group);8231 $('#set_chat_character_settings').toggle(!selected_group);
75948232
7595 // Don't update the navbar name if we're peeking the group member defs8233 // Don't update the navbar name if we're peeking the group member defs
7596 if (!selected_group) {8234 if (!selected_group) {
@@ -7672,7 +8310,7 @@ function select_rm_create({ switchMenu = true } = {}) {
76728310
7673 switchMenu && selectRightMenuWithAnimation('rm_ch_create_block');8311 switchMenu && selectRightMenuWithAnimation('rm_ch_create_block');
76748312
7675 $('#set_chat_scenario').hide();8313 $('#set_chat_character_settings').hide();
7676 $('#delete_button_div').css('display', 'none');8314 $('#delete_button_div').css('display', 'none');
7677 $('#delete_button').css('display', 'none');8315 $('#delete_button').css('display', 'none');
7678 $('#export_button').css('display', 'none');8316 $('#export_button').css('display', 'none');
@@ -7807,33 +8445,65 @@ function updateFavButtonState(state) {
7807 $('#favorite_button').toggleClass('fav_off', !state);8445 $('#favorite_button').toggleClass('fav_off', !state);
7808}8446}
78098447
7810export async function setScenarioOverride() {8448export async function setCharacterSettingsOverrides() {
7811 if (!selected_group && (this_chid === undefined || !characters[this_chid])) {8449 if (!selected_group && (this_chid === undefined || !characters[this_chid])) {
7812 console.warn('setScenarioOverride() -- no selected group or character');8450 console.warn('setCharacterSettingsOverrides() -- no selected group or character');
7813 return;8451 return;
7814 }8452 }
78158453
7816 const metadataValue = chat_metadata['scenario'] || '';8454 const scenarioOverrideValue = chat_metadata['scenario'] || '';
8455 const exampleMessagesValue = chat_metadata['mes_example'] || '';
8456 const systemPromptValue = chat_metadata['system_prompt'] || '';
7817 const isGroup = !!selected_group;8457 const isGroup = !!selected_group;
78188458
7819 const $template = $(await renderTemplateAsync('scenarioOverride'));8459 const $template = $(await renderTemplateAsync('scenarioOverride'));
7820 $template.find('[data-group="true"]').toggle(isGroup);8460 $template.find('[data-group="true"]').toggle(isGroup);
7821 $template.find('[data-character="true"]').toggle(!isGroup);8461 $template.find('[data-character="true"]').toggle(!isGroup);
7822 // TODO: Why does this save on every character input? Save on popup close8462 const pendingChanges = {
7823 $template.find('.chat_scenario').val(metadataValue).on('input', onScenarioOverrideInput);8463 scenario: scenarioOverrideValue,
7824 $template.find('.remove_scenario_override').on('click', onScenarioOverrideRemoveClick);8464 examples: exampleMessagesValue,
8465 system_prompt: systemPromptValue,
8466 };
78258467
7826 await callGenericPopup($template, POPUP_TYPE.TEXT, '');8468 // Keep edits local until the popup is closed/confirmed
7827}8469 const $scenario = $template.find('.chat_scenario');
8470 $scenario.val(scenarioOverrideValue).on('input', function () {
8471 pendingChanges.scenario = String($(this).val());
8472 });
8473 const $examples = $template.find('.chat_examples');
8474 $examples.val(exampleMessagesValue).on('input', function () {
8475 pendingChanges.examples = String($(this).val());
8476 });
8477 const $systemPrompt = $template.find('.chat_system_prompt');
8478 $systemPrompt.val(systemPromptValue).on('input', function () {
8479 pendingChanges.system_prompt = String($(this).val());
8480 });
78288481
7829function onScenarioOverrideInput() {8482 $template.find('.remove_scenario_override').on('click', async function () {
7830 const value = String($(this).val());8483 const confirm = await Popup.show.confirm(t`Are you sure you want to remove all overrides?`, t`This action cannot be undone.`);
7831 chat_metadata['scenario'] = value;8484 if (!confirm) {
7832 saveMetadataDebounced();8485 return;
7833}8486 }
78348487
7835function onScenarioOverrideRemoveClick() {8488 $scenario.val('');
7836 $(this).closest('.scenario_override').find('.chat_scenario').val('').trigger('input');8489 pendingChanges.scenario = '';
8490 $examples.val('');
8491 pendingChanges.examples = '';
8492 $systemPrompt.val('');
8493 pendingChanges.system_prompt = '';
8494 });
8495
8496 // Wait for popup close/confirm.
8497 await callGenericPopup($template, POPUP_TYPE.TEXT, '', {
8498 wide: true,
8499 large: true,
8500 allowVerticalScrolling: true,
8501 });
8502
8503 chat_metadata['scenario'] = pendingChanges.scenario;
8504 chat_metadata['mes_example'] = pendingChanges.examples;
8505 chat_metadata['system_prompt'] = pendingChanges.system_prompt;
8506 saveMetadataDebounced();
7837}8507}
78388508
7839/**8509/**
@@ -7900,18 +8570,42 @@ export function callPopup(text, type, inputValue = '', { okButton, rows, wide, w
7900 });8570 });
7901}8571}
79028572
7903export function showSwipeButtons() {8573/**
8574 * Update the swipe counter for mesId.
8575 * @param {Number} mesId
8576 */
8577export async function updateSwipeCounter(mesId) {
8578 const swipeCounterText = formatSwipeCounter((chat[mesId]?.['swipe_id'] + 1), chat[mesId]?.['swipes']?.length);
8579 const currentMessage = chatElement.children().filter(`[mesid="${mesId}"]`);
8580 const swipeCounter = currentMessage.find('.swipes-counter');
8581 swipeCounter.text(swipeCounterText).show();
8582}
8583
8584/**
8585 * Swipe buttons are often toggled to update their position.
8586 * This should be replaced with a more efficient function.
8587 */
8588export function refreshSwipeButtons() {
8589 hideSwipeButtons();
8590 showSwipeButtons();
8591}
8592
8593export function showSwipeButtons(mesId = chat.length - 1) {
8594 isSwipingAllowed = true;
8595
7904 if (chat.length === 0) {8596 if (chat.length === 0) {
7905 return;8597 return;
7906 }8598 }
79078599
7908 if (8600 if (
7909 chat[chat.length - 1].is_system ||8601 chat[mesId].is_system ||
7910 !swipes ||8602 !swipes ||
7911 Number($('.mes:last').attr('mesid')) < 0 ||8603 Number($('.mes:last').attr('mesid')) < 0 ||
7912 chat[chat.length - 1].is_user ||8604 chat[mesId].is_user ||
7913 (selected_group && is_group_generating)8605 (selected_group && is_group_generating)
7914 ) { return; }8606 ) {
8607 return;
8608 }
79158609
7916 // swipe_id should be set if alternate greetings are added8610 // swipe_id should be set if alternate greetings are added
7917 if (chat.length == 1 && chat[0].swipe_id === undefined) {8611 if (chat.length == 1 && chat[0].swipe_id === undefined) {
@@ -7921,35 +8615,35 @@ export function showSwipeButtons() {
7921 //had to add this to make the swipe counter work8615 //had to add this to make the swipe counter work
7922 //(copied from the onclick functions for swipe buttons..8616 //(copied from the onclick functions for swipe buttons..
7923 //don't know why the array isn't set for non-swipe messages in Generate or addOneMessage..)8617 //don't know why the array isn't set for non-swipe messages in Generate or addOneMessage..)
7924 if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array8618 if (chat[mesId]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array
7925 chat[chat.length - 1]['swipe_id'] = 0; // set it to id 08619 chat[mesId]['swipe_id'] = 0; // set it to id 0
7926 chat[chat.length - 1]['swipes'] = []; // empty the array8620 chat[mesId]['swipes'] = []; // empty the array
7927 chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat8621 chat[mesId]['swipes'][0] = chat[mesId]['mes']; //assign swipe array with last message from chat
7928 chat[chat.length - 1]['swipe_info'] = [];8622 chat[mesId]['swipe_info'] = [];
7929 chat[chat.length - 1]['swipe_info'][0] = {8623 chat[mesId]['swipe_info'][0] = {
7930 'send_date': chat[chat.length - 1]['send_date'],8624 'send_date': chat[mesId]['send_date'],
7931 'gen_started': chat[chat.length - 1]['gen_started'],8625 'gen_started': chat[mesId]['gen_started'],
7932 'gen_finished': chat[chat.length - 1]['gen_finished'],8626 'gen_finished': chat[mesId]['gen_finished'],
7933 'extra': structuredClone(chat[chat.length - 1]['extra']),8627 'extra': structuredClone(chat[mesId]['extra']),
7934 };8628 };
7935 }8629 }
79368630
7937 const currentMessage = chatElement.children().filter(`[mesid="${chat.length - 1}"]`);8631 const currentMessage = chatElement.children().filter(`[mesid="${mesId}"]`);
7938 const swipeId = chat[chat.length - 1].swipe_id;8632 const swipeId = chat[mesId].swipe_id;
7939 const swipeCounterText = formatSwipeCounter((swipeId + 1), chat[chat.length - 1].swipes.length);8633 const swipeCounterText = formatSwipeCounter((swipeId + 1), chat[mesId]['swipes'].length);
7940 const swipeRight = currentMessage.find('.swipe_right');8634 const swipeRight = currentMessage.find('.swipe_right');
7941 const swipeLeft = currentMessage.find('.swipe_left');8635 const swipeLeft = currentMessage.find('.swipe_left');
7942 const swipeCounter = currentMessage.find('.swipes-counter');8636 const swipeCounter = currentMessage.find('.swipes-counter');
79438637
7944 if (swipeId !== undefined && (chat[chat.length - 1].swipes.length > 1 || swipeId > 0)) {8638 if (swipeId !== undefined && (chat[mesId].swipes.length > 1 || swipeId > 0)) {
7945 swipeLeft.css('display', 'flex');8639 swipeLeft.css('display', 'flex');
7946 }8640 }
7947 //only show right when generate is off, or when next right swipe would not make a generate happen8641 //only show right when generate is off, or when next right swipe would not make a generate happen
7948 if (is_send_press === false || chat[chat.length - 1].swipes.length >= swipeId) {8642 if (is_send_press === false || chat[mesId].swipes.length >= swipeId) {
7949 swipeRight.css('display', 'flex').css('opacity', '0.3');8643 swipeRight.css('display', 'flex').css('opacity', '0.3');
7950 swipeCounter.css('opacity', '0.3');8644 swipeCounter.css('opacity', '0.3');
7951 }8645 }
7952 if ((chat[chat.length - 1].swipes.length - swipeId) === 1) {8646 if ((chat[mesId].swipes.length - swipeId) === 1) {
7953 //chevron was moved out of hardcode in HTML to class toggle dependent on last_mes or not8647 //chevron was moved out of hardcode in HTML to class toggle dependent on last_mes or not
7954 //necessary for 'swipe_right' div in past messages to have no chevron if 'show swipes for all messages' is turned on8648 //necessary for 'swipe_right' div in past messages to have no chevron if 'show swipes for all messages' is turned on
7955 swipeRight.css('opacity', '0.7');8649 swipeRight.css('opacity', '0.7');
@@ -7961,10 +8655,17 @@ export function showSwipeButtons() {
7961 lastSwipeCounter.text(swipeCounterText).show();8655 lastSwipeCounter.text(swipeCounterText).show();
7962}8656}
79638657
7964export function hideSwipeButtons() {8658/**
8659 * @param {object} [options] Options
8660 * @param {boolean} [options.hideCounters=false] Also hide the swipes counter.
8661 */
8662export function hideSwipeButtons({ hideCounters = false } = {}) {
8663 isSwipingAllowed = false;
7965 chatElement.find('.swipe_right').hide();8664 chatElement.find('.swipe_right').hide();
7966 chatElement.find('.last_mes .swipes-counter').hide();
7967 chatElement.find('.swipe_left').hide();8665 chatElement.find('.swipe_left').hide();
8666 if (hideCounters === true) {
8667 chatElement.find('.last_mes .swipes-counter').hide();
8668 }
7968}8669}
79698670
7970/**8671/**
@@ -8008,6 +8709,8 @@ export async function deleteSwipe(swipeId = null, messageId = chat.length - 1) {
8008 const newSwipeId = Math.min(swipeId, message.swipes.length - 1);8709 const newSwipeId = Math.min(swipeId, message.swipes.length - 1);
8009 syncSwipeToMes(messageId, newSwipeId);8710 syncSwipeToMes(messageId, newSwipeId);
80108711
8712 chat_metadata['tainted'] = true;
8713
8011 await eventSource.emit(event_types.MESSAGE_SWIPE_DELETED, { messageId, swipeId, newSwipeId });8714 await eventSource.emit(event_types.MESSAGE_SWIPE_DELETED, { messageId, swipeId, newSwipeId });
80128715
8013 await saveChatConditional();8716 await saveChatConditional();
@@ -8081,8 +8784,8 @@ async function importCharacterChat(formData, { refresh = true } = {}) {
8081 return [];8784 return [];
8082}8785}
80838786
8084function updateViewMessageIds(startFromZero = false) {8787export function updateViewMessageIds(startIndex = null) {
8085 const minId = startFromZero ? 0 : getFirstDisplayedMessageId();8788 const minId = startIndex ?? getFirstDisplayedMessageId();
80868789
8087 chatElement.find('.mes').each(function (index, element) {8790 chatElement.find('.mes').each(function (index, element) {
8088 $(element).attr('mesid', minId + index);8791 $(element).attr('mesid', minId + index);
@@ -8101,24 +8804,27 @@ export function getFirstDisplayedMessageId() {
8101 return minId;8804 return minId;
8102}8805}
81038806
8104function updateEditArrowClasses() {8807export function updateEditArrowClasses() {
8105 chatElement.find('.mes .mes_edit_up').removeClass('disabled');8808 if (!(this_edit_mes_id >= 0)) {
8106 chatElement.find('.mes .mes_edit_down').removeClass('disabled');8809 return;
8810 }
8811
8812 const message = chatElement.find(`.mes[mesid="${this_edit_mes_id}"]`);
81078813
8108 if (this_edit_mes_id !== undefined) {8814 const downButton = message.find('.mes_edit_down');
8109 const down = chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_down`);8815 const upButton = message.find('.mes_edit_up');
8110 const up = chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_up`);8816 const copyButton = message.find('.mes_edit_copy');
8111 const lastId = Number(chatElement.find('.mes').last().attr('mesid'));8817 const deleteButton = message.find('.mes_edit_delete');
8112 const firstId = Number(chatElement.find('.mes').first().attr('mesid'));8818 const lastId = Number(chatElement.find('.mes').last().attr('mesid'));
8819 const firstId = Number(chatElement.find('.mes').first().attr('mesid'));
81138820
8114 if (lastId == Number(this_edit_mes_id)) {8821 copyButton.removeClass('disabled');
8115 down.addClass('disabled');8822 deleteButton.removeClass('disabled');
8116 }
81178823
8118 if (firstId == Number(this_edit_mes_id)) {8824 // The last message cannot be moved down.
8119 up.addClass('disabled');8825 downButton.toggleClass('disabled', lastId === Number(this_edit_mes_id));
8120 }8826 // The first message cannot be moved up.
8121 }8827 upButton.toggleClass('disabled', firstId === Number(this_edit_mes_id));
8122}8828}
81238829
8124/**8830/**
@@ -8127,7 +8833,7 @@ function updateEditArrowClasses() {
8127 */8833 */
8128export function closeMessageEditor(what = 'all') {8834export function closeMessageEditor(what = 'all') {
8129 if (what === 'message' || what === 'all') {8835 if (what === 'message' || what === 'all') {
8130 if (this_edit_mes_id) {8836 if (this_edit_mes_id >= 0) {
8131 chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).trigger('click');8837 chatElement.find(`.mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).trigger('click');
8132 }8838 }
8133 }8839 }
@@ -8270,6 +8976,8 @@ function openAlternateGreetings() {
8270 array.push('');8976 array.push('');
8271 addAlternateGreeting(template, '', index, getArray, popup);8977 addAlternateGreeting(template, '', index, getArray, popup);
8272 updateAlternateGreetingsHintVisibility(template);8978 updateAlternateGreetingsHintVisibility(template);
8979 const list = template.find('.alternate_greetings_list');
8980 list.scrollTop(list.prop('scrollHeight'));
8273 });8981 });
82748982
8275 popup.show();8983 popup.show();
@@ -8286,6 +8994,7 @@ function openAlternateGreetings() {
8286 */8994 */
8287function addAlternateGreeting(template, greeting, index, getArray, popup) {8995function addAlternateGreeting(template, greeting, index, getArray, popup) {
8288 const greetingBlock = $('#alternate_greeting_form_template .alternate_greeting').clone();8996 const greetingBlock = $('#alternate_greeting_form_template .alternate_greeting').clone();
8997 greetingBlock.attr('data-index', index);
8289 greetingBlock.find('.alternate_greeting_text')8998 greetingBlock.find('.alternate_greeting_text')
8290 .attr('id', `alternate_greeting_${index}`)8999 .attr('id', `alternate_greeting_${index}`)
8291 .on('input', async function () {9000 .on('input', async function () {
@@ -8299,15 +9008,57 @@ function addAlternateGreeting(template, greeting, index, getArray, popup) {
8299 event.preventDefault();9008 event.preventDefault();
8300 event.stopPropagation();9009 event.stopPropagation();
83019010
8302 if (confirm(t`Are you sure you want to delete this alternate greeting?`)) {9011 const confirm = await callGenericPopup(t`Are you sure you want to delete this alternate greeting?`, POPUP_TYPE.CONFIRM);
8303 const array = getArray();9012 if (!confirm) {
8304 array.splice(index, 1);9013 return;
8305
8306 // We need to reopen the popup to update the index numbers
8307 await popup.complete(POPUP_RESULT.AFFIRMATIVE);
8308 openAlternateGreetings();
8309 }9014 }
9015
9016 const array = getArray();
9017 array.splice(index, 1);
9018
9019 // We need to reopen the popup to update the index numbers
9020 await popup.complete(POPUP_RESULT.AFFIRMATIVE);
9021 openAlternateGreetings();
8310 });9022 });
9023 greetingBlock.find('.move_up_alternate_greeting').on('click', function (event) {
9024 handleMoveAlternateGreeting(event, -1);
9025 });
9026 greetingBlock.find('.move_down_alternate_greeting').on('click', function (event) {
9027 handleMoveAlternateGreeting(event, 1);
9028 });
9029
9030 /**
9031 * Handles moving an alternate greeting up or down in the list.
9032 * @param {JQuery.ClickEvent} event - The click event
9033 * @param {number} direction - Direction to move: -1 for up, 1 for down
9034 */
9035 function handleMoveAlternateGreeting(event, direction) {
9036 event.preventDefault();
9037 event.stopPropagation();
9038
9039 const array = getArray();
9040 const index = Number(greetingBlock.attr('data-index'));
9041 const newIndex = index + direction;
9042
9043 // Check bounds
9044 if (direction === -1 && index <= 0) {
9045 return;
9046 }
9047 if (direction === 1 && index >= array.length - 1) {
9048 return;
9049 }
9050
9051 // Swap the greetings
9052 [array[index], array[newIndex]] = [array[newIndex], array[index]];
9053
9054 // Update current greeting
9055 greetingBlock.find('.alternate_greeting_text').val(array[index]);
9056
9057 // Update adjacent greeting
9058 const adjacentGreetingBlock = template.find(`.alternate_greeting[data-index="${newIndex}"]`);
9059 adjacentGreetingBlock.find('.alternate_greeting_text').val(array[newIndex]);
9060 }
9061
8311 template.find('.alternate_greetings_list').append(greetingBlock);9062 template.find('.alternate_greetings_list').append(greetingBlock);
8312}9063}
83139064
@@ -8499,367 +9250,390 @@ export async function createOrEditCharacter(e) {
8499 * @returns {string} The formatted counter.9250 * @returns {string} The formatted counter.
8500 */9251 */
8501function formatSwipeCounter(current, total) {9252function formatSwipeCounter(current, total) {
8502 if (isNaN(current) || isNaN(total)) {9253 if (isNaN(current) && isNaN(total)) {
8503 return '';9254 return '';
8504 }9255 }
85059256 return `${!isNaN(current) ? current : '?'}\u200b/\u200b${!isNaN(total) ? total : '?'}`;
8506 return `${current}\u200b/\u200b${total}`;
8507}9257}
85089258
8509/**9259/**
8510 * Handles the swipe to the left event.9260 * Handles the swipe event.
8511 * @param {JQuery.Event} _event Event.9261 * @param {JQuery.Event} _event Event.
9262 * @param {'left'|'right'} direction The direction to swipe.
8512 * @param {object} params Additional parameters.9263 * @param {object} params Additional parameters.
8513 * @param {string} [params.source] The source of the swipe event.9264 * @param {string} [params.source] The source of the swipe event.
8514 * @param {boolean} [params.repeated] Is the swipe event repeated.9265 * @param {boolean} [params.repeated] Is the swipe event repeated.
9266 * @param {object} [params.message=chat[chat.length - 1]] The chat message to swipe.
8515 */9267 */
8516export function swipe_left(_event, { source, repeated } = {}) {9268export async function swipe(_event, direction, { source, repeated, message = chat[chat.length - 1] } = {}) {
8517 if (chat.length - 1 === Number(this_edit_mes_id)) {9269 if (chat.length === 0) {
8518 closeMessageEditor();9270 console.warn('Swipe was called on an empty chat.');
9271 return;
8519 }9272 }
8520 if (isStreamingEnabled() && streamingProcessor) {9273
8521 streamingProcessor.onStopStreaming();9274 //Only allow one concurrent swipe.
9275 if (!isSwipingAllowed) {
9276 console.info('The swipe has been ignored because another is in progress.');
9277 return;
9278 }
9279 isSwipingAllowed = false;
9280
9281 let generation;
9282 let messageIndex;
9283
9284 //Only set messageIndex if message exists because -1 is truthy.
9285 if (message) {
9286 messageIndex = chat.indexOf(message);
9287 if (messageIndex === -1) {
9288 console.error(`The message must exist in chat. ${message};`);
9289 return;
9290 }
8522 }9291 }
85239292
8524 // Make sure ad-hoc changes to extras are saved before swiping away9293 const mesId = Number($(this).closest('.mes').attr('mesid') ?? messageIndex ?? chat.length - 1);
8525 syncMesToSwipe();
85269294
8527 // If the user is holding down the key and we're at the first swipe, don't do anything9295 const thisMesDiv = chatElement.children().filter(`.mes[mesid="${mesId}"]`);
8528 if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === 0) {9296 const thisMesText = thisMesDiv.find('.mes_block .mes_text');
9297 const thisMesDivHeight = thisMesDiv[0]?.scrollHeight;
9298 const thisMesTextHeight = thisMesText[0]?.scrollHeight;
9299 if (![thisMesDiv.length, thisMesText.length].every(num => num > 0)) {
9300 console.error(`Message #${mesId}'s DOM element is not valid.`);
8529 return;9301 return;
8530 }9302 }
9303 const originalSwipeId = Number(chat[mesId]?.['swipe_id'] ?? 0);
9304 let newSwipeId = Number(originalSwipeId);
9305
9306 const isPristine = !chat_metadata?.tainted;
9307 const swipeDuration = Math.round(animation_duration * 1.25);
9308 const swipeRange = direction === SWIPE_DIRECTION.RIGHT ? -700 : 700;
9309
9310 async function endSwipe() {
9311 //Wait for the generation to end.
9312 try {
9313 await generation;
9314 }
9315 catch (error) {
9316 console.warn(`Swipe failed, Swiping back. ${error}`);
9317 }
9318 //Allow for another swipe.
9319 showSwipeButtons();
9320
9321 //Clamp Id between swipes.
9322 let clampedId = clamp(chat[mesId]['swipe_id'], 0, Math.max(0, chat[mesId]['swipes'].length - 1));
9323
9324 //If the id is not within bounds, Swipe back.
9325 if (chat[mesId]['swipe_id'] !== clampedId) {
9326 chat[mesId]['swipe_id'] = clampedId;
9327 syncSwipeToMes(mesId);
9328 addOneMessage(chat[mesId], { type: 'swipe', forceId: mesId, scroll: false });
9329 }
85319330
8532 const swipe_duration = 120;9331 await updateSwipeCounter(mesId);
8533 const swipe_range = '700px';9332 //Fallback.
8534 chat[chat.length - 1]['swipe_id']--;9333 if (mesId != chat.length - 1) {
9334 await updateSwipeCounter(chat.length - 1);
9335 }
9336 }
85359337
8536 if (chat[chat.length - 1]['swipe_id'] < 0) {9338 async function standardSwipe() {
8537 chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length - 1;9339 //If swipe_id has changed, or the source is being deleted.
9340 if (newSwipeId !== originalSwipeId || source == 'delete') {
9341 //Update the chat.
9342 await loadFromSwipeId(mesId, newSwipeId);
9343 //Transition to the new chat.
9344 await animateSwipe();
9345 }
9346 await endSwipe();
8538 }9347 }
85399348
8540 if (chat[chat.length - 1]['swipe_id'] >= 0) {9349 /**
8541 /*$(this).parent().children('swipe_right').css('display', 'flex');9350 * Sets the message to the newSwipeId and loads it.
8542 if (chat[chat.length - 1]['swipe_id'] === 0) {9351 * @param {number} mesId
8543 $(this).css('display', 'none');9352 * @param {number} newSwipeId
8544 }*/ // Just in case9353 */
8545 if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) {9354 async function loadFromSwipeId(mesId, newSwipeId) {
8546 chat[chat.length - 1]['swipe_info'] = [];9355 //Update the swipe_id.
8547 }9356 chat[mesId]['swipe_id'] = newSwipeId;
8548 let this_mes_div = $(this).parent();9357
8549 let this_mes_block = $(this).parent().children('.mes_block').children('.mes_text');9358 if (chat[mesId].extra && typeof chat[mesId].extra === 'object') {
8550 const this_mes_div_height = this_mes_div[0].scrollHeight;9359 delete chat[mesId].extra.memory;
8551 this_mes_div.css('height', this_mes_div_height);9360 delete chat[mesId].extra.display_text;
8552 const this_mes_block_height = this_mes_block[0].scrollHeight;9361 delete chat[mesId].extra.media;
8553 chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']];9362 delete chat[mesId].extra.inline_image;
8554 chat[chat.length - 1]['send_date'] = chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.send_date || chat[chat.length - 1].send_date; //load the last mes box with the latest generation9363 delete chat[mesId].extra.files;
8555 chat[chat.length - 1]['extra'] = structuredClone(chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.extra || chat[chat.length - 1].extra);9364 delete chat[mesId].extra.fileLength;
85569365 delete chat[mesId].extra.generationType;
8557 if (chat[chat.length - 1].extra) {9366 delete chat[mesId].extra.negative;
8558 // if message has memory attached - remove it to allow regen9367 delete chat[mesId].extra.title;
8559 if (chat[chat.length - 1].extra.memory) {9368 delete chat[mesId].extra.append_title;
8560 delete chat[chat.length - 1].extra.memory;9369 }
8561 }9370 delete chat[mesId].gen_started;
8562 // ditto for display text9371 delete chat[mesId].gen_finished;
8563 if (chat[chat.length - 1].extra.display_text) {9372 //load from swipes.
8564 delete chat[chat.length - 1].extra.display_text;9373 syncSwipeToMes(mesId, chat[mesId]['swipe_id']);
8565 }9374 }
8566 }9375
8567 $(this).parent().children('.mes_block').transition({9376 // Helper function to convert transition to promise
8568 x: swipe_range,9377 const transitionPromise = (element, properties) => {
8569 duration: animation_duration > 0 ? swipe_duration : 0,9378 return new Promise((resolve) => {
9379 element.transition({
9380 ...properties,
9381 complete: resolve,
9382 });
9383 });
9384 };
9385
9386 /**
9387 * Animates a swipe for all messages >= mesId.
9388 * @param {number} mesId
9389 * @param {number} x
9390 * @param {number} duration
9391 */
9392 async function animateSwipeTransition(mesId, x, duration) {
9393 //Selects the swiped message.
9394 const swipedMessagesDiv = chatElement.children().filter((index, div) => {
9395 const $div = $(div);
9396 return mesId === Number($div.attr('mesid'));
9397 });
9398 const swipedElementsDiv = swipedMessagesDiv.children('.mes_block, .mesAvatarWrapper');
9399
9400 //Swipe.
9401 await transitionPromise(swipedElementsDiv, {
9402 x: x,
9403 duration: duration,
8570 easing: animation_easing,9404 easing: animation_easing,
8571 queue: false,9405 queue: false,
8572 complete: async function () {9406 });
8573 const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop('scrollHeight') - $('#chat').outerHeight()) - 10);9407 }
8574 //console.log('on left swipe click calling addOneMessage');
8575 addOneMessage(chat[chat.length - 1], { type: 'swipe' });
8576
8577 if (power_user.message_token_count_enabled) {
8578 if (!chat[chat.length - 1].extra) {
8579 chat[chat.length - 1].extra = {};
8580 }
85819408
8582 const swipeMessage = $('#chat').find(`[mesid="${chat.length - 1}"]`);9409 function getMessageBottomHeight(thisMesDiv) {
8583 const tokenCountText = (chat[chat.length - 1]?.extra?.reasoning || '') + chat[chat.length - 1].mes;9410 const thisMesRect = thisMesDiv[0].getBoundingClientRect();
8584 const tokenCount = await getTokenCountAsync(tokenCountText, 0);9411 //Scroll position + Chat height = Bottom of chat height.
8585 chat[chat.length - 1]['extra']['token_count'] = tokenCount;9412 const chatBottom = chatElement.scrollTop() - chatElement.height();
8586 swipeMessage.find('.tokenCounterDisplay').text(`${tokenCount}t`);9413 //Message offset from viewport top + height = Bottom of message offset.
8587 }9414 const messageBottom = thisMesRect.top + thisMesDiv.height();
9415 // Bottom of chat + Bottom of message offset = target scroll position.
9416 const scrollHeight = (chatBottom + messageBottom);
9417 return scrollHeight;
9418 }
85889419
8589 let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight);9420 function expandNewMessage(thisMesDiv) {
8590 if (new_height < 103) new_height = 103;9421 //Only scroll if the view is not near the bottom.
8591 this_mes_div.animate({ height: new_height + 'px' }, {9422 const is_animation_scroll = (chatElement.scrollTop() >= (chatElement.prop('scrollHeight') - chatElement.outerHeight()) - 10);
8592 duration: 0, //used to be 100
8593 queue: false,
8594 progress: function () {
8595 // Scroll the chat down as the message expands
85969423
8597 if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight);9424 let new_height = thisMesDivHeight - (thisMesTextHeight - thisMesText[0].scrollHeight);
8598 },9425 if (new_height < 103) new_height = 103;
8599 complete: function () {
8600 this_mes_div.css('height', 'auto');
8601 // Scroll the chat down to the bottom once the animation is complete
8602 if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight);
8603 },
8604 });
8605 $(this).parent().children('.mes_block').transition({
8606 x: '-' + swipe_range,
8607 duration: 0,
8608 easing: animation_easing,
8609 queue: false,
8610 complete: function () {
8611 $(this).parent().children('.mes_block').transition({
8612 x: '0px',
8613 duration: animation_duration > 0 ? swipe_duration : 0,
8614 easing: animation_easing,
8615 queue: false,
8616 complete: async function () {
8617 appendMediaToMessage(chat[chat.length - 1], $(this).parent().children('.mes_block'));
8618 await eventSource.emit(event_types.MESSAGE_SWIPED, (chat.length - 1));
8619 saveChatDebounced();
8620 },
8621 });
8622 },
8623 });
8624 },
8625 });
86269426
8627 $(this).parent().children('.avatar').transition({9427 //Keep the swipe buttons at the same height when scrolling is finished.
8628 x: swipe_range,9428
8629 duration: animation_duration > 0 ? swipe_duration : 0,9429 //Expand new message.
8630 easing: animation_easing,9430 thisMesDiv.animate({ height: new_height + 'px' }, {
9431 duration: 0, //used to be 100 //Disabled on Cohee's request. https://github.com/SillyTavern/SillyTavern/pull/4610/files#r2408731744
8631 queue: false,9432 queue: false,
8632 complete: function () {9433 progress: function (animation, progress, remainingMs) {
8633 $(this).parent().children('.avatar').transition({
8634 x: '-' + swipe_range,
8635 duration: 0,
8636 easing: animation_easing,
8637 queue: false,
8638 complete: function () {
8639 $(this).parent().children('.avatar').transition({
8640 x: '0px',
8641 duration: animation_duration > 0 ? swipe_duration : 0,
8642 easing: animation_easing,
8643 queue: false,
8644 complete: function () {
86459434
8646 },9435 if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv));
8647 });9436 },
8648 },9437 complete: function () {
8649 });9438 thisMesDiv.css('height', 'auto');
9439 //Correct height auto offset.
9440 if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv));
8650 },9441 },
8651 });9442 });
8652 }9443 }
8653 if (chat[chat.length - 1]['swipe_id'] < 0) {9444
8654 chat[chat.length - 1]['swipe_id'] = 0;9445 /**
9446 * Anime a swipe, optionally running a generation.
9447 * @param {boolean} run_generate
9448 */
9449 async function animateSwipe(run_generate = false) {
9450
9451 //Swipe out.
9452 await animateSwipeTransition(mesId, swipeRange, swipeDuration);
9453
9454 if (run_generate) {
9455 await updateSwipeCounter(mesId);
9456 //shows "..." while generating
9457 thisMesDiv.find('.mes_text').html('...');
9458 // resets the timer
9459 thisMesDiv.find('.mes_timer').html('');
9460 thisMesDiv.find('.tokenCounterDisplay').text('');
9461 updateReasoningUI(thisMesDiv, { reset: true });
9462 } else {
9463 //console.log('showing previously generated swipe candidate, or "..."');
9464 //console.log('onclick right swipe calling addOneMessage');
9465
9466 //Only scroll when swiping the last message.
9467 const scroll = (mesId == chat.length - 1);
9468 addOneMessage(chat[mesId], { type: 'swipe', forceId: mesId, scroll: scroll });
9469
9470 if (power_user.message_token_count_enabled) {
9471 if (!chat[mesId].extra) {
9472 chat[mesId].extra = {};
9473 }
9474
9475 const tokenCountText = (chat[mesId]?.extra?.reasoning || '') + chat[mesId].mes;
9476 const tokenCount = await getTokenCountAsync(tokenCountText, 0);
9477 chat[mesId]['extra']['token_count'] = tokenCount;
9478 thisMesDiv.find('.tokenCounterDisplay').text(`${tokenCount}t`);
9479 }
9480 }
9481
9482 //Animate expanding to the new message height.
9483 thisMesDiv.css('height', thisMesDivHeight);
9484 expandNewMessage(thisMesDiv);
9485
9486
9487 //Jump to the opposite side.
9488 await animateSwipeTransition(mesId, -swipeRange, 0);
9489
9490 appendMediaToMessage(chat[mesId], thisMesDiv);
9491
9492 await eventSource.emit(event_types.MESSAGE_SWIPED, (mesId));
9493
9494 if (run_generate && !is_send_press) {
9495 is_send_press = true;
9496 generation = Generate('swipe');
9497 } else if (Number(chat[mesId]['swipe_id']) !== chat[mesId]['swipes'].length) {
9498 saveChatDebounced();
9499 }
9500
9501 //Swipe in.
9502 await animateSwipeTransition(mesId, 0, swipeDuration);
8655 }9503 }
8656}
86579504
8658/**9505 if (mesId === Number(this_edit_mes_id)) {
8659 * Handles the swipe to the right event.
8660 * @param {JQuery.Event} [_event] Event.
8661 * @param {object} params Additional parameters.
8662 * @param {string} [params.source] The source of the swipe event.
8663 * @param {boolean} [params.repeated] Is the swipe event repeated.
8664 */
8665//MARK: swipe_right
8666export function swipe_right(_event = null, { source, repeated } = {}) {
8667 if (chat.length - 1 === Number(this_edit_mes_id)) {
8668 closeMessageEditor();9506 closeMessageEditor();
8669 }9507 }
9508 if (isStreamingEnabled() && streamingProcessor) {
9509 streamingProcessor.onStopStreaming();
9510 }
86709511
8671 if (isHordeGenerationNotAllowed()) {9512 if (isHordeGenerationNotAllowed()) {
8672 return unblockGeneration();9513 return unblockGeneration();
8673 }9514 }
86749515
8675 // Make sure ad-hoc changes to extras are saved before swiping away9516 //If the swipe is not being deleted.
8676 syncMesToSwipe();9517 if (source != 'delete') {
86779518
8678 const isPristine = !chat_metadata?.tainted;9519 // Make sure ad-hoc changes to extras are saved before swiping away
8679 const swipe_duration = 200;9520 syncMesToSwipe(mesId);
8680 const swipe_range = 700;9521
8681 //console.log(swipe_range);9522 if (chat[mesId]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array
8682 let run_generate = false;9523 chat[mesId]['swipe_id'] = 0; // set it to id 0
8683 let run_swipe_right = false;9524 chat[mesId]['swipes'] = []; // empty the array
8684 if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array9525 chat[mesId]['swipe_info'] = [];
8685 chat[chat.length - 1]['swipe_id'] = 0; // set it to id 09526 chat[mesId]['swipes'][0] = chat[mesId]['mes']; //assign swipe array with last chat[mesId] from chat
8686 chat[chat.length - 1]['swipes'] = []; // empty the array9527 chat[mesId]['swipe_info'][0] = {
8687 chat[chat.length - 1]['swipe_info'] = [];9528 'send_date': chat[mesId]['send_date'],
8688 chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat9529 'gen_started': chat[mesId]['gen_started'],
8689 chat[chat.length - 1]['swipe_info'][0] = {9530 'gen_finished': chat[mesId]['gen_finished'],
8690 'send_date': chat[chat.length - 1]['send_date'],9531 'extra': structuredClone(chat[mesId]['extra']),
8691 'gen_started': chat[chat.length - 1]['gen_started'],9532 };
8692 'gen_finished': chat[chat.length - 1]['gen_finished'],9533 }
8693 'extra': structuredClone(chat[chat.length - 1]['extra']),9534 // If the user is holding down the key and we're at the last or first swipe, don't do anything.
8694 };9535 let isLastSwipe = (direction === SWIPE_DIRECTION.RIGHT) ? (chat[mesId].swipe_id === Math.max(0, chat[mesId]['swipes'].length - 1)) : chat[mesId].swipe_id === 0;
8695 //assign swipe info array with last message from chat9536 if (source === 'keyboard' && repeated && isLastSwipe) {
9537 await endSwipe();
9538 return;
9539 }
9540 } else if (source == 'delete') {
9541 //If the swipe is being deleted.
9542 await standardSwipe();
9543 return;
8696 }9544 }
8697 // if swipe_right is called on the last alternate greeting in pristine chats, loop back around9545
8698 if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1 && isPristine) {9546 //If swiping left.
8699 chat[0]['swipe_id'] = 0;9547 if (direction === SWIPE_DIRECTION.LEFT) {
8700 } else {9548 newSwipeId--;
8701 // If the user is holding down the key and we're at the last swipe, don't do anything9549 //Loop to last swipe if negative.
8702 if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === chat[chat.length - 1].swipes.length - 1) {9550 if (newSwipeId < 0) {
9551 newSwipeId = Math.max(0, chat[mesId]['swipes'].length - 1);
9552 }
9553 //Limit swipe_id to swipes.
9554 if (newSwipeId > chat[mesId]['swipes'].length - 1) {
9555 toastr.warning(`The swipe_id for message #${mesId} was ${newSwipeId}. It has been reset to ${chat[mesId]['swipes'].length - 1}.`);
9556 chat[mesId]['swipe_id'] = chat[mesId]['swipes'].length - 1;
9557 await endSwipe();
8703 return;9558 return;
8704 }9559 }
9560 await standardSwipe();
9561 return;
9562 }
9563 //If swiping right.
9564 else if (direction === SWIPE_DIRECTION.RIGHT) {
8705 // make new slot in array9565 // make new slot in array
8706 chat[chat.length - 1]['swipe_id']++;9566 newSwipeId++;
8707 }
8708 if (chat[chat.length - 1].extra) {
8709 // if message has memory attached - remove it to allow regen
8710 if (chat[chat.length - 1].extra.memory) {
8711 delete chat[chat.length - 1].extra.memory;
8712 }
8713 // ditto for display text
8714 if (chat[chat.length - 1].extra.display_text) {
8715 delete chat[chat.length - 1].extra.display_text;
8716 }
8717
8718 delete chat[chat.length - 1].extra.image;
8719 delete chat[chat.length - 1].extra.image_swipes;
8720 delete chat[chat.length - 1].extra.video;
8721 delete chat[chat.length - 1].extra.inline_image;
8722 }
8723 if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) {
8724 chat[chat.length - 1]['swipe_info'] = [];
8725 }
8726 //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting
8727 if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length && (chat.length !== 1 || !isPristine)) {
8728 delete chat[chat.length - 1].gen_started;
8729 delete chat[chat.length - 1].gen_finished;
8730 run_generate = true;
8731 } else if (parseInt(chat[chat.length - 1]['swipe_id']) < chat[chat.length - 1]['swipes'].length) { //otherwise, if the id is less than the number of swipes
8732 chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; //load the last mes box with the latest generation
8733 chat[chat.length - 1]['send_date'] = chat[chat.length - 1]?.swipe_info[chat[chat.length - 1]['swipe_id']]?.send_date || chat[chat.length - 1]['send_date']; //update send date
8734 chat[chat.length - 1]['extra'] = structuredClone(chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.extra || chat[chat.length - 1].extra || []);
8735 run_swipe_right = true; //then prepare to do normal right swipe to show next message
8736 }
8737
8738 const currentMessage = $('#chat').children().filter(`[mesid="${chat.length - 1}"]`);
8739 let this_div = currentMessage.find('.swipe_right');
8740 let this_mes_div = this_div.parent().parent();
8741
8742 if (chat[chat.length - 1]['swipe_id'] > chat[chat.length - 1]['swipes'].length) { //if we swipe right while generating (the swipe ID is greater than what we are viewing now)
8743 chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length; //show that message slot (will be '...' while generating)
8744 }
8745 if (run_generate) { //hide swipe arrows while generating
8746 this_div.css('display', 'none');
8747 }
8748 // handles animated transitions when swipe right, specifically height transitions between messages
8749 if (run_generate || run_swipe_right) {
8750 let this_mes_block = this_mes_div.find('.mes_block .mes_text');
8751 const this_mes_div_height = this_mes_div[0].scrollHeight;
8752 const this_mes_block_height = this_mes_block[0].scrollHeight;
8753
8754 this_mes_div.children('.swipe_left').css('display', 'flex');
8755 this_mes_div.children('.mes_block').transition({ // this moves the div back and forth
8756 x: '-' + swipe_range,
8757 duration: animation_duration > 0 ? swipe_duration : 0,
8758 easing: animation_easing,
8759 queue: false,
8760 complete: async function () {
8761 const is_animation_scroll = (chatElement.scrollTop() >= (chatElement.prop('scrollHeight') - chatElement.outerHeight()) - 10);
8762 //console.log(parseInt(chat[chat.length-1]['swipe_id']));
8763 //console.log(chat[chat.length-1]['swipes'].length);
8764 const swipeMessage = chatElement.find('[mesid="' + (chat.length - 1) + '"]');
8765 if (run_generate && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) {
8766 //shows "..." while generating
8767 swipeMessage.find('.mes_text').html('...');
8768 // resets the timer
8769 swipeMessage.find('.mes_timer').html('');
8770 swipeMessage.find('.tokenCounterDisplay').text('');
8771 updateReasoningUI(swipeMessage, { reset: true });
8772 } else {
8773 //console.log('showing previously generated swipe candidate, or "..."');
8774 //console.log('onclick right swipe calling addOneMessage');
8775 addOneMessage(chat[chat.length - 1], { type: 'swipe' });
8776
8777 if (power_user.message_token_count_enabled) {
8778 if (!chat[chat.length - 1].extra) {
8779 chat[chat.length - 1].extra = {};
8780 }
87819567
8782 const tokenCountText = (chat[chat.length - 1]?.extra?.reasoning || '') + chat[chat.length - 1].mes;9568 //Minimum of zero.
8783 const tokenCount = await getTokenCountAsync(tokenCountText, 0);9569 if (newSwipeId < 0) {
8784 chat[chat.length - 1]['extra']['token_count'] = tokenCount;9570 toastr.warning(`The swipe_id for message #${mesId} was ${newSwipeId}. It has been reset to zero.`);
8785 swipeMessage.find('.tokenCounterDisplay').text(`${tokenCount}t`);9571 chat[mesId]['swipe_id'] = 0;
8786 }9572 await endSwipe();
8787 }9573 return;
8788 let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight);9574 }
8789 if (new_height < 103) new_height = 103;
87909575
9576 //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting.
9577 if (newSwipeId >= chat[mesId]['swipes'].length && ((chat.length !== 1 || !isPristine))) {
9578 newSwipeId = chat[mesId]['swipes'].length;
87919579
8792 this_mes_div.animate({ height: new_height + 'px' }, {9580 //Update the swipe_id.
8793 duration: 0, //used to be 1009581 chat[mesId]['swipe_id'] = newSwipeId;
8794 queue: false,
8795 progress: function () {
8796 // Scroll the chat down as the message expands
8797 if (is_animation_scroll) chatElement.scrollTop(chatElement[0].scrollHeight);
8798 },
8799 complete: function () {
8800 this_mes_div.css('height', 'auto');
8801 // Scroll the chat down to the bottom once the animation is complete
8802 if (is_animation_scroll) chatElement.scrollTop(chatElement[0].scrollHeight);
8803 },
8804 });
8805 this_mes_div.children('.mes_block').transition({
8806 x: swipe_range,
8807 duration: 0,
8808 easing: animation_easing,
8809 queue: false,
8810 complete: function () {
8811 this_mes_div.children('.mes_block').transition({
8812 x: '0px',
8813 duration: animation_duration > 0 ? swipe_duration : 0,
8814 easing: animation_easing,
8815 queue: false,
8816 complete: async function () {
8817 appendMediaToMessage(chat[chat.length - 1], swipeMessage);
8818 await eventSource.emit(event_types.MESSAGE_SWIPED, (chat.length - 1));
8819 if (run_generate && !is_send_press && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) {
8820 console.debug('caught here 2');
8821 is_send_press = true;
8822 await Generate('swipe');
8823 } else {
8824 if (parseInt(chat[chat.length - 1]['swipe_id']) !== chat[chat.length - 1]['swipes'].length) {
8825 saveChatDebounced();
8826 }
8827 }
8828 },
8829 });
8830 },
8831 });
8832 },
8833 });
8834 this_mes_div.children('.avatar').transition({ // moves avatar along with swipe
8835 x: '-' + swipe_range,
8836 duration: animation_duration > 0 ? swipe_duration : 0,
8837 easing: animation_easing,
8838 queue: false,
8839 complete: function () {
8840 this_mes_div.children('.avatar').transition({
8841 x: swipe_range,
8842 duration: 0,
8843 easing: animation_easing,
8844 queue: false,
8845 complete: function () {
8846 this_mes_div.children('.avatar').transition({
8847 x: '0px',
8848 duration: animation_duration > 0 ? swipe_duration : 0,
8849 easing: animation_easing,
8850 queue: false,
8851 complete: function () {
88529582
8853 },9583 //Cancel the generation if it's a user message or the first message in a pristine chat.
8854 });9584 if (chat[mesId].is_user || (mesId === 0 && isPristine)) {
8855 },9585 //Cancel swipe.
8856 });9586 chat[mesId]['swipe_id'] = originalSwipeId;
8857 },9587 await endSwipe();
8858 });9588 return;
9589 } else {
9590 //Generate.
9591 await loadFromSwipeId(mesId, newSwipeId);
9592 let run_generate = true;
9593 await animateSwipe(run_generate);
9594 await endSwipe();
9595 return;
9596 }
9597 }
9598 else {
9599 // if swipe_right is called on the last alternate greeting in pristine chats, loop back around
9600 if (chat.length === 1 && newSwipeId !== undefined && newSwipeId === chat[0]['swipes'].length && isPristine) {
9601 newSwipeId = 0;
9602 }
9603 }
9604 await standardSwipe();
9605 return;
8859 }9606 }
8860}9607}
88619608
8862/**9609/**
9610 * @deprecated Use `swipe` instead.
9611 * Handles the swipe to the left event.
9612 * @param {JQuery.Event} _event Event.
9613 * @param {object} params Additional parameters.
9614 * @param {string} [params.source] The source of the swipe event.
9615 * @param {boolean} [params.repeated] Is the swipe event repeated.
9616 * @param {object} [params.message] The chat message to swipe.
9617 */
9618export async function swipe_left(_event, { source, repeated, message } = {}) {
9619 await swipe.call(this, _event, SWIPE_DIRECTION.LEFT, { source: source, repeated: repeated, message: message });
9620}
9621
9622/**
9623 * @deprecated Use `swipe` instead.
9624 * Handles the swipe to the right event.
9625 * @param {JQuery.Event} [_event] Event.
9626 * @param {object} params Additional parameters.
9627 * @param {string} [params.source] The source of the swipe event.
9628 * @param {boolean} [params.repeated] Is the swipe event repeated.
9629 * @param {object} [params.message] The chat message to swipe.
9630 */
9631//MARK: swipe_right
9632export async function swipe_right(_event = null, { source, repeated, message } = {}) {
9633 await swipe.call(this, _event, SWIPE_DIRECTION.RIGHT, { source: source, repeated: repeated, message: message });
9634}
9635
9636/**
8863 * Imports supported files dropped into the app window.9637 * Imports supported files dropped into the app window.
8864 * @param {File[]} files Array of files to process9638 * @param {File[]} files Array of files to process
8865 * @param {Map<File, string>} [data] Extra data to pass to the import function9639 * @param {Map<File, string>} [data] Extra data to pass to the import function
@@ -8952,6 +9726,7 @@ async function importCharacter(file, { preserveFileName = '', importTags = false
8952 const formData = new FormData();9726 const formData = new FormData();
8953 formData.append('avatar', file);9727 formData.append('avatar', file);
8954 formData.append('file_type', format);9728 formData.append('file_type', format);
9729 formData.append('user_name', name1);
8955 if (preserveFileName) formData.append('preserved_name', preserveFileName);9730 if (preserveFileName) formData.append('preserved_name', preserveFileName);
89569731
8957 try {9732 try {
@@ -9543,8 +10318,8 @@ jQuery(async function () {
9543 ///// SWIPE BUTTON CLICKS ///////10318 ///// SWIPE BUTTON CLICKS ///////
954410319
9545 //limit swiping to only last message clicks10320 //limit swiping to only last message clicks
9546 $(document).on('click', '.last_mes .swipe_right', swipe_right);10321 $(document).on('click', '.last_mes .swipe_right', async (e, data) => await swipe(e, SWIPE_DIRECTION.RIGHT, data));
9547 $(document).on('click', '.last_mes .swipe_left', swipe_left);10322 $(document).on('click', '.last_mes .swipe_left', async (e, data) => await swipe(e, SWIPE_DIRECTION.LEFT, data));
954810323
9549 initCharacterSearch();10324 initCharacterSearch();
955010325
@@ -9556,8 +10331,9 @@ jQuery(async function () {
9556 $('#option_continue').trigger('click');10331 $('#option_continue').trigger('click');
9557 });10332 });
955810333
9559 $('#send_but').on('click', function () {10334 const userInputGenerateMutex = new SimpleMutex(sendTextareaMessage);
9560 sendTextareaMessage();10335 $('#send_but').on('click', async function () {
10336 await userInputGenerateMutex.update();
9561 });10337 });
956210338
9563 //menu buttons setup10339 //menu buttons setup
@@ -9970,7 +10746,7 @@ jQuery(async function () {
9970 if (!isMouseOverButtonOrMenu()) { hideMenu(); }10746 if (!isMouseOverButtonOrMenu()) { hideMenu(); }
9971 });10747 });
997210748
9973 /* $('#set_chat_scenario').on('click', setScenarioOverride); */10749 /* $('#set_chat_character_settings').on('click', setScenarioOverride); */
997410750
9975 ///////////// OPTIMIZED LISTENERS FOR LEFT SIDE OPTIONS POPUP MENU //////////////////////10751 ///////////// OPTIMIZED LISTENERS FOR LEFT SIDE OPTIONS POPUP MENU //////////////////////
9976 $('#options [id]').on('click', async function (event, customData) {10752 $('#options [id]').on('click', async function (event, customData) {
@@ -10046,7 +10822,7 @@ jQuery(async function () {
10046 }10822 }
1004710823
10048 else if (id == 'option_continue') {10824 else if (id == 'option_continue') {
10049 if (this_edit_mes_id) return; // don't proceed if editing a message10825 if (this_edit_mes_id >= 0) return; // don't proceed if editing a message
1005010826
10051 if (is_send_press == false || fromSlashCommand) {10827 if (is_send_press == false || fromSlashCommand) {
10052 is_send_press = true;10828 is_send_press = true;
@@ -10236,8 +11012,7 @@ jQuery(async function () {
10236 return;11012 return;
10237 }*/11013 }*/
1023811014
10239 let chatScrollPosition = chatElement.scrollTop();11015 if (this_edit_mes_id >= 0) {
10240 if (this_edit_mes_id !== undefined) {
10241 let mes_edited = chatElement.find(`[mesid="${this_edit_mes_id}"]`).find('.mes_edit_done');11016 let mes_edited = chatElement.find(`[mesid="${this_edit_mes_id}"]`).find('.mes_edit_done');
10242 if (Number(edit_mes_id) == chat.length - 1) { //if the generating swipe (...)11017 if (Number(edit_mes_id) == chat.length - 1) { //if the generating swipe (...)
10243 let run_edit = true;11018 let run_edit = true;
@@ -10252,55 +11027,9 @@ jQuery(async function () {
10252 }11027 }
10253 await messageEditDone(mes_edited);11028 await messageEditDone(mes_edited);
10254 }11029 }
10255 $(this).closest('.mes_block').find('.mes_text').empty();11030 var edit_mes_id = Number($(this).closest('.mes').attr('mesid'));
10256 $(this).closest('.mes_block').find('.mes_buttons').css('display', 'none');
10257 $(this).closest('.mes_block').find('.mes_edit_buttons').css('display', 'inline-flex');
10258 var edit_mes_id = $(this).closest('.mes').attr('mesid');
10259 this_edit_mes_id = edit_mes_id;
10260
10261 // Also edit reasoning, if it exists
10262 const reasoningEdit = $(this).closest('.mes_block').find('.mes_reasoning_edit:visible');
10263 if (reasoningEdit.length > 0) {
10264 reasoningEdit.trigger('click');
10265 }
10266
10267 var text = chat[edit_mes_id]['mes'];
10268 if (chat[edit_mes_id]['is_user']) {
10269 this_edit_mes_chname = name1;
10270 } else if (chat[edit_mes_id]['force_avatar']) {
10271 this_edit_mes_chname = chat[edit_mes_id]['name'];
10272 } else {
10273 this_edit_mes_chname = name2;
10274 }
10275 if (power_user.trim_spaces) {
10276 text = text.trim();
10277 }
10278 $(this)
10279 .closest('.mes_block')
10280 .find('.mes_text')
10281 .append(
10282 '<textarea id=\'curEditTextarea\' class=\'edit_textarea mdHotkeys\'></textarea>',
10283 );
10284 $('#curEditTextarea').val(text);
10285 let edit_textarea = $(this)
10286 .closest('.mes_block')
10287 .find('.edit_textarea');
10288 if (!cssAutofit) {
10289 edit_textarea.height(0);
10290 edit_textarea.height(edit_textarea[0].scrollHeight);
10291 }
10292 edit_textarea.trigger('focus');
10293 const textAreaElement = /** @type {HTMLTextAreaElement} */ (edit_textarea[0]);
10294 // Sets the cursor at the end of the text
10295 textAreaElement.setSelectionRange(
10296 String(edit_textarea.val()).length,
10297 String(edit_textarea.val()).length,
10298 );
10299 if (Number(this_edit_mes_id) === chat.length - 1) {
10300 chatElement.scrollTop(chatScrollPosition);
10301 }
1030211031
10303 updateEditArrowClasses();11032 await messageEdit(edit_mes_id);
10304 }11033 }
10305 });11034 });
1030611035
@@ -10379,91 +11108,24 @@ jQuery(async function () {
10379 });11108 });
1038011109
10381 $(document).on('click', '.mes_edit_cancel', async function () {11110 $(document).on('click', '.mes_edit_cancel', async function () {
10382 let text = chat[this_edit_mes_id]['mes'];11111 await messageEditCancel.call(this, this_edit_mes_id);
10383
10384 $(this).closest('.mes_block').find('.mes_text').empty();
10385 $(this).closest('.mes_edit_buttons').css('display', 'none');
10386 $(this).closest('.mes_block').find('.mes_buttons').css('display', '');
10387 $(this)
10388 .closest('.mes_block')
10389 .find('.mes_text')
10390 .append(messageFormatting(
10391 text,
10392 this_edit_mes_chname,
10393 chat[this_edit_mes_id].is_system,
10394 chat[this_edit_mes_id].is_user,
10395 this_edit_mes_id,
10396 {},
10397 false,
10398 ));
10399 appendMediaToMessage(chat[this_edit_mes_id], $(this).closest('.mes'));
10400 addCopyToCodeBlocks($(this).closest('.mes'));
10401
10402 const reasoningEditDone = $(this).closest('.mes_block').find('.mes_reasoning_edit_cancel:visible');
10403 if (reasoningEditDone.length > 0) {
10404 reasoningEditDone.trigger('click');
10405 }
10406
10407 await eventSource.emit(event_types.MESSAGE_UPDATED, this_edit_mes_id);
10408 this_edit_mes_id = undefined;
10409 });11112 });
1041011113
10411 $(document).on('click', '.mes_edit_up', async function () {11114 $(document).on('click', '.mes_edit_up', async function () {
10412 if (is_send_press || this_edit_mes_id <= 0) {11115 if (this_edit_mes_id <= 0) {
10413 return;11116 return;
10414 }11117 }
10415
10416 hideSwipeButtons();
10417 const targetId = Number(this_edit_mes_id) - 1;11118 const targetId = Number(this_edit_mes_id) - 1;
10418 const target = chatElement.find(`.mes[mesid="${targetId}"]`);11119 await messageEditMove(this_edit_mes_id, targetId);
10419 const root = $(this).closest('.mes');
10420
10421 if (root.length === 0 || target.length === 0) {
10422 return;
10423 }
10424
10425 root.insertBefore(target);
10426
10427 target.attr('mesid', this_edit_mes_id);
10428 root.attr('mesid', targetId);
10429
10430 const temp = chat[targetId];
10431 chat[targetId] = chat[this_edit_mes_id];
10432 chat[this_edit_mes_id] = temp;
10433
10434 this_edit_mes_id = targetId;
10435 updateViewMessageIds();
10436 await saveChatConditional();
10437 showSwipeButtons();
10438 });11120 });
1043911121
10440 $(document).on('click', '.mes_edit_down', async function () {11122 $(document).on('click', '.mes_edit_down', async function () {
10441 if (is_send_press || this_edit_mes_id >= chat.length - 1) {11123 if (this_edit_mes_id >= chat.length - 1) {
10442 return;11124 return;
10443 }11125 }
1044411126
10445 hideSwipeButtons();
10446 const targetId = Number(this_edit_mes_id) + 1;11127 const targetId = Number(this_edit_mes_id) + 1;
10447 const target = chatElement.find(`.mes[mesid="${targetId}"]`);11128 await messageEditMove(this_edit_mes_id, targetId);
10448 const root = $(this).closest('.mes');
10449
10450 if (root.length === 0 || target.length === 0) {
10451 return;
10452 }
10453
10454 root.insertAfter(target);
10455
10456 target.attr('mesid', this_edit_mes_id);
10457 root.attr('mesid', targetId);
10458
10459 const temp = chat[targetId];
10460 chat[targetId] = chat[this_edit_mes_id];
10461 chat[this_edit_mes_id] = temp;
10462
10463 this_edit_mes_id = targetId;
10464 updateViewMessageIds();
10465 await saveChatConditional();
10466 showSwipeButtons();
10467 });11129 });
1046811130
10469 $(document).on('click', '.mes_edit_copy', async function () {11131 $(document).on('click', '.mes_edit_copy', async function () {
@@ -10476,7 +11138,7 @@ jQuery(async function () {
10476 const oldScroll = chatElement[0].scrollTop;11138 const oldScroll = chatElement[0].scrollTop;
10477 const clone = structuredClone(chat[this_edit_mes_id]);11139 const clone = structuredClone(chat[this_edit_mes_id]);
10478 clone.send_date = Date.now();11140 clone.send_date = Date.now();
10479 clone.mes = $(this).closest('.mes').find('.edit_textarea').val();11141 clone.mes = $(this).closest('.mes').find('.edit_textarea').val().toString();
1048011142
10481 if (power_user.trim_spaces) {11143 if (power_user.trim_spaces) {
10482 clone.mes = clone.mes.trim();11144 clone.mes = clone.mes.trim();
@@ -10493,48 +11155,11 @@ jQuery(async function () {
1049311155
10494 $(document).on('click', '.mes_edit_delete', async function (event, customData) {11156 $(document).on('click', '.mes_edit_delete', async function (event, customData) {
10495 const fromSlashCommand = customData?.fromSlashCommand || false;11157 const fromSlashCommand = customData?.fromSlashCommand || false;
10496 const canDeleteSwipe = (Array.isArray(chat[this_edit_mes_id].swipes) && chat[this_edit_mes_id].swipes.length > 1 && !chat[this_edit_mes_id].is_user && parseInt(this_edit_mes_id) === chat.length - 1);11158 const message = chat[this_edit_mes_id];
1049711159 const selectedSwipe = message['swipe_id'] ?? undefined;
10498 let deleteOnlySwipe = false;11160 const swipesArray = Array.isArray(message['swipes']) ? message['swipes'] : [];
10499 if (power_user.confirm_message_delete && fromSlashCommand !== true) {11161 const canDeleteSwipe = !fromSlashCommand && !message.is_user && swipesArray.length > 1 && this_edit_mes_id === chat.length - 1 && selectedSwipe !== undefined;
10500 const result = await callGenericPopup(t`Are you sure you want to delete this message?`, POPUP_TYPE.CONFIRM, null, {11162 await deleteMessage(Number(this_edit_mes_id), canDeleteSwipe ? selectedSwipe : undefined, power_user.confirm_message_delete && fromSlashCommand !== true);
10501 okButton: canDeleteSwipe ? t`Delete Swipe` : t`Delete Message`,
10502 cancelButton: 'Cancel',
10503 customButtons: canDeleteSwipe ? [t`Delete Message`] : null,
10504 });
10505 if (!result) {
10506 return;
10507 }
10508 deleteOnlySwipe = canDeleteSwipe && result === 1; // Default button, not the custom one
10509 }
10510
10511 const messageElement = $(this).closest('.mes');
10512 if (!messageElement) {
10513 return;
10514 }
10515
10516 if (deleteOnlySwipe) {
10517 const message = chat[this_edit_mes_id];
10518 const swipe_id = message.swipe_id;
10519 await deleteSwipe(swipe_id, Number(this_edit_mes_id));
10520 return;
10521 }
10522
10523 chat.splice(this_edit_mes_id, 1);
10524 messageElement.remove();
10525
10526 let startFromZero = Number(this_edit_mes_id) === 0;
10527
10528 this_edit_mes_id = undefined;
10529 chat_metadata['tainted'] = true;
10530
10531 updateViewMessageIds(startFromZero);
10532 saveChatDebounced();
10533
10534 hideSwipeButtons();
10535 showSwipeButtons();
10536
10537 await eventSource.emit(event_types.MESSAGE_DELETED, chat.length);
10538 });11163 });
1053911164
10540 $(document).on('click', '.mes_edit_done', async function () {11165 $(document).on('click', '.mes_edit_done', async function () {
@@ -10872,8 +11497,8 @@ jQuery(async function () {
10872 }11497 }
10873 });11498 });
1087411499
10875 $(document).on('keyup', function (e) {11500 $(document).on('keydown', function (e) {
10876 if (e.key === 'Escape') {11501 if (e.key === 'Escape' && !e.originalEvent.isComposing) {
10877 const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0;11502 const isEditVisible = $('#curEditTextarea').is(':visible') || $('.reasoning_edit_textarea').length > 0;
10878 if (isEditVisible && power_user.auto_save_msg_edits === false) {11503 if (isEditVisible && power_user.auto_save_msg_edits === false) {
10879 closeMessageEditor('all');11504 closeMessageEditor('all');
@@ -10886,7 +11511,7 @@ jQuery(async function () {
10886 $('#send_textarea').trigger('focus');11511 $('#send_textarea').trigger('focus');
10887 return;11512 return;
10888 }11513 }
10889 if (!this_edit_mes_id && $('#mes_stop').is(':visible')) {11514 if (this_edit_mes_id === undefined && $('#mes_stop').is(':visible')) {
10890 $('#mes_stop').trigger('click');11515 $('#mes_stop').trigger('click');
10891 if (chat.length && Array.isArray(chat[chat.length - 1].swipes) && chat[chat.length - 1].swipe_id == chat[chat.length - 1].swipes.length) {11516 if (chat.length && Array.isArray(chat[chat.length - 1].swipes) && chat[chat.length - 1].swipe_id == chat[chat.length - 1].swipes.length) {
10892 $('.last_mes .swipe_left').trigger('click');11517 $('.last_mes .swipe_left').trigger('click');
@@ -10902,8 +11527,8 @@ jQuery(async function () {
10902 case 'set_character_world':11527 case 'set_character_world':
10903 await openCharacterWorldPopup();11528 await openCharacterWorldPopup();
10904 break;11529 break;
10905 case 'set_chat_scenario':11530 case 'set_chat_character_settings':
10906 await setScenarioOverride();11531 await setCharacterSettingsOverrides();
10907 break;11532 break;
10908 case 'renameCharButton':11533 case 'renameCharButton':
10909 await renameCharacter();11534 await renameCharacter();
@@ -11134,7 +11759,7 @@ jQuery(async function () {
11134 await firstLoadInit();11759 await firstLoadInit();
1113511760
11136 window.addEventListener('beforeunload', (e) => {11761 window.addEventListener('beforeunload', (e) => {
11137 if (isChatSaving) {11762 if (isChatSaving || this_edit_mes_id >= 0) {
11138 e.preventDefault();11763 e.preventDefault();
11139 e.returnValue = true;11764 e.returnValue = true;
11140 }11765 }
public/scripts/RossAscends-mods.js+5 -2
@@ -19,6 +19,7 @@ import {
19 substituteParams,19 substituteParams,
20 sendTextareaMessage,20 sendTextareaMessage,
21 doNavbarIconClick,21 doNavbarIconClick,
22 isSwipingAllowed,
22} from '../script.js';23} from '../script.js';
2324
24import {25import {
@@ -402,6 +403,7 @@ function RA_autoconnect(PrevApi) {
402 || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE)403 || (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE)
403 || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY)404 || (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY)
404 || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ)405 || (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ)
406 || (secret_state[SECRET_KEYS.SILICONFLOW] && oai_settings.chat_completion_source == chat_completion_sources.SILICONFLOW)
405 || (secret_state[SECRET_KEYS.ELECTRONHUB] && oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB)407 || (secret_state[SECRET_KEYS.ELECTRONHUB] && oai_settings.chat_completion_source == chat_completion_sources.ELECTRONHUB)
406 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)408 || (secret_state[SECRET_KEYS.NANOGPT] && oai_settings.chat_completion_source == chat_completion_sources.NANOGPT)
407 || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)409 || (secret_state[SECRET_KEYS.DEEPSEEK] && oai_settings.chat_completion_source == chat_completion_sources.DEEPSEEK)
@@ -410,6 +412,7 @@ function RA_autoconnect(PrevApi) {
410 || (secret_state[SECRET_KEYS.MOONSHOT] && oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT)412 || (secret_state[SECRET_KEYS.MOONSHOT] && oai_settings.chat_completion_source == chat_completion_sources.MOONSHOT)
411 || (secret_state[SECRET_KEYS.FIREWORKS] && oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS)413 || (secret_state[SECRET_KEYS.FIREWORKS] && oai_settings.chat_completion_source == chat_completion_sources.FIREWORKS)
412 || (secret_state[SECRET_KEYS.COMETAPI] && oai_settings.chat_completion_source == chat_completion_sources.COMETAPI)414 || (secret_state[SECRET_KEYS.COMETAPI] && oai_settings.chat_completion_source == chat_completion_sources.COMETAPI)
415 || (secret_state[SECRET_KEYS.ZAI] && oai_settings.chat_completion_source == chat_completion_sources.ZAI)
413 || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS)416 || (oai_settings.chat_completion_source === chat_completion_sources.POLLINATIONS)
414 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)417 || (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
415 || (secret_state[SECRET_KEYS.AZURE_OPENAI] && oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI)418 || (secret_state[SECRET_KEYS.AZURE_OPENAI] && oai_settings.chat_completion_source == chat_completion_sources.AZURE_OPENAI)
@@ -1109,8 +1112,8 @@ export function initRossMods() {
11091112
1110 if (event.key == 'ArrowLeft') { //swipes left1113 if (event.key == 'ArrowLeft') { //swipes left
1111 if (1114 if (
1115 isSwipingAllowed &&
1112 !isNanogallery2LightboxActive() && // Check if lightbox is NOT active1116 !isNanogallery2LightboxActive() && // Check if lightbox is NOT active
1113 $('.swipe_left:last').css('display') === 'flex' &&
1114 $('#send_textarea').val() === '' &&1117 $('#send_textarea').val() === '' &&
1115 $('#character_popup').css('display') === 'none' &&1118 $('#character_popup').css('display') === 'none' &&
1116 $('#shadow_select_chat_popup').css('display') === 'none' &&1119 $('#shadow_select_chat_popup').css('display') === 'none' &&
@@ -1123,8 +1126,8 @@ export function initRossMods() {
1123 }1126 }
1124 if (event.key == 'ArrowRight') { //swipes right1127 if (event.key == 'ArrowRight') { //swipes right
1125 if (1128 if (
1129 isSwipingAllowed &&
1126 !isNanogallery2LightboxActive() && // Check if lightbox is NOT active1130 !isNanogallery2LightboxActive() && // Check if lightbox is NOT active
1127 $('.swipe_right:last').css('display') === 'flex' &&
1128 $('#send_textarea').val() === '' &&1131 $('#send_textarea').val() === '' &&
1129 $('#character_popup').css('display') === 'none' &&1132 $('#character_popup').css('display') === 'none' &&
1130 $('#shadow_select_chat_popup').css('display') === 'none' &&1133 $('#shadow_select_chat_popup').css('display') === 'none' &&
public/scripts/audio-player.js+605 -0
@@ -0,0 +1,605 @@
1import { formatTime } from './utils.js';
2
3export class AudioPlayer {
4 /**
5 * Creates an audio player instance
6 * @param {HTMLElement} audioElement - The audio element to control
7 * @param {HTMLElement} containerElement - The container element with player controls
8 * @param {Object} options - Configuration options
9 */
10 constructor(audioElement, containerElement, options = {}) {
11 if (!(audioElement instanceof HTMLAudioElement)) {
12 throw new Error('First argument must be an HTMLAudioElement');
13 }
14 if (!(containerElement instanceof HTMLElement)) {
15 throw new Error('Second argument must be an HTMLElement');
16 }
17
18 this.audio = audioElement;
19 this.container = containerElement;
20 this.options = {
21 title: '',
22 autoplay: false,
23 volume: 1.0,
24 onPlay: null,
25 onPause: null,
26 onEnded: null,
27 onTimeUpdate: null,
28 onVolumeChange: null,
29 ...options,
30 };
31
32 this.isDragging = false;
33 this.isDestroyed = false;
34
35 // Store bound event handlers for cleanup
36 this.boundHandlers = {
37 // Audio event handlers
38 audioLoadedMetadata: this.onAudioLoadedMetadata.bind(this),
39 audioTimeUpdate: this.onAudioTimeUpdate.bind(this),
40 audioPlay: this.onAudioPlay.bind(this),
41 audioPause: this.onAudioPause.bind(this),
42 audioEnded: this.onAudioEnded.bind(this),
43 audioVolumeChange: this.onAudioVolumeChange.bind(this),
44 // Control event handlers
45 playPauseClick: this.onPlayPauseClick.bind(this),
46 volumeClick: this.onVolumeClick.bind(this),
47 volumeInput: this.onVolumeInput.bind(this),
48 progressMouseDown: this.onProgressMouseDown.bind(this),
49 progressClick: this.onProgressClick.bind(this),
50 progressMouseMove: this.onProgressMouseMove.bind(this),
51 documentMouseMove: this.onDocumentMouseMove.bind(this),
52 documentMouseUp: this.onDocumentMouseUp.bind(this),
53 };
54
55 // MutationObserver for DOM cleanup detection
56 this.observer = null;
57
58 this.init();
59 }
60
61 /**
62 * Initializes the audio player by setting up elements, events, and initial state
63 * @returns {void}
64 */
65 init() {
66 this.findElements();
67 this.bindEvents();
68 this.setupDOMObserver();
69
70 if (this.options.title) {
71 this.setTitle(this.options.title);
72 } else if (this.audio.title) {
73 this.setTitle(this.audio.title);
74 } else if (this.audio.src) {
75 const srcParts = this.audio.src.split('/');
76 this.setTitle(decodeURIComponent(srcParts[srcParts.length - 1]));
77 }
78
79 if (this.options.autoplay) {
80 this.play();
81 }
82
83 this.setVolume(this.options.volume);
84
85 // Initialize time displays
86 this.updateTimeDisplays();
87 }
88
89 /**
90 * Finds and caches all required DOM elements within the container
91 * @returns {void}
92 */
93 findElements() {
94 this.elements = {
95 title: this.container.querySelector('.audio-player-title'),
96 playPauseBtn: this.container.querySelector('.audio-player-play-pause'),
97 currentTime: this.container.querySelector('.audio-player-current-time'),
98 totalTime: this.container.querySelector('.audio-player-total-time'),
99 progress: this.container.querySelector('.audio-player-progress'),
100 progressBar: this.container.querySelector('.audio-player-progress-bar'),
101 volumeBtn: this.container.querySelector('.audio-player-volume'),
102 };
103
104 // Validate required elements
105 const requiredElements = ['playPauseBtn', 'currentTime', 'totalTime', 'progress', 'progressBar', 'volumeBtn'];
106 for (const key of requiredElements) {
107 if (!this.elements[key]) {
108 console.warn(`AudioPlayer: Required element .audio-player-${key.replace(/([A-Z])/g, '-$1').toLowerCase()} not found`);
109 }
110 }
111 }
112
113 /**
114 * Sets up a MutationObserver to detect when audio or container elements are removed from DOM
115 * @returns {void}
116 */
117 setupDOMObserver() {
118 // Watch for removal of audio or container from DOM
119 this.observer = new MutationObserver((mutations) => {
120 for (const mutation of mutations) {
121 for (const node of mutation.removedNodes) {
122 if (node === this.audio || node === this.container ||
123 node.contains?.(this.audio) || node.contains?.(this.container)) {
124 this.destroy();
125 return;
126 }
127 }
128 }
129 });
130
131 // Observe the parent nodes
132 const chatParent = this.audio.closest('#chat') ?? document.body;
133
134 if (chatParent) {
135 this.observer.observe(chatParent, { childList: true, subtree: true });
136 }
137 }
138
139 /**
140 * Binds all event listeners to audio and control elements
141 * @returns {void}
142 */
143 bindEvents() {
144 // Audio events
145 this.audio.addEventListener('loadedmetadata', this.boundHandlers.audioLoadedMetadata);
146 this.audio.addEventListener('timeupdate', this.boundHandlers.audioTimeUpdate);
147 this.audio.addEventListener('play', this.boundHandlers.audioPlay);
148 this.audio.addEventListener('pause', this.boundHandlers.audioPause);
149 this.audio.addEventListener('ended', this.boundHandlers.audioEnded);
150 this.audio.addEventListener('volumechange', this.boundHandlers.audioVolumeChange);
151
152 // Control events
153 if (this.elements.playPauseBtn) {
154 this.elements.playPauseBtn.addEventListener('click', this.boundHandlers.playPauseClick);
155 }
156 if (this.elements.volumeBtn) {
157 this.elements.volumeBtn.addEventListener('click', this.boundHandlers.volumeClick);
158 }
159 if (this.elements.progress) {
160 this.elements.progress.addEventListener('mousedown', this.boundHandlers.progressMouseDown);
161 this.elements.progress.addEventListener('click', this.boundHandlers.progressClick);
162 this.elements.progress.addEventListener('mousemove', this.boundHandlers.progressMouseMove);
163 }
164 }
165
166 /**
167 * Removes all event listeners from audio and control elements
168 * @returns {void}
169 */
170 unbindEvents() {
171 // Audio events
172 this.audio.removeEventListener('loadedmetadata', this.boundHandlers.audioLoadedMetadata);
173 this.audio.removeEventListener('timeupdate', this.boundHandlers.audioTimeUpdate);
174 this.audio.removeEventListener('play', this.boundHandlers.audioPlay);
175 this.audio.removeEventListener('pause', this.boundHandlers.audioPause);
176 this.audio.removeEventListener('ended', this.boundHandlers.audioEnded);
177 this.audio.removeEventListener('volumechange', this.boundHandlers.audioVolumeChange);
178
179 // Control events
180 if (this.elements.playPauseBtn) {
181 this.elements.playPauseBtn.removeEventListener('click', this.boundHandlers.playPauseClick);
182 }
183 if (this.elements.volumeBtn) {
184 this.elements.volumeBtn.removeEventListener('click', this.boundHandlers.volumeClick);
185 }
186 if (this.elements.progress) {
187 this.elements.progress.removeEventListener('mousedown', this.boundHandlers.progressMouseDown);
188 this.elements.progress.removeEventListener('click', this.boundHandlers.progressClick);
189 this.elements.progress.removeEventListener('mousemove', this.boundHandlers.progressMouseMove);
190 }
191
192 // Document events
193 document.removeEventListener('mousemove', this.boundHandlers.documentMouseMove);
194 document.removeEventListener('mouseup', this.boundHandlers.documentMouseUp);
195 }
196
197 // Audio event handlers
198 /**
199 * Handles the audio element's loadedmetadata event
200 * @returns {void}
201 */
202 onAudioLoadedMetadata() {
203 if (this.isDestroyed) return;
204 this.updateTimeDisplays();
205 }
206
207 /**
208 * Handles the audio element's timeupdate event
209 * @returns {void}
210 */
211 onAudioTimeUpdate() {
212 if (this.isDestroyed || this.isDragging) return;
213
214 const percent = (this.audio.currentTime / this.audio.duration) * 100 || 0;
215 if (this.elements.progressBar) {
216 /** @type {HTMLElement} */ (this.elements.progressBar).style.width = percent + '%';
217 }
218 if (this.elements.currentTime) {
219 this.elements.currentTime.textContent = formatTime(this.audio.currentTime);
220 }
221
222 if (typeof this.options.onTimeUpdate === 'function') {
223 this.options.onTimeUpdate.call(this, this.audio.currentTime, this.audio.duration);
224 }
225 }
226
227 /**
228 * Handles the audio element's play event
229 * @returns {void}
230 */
231 onAudioPlay() {
232 if (this.isDestroyed) return;
233
234 if (this.elements.playPauseBtn) {
235 this.elements.playPauseBtn.classList.remove('fa-play');
236 this.elements.playPauseBtn.classList.add('fa-pause');
237 this.elements.playPauseBtn.setAttribute('title', 'Pause');
238 }
239
240 if (typeof this.options.onPlay === 'function') {
241 this.options.onPlay.call(this);
242 }
243 }
244
245 /**
246 * Handles the audio element's pause event
247 * @returns {void}
248 */
249 onAudioPause() {
250 if (this.isDestroyed) return;
251
252 if (this.elements.playPauseBtn) {
253 this.elements.playPauseBtn.classList.remove('fa-pause');
254 this.elements.playPauseBtn.classList.add('fa-play');
255 this.elements.playPauseBtn.setAttribute('title', 'Play');
256 }
257
258 if (typeof this.options.onPause === 'function') {
259 this.options.onPause.call(this);
260 }
261 }
262
263 /**
264 * Handles the audio element's ended event
265 * @returns {void}
266 */
267 onAudioEnded() {
268 if (this.isDestroyed) return;
269
270 if (this.elements.playPauseBtn) {
271 this.elements.playPauseBtn.classList.remove('fa-pause');
272 this.elements.playPauseBtn.classList.add('fa-play');
273 this.elements.playPauseBtn.setAttribute('title', 'Play');
274 }
275
276 if (typeof this.options.onEnded === 'function') {
277 this.options.onEnded.call(this);
278 }
279 }
280
281 /**
282 * Handles the audio element's volumechange event
283 * @returns {void}
284 */
285 onAudioVolumeChange() {
286 if (this.isDestroyed) return;
287
288 this.updateVolumeIcon();
289
290 if (typeof this.options.onVolumeChange === 'function') {
291 this.options.onVolumeChange.call(this, this.audio.volume, this.audio.muted);
292 }
293 }
294
295 // Control event handlers
296 /**
297 * Handles click events on the play/pause button
298 * @param {MouseEvent} e - The click event
299 * @returns {void}
300 */
301 onPlayPauseClick(e) {
302 e.preventDefault();
303 this.togglePlay();
304 }
305
306 /**
307 * Handles click events on the volume button
308 * @param {MouseEvent} e - The click event
309 * @returns {void}
310 */
311 onVolumeClick(e) {
312 e.preventDefault();
313 this.toggleMute();
314 }
315
316 /**
317 * Handles input events on the volume slider
318 * @param {InputEvent} e - The input event
319 * @returns {void}
320 */
321 onVolumeInput(e) {
322 if (!(e.target instanceof HTMLInputElement)) return;
323 const value = parseFloat(e.target.value);
324 this.setVolume(value);
325 }
326
327 /**
328 * Handles mousedown events on the progress bar
329 * @param {MouseEvent} e - The mousedown event
330 * @returns {void}
331 */
332 onProgressMouseDown(e) {
333 this.isDragging = true;
334 this.updateProgress(e);
335 document.addEventListener('mousemove', this.boundHandlers.documentMouseMove);
336 document.addEventListener('mouseup', this.boundHandlers.documentMouseUp);
337 }
338
339 /**
340 * Handles click events on the progress bar
341 * @param {MouseEvent} e - The click event
342 * @returns {void}
343 */
344 onProgressClick(e) {
345 if (!this.isDragging) {
346 this.updateProgress(e);
347 }
348 }
349
350 /**
351 * Handles mousemove on the progress bar (no-op if dragging)
352 * @param {MouseEvent} e - The mousemove event
353 * @returns {void}
354 */
355 onProgressMouseMove(e) {
356 if (!this.isDragging) {
357 this.updateProgressTitle(e);
358 }
359 }
360
361 /**
362 * Handles document mousemove events during progress bar dragging
363 * @param {MouseEvent} e - The mousemove event
364 * @returns {void}
365 */
366 onDocumentMouseMove(e) {
367 if (this.isDragging) {
368 this.updateProgress(e);
369 }
370 }
371
372 /**
373 * Handles document mouseup events to end progress bar dragging
374 * @returns {void}
375 */
376 onDocumentMouseUp() {
377 if (this.isDragging) {
378 this.isDragging = false;
379 document.removeEventListener('mousemove', this.boundHandlers.documentMouseMove);
380 document.removeEventListener('mouseup', this.boundHandlers.documentMouseUp);
381 }
382 }
383
384 /**
385 * Updates the progress bar position and seeks audio based on mouse position
386 * @param {MouseEvent} e - The mouse event containing position information
387 * @returns {void}
388 */
389 updateProgress(e) {
390 if (!this.elements.progress) return;
391
392 const rect = this.elements.progress.getBoundingClientRect();
393 const offsetX = e.clientX - rect.left;
394 const width = rect.width;
395 const percent = Math.max(0, Math.min(100, (offsetX / width) * 100));
396
397 if (this.elements.progressBar) {
398 /** @type {HTMLElement} */ (this.elements.progressBar).style.width = percent + '%';
399 }
400
401 const seekTime = (percent / 100) * this.audio.duration;
402 if (isFinite(seekTime)) {
403 this.audio.currentTime = seekTime;
404 if (this.elements.currentTime) {
405 this.elements.currentTime.textContent = formatTime(seekTime);
406 }
407 }
408 }
409
410 /**
411 * Updates the volume icon based on current volume and mute state
412 * @returns {void}
413 */
414 updateVolumeIcon() {
415 if (!this.elements.volumeBtn) return;
416
417 const volume = this.audio.volume;
418 const isMuted = this.audio.muted;
419
420 this.elements.volumeBtn.classList.remove('fa-volume-high', 'fa-volume-low', 'fa-volume-off', 'fa-volume-xmark');
421
422 if (isMuted || volume === 0) {
423 this.elements.volumeBtn.classList.add('fa-volume-xmark');
424 } else if (volume < 0.5) {
425 this.elements.volumeBtn.classList.add('fa-volume-low');
426 } else {
427 this.elements.volumeBtn.classList.add('fa-volume-high');
428 }
429 }
430
431 /**
432 * Updates the current time and total time display elements
433 * @returns {void}
434 */
435 updateTimeDisplays() {
436 if (this.elements.currentTime) {
437 this.elements.currentTime.textContent = formatTime(this.audio.currentTime || 0);
438 }
439 if (this.elements.totalTime) {
440 this.elements.totalTime.textContent = formatTime(this.audio.duration || 0);
441 }
442 }
443
444 /**
445 * Updates the mouseover title on the progress bar to show time at cursor position
446 * @param {MouseEvent} e - The mouse event
447 * @returns {void}
448 */
449 updateProgressTitle(e) {
450 if (!this.elements.progress) return;
451
452 const rect = this.elements.progress.getBoundingClientRect();
453 const offsetX = e.clientX - rect.left;
454 const width = rect.width;
455 const percent = Math.max(0, Math.min(100, (offsetX / width) * 100));
456
457 this.elements.progress.setAttribute('title', formatTime((percent / 100) * this.audio.duration));
458 }
459
460 // Public methods
461 /**
462 * Starts audio playback
463 * @returns {void}
464 */
465 play() {
466 if (this.isDestroyed) return;
467 if (this.audio.paused) {
468 const playPromise = this.audio.play();
469 if (playPromise !== undefined) {
470 playPromise.catch(error => {
471 console.error('Audio play failed:', error);
472 });
473 }
474 }
475 }
476
477 /**
478 * Pauses audio playback
479 * @returns {void}
480 */
481 pause() {
482 if (this.isDestroyed) return;
483 if (!this.audio.paused) {
484 this.audio.pause();
485 }
486 }
487
488 /**
489 * Toggles between play and pause states
490 * @returns {void}
491 */
492 togglePlay() {
493 if (this.audio.paused) {
494 this.play();
495 } else {
496 this.pause();
497 }
498 }
499
500 /**
501 * Seeks to a specific time in the audio
502 * @param {number} time - The time in seconds to seek to
503 * @returns {void}
504 */
505 seek(time) {
506 if (this.isDestroyed) return;
507 if (isFinite(time) && time >= 0 && time <= this.audio.duration) {
508 this.audio.currentTime = time;
509 }
510 }
511
512 /**
513 * Sets the volume level
514 * @param {number} volume - Volume level between 0.0 and 1.0
515 * @returns {void}
516 */
517 setVolume(volume) {
518 if (this.isDestroyed) return;
519 volume = Math.max(0, Math.min(1, volume));
520 this.audio.volume = volume;
521
522 if (volume > 0 && this.audio.muted) {
523 this.audio.muted = false;
524 }
525 }
526
527 /**
528 * Mutes the audio
529 * @returns {void}
530 */
531 mute() {
532 if (this.isDestroyed) return;
533 this.audio.muted = true;
534 }
535
536 /**
537 * Unmutes the audio
538 * @returns {void}
539 */
540 unmute() {
541 if (this.isDestroyed) return;
542 this.audio.muted = false;
543 }
544
545 /**
546 * Toggles the mute state
547 * @returns {void}
548 */
549 toggleMute() {
550 if (this.isDestroyed) return;
551 this.audio.muted = !this.audio.muted;
552 }
553
554 /**
555 * Sets the audio source URL
556 * @param {string} src - The URL of the audio file
557 * @returns {void}
558 */
559 setSrc(src) {
560 if (this.isDestroyed) return;
561 this.audio.src = src;
562 }
563
564 /**
565 * Sets the title displayed in the player
566 * @param {string} title - The title text to display
567 * @returns {void}
568 */
569 setTitle(title) {
570 if (this.isDestroyed) return;
571 this.options.title = title;
572 if (this.elements.title) {
573 this.elements.title.textContent = title;
574 }
575 }
576
577 /**
578 * Cleans up the player by removing event listeners and clearing references
579 * @returns {void}
580 */
581 destroy() {
582 if (this.isDestroyed) return;
583 this.isDestroyed = true;
584
585 // Stop observing DOM changes
586 if (this.observer) {
587 this.observer.disconnect();
588 this.observer = null;
589 }
590
591 // Pause and clear audio
592 this.pause();
593 this.audio.src = '';
594
595 // Remove all event listeners
596 this.unbindEvents();
597
598 // Clear references to prevent memory leaks
599 this.audio = null;
600 this.container = null;
601 this.elements = null;
602 this.options = null;
603 this.boundHandlers = null;
604 }
605}
public/scripts/bookmarks.js+1 -0
@@ -344,6 +344,7 @@ export async function convertSoloToGroupChat() {
344344
345 // Save group-chat marker345 // Save group-chat marker
346 if (index == 0) {346 if (index == 0) {
347 // @ts-ignore
347 message.is_group = true;348 message.is_group = true;
348 }349 }
349350
public/scripts/chats.js+250 -124
@@ -10,12 +10,10 @@ import {
10 event_types,10 event_types,
11 getCurrentChatId,11 getCurrentChatId,
12 getRequestHeaders,12 getRequestHeaders,
13 hideSwipeButtons,
14 name1,13 name1,
15 name2,14 name2,
16 reloadCurrentChat,15 reloadCurrentChat,
17 saveSettingsDebounced,16 saveSettingsDebounced,
18 showSwipeButtons,
19 this_chid,17 this_chid,
20 saveChatConditional,18 saveChatConditional,
21 chat_metadata,19 chat_metadata,
@@ -27,6 +25,10 @@ import {
27 getSystemMessageByType,25 getSystemMessageByType,
28 printMessages,26 printMessages,
29 clearChat,27 clearChat,
28 refreshSwipeButtons,
29 getMediaIndex,
30 getMediaDisplay,
31 chatElement,
30} from '../script.js';32} from '../script.js';
31import { selected_group } from './group-chats.js';33import { selected_group } from './group-chats.js';
32import { power_user } from './power-user.js';34import { power_user } from './power-user.js';
@@ -44,6 +46,8 @@ import {
44 getFileText,46 getFileText,
45 getFileExtension,47 getFileExtension,
46 convertTextToBase64,48 convertTextToBase64,
49 isSameFile,
50 clamp,
47} from './utils.js';51} from './utils.js';
48import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js';52import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js';
49import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';53import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
@@ -53,6 +57,7 @@ import { renderTemplateAsync } from './templates.js';
53import { t } from './i18n.js';57import { t } from './i18n.js';
54import { humanizedDateTime } from './RossAscends-mods.js';58import { humanizedDateTime } from './RossAscends-mods.js';
55import { accountStorage } from './util/AccountStorage.js';59import { accountStorage } from './util/AccountStorage.js';
60import { MEDIA_DISPLAY, MEDIA_SOURCE, MEDIA_TYPE, SCROLL_BEHAVIOR, SWIPE_DIRECTION } from './constants.js';
5661
57/**62/**
58 * @typedef {Object} FileAttachment63 * @typedef {Object} FileAttachment
@@ -159,8 +164,7 @@ export async function hideChatMessageRange(start, end, unhide, nameFitler = null
159 }164 }
160165
161 // Reload swipes. Useful when a last message is hidden.166 // Reload swipes. Useful when a last message is hidden.
162 hideSwipeButtons();167 refreshSwipeButtons();
163 showSwipeButtons();
164168
165 await saveChatConditional();169 await saveChatConditional();
166}170}
@@ -189,62 +193,71 @@ export async function unhideChatMessage(messageId, _messageBlock) {
189193
190/**194/**
191 * Adds a file attachment to the message.195 * Adds a file attachment to the message.
192 * @param {object} message Message object196 * @param {ChatMessage} message Message object
193 * @returns {Promise<void>} A promise that resolves when file is uploaded.197 * @returns {Promise<void>} A promise that resolves when file is uploaded.
194 */198 */
195export async function populateFileAttachment(message, inputId = 'file_form_input') {199export async function populateFileAttachment(message, inputId = 'file_form_input') {
196 try {200 try {
197 if (!message) return;201 if (!message) return;
198 if (!message.extra) message.extra = {};202 if (!message.extra || typeof message.extra !== 'object') message.extra = {};
199 const fileInput = document.getElementById(inputId);203 const fileInput = document.getElementById(inputId);
200 if (!(fileInput instanceof HTMLInputElement)) return;204 if (!(fileInput instanceof HTMLInputElement)) return;
201 const file = fileInput.files[0];205
202 if (!file) return;206 for (const file of fileInput.files) {
203207 const slug = getStringHash(file.name);
204 const slug = getStringHash(file.name);208 const fileNamePrefix = `${Date.now()}_${slug}`;
205 const fileNamePrefix = `${Date.now()}_${slug}`;209 const fileBase64 = await getBase64Async(file);
206 const fileBase64 = await getBase64Async(file);210 let base64Data = fileBase64.split(',')[1];
207 let base64Data = fileBase64.split(',')[1];211 const extension = getFileExtension(file);
208 const extension = getFileExtension(file);212
209213 const mediaType = MEDIA_TYPE.getFromMime(file.type);
210 // If file is image214 if (mediaType) {
211 if (file.type.startsWith('image/')) {215 const imageUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension);
212 const imageUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension);216 if (!Array.isArray(message.extra.media)) {
213 message.extra.image = imageUrl;217 message.extra.media = [];
214 message.extra.inline_image = true;218 }
215 }219 /** @type {MediaAttachment} */
216 // If file is video220 const mediaAttachment = {
217 else if (file.type.startsWith('video/')) {221 url: imageUrl,
218 const videoUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension);222 type: mediaType,
219 message.extra.video = videoUrl;223 title: file.name,
220 } else {224 source: MEDIA_SOURCE.UPLOAD,
221 const uniqueFileName = `${fileNamePrefix}.txt`;225 };
222226 message.extra.media.push(mediaAttachment);
223 if (isConvertible(file.type)) {227 message.extra.media_index = message.extra.media.length - 1;
224 try {228 message.extra.inline_image = true;
225 const converter = getConverter(file.type);229 } else {
226 const fileText = await converter(file);230 const uniqueFileName = `${fileNamePrefix}.txt`;
227 base64Data = convertTextToBase64(fileText);231
228 } catch (error) {232 if (isConvertible(file.type)) {
229 toastr.error(String(error), t`Could not convert file`);233 try {
230 console.error('Could not convert file', error);234 const converter = getConverter(file.type);
235 const fileText = await converter(file);
236 base64Data = convertTextToBase64(fileText);
237 } catch (error) {
238 toastr.error(String(error), t`Could not convert file`);
239 console.error('Could not convert file', error);
240 }
231 }241 }
232 }
233242
234 const fileUrl = await uploadFileAttachment(uniqueFileName, base64Data);243 const fileUrl = await uploadFileAttachment(uniqueFileName, base64Data);
235244
236 if (!fileUrl) {245 if (!fileUrl) {
237 return;246 continue;
238 }247 }
239248
240 message.extra.file = {249 if (!Array.isArray(message.extra.files)) {
241 url: fileUrl,250 message.extra.files = [];
242 size: file.size,251 }
243 name: file.name,
244 created: Date.now(),
245 };
246 }
247252
253 message.extra.files.push({
254 url: fileUrl,
255 size: file.size,
256 name: file.name,
257 created: Date.now(),
258 });
259 }
260 }
248 } catch (error) {261 } catch (error) {
249 console.error('Could not upload file', error);262 console.error('Could not upload file', error);
250 toastr.error(t`Either the file is corrupted or its format is not supported.`, t`Could not upload the file`);263 toastr.error(t`Either the file is corrupted or its format is not supported.`, t`Could not upload the file`);
@@ -316,16 +329,16 @@ export async function getFileAttachment(url) {
316 */329 */
317async function validateFile(file) {330async function validateFile(file) {
318 const fileText = await file.text();331 const fileText = await file.text();
319 const isImage = file.type.startsWith('image/');332 const isMedia = file.type.startsWith('image/') || file.type.startsWith('video/') || file.type.startsWith('audio/');
320 const isBinary = /^[\x00-\x08\x0E-\x1F\x7F-\xFF]*$/.test(fileText);333 const isBinary = /^[\x00-\x08\x0E-\x1F\x7F-\xFF]*$/.test(fileText);
321334
322 if (!isImage && file.size > fileSizeLimit) {335 if (!isMedia && file.size > fileSizeLimit) {
323 toastr.error(t`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`);336 toastr.error(t`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`);
324 return false;337 return false;
325 }338 }
326339
327 // If file is binary340 // If file is binary
328 if (isBinary && !isImage && !isConvertible(file.type)) {341 if (isBinary && !isMedia && !isConvertible(file.type)) {
329 toastr.error(t`Binary files are not supported. Select a text file or image.`);342 toastr.error(t`Binary files are not supported. Select a text file or image.`);
330 return false;343 return false;
331 }344 }
@@ -342,22 +355,28 @@ export function hasPendingFileAttachment() {
342355
343/**356/**
344 * Displays file information in the message sending form.357 * Displays file information in the message sending form.
345 * @param {File} file File object358 * @param {FileList} fileList File object
346 * @returns {Promise<void>}359 * @returns {Promise<void>}
347 */360 */
348async function onFileAttach(file) {361async function onFileAttach(fileList) {
349 if (!file) return;362 if (!fileList || fileList.length === 0) return;
350363
351 const isValid = await validateFile(file);364 for (const file of fileList) {
365 const isValid = await validateFile(file);
352366
353 // If file is binary367 // If file is binary
354 if (!isValid) {368 if (!isValid) {
355 $('#file_form').trigger('reset');369 toastr.warning(t`File ${file.name} is not supported.`);
356 return;370 $('#file_form').trigger('reset');
371 return;
372 }
357 }373 }
358374
359 $('#file_form .file_name').text(file.name);375 const name = fileList.length === 1 ? fileList[0].name : t`${fileList.length} files selected`;
360 $('#file_form .file_size').text(humanFileSize(file.size));376 const size = [...fileList].reduce((acc, file) => acc + file.size, 0);
377 const title = [...fileList].map(x => x.name).join('\n');
378 $('#file_form .file_name').text(name).attr('title', title);
379 $('#file_form .file_size').text(humanFileSize(size)).attr('title', size);
361 $('#file_form').removeClass('displayNone');380 $('#file_form').removeClass('displayNone');
362381
363 // Reset form on chat change (if not on a welcome screen)382 // Reset form on chat change (if not on a welcome screen)
@@ -370,10 +389,17 @@ async function onFileAttach(file) {
370}389}
371390
372/**391/**
373 * Deletes file from message.392 * Deletes file from a message.
393 * @param {JQuery<HTMLElement>} messageBlock Message block element
374 * @param {number} messageId Message ID394 * @param {number} messageId Message ID
395 * @param {number} fileIndex File index
375 */396 */
376async function deleteMessageFile(messageId) {397async function deleteMessageFile(messageBlock, messageId, fileIndex) {
398 if (isNaN(messageId) || isNaN(fileIndex)) {
399 console.warn('Invalid message ID or file index');
400 return;
401 }
402
377 const confirm = await callGenericPopup('Are you sure you want to delete this file?', POPUP_TYPE.CONFIRM);403 const confirm = await callGenericPopup('Are you sure you want to delete this file?', POPUP_TYPE.CONFIRM);
378404
379 if (confirm !== POPUP_RESULT.AFFIRMATIVE) {405 if (confirm !== POPUP_RESULT.AFFIRMATIVE) {
@@ -383,26 +409,49 @@ async function deleteMessageFile(messageId) {
383409
384 const message = chat[messageId];410 const message = chat[messageId];
385411
386 if (!message?.extra?.file) {412 if (!Array.isArray(message?.extra?.files)) {
387 console.debug('Message has no file');413 console.debug('Message has no files');
414 return;
415 }
416
417 if (fileIndex < 0 || fileIndex >= message.extra.files.length) {
418 console.warn('Invalid file index for message');
388 return;419 return;
389 }420 }
390421
391 const url = message.extra.file.url;422 const url = message.extra.files[fileIndex]?.url;
423 message.extra.files.splice(fileIndex, 1);
392424
393 delete message.extra.file;
394 $(`.mes[mesid="${messageId}"] .mes_file_container`).remove();
395 await saveChatConditional();425 await saveChatConditional();
396 await deleteFileFromServer(url);426 await deleteFileFromServer(url);
397}
398427
428 appendMediaToMessage(message, messageBlock, SCROLL_BEHAVIOR.KEEP);
429}
399430
400/**431/**
401 * Opens file from message in a modal.432 * Opens file from message in a modal.
402 * @param {number} messageId Message ID433 * @param {number} messageId Message ID
434 * @param {number} fileIndex File index
403 */435 */
404async function viewMessageFile(messageId) {436async function viewMessageFile(messageId, fileIndex) {
405 const messageFile = chat[messageId]?.extra?.file;437 if (isNaN(messageId) || isNaN(fileIndex)) {
438 console.warn('Invalid message ID or file index');
439 return;
440 }
441
442 const message = chat[messageId];
443
444 if (!Array.isArray(message?.extra?.files)) {
445 console.debug('Message has no files');
446 return;
447 }
448
449 if (fileIndex < 0 || fileIndex >= message.extra.files.length) {
450 console.warn('Invalid file index for message');
451 return;
452 }
453
454 const messageFile = message.extra.files[fileIndex];
406455
407 if (!messageFile) {456 if (!messageFile) {
408 console.debug('Message has no file or it is empty');457 console.debug('Message has no file or it is empty');
@@ -431,39 +480,51 @@ function embedMessageFile(messageId, messageBlock) {
431 .on('change', parseAndUploadEmbed)480 .on('change', parseAndUploadEmbed)
432 .trigger('click');481 .trigger('click');
433482
434 async function parseAndUploadEmbed(e) {483 async function parseAndUploadEmbed(/** @type {JQuery.ChangeEvent} */ e) {
435 const file = e.target.files[0];484 if (!(e.target instanceof HTMLInputElement)) return;
436 if (!file) return;485 if (!e.target.files.length) return;
437486
438 const isValid = await validateFile(file);487 for (const file of e.target.files) {
488 const isValid = await validateFile(file);
439489
440 if (!isValid) {490 if (!isValid) {
441 $('#file_form').trigger('reset');491 toastr.warning(t`File ${file.name} is not supported.`);
442 return;492 $('#file_form').trigger('reset');
493 return;
494 }
443 }495 }
444496
445 await populateFileAttachment(message, 'embed_file_input');497 await populateFileAttachment(message, 'embed_file_input');
446 await eventSource.emit(event_types.MESSAGE_FILE_EMBEDDED, messageId);498 await eventSource.emit(event_types.MESSAGE_FILE_EMBEDDED, messageId);
447 appendMediaToMessage(message, messageBlock);499 appendMediaToMessage(message, messageBlock, SCROLL_BEHAVIOR.KEEP);
448 await saveChatConditional();500 await saveChatConditional();
449 }501 }
450}502}
451503
452/**504/**
453 * Appends file content to the message text.505 * Appends file content to the message text.
454 * @param {object} message Message object506 * @param {ChatMessage} message Message object
455 * @param {string} messageText Message text507 * @param {string} messageText Message text
456 * @returns {Promise<string>} Message text with file content appended.508 * @returns {Promise<string>} Message text with file content appended.
457 */509 */
458export async function appendFileContent(message, messageText) {510export async function appendFileContent(message, messageText) {
459 if (message.extra?.file) {511 if (!message || !message.extra || typeof message.extra !== 'object') {
460 const fileText = message.extra.file.text || (await getFileAttachment(message.extra.file.url));512 return messageText;
461513 }
462 if (fileText) {514 if (message.extra.fileLength >= 0) {
463 const fileWrapped = `${fileText}\n\n`;515 delete message.extra.fileLength;
464 message.extra.fileLength = fileWrapped.length;516 }
465 messageText = fileWrapped + messageText;517 if (Array.isArray(message.extra?.files) && message.extra.files.length > 0) {
518 const fileTexts = [];
519 for (const file of message.extra.files) {
520 const fileText = file.text || (await getFileAttachment(file.url));
521 if (fileText) {
522 fileTexts.push(fileText);
523 }
466 }524 }
525 const mergedFileTexts = fileTexts.join('\n\n') + '\n\n';
526 message.extra.fileLength = mergedFileTexts.length;
527 return mergedFileTexts + messageText;
467 }528 }
468 return messageText;529 return messageText;
469}530}
@@ -809,62 +870,128 @@ export function isExternalMediaAllowed() {
809 return !power_user.forbid_external_media;870 return !power_user.forbid_external_media;
810}871}
811872
812function expandMessageImage(event) {873/**
813 const mesBlock = $(event.currentTarget).closest('.mes');874 * Expands the message media attachment.
814 const mesId = mesBlock.attr('mesid');875 * @param {number} messageId Message ID
815 const message = chat[mesId];876 * @param {number} mediaIndex Media index
816 const imgSrc = message?.extra?.image;877 * @returns {HTMLElement} Enlarged media element
817 const title = message?.extra?.title;878 */
879function expandMessageMedia(messageId, mediaIndex) {
880 if (isNaN(messageId) || isNaN(mediaIndex)) {
881 console.warn('Invalid message ID or media index');
882 return;
883 }
884
885 /** @type {ChatMessage} */
886 const message = chat[messageId];
818887
819 if (!imgSrc) {888 if (!Array.isArray(message?.extra?.media) || message.extra.media.length === 0) {
889 console.warn('Message has no media to expand');
820 return;890 return;
821 }891 }
822892
823 const img = document.createElement('img');893 const mediaAttachment = message.extra.media[mediaIndex];
824 img.classList.add('img_enlarged');894 const title = mediaAttachment.title || message.extra.title || '';
825 img.src = imgSrc;
826 const imgHolder = document.createElement('div');
827 imgHolder.classList.add('img_enlarged_holder');
828 imgHolder.append(img);
829 const imgContainer = $('<div><pre><code class="img_enlarged_title"></code></pre></div>');
830 imgContainer.prepend(imgHolder);
831 imgContainer.addClass('img_enlarged_container');
832895
833 const codeTitle = imgContainer.find('.img_enlarged_title');896 if (!mediaAttachment) {
834 codeTitle.addClass('txt').text(title);897 return;
835 const titleEmpty = !title || title.trim().length === 0;898 }
836 imgContainer.find('pre').toggle(!titleEmpty);
837 addCopyToCodeBlocks(imgContainer);
838899
839 const popup = new Popup(imgContainer, POPUP_TYPE.DISPLAY, '', { large: true, transparent: true });900 if (mediaAttachment.type === MEDIA_TYPE.AUDIO) {
901 console.warn('Audio media cannot be expanded');
902 return;
903 }
840904
841 popup.dlg.style.width = 'unset';905 /**
842 popup.dlg.style.height = 'unset';906 * Gets the media element based on its type.
907 * @returns {HTMLElement} Media element
908 */
909 function getMediaElement() {
910 function getImageElement() {
911 const img = document.createElement('img');
912 img.src = mediaAttachment.url;
913 img.classList.add('img_enlarged');
914 return img;
915 }
843916
844 img.addEventListener('click', event => {917 function getVideoElement() {
845 const shouldZoom = !img.classList.contains('zoomed');918 const video = document.createElement('video');
846 img.classList.toggle('zoomed', shouldZoom);919 video.src = mediaAttachment.url;
847 event.stopPropagation();920 video.classList.add('img_enlarged');
848 });921 video.controls = true;
849 codeTitle[0]?.addEventListener('click', event => {922 video.autoplay = true;
923 return video;
924 }
925
926 switch (mediaAttachment.type) {
927 case MEDIA_TYPE.IMAGE:
928 return getImageElement();
929 case MEDIA_TYPE.VIDEO:
930 return getVideoElement();
931 }
932
933 console.warn('Unsupported media type for enlargement:', mediaAttachment.type);
934 return getImageElement();
935 }
936
937 const mediaElement = getMediaElement();
938 const mediaHolder = document.createElement('div');
939 mediaHolder.classList.add('img_enlarged_holder');
940 mediaHolder.append(mediaElement);
941 const mediaContainer = document.createElement('div');
942 mediaContainer.classList.add('img_enlarged_container');
943 mediaContainer.append(mediaHolder);
944
945 mediaElement.addEventListener('click', event => {
946 const shouldZoom = !mediaElement.classList.contains('zoomed') && mediaElement.nodeName === 'IMG';
947 mediaElement.classList.toggle('zoomed', shouldZoom);
850 event.stopPropagation();948 event.stopPropagation();
851 });949 });
852950
853 popup.dlg.addEventListener('click', event => {951 if (title.trim().length > 0) {
952 const mediaTitlePre = document.createElement('pre');
953 const mediaTitleCode = document.createElement('code');
954 mediaTitleCode.classList.add('img_enlarged_title', 'txt');
955 mediaTitleCode.textContent = title;
956 mediaTitlePre.append(mediaTitleCode);
957 mediaTitleCode.addEventListener('click', event => {
958 event.stopPropagation();
959 });
960 mediaContainer.append(mediaTitlePre);
961 addCopyToCodeBlocks(mediaContainer);
962 }
963
964 const popup = new Popup(mediaContainer, POPUP_TYPE.DISPLAY, '', { large: true, transparent: true });
965
966 popup.dlg.style.width = 'unset';
967 popup.dlg.style.height = 'unset';
968 popup.dlg.addEventListener('click', () => {
854 popup.completeCancelled();969 popup.completeCancelled();
855 });970 });
856971
857 popup.show();972 popup.show();
858 return img;973 return mediaElement;
859}974}
860975
861function expandAndZoomMessageImage(event) {976/**
862 expandMessageImage(event).click();977 * Deletes an image from a message.
863}978 * @param {number} messageId Message ID
979 * @param {number} mediaIndex Image index
980 * @param {JQuery<HTMLElement>} messageBlock Message block element
981 */
982async function deleteMessageMedia(messageId, mediaIndex, messageBlock) {
983 if (isNaN(messageId) || isNaN(mediaIndex)) {
984 console.warn('Invalid message ID or media index');
985 return;
986 }
987
988 const deleteUrls = [];
989 const deleteFromServerId = 'delete_media_files_checkbox';
990 let deleteFromServer = true;
864991
865async function deleteMessageImage() {992 const value = await Popup.show.confirm(t`Delete media from message?`, t`This action can't be undone.`, {
866 const value = await callGenericPopup('<h3>Delete image from message?<br>This action can\'t be undone.</h3>', POPUP_TYPE.TEXT, '', {
public/scripts/constants.js+0 -0
public/scripts/events.js+0 -0
public/scripts/extensions.js+0 -0
public/scripts/extensions/caption/index.js+0 -0
public/scripts/extensions/caption/settings.html+0 -0
public/scripts/extensions/connection-manager/index.js+0 -0
public/scripts/extensions/gallery/index.js+0 -0
public/scripts/extensions/quick-reply/index.js+0 -0
public/scripts/extensions/regex/dropdown.html+0 -0
public/scripts/extensions/regex/engine.js+0 -0
public/scripts/extensions/regex/importTarget.html+0 -0
public/scripts/extensions/regex/index.js+0 -0
public/scripts/extensions/regex/scriptTemplate.html+0 -0
public/scripts/extensions/shared.js+0 -0
public/scripts/extensions/stable-diffusion/index.js+0 -0
public/scripts/extensions/stable-diffusion/settings.html+0 -0
public/scripts/extensions/tts/cosyvoice.js+0 -0
public/scripts/extensions/vectors/index.js+0 -0
public/scripts/extensions/vectors/settings.html+0 -0
public/scripts/group-chats.js+0 -0
public/scripts/horde.js+0 -0
public/scripts/openai.js+0 -0
public/scripts/popup.js+0 -0
public/scripts/power-user.js+0 -0
public/scripts/preset-manager.js+0 -0
public/scripts/reasoning.js+0 -0
public/scripts/samplerSelect.js+0 -0
public/scripts/scrapers.js+0 -0
public/scripts/secrets.js+0 -0
public/scripts/slash-commands.js+0 -0
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js+0 -0
public/scripts/st-context.js+0 -0
public/scripts/system-messages.js+0 -0
public/scripts/tags.js+0 -0
public/scripts/templates/samplerSelector.html+0 -0
public/scripts/templates/scenarioOverride.html+0 -0
public/scripts/templates/tagManagement.html+0 -0
public/scripts/textgen-models.js+0 -0
public/scripts/textgen-settings.js+0 -0
public/scripts/tool-calling.js+0 -0
public/scripts/util/SimpleMutex.js+0 -0
public/scripts/utils.js+0 -0
public/scripts/welcome-screen.js+0 -0
public/scripts/world-info.js+0 -0
public/style.css+0 -0
src/byaf.js+0 -0
src/constants.js+0 -0
src/endpoints/backends/chat-completions.js+0 -0
src/endpoints/backends/text-completions.js+0 -0
src/endpoints/characters.js+0 -0
src/endpoints/chats.js+0 -0
src/endpoints/data-maid.js+0 -0
src/endpoints/extensions.js+0 -0
src/endpoints/google.js+0 -0
src/endpoints/horde.js+0 -0
src/endpoints/openai.js+0 -0
src/endpoints/openrouter.js+0 -0
src/endpoints/secrets.js+0 -0
src/endpoints/stable-diffusion.js+0 -0
src/endpoints/thumbnails.js+0 -0
src/endpoints/vectors.js+0 -0
src/express-common.js+0 -0
src/middleware/whitelist.js+0 -0
src/prompt-converters.js+0 -0
src/types/byaf.d.ts+0 -0
src/users.js+0 -0
src/util.js+0 -0
src/vectors/ollama-vectors.js+0 -0
src/vectors/openai-vectors.js+0 -0
tests/.eslintrc.js → tests/.eslintrc.cjs+0 -0
tests/jest-e2e.config.json+0 -0
tests/jest.config.json+0 -0
tests/package-lock.json+0 -0
tests/package.json+0 -0
tests/sample.test.js → tests/sample.e2e.js+0 -0
tests/util.test.js+0 -0
Diff truncated