Compare commits

...

945 Commits

Author SHA1 Message Date
Cohee
6eb74cb715 Merge pull request #2446 from SillyTavern/staging
Staging
2024-06-30 18:22:35 +03:00
Cohee
4d67d7d748 Bump package version 2024-06-30 14:16:08 +03:00
Cohee
cee304fe29 Merge pull request #2445 from Risenafis/fix-initvoicemap
Prevent concurrent execution of initVoiceMap
2024-06-30 14:08:30 +03:00
Cohee
2a3e71bf6e Force reinitialize when chat changed 2024-06-30 14:06:31 +03:00
Risenafis
d3a7466929 remove line break 2024-06-30 16:22:05 +09:00
Risenafis
26d506874f prevent parallel execution of initVoiceMap 2024-06-30 13:58:51 +09:00
Cohee
4828bd95f3 Animate recaption image 2024-06-30 01:19:43 +03:00
Cohee
336674b724 Ensure unique files name for pasted images 2024-06-30 01:00:43 +03:00
Cohee
f181d1a847 Add button to re-caption message image 2024-06-30 00:31:54 +03:00
Cohee
7149f46c9a Add automatic image captioning mode 2024-06-30 00:06:17 +03:00
Cohee
2670709237 Fix caption template references 2024-06-29 23:22:29 +03:00
Cohee
7fe329b5cf Allow paste file and images into chat input form 2024-06-29 23:14:55 +03:00
Cohee
175a91f979 Merge pull request #2436 from SillyTavern/translation-improvements
Translation improvements
2024-06-29 22:38:27 +03:00
Cohee
fcc00e0b26 Merge branch 'staging' into translation-improvements 2024-06-29 14:36:12 +03:00
Cohee
2b50ab398b Add jsconfig exclusions 2024-06-29 14:35:16 +03:00
Cohee
bf28ae07b3 Merge pull request #2438 from SillyTavern/commands-send-at-supports-depth
Various commands with 'at' support depth values
2024-06-29 14:33:22 +03:00
Cohee
76b822c627 Merge pull request #2437 from SillyTavern/echo-command-args
Add optional args to /echo command
2024-06-29 14:26:10 +03:00
Risenafis
bb39e852b8 TTS: Add support for VITS/W2V2-VITS/Bert-VITS2 (#2439)
* add VITSTtsProvider

* add options

* fix params, drop reference_audio_path

* post with body

* improve preview lang

* add space in label
2024-06-29 14:15:37 +03:00
Wolfsblvt
f7d3a1c942 Various commands with 'at' support depth values 2024-06-29 02:52:30 +02:00
Wolfsblvt
75099d3a22 Fix oversight in forceEnum slash commands 2024-06-29 02:42:01 +02:00
Wolfsblvt
5c3b799d65 Fix naming inconsistencies 2024-06-29 02:24:20 +02:00
Wolfsblvt
1d6f038601 Add optional args to /echo command 2024-06-29 02:16:36 +02:00
Wolfsblvt
cba2b54531 Refactor main slassh-commands into init func 2024-06-29 00:25:10 +02:00
Wolfsblvt
d994528548 Extend i18n with translate and template literal 2024-06-28 23:53:25 +02:00
Cohee
003066a036 Add vLLM as multimodal captioning source 2024-06-29 00:33:12 +03:00
Wolfsblvt
be08e62fc1 Observer to find new elements with i18n attribute 2024-06-28 23:01:54 +02:00
Cohee
a287ccfca2 Merge pull request #2435 from SillyTavern/remove-var-from-at-arg
Remove variable usage of 'at' arg in send commands
2024-06-28 22:54:40 +03:00
Wolfsblvt
38792d071b Remove variable usage of 'at' arg in send commands 2024-06-28 20:48:55 +02:00
Cohee
c34150fef0 Limit height to match large popup 2024-06-28 21:32:39 +03:00
Cohee
e98f38b6da Final(?) iOS cope 2024-06-28 21:27:48 +03:00
Cohee
1c69ba1ae3 Change mobile cope styles 2024-06-28 20:51:10 +03:00
Cohee
3803714465 Limit height of enlarged image prompt 2024-06-28 20:46:41 +03:00
Cohee
fa1d45635b Put mobile height fix under a breakpoint 2024-06-28 20:40:57 +03:00
Cohee
54c772622e Add you-know-what for featherless 2024-06-28 20:26:25 +03:00
Cohee
1ab674ba28 Merge pull request #2434 from DarokCx/release
Added featherless to the list of providers
2024-06-28 20:16:37 +03:00
Cohee
b3577024f4 Merge branch 'staging' into DarokCx/release 2024-06-28 19:46:57 +03:00
Cohee
7ea560307c Add third-party extensions links to gitignore 2024-06-28 19:45:47 +03:00
Cohee
cc9eca8427 Apply select2 to model selection 2024-06-28 19:13:46 +03:00
Cohee
4e33253a91 Code clean-up 2024-06-28 19:12:56 +03:00
Cohee
b62cbdeebd Merge branch 'staging' into DarokCx/release 2024-06-28 19:09:12 +03:00
Cohee
0c129f6dbe Rename PULL_REQUEST_TEMPLATE.md to pull_request_template.md 2024-06-28 18:31:16 +03:00
Cohee
c69c5e07e3 Update PULL_REQUEST_TEMPLATE.md 2024-06-28 18:25:07 +03:00
Cohee
62a14fb74b Create PULL_REQUEST_TEMPLATE.md 2024-06-28 18:22:29 +03:00
Cohee
bbb1a6e578 Add huggingface inference as text completion source 2024-06-28 18:17:27 +03:00
Cohee
6b204ada9f Fix no-blur not being respected in popups 2024-06-28 17:01:05 +03:00
Cohee
889a552629 Fix popup height on iPhone 2024-06-28 16:58:37 +03:00
Cohee
89e5562494 Explicitly set min and max dimensions for popup dialog 2024-06-28 13:10:15 +00:00
DarokCx
29ff0876a7 Added additional headers 2024-06-28 08:20:15 -04:00
Cohee
8136293593 Merge pull request #2431 from SillyTavern/remove-slash-command-var-usages
Remove slash command var usages
2024-06-28 13:50:06 +03:00
Cohee
902dfbcdcc Add theme contest winners, pt.1 2024-06-28 10:30:32 +00:00
Cohee
e713b32bdc Fix empty toast suppression 2024-06-28 10:22:26 +00:00
Cohee
d3be6caaa1 Create CONTRIBUTING.md 2024-06-28 12:22:35 +03:00
Cohee
46830a27d0 Merge pull request #2430 from SillyTavern/toast-save-errors
Improve logs (+add toasts) on save calls
2024-06-28 12:03:42 +03:00
Cohee
190bed8025 Fix theme and movingUI toasts 2024-06-28 09:01:28 +00:00
Cohee
2293828f8e Ditto, for chat completion 2024-06-28 08:14:38 +00:00
Cohee
985c2dd031 Don't indicate success in saving presets 2024-06-28 08:09:22 +00:00
Cohee
043eead149 Don't show empty toasts in slash command executor 2024-06-28 08:06:33 +00:00
Wolfsblvt
6653757c5c Remove /imagine's variable usage in 'negative' 2024-06-28 04:06:22 +02:00
Wolfsblvt
b29d32d518 Remove /regex's variable usage in 'name' argument 2024-06-28 04:04:58 +02:00
Wolfsblvt
b97dceeb7a Remove /flushinject's variable usage in unnamed 2024-06-28 04:00:32 +02:00
Wolfsblvt
11ca0dd22e Remove /send's variable usage in 'name' argument 2024-06-28 03:58:04 +02:00
Wolfsblvt
9666b9920a Remove /summarize's variable usage in 'prompt' 2024-06-28 03:55:03 +02:00
Wolfsblvt
7cf5a4cb2e Remove /inject's variable usage in 'id' argument 2024-06-28 03:53:23 +02:00
Wolfsblvt
54e111886b Improve logs (+add toasts) on save calls
- Fixes #2429
2024-06-28 03:28:16 +02:00
Wolfsblvt
b8295ac8f5 Unregister function for macro registration 2024-06-28 03:01:33 +02:00
Cohee
cf56bfb6a9 Add 01.AI as a chat completion source 2024-06-28 00:51:09 +03:00
Cohee
537cfbc027 Remove commented theme toggles 2024-06-27 23:40:47 +03:00
Cohee
599c55938b Merge pull request #2427 from SillyTavern/more-popups
More popups
2024-06-27 23:20:10 +03:00
DarokCx
8608bc92ae no authorization 2024-06-27 10:02:28 -04:00
DarokCx
bd5592de7b Added featherless, connect button not working 2024-06-27 09:06:11 -04:00
Cohee
79b8dc98eb Fix performance of WI editor when adding a new entry 2024-06-27 10:04:49 +00:00
Cohee
4e083ebd4f Allow vertical scrolling in settings snapshots 2024-06-27 08:45:09 +00:00
Cohee
5075534b2e Fix vertical scrolling in data bank 2024-06-27 08:42:23 +00:00
Wolfsblvt
b8ae54fb2c Add i18n to popup controls 2024-06-27 03:01:07 +02:00
Wolfsblvt
d5016ad672 Update tag import popup to new input 2024-06-27 02:52:34 +02:00
Wolfsblvt
d737c0f285 Update Regenerate popup to use input control 2024-06-27 02:40:47 +02:00
Wolfsblvt
d084f579c5 Refactor Popup with private and readonly modifiers 2024-06-27 02:39:59 +02:00
Wolfsblvt
124cbfdfa4 Update Popup to support custom input checkboxes 2024-06-27 02:28:25 +02:00
Wolfsblvt
7bf793d2be Update /newchat command skip popup 2024-06-27 01:39:05 +02:00
Cohee
f73986d23f Remove extra linebreak 2024-06-27 02:25:08 +03:00
Wolfsblvt
1c6c9efba1 Refactor convert to group chat to new popup 2024-06-27 01:01:43 +02:00
Wolfsblvt
efb9fbcc7e Refactor new chat to new popup 2024-06-27 00:45:26 +02:00
Wolfsblvt
360c2985f5 Switch char deletion to new popup
- New popup
- Move char CHARACTER_DELETED to after char deleting, and inside the correct function
2024-06-27 00:29:25 +02:00
Wolfsblvt
d64d16bdf2 Fix popup onClose executing after resolver 2024-06-27 00:27:55 +02:00
Cohee
52a803b6ab Merge pull request #2426 from SillyTavern/dataroot-uploads
Move uploads to data root
2024-06-27 00:54:22 +03:00
Cohee
3b7540da05 Merge pull request #2425 from SillyTavern/wi-delay
Add WI entry delay
2024-06-27 00:36:23 +03:00
Cohee
b80b2d9a74 Fix imported chats not deleting itself after upload 2024-06-26 23:25:00 +03:00
Cohee
5b002c6e46 #2422 Move uploads under the data root 2024-06-26 23:22:42 +03:00
Cohee
886b6fee64 Add WI entry delay 2024-06-26 22:43:30 +03:00
Cohee
54fb7a9030 Add 'online_status_changed' event 2024-06-26 22:11:22 +03:00
Cohee
aceca89080 Merge pull request #2421 from SillyTavern/macro-register
Add simple custom macros registration
2024-06-26 22:01:24 +03:00
Cohee
719539c2ab Improve types and sanitation of macro values 2024-06-26 21:58:57 +03:00
Cohee
ef0772bc9f Merge branch 'staging' into macro-register 2024-06-26 21:54:00 +03:00
Cohee
8b1492a2d9 Mono font family for kbd 2024-06-26 20:39:39 +03:00
Cohee
b1fa4d3038 Remove font-family we don't vendor 2024-06-26 20:37:29 +03:00
Cohee
d9536ae3a8 Add tri-state argument for /lock command 2024-06-26 20:18:05 +03:00
Cohee
112e26a0ff Model icon for slash command messages 2024-06-26 19:48:45 +03:00
Cohee
584d0e6222 Only add missing modules string if there are any modules to report 2024-06-26 12:49:23 +00:00
Wolfsblvt
4e7232f13e Move group chat popups to new popup 2024-06-26 05:56:15 +02:00
Wolfsblvt
ec58d9272a Move ctrl+enter regenerate to new popup 2024-06-26 05:46:34 +02:00
Wolfsblvt
ff5f89bd5e Move overwrite data confirm to new popup 2024-06-26 05:35:41 +02:00
Wolfsblvt
cd9013cf73 Update some WI confirm/input popups to new popup 2024-06-26 05:29:08 +02:00
Wolfsblvt
717c524b01 Update copy message to new popup 2024-06-26 05:01:58 +02:00
Wolfsblvt
c55452d0ea Update prompt itemization to new popup 2024-06-26 04:49:07 +02:00
Wolfsblvt
c8411b6dfb Update delete message to new popup 2024-06-26 03:36:06 +02:00
Wolfsblvt
0c402e2a5f Setup swipe data on /sendas 2024-06-26 03:13:05 +02:00
Wolfsblvt
9113fae4fe Fix /addswipe error if swipe_info not initialized 2024-06-26 02:46:53 +02:00
Wolfsblvt
071a77fe1a Fix deleting swipe not clean swipe_info 2024-06-26 02:14:26 +02:00
Cohee
8034564c3e Update TTS voice preview to new popup 2024-06-26 00:41:37 +03:00
Cohee
2ef6004bd5 Update translation extension to new popup 2024-06-26 00:40:13 +03:00
Cohee
d188795591 Allow vertical scrolling in new popups 2024-06-26 00:35:21 +03:00
Cohee
3e1b54c6f0 Update token counter to new popup 2024-06-26 00:26:31 +03:00
Cohee
c3461307a0 Update debug menu, theme and MUI naming popups 2024-06-26 00:24:21 +03:00
Cohee
1188cb46b8 Update theme import warning to new popup 2024-06-26 00:18:44 +03:00
Cohee
0298849953 Update theme delete confirm to new popup 2024-06-26 00:15:16 +03:00
Cohee
a030237641 Evaluate macro functions for every instance 2024-06-25 22:44:00 +03:00
Cohee
24ae2b6fa6 Add sanitation of macro values 2024-06-25 22:15:40 +03:00
Cohee
01d38f9218 Additional validation of custom macro keys 2024-06-25 22:02:05 +03:00
Cohee
8dab4ecb06 Add simple custom macros registration 2024-06-25 21:53:10 +03:00
Cohee
083ea43971 Update dupe character to use new popup 2024-06-25 21:34:08 +03:00
Cohee
d0f59edf09 Update forbid media and field extend to new popup 2024-06-25 21:24:03 +03:00
steve green
2687618840 Update zh-cn.json (#2411)
* update zh-cn.json

* fix

* another fix
2024-06-25 17:51:47 +03:00
Cohee
20a23c5e31 Merge pull request #2419 from Risenafis/fix-sanitize
Fix non-ASCII name character voice setting
2024-06-25 16:50:10 +03:00
Risenafis
0276a2ef71 fix sanitizeId 2024-06-25 22:23:55 +09:00
Cohee
0f00adca0c Merge pull request #2418 from Risenafis/fix-sbvits-style
Fix Style-Bert-VITS2 style
2024-06-25 15:07:47 +03:00
Risenafis
bbd4d7e2fd rejoin style 2024-06-25 20:05:41 +09:00
Cohee
6b716980be Update extension manager to use new popup 2024-06-25 11:54:59 +03:00
Cohee
0e0bd0d3d9 Update char avatar crop. Remove old cropper 2024-06-25 02:25:38 +03:00
Cohee
650755198d Update persona image upload to new cropper 2024-06-25 02:18:10 +03:00
Cohee
45ae8d1060 Update group custom avatar to new cropper 2024-06-25 02:10:11 +03:00
Cohee
e0000bade6 Port image cropper to new popup 2024-06-25 02:05:35 +03:00
Cohee
974b98ed8e Remove green border from selected tags 2024-06-25 01:03:09 +03:00
Cohee
3b1bd97845 Somewhat restore old wand order 2024-06-24 23:51:18 +03:00
Cohee
990130d7c2 Clean-up wand menu styles 2024-06-24 23:32:24 +03:00
Cohee
62a1cb1dce Move built-in extensions to fixed wand containers 2024-06-24 23:17:58 +03:00
Cohee
444705a5f8 RVC exists too.. 2024-06-24 22:41:19 +03:00
Wolfsblvt
675e7b1de3 Fix stscript autocomplete theme setting 2024-06-24 21:35:09 +02:00
Cohee
1efc26759f Forgot chromadb still exists... 2024-06-24 22:30:14 +03:00
Cohee
d2b2856630 Move TTS settings to HTML template 2024-06-24 22:19:21 +03:00
Cohee
c8b9b62d8a Update built-in extensions to use fixed order in extensions menu 2024-06-24 22:15:08 +03:00
Cohee
508b685fdc Add css, less, html to editorconfig 2024-06-24 21:49:15 +03:00
Cohee
cf9a5383a9 Fix QR .less format 2024-06-24 21:43:13 +03:00
Cohee
7a27c29695 #2416 Recompile popup styles 2024-06-24 21:37:21 +03:00
Cohee
db8fec7757 Add mrcrowl.easy-less to recommended vscode extensions 2024-06-24 21:34:05 +03:00
Cohee
41ab90bb8e Support more parameters for Infermatic 2024-06-24 19:16:20 +03:00
Wolfsblvt
b188c176fd Don't show tag import if no tags to import 2024-06-24 17:17:42 +02:00
Cohee
4b58a822db Fix off-by-one in timed effects. Add protected status 2024-06-24 11:51:04 +00:00
Wolfsblvt
e7ab43527a Fix /echo command falsely stripping HTML-like text 2024-06-24 03:09:46 +02:00
Cohee
a3dbcf3c2a Fix context and response size not being passed to Ollama 2024-06-24 03:48:34 +03:00
Cohee
b89afe6d13 Ignore advancement requirement for immediately set cooldown 2024-06-24 03:13:27 +03:00
Cohee
55483e76e0 Merge pull request #2408 from SillyTavern/timed-wi
Timed Effects for World Info
2024-06-24 02:37:57 +03:00
Cohee
8b9afff30d Generalize onEnded callbacks 2024-06-24 02:33:51 +03:00
Cohee
893f4f3ed6 Use raw metadata for set effect command 2024-06-24 01:28:37 +03:00
Wolfsblvt
9059621dab Fix wider popup overflowing on small screens
-Fixes #2414
2024-06-24 00:28:02 +02:00
Cohee
14879af678 Add format variable to get timed effect command 2024-06-24 01:20:39 +03:00
Cohee
80496db482 Remove resolveVariable calls 2024-06-24 01:08:24 +03:00
Cohee
3b03561d27 Merge branch 'staging' into timed-wi 2024-06-24 01:07:44 +03:00
Cohee
7e3e75875d Remove undocumented calls to resolveVariable in WI slash commands 2024-06-24 01:07:24 +03:00
Cohee
e0a404e099 Fix popup input going off on click 2024-06-23 23:09:22 +03:00
Cohee
66210e9c0f Add command for checking WI state 2024-06-23 21:35:31 +03:00
Cohee
8b5224e274 Add slash command for setting sticky/cooldown. Normalize naming: timed event => timed effect 2024-06-23 21:18:18 +03:00
Cohee
5db2254548 Generalize effect methods 2024-06-23 20:34:07 +03:00
Cohee
d1dd3a5433 Merge branch 'staging' into timed-wi 2024-06-23 20:24:53 +03:00
Cohee
59e1f9cca1 Accept JSON-serialized string arrays for /setentryfield. Return JSON lists in /getentryfield 2024-06-23 19:43:56 +03:00
Cohee
7c57132710 Don't auto-add boolean provider if there are more than one type in the list 2024-06-23 19:35:14 +03:00
Cohee
89a2e266a0 Merge pull request #2412 from harrisonvanderbyl/modelsearch
add search functionality for models
2024-06-23 19:19:46 +03:00
Cohee
de7a5085b1 Partial revert of class/id distinction 2024-06-23 19:18:40 +03:00
Cohee
f2d64a7d08 Merge branch 'staging' into modelsearch 2024-06-23 19:05:00 +03:00
Cohee
3dcb4dee59 Pre-cache related WI entries on chat load 2024-06-23 18:50:40 +03:00
Cohee
39362fd566 Fix some type errors 2024-06-23 18:41:49 +03:00
Cohee
5de80f4c6d Merge branch 'staging' into timed-wi 2024-06-23 18:31:40 +03:00
Cohee
fa9ae4c979 Specify that flushvar supports closures 2024-06-23 18:28:22 +03:00
Cohee
946994af22 /input should return empty string if canceled 2024-06-23 18:16:15 +03:00
Cohee
bd9c10c2eb /messages text consistency 2024-06-23 18:14:10 +03:00
Cohee
b105a2ef24 Add missing /trigger unnamed type, fix names for ask and delname 2024-06-23 18:10:56 +03:00
Cohee
a85ac96f82 Fix /peek typings. Clarify hints for member indices 2024-06-23 18:01:16 +03:00
Cohee
4d493ca733 Merge pull request #2403 from SillyTavern/slash-command-enums
Expand slash commands with enums/enum providers
2024-06-23 17:49:57 +03:00
Harrison
9b17f4e0c0 add search functionality for models 2024-06-24 00:47:06 +10:00
Cohee
eb8f4bebe0 Argument for API is not required 2024-06-23 17:42:00 +03:00
Cohee
f3327c06ab Update trim direction emoji 2024-06-23 17:39:57 +03:00
Cohee
6594b3c7fa Inject supports variables for ID 2024-06-23 17:21:55 +03:00
Cohee
2012bb49d2 Make /member command indices 0-based to match autocomplete 2024-06-23 16:47:07 +03:00
Cohee
e736283785 Return cache to WI 2024-06-23 16:24:33 +03:00
Cohee
38cc4f789b Fix string quotes 2024-06-23 15:57:07 +03:00
Cohee
e2593215bf Fix speak command broken 2024-06-23 15:44:53 +03:00
Cohee
278b526898 Add icon for voice command 2024-06-23 15:43:57 +03:00
Cohee
5a50ed97be Clean-up /sd command help 2024-06-23 15:27:19 +03:00
Cohee
d0b6243f77 Add character filter to lastsprite 2024-06-23 15:23:03 +03:00
Cohee
eba0f54477 Merge branch 'staging' into slash-command-enums 2024-06-23 15:01:55 +03:00
Cohee
3a15e44d0f Merge pull request #2410 from SillyTavern/inline-image-enlarge-rework
Inline image enlarge rework
2024-06-23 14:59:24 +03:00
Cohee
03cfbca7cf Distraction-free image zooming 2024-06-23 14:58:08 +03:00
Cohee
a161ebfcaf Up visibility of close button 2024-06-23 14:53:01 +03:00
Cohee
58a85fa0c8 Remove focus outline from transparent popups 2024-06-23 14:11:00 +03:00
Wolfsblvt
7642b66a0e Improve enlarge inline image
- Make enlarge inline image popup zoomable
- Add optional popup class for transparent popups
2024-06-23 12:26:52 +02:00
Wolfsblvt
48621f1d50 Fix scaling of enlarged popup image 2024-06-23 02:43:37 +02:00
Wolfsblvt
42766a715d Popup type "DISPLAY" & image enlarge changes
- New popup type "DISPLAY", for showing content with an X in the corner, without buttons
- Rework popup result controls to automatically support click (or other) events to close complete the popup
- Fix inline image icons/actions being keyboard interactable
- Switch inline image enlarge popup to new DISPLAY type
2024-06-23 02:32:06 +02:00
Cohee
3e27f0213a Fix cooldown debug log 2024-06-23 01:58:18 +03:00
Cohee
9ec8aa3bf9 Fix JSDocs 2024-06-23 01:53:45 +03:00
Cohee
7875a65b44 Kinda misleading comment 2024-06-23 01:52:10 +03:00
Cohee
461b73facf Adjust min values.
For easier disabling
2024-06-23 01:50:17 +03:00
Cohee
4b4ee7409b Merge branch 'staging' into timed-wi 2024-06-23 01:49:49 +03:00
Cohee
323f34f5d4 Fix QR breaking when no sets 2024-06-23 01:34:10 +03:00
Cohee
de1910268a Add missing macro reference 2024-06-23 01:26:25 +03:00
Cohee
a39a1a7cec Fix odd-named preset selection via command 2024-06-22 17:44:08 +03:00
Cohee
d64647280a Fix method deprecation warning 2024-06-22 17:41:40 +03:00
Cohee
8564d6faa8 Debug function to purge all vectors 2024-06-22 17:41:02 +03:00
Cohee
b8830e34d3 Add ollama download shortcut to vector storage 2024-06-22 16:38:00 +03:00
Cohee
b448568aa3 More ollama multimodal models 2024-06-22 16:28:57 +03:00
Cohee
b513043e4a Prevent sticky from using probability 2024-06-22 15:04:49 +03:00
Cohee
0fe19bca47 Non-static map. Better typing. 2024-06-22 14:56:46 +03:00
Cohee
b4559d3fd8 Use WeakMap for WI cache 2024-06-22 14:43:15 +03:00
Cohee
6c9f3a868d Merge branch 'staging' into timed-wi 2024-06-22 14:39:38 +03:00
Cohee
0f92c90b71 Merge pull request #2405 from SillyTavern/tag-import-setting
Tag import setting
2024-06-22 13:04:14 +03:00
Cohee
36ecf8a717 Update UI when remembering tag import setting 2024-06-22 12:56:57 +03:00
Cohee
aa16ac446d Migrate preference for existing users 2024-06-22 12:53:03 +03:00
Cohee
a6e2692e52 Merge branch 'staging' into tag-import-setting 2024-06-22 12:48:08 +03:00
Cohee
26eb5f0926 Merge pull request #2406 from SillyTavern/gray-out-useless-folders
Gray out bogus folders if they don't drill down
2024-06-22 12:46:06 +03:00
Wolfsblvt
07da2461d0 Fix vertical scaling of images in enlarge popup 2024-06-22 10:04:14 +02:00
Wolfsblvt
c79f1e4360 Fix image enlarge popup image sizing 2024-06-22 08:52:13 +02:00
Wolfsblvt
87915a5f79 Gray out bogus folders if they don't drill down
- Implements and resolves #2404
- Common CSS class for entities in char list
- entity flag to lower opacity for entities that aren't really useful for navigation
2024-06-22 08:15:31 +02:00
Wolfsblvt
d64b265a39 Tag import popup improvements
- Save "remember" setting of tag import popup
- Add user option to change the tag import setting
- Improve tag import popup with adding drilled down bogus folders as auto-added tags
- Extract tag import popup to template
- Force-open popup no matter the setting on char dropdown button option
2024-06-22 05:03:05 +02:00
Wolfsblvt
7c2b475e46 Improve popup class with close event handlers 2024-06-22 04:54:13 +02:00
Cohee
d02fbbb42f Change type of timed events metadata 2024-06-22 03:54:54 +03:00
Cohee
37930caade Refactor timed events funcs 2024-06-22 03:15:13 +03:00
Wolfsblvt
c6c8f91c99 forceEnum:false as default & enum icon changes
- Set forceEnum to false, for now
- Switch some icons around
2024-06-22 01:04:03 +02:00
Cohee
473e11c773 New OpenRouter providers 2024-06-22 02:03:39 +03:00
Cohee
9c2de78ad3 Fix OpenRouter caption headers 2024-06-22 01:42:28 +03:00
Cohee
abb186db01 He warned me. I didn't listen. 2024-06-22 00:46:14 +03:00
Cohee
a00560d2b3 Ensure format supported before captioning 2024-06-22 00:36:29 +03:00
Cohee
791ce3da86 Add stopgaps to fill the second row 2024-06-22 00:11:08 +03:00
Cohee
6380e0a062 Add fallback source for attachments. Fix typo 2024-06-21 23:48:11 +03:00
Cohee
62bc550d3a Open enums with Alt+Space (also non-breaking) 2024-06-21 23:32:17 +03:00
Cohee
e3714e9b6a Fix search provider 2024-06-21 22:31:34 +03:00
Wolfsblvt
da6d77cffd Enum provider for /model 2024-06-21 21:24:37 +02:00
Wolfsblvt
824d0a9b63 Small fix to boolean automatic enums 2024-06-21 20:40:58 +02:00
Cohee
1ede346cbc Merge branch 'staging' into timed-wi 2024-06-21 21:18:12 +03:00
Wolfsblvt
3ab5cc1766 Merge branch 'staging' into slash-command-enums 2024-06-21 20:07:19 +02:00
Wolfsblvt
48077d200b More slash command enums (nearly done) 2024-06-21 20:04:55 +02:00
Cohee
30765550c8 Place sticky + cooldown entry on cooldown when unstuck 2024-06-21 20:50:18 +03:00
Cohee
f2cc66d414 Add console logs to search module 2024-06-21 17:27:28 +03:00
Cohee
56710fee39 Apply fix for group chats 2024-06-21 13:09:41 +00:00
Cohee
7667231137 Merge pull request #2402 from splitclover/staging
Added events for creating new chats
2024-06-21 16:07:38 +03:00
splitclover
0c69b698b9 Removed redundant emmiter 2024-06-21 14:16:59 +02:00
splitclover
feb8321147 Fix emmiter for imported cards 2024-06-21 13:53:31 +02:00
splitclover
3092c68a05 Fixed typo 2024-06-21 13:19:36 +02:00
splitclover
2a1704add0 Added event emmiters when creating new chats 2024-06-21 13:12:57 +02:00
Cohee
9c3cad2df2 Fix sticky/cooldown interaction. Add icons 2024-06-21 02:42:15 +03:00
Cohee
aa473dd749 Move new fields to the right 2024-06-21 01:06:00 +03:00
Cohee
ab7b07ba28 Add sticky and cooldown for timed WI entries 2024-06-21 00:53:00 +03:00
Cohee
e9f93ba748 Remove legacy Claude stop sequences 2024-06-20 22:53:07 +03:00
Wolfsblvt
a5baa3605f Fix closing popup sometimes being stuck via Escape 2024-06-20 21:43:13 +02:00
Wolfsblvt
f092269c01 Fix toastr alignment in popups 2024-06-20 21:02:50 +02:00
Wolfsblvt
ffc84f5118 Merge branch 'staging' into slash-command-enums 2024-06-20 20:38:55 +02:00
Wolfsblvt
461b1a9d87 Even more enum refactorings (not done yet)
- Add common enum icons
- enum def for existing enum types, with color description
2024-06-20 20:33:45 +02:00
Cohee
514ac27d00 Remove unmatched closing div 2024-06-20 20:40:37 +03:00
Cohee
2a4d11e6a6 Merge pull request #2399 from conornash/claude_sonnet_3point5
Claude Sonnet 3.5
2024-06-20 18:43:57 +03:00
Conor Nash
c684bfbf52 Claude Sonnet 3.5 2024-06-20 16:31:55 +01:00
Cohee
0ffad7f4fe Add endpoint for Searxng search 2024-06-19 23:21:40 +03:00
Cohee
8d5876c2c8 Rename endpoints for websearch 2024-06-19 22:37:51 +03:00
Cohee
75dfe87054 Fix character_message_rendered firing twice on new chat 2024-06-19 21:34:46 +03:00
Cohee
8e8b6b353a Fix deleting first message with /del 2024-06-19 21:28:07 +03:00
Cohee
10fd2e1334 #2395 Treat default example as empty 2024-06-19 21:23:25 +03:00
Cohee
41befc3587 Merge branch 'staging' of https://github.com/SillyTavern/SillyTavern into staging 2024-06-19 13:27:27 +03:00
Cohee
8812e09e8d Merge branch 'release' into staging 2024-06-19 13:27:14 +03:00
Cohee
00b44071a6 Merge branch 'release' of https://github.com/SillyTavern/SillyTavern into release 2024-06-19 13:25:42 +03:00
Cohee
9923018a49 Update ws dependency 2024-06-19 13:25:29 +03:00
Cohee
e6bd46acef Merge pull request #2392 from dllt98/migrate-janitor-endpoint
Update JanitorAI.me endpoint to JannyAI.com endpoint
2024-06-19 13:23:49 +03:00
Cohee
190400eb6b Merge pull request #2391 from Wolfsblvt/popup-quickfixes
Small fixes to /popup, /buttons and QR popup
2024-06-19 13:14:27 +03:00
Cohee
e5c8a920ee Remove debug toast(?) 2024-06-19 13:13:34 +03:00
dllt98
fc488574c6 update endpoint 2024-06-19 02:22:05 +00:00
Wolfsblvt
dca81aef3d Small fixes to /popup, /buttons and QR popup
- FIx /popup and /buttons commands to use the new popups
- Change /buttons to utilize data results
- Fix "hide while executing" option from QR editor
- Fix QR editor throwing an error on execution
2024-06-19 01:40:22 +02:00
Cohee
e7772f04a4 Don't require a primary WI to use additionals 2024-06-18 12:09:28 +03:00
Cohee
7249294ffd Fix startup on old firefox 2024-06-18 11:32:50 +03:00
Cohee
e861a406a3 Don't auto-switch to a new theme on import 2024-06-18 02:14:22 +03:00
Cohee
22d598c0f5 Fainter faint outline 2024-06-18 02:01:39 +03:00
Cohee
c3cbf33ba0 Merge pull request #2330 from Wolfsblvt/smol-tag-improvements
Smol tag improvements & Huuuuuge popup/dialog rework (heh)
2024-06-18 01:58:52 +03:00
Wolfsblvt
dadef92fdf Switch focus styles to :focus-visible
- Switched dynamic styles to :focus-visible to let the browser decide when to display
- Changed most existing :focus CSS selectors to also use :focus-visible
-Made style variables for focus outlines (main and a faint one)
- Remove focus outline from chat bar buttons
- Fix focus of chat bar highlight, moved to outer border
- Fix buttons in chat backgrounds with keyboard navigation
2024-06-18 00:14:15 +02:00
Cohee
88b6331aed Add swap SD dimensions button 2024-06-18 01:10:23 +03:00
Cohee
a9c4422c87 Redesign SD settings 2024-06-18 00:49:42 +03:00
Cohee
08a0b1e828 Merge branch 'staging' into smol-tag-improvements 2024-06-17 21:52:36 +03:00
Cohee
b09e86fb53 TTS code clean-up 2024-06-17 21:21:41 +03:00
Cohee
feb7675d2f Auto-set language on exported translate function. 2024-06-17 21:18:30 +03:00
Casey Haralson
4d25856b4f periodically calls the tts module when a paragraph has been generated (#2381)
* periodically calls the tts module when a paragraph has been generated

* adding option for periodic auto generation

* updating find end paragraph logic and config label

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-06-17 21:17:31 +03:00
DreamGenX
c8eaa15f18 Add DreamGen llama 3 templates (#2389) 2024-06-17 20:54:08 +03:00
Cohee
fe5289c495 Fix TTS audio preview 2024-06-17 20:28:19 +03:00
Cohee
5843bb788f Update readme.md 2024-06-17 14:31:12 +03:00
Cohee
4607b79a83 Update readme.md 2024-06-17 14:27:50 +03:00
deffcolony
bca99a4d7f Update readme.md
+ Updated install instructions for SillyTavern Launcher
2024-06-17 13:04:06 +02:00
Cohee
1d3914324f Fix data-i18n removing options 2024-06-17 11:25:13 +03:00
Cohee
be9f34ab8a Fix data-i18n removing options 2024-06-17 11:23:59 +03:00
Wolfsblvt
7f7ecdcca8 Merge branch 'staging' into slash-command-enums 2024-06-17 07:06:26 +02:00
Wolfsblvt
66d609c35f Several million refactoring of existing slash commands with enums (really) 2024-06-17 07:04:10 +02:00
Wolfsblvt
6f7ef25369 Rework slash command enum values pt.2
- Fix jsconfig module resolution for imports in frontend scripts
- Add file with common slash command enum values
2024-06-17 03:30:52 +02:00
Wolfsblvt
fca626d246 Add style on hover over focused popup button
- Add CSS styling rule to still highlight a button on hover when it is being focused already (Otherwise you won't get any effect on hovering and clicking on the default button if a popup has just opened)
- Dynamic styles extended to ignore rules where both hover and focus is used
2024-06-16 23:33:07 +02:00
Cohee
065d453477 Use main font variable where possible 2024-06-17 00:25:08 +03:00
Wolfsblvt
316df6ed17 Remove remnant CSS classes, whoops 2024-06-16 23:20:24 +02:00
Wolfsblvt
f67ed6d22a Fix tabbing with hotswap multiple rows
- Add scroll-reset-container CSS class and handling
- Fix tabbing through hotswap favs by resetting position
2024-06-16 23:13:36 +02:00
Cohee
1a061c6ae5 Skip connect on max context unlock via preset 2024-06-16 22:16:47 +03:00
steve green
1467c4539e Update zh-cn.json (#2385)
* Update zh-cn.json

* other fixes

* typo fix
2024-06-16 22:06:34 +03:00
Cohee
60b09a431a Fix 2024-06-16 16:06:15 +03:00
Cohee
e3a46df010 Merge branch 'staging' into smol-tag-improvements 2024-06-16 16:04:37 +03:00
Cohee
5ed4bd8748 Merge pull request #2374 from Yokayo/staging
More localizable texts
2024-06-16 16:01:41 +03:00
Cohee
a9143e8ea2 ??? 2024-06-16 15:57:16 +03:00
Cohee
037ba84916 Merge branch 'staging' of https://github.com/Yokayo/SillyTavern into ruRuNew 2024-06-16 15:56:37 +03:00
Cohee
c7dc63200a Merge branch 'staging' into ruRuNew 2024-06-16 15:56:07 +03:00
Yokayo
084aa794f8 Merge branch 'staging' into staging 2024-06-16 19:52:08 +07:00
Cohee
d75b30d51a Don't auto-adjust scroll height if not in viewport 2024-06-16 14:56:08 +03:00
steve green
5e44403346 fixup translates (#2382)
* Update i18n.js

* fixup

* update i18n CI

* fix trigger?

* i18n changes

* Update zh-cn.json

* add missing keys

* Revert "i18n changes"

This reverts commit ebe0ede6e1.

* Revert "update i18n CI"

This reverts commit ac923c8bd6.

* Revert "Update i18n.js"

This reverts commit 14a845836b.

* typo fix

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Touch-Night <1762918301@qq.com>
2024-06-16 14:39:46 +03:00
Cohee
861decd5c9 Refactor prompt entry callback 2024-06-16 13:56:43 +03:00
Cohee
0fe579e782 Merge pull request #2383 from splitclover/staging
Add /setpromptentry command to manipulate individual chat completion preset entries
2024-06-16 13:42:51 +03:00
splitclover
aa513e1e3d Fix helpString 2024-06-16 12:36:52 +02:00
splitclover
7f284a3752 Merged redundant args for /setpromptentry 2024-06-16 12:16:56 +02:00
splitclover
e5d9f2937e Merge branch 'SillyTavern:staging' into staging 2024-06-16 12:03:22 +02:00
Cohee
974d6275bf Revert "#2369 Ignore invalid characters in getLastCharacterMessage" 2024-06-16 11:27:11 +03:00
splitclover
e5ba96d6aa Clarify /setpromptentry descriptions 2024-06-16 04:43:45 +02:00
splitclover
716d407753 Add /setpromptentry command to manipulate chat completion presets 2024-06-16 04:37:42 +02:00
Wolfsblvt
34e8cf476a Default enum values for STScript boolean argument 2024-06-16 03:14:43 +02:00
Wolfsblvt
51d7ba728f Tag commands enum providers 2024-06-16 02:59:37 +02:00
Cohee
bba16f5263 Custom vector chunk boundary 2024-06-16 02:16:27 +03:00
Cohee
67b7cbe920 Cut text for group prioritize 2024-06-16 01:05:01 +03:00
Cohee
4892f04a2a Add enum providers for /theme and /movingui commands 2024-06-15 22:35:38 +03:00
Cohee
5860719780 Fix return type of /translate command 2024-06-15 21:58:15 +03:00
Cohee
101c735d91 Add enum provider for /emote 2024-06-15 18:21:44 +03:00
Cohee
3ca6795cde #2369 Ignore invalid characters in getLastCharacterMessage 2024-06-15 18:13:59 +03:00
Cohee
339428a4e9 #2379 Move continue prefill to end of completion 2024-06-15 18:00:09 +03:00
Cohee
3cafc22e1d Fix textarea height adjust 2024-06-15 16:48:35 +03:00
Cohee
788a313024 Combine char. negative prompts in free mode 2024-06-15 16:24:32 +03:00
Cohee
67dc5e5252 Toggle SD message visibility by source 2024-06-15 15:57:50 +03:00
Cohee
2ea0d6466c Console log anthropic multimodal caption errors 2024-06-15 15:55:02 +03:00
Yokayo
86ad8416df Small fix 2024-06-15 18:46:01 +07:00
Yokayo
a91ba2a277 Remove outdated entries, fix a few keys 2024-06-15 18:40:50 +07:00
Cohee
1ac2241d2c Lower main text intensity in Cappuccino theme 2024-06-15 13:30:03 +03:00
Cohee
405fc1458c Use ext. macros in prompt manager 2024-06-15 13:15:52 +03:00
Cohee
b22bc47c4f Update ext.macro calls in built-in extensions 2024-06-15 01:40:16 +03:00
Cohee
bda4958cb3 Visible SD message template 2024-06-15 01:23:51 +03:00
Cohee
2aa8564522 Substitute params with addl. macro 2024-06-15 01:22:15 +03:00
Len
5cb319771d Parser followup (#2377)
* set pipe to empty string on empty closure

* fix missing parser flags and scope

* add closure serializing

* add enum provider function to slash command arguments

* add enum providers for /bg, /ask, and /go

* fix index out of bounds returning undefined

* keep whitespace as is in mixed unnamed args (string+closure)

* add _hasUnnamedArgument to named arguments dictionary

* allow /var key=x retrieval

* add enum provider to /tag-add

* fix typo (case)

* add option to make enum matching optional

* add executor to enum provider

* change /tag-add enum provider to only show tags not already assigned

* add enum provider to /tag-remove

* fix name enum provider excluding groups

* remove void from slash command callback return types

* Lint undefined and null pipes

* enable pointer events in chat autocomplete

* fix type hint

---------

Co-authored-by: LenAnderson <Anderson.Len@outlook.com>
Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-06-15 00:48:41 +03:00
Cohee
cef65a17f9 Fix SD prefix combiner for free mode 2024-06-15 00:03:25 +03:00
steve green
3ede4aafbe Update zh-cn.json (#2376)
* Update zh-cn.json

* html changes

* `div`->`span`

* fixes

* fixes

* more fixes

* Revert last divs

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-06-14 22:46:40 +03:00
Cohee
560119bc3e LLM extended free mode SD prompts 2024-06-14 22:15:29 +03:00
RossAscends
4c81215a60 fix theme-disrespecting text colorizing 2024-06-14 21:50:54 +09:00
Cohee
5699eb115d Merge pull request #2378 from Wolfsblvt/wi-fix-regex-tokenizer
Fix WI keys regex tokenization breaking falsely on comma
2024-06-14 12:46:46 +03:00
Wolfsblvt
64698ac073 Fix WI keys regex tokenization breaking falsely
- Change regex tokenization to check commas inside regexes via opening and closing delimiter.
- Fixes #2375
2024-06-14 01:02:59 +02:00
Wolfsblvt
bdf7fccbae Fix small things from code review
- Remove unused tailwind classes
- Added comment about timeout jsdoc
- Moved new CSS files to @import
2024-06-13 23:55:28 +02:00
Wolfsblvt
96f04a1c49 Merge branch 'staging' into smol-tag-improvements 2024-06-13 23:40:19 +02:00
Len
aa4bdec79c Fix syntax highlight editor (#2300)
* add Noto Sans Mono as default monospace font

* fix ::selection for syntax highlighted editor

* add full noto sans mono

* add explicit "overflow: auto" to textarea to stop Firefox from freaking out

* add syntax hightlight disable toggle

* fix noto sans mono path

* fix details position on scroll

* disable pointer events on autocomplete wrap

* fix for Firefox bug using relative colors

* Shorten font file names.
So that I won't have to scroll the list horizontally

---------

Co-authored-by: LenAnderson <Anderson.Len@outlook.com>
Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-06-13 21:05:50 +03:00
Yokayo
10a4e54a3b Another small fix 2024-06-12 17:15:56 +07:00
Yokayo
839d79f407 Small fix 2024-06-12 16:50:08 +07:00
Yokayo
a1a9f0002c Merge branch 'staging' of https://github.com/Yokayo/SillyTavern into staging 2024-06-12 16:31:11 +07:00
Yokayo
84ee968ab4 More localizable text 2024-06-12 16:30:32 +07:00
Cohee
9c3176b29f Preserve scroll position of the prompt manager 2024-06-12 00:26:31 +03:00
Cohee
d69263923a Include emoji into trim to end sentence 2024-06-11 23:37:00 +03:00
Cohee
abed49c277 JSDoc, toast capitalization 2024-06-11 09:55:37 +03:00
Cohee
75512842d0 Merge pull request #2366 from Wolfsblvt/persona-command-changes
Update /persona slash command with arguments
2024-06-11 09:53:13 +03:00
Cohee
9a5d0e829b Merge pull request #2367 from Wolfsblvt/html-attr-for-menu-type
Add data attribute for the currently open menu_type
2024-06-11 09:50:16 +03:00
Wolfsblvt
679b3587b5 Data attribute for the currently open menu_type
- Add data attribute to the right nav panel for the currently open menu type
- JSDoc of possible menu_type values
- Refactor using the menu_type setter
- Remove legacy "settings" menu type, as that one is not part of those really
2024-06-11 02:54:06 +02:00
Wolfsblvt
860a2f6929 Fix naming 2024-06-11 02:25:01 +02:00
Wolfsblvt
bb09f5a292 Prep to fix AutoComplete display in popups 2024-06-11 02:22:46 +02:00
Wolfsblvt
9fb9253dcc Update /persona slash command with arguments 2024-06-11 01:00:13 +02:00
Cohee
ea21de89c3 Merge pull request #2365 from Risenafis/fix-sbvits-splitting
Fix Style-Bert-VITS2 auto splitting
2024-06-10 23:23:27 +03:00
Risenafis
593f9b5832 fix sbvits2 auto splitting by backup/restore 2024-06-11 01:17:35 +09:00
Risenafis
4e447a59b5 fix sbvits2 auto splitting 2024-06-11 00:21:05 +09:00
Cohee
b3e57dae85 Use crypto UUID for UI 2024-06-10 14:20:52 +03:00
Cohee
d1ed983106 Use crypto UUID if available 2024-06-10 14:18:38 +03:00
Cohee
a20b2a566d Merge pull request #2364 from Yokayo/staging
Add support for Yandex Translate API
2024-06-10 14:10:23 +03:00
Yokayo
fc03fea00a Add support for Yandex Translate API 2024-06-10 17:12:09 +07:00
Wolfsblvt
b814ba5b35 Merge branch 'staging' into smol-tag-improvements 2024-06-10 01:45:15 +02:00
Wolfsblvt
d14af1592e Refactor naming/structure of popup CSS classes
- Refactor naming/structure of popup CSS classes
- Prepare Popup utility of opening/showing dialogs
2024-06-09 22:02:51 +02:00
Cohee
3e60d9e4d8 (chore) Run ESLint 2024-06-09 22:13:20 +03:00
Cohee
c8f3a0be40 Merge pull request #2358 from Risenafis/staging-sbvits2
TTS: Add support for Style-Bert-VITS2
2024-06-09 22:11:33 +03:00
Cohee
de7f8de3e3 Fix elevenlabs v2 settings 2024-06-09 21:04:35 +03:00
Cohee
230215a211 Bulk enable/disable databank attachments 2024-06-09 19:10:18 +03:00
Cohee
bb48dfe084 Add await arg to /imp command 2024-06-09 18:36:52 +03:00
Cohee
1685f6ded0 #1069 Convert to number 2024-06-09 14:41:49 +03:00
Cohee
3dfe10815d Spelling 2024-06-09 14:26:49 +03:00
Cohee
67f2c380a3 #1069 Handle string timestamps as numbers 2024-06-09 11:15:17 +03:00
Risenafis
1ae6f05d09 change the location of the link 2024-06-09 16:14:35 +09:00
Risenafis
2c171fdcfd add project page url 2024-06-09 12:19:09 +09:00
Risenafis
305d60a28e add SBVits2TtsProvider 2024-06-09 12:03:09 +09:00
Cohee
4e822eeebb Add VLLM as vector source 2024-06-09 01:03:22 +03:00
Cohee
1dd21caa66 Adjust number of VLLM logprobs 2024-06-09 00:59:40 +03:00
Cohee
60b7164c28 Import character icon from CHARX 2024-06-08 22:37:17 +03:00
Wolfsblvt
10da7eb474 Comment interactable selectors & more small fixes 2024-06-08 21:15:37 +02:00
Wolfsblvt
d98d811cc1 Merge branch 'staging' into smol-tag-improvements 2024-06-08 21:13:11 +02:00
Cohee
f05d90bada Merge pull request #2356 from SillyTavern/staging
Staging
2024-06-08 18:45:16 +03:00
Cohee
66fd973830 Bump package version 2024-06-08 16:55:40 +03:00
Wolfsblvt
d1824acee0 More small improvements on interactable styling 2024-06-08 07:13:52 +02:00
Wolfsblvt
61906d8dbe Dynamic focus styles from existing hover styles 2024-06-08 05:10:44 +02:00
Cohee
4dcb2acba5 Pretty print group JSON files 2024-06-07 11:56:41 +03:00
steve green
64711109a6 Create update-i18n.yaml (#2342)
* Create update-i18n.yaml

* i18n changes

* fixes of fail in no changes and auto crlf

* i18n changes

* clear en.json

* i18n changes

* only in workflow_dispatch

* Update i18n

* fix

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2024-06-07 11:43:23 +03:00
Cohee
d1b533cbfa Move caption extension settings into template 2024-06-07 02:25:42 +03:00
Cohee
d31eb639dc Add codestral for Mistral 2024-06-06 23:27:36 +03:00
Cohee
fae6ff481e Remove dead Perplexity models 2024-06-06 23:20:27 +03:00
Cohee
bcfc4d5c64 Split overlap size in two 2024-06-06 23:00:49 +03:00
Cohee
39721b6a8f Add file chunks overlap control 2024-06-06 21:45:47 +03:00
Wolfsblvt
e2089b1e44 Dozens new keyboard interactables
- Made dozens of existing controls keyboard interactable
- Tweaked styling so the keyboard focus looks more pleasant
2024-06-06 02:48:06 +02:00
Cohee
671b7ef7cb Add just a chat fields list from server 2024-06-06 02:05:26 +03:00
Cohee
76c35d269b Calculate number of messages after event 2024-06-06 00:44:59 +03:00
Cohee
ff241dd0a9 Add events for completed prompts 2024-06-06 00:23:12 +03:00
Cohee
179a099954 Merge pull request #2351 from Wolfsblvt/rename-char-command
/rename-char slash command
2024-06-05 22:53:54 +03:00
Cohee
2c787f23c7 Fix named argument. 2024-06-05 22:53:41 +03:00
Cohee
ff680f46cc Add rep_pen_slope control for koboldcpp 2024-06-05 22:05:41 +03:00
Cohee
0a3e91287d New syntax for /ask command 2024-06-05 21:37:33 +03:00
Wolfsblvt
f04bbdf112 Small changes to /rename-char 2024-06-05 20:24:50 +02:00
Cohee
c911265dbd Add name argument to /flushinjects command 2024-06-05 21:20:55 +03:00
Wolfsblvt
858e5f2efb /rename-char slash command
- Rename char slash command (with optional parameters for silent and rename old chats)
- JSDoc fix for STscript named args in callbacks
2024-06-05 02:19:22 +02:00
Cohee
144376fbb4 Add KoboldCpp transcription endpoint 2024-06-05 01:36:52 +03:00
Cohee
6bed373f0a Merge pull request #2350 from Wolfsblvt/fix-group-disable
Fix /member-disable wrongfully stacking
2024-06-05 00:02:07 +03:00
Wolfsblvt
cebaf2ee08 Fix /member-disable wrongfully stacking
Fixes #2347
2024-06-04 22:13:19 +02:00
Cohee
340b3920ac Merge pull request #2344 from Wolfsblvt/fix-tags-on-char-creation
Fix adding tags on char/group creation again
2024-06-04 17:09:32 +03:00
Wolfsblvt
55a95c910f Refactor keyboard controls to name "interactable" 2024-06-04 04:05:40 +02:00
Wolfsblvt
e8aba9fa5f Fix adding tags on char/group creation again 2024-06-04 00:32:30 +02:00
Cohee
6ac81c06db Merge pull request #2341 from Wolfsblvt/slight-char-import-popup-fixes
Slight layout fixes to the char import popup
2024-06-03 22:58:23 +03:00
Wolfsblvt
b8cbd93618 Tweaking popup help text 2024-06-03 21:52:46 +02:00
Cohee
3bc68a1ac4 Merge pull request #2343 from henk717/staging 2024-06-03 21:49:10 +03:00
henk717
54660e2d66 Modern Horde domain 2024-06-03 20:34:13 +02:00
Wolfsblvt
e9d4a982c0 Small tweaks to (focus) element styling 2024-06-03 06:19:41 +02:00
Wolfsblvt
5cc4242c6f Make ST-style buttons keyboard selectable
- Make ST-style buttons keyboard selectable
- Allow custom classes/selectors to be set as buttons too, with the same functionality (CSS selector-based)
- Observer to automatically add functionality to any button added to the DOM
- Allow buttons to not be selectable via 'disabled' or 'not_focusable'
2024-06-03 02:52:54 +02:00
Wolfsblvt
98905e0e53 Slight layout fixes to the char import popup
- Need to pull my "wider" popup type from the other branch, because 1/1 aspect ratio scaling is just bad
- Add a few tailwind-like classes for ul-li styling
- Add <kbd> element styling for keyboard buttons
2024-06-03 01:17:19 +02:00
Cohee
9b969b283e Merge pull request #2339 from Wolfsblvt/char-import-multiple-url
Support importing multiple URLs on external import
2024-06-03 01:49:32 +03:00
Cohee
91061c1d55 Fix i18n, make dialog wide 2024-06-03 01:49:01 +03:00
Wolfsblvt
e93bc49b36 Support importing multiple URLs on external import 2024-06-02 23:44:50 +02:00
Wolfsblvt
9318f94f08 Merge branch 'staging' into smol-tag-improvements 2024-06-02 21:07:46 +02:00
steve green
9128c2128e Update zh-cn.json (#2336)
* Update zh-cn.json

More fixes

* little fix

* reorder keys for better edit exp

* add missing keys

* little fix

* Split welcome menu text

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-06-02 15:51:37 +03:00
Cohee
d8949fddc7 Escape commas in comma-separated random and pick 2024-06-02 15:02:54 +03:00
Wolfsblvt
89d1bc8341 Drag&Drop handler utility and animation 2024-06-02 05:54:41 +02:00
Wolfsblvt
6ca71c3e2c Popup styling changes for smaller content & small fixes 2024-06-02 00:09:25 +02:00
steve green
65cf9c8f4d Update zh-cn.json (#2335)
* Update zh-cn.json

* auto trans all strs

* lf

* auto removes

* Delete generate.py
2024-06-02 00:54:53 +03:00
Cohee
20d12dc98e (WIP) Import JSON from .charx 2024-06-02 00:28:41 +03:00
Cohee
a41fe1d801 Show prompt names on hover in PM list 2024-06-01 23:04:13 +03:00
Cohee
b559f2f559 V3 spec (IMPORT ONLY) 2024-06-01 22:07:57 +03:00
Cohee
2e23e78937 Update WI top block layout 2024-06-01 02:05:42 +03:00
Cohee
358d40f502 Restyle WI activation settings 2024-05-31 23:54:24 +03:00
Wolfsblvt
c939c544e2 Rename popup css classes 2024-05-31 21:59:26 +02:00
Wolfsblvt
d3327f7829 Create popup and animation css files 2024-05-31 03:30:41 +02:00
Cohee
61968cb58f Merge pull request #2317 from PasserDreamer/staging
Add template.json for translation, update index.html and SD extension i18n
2024-05-31 01:34:22 +03:00
Cohee
77b80da520 Extract SD templates 2024-05-30 23:37:19 +03:00
Cohee
961e778a75 Autocomplete can't be translated 2024-05-30 23:26:10 +03:00
Cohee
dbf1aa6816 Add line breaks 2024-05-30 23:22:41 +03:00
Cohee
d501c6cf6e Remove template 2024-05-30 23:12:03 +03:00
Cohee
abafdadf33 Merge branch 'staging' into l18n-tw 2024-05-30 23:10:01 +03:00
Cohee
5ec2f33cb0 Merge pull request #2329 from Vhallo/patch-1
Extending punctuation
2024-05-30 23:03:28 +03:00
Cohee
07cfc1fb0b Fix CLIP skip for SD.Next 2024-05-30 22:51:43 +03:00
Cohee
7af27bb6a9 Remove schedulers from SD.Next 2024-05-30 22:42:21 +03:00
Cohee
886f5adce7 Add /db-enable and /db-disable commands 2024-05-30 22:18:00 +03:00
Wolfsblvt
1c6671df31 popup fix scrollbar style, align toastr 2024-05-30 21:03:52 +02:00
Cohee
62eb790b0b Add /translate command 2024-05-30 22:03:51 +03:00
Cohee
e660ec1f14 Remove stray newlines from WI/AN entries 2024-05-30 21:23:13 +03:00
Cohee
760af12252 Update AI Horde client library 2024-05-30 21:09:53 +03:00
Cohee
6228d1d3b1 Add schedulers selection for AUTO1111 2024-05-30 21:04:22 +03:00
Cohee
e0ba516551 Transition only opacity on send form buttons 2024-05-30 18:01:04 +03:00
Cohee
e3ec65fd31 Collapse send buttons when commands are executed 2024-05-30 17:58:17 +03:00
Cohee
716366070b Clamp /db-search threshold arg 2024-05-30 17:15:17 +03:00
Cohee
43f52d5436 Add /yt-script command 2024-05-30 17:01:00 +03:00
Cohee
2c911a3ea2 Add more Data Bank script commands 2024-05-30 14:49:57 +03:00
Wolfsblvt
6c3118549f Make generic popups be modal dialogs
- Switch generic popups to actual <dialog> elements
- Move toastr settings from html to JS
- Add style variable for animation duration (to re-use in CSS)
- Remember focus of popup on stacking pop-up close to switch back to the element you started out in
- Fix keybinds of popups to only act on actual result-triggering controls
- Fix toastr appearing behind popups by dynamically moving the container inside the currently open dialog
- Improve autofocus on popup open
- Make cleaner and prettier popup animations, and tie them to the animation speed
-
2024-05-30 05:11:23 +02:00
Vhallo
d25ba41fb5 Extending punctuation
Extending punctuation for thoughts.
2024-05-30 01:29:28 +02:00
Cohee
6a832bdf2a Fix summarize command return type 2024-05-30 01:48:27 +03:00
Cohee
bc94bcb25c Add data bank management commands 2024-05-30 01:47:33 +03:00
Cohee
9ff2da4c8c Implement sharable SD prefixes 2024-05-30 00:21:27 +03:00
Cohee
e007fe7529 Add SD style deletion 2024-05-29 23:44:11 +03:00
Cohee
283bb2fa89 Add SD multimodal prompt toast 2024-05-29 23:38:55 +03:00
Cohee
4eb6657b51 Add SD seed control 2024-05-29 23:29:45 +03:00
Cohee
31eb0235c2 Clean-up button styles 2024-05-29 19:51:00 +03:00
Cohee
b904f501ba Don't pre-render PM error if empty 2024-05-29 17:23:37 +03:00
Cohee
097894308e #2328 Auto-regenerate corrupt vector indices 2024-05-29 14:53:55 +03:00
Cohee
d350dbf0d7 Add Novel decrisper control 2024-05-29 03:00:42 +03:00
Cohee
110d343eea Add upscale amount control to DrawThings 2024-05-29 02:49:13 +03:00
Cohee
24b6f99abf Fix Claude function tools with prefills 2024-05-29 02:25:32 +03:00
Cohee
2aeaf43c28 Add CLIP skip control for SD 2024-05-29 02:14:08 +03:00
Cohee
f27a83ef73 Restrict function calling to non-streaming only 2024-05-29 01:11:40 +03:00
Cohee
b833f36c75 Function calling for Groq 2024-05-29 01:10:18 +03:00
Cohee
7d983adc6e Log event args when tracing is enabled 2024-05-29 00:57:32 +03:00
Cohee
309eb80748 Function calling for Claude and OpenRouter 2024-05-29 00:56:55 +03:00
Cohee
865c48bcc0 Cohee forgot the ABC 2024-05-28 22:57:07 +03:00
Cohee
2b3dfc5ae2 Add ollama and llamacpp as vector sources 2024-05-28 22:54:50 +03:00
Cohee
c858fccc5f Merge branch 'release' into staging 2024-05-28 20:10:42 +03:00
Cohee
e66b270811 Change backups to be user data scoped 2024-05-28 17:49:34 +03:00
Cohee
1d32749ed2 Update latest tag for release branch pushes 2024-05-28 15:24:36 +03:00
Cohee
0024f96a99 Merge pull request #2325 from bdashore3/tabby-multiswipe
Tabby multiswipe
2024-05-28 10:39:46 +03:00
kingbri
4528655bb7 Textgen: Add multiswipe support for TabbyAPI
Tabby now supports batching and the "n" parameter for both non-streaming
and streaming. Add this into SillyTavern.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-28 00:55:57 -04:00
Cohee
965dac6514 #2296 Add data bank bulk edit 2024-05-27 22:22:21 +03:00
Cohee
80e104e723 Don't open click to edit in document mode if text selected 2024-05-27 21:50:42 +03:00
Cohee
a6e6677c32 Merge branch 'release' into staging 2024-05-27 19:58:19 +03:00
Cohee
66db820c9e Fix external style declaration filtering 2024-05-27 19:55:55 +03:00
Cohee
62a1919402 Use recursive stylesheet sanitation 2024-05-27 14:28:40 +03:00
Cohee
99e09f0b91 Improve external media removal in style blocks 2024-05-27 14:28:28 +03:00
Cohee
8726def6e0 Use recursive stylesheet sanitation 2024-05-27 14:26:59 +03:00
Cohee
1bc45d2869 Improve external media removal in style blocks 2024-05-27 13:43:59 +03:00
Cohee
2c049e5611 Remove imports from embedded styles 2024-05-27 13:26:24 +03:00
Cohee
630111c737 Remove imports from embedded styles 2024-05-27 13:25:21 +03:00
Wolfsblvt
311fb261a4 Allow re-linking tag colors to theme
- Add button to link tag color back to theme color, but explicitly setting it to empty again
- Debounce redrawing of tag color for performance
2024-05-27 05:02:00 +02:00
Wolfsblvt
24224dc0b1 Fix and improve more tag popups
- Rework tag color pickers to... actually work without hacks
- Color picker default to main text color and tag default background. If default color is chosen, sets "empty" in tag, for possible style changes
- Fix tabbing on tag name in tag view list being broken
- Unique names on new tag click
- Several fixes on tags popups
- Animation utility functions (for popup, heh)
- Utility function to get free (unique) name
2024-05-27 03:35:03 +02:00
Wolfsblvt
35e21c3568 WIP: Rework import tags popup for more options
- Rework "import tags" dialog, providing options which tags to import, and rendering the tags there, for manual management
- Refactor tag list function to allow custom remove actions
- Refactor functions to allow adding of multiple tags at once
2024-05-26 20:29:50 +02:00
PasserDreamer
813b9e6a4b Fix other i18n entity changes. 2024-05-26 23:58:12 +08:00
PasserDreamer
b8e8e96f01 update entity "novelaipreserts" to "novelaipresets" 2024-05-26 23:25:00 +08:00
PasserDreamer
678a0ee136 Merge branch 'SillyTavern:staging' into staging 2024-05-26 23:19:54 +08:00
steve green
00fc40408a allow char scpoed regex (#2271)
* Update engine.js to allow char scpoed regex

no ui because i'm not good at it, but works.

* add typedef

* update

* little fix

* Rework scoped scripts UI

* Add locale attributes

* Purge allowance on delete

* add d&d for `saved_scoped_scripts`

* better code

* Save settings on regex scope toggle

* Fix reordering logic

* Fix scoped setter

* Add unique ids for regex scripts

* Wording

* Reload chat after deleting scripts

* Reload chat after toggling scoped regex

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-05-26 17:19:00 +03:00
Cohee
31f4a34f5a Merge pull request #2312 from NijikaMyWaifu/gpt4o-tokenizer-for-gemini
Use GPT-4o tokenizer for Gemini
2024-05-25 20:20:30 +03:00
PasserDreamer
ee2b09ec4c update i18n 2024-05-25 23:58:18 +08:00
Cohee
ef137f68c4 Fallback to Fuse if not parsed expression 2024-05-25 17:32:11 +03:00
Cohee
cb381595f9 Function calling for Mistral 2024-05-25 17:31:40 +03:00
Cohee
b545185f1a Transform LLM emotion response to lower 2024-05-25 17:11:58 +03:00
Cohee
fa6fc45e6f Function calling for Cohere 2024-05-25 17:09:47 +03:00
PasserDreamer
c6745d76a8 Update zh-tw.json 2024-05-25 22:03:54 +08:00
PasserDreamer
1e0efb73c5 Update zh-tw.json 2024-05-25 22:02:45 +08:00
PasserDreamer
73e6e3725d Update template.json 2024-05-25 22:02:06 +08:00
PasserDreamer
83bfe59991 Update index.html 2024-05-25 22:01:27 +08:00
PasserDreamer
df3552d0d8 Update zh-tw.json
missing comma
2024-05-25 21:42:42 +08:00
PasserDreamer
c3544ba07d Update zh-tw.json 2024-05-25 21:35:13 +08:00
PasserDreamer
1c7e696549 remove duplicates from template.json
remove duplicates entities.
2024-05-25 21:25:32 +08:00
PasserDreamer
b23f6944f1 Update template.json
fix typo.
2024-05-25 21:16:48 +08:00
PasserDreamer
1e15be34b6 1. update index.html 18n.
2. update SD extension dropdown menu i18n.
3. update zh-tw.json.
4. add a template.json for translation.
2024-05-25 20:47:24 +08:00
Cohee
dc8530049f Reference implementation: Set expressions with function calling 2024-05-25 15:38:32 +03:00
Cohee
a20c6bb01e Extension framework for function tool calling 2024-05-25 15:31:57 +03:00
NijikaMyWaifu
33b22bd4f8 Use GPT-4o tokenizer for Gemini
Use GPT-4o tokenizer for Gemini, as Gemini tokenizer is more similar to GPT-4o's
2024-05-25 13:26:11 +08:00
Wolfsblvt
4f2543f7ae Fix popup custom buttons 2024-05-25 01:02:13 +02:00
Wolfsblvt
d9582062d2 Expand popup functionality
- Add "custom buttons" functionality, each with their own popup result
- Handle 'Enter' by defining a default action
- Using default action to style the default button to make the default action visible
- Allow override of ok/cancel button on any popup type to display those
- Allow multiple popups to overlay each other
- Small styling changes for bottom spacing on non-input popups
2024-05-25 00:44:09 +02:00
Cohee
439ef0dc5e #2308 Preserve itemized prompts for branches and checkpoints 2024-05-25 00:07:36 +03:00
Cohee
da4f0f53be Resolve char macros to message name in first message display 2024-05-24 23:41:27 +03:00
Cohee
b20cf52fe6 Merge pull request #2291 from Yokayo/staging
Localizable prompt manager
2024-05-24 22:32:04 +03:00
Cohee
761f903fdb Expand rightmost column a bit 2024-05-24 22:27:24 +03:00
Cohee
a717e2ace8 Prefer const 2024-05-24 22:25:18 +03:00
Cohee
5c3ad3e0bc Let's make the diff even cleaner! 2024-05-24 22:23:55 +03:00
Cohee
1ed1e18304 Revert async forEach executor 2024-05-24 22:23:04 +03:00
Cohee
0ebac0e2af Pretty print PM exports 2024-05-24 22:15:28 +03:00
Cohee
800c94cb93 Fix for character export HTML 2024-05-24 22:11:36 +03:00
Cohee
2f2a4fca35 Sanitize error text 2024-05-24 22:05:28 +03:00
Cohee
d5f6849c8e Fix HTML error 2024-05-24 22:04:00 +03:00
Cohee
61e5c32cd2 Fix make draggable 2024-05-24 22:00:21 +03:00
Cohee
8bcb1ef2db Merge branch 'staging' into pm-i18n 2024-05-24 21:56:34 +03:00
Cohee
0e7eff155d Fix ephemeral injects clean-up 2024-05-24 21:53:29 +03:00
daiaji
66454bb711 Add reverse proxy support to Google MakerSuite to allow some Google MakerSuite URLs to no longer be hardcoded with domain names. (#2307)
* Add reverse proxy support to Google MakerSuite.

* Remove hardcoded URLs for some Google MakerSuite API calls.

* Don't send real key to alt.endpoint

* Fix for image captioning

* Fix key validation

* +fix key check for mistral

* Fix caption key validation

* Fix tokenization endpoint use

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-05-24 21:38:29 +03:00
Cohee
e1dfbc0bea Merge branch 'release' into staging 2024-05-24 20:36:01 +03:00
Cohee
7dc3b06d0f /api returns current name if no params 2024-05-24 20:34:29 +03:00
Cohee
4d161768c0 New Cohere model 2024-05-24 17:17:21 +03:00
Cohee
967a7980f5 Add vector retrieval score threshold 2024-05-23 17:28:43 +03:00
Yokayo
5450bacf0f Merge branch 'staging' of https://github.com/Yokayo/SillyTavern into staging 2024-05-23 17:17:22 +07:00
Yokayo
97965b2de5 Fix templates 2024-05-23 17:16:16 +07:00
Wolfsblvt
26572458b6 Do not allow same-ish tag names / allow same-ish tag search 2024-05-23 03:34:35 +02:00
Wolfsblvt
3a5dfadac5 Fix group tag list not updating 2024-05-23 02:45:23 +02:00
Wolfsblvt
33cec69df9 Add option to merge into other tag on delete 2024-05-23 01:55:43 +02:00
Cohee
039f3b875b Add "ephemeral" option script /inject 2024-05-23 02:34:13 +03:00
Cohee
1f46d334b1 Merge pull request #2302 from Wolfsblvt/world-override-failsafe
Implement failsafe for world creation with same name
2024-05-23 02:11:54 +03:00
Cohee
8a8e8a89dc Remove debug log.
Don't think it makes much sense
2024-05-23 02:10:39 +03:00
Cohee
a11231dd2e Revert export removal 2024-05-23 01:47:06 +03:00
Wolfsblvt
92cb70213a Fix no sanitize check on wi create 2024-05-23 00:39:49 +02:00
Wolfsblvt
ab8c67ede6 Refactor overwrite check to utility function
- Refactor overwrite check to utility function
- Don't mind me refactoring character delete functions. I tried something, but I think the refactoring still makes sense
2024-05-22 23:52:35 +02:00
Cohee
23d3b85696 Merge pull request #2295 from bdashore3/new-samplers
Add new tabby Samplers
2024-05-22 23:45:14 +03:00
Cohee
65c3dfb694 Zen sliders fix 2024-05-22 23:37:51 +03:00
Cohee
e8b96fec02 Merge branch 'staging' into new-samplers 2024-05-22 23:26:47 +03:00
Wolfsblvt
a251849f8f WI import checking for existing worlds too
- WI import uses the same check as create new world
- API endpoint to get server-side sanitized filenames
- Small changes to toast messages
2024-05-22 21:11:39 +02:00
kokansei
75a1ef4304 Add DRY Samplers to ST Staging (#2211)
* Add files via upload

* Add files via upload

* Delete public/index.html

* Add files via upload

* Delete public/scripts/textgen-settings.js

* Add files via upload

* Delete public/scripts/power-user.js

* Add files via upload

* Delete public/scripts/power-user.js

* Add files via upload

* Update power-user.js

* Update index.html

* Fix control attribution

* Fix app loading

* Put sequence breakers under DRY block

* DRY for DRY

* Update public/index.html

Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>

* Merge fix

* Add llamacpp control. Add default value for sequence breakers

* Forgot reset

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>
2024-05-22 20:46:52 +03:00
Cohee
d33ca68620 Merge pull request #2301 from LenAnderson/fix-var-behavior
Fix var behavior
2024-05-22 20:01:30 +03:00
Wolfsblvt
29d817d549 Implement failsafe for world creation with same name
- Fixes #2297
- Added another utils function for string comparison
2024-05-22 18:19:01 +02:00
LenAnderson
6b66bc41fe Merge branch 'staging' into fix-var-behavior 2024-05-22 10:22:54 -04:00
LenAnderson
46cd47bdfc fix /var behavior 2024-05-22 10:21:49 -04:00
Cohee
5e970c8a51 Only refresh settings on extras connected if current SD source is extras 2024-05-22 16:14:42 +03:00
Cohee
bce8627644 [chore] Replace tabs with spaces 2024-05-22 16:12:09 +03:00
Cohee
0b95ea3f7b Merge pull request #2299 from steve02081504/patch-7
Always make sure that the delete WI is available
2024-05-22 14:33:51 +03:00
steve green
3dd4f2b94a Always make sure that the delete ****** available 2024-05-22 19:23:51 +08:00
Cohee
d011d60351 Merge pull request #2298 from SSJGabraham/Gabraham/Markdown-Single-Space-Indent
Markdown Single Space Indent
2024-05-22 11:04:45 +03:00
Gabraham
a9c3a808ac Merge remote-tracking branch 'upstream/staging' into Gabraham/Markdown-Single-Space-Indent 2024-05-22 04:03:33 -04:00
Gabraham
d5533854cc Merge branch 'staging' into Gabraham/Markdown-Single-Space-Indent 2024-05-22 00:57:08 -04:00
kingbri
74b6ed97c2 Textgen: Add repetition decay for TabbyAPI
Repetition decay softens the drop off for repetition penalty. It's
best paired with rep pen range.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-22 00:09:10 -04:00
kingbri
99d143263d Textgen: Add skew sampling
Adds the option from skew sampling from exllamaV2

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-21 23:48:33 -04:00
kingbri
a12df762a0 Textgen: Add speculative_ngram for TabbyAPI
Speculative ngram allows for a different method of speculative
decoding. Using a draft model is still preferred.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-21 23:37:36 -04:00
Cohee
f5fccc0387 Add Azure TTS service 2024-05-22 01:37:51 +03:00
Cohee
0371bf4e9f Revoke 1-time object URLs 2024-05-22 01:36:38 +03:00
Cohee
f56fecaa26 Merge branch 'staging' into pm-l10n 2024-05-21 20:56:26 +03:00
Cohee
255cd1310d Merge pull request #2281 from PasserDreamer/staging
Image Generation extension add i18n support.
2024-05-21 20:53:43 +03:00
Cohee
56392c1789 Update readme.md 2024-05-21 20:46:41 +03:00
Cohee
8b7a858e1f Update readme.md 2024-05-21 20:45:28 +03:00
Cohee
103c460f0a Merge pull request #2288 from Bronya-Rand/staging
feat: add docker instructions
2024-05-21 20:44:17 +03:00
Cohee
c1d8896db9 Merge guides 2024-05-21 20:43:51 +03:00
Cohee
aae95f70c4 Merge branch 'staging' into docker-readme 2024-05-21 20:40:57 +03:00
Cohee
e582bb9117 Merge branch 'release' into staging 2024-05-21 20:40:19 +03:00
Cohee
3616c2acf0 Docker guide credit 2024-05-21 20:32:44 +03:00
Cohee
19630735e0 Merge pull request #2287 from mrguymiah/release
Update readme.md
2024-05-21 20:32:00 +03:00
Cohee
c2ed5d07e2 Update readme.md 2024-05-21 20:30:28 +03:00
Cohee
319b0a543c Enable markdown strikethough 2024-05-21 16:58:42 +03:00
Cohee
e0ac189acc #2290 Allow square brackets and underline in SD prompts 2024-05-21 16:51:11 +03:00
Yokayo
2c69d77fae Merge branch 'staging' into staging 2024-05-21 20:42:08 +07:00
Cohee
f24aa1fa5f Hide inline image quality control for unsupported sources 2024-05-21 16:24:58 +03:00
Cohee
86af5ac217 Cut gemini prompt hint 2024-05-21 16:22:33 +03:00
Cohee
0b06f9686b Enable image inlining for Gemini flash 2024-05-21 16:14:21 +03:00
Cohee
bac00659ef Add RisuRealm import example 2024-05-21 15:58:00 +03:00
Cohee
b1c9fee29e #2188 Make first message not required 2024-05-21 15:46:41 +03:00
Cohee
226852233f Clean-up SD message sending 2024-05-21 15:03:57 +03:00
Cohee
630b72f13a #2290 Allow curly braces in SD prompts.
+remove unused code
2024-05-21 14:28:47 +03:00
Cohee
c21deb3a8c #2289 Fix message translation on edit 2024-05-21 14:23:18 +03:00
Cohee
055defa204 Remove unused package reference 2024-05-21 14:18:28 +03:00
Yokayo
0275f2ec15 Redo localizable strings 2024-05-21 17:53:05 +07:00
Yokayo
d2ce1e17b3 Wait this was not supposed to happen 2024-05-21 17:49:44 +07:00
Yokayo
7efe9cf209 More localizable strings 2024-05-21 17:40:14 +07:00
Yokayo
5c243fa465 Merge branch 'staging' of https://github.com/Yokayo/SillyTavern into staging 2024-05-21 17:14:36 +07:00
Yokayo
456e1124a3 Revert "Remove prompt manager changes"
This reverts commit a8c9fe4dce.

Move HTML pieces to templates
2024-05-21 17:06:42 +07:00
RossAscends
9b1a254553 scale MUI on window resize 2024-05-21 13:55:00 +09:00
Bronya-Rand
a119a5cbfb chore: un-prettify 2024-05-21 04:43:09 +01:00
Bronya-Rand
c2592d7d86 chore: update docker file to auto-create the plugins folder. 2024-05-21 04:31:21 +01:00
Bronya-Rand
927dc4394d chore: add docker section to point to docs 2024-05-21 04:31:20 +01:00
mrguymiah
04ad1011f0 Update readme.md
Added Docker instructions
2024-05-20 22:42:25 -04:00
RossAscends
56d0ffc1fd fix MovingUI infinite loop on resize to Y edge 2024-05-21 09:55:56 +09:00
Cohee
3dc4c8ca39 #2284 Persona description in-chat-at-depth 2024-05-21 01:57:04 +03:00
RossAscends
09a575b783 remove debug css on .draggable 2024-05-21 07:50:24 +09:00
Cohee
3cd3890263 #2286 Fix SD interactive mode loose trigger 2024-05-21 01:11:40 +03:00
Cohee
435821348a Allow setting unnamed persona names with a tick button 2024-05-21 00:40:12 +03:00
Cohee
03bb911ee7 Fix persona sorting on load 2024-05-21 00:22:56 +03:00
Cohee
63f96f4dc7 Merge branch 'release' into staging 2024-05-21 00:10:56 +03:00
Cohee
db2c9a9926 Attempt docker release fix 6 2024-05-20 23:50:34 +03:00
Cohee
1fc88e97f4 Attempt docker release fix 5 2024-05-20 23:44:01 +03:00
Cohee
3d3914645d Attempt docker release fix 4 2024-05-20 23:35:36 +03:00
Cohee
68ade7b384 Attempt docker release fix 3 2024-05-20 23:20:28 +03:00
Cohee
071f232611 Attempt docker release fix 2 2024-05-20 23:08:51 +03:00
Cohee
dff5ca7e92 Attempt docker release fix 2024-05-20 23:03:22 +03:00
Cohee
a47dda79a3 Merge pull request #2224 from Yokayo/staging
Onboarding language switch, more localizable strings, work on ru-ru translation
2024-05-20 22:09:18 +03:00
Cohee
549b2d52a4 Remove unnecessary DOM query 2024-05-20 21:58:45 +03:00
Cohee
ad3f677a9e Format fix 2024-05-20 21:57:02 +03:00
Cohee
0d68473010 Fix client version display on welcome message 2024-05-20 21:50:57 +03:00
Cohee
6ed7729b18 Merge branch 'staging' of https://github.com/Yokayo/SillyTavern into ru-l10n 2024-05-20 21:45:18 +03:00
Cohee
0c36d4e67d Merge branch 'staging' into ru-l10n 2024-05-20 21:45:02 +03:00
Yokayo
d6a02e3c47 Translated a bit more 2024-05-21 01:16:20 +07:00
Yokayo
a8c9fe4dce Remove prompt manager changes 2024-05-21 00:54:46 +07:00
Cohee
454a71922d Whack punycode deprecation message 2024-05-20 14:37:10 +03:00
PasserDreamer
b4dc66f950 Merge pull request #4 from SillyTavern/staging
Staging
2024-05-20 19:32:28 +08:00
Cohee
d902d0d202 Require at least node 18 2024-05-20 14:27:51 +03:00
PasserDreamer
b6cb08101b update zh-tw 2024-05-20 19:02:29 +08:00
PasserDreamer
c10323424d Update Image Generation 2024-05-20 18:49:33 +08:00
Cohee
df2710bcbe Transform WI haystack after regex matching 2024-05-20 13:44:12 +03:00
PasserDreamer
5506c81397 update Image Generation locale. 2024-05-20 18:15:16 +08:00
Cohee
ed2e7a2f47 Fix RisuRealm UUID identifier import 2024-05-20 12:51:10 +03:00
PasserDreamer
27e3a9201e Update zh-tw 2024-05-20 13:58:56 +08:00
RossAscends
863e0c3643 fix power_user.movingUIState not saving properly 2024-05-20 12:56:48 +09:00
RossAscends
8d2b7a15dc don't hide close button on unzoomified avatars 2024-05-20 12:23:54 +09:00
RossAscends
67381cf493 fix zoomedAvatar resize and movement 2024-05-20 12:18:30 +09:00
Cohee
86f54dccdc Merge pull request #1930 from X-T-E-R/release
Adapting a TTS API for the GSVI (GPT-SoVits Inference) Project
2024-05-20 01:05:05 +03:00
Cohee
edf981a5a1 Don't convert markdown to plaintext 2024-05-20 00:48:23 +03:00
Cohee
ab75680ed3 Merge pull request #2277 from SillyTavern/staging
Staging
2024-05-19 23:48:13 +03:00
Cohee
8c11d7e8e8 Merge pull request #2276 from LenAnderson/stop-parser-from-bitching-about-space-after-quote
stop parser from complaining about space after closing quote of quoted argument
2024-05-19 23:09:29 +03:00
LenAnderson
8b776491e8 fix endOfText
current char must be whitespace as well
2024-05-19 15:52:30 -04:00
Cohee
884f26924c Merge pull request #2275 from SillyTavern/staging
Staging
2024-05-19 22:37:33 +03:00
Cohee
5f79579a4d Fix selector? 2024-05-19 22:33:16 +03:00
Cohee
82f56da16b Hide script buttons on old Safari 2024-05-19 22:25:41 +03:00
Cohee
bc2035d362 Don't use autocomplete on old Safari 2024-05-19 22:22:32 +03:00
Cohee
41f25edb15 Workaround for old Safari 2024-05-19 22:16:14 +03:00
Cohee
cf28d6653c Import characters from RisuRealm by URL 2024-05-19 20:19:20 +03:00
Cohee
1eca18f287 Merge branch 'staging' into ru-l10n 2024-05-19 19:48:38 +03:00
Yokayo
6671c9aa80 Move dynamic html to templates 2024-05-19 21:49:43 +07:00
Cohee
53496d70f1 Merge pull request #2272 from SillyTavern/staging
Staging
2024-05-19 16:45:57 +03:00
Cohee
a17588fb1b Fix smooth streaming not working with multiswipe 2024-05-19 16:41:55 +03:00
Cohee
dd06fddd17 #2267 Fix multiswipe mutating the array returning by the streaming provider 2024-05-19 16:38:18 +03:00
Cohee
e9c5618b10 Force generate unlock on wrapped API error 2024-05-19 16:25:22 +03:00
Cohee
b32330df0f Merge pull request #2270 from LenAnderson/more-subcommand-shenanigans
More subcommand shenanigans
2024-05-19 15:47:55 +03:00
LenAnderson
3bd2edf4d2 move silencing of loud /aborts into execute function when handled 2024-05-19 07:34:09 -04:00
Cohee
697949c784 Bump package version 2024-05-19 14:31:52 +03:00
Cohee
ee913be46b Merge pull request #2266 from sasha0552/vllm-fixes
vLLM fixes
2024-05-19 14:23:07 +03:00
LenAnderson
4f5813a6ce fix /if subcommand strings 2024-05-19 06:40:08 -04:00
LenAnderson
4a25821aba remove todo 2024-05-19 06:38:59 -04:00
LenAnderson
c049ff82cd fix typehint 2024-05-19 06:31:58 -04:00
LenAnderson
64ee2d77b8 fix switch to play button when script paused 2024-05-19 06:27:27 -04:00
LenAnderson
ce4106eb3d fix typehint 2024-05-19 06:27:09 -04:00
LenAnderson
974d27ce26 use root AbortController in /if subcommands 2024-05-19 06:26:16 -04:00
LenAnderson
dfe482b37b fix /abort toast and loop break in /times 2024-05-19 06:25:19 -04:00
LenAnderson
1f18694aa6 fix /abort toasts in /while 2024-05-19 06:25:00 -04:00
LenAnderson
89de668241 fix typehints for while unnamed arg / command 2024-05-19 06:24:32 -04:00
LenAnderson
963e525e07 fix typehints 2024-05-19 06:23:34 -04:00
LenAnderson
94ee7167e0 unescape macros inside unnamed arg arrays 2024-05-19 06:23:19 -04:00
Cohee
48c075fb42 #2268 Fix while command 2024-05-19 12:19:08 +03:00
Cohee
581e5f1f04 Fix app init 2024-05-19 11:52:49 +03:00
RossAscends
9637b3fbe1 Merge branch 'staging' of https://github.com/Cohee1207/SillyTavern into staging 2024-05-19 15:06:32 +09:00
RossAscends
c7232ae23c WIP textgen API custom sampler display 2024-05-19 15:06:29 +09:00
sasha0552
01912f5b3e Fix typo 2024-05-19 04:36:36 +00:00
sasha0552
db5e2d95c2 vLLM fixes
* Enable seed field for vLLM

* Enable beam search for vLLM

* Set the default length penalty to 1
(There is validation error from vLLM when beam search is disabled and the value is not equal to 1)
2024-05-19 04:34:11 +00:00
Cohee
d9b55df883 Fix loading characters from assets on first load 2024-05-19 03:31:09 +03:00
Cohee
4e9a113a35 Merge pull request #2265 from LenAnderson/parser-post-stuff
Follow ups and fixes for the new STscript parser
2024-05-18 22:39:23 +03:00
LenAnderson
70a35e9b49 Merge branch 'staging' into parser-post-stuff 2024-05-18 14:51:06 -04:00
LenAnderson
bc4a8fbe1d fix qr editor height on narrow 2024-05-18 14:49:33 -04:00
LenAnderson
d77a70b25a fix type hints 2024-05-18 14:49:02 -04:00
LenAnderson
e49317a73c fix empty unnamed arg assignment start 2024-05-18 14:48:50 -04:00
LenAnderson
87cc28ae28 subcommand and /abort fixes
- use AbortController in /abort instead of execption
- allow quiet abort
- allow loud abort
- allow abort reason
- abort when aborted in subcommand
- break out of loops when aborted inside
- fix parsing of subcommands with multiple commands
2024-05-18 14:48:31 -04:00
Cohee
699d640845 Clean-up labels 2024-05-18 20:03:02 +03:00
Cohee
93c3e9e1dd Merge branch 'staging' into X-T-E-R/release 2024-05-18 19:52:33 +03:00
Cohee
b93131ec7a Lint fix 2024-05-18 18:58:25 +03:00
Cohee
4219468e20 Merge pull request #2264 from racinmat/staging
fix: correct usage of fuzzy search in emotion detection by LLM
2024-05-18 18:57:34 +03:00
Cohee
4227968dfa Allow using JSON schema with llamacpp server 2024-05-18 18:50:48 +03:00
Cohee
09790bb994 Merge pull request #2258 from Wolfsblvt/tag-slash-commands
Add slash commands for tag management
2024-05-18 18:34:24 +03:00
Matěj Račinský
bd1bfee941 fix: correct usage of fuzzy search 2024-05-18 17:05:55 +02:00
Cohee
0b3c49da90 Allow bulk edit menu to wrap 2024-05-18 17:59:59 +03:00
Cohee
c3d6e10795 Fix error on creating new tags 2024-05-18 17:55:22 +03:00
Cohee
1eae9bd18b Draw updated tags immediately 2024-05-18 17:51:42 +03:00
Cohee
99e24f5588 Fix group tags opacity 2024-05-18 17:51:10 +03:00
Cohee
38e2bf955c Merge branch 'staging' into tag-slash-commands 2024-05-18 17:27:04 +03:00
Cohee
0653dad5c5 Show tags when auto-loading a character 2024-05-18 17:05:46 +03:00
Cohee
51af830db8 Only auto-select preset on full name match 2024-05-18 16:46:41 +03:00
Cohee
2bde9d2b15 Merge branch 'staging' into tag-slash-commands 2024-05-18 16:42:25 +03:00
Cohee
d9f9da99e6 Silent /abort 2024-05-18 15:41:02 +03:00
Cohee
64b0123acf Merge pull request #2263 from PasserDreamer/staging
Fix some typo and add zh-tw locale.
2024-05-18 14:48:47 +03:00
Cohee
35d853b851 Normalize "Default" and "Match Whole Words" data-i18n 2024-05-18 14:43:06 +03:00
Cohee
1966baad84 Fix invalid JSON format 2024-05-18 14:39:04 +03:00
Cohee
a398566b33 [BUG]In the lorebooks management panel, when in the Custom sorting mode, entries may be incorrectly placed above the table header. #2262 2024-05-18 13:27:22 +03:00
PasserDreamer
9f2c473040 Add files via upload
Add zh-TW locale.
2024-05-18 17:23:54 +08:00
PasserDreamer
a73db4984a Merge pull request #3 from PasserDreamer/patch-3
Update mediawiki-scrape.html
2024-05-18 17:21:45 +08:00
PasserDreamer
3498eb92bb Merge pull request #2 from PasserDreamer/patch-1
Update fandom-scrape.html
2024-05-18 17:17:25 +08:00
PasserDreamer
455db18d71 Merge pull request #1 from PasserDreamer/patch-2
Update index.html
2024-05-18 17:16:37 +08:00
PasserDreamer
2aeffe4095 Update mediawiki-scrape.html
fix typo
2024-05-18 15:58:32 +08:00
PasserDreamer
c4fe9749d5 Update index.html
Correct typos and standardize the capitalization of repeated terms.
2024-05-18 15:52:42 +08:00
PasserDreamer
a0512585b1 Update fandom-scrape.html
fix missing qoutes.
2024-05-18 15:34:05 +08:00
Cohee
c52bdb9a4a Use new command names in examples 2024-05-17 20:59:00 +03:00
Cohee
bbd9c89357 Add aliases for group member commands 2024-05-17 20:57:03 +03:00
Cohee
fb2190ace1 #2254 Don't suppress abort in subcommands 2024-05-17 18:21:13 +03:00
Cohee
deb09bf5bf Fix console errors on not found command autocomplete 2024-05-17 17:47:40 +03:00
Cohee
d951beb626 #2260 Handle window resize in script editor 2024-05-17 17:47:18 +03:00
Cohee
748dd5f2e6 Remove duplicate command registration 2024-05-17 15:04:53 +03:00
Cohee
75de4c8fcb Resolve boolean fields to constant values when searching WI entries with command 2024-05-17 14:32:57 +03:00
Cohee
432be09583 Merge pull request #2259 from Succubyss/staging
[Claude] Implements Assistant Impersonation Prefill
2024-05-17 11:15:37 +03:00
Succubyss
c822b9e2da Implements Assistant Impersonation Prefill 2024-05-16 21:59:58 -05:00
Cohee
c661fea07d #2227 Implement content scaffolding 2024-05-17 02:43:14 +03:00
Cohee
782f85e05d Merge pull request #2233 from Bronya-Rand/staging
feat: add default tip to welcome screen
2024-05-17 02:07:01 +03:00
Wolfsblvt
96a9f7108c Add slash commands for tag management 2024-05-17 01:01:51 +02:00
Bronya-Rand
9475147435 chore: adjustments to the bundle notice and update spanish locale 2024-05-16 17:45:42 -05:00
Cohee
909ec4191d Allow JS syntax in instruct activation regex 2024-05-17 01:14:07 +03:00
Cohee
59d00cca74 Allow multiple import of regex 2024-05-17 01:06:00 +03:00
Cohee
71a3e2c91b Don't modify response length when changing mancer model 2024-05-17 00:19:43 +03:00
Cohee
719202ba12 Merge pull request #2200 from Wolfsblvt/wi-regex-keys
WI regex keys
2024-05-17 00:06:07 +03:00
Cohee
8ae4332110 Fix secondary key expansion 2024-05-17 00:03:41 +03:00
Cohee
964f53273c Emit event after edited message is updated 2024-05-16 23:13:11 +03:00
Cohee
9e10022014 I want my 5px back... 2024-05-16 23:11:59 +03:00
Cohee
2eaabe13e3 Merge branch 'staging' into wi-regex-keys 2024-05-16 22:18:32 +03:00
steve green
3389b5dd16 allow custom source url (#2255)
* Update script.js to allow custom source url

* type hint fix

* fixes
2024-05-16 22:16:57 +03:00
Cohee
3832afaeba Merge pull request #2257 from hexa4ce/staging
Add support for new characterhub.org url (chub.ai legacy site)
2024-05-16 22:11:10 +03:00
Cohee
e026ddf6be Merge pull request #2246 from Wolfsblvt/tag-folders-folder-filter
Tag folders folder filter
2024-05-16 22:08:28 +03:00
hexa4ce
116fa673c6 Added support for new characterhub.org url (former chub.ai) for character imports 2024-05-16 20:07:52 +02:00
Cohee
517da9f972 TTS Rate: fix settings load. Hide when System source. 2024-05-16 09:35:48 +03:00
Cohee
74256dc411 Merge pull request #2249 from Surye/staging
Added TTS Audio Playback Speed Config
2024-05-16 09:35:04 +03:00
Vincent Castellano
1b23a62c13 Added TTS Audio Playback Speed Config 2024-05-15 23:16:25 -07:00
Wolfsblvt
97de520f9a Fix switchy button to top-right 2024-05-16 00:25:11 +02:00
Wolfsblvt
a6333f3285 Sort tag folder inline avatars too 2024-05-16 00:05:03 +02:00
Cohee
012f70336f Prevent header from jumping a few pixels when switching from list to character view 2024-05-16 01:02:22 +03:00
Cohee
7fbed26c26 #2245 Fix custom group avatar display 2024-05-16 00:49:26 +03:00
Wolfsblvt
a94af2678b Re-enable autofit height on plaintext key input 2024-05-15 23:47:48 +02:00
Cohee
eb57289b2a Non-Chromium browsers require padding to wrap around 2024-05-16 00:38:32 +03:00
Wolfsblvt
068b542c50 Tag folders "onboarding" icon (: 2024-05-15 23:37:18 +02:00
Cohee
912fd36e29 Set proper height of fancypants button instead of 100% 2024-05-16 00:32:58 +03:00
Cohee
b7a91770dc Set line height for select2 search textarea
Prevent height from jumping around when input is focused
2024-05-16 00:28:35 +03:00
Cohee
f0af503b4a Transition to full opacity on hover 2024-05-16 00:22:09 +03:00
Cohee
3d023a5cf6 Add opacity to fancypants switch button
Want it to be more subtle yet still visible
2024-05-16 00:18:27 +03:00
Cohee
1e2d1aa118 Merge branch 'staging' into wi-regex-keys 2024-05-16 00:12:51 +03:00
Cohee
ccfd3606dc Msg. to Load step 25 => 5 2024-05-16 00:05:28 +03:00
Cohee
fe95e09c8b Merge pull request #2244 from Wolfsblvt/rename-chat-command
Add /renamechat slash command
2024-05-15 23:47:12 +03:00
Cohee
bac90edfad Merge branch 'staging' into wi-regex-keys 2024-05-15 23:40:19 +03:00
Wolfsblvt
b7043a428f Add /renamechat slash command 2024-05-15 22:39:32 +02:00
Cohee
5b47b83fe2 Merge pull request #2238 from Succubyss/staging
Typo fix for /while example
2024-05-15 23:35:19 +03:00
Cohee
7289ed72f8 #2240 Yes, I can add new maker suite model 2024-05-15 23:31:09 +03:00
Cohee
c4936ed535 Properly colorize webkit search cancel button 2024-05-15 23:06:10 +03:00
Cohee
8a5f05fb74 Merge pull request #2242 from LenAnderson/fix-qr-editor-narrow
fix QR editor on narrow screen
2024-05-15 23:05:24 +03:00
LenAnderson
36f7bc4aae reduce qr editor small screen height 2024-05-15 15:41:26 -04:00
Cohee
d5869e3f90 Fix isolated modules not being loaded 2024-05-15 17:21:51 +03:00
Cohee
3b83d081db Merge pull request #2243 from steve02081504/patch-3
add import tags in list of more opt
2024-05-15 17:15:14 +03:00
steve green
6861135925 Discard changes to public/scripts/power-user.js 2024-05-15 22:02:28 +08:00
LenAnderson
b6f47c9927 prevent overflow of command results 2024-05-15 09:51:23 -04:00
steve02081504
796cc3c60c add import_tags in list of more opt 2024-05-15 21:34:09 +08:00
steve green
f1a57d76a2 enable import_card_tags by default 2024-05-15 21:27:50 +08:00
LenAnderson
87b61f7cff fix QR editor on narrow screen 2024-05-15 08:27:22 -04:00
Cohee
1999f607d6 Set tainted flag metadata if a message was edited 2024-05-15 13:19:23 +03:00
Wolfsblvt
bb2f553c46 Tag Folders folder filter showing only folders 2024-05-15 02:06:11 +02:00
Wolfsblvt
6c2dc6756b Merge branch 'wi-regex-keys' of https://github.com/Wolfsblvt/SillyTavern into wi-regex-keys 2024-05-15 00:39:02 +02:00
Wolfsblvt
f7c12264e8 Fix select2 local ajax breaking 2024-05-15 00:38:48 +02:00
Succubyss
9ef3dea884 rule typo fix for /while example 2024-05-14 17:36:10 -05:00
Cohee
cd90e252bf Add 1px height 2024-05-15 01:23:44 +03:00
Cohee
ac2475fb26 Merge branch 'staging' into wi-regex-keys 2024-05-15 01:21:45 +03:00
Wolfsblvt
8f1a959da1 WI key input default to plaintext 2024-05-15 00:19:09 +02:00
Cohee
8c55e1b05b Merge pull request #2231 from Wolfsblvt/wi-multiple-inlcusion-groups
WI support multiple inclusion groups
2024-05-15 01:07:57 +03:00
Cohee
a0bbee8b79 Merge branch 'staging' into wi-multiple-inlcusion-groups 2024-05-15 00:54:27 +03:00
Cohee
caf85ad040 Merge pull request #2229 from Wolfsblvt/wi-delay-until-recursion
WI entry setting "Delay until recursion"
2024-05-15 00:43:52 +03:00
Cohee
3999bee482 Replace UI hint text
I just don't like "checking" twice in one sentence
2024-05-15 00:39:26 +03:00
Cohee
f0016b5368 Fallback for old safari 2024-05-14 23:43:17 +03:00
Cohee
1dec93de8a Fallback for old safari 2024-05-14 23:28:52 +03:00
Cohee
caf236d60a Add event for chat completion settings ready 2024-05-14 22:34:40 +03:00
Cohee
c8ed8e06f1 Unset doc-height for body 2024-05-14 22:13:00 +03:00
Cohee
aa845b4727 Cancel message deletion with Escape 2024-05-14 22:06:38 +03:00
Cohee
1ebe5547d4 Revert themed coloring for message deletion highlight 2024-05-14 22:05:04 +03:00
Cohee
e2e7d5870a Export a function for renaming an active chat 2024-05-14 21:15:01 +03:00
Cohee
ea45d372f3 Reformat es-es for cleaner diff 2024-05-14 19:57:31 +03:00
Cohee
3113109f0a Use a proper tokenizer for GPT-4o 2024-05-14 15:30:11 +03:00
Bronya-Rand
6ec51ff086 chore: slight english updates and spanish translation cuz I know it 2024-05-14 10:02:04 +01:00
Azariel Del Carmen
9eae4d9739 Merge branch 'SillyTavern:staging' into staging 2024-05-14 10:47:08 +01:00
Bronya-Rand
84aa746241 feat: add default asset tip to welcome screen 2024-05-14 09:46:37 +01:00
Wolfsblvt
00ce078630 WI key input mode switch fancy/plaintext
- Implemented switch between fancy and plaintext input controls
- Fixed splitting keys into regexes index issue
- Fixed focus falsely adding text as key
2024-05-14 04:51:22 +02:00
Wolfsblvt
5426431adf Merge branch 'staging' into wi-regex-keys 2024-05-14 01:56:36 +02:00
Wolfsblvt
726ec0fbfc WI automation/inclusionGroup not autocompleting to itself 2024-05-14 00:54:43 +02:00
Wolfsblvt
094fc1f24b WI allow multiple inclusion groups on a single entry 2024-05-14 00:16:41 +02:00
Cohee
49cb8daf7d Add inline image control 2024-05-14 01:08:31 +03:00
Cohee
16660e995e Merge pull request #2230 from deffcolony/staging
Update ko-kr.json
2024-05-14 00:21:31 +03:00
deffcolony
8469f43285 Update ko-kr.json
checked by WolfCat (pk2381)
2024-05-13 22:48:21 +02:00
Wolfsblvt
6865f84eb1 Someone forgot preventRecursion default value 2024-05-13 22:39:21 +02:00
Wolfsblvt
036603c9e9 WI entry setting "Delay until recursion" 2024-05-13 22:33:25 +02:00
Cohee
ab0f57aba3 Merge pull request #2228 from LenAnderson/parser-fix-sort
fix autocomplete sort
2024-05-13 23:18:33 +03:00
Cohee
13c755c197 Compact summary log 2024-05-13 23:17:28 +03:00
LenAnderson
5250d1fcaf fix sort 2024-05-13 16:16:52 -04:00
Cohee
492f857012 Remove console spam 2024-05-13 23:16:33 +03:00
Cohee
f1a0462ca3 Fix toast msg in SD command 2024-05-13 23:11:07 +03:00
Cohee
6254ac6fbf Merge pull request #2226 from LenAnderson/parser-improvements
Parser improvements
2024-05-13 22:57:29 +03:00
Cohee
5207b3a7f0 Role filter conditions 2024-05-13 22:45:06 +03:00
Cohee
9e968de4e4 Merge pull request #2225 from kingbased/staging
gpt-4o
2024-05-13 22:30:31 +03:00
LenAnderson
e3edb96568 add force hide and auto hide of autocomplete details 2024-05-13 14:56:36 -04:00
LenAnderson
dded42374c show command details as argument and enum details 2024-05-13 14:56:17 -04:00
Cohee
c561fb4fab Don't check for system flag in role filter 2024-05-13 21:40:01 +03:00
based
67610b9f7f gpt-4o 2024-05-14 04:37:36 +10:00
Cohee
14aa70eea8 Add role and hidden arguments to /messages commands 2024-05-13 21:36:55 +03:00
Cohee
28da838bd1 Add install to plugin manager script 2024-05-13 21:22:01 +03:00
Cohee
fd18e0cc78 #2192 Fix order of events in TTS/translate interaction 2024-05-13 18:53:54 +03:00
Cohee
2a30a74886 Merge pull request #2221 from steve02081504/patch-1
More worldinfo page sizes
2024-05-13 16:56:53 +03:00
Cohee
6130ebb6d9 Merge pull request #2223 from LenAnderson/parser-flags-doclinks
populate parser flag doclinks in user settings
2024-05-13 16:52:50 +03:00
Cohee
64500bfb37 Add rounding to textarea autofit 2024-05-13 16:48:35 +03:00
Cohee
cc077732c4 Sort assets alphabetically, highlight in the list 2024-05-13 16:29:34 +03:00
Cohee
cd47f3b238 Fix loading locale data 2024-05-13 15:56:37 +03:00
Cohee
297519c401 Default to 100% probability in external imported lorebooks 2024-05-13 15:24:16 +03:00
Yokayo
118d2c5bcf Remove unneeded comment 2024-05-13 19:22:48 +07:00
Yokayo
6023eac4bb Onboarding lang switch; more localizable strings; enhance ru-ru translation 2024-05-13 19:20:28 +07:00
LenAnderson
09d410ec48 populate parser flag doclinks 2024-05-13 08:04:58 -04:00
steve green
1369025092 More worldinfo page sizes
I have a WIbook with more than 100 entries and it's a hassle to edit
So I want to raise the cap to 1000
2024-05-13 17:51:42 +08:00
Cohee
5147233391 Fix file attachment chunk size inconsistency 2024-05-13 00:27:32 +03:00
Cohee
38585cb6af Merge pull request #2218 from SillyTavern/default-content
Default content
2024-05-13 00:12:39 +03:00
Cohee
f53775d3f5 Fix img scaling 2024-05-13 00:11:14 +03:00
Cohee
14ba7fc646 Split downloadables list into sections 2024-05-13 00:05:32 +03:00
Cohee
5b7bfbaa98 Merge branch 'staging' into default-content 2024-05-12 23:48:49 +03:00
Len
1d75b98393 STscript Parser Rewrite (#1965)
* set isForced to true on input

* make floating auto-complete follow horizontal scrolling

* add callable closure vars

* changes to /let and /var for callable closures

* fix error message

* fix scope for closure arguments

* if should return the pipe result from closures

* use /run to call closures and no arguments on immediate closures

* throw exception from QRs window-function if no match

* when to show autocomplete vs info only

* autocomplete positioning

* autocomplete styling

* add theming to autocomplete (theme, dark, light)

* improve autocomplete show/hide logic and editor selection

* use blur tint color instead of chat tint color and use blur setting

* cleanup and docs

* use scope macros for QR args

* add enter to select autocomplete

* fix no executor found

* cleanup and comment

* fix alias list in help string

* fallback to empty string piped value if null or undefined

* fix typo

* blur textarea on ctrl+enter execute (and refocus after)

* stop executeSlashCommand if parser throws

* move /let and /var callbacks into functions

* switch textarea to monospace when value starts with slash

* add double pipe a pipe breaker

* fix /? slash

* remove some logging

* add "/:name" as shorthand for "/run name" after all

* move shit around

* fix error message

* use testRunShorthandEnd

* use parseQuotedValue and parseValue to determine name for "/:"

QR labels and set names can include spaces

* add some adjustments to make autocomplete work properly

some hint in there about "/:" would still be nice

* add autocomplete style  selector

* only strip quotes from subcommand if they are at both ends

* fix JSDoc

* escaping

* allow open quotes on dry run

* throwing shit at the wall for /: autocomplete

* escapes only for symbols

* clean up autocomplete

* improve performance

* fix scope macros

* remove unescaping of pipes

* fix macros in scope copy

* fix "/? slash"

* don't run parser for getNameAt if text has not changed

* fix options filter

* re-enable blur listener

* restore selection on non-replace select

* fix for escaping first character of value

* add support for {{pipe}} and {{var::}} closures

* add index support to var macro

* add scoped var macro to macro help

* more escape fixes

* reduce autocomplete render debounce

* cleanup

* restore old escape handling and parser flag for strict escaping

* fix "no match" autocomplete message

* add dummy commands for comments and parser flag

* fix type annotations

* somewhat safer macro replacements

* fix autocomplete select on blank / "no match"

* fix cutting off handled part in substitution

* add parser flag REPLACE_GETVAR

Replaces all {{getvar::}} and {{getglobalvar::}} macros with {{var::}}.
Inserts a series of command executors before the command with the macros that:
- save {{pipe}} to a var
- call /getvar or /getglobalvar to get the variable used in the macro
- call /let to save the retrieved variable
- return the saved {{pipe}} value

This helps to avoid double-substitutions when the var values contain text that could be interpreted as macros.

* remove old parser

* fix send on enter when no match

* deal with pipes in quoted values (loose escaping)

* add default parser flags to user settings

* allow quoted values in unnamed argument

* set parser flag without explicit state to "on"

* add click hint on parser error toast

* dirty more detailed cmd defs

* remove name from unnamed arg

* move autocomplete into class and floating with details

* replace jQuery's trigger('input') on #send_textarea with native events because jQuery does not dispatch the native event

* fix ctrl+space

* fix arrow navigation

* add comments

* fix pointer block

* add static fromProps

* fix up dummy commands

* migrate all commands to addCommandObject

* remove commented comment command

* fix alias in details

* add range as argument type

* switch to addCommandObject

* switch to addCommandObject

* fix height

* fix floating details position on left

* re-enable blur event

* use auto width for full details on floating autocomplete

* auto-size floating full details

* fix typo

* re-enable blur listener

* don't prevent enter when selected item is fully typed out

* add autocomplete details tooltips

* add language to slash command examples

* move makeItem into option and command and fix click select

* use autocomplete parts in /? slash

* fix alias formatting

* add language to slash command examples

* fix details position on initial input history

* small screen styles

* replace registerSlashCommand with detailed declarations

* put name on first line

* add missing returns

* fix missing comma

* fix alias display in autocomplete list

* remove args from help string

* move parser settings to its own section

* jsdoc

* hljs stscript lang

* add hljs to autocomplete help examples

* add missing import

* apply autocomplete colors to stscript codeblocks (hljs)

* add fromProps

* cache autocomplete elements

* towards generic autocomplete

* remove unused imports

* fix blanks

* add return types

* re-enable blur

* fix blank check

* Caption messages by id

* add aborting command execution

* fix return type

* fix chat input font reset

* add slash command progress indicator

* add missing return

* mark registerSlashCommand deprecated

* why??

* separate abort logic for commands

* remove parsing of quoted values from unnamed arg

* add adjustable autocomplete width

* revert stop button pulse

* add progress and pause/abort to QR editor

* add resize event on autocomplete width change

* add key= argument to all get vars

* refactoring

* introduce NamedArgumentAsignment

* add TODOs

* refactoring

* record start and end of named arg assignment

* refactoring

* prevent duplicate calls to show

* refactoring

* remove macro ac

* add secondary autocomplete and enum descriptions

* add syntax highlighting to QR editor

* add enum descriptions to /while

* add /let key=... to scope variable names

* add unnamed argument assignment class and unnamed argument splitting

* fix QR editor style

* remove dash before autocomplete help text

* add autocomplete for unnamed enums

* fix remaining dom after holding backslash

* fix for unnamed enums

* fix autocomplete for /parser-flag

* add parser-flag enum help

* fix type annotations

* fix autocomplete result for /:

* add colored autocomplete type icons

* collapse second line autocomplete help if empty

* mark optional named args in autocomplete

* fix when what

* remove duplicate debug buttons

* dispatch input on autocomplete select

* prevent grow from editor syntax layer

* add auto-adjust qr editor caret color

* remove text-shadow from autocomplete

* join value strings in /let and /var

* add /abort syntax highlight

* fix attempting secondary result when there is none

* rename settings headers and split autocomplete / stscript

* add parser flag tooltips

* add tooltips to chat width stops

* fix typo

* return clone of help item

* fix enum string

* don't make optional notice for autocomplete arguments smaller

* avoid scrollbar in chat input

* add rudimentary macro autocomplete

* strip macro from helptext

* finally remove closure delimiters around root

* cleanup

* fix index stuff for removed closure delimiters

* fix type hint

* add child commands to progress indicator

* include sub-separator in macro autocomplete

* remove all mentions of interruptsGeneration and purge

* remove unused imports

* fix syntax highlight with newline at end of input

* cleanup select pointer events

* coalesce onProgress call

* add regex to STscript syntax highlighting

* fix closure end

* fix autocomplete type icon alignment

* adjustments for small screens

* fix removing wrong element

* add missing "at=" arg to /sys, /comment, /sendas

* add font scale setting for autocomplete

* add target=_blank for parser flag links

* fix for searching enums

* remove REGEXP_MODE from hljs
just causes trouble

* fix autocomplete in closures

* fix typo

* fix type hint

* Get rid of scroll bar on load

* Add type hint for /send name argument. Fix 'at' types

* Add 'negative' arg hint to /sd command

* reenable blur event

* Allow /summarize to process any text

* Compact layout of script toggles

* Expand CSS by default

* fix double ranger indicator and adjust to narrow container

* make custom css input fill available vertical space

* reduce scroll lag

* use default cursor on scrollbar

* Clean-up module loading in index.html

* fix tab indent with hljs

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-05-12 22:15:05 +03:00
Cohee
c7d75b7789 llamacpp broke 2024-05-12 21:41:07 +03:00
Cohee
4ccedb939c Merge pull request #2204 from steve02081504/patch-2
impl `{{char_version}}`
2024-05-12 17:57:37 +03:00
Cohee
4bb463dd56 Remove unused macros 2024-05-12 17:55:00 +03:00
Cohee
0ba600bb2b Code clean-up 2024-05-12 17:53:38 +03:00
Cohee
9ed6ee2161 Sample Character browser to onboarding 2024-05-12 16:43:09 +03:00
Cohee
c4ade296ae Rotate Flux the Cat to downloadable content index 2024-05-12 15:09:00 +03:00
Cohee
0ed81e3b1a Rotate Coding Sensei to downloadable content index 2024-05-12 14:49:13 +03:00
steve02081504
d1933be86a remove {{char_version_url_encoded}} 2024-05-12 09:04:50 +08:00
steve02081504
15ff8de45c add template 2024-05-12 09:04:03 +08:00
steve02081504
45a080016e move to env 2024-05-12 09:01:30 +08:00
steve02081504
78cf6e9086 Merge branch 'staging' into pr/2204 2024-05-12 08:51:47 +08:00
Cohee
7d65a6e264 Add content manager config notice 2024-05-12 00:44:46 +03:00
Cohee
91945ec77e Fix misleading JSDoc 2024-05-12 00:22:36 +03:00
Cohee
7b472f13af Require a ping call before generation 2024-05-12 00:18:56 +03:00
Cohee
a93777e3b7 (chore) JSDoc comment 2024-05-11 23:38:26 +03:00
Cohee
2f310c72fa Merge pull request #2215 from Hydroerotic/staging
Added {{timeDiff}} macro.
2024-05-11 23:35:55 +03:00
Cohee
6a4ee68113 Message delete highlight color follows theme settings 2024-05-11 17:17:42 +03:00
Cohee
e73b5713fd Add types for moment 2024-05-11 14:49:11 +03:00
Hydroerotic
1f81086a21 Update macros.js 2024-05-11 14:13:03 +03:00
Hydroerotic
3e48f4b805 Update macros.html 2024-05-11 13:55:15 +03:00
Hydroerotic
432be2ee57 Update macros.js 2024-05-11 13:52:31 +03:00
steve green
f421139402 Create char-data.js for type hint (#2209)
* Create char-data.js for type hint

code from 7df0d1e06d/src/charData.mjs

* add hint

* fixes

* `class` -> JSdoc typedef by AI

* use `import`

* `v2DataWorldInfo`

* Rename book typedef

* Fix type errors

---------

Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
2024-05-11 12:05:13 +03:00
RossAscends
081223cc8f Merge pull request #2212 from bdashore3/token-ban-upgrades
min_length and strict string ban for Tabby
2024-05-11 17:39:05 +09:00
Cohee
27ccc6b090 Minor stylistic changes 2024-05-11 11:38:22 +03:00
kingbri
62faddac8d Textgen: Add banned_strings
TabbyAPI supports the ability to ban the presence of strings during
a generation. Add this support in SillyTavern by handling lines
enclosed in quotes as a special case.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-11 00:58:29 -04:00
kingbri
6804e4c679 Index: Expose min_tokens for TabbyAPI
Now supports the minimum amount of tokens to generate.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-10 23:19:57 -04:00
Cohee
10ee002091 Merge pull request #2208 from Wolfsblvt/global-d-ts-expanded
Expand global.d.ts with code docs
2024-05-10 23:11:08 +03:00
Cohee
1430eb26ea Delete toastr types.
@Wolfsblvt add it back if needed.
2024-05-10 23:05:14 +03:00
Cohee
e17a18ad5d #2210 Replace line breaks with <br> in unknown elements 2024-05-10 15:59:01 +03:00
Wolfsblvt
eeaa52bf5d Expand global.d.ts with code docs
- docs and syntax for toastr
- docs and syntax for Fuse
- docs and syntax for select2
- docs and syntax for sortable
2024-05-10 04:48:30 +02:00
Cohee
07a6cb1252 Merge pull request #2205 from deffcolony/staging
move expression buttons above Sprite set
2024-05-10 02:24:11 +03:00
steve02081504
7a2f6fb63f {{char_version_url_encoded}} and macro replace in creator_notes_spoiler 2024-05-10 07:24:05 +08:00
Wolfsblvt
bb3ac095c4 WI key input allow click to edit
- Allow click on WI keys to edit
- Removes them from the key list, allowing direct text editing
- Refactor select2 click subscribe some more, fixing a few issues
2024-05-10 00:42:35 +02:00
Wolfsblvt
e18d554489 Refactor select2 choice click event to utils 2024-05-09 23:30:18 +02:00
Wolfsblvt
a2625ecec6 Merge branch 'staging' into wi-regex-keys 2024-05-09 22:54:27 +02:00
deffcolony
0252b21901 move expression buttons above Sprite set
+moves the buttons above the Sprite set so user does not have to scroll all the way down to find the buttons now it will be directly visiable
2024-05-09 16:33:04 +02:00
steve green
f6343436b4 impl {{char_version}}
https://github.com/SillyTavern/SillyTavern/issues/2111
2024-05-09 22:29:48 +08:00
Cohee
9db2f1cb91 #2203 Fix copy not working in hidden messages 2024-05-09 16:07:13 +03:00
Cohee
2fd59f5aef Merge pull request #2201 from Wolfsblvt/wi-no-doube-substitution
Do not double-parse WI content on "always on"
2024-05-09 15:31:14 +03:00
Cohee
18d96bc346 Merge branch 'staging' into wi-no-doube-substitution 2024-05-09 15:11:16 +03:00
Cohee
535da63e52 Merge pull request #2199 from steve02081504/patch-4
remove empty entrys from WIs
2024-05-09 15:05:25 +03:00
Cohee
e14c9506b6 Revert entry post-process 2024-05-09 14:55:09 +03:00
Cohee
88aae5978f Simplify condition. Add debug log 2024-05-09 14:53:17 +03:00
Wolfsblvt
b9d72bfdf4 Do not double-parse WI content on "always on" 2024-05-09 06:37:14 +02:00
Wolfsblvt
f4bb4fe51e Merge branch 'staging' into wi-regex-keys 2024-05-09 04:23:14 +02:00
Wolfsblvt
cf77b9e7ee WI regex key syntax highlighting 2024-05-09 03:35:36 +02:00
steve green
ff1399d1ba remove empty lines from WIs 2024-05-09 08:30:40 +08:00
Wolfsblvt
eb273a1873 WI key dropdown templating shows all keys
- Cache all keys for the loaded lorebook
- Key selection dropdown shows all keys and how often they are used already
- More templating changes
2024-05-08 20:34:53 +02:00
Cohee
0587931cae Merge pull request #2193 from steve02081504/patch-2
also run regex on worldinfo
2024-05-08 21:15:39 +03:00
Cohee
7408673e41 Back to const 2024-05-08 20:59:59 +03:00
Cohee
3c0664dfb6 Fix naming and improve regex application 2024-05-08 20:10:52 +03:00
steve green
d2477bba0c also run regex on worldinfo 2024-05-08 23:41:18 +08:00
Cohee
f37e444791 Merge pull request #2194 from LenAnderson/remove-hljs-innerText
don't replace codeblock textContent with innerText in hljs
2024-05-08 18:13:02 +03:00
LenAnderson
1ae08f49c5 don't replace codeblock textContent with innerText in hljs 2024-05-08 11:03:05 -04:00
Cohee
10fda0b220 Merge pull request #2191 from bdashore3/example-wi
mesExamples anchor for World Info
2024-05-08 15:33:45 +03:00
Cohee
61d5dde497 Fix line break 2024-05-08 15:13:12 +03:00
Cohee
edc33584da Fix extra & in title 2024-05-08 15:12:31 +03:00
Cohee
883da48762 Prefer const variables 2024-05-08 15:10:53 +03:00
Cohee
49d0d9f557 Fix return type on empty WI 2024-05-08 15:04:17 +03:00
Cohee
852bc15a94 Update title and i18n 2024-05-08 14:10:34 +03:00
Cohee
c43ddd9d62 Merge pull request #2178 from Yokayo/staging
Localization enhancements
2024-05-08 13:59:52 +03:00
Cohee
c851961234 Update movingUI i18n attr 2024-05-08 13:58:54 +03:00
kingbri
01aacb9280 World Info: Add example messages insertion point
Allow insertion above and below mesExamples (also known as the
"examples of dialogue") box.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-07 21:55:26 -04:00
Yokayo
dfa8c6c3d4 Remove cases 2024-05-07 13:11:59 +07:00
Wolfsblvt
fda0e886e4 WI custom styling for regex keys
- WI custom style for regex keys
- moved select2 styling to its own file
2024-05-07 05:44:18 +02:00
Wolfsblvt
5a45e64999 Regex matching for keys and secondary keys 2024-05-07 02:52:22 +02:00
Wolfsblvt
70a2f71e33 WI switch key controls to multi input
- Switch key/secondarykey controls to select2 input
- Custom tokenizer for regex parsing, allowing comma in regex
- Keep mobile-compatibility by switching to textarea
- select2 utility method to pre-fill options
- New inline display mode of select2 multi to save space
2024-05-07 02:01:54 +02:00
Cohee
4a70e68c22 Add ping endpoint 2024-05-07 01:27:17 +03:00
Cohee
542018cecb Fix group weight clamping 2024-05-06 22:55:31 +03:00
Cohee
5e7c214c89 Substitute macros in text to classify 2024-05-06 22:02:13 +03:00
Cohee
12eabd167d #2187 Add negative prefix arg to /sd command 2024-05-06 21:39:07 +03:00
Cohee
c73bfbd7b0 Safari bruh moment 2024-05-06 21:21:03 +03:00
Cohee
7063fce2af Selectable openrouter providers 2024-05-06 19:26:20 +03:00
Cohee
694cf6f762 Fix field name 2024-05-06 17:27:43 +03:00
Cohee
83c77c1f18 Split group weight and trigger% 2024-05-06 17:00:42 +03:00
Cohee
d54ccece5c Merge pull request #2184 from bdashore3/fixed-slash-command
Fix the /send command
2024-05-06 16:25:09 +03:00
kingbri
96506947cb Messages + Instruct: Fix /send with name= if name is empty
If name is empty, don't try appending it to the message. This applies
for both instruct and non-instruct modes.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-05-05 20:35:03 -04:00
Cohee
afc3071576 Add name argument for /send.
Tech debt: move to new STscript branch
2024-05-06 01:18:59 +03:00
Cohee
10727d9a02 Add plugins update script 2024-05-06 00:49:00 +03:00
Cohee
55d31a976f Add generic mediawiki downloader 2024-05-05 22:26:13 +03:00
Cohee
181b5aff97 Add Groq as chat completion source 2024-05-05 18:53:12 +03:00
Cohee
31f1b34911 Add Perplexity L3-sonar models 2024-05-05 18:21:58 +03:00
Cohee
ef5499c8dc Remove disable attribute from send_textarea. It never worked. 2024-05-05 14:27:20 +03:00
Cohee
292ecf580e #2182 Add quiet prompts to WI buffer 2024-05-05 14:23:54 +03:00
Cohee
de1ca9af74 Add type casts 2024-05-05 13:51:16 +03:00
Cohee
75832c1ad6 Fix group removal 2024-05-05 01:08:49 +03:00
Cohee
39a54d158d Per-entry group scoring 2024-05-05 00:42:33 +03:00
Cohee
2bf9869e5f Add WI group scoring mode 2024-05-04 23:51:28 +03:00
Cohee
b13434c505 Merge branch 'release' into staging 2024-05-04 20:45:48 +03:00
Cohee
5197809d6b Add global variables to TypeScript definitions. Fix some errors 2024-05-04 20:44:41 +03:00
RossAscends
204a934553 update coding sensei with proper codeblock format 2024-05-05 00:06:46 +09:00
Cohee
de1bb90c23 #2180 Add critical style tag 2024-05-04 15:36:25 +03:00
Cohee
478be72659 #2181 Unstuck moving images 2024-05-04 14:20:59 +03:00
Cohee
d972ed5a2b #2180 Add preload for style 2024-05-04 14:02:53 +03:00
RossAscends
932d3dc10c fix tabby sampler viz, clarify grammar title 2024-05-04 15:10:47 +09:00
Cohee
f610d5930c Update readme.md 2024-05-04 02:50:41 +03:00
Cohee
05db2552b3 Fix Top K disabled state for Infermatic.
Also an icon.
2024-05-04 02:37:05 +03:00
Cohee
7bfd666321 Add llama 3 tokenizer 2024-05-03 23:59:39 +03:00
Yokayo
a02f5ead7e Some localization fixes 2024-05-04 03:37:55 +07:00
Yokayo
d9fae7a02c Fix tabs 2024-05-04 02:52:19 +07:00
Yokayo
29e2e8f607 Add localizable strings to two extensions & translate them 2024-05-04 02:44:15 +07:00
Cohee
7bc87b6e28 8x22b is supposed to have 64k tokens 2024-05-03 21:36:41 +03:00
Cohee
ed65ddf981 Add Open Mixtral 8x22b model 2024-05-03 20:22:17 +03:00
Cohee
3c2017c7b8 Fix Mistral's Chat Completion moment 2024-05-03 20:22:03 +03:00
Gabraham
4e99c3e4cb Disabled forced 4 spaces indented sublists for markdown formatting
- For #2176
2024-05-03 13:15:38 -04:00
Cohee
6b2b849a26 Add server history connect missing attributes 2024-05-03 20:05:42 +03:00
Cohee
b69c5bcd17 Merge pull request #2177 from sasha0552/vllm-support
vLLM support
2024-05-03 20:03:05 +03:00
Cohee
7b87f44518 Clean-up API-specific settings 2024-05-03 20:02:13 +03:00
RossAscends
5ab1e74c5f WIP Debug Menu button to copy API setup to clipboard. 2024-05-03 16:35:32 +09:00
sasha0552
2bd239fe81 Initial vLLM support 2024-05-02 22:40:40 +00:00
Cohee
1a219e32fe Switch sheld to use flex layout 2024-05-02 23:15:17 +03:00
Cohee
203146f7e2 Remove borders from scrollbar gutters.
Leave for moving UI vertical
2024-05-02 23:06:16 +03:00
Cohee
73bea1f454 Merge pull request #2175 from Wolfsblvt/wi-search-quickselect
WI world search allows quick-select
2024-05-02 22:51:24 +03:00
Cohee
408151c9cb Use menu_button style colors 2024-05-02 22:50:07 +03:00
Wolfsblvt
f0adbc3c28 WI world search allows quick-select 2024-05-02 20:04:24 +02:00
Cohee
9acf057aae Fix reset on generic draggables 2024-05-02 01:34:47 +03:00
XTer
6c44f5b3fd 增加了提示性信息 2024-03-14 01:21:04 +08:00
XTer
42083b371b 添加了第一版GSVI的TTS适配 2024-03-14 00:36:56 +08:00
272 changed files with 48295 additions and 15088 deletions

View File

@@ -8,3 +8,5 @@ Start.bat
cloudflared.exe
access.log
/data
/cache
.DS_Store

View File

@@ -5,7 +5,7 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{js, conf, json}]
[*.{js, conf, json, css, less, html}]
charset = utf-8
indent_style = space
indent_size = 4

View File

@@ -44,6 +44,7 @@ module.exports = {
toastr: 'readonly',
Readability: 'readonly',
isProbablyReaderable: 'readonly',
ePub: 'readonly',
},
},
],

3
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,3 @@
## Checklist:
- [ ] I have read the [Contributing guidelines](https://github.com/SillyTavern/SillyTavern/blob/release/CONTRIBUTING.md).

102
.github/readme.md vendored
View File

@@ -144,12 +144,14 @@ A full list of included extensions and tutorials on how to use them can be found
8. The server will then start, and SillyTavern will pop up in your browser.
## Installing via SillyTavern Launcher
1. Install [Git for Windows](https://gitforwindows.org/)
2. Open Windows Explorer (`Win+E`) and make or choose a folder where you wanna install the launcher to
3. Open a Command Prompt inside that folder by clicking in the 'Address Bar' at the top, typing `cmd`, and pressing Enter.
4. When you see a black box, insert the following command: `git clone https://github.com/SillyTavern/SillyTavern-Launcher.git`
5. Double-click on `installer.bat` and choose what you wanna install
6. After installation double-click on `launcher.bat`
1. On your keyboard: press **`WINDOWS + R`** to open Run dialog box. Then, run the following command to install git:
```shell
cmd /c winget install -e --id Git.Git
```
2. On your keyboard: press **`WINDOWS + E`** to open File Explorer, then navigate to the folder where you want to install the launcher. Once in the desired folder, type `cmd` into the address bar and press enter. Then, run the following command:
```shell
git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher && start installer.bat
```
## Installing via GitHub Desktop
(This allows git usage **only** in GitHub Desktop, if you want to use `git` on the command line too, you also need to install [Git for Windows](https://gitforwindows.org/))
@@ -183,18 +185,79 @@ For MacOS / Linux all of these will be done in a Terminal.
### For Linux users
1. Open your favorite terminal and install git
2. Download Sillytavern Launcher with: `git clone https://github.com/SillyTavern/SillyTavern-Launcher.git`
3. Navigate to the SillyTavern-Launcher with: `cd SillyTavern-Launcher`
4. Start the install launcher with: `chmod +x install.sh && ./install.sh` and choose what you wanna install
5. After installation start the launcher with: `chmod +x launcher.sh && ./launcher.sh`
2. Git clone the Sillytavern-Launcher with:
```shell
git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher
```
3. Start the installer.sh with:
```shell
chmod +x install.sh && ./install.sh
```
4. After installation start the launcher.sh with:
```shell
chmod +x launcher.sh && ./launcher.sh
```
### For Mac users
1. Open a terminal and install brew with: `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
2. Then install git with: `brew install git`
3. Download Sillytavern Launcher with: `git clone https://github.com/SillyTavern/SillyTavern-Launcher.git`
4. Navigate to the SillyTavern-Launcher with: `cd SillyTavern-Launcher`
5. Start the install launcher with: `chmod +x install.sh && ./install.sh` and choose what you wanna install
6. After installation start the launcher with: `chmod +x launcher.sh && ./launcher.sh`
1. Open a terminal and install brew with:
```shell
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
2. Install git with:
```shell
brew install git
```
3. Git clone the Sillytavern-Launcher with:
```shell
git clone https://github.com/SillyTavern/SillyTavern-Launcher.git && cd SillyTavern-Launcher
```
4. Start the installer.sh with:
```shell
chmod +x install.sh && ./install.sh
```
5. After installation start the launcher.sh with:
```shell
chmod +x launcher.sh && ./launcher.sh
```
## 🐋 Installing via Docker
These instructions assume you have installed Docker, are able to access your command line for the installation of containers, and familiar with their general operation.
### Building the image yourself
We have a comprehensive guide on using SillyTavern in Docker [here](http://docs.sillytavern.app/installation/docker/) which covers installations on Windows, macOS and Linux! Give it a read if you wish to build the image yourself.
### Using the GitHub Container Registry (easiest)
You will need two mandatory directory mappings and a port mapping to allow SillyTavern to function. In the command, replace your selections in the following places:
#### Container Variables
##### Volume Mappings
- [config] - The directory where SillyTavern configuration files will be stored on your host machine
- [data] - The directory where SillyTavern user data (including characters) will be stored on your host machine
- [plugins] - (optional) The directory where SillyTavern server plugins will be stored on your host machine
##### Port Mappings
- [PublicPort] - The port to expose the traffic on. This is mandatory, as you will be accessing the instance from outside of its virtual machine container. DO NOT expose this to the internet without implementing a separate service for security.
##### Additional Settings
- [TimeZone] - The timezone your instance should use. This is useful for making logs match your local time for easier troubleshooting. Use your TZ Identifier. (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
- [DockerNet] - The docker network that the container should be created with a connection to. If you don't know what it is, see the [official Docker documentation](https://docs.docker.com/reference/cli/docker/network/).
- [version] - On the right-hand side of this GitHub page, you'll see "Packages". Select the "sillytavern" package and you'll see the image versions. The image tag "latest" will keep you up-to-date with the current release. You can also utilize "staging" and "release" tags that point to the nightly images of the respective branches, but this may not be appropriate, if you are utilizing extensions that could be broken, and may need time to update.
#### Install command
1. Open your Command Line
2. Run the following command
`docker create --name='sillytavern' --net='[DockerNet]' -e TZ="[TimeZone]" -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'`
> Note that 8000 is a default listening port. Don't forget to use an appropriate port if you change it in the config.
## 📱 Mobile - Installing via termux
@@ -205,7 +268,7 @@ For MacOS / Linux all of these will be done in a Terminal.
## API keys management
SillyTavern saves your API keys to a `secrets.json` file in the server directory.
SillyTavern saves your API keys to a `secrets.json` file in the user data directory (`/data/default-user/secrets.json` is the default path).
By default, they will not be exposed to a frontend after you enter them and reload the page.
@@ -220,7 +283,7 @@ Most often this is for people who want to use SillyTavern on their mobile phones
However, it can be used to allow remote connections from anywhere as well.
**IMPORTANT: SillyTavern is a single-user program, so anyone who logs in will be able to see all characters and chats, and be able to change any settings inside the UI.**
**IMPORTANT: Refer to the official guide if you want to configure SillyTavern user accounts with (optional) password protection: [Users](https://docs.sillytavern.app/installation/st-1.12.0-migration-guide/#users).**
### 1. Managing whitelisted IPs
@@ -326,7 +389,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.**
* TAI Base by Humi: Unknown license
* TAI Base by Humi: MIT
* Cohee's modifications and derived code: AGPL v3
* RossAscends' additions: AGPL v3
* Portions of CncAnon's TavernAITurbo mod: Unknown license
@@ -347,6 +410,7 @@ GNU Affero General Public License for more details.**
* Korean translation by @doloroushyeonse
* k_euler_a support for Horde by <https://github.com/Teashrock>
* Chinese translation by [@XXpE3](https://github.com/XXpE3), 中文 ISSUES 可以联系 @XXpE3
* Docker guide by [@mrguymiah](https://github.com/mrguymiah) and [@Bronya-Rand](https://github.com/Bronya-Rand)
<!-- LINK GROUP -->
[back-to-top]: https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square

View File

@@ -30,7 +30,7 @@ jobs:
run: |
echo "IMAGE_NAME=${REPO,,}" >> ${GITHUB_ENV}
# Using the following workaround because currently GitHub Actions
# Using the following workaround because currently GitHub Actions
# does not support logical AND/OR operations on triggers
# It's currently not possible to have `branches` under the `schedule` trigger
- name: Checkout the release branch (on release)
@@ -65,7 +65,12 @@ jobs:
id: metadata
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: ${{ env.BRANCH_NAME }}
# Release version tag if the workflow is triggered by a release
# Branch name tag if the workflow is triggered by a push
# Latest tag if the branch is release and the workflow is triggered by a push
tags: |
${{ github.event_name == 'release' && github.ref_name || env.BRANCH_NAME }}
${{ github.event_name == 'push' && env.BRANCH_NAME == 'release' && 'latest' || '' }}
# Login into package repository as the person who created the release
- name: Log in to the Container registry
@@ -87,10 +92,3 @@ jobs:
push: true
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
# If the workflow is triggered by a release, marks and push the image as such
- name: Docker tag latest and push
if: ${{ github.event_name == 'release' }}
run: |
docker tag $IMAGE_NAME:${{ github.ref_name }} $IMAGE_NAME:latest
docker push $IMAGE_NAME:latest

32
.github/workflows/update-i18n.yaml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Update i18n data
on: workflow_dispatch
jobs:
build:
runs-on: ubuntu-latest
permissions: # Job-level permissions configuration starts here
contents: write # 'write' access to repository contents
steps:
- name: disable auto crlf
uses: steve02081504/disable-autocrlf@v1
- uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
- name: Create local changes
run: |
aria2c https://raw.githubusercontent.com/SillyTavern/SillyTavern-i18n/main/generate.py
aria2c https://raw.githubusercontent.com/SillyTavern/SillyTavern-i18n/main/requirements.txt
pip install -r ./requirements.txt
python ./generate.py "" --sort-keys
rm -f ./generate.py ./requirements.txt
- name: add all
run: git add -A
- name: push
uses: actions-go/push@master
with:
author-email: 41898282+github-actions[bot]@users.noreply.github.com
author-name: github-actions[bot]
commit-message: 'i18n changes'
remote: origin

2
.gitignore vendored
View File

@@ -47,3 +47,5 @@ access.log
public/css/user.css
/plugins/
/data
/default/scaffold
public/scripts/extensions/third-party

View File

@@ -5,4 +5,6 @@ node_modules/
secrets.json
/dist
/backups/
/data
/cache
access.log

View File

@@ -4,7 +4,8 @@
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"dbaeumer.vscode-eslint",
"EditorConfig.EditorConfig"
"EditorConfig.EditorConfig",
"mrcrowl.easy-less"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []

32
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,32 @@
# How to contribute to SillyTavern
## Setting up the dev environment
1. Required software: git and node.
2. Recommended editor: Visual Studio Code.
3. You can also use GitHub Codespaces which sets up everything for you.
## Getting the code ready
1. Register a GitHub account.
2. Fork this repository under your account.
3. Clone the fork onto your machine.
4. Open the cloned repository in the code editor.
5. Create a git branch (recommended).
6. Make your changes and test them locally.
7. Commit the changes and push the branch to the remote repo.
8. Go to GitHub, and open a pull request, targeting the upstream branch.
## Contribution guidelines
1. Our standards are pretty low, but make sure the code is not too ugly:
- Run VS Code's autoformat when you're done.
- Check with ESLint by running `npm run lint`, then fix the errors.
- Use common sense and follow existing naming conventions.
2. Create pull requests for the staging branch, 99% of contributions should go there. That way people could test your code before the next stable release.
3. You can still send a pull request for release in the following scenarios:
- Updating README.
- Updating GitHub Actions.
- Hotfixing a critical bug.
4. Project maintainers will test and can change your code before merging.
5. Mind the license. Your contributions will be licensed under the GNU Affero General Public License. If you don't know what that implies, consult your lawyer.

9
backups/!README.md Normal file
View File

@@ -0,0 +1,9 @@
# Looking for setting snapshots or chat backups?
Individual user backups are now located in the data directory.
Example for the default user under default data root:
/data/default-user/backups
This folder remains for historical purposes only.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 598 KiB

View File

@@ -11,6 +11,14 @@
"filename": "themes/Cappuccino.json",
"type": "theme"
},
{
"filename": "themes/Celestial Macaron.json",
"type": "theme"
},
{
"filename": "themes/Dark V 1.0.json",
"type": "theme"
},
{
"filename": "backgrounds/__transparent.png",
"type": "background"
@@ -107,14 +115,6 @@
"filename": "default_Seraphina.png",
"type": "character"
},
{
"filename": "default_CodingSensei.png",
"type": "character"
},
{
"filename": "default_FluxTheCat.png",
"type": "character"
},
{
"filename": "Seraphina",
"type": "sprites"
@@ -484,7 +484,11 @@
"type": "context"
},
{
"filename": "presets/context/DreamGen Role-Play V1.json",
"filename": "presets/context/DreamGen Role-Play V1 ChatML.json",
"type": "context"
},
{
"filename": "presets/context/DreamGen Role-Play V1 Llama3.json",
"type": "context"
},
{
@@ -564,7 +568,11 @@
"type": "instruct"
},
{
"filename": "presets/instruct/DreamGen Role-Play V1.json",
"filename": "presets/instruct/DreamGen Role-Play V1 ChatML.json",
"type": "instruct"
},
{
"filename": "presets/instruct/DreamGen Role-Play V1 Llama3.json",
"type": "instruct"
},
{

View File

@@ -8,5 +8,5 @@
"trim_sentences": true,
"include_newline": false,
"single_line": false,
"name": "DreamGen Role-Play V1"
"name": "DreamGen Role-Play V1 ChatML"
}

View File

@@ -0,0 +1,12 @@
{
"story_string": "<|start_header_id|>system<|end_header_id|>\n\n{{#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}}",
"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.",
"chat_start": "<|eot_id|>\n<|start_header_id|>user<|end_header_id|>\n\nStart the role-play between {{char}} and {{user}}.",
"use_stop_strings": false,
"allow_jailbreak": false,
"always_force_name2": false,
"trim_sentences": true,
"include_newline": false,
"single_line": false,
"name": "DreamGen Role-Play V1 Llama3"
}

View File

@@ -20,5 +20,5 @@
"user_alignment_message": "",
"system_same_as_user": true,
"last_system_sequence": "",
"name": "DreamGen Role-Play V1"
"name": "DreamGen Role-Play V1 ChatML"
}

View File

@@ -0,0 +1,18 @@
{
"system_prompt": "You are an intelligent, skilled, versatile writer.\n\nYour task is to write a role-play based on the information below.",
"input_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{user}}<|end_header_id|>\n\n",
"output_sequence": "<|eot_id|>\n<|start_header_id|>writer character: {{char}}<|end_header_id|>\n\n",
"first_output_sequence": "",
"last_output_sequence": "",
"system_sequence_prefix": "",
"system_sequence_suffix": "",
"stop_sequence": "",
"separator_sequence": "",
"wrap": false,
"macro": true,
"names": false,
"names_force_groups": false,
"activation_regex": "",
"skip_examples": false,
"name": "DreamGen Role-Play V1 Llama3"
}

View File

@@ -231,6 +231,7 @@
"api_url_scale": "",
"show_external_models": false,
"assistant_prefill": "",
"assistant_impersonation": "",
"human_sysprompt_message": "Let's get started. Please generate your response based on the information and instructions provided above.",
"use_ai21_tokenizer": false,
"use_google_tokenizer": false,

View File

@@ -33,8 +33,8 @@
"negative_prompt": "",
"grammar_string": "",
"banned_tokens": "",
"ignore_eos_token_aphrodite": false,
"spaces_between_special_tokens_aphrodite": true,
"ignore_eos_token": false,
"spaces_between_special_tokens": true,
"type": "ooba",
"legacy_api": false,
"sampler_order": [

View File

@@ -33,8 +33,8 @@
"negative_prompt": "",
"grammar_string": "",
"banned_tokens": "",
"ignore_eos_token_aphrodite": false,
"spaces_between_special_tokens_aphrodite": true,
"ignore_eos_token": false,
"spaces_between_special_tokens": true,
"type": "ooba",
"legacy_api": false,
"sampler_order": [

View File

@@ -33,8 +33,8 @@
"negative_prompt": "",
"grammar_string": "",
"banned_tokens": "",
"ignore_eos_token_aphrodite": false,
"spaces_between_special_tokens_aphrodite": true,
"ignore_eos_token": false,
"spaces_between_special_tokens": true,
"type": "ooba",
"legacy_api": false,
"sampler_order": [

View File

@@ -387,14 +387,8 @@
}
],
"tag_map": {
"default_FluxTheCat.png": [
"1345561466591"
],
"default_Seraphina.png": [
"1345561466591"
],
"default_CodingSensei.png": [
"1345561466591"
]
},
"nai_settings": {
@@ -630,6 +624,7 @@
"show_external_models": false,
"proxy_password": "",
"assistant_prefill": "",
"assistant_impersonation": "",
"use_ai21_tokenizer": false
}
}

View File

@@ -1,7 +1,7 @@
{
"name": "Cappuccino",
"blur_strength": 3,
"main_text_color": "rgba(255, 255, 255, 1)",
"main_text_color": "rgba(235, 235, 235, 1)",
"italics_text_color": "rgba(230, 210, 190, 1)",
"underline_text_color": "rgba(205, 180, 160, 1)",
"quote_text_color": "rgba(165, 140, 115, 1)",

View File

@@ -0,0 +1,37 @@
{
"name": "Celestial Macaron",
"blur_strength": 10,
"main_text_color": "rgba(229, 175, 162, 1)",
"italics_text_color": "rgba(146, 147, 161, 1)",
"underline_text_color": "rgba(157, 215, 198, 1)",
"quote_text_color": "rgba(197, 202, 206, 1)",
"blur_tint_color": "rgba(23, 36, 55, 0.9)",
"chat_tint_color": "rgba(18, 26, 40, 0.9)",
"user_mes_blur_tint_color": "rgba(51, 67, 90, 0.7)",
"bot_mes_blur_tint_color": "rgba(23, 36, 55, 0.75)",
"shadow_color": "rgba(0, 0, 0, 0.3)",
"shadow_width": 1,
"border_color": "rgba(60, 74, 110, 0.93)",
"font_scale": 1,
"fast_ui_mode": false,
"waifuMode": false,
"avatar_style": 0,
"chat_display": 1,
"noShadows": true,
"chat_width": 58,
"timer_enabled": true,
"timestamps_enabled": true,
"timestamp_model_icon": false,
"mesIDDisplay_enabled": true,
"hideChatAvatars_enabled": false,
"message_token_count_enabled": true,
"expand_message_actions": true,
"enableZenSliders": false,
"enableLabMode": false,
"hotswap_enabled": true,
"custom_css": "",
"bogus_folders": true,
"zoomed_avatar_magnification": false,
"reduced_motion": false,
"compact_input_area": true
}

View File

@@ -0,0 +1,37 @@
{
"name": "Dark V 1.0",
"blur_strength": 13,
"main_text_color": "rgba(207, 207, 197, 1)",
"italics_text_color": "rgba(145, 145, 145, 1)",
"underline_text_color": "rgba(145, 145, 145, 1)",
"quote_text_color": "rgba(198, 193, 151, 1)",
"blur_tint_color": "rgba(29, 33, 40, 0.9)",
"chat_tint_color": "rgba(29, 33, 40, 0.9)",
"user_mes_blur_tint_color": "rgba(29, 33, 40, 0.9)",
"bot_mes_blur_tint_color": "rgba(29, 33, 40, 0.9)",
"shadow_color": "rgba(0, 0, 0, 0.9)",
"shadow_width": 2,
"border_color": "rgba(0, 0, 0, 1)",
"font_scale": 1,
"fast_ui_mode": false,
"waifuMode": false,
"avatar_style": 0,
"chat_display": 0,
"noShadows": false,
"chat_width": 55,
"timer_enabled": false,
"timestamps_enabled": false,
"timestamp_model_icon": false,
"mesIDDisplay_enabled": false,
"hideChatAvatars_enabled": false,
"message_token_count_enabled": false,
"expand_message_actions": false,
"enableZenSliders": false,
"enableLabMode": false,
"hotswap_enabled": true,
"custom_css": "",
"bogus_folders": true,
"zoomed_avatar_magnification": true,
"reduced_motion": true,
"compact_input_area": false
}

View File

@@ -0,0 +1,26 @@
# Content Scaffolding
Content files in this folder will be copied for all users (old and new) on the server startup.
1. You **must** create an `index.json` file in `/default/scaffold` for it to work. The syntax is the same as for default content.
2. All file paths should be relative to `/default/scaffold`, the use of subdirectories is allowed.
3. Scaffolded files are copied first, so they override any of the default files (presets/settings/etc.) that have the same file name.
## Example
```json
[
{
"filename": "themes/Midnight.json",
"type": "theme"
},
{
"filename": "backgrounds/city.png",
"type": "background"
},
{
"filename": "characters/Charlie.png",
"type": "character"
}
]
```

View File

@@ -10,4 +10,5 @@ services:
volumes:
- "./config:/home/node/app/config"
- "./data:/home/node/app/data"
- "./plugins:/home/node/app/plugins"
restart: unless-stopped

View File

@@ -15,6 +15,11 @@
"**/node_modules/*",
"public/lib",
"backups/*",
"data/*"
"data/*",
"**/dist/*",
"dist/*",
"cache/*",
"src/tokenizers/*",
"docker/*",
]
}

92
package-lock.json generated
View File

@@ -1,19 +1,18 @@
{
"name": "sillytavern",
"version": "1.12.0-preview",
"version": "1.12.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sillytavern",
"version": "1.12.0-preview",
"version": "1.12.2",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
"@agnai/sentencepiece-js": "^1.1.1",
"@agnai/web-tokenizers": "^0.1.3",
"@dqbd/tiktoken": "^1.0.13",
"@zeldafan0225/ai_horde": "^4.0.1",
"@zeldafan0225/ai_horde": "^5.1.0",
"archiver": "^7.0.1",
"bing-translate-api": "^2.9.1",
"body-parser": "^1.20.2",
@@ -26,7 +25,6 @@
"express": "^4.19.2",
"form-data": "^4.0.0",
"google-translate-api-browser": "^3.0.1",
"gpt3-tokenizer": "^1.1.5",
"he": "^1.2.0",
"helmet": "^7.1.0",
"ip-matching": "^2.1.2",
@@ -46,10 +44,11 @@
"sanitize-filename": "^1.6.3",
"sillytavern-transformers": "^2.14.6",
"simple-git": "^3.19.1",
"tiktoken": "^1.0.15",
"vectra": "^0.2.2",
"wavefile": "^11.0.0",
"write-file-atomic": "^5.0.1",
"ws": "^8.13.0",
"ws": "^8.17.1",
"yaml": "^2.3.4",
"yargs": "^17.7.1",
"yauzl": "^2.10.0"
@@ -61,6 +60,9 @@
"@types/jquery": "^3.5.29",
"eslint": "^8.55.0",
"jquery": "^3.6.4"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -82,10 +84,6 @@
"version": "0.1.3",
"license": "Apache-2.0"
},
"node_modules/@dqbd/tiktoken": {
"version": "1.0.13",
"license": "MIT"
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"dev": true,
@@ -882,12 +880,14 @@
"license": "ISC"
},
"node_modules/@zeldafan0225/ai_horde": {
"version": "4.0.1",
"license": "MIT",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@zeldafan0225/ai_horde/-/ai_horde-5.1.0.tgz",
"integrity": "sha512-rPC0nmmFSXK808Oon0zFPA7yGSUKBXiLtMejkmKTyfAzzOHHQt/i2lO4ccfN2e355LzX1lBLwSi+nlATVA43Sw==",
"dependencies": {
"@thunder04/supermap": "^3.0.2",
"centra": "^2.5.0",
"esbuild": "^0.12.28"
"@thunder04/supermap": "^3.0.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/abort-controller": {
@@ -1214,10 +1214,6 @@
"version": "1.1.1",
"license": "MIT"
},
"node_modules/array-keyed-map": {
"version": "2.1.3",
"license": "ISC"
},
"node_modules/async": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
@@ -2128,12 +2124,6 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/esbuild": {
"name": "dry-uninstall",
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/dry-uninstall/-/dry-uninstall-0.3.0.tgz",
"integrity": "sha512-b8h94RVpETWkVV59x62NsY++79bM7Si6Dxq7a4iVxRcJU3ZJJ4vaiC7wUZwM8WDK0ySRL+i+T/1SMAzbJLejYA=="
},
"node_modules/escalade": {
"version": "3.1.1",
"license": "MIT",
@@ -2739,16 +2729,6 @@
"version": "1.1.4",
"license": "MIT"
},
"node_modules/gpt3-tokenizer": {
"version": "1.1.5",
"license": "MIT",
"dependencies": {
"array-keyed-map": "^2.1.3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -3889,7 +3869,6 @@
},
"node_modules/punycode": {
"version": "2.3.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
@@ -4403,6 +4382,11 @@
"dev": true,
"license": "MIT"
},
"node_modules/tiktoken": {
"version": "1.0.15",
"resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.15.tgz",
"integrity": "sha512-sCsrq/vMWUSEW29CJLNmPvWxlVp7yh2tlkAjpJltIKqp5CKf98ZNpdeHRmAlPVFlGEbswDc6SmI8vz64W/qErw=="
},
"node_modules/timm": {
"version": "1.7.1",
"license": "MIT"
@@ -4434,8 +4418,15 @@
}
},
"node_modules/tr46": {
"version": "0.0.3",
"license": "MIT"
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
"integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
"dependencies": {
"punycode": "^2.3.1"
},
"engines": {
"node": ">=18"
}
},
"node_modules/truncate-utf8-bytes": {
"version": "1.0.2",
@@ -4584,19 +4575,27 @@
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"license": "BSD-2-Clause"
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
"engines": {
"node": ">=12"
}
},
"node_modules/whatwg-fetch": {
"version": "3.6.18",
"license": "MIT"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"license": "MIT",
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
"integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
"tr46": "^5.0.0",
"webidl-conversions": "^7.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/which": {
@@ -4660,8 +4659,9 @@
}
},
"node_modules/ws": {
"version": "8.13.0",
"license": "MIT",
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"engines": {
"node": ">=10.0.0"
},

View File

@@ -2,8 +2,7 @@
"dependencies": {
"@agnai/sentencepiece-js": "^1.1.1",
"@agnai/web-tokenizers": "^0.1.3",
"@dqbd/tiktoken": "^1.0.13",
"@zeldafan0225/ai_horde": "^4.0.1",
"@zeldafan0225/ai_horde": "^5.1.0",
"archiver": "^7.0.1",
"bing-translate-api": "^2.9.1",
"body-parser": "^1.20.2",
@@ -16,7 +15,6 @@
"express": "^4.19.2",
"form-data": "^4.0.0",
"google-translate-api-browser": "^3.0.1",
"gpt3-tokenizer": "^1.1.5",
"he": "^1.2.0",
"helmet": "^7.1.0",
"ip-matching": "^2.1.2",
@@ -36,14 +34,18 @@
"sanitize-filename": "^1.6.3",
"sillytavern-transformers": "^2.14.6",
"simple-git": "^3.19.1",
"tiktoken": "^1.0.15",
"vectra": "^0.2.2",
"wavefile": "^11.0.0",
"write-file-atomic": "^5.0.1",
"ws": "^8.13.0",
"ws": "^8.17.1",
"yaml": "^2.3.4",
"yargs": "^17.7.1",
"yauzl": "^2.10.0"
},
"engines": {
"node": ">= 18"
},
"overrides": {
"parse-bmfont-xml": {
"xml2js": "^0.5.0"
@@ -57,8 +59,8 @@
"axios": {
"follow-redirects": "^1.15.4"
},
"@zeldafan0225/ai_horde": {
"esbuild": "npm:dry-uninstall"
"node-fetch": {
"whatwg-url": "^14.0.0"
}
},
"name": "sillytavern",
@@ -68,13 +70,15 @@
"type": "git",
"url": "https://github.com/SillyTavern/SillyTavern.git"
},
"version": "1.12.0-preview",
"version": "1.12.2",
"scripts": {
"start": "node server.js",
"start-multi": "node server.js --disableCsrf",
"start:no-csrf": "node server.js --disableCsrf",
"postinstall": "node post-install.js",
"lint": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js",
"lint-fix": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js --fix"
"lint:fix": "eslint \"src/**/*.js\" \"public/**/*.js\" ./*.js --fix",
"plugins:update": "node plugins update",
"plugins:install": "node plugins install"
},
"bin": {
"sillytavern": "./server.js"

75
plugins.js Normal file
View File

@@ -0,0 +1,75 @@
// Plugin manager script.
// Usage: node plugins.js update
// More operations coming soon.
const { default: git } = require('simple-git');
const fs = require('fs');
const path = require('path');
const { color } = require('./src/util');
const pluginsPath = './plugins';
const command = process.argv[2];
if (command === 'update') {
console.log(color.magenta('Updating all plugins'));
updatePlugins();
}
if (command === 'install') {
const pluginName = process.argv[3];
console.log('Installing a new plugin', color.green(pluginName));
installPlugin(pluginName);
}
async function updatePlugins() {
const directories = fs.readdirSync(pluginsPath)
.filter(file => !file.startsWith('.'))
.filter(file => fs.statSync(path.join(pluginsPath, file)).isDirectory());
console.log(`Found ${color.cyan(directories.length)} directories in ./plugins`);
for (const directory of directories) {
try {
console.log(`Updating plugin ${color.green(directory)}...`);
const pluginPath = path.join(pluginsPath, directory);
const pluginRepo = git(pluginPath);
await pluginRepo.fetch();
const commitHash = await pluginRepo.revparse(['HEAD']);
const trackingBranch = await pluginRepo.revparse(['--abbrev-ref', '@{u}']);
const log = await pluginRepo.log({
from: commitHash,
to: trackingBranch,
});
if (log.total === 0) {
console.log(`Plugin ${color.blue(directory)} is already up to date`);
continue;
}
await pluginRepo.pull();
const latestCommit = await pluginRepo.revparse(['HEAD']);
console.log(`Plugin ${color.green(directory)} updated to commit ${color.cyan(latestCommit)}`);
} catch (error) {
console.error(color.red(`Failed to update plugin ${directory}: ${error.message}`));
}
}
console.log(color.magenta('All plugins updated!'));
}
async function installPlugin(pluginName) {
try {
const pluginPath = path.join(pluginsPath, path.basename(pluginName, '.git'));
if (fs.existsSync(pluginPath)) {
return console.log(color.yellow(`Directory already exists at ${pluginPath}`));
}
await git().clone(pluginName, pluginPath, { '--depth': 1 });
console.log(`Plugin ${color.green(pluginName)} installed to ${color.cyan(pluginPath)}`);
}
catch (error) {
console.error(color.red(`Failed to install plugin ${pluginName}`), error);
}
}

122
public/css/animations.css Normal file
View File

@@ -0,0 +1,122 @@
/* Fade animations with opacity */
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
/* Pop animations with opacity and vertical scaling */
@keyframes pop-in {
0% {
opacity: 0;
transform: scaleY(0);
}
/* Make the scaling faster on pop-in, otherwise it looks a bit weird */
33% {
transform: scaleY(1);
}
100% {
opacity: 1;
transform: scaleY(1);
}
}
@keyframes pop-out {
0% {
opacity: 1;
transform: scaleY(1);
}
100% {
opacity: 0;
transform: scaleY(0);
}
}
/* Flashing for highlighting animation */
@keyframes flash {
20%,
60%,
100% {
opacity: 1;
}
0%,
40%,
80% {
opacity: 0.2;
}
}
/* Pulsing highlight, slightly resizing the element */
@keyframes pulse {
from {
transform: scale(1);
filter: brightness(1.1);
}
to {
transform: scale(1.01);
filter: brightness(1.3);
}
}
/* Ellipsis animation */
@keyframes ellipsis {
0% {
content: ""
}
25% {
content: "."
}
50% {
content: ".."
}
75% {
content: "..."
}
}
/* HEINOUS */
@keyframes infinite-spinning {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
/* STscript animation */
@keyframes script_progress_pulse {
0%,
100% {
border-top-color: var(--progColor);
}
50% {
border-top-color: var(--progFlashColor);
}
}

View File

@@ -36,7 +36,6 @@ label[for="extensions_autoconnect"] {
.extensions_info {
text-align: left;
margin: 0 1em;
}
.extensions_info h3 {
@@ -97,114 +96,11 @@ input.extension_missing[type="checkbox"] {
flex-direction: column;
}
/** LEFT COLUMN **/
/* Must be always on top */
#extensions_settings>#assets_ui {
order: -1;
/* Fixes order of settings for extensions */
.extension_container {
display: contents;
}
#extensions_settings>.expression_settings {
order: 2;
}
#extensions_settings>.background_settings {
order: 3;
}
#extensions_settings>.sd_settings {
order: 4;
}
#extensions_settings>#tts_settings {
order: 5;
}
#extensions_settings>#rvc_settings {
order: 6;
}
#extensions_settings>.objective-settings {
order: 7;
}
#extensions_settings>#speech_recognition_settings {
order: 8;
}
#extensions_settings>#audio_settings {
order: 9;
}
/** RIGHT COLUMN **/
#extensions_settings2>.translation_settings {
order: 1;
}
#extensions_settings2>.caption_settings {
order: 2;
}
#extensions_settings2>.quickReplySettings {
order: 3;
}
#extensions_settings2>.idle-settings {
order: 4;
}
#extensions_settings2>#memory_settings {
order: 5;
}
#extensions_settings2>.hypebot_settings {
order: 6;
}
#extensions_settings2>.regex_settings {
order: 7;
}
#extensions_settings2>.vectors_settings {
order: 8;
}
#extensions_settings2>.chromadb_settings {
order: 9;
}
#extensions_settings2>.randomizer_settings {
order: 10;
}
/** WAND MENU **/
#extensionsMenu>#ttsExtensionMenuItem {
order: 1;
}
#extensionsMenu>#sd_gen {
order: 2;
}
#extensionsMenu>#send_picture {
order: 3;
}
#extensionsMenu>#token_counter {
order: 4;
}
#extensionsMenu>#objective-task-manual-check-menu-item {
order: 5;
}
#extensionsMenu>#roll_dice {
order: 6;
}
#extensionsMenu>#translate_chat {
order: 7;
}
#extensionsMenu>#translate_input_message {
order: 8;
#extensionsMenu>div.extension_container:empty {
display: none;
}

View File

@@ -98,7 +98,7 @@
font-weight: bold;
}
.logprobs_top_candidate:not([disabled]):hover, .logprobs_top_candidate:not([disabled]):focus {
.logprobs_top_candidate:not([disabled]):hover {
background-color: rgba(0, 0, 0, 0.3);
}

View File

@@ -117,6 +117,11 @@
max-width: unset;
}
#wiActivationSettings,
#wiTopBlock {
flex-direction: column;
}
#top-settings-holder,
#top-bar {
position: fixed;

View File

@@ -0,0 +1,8 @@
/* iPhone copium land */
@media screen and (max-width: 1000px) {
.ios .popup .popup-body {
height: fit-content;
max-height: 90vh;
max-height: 90svh;
}
}

175
public/css/popup.css Normal file
View File

@@ -0,0 +1,175 @@
@import url('./popup-safari-fix.css');
dialog {
color: var(--SmartThemeBodyColor);
}
/* Closed state of the dialog */
.popup {
width: 500px;
text-align: center;
box-shadow: 0px 0px 14px var(--black70a);
border: 1px solid var(--SmartThemeBorderColor);
padding: 4px 14px;
background-color: var(--SmartThemeBlurTintColor);
border-radius: 10px;
display: flex;
flex-direction: column;
max-height: calc(100svh - 2em);
max-width: calc(100svw - 2em);
min-height: fit-content;
/* Overflow visible so elements (like toasts) can appear outside of the dialog. '.popup-body' is hiding overflow for the real content. */
overflow: visible;
/* Fix weird animation issue with font-scaling during popup open */
backface-visibility: hidden;
transform: translateZ(0);
-webkit-font-smoothing: subpixel-antialiased;
}
.popup .popup-body {
display: flex;
flex-direction: column;
overflow: hidden;
width: 100%;
height: 100%;
padding: 1px;
}
.popup .popup-content {
margin-top: 10px;
padding: 0 8px;
overflow: hidden;
flex-grow: 1;
}
.popup .popup-content h3:first-child {
/* No double spacing for the first heading needed, the .popup-content already has margin */
margin-top: 0px;
}
.popup.vertical_scrolling_dialogue_popup .popup-content {
overflow-y: auto;
}
.popup.horizontal_scrolling_dialogue_popup .popup-content {
overflow-x: auto;
}
/* Opening animation */
.popup[opening] {
animation: pop-in var(--animation-duration-slow) ease-in-out;
}
.popup[opening]::backdrop {
animation: fade-in var(--animation-duration-slow) ease-in-out;
}
/* Open state of the dialog */
.popup[open] {
color: var(--SmartThemeBodyColor);
}
.popup[open]::backdrop {
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2));
-webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength) * 2));
background-color: var(--black30a);
}
body.no-blur .popup[open]::backdrop {
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
/* Closing animation */
.popup[closing] {
animation: pop-out var(--animation-duration-slow) ease-in-out;
}
.popup[closing]::backdrop {
animation: fade-out var(--animation-duration-slow) ease-in-out;
}
.popup #toast-container {
/* Fix toastr in dialogs by actually placing it at the top of the screen via transform */
height: 100svh;
top: calc(50% + var(--topBarBlockSize));
left: 50%;
transform: translate(-50%, -50%);
/* Fix text align, popups are centered by default. toasts should not. */
text-align: left;
}
.popup-crop-wrap {
margin: 10px auto;
max-height: 75vh;
max-height: 75svh;
max-width: 100%;
}
.popup-crop-wrap img {
max-width: 100%;
/* This rule is very important, please do not ignore this! */
}
.popup-inputs {
margin-top: 10px;
font-size: smaller;
opacity: 0.7;
}
.popup-input {
margin-top: 10px;
}
.popup-controls {
margin-top: 10px;
display: flex;
align-self: center;
gap: 20px;
}
.menu_button.menu_button_default {
box-shadow: 0 0 5px var(--white20a);
}
.menu_button.popup-button-ok {
background-color: var(--crimson70a);
}
.menu_button.popup-button-ok:hover {
background-color: var(--crimson-hover);
}
.popup-controls .menu_button {
/* Popup buttons should not scale to smallest size, otherwise they will always break to multiline if multiple words */
width: unset;
/* Fix weird animation issue with fonts on brightness filter */
backface-visibility: hidden;
transform: translateZ(0);
-webkit-font-smoothing: subpixel-antialiased;
}
.popup-controls .menu_button:hover:focus-visible {
filter: brightness(1.3) saturate(1.3);
}
.popup .popup-button-close {
position: absolute;
top: -6px;
right: -6px;
width: 24px;
height: 24px;
font-size: 20px;
padding: 2px 3px 3px 2px;
filter: brightness(0.8);
/* Fix weird animation issue with font-scaling during popup open */
backface-visibility: hidden;
}

View File

@@ -19,7 +19,7 @@
#completion_prompt_manager #completion_prompt_manager_list li {
display: grid;
grid-template-columns: 4fr 80px 40px;
grid-template-columns: 4fr 80px 45px;
margin-bottom: 0.5em;
width: 100%
}

View File

@@ -23,6 +23,14 @@
opacity: 0.8;
}
.select2-selection--single .select2-selection__placeholder {
color: var(--SmartThemeEmColor);
}
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
color: var(--SmartThemeEmColor);
}
.select2-container .select2-selection--single .select2-selection__rendered {
color: var(--SmartThemeBodyColor);
line-height: revert;
@@ -49,7 +57,7 @@
color: var(--SmartThemeBodyColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 7px;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
padding: 3px 5px;
}
@@ -77,7 +85,7 @@
color: var(--SmartThemeBodyColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 7px;
font-family: "Noto Sans", "Noto Color Emoji", sans-serif;
font-family: var(--mainFontFamily);
padding: 3px 5px;
}
@@ -171,3 +179,92 @@
.select2-results__option.select2-results__message::before {
display: none;
}
.select2-selection__choice__display {
/* Fix weird alignment of the inside block */
margin-left: 3px;
margin-right: 1px;
}
/* Styling for choice remove icon */
span.select2.select2-container .select2-selection__choice__remove {
cursor: pointer;
transition: background-color 0.3s;
color: var(--SmartThemeBodyColor);
background-color: var(--black50a);
}
span.select2.select2-container .select2-selection__choice__remove:hover {
color: var(--SmartThemeBodyColor);
background-color: var(--white30a);
}
/* Custom class to support styling to show clickable choice options */
.select2_choice_clickable+span.select2-container .select2-selection__choice__display {
cursor: pointer;
}
.select2_choice_clickable_buttonstyle+span.select2-container .select2-selection__choice__display {
cursor: pointer;
transition: background-color 0.3s;
color: var(--SmartThemeBodyColor);
background-color: var(--black50a);
white-space: break-spaces;
word-break: break-all;
}
.select2_choice_clickable_buttonstyle+span.select2-container .select2-selection__choice__display:hover {
background-color: var(--white30a);
}
/* Custom class to support same line multi inputs of select2 controls */
.select2_multi_sameline+span.select2-container .select2-selection--multiple {
display: flex;
flex-wrap: wrap;
}
.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-search--inline {
/* Allow search placeholder to take up all space if needed */
flex-grow: 1;
}
.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-selection__rendered {
/* Fix weird styling choice or huge margin around selected options */
margin-block-start: 2px;
margin-block-end: 2px;
display: flex;
align-items: center;
flex-wrap: wrap;
row-gap: 5px;
}
.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-selection__choice {
margin-top: 0px;
}
.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-search__field {
/* Min height to reserve spacing */
min-height: calc(var(--mainFontSize) + 13px);
/* Min width to be clickable */
min-width: 4em;
align-content: center;
/* Fix search textarea alignment issue with UL elements */
margin-top: 0px;
height: unset;
/* Prevent height from jumping around when input is focused */
line-height: 1;
}
.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-selection__rendered {
/* Min height to reserve spacing */
min-height: calc(var(--mainFontSize) + 13px);
}
/* Make search bar invisible unless the select2 is active, to save space */
.select2_multi_sameline+span.select2-container .select2-selection--multiple .select2-search--inline {
height: 1px;
}
.select2_multi_sameline+span.select2-container.select2-container--focus .select2-selection--multiple .select2-search--inline {
height: unset;
}

View File

@@ -220,7 +220,7 @@
}
.monospace {
font-family: monospace;
font-family: var(--monoFontFamily);
}
.expander {
@@ -292,6 +292,14 @@
flex-wrap: nowrap;
}
.inline-flex {
display: inline-flex;
}
.inline-block {
display: inline-block;
}
.alignitemscenter,
.alignItemsCenter {
align-items: center;
@@ -348,6 +356,10 @@
margin-right: 5px;
}
.margin-r2 {
margin-right: 2px;
}
.flex0 {
flex: 0;
}
@@ -360,6 +372,14 @@
flex: 2 !important;
}
.flex3 {
flex: 3;
}
.flex4 {
flex: 4;
}
.flexFlowColumn {
flex-flow: column;
}
@@ -563,4 +583,24 @@ textarea:disabled {
height: 30px;
text-align: center;
padding: 5px;
}
}
ul.li-padding-b-1 li {
padding-bottom: 1em;
}
ul.li-padding-b-2 li {
padding-bottom: 2em;
}
ul.li-padding-b-5 li {
padding-bottom: 5em;
}
ul.li-padding-bot5 li {
padding-bottom: 5px;
}
ul.li-padding-bot10 li {
padding-bottom: 10px;
}

View File

@@ -14,7 +14,7 @@
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
gap: 6px;
margin-bottom: 5px;
}
@@ -27,8 +27,19 @@
flex: 1;
}
.tag_view_color_picker {
position: relative;
}
.tag_view_color_picker .link_icon {
position: absolute;
top: 50%;
right: 0px;
opacity: 0.5;
}
.tag_delete {
padding-right: 0;
padding: 2px 4px;
color: var(--SmartThemeBodyColor) !important;
}
@@ -103,7 +114,16 @@
}
#bulkTagsList,
#tagList .tag {
#tagList .tag,
#groupTagList .tag {
opacity: 0.6;
}
#tagList .tag:has(.tag_remove:hover) {
opacity: 1;
}
#tagList .tag:has(.tag_remove:hover) .tag_name {
opacity: 0.6;
}
@@ -193,7 +213,8 @@
filter: brightness(75%) saturate(0.6);
}
.tag_as_folder:hover {
.tag_as_folder:hover,
.tag_as_folder.flash {
filter: brightness(150%) saturate(0.6) !important;
}

View File

@@ -76,6 +76,12 @@
.world_entry_form_control {
display: flex;
flex-direction: column;
position: relative;
}
.world_entry_form_control .keyprimarytextpole,
.world_entry_form_control .keysecondarytextpole {
padding-right: 25px;
}
.world_entry_thin_controls {
@@ -101,7 +107,7 @@
height: auto;
margin-top: 0;
margin-bottom: 0;
min-height: calc(var(--mainFontSize) + 13px);
min-height: calc(var(--mainFontSize) + 14px);
}
.delete_entry_button {
@@ -196,3 +202,63 @@
.WIEntryHeaderTitleMobile {
display: none;
}
span.select2-container .select2-selection__choice__display:has(> .regex_item),
span.select2-container .select2-results__option:has(> .result_block .regex_item) {
background-color: #D27D2D30;
}
.regex_item .regex_icon {
background-color: var(--black30a);
color: var(--SmartThemeBodyColor);
border: 1px solid var(--SmartThemeBorderColor);
border-radius: 7px;
font-weight: bold;
font-size: calc(var(--mainFontSize) * 0.75);
padding: 0px 3px;
position: relative;
top: -1px;
margin-right: 3px;
}
.select2-results__option .regex_item .regex_icon {
margin-right: 6px;
}
.select2-results__option .item_count {
margin-left: 10px;
float: right;
}
select.keyselect+span.select2-container .select2-selection--multiple {
padding-right: 30px;
}
.switch_input_type_icon {
cursor: pointer;
font-weight: bold;
height: 20px;
width: fit-content;
margin-right: 5px;
margin-top: calc(5px + var(--mainFontSize));
position: absolute;
right: 0;
padding: 1px;
background-color: transparent;
border: none;
font-size: 1em;
opacity: 0.5;
color: var(--SmartThemeBodyColor);
transition: opacity 0.3s;
}
.switch_input_type_icon:hover {
opacity: 1;
}
#wiCheckboxes {
align-self: center;
width: 100%;
}

1401
public/global.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

59
public/img/01ai.svg Normal file
View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="363.44339"
height="375.68854"
viewBox="0 0 363.44339 375.68854"
version="1.1"
id="svg2"
sodipodi:docname="Yi_logo_icon_dark.svg"
inkscape:version="1.3 (0e150ed, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<sodipodi:namedview
id="namedview2"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.1073359"
inkscape:cx="192.35355"
inkscape:cy="196.86889"
inkscape:window-width="1512"
inkscape:window-height="857"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<rect
x="287.14771"
y="224.04056"
width="42.3862"
height="151.64799"
rx="21.1931"
id="rect1" />
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="m 299.41969,17.362538 c -8.916,-7.5830004 -22.291,-6.503 -29.874,2.414 l -118.432,139.253002 c -3.056,3.593 -4.705,7.911 -5.001,12.281 -0.166,1.069 -0.252,2.164 -0.252,3.279 v 178.022 c 0,11.705 9.488,21.193 21.193,21.193 11.705,0 21.193,-9.488 21.193,-21.193 v -171.819 l 113.587,-133.556002 c 7.583,-8.916 6.502,-22.291 -2.414,-29.874 z"
id="path1" />
<rect
x="-18.236605"
y="8.6596518"
width="42.3862"
height="174.745"
rx="21.1931"
transform="rotate(-39.3441)"
id="rect2" />
<circle
cx="337.54071"
cy="163.28656"
r="25.9027"
id="circle2" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
class="logo"
width="36"
height="30.9767"
viewBox="0 0 36 30.9767"
version="1.1"
id="svg2"
sodipodi:docname="featherless.svg"
inkscape:version="1.3 (0e150ed, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<sodipodi:namedview
id="namedview2"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="4.0920245"
inkscape:cx="75.268366"
inkscape:cy="15.151424"
inkscape:window-width="1512"
inkscape:window-height="857"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
d="M 34.0866,1.68482 C 32.2902,0.5825 29.863,0 27.0672,0 22.7842,0 18.0653,1.35865 13.8276,3.72206 L 13.7979,3.71083 c 0,0 -0.0042,0.02261 -0.0065,0.0334 C 12.5086,4.4617 11.2656,5.2629 10.0981,6.15731 3.22112,11.4248 1.29519,17.6748 2.92004,21.0156 1.14142,24.0728 0.0457,27.2332 0,30.9767 3.41949,24.421 5.4719,19.108 16.6146,10.1637 13.4309,10.8501 7.9281,14.1057 4.2271,19.0459 3.87793,16.156 6.1477,11.4895 11.2033,7.6174 11.8435,7.127 12.5092,6.66864 13.1886,6.23374 12.6577,7.8934 12.8269,7.4806 11.7254,9.8076 c 1.6289,-1.551 2.7014,-2.5081 4.3096,-5.16615 2.088,-1.03181 4.2598,-1.80301 6.4132,-2.2691 -0.3563,1.18836 -1.0345,3.20231 -1.9527,4.79455 0,0 2.3303,-0.50255 4.2563,-0.38902 -1.0523,1.16802 -1.9991,2.43152 -2.9592,3.72332 -1.3149,1.7684 -2.6742,3.5971 -4.4148,5.2993 -0.2095,0.2049 -0.4098,0.3907 -0.6129,0.5825 -2.6747,-0.2576 -4.4414,0.7485 -6.0966,2.5259 1.3054,-0.6123 3.059,-1.1165 4.1583,-0.813 -2.0258,1.662 -5.216,3.8529 -7.8373,3.6725 -0.4971,0.7611 -0.5285,0.7844 -1.0749,1.7038 4.252,1.0648 9.5926,-3.2817 12.7354,-6.3561 1.8428,-1.803 3.2466,-3.6904 4.6036,-5.5149 2.7947,-3.7585 5.2082,-7.0038 10.5619,-8.2388 L 36,2.85877 Z"
class="logo-mark"
id="path1"/>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

48
public/img/groq.svg Normal file
View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="107.644"
height="156.436"
viewBox="0 0 107.644 156.436"
fill="none"
version="1.1"
id="svg9"
sodipodi:docname="groqcloud_dark_v2.svg"
inkscape:version="1.3 (0e150ed, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="0.667"
inkscape:cx="499.25037"
inkscape:cy="56.971514"
inkscape:window-width="1312"
inkscape:window-height="449"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="0"
inkscape:current-layer="svg9" />
<defs
id="defs9">
<clipPath
id="clip0_872_2594">
<rect
width="1000"
height="200.345"
id="rect9"
x="0"
y="0" />
</clipPath>
</defs>
<path
d="M 54.0487,0.00281139 C 24.4736,-0.29748861 0.303066,23.497811 0.00281057,53.072911 -0.297445,82.648011 23.4978,106.89401 53.0729,107.11901 c 0.3003,0 0.6756,0 0.9758,0 H 71.6888 V 87.077011 H 54.0487 c -18.4656,0.225 -33.6285,-14.563 -33.8537,-33.1033 -0.2252,-18.4657 14.5624,-33.6286 33.1031,-33.8538 0.2252,0 0.5255,0 0.7506,0 18.4657,0 33.5536,15.0128 33.5536,33.4784 v 49.316699 c 0,18.316 -14.9377,33.254 -33.2533,33.479 -8.7825,0 -17.1145,-3.603 -23.2698,-9.834 l -14.187,14.187 c 9.8333,9.909 23.1947,15.539 37.1565,15.689 h 0.7507 c 29.1998,-0.451 52.6946,-24.096 52.8446,-53.296 V 52.247211 C 106.894,23.197511 83.1735,0.00281139 54.1238,0.00281139 Z"
id="path7" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="88.001465mm"
height="81.280983mm"
version="1.1"
id="svg9"
sodipodi:docname="huggingface.svg"
inkscape:version="1.3 (0e150ed, 2023-07-21)"
viewBox="0 0 88.001465 81.280983"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs9" />
<sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="0.68605868"
inkscape:cx="424.16197"
inkscape:cy="154.50573"
inkscape:window-width="1512"
inkscape:window-height="857"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="svg9"
inkscape:clip-to-page="false"
inkscape:document-units="mm" />
<path
id="path2-9"
style="display:inline;"
d="M 40.855186,0.10840487 A 38.75,38.75 0 0 0 5.0016702,38.750983 a 38.75,38.75 0 0 0 1.7871095,11.589844 7.1,7.1 0 0 1 1.871094,0.291015 5.97,5.97 0 0 1 1.330078,-3.761718 c 0.02089,-0.02502 0.04515,-0.04576 0.06641,-0.07031 a 34.75,34.75 0 0 1 -1.0547201,-8.048831 34.750014,34.750014 0 0 1 69.5000291,0 34.75,34.75 0 0 1 -0.957032,7.630859 c 0.163358,0.152193 0.321565,0.31255 0.466797,0.488282 a 5.97,5.97 0 0 1 1.330078,3.761718 7.1,7.1 0 0 1 1.337891,-0.207031 A 38.75,38.75 0 0 0 82.501671,38.750983 38.75,38.75 0 0 0 40.855186,0.10840487 Z M 48.015342,73.165045 a 34.75,34.75 0 0 1 -8.044921,0.03906 c -0.396448,0.901178 -0.898324,1.811009 -1.529297,2.736328 -0.233308,0.342701 -0.489288,0.664577 -0.75586,0.974609 a 38.75,38.75 0 0 0 12.574219,-0.06641 c -0.245421,-0.290144 -0.482504,-0.589875 -0.699219,-0.908203 -0.639915,-0.938432 -1.14623,-1.86177 -1.544922,-2.775391 z M 73.940733,45.000983 c 1.62,0 3.07,0.66 4.07,1.87 a 5.97,5.97 0 0 1 1.33,3.76 7.1,7.1 0 0 1 1.95,-0.3 c 1.55,0 2.95,0.59 3.94,1.66 a 5.8,5.8 0 0 1 0.8,7 5.3,5.3 0 0 1 1.78,2.82 c 0.24,0.9 0.48,2.8 -0.8,4.74 a 5.22,5.22 0 0 1 0.37,5.02 c -1.02,2.32 -3.57,4.14 -8.51,6.1 -3.08,1.22 -5.9,2 -5.92,2.01 a 44.33,44.33 0 0 1 -10.93,1.6 c -5.86,0 -10.05,-1.8 -12.46,-5.34 -3.88,-5.69 -3.33,-10.9 1.7,-15.92 2.78,-2.78 4.63,-6.87 5.01,-7.77 0.78,-2.66 2.83,-5.62 6.24,-5.62 a 5.7,5.7 0 0 1 4.6,2.46 c 1,-1.26 1.98,-2.25 2.87,-2.82 a 7.4,7.4 0 0 1 3.96,-1.27 z m 0,4 c -0.51,0 -1.13,0.22 -1.82,0.65 -2.13,1.36 -6.25,8.43 -7.76,11.18 a 2.43,2.43 0 0 1 -2.14,1.31 c -1.54,0 -2.75,-1.53 -0.14,-3.48 3.91,-2.93 2.54,-7.72 0.67,-8.01 a 1.54,1.54 0 0 0 -0.24,-0.02 c -1.7,0 -2.45,2.93 -2.45,2.93 0,0 -2.2,5.52 -5.97,9.3 -3.78,3.77 -3.98,6.8 -1.22,10.83 1.87,2.75 5.47,3.58 9.15,3.58 3.82,0 7.73,-0.9 9.93,-1.46 0.1,-0.03 13.45,-3.8 11.76,-7 -0.29,-0.54 -0.75,-0.76 -1.34,-0.76 -2.38,0 -6.71,3.54 -8.57,3.54 -0.42,0 -0.71,-0.17 -0.83,-0.6 -0.8,-2.85 12.05,-4.05 10.97,-8.17 -0.19,-0.73 -0.7,-1.02 -1.44,-1.02 -3.14,0 -10.2,5.53 -11.68,5.53 -0.1,0 -0.19,-0.03 -0.23,-0.1 -0.74,-1.2 -0.34,-2.04 4.88,-5.2 5.23,-3.16 8.9,-5.06 6.8,-7.33 -0.23,-0.26 -0.57,-0.38 -0.98,-0.38 -3.18,0 -10.67,6.82 -10.67,6.82 0,0 -2.02,2.1 -3.24,2.1 a 0.74,0.74 0 0 1 -0.68,-0.38 c -0.87,-1.46 8.05,-8.22 8.55,-11.01 0.34,-1.9 -0.24,-2.85 -1.31,-2.85 z m -6.69,-15 a 3.25,3.25 0 1 0 0,-6.5 3.25,3.25 0 0 0 0,6.5 z m -46.5,0 a 3.25,3.25 0 1 0 0,-6.5 3.25,3.25 0 0 0 0,6.5 z m -6.69,11 c -1.62,0 -3.06,0.66 -4.0700003,1.87 a 5.97,5.97 0 0 0 -1.33,3.76 7.1,7.1 0 0 0 -1.94,-0.3 c -1.55,0 -2.95,0.59 -3.94,1.66 a 5.8,5.8 0 0 0 -0.8,7 5.3,5.3 0 0 0 -1.79000004,2.82 c -0.24,0.9 -0.48,2.8 0.8,4.74 a 5.22,5.22 0 0 0 -0.37,5.02 c 1.02000004,2.32 3.57000004,4.14 8.52000004,6.1 3.0700003,1.22 5.8900003,2 5.9100003,2.01 a 44.33,44.33 0 0 0 10.93,1.6 c 5.86,0 10.05,-1.8 12.46,-5.34 3.88,-5.69 3.33,-10.9 -1.7,-15.92 -2.77,-2.78 -4.62,-6.87 -5,-7.77 -0.78,-2.66 -2.84,-5.62 -6.25,-5.62 a 5.7,5.7 0 0 0 -4.6,2.46 c -1,-1.26 -1.98,-2.25 -2.86,-2.82 a 7.4,7.4 0 0 0 -3.97,-1.27 z m 0,4 c 0.51,0 1.14,0.22 1.82,0.65 2.14,1.36 6.25,8.43 7.76,11.18 0.5,0.92 1.37,1.31 2.14,1.31 1.55,0 2.75,-1.53 0.15,-3.48 -3.92,-2.93 -2.55,-7.72 -0.68,-8.01 0.08,-0.02 0.17,-0.02 0.24,-0.02 1.7,0 2.45,2.93 2.45,2.93 0,0 2.2,5.52 5.98,9.3 3.77,3.77 3.97,6.8 1.22,10.83 -1.88,2.75 -5.47,3.58 -9.16,3.58 -3.81,0 -7.73,-0.9 -9.92,-1.46 -0.11,-0.03 -13.4500003,-3.8 -11.7600003,-7 0.28,-0.54 0.75,-0.76 1.34,-0.76 2.38,0 6.7000003,3.54 8.5700003,3.54 0.41,0 0.7,-0.17 0.83,-0.6 0.79,-2.85 -12.0600003,-4.05 -10.9800003,-8.17 0.2,-0.73 0.71,-1.02 1.44,-1.02 3.14,0 10.2000003,5.53 11.6800003,5.53 0.11,0 0.2,-0.03 0.24,-0.1 0.74,-1.2 0.33,-2.04 -4.9,-5.2 -5.2100003,-3.16 -8.8800003,-5.06 -6.8000003,-7.33 0.24,-0.26 0.58,-0.38 1,-0.38 3.17,0 10.6600003,6.82 10.6600003,6.82 0,0 2.02,2.1 3.25,2.1 0.28,0 0.52,-0.1 0.68,-0.38 0.86,-1.46 -8.06,-8.22 -8.56,-11.01 -0.34,-1.9 0.24,-2.85 1.31,-2.85 z m 21.91,2 a 8.7,8.7 0 0 1 5.3,-4.49 c 0.4,-0.12 0.81,0.57 1.24,1.28 0.4,0.68 0.82,1.37 1.24,1.37 0.45,0 0.9,-0.68 1.33,-1.35 0.45,-0.7 0.89,-1.38 1.32,-1.25 a 8.61,8.61 0 0 1 5,4.17 c 3.73,-2.94 5.1,-7.74 5.1,-10.7 0,-2.34 -1.57,-1.6 -4.09,-0.36 l -0.14,0.07 c -2.31,1.15 -5.39,2.67 -8.77,2.67 -3.38,0 -6.45,-1.52 -8.77,-2.67 -2.6,-1.29 -4.23,-2.1 -4.23,0.29 0,3.05 1.46,8.06 5.47,10.97 z m 19.07,-21.7 c 1.28,0.44 1.78,3.06 3.07,2.38 a 5,5 0 1 0 -6.76,-2.07 c 0.61,1.15 2.55,-0.72 3.7,-0.32 z m -23.55,0 c -1.28,0.44 -1.79,3.06 -3.07,2.38 a 5,5 0 1 1 6.76,-2.07 c -0.61,1.15 -2.56,-0.72 -3.7,-0.32 z" />
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
width="70pt"
height="70pt"
viewBox="0 0 70 70"
preserveAspectRatio="xMidYMid"
id="svg15"
sodipodi:docname="infermatic.svg"
inkscape:version="1.3 (0e150ed, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs15" />
<sodipodi:namedview
id="namedview15"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="pt"
inkscape:zoom="0.75112613"
inkscape:cx="306.2069"
inkscape:cy="50.590705"
inkscape:window-width="1312"
inkscape:window-height="449"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="0"
inkscape:current-layer="svg15" />
<path
id="path15"
d="m 1030,375 v -75 h 75 74 l 6,33 c 4,18 5,51 3,72 l -3,40 -77,3 -78,3 z m 547,619 c -4,-4 -7,-41 -7,-81 v -74 l 78,3 77,3 v 75 75 l -70,3 c -39,1 -74,0 -78,-4 z m -547,-74 v -79 l 133,-3 132,-3 3,-267 2,-268 h 215 215 v 75 75 h -135 -135 l -2,273 -3,272 -212,3 -213,2 z"
transform="matrix(0.1,0,0,-0.1,-103,99.999998)" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

6
public/img/manual.svg Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M13.3252 3.05011L8.66765 20.4323L10.5995 20.9499L15.257 3.56775L13.3252 3.05011Z" />
<path d="M7.61222 18.3608L8.97161 16.9124L8.9711 16.8933L3.87681 12.1121L8.66724 7.00798L7.20892 5.63928L1.0498 12.2017L7.61222 18.3608Z" />
<path d="M16.3883 18.3608L15.0289 16.9124L15.0294 16.8933L20.1237 12.1121L15.3333 7.00798L16.7916 5.63928L22.9507 12.2017L16.3883 18.3608Z" />
</svg>

After

Width:  |  Height:  |  Size: 514 B

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
"checkJs": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowUmdGlobalAccess": true,
"allowSyntheticDefaultImports": true
},

View File

@@ -42,6 +42,46 @@ EventEmitter.prototype.on = function (event, listener) {
this.events[event].push(listener);
};
/**
* Makes the listener the last to be called when the event is emitted
* @param {string} event Event name
* @param {function} listener Event listener
*/
EventEmitter.prototype.makeLast = function (event, listener) {
if (typeof this.events[event] !== 'object') {
this.events[event] = [];
}
const events = this.events[event];
const idx = events.indexOf(listener);
if (idx > -1) {
events.splice(idx, 1);
}
events.push(listener);
}
/**
* Makes the listener the first to be called when the event is emitted
* @param {string} event Event name
* @param {function} listener Event listener
*/
EventEmitter.prototype.makeFirst = function (event, listener) {
if (typeof this.events[event] !== 'object') {
this.events[event] = [];
}
const events = this.events[event];
const idx = events.indexOf(listener);
if (idx > -1) {
events.splice(idx, 1);
}
events.unshift(listener);
}
EventEmitter.prototype.removeListener = function (event, listener) {
var idx;
@@ -56,7 +96,7 @@ EventEmitter.prototype.removeListener = function (event, listener) {
EventEmitter.prototype.emit = async function (event) {
if (localStorage.getItem('eventTracing') === 'true') {
console.trace('Event emitted: ' + event);
console.trace('Event emitted: ' + event, args);
} else {
console.debug('Event emitted: ' + event);
}
@@ -81,7 +121,7 @@ EventEmitter.prototype.emit = async function (event) {
EventEmitter.prototype.emitAndWait = function (event) {
if (localStorage.getItem('eventTracing') === 'true') {
console.trace('Event emitted: ' + event);
console.trace('Event emitted: ' + event, args);
} else {
console.debug('Event emitted: ' + event);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
[
{ "lang": "ar-sa", "display": "عربي (Arabic)" },
{ "lang": "zh-cn", "display": "简体中文 (Chinese) (Simplified)" },
{ "lang": "zh-tw", "display": "繁體中文 (Chinese) (Taiwan)" },
{ "lang": "nl-nl", "display": "Nederlands (Dutch)" },
{ "lang": "de-de", "display": "Deutsch (German)" },
{ "lang": "fr-fr", "display": "Français (French)" },

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1458
public/locales/zh-tw.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,13 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="darkreader-lock">
<meta name="robots" content="noindex, nofollow" />
<style>
/* Put critical CSS here. The rest should go in stylesheets. */
body {
background-color: rgb(36, 36, 37);
}
</style>
<link rel="preload" as="style" href="style.css">
<link rel="apple-touch-icon" sizes="57x57" href="img/apple-icon-57x57.png" />
<link rel="apple-touch-icon" sizes="72x72" href="img/apple-icon-72x72.png" />
<link rel="apple-touch-icon" sizes="114x114" href="img/apple-icon-114x114.png" />
@@ -19,9 +26,10 @@
<link rel="stylesheet" type="text/css" href="css/login.css">
<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
<link href="webfonts/NotoSans/stylesheet.css" rel="stylesheet">
<link href="webfonts/NotoSansMono/stylesheet.css" rel="stylesheet">
<!-- fontawesome webfonts-->
<link href="css/fontawesome.css" rel="stylesheet">
<link href="css/solid.css" rel="stylesheet">
<link href="css/fontawesome.min.css" rel="stylesheet">
<link href="css/solid.min.css" rel="stylesheet">
<link href="css/user.css" rel="stylesheet">
<script src="lib/jquery-3.5.1.min.js"></script>
<script src="scripts/login.js"></script>

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ import {
characterGroupOverlay,
callPopup,
characters,
deleteCharacter,
event_types,
eventSource,
getCharacters,
@@ -13,6 +12,7 @@ import {
buildAvatarList,
characterToEntity,
printCharactersDebounced,
deleteCharacter,
} from '../script.js';
import { favsToHotswap } from './RossAscends-mods.js';
@@ -115,24 +115,7 @@ class CharacterContextMenu {
static delete = async (characterId, deleteChats = false) => {
const character = CharacterContextMenu.#getCharacter(characterId);
return fetch('/api/characters/delete', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ avatar_url: character.avatar, delete_chats: deleteChats }),
cache: 'no-cache',
}).then(response => {
if (response.ok) {
eventSource.emit(event_types.CHARACTER_DELETED, { id: characterId, character: character });
return deleteCharacter(character.name, character.avatar, false).then(() => {
if (deleteChats) getPastCharacterChats(characterId).then(pastChats => {
for (const chat of pastChats) {
const name = chat.file_name.replace('.jsonl', '');
eventSource.emit(event_types.CHAT_DELETED, name);
}
});
});
}
});
await deleteCharacter(character.avatar, { deleteChats: deleteChats });
};
static #getCharacter = (characterId) => characters[characterId] ?? null;

View File

@@ -6,6 +6,7 @@ import { Message, TokenHandler } from './openai.js';
import { power_user } from './power-user.js';
import { debounce, waitUntilCondition, escapeHtml } from './utils.js';
import { debounce_timeout } from './constants.js';
import { renderTemplateAsync } from './templates.js';
function debouncePromise(func, delay) {
let timeoutId;
@@ -250,7 +251,7 @@ class PromptManager {
this.error = null;
/** Dry-run for generate, must return a promise */
this.tryGenerate = () => { };
this.tryGenerate = async () => { };
/** Called to persist the configuration, must return a promise */
this.saveServiceSettings = () => { };
@@ -684,6 +685,23 @@ class PromptManager {
this.log('Initialized');
}
/**
* Get the scroll position of the prompt manager
* @returns {number} - Scroll position of the prompt manager
*/
#getScrollPosition() {
return document.getElementById(this.configuration.prefix + 'prompt_manager')?.closest('.scrollableInner')?.scrollTop;
}
/**
* Set the scroll position of the prompt manager
* @param {number} scrollPosition - The scroll position to set
*/
#setScrollPosition(scrollPosition) {
if (scrollPosition === undefined || scrollPosition === null) return;
document.getElementById(this.configuration.prefix + 'prompt_manager')?.closest('.scrollableInner')?.scrollTo(0, scrollPosition);
}
/**
* Main rendering function
*
@@ -695,24 +713,28 @@ class PromptManager {
if ('character' === this.configuration.promptOrder.strategy && null === this.activeCharacter) return;
this.error = null;
waitUntilCondition(() => !is_send_press && !is_group_generating, 1024 * 1024, 100).then(() => {
waitUntilCondition(() => !is_send_press && !is_group_generating, 1024 * 1024, 100).then(async () => {
if (true === afterTryGenerate) {
// Executed during dry-run for determining context composition
this.profileStart('filling context');
this.tryGenerate().finally(() => {
this.tryGenerate().finally(async () => {
this.profileEnd('filling context');
this.profileStart('render');
this.renderPromptManager();
this.renderPromptManagerListItems();
const scrollPosition = this.#getScrollPosition();
await this.renderPromptManager();
await this.renderPromptManagerListItems();
this.makeDraggable();
this.#setScrollPosition(scrollPosition);
this.profileEnd('render');
});
} else {
// Executed during live communication
this.profileStart('render');
this.renderPromptManager();
this.renderPromptManagerListItems();
const scrollPosition = this.#getScrollPosition();
await this.renderPromptManager();
await this.renderPromptManagerListItems();
this.makeDraggable();
this.#setScrollPosition(scrollPosition);
this.profileEnd('render');
}
}).catch(() => {
@@ -1338,7 +1360,7 @@ class PromptManager {
/**
* Empties, then re-assembles the container containing the prompt list.
*/
renderPromptManager() {
async renderPromptManager() {
let selectedPromptIndex = 0;
const existingAppendSelect = document.getElementById(`${this.configuration.prefix}prompt_manager_footer_append_prompt`);
if (existingAppendSelect instanceof HTMLSelectElement) {
@@ -1347,26 +1369,16 @@ class PromptManager {
const promptManagerDiv = this.containerElement;
promptManagerDiv.innerHTML = '';
const errorDiv = `
const errorDiv = this.error ? `
<div class="${this.configuration.prefix}prompt_manager_error">
<span class="fa-solid tooltip fa-triangle-exclamation text_danger"></span> ${this.error}
<span class="fa-solid tooltip fa-triangle-exclamation text_danger"></span> ${DOMPurify.sanitize(this.error)}
</div>
`;
` : '';
const totalActiveTokens = this.tokenUsage;
promptManagerDiv.insertAdjacentHTML('beforeend', `
<div class="range-block">
${this.error ? errorDiv : ''}
<div class="${this.configuration.prefix}prompt_manager_header">
<div class="${this.configuration.prefix}prompt_manager_header_advanced">
<span data-i18n="Prompts">Prompts</span>
</div>
<div>Total Tokens: ${totalActiveTokens} </div>
</div>
<ul id="${this.configuration.prefix}prompt_manager_list" class="text_pole"></ul>
</div>
`);
const headerHtml = await renderTemplateAsync('promptManagerHeader', { error: this.error, errorDiv, prefix: this.configuration.prefix, totalActiveTokens });
promptManagerDiv.insertAdjacentHTML('beforeend', headerHtml);
this.listElement = promptManagerDiv.querySelector(`#${this.configuration.prefix}prompt_manager_list`);
@@ -1384,22 +1396,9 @@ class PromptManager {
selectedPromptIndex = 0;
}
const footerHtml = `
<div class="${this.configuration.prefix}prompt_manager_footer">
<select id="${this.configuration.prefix}prompt_manager_footer_append_prompt" class="text_pole" name="append-prompt">
${promptsHtml}
</select>
<a class="menu_button fa-chain fa-solid" title="Insert prompt" data-i18n="[title]Insert prompt"></a>
<a class="caution menu_button fa-x fa-solid" title="Delete prompt" data-i18n="[title]Delete prompt"></a>
<a class="menu_button fa-file-import fa-solid" id="prompt-manager-import" title="Import a prompt list" data-i18n="[title]Import a prompt list"></a>
<a class="menu_button fa-file-export fa-solid" id="prompt-manager-export" title="Export this prompt list" data-i18n="[title]Export this prompt list"></a>
<a class="menu_button fa-undo fa-solid" id="prompt-manager-reset-character" title="Reset current character" data-i18n="[title]Reset current character"></a>
<a class="menu_button fa-plus-square fa-solid" title="New prompt" data-i18n="[title]New prompt"></a>
</div>
`;
const rangeBlockDiv = promptManagerDiv.querySelector('.range-block');
const headerDiv = promptManagerDiv.querySelector('.completion_prompt_manager_header');
const footerHtml = await renderTemplateAsync('promptManagerFooter', { promptsHtml, prefix: this.configuration.prefix });
headerDiv.insertAdjacentHTML('afterend', footerHtml);
rangeBlockDiv.querySelector('#prompt-manager-reset-character').addEventListener('click', this.handleCharacterReset);
@@ -1410,23 +1409,9 @@ class PromptManager {
footerDiv.querySelector('select').selectedIndex = selectedPromptIndex;
// Add prompt export dialogue and options
const exportForCharacter = `
<div class="row">
<a class="export-promptmanager-prompts-character list-group-item" data-i18n="Export for character">Export for character</a>
<span class="tooltip fa-solid fa-info-circle" title="Export prompts for this character, including their order."></span>
</div>`;
const exportPopup = `
<div id="prompt-manager-export-format-popup" class="list-group">
<div class="prompt-manager-export-format-popup-flex">
<div class="row">
<a class="export-promptmanager-prompts-full list-group-item" data-i18n="Export all">Export all</a>
<span class="tooltip fa-solid fa-info-circle" title="Export all your prompts to a file"></span>
</div>
${'global' === this.configuration.promptOrder.strategy ? '' : exportForCharacter}
</div>
</div>
`;
const exportForCharacter = await renderTemplateAsync('promptManagerExportForCharacter');
const exportPopup = await renderTemplateAsync('promptManagerExportPopup', { isGlobalStrategy: 'global' === this.configuration.promptOrder.strategy, exportForCharacter });
rangeBlockDiv.insertAdjacentHTML('beforeend', exportPopup);
// Destroy previous popper instance if it exists
@@ -1460,7 +1445,7 @@ class PromptManager {
/**
* Empties, then re-assembles the prompt list
*/
renderPromptManagerListItems() {
async renderPromptManagerListItems() {
if (!this.serviceSettings.prompts) return;
const promptManagerList = this.listElement;
@@ -1468,16 +1453,7 @@ class PromptManager {
const { prefix } = this.configuration;
let listItemHtml = `
<li class="${prefix}prompt_manager_list_head">
<span data-i18n="Name">Name</span>
<span></span>
<span class="prompt_manager_prompt_tokens" data-i18n="Tokens">Tokens</span>
</li>
<li class="${prefix}prompt_manager_list_separator">
<hr>
</li>
`;
let listItemHtml = await renderTemplateAsync('promptManagerListHeader', { prefix });
this.getPromptsForCharacter(this.activeCharacter).forEach(prompt => {
if (!prompt) return;
@@ -1551,7 +1527,7 @@ class PromptManager {
${isImportantPrompt ? '<span class="fa-fw fa-solid fa-star" title="Important Prompt"></span>' : ''}
${isUserPrompt ? '<span class="fa-fw fa-solid fa-user" title="User Prompt"></span>' : ''}
${isInjectionPrompt ? '<span class="fa-fw fa-solid fa-syringe" title="In-Chat Injection"></span>' : ''}
${this.isPromptInspectionAllowed(prompt) ? `<a class="prompt-manager-inspect-action">${encodedName}</a>` : encodedName}
${this.isPromptInspectionAllowed(prompt) ? `<a title="${encodedName}" class="prompt-manager-inspect-action">${encodedName}</a>` : `<span title="${encodedName}">${encodedName}</span>`}
${isInjectionPrompt ? `<small class="prompt-manager-injection-depth">@ ${prompt.injection_depth}</small>` : ''}
${isOverriddenPrompt ? '<small class="fa-solid fa-address-card prompt-manager-overridden" title="Pulled from a character card"></small>' : ''}
</span>
@@ -1602,7 +1578,7 @@ class PromptManager {
data: data,
};
const serializedObject = JSON.stringify(promptExport);
const serializedObject = JSON.stringify(promptExport, null, 4);
const blob = new Blob([serializedObject], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const downloadLink = document.createElement('a');

View File

@@ -16,7 +16,6 @@ import {
eventSource,
menu_type,
substituteParams,
callPopup,
sendTextareaMessage,
} from '../script.js';
@@ -39,6 +38,7 @@ import { textgen_types, textgenerationwebui_settings as textgen_settings, getTex
import { debounce_timeout } from './constants.js';
import Bowser from '../lib/bowser.min.js';
import { Popup } from './popup.js';
var RPanelPin = document.getElementById('rm_button_panel_pin');
var LPanelPin = document.getElementById('lm_button_panel_pin');
@@ -303,7 +303,7 @@ export async function favsToHotswap() {
return;
}
buildAvatarList(container, favs, { selectable: true, highlightFavs: false });
buildAvatarList(container, favs, { interactable: true, highlightFavs: false });
}
//changes input bar and send button display depending on connection status
@@ -360,6 +360,7 @@ function RA_autoconnect(PrevApi) {
|| (textgen_settings.type === textgen_types.INFERMATICAI && secret_state[SECRET_KEYS.INFERMATICAI])
|| (textgen_settings.type === textgen_types.DREAMGEN && secret_state[SECRET_KEYS.DREAMGEN])
|| (textgen_settings.type === textgen_types.OPENROUTER && secret_state[SECRET_KEYS.OPENROUTER])
|| (textgen_settings.type === textgen_types.FEATHERLESS && secret_state[SECRET_KEYS.FEATHERLESS])
) {
$('#api_button_textgenerationwebui').trigger('click');
}
@@ -378,6 +379,8 @@ function RA_autoconnect(PrevApi) {
|| (secret_state[SECRET_KEYS.MISTRALAI] && oai_settings.chat_completion_source == chat_completion_sources.MISTRALAI)
|| (secret_state[SECRET_KEYS.COHERE] && oai_settings.chat_completion_source == chat_completion_sources.COHERE)
|| (secret_state[SECRET_KEYS.PERPLEXITY] && oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY)
|| (secret_state[SECRET_KEYS.GROQ] && oai_settings.chat_completion_source == chat_completion_sources.GROQ)
|| (secret_state[SECRET_KEYS.ZEROONEAI] && oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI)
|| (isValidUrl(oai_settings.custom_url) && oai_settings.chat_completion_source == chat_completion_sources.CUSTOM)
) {
$('#api_button_openai').trigger('click');
@@ -423,7 +426,7 @@ function restoreUserInput() {
const userInput = LoadLocal('userInput');
if (userInput) {
$('#send_textarea').val(userInput).trigger('input');
$('#send_textarea').val(userInput)[0].dispatchEvent(new Event('input', { bubbles: true }));
}
}
@@ -435,10 +438,8 @@ const saveUserInputDebounced = debounce(saveUserInput);
// Make the DIV element draggable:
// THIRD UPDATE, prevent resize window breaks and smartly handle saving
export function dragElement(elmnt) {
var hasBeenDraggedByUser = false;
var isHeaderBeingDragged = false;
var isMouseDown = false;
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
@@ -449,16 +450,16 @@ export function dragElement(elmnt) {
var elmntName = elmnt.attr('id');
console.debug(`dragElement called for ${elmntName}`);
const elmntNameEscaped = $.escapeSelector(elmntName);
console.debug(`dragElement escaped name: ${elmntNameEscaped}`);
const elmntHeader = $(`#${elmntNameEscaped}header`);
if (elmntHeader.length) {
elmntHeader.off('mousedown').on('mousedown', (e) => {
hasBeenDraggedByUser = true;
elmntHeader.off('mousedown').on('mousedown', (e) => { //listener for drag handle repositioning
isHeaderBeingDragged = true;
isMouseDown = true;
observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] });
dragMouseDown(e);
});
$(elmnt).off('mousedown').on('mousedown', () => {
$(elmnt).off('mousedown').on('mousedown', () => { //listener for resize
isMouseDown = true;
observer.observe(elmnt.get(0), { attributes: true, attributeFilter: ['style'] });
});
@@ -466,20 +467,19 @@ export function dragElement(elmnt) {
const observer = new MutationObserver((mutations) => {
const target = mutations[0].target;
if (!$(target).is(':visible')
|| $(target).hasClass('resizing')
|| Number((String(target.height).replace('px', ''))) < 50
|| Number((String(target.width).replace('px', ''))) < 50
|| power_user.movingUI === false
|| isMobile()
if (!$(target).is(':visible') //abort if element is invisible
|| $(target).hasClass('resizing') //being auto-resized by other JS code
|| Number((String(target.height).replace('px', ''))) < 50 //too short
|| Number((String(target.width).replace('px', ''))) < 50 //too narrow
|| power_user.movingUI === false // if MUI is not turned on
|| isMobile() // if it's a mobile screen
) {
console.debug('aborting mutator');
return;
}
//console.debug(left + width, winWidth, hasBeenDraggedByUser, isMouseDown)
const style = getComputedStyle(target); //use computed values because not all CSS are set by default
height = target.offsetHeight;
width = target.offsetWidth;
const style = getComputedStyle(target);
height = parseInt(style.height);
width = parseInt(style.width);
top = parseInt(style.top);
left = parseInt(style.left);
right = parseInt(style.right);
@@ -494,53 +494,53 @@ export function dragElement(elmnt) {
topBarFirstX = parseInt(topbarstyle.marginInline);
topBarLastY = parseInt(topbarstyle.height);
/*console.log(`
winWidth: ${winWidth}, winHeight: ${winHeight}
sheldWidth: ${sheldWidth}
X: ${$(elmnt).css('left')}
Y: ${$(elmnt).css('top')}
MaxX: ${maxX}, MaxY: ${maxY}
height: ${height}
width: ${width}
Topbar 1st X: ${topBarFirstX}
TopBar lastX: ${topBarLastX}
`);*/
//prepare an empty poweruser object for the item being altered if we don't have one already
if (!power_user.movingUIState[elmntName]) {
console.debug(`adding config property for ${elmntName}`);
power_user.movingUIState[elmntName] = {};
}
//only record position changes if caused by a user click-drag
if (hasBeenDraggedByUser && isMouseDown) {
power_user.movingUIState[elmntName].top = top;
power_user.movingUIState[elmntName].left = left;
power_user.movingUIState[elmntName].right = right;
power_user.movingUIState[elmntName].bottom = bottom;
power_user.movingUIState[elmntName].margin = 'unset';
}
//handle resizing
if (!hasBeenDraggedByUser && isMouseDown) {
console.debug('saw resize, NOT header drag');
if (!isHeaderBeingDragged && isMouseDown) { //if user is dragging the resize handle (not in header)
let imgHeight, imgWidth, imageAspectRatio;
let containerAspectRatio = height / width;
//prevent resizing offscreen
if (top + elmnt.height() >= winHeight) {
console.debug('resizing height to prevent offscreen');
elmnt.css('height', winHeight - top - 1 + 'px');
}
//force aspect ratio for zoomed avatars
if ($(elmnt).attr('id').startsWith('zoomFor_')) {
let zoomedAvatarImage = $(elmnt).find('.zoomed_avatar_img');
imgHeight = zoomedAvatarImage.height();
imgWidth = zoomedAvatarImage.width();
imageAspectRatio = imgHeight / imgWidth;
if (left + elmnt.width() >= winWidth) {
console.debug('resizing width to prevent offscreen');
elmnt.css('width', winWidth - left - 1 + 'px');
// Maintain aspect ratio
if (containerAspectRatio !== imageAspectRatio) {
elmnt.css('width', elmnt.width());
elmnt.css('height', elmnt.width() * imageAspectRatio);
}
// Prevent resizing offscreen
if (top + elmnt.height() >= winHeight) {
elmnt.css('height', winHeight - top - 1 + 'px');
elmnt.css('width', (winHeight - top - 1) / imageAspectRatio + 'px');
}
if (left + elmnt.width() >= winWidth) {
elmnt.css('width', winWidth - left - 1 + 'px');
elmnt.css('height', (winWidth - left - 1) * imageAspectRatio + 'px');
}
} else { //prevent divs that are not zoomedAvatars from resizing offscreen
if (top + elmnt.height() >= winHeight) {
elmnt.css('height', winHeight - top - 1 + 'px');
}
if (left + elmnt.width() >= winWidth) {
elmnt.css('width', winWidth - left - 1 + 'px');
}
}
//prevent resizing from top left into the top bar
if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX
) {
console.debug('prevent topbar underlap resize');
if (top < topBarLastY && maxX >= topBarFirstX && left <= topBarFirstX) {
elmnt.css('width', width - 1 + 'px');
}
@@ -549,11 +549,11 @@ export function dragElement(elmnt) {
elmnt.css('top', top);
//set a listener for mouseup to save new width/height
elmnt.off('mouseup').on('mouseup', () => {
console.debug(`Saving ${elmntName} Height/Width`);
$(window).off('mouseup').on('mouseup', () => {
console.log(`Saving ${elmntName} Height/Width`);
// check if the height or width actually changed
if (power_user.movingUIState[elmntName].width === width && power_user.movingUIState[elmntName].height === height) {
console.debug('no change detected, aborting save');
if (power_user.movingUIState[elmntName].width === elmnt.width() && power_user.movingUIState[elmntName].height === elmnt.height()) {
console.log('no change detected, aborting save');
return;
}
@@ -561,12 +561,27 @@ export function dragElement(elmnt) {
power_user.movingUIState[elmntName].height = height;
eventSource.emit('resizeUI', elmntName);
saveSettingsDebounced();
imgHeight = null;
imgWidth = null;
height = null;
width = null;
containerAspectRatio = null;
imageAspectRatio = null;
$(window).off('mouseup');
});
}
//handle dragging hit detection
if (hasBeenDraggedByUser && isMouseDown) {
//prevent dragging offscreen
//only record position changes if header is being dragged
power_user.movingUIState[elmntName].top = top;
power_user.movingUIState[elmntName].left = left;
power_user.movingUIState[elmntName].right = right;
power_user.movingUIState[elmntName].bottom = bottom;
power_user.movingUIState[elmntName].margin = 'unset';
//handle dragging hit detection to prevent dragging offscreen
if (isHeaderBeingDragged && isMouseDown) {
if (top <= 0) {
elmnt.css('top', '0px');
} else if (maxY >= winHeight) {
@@ -578,27 +593,14 @@ export function dragElement(elmnt) {
} else if (maxX >= winWidth) {
elmnt.css('left', winWidth - maxX + left - 1 + 'px');
}
//prevent underlap with topbar div
/*
if (top < topBarLastY
&& (maxX >= topBarFirstX && left <= topBarFirstX //elmnt is hitting topbar from left side
|| left <= topBarLastX && maxX >= topBarLastX //elmnt is hitting topbar from right side
|| left >= topBarFirstX && maxX <= topBarLastX) //elmnt hitting topbar in the middle
) {
console.debug('topbar hit')
elmnt.css('top', top + 1 + "px");
}
*/
}
// Check if the element header exists and set the listener on the grabber
// Check if the element header exists and set the reposition listener on the grabber in the header
if (elmntHeader.length) {
elmntHeader.off('mousedown').on('mousedown', (e) => {
console.debug('listener started from header');
dragMouseDown(e);
});
} else {
} else { //if no header, put the listener on the elmnt itself.
elmnt.off('mousedown').on('mousedown', dragMouseDown);
}
});
@@ -606,7 +608,7 @@ export function dragElement(elmnt) {
function dragMouseDown(e) {
if (e) {
hasBeenDraggedByUser = true;
isHeaderBeingDragged = true;
e.preventDefault();
pos3 = e.clientX; //mouse X at click
pos4 = e.clientY; //mouse Y at click
@@ -638,34 +640,20 @@ export function dragElement(elmnt) {
elmnt.css('margin', 'unset');
elmnt.css('left', (elmnt.offset().left - pos1) + 'px');
elmnt.css('top', (elmnt.offset().top - pos2) + 'px');
elmnt.css('right', ((winWidth - maxX) + 'px'));
elmnt.css('bottom', ((winHeight - maxY) + 'px'));
/* elmnt.css('right', ((winWidth - maxX) + 'px'));
elmnt.css('bottom', ((winHeight - maxY) + 'px')); */
// Height/Width here are for visuals only, and are not saved to settings
// required because some divs do hot have a set width/height..
// and will defaults to shrink to min value of 100px set in CSS file
// Height/Width here are for visuals only, and are not saved to settings.
// This is required because some divs do hot have a set width/height
// and will default to shrink to min value of 100px set in CSS file
elmnt.css('height', height);
elmnt.css('width', width);
/*
console.log(`
winWidth: ${winWidth}, winHeight: ${winHeight}
sheldWidth: ${sheldWidth}
X: ${$(elmnt).css('left')}
Y: ${$(elmnt).css('top')}
MaxX: ${maxX}, MaxY: ${maxY}
height: ${height}
width: ${width}
Topbar 1st X: ${topBarFirstX}
TopBar lastX: ${topBarLastX}
`);
*/
return;
}
function closeDragElement() {
console.debug('drag finished');
hasBeenDraggedByUser = false;
isHeaderBeingDragged = false;
isMouseDown = false;
$(document).off('mouseup', closeDragElement);
$(document).off('mousemove', elementDrag);
@@ -675,6 +663,12 @@ export function dragElement(elmnt) {
observer.disconnect();
console.debug(`Saving ${elmntName} UI position`);
saveSettingsDebounced();
top = null;
left = null;
right = null;
bottom = null;
maxX = null;
maxY = null;
}
}
@@ -701,12 +695,12 @@ const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
*/
function autoFitSendTextArea() {
const originalScrollBottom = chatBlock.scrollHeight - (chatBlock.scrollTop + chatBlock.offsetHeight);
if (sendTextArea.scrollHeight == sendTextArea.offsetHeight) {
if (Math.ceil(sendTextArea.scrollHeight + 3) >= Math.floor(sendTextArea.offsetHeight)) {
// Needs to be pulled dynamically because it is affected by font size changes
const sendTextAreaMinHeight = window.getComputedStyle(sendTextArea).getPropertyValue('min-height');
sendTextArea.style.height = sendTextAreaMinHeight;
}
sendTextArea.style.height = sendTextArea.scrollHeight + 0.3 + 'px';
sendTextArea.style.height = sendTextArea.scrollHeight + 3 + 'px';
if (!isFirefox) {
const newScrollTop = Math.round(chatBlock.scrollHeight - (chatBlock.offsetHeight + originalScrollBottom));
@@ -731,6 +725,10 @@ export function initRossMods() {
RA_autoconnect();
}
if (getParsedUA()?.os?.name === 'iOS') {
document.body.classList.add('ios');
}
$('#main_api').change(function () {
var PrevAPI = main_api;
setTimeout(() => RA_autoconnect(PrevAPI), 100);
@@ -934,8 +932,8 @@ export function initRossMods() {
return false;
}
$(document).on('keydown', function (event) {
processHotkeys(event.originalEvent);
$(document).on('keydown', async function (event) {
await processHotkeys(event.originalEvent);
});
const hotkeyTargets = {
@@ -947,7 +945,7 @@ export function initRossMods() {
/**
* @param {KeyboardEvent} event
*/
function processHotkeys(event) {
async function processHotkeys(event) {
//Enter to send when send_textarea in focus
if (document.activeElement == hotkeyTargets['send_textarea']) {
const sendOnEnter = shouldSendOnEnter();
@@ -1011,20 +1009,17 @@ export function initRossMods() {
if (skipConfirm) {
doRegenerate();
} else {
const popupText = `
<div class="marginBot10">Are you sure you want to regenerate the latest message?</div>
<label class="checkbox_label justifyCenter" for="regenerateWithCtrlEnter">
<input type="checkbox" id="regenerateWithCtrlEnter">
Don't ask again
</label>`;
callPopup(popupText, 'confirm').then(result => {
if (!result) {
return;
}
const regenerateWithCtrlEnter = $('#regenerateWithCtrlEnter').prop('checked');
SaveLocal(skipConfirmKey, regenerateWithCtrlEnter);
doRegenerate();
let regenerateWithCtrlEnter = false;
const result = await Popup.show.confirm('Regenerate Message', 'Are you sure you want to regenerate the latest message?', {
customInputs: [{ id: 'regenerateWithCtrlEnter', label: 'Don\'t ask again' }],
onClose: (popup) => regenerateWithCtrlEnter = popup.inputResults.get('regenerateWithCtrlEnter') ?? false,
});
if (!result) {
return;
}
SaveLocal(skipConfirmKey, regenerateWithCtrlEnter);
doRegenerate();
}
return;
} else {
@@ -1104,6 +1099,9 @@ export function initRossMods() {
}
if (event.key == 'Escape') { //closes various panels
// Do not close panels if we are currently inside a popup
if (Popup.util.isPopupOpen())
return;
//dont override Escape hotkey functions from script.js
//"close edit box" and "cancel stream generation".
@@ -1132,6 +1130,11 @@ export function initRossMods() {
return;
}
if ($('#dialogue_del_mes_cancel').is(':visible')) {
$('#dialogue_del_mes_cancel').trigger('click');
return;
}
if ($('.drawer-content')
.not('#WorldInfo')
.not('#left-nav-panel')

View File

@@ -9,10 +9,12 @@ import {
} from '../script.js';
import { selected_group } from './group-chats.js';
import { extension_settings, getContext, saveMetadataDebounced } from './extensions.js';
import { registerSlashCommand } from './slash-commands.js';
import { getCharaFilename, debounce, delay } from './utils.js';
import { getTokenCountAsync } from './tokenizers.js';
import { debounce_timeout } from './constants.js';
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import { SlashCommand } from './slash-commands/SlashCommand.js';
import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
export { MODULE_NAME as NOTE_MODULE_NAME };
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
@@ -36,6 +38,7 @@ const chara_note_position = {
function setNoteTextCommand(_, text) {
$('#extension_floating_prompt').val(text).trigger('input');
toastr.success('Author\'s Note text updated');
return '';
}
function setNoteDepthCommand(_, text) {
@@ -48,6 +51,7 @@ function setNoteDepthCommand(_, text) {
$('#extension_floating_depth').val(Math.abs(value)).trigger('input');
toastr.success('Author\'s Note depth updated');
return '';
}
function setNoteIntervalCommand(_, text) {
@@ -60,6 +64,7 @@ function setNoteIntervalCommand(_, text) {
$('#extension_floating_interval').val(Math.abs(value)).trigger('input');
toastr.success('Author\'s Note frequency updated');
return '';
}
function setNotePositionCommand(_, text) {
@@ -77,6 +82,7 @@ function setNotePositionCommand(_, text) {
$(`input[name="extension_floating_position"][value="${position}"]`).prop('checked', true).trigger('input');
toastr.info('Author\'s Note position updated');
return '';
}
function updateSettings() {
@@ -455,9 +461,59 @@ export function initAuthorsNote() {
});
$('#option_toggle_AN').on('click', onANMenuItemClick);
registerSlashCommand('note', setNoteTextCommand, [], '<span class=\'monospace\'>(text)</span> sets an author\'s note for the currently selected chat', true, true);
registerSlashCommand('depth', setNoteDepthCommand, [], '<span class=\'monospace\'>(number)</span> sets an author\'s note depth for in-chat positioning', true, true);
registerSlashCommand('freq', setNoteIntervalCommand, ['interval'], '<span class=\'monospace\'>(number)</span> sets an author\'s note insertion frequency', true, true);
registerSlashCommand('pos', setNotePositionCommand, ['position'], '(<span class=\'monospace\'>chat</span> or <span class=\'monospace\'>scenario</span>) sets an author\'s note position', true, true);
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'note',
callback: setNoteTextCommand,
unnamedArgumentList: [
new SlashCommandArgument(
'text', [ARGUMENT_TYPE.STRING], true,
),
],
helpString: `
<div>
Sets an author's note for the currently selected chat.
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'depth',
callback: setNoteDepthCommand,
unnamedArgumentList: [
new SlashCommandArgument(
'number', [ARGUMENT_TYPE.NUMBER], true,
),
],
helpString: `
<div>
Sets an author's note depth for in-chat positioning.
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'freq',
callback: setNoteIntervalCommand,
namedArgumentList: [],
unnamedArgumentList: [
new SlashCommandArgument(
'number', [ARGUMENT_TYPE.NUMBER], true,
),
],
helpString: `
<div>
Sets an author's note insertion frequency.
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'pos',
callback: setNotePositionCommand,
namedArgumentList: [],
unnamedArgumentList: [
new SlashCommandArgument(
'position', [ARGUMENT_TYPE.STRING], true, false, null, ['chat', 'scenario'],
),
],
helpString: `
<div>
Sets an author's note position.
</div>
`,
}));
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
}

View File

@@ -0,0 +1,801 @@
import { power_user } from '../power-user.js';
import { debounce, escapeRegex } from '../utils.js';
import { AutoCompleteOption } from './AutoCompleteOption.js';
import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js';
import { BlankAutoCompleteOption } from './BlankAutoCompleteOption.js';
// eslint-disable-next-line no-unused-vars
import { AutoCompleteNameResult } from './AutoCompleteNameResult.js';
import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js';
import { Popup, getTopmostModalLayer } from '../popup.js';
/**@readonly*/
/**@enum {Number}*/
export const AUTOCOMPLETE_WIDTH = {
'INPUT': 0,
'CHAT': 1,
'FULL': 2,
};
export class AutoComplete {
/**@type {HTMLTextAreaElement}*/ textarea;
/**@type {boolean}*/ isFloating = false;
/**@type {()=>boolean}*/ checkIfActivate;
/**@type {(text:string, index:number) => Promise<AutoCompleteNameResult>}*/ getNameAt;
/**@type {boolean}*/ isActive = false;
/**@type {boolean}*/ isReplaceable = false;
/**@type {boolean}*/ isShowingDetails = false;
/**@type {boolean}*/ wasForced = false;
/**@type {boolean}*/ isForceHidden = false;
/**@type {boolean}*/ canBeAutoHidden = false;
/**@type {string}*/ text;
/**@type {AutoCompleteNameResult}*/ parserResult;
/**@type {AutoCompleteSecondaryNameResult}*/ secondaryParserResult;
get effectiveParserResult() { return this.secondaryParserResult ?? this.parserResult; }
/**@type {string}*/ name;
/**@type {boolean}*/ startQuote;
/**@type {boolean}*/ endQuote;
/**@type {number}*/ selectionStart;
/**@type {RegExp}*/ fuzzyRegex;
/**@type {AutoCompleteOption[]}*/ result = [];
/**@type {AutoCompleteOption}*/ selectedItem = null;
/**@type {HTMLElement}*/ clone;
/**@type {HTMLElement}*/ domWrap;
/**@type {HTMLElement}*/ dom;
/**@type {HTMLElement}*/ detailsWrap;
/**@type {HTMLElement}*/ detailsDom;
/**@type {function}*/ renderDebounced;
/**@type {function}*/ renderDetailsDebounced;
/**@type {function}*/ updatePositionDebounced;
/**@type {function}*/ updateDetailsPositionDebounced;
/**@type {function}*/ updateFloatingPositionDebounced;
get matchType() {
return power_user.stscript.matching ?? 'fuzzy';
}
get autoHide() {
return power_user.stscript.autocomplete.autoHide ?? false;
}
/**
* @param {HTMLTextAreaElement} textarea The textarea to receive autocomplete.
* @param {() => boolean} checkIfActivate Function should return true only if under the current conditions, autocomplete should display (e.g., for slash commands: autoComplete.text[0] == '/')
* @param {(text: string, index: number) => Promise<AutoCompleteNameResult>} getNameAt Function should return (unfiltered, matching against input is done in AutoComplete) information about name options at index in text.
* @param {boolean} isFloating Whether autocomplete should float at the keyboard cursor.
*/
constructor(textarea, checkIfActivate, getNameAt, isFloating = false) {
this.textarea = textarea;
this.checkIfActivate = checkIfActivate;
this.getNameAt = getNameAt;
this.isFloating = isFloating;
this.domWrap = document.createElement('div'); {
this.domWrap.classList.add('autoComplete-wrap');
if (isFloating) this.domWrap.classList.add('isFloating');
}
this.dom = document.createElement('ul'); {
this.dom.classList.add('autoComplete');
this.domWrap.append(this.dom);
}
this.detailsWrap = document.createElement('div'); {
this.detailsWrap.classList.add('autoComplete-detailsWrap');
if (isFloating) this.detailsWrap.classList.add('isFloating');
}
this.detailsDom = document.createElement('div'); {
this.detailsDom.classList.add('autoComplete-details');
this.detailsWrap.append(this.detailsDom);
}
this.renderDebounced = debounce(this.render.bind(this), 10);
this.renderDetailsDebounced = debounce(this.renderDetails.bind(this), 10);
this.updatePositionDebounced = debounce(this.updatePosition.bind(this), 10);
this.updateDetailsPositionDebounced = debounce(this.updateDetailsPosition.bind(this), 10);
this.updateFloatingPositionDebounced = debounce(this.updateFloatingPosition.bind(this), 10);
textarea.addEventListener('input', ()=>this.text != this.textarea.value && this.show(true, this.wasForced));
textarea.addEventListener('keydown', (evt)=>this.handleKeyDown(evt));
textarea.addEventListener('click', ()=>this.isActive ? this.show() : null);
textarea.addEventListener('selectionchange', ()=>this.show());
textarea.addEventListener('blur', ()=>this.hide());
if (isFloating) {
textarea.addEventListener('scroll', ()=>this.updateFloatingPositionDebounced());
}
window.addEventListener('resize', ()=>this.updatePositionDebounced());
}
/**
*
* @param {AutoCompleteOption} option
*/
makeItem(option) {
const li = option.renderItem();
// gotta listen to pointerdown (happens before textarea-blur)
li.addEventListener('pointerdown', (evt)=>{
evt.preventDefault();
this.selectedItem = this.result.find(it=>it.name == li.getAttribute('data-name'));
this.select();
});
return li;
}
/**
*
* @param {AutoCompleteOption} item
*/
updateName(item) {
const chars = Array.from(item.dom.querySelector('.name').children);
switch (this.matchType) {
case 'strict': {
chars.forEach((it, idx)=>{
if (idx + item.nameOffset < item.name.length) {
it.classList.add('matched');
} else {
it.classList.remove('matched');
}
});
break;
}
case 'includes': {
const start = item.name.toLowerCase().search(this.name);
chars.forEach((it, idx)=>{
if (idx + item.nameOffset < start) {
it.classList.remove('matched');
} else if (idx + item.nameOffset < start + item.name.length) {
it.classList.add('matched');
} else {
it.classList.remove('matched');
}
});
break;
}
case 'fuzzy': {
item.name.replace(this.fuzzyRegex, (_, ...parts)=>{
parts.splice(-2, 2);
if (parts.length == 2) {
chars.forEach(c=>c.classList.remove('matched'));
} else {
let cIdx = item.nameOffset;
parts.forEach((it, idx)=>{
if (it === null || it.length == 0) return '';
if (idx % 2 == 1) {
chars.slice(cIdx, cIdx + it.length).forEach(c=>c.classList.add('matched'));
} else {
chars.slice(cIdx, cIdx + it.length).forEach(c=>c.classList.remove('matched'));
}
cIdx += it.length;
});
}
return '';
});
}
}
return item;
}
/**
* Calculate score for the fuzzy match.
* @param {AutoCompleteOption} option
* @returns The option.
*/
fuzzyScore(option) {
const parts = this.fuzzyRegex.exec(option.name).slice(1, -1);
let start = null;
let consecutive = [];
let current = '';
let offset = 0;
parts.forEach((part, idx) => {
if (idx % 2 == 0) {
if (part.length > 0) {
if (current.length > 0) {
consecutive.push(current);
}
current = '';
}
} else {
if (start === null) {
start = offset;
}
current += part;
}
offset += part.length;
});
if (current.length > 0) {
consecutive.push(current);
}
consecutive.sort((a,b)=>b.length - a.length);
option.score = new AutoCompleteFuzzyScore(start, consecutive[0]?.length ?? 0);
return option;
}
/**
* Compare two auto complete options by their fuzzy score.
* @param {AutoCompleteOption} a
* @param {AutoCompleteOption} b
*/
fuzzyScoreCompare(a, b) {
if (a.score.start < b.score.start) return -1;
if (a.score.start > b.score.start) return 1;
if (a.score.longestConsecutive > b.score.longestConsecutive) return -1;
if (a.score.longestConsecutive < b.score.longestConsecutive) return 1;
return a.name.localeCompare(b.name);
}
basicAutoHideCheck() {
// auto hide only if at least one char has been typed after the name + space
return this.textarea.selectionStart > this.parserResult.start
+ this.parserResult.name.length
+ (this.startQuote ? 1 : 0)
+ (this.endQuote ? 1 : 0)
+ 1
;
}
/**
* Show the autocomplete.
* @param {boolean} isInput Whether triggered by input.
* @param {boolean} isForced Whether force-showing (ctrl+space).
* @param {boolean} isSelect Whether an autocomplete option was just selected.
*/
async show(isInput = false, isForced = false, isSelect = false) {
//TODO check if isInput and isForced are both required
this.text = this.textarea.value;
this.isReplaceable = false;
if (document.activeElement != this.textarea) {
// only show with textarea in focus
return this.hide();
}
if (!this.checkIfActivate()) {
// only show if provider wants to
return this.hide();
}
// disable force-hide if trigger was forced
if (isForced) this.isForceHidden = false;
// request provider to get name result (potentially "incomplete", i.e. not an actual existing name) for
// cursor position
this.parserResult = await this.getNameAt(this.text, this.textarea.selectionStart);
this.secondaryParserResult = null;
if (!this.parserResult) {
// don't show if no name result found, e.g., cursor's area is not a command
return this.hide();
}
// need to know if name can be inside quotes, and then check if quotes are already there
if (this.parserResult.canBeQuoted) {
this.startQuote = this.text[this.parserResult.start] == '"';
this.endQuote = this.startQuote && this.text[this.parserResult.start + this.parserResult.name.length + 1] == '"';
} else {
this.startQuote = false;
this.endQuote = false;
}
// use lowercase name for matching
this.name = this.parserResult.name.toLowerCase() ?? '';
const isCursorInNamePart = this.textarea.selectionStart >= this.parserResult.start && this.textarea.selectionStart <= this.parserResult.start + this.parserResult.name.length + (this.startQuote ? 1 : 0);
if (isForced || isInput) {
// if forced (ctrl+space) or user input...
if (isCursorInNamePart) {
// ...and cursor is somewhere in the name part (including right behind the final char)
// -> show autocomplete for the (partial if cursor in the middle) name
this.name = this.name.slice(0, this.textarea.selectionStart - (this.parserResult.start) - (this.startQuote ? 1 : 0));
this.parserResult.name = this.name;
this.isReplaceable = true;
this.isForceHidden = false;
this.canBeAutoHidden = false;
} else {
this.isReplaceable = false;
this.canBeAutoHidden = this.basicAutoHideCheck();
}
} else {
// if not forced and no user input -> just show details
this.isReplaceable = false;
this.canBeAutoHidden = this.basicAutoHideCheck();
}
if (isForced || isInput || isSelect) {
// is forced or user input or just selected autocomplete option...
if (!isCursorInNamePart) {
// ...and cursor is not somwehere in the main name part -> check for secondary options (e.g., named arguments)
const result = this.parserResult.getSecondaryNameAt(this.text, this.textarea.selectionStart, isSelect);
if (result && (isForced || result.isRequired)) {
this.secondaryParserResult = result;
this.name = this.secondaryParserResult.name;
this.isReplaceable = isForced || this.secondaryParserResult.isRequired;
this.isForceHidden = false;
this.canBeAutoHidden = false;
} else {
this.isReplaceable = false;
this.canBeAutoHidden = this.basicAutoHideCheck();
}
}
}
if (this.matchType == 'fuzzy') {
// only build the fuzzy regex if match type is set to fuzzy
this.fuzzyRegex = new RegExp(`^(.*?)${this.name.split('').map(char=>`(${escapeRegex(char)})`).join('(.*?)')}(.*?)$`, 'i');
}
//TODO maybe move the matchers somewhere else; a single match function? matchType is available as property
const matchers = {
'strict': (name) => name.toLowerCase().startsWith(this.name),
'includes': (name) => name.toLowerCase().includes(this.name),
'fuzzy': (name) => this.fuzzyRegex.test(name),
};
this.result = this.effectiveParserResult.optionList
// filter the list of options by the partial name according to the matching type
.filter(it => this.isReplaceable || it.name == '' ? matchers[this.matchType](it.name) : it.name.toLowerCase() == this.name)
// remove aliases
.filter((it,idx,list) => list.findIndex(opt=>opt.value == it.value) == idx);
if (this.result.length == 0 && this.effectiveParserResult != this.parserResult && isForced) {
// no matching secondary results and forced trigger -> show current command details
this.secondaryParserResult = null;
this.result = [this.effectiveParserResult.optionList.find(it=>it.name == this.effectiveParserResult.name)];
this.name = this.effectiveParserResult.name;
this.fuzzyRegex = /(.*)(.*)(.*)/;
}
this.result = this.result
// update remaining options
.map(option => {
// build element
option.dom = this.makeItem(option);
// update replacer and add quotes if necessary
if (this.effectiveParserResult.canBeQuoted) {
option.replacer = option.name.includes(' ') || this.startQuote || this.endQuote ? `"${option.name}"` : `${option.name}`;
} else {
option.replacer = option.name;
}
// calculate fuzzy score if matching is fuzzy
if (this.matchType == 'fuzzy') this.fuzzyScore(option);
// update the name to highlight the matched chars
this.updateName(option);
return option;
})
// sort by fuzzy score or alphabetical
.toSorted(this.matchType == 'fuzzy' ? this.fuzzyScoreCompare : (a, b) => a.name.localeCompare(b.name))
;
if (this.isForceHidden) {
// hidden with escape
return this.hide();
}
if (this.autoHide && this.canBeAutoHidden && !isForced && this.effectiveParserResult == this.parserResult && this.result.length == 1) {
// auto hide user setting enabled and somewhere after name part and would usually show command details
return this.hide();
}
if (this.result.length == 0) {
if (!isInput) {
// no result and no input? hide autocomplete
return this.hide();
}
if (this.effectiveParserResult instanceof AutoCompleteSecondaryNameResult && !this.effectiveParserResult.forceMatch) {
// no result and matching is no forced? hide autocomplete
return this.hide();
}
// otherwise add "no match" notice
const option = new BlankAutoCompleteOption(
this.name.length ?
this.effectiveParserResult.makeNoMatchText()
: this.effectiveParserResult.makeNoOptionsText()
,
);
this.result.push(option);
} else if (this.result.length == 1 && this.effectiveParserResult && this.result[0].name == this.effectiveParserResult.name) {
// only one result that is exactly the current value? just show hint, no autocomplete
this.isReplaceable = false;
this.isShowingDetails = false;
} else if (!this.isReplaceable && this.result.length > 1) {
return this.hide();
}
this.selectedItem = this.result[0];
this.isActive = true;
this.wasForced = isForced;
this.renderDebounced();
}
/**
* Hide autocomplete.
*/
hide() {
this.domWrap?.remove();
this.detailsWrap?.remove();
this.isActive = false;
this.isShowingDetails = false;
this.wasForced = false;
}
/**
* Create updated DOM.
*/
render() {
if (!this.isActive) return this.domWrap.remove();
if (this.isReplaceable) {
this.dom.innerHTML = '';
const frag = document.createDocumentFragment();
for (const item of this.result) {
if (item == this.selectedItem) {
item.dom.classList.add('selected');
} else {
item.dom.classList.remove('selected');
}
frag.append(item.dom);
}
this.dom.append(frag);
this.updatePosition();
getTopmostModalLayer().append(this.domWrap);
} else {
this.domWrap.remove();
}
this.renderDetailsDebounced();
}
/**
* Create updated DOM for details.
*/
renderDetails() {
if (!this.isActive) return this.detailsWrap.remove();
if (!this.isShowingDetails && this.isReplaceable) return this.detailsWrap.remove();
this.detailsDom.innerHTML = '';
this.detailsDom.append(this.selectedItem?.renderDetails() ?? 'NO ITEM');
getTopmostModalLayer().append(this.detailsWrap);
this.updateDetailsPositionDebounced();
}
/**
* Update position of DOM.
*/
updatePosition() {
if (this.isFloating) {
this.updateFloatingPosition();
} else {
const rect = {};
rect[AUTOCOMPLETE_WIDTH.INPUT] = this.textarea.getBoundingClientRect();
rect[AUTOCOMPLETE_WIDTH.CHAT] = document.querySelector('#sheld').getBoundingClientRect();
rect[AUTOCOMPLETE_WIDTH.FULL] = getTopmostModalLayer().getBoundingClientRect();
this.domWrap.style.setProperty('--bottom', `${window.innerHeight - rect[AUTOCOMPLETE_WIDTH.INPUT].top}px`);
this.dom.style.setProperty('--bottom', `${window.innerHeight - rect[AUTOCOMPLETE_WIDTH.INPUT].top}px`);
this.domWrap.style.bottom = `${window.innerHeight - rect[AUTOCOMPLETE_WIDTH.INPUT].top}px`;
if (this.isShowingDetails) {
this.domWrap.style.setProperty('--leftOffset', '1vw');
this.domWrap.style.setProperty('--leftOffset', `max(1vw, ${rect[power_user.stscript.autocomplete.width.left].left}px)`);
this.domWrap.style.setProperty('--rightOffset', `calc(100vw - min(${rect[power_user.stscript.autocomplete.width.right].right}px, ${this.isShowingDetails ? 74 : 0}vw)`);
} else {
this.domWrap.style.setProperty('--leftOffset', `max(1vw, ${rect[power_user.stscript.autocomplete.width.left].left}px)`);
this.domWrap.style.setProperty('--rightOffset', `calc(100vw - min(99vw, ${rect[power_user.stscript.autocomplete.width.right].right}px)`);
}
}
this.updateDetailsPosition();
}
/**
* Update position of details DOM.
*/
updateDetailsPosition() {
if (this.isShowingDetails || !this.isReplaceable) {
if (this.isFloating) {
this.updateFloatingDetailsPosition();
} else {
const rect = {};
rect[AUTOCOMPLETE_WIDTH.INPUT] = this.textarea.getBoundingClientRect();
rect[AUTOCOMPLETE_WIDTH.CHAT] = document.querySelector('#sheld').getBoundingClientRect();
rect[AUTOCOMPLETE_WIDTH.FULL] = getTopmostModalLayer().getBoundingClientRect();
if (this.isReplaceable) {
this.detailsWrap.classList.remove('full');
const selRect = this.selectedItem.dom.children[0].getBoundingClientRect();
this.detailsWrap.style.setProperty('--targetOffset', `${selRect.top}`);
this.detailsWrap.style.setProperty('--rightOffset', '1vw');
this.detailsWrap.style.setProperty('--bottomOffset', `calc(100vh - ${rect[AUTOCOMPLETE_WIDTH.INPUT].top}px)`);
this.detailsWrap.style.setProperty('--leftOffset', `calc(100vw - ${this.domWrap.style.getPropertyValue('--rightOffset')}`);
} else {
this.detailsWrap.classList.add('full');
this.detailsWrap.style.setProperty('--targetOffset', `${rect[AUTOCOMPLETE_WIDTH.INPUT].top}`);
this.detailsWrap.style.setProperty('--bottomOffset', `calc(100vh - ${rect[AUTOCOMPLETE_WIDTH.INPUT].top}px)`);
this.detailsWrap.style.setProperty('--leftOffset', `${rect[power_user.stscript.autocomplete.width.left].left}px`);
this.detailsWrap.style.setProperty('--rightOffset', `calc(100vw - ${rect[power_user.stscript.autocomplete.width.right].right}px)`);
}
}
}
}
/**
* Update position of floating autocomplete.
*/
updateFloatingPosition() {
const location = this.getCursorPosition();
const rect = this.textarea.getBoundingClientRect();
// cursor is out of view -> hide
if (location.bottom < rect.top || location.top > rect.bottom || location.left < rect.left || location.left > rect.right) {
return this.hide();
}
const left = Math.max(rect.left, location.left);
this.domWrap.style.setProperty('--targetOffset', `${left}`);
if (location.top <= window.innerHeight / 2) {
// if cursor is in lower half of window, show list above line
this.domWrap.style.top = `${location.bottom}px`;
this.domWrap.style.bottom = 'auto';
this.domWrap.style.maxHeight = `calc(${location.bottom}px - 1vh)`;
} else {
// if cursor is in upper half of window, show list below line
this.domWrap.style.top = 'auto';
this.domWrap.style.bottom = `calc(100vh - ${location.top}px)`;
this.domWrap.style.maxHeight = `calc(${location.top}px - 1vh)`;
}
}
updateFloatingDetailsPosition(location = null) {
if (!location) location = this.getCursorPosition();
const rect = this.textarea.getBoundingClientRect();
if (location.bottom < rect.top || location.top > rect.bottom || location.left < rect.left || location.left > rect.right) {
return this.hide();
}
const left = Math.max(rect.left, location.left);
this.detailsWrap.style.setProperty('--targetOffset', `${left}`);
if (this.isReplaceable) {
this.detailsWrap.classList.remove('full');
if (left < window.innerWidth / 4) {
// if cursor is in left part of screen, show details on right of list
this.detailsWrap.classList.add('right');
this.detailsWrap.classList.remove('left');
} else {
// if cursor is in right part of screen, show details on left of list
this.detailsWrap.classList.remove('right');
this.detailsWrap.classList.add('left');
}
} else {
this.detailsWrap.classList.remove('left');
this.detailsWrap.classList.remove('right');
this.detailsWrap.classList.add('full');
}
if (location.top <= window.innerHeight / 2) {
// if cursor is in lower half of window, show list above line
this.detailsWrap.style.top = `${location.bottom}px`;
this.detailsWrap.style.bottom = 'auto';
this.detailsWrap.style.maxHeight = `calc(${location.bottom}px - 1vh)`;
} else {
// if cursor is in upper half of window, show list below line
this.detailsWrap.style.top = 'auto';
this.detailsWrap.style.bottom = `calc(100vh - ${location.top}px)`;
this.detailsWrap.style.maxHeight = `calc(${location.top}px - 1vh)`;
}
}
/**
* Calculate (keyboard) cursor coordinates within textarea.
* @returns {{left:number, top:number, bottom:number}}
*/
getCursorPosition() {
const inputRect = this.textarea.getBoundingClientRect();
const style = window.getComputedStyle(this.textarea);
if (!this.clone) {
this.clone = document.createElement('div');
for (const key of style) {
this.clone.style[key] = style[key];
}
this.clone.style.position = 'fixed';
this.clone.style.visibility = 'hidden';
getTopmostModalLayer().append(this.clone);
const mo = new MutationObserver(muts=>{
if (muts.find(it=>Array.from(it.removedNodes).includes(this.textarea))) {
this.clone.remove();
}
});
mo.observe(this.textarea.parentElement, { childList:true });
}
this.clone.style.height = `${inputRect.height}px`;
this.clone.style.left = `${inputRect.left}px`;
this.clone.style.top = `${inputRect.top}px`;
this.clone.style.whiteSpace = style.whiteSpace;
this.clone.style.tabSize = style.tabSize;
const text = this.textarea.value;
const before = text.slice(0, this.textarea.selectionStart);
this.clone.textContent = before;
const locator = document.createElement('span');
locator.textContent = text[this.textarea.selectionStart];
this.clone.append(locator);
this.clone.append(text.slice(this.textarea.selectionStart + 1));
this.clone.scrollTop = this.textarea.scrollTop;
this.clone.scrollLeft = this.textarea.scrollLeft;
const locatorRect = locator.getBoundingClientRect();
const location = {
left: locatorRect.left,
top: locatorRect.top,
bottom: locatorRect.bottom,
};
return location;
}
/**
* Toggle details view alongside autocomplete list.
*/
toggleDetails() {
this.isShowingDetails = !this.isShowingDetails;
this.renderDetailsDebounced();
this.updatePosition();
}
/**
* Select an item for autocomplete and put text into textarea.
*/
async select() {
if (this.isReplaceable && this.selectedItem.value !== null) {
this.textarea.value = `${this.text.slice(0, this.effectiveParserResult.start)}${this.selectedItem.replacer}${this.text.slice(this.effectiveParserResult.start + this.effectiveParserResult.name.length + (this.startQuote ? 1 : 0) + (this.endQuote ? 1 : 0))}`;
this.textarea.selectionStart = this.effectiveParserResult.start + this.selectedItem.replacer.length;
this.textarea.selectionEnd = this.textarea.selectionStart;
this.show(false, false, true);
} else {
const selectionStart = this.textarea.selectionStart;
const selectionEnd = this.textarea.selectionDirection;
this.textarea.selectionStart = selectionStart;
this.textarea.selectionDirection = selectionEnd;
}
this.wasForced = false;
this.textarea.dispatchEvent(new Event('input', { bubbles:true }));
}
/**
* Mark the item at newIdx in the autocomplete list as selected.
* @param {number} newIdx
*/
selectItemAtIndex(newIdx) {
this.selectedItem.dom.classList.remove('selected');
this.selectedItem = this.result[newIdx];
this.selectedItem.dom.classList.add('selected');
const rect = this.selectedItem.dom.children[0].getBoundingClientRect();
const rectParent = this.dom.getBoundingClientRect();
if (rect.top < rectParent.top || rect.bottom > rectParent.bottom ) {
this.dom.scrollTop += rect.top < rectParent.top ? rect.top - rectParent.top : rect.bottom - rectParent.bottom;
}
this.renderDetailsDebounced();
}
/**
* Handle keyboard events.
* @param {KeyboardEvent} evt The event.
*/
async handleKeyDown(evt) {
// autocomplete is shown and cursor at end of current command name (or inside name and typed or forced)
if (this.isActive && this.isReplaceable) {
// actions in the list
switch (evt.key) {
case 'ArrowUp': {
// select previous item
if (evt.ctrlKey || evt.altKey || evt.shiftKey) return;
evt.preventDefault();
evt.stopPropagation();
const idx = this.result.indexOf(this.selectedItem);
let newIdx;
if (idx == 0) newIdx = this.result.length - 1;
else newIdx = idx - 1;
this.selectItemAtIndex(newIdx);
return;
}
case 'ArrowDown': {
// select next item
if (evt.ctrlKey || evt.altKey || evt.shiftKey) return;
evt.preventDefault();
evt.stopPropagation();
const idx = this.result.indexOf(this.selectedItem);
const newIdx = (idx + 1) % this.result.length;
this.selectItemAtIndex(newIdx);
return;
}
case 'Enter': {
// pick the selected item to autocomplete
if (evt.ctrlKey || evt.altKey || evt.shiftKey || this.selectedItem.value == '') break;
if (this.selectedItem.name == this.name) break;
evt.preventDefault();
evt.stopImmediatePropagation();
this.select();
return;
}
case 'Tab': {
// pick the selected item to autocomplete
if (evt.ctrlKey || evt.altKey || evt.shiftKey || this.selectedItem.value == '') break;
evt.preventDefault();
evt.stopImmediatePropagation();
this.select();
return;
}
}
}
// details are shown, cursor can be anywhere
if (this.isActive) {
switch (evt.key) {
case 'Escape': {
// close autocomplete
if (evt.ctrlKey || evt.altKey || evt.shiftKey) return;
evt.preventDefault();
evt.stopPropagation();
this.isForceHidden = true;
this.wasForced = false;
this.hide();
return;
}
case 'Enter': {
// hide autocomplete on enter (send, execute, ...)
if (!evt.shiftKey) {
this.hide();
return;
}
break;
}
}
}
// autocomplete shown or not, cursor anywhere
switch (evt.key) {
// The first is a non-breaking space, the second is a regular space.
case ' ':
case ' ': {
if (evt.ctrlKey || evt.altKey) {
if (this.isActive && this.isReplaceable) {
// ctrl-space to toggle details for selected item
this.toggleDetails();
} else {
// ctrl-space to force show autocomplete
this.show(false, true);
}
evt.preventDefault();
evt.stopPropagation();
return;
}
break;
}
}
if (['Control', 'Shift', 'Alt'].includes(evt.key)) {
// ignore keydown on modifier keys
return;
}
switch (evt.key) {
case 'ArrowUp':
case 'ArrowDown':
case 'ArrowRight':
case 'ArrowLeft': {
if (this.isActive) {
// keyboard navigation, wait for keyup to complete cursor move
const oldText = this.textarea.value;
await new Promise(resolve=>{
window.addEventListener('keyup', resolve, { once:true });
});
if (this.selectionStart != this.textarea.selectionStart) {
this.selectionStart = this.textarea.selectionStart;
this.show(this.isReplaceable || oldText != this.textarea.value);
}
}
break;
}
default: {
if (this.isActive) {
this.text != this.textarea.value && this.show(this.isReplaceable);
}
break;
}
}
}
}

View File

@@ -0,0 +1,16 @@
export class AutoCompleteFuzzyScore {
/**@type {number}*/ start;
/**@type {number}*/ longestConsecutive;
/**
* @param {number} start
* @param {number} longestConsecutive
*/
constructor(start, longestConsecutive) {
this.start = start;
this.longestConsecutive = longestConsecutive;
}
}

View File

@@ -0,0 +1,44 @@
import { SlashCommandNamedArgumentAutoCompleteOption } from '../slash-commands/SlashCommandNamedArgumentAutoCompleteOption.js';
import { AutoCompleteOption } from './AutoCompleteOption.js';
// import { AutoCompleteSecondaryNameResult } from './AutoCompleteSecondaryNameResult.js';
export class AutoCompleteNameResult {
/**@type {string} */ name;
/**@type {number} */ start;
/**@type {AutoCompleteOption[]} */ optionList = [];
/**@type {boolean} */ canBeQuoted = false;
/**@type {()=>string} */ makeNoMatchText = ()=>`No matches found for "${this.name}"`;
/**@type {()=>string} */ makeNoOptionsText = ()=>'No options';
/**
* @param {string} name Name (potentially partial) of the name at the requested index.
* @param {number} start Index where the name starts.
* @param {AutoCompleteOption[]} optionList A list of autocomplete options found in the current scope.
* @param {boolean} canBeQuoted Whether the name can be inside quotes.
* @param {()=>string} makeNoMatchText Function that returns text to show when no matches where found.
* @param {()=>string} makeNoOptionsText Function that returns text to show when no options are available to match against.
*/
constructor(name, start, optionList = [], canBeQuoted = false, makeNoMatchText = null, makeNoOptionsText = null) {
this.name = name;
this.start = start;
this.optionList = optionList;
this.canBeQuoted = canBeQuoted;
this.noMatchText = makeNoMatchText ?? this.makeNoMatchText;
this.noOptionstext = makeNoOptionsText ?? this.makeNoOptionsText;
}
/**
*
* @param {string} text The whole text
* @param {number} index Cursor index within text
* @param {boolean} isSelect Whether autocomplete was triggered by selecting an autocomplete option
* @returns {AutoCompleteSecondaryNameResult}
*/
getSecondaryNameAt(text, index, isSelect) {
return null;
}
}

View File

@@ -0,0 +1,214 @@
import { SlashCommand } from '../slash-commands/SlashCommand.js';
import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js';
export class AutoCompleteOption {
/**@type {string}*/ name;
/**@type {string}*/ typeIcon;
/**@type {string}*/ type;
/**@type {number}*/ nameOffset = 0;
/**@type {AutoCompleteFuzzyScore}*/ score;
/**@type {string}*/ replacer;
/**@type {HTMLElement}*/ dom;
/**
* Used as a comparison value when removing duplicates (e.g., when a SlashCommand has aliases).
* @type {any}
* */
get value() {
return this.name;
}
/**
* @param {string} name
*/
constructor(name, typeIcon = ' ', type = '') {
this.name = name;
this.typeIcon = typeIcon;
this.type = type;
}
makeItem(key, typeIcon, noSlash, namedArguments = [], unnamedArguments = [], returnType = 'void', helpString = '', aliasList = []) {
const li = document.createElement('li'); {
li.classList.add('item');
const type = document.createElement('span'); {
type.classList.add('type');
type.classList.add('monospace');
type.textContent = typeIcon;
li.append(type);
}
const specs = document.createElement('span'); {
specs.classList.add('specs');
const name = document.createElement('span'); {
name.classList.add('name');
name.classList.add('monospace');
name.textContent = noSlash ? '' : '/';
key.split('').forEach(char=>{
const span = document.createElement('span'); {
span.textContent = char;
name.append(span);
}
});
specs.append(name);
}
const body = document.createElement('span'); {
body.classList.add('body');
const args = document.createElement('span'); {
args.classList.add('arguments');
for (const arg of namedArguments) {
const argItem = document.createElement('span'); {
argItem.classList.add('argument');
argItem.classList.add('namedArgument');
if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');
if (arg.acceptsMultiple) argItem.classList.add('multiple');
const name = document.createElement('span'); {
name.classList.add('argument-name');
name.textContent = arg.name;
argItem.append(name);
}
if (arg.enumList.length > 0) {
const enums = document.createElement('span'); {
enums.classList.add('argument-enums');
for (const e of arg.enumList) {
const enumItem = document.createElement('span'); {
enumItem.classList.add('argument-enum');
enumItem.textContent = e;
enums.append(enumItem);
}
}
argItem.append(enums);
}
} else {
const types = document.createElement('span'); {
types.classList.add('argument-types');
for (const t of arg.typeList) {
const type = document.createElement('span'); {
type.classList.add('argument-type');
type.textContent = t;
types.append(type);
}
}
argItem.append(types);
}
}
args.append(argItem);
}
}
for (const arg of unnamedArguments) {
const argItem = document.createElement('span'); {
argItem.classList.add('argument');
argItem.classList.add('unnamedArgument');
if (!arg.isRequired || (arg.defaultValue ?? false)) argItem.classList.add('optional');
if (arg.acceptsMultiple) argItem.classList.add('multiple');
if (arg.enumList.length > 0) {
const enums = document.createElement('span'); {
enums.classList.add('argument-enums');
for (const e of arg.enumList) {
const enumItem = document.createElement('span'); {
enumItem.classList.add('argument-enum');
enumItem.textContent = e;
enums.append(enumItem);
}
}
argItem.append(enums);
}
} else {
const types = document.createElement('span'); {
types.classList.add('argument-types');
for (const t of arg.typeList) {
const type = document.createElement('span'); {
type.classList.add('argument-type');
type.textContent = t;
types.append(type);
}
}
argItem.append(types);
}
}
args.append(argItem);
}
}
body.append(args);
}
const returns = document.createElement('span'); {
returns.classList.add('returns');
returns.textContent = returnType ?? 'void';
// body.append(returns);
}
specs.append(body);
}
li.append(specs);
}
const stopgap = document.createElement('span'); {
stopgap.classList.add('stopgap');
stopgap.textContent = '';
li.append(stopgap);
}
const help = document.createElement('span'); {
help.classList.add('help');
const content = document.createElement('span'); {
content.classList.add('helpContent');
content.innerHTML = helpString;
const text = content.textContent;
content.innerHTML = '';
content.textContent = text;
help.append(content);
}
li.append(help);
}
if (aliasList.length > 0) {
const aliases = document.createElement('span'); {
aliases.classList.add('aliases');
aliases.append(' (alias: ');
for (const aliasName of aliasList) {
const alias = document.createElement('span'); {
alias.classList.add('monospace');
alias.textContent = `/${aliasName}`;
aliases.append(alias);
}
}
aliases.append(')');
// li.append(aliases);
}
}
}
return li;
}
/**
* @returns {HTMLElement}
*/
renderItem() {
// throw new Error(`${this.constructor.name}.renderItem() is not implemented`);
let li;
li = this.makeItem(this.name, this.typeIcon, true);
li.setAttribute('data-name', this.name);
li.setAttribute('data-option-type', this.type);
return li;
}
/**
* @returns {DocumentFragment}
*/
renderDetails() {
// throw new Error(`${this.constructor.name}.renderDetails() is not implemented`);
const frag = document.createDocumentFragment();
const specs = document.createElement('div'); {
specs.classList.add('specs');
const name = document.createElement('div'); {
name.classList.add('name');
name.classList.add('monospace');
name.textContent = this.name;
specs.append(name);
}
frag.append(specs);
}
return frag;
}
}

View File

@@ -0,0 +1,6 @@
import { AutoCompleteNameResult } from './AutoCompleteNameResult.js';
export class AutoCompleteSecondaryNameResult extends AutoCompleteNameResult {
/**@type {boolean}*/ isRequired = false;
/**@type {boolean}*/ forceMatch = true;
}

View File

@@ -0,0 +1,29 @@
import { AutoCompleteOption } from './AutoCompleteOption.js';
export class BlankAutoCompleteOption extends AutoCompleteOption {
/**
* @param {string} name
*/
constructor(name) {
super(name);
this.dom = this.renderItem();
}
get value() { return null; }
renderItem() {
const li = document.createElement('li'); {
li.classList.add('item');
li.classList.add('blank');
li.textContent = this.name;
}
return li;
}
renderDetails() {
const frag = document.createDocumentFragment();
return frag;
}
}

View File

@@ -0,0 +1,44 @@
import { AutoCompleteOption } from './AutoCompleteOption.js';
export class MacroAutoCompleteOption extends AutoCompleteOption {
/**@type {string}*/ fullName;
/**@type {string}*/ description;
constructor(name, fullName, description) {
super(name, '{}');
this.fullName = fullName;
this.description = description;
this.nameOffset = 2;
}
renderItem() {
let li;
li = this.makeItem(`${this.fullName}`, '{}', true, [], [], null, this.description);
li.setAttribute('data-name', this.name);
li.setAttribute('data-option-type', 'macro');
return li;
}
renderDetails() {
const frag = document.createDocumentFragment();
const specs = document.createElement('div'); {
specs.classList.add('specs');
const name = document.createElement('div'); {
name.classList.add('name');
name.classList.add('monospace');
name.textContent = this.fullName;
specs.append(name);
}
frag.append(specs);
}
const help = document.createElement('span'); {
help.classList.add('help');
help.innerHTML = this.description;
frag.append(help);
}
return frag;
}
}

View File

@@ -1,6 +1,7 @@
import { callPopup, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl, saveSettingsDebounced } from '../script.js';
import { saveMetadataDebounced } from './extensions.js';
import { registerSlashCommand } from './slash-commands.js';
import { SlashCommand } from './slash-commands/SlashCommand.js';
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import { flashHighlight, stringFormat } from './utils.js';
const BG_METADATA_KEY = 'custom_background';
@@ -94,7 +95,7 @@ function onLockBackgroundClick(e) {
if (!chatName) {
toastr.warning('Select a chat to lock the background for it');
return;
return '';
}
const relativeBgImage = getUrlParameter(this);
@@ -102,6 +103,7 @@ function onLockBackgroundClick(e) {
saveBackgroundMetadata(relativeBgImage);
setCustomBackground();
highlightLockedBackground();
return '';
}
function onUnlockBackgroundClick(e) {
@@ -109,6 +111,7 @@ function onUnlockBackgroundClick(e) {
removeBackgroundMetadata();
unsetCustomBackground();
highlightLockedBackground();
return '';
}
function hasCustomBackground() {
@@ -318,7 +321,7 @@ async function autoBackgroundCommand() {
const options = bgTitles.map(x => ({ element: x, text: x.innerText.trim() })).filter(x => x.text.length > 0);
if (options.length == 0) {
toastr.warning('No backgrounds to choose from. Please upload some images to the "backgrounds" folder.');
return;
return '';
}
const list = options.map(option => `- ${option.text}`).join('\n');
@@ -329,11 +332,12 @@ async function autoBackgroundCommand() {
if (bestMatch.length == 0) {
toastr.warning('No match found. Please try again.');
return;
return '';
}
console.debug('Automatically choosing background:', bestMatch);
bestMatch[0].item.element.click();
return '';
}
export async function getBackgrounds() {
@@ -480,7 +484,20 @@ export function initBackgrounds() {
$('#auto_background').on('click', autoBackgroundCommand);
$('#add_bg_button').on('change', onBackgroundUploadSelected);
$('#bg-filter').on('input', onBackgroundFilterInput);
registerSlashCommand('lockbg', onLockBackgroundClick, ['bglock'], ' locks a background for the currently selected chat', true, true);
registerSlashCommand('unlockbg', onUnlockBackgroundClick, ['bgunlock'], ' unlocks a background for the currently selected chat', true, true);
registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], ' automatically changes the background based on the chat context using the AI request prompt', true, true);
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lockbg',
callback: onLockBackgroundClick,
aliases: ['bglock'],
helpString: 'Locks a background for the currently selected chat',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'unlockbg',
callback: onUnlockBackgroundClick,
aliases: ['bgunlock'],
helpString: 'Unlocks a background for the currently selected chat',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'autobg',
callback: autoBackgroundCommand,
aliases: ['bgauto'],
helpString: 'Automatically changes the background based on the chat context using the AI request prompt',
}));
}

View File

@@ -12,6 +12,7 @@ import {
getCharacters,
chat,
saveChatConditional,
saveItemizedPrompts,
} from '../script.js';
import { humanizedDateTime } from './RossAscends-mods.js';
import {
@@ -23,6 +24,7 @@ import {
saveGroupBookmarkChat,
selected_group,
} from './group-chats.js';
import { Popup } from './popup.js';
import { createTagMapFromList } from './tags.js';
import {
@@ -199,6 +201,7 @@ async function createNewBookmark(mesId) {
const mainChat = selected_group ? groups?.find(x => x.id == selected_group)?.chat_id : characters[this_chid].chat;
const newMetadata = { main_chat: mainChat };
await saveItemizedPrompts(name);
if (selected_group) {
await saveGroupBookmarkChat(selected_group, name, newMetadata, mesId);
@@ -237,8 +240,7 @@ async function convertSoloToGroupChat() {
return;
}
const confirm = await callPopup('Are you sure you want to convert this chat to a group chat?', 'confirm');
const confirm = await Popup.show.confirm('Convert to group chat', 'Are you sure you want to convert this chat to a group chat?<br />This cannot be reverted.');
if (!confirm) {
return;
}
@@ -334,6 +336,7 @@ async function convertSoloToGroupChat() {
if (!createChatResponse.ok) {
console.error('Group chat creation unsuccessful');
toastr.error('Group chat creation unsuccessful');
return;
}

View File

@@ -94,6 +94,9 @@ function enableBulkSelect() {
});
$(el).prepend(checkbox);
});
$('#rm_print_characters_block.group_overlay_mode_select .bogus_folder_select, #rm_print_characters_block.group_overlay_mode_select .group_select')
.addClass('disabled');
$('#rm_print_characters_block').addClass('bulk_select');
// We also need to disable the default click event for the character_select divs
$(document).on('click', '.bulk_select_checkbox', function (event) {
@@ -106,6 +109,8 @@ function enableBulkSelect() {
*/
function disableBulkSelect() {
$('.bulk_select_checkbox').remove();
$('#rm_print_characters_block.group_overlay_mode_select .bogus_folder_select, #rm_print_characters_block.group_overlay_mode_select .group_select')
.removeClass('disabled');
$('#rm_print_characters_block').removeClass('bulk_select');
}

116
public/scripts/char-data.js Normal file
View File

@@ -0,0 +1,116 @@
/**
* @typedef {object} v2DataWorldInfoEntry
* @property {string[]} keys - An array of primary keys associated with the entry.
* @property {string[]} secondary_keys - An array of secondary keys associated with the entry (optional).
* @property {string} comment - A human-readable description or explanation for the entry.
* @property {string} content - The main content or data associated with the entry.
* @property {boolean} constant - Indicates if the entry's content is fixed and unchangeable.
* @property {boolean} selective - Indicates if the entry's inclusion is controlled by specific conditions.
* @property {number} insertion_order - Defines the order in which the entry is inserted during processing.
* @property {boolean} enabled - Controls whether the entry is currently active and used.
* @property {string} position - Specifies the location or context where the entry applies.
* @property {v2DataWorldInfoEntryExtensionInfos} extensions - An object containing additional details for extensions associated with the entry.
* @property {number} id - A unique identifier assigned to the entry.
*/
/**
* @typedef {object} v2DataWorldInfoEntryExtensionInfos
* @property {number} position - The order in which the extension is applied relative to other extensions.
* @property {boolean} exclude_recursion - Prevents the extension from being applied recursively.
* @property {number} probability - The chance (between 0 and 1) of the extension being applied.
* @property {boolean} useProbability - Determines if the `probability` property is used.
* @property {number} depth - The maximum level of nesting allowed for recursive application of the extension.
* @property {number} selectiveLogic - Defines the logic used to determine if the extension is applied selectively.
* @property {string} group - A category or grouping for the extension.
* @property {boolean} group_override - Overrides any existing group assignment for the extension.
* @property {number} group_weight - A value used for prioritizing extensions within the same group.
* @property {boolean} prevent_recursion - Completely disallows recursive application of the extension.
* @property {boolean} delay_until_recursion - Will only be checked during recursion.
* @property {number} scan_depth - The maximum depth to search for matches when applying the extension.
* @property {boolean} match_whole_words - Specifies if only entire words should be matched during extension application.
* @property {boolean} use_group_scoring - Indicates if group weight is considered when selecting extensions.
* @property {boolean} case_sensitive - Controls whether case sensitivity is applied during matching for the extension.
* @property {string} automation_id - An identifier used for automation purposes related to the extension.
* @property {number} role - The specific function or purpose of the extension.
* @property {boolean} vectorized - Indicates if the extension is optimized for vectorized processing.
* @property {number} display_index - The order in which the extension should be displayed for user interfaces.
*/
/**
* @typedef {object} v2WorldInfoBook
* @property {string} name - the name of the book
* @property {v2DataWorldInfoEntry[]} entries - the entries of the book
*/
/**
* @typedef {object} v2CharData
* @property {string} name - The character's name.
* @property {string} description - A brief description of the character.
* @property {string} character_version - The character's data version.
* @property {string} personality - A short summary of the character's personality traits.
* @property {string} scenario - A description of the character's background or setting.
* @property {string} first_mes - The character's opening message in a conversation.
* @property {string} mes_example - An example message demonstrating the character's conversation style.
* @property {string} creator_notes - Internal notes or comments left by the character's creator.
* @property {string[]} tags - A list of keywords or labels associated with the character.
* @property {string} system_prompt - The system prompt used to interact with the character.
* @property {string} post_history_instructions - Instructions for handling the character's conversation history.
* @property {string} creator - The name of the person who created the character.
* @property {string[]} alternate_greetings - Additional greeting messages the character can use.
* @property {v2WorldInfoBook} character_book - Data about the character's world or story (if applicable).
* @property {v2CharDataExtensionInfos} extensions - Additional details specific to the character.
*/
/**
* @typedef {object} v2CharDataExtensionInfos
* @property {number} talkativeness - A numerical value indicating the character's propensity to talk.
* @property {boolean} fav - A flag indicating whether the character is a favorite.
* @property {string} world - The fictional world or setting where the character exists (if applicable).
* @property {object} depth_prompt - Prompts used to explore the character's depth and complexity.
* @property {number} depth_prompt.depth - The level of detail or nuance targeted by the prompt.
* @property {string} depth_prompt.prompt - The actual prompt text used for deeper character interaction.
* @property {"system" | "user" | "assistant"} depth_prompt.role - The role the character takes on during the prompted interaction (system, user, or assistant).
* @property {RegexScriptData[]} regex_scripts - Custom regex scripts for the character.
* // Non-standard extensions added by external tools
* @property {string} [pygmalion_id] - The unique identifier assigned to the character by the Pygmalion.chat.
* @property {string} [github_repo] - The gitHub repository associated with the character.
* @property {string} [source_url] - The source URL associated with the character.
* @property {{full_path: string}} [chub] - The Chub-specific data associated with the character.
* @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character.
*/
/**
* @typedef {object} RegexScriptData
* @property {string} id - UUID of the script
* @property {string} scriptName - The name of the script
* @property {string} findRegex - The regex to find
* @property {string} replaceString - The string to replace
* @property {string[]} trimStrings - The strings to trim
* @property {number[]} placement - The placement of the script
* @property {boolean} disabled - Whether the script is disabled
* @property {boolean} markdownOnly - Whether the script only applies to Markdown
* @property {boolean} promptOnly - Whether the script only applies to prompts
* @property {boolean} runOnEdit - Whether the script runs on edit
* @property {boolean} substituteRegex - Whether the regex should be substituted
* @property {number} minDepth - The minimum depth
* @property {number} maxDepth - The maximum depth
*/
/**
* @typedef {object} v1CharData
* @property {string} name - the name of the character
* @property {string} description - the description of the character
* @property {string} personality - a short personality description of the character
* @property {string} scenario - a scenario description of the character
* @property {string} first_mes - the first message in the conversation
* @property {string} mes_example - the example message in the conversation
* @property {string} creatorcomment - creator's notes of the character
* @property {string[]} tags - the tags of the character
* @property {number} talkativeness - talkativeness
* @property {boolean|string} fav - fav
* @property {string} create_date - create_date
* @property {v2CharData} data - v2 data extension
* // Non-standard extensions added by the ST server (not part of the original data)
* @property {string} chat - name of the current chat file chat
* @property {string} avatar - file name of the avatar image (acts as a unique identifier)
* @property {string} json_data - the full raw JSON data of the character
*/
export default 0;// now this file is a module

View File

@@ -4,7 +4,6 @@ import css from '../lib/css-parser.mjs';
import {
addCopyToCodeBlocks,
appendMediaToMessage,
callPopup,
characters,
chat,
eventSource,
@@ -35,8 +34,10 @@ import {
extractTextFromOffice,
} from './utils.js';
import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js';
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from './popup.js';
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
import { ScraperManager } from './scrapers.js';
import { DragAndDropHandler } from './dragdrop.js';
import { renderTemplateAsync } from './templates.js';
/**
* @typedef {Object} FileAttachment
@@ -184,18 +185,19 @@ export async function populateFileAttachment(message, inputId = 'file_form_input
const file = fileInput.files[0];
if (!file) return;
const slug = getStringHash(file.name);
const fileNamePrefix = `${Date.now()}_${slug}`;
const fileBase64 = await getBase64Async(file);
let base64Data = fileBase64.split(',')[1];
// If file is image
if (file.type.startsWith('image/')) {
const extension = file.type.split('/')[1];
const imageUrl = await saveBase64AsFile(base64Data, name2, file.name, extension);
const imageUrl = await saveBase64AsFile(base64Data, name2, fileNamePrefix, extension);
message.extra.image = imageUrl;
message.extra.inline_image = true;
} else {
const slug = getStringHash(file.name);
const uniqueFileName = `${Date.now()}_${slug}.txt`;
const uniqueFileName = `${fileNamePrefix}.txt`;
if (isConvertible(file.type)) {
try {
@@ -318,12 +320,10 @@ export function hasPendingFileAttachment() {
/**
* Displays file information in the message sending form.
* @param {File} file File object
* @returns {Promise<void>}
*/
async function onFileAttach() {
const fileInput = document.getElementById('file_form_input');
if (!(fileInput instanceof HTMLInputElement)) return;
const file = fileInput.files[0];
async function onFileAttach(file) {
if (!file) return;
const isValid = await validateFile(file);
@@ -418,6 +418,7 @@ function embedMessageFile(messageId, messageBlock) {
}
await populateFileAttachment(message, 'embed_file_input');
await eventSource.emit(event_types.MESSAGE_FILE_EMBEDDED, messageId);
appendMediaToMessage(message, messageBlock);
await saveChatConditional();
}
@@ -463,33 +464,50 @@ export function encodeStyleTags(text) {
*/
export function decodeStyleTags(text) {
const styleDecodeRegex = /<custom-style>(.+?)<\/custom-style>/gms;
const mediaAllowed = isExternalMediaAllowed();
function sanitizeRule(rule) {
if (Array.isArray(rule.selectors)) {
for (let i = 0; i < rule.selectors.length; i++) {
const selector = rule.selectors[i];
if (selector) {
const selectors = (selector.split(' ') ?? []).map((v) => {
if (v.startsWith('.')) {
return '.custom-' + v.substring(1);
}
return v;
}).join(' ');
rule.selectors[i] = '.mes_text ' + selectors;
}
}
}
if (!mediaAllowed && Array.isArray(rule.declarations) && rule.declarations.length > 0) {
rule.declarations = rule.declarations.filter(declaration => !declaration.value.includes('://'));
}
}
function sanitizeRuleSet(ruleSet) {
if (Array.isArray(ruleSet.selectors) || Array.isArray(ruleSet.declarations)) {
sanitizeRule(ruleSet);
}
if (Array.isArray(ruleSet.rules)) {
ruleSet.rules = ruleSet.rules.filter(rule => rule.type !== 'import');
for (const mediaRule of ruleSet.rules) {
sanitizeRuleSet(mediaRule);
}
}
}
return text.replaceAll(styleDecodeRegex, (_, style) => {
try {
let styleCleaned = unescape(style).replaceAll(/<br\/>/g, '');
const ast = css.parse(styleCleaned);
const rules = ast?.stylesheet?.rules;
if (rules) {
for (const rule of rules) {
if (rule.type === 'rule') {
if (rule.selectors) {
for (let i = 0; i < rule.selectors.length; i++) {
let selector = rule.selectors[i];
if (selector) {
let selectors = (selector.split(' ') ?? []).map((v) => {
if (v.startsWith('.')) {
return '.custom-' + v.substring(1);
}
return v;
}).join(' ');
rule.selectors[i] = '.mes_text ' + selectors;
}
}
}
}
}
const sheet = ast?.stylesheet;
if (sheet) {
sanitizeRuleSet(ast.stylesheet);
}
return `<style>${css.stringify(ast)}</style>`;
} catch (error) {
@@ -506,7 +524,7 @@ async function openExternalMediaOverridesDialog() {
return;
}
const template = $('#forbid_media_override_template > .forbid_media_override').clone();
const template = $(await renderTemplateAsync('forbidMedia'));
template.find('.forbid_media_global_state_forbidden').toggle(power_user.forbid_external_media);
template.find('.forbid_media_global_state_allowed').toggle(!power_user.forbid_external_media);
@@ -520,7 +538,7 @@ async function openExternalMediaOverridesDialog() {
template.find('#forbid_media_override_global').prop('checked', true);
}
callPopup(template, 'text', '', { wide: false, large: false });
callGenericPopup(template, POPUP_TYPE.TEXT, '', { wide: false, large: false });
}
export function getCurrentEntityId() {
@@ -548,7 +566,7 @@ export function isExternalMediaAllowed() {
return !power_user.forbid_external_media;
}
function enlargeMessageImage() {
async function enlargeMessageImage() {
const mesBlock = $(this).closest('.mes');
const mesId = mesBlock.attr('mesid');
const message = chat[mesId];
@@ -562,14 +580,28 @@ function enlargeMessageImage() {
const img = document.createElement('img');
img.classList.add('img_enlarged');
img.src = imgSrc;
const imgHolder = document.createElement('div');
imgHolder.classList.add('img_enlarged_holder');
imgHolder.append(img);
const imgContainer = $('<div><pre><code></code></pre></div>');
imgContainer.prepend(img);
imgContainer.prepend(imgHolder);
imgContainer.addClass('img_enlarged_container');
imgContainer.find('code').addClass('txt').text(title);
const titleEmpty = !title || title.trim().length === 0;
imgContainer.find('pre').toggle(!titleEmpty);
addCopyToCodeBlocks(imgContainer);
callGenericPopup(imgContainer, POPUP_TYPE.TEXT, '', { wide: true, large: true });
const popup = new Popup(imgContainer, POPUP_TYPE.DISPLAY, '', { large: true, transparent: true });
popup.dlg.style.width = 'unset';
popup.dlg.style.height = 'unset';
img.addEventListener('click', () => {
const shouldZoom = !img.classList.contains('zoomed');
img.classList.toggle('zoomed', shouldZoom);
});
await popup.show();
}
async function deleteMessageImage() {
@@ -584,6 +616,8 @@ async function deleteMessageImage() {
const message = chat[mesId];
delete message.extra.image;
delete message.extra.inline_image;
delete message.extra.title;
delete message.extra.append_title;
mesBlock.find('.mes_img_container').removeClass('img_extra');
mesBlock.find('.mes_img').attr('src', '');
await saveChatConditional();
@@ -751,7 +785,7 @@ async function moveAttachment(attachment, source, callback) {
* @param {boolean} [confirm=true] If true, show a confirmation dialog
* @returns {Promise<void>} A promise that resolves when the attachment is deleted.
*/
async function deleteAttachment(attachment, source, callback, confirm = true) {
export async function deleteAttachment(attachment, source, callback, confirm = true) {
if (confirm) {
const result = await callGenericPopup('Are you sure you want to delete this attachment?', POPUP_TYPE.CONFIRM);
@@ -838,6 +872,12 @@ async function openAttachmentManager() {
[ATTACHMENT_SOURCE.CHAT]: '.chatAttachmentsList',
};
const selected = template
.find(sources[source])
.find('.attachmentListItemCheckbox:checked')
.map((_, el) => $(el).closest('.attachmentListItem').attr('data-attachment-url'))
.get();
template.find(sources[source]).empty();
// Sort attachments by sortField and sortOrder, and apply filter
@@ -847,6 +887,8 @@ async function openAttachmentManager() {
const isDisabled = isAttachmentDisabled(attachment);
const attachmentTemplate = template.find('.attachmentListItemTemplate .attachmentListItem').clone();
attachmentTemplate.toggleClass('disabled', isDisabled);
attachmentTemplate.attr('data-attachment-url', attachment.url);
attachmentTemplate.attr('data-attachment-source', source);
attachmentTemplate.find('.attachmentFileIcon').attr('title', attachment.url);
attachmentTemplate.find('.attachmentListItemName').text(attachment.name);
attachmentTemplate.find('.attachmentListItemSize').text(humanFileSize(attachment.size));
@@ -859,6 +901,10 @@ async function openAttachmentManager() {
attachmentTemplate.find('.enableAttachmentButton').toggle(isDisabled).on('click', () => enableAttachment(attachment, renderAttachments));
attachmentTemplate.find('.disableAttachmentButton').toggle(!isDisabled).on('click', () => disableAttachment(attachment, renderAttachments));
template.find(sources[source]).append(attachmentTemplate);
if (selected.includes(attachment.url)) {
attachmentTemplate.find('.attachmentListItemCheckbox').prop('checked', true);
}
}
}
@@ -962,49 +1008,24 @@ async function openAttachmentManager() {
template.find('.chatAttachmentsName').text(chatName);
}
function addDragAndDrop() {
$(document.body).on('dragover', '.dialogue_popup', (event) => {
event.preventDefault();
event.stopPropagation();
$(event.target).closest('.dialogue_popup').addClass('dragover');
const dragDropHandler = new DragAndDropHandler('.popup', async (files, event) => {
let selectedTarget = ATTACHMENT_SOURCE.GLOBAL;
const targets = getAvailableTargets();
const targetSelectTemplate = $(await renderExtensionTemplateAsync('attachments', 'files-dropped', { count: files.length, targets: targets }));
targetSelectTemplate.find('.droppedFilesTarget').on('input', function () {
selectedTarget = String($(this).val());
});
$(document.body).on('dragleave', '.dialogue_popup', (event) => {
event.preventDefault();
event.stopPropagation();
$(event.target).closest('.dialogue_popup').removeClass('dragover');
});
$(document.body).on('drop', '.dialogue_popup', async (event) => {
event.preventDefault();
event.stopPropagation();
$(event.target).closest('.dialogue_popup').removeClass('dragover');
const files = Array.from(event.originalEvent.dataTransfer.files);
let selectedTarget = ATTACHMENT_SOURCE.GLOBAL;
const targets = getAvailableTargets();
const targetSelectTemplate = $(await renderExtensionTemplateAsync('attachments', 'files-dropped', { count: files.length, targets: targets }));
targetSelectTemplate.find('.droppedFilesTarget').on('input', function () {
selectedTarget = String($(this).val());
});
const result = await callGenericPopup(targetSelectTemplate, POPUP_TYPE.CONFIRM, '', { wide: false, large: false, okButton: 'Upload', cancelButton: 'Cancel' });
if (result !== POPUP_RESULT.AFFIRMATIVE) {
console.log('File upload cancelled');
return;
}
for (const file of files) {
await uploadFileAttachmentToServer(file, selectedTarget);
}
renderAttachments();
});
}
function removeDragAndDrop() {
$(document.body).off('dragover', '.shadow_popup');
$(document.body).off('dragleave', '.shadow_popup');
$(document.body).off('drop', '.shadow_popup');
}
const result = await callGenericPopup(targetSelectTemplate, POPUP_TYPE.CONFIRM, '', { wide: false, large: false, okButton: 'Upload', cancelButton: 'Cancel' });
if (result !== POPUP_RESULT.AFFIRMATIVE) {
console.log('File upload cancelled');
return;
}
for (const file of files) {
await uploadFileAttachmentToServer(file, selectedTarget);
}
renderAttachments();
});
let sortField = localStorage.getItem('DataBank_sortField') || 'created';
let sortOrder = localStorage.getItem('DataBank_sortOrder') || 'desc';
@@ -1027,15 +1048,83 @@ async function openAttachmentManager() {
localStorage.setItem('DataBank_sortOrder', sortOrder);
renderAttachments();
});
function handleBulkAction(action) {
return async () => {
const selectedAttachments = document.querySelectorAll('.attachmentListItemCheckboxContainer .attachmentListItemCheckbox:checked');
if (selectedAttachments.length === 0) {
toastr.info('No attachments selected.', 'Data Bank');
return;
}
if (action.confirmMessage) {
const confirm = await callGenericPopup(action.confirmMessage, POPUP_TYPE.CONFIRM);
if (confirm !== POPUP_RESULT.AFFIRMATIVE) {
return;
}
}
const includeDisabled = true;
const attachments = getDataBankAttachments(includeDisabled);
selectedAttachments.forEach(async (checkbox) => {
const listItem = checkbox.closest('.attachmentListItem');
if (!(listItem instanceof HTMLElement)) {
return;
}
const url = listItem.dataset.attachmentUrl;
const source = listItem.dataset.attachmentSource;
const attachment = attachments.find(a => a.url === url);
if (!attachment) {
return;
}
await action.perform(attachment, source);
});
document.querySelectorAll('.attachmentListItemCheckbox, .attachmentsBulkEditCheckbox').forEach(checkbox => {
if (checkbox instanceof HTMLInputElement) {
checkbox.checked = false;
}
});
await renderAttachments();
};
}
template.find('.bulkActionDisable').on('click', handleBulkAction({
perform: (attachment) => disableAttachment(attachment, () => { }),
}));
template.find('.bulkActionEnable').on('click', handleBulkAction({
perform: (attachment) => enableAttachment(attachment, () => { }),
}));
template.find('.bulkActionDelete').on('click', handleBulkAction({
confirmMessage: 'Are you sure you want to delete the selected attachments?',
perform: async (attachment, source) => await deleteAttachment(attachment, source, () => { }, false),
}));
template.find('.bulkActionSelectAll').on('click', () => {
$('.attachmentListItemCheckbox:visible').each((_, checkbox) => {
if (checkbox instanceof HTMLInputElement) {
checkbox.checked = true;
}
});
});
template.find('.bulkActionSelectNone').on('click', () => {
$('.attachmentListItemCheckbox:visible').each((_, checkbox) => {
if (checkbox instanceof HTMLInputElement) {
checkbox.checked = false;
}
});
});
const cleanupFn = await renderButtons();
await verifyAttachments();
await renderAttachments();
addDragAndDrop();
await callGenericPopup(template, POPUP_TYPE.TEXT, '', { wide: true, large: true, okButton: 'Close' });
await callGenericPopup(template, POPUP_TYPE.TEXT, '', { wide: true, large: true, okButton: 'Close', allowVerticalScrolling: true });
cleanupFn();
removeDragAndDrop();
dragDropHandler.destroy();
}
/**
@@ -1099,7 +1188,7 @@ async function runScraper(scraperId, target, callback) {
* Uploads a file attachment to the server.
* @param {File} file File to upload
* @param {string} target Target for the attachment
* @returns
* @returns {Promise<string>} Path to the uploaded file
*/
export async function uploadFileAttachmentToServer(file, target) {
const isValid = await validateFile(file);
@@ -1156,6 +1245,8 @@ export async function uploadFileAttachmentToServer(file, target) {
saveSettingsDebounced();
break;
}
return fileUrl;
}
function ensureAttachmentsExist() {
@@ -1183,36 +1274,42 @@ function ensureAttachmentsExist() {
}
/**
* Gets all currently available attachments. Ignores disabled attachments.
* Gets all currently available attachments. Ignores disabled attachments by default.
* @param {boolean} [includeDisabled=false] If true, include disabled attachments
* @returns {FileAttachment[]} List of attachments
*/
export function getDataBankAttachments() {
export function getDataBankAttachments(includeDisabled = false) {
ensureAttachmentsExist();
const globalAttachments = extension_settings.attachments ?? [];
const chatAttachments = chat_metadata.attachments ?? [];
const characterAttachments = extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? [];
return [...globalAttachments, ...chatAttachments, ...characterAttachments].filter(x => !isAttachmentDisabled(x));
return [...globalAttachments, ...chatAttachments, ...characterAttachments].filter(x => includeDisabled || !isAttachmentDisabled(x));
}
/**
* Gets all attachments for a specific source. Includes disabled attachments.
* Gets all attachments for a specific source. Includes disabled attachments by default.
* @param {string} source Attachment source
* @param {boolean} [includeDisabled=true] If true, include disabled attachments
* @returns {FileAttachment[]} List of attachments
*/
export function getDataBankAttachmentsForSource(source) {
export function getDataBankAttachmentsForSource(source, includeDisabled = true) {
ensureAttachmentsExist();
switch (source) {
case ATTACHMENT_SOURCE.GLOBAL:
return extension_settings.attachments ?? [];
case ATTACHMENT_SOURCE.CHAT:
return chat_metadata.attachments ?? [];
case ATTACHMENT_SOURCE.CHARACTER:
return extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? [];
function getBySource() {
switch (source) {
case ATTACHMENT_SOURCE.GLOBAL:
return extension_settings.attachments ?? [];
case ATTACHMENT_SOURCE.CHAT:
return chat_metadata.attachments ?? [];
case ATTACHMENT_SOURCE.CHARACTER:
return extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? [];
}
return [];
}
return [];
return getBySource().filter(x => includeDisabled || !isAttachmentDisabled(x));
}
/**
@@ -1370,10 +1467,11 @@ jQuery(function () {
});
}
callPopup(wrapper, 'text', '', { wide: true, large: true });
callGenericPopup(wrapper, POPUP_TYPE.TEXT, '', { wide: true, large: true });
});
$(document).on('click', 'body.documentstyle .mes .mes_text', function () {
if (window.getSelection().toString()) return;
if ($('.edit_textarea').length) return;
$(this).closest('.mes').find('.mes_edit').trigger('click');
});
@@ -1407,8 +1505,28 @@ jQuery(function () {
$(document).on('click', '.mes_img_enlarge', enlargeMessageImage);
$(document).on('click', '.mes_img_delete', deleteMessageImage);
$('#file_form_input').on('change', onFileAttach);
$('#file_form_input').on('change', async () => {
const fileInput = document.getElementById('file_form_input');
if (!(fileInput instanceof HTMLInputElement)) return;
const file = fileInput.files[0];
await onFileAttach(file);
});
$('#file_form').on('reset', function () {
$('#file_form').addClass('displayNone');
});
document.getElementById('send_textarea').addEventListener('paste', async function (event) {
if (event.clipboardData.files.length === 0) {
return;
}
event.preventDefault();
event.stopPropagation();
const fileInput = document.getElementById('file_form_input');
if (!(fileInput instanceof HTMLInputElement)) return;
fileInput.files = event.clipboardData.files;
await onFileAttach(fileInput.files[0]);
});
});

107
public/scripts/dragdrop.js vendored Normal file
View File

@@ -0,0 +1,107 @@
import { debounce_timeout } from './constants.js';
/**
* Drag and drop handler
*
* Can be used on any element, enabling drag&drop styling and callback on drop.
*/
export class DragAndDropHandler {
/** @private @type {JQuery.Selector} */ selector;
/** @private @type {(files: File[], event:JQuery.DropEvent<HTMLElement, undefined, any, any>) => void} */ onDropCallback;
/** @private @type {NodeJS.Timeout} Remark: Not actually NodeJS timeout, but it's close */ dragLeaveTimeout;
/** @private @type {boolean} */ noAnimation;
/**
* Create a DragAndDropHandler
* @param {JQuery.Selector} selector - The CSS selector for the elements to enable drag and drop
* @param {(files: File[], event:JQuery.DropEvent<HTMLElement, undefined, any, any>) => void} onDropCallback - The callback function to handle the drop event
*/
constructor(selector, onDropCallback, { noAnimation = false } = {}) {
this.selector = selector;
this.onDropCallback = onDropCallback;
this.dragLeaveTimeout = null;
this.noAnimation = noAnimation;
this.init();
}
/**
* Destroy the drag and drop functionality
*/
destroy() {
if (this.selector === 'body') {
$(document.body).off('dragover', this.handleDragOver.bind(this));
$(document.body).off('dragleave', this.handleDragLeave.bind(this));
$(document.body).off('drop', this.handleDrop.bind(this));
} else {
$(document.body).off('dragover', this.selector, this.handleDragOver.bind(this));
$(document.body).off('dragleave', this.selector, this.handleDragLeave.bind(this));
$(document.body).off('drop', this.selector, this.handleDrop.bind(this));
}
$(this.selector).remove('drop_target no_animation');
}
/**
* Initialize the drag and drop functionality
* Automatically called on construction
* @private
*/
init() {
if (this.selector === 'body') {
$(document.body).on('dragover', this.handleDragOver.bind(this));
$(document.body).on('dragleave', this.handleDragLeave.bind(this));
$(document.body).on('drop', this.handleDrop.bind(this));
} else {
$(document.body).on('dragover', this.selector, this.handleDragOver.bind(this));
$(document.body).on('dragleave', this.selector, this.handleDragLeave.bind(this));
$(document.body).on('drop', this.selector, this.handleDrop.bind(this));
}
$(this.selector).addClass('drop_target');
if (this.noAnimation) $(this.selector).addClass('no_animation');
}
/**
* @param {JQuery.DragOverEvent<HTMLElement, undefined, any, any>} event - The dragover event
* @private
*/
handleDragOver(event) {
event.preventDefault();
event.stopPropagation();
clearTimeout(this.dragLeaveTimeout);
$(this.selector).addClass('drop_target dragover');
if (this.noAnimation) $(this.selector).addClass('no_animation');
}
/**
* @param {JQuery.DragLeaveEvent<HTMLElement, undefined, any, any>} event - The dragleave event
* @private
*/
handleDragLeave(event) {
event.preventDefault();
event.stopPropagation();
// Debounce the removal of the class, so it doesn't "flicker" on dragging over
clearTimeout(this.dragLeaveTimeout);
this.dragLeaveTimeout = setTimeout(() => {
$(this.selector).removeClass('dragover');
}, debounce_timeout.quick);
}
/**
* @param {JQuery.DropEvent<HTMLElement, undefined, any, any>} event - The drop event
* @private
*/
handleDrop(event) {
event.preventDefault();
event.stopPropagation();
clearTimeout(this.dragLeaveTimeout);
$(this.selector).removeClass('dragover');
const files = Array.from(event.originalEvent.dataTransfer.files);
this.onDropCallback(files, event);
}
}

View File

@@ -0,0 +1,162 @@
/** @type {CSSStyleSheet} */
let dynamicStyleSheet = null;
/** @type {CSSStyleSheet} */
let dynamicExtensionStyleSheet = null;
/**
* An observer that will check if any new stylesheets are added to the head
* @type {MutationObserver}
*/
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
if (mutation.type !== 'childList') return;
mutation.addedNodes.forEach(node => {
if (node instanceof HTMLLinkElement && node.tagName === 'LINK' && node.rel === 'stylesheet') {
node.addEventListener('load', () => {
try {
applyDynamicFocusStyles(node.sheet);
} catch (e) {
console.warn('Failed to process new stylesheet:', e);
}
});
}
});
});
});
/**
* Generates dynamic focus styles based on the given stylesheet, taking its hover styles as reference
*
* @param {CSSStyleSheet} styleSheet - The stylesheet to process
* @param {object} [options] - Optional configuration options
* @param {boolean} [options.fromExtension=false] - Indicates if the styles are from an extension
*/
function applyDynamicFocusStyles(styleSheet, { fromExtension = false } = {}) {
/** @type {{baseSelector: string, rule: CSSStyleRule}[]} */
const hoverRules = [];
/** @type {Set<string>} */
const focusRules = new Set();
const PLACEHOLDER = ':__PLACEHOLDER__';
/**
* Processes the CSS rules and separates selectors for hover and focus
* @param {CSSRuleList} rules - The CSS rules to process
*/
function processRules(rules) {
Array.from(rules).forEach(rule => {
if (rule instanceof CSSImportRule) {
// Make sure that @import rules are processed recursively
processImportedStylesheet(rule.styleSheet);
} else if (rule instanceof CSSStyleRule) {
// Separate multiple selectors on a rule
const selectors = rule.selectorText.split(',').map(s => s.trim());
// We collect all hover and focus rules to be able to later decide which hover rules don't have a matching focus rule
selectors.forEach(selector => {
const isHover = selector.includes(':hover'), isFocus = selector.includes(':focus');
if (isHover && isFocus) {
// We currently do nothing here. Rules containing both hover and focus are very specific and should never be automatically touched
}
else if (isHover) {
const baseSelector = selector.replace(':hover', PLACEHOLDER).trim();
hoverRules.push({ baseSelector, rule });
} else if (isFocus) {
// We need to make sure that we remember all existing :focus, :focus-within and :focus-visible rules
const baseSelector = selector.replace(':focus-within', PLACEHOLDER).replace(':focus-visible', PLACEHOLDER).replace(':focus', PLACEHOLDER).trim();
focusRules.add(baseSelector);
}
});
} else if (rule instanceof CSSMediaRule || rule instanceof CSSSupportsRule) {
// Recursively process nested rules
processRules(rule.cssRules);
}
});
}
/**
* Processes the CSS rules of an imported stylesheet recursively
* @param {CSSStyleSheet} sheet - The imported stylesheet to process
*/
function processImportedStylesheet(sheet) {
if (sheet && sheet.cssRules) {
processRules(sheet.cssRules);
}
}
processRules(styleSheet.cssRules);
/** @type {CSSStyleSheet} */
let targetStyleSheet = null;
// Now finally create the dynamic focus rules
hoverRules.forEach(({ baseSelector, rule }) => {
if (!focusRules.has(baseSelector)) {
// Only initialize the dynamic stylesheet if needed
targetStyleSheet ??= getDynamicStyleSheet({ fromExtension });
// The closest keyboard-equivalent to :hover styling is utilizing the :focus-visible rule from modern browsers.
// It let's the browser decide whether a focus highlighting is expected and makes sense.
// So we take all :hover rules that don't have a manually defined focus rule yet, and create their
// :focus-visible counterpart, which will make the styling work the same for keyboard and mouse.
// If something like :focus-within or a more specific selector like `.blah:has(:focus-visible)` for elements inside,
// it should be manually defined in CSS.
const focusSelector = rule.selectorText.replace(/:hover/g, ':focus-visible');
const focusRule = `${focusSelector} { ${rule.style.cssText} }`;
try {
targetStyleSheet.insertRule(focusRule, targetStyleSheet.cssRules.length);
} catch (e) {
console.warn('Failed to insert focus rule:', e);
}
}
});
}
/**
* Retrieves the stylesheet that should be used for dynamic rules
*
* @param {object} options - The options object
* @param {boolean} [options.fromExtension=false] - Indicates whether the rules are coming from extensions
* @return {CSSStyleSheet} The dynamic stylesheet
*/
function getDynamicStyleSheet({ fromExtension = false } = {}) {
if (fromExtension) {
if (!dynamicExtensionStyleSheet) {
const styleSheetElement = document.createElement('style');
styleSheetElement.setAttribute('id', 'dynamic-extension-styles');
document.head.appendChild(styleSheetElement);
dynamicExtensionStyleSheet = styleSheetElement.sheet;
}
return dynamicExtensionStyleSheet;
} else {
if (!dynamicStyleSheet) {
const styleSheetElement = document.createElement('style');
styleSheetElement.setAttribute('id', 'dynamic-styles');
document.head.appendChild(styleSheetElement);
dynamicStyleSheet = styleSheetElement.sheet;
}
return dynamicStyleSheet;
}
}
/**
* Initializes dynamic styles for ST
*/
export function initDynamicStyles() {
// Start observing the head for any new added stylesheets
observer.observe(document.head, {
childList: true,
subtree: true
});
// Process all stylesheets on initial load
Array.from(document.styleSheets).forEach(sheet => {
try {
applyDynamicFocusStyles(sheet, { fromExtension: sheet.href.toLowerCase().includes('scripts/extensions') });
} catch (e) {
console.warn('Failed to process stylesheet on initial load:', e);
}
});
}

View File

@@ -1,5 +1,6 @@
import { callPopup, eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js';
import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js';
import { hideLoader, showLoader } from './loader.js';
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
import { renderTemplate, renderTemplateAsync } from './templates.js';
import { isSubsetOf, setValueByPath } from './utils.js';
export {
@@ -122,7 +123,9 @@ const extension_settings = {
custom: [],
},
dice: {},
/** @type {import('./char-data.js').RegexScriptData[]} */
regex: [],
character_allowed_regex: [],
tts: {},
sd: {
prompts: {},
@@ -345,14 +348,12 @@ function autoConnectInputHandler() {
saveSettingsDebounced();
}
function addExtensionsButtonAndMenu() {
const buttonHTML =
'<div id="extensionsMenuButton" style="display: none;" class="fa-solid fa-magic-wand-sparkles" title="Extras Extensions" /></div>';
const extensionsMenuHTML = '<div id="extensionsMenu" class="options-content" style="display: none;"></div>';
async function addExtensionsButtonAndMenu() {
const buttonHTML = await renderTemplateAsync('wandButton');
const extensionsMenuHTML = await renderTemplateAsync('wandMenu');
$(document.body).append(extensionsMenuHTML);
$('#leftSendForm').prepend(buttonHTML);
$('#leftSendForm').append(buttonHTML);
const button = $('#extensionsMenuButton');
const dropdown = $('#extensionsMenu');
@@ -503,7 +504,7 @@ function addExtensionScript(name, manifest) {
* @param {boolean} isDisabled - Whether the extension is disabled or not.
* @param {boolean} isExternal - Whether the extension is external or not.
* @param {string} checkboxClass - The class for the checkbox HTML element.
* @return {string} - The HTML string that represents the extension.
* @return {Promise<string>} - The HTML string that represents the extension.
*/
async function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, checkboxClass) {
const displayName = manifest.display_name;
@@ -555,8 +556,10 @@ async function generateExtensionHtml(name, manifest, isActive, isDisabled, isExt
} else if (!isDisabled) { // Neither active nor disabled
const requirements = new Set(manifest.requires);
modules.forEach(x => requirements.delete(x));
const requirementsString = DOMPurify.sanitize([...requirements].join(', '));
extensionHtml += `<p>Missing modules: <span class="failure">${requirementsString}</span></p>`;
if (requirements.size > 0) {
const requirementsString = DOMPurify.sanitize([...requirements].join(', '));
extensionHtml += `<p>Missing modules: <span class="failure">${requirementsString}</span></p>`;
}
}
return extensionHtml;
@@ -631,7 +634,18 @@ async function showExtensionsDetails() {
${htmlDefault}
${htmlExternal}
`;
popupPromise = callPopup(`<div class="extensions_info">${html}</div>`, 'text', '', { okButton: 'Close', wide: true, large: true });
/** @type {import('./popup.js').CustomPopupButton} */
const updateAllButton = {
text: 'Update all',
appendAtEnd: true,
action: async () => {
requiresReload = true;
await autoUpdateExtensions(true);
popup.complete(POPUP_RESULT.AFFIRMATIVE);
},
};
const popup = new Popup(`<div class="extensions_info">${html}</div>`, POPUP_TYPE.TEXT, '', { okButton: 'Close', wide: true, large: true, customButtons: [updateAllButton], allowVerticalScrolling: true });
popupPromise = popup.show();
} catch (error) {
toastr.error('Error loading extensions. See browser console for details.');
console.error(error);
@@ -700,8 +714,8 @@ async function updateExtension(extensionName, quiet) {
async function onDeleteClick() {
const extensionName = $(this).data('name');
// use callPopup to create a popup for the user to confirm before delete
const confirmation = await callPopup(`Are you sure you want to delete ${extensionName}?`, 'delete_extension');
if (confirmation) {
const confirmation = await callGenericPopup(`Are you sure you want to delete ${extensionName}?`, POPUP_TYPE.CONFIRM, '', {});
if (confirmation === POPUP_RESULT.AFFIRMATIVE) {
await deleteExtension(extensionName);
}
}
@@ -797,7 +811,7 @@ async function loadExtensionSettings(settings, versionChanged) {
manifests = await getManifests(extensionNames);
if (versionChanged) {
await autoUpdateExtensions();
await autoUpdateExtensions(false);
}
await activateExtensions();
@@ -860,7 +874,12 @@ async function checkForExtensionUpdates(force) {
}
}
async function autoUpdateExtensions() {
/**
* Updates all 3rd-party extensions that have auto-update enabled.
* @param {boolean} forceAll Force update all even if not auto-updating
* @returns {Promise<void>}
*/
async function autoUpdateExtensions(forceAll) {
if (!Object.values(manifests).some(x => x.auto_update)) {
return;
}
@@ -868,7 +887,7 @@ async function autoUpdateExtensions() {
const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 });
const promises = [];
for (const [id, manifest] of Object.entries(manifests)) {
if (manifest.auto_update && id.startsWith('third-party')) {
if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) {
console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`);
promises.push(updateExtension(id.replace('third-party', ''), true));
}
@@ -959,8 +978,8 @@ export async function writeExtensionField(characterId, key, value) {
}
}
jQuery(function () {
addExtensionsButtonAndMenu();
jQuery(async function () {
await addExtensionsButtonAndMenu();
$('#extensionsMenuButton').css('display', 'flex');
$('#extensions_connect').on('click', connectClickHandler);
@@ -988,14 +1007,14 @@ jQuery(function () {
<p><b>Disclaimer:</b> Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.</p>
<br>
<p>Example: <tt> https://github.com/author/extension-name </tt></p>`;
const input = await callPopup(html, 'input');
const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '');
if (!input) {
console.debug('Extension install cancelled');
return;
}
const url = input.trim();
const url = String(input).trim();
await installExtension(url);
});
});

View File

@@ -0,0 +1,9 @@
<div class="characterAsset">
<div class="characterAssetName">{{name}}</div>
<img class="characterAssetImage" alt="{{name}}" src="{{url}}" />
<div class="characterAssetDescription" title="{{description}}">{{description}}</div>
<div class="characterAssetButtons flex-container">
<div class="characterAssetDownloadButton right_menu_button fa-fw fa-solid fa-download" title="Download"></div>
<div class="characterAssetCheckMark right_menu_button fa-fw fa-solid fa-check" title="Installed"></div>
</div>
</div>

View File

@@ -3,8 +3,9 @@ TODO:
*/
//const DEBUG_TONY_SAMA_FORK_MODE = true
import { getRequestHeaders, callPopup, processDroppedFiles } from '../../../script.js';
import { getRequestHeaders, callPopup, processDroppedFiles, eventSource, event_types } from '../../../script.js';
import { deleteExtension, extensionNames, getContext, installExtension, renderExtensionTemplateAsync } from '../../extensions.js';
import { POPUP_TYPE, callGenericPopup } from '../../popup.js';
import { executeSlashCommands } from '../../slash-commands.js';
import { getStringHash, isValidUrl } from '../../utils.js';
export { MODULE_NAME };
@@ -108,7 +109,7 @@ function downloadAssetsList(url) {
</div>`);
}
for (const i in availableAssets[assetType]) {
for (const i in availableAssets[assetType].sort((a, b) => a?.name && b?.name && a['name'].localeCompare(b['name']))) {
const asset = availableAssets[assetType][i];
const elemId = `assets_install_${assetType}_${i}`;
let element = $('<div />', { id: elemId, class: 'asset-download-button right_menu_button' });
@@ -199,6 +200,9 @@ function downloadAssetsList(url) {
</div>`);
if (assetType === 'character') {
if (asset.highlight) {
assetBlock.find('.asset-name').append('<i class="fa-solid fa-sm fa-trophy"></i>');
}
assetBlock.find('.asset-name').prepend(`<div class="avatar"><img src="${asset['url']}" alt="${displayName}"></div>`);
}
@@ -328,6 +332,41 @@ async function deleteAsset(assetType, filename) {
}
}
async function openCharacterBrowser(forceDefault) {
const url = forceDefault ? ASSETS_JSON_URL : String($('#assets-json-url-field').val());
const fetchResult = await fetch(url, { cache: 'no-cache' });
const json = await fetchResult.json();
const characters = json.filter(x => x.type === 'character');
if (!characters.length) {
toastr.error('No characters found in the assets list', 'Character browser');
return;
}
const template = $(await renderExtensionTemplateAsync(MODULE_NAME, 'market', {}));
for (const character of characters.sort((a, b) => a.name.localeCompare(b.name))) {
const listElement = template.find(character.highlight ? '.contestWinnersList' : '.featuredCharactersList');
const characterElement = $(await renderExtensionTemplateAsync(MODULE_NAME, 'character', character));
const downloadButton = characterElement.find('.characterAssetDownloadButton');
const checkMark = characterElement.find('.characterAssetCheckMark');
const isInstalled = isAssetInstalled('character', character.id);
downloadButton.toggle(!isInstalled).on('click', async () => {
downloadButton.toggleClass('fa-download fa-spinner fa-spin');
await installAsset(character.url, 'character', character.id);
downloadButton.hide();
checkMark.show();
});
checkMark.toggle(isInstalled);
listElement.append(characterElement);
}
callGenericPopup(template, POPUP_TYPE.TEXT, '', { okButton: 'Close', wide: true, large: true, allowVerticalScrolling: true, allowHorizontalScrolling: false });
}
//#############################//
// API Calls //
//#############################//
@@ -361,6 +400,11 @@ jQuery(async () => {
const assetsJsonUrl = windowHtml.find('#assets-json-url-field');
assetsJsonUrl.val(ASSETS_JSON_URL);
const charactersButton = windowHtml.find('#assets-characters-button');
charactersButton.on('click', async function () {
openCharacterBrowser(false);
});
const connectButton = windowHtml.find('#assets-connect-button');
connectButton.on('click', async function () {
const url = String(assetsJsonUrl.val());
@@ -396,5 +440,9 @@ jQuery(async () => {
});
windowHtml.find('#assets_filters').hide();
$('#extensions_settings').append(windowHtml);
$('#assets_container').append(windowHtml);
eventSource.on(event_types.OPEN_CHARACTER_LIBRARY, async (forceDefault) => {
openCharacterBrowser(forceDefault);
});
});

View File

@@ -0,0 +1,19 @@
<div class="flex-container flexFlowColumn padding5">
<div class="contestWinners flex-container flexFlowColumn">
<h3 class="flex-container alignItemsBaseline justifyCenter" data-i18n="[title]These characters are the winners of character design contests and have outstandable quality." title="These characters are the winners of character design contests and have outstandable quality.">
<span data-i18n="Contest Winners">Contest Winners</span>
<i class="fa-solid fa-star"></i>
</h3>
<div class="contestWinnersList characterAssetList">
</div>
</div>
<hr>
<div class="featuredCharacters flex-container flexFlowColumn">
<h3 class="flex-container alignItemsBaseline justifyCenter" data-i18n="[title]These characters are the finalists of character design contests and have remarkable quality." title="These characters are the finalists of character design contests and have remarkable quality.">
<span data-i18n="Featured Characters">Featured Characters</span>
<i class="fa-solid fa-thumbs-up"></i>
</h3>
<div class="featuredCharactersList characterAssetList">
</div>
</div>
</div>

View File

@@ -105,3 +105,54 @@
transform: rotate(1turn);
}
}
.characterAssetList {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
.characterAsset {
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
gap: 10px;
border: 1px solid var(--SmartThemeBorderColor);
background-color: var(--black30a);
border-radius: 10px;
width: 17%;
min-width: 150px;
margin: 5px;
overflow: hidden;
}
.characterAssetName {
font-size: 1.2em;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.characterAssetImage {
max-height: 140px;
object-fit: scale-down;
border-radius: 5px;
}
.characterAssetDescription {
font-size: 0.75em;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
flex: 1;
}
.characterAssetButtons {
display: flex;
flex-direction: row;
gap: 5px;
align-items: center;
}

View File

@@ -1,11 +1,11 @@
<div id="assets_ui">
<div class="inline-drawer">
<div class="inline-drawer-toggle inline-drawer-header">
<b>Download Extensions & Assets</b>
<b data-i18n="Download Extensions & Assets">Download Extensions & Assets</b>
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
</div>
<div class="inline-drawer-content">
<label for="assets-json-url-field">Assets URL</label>
<label for="assets-json-url-field" data-i18n="Assets URL">Assets URL</label>
<div class="assets-connect-div">
<input id="assets-json-url-field" class="text_pole widthUnset flex1">
<i id="assets-connect-button" class="menu_button fa-solid fa-plug-circle-exclamation fa-xl redOverlayGlow"></i>
@@ -14,6 +14,10 @@
<select id="assets_type_select" class="text_pole flex1">
</select>
<input id="assets_search" class="text_pole flex1" placeholder="Search" type="search">
<div id="assets-characters-button" class="menu_button menu_button_icon">
<i class="fa-solid fa-image-portrait"></i>
<span data-i18n="Characters">Characters</span>
</div>
</div>
<div class="inline-drawer-content" id="assets_menu">
</div>

View File

@@ -0,0 +1,4 @@
<div id="attachFile" class="list-group-item flex-container flexGap5" title="Attach a file or image to a current chat.">
<div class="fa-fw fa-solid fa-paperclip extensionsMenuExtensionButton"></div>
<span data-i18n="Attach a File">Attach a File</span>
</div>

View File

@@ -4,7 +4,7 @@
Enter a URL or the ID of a Fandom wiki page to scrape:
</label>
<small>
<span data-i18n=Examples:">Examples:</span>
<span data-i18n="Examples:">Examples:</span>
<code>https://harrypotter.fandom.com/</code>
<span data-i18n="or">or</span>
<code>harrypotter</code>

View File

@@ -1,9 +1,360 @@
import { renderExtensionTemplateAsync } from '../../extensions.js';
import { registerSlashCommand } from '../../slash-commands.js';
import { deleteAttachment, getDataBankAttachments, getDataBankAttachmentsForSource, getFileAttachment, uploadFileAttachmentToServer } from '../../chats.js';
import { extension_settings, renderExtensionTemplateAsync } from '../../extensions.js';
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
import { SlashCommandClosure } from '../../slash-commands/SlashCommandClosure.js';
import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
import { SlashCommandExecutor } from '../../slash-commands/SlashCommandExecutor.js';
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
/**
* List of attachment sources
* @type {string[]}
*/
const TYPES = ['global', 'character', 'chat'];
const FIELDS = ['name', 'url'];
/**
* Get attachments from the data bank. Includes disabled attachments.
* @param {string} [source] Source for the attachments
* @returns {import('../../chats').FileAttachment[]} List of attachments
*/
function getAttachments(source) {
if (!source || !TYPES.includes(source)) {
return getDataBankAttachments(true);
}
return getDataBankAttachmentsForSource(source, true);
}
/**
* Get attachment by a single name or URL.
* @param {import('../../chats').FileAttachment[]} attachments List of attachments
* @param {string} value Name or URL of the attachment
* @returns {import('../../chats').FileAttachment} Attachment
*/
function getAttachmentByField(attachments, value) {
const match = (a) => String(a).trim().toLowerCase() === String(value).trim().toLowerCase();
const fullMatchByURL = attachments.find(it => match(it.url));
const fullMatchByName = attachments.find(it => match(it.name));
return fullMatchByURL || fullMatchByName;
}
/**
* Get attachment by multiple fields.
* @param {import('../../chats').FileAttachment[]} attachments List of attachments
* @param {string[]} values Name and URL of the attachment to search for
* @returns
*/
function getAttachmentByFields(attachments, values) {
for (const value of values) {
const attachment = getAttachmentByField(attachments, value);
if (attachment) {
return attachment;
}
}
return null;
}
/**
* Callback for listing attachments in the data bank.
* @param {object} args Named arguments
* @returns {string} JSON string of the list of attachments
*/
function listDataBankAttachments(args) {
const attachments = getAttachments(args?.source);
const field = args?.field;
return JSON.stringify(attachments.map(a => FIELDS.includes(field) ? a[field] : a.url));
}
/**
* Callback for getting text from an attachment in the data bank.
* @param {object} args Named arguments
* @param {string} value Name or URL of the attachment
* @returns {Promise<string>} Content of the attachment
*/
async function getDataBankText(args, value) {
if (!value) {
toastr.warning('No attachment name or URL provided.');
return;
}
const attachments = getAttachments(args?.source);
const attachment = getAttachmentByField(attachments, value);
if (!attachment) {
toastr.warning('Attachment not found.');
return;
}
const content = await getFileAttachment(attachment.url);
return content;
}
/**
* Callback for adding an attachment to the data bank.
* @param {object} args Named arguments
* @param {string} value Content of the attachment
* @returns {Promise<string>} URL of the attachment
*/
async function uploadDataBankAttachment(args, value) {
const source = args?.source && TYPES.includes(args.source) ? args.source : 'chat';
const name = args?.name || new Date().toLocaleString();
const file = new File([value], name, { type: 'text/plain' });
const url = await uploadFileAttachmentToServer(file, source);
return url;
}
/**
* Callback for updating an attachment in the data bank.
* @param {object} args Named arguments
* @param {string} value Content of the attachment
* @returns {Promise<string>} URL of the attachment
*/
async function updateDataBankAttachment(args, value) {
const source = args?.source && TYPES.includes(args.source) ? args.source : 'chat';
const attachments = getAttachments(source);
const attachment = getAttachmentByFields(attachments, [args?.url, args?.name]);
if (!attachment) {
toastr.warning('Attachment not found.');
return '';
}
await deleteAttachment(attachment, source, () => { }, false);
const file = new File([value], attachment.name, { type: 'text/plain' });
const url = await uploadFileAttachmentToServer(file, source);
return url;
}
/**
* Callback for deleting an attachment from the data bank.
* @param {object} args Named arguments
* @param {string} value Name or URL of the attachment
* @returns {Promise<string>} Empty string
*/
async function deleteDataBankAttachment(args, value) {
const source = args?.source && TYPES.includes(args.source) ? args.source : 'chat';
const attachments = getAttachments(source);
const attachment = getAttachmentByField(attachments, value);
if (!attachment) {
toastr.warning('Attachment not found.');
return '';
}
await deleteAttachment(attachment, source, () => { }, false);
return '';
}
/**
* Callback for disabling an attachment in the data bank.
* @param {object} args Named arguments
* @param {string} value Name or URL of the attachment
* @returns {Promise<string>} Empty string
*/
async function disableDataBankAttachment(args, value) {
const attachments = getAttachments(args?.source);
const attachment = getAttachmentByField(attachments, value);
if (!attachment) {
toastr.warning('Attachment not found.');
return '';
}
if (extension_settings.disabled_attachments.includes(attachment.url)) {
return '';
}
extension_settings.disabled_attachments.push(attachment.url);
return '';
}
/**
* Callback for enabling an attachment in the data bank.
* @param {object} args Named arguments
* @param {string} value Name or URL of the attachment
* @returns {Promise<string>} Empty string
*/
async function enableDataBankAttachment(args, value) {
const attachments = getAttachments(args?.source);
const attachment = getAttachmentByField(attachments, value);
if (!attachment) {
toastr.warning('Attachment not found.');
return '';
}
const index = extension_settings.disabled_attachments.indexOf(attachment.url);
if (index === -1) {
return '';
}
extension_settings.disabled_attachments.splice(index, 1);
return '';
}
jQuery(async () => {
const buttons = await renderExtensionTemplateAsync('attachments', 'buttons', {});
$('#extensionsMenu').prepend(buttons);
const manageButton = await renderExtensionTemplateAsync('attachments', 'manage-button', {});
const attachButton = await renderExtensionTemplateAsync('attachments', 'attach-button', {});
$('#data_bank_wand_container').append(manageButton);
$('#attach_file_wand_container').append(attachButton);
registerSlashCommand('db', () => document.getElementById('manageAttachments')?.click(), ['databank', 'data-bank'], ' open the data bank', true, true);
/** A collection of local enum providers for this context of data bank */
const localEnumProviders = {
/**
* All attachments in the data bank based on the source argument. If not provided, defaults to 'chat'.
* @param {'name' | 'url'} returnField - Whether the enum should return the 'name' field or the 'url'
* @param {'chat' | 'character' | 'global' | ''} fallbackSource - The source to use if the source argument is not provided. Empty string to use all sources.
* */
attachments: (returnField = 'name', fallbackSource = 'chat') => (/** @type {SlashCommandExecutor} */ executor) => {
const source = executor.namedArgumentList.find(it => it.name == 'source')?.value ?? fallbackSource;
if (source instanceof SlashCommandClosure) throw new Error('Argument \'source\' does not support closures');
const attachments = getAttachments(source);
return attachments.map(attachment => new SlashCommandEnumValue(
returnField === 'name' ? attachment.name : attachment.url,
`${enumIcons.getStateIcon(!extension_settings.disabled_attachments.includes(attachment.url))} [${source}] ${returnField === 'url' ? attachment.name : attachment.url}`,
enumTypes.enum, enumIcons.file));
},
};
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db',
callback: () => {
document.getElementById('manageAttachments')?.click();
return '';
},
aliases: ['databank', 'data-bank'],
helpString: 'Open the data bank',
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-list',
callback: listDataBankAttachments,
aliases: ['databank-list', 'data-bank-list'],
helpString: 'List attachments in the Data Bank as a JSON-serialized array. Optionally, provide the source of the attachments and the field to list by.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source of the attachments.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
new SlashCommandNamedArgument('field', 'The field to list by.', ARGUMENT_TYPE.STRING, false, false, 'url', FIELDS),
],
returns: ARGUMENT_TYPE.LIST,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-get',
callback: getDataBankText,
aliases: ['databank-get', 'data-bank-get'],
helpString: 'Get attachment text from the Data Bank. Either provide the name or URL of the attachment. Optionally, provide the source of the attachment.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'The name or URL of the attachment.',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
acceptsMultiple: false,
enumProvider: localEnumProviders.attachments('name', ''),
}),
],
returns: ARGUMENT_TYPE.STRING,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-add',
callback: uploadDataBankAttachment,
aliases: ['databank-add', 'data-bank-add'],
helpString: 'Add an attachment to the Data Bank. If name is not provided, it will be generated automatically. Returns the URL of the attachment.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source for the attachment.', ARGUMENT_TYPE.STRING, false, false, 'chat', TYPES),
new SlashCommandNamedArgument('name', 'The name of the attachment.', ARGUMENT_TYPE.STRING, false, false),
],
unnamedArgumentList: [
new SlashCommandArgument('The content of the file attachment.', ARGUMENT_TYPE.STRING, true, false),
],
returns: ARGUMENT_TYPE.STRING,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-update',
callback: updateDataBankAttachment,
aliases: ['databank-update', 'data-bank-update'],
helpString: 'Update an attachment in the Data Bank, preserving its name. Returns a new URL of the attachment.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source for the attachment.', ARGUMENT_TYPE.STRING, false, false, 'chat', TYPES),
SlashCommandNamedArgument.fromProps({
name: 'name',
description: 'The name of the attachment.',
typeList: [ARGUMENT_TYPE.STRING],
enumProvider: localEnumProviders.attachments('name'),
}),
SlashCommandNamedArgument.fromProps({
name: 'url',
description: 'The URL of the attachment.',
typeList: [ARGUMENT_TYPE.STRING],
enumProvider: localEnumProviders.attachments('url'),
}),
],
unnamedArgumentList: [
new SlashCommandArgument('The content of the file attachment.', ARGUMENT_TYPE.STRING, true, false),
],
returns: ARGUMENT_TYPE.STRING,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-disable',
callback: disableDataBankAttachment,
aliases: ['databank-disable', 'data-bank-disable'],
helpString: 'Disable an attachment in the Data Bank by its name or URL. Optionally, provide the source of the attachment.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'The name or URL of the attachment.',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: localEnumProviders.attachments('name', ''),
}),
],
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-enable',
callback: enableDataBankAttachment,
aliases: ['databank-enable', 'data-bank-enable'],
helpString: 'Enable an attachment in the Data Bank by its name or URL. Optionally, provide the source of the attachment.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, '', TYPES),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'The name or URL of the attachment.',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: localEnumProviders.attachments('name', ''),
}),
],
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'db-delete',
callback: deleteDataBankAttachment,
aliases: ['databank-delete', 'data-bank-delete'],
helpString: 'Delete an attachment from the Data Bank.',
namedArgumentList: [
new SlashCommandNamedArgument('source', 'The source of the attachment.', ARGUMENT_TYPE.STRING, false, false, 'chat', TYPES),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'The name or URL of the attachment.',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
enumProvider: localEnumProviders.attachments(),
}),
],
}));
});

View File

@@ -1,7 +1,4 @@
<div id="attachFile" class="list-group-item flex-container flexGap5" title="Attach a file or image to a current chat.">
<div class="fa-fw fa-solid fa-paperclip extensionsMenuExtensionButton"></div>
<span data-i18n="Attach a File">Attach a File</span>
</div>
<div id="manageAttachments" class="list-group-item flex-container flexGap5" title="View global, character, or data files.">
<div class="fa-fw fa-solid fa-book-open-reader extensionsMenuExtensionButton"></div>

Some files were not shown because too many files have changed in this diff Show More